@spark-line/web-framework 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.
- package/LICENSE +21 -0
- package/README.md +171 -0
- package/dist/astro/index.js +13 -0
- package/dist/react/Carousel.d.ts +13 -0
- package/dist/react/Carousel.d.ts.map +1 -0
- package/dist/react/Carousel.js +14 -0
- package/dist/react/Carousel.js.map +1 -0
- package/dist/react/Dialog.d.ts +8 -0
- package/dist/react/Dialog.d.ts.map +1 -0
- package/dist/react/Dialog.js +23 -0
- package/dist/react/Dialog.js.map +1 -0
- package/dist/react/Menu.d.ts +11 -0
- package/dist/react/Menu.d.ts.map +1 -0
- package/dist/react/Menu.js +46 -0
- package/dist/react/Menu.js.map +1 -0
- package/dist/react/Tabs.d.ts +12 -0
- package/dist/react/Tabs.d.ts.map +1 -0
- package/dist/react/Tabs.js +43 -0
- package/dist/react/Tabs.js.map +1 -0
- package/dist/react/index.d.ts +9 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +5 -0
- package/dist/react/index.js.map +1 -0
- package/dist/registry/index.d.ts +197 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +170 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/sanity/index.d.ts +57 -0
- package/dist/sanity/index.d.ts.map +1 -0
- package/dist/sanity/index.js +117 -0
- package/dist/sanity/index.js.map +1 -0
- package/package.json +96 -0
- package/skills/spark-line-web-framework/SKILL.md +84 -0
- package/skills/spark-line-web-framework/agents/openai.yaml +4 -0
- package/skills/spark-line-web-framework/references/contracts.md +75 -0
- package/skills/spark-line-web-framework/references/qa-checklist.md +56 -0
- package/skills/spark-line-web-framework/references/stack-boundaries.md +53 -0
- package/skills/spark-line-web-framework/scripts/audit_layout.mjs +66 -0
- package/src/astro/Action.astro +34 -0
- package/src/astro/CardShell.astro +19 -0
- package/src/astro/Cluster.astro +30 -0
- package/src/astro/Container.astro +15 -0
- package/src/astro/Disclosure.astro +16 -0
- package/src/astro/Grid.astro +38 -0
- package/src/astro/Heading.astro +17 -0
- package/src/astro/PageFlow.astro +13 -0
- package/src/astro/Section.astro +44 -0
- package/src/astro/SectionGroup.astro +14 -0
- package/src/astro/Stack.astro +16 -0
- package/src/astro/Text.astro +21 -0
- package/src/astro/VisualFrame.astro +32 -0
- package/src/astro/index.d.ts +17 -0
- package/starter/astro/astro.config.mjs +5 -0
- package/starter/astro/package.json +13 -0
- package/starter/astro/src/pages/index.astro +48 -0
- package/starter/astro/src/pages/style-guide.astro +76 -0
- package/starter/astro/src/styles/project.css +27 -0
- package/styles/foundation.css +267 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Interface QA checklist
|
|
2
|
+
|
|
3
|
+
## Evidence
|
|
4
|
+
|
|
5
|
+
- Capture the current rendered baseline before restructuring.
|
|
6
|
+
- Compare against the actual reference at the same viewport.
|
|
7
|
+
- Preserve approved copy, URLs, assets, states, and route behavior.
|
|
8
|
+
|
|
9
|
+
## Target and neighbors
|
|
10
|
+
|
|
11
|
+
Verify the changed section, previous section, and next section together:
|
|
12
|
+
|
|
13
|
+
- independent theme and background;
|
|
14
|
+
- intended seam or separation;
|
|
15
|
+
- no unexplained gap;
|
|
16
|
+
- no accidental overlap;
|
|
17
|
+
- no clipping of focus or content;
|
|
18
|
+
- no cross-section selector effects;
|
|
19
|
+
- correct normal-flow movement after height changes.
|
|
20
|
+
|
|
21
|
+
## Responsive
|
|
22
|
+
|
|
23
|
+
Use the project's required viewport matrix. When none exists, include:
|
|
24
|
+
|
|
25
|
+
- wide desktop;
|
|
26
|
+
- 1024px tablet landscape;
|
|
27
|
+
- 834px tablet portrait;
|
|
28
|
+
- 390px mobile;
|
|
29
|
+
- 320px narrow mobile.
|
|
30
|
+
|
|
31
|
+
At each width verify:
|
|
32
|
+
|
|
33
|
+
- no horizontal document overflow;
|
|
34
|
+
- correct DOM and visual order;
|
|
35
|
+
- readable measures and type;
|
|
36
|
+
- minimum 44px interactive targets on touch layouts;
|
|
37
|
+
- visual frames reserve their complete space;
|
|
38
|
+
- component variants reflow without content loss.
|
|
39
|
+
|
|
40
|
+
## Interaction and accessibility
|
|
41
|
+
|
|
42
|
+
- Keyboard-operate every control.
|
|
43
|
+
- Keep focus visible.
|
|
44
|
+
- Confirm ARIA labels, relationships, expanded state, and live regions.
|
|
45
|
+
- Confirm Escape and focus return for overlays.
|
|
46
|
+
- Confirm native anchors and history behavior.
|
|
47
|
+
- Confirm reduced motion removes nonessential movement.
|
|
48
|
+
- Confirm React hydration adds behavior without shifting the Astro layout.
|
|
49
|
+
|
|
50
|
+
## Completion
|
|
51
|
+
|
|
52
|
+
- Run build and existing tests.
|
|
53
|
+
- Run browser regression tests for unchanged routes.
|
|
54
|
+
- Add or update the component-gallery scenario for every changed reusable
|
|
55
|
+
component.
|
|
56
|
+
- Report remaining deviations with exact affected viewports and components.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Astro, Sanity, and React boundaries
|
|
2
|
+
|
|
3
|
+
## Astro
|
|
4
|
+
|
|
5
|
+
Default to Astro for:
|
|
6
|
+
|
|
7
|
+
- page and section composition;
|
|
8
|
+
- semantic content markup;
|
|
9
|
+
- surfaces, containers, and spacing;
|
|
10
|
+
- static cards, headings, actions, and disclosures;
|
|
11
|
+
- server or build-time data mapping.
|
|
12
|
+
|
|
13
|
+
Use slots for open components whose child structure is intentionally flexible.
|
|
14
|
+
Use typed props for closed components with a fixed content contract.
|
|
15
|
+
|
|
16
|
+
## React islands
|
|
17
|
+
|
|
18
|
+
Use React only when persistent client state or interaction justifies hydration.
|
|
19
|
+
|
|
20
|
+
- Keep the Astro-owned section and visual frame outside the island.
|
|
21
|
+
- Accept serializable props.
|
|
22
|
+
- Keep state, effects, and event handling local.
|
|
23
|
+
- Default to `client:visible` or `client:idle`.
|
|
24
|
+
- Use `client:load` only when interaction must work immediately.
|
|
25
|
+
- Support semantic roles, ARIA relationships, keyboard operation, focus return,
|
|
26
|
+
and reduced motion.
|
|
27
|
+
|
|
28
|
+
Do not let an island set page-level theme, section padding, container width, or
|
|
29
|
+
adjacent-section layout.
|
|
30
|
+
|
|
31
|
+
## Sanity
|
|
32
|
+
|
|
33
|
+
Map Sanity `_type` values to registered Astro section IDs.
|
|
34
|
+
|
|
35
|
+
Preserve:
|
|
36
|
+
|
|
37
|
+
- `_key`;
|
|
38
|
+
- record order;
|
|
39
|
+
- Portable Text;
|
|
40
|
+
- references and asset provenance;
|
|
41
|
+
- preview and Stega metadata;
|
|
42
|
+
- the original source record for visual editing.
|
|
43
|
+
|
|
44
|
+
Expose constrained enums for theme, spacing, and layout. Do not expose arbitrary
|
|
45
|
+
CSS classes or freeform page markup.
|
|
46
|
+
|
|
47
|
+
Choose unknown-section behavior explicitly:
|
|
48
|
+
|
|
49
|
+
- `omit` for resilient production rendering;
|
|
50
|
+
- `preserve` for preview tooling and diagnostics;
|
|
51
|
+
- `throw` for strict tests and migrations.
|
|
52
|
+
|
|
53
|
+
Do not install Sanity into a project that does not use the Sanity export.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
|
|
7
|
+
const targets = process.argv.slice(2);
|
|
8
|
+
if (targets.length === 0) {
|
|
9
|
+
console.error("Usage: audit_layout.mjs <file-or-directory> [...]");
|
|
10
|
+
process.exit(2);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const rules = [
|
|
14
|
+
{
|
|
15
|
+
label: "section selector reaches a sibling",
|
|
16
|
+
expression: /(?:\[data-slf-section\]|\.slf-section|section\.[\w-]+)\s*[+~]/g
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
label: "ordinary negative margin",
|
|
20
|
+
expression: /margin(?:-(?:block|top|bottom))?(?:-start|-end)?:\s*-\d/gi
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
label: "raw layout class stored in a Sanity field",
|
|
24
|
+
expression: /name\s*:\s*["'](?:class|className|cssClass)["']/g
|
|
25
|
+
}
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const files = [];
|
|
29
|
+
for (const target of targets) await collect(path.resolve(target), files);
|
|
30
|
+
|
|
31
|
+
let findings = 0;
|
|
32
|
+
for (const file of files) {
|
|
33
|
+
if (!/\.(?:astro|css|js|jsx|mjs|ts|tsx)$/.test(file)) continue;
|
|
34
|
+
const source = await readFile(file, "utf8");
|
|
35
|
+
const lines = source.split(/\r?\n/);
|
|
36
|
+
for (const rule of rules) {
|
|
37
|
+
rule.expression.lastIndex = 0;
|
|
38
|
+
for (const match of source.matchAll(rule.expression)) {
|
|
39
|
+
const line = source.slice(0, match.index).split(/\r?\n/).length;
|
|
40
|
+
console.log(`${file}:${line}: ${rule.label}`);
|
|
41
|
+
console.log(` ${lines[line - 1]?.trim() ?? ""}`);
|
|
42
|
+
findings += 1;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (findings) {
|
|
48
|
+
console.log(`Advisory: ${findings} potential framework deviation(s).`);
|
|
49
|
+
process.exitCode = 1;
|
|
50
|
+
} else {
|
|
51
|
+
console.log(`No static layout deviations found in ${files.length} file(s).`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function collect(target, output) {
|
|
55
|
+
const details = await stat(target);
|
|
56
|
+
if (details.isFile()) {
|
|
57
|
+
output.push(target);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
for (const entry of await readdir(target, { withFileTypes: true })) {
|
|
61
|
+
if (["node_modules", "dist", ".git"].includes(entry.name)) continue;
|
|
62
|
+
const next = path.join(target, entry.name);
|
|
63
|
+
if (entry.isDirectory()) await collect(next, output);
|
|
64
|
+
else output.push(next);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
|
|
4
|
+
type AnchorAttributes = HTMLAttributes<"a">;
|
|
5
|
+
type ButtonAttributes = HTMLAttributes<"button">;
|
|
6
|
+
|
|
7
|
+
interface Props extends AnchorAttributes, ButtonAttributes {
|
|
8
|
+
href?: string;
|
|
9
|
+
variant?: "primary" | "secondary" | "quiet";
|
|
10
|
+
size?: "sm" | "md" | "lg";
|
|
11
|
+
type?: "button" | "submit" | "reset";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
href,
|
|
16
|
+
variant = "primary",
|
|
17
|
+
size = "md",
|
|
18
|
+
type = "button",
|
|
19
|
+
class: className,
|
|
20
|
+
...attributes
|
|
21
|
+
} = Astro.props;
|
|
22
|
+
const Tag = href ? "a" : "button";
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
<Tag
|
|
26
|
+
class:list={["slf-action", className]}
|
|
27
|
+
data-variant={variant}
|
|
28
|
+
data-size={size}
|
|
29
|
+
href={href}
|
|
30
|
+
type={href ? undefined : type}
|
|
31
|
+
{...attributes}
|
|
32
|
+
>
|
|
33
|
+
<slot />
|
|
34
|
+
</Tag>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
|
|
4
|
+
interface Props extends HTMLAttributes<"article"> {
|
|
5
|
+
as?: "article" | "div" | "li";
|
|
6
|
+
surface?: "default" | "quiet" | "accent";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
as: Tag = "article",
|
|
11
|
+
surface = "default",
|
|
12
|
+
class: className,
|
|
13
|
+
...attributes
|
|
14
|
+
} = Astro.props;
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<Tag class:list={["slf-card-shell", className]} data-surface={surface} {...attributes}>
|
|
18
|
+
<slot />
|
|
19
|
+
</Tag>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import type { LayoutGap } from "./Stack.astro";
|
|
4
|
+
|
|
5
|
+
interface Props extends HTMLAttributes<"div"> {
|
|
6
|
+
as?: "div" | "nav" | "ul";
|
|
7
|
+
gap?: LayoutGap;
|
|
8
|
+
align?: "start" | "center" | "end" | "stretch";
|
|
9
|
+
justify?: "start" | "center" | "end" | "between";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
as: Tag = "div",
|
|
14
|
+
gap = "sm",
|
|
15
|
+
align = "center",
|
|
16
|
+
justify = "start",
|
|
17
|
+
class: className,
|
|
18
|
+
...attributes
|
|
19
|
+
} = Astro.props;
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
<Tag
|
|
23
|
+
class:list={["slf-cluster", className]}
|
|
24
|
+
data-gap={gap}
|
|
25
|
+
data-align={align}
|
|
26
|
+
data-justify={justify}
|
|
27
|
+
{...attributes}
|
|
28
|
+
>
|
|
29
|
+
<slot />
|
|
30
|
+
</Tag>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import type { ContainerWidth } from "./Section.astro";
|
|
4
|
+
|
|
5
|
+
interface Props extends HTMLAttributes<"div"> {
|
|
6
|
+
as?: "div" | "article" | "nav";
|
|
7
|
+
width?: ContainerWidth;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { as: Tag = "div", width = "wide", class: className, ...attributes } = Astro.props;
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<Tag class:list={["slf-container", className]} data-container={width} {...attributes}>
|
|
14
|
+
<slot />
|
|
15
|
+
</Tag>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
|
|
4
|
+
interface Props extends HTMLAttributes<"details"> {
|
|
5
|
+
summary: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const { summary, class: className, ...attributes } = Astro.props;
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<details class:list={["slf-disclosure", className]} {...attributes}>
|
|
12
|
+
<summary>{summary}</summary>
|
|
13
|
+
<div class="slf-disclosure__content">
|
|
14
|
+
<slot />
|
|
15
|
+
</div>
|
|
16
|
+
</details>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import type { LayoutGap } from "./Stack.astro";
|
|
4
|
+
|
|
5
|
+
interface Props extends HTMLAttributes<"div"> {
|
|
6
|
+
as?: "div" | "ul" | "ol";
|
|
7
|
+
columns?: 1 | 2 | 3 | 4 | 6 | 12 | "auto-fit" | "auto-fill";
|
|
8
|
+
minItemWidth?: string;
|
|
9
|
+
gap?: LayoutGap;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
as: Tag = "div",
|
|
14
|
+
columns = "auto-fit",
|
|
15
|
+
minItemWidth = "16rem",
|
|
16
|
+
gap = "md",
|
|
17
|
+
class: className,
|
|
18
|
+
style,
|
|
19
|
+
...attributes
|
|
20
|
+
} = Astro.props;
|
|
21
|
+
const inlineStyle = [
|
|
22
|
+
`--slf-grid-min:${minItemWidth}`,
|
|
23
|
+
typeof columns === "number" ? `--slf-grid-columns:${columns}` : "",
|
|
24
|
+
typeof style === "string" ? style : ""
|
|
25
|
+
]
|
|
26
|
+
.filter(Boolean)
|
|
27
|
+
.join(";");
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
<Tag
|
|
31
|
+
class:list={["slf-grid", className]}
|
|
32
|
+
data-columns={columns}
|
|
33
|
+
data-gap={gap}
|
|
34
|
+
style={inlineStyle}
|
|
35
|
+
{...attributes}
|
|
36
|
+
>
|
|
37
|
+
<slot />
|
|
38
|
+
</Tag>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
|
|
4
|
+
export type HeadingSize = "display" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
|
|
5
|
+
|
|
6
|
+
interface Props extends HTMLAttributes<"h2"> {
|
|
7
|
+
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
8
|
+
size?: HeadingSize;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { level = 2, size = `h${level}` as HeadingSize, class: className, ...attributes } = Astro.props;
|
|
12
|
+
const Tag = `h${level}` as const;
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<Tag class:list={["slf-heading", className]} data-size={size} {...attributes}>
|
|
16
|
+
<slot />
|
|
17
|
+
</Tag>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
|
|
4
|
+
interface Props extends HTMLAttributes<"main"> {
|
|
5
|
+
as?: "main" | "div";
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const { as: Tag = "main", class: className, ...attributes } = Astro.props;
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<Tag class:list={["slf-page-flow", className]} data-slf-page-flow {...attributes}>
|
|
12
|
+
<slot />
|
|
13
|
+
</Tag>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
|
|
4
|
+
export type SectionTheme = "default" | "inverse" | "accent" | "quiet";
|
|
5
|
+
export type SectionSpace = "none" | "xs" | "sm" | "md" | "lg" | "xl";
|
|
6
|
+
export type ContainerWidth = "narrow" | "content" | "wide" | "full";
|
|
7
|
+
|
|
8
|
+
interface Props extends HTMLAttributes<"section"> {
|
|
9
|
+
as?: "section" | "header" | "footer" | "aside" | "div";
|
|
10
|
+
theme?: SectionTheme;
|
|
11
|
+
spaceTop?: SectionSpace;
|
|
12
|
+
spaceBottom?: SectionSpace;
|
|
13
|
+
container?: ContainerWidth | false;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const {
|
|
17
|
+
as: Tag = "section",
|
|
18
|
+
theme = "default",
|
|
19
|
+
spaceTop = "md",
|
|
20
|
+
spaceBottom = "md",
|
|
21
|
+
container = "wide",
|
|
22
|
+
class: className,
|
|
23
|
+
...attributes
|
|
24
|
+
} = Astro.props;
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
<Tag
|
|
28
|
+
class:list={["slf-section", className]}
|
|
29
|
+
data-slf-section
|
|
30
|
+
data-theme={theme}
|
|
31
|
+
data-space-top={spaceTop}
|
|
32
|
+
data-space-bottom={spaceBottom}
|
|
33
|
+
{...attributes}
|
|
34
|
+
>
|
|
35
|
+
{
|
|
36
|
+
container === false ? (
|
|
37
|
+
<slot />
|
|
38
|
+
) : (
|
|
39
|
+
<div class="slf-container" data-container={container}>
|
|
40
|
+
<slot />
|
|
41
|
+
</div>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
</Tag>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
|
|
4
|
+
interface Props extends HTMLAttributes<"div"> {
|
|
5
|
+
as?: "div" | "section";
|
|
6
|
+
mode?: "joined" | "overlap";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const { as: Tag = "div", mode = "joined", class: className, ...attributes } = Astro.props;
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<Tag class:list={["slf-section-group", className]} data-slf-section-group data-mode={mode} {...attributes}>
|
|
13
|
+
<slot />
|
|
14
|
+
</Tag>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
|
|
4
|
+
export type LayoutGap = "none" | "xs" | "sm" | "md" | "lg" | "xl";
|
|
5
|
+
|
|
6
|
+
interface Props extends HTMLAttributes<"div"> {
|
|
7
|
+
as?: "div" | "section" | "article" | "ul" | "ol";
|
|
8
|
+
gap?: LayoutGap;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { as: Tag = "div", gap = "md", class: className, ...attributes } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<Tag class:list={["slf-stack", className]} data-gap={gap} {...attributes}>
|
|
15
|
+
<slot />
|
|
16
|
+
</Tag>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
|
|
4
|
+
interface Props extends HTMLAttributes<"p"> {
|
|
5
|
+
as?: "p" | "span" | "div" | "li";
|
|
6
|
+
size?: "small" | "body" | "lead";
|
|
7
|
+
tone?: "default" | "muted";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
as: Tag = "p",
|
|
12
|
+
size = "body",
|
|
13
|
+
tone = "default",
|
|
14
|
+
class: className,
|
|
15
|
+
...attributes
|
|
16
|
+
} = Astro.props;
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
<Tag class:list={["slf-text", className]} data-size={size} data-tone={tone} {...attributes}>
|
|
20
|
+
<slot />
|
|
21
|
+
</Tag>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
|
|
4
|
+
interface Props extends HTMLAttributes<"div"> {
|
|
5
|
+
as?: "div" | "figure";
|
|
6
|
+
aspectRatio?: string;
|
|
7
|
+
minBlockSize?: string;
|
|
8
|
+
overflow?: "clip" | "hidden" | "visible";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
as: Tag = "div",
|
|
13
|
+
aspectRatio,
|
|
14
|
+
minBlockSize,
|
|
15
|
+
overflow = "clip",
|
|
16
|
+
class: className,
|
|
17
|
+
style,
|
|
18
|
+
...attributes
|
|
19
|
+
} = Astro.props;
|
|
20
|
+
const inlineStyle = [
|
|
21
|
+
aspectRatio ? `--slf-visual-aspect:${aspectRatio}` : "",
|
|
22
|
+
minBlockSize ? `--slf-visual-min-block:${minBlockSize}` : "",
|
|
23
|
+
`--slf-visual-overflow:${overflow}`,
|
|
24
|
+
typeof style === "string" ? style : ""
|
|
25
|
+
]
|
|
26
|
+
.filter(Boolean)
|
|
27
|
+
.join(";");
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
<Tag class:list={["slf-visual-frame", className]} data-slf-visual-frame style={inlineStyle} {...attributes}>
|
|
31
|
+
<slot />
|
|
32
|
+
</Tag>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { default as PageFlow } from "./PageFlow.astro";
|
|
2
|
+
export { default as Section } from "./Section.astro";
|
|
3
|
+
export { default as SectionGroup } from "./SectionGroup.astro";
|
|
4
|
+
export { default as Container } from "./Container.astro";
|
|
5
|
+
export { default as Stack } from "./Stack.astro";
|
|
6
|
+
export { default as Cluster } from "./Cluster.astro";
|
|
7
|
+
export { default as Grid } from "./Grid.astro";
|
|
8
|
+
export { default as VisualFrame } from "./VisualFrame.astro";
|
|
9
|
+
export { default as Heading } from "./Heading.astro";
|
|
10
|
+
export { default as Text } from "./Text.astro";
|
|
11
|
+
export { default as Action } from "./Action.astro";
|
|
12
|
+
export { default as CardShell } from "./CardShell.astro";
|
|
13
|
+
export { default as Disclosure } from "./Disclosure.astro";
|
|
14
|
+
|
|
15
|
+
export type { ContainerWidth, SectionSpace, SectionTheme } from "./Section.astro";
|
|
16
|
+
export type { LayoutGap } from "./Stack.astro";
|
|
17
|
+
export type { HeadingSize } from "./Heading.astro";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
import "@spark-line/web-framework/styles/foundation.css";
|
|
3
|
+
import "../styles/project.css";
|
|
4
|
+
import {
|
|
5
|
+
Action,
|
|
6
|
+
CardShell,
|
|
7
|
+
Grid,
|
|
8
|
+
Heading,
|
|
9
|
+
PageFlow,
|
|
10
|
+
Section,
|
|
11
|
+
Stack,
|
|
12
|
+
Text,
|
|
13
|
+
VisualFrame
|
|
14
|
+
} from "@spark-line/web-framework/astro";
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<!doctype html>
|
|
18
|
+
<html lang="en">
|
|
19
|
+
<head>
|
|
20
|
+
<meta charset="UTF-8" />
|
|
21
|
+
<meta name="viewport" content="width=device-width" />
|
|
22
|
+
<title>Spark Line framework starter</title>
|
|
23
|
+
</head>
|
|
24
|
+
<body>
|
|
25
|
+
<PageFlow>
|
|
26
|
+
<Section theme="default" spaceTop="xl" spaceBottom="lg">
|
|
27
|
+
<Stack gap="md">
|
|
28
|
+
<Heading level={1} size="display">Structure without visual inheritance</Heading>
|
|
29
|
+
<Text size="lead">Supply the project's reviewed tokens and content.</Text>
|
|
30
|
+
<Action href="#proof">See the proof</Action>
|
|
31
|
+
</Stack>
|
|
32
|
+
</Section>
|
|
33
|
+
<Section id="proof" theme="quiet" spaceTop="lg" spaceBottom="xl">
|
|
34
|
+
<Grid columns="auto-fit" minItemWidth="15rem">
|
|
35
|
+
<CardShell>
|
|
36
|
+
<Stack gap="sm">
|
|
37
|
+
<Heading level={2} size="h4">Section-owned edges</Heading>
|
|
38
|
+
<Text>Changing this card cannot restyle the following section.</Text>
|
|
39
|
+
</Stack>
|
|
40
|
+
</CardShell>
|
|
41
|
+
<VisualFrame aspectRatio="4 / 3" class="starter-frame">
|
|
42
|
+
<Text>Reserved visual space</Text>
|
|
43
|
+
</VisualFrame>
|
|
44
|
+
</Grid>
|
|
45
|
+
</Section>
|
|
46
|
+
</PageFlow>
|
|
47
|
+
</body>
|
|
48
|
+
</html>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
import "@spark-line/web-framework/styles/foundation.css";
|
|
3
|
+
import "../styles/project.css";
|
|
4
|
+
import {
|
|
5
|
+
Action,
|
|
6
|
+
CardShell,
|
|
7
|
+
Cluster,
|
|
8
|
+
Disclosure,
|
|
9
|
+
Grid,
|
|
10
|
+
Heading,
|
|
11
|
+
PageFlow,
|
|
12
|
+
Section,
|
|
13
|
+
SectionGroup,
|
|
14
|
+
Stack,
|
|
15
|
+
Text,
|
|
16
|
+
VisualFrame
|
|
17
|
+
} from "@spark-line/web-framework/astro";
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
<!doctype html>
|
|
21
|
+
<html lang="en">
|
|
22
|
+
<head>
|
|
23
|
+
<meta charset="UTF-8" />
|
|
24
|
+
<meta name="viewport" content="width=device-width" />
|
|
25
|
+
<meta name="robots" content="noindex, nofollow" />
|
|
26
|
+
<title>Component gallery</title>
|
|
27
|
+
</head>
|
|
28
|
+
<body>
|
|
29
|
+
<PageFlow>
|
|
30
|
+
<Section theme="default" spaceTop="lg" spaceBottom="lg">
|
|
31
|
+
<Stack gap="md">
|
|
32
|
+
<Text size="small">Unlinked development route</Text>
|
|
33
|
+
<Heading level={1} size="display">Component gallery</Heading>
|
|
34
|
+
<Text size="lead">Every registered variant and meaningful state belongs here.</Text>
|
|
35
|
+
</Stack>
|
|
36
|
+
</Section>
|
|
37
|
+
|
|
38
|
+
<SectionGroup mode="joined">
|
|
39
|
+
<Section theme="quiet" spaceTop="lg" spaceBottom="lg">
|
|
40
|
+
<Stack gap="md">
|
|
41
|
+
<Heading level={2} size="h2">Actions and surfaces</Heading>
|
|
42
|
+
<Cluster>
|
|
43
|
+
<Action href="#layout">Primary</Action>
|
|
44
|
+
<Action href="#layout" variant="secondary">Secondary</Action>
|
|
45
|
+
<Action href="#layout" variant="quiet">Quiet</Action>
|
|
46
|
+
</Cluster>
|
|
47
|
+
<Grid columns="auto-fit" minItemWidth="14rem">
|
|
48
|
+
{
|
|
49
|
+
["default", "quiet", "accent"].map((surface) => (
|
|
50
|
+
<CardShell surface={surface}>
|
|
51
|
+
<Heading level={3} size="h4">{surface}</Heading>
|
|
52
|
+
<Text>Project tokens supply this surface.</Text>
|
|
53
|
+
</CardShell>
|
|
54
|
+
))
|
|
55
|
+
}
|
|
56
|
+
</Grid>
|
|
57
|
+
</Stack>
|
|
58
|
+
</Section>
|
|
59
|
+
|
|
60
|
+
<Section id="layout" theme="default" spaceTop="lg" spaceBottom="lg">
|
|
61
|
+
<Grid columns={2}>
|
|
62
|
+
<Stack gap="sm">
|
|
63
|
+
<Heading level={2} size="h3">Native disclosure</Heading>
|
|
64
|
+
<Disclosure summary="What owns section spacing?">
|
|
65
|
+
<Text>The section owns both internal vertical edges.</Text>
|
|
66
|
+
</Disclosure>
|
|
67
|
+
</Stack>
|
|
68
|
+
<VisualFrame aspectRatio="16 / 9" class="starter-frame">
|
|
69
|
+
<Text>16 / 9 reserved frame</Text>
|
|
70
|
+
</VisualFrame>
|
|
71
|
+
</Grid>
|
|
72
|
+
</Section>
|
|
73
|
+
</SectionGroup>
|
|
74
|
+
</PageFlow>
|
|
75
|
+
</body>
|
|
76
|
+
</html>
|