handzon-core 0.10.0 → 0.12.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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "handzon-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Core framework for Handzon — layouts, components, content + AI libs, and server runtime (handlers, DB, auth, migration runner) consumed by Handzon scaffolds.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -1,44 +1,77 @@
|
|
|
1
1
|
---
|
|
2
2
|
/**
|
|
3
|
-
* Site footer. A single quiet line at the bottom of every page,
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Site footer. A single quiet line at the bottom of every page, sized
|
|
4
|
+
* to match the rest of the brutalist surface treatment.
|
|
5
|
+
*
|
|
6
|
+
* Two modes:
|
|
7
|
+
* - Default (no `siteUrl`): one centered "Built with Handzon" credit,
|
|
8
|
+
* preserving the framework's original footer for unbranded scaffolds.
|
|
9
|
+
* - Branded (`siteUrl` set): the site owner's credit leads on the left
|
|
10
|
+
* (linked to `siteUrl`), and "Built with Handzon" moves to a quieter
|
|
11
|
+
* secondary link on the right.
|
|
6
12
|
*/
|
|
7
13
|
interface Props {
|
|
8
|
-
/**
|
|
14
|
+
/** Primary credit label — the site owner. */
|
|
15
|
+
siteName?: string;
|
|
16
|
+
/** Primary footer credit label. Defaults to `siteName`, but can be
|
|
17
|
+
* shorter (for example `render.com`) without changing page titles,
|
|
18
|
+
* nav labels, or Open Graph metadata. */
|
|
19
|
+
siteCreditLabel?: string;
|
|
20
|
+
/** Primary credit link. When set, the footer leads with this credit
|
|
21
|
+
* and demotes the Handzon link to a secondary side link. */
|
|
22
|
+
siteUrl?: string;
|
|
23
|
+
/** Handzon project/package link (the secondary "Built with" credit). */
|
|
9
24
|
repoUrl?: string;
|
|
10
25
|
/** Year displayed in the credit line; defaults to the current year. */
|
|
11
26
|
year?: number;
|
|
12
27
|
}
|
|
13
28
|
|
|
14
29
|
const {
|
|
30
|
+
siteName = "Handzon",
|
|
31
|
+
siteCreditLabel = siteName,
|
|
32
|
+
siteUrl,
|
|
15
33
|
repoUrl = "https://github.com/R4ph-t/handzon",
|
|
16
34
|
year = new Date().getFullYear(),
|
|
17
35
|
} = Astro.props;
|
|
18
36
|
---
|
|
19
37
|
<footer class="hz-footer">
|
|
20
|
-
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
viewBox="0 0 24 24"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
{siteUrl ? (
|
|
39
|
+
<div class="hz-footer-inner hz-footer-split">
|
|
40
|
+
<span class="hz-footer-credit">
|
|
41
|
+
© {year}
|
|
42
|
+
<a class="hz-footer-link" href={siteUrl} target="_blank" rel="noopener">
|
|
43
|
+
{siteCreditLabel}
|
|
44
|
+
<svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
45
|
+
<path d="M7 17 17 7" />
|
|
46
|
+
<path d="M7 7h10v10" />
|
|
47
|
+
</svg>
|
|
48
|
+
</a>
|
|
49
|
+
</span>
|
|
50
|
+
<span class="hz-footer-built">
|
|
51
|
+
Built with
|
|
52
|
+
<a class="hz-footer-link" href={repoUrl} target="_blank" rel="noopener">
|
|
53
|
+
Handzon
|
|
54
|
+
<svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
55
|
+
<path d="M7 17 17 7" />
|
|
56
|
+
<path d="M7 7h10v10" />
|
|
57
|
+
</svg>
|
|
58
|
+
</a>
|
|
59
|
+
</span>
|
|
60
|
+
</div>
|
|
61
|
+
) : (
|
|
62
|
+
<div class="hz-footer-inner">
|
|
63
|
+
<span class="hz-footer-credit">
|
|
64
|
+
© {year} · Built with
|
|
65
|
+
<a class="hz-footer-link" href={repoUrl} target="_blank" rel="noopener">
|
|
66
|
+
Handzon
|
|
67
|
+
<svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
68
|
+
<path d="M7 17 17 7" />
|
|
69
|
+
<path d="M7 7h10v10" />
|
|
70
|
+
</svg>
|
|
71
|
+
</a>
|
|
72
|
+
</span>
|
|
73
|
+
</div>
|
|
74
|
+
)}
|
|
42
75
|
</footer>
|
|
43
76
|
|
|
44
77
|
<style is:global>
|
|
@@ -64,11 +97,24 @@ const {
|
|
|
64
97
|
font-family: var(--font-mono);
|
|
65
98
|
font-size: 0.75em;
|
|
66
99
|
}
|
|
100
|
+
/* Branded mode: site credit left, "Built with Handzon" right. Falls
|
|
101
|
+
* back to a stacked, centered layout on narrow viewports. */
|
|
102
|
+
.hz-footer-split {
|
|
103
|
+
justify-content: space-between;
|
|
104
|
+
gap: 0.75rem 1.5rem;
|
|
105
|
+
flex-wrap: wrap;
|
|
106
|
+
}
|
|
67
107
|
.hz-footer-credit {
|
|
68
108
|
display: inline-flex;
|
|
69
109
|
align-items: center;
|
|
70
110
|
gap: 0.45rem;
|
|
71
111
|
}
|
|
112
|
+
.hz-footer-built {
|
|
113
|
+
display: inline-flex;
|
|
114
|
+
align-items: center;
|
|
115
|
+
gap: 0.4rem;
|
|
116
|
+
opacity: 0.85;
|
|
117
|
+
}
|
|
72
118
|
.hz-footer-link {
|
|
73
119
|
display: inline-flex;
|
|
74
120
|
align-items: center;
|
|
@@ -34,6 +34,12 @@ interface Props {
|
|
|
34
34
|
showFooter?: boolean;
|
|
35
35
|
/** Footer link URL; defaults to the Handzon repo. */
|
|
36
36
|
repoUrl?: string;
|
|
37
|
+
/** Primary footer credit link (the site owner, e.g. https://render.com).
|
|
38
|
+
* When set, the footer leads with the site credit and demotes the
|
|
39
|
+
* Handzon link to a secondary side link. */
|
|
40
|
+
siteUrl?: string;
|
|
41
|
+
/** Primary footer credit label. Defaults to siteName. */
|
|
42
|
+
siteCreditLabel?: string;
|
|
37
43
|
/**
|
|
38
44
|
* Width of the page's content column. Drives the navbar + footer
|
|
39
45
|
* alignment via the --hz-page-max-width CSS custom property so the
|
|
@@ -63,6 +69,8 @@ const {
|
|
|
63
69
|
faviconUrl = "/favicon.svg",
|
|
64
70
|
showFooter = true,
|
|
65
71
|
repoUrl,
|
|
72
|
+
siteUrl,
|
|
73
|
+
siteCreditLabel,
|
|
66
74
|
// Default to a full-width navbar + footer with a small consistent
|
|
67
75
|
// inset, matching the tutorial step page. Pages with a centred
|
|
68
76
|
// column (home grid, tutorial landing) keep their own content
|
|
@@ -113,7 +121,17 @@ const desc = description ?? tagline;
|
|
|
113
121
|
<div class="hz-page">
|
|
114
122
|
<slot />
|
|
115
123
|
</div>
|
|
116
|
-
{
|
|
124
|
+
{/* Footer content is configurable via siteName/siteCreditLabel/siteUrl/repoUrl. For
|
|
125
|
+
a fully custom footer, a scaffold can pass showFooter={false} and
|
|
126
|
+
render its own markup in the page body. */}
|
|
127
|
+
{showFooter && (
|
|
128
|
+
<Footer
|
|
129
|
+
siteName={siteName}
|
|
130
|
+
siteCreditLabel={siteCreditLabel}
|
|
131
|
+
siteUrl={siteUrl}
|
|
132
|
+
repoUrl={repoUrl}
|
|
133
|
+
/>
|
|
134
|
+
)}
|
|
117
135
|
<script>
|
|
118
136
|
// Render any <pre class="mermaid"> blocks emitted by rehype-mermaid.
|
|
119
137
|
if (document.querySelector("pre.mermaid")) {
|
|
@@ -18,6 +18,10 @@ interface Props {
|
|
|
18
18
|
logoHeight?: number;
|
|
19
19
|
faviconUrl?: string;
|
|
20
20
|
repoUrl?: string;
|
|
21
|
+
siteUrl?: string;
|
|
22
|
+
siteCreditLabel?: string;
|
|
23
|
+
/** Set false to drop the built-in footer and supply your own. */
|
|
24
|
+
showFooter?: boolean;
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
const {
|
|
@@ -33,6 +37,9 @@ const {
|
|
|
33
37
|
logoHeight,
|
|
34
38
|
faviconUrl,
|
|
35
39
|
repoUrl,
|
|
40
|
+
siteUrl,
|
|
41
|
+
siteCreditLabel,
|
|
42
|
+
showFooter = true,
|
|
36
43
|
} = Astro.props;
|
|
37
44
|
|
|
38
45
|
const stepSlugs = steps.map((s) => parseStepId(s.id).stepSlug);
|
|
@@ -47,6 +54,9 @@ const stepSlugs = steps.map((s) => parseStepId(s.id).stepSlug);
|
|
|
47
54
|
logoHeight={logoHeight}
|
|
48
55
|
faviconUrl={faviconUrl}
|
|
49
56
|
repoUrl={repoUrl}
|
|
57
|
+
siteUrl={siteUrl}
|
|
58
|
+
siteCreditLabel={siteCreditLabel}
|
|
59
|
+
showFooter={showFooter}
|
|
50
60
|
>
|
|
51
61
|
<slot name="head" slot="head" />
|
|
52
62
|
<div class="layout">
|
package/src/pages/Home.astro
CHANGED
|
@@ -16,6 +16,10 @@ interface Props {
|
|
|
16
16
|
logoHeight?: number;
|
|
17
17
|
faviconUrl?: string;
|
|
18
18
|
repoUrl?: string;
|
|
19
|
+
siteUrl?: string;
|
|
20
|
+
siteCreditLabel?: string;
|
|
21
|
+
/** Set false to drop the built-in footer and supply your own. */
|
|
22
|
+
showFooter?: boolean;
|
|
19
23
|
showResumeRail?: boolean;
|
|
20
24
|
emptyStateCommand?: string;
|
|
21
25
|
/** Tutorials per page on the grid. */
|
|
@@ -31,6 +35,9 @@ const {
|
|
|
31
35
|
logoHeight,
|
|
32
36
|
faviconUrl,
|
|
33
37
|
repoUrl,
|
|
38
|
+
siteUrl,
|
|
39
|
+
siteCreditLabel,
|
|
40
|
+
showFooter = true,
|
|
34
41
|
showResumeRail = true,
|
|
35
42
|
emptyStateCommand = "pnpm handzon:new",
|
|
36
43
|
pageSize = 9,
|
|
@@ -64,6 +71,9 @@ for (const t of tutorials) {
|
|
|
64
71
|
logoHeight={logoHeight}
|
|
65
72
|
faviconUrl={faviconUrl}
|
|
66
73
|
repoUrl={repoUrl}
|
|
74
|
+
siteUrl={siteUrl}
|
|
75
|
+
siteCreditLabel={siteCreditLabel}
|
|
76
|
+
showFooter={showFooter}
|
|
67
77
|
nav="userMenu"
|
|
68
78
|
>
|
|
69
79
|
<slot name="head" slot="head" />
|
|
@@ -13,6 +13,10 @@ interface Props {
|
|
|
13
13
|
logoHeight?: number;
|
|
14
14
|
faviconUrl?: string;
|
|
15
15
|
repoUrl?: string;
|
|
16
|
+
siteUrl?: string;
|
|
17
|
+
siteCreditLabel?: string;
|
|
18
|
+
/** Set false to drop the built-in footer and supply your own. */
|
|
19
|
+
showFooter?: boolean;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
const {
|
|
@@ -24,6 +28,9 @@ const {
|
|
|
24
28
|
logoHeight,
|
|
25
29
|
faviconUrl,
|
|
26
30
|
repoUrl,
|
|
31
|
+
siteUrl,
|
|
32
|
+
siteCreditLabel,
|
|
33
|
+
showFooter = true,
|
|
27
34
|
} = Astro.props;
|
|
28
35
|
const steps = await getStepsForTutorial(tutorial.id);
|
|
29
36
|
const duration = tutorial.data.estimatedDuration ?? sumDurations(steps) ?? "";
|
|
@@ -39,6 +46,9 @@ const firstStepSlug = steps[0] ? parseStepId(steps[0].id).stepSlug : null;
|
|
|
39
46
|
logoHeight={logoHeight}
|
|
40
47
|
faviconUrl={faviconUrl}
|
|
41
48
|
repoUrl={repoUrl}
|
|
49
|
+
siteUrl={siteUrl}
|
|
50
|
+
siteCreditLabel={siteCreditLabel}
|
|
51
|
+
showFooter={showFooter}
|
|
42
52
|
>
|
|
43
53
|
<slot name="head" slot="head" />
|
|
44
54
|
<div class="landing">
|
|
@@ -24,6 +24,10 @@ interface Props {
|
|
|
24
24
|
logoHeight?: number;
|
|
25
25
|
faviconUrl?: string;
|
|
26
26
|
repoUrl?: string;
|
|
27
|
+
siteUrl?: string;
|
|
28
|
+
siteCreditLabel?: string;
|
|
29
|
+
/** Set false to drop the built-in footer and supply your own. */
|
|
30
|
+
showFooter?: boolean;
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
const {
|
|
@@ -38,6 +42,9 @@ const {
|
|
|
38
42
|
logoHeight,
|
|
39
43
|
faviconUrl,
|
|
40
44
|
repoUrl,
|
|
45
|
+
siteUrl,
|
|
46
|
+
siteCreditLabel,
|
|
47
|
+
showFooter = true,
|
|
41
48
|
} = Astro.props;
|
|
42
49
|
const { stepSlug } = parseStepId(currentStep.id);
|
|
43
50
|
const { Content } = await render(currentStep);
|
|
@@ -68,6 +75,9 @@ const initialContext = buildContext({
|
|
|
68
75
|
logoHeight={logoHeight}
|
|
69
76
|
faviconUrl={faviconUrl}
|
|
70
77
|
repoUrl={repoUrl}
|
|
78
|
+
siteUrl={siteUrl}
|
|
79
|
+
siteCreditLabel={siteCreditLabel}
|
|
80
|
+
showFooter={showFooter}
|
|
71
81
|
>
|
|
72
82
|
<slot name="head" slot="head" />
|
|
73
83
|
<Content components={components} />
|