Skip to content

Commit 1d58357

Browse files
maskedsyntaxclaude
andcommitted
Add recovery toolkit, Pro features, and blog to website
- Surface the recovery toolkit and Patterns Pro tools: new homepage RecoveryToolkit section and a full /toolkit page (free vs Pro, how to use the app), with toolkit copy mirrored from the app. - Add a blog (/blog + posts) written first-person from the maintainer's POV as someone with OCD; article Open Graph tags via the Seo component. - Wire Toolkit and Blog into the navbar and footer; add both plus posts to the sitemap; bump site appVersion to 1.5.0 and update JSON-LD featureList/offers to include the toolkit and Pro. - Performance/SEO: load fonts off the critical path and drop unused italic/weight files; defer analytics to idle; shrink brand logo. - Use the spiral brand mark everywhere (favicon, apple-touch, PWA icons, navbar/footer brand) to match the app. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent b0733d5 commit 1d58357

22 files changed

Lines changed: 1820 additions & 11 deletions

website/src/app.html

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,52 @@
55
<meta name="viewport" content="width=device-width, initial-scale=1" />
66
<link rel="preconnect" href="https://fonts.googleapis.com" />
77
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
8+
<!-- Fonts loaded off the critical path: preload the stylesheet, then flip it
9+
from media="print" to "all" once it arrives so it never blocks first paint.
10+
Only the weights/styles actually used are requested (no unused italics). -->
11+
<link
12+
rel="preload"
13+
as="style"
14+
href="https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600;9..40,700&family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600;9..144,700&family=Lora:ital,wght@0,400;0,500;0,600;1,400&display=swap"
15+
/>
816
<link
9-
href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,400;0,9..144,500;0,9..144,600;0,9..144,700;1,9..144,400&family=Lora:ital,wght@0,400;0,500;0,600;1,400&display=swap"
1017
rel="stylesheet"
18+
href="https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600;9..40,700&family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600;9..144,700&family=Lora:ital,wght@0,400;0,500;0,600;1,400&display=swap"
19+
media="print"
20+
onload="this.media='all'"
1121
/>
12-
<link rel="icon" type="image/png" href="%sveltekit.assets%/favicon.png" />
22+
<noscript>
23+
<link
24+
rel="stylesheet"
25+
href="https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600;9..40,700&family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600;9..144,700&family=Lora:ital,wght@0,400;0,500;0,600;1,400&display=swap"
26+
/>
27+
</noscript>
28+
<link rel="icon" type="image/png" sizes="64x64" href="%sveltekit.assets%/favicon.png" />
29+
<link rel="apple-touch-icon" href="%sveltekit.assets%/apple-touch-icon.png" />
1330
<link rel="manifest" href="%sveltekit.assets%/manifest.json" />
1431
<meta name="apple-itunes-app" content="app-id=6762611172, app-argument=https://patterns.maskedsyntax.com/" />
15-
<script async src="https://www.googletagmanager.com/gtag/js?id=G-CGS962TNLY"></script>
32+
<!-- Analytics deferred to the browser idle callback so it never competes with
33+
content for the main thread during initial load. -->
1634
<script>
1735
window.dataLayer = window.dataLayer || [];
1836
function gtag() {
1937
dataLayer.push(arguments);
2038
}
21-
gtag('js', new Date());
22-
gtag('config', 'G-CGS962TNLY');
39+
(function () {
40+
var loadAnalytics = function () {
41+
var s = document.createElement('script');
42+
s.async = true;
43+
s.src = 'https://www.googletagmanager.com/gtag/js?id=G-CGS962TNLY';
44+
document.head.appendChild(s);
45+
gtag('js', new Date());
46+
gtag('config', 'G-CGS962TNLY');
47+
};
48+
if ('requestIdleCallback' in window) {
49+
requestIdleCallback(loadAnalytics, { timeout: 4000 });
50+
} else {
51+
window.addEventListener('load', loadAnalytics);
52+
}
53+
})();
2354
</script>
2455
%sveltekit.head%
2556
</head>

website/src/lib/components/Navbar.svelte

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
const learnLinks = [
2222
{ label: 'Understanding OCD', href: '/ocd' },
2323
{ label: 'ERP & how it helps', href: '/erp' },
24+
{ label: 'Recovery toolkit', href: '/toolkit' },
2425
{ label: 'FAQ', href: '/faq' }
2526
];
2627
@@ -110,6 +111,7 @@
110111
{/each}
111112
</div>
112113
</div>
114+
<a href="/blog" class="nav-link">Blog</a>
113115
<button type="button" onclick={goPrivacy}>Privacy</button>
114116
<button
115117
type="button"
@@ -184,6 +186,7 @@
184186
</div>
185187

186188
<div class="mobile-nav-section">
189+
<a href="/blog" onclick={closeMobile}>Blog</a>
187190
<button type="button" onclick={goPrivacy}>Privacy</button>
188191
</div>
189192
</nav>
@@ -250,14 +253,16 @@
250253
gap: 32px;
251254
}
252255
253-
.desktop-links button {
256+
.desktop-links button,
257+
.desktop-links .nav-link {
254258
font-size: 14px;
255259
font-weight: 500;
256260
color: color-mix(in srgb, var(--text) 65%, transparent);
257261
transition: color 0.2s;
258262
}
259263
260-
.desktop-links button:hover {
264+
.desktop-links button:hover,
265+
.desktop-links .nav-link:hover {
261266
color: var(--text);
262267
}
263268

website/src/lib/components/Seo.svelte

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
ogType = 'website',
1313
twitterCard = 'summary_large_image',
1414
keywords,
15-
jsonLd = []
15+
jsonLd = [],
16+
article
1617
}: {
1718
title: string;
1819
description: string;
@@ -23,6 +24,8 @@
2324
twitterCard?: string;
2425
keywords?: string;
2526
jsonLd?: Record<string, unknown>[];
27+
/** Extra Open Graph metadata for article pages (blog posts). */
28+
article?: { publishedTime?: string; modifiedTime?: string; author?: string };
2629
} = $props();
2730
2831
const url = $derived(`${links.site}${path}`);
@@ -45,6 +48,18 @@
4548
<meta property="og:image:height" content={String(site.ogImageHeight)} />
4649
<meta property="og:image:alt" content={imageAlt} />
4750

51+
{#if article}
52+
{#if article.publishedTime}
53+
<meta property="article:published_time" content={article.publishedTime} />
54+
{/if}
55+
{#if article.modifiedTime}
56+
<meta property="article:modified_time" content={article.modifiedTime} />
57+
{/if}
58+
{#if article.author}
59+
<meta property="article:author" content={article.author} />
60+
{/if}
61+
{/if}
62+
4863
<meta name="twitter:card" content={twitterCard} />
4964
<meta name="twitter:title" content={title} />
5065
<meta name="twitter:description" content={description} />

0 commit comments

Comments
 (0)