fractalstyler2 0.1.0 → 0.3.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.
- package/README.md +60 -58
- package/dist/cli.js +47 -9
- package/dist/index.d.ts +32 -1
- package/dist/index.js +73 -4
- package/dist/mcp/export.d.ts +13 -0
- package/dist/mcp/export.js +76 -0
- package/dist/mcp/schemas/compile_fractals.json +20 -0
- package/dist/mcp/schemas/css_to_fractals.json +16 -0
- package/dist/mcp/schemas/generate_component.json +45 -0
- package/dist/mcp/schemas/get_design_tokens.json +23 -0
- package/dist/mcp/schemas/instructions.md +18 -0
- package/dist/mcp/schemas/list_fractals.json +20 -0
- package/dist/mcp/schemas/snap_to_tokens.json +25 -0
- package/dist/mcp/schemas/validate_recipe.json +16 -0
- package/dist/mcp/server.js +28 -12
- package/dist/styles/_00_tokens.sass +177 -0
- package/{templates/_config.sass → dist/styles/_01_config.sass} +11 -5
- package/dist/styles/_02_fonts.sass +13 -0
- package/dist/styles/_03_responsive.sass +31 -0
- package/dist/styles/{_atoms.sass → _04_atoms.sass} +4 -4
- package/{templates/_molecules.sass → dist/styles/_05_molecules.sass} +16 -12
- package/dist/styles/_06_recipes.sass +189 -0
- package/dist/styles/{_base.sass → _07_base.sass} +3 -2
- package/dist/styles/_08_blocks.sass +433 -0
- package/dist/styles/{_utilities.sass → _09_utilities.sass} +96 -16
- package/dist/styles/_10_layouts.sass +373 -0
- package/dist/styles/_11_own.sass +21 -0
- package/dist/styles/_fractals.sass +7 -6
- package/dist/styles/index.sass +14 -16
- package/mcp.json +11 -0
- package/package.json +6 -3
- package/plugin.json +22 -0
- package/skills/fractal-styler/SKILL.md +83 -0
- package/skills/fractal-styler/references/fractals.md +28 -0
- package/skills/fractal-styler/references/tokens.md +36 -0
- package/skills/style-migration/SKILL.md +45 -0
- package/templates/_00_tokens.sass +177 -0
- package/{dist/styles/_config.sass → templates/_01_config.sass} +11 -5
- package/templates/_02_fonts.sass +13 -0
- package/templates/_03_responsive.sass +31 -0
- package/templates/{_atoms.sass → _04_atoms.sass} +4 -4
- package/{dist/styles/_molecules.sass → templates/_05_molecules.sass} +16 -12
- package/templates/_06_recipes.sass +189 -0
- package/templates/{_base.sass → _07_base.sass} +3 -2
- package/templates/_08_blocks.sass +433 -0
- package/templates/{_utilities.sass → _09_utilities.sass} +96 -16
- package/templates/_10_layouts.sass +373 -0
- package/templates/_11_own.sass +21 -0
- package/templates/_fractals.sass +7 -6
- package/templates/index.sass +14 -16
- package/dist/styles/_blocks.sass +0 -88
- package/dist/styles/_layouts.sass +0 -108
- package/dist/styles/_responsive.sass +0 -43
- package/dist/styles/_tokens.sass +0 -127
- package/templates/_blocks.sass +0 -88
- package/templates/_layouts.sass +0 -108
- package/templates/_responsive.sass +0 -43
- package/templates/_tokens.sass +0 -127
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "snap_to_tokens",
|
|
3
|
+
"description": "Takes raw pixel values (e.g. from canvas elements in OpenDesign / Figma) and snaps them to the nearest fractalstyler2 design tokens, CSS variables, and suggested mixins.",
|
|
4
|
+
"parameters": {
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"gap": {
|
|
8
|
+
"type": "number",
|
|
9
|
+
"description": "Gap in pixels (e.g. 16)"
|
|
10
|
+
},
|
|
11
|
+
"padding": {
|
|
12
|
+
"type": "number",
|
|
13
|
+
"description": "Padding in pixels (e.g. 24)"
|
|
14
|
+
},
|
|
15
|
+
"radius": {
|
|
16
|
+
"type": "number",
|
|
17
|
+
"description": "Border radius in pixels (e.g. 10)"
|
|
18
|
+
},
|
|
19
|
+
"fontSize": {
|
|
20
|
+
"type": "number",
|
|
21
|
+
"description": "Font size in pixels (e.g. 18)"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "validate_recipe",
|
|
3
|
+
"description": "Lints a SASS snippet or Svelte component against fractalstyler2 golden rules (flags legacy v1 classes like gap8/pad16, hardcoded pixels, modifier classes).",
|
|
4
|
+
"parameters": {
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"code": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "The SASS or Svelte code to validate."
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"required": [
|
|
13
|
+
"code"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
}
|
package/dist/mcp/server.js
CHANGED
|
@@ -11,7 +11,7 @@ import * as sass from 'sass';
|
|
|
11
11
|
import { existsSync, readFileSync } from 'node:fs';
|
|
12
12
|
import { dirname, join } from 'node:path';
|
|
13
13
|
import { fileURLToPath } from 'node:url';
|
|
14
|
-
const VERSION = '0.
|
|
14
|
+
const VERSION = '0.3.0';
|
|
15
15
|
// Resolve styles directory for SASS compiler loadPaths
|
|
16
16
|
function getStylesDir() {
|
|
17
17
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
@@ -23,7 +23,7 @@ function getStylesDir() {
|
|
|
23
23
|
join(process.cwd(), 'templates')
|
|
24
24
|
];
|
|
25
25
|
for (const candidate of candidates) {
|
|
26
|
-
if (existsSync(candidate) && existsSync(join(candidate, '
|
|
26
|
+
if (existsSync(candidate) && existsSync(join(candidate, '_00_tokens.sass'))) {
|
|
27
27
|
return candidate;
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -93,10 +93,11 @@ const DESIGN_TOKENS = {
|
|
|
93
93
|
}
|
|
94
94
|
},
|
|
95
95
|
radius: {
|
|
96
|
-
steps: ['0', '2', '4', '6', '8', '12', '16', '24', 'full'],
|
|
96
|
+
steps: ['0', '2', '3', '4', '6', '8', '12', '16', '24', 'full'],
|
|
97
97
|
values: {
|
|
98
98
|
'0': '0px',
|
|
99
99
|
'2': '2px',
|
|
100
|
+
'3': '3px',
|
|
100
101
|
'4': '4px',
|
|
101
102
|
'6': '6px',
|
|
102
103
|
'8': '8px',
|
|
@@ -114,13 +115,22 @@ const DESIGN_TOKENS = {
|
|
|
114
115
|
surfaces: {
|
|
115
116
|
bg: 'var(--bg)',
|
|
116
117
|
surface: 'var(--bg-surface)',
|
|
117
|
-
raised: 'var(--bg-raised)'
|
|
118
|
+
raised: 'var(--bg-raised)',
|
|
119
|
+
panel: 'var(--bg-panel)',
|
|
120
|
+
footer: 'var(--bg-footer)',
|
|
121
|
+
popover: 'var(--bg-popover)',
|
|
122
|
+
dialog: 'var(--bg-dialog)',
|
|
123
|
+
terminal: 'var(--bg-terminal)',
|
|
124
|
+
input: 'var(--bg-input)',
|
|
125
|
+
canvas: 'var(--bg-canvas)'
|
|
118
126
|
},
|
|
119
127
|
ink: {
|
|
120
128
|
primary: 'var(--text-primary)',
|
|
121
129
|
secondary: 'var(--text-secondary)',
|
|
122
130
|
muted: 'var(--text-muted)',
|
|
123
|
-
inverse: 'var(--text-inverse)'
|
|
131
|
+
inverse: 'var(--text-inverse)',
|
|
132
|
+
themeColor: 'var(--theme-color)',
|
|
133
|
+
themeColorAlt: 'var(--theme-color-alt)'
|
|
124
134
|
},
|
|
125
135
|
brand: {
|
|
126
136
|
theme: 'var(--theme)',
|
|
@@ -158,10 +168,10 @@ const FRACTAL_CATALOG = {
|
|
|
158
168
|
{ name: 'grow', signature: '+grow($n: 1)', description: 'Sets flex-grow.' },
|
|
159
169
|
{ name: 'shrink', signature: '+shrink($n: 0)', description: 'Sets flex-shrink.' },
|
|
160
170
|
{ name: 'min0', signature: '+min0', description: 'Sets min-width: 0 and min-height: 0 to prevent overflow.' },
|
|
161
|
-
{ name: 'bg', signature: '+bg($role: surface)', description: 'Sets background-color to
|
|
162
|
-
{ name: 'ink', signature: '+ink($role: primary)', description: 'Sets text color to primary, secondary, muted,
|
|
171
|
+
{ name: 'bg', signature: '+bg($role: surface)', description: 'Sets background-color to any of the 21 surface tokens.' },
|
|
172
|
+
{ name: 'ink', signature: '+ink($role: primary)', description: 'Sets text color to primary, secondary, muted, inverse, theme-color, theme-color-alt.' },
|
|
163
173
|
{ name: 'border', signature: '+border($side: all, $color: var(--border))', description: 'Applies 1px solid border on all sides or a specific side.' },
|
|
164
|
-
{ name: 'radius', signature: '+radius($v:
|
|
174
|
+
{ name: 'radius', signature: '+radius($v: 6)', description: 'Applies border-radius from radius token or raw px.' },
|
|
165
175
|
{ name: 'shadow', signature: '+shadow($v: md)', description: 'Applies box-shadow from shadow scale (sm, md, lg).' },
|
|
166
176
|
{ name: 'type', signature: '+type($v)', description: 'Applies font-size from fluid type scale (xs..4xl).' },
|
|
167
177
|
{ name: 'weight', signature: '+weight($w: 500)', description: 'Sets font-weight.' },
|
|
@@ -179,9 +189,15 @@ const FRACTAL_CATALOG = {
|
|
|
179
189
|
{ name: 'frame', signature: '+frame($ratio: 16 / 9)', description: 'Aspect-ratio container for media (images, video, iframe).' },
|
|
180
190
|
{ name: 'reel', signature: '+reel($gap: xs)', description: 'Horizontal scroll-snap rail.' },
|
|
181
191
|
{ name: 'with-sidebar', signature: '+with-sidebar($rail: 240px, $gap: s, $min: 60%)', description: 'Intrinsic sidebar and fluid main content.' },
|
|
182
|
-
{ name: 'surface', signature: '+surface($bg: surface, $pad:
|
|
192
|
+
{ name: 'surface', signature: '+surface($bg: surface, $pad: null, $radius: 6, $elevation: none)', description: 'All-in-one material fractal: skin, radius, pad, and elevation.' },
|
|
183
193
|
{ name: 'cols', signature: '+cols($map, $gap: s)', description: 'Responsive column grid mapped across breakpoints, e.g. (base: 1, sm: 2, lg: 3).' }
|
|
184
194
|
],
|
|
195
|
+
recipes: [
|
|
196
|
+
{ name: 'card', signature: '+card($bg: surface, $pad: null, $radius: 6, $elevation: none)', description: 'Vertical card container recipe with optional pad and elevation.' },
|
|
197
|
+
{ name: 'control', signature: '+control($size: md, $radius: 4)', description: 'Universal interactive control recipe (buttons, triggers, inputs).' },
|
|
198
|
+
{ name: 'select', signature: '+select($size: md, $radius: 4)', description: 'Select input recipe with embedded SVG chevron.' },
|
|
199
|
+
{ name: 'badge', signature: '+badge($radius: 4)', description: 'Compact status badge recipe.' }
|
|
200
|
+
],
|
|
185
201
|
layouts: [
|
|
186
202
|
{ name: 'grid-3', class: '.grid-3', description: 'Responsive 1 → 2 → 3 column reflow.' },
|
|
187
203
|
{ name: 'card-grid', class: '.card-grid', description: 'Intrinsic auto-fit grid for cards.' },
|
|
@@ -195,8 +211,8 @@ const FRACTAL_CATALOG = {
|
|
|
195
211
|
const GUIDELINES = `
|
|
196
212
|
# fractalstyler2 Design System Rules
|
|
197
213
|
|
|
198
|
-
1. Never hardcode a value that a token covers (+gap(m), +radius(
|
|
199
|
-
2. Compose fractals (+surface, +stack, +cluster); write raw CSS only for genuinely unique lines.
|
|
214
|
+
1. Never hardcode a value that a token covers (+gap(m), +radius(6), +bg(surface)).
|
|
215
|
+
2. Compose fractals (+surface, +stack, +cluster, +card); write raw CSS only for genuinely unique lines.
|
|
200
216
|
3. Express component state on data-* / aria-* attributes, never modifier classes (e.g. &[data-elevated], &[data-variant='ghost']).
|
|
201
217
|
4. Markup stays thin and semantic: prefer clean tags (<article class="card">) over utility class soup.
|
|
202
218
|
5. Mobile-first: define base styles first, then grow with +at(md/lg/xl) or +cols().
|
|
@@ -332,7 +348,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
332
348
|
properties: {
|
|
333
349
|
tier: {
|
|
334
350
|
type: 'string',
|
|
335
|
-
enum: ['all', 'atoms', 'molecules', 'layouts'],
|
|
351
|
+
enum: ['all', 'atoms', 'molecules', 'recipes', 'layouts'],
|
|
336
352
|
description: 'Filter by fractal tier.'
|
|
337
353
|
}
|
|
338
354
|
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// =============================================================================
|
|
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
|
+
// =============================================================================
|
|
7
|
+
|
|
8
|
+
:root
|
|
9
|
+
color-scheme: light
|
|
10
|
+
|
|
11
|
+
// Fonts
|
|
12
|
+
--font-sans: "Google Sans Flex", sans-serif
|
|
13
|
+
--font-mono: "JetBrains Mono", monospace
|
|
14
|
+
|
|
15
|
+
// Fluid type scale (Utopia 360→1240)
|
|
16
|
+
--text-xs: 0.75rem
|
|
17
|
+
--text-sm: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem)
|
|
18
|
+
--text-md: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem)
|
|
19
|
+
--text-lg: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem)
|
|
20
|
+
--text-xl: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem)
|
|
21
|
+
--text-2xl: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem)
|
|
22
|
+
--text-3xl: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem)
|
|
23
|
+
--text-4xl: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem)
|
|
24
|
+
|
|
25
|
+
// Fluid space scale
|
|
26
|
+
--space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem)
|
|
27
|
+
--space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem)
|
|
28
|
+
--space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem)
|
|
29
|
+
--space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem)
|
|
30
|
+
--space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem)
|
|
31
|
+
--space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem)
|
|
32
|
+
--space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem)
|
|
33
|
+
--space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem)
|
|
34
|
+
--space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem)
|
|
35
|
+
--space-s-l: clamp(1.125rem, 0.5625rem + 2.5vw, 2.5rem)
|
|
36
|
+
|
|
37
|
+
// Radius (Concentric 2px, 3px, 4px, 6px hierarchy)
|
|
38
|
+
--radius-0: 0
|
|
39
|
+
--radius-2: 2px
|
|
40
|
+
--radius-3: 3px
|
|
41
|
+
--radius-4: 4px
|
|
42
|
+
--radius-6: 6px
|
|
43
|
+
--radius-8: 6px
|
|
44
|
+
--radius-12: 6px
|
|
45
|
+
--radius-16: 6px
|
|
46
|
+
--radius-24: 6px
|
|
47
|
+
--radius-full: 9999px
|
|
48
|
+
|
|
49
|
+
// Control Heights
|
|
50
|
+
--control-h-sm: 26px
|
|
51
|
+
--control-h-md: 32px
|
|
52
|
+
--control-h-lg: 38px
|
|
53
|
+
|
|
54
|
+
// Shadow
|
|
55
|
+
--shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06)
|
|
56
|
+
--shadow-md: 0 4px 12px rgba(15, 23, 42, 0.08)
|
|
57
|
+
--shadow-lg: 0 12px 32px rgba(15, 23, 42, 0.12)
|
|
58
|
+
|
|
59
|
+
// Layering
|
|
60
|
+
--z-base: 0
|
|
61
|
+
--z-raised: 10
|
|
62
|
+
--z-sticky: 100
|
|
63
|
+
--z-modal: 200
|
|
64
|
+
--z-toast: 300
|
|
65
|
+
|
|
66
|
+
// Layout
|
|
67
|
+
--header-height: 48px
|
|
68
|
+
--footer-height: 56px
|
|
69
|
+
--measure: 65ch
|
|
70
|
+
|
|
71
|
+
// Light palette (marker-free default)
|
|
72
|
+
--bg: #fdfefe
|
|
73
|
+
--bg-surface: #f8f7f7
|
|
74
|
+
--bg-raised: #f1f5f9
|
|
75
|
+
--bg-panel: #F1F3F5
|
|
76
|
+
--bg-footer: #E9ECEF
|
|
77
|
+
--bg-popover: #FFFFFF
|
|
78
|
+
--bg-dialog: #FFFFFF
|
|
79
|
+
--bg-terminal: #0F172A
|
|
80
|
+
--bg-input: #FFFFFF
|
|
81
|
+
--bg-canvas: #F8F9FA
|
|
82
|
+
--text-primary: #0f172a
|
|
83
|
+
--text-secondary: #5b6472
|
|
84
|
+
--text-muted: #929497
|
|
85
|
+
--text-inverse: #ffffff
|
|
86
|
+
--state-hover: #E2E8F0
|
|
87
|
+
--state-hover-subtle: #F1F5F9
|
|
88
|
+
--state-selected: #CBD5E1
|
|
89
|
+
--border: #E2E8F0
|
|
90
|
+
--border-subtle: #EDF2F7
|
|
91
|
+
--theme-color: #04825B
|
|
92
|
+
--theme-color-alt: #047857
|
|
93
|
+
--theme: var(--theme-color)
|
|
94
|
+
--theme-hover: var(--theme-color-alt)
|
|
95
|
+
--ring: rgba(0, 127, 78, 0.35)
|
|
96
|
+
|
|
97
|
+
@media (prefers-color-scheme: dark)
|
|
98
|
+
:root:not([data-mode='light'])
|
|
99
|
+
color-scheme: dark
|
|
100
|
+
--bg: #0E1118
|
|
101
|
+
--bg-surface: #141824
|
|
102
|
+
--bg-raised: #1C2232
|
|
103
|
+
--bg-panel: #101420
|
|
104
|
+
--bg-footer: #0B0D14
|
|
105
|
+
--bg-popover: #20273A
|
|
106
|
+
--bg-dialog: #20273A
|
|
107
|
+
--bg-terminal: #080A0F
|
|
108
|
+
--bg-input: #121622
|
|
109
|
+
--bg-canvas: #0E1118
|
|
110
|
+
--border: #28324A
|
|
111
|
+
--border-subtle: #1E2538
|
|
112
|
+
--text-primary: #EDF2F7
|
|
113
|
+
--text-secondary: #9BB0C7
|
|
114
|
+
--text-muted: #5D7087
|
|
115
|
+
--state-hover: #263047
|
|
116
|
+
--state-hover-subtle: #1B2233
|
|
117
|
+
--state-selected: #32405E
|
|
118
|
+
--theme-color: #38BDF8
|
|
119
|
+
--theme-color-alt: #0EA5E9
|
|
120
|
+
--theme: var(--theme-color)
|
|
121
|
+
--theme-hover: var(--theme-color-alt)
|
|
122
|
+
--text-inverse: #0E1118
|
|
123
|
+
--ring: rgba(16, 185, 129, 0.4)
|
|
124
|
+
|
|
125
|
+
[data-mode='dark']
|
|
126
|
+
color-scheme: dark
|
|
127
|
+
--bg: #0E1118
|
|
128
|
+
--bg-surface: #141824
|
|
129
|
+
--bg-raised: #1C2232
|
|
130
|
+
--bg-panel: #101420
|
|
131
|
+
--bg-footer: #0B0D14
|
|
132
|
+
--bg-popover: #20273A
|
|
133
|
+
--bg-dialog: #20273A
|
|
134
|
+
--bg-terminal: #080A0F
|
|
135
|
+
--bg-input: #121622
|
|
136
|
+
--bg-canvas: #0E1118
|
|
137
|
+
--border: #28324A
|
|
138
|
+
--border-subtle: #1E2538
|
|
139
|
+
--text-primary: #EDF2F7
|
|
140
|
+
--text-secondary: #9BB0C7
|
|
141
|
+
--text-muted: #5D7087
|
|
142
|
+
--state-hover: #263047
|
|
143
|
+
--state-hover-subtle: #1B2233
|
|
144
|
+
--state-selected: #32405E
|
|
145
|
+
--theme-color: #38BDF8
|
|
146
|
+
--theme-color-alt: #0EA5E9
|
|
147
|
+
--theme: var(--theme-color)
|
|
148
|
+
--theme-hover: var(--theme-color-alt)
|
|
149
|
+
--text-inverse: #0E1118
|
|
150
|
+
--ring: rgba(16, 185, 129, 0.4)
|
|
151
|
+
|
|
152
|
+
[data-mode='light']
|
|
153
|
+
color-scheme: light
|
|
154
|
+
--bg: #fdfefe
|
|
155
|
+
--bg-surface: #f8f7f7
|
|
156
|
+
--bg-raised: #f1f5f9
|
|
157
|
+
--bg-panel: #F1F3F5
|
|
158
|
+
--bg-footer: #E9ECEF
|
|
159
|
+
--bg-popover: #FFFFFF
|
|
160
|
+
--bg-dialog: #FFFFFF
|
|
161
|
+
--bg-terminal: #0F172A
|
|
162
|
+
--bg-input: #FFFFFF
|
|
163
|
+
--bg-canvas: #F8F9FA
|
|
164
|
+
--text-primary: #0f172a
|
|
165
|
+
--text-secondary: #5b6472
|
|
166
|
+
--text-muted: #929497
|
|
167
|
+
--text-inverse: #ffffff
|
|
168
|
+
--state-hover: #E2E8F0
|
|
169
|
+
--state-hover-subtle: #F1F5F9
|
|
170
|
+
--state-selected: #CBD5E1
|
|
171
|
+
--border: #E2E8F0
|
|
172
|
+
--border-subtle: #EDF2F7
|
|
173
|
+
--theme-color: #04825B
|
|
174
|
+
--theme-color-alt: #047857
|
|
175
|
+
--theme: var(--theme-color)
|
|
176
|
+
--theme-hover: var(--theme-color-alt)
|
|
177
|
+
--ring: rgba(0, 127, 78, 0.35)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// =============================================================================
|
|
2
|
-
//
|
|
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,15 +11,17 @@
|
|
|
11
11
|
@use 'sass:meta'
|
|
12
12
|
@use 'sass:list'
|
|
13
13
|
|
|
14
|
-
// --- Scales (mirror the custom properties in
|
|
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
|
-
|
|
22
|
-
|
|
21
|
+
|
|
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
|
|
23
25
|
|
|
24
26
|
$align-map: (start: flex-start, end: flex-end, center: center, between: space-between, around: space-around, evenly: space-evenly, stretch: stretch, baseline: baseline)
|
|
25
27
|
|
|
@@ -59,12 +61,16 @@ $align-map: (start: flex-start, end: flex-end, center: center, between: space-be
|
|
|
59
61
|
@function surface($role)
|
|
60
62
|
@if $role == bg
|
|
61
63
|
@return var(--bg)
|
|
64
|
+
@else if list.index($surface-roles, $role)
|
|
65
|
+
@return var(--bg-#{$role})
|
|
62
66
|
@else
|
|
63
67
|
@return var(--bg-#{$role})
|
|
64
68
|
|
|
65
69
|
@function ink($role)
|
|
66
70
|
@if $role == primary
|
|
67
71
|
@return var(--text-primary)
|
|
72
|
+
@else if list.index($ink-roles, $role)
|
|
73
|
+
@return var(--text-#{$role})
|
|
68
74
|
@else
|
|
69
75
|
@return var(--text-#{$role})
|
|
70
76
|
|
|
@@ -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
|
-
//
|
|
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
|
-
//
|
|
5
|
+
// _09_utilities.sass project it to a utility class. Same fractal, two consumers.
|
|
6
6
|
// =============================================================================
|
|
7
7
|
|
|
8
|
-
@use '
|
|
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:
|
|
105
|
+
=radius($v: 4)
|
|
106
106
|
border-radius: radius($v)
|
|
107
107
|
|
|
108
108
|
=shadow($v: md)
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
// =============================================================================
|
|
2
|
-
//
|
|
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 '
|
|
10
|
-
@use '
|
|
11
|
-
@use '
|
|
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
|
-
|
|
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 +
|
|
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:
|
|
77
|
+
=surface($bg: surface, $pad: null, $radius: 6, $elevation: none)
|
|
75
78
|
+bg($bg)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
|