Skip to content

Commit 69db237

Browse files
feat: /pricing page — "Death is free. So is this."
86 visitors/year were hitting /pricing and getting redirected to home. Replace the redirect with a brand-aligned landing page that: - Reinforces no-pricing-ever policy in 5 short sections - Converts visitors to repo-input via "Bury a repo" CTA - Keeps gothic morgue voice consistent with /about Also adds /pricing to sitemap.ts for SEO indexing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 7ab573d commit 69db237

7 files changed

Lines changed: 140 additions & 19 deletions

File tree

next.config.mjs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
const nextConfig = {
33
async redirects() {
44
return [
5-
{ source: '/pricing', destination: '/', permanent: true },
65
{ source: '/privacy', destination: '/about', permanent: true },
76
{ source: '/terms', destination: '/about', permanent: true },
87
]

src/app/pricing/PricingContent.tsx

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
'use client'
2+
3+
import Link from 'next/link'
4+
import SubpageShell from '@/components/SubpageShell'
5+
6+
const SECTIONS = [
7+
{
8+
id: 'no-tiers',
9+
heading: 'No Tiers, No Trials, No Tricks',
10+
body: 'There is no Basic. There is no Pro. There is no Enterprise. Every funeral receives the same rites, the same paperwork, the same dignified treatment.',
11+
},
12+
{
13+
id: 'no-accounts',
14+
heading: 'No Account Required',
15+
body: 'You will not be asked for an email. You will not be asked to subscribe. The deceased never asked for credentials, and neither do we.',
16+
},
17+
{
18+
id: 'no-ads',
19+
heading: 'No Advertisements',
20+
body: 'No banners. No popups. No "sponsored by". The morgue is not a marketplace.',
21+
},
22+
{
23+
id: 'open-source',
24+
heading: 'Open Source Forever',
25+
body: 'The code is on GitHub under MIT license. Fork it. Self-host it. Improve it. The undertaker has no secrets.',
26+
github: true,
27+
},
28+
{
29+
id: 'how-we-survive',
30+
heading: 'How We Stay Alive',
31+
body: 'Commitment Issues is built and maintained by Dot Systems — an indie studio that funds this work from other projects. If you want to support it, fork it, share it, or open a pull request with new famous casualties.',
32+
},
33+
]
34+
35+
export default function PricingContent() {
36+
return (
37+
<SubpageShell
38+
title="Death Is Free."
39+
subtitle={
40+
<span style={{
41+
fontFamily: `var(--font-courier), system-ui, sans-serif`,
42+
fontSize: '12px',
43+
color: 'var(--c-muted)',
44+
letterSpacing: '0.04em',
45+
}}>
46+
So is this.
47+
</span>
48+
}
49+
microcopy={null}
50+
>
51+
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
52+
{SECTIONS.map(({ id, heading, body, github }) => (
53+
<div
54+
key={id}
55+
className="record-card"
56+
style={{ border: '2px solid var(--c-border)' }}
57+
>
58+
<p className="record-label">{heading}</p>
59+
<p className="record-value" style={{ fontSize: 'clamp(14px, 3.8vw, 15px)', lineHeight: 1.75, color: 'var(--c-ink-2)' }}>
60+
{body}
61+
</p>
62+
{github && (
63+
<a
64+
href="https://github.com/dotsystemsdevs/commitmentissues"
65+
target="_blank"
66+
rel="noopener noreferrer"
67+
className="subpage-faq-cta"
68+
style={{ marginTop: '14px', display: 'inline-flex' }}
69+
>
70+
★ View on GitHub
71+
</a>
72+
)}
73+
</div>
74+
))}
75+
76+
<div
77+
className="record-card"
78+
style={{
79+
border: '2px solid var(--c-border)',
80+
background: 'var(--c-panel-2, transparent)',
81+
textAlign: 'center',
82+
padding: '28px 20px',
83+
marginTop: '8px',
84+
}}
85+
>
86+
<p className="record-label" style={{ marginBottom: '14px' }}>Begin the Examination</p>
87+
<Link
88+
href="/"
89+
className="subpage-faq-cta"
90+
style={{ display: 'inline-flex', justifyContent: 'center' }}
91+
>
92+
⚰ Bury a repo →
93+
</Link>
94+
</div>
95+
</div>
96+
</SubpageShell>
97+
)
98+
}

src/app/pricing/page.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { Metadata } from 'next'
2+
import PricingContent from './PricingContent'
3+
4+
export const metadata: Metadata = {
5+
title: 'Pricing — Commitment Issues | Death Is Free',
6+
description: 'No price. No paywall. No premium tier. Commitment Issues is free and open source forever. Death does not charge admission.',
7+
alternates: { canonical: 'https://commitmentissues.dev/pricing' },
8+
openGraph: {
9+
title: 'Pricing — Commitment Issues | Death Is Free',
10+
description: 'No price. No paywall. No premium tier. Commitment Issues is free and open source forever.',
11+
url: 'https://commitmentissues.dev/pricing',
12+
},
13+
}
14+
15+
export default function PricingPage() {
16+
return <PricingContent />
17+
}

src/app/sitemap.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ const BASE_URL = 'https://commitmentissues.dev'
55
export default function sitemap(): MetadataRoute.Sitemap {
66
const now = new Date()
77
return [
8-
{ url: BASE_URL, lastModified: now, changeFrequency: 'weekly', priority: 1.0 },
9-
{ url: `${BASE_URL}/faq`, lastModified: now, changeFrequency: 'monthly', priority: 0.9 },
10-
{ url: `${BASE_URL}/about`, lastModified: now, changeFrequency: 'monthly', priority: 0.6 },
11-
{ url: `${BASE_URL}/legal`, lastModified: now, changeFrequency: 'yearly', priority: 0.3 },
8+
{ url: BASE_URL, lastModified: now, changeFrequency: 'weekly', priority: 1.0 },
9+
{ url: `${BASE_URL}/faq`, lastModified: now, changeFrequency: 'monthly', priority: 0.9 },
10+
{ url: `${BASE_URL}/pricing`, lastModified: now, changeFrequency: 'monthly', priority: 0.7 },
11+
{ url: `${BASE_URL}/about`, lastModified: now, changeFrequency: 'monthly', priority: 0.6 },
12+
{ url: `${BASE_URL}/legal`, lastModified: now, changeFrequency: 'yearly', priority: 0.3 },
1213
]
1314
}

src/components/ReadmeBadge.tsx

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,16 @@ export default function ReadmeBadge({ username }: Props) {
2727
}
2828

2929
return (
30-
<div className="readme-badge-block readme-badge-block--profile record-card" style={{ width: '100%', marginBottom: '22px', border: '2px solid #1a1a1a' }}>
30+
<div
31+
className="readme-badge-block readme-badge-block--profile record-card"
32+
style={{
33+
width: '100%',
34+
marginBottom: '22px',
35+
background: 'var(--c-surface)',
36+
border: '2px solid var(--c-border)',
37+
padding: '16px 18px',
38+
}}
39+
>
3140
{/* Badge preview — the SVG already has its own border; keep the wrapper borderless */}
3241
<div className="readme-badge-preview" style={{ width: '100%', aspectRatio: '440 / 96' }}>
3342
{/* eslint-disable-next-line @next/next/no-img-element */}
@@ -55,24 +64,24 @@ export default function ReadmeBadge({ username }: Props) {
5564
letterSpacing: '0.06em',
5665
padding: '8px 14px',
5766
minHeight: '36px',
58-
background: copied ? '#2d7a3c' : 'transparent',
59-
color: copied ? '#fff' : '#4a4440',
60-
border: `2px solid ${copied ? '#2d7a3c' : '#cec6bb'}`,
67+
background: copied ? 'var(--c-green)' : 'transparent',
68+
color: copied ? 'var(--c-bg)' : 'var(--c-ink-2)',
69+
border: `2px solid ${copied ? 'var(--c-green)' : 'var(--c-border-light)'}`,
6170
cursor: 'pointer',
6271
transition: 'all 0.15s',
6372
whiteSpace: 'nowrap',
6473
flexShrink: 0,
6574
}}
6675
onMouseEnter={e => {
6776
if (!copied) {
68-
e.currentTarget.style.borderColor = '#1a1a1a'
69-
e.currentTarget.style.color = '#1a1a1a'
77+
e.currentTarget.style.borderColor = 'var(--c-ink)'
78+
e.currentTarget.style.color = 'var(--c-ink)'
7079
}
7180
}}
7281
onMouseLeave={e => {
7382
if (!copied) {
74-
e.currentTarget.style.borderColor = '#cec6bb'
75-
e.currentTarget.style.color = '#4a4440'
83+
e.currentTarget.style.borderColor = 'var(--c-border-light)'
84+
e.currentTarget.style.color = 'var(--c-ink-2)'
7685
}
7786
}}
7887
>

src/components/ScannerBanner.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export default function ScannerBanner() {
4646
left: 0,
4747
right: 0,
4848
zIndex: 1001,
49-
background: 'var(--c-border)',
49+
background: 'var(--c-ink)',
5050
height: '32px',
5151
display: 'flex',
5252
alignItems: 'center',
@@ -89,7 +89,7 @@ export default function ScannerBanner() {
8989
style={{ color: 'var(--c-bg)', textDecoration: 'none', display: 'inline-flex', alignItems: 'center', gap: '6px' }}
9090
>
9191
<span aria-hidden style={{ opacity: 0.9 }}>🪦</span>
92-
<span style={{ textDecoration: 'underline', textUnderlineOffset: '2px', textDecorationColor: 'rgba(255,255,255,0.2)' }}>
92+
<span style={{ textDecoration: 'underline', textUnderlineOffset: '2px', textDecorationColor: 'color-mix(in srgb, var(--c-bg) 30%, transparent)' }}>
9393
{entry.fullName}
9494
</span>
9595
</Link>
@@ -99,7 +99,7 @@ export default function ScannerBanner() {
9999
})}
100100
</div>
101101
</div>
102-
<div style={{ padding: '0 8px', display: 'flex', alignItems: 'center', borderLeft: '1px solid rgba(255,255,255,0.1)', height: '100%' }}>
102+
<div style={{ padding: '0 8px', display: 'flex', alignItems: 'center', borderLeft: '1px solid color-mix(in srgb, var(--c-bg) 20%, transparent)', height: '100%' }}>
103103
<ThemeToggle />
104104
</div>
105105
</div>

src/components/SiteFooter.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import Link from 'next/link'
44
import GitHubIcon from '@/components/GitHubIcon'
5-
import ThemeToggle from '@/components/ThemeToggle'
65

76
const FONT = `var(--font-courier), system-ui, sans-serif`
87

@@ -50,8 +49,6 @@ export default function SiteFooter({ compact = false }: SiteFooterProps) {
5049
<GitHubIcon size={13} />
5150
Open source
5251
</a>
53-
<span style={{ color: 'var(--c-border-light)', fontSize: '12px' }}>·</span>
54-
<ThemeToggle />
5552
</div>
5653
</footer>
5754
)

0 commit comments

Comments
 (0)