@the-smithy/create-hearth-site 0.19.0 → 0.21.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/bin/create-hearth-site.js +5 -0
- package/package.json +2 -2
- package/template/AGENTS.md +11 -2
- package/template/CLAUDE.md +87 -20
- package/template/README.md +55 -24
- package/template/SITE.md +17 -0
- package/template/package.json +3 -1
- package/template/scripts/hearth.mjs +194 -14
- package/template/src/app/[[...slug]]/page.tsx +2 -54
- package/template/src/app/api/preview/exit/route.ts +1 -1
- package/template/src/app/api/preview/route.ts +1 -1
- package/template/src/app/api/revalidate/route.ts +1 -1
- package/template/src/app/apple-icon.tsx +1 -1
- package/template/src/app/donate/page.tsx +2 -35
- package/template/src/app/donate/thank-you/page.tsx +2 -22
- package/template/src/app/events/[slug]/page.tsx +2 -26
- package/template/src/app/events/page.tsx +2 -29
- package/template/src/app/fundraisers/[slug]/page.tsx +2 -55
- package/template/src/app/fundraisers/page.tsx +2 -37
- package/template/src/app/globals.css +3 -74
- package/template/src/app/icon.tsx +1 -1
- package/template/src/app/layout.tsx +2 -36
- package/template/src/app/not-found.tsx +2 -14
- package/template/src/app/registered/page.tsx +2 -22
- package/template/src/app/robots.ts +1 -1
- package/template/src/app/sitemap.ts +2 -2
- package/template/src/{app → hearth}/actions.ts +15 -1
- package/template/src/hearth/blocks/OpenMap.tsx +104 -0
- package/template/src/hearth/blocks/collections.tsx +74 -0
- package/template/src/hearth/blocks/content.tsx +252 -0
- package/template/src/hearth/blocks/custom.tsx +12 -0
- package/template/src/hearth/blocks/events.tsx +130 -0
- package/template/src/hearth/blocks/giving.tsx +123 -0
- package/template/src/{components → hearth}/blocks/index.tsx +17 -11
- package/template/src/hearth/blocks/info.tsx +84 -0
- package/template/src/{components → hearth}/blocks/media.tsx +30 -27
- package/template/src/hearth/components/EventView.tsx +120 -0
- package/template/src/{components → hearth/components}/Registration.tsx +14 -14
- package/template/src/hearth/components/Share.tsx +102 -0
- package/template/src/hearth/format.ts +31 -0
- package/template/src/hearth/forms/ContactForm.tsx +27 -0
- package/template/src/hearth/forms/DonateForm.tsx +69 -0
- package/template/src/{components/blocks → hearth/forms}/EmberFormBlock.tsx +6 -5
- package/template/src/hearth/forms/RegistrationForm.tsx +68 -0
- package/template/src/hearth/forms/VolunteerForm.tsx +58 -0
- package/template/src/hearth/forms/fields.tsx +137 -0
- package/template/src/hearth/hearth.css +52 -0
- package/template/src/hearth/layout/MobileNav.tsx +49 -0
- package/template/src/hearth/layout/NavLink.tsx +16 -0
- package/template/src/hearth/layout/RootLayout.tsx +40 -0
- package/template/src/{components → hearth/layout}/SiteFooter.tsx +19 -14
- package/template/src/hearth/layout/SiteHeader.tsx +53 -0
- package/template/src/hearth/manifest.json +36 -0
- package/template/src/hearth/pages/donate.tsx +36 -0
- package/template/src/hearth/pages/event.tsx +26 -0
- package/template/src/hearth/pages/events.tsx +30 -0
- package/template/src/hearth/pages/fundraiser.tsx +77 -0
- package/template/src/hearth/pages/fundraisers.tsx +38 -0
- package/template/src/hearth/pages/not-found.tsx +15 -0
- package/template/src/hearth/pages/page.tsx +54 -0
- package/template/src/hearth/pages/registered.tsx +19 -0
- package/template/src/hearth/pages/thank-you.tsx +19 -0
- package/template/src/hearth/theme/defaults.ts +510 -0
- package/template/src/hearth/theme/index.ts +31 -0
- package/template/src/hearth/ui.tsx +144 -0
- package/template/src/theme/custom-blocks.tsx +11 -0
- package/template/src/theme/fonts.ts +9 -0
- package/template/src/theme/index.ts +13 -0
- package/template/src/theme/overrides.tsx +16 -0
- package/template/src/theme/theme.css +29 -0
- package/template/src/components/DonateForm.tsx +0 -104
- package/template/src/components/EventView.tsx +0 -48
- package/template/src/components/RegistrationForm.tsx +0 -103
- package/template/src/components/SiteHeader.tsx +0 -37
- package/template/src/components/blocks/Form.tsx +0 -92
- package/template/src/components/blocks/collections.tsx +0 -75
- package/template/src/components/blocks/content.tsx +0 -257
- package/template/src/components/blocks/custom.tsx +0 -20
- package/template/src/components/blocks/events.tsx +0 -104
- package/template/src/components/blocks/giving.tsx +0 -120
- package/template/src/components/blocks/info.tsx +0 -52
- package/template/src/components/ui.tsx +0 -128
- /package/template/src/{lib/hearth.ts → hearth/client.ts} +0 -0
- /package/template/src/{lib → hearth}/site.ts +0 -0
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import Link from "next/link";
|
|
2
|
-
import { Fragment, type ReactNode } from "react";
|
|
3
|
-
import ReactMarkdown from "react-markdown";
|
|
4
|
-
|
|
5
|
-
type LinkRef = { label: string; href: string };
|
|
6
|
-
export type Tone = "default" | "muted" | "inverse" | "accent";
|
|
7
|
-
|
|
8
|
-
const toneClass: Record<Tone, string> = {
|
|
9
|
-
default: "bg-bg text-ink",
|
|
10
|
-
muted: "bg-muted text-ink",
|
|
11
|
-
inverse: "bg-inverse text-inverse-ink",
|
|
12
|
-
accent: "bg-accent text-accent-ink",
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export const isDark = (tone?: Tone) => tone === "inverse" || tone === "accent";
|
|
16
|
-
|
|
17
|
-
/** A full-width band with the site's content width inside. */
|
|
18
|
-
export function Section({ tone = "default", className = "", children }: { tone?: Tone; className?: string; children: ReactNode }) {
|
|
19
|
-
return (
|
|
20
|
-
<section className={toneClass[tone]}>
|
|
21
|
-
<div className={`mx-auto max-w-site px-4 py-16 sm:px-6 sm:py-20 ${className}`}>{children}</div>
|
|
22
|
-
</section>
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Headings may mark words with *asterisks* to highlight them:
|
|
28
|
-
* "Fresh bread, *baked daily*".
|
|
29
|
-
*/
|
|
30
|
-
export function Emphasis({ text, className = "text-highlight" }: { text: string; className?: string }) {
|
|
31
|
-
return (
|
|
32
|
-
<>
|
|
33
|
-
{text.split(/\*([^*]+)\*/g).map((part, i) =>
|
|
34
|
-
i % 2 ? (
|
|
35
|
-
<span key={i} className={className}>
|
|
36
|
-
{part}
|
|
37
|
-
</span>
|
|
38
|
-
) : (
|
|
39
|
-
<Fragment key={i}>{part}</Fragment>
|
|
40
|
-
),
|
|
41
|
-
)}
|
|
42
|
-
</>
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** The text without highlight markers, for alt text and titles. */
|
|
47
|
-
export const plain = (text: string) => text.replace(/\*([^*]+)\*/g, "$1");
|
|
48
|
-
|
|
49
|
-
export function SectionHeading({ eyebrow, heading, intro, dark }: { eyebrow?: string; heading?: string; intro?: string; dark?: boolean }) {
|
|
50
|
-
if (!eyebrow && !heading && !intro) return null;
|
|
51
|
-
return (
|
|
52
|
-
<div className="mb-10 max-w-3xl">
|
|
53
|
-
{eyebrow ? <p className="mb-3 text-sm font-semibold uppercase tracking-[0.18em] opacity-75">{eyebrow}</p> : null}
|
|
54
|
-
{heading ? (
|
|
55
|
-
<h2 className="text-[clamp(28px,3.4vw,40px)] font-bold leading-tight tracking-tight">
|
|
56
|
-
<Emphasis text={heading} className={dark ? "underline decoration-2 underline-offset-4" : "text-highlight"} />
|
|
57
|
-
</h2>
|
|
58
|
-
) : null}
|
|
59
|
-
{intro ? <p className="mt-4 text-lg leading-relaxed opacity-85">{intro}</p> : null}
|
|
60
|
-
</div>
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function Markdown({ children, className = "" }: { children: string; className?: string }) {
|
|
65
|
-
return (
|
|
66
|
-
<div className={`prose text-lg ${className}`}>
|
|
67
|
-
<ReactMarkdown>{children}</ReactMarkdown>
|
|
68
|
-
</div>
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const isExternal = (href: string) => /^(https?:|mailto:|tel:)/.test(href);
|
|
73
|
-
|
|
74
|
-
/** A link to a path on the site or to anywhere else. */
|
|
75
|
-
export function SmartLink({ href, className, children }: { href: string; className?: string; children: ReactNode }) {
|
|
76
|
-
return isExternal(href) ? (
|
|
77
|
-
<a href={href} className={className}>
|
|
78
|
-
{children}
|
|
79
|
-
</a>
|
|
80
|
-
) : (
|
|
81
|
-
<Link href={href} className={className}>
|
|
82
|
-
{children}
|
|
83
|
-
</Link>
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export function Button({ link, variant = "primary", dark }: { link?: LinkRef; variant?: "primary" | "secondary"; dark?: boolean }) {
|
|
88
|
-
if (!link) return null;
|
|
89
|
-
const cls =
|
|
90
|
-
variant === "primary"
|
|
91
|
-
? dark
|
|
92
|
-
? "rounded-lg bg-inverse-ink px-6 py-3.5 font-semibold text-inverse hover:opacity-90"
|
|
93
|
-
: "rounded-lg bg-accent px-6 py-3.5 font-semibold text-accent-ink hover:opacity-90"
|
|
94
|
-
: "rounded-lg border-[1.5px] border-current/40 px-6 py-3.5 font-medium hover:border-current";
|
|
95
|
-
return (
|
|
96
|
-
<SmartLink href={link.href} className={`inline-block ${cls}`}>
|
|
97
|
-
{link.label}
|
|
98
|
-
</SmartLink>
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* An image from Hearth. Its width and height (from Hearth's media library) reserve its space, so the page doesn't jump
|
|
104
|
-
* as it loads. `priority` loads it first: use it for the image at the top of the page (the hero), which is usually
|
|
105
|
-
* the largest thing on screen; everything else loads as it scrolls into view.
|
|
106
|
-
*/
|
|
107
|
-
/* eslint-disable @next/next/no-img-element -- Hearth serves media from its CDN at the uploaded size */
|
|
108
|
-
export function Img({
|
|
109
|
-
image,
|
|
110
|
-
className = "",
|
|
111
|
-
priority = false,
|
|
112
|
-
}: {
|
|
113
|
-
image: { src: string; alt: string; width?: number; height?: number };
|
|
114
|
-
className?: string;
|
|
115
|
-
priority?: boolean;
|
|
116
|
-
}) {
|
|
117
|
-
return (
|
|
118
|
-
<img
|
|
119
|
-
src={image.src}
|
|
120
|
-
alt={image.alt}
|
|
121
|
-
{...(image.width && image.height ? { width: image.width, height: image.height } : {})}
|
|
122
|
-
loading={priority ? "eager" : "lazy"}
|
|
123
|
-
fetchPriority={priority ? "high" : "auto"}
|
|
124
|
-
decoding={priority ? "sync" : "async"}
|
|
125
|
-
className={className}
|
|
126
|
-
/>
|
|
127
|
-
);
|
|
128
|
-
}
|
|
File without changes
|
|
File without changes
|