@motion-proto/live-tokens 0.28.1 → 0.29.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/dist-plugin/{chunk-CUC32QJ2.js → chunk-2TW77U3O.js} +21 -1
- package/dist-plugin/index.cjs +21 -1
- package/dist-plugin/index.js +1 -1
- package/dist-plugin/tokensCssMigrations/index.cjs +21 -1
- package/dist-plugin/tokensCssMigrations/index.js +1 -1
- package/package.json +3 -2
- package/src/editor/component-editor/CardEditor.svelte +72 -9
- package/src/editor/component-editor/ImageEditor.svelte +58 -2
- package/src/editor/component-editor/PanelEditor.svelte +8 -5
- package/src/editor/component-editor/registry.ts +4 -2
- package/src/editor/component-editor/scaffolding/TokenLayout.svelte +6 -1
- package/src/editor/component-editor/scaffolding/VariantGroup.svelte +6 -1
- package/src/editor/ui/variantScales.ts +12 -0
- package/src/system/components/Card.svelte +33 -32
- package/src/system/components/CollapsibleSection.svelte +6 -19
- package/src/system/components/Image.svelte +20 -2
- package/src/system/components/Panel.svelte +1 -1
- package/src/system/styles/CONVENTIONS.md +1 -1
- package/src/system/styles/_slot-prose.scss +52 -0
- package/src/system/styles/fonts.css +4 -6
- package/src/system/styles/tokens.css +7 -0
|
@@ -154,6 +154,25 @@ var tokensCssMigration_2026_05_29_sectiondividerLegacyAxisCleanup = {
|
|
|
154
154
|
}
|
|
155
155
|
};
|
|
156
156
|
|
|
157
|
+
// vite-plugin/tokensCssMigrations/migrations/2026-06-03-transform-scale-additions.ts
|
|
158
|
+
var tokensCssMigration_2026_06_03_transformScaleAdditions = {
|
|
159
|
+
id: "2026-06-03-transform-scale-additions",
|
|
160
|
+
description: "Add the --scale-{sm..2xl} transform-multiplier scale",
|
|
161
|
+
apply(css) {
|
|
162
|
+
return ensureScale(css, {
|
|
163
|
+
sectionComment: "Transform-scale multipliers (e.g. hover zoom). 5% per step.",
|
|
164
|
+
anchorPrefixes: ["--blur-", "--shadow-", "--radius-"],
|
|
165
|
+
entries: [
|
|
166
|
+
{ name: "--scale-sm", value: "1.05" },
|
|
167
|
+
{ name: "--scale-md", value: "1.1" },
|
|
168
|
+
{ name: "--scale-lg", value: "1.15" },
|
|
169
|
+
{ name: "--scale-xl", value: "1.2" },
|
|
170
|
+
{ name: "--scale-2xl", value: "1.25" }
|
|
171
|
+
]
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
157
176
|
// vite-plugin/files/dataPaths.ts
|
|
158
177
|
import fs from "fs";
|
|
159
178
|
import path from "path";
|
|
@@ -203,7 +222,8 @@ function resolveDataDirs(opts = {}) {
|
|
|
203
222
|
// vite-plugin/tokensCssMigrations/index.ts
|
|
204
223
|
var TOKENS_CSS_MIGRATIONS = [
|
|
205
224
|
tokensCssMigration_2026_05_29_typographyScaleAdditions,
|
|
206
|
-
tokensCssMigration_2026_05_29_sectiondividerLegacyAxisCleanup
|
|
225
|
+
tokensCssMigration_2026_05_29_sectiondividerLegacyAxisCleanup,
|
|
226
|
+
tokensCssMigration_2026_06_03_transformScaleAdditions
|
|
207
227
|
];
|
|
208
228
|
function runTokensCssMigrations(css) {
|
|
209
229
|
let out = css;
|
package/dist-plugin/index.cjs
CHANGED
|
@@ -778,10 +778,30 @@ var tokensCssMigration_2026_05_29_sectiondividerLegacyAxisCleanup = {
|
|
|
778
778
|
}
|
|
779
779
|
};
|
|
780
780
|
|
|
781
|
+
// vite-plugin/tokensCssMigrations/migrations/2026-06-03-transform-scale-additions.ts
|
|
782
|
+
var tokensCssMigration_2026_06_03_transformScaleAdditions = {
|
|
783
|
+
id: "2026-06-03-transform-scale-additions",
|
|
784
|
+
description: "Add the --scale-{sm..2xl} transform-multiplier scale",
|
|
785
|
+
apply(css) {
|
|
786
|
+
return ensureScale(css, {
|
|
787
|
+
sectionComment: "Transform-scale multipliers (e.g. hover zoom). 5% per step.",
|
|
788
|
+
anchorPrefixes: ["--blur-", "--shadow-", "--radius-"],
|
|
789
|
+
entries: [
|
|
790
|
+
{ name: "--scale-sm", value: "1.05" },
|
|
791
|
+
{ name: "--scale-md", value: "1.1" },
|
|
792
|
+
{ name: "--scale-lg", value: "1.15" },
|
|
793
|
+
{ name: "--scale-xl", value: "1.2" },
|
|
794
|
+
{ name: "--scale-2xl", value: "1.25" }
|
|
795
|
+
]
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
|
|
781
800
|
// vite-plugin/tokensCssMigrations/index.ts
|
|
782
801
|
var TOKENS_CSS_MIGRATIONS = [
|
|
783
802
|
tokensCssMigration_2026_05_29_typographyScaleAdditions,
|
|
784
|
-
tokensCssMigration_2026_05_29_sectiondividerLegacyAxisCleanup
|
|
803
|
+
tokensCssMigration_2026_05_29_sectiondividerLegacyAxisCleanup,
|
|
804
|
+
tokensCssMigration_2026_06_03_transformScaleAdditions
|
|
785
805
|
];
|
|
786
806
|
function runTokensCssMigrations(css) {
|
|
787
807
|
let out = css;
|
package/dist-plugin/index.js
CHANGED
|
@@ -199,6 +199,25 @@ var tokensCssMigration_2026_05_29_sectiondividerLegacyAxisCleanup = {
|
|
|
199
199
|
}
|
|
200
200
|
};
|
|
201
201
|
|
|
202
|
+
// vite-plugin/tokensCssMigrations/migrations/2026-06-03-transform-scale-additions.ts
|
|
203
|
+
var tokensCssMigration_2026_06_03_transformScaleAdditions = {
|
|
204
|
+
id: "2026-06-03-transform-scale-additions",
|
|
205
|
+
description: "Add the --scale-{sm..2xl} transform-multiplier scale",
|
|
206
|
+
apply(css) {
|
|
207
|
+
return ensureScale(css, {
|
|
208
|
+
sectionComment: "Transform-scale multipliers (e.g. hover zoom). 5% per step.",
|
|
209
|
+
anchorPrefixes: ["--blur-", "--shadow-", "--radius-"],
|
|
210
|
+
entries: [
|
|
211
|
+
{ name: "--scale-sm", value: "1.05" },
|
|
212
|
+
{ name: "--scale-md", value: "1.1" },
|
|
213
|
+
{ name: "--scale-lg", value: "1.15" },
|
|
214
|
+
{ name: "--scale-xl", value: "1.2" },
|
|
215
|
+
{ name: "--scale-2xl", value: "1.25" }
|
|
216
|
+
]
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
202
221
|
// vite-plugin/files/dataPaths.ts
|
|
203
222
|
var import_fs = __toESM(require("fs"), 1);
|
|
204
223
|
var import_path = __toESM(require("path"), 1);
|
|
@@ -235,7 +254,8 @@ function readLiveTokensConfig() {
|
|
|
235
254
|
// vite-plugin/tokensCssMigrations/index.ts
|
|
236
255
|
var TOKENS_CSS_MIGRATIONS = [
|
|
237
256
|
tokensCssMigration_2026_05_29_typographyScaleAdditions,
|
|
238
|
-
tokensCssMigration_2026_05_29_sectiondividerLegacyAxisCleanup
|
|
257
|
+
tokensCssMigration_2026_05_29_sectiondividerLegacyAxisCleanup,
|
|
258
|
+
tokensCssMigration_2026_06_03_transformScaleAdditions
|
|
239
259
|
];
|
|
240
260
|
function runTokensCssMigrations(css) {
|
|
241
261
|
let out = css;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@motion-proto/live-tokens",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Design token editor with live CSS variable editing. Svelte 5 + Vite 8.",
|
|
6
6
|
"keywords": [
|
|
@@ -94,6 +94,7 @@
|
|
|
94
94
|
"build:lib": "npm run build:plugin",
|
|
95
95
|
"deploy:local": "bash scripts/deploy-local.sh",
|
|
96
96
|
"check:no-style-imports": "node scripts/check-no-style-imports.mjs",
|
|
97
|
+
"check:slot-prose": "node scripts/check-slot-prose.mjs",
|
|
97
98
|
"check:editor-font-isolation": "node scripts/check-editor-font-isolation.mjs",
|
|
98
99
|
"check:component-defaults": "node scripts/sync-component-defaults.mjs --check",
|
|
99
100
|
"check:production-is-default": "node scripts/check-production-is-default.mjs",
|
|
@@ -103,7 +104,7 @@
|
|
|
103
104
|
"collapse:manifest": "node scripts/collapse-manifest-to-default.mjs",
|
|
104
105
|
"check:smoke-install": "bash scripts/smoke-install.sh",
|
|
105
106
|
"check:smoke-create": "bash scripts/smoke-create.sh",
|
|
106
|
-
"prepublishOnly": "npm run check:no-style-imports && npm run check:editor-font-isolation && npm run check:component-defaults && npm run check:production-is-default && npm run check:docs-content && npm run build:lib && npm run check:smoke-install && npm run check:smoke-create"
|
|
107
|
+
"prepublishOnly": "npm run check:no-style-imports && npm run check:slot-prose && npm run check:editor-font-isolation && npm run check:component-defaults && npm run check:production-is-default && npm run check:docs-content && npm run build:lib && npm run check:smoke-install && npm run check:smoke-create"
|
|
107
108
|
},
|
|
108
109
|
"peerDependencies": {
|
|
109
110
|
"@sveltejs/vite-plugin-svelte": "^7.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
2
|
import { buildTypeGroupColorTokens } from './scaffolding/buildTypeGroupTokens';
|
|
3
|
-
import type { Token, TypeGroupConfig } from './scaffolding/types';
|
|
3
|
+
import type { Token, TypeGroupConfig, IntrinsicSpec } from './scaffolding/types';
|
|
4
4
|
|
|
5
5
|
export const component = 'card';
|
|
6
6
|
|
|
@@ -83,13 +83,34 @@
|
|
|
83
83
|
...buildTypeGroupColorTokens(typeGroups, { component, variants: ['default'] }),
|
|
84
84
|
...typeGroupTokens,
|
|
85
85
|
];
|
|
86
|
+
|
|
87
|
+
// Global "Use hover" default. The two `*-active` vars flip together: off = resting
|
|
88
|
+
// tokens (no visible hover), on = the `--card-hover-*` tokens. Stored per-component.
|
|
89
|
+
const HOVER_OFF = { border: 'var(--card-default-border)', shadow: 'var(--card-default-shadow)' };
|
|
90
|
+
const HOVER_ON = { border: 'var(--card-hover-border)', shadow: 'var(--card-hover-shadow)' };
|
|
91
|
+
export const intrinsics: IntrinsicSpec[] = [
|
|
92
|
+
{
|
|
93
|
+
key: 'hover-border',
|
|
94
|
+
variants: ['default'],
|
|
95
|
+
variable: () => '--card-hover-border-active',
|
|
96
|
+
values: [HOVER_OFF.border, HOVER_ON.border],
|
|
97
|
+
default: { default: HOVER_OFF.border },
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
key: 'hover-shadow',
|
|
101
|
+
variants: ['default'],
|
|
102
|
+
variable: () => '--card-hover-shadow-active',
|
|
103
|
+
values: [HOVER_OFF.shadow, HOVER_ON.shadow],
|
|
104
|
+
default: { default: HOVER_OFF.shadow },
|
|
105
|
+
},
|
|
106
|
+
];
|
|
86
107
|
</script>
|
|
87
108
|
|
|
88
109
|
<script lang="ts">
|
|
89
110
|
import Card from '../../system/components/Card.svelte';
|
|
90
111
|
import VariantGroup from './scaffolding/VariantGroup.svelte';
|
|
91
112
|
import ComponentEditorBase from './scaffolding/ComponentEditorBase.svelte';
|
|
92
|
-
import { editorState } from '../core/store/editorStore';
|
|
113
|
+
import { editorState, setComponentAlias } from '../core/store/editorStore';
|
|
93
114
|
import { computeLinkedBlock, withLinkedDisabled } from './scaffolding/linkedBlock';
|
|
94
115
|
let linked = $derived(computeLinkedBlock(component, linkableContexts, allTokens, $editorState));
|
|
95
116
|
|
|
@@ -97,7 +118,20 @@
|
|
|
97
118
|
Object.entries(states).map(([name, list]) => [name, withLinkedDisabled(list, linked.varSet)]),
|
|
98
119
|
) as Record<string, Token[]>);
|
|
99
120
|
|
|
100
|
-
let
|
|
121
|
+
let aliases = $derived(
|
|
122
|
+
($editorState.components[component]?.aliases ?? {}) as Record<string, import('../core/store/editorTypes').CssVarRef>,
|
|
123
|
+
);
|
|
124
|
+
let hoverEnabled = $derived.by(() => {
|
|
125
|
+
const ref = aliases['--card-hover-border-active'];
|
|
126
|
+
const raw = ref?.kind === 'literal' ? ref.value : HOVER_OFF.border;
|
|
127
|
+
return raw === HOVER_ON.border;
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
function setHoverEnabled(checked: boolean) {
|
|
131
|
+
const v = checked ? HOVER_ON : HOVER_OFF;
|
|
132
|
+
setComponentAlias(component, '--card-hover-border-active', { kind: 'literal', value: v.border });
|
|
133
|
+
setComponentAlias(component, '--card-hover-shadow-active', { kind: 'literal', value: v.shadow });
|
|
134
|
+
}
|
|
101
135
|
</script>
|
|
102
136
|
|
|
103
137
|
<ComponentEditorBase {component} title="Card" description="Generic card with icon, title, and slotted body." tokens={allTokens} {linked}>
|
|
@@ -110,17 +144,23 @@
|
|
|
110
144
|
>
|
|
111
145
|
{#snippet stateActions(stateName)}
|
|
112
146
|
{#if stateName === 'hover'}
|
|
113
|
-
<
|
|
114
|
-
<
|
|
115
|
-
|
|
116
|
-
|
|
147
|
+
<div class="hover-control">
|
|
148
|
+
<label class="hover-enable">
|
|
149
|
+
<input type="checkbox" checked={hoverEnabled} onchange={(e) => setHoverEnabled(e.currentTarget.checked)} />
|
|
150
|
+
<span>Use hover</span>
|
|
151
|
+
</label>
|
|
152
|
+
<p class="hover-help">
|
|
153
|
+
Checked: every card lifts on hover. Unchecked: hover is off by default and a page turns it on
|
|
154
|
+
per card with the <code>hover</code> prop.
|
|
155
|
+
</p>
|
|
156
|
+
</div>
|
|
117
157
|
{/if}
|
|
118
158
|
{/snippet}
|
|
119
159
|
{#snippet children({ activeState })}
|
|
120
|
-
{@const previewClass = activeState === 'hover' ? 'force-hover' :
|
|
160
|
+
{@const previewClass = activeState === 'hover' ? 'force-hover' : ''}
|
|
121
161
|
<div class="card-demo">
|
|
122
162
|
<Card title="Card title" class={previewClass}>
|
|
123
|
-
<
|
|
163
|
+
<div class="content-placeholder">Content Placeholder</div>
|
|
124
164
|
</Card>
|
|
125
165
|
</div>
|
|
126
166
|
{/snippet}
|
|
@@ -129,6 +169,21 @@
|
|
|
129
169
|
|
|
130
170
|
<style>
|
|
131
171
|
.card-demo {
|
|
172
|
+
min-width: 16rem;
|
|
173
|
+
max-width: 28rem;
|
|
174
|
+
}
|
|
175
|
+
.content-placeholder {
|
|
176
|
+
display: flex;
|
|
177
|
+
align-items: center;
|
|
178
|
+
justify-content: center;
|
|
179
|
+
width: 100%;
|
|
180
|
+
min-height: 6rem;
|
|
181
|
+
background: color-mix(in srgb, white 8%, transparent);
|
|
182
|
+
border-radius: var(--ui-radius-sm);
|
|
183
|
+
font-size: var(--ui-font-size-sm);
|
|
184
|
+
color: var(--ui-text-secondary);
|
|
185
|
+
}
|
|
186
|
+
.hover-control {
|
|
132
187
|
max-width: 28rem;
|
|
133
188
|
}
|
|
134
189
|
.hover-enable {
|
|
@@ -139,4 +194,12 @@
|
|
|
139
194
|
color: var(--ui-text-secondary);
|
|
140
195
|
cursor: pointer;
|
|
141
196
|
}
|
|
197
|
+
.hover-help {
|
|
198
|
+
margin: var(--ui-space-4) 0 0;
|
|
199
|
+
font-size: var(--ui-font-size-sm);
|
|
200
|
+
color: var(--ui-text-tertiary);
|
|
201
|
+
}
|
|
202
|
+
.hover-help code {
|
|
203
|
+
font-family: var(--ui-font-mono);
|
|
204
|
+
}
|
|
142
205
|
</style>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
|
-
import type { Token } from './scaffolding/types';
|
|
2
|
+
import type { Token, IntrinsicSpec } from './scaffolding/types';
|
|
3
3
|
|
|
4
4
|
export const component = 'image';
|
|
5
5
|
|
|
@@ -10,10 +10,23 @@
|
|
|
10
10
|
{ label: 'border width', groupKey: 'width', variable: '--image-default-border-width' },
|
|
11
11
|
{ label: 'corner radius', groupKey: 'radius', variable: '--image-default-radius' },
|
|
12
12
|
{ label: 'image shadow', groupKey: 'shadow', variable: '--image-default-shadow' },
|
|
13
|
+
{ label: 'zoom amount', groupKey: 'scale', variable: '--image-zoom-scale' },
|
|
13
14
|
],
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
export const allTokens: Token[] = Object.values(states).flat();
|
|
18
|
+
|
|
19
|
+
// Global "Use zoom" default. `none` = off; `scale(...)` = every image zooms on hover.
|
|
20
|
+
const ZOOM_ON = 'scale(var(--image-zoom-scale))';
|
|
21
|
+
export const intrinsics: IntrinsicSpec[] = [
|
|
22
|
+
{
|
|
23
|
+
key: 'zoom',
|
|
24
|
+
variants: ['default'],
|
|
25
|
+
variable: () => '--image-zoom-hover',
|
|
26
|
+
values: ['none', ZOOM_ON],
|
|
27
|
+
default: { default: 'none' },
|
|
28
|
+
},
|
|
29
|
+
];
|
|
17
30
|
</script>
|
|
18
31
|
|
|
19
32
|
<script lang="ts">
|
|
@@ -21,10 +34,53 @@
|
|
|
21
34
|
import VariantGroup from './scaffolding/VariantGroup.svelte';
|
|
22
35
|
import ComponentEditorBase from './scaffolding/ComponentEditorBase.svelte';
|
|
23
36
|
import demoImageUrl from '../../system/assets/offering.webp';
|
|
37
|
+
import { editorState, setComponentAlias } from '../core/store/editorStore';
|
|
38
|
+
|
|
39
|
+
let aliases = $derived(
|
|
40
|
+
($editorState.components[component]?.aliases ?? {}) as Record<string, import('../core/store/editorTypes').CssVarRef>,
|
|
41
|
+
);
|
|
42
|
+
let useZoom = $derived.by(() => {
|
|
43
|
+
const ref = aliases['--image-zoom-hover'];
|
|
44
|
+
const raw = ref?.kind === 'literal' ? ref.value : intrinsics[0].default.default;
|
|
45
|
+
return raw === ZOOM_ON;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
function setUseZoom(checked: boolean) {
|
|
49
|
+
setComponentAlias(component, '--image-zoom-hover', { kind: 'literal', value: checked ? ZOOM_ON : 'none' });
|
|
50
|
+
}
|
|
24
51
|
</script>
|
|
25
52
|
|
|
26
53
|
<ComponentEditorBase {component} title="Image" description="Framed image with rounded corners, border, and shadow." tokens={allTokens}>
|
|
27
54
|
<VariantGroup name="image" title="Image" {states} {component}>
|
|
28
|
-
|
|
55
|
+
{#snippet stateActions()}
|
|
56
|
+
<label class="zoom-enable">
|
|
57
|
+
<input type="checkbox" checked={useZoom} onchange={(e) => setUseZoom(e.currentTarget.checked)} />
|
|
58
|
+
<span>Use zoom on hover</span>
|
|
59
|
+
</label>
|
|
60
|
+
{/snippet}
|
|
61
|
+
<Image src={demoImageUrl} alt="Demo" variant="banner" zoom={useZoom ? undefined : false} />
|
|
62
|
+
<p class="zoom-help">
|
|
63
|
+
Checked: every image zooms its contents on hover. Unchecked: zoom is off by default and a page turns it
|
|
64
|
+
on per image with the <code>zoom</code> prop.
|
|
65
|
+
</p>
|
|
29
66
|
</VariantGroup>
|
|
30
67
|
</ComponentEditorBase>
|
|
68
|
+
|
|
69
|
+
<style>
|
|
70
|
+
.zoom-enable {
|
|
71
|
+
display: inline-flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
gap: var(--ui-space-4);
|
|
74
|
+
font-size: var(--ui-font-size-sm);
|
|
75
|
+
color: var(--ui-text-secondary);
|
|
76
|
+
cursor: pointer;
|
|
77
|
+
}
|
|
78
|
+
.zoom-help {
|
|
79
|
+
margin: var(--ui-space-8) 0 0;
|
|
80
|
+
font-size: var(--ui-font-size-sm);
|
|
81
|
+
color: var(--ui-text-tertiary);
|
|
82
|
+
}
|
|
83
|
+
.zoom-help code {
|
|
84
|
+
font-family: var(--ui-font-mono);
|
|
85
|
+
}
|
|
86
|
+
</style>
|
|
@@ -58,8 +58,7 @@
|
|
|
58
58
|
{#snippet children()}
|
|
59
59
|
<div class="panel-demo">
|
|
60
60
|
<Panel minHeight="6rem">
|
|
61
|
-
<
|
|
62
|
-
<span class="demo-chip">Stage content</span>
|
|
61
|
+
<div class="content-placeholder">Content Placeholder</div>
|
|
63
62
|
</Panel>
|
|
64
63
|
</div>
|
|
65
64
|
{/snippet}
|
|
@@ -71,9 +70,13 @@
|
|
|
71
70
|
width: 100%;
|
|
72
71
|
max-width: 34rem;
|
|
73
72
|
}
|
|
74
|
-
.
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
.content-placeholder {
|
|
74
|
+
display: flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
justify-content: center;
|
|
77
|
+
align-self: stretch;
|
|
78
|
+
width: 100%;
|
|
79
|
+
background: color-mix(in srgb, white 8%, transparent);
|
|
77
80
|
border-radius: var(--ui-radius-sm);
|
|
78
81
|
font-size: var(--ui-font-size-sm);
|
|
79
82
|
color: var(--ui-text-secondary);
|
|
@@ -6,11 +6,11 @@ import BadgeEditor, { allTokens as badgeTokens } from './BadgeEditor.svelte';
|
|
|
6
6
|
import CalloutEditor, { allTokens as calloutTokens } from './CalloutEditor.svelte';
|
|
7
7
|
import CornerBadgeEditor, { allTokens as cornerBadgeTokens } from './CornerBadgeEditor.svelte';
|
|
8
8
|
import ButtonEditor, { allTokens as buttonTokens } from './ButtonEditor.svelte';
|
|
9
|
-
import CardEditor, { allTokens as cardTokens } from './CardEditor.svelte';
|
|
9
|
+
import CardEditor, { allTokens as cardTokens, intrinsics as cardIntrinsics } from './CardEditor.svelte';
|
|
10
10
|
import CodeSnippetEditor, { allTokens as codeSnippetTokens } from './CodeSnippetEditor.svelte';
|
|
11
11
|
import CollapsibleSectionEditor, { allTokens as collapsibleSectionTokens } from './CollapsibleSectionEditor.svelte';
|
|
12
12
|
import DialogEditor, { allTokens as dialogTokens } from './DialogEditor.svelte';
|
|
13
|
-
import ImageEditor, { allTokens as imageTokens } from './ImageEditor.svelte';
|
|
13
|
+
import ImageEditor, { allTokens as imageTokens, intrinsics as imageIntrinsics } from './ImageEditor.svelte';
|
|
14
14
|
import ImageLightboxEditor, { allTokens as imageLightboxTokens } from './ImageLightboxEditor.svelte';
|
|
15
15
|
import InlineEditActionsEditor, { allTokens as inlineEditActionsTokens } from './InlineEditActionsEditor.svelte';
|
|
16
16
|
import InputEditor, { allTokens as inputTokens } from './InputEditor.svelte';
|
|
@@ -142,6 +142,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
|
|
|
142
142
|
sourceFile: 'src/system/components/Card.svelte',
|
|
143
143
|
editorComponent: CardEditor,
|
|
144
144
|
schema: cardTokens,
|
|
145
|
+
intrinsics: cardIntrinsics,
|
|
145
146
|
origin: 'system',
|
|
146
147
|
},
|
|
147
148
|
badge: {
|
|
@@ -187,6 +188,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
|
|
|
187
188
|
sourceFile: 'src/system/components/Image.svelte',
|
|
188
189
|
editorComponent: ImageEditor,
|
|
189
190
|
schema: imageTokens,
|
|
191
|
+
intrinsics: imageIntrinsics,
|
|
190
192
|
origin: 'system',
|
|
191
193
|
},
|
|
192
194
|
imagelightbox: {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import UIPaddingSelector from '../../ui/UIPaddingSelector.svelte';
|
|
10
10
|
import UILetterSpacingSelector from '../../ui/UILetterSpacingSelector.svelte';
|
|
11
11
|
import UIEasingSelector from '../../ui/UIEasingSelector.svelte';
|
|
12
|
-
import { BLUR, BORDER_WIDTH, DOT_SIZE, DURATION, RADIUS, SHADOW, DIVIDER_HEIGHT, DIVIDER_INSET } from '../../ui/variantScales';
|
|
12
|
+
import { BLUR, BORDER_WIDTH, DOT_SIZE, DURATION, RADIUS, SCALE, SHADOW, DIVIDER_HEIGHT, DIVIDER_INSET } from '../../ui/variantScales';
|
|
13
13
|
import {
|
|
14
14
|
editorState,
|
|
15
15
|
getComponentPropertySiblings,
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
| 'divider-inset'
|
|
32
32
|
| 'dot-size'
|
|
33
33
|
| 'blur'
|
|
34
|
+
| 'scale'
|
|
34
35
|
| 'shadow'
|
|
35
36
|
| 'font-family'
|
|
36
37
|
| 'font-weight'
|
|
@@ -99,6 +100,7 @@
|
|
|
99
100
|
{ kind: 'divider-inset', matches: (v) => v.endsWith('-divider-inset') },
|
|
100
101
|
{ kind: 'dot-size', matches: (v) => v.endsWith('-dot-size') },
|
|
101
102
|
{ kind: 'blur', matches: (v) => v.endsWith('-blur') || v.startsWith('--blur-') },
|
|
103
|
+
{ kind: 'scale', matches: (v) => v.endsWith('-scale') || v.startsWith('--scale-') },
|
|
102
104
|
{ kind: 'shadow', matches: (v) => v.endsWith('-shadow') || v.startsWith('--shadow-') },
|
|
103
105
|
{ kind: 'padding', matches: (v) => v.endsWith('-padding') || v.endsWith('-margin') },
|
|
104
106
|
{ kind: 'gap', matches: (v) => v.endsWith('-gap') },
|
|
@@ -134,6 +136,7 @@
|
|
|
134
136
|
'duration',
|
|
135
137
|
'easing',
|
|
136
138
|
'blur',
|
|
139
|
+
'scale',
|
|
137
140
|
'shadow',
|
|
138
141
|
'text-color',
|
|
139
142
|
'surface',
|
|
@@ -205,6 +208,7 @@
|
|
|
205
208
|
'duration': { component: UIVariantSelector, extra: () => ({ ...DURATION }) },
|
|
206
209
|
'easing': { component: UIEasingSelector },
|
|
207
210
|
'blur': { component: UIVariantSelector, extra: () => ({ ...BLUR }) },
|
|
211
|
+
'scale': { component: UIVariantSelector, extra: () => ({ ...SCALE }) },
|
|
208
212
|
'shadow': { component: UIVariantSelector, extra: () => ({ ...SHADOW }) },
|
|
209
213
|
'surface': { component: UIPaletteSelector },
|
|
210
214
|
'border': { component: UIPaletteSelector },
|
|
@@ -234,6 +238,7 @@
|
|
|
234
238
|
'duration',
|
|
235
239
|
'easing',
|
|
236
240
|
'blur',
|
|
241
|
+
'scale',
|
|
237
242
|
'shadow',
|
|
238
243
|
'surface',
|
|
239
244
|
'border-width',
|
|
@@ -804,15 +804,20 @@
|
|
|
804
804
|
gap: var(--ui-space-8);
|
|
805
805
|
}
|
|
806
806
|
|
|
807
|
+
/* Baseline (not center) so a tall stateActions block — e.g. a checkbox with a
|
|
808
|
+
wrapping help paragraph — keeps the part strip and its first line pinned at
|
|
809
|
+
the top and grows downward, pushing Properties down rather than recentering
|
|
810
|
+
the strip and shifting it on every state switch. */
|
|
807
811
|
.tabs-selectors {
|
|
808
812
|
display: flex;
|
|
809
|
-
align-items:
|
|
813
|
+
align-items: baseline;
|
|
810
814
|
gap: var(--ui-space-12);
|
|
811
815
|
}
|
|
812
816
|
|
|
813
817
|
/* Sub-strip sits flush under the parts strip when a part has interaction states.
|
|
814
818
|
The eyebrow label distinguishes it from the parts row above. */
|
|
815
819
|
.tabs-selectors.substrip {
|
|
820
|
+
align-items: center;
|
|
816
821
|
margin-top: var(--ui-space-6);
|
|
817
822
|
}
|
|
818
823
|
.tabs-selectors.substrip .state-eyebrow {
|
|
@@ -33,6 +33,18 @@ export const BLUR: VariantScaleEntry = {
|
|
|
33
33
|
],
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
+
/** Transform-scale multipliers (e.g. image zoom-on-hover). 5% per step. */
|
|
37
|
+
export const SCALE: VariantScaleEntry = {
|
|
38
|
+
varPrefix: '--scale-',
|
|
39
|
+
options: [
|
|
40
|
+
{ key: 'sm', label: 'Small', value: '1.05' },
|
|
41
|
+
{ key: 'md', label: 'Medium', value: '1.1' },
|
|
42
|
+
{ key: 'lg', label: 'Large', value: '1.15' },
|
|
43
|
+
{ key: 'xl', label: 'X-Large', value: '1.2' },
|
|
44
|
+
{ key: '2xl', label: '2X-Large', value: '1.25' },
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
|
|
36
48
|
export const BORDER_WIDTH: VariantScaleEntry = {
|
|
37
49
|
varPrefix: '--border-width-',
|
|
38
50
|
options: [
|
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
iconColor?: string;
|
|
5
5
|
title?: string;
|
|
6
6
|
size?: 'default' | 'compact';
|
|
7
|
+
/** false → the card stops pinning body typography so the consumer fully owns slotted content's styling. */
|
|
8
|
+
prose?: boolean;
|
|
9
|
+
/** Apply hover styling on pointer-over. `undefined` inherits the editor's global "Use hover"
|
|
10
|
+
default; `true`/`false` force this instance on/off. */
|
|
11
|
+
hover?: boolean | undefined;
|
|
7
12
|
class?: string;
|
|
8
13
|
children?: import('svelte').Snippet;
|
|
9
14
|
}
|
|
@@ -13,16 +18,27 @@
|
|
|
13
18
|
iconColor = 'var(--text-secondary)',
|
|
14
19
|
title = '',
|
|
15
20
|
size = 'default',
|
|
21
|
+
prose = true,
|
|
22
|
+
hover = undefined,
|
|
16
23
|
class: className = '',
|
|
17
24
|
children
|
|
18
25
|
}: Props = $props();
|
|
19
|
-
|
|
26
|
+
|
|
27
|
+
// Per-instance override of the global hover intrinsic; undefined leaves :root in charge.
|
|
28
|
+
let hoverBorder = $derived(
|
|
29
|
+
hover === undefined ? undefined : hover ? 'var(--card-hover-border)' : 'var(--card-default-border)',
|
|
30
|
+
);
|
|
31
|
+
let hoverShadow = $derived(
|
|
32
|
+
hover === undefined ? undefined : hover ? 'var(--card-hover-shadow)' : 'var(--card-default-shadow)',
|
|
33
|
+
);
|
|
20
34
|
</script>
|
|
21
35
|
|
|
22
36
|
<div
|
|
23
37
|
class="card {className}"
|
|
24
38
|
class:compact={size === 'compact'}
|
|
25
|
-
style
|
|
39
|
+
style:--card-color={iconColor}
|
|
40
|
+
style:--card-hover-border-active={hoverBorder}
|
|
41
|
+
style:--card-hover-shadow-active={hoverShadow}
|
|
26
42
|
>
|
|
27
43
|
{#if icon || title}
|
|
28
44
|
<div class="card-header">
|
|
@@ -34,13 +50,14 @@
|
|
|
34
50
|
{/if}
|
|
35
51
|
</div>
|
|
36
52
|
{/if}
|
|
37
|
-
<div class="card-body">
|
|
53
|
+
<div class="card-body" class:prose>
|
|
38
54
|
{@render children?.()}
|
|
39
55
|
</div>
|
|
40
56
|
</div>
|
|
41
57
|
|
|
42
58
|
<style lang="scss">
|
|
43
59
|
@use '../styles/padding' as *;
|
|
60
|
+
@use '../styles/slot-prose' as *;
|
|
44
61
|
|
|
45
62
|
:global(:root) {
|
|
46
63
|
--card-default-surface: color-mix(in srgb, var(--surface-neutral-lower) 70%, transparent);
|
|
@@ -78,6 +95,12 @@
|
|
|
78
95
|
|
|
79
96
|
--card-hover-border: var(--border-neutral-strong);
|
|
80
97
|
--card-hover-shadow: var(--shadow-md);
|
|
98
|
+
|
|
99
|
+
/* Global "Use hover" intrinsic: the active hover values default to the resting
|
|
100
|
+
tokens (hover off). The editor checkbox / a per-instance `hover` prop swap
|
|
101
|
+
these to the `--card-hover-*` tokens to turn hover on. */
|
|
102
|
+
--card-hover-border-active: var(--card-default-border);
|
|
103
|
+
--card-hover-shadow-active: var(--card-default-shadow);
|
|
81
104
|
}
|
|
82
105
|
|
|
83
106
|
.card {
|
|
@@ -92,7 +115,12 @@
|
|
|
92
115
|
overflow: hidden;
|
|
93
116
|
}
|
|
94
117
|
|
|
95
|
-
.card:
|
|
118
|
+
.card:hover {
|
|
119
|
+
border-color: var(--card-hover-border-active);
|
|
120
|
+
box-shadow: var(--card-hover-shadow-active);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* Editor preview hook: paint hover tokens directly, ignoring the on/off gate. */
|
|
96
124
|
.card.force-hover {
|
|
97
125
|
border-color: var(--card-hover-border);
|
|
98
126
|
box-shadow: var(--card-hover-shadow);
|
|
@@ -139,35 +167,8 @@
|
|
|
139
167
|
font-weight: var(--card-default-body-font-weight);
|
|
140
168
|
line-height: var(--card-default-body-line-height);
|
|
141
169
|
@include themed-padding(--card-default-body-padding);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/* Slot content inherits the card's body typography so consumer-side global
|
|
145
|
-
element rules (e.g. site.css `p { font-family: serif }`) don't override
|
|
146
|
-
the card-body-font-family alias. */
|
|
147
|
-
.card-body :global(p),
|
|
148
|
-
.card-body :global(ul),
|
|
149
|
-
.card-body :global(ol),
|
|
150
|
-
.card-body :global(li) {
|
|
151
|
-
font: inherit;
|
|
152
|
-
color: inherit;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
.card-body :global(p) {
|
|
156
|
-
margin: 0 0 var(--space-12);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.card-body :global(p:last-child) {
|
|
160
|
-
margin-bottom: 0;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
.card-body :global(ul),
|
|
164
|
-
.card-body :global(ol) {
|
|
165
|
-
margin: var(--space-12) 0;
|
|
166
|
-
padding-left: var(--space-24);
|
|
167
|
-
}
|
|
168
170
|
|
|
169
|
-
|
|
170
|
-
margin-bottom: var(--space-4);
|
|
171
|
+
@include slot-prose;
|
|
171
172
|
}
|
|
172
173
|
|
|
173
174
|
.card.compact .card-body {
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
expanded?: boolean;
|
|
7
7
|
href?: string | undefined;
|
|
8
8
|
variant?: 'chromeless' | 'divider' | 'container';
|
|
9
|
+
/** false → the section stops pinning body typography so the consumer fully owns slotted content's styling. */
|
|
10
|
+
prose?: boolean;
|
|
9
11
|
class?: string;
|
|
10
12
|
/** Toggle callback. Preferred over `on:toggle` from 0.5.0 onward. */
|
|
11
13
|
ontoggle?: () => void;
|
|
@@ -18,6 +20,7 @@
|
|
|
18
20
|
expanded = false,
|
|
19
21
|
href = undefined,
|
|
20
22
|
variant = 'container',
|
|
23
|
+
prose = true,
|
|
21
24
|
class: className = '',
|
|
22
25
|
ontoggle,
|
|
23
26
|
summary,
|
|
@@ -67,7 +70,7 @@
|
|
|
67
70
|
</div>
|
|
68
71
|
{/if}
|
|
69
72
|
{#if expanded && children}
|
|
70
|
-
<div class="section-content">
|
|
73
|
+
<div class="section-content" class:prose>
|
|
71
74
|
{@render children?.()}
|
|
72
75
|
</div>
|
|
73
76
|
{/if}
|
|
@@ -75,6 +78,7 @@
|
|
|
75
78
|
|
|
76
79
|
<style lang="scss">
|
|
77
80
|
@use '../styles/padding' as *;
|
|
81
|
+
@use '../styles/slot-prose' as *;
|
|
78
82
|
|
|
79
83
|
:global(:root) {
|
|
80
84
|
/* Chromeless — default */
|
|
@@ -285,24 +289,7 @@
|
|
|
285
289
|
color: var(--text-secondary);
|
|
286
290
|
font-size: var(--font-size-md);
|
|
287
291
|
line-height: var(--line-height-md);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/* Slot content inherits the section's body typography so consumer-side
|
|
291
|
-
global element rules (e.g. site.css `p { font-family: serif }`) don't
|
|
292
|
-
override the collapsible's intended type styling. */
|
|
293
|
-
.section-content :global(p),
|
|
294
|
-
.section-content :global(ul),
|
|
295
|
-
.section-content :global(ol),
|
|
296
|
-
.section-content :global(li) {
|
|
297
|
-
font: inherit;
|
|
298
|
-
color: inherit;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
.section-content :global(p) {
|
|
302
|
-
margin: 0 0 var(--space-12);
|
|
303
|
-
}
|
|
304
292
|
|
|
305
|
-
|
|
306
|
-
margin-bottom: 0;
|
|
293
|
+
@include slot-prose;
|
|
307
294
|
}
|
|
308
295
|
</style>
|
|
@@ -4,13 +4,17 @@
|
|
|
4
4
|
alt: string;
|
|
5
5
|
variant?: 'default' | 'banner' | 'medium' | 'compact';
|
|
6
6
|
height?: string | undefined;
|
|
7
|
+
/** Zoom the contents on hover (frame stays fixed). `undefined` inherits the editor's
|
|
8
|
+
global "Use zoom" default; `true`/`false` force this instance on/off. */
|
|
9
|
+
zoom?: boolean | undefined;
|
|
7
10
|
}
|
|
8
11
|
|
|
9
12
|
let {
|
|
10
13
|
src,
|
|
11
14
|
alt,
|
|
12
15
|
variant = 'default',
|
|
13
|
-
height = undefined
|
|
16
|
+
height = undefined,
|
|
17
|
+
zoom = undefined
|
|
14
18
|
}: Props = $props();
|
|
15
19
|
|
|
16
20
|
const variantHeights: Record<string, string | undefined> = {
|
|
@@ -21,9 +25,14 @@
|
|
|
21
25
|
};
|
|
22
26
|
|
|
23
27
|
let resolvedHeight = $derived(height ?? variantHeights[variant]);
|
|
28
|
+
|
|
29
|
+
// Per-instance override of the global zoom intrinsic; undefined leaves :root in charge.
|
|
30
|
+
let zoomOverride = $derived(
|
|
31
|
+
zoom === undefined ? undefined : zoom ? 'scale(var(--image-zoom-scale))' : 'none',
|
|
32
|
+
);
|
|
24
33
|
</script>
|
|
25
34
|
|
|
26
|
-
<div class="image" style:height={resolvedHeight}>
|
|
35
|
+
<div class="image" style:height={resolvedHeight} style:--image-zoom-hover={zoomOverride}>
|
|
27
36
|
<img {src} {alt} />
|
|
28
37
|
</div>
|
|
29
38
|
|
|
@@ -33,6 +42,9 @@
|
|
|
33
42
|
--image-default-border: var(--border-neutral);
|
|
34
43
|
--image-default-border-width: var(--border-width-1);
|
|
35
44
|
--image-default-shadow: var(--shadow-md);
|
|
45
|
+
--image-zoom-scale: var(--scale-sm);
|
|
46
|
+
/* Global "Use zoom" intrinsic: `none` (off) or `scale(var(--image-zoom-scale))` (on). */
|
|
47
|
+
--image-zoom-hover: none;
|
|
36
48
|
}
|
|
37
49
|
|
|
38
50
|
.image {
|
|
@@ -48,5 +60,11 @@
|
|
|
48
60
|
display: block;
|
|
49
61
|
object-fit: cover;
|
|
50
62
|
object-position: center;
|
|
63
|
+
transform-origin: center;
|
|
64
|
+
transition: transform var(--duration-300) var(--ease-out-cubic);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.image:hover img {
|
|
68
|
+
transform: var(--image-zoom-hover);
|
|
51
69
|
}
|
|
52
70
|
</style>
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
--panel-stage-surface: linear-gradient(0deg, color-mix(in srgb, var(--surface-neutral-low) 40%, transparent) 0.5%, color-mix(in srgb, var(--surface-neutral-lowest) 75%, transparent) 100%);
|
|
26
26
|
--panel-stage-padding: var(--space-16);
|
|
27
|
-
--panel-stage-inline-padding: var(--space-
|
|
27
|
+
--panel-stage-inline-padding: var(--space-16);
|
|
28
28
|
--panel-stage-gap: var(--space-16);
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -11,7 +11,7 @@ Each file plays a distinct role. Don't merge them without understanding why they
|
|
|
11
11
|
| `tokens.css` | Themed pages | Defines `--color-*`, `--surface-*`, `--text-*`, `--space-*`, … | `main.ts` | **Runtime-edited.** The token editor rewrites this file via the `themeFileApi` Vite plugin. Starter content; consumers replace at will. |
|
|
12
12
|
| `ui-editor.css` | Editor chrome only | Defines `--ui-*` (opaque grayscale, system fonts) | JS-imported by `Editor.svelte` and `ComponentEditorPage.svelte` | Deliberately isolated from the theme system so editor surfaces stay neutral while live theme edits flow through the components being edited. Never load globally. |
|
|
13
13
|
| `ui-form-controls.css` | Editor chrome only | Consumes `--ui-*` only | JS-imported by `Editor.svelte` and `ComponentEditorPage.svelte` | `.ui-form-select` / `.ui-form-input` / `.ui-form-field-*` classes. Used by `ProjectFontsSection`, `FontStackEditor`, `DialogEditor`, `NotificationEditor`. Theme-immune — must not reference `--font-*`, `--surface-*`, etc. |
|
|
14
|
-
| `site.css` | Themed pages | Consumes theme tokens | Page-imported by `Home.svelte` | Consumer-facing starter typography for the landing page (unscoped `h1`, `p`, `a`, …). Never load on editor pages. Replaceable starter content — users edit or replace this file to style their own site. Components that
|
|
14
|
+
| `site.css` | Themed pages | Consumes theme tokens | Page-imported by `Home.svelte` | Consumer-facing starter typography for the landing page (unscoped `h1`, `p`, `a`, …). Never load on editor pages. Replaceable starter content — users edit or replace this file to style their own site. Components that slot consumer content (Card body, CollapsibleSection content, SectionKit) defend their body typography against these global rules with `@include slot-prose` (from `styles/_slot-prose.scss`): the mixin pins only the owned type axes (font-family, font-size, font-weight, line-height, color) plus list spacing onto slotted `p`/`ul`/`ol`/`li`, while `a`, `strong`, font-style, letter-spacing and text-transform are left to inherit the page (links stay links, a consumer's italics survive). `prose={false}` opts a slot out entirely, and the `check:slot-prose` guard fails the build on a hand-rolled copy of the pin. The demo page no longer imports it; the demo uses scoped classes and component-owned slot typography instead. |
|
|
15
15
|
| `fonts.css` + `fonts/` | Themed pages only | n/a (`@font-face` only) | `main.ts` | Build-special-cased: copied directly to `dist/` without processing so Vite doesn't inline woff2 files as base64. Starter content; editor's font invariant means these never affect chrome. |
|
|
16
16
|
|
|
17
17
|
### Publishing layout
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Slot-prose defense.
|
|
2
|
+
//
|
|
3
|
+
// Components render the consumer's raw HTML as slot content in the *same* light
|
|
4
|
+
// DOM tree, so a consumer's global element rules (site.css `p`, `ul li`, …)
|
|
5
|
+
// directly match the slotted `<p>`/`<li>` and beat the container's inherited
|
|
6
|
+
// body typography. Svelte's scope class never reaches slotted content, so there
|
|
7
|
+
// is no automatic protection — the container must pin the type axes it owns.
|
|
8
|
+
//
|
|
9
|
+
// This mixin is the single definition of that pin. It covers p/ul/ol/li and
|
|
10
|
+
// pins ONLY the axes the component owns: font-family, font-size, font-weight,
|
|
11
|
+
// line-height, color, plus the component's spacing rhythm. font-style,
|
|
12
|
+
// letter-spacing and text-transform stay free, so a consumer's italics or
|
|
13
|
+
// tracking survive; `a` and `strong` are left untouched, so links keep looking
|
|
14
|
+
// like links inside a card. `&.prose` gates the whole thing: `prose={false}`
|
|
15
|
+
// drops the pin and the consumer fully owns the slot's content styling.
|
|
16
|
+
//
|
|
17
|
+
// Usage:
|
|
18
|
+
// .card-body { /* owns the baseline axes */ @include slot-prose; }
|
|
19
|
+
// <div class="card-body" class:prose>…</div>
|
|
20
|
+
|
|
21
|
+
@mixin slot-prose {
|
|
22
|
+
&.prose {
|
|
23
|
+
:global(p),
|
|
24
|
+
:global(ul),
|
|
25
|
+
:global(ol),
|
|
26
|
+
:global(li) {
|
|
27
|
+
font-family: inherit;
|
|
28
|
+
font-size: inherit;
|
|
29
|
+
font-weight: inherit;
|
|
30
|
+
line-height: inherit;
|
|
31
|
+
color: inherit;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
:global(p) {
|
|
35
|
+
margin: 0 0 var(--space-12);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
:global(p:last-child) {
|
|
39
|
+
margin-bottom: 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
:global(ul),
|
|
43
|
+
:global(ol) {
|
|
44
|
+
margin: var(--space-12) 0;
|
|
45
|
+
padding-left: var(--space-24);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
:global(li) {
|
|
49
|
+
margin-bottom: var(--space-4);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
/* Generated from the production theme by syncFontsToCss. Do not edit. */
|
|
2
|
+
/* Both fonts.css and fonts/ are in dist/, so relative paths work at runtime. */
|
|
2
3
|
|
|
3
4
|
/* Adobe Typekit — fira-code */
|
|
4
5
|
@import url('https://use.typekit.net/jes8oow.css');
|
|
5
6
|
|
|
7
|
+
/* Google Fonts — Manrope */
|
|
8
|
+
@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap');
|
|
9
|
+
|
|
6
10
|
/* Google Fonts — Arvo */
|
|
7
11
|
@import url('https://fonts.googleapis.com/css2?family=Arvo:ital,wght@0,400;0,700;1,400;1,700&display=swap');
|
|
8
12
|
|
|
9
13
|
/* Google Fonts — GFS Didot */
|
|
10
14
|
@import url('https://fonts.googleapis.com/css2?family=GFS+Didot&display=swap');
|
|
11
|
-
|
|
12
|
-
/* Google Fonts — Fraunces */
|
|
13
|
-
@import url('https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,100..900;1,9..144,100..900&display=swap');
|
|
14
|
-
|
|
15
|
-
/* Google Fonts — Manrope */
|
|
16
|
-
@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap');
|
|
@@ -458,6 +458,13 @@
|
|
|
458
458
|
--blur-xl: 24px;
|
|
459
459
|
--blur-2xl: 32px;
|
|
460
460
|
|
|
461
|
+
/* Transform-scale multipliers (e.g. hover zoom). 5% per step. */
|
|
462
|
+
--scale-sm: 1.05;
|
|
463
|
+
--scale-md: 1.1;
|
|
464
|
+
--scale-lg: 1.15;
|
|
465
|
+
--scale-xl: 1.2;
|
|
466
|
+
--scale-2xl: 1.25;
|
|
467
|
+
|
|
461
468
|
/* COLUMN LAYOUT — 12-col grid. Drives the dev overlay; consume via
|
|
462
469
|
grid-template-columns: repeat(var(--columns-count), 1fr) etc.
|
|
463
470
|
--columns-margin = side gutters (0 = flush). */
|