Skip to content

Commit 44c88bf

Browse files
committed
feat(website): add OCD/ERP content hub, SEO depth, and refreshed support section
- Add evergreen educational pages: /ocd (Understanding OCD), /erp (ERP & how Patterns helps), and /faq, with empathy-first copy and a medical disclaimer - Enrich homepage with Understanding and BuiltForErp sections; refresh hero and feature copy to be ERP-aware - Centralize per-page SEO in a reusable Seo component + site.ts version source; fix stale softwareVersion (1.1.2 -> 1.4.0) - Add FAQPage, MedicalWebPage, and BreadcrumbList structured data - Add purpose-built 1200x630 OG share image and summary_large_image card - Surface new pages via a Learn nav dropdown and a footer Resources column - Rework Support section to the brand amber palette (drop Ko-fi blue) - Update sitemap with new routes
1 parent 2180549 commit 44c88bf

23 files changed

Lines changed: 1690 additions & 181 deletions
Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
<script lang="ts">
2+
import type { Snippet } from 'svelte';
3+
import type { LucideIcon } from '$lib/types/icons';
4+
import ContentContainer from '$lib/components/ContentContainer.svelte';
5+
import AnimatedOnScroll from '$lib/components/AnimatedOnScroll.svelte';
6+
import MedicalDisclaimer from '$lib/components/MedicalDisclaimer.svelte';
7+
import { ArrowRight } from 'lucide-svelte';
8+
9+
type RelatedLink = { label: string; href: string };
10+
11+
let {
12+
icon,
13+
eyebrow,
14+
title,
15+
intro,
16+
children,
17+
related = []
18+
}: {
19+
icon: LucideIcon;
20+
eyebrow: string;
21+
title: string;
22+
intro: string;
23+
children: Snippet;
24+
related?: RelatedLink[];
25+
} = $props();
26+
27+
const Icon = $derived(icon);
28+
</script>
29+
30+
<article class="guide section-pad">
31+
<ContentContainer>
32+
<AnimatedOnScroll>
33+
<div class="head">
34+
<div class="icon-tile">
35+
<Icon size={34} color="var(--accent)" strokeWidth={1.75} />
36+
</div>
37+
<p class="eyebrow">{eyebrow}</p>
38+
<h1 class="title serif">{title}</h1>
39+
<p class="intro">{intro}</p>
40+
</div>
41+
42+
<div class="prose reading">
43+
{@render children()}
44+
</div>
45+
46+
<div class="disclaimer-wrap">
47+
<MedicalDisclaimer />
48+
</div>
49+
50+
{#if related.length}
51+
<nav class="related" aria-label="Related pages">
52+
{#each related as link}
53+
<a href={link.href} class="related-card">
54+
<span>{link.label}</span>
55+
<ArrowRight size={18} />
56+
</a>
57+
{/each}
58+
</nav>
59+
{/if}
60+
61+
<div class="back-wrap">
62+
<a href="/">← Back to Home</a>
63+
</div>
64+
</AnimatedOnScroll>
65+
</ContentContainer>
66+
</article>
67+
68+
<style>
69+
.guide {
70+
background: var(--surface);
71+
}
72+
73+
.head {
74+
max-width: 720px;
75+
margin: 0 auto 48px;
76+
text-align: center;
77+
}
78+
79+
.icon-tile {
80+
width: 80px;
81+
height: 80px;
82+
margin: 0 auto 28px;
83+
display: flex;
84+
align-items: center;
85+
justify-content: center;
86+
border-radius: 20px;
87+
background: color-mix(in srgb, var(--accent) 10%, transparent);
88+
}
89+
90+
.eyebrow {
91+
margin: 0 0 12px;
92+
font-size: 13px;
93+
font-weight: 600;
94+
letter-spacing: 0.08em;
95+
text-transform: uppercase;
96+
color: var(--accent);
97+
}
98+
99+
.title {
100+
margin: 0;
101+
font-size: 48px;
102+
line-height: 1.1;
103+
}
104+
105+
.intro {
106+
margin: 20px auto 0;
107+
max-width: 620px;
108+
font-size: 19px;
109+
line-height: 1.6;
110+
color: var(--text-secondary);
111+
}
112+
113+
/* Long-form prose. Children supply <h2>, <p>, <ul>, etc. */
114+
.prose {
115+
max-width: 720px;
116+
margin: 0 auto;
117+
font-size: 17px;
118+
color: var(--text-secondary);
119+
}
120+
121+
.prose :global(h2) {
122+
margin: 48px 0 16px;
123+
font-size: 28px;
124+
line-height: 1.2;
125+
color: var(--text);
126+
}
127+
128+
.prose :global(h3) {
129+
margin: 32px 0 10px;
130+
font-size: 20px;
131+
color: var(--text);
132+
}
133+
134+
.prose :global(p) {
135+
margin: 0 0 18px;
136+
}
137+
138+
.prose :global(strong) {
139+
color: var(--text);
140+
font-weight: 600;
141+
}
142+
143+
.prose :global(a) {
144+
color: var(--accent);
145+
text-decoration: underline;
146+
text-underline-offset: 3px;
147+
}
148+
149+
.prose :global(ul) {
150+
margin: 0 0 18px;
151+
padding-left: 22px;
152+
}
153+
154+
.prose :global(li) {
155+
margin: 0 0 10px;
156+
}
157+
158+
.prose :global(.lead) {
159+
font-size: 20px;
160+
line-height: 1.6;
161+
color: var(--text);
162+
}
163+
164+
/* Reusable "cycle" / step visual used inside guides. */
165+
.prose :global(.cycle) {
166+
display: flex;
167+
flex-wrap: wrap;
168+
gap: 10px;
169+
align-items: stretch;
170+
margin: 8px 0 28px;
171+
}
172+
173+
.prose :global(.cycle-step) {
174+
flex: 1 1 140px;
175+
padding: 16px;
176+
border-radius: 14px;
177+
border: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
178+
background: color-mix(in srgb, var(--bg) 40%, transparent);
179+
}
180+
181+
.prose :global(.cycle-step h4) {
182+
margin: 0 0 6px;
183+
font-size: 15px;
184+
font-weight: 700;
185+
color: var(--text);
186+
}
187+
188+
.prose :global(.cycle-step p) {
189+
margin: 0;
190+
font-size: 14px;
191+
line-height: 1.5;
192+
}
193+
194+
/* Callout box for "How Patterns helps" moments. */
195+
.prose :global(.callout) {
196+
margin: 28px 0;
197+
padding: 24px;
198+
border-radius: 16px;
199+
border: 1px solid color-mix(in srgb, var(--accent) 22%, transparent);
200+
background: color-mix(in srgb, var(--accent) 6%, transparent);
201+
}
202+
203+
.prose :global(.callout h3) {
204+
margin: 0 0 8px;
205+
}
206+
207+
.prose :global(.callout p:last-child) {
208+
margin-bottom: 0;
209+
}
210+
211+
.disclaimer-wrap {
212+
max-width: 720px;
213+
margin: 48px auto 0;
214+
}
215+
216+
.related {
217+
max-width: 720px;
218+
margin: 32px auto 0;
219+
display: grid;
220+
gap: 12px;
221+
grid-template-columns: 1fr;
222+
}
223+
224+
@media (min-width: 600px) {
225+
.related {
226+
grid-template-columns: repeat(2, 1fr);
227+
}
228+
}
229+
230+
.related-card {
231+
display: flex;
232+
align-items: center;
233+
justify-content: space-between;
234+
gap: 12px;
235+
padding: 18px 20px;
236+
border-radius: 14px;
237+
border: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
238+
font-weight: 600;
239+
color: var(--text);
240+
transition: border-color 0.2s, color 0.2s;
241+
}
242+
243+
.related-card:hover {
244+
border-color: color-mix(in srgb, var(--accent) 55%, transparent);
245+
color: var(--accent);
246+
}
247+
248+
.back-wrap {
249+
text-align: center;
250+
margin-top: 48px;
251+
}
252+
253+
.back-wrap a {
254+
font-weight: 600;
255+
color: var(--accent);
256+
}
257+
258+
@media (max-width: 599px) {
259+
.title {
260+
font-size: 34px;
261+
}
262+
263+
.intro {
264+
font-size: 16px;
265+
}
266+
267+
.prose {
268+
font-size: 16px;
269+
}
270+
271+
.prose :global(h2) {
272+
font-size: 24px;
273+
}
274+
}
275+
</style>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<script lang="ts">
2+
import { Info } from 'lucide-svelte';
3+
4+
let { compact = false }: { compact?: boolean } = $props();
5+
</script>
6+
7+
<aside class="disclaimer" class:compact aria-label="Health disclaimer">
8+
<Info size={compact ? 18 : 20} color="var(--accent)" strokeWidth={1.75} />
9+
<p>
10+
Patterns is a self-reflection and tracking tool. It supports your own journaling
11+
and ERP practice — it does not diagnose, treat, or cure OCD, and it is
12+
<strong>not a substitute for care from a qualified clinician</strong>. If you're
13+
struggling, reaching out to a mental health professional is a sign of strength.
14+
</p>
15+
</aside>
16+
17+
<style>
18+
.disclaimer {
19+
display: flex;
20+
gap: 12px;
21+
align-items: flex-start;
22+
padding: 18px 20px;
23+
border-radius: 14px;
24+
border: 1px solid color-mix(in srgb, var(--accent) 24%, transparent);
25+
background: color-mix(in srgb, var(--accent) 7%, transparent);
26+
}
27+
28+
.disclaimer :global(svg) {
29+
flex-shrink: 0;
30+
margin-top: 2px;
31+
}
32+
33+
.disclaimer p {
34+
margin: 0;
35+
font-size: 14px;
36+
line-height: 1.6;
37+
color: var(--text-secondary);
38+
}
39+
40+
.disclaimer strong {
41+
color: var(--text);
42+
font-weight: 600;
43+
}
44+
45+
.compact {
46+
padding: 14px 16px;
47+
}
48+
49+
.compact p {
50+
font-size: 13px;
51+
}
52+
</style>

0 commit comments

Comments
 (0)