max / makenotwork
8 files changed,
+128 insertions,
-3 deletions
| @@ -53,11 +53,11 @@ Usability audit grade: B. Complexity C+, Completeness B+, Learnability B, Discov | |||
| 53 | 53 | ||
| 54 | 54 | ### Low (power-user improvements) | |
| 55 | 55 | ||
| 56 | - | - [ ] **[LOW]** Add bulk operations for item management — multi-select items in project Content tab for batch publish/unpublish/tag/price changes | |
| 57 | - | - [ ] **[LOW]** Add keyboard shortcuts — Cmd+K search, ? help overlay, p publish toggle, Esc close modal | |
| 56 | + | - [x] **[LOW]** Add bulk operations for item management — already implemented (publish/unpublish/delete in project Content tab with multi-select) | |
| 57 | + | - [x] **[LOW]** Add keyboard shortcuts — `?` help overlay with shortcut list, `Esc` closes modals, `Cmd+S` saves forms (Cmd+K deferred until global search) | |
| 58 | 58 | - [ ] **[LOW]** Add soft delete with 7-day recovery — items/projects currently hard-delete on confirmation. Add "Recently Deleted" archive with restore option | |
| 59 | 59 | - [ ] **[LOW]** Add wishlist/bookmark for fans — simple heart icon on item cards, DB table for saved items. Table-stakes vs Bandcamp/Gumroad/itch.io | |
| 60 | - | - [ ] **[LOW]** Add changelog or "What's New" — no mechanism to inform existing users about new features | |
| 60 | + | - [x] **[LOW]** Add changelog or "What's New" — `/changelog` page with entry history, linked from site footer | |
| 61 | 61 | ||
| 62 | 62 | ### Deferred (post-beta table stakes) | |
| 63 | 63 |
| @@ -251,6 +251,18 @@ pub(super) async fn policy_page( | |||
| 251 | 251 | } | |
| 252 | 252 | } | |
| 253 | 253 | ||
| 254 | + | /// Render the What's New / changelog page. | |
| 255 | + | #[tracing::instrument(skip_all, name = "landing::changelog_page")] | |
| 256 | + | pub(super) async fn changelog_page( | |
| 257 | + | session: Session, | |
| 258 | + | MaybeUser(maybe_user): MaybeUser, | |
| 259 | + | ) -> impl IntoResponse { | |
| 260 | + | ChangelogTemplate { | |
| 261 | + | csrf_token: get_csrf_token(&session).await, | |
| 262 | + | session_user: maybe_user, | |
| 263 | + | } | |
| 264 | + | } | |
| 265 | + | ||
| 254 | 266 | /// Query params for the Fan+ page. | |
| 255 | 267 | #[derive(Debug, Deserialize)] | |
| 256 | 268 | pub(super) struct FanPlusQuery { |
| @@ -71,6 +71,7 @@ pub fn public_routes() -> Router<AppState> { | |||
| 71 | 71 | .route("/pricing", get(landing::pricing_page)) | |
| 72 | 72 | .route("/use-cases", get(landing::use_cases_page)) | |
| 73 | 73 | .route("/policy", get(landing::policy_page)) | |
| 74 | + | .route("/changelog", get(landing::changelog_page)) | |
| 74 | 75 | .route("/fan-plus", get(landing::fan_plus_page)) | |
| 75 | 76 | .route("/creators", get(creators_page)) | |
| 76 | 77 | .route("/docs", get(docs::docs_index)) |
| @@ -81,6 +81,8 @@ impl_into_response!( | |||
| 81 | 81 | PricingTemplate, | |
| 82 | 82 | // Use cases | |
| 83 | 83 | UseCasesTemplate, | |
| 84 | + | // Changelog | |
| 85 | + | ChangelogTemplate, | |
| 84 | 86 | // Fan+ | |
| 85 | 87 | FanPlusTemplate, | |
| 86 | 88 | // Creator invite system |
| @@ -576,6 +576,14 @@ pub struct UseCasesTemplate { | |||
| 576 | 576 | pub session_user: Option<SessionUser>, | |
| 577 | 577 | } | |
| 578 | 578 | ||
| 579 | + | /// What's New / changelog page. | |
| 580 | + | #[derive(Template)] | |
| 581 | + | #[template(path = "pages/changelog.html")] | |
| 582 | + | pub struct ChangelogTemplate { | |
| 583 | + | pub csrf_token: CsrfTokenOption, | |
| 584 | + | pub session_user: Option<SessionUser>, | |
| 585 | + | } | |
| 586 | + | ||
| 579 | 587 | // ============================================================================ | |
| 580 | 588 | // Creator Invite System | |
| 581 | 589 | // ============================================================================ |
| @@ -142,6 +142,10 @@ document.body.addEventListener('htmx:afterRequest', function(evt) { | |||
| 142 | 142 | =========================================== */ | |
| 143 | 143 | ||
| 144 | 144 | document.addEventListener('keydown', function(e) { | |
| 145 | + | // Skip shortcuts when typing in inputs | |
| 146 | + | var tag = document.activeElement?.tagName; | |
| 147 | + | var inInput = tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT'; | |
| 148 | + | ||
| 145 | 149 | if (e.key === 'Escape') { | |
| 146 | 150 | var overlay = document.querySelector('.modal-overlay'); | |
| 147 | 151 | if (overlay) overlay.remove(); | |
| @@ -151,8 +155,39 @@ document.addEventListener('keydown', function(e) { | |||
| 151 | 155 | var form = document.activeElement?.closest('form'); | |
| 152 | 156 | if (form) { var btn = form.querySelector('button[type="submit"]'); if (btn) btn.click(); } | |
| 153 | 157 | } | |
| 158 | + | // ? — show keyboard shortcuts help (not in inputs) | |
| 159 | + | if (e.key === '?' && !inInput && !e.metaKey && !e.ctrlKey) { | |
| 160 | + | e.preventDefault(); | |
| 161 | + | toggleShortcutsHelp(); | |
| 162 | + | } | |
| 154 | 163 | }); | |
| 155 | 164 | ||
| 165 | + | function toggleShortcutsHelp() { | |
| 166 | + | var existing = document.getElementById('shortcuts-help'); | |
| 167 | + | if (existing) { existing.remove(); return; } | |
| 168 | + | ||
| 169 | + | var overlay = document.createElement('div'); | |
| 170 | + | overlay.id = 'shortcuts-help'; | |
| 171 | + | overlay.className = 'modal-overlay'; | |
| 172 | + | overlay.style.display = 'flex'; | |
| 173 | + | overlay.onclick = function(e) { if (e.target === overlay) overlay.remove(); }; | |
| 174 | + | ||
| 175 | + | overlay.innerHTML = | |
| 176 | + | '<div class="modal-content" style="max-width: 420px; padding: 2rem;">' | |
| 177 | + | + '<div class="modal-header" style="margin-bottom: 1rem;">' | |
| 178 | + | + '<h2>Keyboard Shortcuts</h2>' | |
| 179 | + | + '<button type="button" class="modal-close" onclick="document.getElementById(\'shortcuts-help\').remove()">×</button>' | |
| 180 | + | + '</div>' | |
| 181 | + | + '<table style="width: 100%; font-size: 0.9rem;">' | |
| 182 | + | + '<tr><td style="padding: 0.3rem 0;"><kbd>?</kbd></td><td>Show this help</td></tr>' | |
| 183 | + | + '<tr><td style="padding: 0.3rem 0;"><kbd>Esc</kbd></td><td>Close modal / overlay</td></tr>' | |
| 184 | + | + '<tr><td style="padding: 0.3rem 0;"><kbd>Cmd+S</kbd></td><td>Save current form</td></tr>' | |
| 185 | + | + '</table>' | |
| 186 | + | + '</div>'; | |
| 187 | + | ||
| 188 | + | document.body.appendChild(overlay); | |
| 189 | + | } | |
| 190 | + | ||
| 156 | 191 | /* =========================================== | |
| 157 | 192 | NAV TOGGLE | |
| 158 | 193 | =========================================== */ |
| @@ -27,6 +27,7 @@ | |||
| 27 | 27 | <a href="/docs/terms-of-service">Terms</a> | |
| 28 | 28 | <a href="/docs/privacy-policy">Privacy</a> | |
| 29 | 29 | <a href="/health">Status</a> | |
| 30 | + | <a href="/changelog">What's New</a> | |
| 30 | 31 | </div> | |
| 31 | 32 | <p>© 2026 Makenotwork</p> | |
| 32 | 33 | </footer> |
| @@ -0,0 +1,66 @@ | |||
| 1 | + | {% extends "base.html" %} | |
| 2 | + | ||
| 3 | + | {% block title %}What's New - Makenot.work{% endblock %} | |
| 4 | + | {% block body_attrs %} class="padded-page"{% endblock %} | |
| 5 | + | ||
| 6 | + | {% block head %} | |
| 7 | + | <style> | |
| 8 | + | .container { max-width: 900px; margin: 0 auto; } | |
| 9 | + | h1 { font-size: 2.5rem; margin-bottom: 0.5rem; } | |
| 10 | + | .intro { font-size: 1.1rem; margin-bottom: 2rem; line-height: 1.6; } | |
| 11 | + | .changelog-entry { margin-bottom: 2.5rem; padding-bottom: 2rem; border-bottom: 1px solid var(--border); } | |
| 12 | + | .changelog-entry:last-child { border-bottom: none; } | |
| 13 | + | .changelog-date { font-family: var(--font-mono); font-size: 0.9rem; opacity: 0.6; margin-bottom: 0.5rem; } | |
| 14 | + | .changelog-entry h2 { font-size: 1.3rem; margin-bottom: 0.75rem; } | |
| 15 | + | .changelog-entry ul { padding-left: 1.5rem; margin: 0.5rem 0; line-height: 1.7; } | |
| 16 | + | .changelog-entry li { margin-bottom: 0.25rem; } | |
| 17 | + | </style> | |
| 18 | + | {% endblock %} | |
| 19 | + | ||
| 20 | + | {% block content %} | |
| 21 | + | {% include "partials/site_header.html" %} | |
| 22 | + | ||
| 23 | + | <div class="container"> | |
| 24 | + | <h1>What's New</h1> | |
| 25 | + | <p class="intro">Recent updates and improvements to Makenot.work.</p> | |
| 26 | + | ||
| 27 | + | <div class="changelog-entry"> | |
| 28 | + | <div class="changelog-date">May 2026</div> | |
| 29 | + | <h2>Creator dashboard improvements</h2> | |
| 30 | + | <ul> | |
| 31 | + | <li>Self-service refunds: issue refunds directly from the item Sales tab</li> | |
| 32 | + | <li>Simplified item wizard: 6 steps instead of 8</li> | |
| 33 | + | <li>Dashboard tabs reorganized: 4 core tabs with overflow menu</li> | |
| 34 | + | <li>Price inputs now accept dollars instead of cents</li> | |
| 35 | + | <li>Promo code field visible on item pages (no longer hidden)</li> | |
| 36 | + | <li>"Edit" and "Embed" links on public item pages for creators</li> | |
| 37 | + | <li>Data export promoted to visible section in Account tab</li> | |
| 38 | + | <li>Keyboard shortcuts: press <kbd>?</kbd> for help</li> | |
| 39 | + | </ul> | |
| 40 | + | </div> | |
| 41 | + | ||
| 42 | + | <div class="changelog-entry"> | |
| 43 | + | <div class="changelog-date">May 2026</div> | |
| 44 | + | <h2>Collections</h2> | |
| 45 | + | <ul> | |
| 46 | + | <li>"Save to collection" button on item pages</li> | |
| 47 | + | <li>"Add to collection" in library purchase context menus</li> | |
| 48 | + | <li>Inline collection creation from item pages</li> | |
| 49 | + | </ul> | |
| 50 | + | </div> | |
| 51 | + | ||
| 52 | + | <div class="changelog-entry"> | |
| 53 | + | <div class="changelog-date">April 2026</div> | |
| 54 | + | <h2>Platform launch</h2> | |
| 55 | + | <ul> | |
| 56 | + | <li>Soft launch: creator accounts, storefronts, and purchases live</li> | |
| 57 | + | <li>0% platform fee: only Stripe's ~3% processing fee</li> | |
| 58 | + | <li>Audio, video, text, and file hosting</li> | |
| 59 | + | <li>Subscription tiers, license keys, and promo codes</li> | |
| 60 | + | <li>Git hosting with source browser</li> | |
| 61 | + | <li>Community forums (Multithreaded)</li> | |
| 62 | + | <li>Cloud sync (SyncKit) for desktop apps</li> | |
| 63 | + | </ul> | |
| 64 | + | </div> | |
| 65 | + | </div> | |
| 66 | + | {% endblock %} |