Skip to content

Commit

Permalink
feat: add grow(), shrink() and pxrem features 😎
Browse files Browse the repository at this point in the history
  • Loading branch information
BernhardBaumrock committed Feb 4, 2025
1 parent 9a77e97 commit 4120d15
Show file tree
Hide file tree
Showing 5 changed files with 295 additions and 6 deletions.
12 changes: 12 additions & 0 deletions RockDevTools.module.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use RockDevTools\Assets;
use RockDevTools\LiveReload;
use RockDevTools\RockCSS;

function rockdevtools(): RockDevTools
{
Expand All @@ -20,6 +21,8 @@ class RockDevTools extends WireData implements Module
{
public $livereload;

private $rockcss = false;

public function __construct()
{
// early exit if not enabled to keep the footprint as low as possible
Expand Down Expand Up @@ -69,6 +72,15 @@ public function resetCache(HookEvent $event): void
wire()->cache->delete('rockdevtools-filenames-*');
}

/**
* @return RockCSS
*/
public function rockcss()
{
if (!$this->rockcss) $this->rockcss = new RockCSS();
return $this->rockcss;
}

/**
* Ensures that given path is a path within the PW root.
*
Expand Down
17 changes: 12 additions & 5 deletions classes/CssArray.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,28 @@

use MatthiasMullie\Minify\CSS;

use function ProcessWire\rockdevtools;
use function ProcessWire\wire;

class CssArray extends FilenameArray
{
public function saveCSS(string $to): void
{
// first we merge all the css
$css = '';
foreach ($this as $file) $css .= @wire()->files->fileGetContents($file);

// then we compile rockcss features (grow/shrink/pxrem)
$css = rockdevtools()->rockcss()->compile($css);

// then write resulting css back to file
if (str_ends_with($to, '.min.css')) {
// minify content
// minified
$minifier = new CSS();
foreach ($this as $file) $minifier->add($file);
$minifier->add($css);
$minifier->minify($to);
} else {
// merge content
$css = '';
foreach ($this as $file) $css .= @wire()->files->fileGetContents($file);
// unminified
wire()->files->filePutContents($to, $css);
}
}
Expand Down
7 changes: 6 additions & 1 deletion classes/LessArray.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace RockDevTools;

use ProcessWire\Less;

use function ProcessWire\rockdevtools;
use function ProcessWire\wire;

class LessArray extends FilenameArray
Expand All @@ -11,6 +14,8 @@ public function saveLESS(string $dst): void
/** @var Less $less */
$less = wire()->modules->get('Less');
foreach ($this as $file) $less->addFile($file);
$less->saveCss($dst);
$css = $less->getCss();
$css = rockdevtools()->rockcss()->compile($css);
wire()->files->filePutContents($dst, $css);
}
}
108 changes: 108 additions & 0 deletions classes/RockCSS.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php

namespace RockDevTools;

use ProcessWire\Wire;

class RockCSS extends Wire
{
private $remBase = 16;
private $min = 375;
private $max = 1440;

public function __debugInfo(): array
{
return [
'max' => $this->max,
'min' => $this->min,
'remBase' => $this->remBase,
];
}

/**
* Compile given css to css with applied RockCSS rules
* @param string $css
* @return string
*/
public function compile(string $css): string
{
$css = $this->compileGrow($css);
$css = $this->compileShrink($css);
$css = $this->pxREM($css); // after grow + shrink!
return $css;
}

/**
* Compile grow() function
* @param string $css
* @return string
*/
public function compileGrow(string $css): string
{
if (!str_contains($css, 'grow(')) return $css;
return preg_replace_callback(
"/grow\((.*?),(.*?)(,(.*?))?(,(.*?))?\);/",
function ($match) {
if (count($match) < 3) return false;
$match = array_map('trim', $match);
$from = $match[1];
$to = $match[2];
$breakpointMin = $match[3] ?? $this->min;
$breakpointMax = $match[4] ?? $this->max;
$diff = (int)$to - (int)$from;

$percent = "((100vw - {$breakpointMin}px) / ($breakpointMax - $breakpointMin))";
$result = "clamp($from, $from + $diff * $percent, $to);";
return $result;
},
$css
);
}

/**
* Compile shrink() function
* @param string $css
* @return string
*/
public function compileShrink(string $css): string
{
if (!str_contains($css, 'shrink(')) return $css;
return preg_replace_callback(
"/shrink\((.*?),(.*?)(,(.*?))?(,(.*?))?\);/",
function ($match) {
if (count($match) < 3) return false;
$match = array_map('trim', $match);
$to = $match[1];
$from = $match[2];
$breakpointMin = $match[3] ?? $this->min;
$breakpointMax = $match[4] ?? $this->max;
$diff = (int)$to - (int)$from;

$percent = "((100vw - {$breakpointMin}px) / ($breakpointMax - $breakpointMin))";
$result = "clamp($from, $to - $diff * $percent, $to);";
return $result;
},
$css
);
}

public function pxrem(string $css): string
{
if (!str_contains($css, 'pxrem')) return $css;
return preg_replace_callback("/([0-9\.]+)(pxrem)/", function ($matches) {
$px = $matches[1];
$rem = round($px / $this->remBase, 3);
return $rem . "rem";
}, $css);
}

/**
* Set remBase, min and max
* @param array $values
* @return void
*/
public function setup(array $values): void
{
foreach ($values as $k => $v) $this->$k = $v;
}
}
157 changes: 157 additions & 0 deletions docs/rockcss/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# RockCSS

RockCSS is a powerful CSS extension that brings fluid typography and responsive scaling to your ProcessWire projects with minimal effort. It introduces two groundbreaking functions - `grow()` and `shrink()` - that make responsive design intuitive and maintainable.

## Why RockCSS is Great

1. **Simplified Fluid Typography**
- No more complex `calc()` or `clamp()` formulas
- Intuitive syntax that clearly shows your intent
- Perfect for creating smooth, responsive text scaling

2. **Smart Defaults**
- Pre-configured breakpoints (375px to 1440px) that work for most projects
- Easily customizable when needed
- Based on real-world usage patterns

3. **Zero Dependencies**
- Built directly into RockDevTools
- No external libraries required
- Lightweight and fast

4. **Developer-Friendly**
- Clean, readable syntax
- Predictable output
- Easy to debug

## Usage

### The grow() Function

The `grow()` function smoothly scales a value UP as the viewport width increases:

```css
.element {
font-size: grow(16px, 24px);
}
```

This will:
- Start at 16px on mobile (375px viewport)
- Smoothly scale up to 24px on desktop (1440px viewport)
- Create fluid scaling in between
- Maintain min/max limits for viewport sizes outside the range

### The shrink() Function

The `shrink()` function smoothly scales a value DOWN as the viewport width decreases:

```css
.element {
padding: shrink(100px, 20px);
}
```

This will:
- Start at 100px on desktop (1440px viewport)
- Smoothly scale down to 20px on mobile (375px viewport)
- Create fluid scaling in between
- Maintain min/max limits for viewport sizes outside the range

### The pxrem Feature

The `pxrem` feature converts pixel values to rem units based on your configured `remBase`:

```css
.element {
padding: 20pxrem;
}
```

This will convert 20px to rem units. For example, if your `remBase` is 20, this would output `1rem`.

### Custom Breakpoints

You can optionally specify custom breakpoints:

```css
.element {
margin: grow(20px, 40px, 768px, 1920px);
}
```

## Configuration

RockCSS comes with sensible defaults but can be easily customized:

```php
// site/ready.php
$rockcss = rockdevtools()->rockcss();
$rockcss->setup([
'remBase' => 20, // Change the base rem value
'min' => 375, // Change minimum viewport width
'max' => 1440, // Change maximum viewport width
]);
```

## How It Works

RockCSS transforms your intuitive `grow()` and `shrink()` functions into optimized CSS `clamp()` statements. For example:

```css
/* Your code */
font-size: grow(16px, 24px);

/* Compiles to */
font-size: clamp(16px, 16px + 8 * ((100vw - 375px) / (1440 - 375)), 24px);
```

## Benefits Over Traditional Methods

1. **Maintainability**
- Clear intent in your code
- Easy to understand and modify values
- No complex calculations to maintain

2. **Reliability**
- Consistent behavior across browsers
- No floating-point rounding issues
- Predictable scaling

3. **Performance**
- Compiles to native CSS
- No JavaScript required
- Zero runtime overhead

4. **DRY (Don't Repeat Yourself)**
- No need to repeat complex calculations
- Consistent scaling across your project
- Easy to update global scaling behavior

## Best Practices

1. Use `grow()` for properties that should increase with screen size:
- Font sizes
- Margins and padding
- Grid gaps

2. Use `shrink()` for properties that should decrease with screen size:
- Hero image heights
- Sidebar widths
- Large spacings

3. Keep your scale ranges reasonable:
- Don't scale too dramatically
- Consider readability at all sizes
- Test on real devices

## Integration with RockFrontend

RockCSS is seamlessly integrated with RockFrontend, making it a perfect companion for:
- LESS/SCSS preprocessing
- Asset compilation
- Component-based development

## Conclusion

RockCSS brings the power of fluid typography and responsive scaling to ProcessWire in an elegant, maintainable way. It simplifies complex responsive design patterns into intuitive functions that are easy to understand and modify, making it an invaluable tool for modern web development.

0 comments on commit 4120d15

Please sign in to comment.