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.
- package/README.md +61 -59
- 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/{_tokens.sass → _00_tokens.sass} +75 -64
- package/dist/styles/{_config.sass → _01_config.sass} +28 -36
- 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/_09_utilities.sass +208 -0
- 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/{_tokens.sass → _00_tokens.sass} +73 -64
- package/templates/{_config.sass → _01_config.sass} +24 -36
- 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/_09_utilities.sass +207 -0
- 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/_utilities.sass +0 -125
- package/templates/_blocks.sass +0 -88
- package/templates/_layouts.sass +0 -108
- package/templates/_responsive.sass +0 -43
- package/templates/_utilities.sass +0 -125
package/dist/styles/_blocks.sass
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
// =============================================================================
|
|
2
|
-
// BLOCKS — components as recipes of fractals. Note how little CSS is here:
|
|
3
|
-
// each block is a handful of fractal calls plus its own genuinely-unique lines.
|
|
4
|
-
// State is expressed with data-*/aria-*, never modifier classes.
|
|
5
|
-
// =============================================================================
|
|
6
|
-
|
|
7
|
-
@use 'fractals' as *
|
|
8
|
-
|
|
9
|
-
.card
|
|
10
|
-
+surface(surface, s, 12)
|
|
11
|
-
+stack(s)
|
|
12
|
-
&[data-elevated]
|
|
13
|
-
+shadow(md)
|
|
14
|
-
|
|
15
|
-
.panel
|
|
16
|
-
+surface(raised, m, 16)
|
|
17
|
-
+stack(m)
|
|
18
|
-
|
|
19
|
-
.badge
|
|
20
|
-
+row(center, center)
|
|
21
|
-
display: inline-flex
|
|
22
|
-
+px(2xs)
|
|
23
|
-
+type(xs)
|
|
24
|
-
+weight(500)
|
|
25
|
-
+radius(full)
|
|
26
|
-
+bg(raised)
|
|
27
|
-
+ink(secondary)
|
|
28
|
-
padding-block: 2px
|
|
29
|
-
|
|
30
|
-
.avatar
|
|
31
|
-
+center
|
|
32
|
-
+square(var(--avatar-size, 40px))
|
|
33
|
-
+radius(full)
|
|
34
|
-
+bg(raised)
|
|
35
|
-
+ink(secondary)
|
|
36
|
-
overflow: hidden
|
|
37
|
-
|
|
38
|
-
.input
|
|
39
|
-
display: block
|
|
40
|
-
+w(100%)
|
|
41
|
-
+px(2xs)
|
|
42
|
-
+type(md)
|
|
43
|
-
+leading(1.5)
|
|
44
|
-
+border
|
|
45
|
-
+radius(6)
|
|
46
|
-
+bg(bg)
|
|
47
|
-
+ink(primary)
|
|
48
|
-
padding-block: 8px
|
|
49
|
-
&:focus-visible
|
|
50
|
-
+ring
|
|
51
|
-
|
|
52
|
-
.button
|
|
53
|
-
+row(center, center)
|
|
54
|
-
+gap(2xs)
|
|
55
|
-
+px(s)
|
|
56
|
-
+radius(6)
|
|
57
|
-
+weight(500)
|
|
58
|
-
+transition(background-color)
|
|
59
|
-
cursor: pointer
|
|
60
|
-
padding-block: 8px
|
|
61
|
-
user-select: none
|
|
62
|
-
// Exceptions: variants live on data-variant, not in the class name.
|
|
63
|
-
&[data-variant='primary']
|
|
64
|
-
background: var(--theme)
|
|
65
|
-
color: var(--text-inverse)
|
|
66
|
-
&:hover
|
|
67
|
-
background: var(--theme-hover)
|
|
68
|
-
&[data-variant='ghost']
|
|
69
|
-
background: transparent
|
|
70
|
-
+ink(secondary)
|
|
71
|
-
&:hover
|
|
72
|
-
+bg(raised)
|
|
73
|
-
|
|
74
|
-
.divider
|
|
75
|
-
border: none
|
|
76
|
-
+border(top)
|
|
77
|
-
margin-block: space(s)
|
|
78
|
-
|
|
79
|
-
.kbd
|
|
80
|
-
display: inline-block
|
|
81
|
-
+px(3xs)
|
|
82
|
-
+type(xs)
|
|
83
|
-
+leading(1)
|
|
84
|
-
+radius(4)
|
|
85
|
-
+bg(raised)
|
|
86
|
-
border: 1px solid var(--border-strong)
|
|
87
|
-
font-family: var(--font-mono)
|
|
88
|
-
padding-block: 2px
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
// =============================================================================
|
|
2
|
-
// LAYOUTS — the largest fractals. Same recipe move, page scale.
|
|
3
|
-
// These are the concrete deliverables you named: a responsive 3-col grid, a
|
|
4
|
-
// hero, a holy-grail, a docs template. Each is a short composition of fractals.
|
|
5
|
-
// =============================================================================
|
|
6
|
-
|
|
7
|
-
@use 'fractals' as *
|
|
8
|
-
|
|
9
|
-
// 1. Responsive grid of 3 columns — 1 → 2 → 3 across breakpoints.
|
|
10
|
-
.grid-3
|
|
11
|
-
+cols((base: 1, sm: 2, lg: 3), m)
|
|
12
|
-
|
|
13
|
-
// A grid that never needs breakpoints: it fits as many columns as will hold
|
|
14
|
-
// the min track. Reach for this before .grid-3 when column count is negotiable.
|
|
15
|
-
.card-grid
|
|
16
|
-
+auto-grid(16rem, m)
|
|
17
|
-
|
|
18
|
-
// 2. Hero — full-viewport cover with a centered, measured message.
|
|
19
|
-
.hero
|
|
20
|
-
+cover(80vh, xl)
|
|
21
|
-
> .center
|
|
22
|
-
+stack(m, center)
|
|
23
|
-
text-align: center
|
|
24
|
-
max-width: 45ch
|
|
25
|
-
|
|
26
|
-
// 3. Holy grail — header / (nav · main · aside) / footer.
|
|
27
|
-
.holy-grail
|
|
28
|
-
display: grid
|
|
29
|
-
min-height: 100vh
|
|
30
|
-
grid-template-rows: auto 1fr auto
|
|
31
|
-
grid-template-areas: 'header' 'main' 'footer'
|
|
32
|
-
> .hg-header
|
|
33
|
-
grid-area: header
|
|
34
|
-
> .hg-footer
|
|
35
|
-
grid-area: footer
|
|
36
|
-
> .hg-body
|
|
37
|
-
grid-area: main
|
|
38
|
-
display: grid
|
|
39
|
-
grid-template-columns: 1fr
|
|
40
|
-
+gap(m)
|
|
41
|
-
+pad(m)
|
|
42
|
-
+at(lg)
|
|
43
|
-
> .hg-body
|
|
44
|
-
grid-template-columns: var(--nav-w, 220px) minmax(0, 1fr) var(--aside-w, 260px)
|
|
45
|
-
> .hg-nav
|
|
46
|
-
+sticky(var(--space-m))
|
|
47
|
-
align-self: start
|
|
48
|
-
> .hg-aside
|
|
49
|
-
+sticky(var(--space-m))
|
|
50
|
-
align-self: start
|
|
51
|
-
|
|
52
|
-
// 4. Docs template — sidebar nav + reading column + on-page TOC.
|
|
53
|
-
.docs
|
|
54
|
-
display: grid
|
|
55
|
-
min-height: 100vh
|
|
56
|
-
grid-template-columns: 1fr
|
|
57
|
-
> .docs-nav
|
|
58
|
-
display: none
|
|
59
|
-
> .docs-toc
|
|
60
|
-
display: none
|
|
61
|
-
> .docs-main
|
|
62
|
-
+min0
|
|
63
|
-
+stack(m)
|
|
64
|
-
+center-column(72ch, s-l)
|
|
65
|
-
+py(l)
|
|
66
|
-
+at(md)
|
|
67
|
-
grid-template-columns: var(--docs-nav-w, 240px) minmax(0, 1fr)
|
|
68
|
-
> .docs-nav
|
|
69
|
-
+box
|
|
70
|
-
+sticky(0)
|
|
71
|
-
+py(l)
|
|
72
|
-
+px(s)
|
|
73
|
-
height: 100vh
|
|
74
|
-
overflow-y: auto
|
|
75
|
-
+border(right)
|
|
76
|
-
+at(xl)
|
|
77
|
-
grid-template-columns: var(--docs-nav-w, 240px) minmax(0, 1fr) var(--docs-toc-w, 220px)
|
|
78
|
-
> .docs-toc
|
|
79
|
-
+box
|
|
80
|
-
+sticky(0)
|
|
81
|
-
+py(l)
|
|
82
|
-
+px(s)
|
|
83
|
-
height: 100vh
|
|
84
|
-
overflow-y: auto
|
|
85
|
-
+ink(secondary)
|
|
86
|
-
|
|
87
|
-
// 5. App shell — sticky header, fluid body, footer. The frame most apps live in.
|
|
88
|
-
.app-shell
|
|
89
|
-
+box
|
|
90
|
-
+relative
|
|
91
|
-
isolation: isolate
|
|
92
|
-
min-height: 100vh
|
|
93
|
-
> .app-header
|
|
94
|
-
+row(null, center)
|
|
95
|
-
+sticky(0)
|
|
96
|
-
+px(m)
|
|
97
|
-
z-index: var(--z-sticky)
|
|
98
|
-
height: var(--header-height)
|
|
99
|
-
+bg(surface)
|
|
100
|
-
+border(bottom)
|
|
101
|
-
> .app-main
|
|
102
|
-
+grow
|
|
103
|
-
+min0
|
|
104
|
-
> .app-footer
|
|
105
|
-
+row(null, center)
|
|
106
|
-
+px(m)
|
|
107
|
-
min-height: var(--footer-height)
|
|
108
|
-
+border(top)
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// =============================================================================
|
|
2
|
-
// RESPONSIVE FRACTALS — the units that let any other fractal grow with the page.
|
|
3
|
-
// -----------------------------------------------------------------------------
|
|
4
|
-
// These are self-similar too: +at(md) wraps any block of fractal calls in a
|
|
5
|
-
// breakpoint, so a "responsive component" is just a component whose fractals
|
|
6
|
-
// are re-stated inside +at(...).
|
|
7
|
-
// =============================================================================
|
|
8
|
-
|
|
9
|
-
@use 'sass:map'
|
|
10
|
-
@use 'config' as *
|
|
11
|
-
|
|
12
|
-
// +at(md) — mobile-first min-width query by name (sm/md/lg/xl) or raw length.
|
|
13
|
-
=at($name)
|
|
14
|
-
$edge: $name
|
|
15
|
-
@if map.has-key($breakpoints, $name)
|
|
16
|
-
$edge: bp($name)
|
|
17
|
-
@media (min-width: #{$edge})
|
|
18
|
-
@content
|
|
19
|
-
|
|
20
|
-
// +until(md) — max-width query (one below the named edge).
|
|
21
|
-
=until($name)
|
|
22
|
-
$edge: $name
|
|
23
|
-
@if map.has-key($breakpoints, $name)
|
|
24
|
-
$edge: bp($name)
|
|
25
|
-
@media (max-width: #{$edge})
|
|
26
|
-
@content
|
|
27
|
-
|
|
28
|
-
// Container-query fractals — component-scoped responsiveness.
|
|
29
|
-
=cq
|
|
30
|
-
container-type: inline-size
|
|
31
|
-
|
|
32
|
-
=cq-at($width)
|
|
33
|
-
@container (min-width: #{$width})
|
|
34
|
-
@content
|
|
35
|
-
|
|
36
|
-
=cq-until($width)
|
|
37
|
-
@container (max-width: #{$width})
|
|
38
|
-
@content
|
|
39
|
-
|
|
40
|
-
// Motion / preference-aware fractal.
|
|
41
|
-
=reduce-motion
|
|
42
|
-
@media (prefers-reduced-motion: reduce)
|
|
43
|
-
@content
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
// =============================================================================
|
|
2
|
-
// UTILITY PROJECTION — the *other* way to consume a fractal.
|
|
3
|
-
// -----------------------------------------------------------------------------
|
|
4
|
-
// A fractal is a mixin. Here we bind a subset of them to class names so they
|
|
5
|
-
// stay usable straight from markup (`class="box gap-m pad-l"`). This is the
|
|
6
|
-
// key idea: utility classes are not a separate system — they are a generated
|
|
7
|
-
// projection of the exact same fractals your components compose. Emit only the
|
|
8
|
-
// atoms you want in markup; delete this whole file if you go SASS-only.
|
|
9
|
-
// =============================================================================
|
|
10
|
-
|
|
11
|
-
@use 'config' as *
|
|
12
|
-
@use 'atoms' as *
|
|
13
|
-
@use 'molecules' as *
|
|
14
|
-
@use 'responsive' as *
|
|
15
|
-
|
|
16
|
-
// --- Flow ------------------------------------------------------------------
|
|
17
|
-
.box
|
|
18
|
-
+box
|
|
19
|
-
.row
|
|
20
|
-
+row
|
|
21
|
-
&.wrap
|
|
22
|
-
+wrap
|
|
23
|
-
|
|
24
|
-
// Alignment modifiers, semantic and axis-aware.
|
|
25
|
-
.box
|
|
26
|
-
&.xcenter
|
|
27
|
-
align-items: center
|
|
28
|
-
&.xleft
|
|
29
|
-
align-items: flex-start
|
|
30
|
-
&.xright
|
|
31
|
-
align-items: flex-end
|
|
32
|
-
&.ycenter
|
|
33
|
-
justify-content: center
|
|
34
|
-
&.ytop
|
|
35
|
-
justify-content: flex-start
|
|
36
|
-
&.ybot
|
|
37
|
-
justify-content: flex-end
|
|
38
|
-
|
|
39
|
-
.row
|
|
40
|
-
&.ycenter
|
|
41
|
-
align-items: center
|
|
42
|
-
&.ytop
|
|
43
|
-
align-items: flex-start
|
|
44
|
-
&.ybot
|
|
45
|
-
align-items: flex-end
|
|
46
|
-
&.xbetween
|
|
47
|
-
justify-content: space-between
|
|
48
|
-
&.xevenly
|
|
49
|
-
justify-content: space-evenly
|
|
50
|
-
&.xleft
|
|
51
|
-
justify-content: flex-start
|
|
52
|
-
&.xright
|
|
53
|
-
justify-content: flex-end
|
|
54
|
-
|
|
55
|
-
// Fixed column grids.
|
|
56
|
-
@for $n from 1 through 6
|
|
57
|
-
.grid-cols-#{$n}
|
|
58
|
-
+grid($n)
|
|
59
|
-
|
|
60
|
-
.center
|
|
61
|
-
+center
|
|
62
|
-
|
|
63
|
-
// --- Spacing scale → gap-* / pad-* -----------------------------------------
|
|
64
|
-
@each $s in $space-steps
|
|
65
|
-
.gap-#{$s}
|
|
66
|
-
+gap($s)
|
|
67
|
-
.pad-#{$s}
|
|
68
|
-
+pad($s)
|
|
69
|
-
.px-#{$s}
|
|
70
|
-
+px($s)
|
|
71
|
-
.py-#{$s}
|
|
72
|
-
+py($s)
|
|
73
|
-
|
|
74
|
-
// --- Radius / shadow / surface ---------------------------------------------
|
|
75
|
-
@each $r in $radius-steps
|
|
76
|
-
.radius-#{$r}
|
|
77
|
-
+radius($r)
|
|
78
|
-
|
|
79
|
-
@each $s in $shadow-steps
|
|
80
|
-
.shadow-#{$s}
|
|
81
|
-
+shadow($s)
|
|
82
|
-
|
|
83
|
-
@each $role in $surface-roles
|
|
84
|
-
.bg-#{$role}
|
|
85
|
-
+bg($role)
|
|
86
|
-
|
|
87
|
-
.border
|
|
88
|
-
+border
|
|
89
|
-
@each $side in top right bottom left
|
|
90
|
-
.border-#{$side}
|
|
91
|
-
+border($side)
|
|
92
|
-
|
|
93
|
-
// --- Type ------------------------------------------------------------------
|
|
94
|
-
@each $t in $text-steps
|
|
95
|
-
.text-#{$t}
|
|
96
|
-
+type($t)
|
|
97
|
-
|
|
98
|
-
.truncate
|
|
99
|
-
+truncate
|
|
100
|
-
|
|
101
|
-
// Semantic type primitives — so you stop retyping `.text-sm .lh15 .muted`.
|
|
102
|
-
.body
|
|
103
|
-
+type(md)
|
|
104
|
-
+leading(1.6)
|
|
105
|
-
+ink(primary)
|
|
106
|
-
.muted
|
|
107
|
-
+ink(secondary)
|
|
108
|
-
.eyebrow
|
|
109
|
-
+type(sm)
|
|
110
|
-
+ink(muted)
|
|
111
|
-
text-transform: uppercase
|
|
112
|
-
letter-spacing: 0.06em
|
|
113
|
-
font-weight: 500
|
|
114
|
-
|
|
115
|
-
// --- Sizing shortcuts ------------------------------------------------------
|
|
116
|
-
.wfull
|
|
117
|
-
+w(100%)
|
|
118
|
-
.hfull
|
|
119
|
-
+h(100%)
|
|
120
|
-
.full
|
|
121
|
-
+full
|
|
122
|
-
.grow
|
|
123
|
-
+grow
|
|
124
|
-
.min0
|
|
125
|
-
+min0
|
package/templates/_blocks.sass
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
// =============================================================================
|
|
2
|
-
// BLOCKS — components as recipes of fractals. Note how little CSS is here:
|
|
3
|
-
// each block is a handful of fractal calls plus its own genuinely-unique lines.
|
|
4
|
-
// State is expressed with data-*/aria-*, never modifier classes.
|
|
5
|
-
// =============================================================================
|
|
6
|
-
|
|
7
|
-
@use 'fractals' as *
|
|
8
|
-
|
|
9
|
-
.card
|
|
10
|
-
+surface(surface, s, 12)
|
|
11
|
-
+stack(s)
|
|
12
|
-
&[data-elevated]
|
|
13
|
-
+shadow(md)
|
|
14
|
-
|
|
15
|
-
.panel
|
|
16
|
-
+surface(raised, m, 16)
|
|
17
|
-
+stack(m)
|
|
18
|
-
|
|
19
|
-
.badge
|
|
20
|
-
+row(center, center)
|
|
21
|
-
display: inline-flex
|
|
22
|
-
+px(2xs)
|
|
23
|
-
+type(xs)
|
|
24
|
-
+weight(500)
|
|
25
|
-
+radius(full)
|
|
26
|
-
+bg(raised)
|
|
27
|
-
+ink(secondary)
|
|
28
|
-
padding-block: 2px
|
|
29
|
-
|
|
30
|
-
.avatar
|
|
31
|
-
+center
|
|
32
|
-
+square(var(--avatar-size, 40px))
|
|
33
|
-
+radius(full)
|
|
34
|
-
+bg(raised)
|
|
35
|
-
+ink(secondary)
|
|
36
|
-
overflow: hidden
|
|
37
|
-
|
|
38
|
-
.input
|
|
39
|
-
display: block
|
|
40
|
-
+w(100%)
|
|
41
|
-
+px(2xs)
|
|
42
|
-
+type(md)
|
|
43
|
-
+leading(1.5)
|
|
44
|
-
+border
|
|
45
|
-
+radius(6)
|
|
46
|
-
+bg(bg)
|
|
47
|
-
+ink(primary)
|
|
48
|
-
padding-block: 8px
|
|
49
|
-
&:focus-visible
|
|
50
|
-
+ring
|
|
51
|
-
|
|
52
|
-
.button
|
|
53
|
-
+row(center, center)
|
|
54
|
-
+gap(2xs)
|
|
55
|
-
+px(s)
|
|
56
|
-
+radius(6)
|
|
57
|
-
+weight(500)
|
|
58
|
-
+transition(background-color)
|
|
59
|
-
cursor: pointer
|
|
60
|
-
padding-block: 8px
|
|
61
|
-
user-select: none
|
|
62
|
-
// Exceptions: variants live on data-variant, not in the class name.
|
|
63
|
-
&[data-variant='primary']
|
|
64
|
-
background: var(--theme)
|
|
65
|
-
color: var(--text-inverse)
|
|
66
|
-
&:hover
|
|
67
|
-
background: var(--theme-hover)
|
|
68
|
-
&[data-variant='ghost']
|
|
69
|
-
background: transparent
|
|
70
|
-
+ink(secondary)
|
|
71
|
-
&:hover
|
|
72
|
-
+bg(raised)
|
|
73
|
-
|
|
74
|
-
.divider
|
|
75
|
-
border: none
|
|
76
|
-
+border(top)
|
|
77
|
-
margin-block: space(s)
|
|
78
|
-
|
|
79
|
-
.kbd
|
|
80
|
-
display: inline-block
|
|
81
|
-
+px(3xs)
|
|
82
|
-
+type(xs)
|
|
83
|
-
+leading(1)
|
|
84
|
-
+radius(4)
|
|
85
|
-
+bg(raised)
|
|
86
|
-
border: 1px solid var(--border-strong)
|
|
87
|
-
font-family: var(--font-mono)
|
|
88
|
-
padding-block: 2px
|
package/templates/_layouts.sass
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
// =============================================================================
|
|
2
|
-
// LAYOUTS — the largest fractals. Same recipe move, page scale.
|
|
3
|
-
// These are the concrete deliverables you named: a responsive 3-col grid, a
|
|
4
|
-
// hero, a holy-grail, a docs template. Each is a short composition of fractals.
|
|
5
|
-
// =============================================================================
|
|
6
|
-
|
|
7
|
-
@use 'fractals' as *
|
|
8
|
-
|
|
9
|
-
// 1. Responsive grid of 3 columns — 1 → 2 → 3 across breakpoints.
|
|
10
|
-
.grid-3
|
|
11
|
-
+cols((base: 1, sm: 2, lg: 3), m)
|
|
12
|
-
|
|
13
|
-
// A grid that never needs breakpoints: it fits as many columns as will hold
|
|
14
|
-
// the min track. Reach for this before .grid-3 when column count is negotiable.
|
|
15
|
-
.card-grid
|
|
16
|
-
+auto-grid(16rem, m)
|
|
17
|
-
|
|
18
|
-
// 2. Hero — full-viewport cover with a centered, measured message.
|
|
19
|
-
.hero
|
|
20
|
-
+cover(80vh, xl)
|
|
21
|
-
> .center
|
|
22
|
-
+stack(m, center)
|
|
23
|
-
text-align: center
|
|
24
|
-
max-width: 45ch
|
|
25
|
-
|
|
26
|
-
// 3. Holy grail — header / (nav · main · aside) / footer.
|
|
27
|
-
.holy-grail
|
|
28
|
-
display: grid
|
|
29
|
-
min-height: 100vh
|
|
30
|
-
grid-template-rows: auto 1fr auto
|
|
31
|
-
grid-template-areas: 'header' 'main' 'footer'
|
|
32
|
-
> .hg-header
|
|
33
|
-
grid-area: header
|
|
34
|
-
> .hg-footer
|
|
35
|
-
grid-area: footer
|
|
36
|
-
> .hg-body
|
|
37
|
-
grid-area: main
|
|
38
|
-
display: grid
|
|
39
|
-
grid-template-columns: 1fr
|
|
40
|
-
+gap(m)
|
|
41
|
-
+pad(m)
|
|
42
|
-
+at(lg)
|
|
43
|
-
> .hg-body
|
|
44
|
-
grid-template-columns: var(--nav-w, 220px) minmax(0, 1fr) var(--aside-w, 260px)
|
|
45
|
-
> .hg-nav
|
|
46
|
-
+sticky(var(--space-m))
|
|
47
|
-
align-self: start
|
|
48
|
-
> .hg-aside
|
|
49
|
-
+sticky(var(--space-m))
|
|
50
|
-
align-self: start
|
|
51
|
-
|
|
52
|
-
// 4. Docs template — sidebar nav + reading column + on-page TOC.
|
|
53
|
-
.docs
|
|
54
|
-
display: grid
|
|
55
|
-
min-height: 100vh
|
|
56
|
-
grid-template-columns: 1fr
|
|
57
|
-
> .docs-nav
|
|
58
|
-
display: none
|
|
59
|
-
> .docs-toc
|
|
60
|
-
display: none
|
|
61
|
-
> .docs-main
|
|
62
|
-
+min0
|
|
63
|
-
+stack(m)
|
|
64
|
-
+center-column(72ch, s-l)
|
|
65
|
-
+py(l)
|
|
66
|
-
+at(md)
|
|
67
|
-
grid-template-columns: var(--docs-nav-w, 240px) minmax(0, 1fr)
|
|
68
|
-
> .docs-nav
|
|
69
|
-
+box
|
|
70
|
-
+sticky(0)
|
|
71
|
-
+py(l)
|
|
72
|
-
+px(s)
|
|
73
|
-
height: 100vh
|
|
74
|
-
overflow-y: auto
|
|
75
|
-
+border(right)
|
|
76
|
-
+at(xl)
|
|
77
|
-
grid-template-columns: var(--docs-nav-w, 240px) minmax(0, 1fr) var(--docs-toc-w, 220px)
|
|
78
|
-
> .docs-toc
|
|
79
|
-
+box
|
|
80
|
-
+sticky(0)
|
|
81
|
-
+py(l)
|
|
82
|
-
+px(s)
|
|
83
|
-
height: 100vh
|
|
84
|
-
overflow-y: auto
|
|
85
|
-
+ink(secondary)
|
|
86
|
-
|
|
87
|
-
// 5. App shell — sticky header, fluid body, footer. The frame most apps live in.
|
|
88
|
-
.app-shell
|
|
89
|
-
+box
|
|
90
|
-
+relative
|
|
91
|
-
isolation: isolate
|
|
92
|
-
min-height: 100vh
|
|
93
|
-
> .app-header
|
|
94
|
-
+row(null, center)
|
|
95
|
-
+sticky(0)
|
|
96
|
-
+px(m)
|
|
97
|
-
z-index: var(--z-sticky)
|
|
98
|
-
height: var(--header-height)
|
|
99
|
-
+bg(surface)
|
|
100
|
-
+border(bottom)
|
|
101
|
-
> .app-main
|
|
102
|
-
+grow
|
|
103
|
-
+min0
|
|
104
|
-
> .app-footer
|
|
105
|
-
+row(null, center)
|
|
106
|
-
+px(m)
|
|
107
|
-
min-height: var(--footer-height)
|
|
108
|
-
+border(top)
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// =============================================================================
|
|
2
|
-
// RESPONSIVE FRACTALS — the units that let any other fractal grow with the page.
|
|
3
|
-
// -----------------------------------------------------------------------------
|
|
4
|
-
// These are self-similar too: +at(md) wraps any block of fractal calls in a
|
|
5
|
-
// breakpoint, so a "responsive component" is just a component whose fractals
|
|
6
|
-
// are re-stated inside +at(...).
|
|
7
|
-
// =============================================================================
|
|
8
|
-
|
|
9
|
-
@use 'sass:map'
|
|
10
|
-
@use 'config' as *
|
|
11
|
-
|
|
12
|
-
// +at(md) — mobile-first min-width query by name (sm/md/lg/xl) or raw length.
|
|
13
|
-
=at($name)
|
|
14
|
-
$edge: $name
|
|
15
|
-
@if map.has-key($breakpoints, $name)
|
|
16
|
-
$edge: bp($name)
|
|
17
|
-
@media (min-width: #{$edge})
|
|
18
|
-
@content
|
|
19
|
-
|
|
20
|
-
// +until(md) — max-width query (one below the named edge).
|
|
21
|
-
=until($name)
|
|
22
|
-
$edge: $name
|
|
23
|
-
@if map.has-key($breakpoints, $name)
|
|
24
|
-
$edge: bp($name)
|
|
25
|
-
@media (max-width: #{$edge})
|
|
26
|
-
@content
|
|
27
|
-
|
|
28
|
-
// Container-query fractals — component-scoped responsiveness.
|
|
29
|
-
=cq
|
|
30
|
-
container-type: inline-size
|
|
31
|
-
|
|
32
|
-
=cq-at($width)
|
|
33
|
-
@container (min-width: #{$width})
|
|
34
|
-
@content
|
|
35
|
-
|
|
36
|
-
=cq-until($width)
|
|
37
|
-
@container (max-width: #{$width})
|
|
38
|
-
@content
|
|
39
|
-
|
|
40
|
-
// Motion / preference-aware fractal.
|
|
41
|
-
=reduce-motion
|
|
42
|
-
@media (prefers-reduced-motion: reduce)
|
|
43
|
-
@content
|