fractalstyler2 0.4.0 → 0.7.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 +114 -95
- package/dist/cli.js +105 -25
- package/dist/components/Accordion.svelte +44 -0
- package/dist/components/Accordion.svelte.d.ts +23 -0
- package/dist/components/AccordionItem.svelte +44 -0
- package/dist/components/AccordionItem.svelte.d.ts +21 -0
- package/dist/components/AppShell.svelte +86 -0
- package/dist/components/AppShell.svelte.d.ts +39 -0
- package/dist/components/ColorPicker.svelte +38 -0
- package/dist/components/ColorPicker.svelte.d.ts +6 -0
- package/dist/components/Hero.svelte +14 -0
- package/dist/components/Hero.svelte.d.ts +9 -0
- package/dist/components/LayoutPicker.svelte +34 -0
- package/dist/components/LayoutPicker.svelte.d.ts +6 -0
- package/dist/components/MotionPicker.svelte +34 -0
- package/dist/components/MotionPicker.svelte.d.ts +6 -0
- package/dist/components/PageShell.svelte +14 -0
- package/dist/components/PageShell.svelte.d.ts +9 -0
- package/dist/components/PageSplit.svelte +26 -0
- package/dist/components/PageSplit.svelte.d.ts +18 -0
- package/dist/components/ShapePicker.svelte +37 -0
- package/dist/components/ShapePicker.svelte.d.ts +6 -0
- package/dist/css/fractalstyler.css +10643 -0
- package/dist/css/fractalstyler.min.css +2 -0
- package/dist/index.d.ts +18 -6
- package/dist/index.js +30 -12
- package/dist/mcp/schemas/compile_fractals.json +3 -3
- package/dist/mcp/schemas/css_to_fractals.json +1 -1
- package/dist/mcp/schemas/generate_component.json +2 -2
- package/dist/mcp/schemas/instructions.md +41 -14
- package/dist/mcp/schemas/list_fractals.json +9 -7
- package/dist/mcp/schemas/validate_recipe.json +2 -2
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +334 -237
- package/dist/presets.core.d.ts +42 -0
- package/dist/presets.core.js +190 -0
- package/dist/presets.svelte.d.ts +6 -0
- package/dist/presets.svelte.js +21 -0
- package/dist/styles/_00_presets.sass +111 -0
- package/dist/styles/_00_themes.sass +1061 -0
- package/dist/styles/_00_tokens.sass +57 -17
- package/dist/styles/_01_config.sass +77 -70
- package/dist/styles/_02_dimensions.sass +174 -0
- package/dist/styles/_03_containers.sass +105 -0
- package/dist/styles/_04_layouts.sass +100 -0
- package/dist/styles/_05_shells.sass +374 -0
- package/dist/styles/_06_visuals.sass +236 -0
- package/dist/styles/_07_interactions.sass +112 -0
- package/dist/styles/_08_own.sass +4 -0
- package/dist/styles/canonical-markups.md +160 -0
- package/dist/styles/index.sass +11 -18
- package/dist/themes.d.ts +7 -0
- package/dist/themes.js +45 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +2 -0
- package/package.json +26 -15
- package/plugin.json +11 -10
- package/registry.json +2002 -0
- package/skills/fractal-styler/SKILL.md +137 -50
- package/skills/fractal-styler/references/fractals.md +416 -28
- package/skills/fractal-styler/references/tokens.md +110 -36
- package/dist/styles/_02_fonts.sass +0 -13
- package/dist/styles/_03_responsive.sass +0 -31
- package/dist/styles/_04_atoms.sass +0 -155
- package/dist/styles/_05_molecules.sass +0 -97
- package/dist/styles/_06_recipes.sass +0 -189
- package/dist/styles/_07_base.sass +0 -44
- package/dist/styles/_08_blocks.sass +0 -433
- package/dist/styles/_09_utilities.sass +0 -208
- package/dist/styles/_10_layouts.sass +0 -373
- package/dist/styles/_11_own.sass +0 -21
- package/dist/styles/_fractals.sass +0 -14
- package/skills/style-migration/SKILL.md +0 -45
- package/templates/_00_tokens.sass +0 -136
- package/templates/_01_config.sass +0 -66
- package/templates/_02_fonts.sass +0 -13
- package/templates/_03_responsive.sass +0 -31
- package/templates/_04_atoms.sass +0 -155
- package/templates/_05_molecules.sass +0 -97
- package/templates/_06_recipes.sass +0 -189
- package/templates/_07_base.sass +0 -44
- package/templates/_08_blocks.sass +0 -433
- package/templates/_09_utilities.sass +0 -207
- package/templates/_10_layouts.sass +0 -373
- package/templates/_11_own.sass +0 -21
- package/templates/_fractals.sass +0 -14
- package/templates/index.sass +0 -18
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The canonical application shell, from canonical-markups.md §1 and §2.
|
|
6
|
+
*
|
|
7
|
+
* The point of this component is not convenience — the classes work by hand.
|
|
8
|
+
* It is that an L4 class without its markup is half a definition: the rails
|
|
9
|
+
* retract, the drawer opens and the TOC folds because of the *structure*,
|
|
10
|
+
* not because of anything you wire. Approximating the structure is where
|
|
11
|
+
* people quietly lose the behaviour and start inventing classes to get it
|
|
12
|
+
* back. This emits the structure exactly.
|
|
13
|
+
*
|
|
14
|
+
* Everything here is registry classes. There is no style block, and adding
|
|
15
|
+
* one would defeat the purpose.
|
|
16
|
+
*/
|
|
17
|
+
interface Props {
|
|
18
|
+
/** Sticky top bar. Omit for a shell with no chrome. */
|
|
19
|
+
header?: Snippet;
|
|
20
|
+
/** Left rail — navigation. Visible ≥1024px, drawer below. */
|
|
21
|
+
sidebarLeft?: Snippet;
|
|
22
|
+
/** Right rail — table of contents. Visible ≥1280px, folds to `mobileToc`. */
|
|
23
|
+
sidebarRight?: Snippet;
|
|
24
|
+
/** The page-top disclosure the right rail retracts into below 1280px. */
|
|
25
|
+
mobileToc?: Snippet;
|
|
26
|
+
/** Bottom bar. */
|
|
27
|
+
footer?: Snippet;
|
|
28
|
+
/** Page content. Wrapped in `.content-shell` unless `bounded` is false. */
|
|
29
|
+
children: Snippet;
|
|
30
|
+
/**
|
|
31
|
+
* Whether the left rail is showing as a drawer. Only has an effect below
|
|
32
|
+
* 1024px, where the rail is off-canvas. Bind it to your menu button.
|
|
33
|
+
*/
|
|
34
|
+
open?: boolean;
|
|
35
|
+
/** Set false to drop `.content-shell` and let content run full width. */
|
|
36
|
+
bounded?: boolean;
|
|
37
|
+
class?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let {
|
|
41
|
+
header,
|
|
42
|
+
sidebarLeft,
|
|
43
|
+
sidebarRight,
|
|
44
|
+
mobileToc,
|
|
45
|
+
footer,
|
|
46
|
+
children,
|
|
47
|
+
open = $bindable(false),
|
|
48
|
+
bounded = true,
|
|
49
|
+
class: className = ''
|
|
50
|
+
}: Props = $props();
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<div class="app-shell {className}" class:open>
|
|
54
|
+
{#if header}
|
|
55
|
+
<header class="app-header row ycenter xbetween gap-sm">
|
|
56
|
+
{@render header()}
|
|
57
|
+
</header>
|
|
58
|
+
{/if}
|
|
59
|
+
|
|
60
|
+
<main class="app-main">
|
|
61
|
+
{#if sidebarLeft}
|
|
62
|
+
<aside class="sidebar-left">{@render sidebarLeft()}</aside>
|
|
63
|
+
{/if}
|
|
64
|
+
|
|
65
|
+
<section class="main-section">
|
|
66
|
+
{#if mobileToc}
|
|
67
|
+
<details class="mobile-toc">{@render mobileToc()}</details>
|
|
68
|
+
{/if}
|
|
69
|
+
{#if bounded}
|
|
70
|
+
<article class="content-shell">{@render children()}</article>
|
|
71
|
+
{:else}
|
|
72
|
+
{@render children()}
|
|
73
|
+
{/if}
|
|
74
|
+
</section>
|
|
75
|
+
|
|
76
|
+
{#if sidebarRight}
|
|
77
|
+
<aside class="sidebar-right">{@render sidebarRight()}</aside>
|
|
78
|
+
{/if}
|
|
79
|
+
</main>
|
|
80
|
+
|
|
81
|
+
{#if footer}
|
|
82
|
+
<footer class="app-footer row ycenter xbetween text-xs text-muted">
|
|
83
|
+
{@render footer()}
|
|
84
|
+
</footer>
|
|
85
|
+
{/if}
|
|
86
|
+
</div>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
/**
|
|
3
|
+
* The canonical application shell, from canonical-markups.md §1 and §2.
|
|
4
|
+
*
|
|
5
|
+
* The point of this component is not convenience — the classes work by hand.
|
|
6
|
+
* It is that an L4 class without its markup is half a definition: the rails
|
|
7
|
+
* retract, the drawer opens and the TOC folds because of the *structure*,
|
|
8
|
+
* not because of anything you wire. Approximating the structure is where
|
|
9
|
+
* people quietly lose the behaviour and start inventing classes to get it
|
|
10
|
+
* back. This emits the structure exactly.
|
|
11
|
+
*
|
|
12
|
+
* Everything here is registry classes. There is no style block, and adding
|
|
13
|
+
* one would defeat the purpose.
|
|
14
|
+
*/
|
|
15
|
+
interface Props {
|
|
16
|
+
/** Sticky top bar. Omit for a shell with no chrome. */
|
|
17
|
+
header?: Snippet;
|
|
18
|
+
/** Left rail — navigation. Visible ≥1024px, drawer below. */
|
|
19
|
+
sidebarLeft?: Snippet;
|
|
20
|
+
/** Right rail — table of contents. Visible ≥1280px, folds to `mobileToc`. */
|
|
21
|
+
sidebarRight?: Snippet;
|
|
22
|
+
/** The page-top disclosure the right rail retracts into below 1280px. */
|
|
23
|
+
mobileToc?: Snippet;
|
|
24
|
+
/** Bottom bar. */
|
|
25
|
+
footer?: Snippet;
|
|
26
|
+
/** Page content. Wrapped in `.content-shell` unless `bounded` is false. */
|
|
27
|
+
children: Snippet;
|
|
28
|
+
/**
|
|
29
|
+
* Whether the left rail is showing as a drawer. Only has an effect below
|
|
30
|
+
* 1024px, where the rail is off-canvas. Bind it to your menu button.
|
|
31
|
+
*/
|
|
32
|
+
open?: boolean;
|
|
33
|
+
/** Set false to drop `.content-shell` and let content run full width. */
|
|
34
|
+
bounded?: boolean;
|
|
35
|
+
class?: string;
|
|
36
|
+
}
|
|
37
|
+
declare const AppShell: import("svelte").Component<Props, {}, "open">;
|
|
38
|
+
type AppShell = ReturnType<typeof AppShell>;
|
|
39
|
+
export default AppShell;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from 'svelte';
|
|
3
|
+
import { presetAxes, presets, initPresets, setPreset } from '../presets.svelte.js';
|
|
4
|
+
|
|
5
|
+
let { class: className = '' }: { class?: string } = $props();
|
|
6
|
+
|
|
7
|
+
onMount(() => initPresets());
|
|
8
|
+
|
|
9
|
+
// Layer-tint glyphs — one swatch, three intensities (least → most tinted).
|
|
10
|
+
const fills: Record<string, number> = { clean: 0, general: 0.45, vibrant: 1 };
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<div class="row ycenter gap-8 {className}" role="group" aria-label="Color tint preset">
|
|
14
|
+
{#each presetAxes.color as color}
|
|
15
|
+
<button
|
|
16
|
+
type="button"
|
|
17
|
+
class="button ghost"
|
|
18
|
+
class:active={presets.color === color}
|
|
19
|
+
aria-pressed={presets.color === color}
|
|
20
|
+
title={color}
|
|
21
|
+
onclick={() => setPreset('color', color)}
|
|
22
|
+
>
|
|
23
|
+
<svg width="16" height="16" viewBox="0 0 19 19" aria-hidden="true">
|
|
24
|
+
<rect
|
|
25
|
+
x="1.5"
|
|
26
|
+
y="1.5"
|
|
27
|
+
width="16"
|
|
28
|
+
height="16"
|
|
29
|
+
rx="4"
|
|
30
|
+
fill="currentColor"
|
|
31
|
+
fill-opacity={fills[color]}
|
|
32
|
+
stroke="currentColor"
|
|
33
|
+
stroke-width="1.5"
|
|
34
|
+
/>
|
|
35
|
+
</svg>
|
|
36
|
+
</button>
|
|
37
|
+
{/each}
|
|
38
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
|
|
4
|
+
/** The centred landing section, from canonical-markups.md §5. */
|
|
5
|
+
interface Props {
|
|
6
|
+
children: Snippet;
|
|
7
|
+
class?: string;
|
|
8
|
+
}
|
|
9
|
+
let { children, class: className = '' }: Props = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<section class="hero {className}">
|
|
13
|
+
{@render children()}
|
|
14
|
+
</section>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
/** The centred landing section, from canonical-markups.md §5. */
|
|
3
|
+
interface Props {
|
|
4
|
+
children: Snippet;
|
|
5
|
+
class?: string;
|
|
6
|
+
}
|
|
7
|
+
declare const Hero: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type Hero = ReturnType<typeof Hero>;
|
|
9
|
+
export default Hero;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from 'svelte';
|
|
3
|
+
import { presetAxes, presets, initPresets, setPreset } from '../presets.svelte.js';
|
|
4
|
+
|
|
5
|
+
let { class: className = '' }: { class?: string } = $props();
|
|
6
|
+
|
|
7
|
+
onMount(() => initPresets());
|
|
8
|
+
|
|
9
|
+
// Density glyphs — three bars, spread tightest → loosest.
|
|
10
|
+
const spreads: Record<string, number[]> = {
|
|
11
|
+
tight: [5.5, 8.5, 11.5],
|
|
12
|
+
comfortable: [3.5, 8.5, 13.5],
|
|
13
|
+
sprawling: [1.5, 8.5, 15.5]
|
|
14
|
+
};
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<div class="row ycenter gap-8 {className}" role="group" aria-label="Layout density preset">
|
|
18
|
+
{#each presetAxes.layout as layout}
|
|
19
|
+
<button
|
|
20
|
+
type="button"
|
|
21
|
+
class="button ghost"
|
|
22
|
+
class:active={presets.layout === layout}
|
|
23
|
+
aria-pressed={presets.layout === layout}
|
|
24
|
+
title={layout}
|
|
25
|
+
onclick={() => setPreset('layout', layout)}
|
|
26
|
+
>
|
|
27
|
+
<svg width="16" height="16" viewBox="0 0 19 19" aria-hidden="true">
|
|
28
|
+
{#each spreads[layout] as y}
|
|
29
|
+
<rect x="3" {y} width="13" height="2" rx="1" fill="currentColor" />
|
|
30
|
+
{/each}
|
|
31
|
+
</svg>
|
|
32
|
+
</button>
|
|
33
|
+
{/each}
|
|
34
|
+
</div>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from 'svelte';
|
|
3
|
+
import { presetAxes, presets, initPresets, setPreset } from '../presets.svelte.js';
|
|
4
|
+
|
|
5
|
+
let { class: className = '' }: { class?: string } = $props();
|
|
6
|
+
|
|
7
|
+
onMount(() => initPresets());
|
|
8
|
+
|
|
9
|
+
// Energy glyphs — one arc, four amplitudes (still → liveliest overshoot).
|
|
10
|
+
const arcs: Record<string, number> = { reduced: 0, heavy: 4, active: 8, springy: 12 };
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<div class="row ycenter gap-8 {className}" role="group" aria-label="Motion energy preset">
|
|
14
|
+
{#each presetAxes.motion as motion}
|
|
15
|
+
<button
|
|
16
|
+
type="button"
|
|
17
|
+
class="button ghost"
|
|
18
|
+
class:active={presets.motion === motion}
|
|
19
|
+
aria-pressed={presets.motion === motion}
|
|
20
|
+
title={motion}
|
|
21
|
+
onclick={() => setPreset('motion', motion)}
|
|
22
|
+
>
|
|
23
|
+
<svg width="16" height="16" viewBox="0 0 19 19" aria-hidden="true">
|
|
24
|
+
<path
|
|
25
|
+
d="M3 15 Q9.5 {15 - arcs[motion]} 16 15"
|
|
26
|
+
fill="none"
|
|
27
|
+
stroke="currentColor"
|
|
28
|
+
stroke-width="1.5"
|
|
29
|
+
stroke-linecap="round"
|
|
30
|
+
/>
|
|
31
|
+
</svg>
|
|
32
|
+
</button>
|
|
33
|
+
{/each}
|
|
34
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
|
|
4
|
+
/** The padded content frame, from canonical-markups.md §4. Registry classes only. */
|
|
5
|
+
interface Props {
|
|
6
|
+
children: Snippet;
|
|
7
|
+
class?: string;
|
|
8
|
+
}
|
|
9
|
+
let { children, class: className = '' }: Props = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<section class="page-shell {className}">
|
|
13
|
+
{@render children()}
|
|
14
|
+
</section>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
/** The padded content frame, from canonical-markups.md §4. Registry classes only. */
|
|
3
|
+
interface Props {
|
|
4
|
+
children: Snippet;
|
|
5
|
+
class?: string;
|
|
6
|
+
}
|
|
7
|
+
declare const PageShell: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type PageShell = ReturnType<typeof PageShell>;
|
|
9
|
+
export default PageShell;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The full-bleed master-detail split, from canonical-markups.md §4.
|
|
6
|
+
*
|
|
7
|
+
* `.page-sidebar` and `.page-main` are not decoration: `.page-split` is a
|
|
8
|
+
* grid whose columns are defined for exactly those two children, and the
|
|
9
|
+
* horizontal padding lives in `.page-main` rather than on the split, so the
|
|
10
|
+
* sidebar can sit flush. Getting either wrong loses the layout silently.
|
|
11
|
+
*/
|
|
12
|
+
interface Props {
|
|
13
|
+
/** Explorer / file tree. Hidden below 768px. */
|
|
14
|
+
sidebar?: Snippet;
|
|
15
|
+
children: Snippet;
|
|
16
|
+
class?: string;
|
|
17
|
+
}
|
|
18
|
+
let { sidebar, children, class: className = '' }: Props = $props();
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<section class="page-split {className}">
|
|
22
|
+
{#if sidebar}
|
|
23
|
+
<aside class="page-sidebar">{@render sidebar()}</aside>
|
|
24
|
+
{/if}
|
|
25
|
+
<main class="page-main">{@render children()}</main>
|
|
26
|
+
</section>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
/**
|
|
3
|
+
* The full-bleed master-detail split, from canonical-markups.md §4.
|
|
4
|
+
*
|
|
5
|
+
* `.page-sidebar` and `.page-main` are not decoration: `.page-split` is a
|
|
6
|
+
* grid whose columns are defined for exactly those two children, and the
|
|
7
|
+
* horizontal padding lives in `.page-main` rather than on the split, so the
|
|
8
|
+
* sidebar can sit flush. Getting either wrong loses the layout silently.
|
|
9
|
+
*/
|
|
10
|
+
interface Props {
|
|
11
|
+
/** Explorer / file tree. Hidden below 768px. */
|
|
12
|
+
sidebar?: Snippet;
|
|
13
|
+
children: Snippet;
|
|
14
|
+
class?: string;
|
|
15
|
+
}
|
|
16
|
+
declare const PageSplit: import("svelte").Component<Props, {}, "">;
|
|
17
|
+
type PageSplit = ReturnType<typeof PageSplit>;
|
|
18
|
+
export default PageSplit;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from 'svelte';
|
|
3
|
+
import { presetAxes, presets, initPresets, setPreset } from '../presets.svelte.js';
|
|
4
|
+
|
|
5
|
+
let { class: className = '' }: { class?: string } = $props();
|
|
6
|
+
|
|
7
|
+
onMount(() => initPresets());
|
|
8
|
+
|
|
9
|
+
// Corner glyphs — one square, four geometries; rx mirrors the sm channel.
|
|
10
|
+
const glyphs: Record<string, number> = { sharp: 0, pro: 4, curved: 8, round: 16 };
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<div class="row ycenter gap-8 {className}" role="group" aria-label="Corner shape preset">
|
|
14
|
+
{#each presetAxes.shape as shape}
|
|
15
|
+
<button
|
|
16
|
+
type="button"
|
|
17
|
+
class="button ghost"
|
|
18
|
+
class:active={presets.shape === shape}
|
|
19
|
+
aria-pressed={presets.shape === shape}
|
|
20
|
+
title={shape}
|
|
21
|
+
onclick={() => setPreset('shape', shape)}
|
|
22
|
+
>
|
|
23
|
+
<svg width="16" height="16" viewBox="0 0 19 19" aria-hidden="true">
|
|
24
|
+
<rect
|
|
25
|
+
x="1.5"
|
|
26
|
+
y="1.5"
|
|
27
|
+
width="16"
|
|
28
|
+
height="16"
|
|
29
|
+
rx={glyphs[shape]}
|
|
30
|
+
fill="none"
|
|
31
|
+
stroke="currentColor"
|
|
32
|
+
stroke-width="1.5"
|
|
33
|
+
/>
|
|
34
|
+
</svg>
|
|
35
|
+
</button>
|
|
36
|
+
{/each}
|
|
37
|
+
</div>
|