Skip to main content

max / makenotwork

Fix dead links and hide unfinished surfaces on the public site Findings from the Aug 1 loose-wire sweep, groups 1 and 2 (landing and marketing, discovery and docs), each verified by an adversarial pass before being acted on. Dead docs links: the six "Other Policies" entries and the two pricing fine-print links pointed at /docs/legal/<slug> and /docs/guide/<slug>, but docengine flattens site-docs to bare slugs and the only route is the single-segment catch-all. All nine now resolve. "Creator guarantees" pointed at the signup page rather than the guarantees doc. /changelog 404s until a changelog project is published. The footer already guards it; economics.html and whats_new.js did not. Both now reuse that guard rather than duplicating the check, and the sitemap stops advertising the URL to crawlers. Both "Coming soon" surfaces are hidden per the Aug 1 gate: the use-cases block and the importer's unsupported-platform sentence. Also: the docs search input gained id, name and a label in all three templates that share the markup; the economics breadcrumb and header comment no longer describe a route that moved; "Read the commits" is relative so staging stops sending visitors to prod; the notify input gained autocomplete; and creators_page drops two per-request queries, two dead template fields, and a doc comment for a page that no longer works that way.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-01 19:37 UTC
Signed with PGP, not checked
Commit: 0b287a093eb9c60ddf9dcc8bd73141df99c20241
Parent: 27cea71
12 files changed, +48 insertions, -68 deletions
@@ -88,16 +88,24 @@
88 88 var body = document.createElement('p');
89 89 body.textContent = FEATURE_BODY;
90 90
91 - var link = document.createElement('a');
92 - link.href = '/changelog';
93 - link.textContent = 'Full changelog →';
94 - link.className = 'section-link';
95 - link.style.display = 'inline-block';
96 - link.style.marginTop = '0.75rem';
91 + // /changelog 404s until a changelog project is published, and base.html
92 + // only renders the footer link while it is. Reuse that server-side guard
93 + // rather than duplicating the check here.
94 + var link = null;
95 + if (document.querySelector('.site-footer-links a[href="/changelog"]')) {
96 + link = document.createElement('a');
97 + link.href = '/changelog';
98 + link.textContent = 'Full changelog →';
99 + link.className = 'section-link';
100 + link.style.display = 'inline-block';
101 + link.style.marginTop = '0.75rem';
102 + }
97 103
98 104 content.appendChild(header);
99 105 content.appendChild(body);
100 - content.appendChild(link);
106 + if (link) {
107 + content.appendChild(link);
108 + }
101 109 overlay.appendChild(content);
102 110 document.body.appendChild(overlay);
103 111 }
@@ -113,7 +113,7 @@
113 113
114 114 <div class="import-note">
115 115 <h3>Supported Formats</h3>
116 - <p>Currently supports generic CSV files. Upload a CSV with subscriber emails, transaction amounts, or item data, then map columns to the right fields. Coming soon: direct Substack, Ghost, Gumroad, Bandcamp, and Patreon imports.</p>
116 + <p>Currently supports generic CSV files. Upload a CSV with subscriber emails, transaction amounts, or item data, then map columns to the right fields.</p>
117 117 </div>
118 118 </div>
119 119
@@ -84,7 +84,7 @@
84 84 <p class="pricing-fineprint">
85 85 Every tier is the complete platform: <code>/u/username</code> profile, project and item pages, project forum, Discover listing, memberships, pay-what-you-want, promo codes, RSS, analytics, full data export, 2FA/passkeys. The tier picks the file-size envelope, not the feature set.
86 86 Sales are in USD; receiving payouts requires <a href="https://stripe.com/global">Stripe</a> in a supported country.
87 - <a href="/docs/guide/tiers">Full tier details</a> | <a href="/docs/guide/pricing">Pricing models</a>
87 + <a href="/docs/tiers">Full tier details</a> | <a href="/docs/pricing">Pricing models</a>
88 88 </p>
89 89
90 90 <p class="trial-callout">
@@ -11,7 +11,7 @@
11 11 <nav class="doc-breadcrumb">
12 12 <a href="/docs">Docs</a> / <span>{{ section }}</span>
13 13 <div class="docs-search-container docs-search-inline">
14 - <input type="text" class="docs-search-input" placeholder="Search docs..." autocomplete="off" />
14 + <input type="text" id="docs-search" name="docs-search" class="docs-search-input" placeholder="Search docs..." aria-label="Search docs" autocomplete="off" />
15 15 <div class="docs-search-results hidden"></div>
16 16 </div>
17 17 </nav>
@@ -11,7 +11,7 @@
11 11 <h1 class="docs-index-title">Documentation</h1>
12 12
13 13 <div class="docs-search-container">
14 - <input type="text" class="docs-search-input" placeholder="Search docs..." autocomplete="off" />
14 + <input type="text" id="docs-search" name="docs-search" class="docs-search-input" placeholder="Search docs..." aria-label="Search docs" autocomplete="off" />
15 15 <div class="docs-search-results hidden"></div>
16 16 </div>
17 17
@@ -2,9 +2,9 @@
2 2
3 3 This page carries live disclosure (paying-creator counts pulled from
4 4 the DB at request time) which docengine's static markdown pipeline
5 - can't express. It shadows the catch-all /docs/{slug} route so the
6 - URL stays at /docs/about/economics for backwards-compatibility with
7 - inbound links.
5 + can't express. It is served at the top-level /economics route, which is
6 + registered before the catch-all /docs/{slug} so axum prefers the exact
7 + match. /docs/economics 301-redirects here for inbound links.
8 8
9 9 Prose mirrors the previous economics.md content (deleted in the same
10 10 commit). To edit prose, edit this file. To edit the runway figure, edit
@@ -20,9 +20,9 @@
20 20
21 21 <article class="doc-container">
22 22 <nav class="doc-breadcrumb">
23 - <a href="/docs">Docs</a> / <span>About</span>
23 + <a href="/docs">Docs</a> / <span>Platform Economics</span>
24 24 <div class="docs-search-container docs-search-inline">
25 - <input type="text" class="docs-search-input" placeholder="Search docs..." autocomplete="off" />
25 + <input type="text" id="docs-search" name="docs-search" class="docs-search-input" placeholder="Search docs..." aria-label="Search docs" autocomplete="off" />
26 26 <div class="docs-search-results hidden"></div>
27 27 </div>
28 28 </nav>
@@ -55,7 +55,9 @@
55 55 <hr>
56 56
57 57 <h2>Where We Are</h2>
58 - <p>Numbers refresh at the close of every two-month sprint, alongside the <a href="/changelog">changelog</a> recap. The paying-creator count is read live from the database at the time you load this page.</p>
58 + {# Same guard the footer uses in base.html: /changelog 404s until a
59 + changelog project is published. See crate::changelog. #}
60 + <p>Numbers refresh at the close of every two-month sprint, alongside the {% if crate::changelog::is_published() %}<a href="/changelog">changelog</a>{% else %}changelog{% endif %} recap. The paying-creator count is read live from the database at the time you load this page.</p>
59 61
60 62 <ul>
61 63 <li>Paying creators today: <strong>{{ paying_creators }}</strong></li>
@@ -181,7 +181,7 @@
181 181 <h3 class="contrast-card-title">Hide the code</h3>
182 182 <ul class="contrast-card-links">
183 183 <li><a href="/docs/open-source">Source available</a></li>
184 - <li><a href="https://makenot.work/git/max/makenotwork/commits/main">Read the commits</a></li>
184 + <li><a href="/git/max/makenotwork/commits/main">Read the commits</a></li>
185 185 <li><a href="/docs/open-source">PolyForm-NC license</a></li>
186 186 </ul>
187 187 </li>
@@ -207,7 +207,7 @@
207 207 <h2 class="section-label">Stay in the loop</h2>
208 208 <p class="landing-prose mb-4">Get notified when something ships.</p>
209 209 <form class="notify-form" id="notify-form" data-submit="onNotifySubmit">
210 - <input type="email" name="email" placeholder="you@example.com" required class="notify-input" aria-label="Email address">
210 + <input type="email" name="email" placeholder="you@example.com" required class="notify-input" aria-label="Email address" autocomplete="email">
211 211 <button type="submit" class="btn-primary">Notify Me</button>
212 212 </form>
213 213 <p class="notify-status" id="notify-status"></p>
@@ -62,7 +62,7 @@
62 62 <li>You'll have the opportunity to appeal</li>
63 63 <li>You can export your data even while suspended (excluding content we can't legally host)</li>
64 64 </ul>
65 - <p>These commitments are part of our <a href="/creators">creator guarantees</a>.</p>
65 + <p>These commitments are part of our <a href="/docs/guarantees">creator guarantees</a>.</p>
66 66 </div>
67 67
68 68 <div class="policy-section">
@@ -80,12 +80,12 @@
80 80 <div class="policy-section">
81 81 <h2 class="section-header">Other Policies</h2>
82 82 <ul>
83 - <li><a href="/docs/legal/terms-of-service">Terms of Service</a>: what you agree to by using Makenot.work</li>
84 - <li><a href="/docs/legal/privacy-policy">Privacy Policy</a>: what we collect, why, and how to exercise your rights</li>
85 - <li><a href="/docs/legal/payments">Payments &amp; Refunds</a>: merchant-of-record model, refunds, chargebacks</li>
86 - <li><a href="/docs/legal/acceptable-use">Acceptable Use</a>: specific behaviour that gets accounts suspended</li>
87 - <li><a href="/docs/legal/copyright">Copyright &amp; DMCA</a>: how takedowns and counter-notifications work</li>
88 - <li><a href="/docs/legal/appeals">Appeals</a>: how to challenge a moderation decision</li>
83 + <li><a href="/docs/terms-of-service">Terms of Service</a>: what you agree to by using Makenot.work</li>
84 + <li><a href="/docs/privacy-policy">Privacy Policy</a>: what we collect, why, and how to exercise your rights</li>
85 + <li><a href="/docs/payments">Payments &amp; Refunds</a>: merchant-of-record model, refunds, chargebacks</li>
86 + <li><a href="/docs/acceptable-use">Acceptable Use</a>: specific behaviour that gets accounts suspended</li>
87 + <li><a href="/docs/copyright">Copyright &amp; DMCA</a>: how takedowns and counter-notifications work</li>
88 + <li><a href="/docs/appeals">Appeals</a>: how to challenge a moderation decision</li>
89 89 </ul>
90 90 </div>
91 91
@@ -135,35 +135,6 @@
135 135 </div>
136 136 </div>
137 137
138 - <div class="tier-section">
139 - <h2 class="section-label">Coming soon</h2>
140 - <div class="use-case-grid use-case-grid-2col">
141 - <div class="use-case-card coming-soon">
142 - <div class="use-case-title">Video Creators</div>
143 - <div class="use-case-who">Filmmakers, tutorial creators</div>
144 - <p class="use-case-desc">Upload and sell video content with adaptive streaming.</p>
145 - <ul class="use-case-features">
146 - <li>Video upload</li>
147 - <li>Adaptive streaming</li>
148 - <li>All existing features included</li>
149 - </ul>
150 - <div class="use-case-tier">Big Files ${{ tier_prices.big_files_std }}/mo &middot; {{ tier_prices.big_files_total }}, {{ tier_prices.big_files_per_file }}/file</div>
151 - </div>
152 -
153 - <div class="use-case-card coming-soon">
154 - <div class="use-case-title">Live Streamers</div>
155 - <div class="use-case-who">Musicians, educators, performers</div>
156 - <p class="use-case-desc">Live streaming with VOD archives and everything in the tiers below.</p>
157 - <ul class="use-case-features">
158 - <li>Live streaming</li>
159 - <li>VOD archives</li>
160 - <li>All existing features included</li>
161 - </ul>
162 - <div class="use-case-tier">Everything ${{ tier_prices.everything_std }}/mo &middot; {{ tier_prices.everything_total }}, all features</div>
163 - </div>
164 - </div>
165 - </div>
166 -
167 138 <div class="tier-section">
168 139 <h2 class="section-label">Everyone gets</h2>
169 140 <div class="feature-grid">