Add Slides to homepage and documentation site#277
Conversation
Slides is the third shipped module alongside Sheets and Docs, but the homepage Hero and FeaturesSection still frame the product as "Word Processor & Spreadsheet" and the docs site has no Slides section. This task doc captures the brainstormed plan for a 3-product office-suite reframe: new Hero copy, a third live Slides tab in DemoSection (Sheets/Docs/Slides, default Sheets), a 6-card product-balanced FeaturesSection, a Slides pitch-deck UseCase, an updated comparison row and Footer brand copy, plus three new documentation pages (Build a Deck, Themes & Layouts, Keyboard Shortcuts). Slides REST API/CLI, additional docs pages, and live Sheets-cell embedding inside slides are explicitly out of scope.
The homepage demo card has only shown Sheets and Docs since v0.3. Slides is now the third shipped module, so the demo needs a live preview tab to back up the new 3-product Hero copy. Mirrors the Docs lazy-mount + theme-postMessage pattern: the Slides iframe mounts on first tab activation and stays mounted across switches; theme changes propagate without reload. Default active tab stays Sheets so the most-polished demo loads first. Token default is the brainstormed demo presentation; override via VITE_DEMO_SLIDES_SHARED_TOKEN.
Hero H1 and Footer brand copy said "Word Processor & Spreadsheet"
— accurate when only Sheets and Docs shipped, but misleading now
that Slides is the third released module. Replace the product
enumeration with a single suite phrase ("The Office Suite") and
move the module list into the sub copy / footer paragraph.
H1 max-width relaxes from 16ch to 20ch since the new title is
shorter and lets the italic emphasis sit on its own line at most
breakpoints.
The secondary feature grid had 4 cards — 2 Sheets-specific, 1 Docs-specific, 1 cross-cutting (Sharing & Permissions) — and 0 for Slides. With Slides now a first-class module, the imbalance made the lineup feel Sheets-heavy and silently omitted the new product. Replace with 6 cards in a product-balanced 2/2/2 layout (Sheets: Formulas + Charts; Docs: Page-Based Editor + Tables & Pagination; Slides: Themes & Layouts + Presentation Mode). The grid markup stays md:grid-cols-2, so 6 cards render as 3 rows of 2 without layout changes. "Sharing & Permissions" overlapped the Real-Time Collaboration hero card directly above, so dropping it removes a duplicate without losing coverage.
UseCasesSection card 2 was a near-duplicate of card 1 (both Sheets-only customer-data scenarios), so the page told the "Slides shipped" story in Hero and Demo but went silent on real-world Slides use in the use-cases section. Replace card 2 with a pitch-deck case that highlights themes/layouts/self-host — deliberately staying away from live Sheets-cell embedding, which isn't implemented yet. WhySection's "Sheets & Docs in one app" comparison row reads as "missing Slides" once Slides is part of the suite story; relabel to "Slides, Docs & Sheets in one app". Google Workspace still gets a checkmark in that column — they also ship all three.
The docs site has shipped guides for Sheets and Docs since v0.3 but silently omitted Slides — every "What's Next" link in homepage cards pointing at /docs/slides/* used to 404. Add the missing surface so the homepage's Slides links resolve and new users have a first-day reference. Three pages mirror the existing Sheets/Docs structure: - Build a Deck — end-to-end tutorial, counterpart to Build a Budget - Themes & Layouts — theme + 11 layouts + placeholders reference - Keyboard Shortcuts — catalog grouped by category Nav and sidebar position the Slides group between Docs and Developers so the order reads as a coherent product progression (Guide, Sheets, Docs, Slides, Developers). Shapes / connectors / presentation-mode deep dives are intentionally deferred — they'll land in follow-up PRs as the surface area stabilizes.
The homepage and docs-site design docs went stale after the 3-product suite refresh — they still described "Word Processor & Spreadsheet" copy, two demo tabs, four secondary cards, and a sheets-and-docs-only documentation tree. Bring both docs back in sync with the shipped code so they're authoritative again: new Hero phrasing, three demo tabs with the Slides token / lazy-mount story, the 3×2 product-balanced features grid, the Slides pitch-deck UseCase, the updated WhySection row, and the Slides documentation group in the VitePress nav and sidebar.
The hero eyebrow read "v0.3" and the demo footer read "[email protected]" — both hardcoded strings that drifted apart from the actual package version (now 0.4.1) and would silently rot at every release. The Slides reframe forced an audit, so fix the root cause: read the root package.json version at vite config time and inject it as a build-time constant. `__APP_VERSION__` is declared in vite-env.d.ts so TypeScript sees it. The hero displays the marketing-style minor tag ("v0.4") by slicing off the patch; the demo footer keeps the full developer-style stamp ("[email protected]"). Bumping the root package.json is now the single touch point at release time.
Browser-driven wrapping at large viewports kept "The Office Suite You Can Own" on a single line at most desktop widths, which buried the italic emphasis. The intended display is two stacked phrases where the syrup-deep italic "You Can Own" lands directly below the white "The Office Suite" — that's how the design reads as a declarative statement instead of a long compound noun. Switch to `block` spans on each half. The em keeps its italic + syrup-deep styling. `max-w-[20ch]` drops since the forced line break makes it redundant.
Three findings from the self code-review pass. The Slides demo footer tip said "press F to present" — but Slides has no F-key handler, only ⌘/Ctrl+Enter (current) and ⌘/Ctrl+Shift+Enter (first), as documented in this same PR's keyboard-shortcuts page. F would only trigger browser fullscreen, not the Slides player. Update the tip to match the real shortcut. The WhySection comparison row read "Slides, Docs & Sheets in one app" while every other place on the page used "Sheets, Docs, and Slides". Align the row to the same ordering for consistency. The "Tables & Pagination" feature card linked to writing-a-document — the same href as the "Page-Based Document Editor" card — and the target page covered neither tables nor pagination. Add Tables and Pagination sections to writing-a-document.md and anchor the Tables card to #tables so each card lands on relevant content.
📝 WalkthroughWalkthroughThis PR reframes the Wafflebase product narrative from a 2-product office suite (Sheets/Docs) to a 3-product suite (Sheets/Docs/Slides) across the homepage, documentation site, and marketing copy, while introducing dynamic version injection infrastructure to replace hardcoded version strings in the UI. Changes3-Product Homepage and Documentation Site Redesign
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/frontend/src/app/home/footer.tsx`:
- Around line 62-64: In the Footer component update the product list text to
match the site-wide ordering (Sheets, Docs, Slides); replace the existing phrase
"presentations, word processor, and spreadsheet" in the JSX string inside Footer
with the consistent ordering (e.g., "spreadsheet, word processor, and
presentations" or the branded "Sheets, Docs, and Slides") so the footer aligns
with the hero, comparison table, and features sections.
In `@packages/frontend/vite.config.ts`:
- Around line 10-16: Wrap the readFileSync + JSON.parse that produces rootPkg in
a try-catch to surface a clear, actionable error when package.json is missing,
unreadable, or contains invalid JSON: catch filesystem and parse errors around
the JSON.parse(readFileSync(...)) expression (referencing readFileSync,
JSON.parse, path.resolve and rootPkg) and rethrow or log a message that includes
the resolved path and the original error message so the build error indicates
whether the file was not found, unreadable, or malformed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f7a65e25-17e0-46e3-a7f1-a55b1b9100f4
📒 Files selected for processing (17)
docs/design/docs-site.mddocs/design/homepage.mddocs/tasks/README.mddocs/tasks/active/20260521-slides-homepage-docs-todo.mdpackages/documentation/.vitepress/config.tspackages/documentation/docs-editor/writing-a-document.mdpackages/documentation/slides/build-a-deck.mdpackages/documentation/slides/keyboard-shortcuts.mdpackages/documentation/slides/themes-and-layouts.mdpackages/frontend/src/app/home/demo-section.tsxpackages/frontend/src/app/home/features-section.tsxpackages/frontend/src/app/home/footer.tsxpackages/frontend/src/app/home/hero-section.tsxpackages/frontend/src/app/home/use-cases-section.tsxpackages/frontend/src/app/home/why-section.tsxpackages/frontend/src/vite-env.d.tspackages/frontend/vite.config.ts
| Self-hosted collaborative presentations, word processor, and | ||
| spreadsheet, with real-time editing and a REST API for | ||
| automation. |
There was a problem hiding this comment.
Product order inconsistent with the rest of the homepage.
The footer lists "presentations, word processor, and spreadsheet" (Slides → Docs → Sheets), but the hero, comparison table, and features section all use "Sheets, Docs, and Slides" ordering. Consider harmonizing to maintain a consistent product narrative.
Proposed fix
- Self-hosted collaborative presentations, word processor, and
- spreadsheet, with real-time editing and a REST API for
- automation.
+ Self-hosted collaborative spreadsheet, word processor, and
+ presentations, with real-time editing and a REST API for
+ automation.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Self-hosted collaborative presentations, word processor, and | |
| spreadsheet, with real-time editing and a REST API for | |
| automation. | |
| Self-hosted collaborative spreadsheet, word processor, and | |
| presentations, with real-time editing and a REST API for | |
| automation. |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/frontend/src/app/home/footer.tsx` around lines 62 - 64, In the
Footer component update the product list text to match the site-wide ordering
(Sheets, Docs, Slides); replace the existing phrase "presentations, word
processor, and spreadsheet" in the JSX string inside Footer with the consistent
ordering (e.g., "spreadsheet, word processor, and presentations" or the branded
"Sheets, Docs, and Slides") so the footer aligns with the hero, comparison
table, and features sections.
| // Root package.json is the single source of truth for the version | ||
| // surfaced on the homepage. Read at config-eval time and inject as a | ||
| // build-time constant so the hero eyebrow and demo footer always | ||
| // match the shipped package. | ||
| const rootPkg = JSON.parse( | ||
| readFileSync(path.resolve(__dirname, "../../package.json"), "utf-8"), | ||
| ) as { version: string }; |
There was a problem hiding this comment.
Add error handling for file I/O and JSON parsing.
If package.json is missing, relocated, or contains invalid JSON, the build will fail with an unclear error. Wrap the read and parse in a try-catch block to provide a more actionable message.
🛡️ Proposed fix
// Root package.json is the single source of truth for the version
// surfaced on the homepage. Read at config-eval time and inject as a
// build-time constant so the hero eyebrow and demo footer always
// match the shipped package.
+let rootPkg: { version: string };
+try {
-const rootPkg = JSON.parse(
- readFileSync(path.resolve(__dirname, "../../package.json"), "utf-8"),
-) as { version: string };
+ rootPkg = JSON.parse(
+ readFileSync(path.resolve(__dirname, "../../package.json"), "utf-8"),
+ );
+ if (typeof rootPkg.version !== "string") {
+ throw new Error("package.json is missing a valid 'version' field");
+ }
+} catch (err) {
+ throw new Error(
+ `Failed to read root package.json for version injection: ${err instanceof Error ? err.message : String(err)}`
+ );
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Root package.json is the single source of truth for the version | |
| // surfaced on the homepage. Read at config-eval time and inject as a | |
| // build-time constant so the hero eyebrow and demo footer always | |
| // match the shipped package. | |
| const rootPkg = JSON.parse( | |
| readFileSync(path.resolve(__dirname, "../../package.json"), "utf-8"), | |
| ) as { version: string }; | |
| // Root package.json is the single source of truth for the version | |
| // surfaced on the homepage. Read at config-eval time and inject as a | |
| // build-time constant so the hero eyebrow and demo footer always | |
| // match the shipped package. | |
| let rootPkg: { version: string }; | |
| try { | |
| rootPkg = JSON.parse( | |
| readFileSync(path.resolve(__dirname, "../../package.json"), "utf-8"), | |
| ); | |
| if (typeof rootPkg.version !== "string") { | |
| throw new Error("package.json is missing a valid 'version' field"); | |
| } | |
| } catch (err) { | |
| throw new Error( | |
| `Failed to read root package.json for version injection: ${err instanceof Error ? err.message : String(err)}` | |
| ); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/frontend/vite.config.ts` around lines 10 - 16, Wrap the readFileSync
+ JSON.parse that produces rootPkg in a try-catch to surface a clear, actionable
error when package.json is missing, unreadable, or contains invalid JSON: catch
filesystem and parse errors around the JSON.parse(readFileSync(...)) expression
(referencing readFileSync, JSON.parse, path.resolve and rootPkg) and rethrow or
log a message that includes the resolved path and the original error message so
the build error indicates whether the file was not found, unreadable, or
malformed.
Verification: verify:selfResult: ✅ PASS in 211.7s
Verification: verify:integrationResult: ✅ PASS |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
These tasks' features merged to main (PRs #267 #271 #277 #284 #285) but their plan checkboxes were never ticked, so the todo files lingered in tasks/active. Added a status note citing each merge commit, marked the checkboxes complete, and ran tasks:archive to move them under archive/2026/05 with regenerated indexes. Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
Summary
Reframe the public surface from a 2-product narrative ("Word Processor & Spreadsheet") to a 3-product office-suite narrative now that Slides is
shipped alongside Sheets and Docs.
Homepage (
packages/frontend/src/app/home/):The Office Suite/You Can Own(forced two-line H1) + subcopy "Sheets, Docs, and Slides. Real-time collaboration, REST API,
fully self-hosted."
Sheets), lazy-mounted, theme-synced via existing
postMessagepattern. Token defaults to a public demo deck; override via
VITE_DEMO_SLIDES_SHARED_TOKEN.(Sheets 2, Docs 2, Slides 2). "Sharing & Permissions" dropped to
remove overlap with the Real-Time Collaboration hero card.
app".
spreadsheet".
__APP_VERSION__, injected at vite build time from the rootpackage.jsonso the strings can't drift from the shipped versionagain.
Documentation site (
packages/documentation/):slides/group with three pages:build-a-deck,themes-and-layouts,keyboard-shortcuts.docs-editor/writing-a-document.mdgains Tables and Paginationsections so the new "Tables & Pagination" feature card lands on
real content.
Design docs:
docs/design/homepage.mdanddocs/design/docs-site.mdbrought back in sync with the shipped state.
Plan:
docs/tasks/active/20260521-slides-homepage-docs-todo.mddocuments the brainstormed decisions chunk-by-chunk.
Slides REST API/CLI, additional Slides docs pages (shapes / connectors
/ presentation-mode deep dives), and live Sheets-cell embedding inside
slides are intentionally out of scope.
Test plan
pnpm verify:fast(frontend + backend + sheets + docs + slides + documentation)pnpm --filter @wafflebase/documentation build— no broken links to new pagespnpm --filter @wafflebase/frontend build— no missing importspnpm devat localhost:5173):postMessagewriting-a-document#tablesresolves and ToC lists Tables + Pagination433c9e92Demo iframe shows "Link unavailable" in local dev for all three tabs
since the demo tokens are production-bound — production at
wafflebase.io serves the real shared decks.
Summary by CodeRabbit
New Features
Documentation
UI/UX Updates