fractalstyler2 0.0.1 → 0.1.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.
@@ -4,7 +4,7 @@
4
4
  // State is expressed with data-*/aria-*, never modifier classes.
5
5
  // =============================================================================
6
6
 
7
- @use '../fractals' as *
7
+ @use 'fractals' as *
8
8
 
9
9
  .card
10
10
  +surface(surface, s, 12)
@@ -1,7 +1,9 @@
1
1
  // =============================================================================
2
2
  // FRACTALS — the pure API barrel. Emits NO css on its own.
3
3
  // -----------------------------------------------------------------------------
4
- // In any component partial: @use '../fractals' as *
4
+ // In any component partial or Svelte component:
5
+ // @use '$lib/styles/fractals' as *
6
+ // (or @use './fractals' as *)
5
7
  // then call fractals freely: +surface(...) +stack(...) space(m) ...
6
8
  // =============================================================================
7
9
 
@@ -4,7 +4,7 @@
4
4
  // hero, a holy-grail, a docs template. Each is a short composition of fractals.
5
5
  // =============================================================================
6
6
 
7
- @use '../fractals' as *
7
+ @use 'fractals' as *
8
8
 
9
9
  // 1. Responsive grid of 3 columns — 1 → 2 → 3 across breakpoints.
10
10
  .grid-3
@@ -2,18 +2,19 @@
2
2
  // STYLES ENTRY — the full emitted stylesheet in cascade order.
3
3
  // -----------------------------------------------------------------------------
4
4
  // 1. tokens the CSS custom properties (only literal values)
5
- // 2. utilities atom fractals projected to markup classes (optional layer)
6
- // 3. blocks components composed from fractals
7
- // 4. layouts page templates composed from fractals
5
+ // 2. base fluid reset
6
+ // 3. utilities atom fractals projected to markup classes (optional layer)
7
+ // 4. blocks components composed from fractals
8
+ // 5. layouts page templates composed from fractals
8
9
  //
9
- // Consume from a SvelteKit app: import 'fractalstyler2/styles'
10
- // or, from SASS: @use 'fractalstyler2/styles'
10
+ // Consume from a SvelteKit app: import '$lib/styles/index.sass'
11
+ // or from package: import 'fractalstyler2/styles'
11
12
  // The fractal mixins/functions themselves emit nothing until called, so output
12
13
  // contains only what you use.
13
14
  // =============================================================================
14
15
 
15
- @use '../fractals/tokens'
16
- @use '../fractals/base'
17
- @use '../fractals/utilities'
18
- @use '../components/blocks'
19
- @use '../components/layouts'
16
+ @use './tokens'
17
+ @use './base'
18
+ @use './utilities'
19
+ @use './blocks'
20
+ @use './layouts'
package/package.json CHANGED
@@ -1,20 +1,26 @@
1
1
  {
2
2
  "name": "fractalstyler2",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "description": "A fractal-composition styling system for SvelteKit — every style unit is a SASS mixin, and components and layouts are recipes of smaller fractals.",
5
+ "bin": {
6
+ "fractalstyler2": "./dist/cli.js",
7
+ "fractalstyler": "./dist/cli.js",
8
+ "fractalstyler2-mcp": "./dist/mcp/server.js"
9
+ },
5
10
  "scripts": {
6
11
  "dev": "vite dev",
7
12
  "build": "vite build && npm run prepack",
8
13
  "preview": "vite preview",
9
14
  "prepare": "svelte-kit sync || echo ''",
10
- "prepack": "svelte-kit sync && svelte-package && publint",
15
+ "prepack": "svelte-kit sync && svelte-package && chmod +x dist/cli.js && chmod +x dist/mcp/server.js && publint",
11
16
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
12
17
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
13
18
  },
14
19
  "files": [
15
20
  "dist",
16
21
  "!dist/**/*.test.*",
17
- "!dist/**/*.spec.*"
22
+ "!dist/**/*.spec.*",
23
+ "templates"
18
24
  ],
19
25
  "sideEffects": [
20
26
  "**/*.css"
@@ -28,8 +34,10 @@
28
34
  "svelte": "./dist/index.js"
29
35
  },
30
36
  "./styles": "./dist/styles/index.sass",
31
- "./fractals": "./dist/fractals/index.sass",
32
- "./tokens": "./dist/fractals/_tokens.sass",
37
+ "./styles/*": "./dist/styles/*",
38
+ "./fractals": "./dist/styles/_fractals.sass",
39
+ "./tokens": "./dist/styles/_tokens.sass",
40
+ "./mcp": "./dist/mcp/server.js",
33
41
  "./package.json": "./package.json"
34
42
  },
35
43
  "peerDependencies": {
@@ -40,6 +48,7 @@
40
48
  "@sveltejs/kit": "^2.63.0",
41
49
  "@sveltejs/package": "^2.5.8",
42
50
  "@sveltejs/vite-plugin-svelte": "^7.1.2",
51
+ "@types/node": "^26.2.0",
43
52
  "publint": "^0.3.21",
44
53
  "sass": "^1.102.0",
45
54
  "svelte": "^5.56.1",
@@ -55,5 +64,8 @@
55
64
  "design-system",
56
65
  "mixins",
57
66
  "fractal"
58
- ]
67
+ ],
68
+ "dependencies": {
69
+ "@modelcontextprotocol/sdk": "^1.30.0"
70
+ }
59
71
  }
@@ -0,0 +1,155 @@
1
+ // =============================================================================
2
+ // ATOM FRACTALS — the indivisible units. One visual decision each.
3
+ // -----------------------------------------------------------------------------
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.
6
+ // =============================================================================
7
+
8
+ @use 'config' as *
9
+
10
+ // --- Flow: the two axes of layout ------------------------------------------
11
+ // A box is a vertical stack, a row is horizontal. Optional semantic alignment:
12
+ // +box(center) → items centered on the cross axis
13
+ // +row(between, center) → spread on main axis, centered on cross axis
14
+ =box($x: null, $y: null)
15
+ display: flex
16
+ flex-direction: column
17
+ @if $x
18
+ align-items: align($x)
19
+ @if $y
20
+ justify-content: align($y)
21
+
22
+ =row($x: null, $y: null)
23
+ display: flex
24
+ flex-direction: row
25
+ @if $x
26
+ justify-content: align($x)
27
+ @if $y
28
+ align-items: align($y)
29
+
30
+ =wrap
31
+ flex-wrap: wrap
32
+
33
+ =grid($cols: 1)
34
+ display: grid
35
+ grid-template-columns: repeat($cols, minmax(0, 1fr))
36
+
37
+ // A grid that reflows on its own — no breakpoints, no counting columns.
38
+ =auto-grid($min: 15rem, $gap: s)
39
+ display: grid
40
+ grid-template-columns: repeat(auto-fit, minmax(min(#{$min}, 100%), 1fr))
41
+ gap: space($gap)
42
+
43
+ // Dead-center anything (grid is the one-liner that works for a single child).
44
+ =center
45
+ display: grid
46
+ place-items: center
47
+
48
+ // --- Spacing ---------------------------------------------------------------
49
+ =gap($v: s)
50
+ gap: space($v)
51
+
52
+ =pad($v: s)
53
+ padding: space($v)
54
+
55
+ =px($v: s)
56
+ padding-inline: space($v)
57
+
58
+ =py($v: s)
59
+ padding-block: space($v)
60
+
61
+ =mx-auto
62
+ margin-inline: auto
63
+
64
+ =my-auto
65
+ margin-block: auto
66
+
67
+ // --- Size ------------------------------------------------------------------
68
+ =w($v: 100%)
69
+ width: $v
70
+
71
+ =h($v: 100%)
72
+ height: $v
73
+
74
+ =full
75
+ width: 100%
76
+ height: 100%
77
+
78
+ =square($v)
79
+ width: $v
80
+ height: $v
81
+
82
+ =grow($n: 1)
83
+ flex-grow: $n
84
+
85
+ =shrink($n: 0)
86
+ flex-shrink: $n
87
+
88
+ =min0
89
+ min-width: 0
90
+ min-height: 0
91
+
92
+ // --- Surface & skin --------------------------------------------------------
93
+ =bg($role: surface)
94
+ background-color: surface($role)
95
+
96
+ =ink($role: primary)
97
+ color: ink($role)
98
+
99
+ =border($side: all, $color: var(--border))
100
+ @if $side == all
101
+ border: 1px solid $color
102
+ @else
103
+ border-#{$side}: 1px solid $color
104
+
105
+ =radius($v: 12)
106
+ border-radius: radius($v)
107
+
108
+ =shadow($v: md)
109
+ box-shadow: shadow($v)
110
+
111
+ // --- Position --------------------------------------------------------------
112
+ =relative
113
+ position: relative
114
+
115
+ =absolute($inset: null)
116
+ position: absolute
117
+ @if $inset
118
+ inset: $inset
119
+
120
+ =sticky($top: 0)
121
+ position: sticky
122
+ top: $top
123
+
124
+ =fill
125
+ position: absolute
126
+ inset: 0
127
+
128
+ // --- Type ------------------------------------------------------------------
129
+ =type($v)
130
+ font-size: text-size($v)
131
+
132
+ =weight($w: 500)
133
+ font-weight: $w
134
+
135
+ =leading($lh: 1.5)
136
+ line-height: $lh
137
+
138
+ =truncate
139
+ overflow: hidden
140
+ white-space: nowrap
141
+ text-overflow: ellipsis
142
+
143
+ =clamp-lines($n: 2)
144
+ display: -webkit-box
145
+ -webkit-line-clamp: $n
146
+ -webkit-box-orient: vertical
147
+ overflow: hidden
148
+
149
+ // --- Motion ----------------------------------------------------------------
150
+ =transition($props: all, $dur: 150ms, $ease: ease)
151
+ transition: $props $dur $ease
152
+
153
+ =ring($color: var(--ring))
154
+ outline: 2px solid $color
155
+ outline-offset: 1px
@@ -0,0 +1,43 @@
1
+ // =============================================================================
2
+ // BASE — a minimal, opinionated reset so the tokens actually reach the page.
3
+ // Kept tiny: box model, sane media defaults, and wiring body to the palette.
4
+ // =============================================================================
5
+
6
+ *, *::before, *::after
7
+ box-sizing: border-box
8
+
9
+ html
10
+ -webkit-text-size-adjust: 100%
11
+
12
+ body
13
+ margin: 0
14
+ min-height: 100vh
15
+ font-family: var(--font-sans)
16
+ font-size: var(--text-md)
17
+ line-height: 1.5
18
+ color: var(--text-primary)
19
+ background-color: var(--bg)
20
+ -webkit-font-smoothing: antialiased
21
+
22
+ :where(h1, h2, h3, h4, h5, h6, p, figure, blockquote)
23
+ margin: 0
24
+
25
+ :where(h1, h2, h3, h4)
26
+ line-height: 1.15
27
+ text-wrap: balance
28
+
29
+ :where(img, picture, video, canvas, svg)
30
+ display: block
31
+ max-width: 100%
32
+
33
+ :where(a)
34
+ color: inherit
35
+ text-decoration-color: var(--border-strong)
36
+
37
+ :where(button, input, select, textarea)
38
+ font: inherit
39
+ color: inherit
40
+
41
+ :where(:focus-visible)
42
+ outline: 2px solid var(--ring)
43
+ outline-offset: 2px
@@ -0,0 +1,88 @@
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
@@ -0,0 +1,78 @@
1
+ // =============================================================================
2
+ // CONFIG — the finite vocabulary every fractal draws from.
3
+ // -----------------------------------------------------------------------------
4
+ // Scales live here as Sass data; resolvers turn a keyword-or-raw value into the
5
+ // right token var() or unit. Fractals never hardcode a px or a token name —
6
+ // they route through space(), radius(), etc. so the system speaks one language.
7
+ // =============================================================================
8
+
9
+ @use 'sass:map'
10
+ @use 'sass:math'
11
+ @use 'sass:meta'
12
+ @use 'sass:list'
13
+
14
+ // --- Scales (mirror the custom properties in _tokens.sass) --------------------
15
+ $breakpoints: (sm: 640px, md: 768px, lg: 1024px, xl: 1240px)
16
+
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
19
+ $text-steps: xs sm md lg xl 2xl 3xl 4xl
20
+ $shadow-steps: sm md lg
21
+ $surface-roles: bg surface raised
22
+ $ink-roles: primary secondary muted inverse
23
+
24
+ $align-map: (start: flex-start, end: flex-end, center: center, between: space-between, around: space-around, evenly: space-evenly, stretch: stretch, baseline: baseline)
25
+
26
+ // --- Resolvers ----------------------------------------------------------------
27
+
28
+ // space(m) → var(--space-m) | space(18) → 18px | space(2rem) → 2rem
29
+ @function space($v)
30
+ @if $v == null
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)
35
+ @return #{$v}px
36
+ @else
37
+ @return $v
38
+
39
+ @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
46
+
47
+ @function text-size($v)
48
+ @if list.index($text-steps, $v)
49
+ @return var(--text-#{$v})
50
+ @else
51
+ @return $v
52
+
53
+ @function shadow($v)
54
+ @if list.index($shadow-steps, $v)
55
+ @return var(--shadow-#{$v})
56
+ @else
57
+ @return $v
58
+
59
+ @function surface($role)
60
+ @if $role == bg
61
+ @return var(--bg)
62
+ @else
63
+ @return var(--bg-#{$role})
64
+
65
+ @function ink($role)
66
+ @if $role == primary
67
+ @return var(--text-primary)
68
+ @else
69
+ @return var(--text-#{$role})
70
+
71
+ @function align($v)
72
+ $m: map.get($align-map, $v)
73
+ @if $m
74
+ @return $m
75
+ @return $v
76
+
77
+ @function bp($name)
78
+ @return map.get($breakpoints, $name)
@@ -0,0 +1,13 @@
1
+ // =============================================================================
2
+ // FRACTALS — the pure API barrel. Emits NO css on its own.
3
+ // -----------------------------------------------------------------------------
4
+ // In any component partial or Svelte component:
5
+ // @use '$lib/styles/fractals' as *
6
+ // (or @use './fractals' as *)
7
+ // then call fractals freely: +surface(...) +stack(...) space(m) ...
8
+ // =============================================================================
9
+
10
+ @forward 'config'
11
+ @forward 'responsive'
12
+ @forward 'atoms'
13
+ @forward 'molecules'
@@ -0,0 +1,108 @@
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)