fractalstyler2 0.1.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +61 -59
  2. package/dist/cli.js +47 -9
  3. package/dist/index.d.ts +32 -1
  4. package/dist/index.js +73 -4
  5. package/dist/mcp/export.d.ts +13 -0
  6. package/dist/mcp/export.js +76 -0
  7. package/dist/mcp/schemas/compile_fractals.json +20 -0
  8. package/dist/mcp/schemas/css_to_fractals.json +16 -0
  9. package/dist/mcp/schemas/generate_component.json +45 -0
  10. package/dist/mcp/schemas/get_design_tokens.json +23 -0
  11. package/dist/mcp/schemas/instructions.md +18 -0
  12. package/dist/mcp/schemas/list_fractals.json +20 -0
  13. package/dist/mcp/schemas/snap_to_tokens.json +25 -0
  14. package/dist/mcp/schemas/validate_recipe.json +16 -0
  15. package/dist/mcp/server.js +28 -12
  16. package/dist/styles/{_tokens.sass → _00_tokens.sass} +75 -64
  17. package/dist/styles/{_config.sass → _01_config.sass} +28 -36
  18. package/dist/styles/_02_fonts.sass +13 -0
  19. package/dist/styles/_03_responsive.sass +31 -0
  20. package/dist/styles/{_atoms.sass → _04_atoms.sass} +4 -4
  21. package/{templates/_molecules.sass → dist/styles/_05_molecules.sass} +16 -12
  22. package/dist/styles/_06_recipes.sass +189 -0
  23. package/dist/styles/{_base.sass → _07_base.sass} +3 -2
  24. package/dist/styles/_08_blocks.sass +433 -0
  25. package/dist/styles/_09_utilities.sass +208 -0
  26. package/dist/styles/_10_layouts.sass +373 -0
  27. package/dist/styles/_11_own.sass +21 -0
  28. package/dist/styles/_fractals.sass +7 -6
  29. package/dist/styles/index.sass +14 -16
  30. package/mcp.json +11 -0
  31. package/package.json +6 -3
  32. package/plugin.json +22 -0
  33. package/skills/fractal-styler/SKILL.md +83 -0
  34. package/skills/fractal-styler/references/fractals.md +28 -0
  35. package/skills/fractal-styler/references/tokens.md +36 -0
  36. package/skills/style-migration/SKILL.md +45 -0
  37. package/templates/{_tokens.sass → _00_tokens.sass} +73 -64
  38. package/templates/{_config.sass → _01_config.sass} +24 -36
  39. package/templates/_02_fonts.sass +13 -0
  40. package/templates/_03_responsive.sass +31 -0
  41. package/templates/{_atoms.sass → _04_atoms.sass} +4 -4
  42. package/{dist/styles/_molecules.sass → templates/_05_molecules.sass} +16 -12
  43. package/templates/_06_recipes.sass +189 -0
  44. package/templates/{_base.sass → _07_base.sass} +3 -2
  45. package/templates/_08_blocks.sass +433 -0
  46. package/templates/_09_utilities.sass +207 -0
  47. package/templates/_10_layouts.sass +373 -0
  48. package/templates/_11_own.sass +21 -0
  49. package/templates/_fractals.sass +7 -6
  50. package/templates/index.sass +14 -16
  51. package/dist/styles/_blocks.sass +0 -88
  52. package/dist/styles/_layouts.sass +0 -108
  53. package/dist/styles/_responsive.sass +0 -43
  54. package/dist/styles/_utilities.sass +0 -125
  55. package/templates/_blocks.sass +0 -88
  56. package/templates/_layouts.sass +0 -108
  57. package/templates/_responsive.sass +0 -43
  58. package/templates/_utilities.sass +0 -125
package/plugin.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "fractalstyler2",
3
+ "version": "0.3.0",
4
+ "description": "Fractal-composition styling system and design token engine for SvelteKit and AI design tools (OpenDesign, Pencil, Cursor).",
5
+ "author": {
6
+ "name": "Amrit",
7
+ "url": "https://github.com/fractal-mandala"
8
+ },
9
+ "license": "MIT",
10
+ "keywords": [
11
+ "svelte",
12
+ "sveltekit",
13
+ "sass",
14
+ "css",
15
+ "design-system",
16
+ "mcp",
17
+ "tokens",
18
+ "fractals"
19
+ ],
20
+ "homepage": "https://github.com/fractal-mandala/fractalstyler2",
21
+ "repository": "https://github.com/fractal-mandala/fractalstyler2"
22
+ }
@@ -0,0 +1,83 @@
1
+ ---
2
+ name: fractal-styler
3
+ description: Design, compose, and build UI components and page layouts using the fractalstyler2 SASS mixin system and fluid design tokens in SvelteKit. Use when authoring components, applying design tokens, styling layouts, or compiling fractal recipes.
4
+ ---
5
+
6
+ # Fractal Styler (fractalstyler2)
7
+
8
+ `fractalstyler2` is a fractal-composition styling system for SvelteKit and modern web applications. Every styling decision is a reusable SASS mixin ("a fractal"), and components and layouts are clean recipes composed of smaller fractals.
9
+
10
+ ---
11
+
12
+ ## The Four Tiers of Composition
13
+
14
+ | Tier | Role | Examples |
15
+ | :--- | :--- | :--- |
16
+ | **1. Tokens & Config** | Fluid Utopia scales & resolvers | `space(m)` → `var(--space-m)`, `radius(12)` → `var(--radius-12)` |
17
+ | **2. Atoms** | Single layout/styling decisions | `+box`, `+row`, `+gap(s)`, `+pad(m)`, `+border`, `+radius(12)`, `+bg(surface)`, `+ink(primary)` |
18
+ | **3. Molecules** | Compositions of atoms | `+stack(s)`, `+cluster(xs)`, `+surface(surface, s, 12)`, `+cover(80vh)`, `+frame(16/9)`, `+with-sidebar` |
19
+ | **4. Components & Layouts** | Recipes of molecules | `.card`, `.panel`, `.button`, `.badge` · `.grid-3`, `.card-grid`, `.hero`, `.holy-grail`, `.docs`, `.app-shell` |
20
+
21
+ ---
22
+
23
+ ## Golden Rules for Agents
24
+
25
+ 1. **Never hardcode values that tokens cover**: Use `+gap(m)`, `+radius(12)`, `+bg(surface)` instead of arbitrary pixel values.
26
+ 2. **Compose fractals; don't write raw CSS**: Raw CSS is strictly for unique lines that no fractal covers.
27
+ 3. **State on `data-*` / `aria-*` attributes**: Never use modifier classes like `.is-active` or `.btn--primary`. Use `&[data-elevated]`, `&[data-variant='primary']`.
28
+ 4. **Markup stays semantic**: Prefer `<article class="card">` over 20 nested utility classes.
29
+ 5. **Mobile-first**: Define base layout first, grow with `+at(md/lg/xl)` and `+cols()`.
30
+
31
+ ---
32
+
33
+ ## How to Author a Svelte 5 Component
34
+
35
+ ```svelte
36
+ <script lang="ts">
37
+ let {
38
+ title = 'Pricing Tier',
39
+ price = '$29',
40
+ highlighted = false,
41
+ children
42
+ } = $props();
43
+ </script>
44
+
45
+ <article class="pricing-card" data-highlighted={highlighted || undefined}>
46
+ <div class="row ycenter xbetween">
47
+ <h3 class="text-xl">{title}</h3>
48
+ {#if highlighted}
49
+ <span class="badge" data-variant="theme">Popular</span>
50
+ {/if}
51
+ </div>
52
+ <div class="row ycenter gap-2xs">
53
+ <span class="text-4xl font-bold">{price}</span>
54
+ <span class="muted">/month</span>
55
+ </div>
56
+ {#if children}
57
+ {@render children()}
58
+ {/if}
59
+ </article>
60
+
61
+ <style lang="sass">
62
+ @use '$lib/styles/fractals' as *
63
+
64
+ .pricing-card
65
+ +surface(surface, m, 16)
66
+ +stack(m)
67
+ transition: transform 150ms ease, box-shadow 150ms ease
68
+
69
+ &[data-highlighted]
70
+ +border(all, var(--theme))
71
+ +shadow(lg)
72
+ </style>
73
+ ```
74
+
75
+ ---
76
+
77
+ ## MCP Tools Integration
78
+
79
+ If the host environment connects to the `fractalstyler2` MCP server, use the available tools:
80
+ * `get_design_tokens`: Query available space, typography, and radius steps.
81
+ * `compile_fractals`: Compile SASS mixin recipes to verify CSS output.
82
+ * `snap_to_tokens`: Snap canvas pixel values to tokens.
83
+ * `validate_recipe`: Lint SASS/Svelte against the golden rules.
@@ -0,0 +1,28 @@
1
+ # Fractals Catalog Reference
2
+
3
+ ## Atom Fractals (Single Decisions)
4
+
5
+ * **Layout Flow**: `+box(x, y)` (flex col), `+row(x, y)` (flex row), `+wrap`, `+grid(cols)`, `+auto-grid(min, gap)`, `+center` (grid center).
6
+ * **Spacing**: `+gap(v)`, `+pad(v)`, `+px(v)`, `+py(v)`, `+mx-auto`, `+my-auto`.
7
+ * **Sizing**: `+w(v)`, `+h(v)`, `+full`, `+square(v)`, `+grow(n)`, `+shrink(n)`, `+min0`.
8
+ * **Surfaces**: `+bg(role)`, `+ink(role)`, `+border(side, color)`, `+radius(v)`, `+shadow(v)`.
9
+ * **Position**: `+relative`, `+absolute(inset)`, `+sticky(top)`, `+fill`.
10
+ * **Type**: `+type(v)`, `+weight(w)`, `+leading(lh)`, `+truncate`, `+clamp-lines(n)`.
11
+ * **Motion**: `+transition(props, dur, ease)`, `+ring(color)`.
12
+
13
+ ## Molecule Fractals (Compositions of Atoms)
14
+
15
+ * **`+stack($gap: xs, $x: null)`**: Vertical flex column rhythm with uniform gap.
16
+ * **`+cluster($gap: xs, $x: start, $y: center)`**: Wrapping flex row for tag clouds, chips, and button rows.
17
+ * **`+center-column($max: 60ch, $pad: s)`**: Bounded reading column with max-width measure and auto margins.
18
+ * **`+cover($min: 100vh, $pad: s)`**: Full-height container with a vertically centered focal child (`> .center`).
19
+ * **`+frame($ratio: 16 / 9)`**: Fixed aspect-ratio container for media.
20
+ * **`+reel($gap: xs)`**: Horizontal scroll-snap rail.
21
+ * **`+with-sidebar($rail: 240px, $gap: s, $min: 60%)`**: Intrinsic sidebar + fluid main layout.
22
+ * **`+surface($bg: surface, $pad: s, $radius: 12, $elevation: none)`**: The all-in-one material mixin.
23
+ * **`+cols($map, $gap: s)`**: Responsive grid mapped across breakpoints, e.g. `+cols((base: 1, sm: 2, lg: 3), m)`.
24
+
25
+ ## Responsive Utilities
26
+ * `+at(sm | md | lg | xl)`: Mobile-first min-width media query.
27
+ * `+until(sm | md | lg | xl)`: Max-width media query.
28
+ * `+cq`, `+cq-at(width)`, `+cq-until(width)`: Container queries.
@@ -0,0 +1,36 @@
1
+ # Design Tokens Reference
2
+
3
+ ## Space Scale (Fluid Utopia)
4
+ | Step | Token Variable | Approximate Px | Clamp Formula |
5
+ | :--- | :--- | :--- | :--- |
6
+ | `3xs` | `--space-3xs` | ~5px | `clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem)` |
7
+ | `2xs` | `--space-2xs` | ~9px | `clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem)` |
8
+ | `xs` | `--space-xs` | ~14px | `clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem)` |
9
+ | `s` | `--space-s` | ~18px | `clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem)` |
10
+ | `m` | `--space-m` | ~27px | `clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem)` |
11
+ | `l` | `--space-l` | ~36px | `clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem)` |
12
+ | `xl` | `--space-xl` | ~54px | `clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem)` |
13
+ | `2xl` | `--space-2xl` | ~72px | `clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem)` |
14
+ | `3xl` | `--space-3xl` | ~108px | `clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem)` |
15
+ | `s-l` | `--space-s-l` | ~18→40px | `clamp(1.125rem, 0.5625rem + 2.5vw, 2.5rem)` |
16
+
17
+ ## Typography Scale
18
+ | Step | Token Variable | Fluid Clamp |
19
+ | :--- | :--- | :--- |
20
+ | `xs` | `--text-xs` | `0.75rem` (12px) |
21
+ | `sm` | `--text-sm` | `clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem)` |
22
+ | `md` | `--text-md` | `clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem)` |
23
+ | `lg` | `--text-lg` | `clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem)` |
24
+ | `xl` | `--text-xl` | `clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem)` |
25
+ | `2xl` | `--text-2xl` | `clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem)` |
26
+ | `3xl` | `--text-3xl` | `clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem)` |
27
+ | `4xl` | `--text-4xl` | `clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem)` |
28
+
29
+ ## Radius Scale
30
+ `0`, `2`, `4`, `6`, `8`, `12`, `16`, `24`, `full`
31
+
32
+ ## Color & Surface Roles
33
+ * **Surfaces**: `--bg`, `--bg-surface`, `--bg-raised`
34
+ * **Ink**: `--text-primary`, `--text-secondary`, `--text-muted`, `--text-inverse`
35
+ * **Borders**: `--border`, `--border-strong`
36
+ * **Brand**: `--theme`, `--theme-hover`, `--theme-active`, `--ring`
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: style-migration
3
+ description: Migrate legacy CSS, Tailwind utilities, or fractals-styler (v1) classes into modern fractalstyler2 SASS mixin recipes and token scales. Use when refactoring stylesheets, updating legacy components, or cleaning up utility class soup.
4
+ ---
5
+
6
+ # Style Migration & Refactoring Skill
7
+
8
+ This skill guides the refactoring and migration of existing styles into idiomatic `fractalstyler2`.
9
+
10
+ ---
11
+
12
+ ## 1. Quick Replacement Matrix
13
+
14
+ | Legacy Pattern | Problem | fractalstyler2 Replacement |
15
+ | :--- | :--- | :--- |
16
+ | `gap8`, `gap16`, `gap24` | Dynamic JIT classes removed in v2 | Markup: `.gap-xs`, `.gap-s`, `.gap-m`<br>SASS: `+gap(8)` or `+gap(s)` |
17
+ | `pad8`, `pad16`, `pad24` | Dynamic JIT classes removed in v2 | Markup: `.pad-xs`, `.pad-s`, `.pad-m`<br>SASS: `+pad(16)` or `+pad(m)` |
18
+ | `<div class="center">` (as reading text column) | In v2, `.center` dead-centers items in a grid | SASS: `.reading-col { +center-column }` |
19
+ | `<div class="stack">` | Markup class `.stack` does not exist | SASS: `.container { +stack(s) }` |
20
+ | `<div class="cluster">` | Markup class `.cluster` does not exist | SASS: `.tag-row { +cluster(xs) }` |
21
+ | `w100`, `h100` | Removed aliases | `.wfull`, `.hfull` |
22
+ | `min-w-0`, `min-h-0` | Removed utilities | `.min0` |
23
+ | `[data-variant='quiet']` | Renamed on button | `[data-variant='ghost']` |
24
+ | `.appshell` | Renamed layout | `.app-shell` |
25
+
26
+ ---
27
+
28
+ ## 2. Refactoring Procedure
29
+
30
+ 1. **Identify the Container**: Is it a card, panel, button, reading column, or grid?
31
+ 2. **Select the Molecule**:
32
+ - Vertical list of items → `+stack(s)`
33
+ - Tag list / button row → `+cluster(xs)`
34
+ - Box with border/radius/padding → `+surface(surface, s, 12)`
35
+ - Full height hero → `+cover(80vh, xl)`
36
+ 3. **Strip Utility Soup from Markup**: Replace long class strings (`class="box pad16 gap12 w100 min-w-0 radius12 border"`) with a single semantic class (`class="card"` or `class="feed-item"`).
37
+ 4. **Move Decisions to `<style lang="sass">`**:
38
+ ```sass
39
+ @use '$lib/styles/fractals' as *
40
+
41
+ .feed-item
42
+ +surface(surface, s, 12)
43
+ +stack(s)
44
+ ```
45
+ 5. **Verify**: Use the MCP tool `validate_recipe` or `npx sass src/lib/styles/index.sass /tmp/check.css`.
@@ -1,16 +1,70 @@
1
1
  // =============================================================================
2
- // TOKENS — the only place literal values live. Everything else is a fractal
3
- // that consumes these custom properties. Light is the marker-free default so
4
- // tokens stay defined during SSR and with JS disabled; dark comes from
5
- // prefers-color-scheme and from an explicit [data-mode='dark'].
2
+ // 00_TOKENS — the single source of truth for runtime CSS custom properties.
3
+ // -----------------------------------------------------------------------------
4
+ // Light is the marker-free default so tokens stay defined during SSR and with
5
+ // JS disabled; dark comes from prefers-color-scheme and explicit [data-mode='dark'].
6
6
  // =============================================================================
7
7
 
8
+ =light-theme-tokens
9
+ color-scheme: light
10
+ --bg: #fdfefe
11
+ --bg-surface: #f8f7f7
12
+ --bg-raised: #f1f5f9
13
+ --bg-panel: #F1F3F5
14
+ --bg-footer: #E9ECEF
15
+ --bg-popover: #FFFFFF
16
+ --bg-dialog: #FFFFFF
17
+ --bg-terminal: #0F172A
18
+ --bg-input: #FFFFFF
19
+ --bg-canvas: #F8F9FA
20
+ --text-primary: #0f172a
21
+ --text-secondary: #5b6472
22
+ --text-muted: #929497
23
+ --text-inverse: #ffffff
24
+ --state-hover: #E2E8F0
25
+ --state-hover-subtle: #F1F5F9
26
+ --state-selected: #CBD5E1
27
+ --border: #E2E8F0
28
+ --border-subtle: #EDF2F7
29
+ --theme-color: #04825B
30
+ --theme-color-alt: #047857
31
+ --theme: var(--theme-color)
32
+ --theme-hover: var(--theme-color-alt)
33
+ --ring: rgba(0, 127, 78, 0.35)
34
+
35
+ =dark-theme-tokens
36
+ color-scheme: dark
37
+ --bg: #0E1118
38
+ --bg-surface: #141824
39
+ --bg-raised: #1C2232
40
+ --bg-panel: #101420
41
+ --bg-footer: #0B0D14
42
+ --bg-popover: #20273A
43
+ --bg-dialog: #20273A
44
+ --bg-terminal: #080A0F
45
+ --bg-input: #121622
46
+ --bg-canvas: #0E1118
47
+ --border: #28324A
48
+ --border-subtle: #1E2538
49
+ --text-primary: #EDF2F7
50
+ --text-secondary: #9BB0C7
51
+ --text-muted: #5D7087
52
+ --state-hover: #263047
53
+ --state-hover-subtle: #1B2233
54
+ --state-selected: #32405E
55
+ --theme-color: #38BDF8
56
+ --theme-color-alt: #0EA5E9
57
+ --theme: var(--theme-color)
58
+ --theme-hover: var(--theme-color-alt)
59
+ --text-inverse: #0E1118
60
+ --ring: rgba(16, 185, 129, 0.4)
61
+
8
62
  :root
9
63
  color-scheme: light
10
64
 
11
65
  // Fonts
12
- --font-sans: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif
13
- --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace
66
+ --font-sans: "Google Sans Flex", sans-serif
67
+ --font-mono: "JetBrains Mono", monospace
14
68
 
15
69
  // Fluid type scale (Utopia 360→1240)
16
70
  --text-xs: 0.75rem
@@ -34,9 +88,10 @@
34
88
  --space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem)
35
89
  --space-s-l: clamp(1.125rem, 0.5625rem + 2.5vw, 2.5rem)
36
90
 
37
- // Radius
91
+ // Radius (Concentric hierarchy)
38
92
  --radius-0: 0
39
93
  --radius-2: 2px
94
+ --radius-3: 3px
40
95
  --radius-4: 4px
41
96
  --radius-6: 6px
42
97
  --radius-8: 8px
@@ -45,6 +100,11 @@
45
100
  --radius-24: 24px
46
101
  --radius-full: 9999px
47
102
 
103
+ // Control Heights
104
+ --control-h-sm: 26px
105
+ --control-h-md: 32px
106
+ --control-h-lg: 38px
107
+
48
108
  // Shadow
49
109
  --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06)
50
110
  --shadow-md: 0 4px 12px rgba(15, 23, 42, 0.08)
@@ -58,70 +118,19 @@
58
118
  --z-toast: 300
59
119
 
60
120
  // Layout
61
- --header-height: 64px
121
+ --header-height: 48px
62
122
  --footer-height: 56px
63
123
  --measure: 65ch
64
124
 
65
- // Light palette (marker-free default)
66
- --bg: #fdfefe
67
- --bg-surface: #f8f7f7
68
- --bg-raised: #f1f5f9
69
- --text-primary: #0f172a
70
- --text-secondary: #5b6472
71
- --text-muted: #929497
72
- --text-inverse: #ffffff
73
- --border: #e2e8f0
74
- --border-strong: #cbd5e1
75
- --theme: #007f4e
76
- --theme-hover: #00663f
77
- --theme-active: #005031
78
- --ring: rgba(0, 127, 78, 0.35)
125
+ // Default Light Palette
126
+ +light-theme-tokens
79
127
 
80
128
  @media (prefers-color-scheme: dark)
81
129
  :root:not([data-mode='light'])
82
- color-scheme: dark
83
- --bg: #131313
84
- --bg-surface: #1e1e1e
85
- --bg-raised: #2b2b2b
86
- --text-primary: #f9fafb
87
- --text-secondary: #a7adb7
88
- --text-muted: #6b7280
89
- --text-inverse: #0b0f17
90
- --border: #2f3030
91
- --border-strong: #4a4b4b
92
- --theme: #10b981
93
- --theme-hover: #34d399
94
- --theme-active: #059669
95
- --ring: rgba(16, 185, 129, 0.4)
130
+ +dark-theme-tokens
96
131
 
97
132
  [data-mode='dark']
98
- color-scheme: dark
99
- --bg: #131313
100
- --bg-surface: #1e1e1e
101
- --bg-raised: #2b2b2b
102
- --text-primary: #f9fafb
103
- --text-secondary: #a7adb7
104
- --text-muted: #6b7280
105
- --text-inverse: #0b0f17
106
- --border: #2f3030
107
- --border-strong: #4a4b4b
108
- --theme: #10b981
109
- --theme-hover: #34d399
110
- --theme-active: #059669
111
- --ring: rgba(16, 185, 129, 0.4)
133
+ +dark-theme-tokens
112
134
 
113
135
  [data-mode='light']
114
- color-scheme: light
115
- --bg: #fdfefe
116
- --bg-surface: #f8f7f7
117
- --bg-raised: #f1f5f9
118
- --text-primary: #0f172a
119
- --text-secondary: #5b6472
120
- --text-muted: #929497
121
- --text-inverse: #ffffff
122
- --border: #e2e8f0
123
- --border-strong: #cbd5e1
124
- --theme: #007f4e
125
- --theme-hover: #00663f
126
- --theme-active: #005031
127
- --ring: rgba(0, 127, 78, 0.35)
136
+ +light-theme-tokens
@@ -1,5 +1,5 @@
1
1
  // =============================================================================
2
- // CONFIG — the finite vocabulary every fractal draws from.
2
+ // 01_CONFIG — the finite vocabulary every fractal draws from.
3
3
  // -----------------------------------------------------------------------------
4
4
  // Scales live here as Sass data; resolvers turn a keyword-or-raw value into the
5
5
  // right token var() or unit. Fractals never hardcode a px or a token name —
@@ -11,68 +11,56 @@
11
11
  @use 'sass:meta'
12
12
  @use 'sass:list'
13
13
 
14
- // --- Scales (mirror the custom properties in _tokens.sass) --------------------
14
+ // --- Scales (mirror the custom properties in _00_tokens.sass) ----------------
15
15
  $breakpoints: (sm: 640px, md: 768px, lg: 1024px, xl: 1240px)
16
16
 
17
17
  $space-steps: 3xs 2xs xs s m l xl 2xl 3xl s-l
18
- $radius-steps: 0 2 4 6 8 12 16 24 full
18
+ $radius-steps: 0 2 3 4 6 8 12 16 24 full
19
19
  $text-steps: xs sm md lg xl 2xl 3xl 4xl
20
20
  $shadow-steps: sm md lg
21
- $surface-roles: bg surface raised
22
- $ink-roles: primary secondary muted inverse
23
21
 
24
- $align-map: (start: flex-start, end: flex-end, center: center, between: space-between, around: space-around, evenly: space-evenly, stretch: stretch, baseline: baseline)
22
+ // Surfaces mapped to the 21 theme token contract
23
+ $surface-roles: bg surface raised panel footer popover dialog terminal input canvas
24
+ $ink-roles: primary secondary muted inverse theme-color theme-color-alt
25
25
 
26
- // --- Resolvers ----------------------------------------------------------------
26
+ $align-map: (start: flex-start, end: flex-end, center: center, between: space-between, around: space-around, evenly: space-evenly, stretch: stretch, baseline: baseline)
27
27
 
28
- // space(m) → var(--space-m) | space(18) → 18px | space(2rem) → 2rem
29
- @function space($v)
28
+ // --- Universal Token Resolver --------------------------------------------------
29
+ @function tok($group, $v)
30
30
  @if $v == null
31
31
  @return null
32
- @else if list.index($space-steps, $v)
33
- @return var(--space-#{$v})
34
- @else if meta.type-of($v) == number and math.is-unitless($v)
32
+ @if meta.type-of($v) == number and math.is-unitless($v)
35
33
  @return #{$v}px
36
- @else
37
- @return $v
34
+ @if meta.type-of($v) == string and not (math.unit($v) != '')
35
+ @return var(--#{$group}-#{$v})
36
+ @return $v
37
+
38
+ // --- Resolvers ----------------------------------------------------------------
39
+
40
+ @function space($v)
41
+ @return tok(space, $v)
38
42
 
39
43
  @function radius($v)
40
- @if list.index($radius-steps, $v)
41
- @return var(--radius-#{$v})
42
- @else if meta.type-of($v) == number and math.is-unitless($v)
43
- @return #{$v}px
44
- @else
45
- @return $v
44
+ @return tok(radius, $v)
46
45
 
47
46
  @function text-size($v)
48
- @if list.index($text-steps, $v)
49
- @return var(--text-#{$v})
50
- @else
51
- @return $v
47
+ @return tok(text, $v)
52
48
 
53
49
  @function shadow($v)
54
- @if list.index($shadow-steps, $v)
55
- @return var(--shadow-#{$v})
56
- @else
57
- @return $v
50
+ @return tok(shadow, $v)
58
51
 
59
52
  @function surface($role)
60
53
  @if $role == bg
61
54
  @return var(--bg)
62
- @else
63
- @return var(--bg-#{$role})
55
+ @return tok(bg, $role)
64
56
 
65
57
  @function ink($role)
66
58
  @if $role == primary
67
59
  @return var(--text-primary)
68
- @else
69
- @return var(--text-#{$role})
60
+ @return tok(text, $role)
70
61
 
71
62
  @function align($v)
72
- $m: map.get($align-map, $v)
73
- @if $m
74
- @return $m
75
- @return $v
63
+ @return map.get($align-map, $v) or $v
76
64
 
77
65
  @function bp($name)
78
66
  @return map.get($breakpoints, $name)
@@ -0,0 +1,13 @@
1
+ // =============================================================================
2
+ // 02_FONTS — local webfont declarations & font-family fallbacks.
3
+ // -----------------------------------------------------------------------------
4
+ // Downstream projects customize their font loading here.
5
+ // =============================================================================
6
+
7
+ // Define custom @font-face rules or load Google / local webfonts as needed:
8
+ // @font-face
9
+ // font-family: 'YourFont'
10
+ // src: url('/fonts/YourFont.woff2') format('woff2')
11
+ // font-weight: 100 900
12
+ // font-style: normal
13
+ // font-display: swap
@@ -0,0 +1,31 @@
1
+ // =============================================================================
2
+ // 03_RESPONSIVE — the breakpoint mixins. Viewport-aware conditional styling.
3
+ // -----------------------------------------------------------------------------
4
+ // Mobile-first defaults; use +at($bp) for min-width media queries.
5
+ // =============================================================================
6
+
7
+ @use '01_config' as *
8
+
9
+ =at($bp)
10
+ $width: bp($bp)
11
+ @if $width
12
+ @media (min-width: $width)
13
+ @content
14
+ @else
15
+ @media (min-width: $bp)
16
+ @content
17
+
18
+ =below($bp)
19
+ $width: bp($bp)
20
+ @if $width
21
+ @media (max-width: ($width - 1px))
22
+ @content
23
+ @else
24
+ @media (max-width: $bp)
25
+ @content
26
+
27
+ =between($min-bp, $max-bp)
28
+ $min: bp($min-bp)
29
+ $max: bp($max-bp)
30
+ @media (min-width: $min) and (max-width: ($max - 1px))
31
+ @content
@@ -1,11 +1,11 @@
1
1
  // =============================================================================
2
- // ATOM FRACTALS — the indivisible units. One visual decision each.
2
+ // 04_ATOMS — the indivisible units. One visual decision each.
3
3
  // -----------------------------------------------------------------------------
4
4
  // Every atom is a mixin. Call it inside a class to compose, or let
5
- // _utilities.sass project it to a utility class. Same fractal, two consumers.
5
+ // _09_utilities.sass project it to a utility class. Same fractal, two consumers.
6
6
  // =============================================================================
7
7
 
8
- @use 'config' as *
8
+ @use '01_config' as *
9
9
 
10
10
  // --- Flow: the two axes of layout ------------------------------------------
11
11
  // A box is a vertical stack, a row is horizontal. Optional semantic alignment:
@@ -102,7 +102,7 @@
102
102
  @else
103
103
  border-#{$side}: 1px solid $color
104
104
 
105
- =radius($v: 12)
105
+ =radius($v: 4)
106
106
  border-radius: radius($v)
107
107
 
108
108
  =shadow($v: md)
@@ -1,14 +1,15 @@
1
1
  // =============================================================================
2
- // MOLECULE FRACTALS — self-similar: each is a small graph of atom fractals.
2
+ // 05_MOLECULES — self-similar: each is a small graph of atom fractals.
3
3
  // -----------------------------------------------------------------------------
4
4
  // This is the payoff of the model. A molecule reads like a recipe of atoms,
5
5
  // and a component (next layer up) reads like a recipe of molecules. Same move
6
6
  // at every scale — that is the "fractal" in fractalstyler2.
7
7
  // =============================================================================
8
8
 
9
- @use 'config' as *
10
- @use 'atoms' as *
11
- @use 'responsive' as *
9
+ @use 'sass:string'
10
+ @use '01_config' as *
11
+ @use '04_atoms' as *
12
+ @use '03_responsive' as *
12
13
 
13
14
  // Stack — vertical rhythm with one shared gap.
14
15
  =stack($gap: xs, $x: null)
@@ -38,11 +39,13 @@
38
39
  +my-auto
39
40
 
40
41
  // Frame — fixed aspect-ratio media box.
41
- =frame($ratio: 16 / 9)
42
- aspect-ratio: $ratio
42
+ =frame($ratio: '16 / 9')
43
+ aspect-ratio: string.unquote('#{$ratio}')
43
44
  overflow: hidden
44
- > :is(img, video, iframe)
45
+ position: relative
46
+ > *
45
47
  +full
48
+ > :is(img, video, iframe)
46
49
  object-fit: cover
47
50
 
48
51
  // Reel — horizontal scroll-snap rail.
@@ -69,13 +72,14 @@
69
72
  flex-grow: 999
70
73
  min-width: $min
71
74
 
72
- // Surface — the "material" fractal: skin + elevation in one call.
75
+ // Surface — the "material" fractal: skin + border + optional radius + optional padding + elevation.
73
76
  // The building block of every card/panel/popover.
74
- =surface($bg: surface, $pad: s, $radius: 12, $elevation: none)
77
+ =surface($bg: surface, $pad: null, $radius: 6, $elevation: none)
75
78
  +bg($bg)
76
- +border
77
- +radius($radius)
78
- +pad($pad)
79
+ @if $radius != null
80
+ +radius($radius)
81
+ @if $pad != null
82
+ +pad($pad)
79
83
  @if $elevation != none
80
84
  +shadow($elevation)
81
85