@fusion.dev/helix-templates 0.139.0 → 0.140.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/package.json +1 -1
- package/templates/angular/src/app/data.ts +17 -17
- package/templates/angular/src/app/docs.ts +9 -9
- package/templates/angular/src/app/landing.html +36 -71
- package/templates/angular/src/app/landing.ts +0 -2
- package/templates/angular/src/app/overview.html +2 -2
- package/templates/angular/src/app/pathname.ts +1 -1
- package/templates/angular/src/app/signup-form.html +9 -10
- package/templates/angular/src/app/site-footer.html +1 -1
- package/templates/angular/src/app/site-header.ts +2 -3
- package/templates/angular/src/app.css +144 -152
- package/templates/react-nextjs/app/app.css +144 -152
- package/templates/react-nextjs/app/data.ts +17 -17
- package/templates/react-nextjs/app/docs.ts +9 -9
- package/templates/react-nextjs/app/landing.tsx +63 -121
- package/templates/react-nextjs/app/overview.tsx +24 -26
- package/templates/react-nextjs/app/signup-form.tsx +36 -39
- package/templates/react-nextjs/app/site-footer.tsx +7 -10
- package/templates/react-nextjs/app/site-header.tsx +17 -21
- package/templates/react-nextjs/helix-jsx.d.ts +5 -7
- package/templates/react-vite/helix-jsx.d.ts +5 -7
- package/templates/react-vite/src/app.css +144 -152
- package/templates/react-vite/src/data.ts +17 -17
- package/templates/react-vite/src/docs.ts +9 -9
- package/templates/react-vite/src/landing.tsx +63 -121
- package/templates/react-vite/src/overview.tsx +24 -26
- package/templates/react-vite/src/routes.tsx +11 -13
- package/templates/react-vite/src/signup-form.tsx +36 -39
- package/templates/react-vite/src/site-footer.tsx +7 -10
- package/templates/react-vite/src/site-header.tsx +15 -19
- package/templates/solid-vite/src/app.css +144 -152
- package/templates/solid-vite/src/data.ts +17 -17
- package/templates/solid-vite/src/docs.ts +9 -9
- package/templates/solid-vite/src/landing.tsx +51 -98
- package/templates/solid-vite/src/overview.tsx +2 -2
- package/templates/solid-vite/src/routes.ts +6 -6
- package/templates/solid-vite/src/signup-form.tsx +10 -10
- package/templates/solid-vite/src/site-footer.tsx +1 -1
- package/templates/solid-vite/src/site-header.tsx +2 -3
- package/templates/svelte-vite/src/Landing.svelte +36 -73
- package/templates/svelte-vite/src/Overview.svelte +2 -2
- package/templates/svelte-vite/src/SignupForm.svelte +9 -10
- package/templates/svelte-vite/src/SiteFooter.svelte +1 -1
- package/templates/svelte-vite/src/SiteHeader.svelte +2 -3
- package/templates/svelte-vite/src/app.css +144 -152
- package/templates/svelte-vite/src/data.ts +17 -17
- package/templates/svelte-vite/src/docs.ts +9 -9
- package/templates/svelte-vite/src/routes.svelte.ts +5 -5
- package/templates/vue-vite/src/LandingPage.vue +36 -73
- package/templates/vue-vite/src/OverviewPage.vue +2 -2
- package/templates/vue-vite/src/SignupForm.vue +10 -10
- package/templates/vue-vite/src/SiteFooter.vue +1 -1
- package/templates/vue-vite/src/SiteHeader.vue +2 -3
- package/templates/vue-vite/src/app.css +144 -152
- package/templates/vue-vite/src/data.ts +17 -17
- package/templates/vue-vite/src/docs.ts +9 -9
- package/templates/vue-vite/src/routes.ts +6 -6
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusion.dev/helix-templates",
|
|
3
3
|
"description": "Starter templates for Helix, as data. Read by `helix new` and by `npm create @fusion.dev/helix-app`.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.140.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ross Sheppard <ross.sheppard@fusion.dev>",
|
|
7
7
|
"repository": {
|
|
@@ -2,39 +2,40 @@
|
|
|
2
2
|
* The rows the overview draws.
|
|
3
3
|
*
|
|
4
4
|
* A local module and no network, so the starter runs with nothing behind it.
|
|
5
|
-
* Point `rows` at whatever you fetch and the table
|
|
6
|
-
* whole result and does the sorting, the filtering and the paging itself. Past
|
|
7
|
-
* the size a browser can hold, `mode="server"`
|
|
8
|
-
*
|
|
5
|
+
* Point `rows` at whatever you fetch and the table stays the same: it takes the
|
|
6
|
+
* whole result and does the sorting, the filtering, and the paging itself. Past
|
|
7
|
+
* the size a browser can hold, `mode="server"` hands the paging to you, one page
|
|
8
|
+
* at a time.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* One person on the roster.
|
|
13
13
|
*
|
|
14
|
-
* **A type alias
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
14
|
+
* **A type alias, which TypeScript makes load-bearing here.** `rows` takes
|
|
15
|
+
* `Readonly<Record<string, unknown>>`, and an interface has no implicit index
|
|
16
|
+
* signature, so an interface of exactly these fields is not assignable to it.
|
|
17
|
+
* The error names the index signature, so it reads as though the data were
|
|
18
|
+
* wrong.
|
|
19
19
|
*/
|
|
20
20
|
export type Member = {
|
|
21
21
|
/**
|
|
22
22
|
* A stable identity, which is what `row-key` names.
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
24
|
+
* With one, a sort moves each row's element whole, so focus and anything
|
|
25
|
+
* attached to a row go with it. Without one, a sort rewrites the cells in
|
|
26
|
+
* place and loses both.
|
|
26
27
|
*/
|
|
27
28
|
readonly id: string
|
|
28
29
|
/**
|
|
29
|
-
*
|
|
30
|
+
* The name a row is found by.
|
|
30
31
|
*/
|
|
31
32
|
readonly name: string
|
|
32
33
|
/**
|
|
33
|
-
* A number
|
|
34
|
+
* A number, so the column sorts by size.
|
|
34
35
|
*
|
|
35
36
|
* A cell showing `2.4k` sorts as text unless the column's `compare` says what
|
|
36
|
-
* the value underneath is, which is
|
|
37
|
-
*
|
|
37
|
+
* the value underneath is, which is cheap to get right now and expensive to
|
|
38
|
+
* add later.
|
|
38
39
|
*/
|
|
39
40
|
readonly reviews: number
|
|
40
41
|
/**
|
|
@@ -68,8 +69,7 @@ export const teams: readonly string[] = [...new Set(members.map((one) => one.tea
|
|
|
68
69
|
/**
|
|
69
70
|
* The same roster as three figures, for the panel on the first screen.
|
|
70
71
|
*
|
|
71
|
-
* Derived
|
|
72
|
-
* does not show.
|
|
72
|
+
* Derived from the rows, so the panel and the table always agree.
|
|
73
73
|
*/
|
|
74
74
|
export const roster = {
|
|
75
75
|
/** How many rows the data view has. */
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The documentation
|
|
2
|
+
* The documentation the starter links to.
|
|
3
3
|
*
|
|
4
|
-
* **One module, because
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* **One module, because links are what rots first in a starter.** A page that
|
|
5
|
+
* composes its own URLs ships a plausible-looking 404 to every project
|
|
6
|
+
* scaffolded from it, and it shows only when the link is followed. Here they
|
|
7
|
+
* are in one list you can open and check, and pointing the starter at a mirror
|
|
8
|
+
* or an internal copy is one edit.
|
|
9
9
|
*
|
|
10
|
-
* Checked
|
|
10
|
+
* Checked October 4, 2026: every entry answers 200.
|
|
11
11
|
*/
|
|
12
12
|
export const DOCS = {
|
|
13
13
|
/** Angular specifically: the schema, property bindings, and events. */
|
|
@@ -16,9 +16,9 @@ export const DOCS = {
|
|
|
16
16
|
elements: 'https://fusion.dev/helix/docs/using-the-elements',
|
|
17
17
|
/** What a `<form>` does with these controls, and what it cannot do. */
|
|
18
18
|
forms: 'https://fusion.dev/helix/docs/forms',
|
|
19
|
-
/** Every component, with its API, its parts and its examples. */
|
|
19
|
+
/** Every component, with its API, its parts, and its examples. */
|
|
20
20
|
gallery: 'https://fusion.dev/helix/components',
|
|
21
|
-
/** The light and dark pair, and the attribute that
|
|
21
|
+
/** The light and dark pair, and the attribute that sets which one shows. */
|
|
22
22
|
modes: 'https://fusion.dev/helix/docs/color-modes',
|
|
23
23
|
/** Reaching a component's parts from a page, which `app.css` does once. */
|
|
24
24
|
parts: 'https://fusion.dev/helix/docs/overriding-a-component',
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
<header class="first-screen">
|
|
2
|
+
<!-- **The light behind the first screen**: a helix, drawn by the library in
|
|
3
|
+
the theme's colors, so a new brand color relights it. It shows one still
|
|
4
|
+
frame where motion is reduced, and a gradient where the browser draws
|
|
5
|
+
without a GPU. -->
|
|
6
|
+
<helix-aura class="first-light" data-layer [speed]="0.4" [terminus]="0.8" variant="braid"></helix-aura>
|
|
2
7
|
<div class="hero">
|
|
3
|
-
<helix-
|
|
4
|
-
<helix-text as="h1">
|
|
5
|
-
<helix-text as="p" class="lede"
|
|
6
|
-
|
|
7
|
-
size and space inside them comes from one set of tokens. Three routes are laid down, and
|
|
8
|
-
all of them are yours.
|
|
8
|
+
<helix-tag emphasis="subtle" tone="primary">Starter</helix-tag>
|
|
9
|
+
<helix-text as="h1" variant="display">Helix design system</helix-text>
|
|
10
|
+
<helix-text as="p" class="lede" variant="body">
|
|
11
|
+
Web components in your brand's colors, drawn from one set of tokens.
|
|
9
12
|
</helix-text>
|
|
10
13
|
<div class="actions">
|
|
11
14
|
<a data-button="solid" data-button-tone="primary" href="#/overview">See the data view</a>
|
|
@@ -13,10 +16,10 @@
|
|
|
13
16
|
</div>
|
|
14
17
|
</div>
|
|
15
18
|
|
|
16
|
-
<!-- The
|
|
17
|
-
module, so the panel is the app
|
|
18
|
-
on
|
|
19
|
-
<helix-card class="specimen" separation="outlined">
|
|
19
|
+
<!-- **The library at work, on the first screen.** The figures are the roster
|
|
20
|
+
the data view draws, read from the same module, so the panel is the app
|
|
21
|
+
itself, on glass over the light. -->
|
|
22
|
+
<helix-card class="specimen" material="glass" separation="outlined">
|
|
20
23
|
<helix-text as="h2" slot="header" variant="title">The roster, in three figures</helix-text>
|
|
21
24
|
<helix-stat-group divided>
|
|
22
25
|
<helix-stat>
|
|
@@ -38,75 +41,37 @@
|
|
|
38
41
|
|
|
39
42
|
<section class="section">
|
|
40
43
|
<helix-text as="h2" variant="subheading">What you have</helix-text>
|
|
41
|
-
<!--
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
They are custom elements, so you write the tags and there is no per-component import
|
|
48
|
-
to keep in step. One line in <helix-code>src/main.ts</helix-code> registers all of
|
|
49
|
-
them, and a subpath like <helix-code>@fusion.dev/helix/tabs</helix-code> registers
|
|
50
|
-
one.
|
|
51
|
-
</helix-text>
|
|
52
|
-
<a data-link [href]="docs.elements">Using the elements</a>
|
|
53
|
-
</article>
|
|
54
|
-
|
|
55
|
-
<article class="fact">
|
|
56
|
-
<helix-text as="h3" variant="title">One set of tokens</helix-text>
|
|
57
|
-
<helix-text as="p" emphasis="muted" variant="body">
|
|
58
|
-
Every color is written once as a light and dark pair, so the control in the bar moves
|
|
59
|
-
the whole page by setting a single attribute on the root. Type, spacing, radii and
|
|
60
|
-
control sizes come from the same place.
|
|
61
|
-
</helix-text>
|
|
62
|
-
<a data-link [href]="docs.tokens">Tokens</a>
|
|
63
|
-
</article>
|
|
64
|
-
|
|
65
|
-
<article class="fact">
|
|
66
|
-
<helix-text as="h3" variant="title">A short stylesheet</helix-text>
|
|
67
|
-
<helix-text as="p" emphasis="muted" variant="body">
|
|
68
|
-
<helix-code>src/app.css</helix-code> holds this page's measure, the rhythm between its
|
|
69
|
-
blocks, and nothing a component already draws. Where a component leaves a decision
|
|
70
|
-
open it names a part: the data view reaches one to paint the row you tick.
|
|
71
|
-
</helix-text>
|
|
72
|
-
<a data-link [href]="docs.parts">Overriding a component</a>
|
|
73
|
-
</article>
|
|
74
|
-
</div>
|
|
75
|
-
</section>
|
|
76
|
-
|
|
77
|
-
<section class="section">
|
|
78
|
-
<helix-text as="h2" variant="subheading">Where to go next</helix-text>
|
|
79
|
-
<!-- **The whole card is the link, which is what `data-card` is for.** The
|
|
80
|
-
base layer draws the ring, moves the card's border to the brand on
|
|
81
|
-
hover, and leaves focus alone. Nothing inside may be interactive,
|
|
82
|
-
since a link inside a link is neither valid nor reachable. -->
|
|
83
|
-
<helix-grid [columns]="2" gap="md">
|
|
84
|
-
<a data-card href="#/overview">
|
|
44
|
+
<!-- **Each tile is a link, which is what `data-card` is for.** The base layer
|
|
45
|
+
draws the ring, moves the card's border to the brand on hover, and leaves
|
|
46
|
+
focus alone. Nothing inside may be interactive, since a link inside a link
|
|
47
|
+
is neither valid nor reachable. -->
|
|
48
|
+
<div class="features">
|
|
49
|
+
<a class="feature" data-card [href]="docs.elements">
|
|
85
50
|
<helix-card separation="outlined">
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
<helix-text emphasis="subtle" variant="code">/overview</helix-text>
|
|
89
|
-
</helix-flex>
|
|
51
|
+
<span class="feature-mark"><helix-icon name="cube"></helix-icon></span>
|
|
52
|
+
<helix-text as="h3" variant="title">Custom elements</helix-text>
|
|
90
53
|
<helix-text as="p" emphasis="muted" variant="body">
|
|
91
|
-
|
|
92
|
-
The columns are markup you can read and the rows are one property, which is what
|
|
93
|
-
keeps the same component working at ten thousand.
|
|
54
|
+
One import in <helix-code>src/main.ts</helix-code> registers every tag.
|
|
94
55
|
</helix-text>
|
|
95
56
|
</helix-card>
|
|
96
57
|
</a>
|
|
97
|
-
|
|
98
|
-
<a data-card href="#/join">
|
|
58
|
+
<a class="feature" data-card [href]="docs.tokens">
|
|
99
59
|
<helix-card separation="outlined">
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
<helix-text emphasis="subtle" variant="code">/join</helix-text>
|
|
103
|
-
</helix-flex>
|
|
60
|
+
<span class="feature-mark"><helix-icon name="palette"></helix-icon></span>
|
|
61
|
+
<helix-text as="h3" variant="title">One set of tokens</helix-text>
|
|
104
62
|
<helix-text as="p" emphasis="muted" variant="body">
|
|
105
|
-
|
|
106
|
-
<helix-code>FormData</helix-code>, because every one of them is a real form
|
|
107
|
-
participant. The email field's complaint is the browser's own.
|
|
63
|
+
Every color, size, and space, in light and dark.
|
|
108
64
|
</helix-text>
|
|
109
65
|
</helix-card>
|
|
110
66
|
</a>
|
|
111
|
-
|
|
67
|
+
<a class="feature" data-card [href]="docs.parts">
|
|
68
|
+
<helix-card separation="outlined">
|
|
69
|
+
<span class="feature-mark"><helix-icon name="sliders-horizontal"></helix-icon></span>
|
|
70
|
+
<helix-text as="h3" variant="title">Parts to style</helix-text>
|
|
71
|
+
<helix-text as="p" emphasis="muted" variant="body">
|
|
72
|
+
Reach inside a component with <helix-code>::part()</helix-code>.
|
|
73
|
+
</helix-text>
|
|
74
|
+
</helix-card>
|
|
75
|
+
</a>
|
|
76
|
+
</div>
|
|
112
77
|
</section>
|
|
@@ -8,8 +8,6 @@ import { DOCS } from './docs'
|
|
|
8
8
|
* Delete it once you know your way around: nothing else imports it, and the
|
|
9
9
|
* route it answers becomes yours.
|
|
10
10
|
*
|
|
11
|
-
* **The heading says what this is, and the project's name stays in the bar.**
|
|
12
|
-
*
|
|
13
11
|
* **The calls to action are anchors.** A button that navigates is a link
|
|
14
12
|
* dressed as a button, and the two are different things to a keyboard and to
|
|
15
13
|
* a screen reader. The base stylesheet styles an anchor that asks with
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
|
|
43
43
|
<!-- A footnote to the table, so it takes the section's gap. -->
|
|
44
44
|
<helix-text as="p" emphasis="muted" variant="caption">
|
|
45
|
-
Filtering, column reordering, resizing, virtualized rows and a server mode
|
|
46
|
-
|
|
45
|
+
Filtering, column reordering, resizing, virtualized rows, and a server mode for large results
|
|
46
|
+
are on
|
|
47
47
|
<a data-link [href]="docs.table">the component's own page</a>.
|
|
48
48
|
</helix-text>
|
|
49
49
|
</section>
|
|
@@ -10,7 +10,7 @@ import { Injectable, signal } from '@angular/core'
|
|
|
10
10
|
the same document, and wherever you deploy has to be told to. A hash asks
|
|
11
11
|
nothing of it. Each link in the app is a plain anchor to `#/` and a path. */
|
|
12
12
|
|
|
13
|
-
/**
|
|
13
|
+
/** The current path, read from the hash, so the first page is `/`. */
|
|
14
14
|
const read = (): string => window.location.hash.slice(1) || '/'
|
|
15
15
|
|
|
16
16
|
/** The current path, kept current as the hash changes. */
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
<helix-input autocomplete="name" label="Name" name="name" required></helix-input>
|
|
15
15
|
|
|
16
16
|
<!-- Validation is the platform's: `type` and `required` are set on the
|
|
17
|
-
real input inside, and its own message shows once the
|
|
18
|
-
touched
|
|
17
|
+
real input inside, and its own message shows once the field has been
|
|
18
|
+
touched. Set `feedback` to say it in your own words. -->
|
|
19
19
|
<helix-input
|
|
20
20
|
hint="Where we send the welcome note."
|
|
21
21
|
label="Email"
|
|
@@ -53,18 +53,17 @@
|
|
|
53
53
|
and the component draws it with a tint and a bar on the inline
|
|
54
54
|
start, so it survives being read in grayscale. -->
|
|
55
55
|
<helix-callout tone="info">
|
|
56
|
-
|
|
57
|
-
have been handed.
|
|
56
|
+
The form posts nothing. Submit it, and a message shows exactly what a server would receive.
|
|
58
57
|
</helix-callout>
|
|
59
|
-
<helix-text as="h2" variant="title">What
|
|
58
|
+
<helix-text as="h2" variant="title">What the form shows</helix-text>
|
|
60
59
|
<helix-text as="p" emphasis="muted" variant="body">
|
|
61
|
-
Every control is a form-associated custom element, so the submit reads them with
|
|
62
|
-
<helix-code>new FormData(form)</helix-code
|
|
63
|
-
|
|
60
|
+
Every control is a form-associated custom element, so the submit reads them all with
|
|
61
|
+
<helix-code>new FormData(form)</helix-code>. Reset the form and they all go back,
|
|
62
|
+
the way an <helix-code>input</helix-code> does.
|
|
64
63
|
</helix-text>
|
|
65
64
|
<helix-text as="p" emphasis="muted" variant="body">
|
|
66
|
-
Leave the email wrong and the
|
|
67
|
-
|
|
65
|
+
Leave the email wrong and the browser shows its own message, in your language. Handle is the
|
|
66
|
+
controlled field: the page refuses each change and writes back a cleaned value.
|
|
68
67
|
</helix-text>
|
|
69
68
|
<a data-link [href]="docs.forms">Forms</a>
|
|
70
69
|
</aside>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div class="footer-row">
|
|
2
2
|
<helix-text as="p" emphasis="subtle" variant="caption">
|
|
3
|
-
Every component
|
|
3
|
+
Every component here has a page, with its API, its parts, and its examples.
|
|
4
4
|
</helix-text>
|
|
5
5
|
<div class="footer-links">
|
|
6
6
|
<a data-link="subtle" [href]="docs.gallery">Components</a>
|
|
@@ -31,8 +31,7 @@ const MARKS: Record<Mode, string> = { dark: 'moon', light: 'sun', system: 'monit
|
|
|
31
31
|
export class SiteHeader {
|
|
32
32
|
protected readonly path = inject(Pathname).current
|
|
33
33
|
protected readonly marks = MARKS
|
|
34
|
-
/* `system` is the resting state,
|
|
35
|
-
and after the reader first touches it. */
|
|
34
|
+
/* `system` is the resting state, the mode the page follows until the control is pressed. */
|
|
36
35
|
protected readonly mode = signal<Mode>('system')
|
|
37
36
|
|
|
38
37
|
/**
|
|
@@ -44,7 +43,7 @@ export class SiteHeader {
|
|
|
44
43
|
* on a panel for a light preview inside a dark page.
|
|
45
44
|
*
|
|
46
45
|
* `system` removes the attribute. Writing out whichever mode is current would
|
|
47
|
-
*
|
|
46
|
+
* hold the page there when the system's own setting changed.
|
|
48
47
|
*/
|
|
49
48
|
protected cycle(): void {
|
|
50
49
|
const next = MODES[(MODES.indexOf(this.mode()) + 1) % MODES.length] ?? 'system'
|