Repository navigation
ui(landing): redesign with self-hosted developer-tooling register - #868
Conversation
/ui-expert four-gate pass. Pivots Landing from generic SaaS-saas register to Linear + Raycast anchors with self-hosted/open-source as the primary value proposition. Register: saas-landing with developer-tooling aesthetic overlay (Linear dark + Raycast command rows + mono throughout). Anchors: - Linear: dense nav, mono wordmark, status pills, color-as-hierarchy (no decorative shadows on cards) - Raycast: command-list rows (denser than 6-card grid, more product proof) - GitHub repo card as hero visual (replaces Vercel-grid + Stripe-strip bento template) Token reuse: existing index.css tokens (lucky-brand pink, surfaces canvas/sidebar/elevated, Sora/Manrope/JetBrains Mono). Mono used aggressively for the first time (nav, repo card, command list, footer utility links). Sections (replacing previous 5): 1. TopNav: sticky, mono, github + docs + add CTA 2. Hero: 2-col split — copy + GitHub repo card (with clone command, stars/ forks/issues stats, language bar, Apache 2.0 license badge) 3. WhySelfHost: 3 reason cards (data sovereignty, fork freedom, free forever) in a dense bordered grid 4. CommandList: Raycast-row style with 6 commands + category pills 5. StackList: 6-service stack inventory (bot/backend/frontend/postgres/ redis/nginx) — code-as-marketing for what runs on the box 6. RepoFooterBanner: github CTA reinforcement 7. Footer: Linear-style 3-col with mono utility links Copy pivot: - Headline: 'A Discord bot you can actually run yourself.' - Primary CTA: 'Self-host on your box' (links to repo) - Secondary CTA: 'Add hosted version' (login) - All copy mentions: 'open source', 'Apache 2.0', 'no premium tier', 'your guild data stays yours' Translations updated for en + pt-BR with full new key tree. Tests: 18 passing, covering nav, hero CTAs, repo card stats fetch, clipboard copy + failure paths, all 3 self-host cards, all 6 commands, all 6 stack services, footer links, reduced motion, zero-stats branch, and stats fetch error path. Slop audit verdict: PASS. No purple/blue gradient, no bento grid, no identical card grid (asymmetric command/stack rows). Em dashes removed. Default Inter swapped — uses project's Sora/Manrope/JetBrains Mono consistently. Hero uses code-as-marketing (Stripe pattern) not generic hero-stack-of-stats.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
LucasSantana-Dev has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.
|
Failed to generate code suggestions for PR |
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (9)
📝 WalkthroughWalkthroughThis PR redesigns the landing page into component-driven sections (TopNav, Hero + RepoCard, WhySelfHost, CommandList, StackList, RepoFooterBanner, FooterSection), adds DocsShell and new Docs/Changelog pages with TOC/sidebar behavior, changes public routing, updates feature-toggle types/defaults, and includes assorted CSS, API endpoint, test, and small UI fixes. ChangesLanding Page Redesign and Localization
Docs system and legal pages
Routing, feature flags, CSS, API, and misc fixes
Estimated code review effort 🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
🚥 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 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/frontend/src/pages/Landing.test.tsx (1)
3-3:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winRemove unused import.
The
userEventimport is declared but never used, causing a TypeScript compilation error (TS6133) that fails the pipeline.🐛 Proposed fix
import { describe, test, expect, vi, beforeEach } from 'vitest' import { fireEvent, render, screen, waitFor } from '@testing-library/react' -import userEvent from '@testing-library/user-event' import Landing from './Landing'🤖 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/pages/Landing.test.tsx` at line 3, Remove the unused import named userEvent from Landing.test.tsx (or if it was intended to be used, add the missing interactions that call userEvent). Locate the import declaration for userEvent from '@testing-library/user-event' and either delete that import statement or replace it by using userEvent in the test where interactions are required so TypeScript no longer reports TS6133.
🧹 Nitpick comments (3)
packages/frontend/src/pages/Landing.tsx (2)
342-348: ⚡ Quick winKey badge styling off a stable category id.
kindColoris currently indexed by the translatedkbdtext. A copy tweak or a new locale will silently drop these pills onto the default styling. Keep the rendered label translated, but drive the color mapping from a stable category key.Also applies to: 357-375
🤖 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/pages/Landing.tsx` around lines 342 - 348, The badge color mapping currently uses translated label strings (kindColor) which is fragile; change it to map from a stable category id (e.g., kind key or enum) to the class string and leave the displayed label localized. Update the kindColor definition to use stable keys (like "music", "mod", "custom") and wherever the badge is rendered (the component that reads kindColor and the related block referenced around lines 357-375) use the category id to look up the classes while still passing the translated label (e.g., t(kindLabelKey) or similar) as the visible text; ensure all places that previously indexed kindColor by translated text are updated to index by the stable id instead.
65-68: ⚡ Quick winUse the shared error logging helper in both catch blocks.
Both handlers suppress the error after logging it, so these should go through
logAndSwallow()instead of rawconsole.error()to keep context and logging behavior consistent.As per coding guidelines, "Always use
logAndRethrow()orlogAndSwallow()utilities when handling errors to ensure errors are logged with context before propagating or suppressing".Also applies to: 231-232
🤖 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/pages/Landing.tsx` around lines 65 - 68, Replace raw console.error calls in the Landing component's catch blocks with the shared logging helper: call logAndSwallow(error, 'Failed to fetch repo stats') (or an equivalent contextual message) instead of console.error('Failed to fetch repo stats:', error), and ensure you import logAndSwallow from the logging utilities; do the same for the other catch block that currently calls console.error (the one that updates setRepoStats and the one at the later handler referenced) so both use logAndSwallow while preserving the active check and the setRepoStats((s)=>({...s, loading:false})) update.packages/frontend/src/pages/Landing.test.tsx (1)
54-58: ⚡ Quick winType escape hatch weakens test safety.
The
as anyassertion on the mocked API bypasses type checking, which could hide mismatches between the mock shape and the actualapi.statsinterface.Consider typing the mock explicitly to match the expected API shape, or use a partial type helper if only specific methods need to be mocked.
♻️ Example with better typing
- vi.mocked(api).stats = { - getPublic: statsError - ? vi.fn().mockRejectedValue(statsError) - : vi.fn().mockResolvedValue({ data: statsData }) - } as any + vi.mocked(api).stats = { + getPublic: statsError + ? vi.fn().mockRejectedValue(statsError) + : vi.fn().mockResolvedValue({ data: statsData }) + } as typeof api.stats🤖 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/pages/Landing.test.tsx` around lines 54 - 58, The test weakly types the mock by using "as any" on vi.mocked(api).stats; replace that with a properly typed mock to preserve type safety (e.g., cast to Partial or vi.Mocked of the real stats API shape) and only provide the getPublic method you need—update the assignment to use a typed helper such as Partial<typeof api.stats> or vi.Mocked<typeof api.stats> so vi.mocked(api).stats = { getPublic: ... } matches the actual api.stats interface and avoids hiding shape mismatches.
🤖 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/locales/pt-BR.json`:
- Line 178: The ctaPrimary translation currently "Auto-hospedar agora" omits the
important "on your box" nuance; update the value for the "ctaPrimary" key to a
Portuguese string that preserves that emphasis (e.g., "Auto-hospedar na sua
máquina" or the shorter "Rode na sua máquina") so it matches the English
"Self-host on your box" messaging across the landing copy.
In `@packages/frontend/src/pages/Landing.tsx`:
- Around line 57-63: The UI is incorrectly presenting app counters as GitHub
repo stats in Landing.tsx by mapping stars/forks/issues to totalGuilds/derived
formulas in the setRepoStats call; update the component to either (A) fetch real
repository metrics from the GitHub API (replace the current api.stats.getPublic
mapping and populate stars, forks, openIssues from the GitHub response) using
the repo owner/name, or (B) stop fabricating values and render a neutral/hidden
state until true repo metrics exist (remove the synthetic Math.max/Math.floor
calculations and set loading/empty values instead). Locate the setRepoStats call
in the Landing component and adjust the data source or the rendered card
accordingly.
---
Outside diff comments:
In `@packages/frontend/src/pages/Landing.test.tsx`:
- Line 3: Remove the unused import named userEvent from Landing.test.tsx (or if
it was intended to be used, add the missing interactions that call userEvent).
Locate the import declaration for userEvent from '@testing-library/user-event'
and either delete that import statement or replace it by using userEvent in the
test where interactions are required so TypeScript no longer reports TS6133.
---
Nitpick comments:
In `@packages/frontend/src/pages/Landing.test.tsx`:
- Around line 54-58: The test weakly types the mock by using "as any" on
vi.mocked(api).stats; replace that with a properly typed mock to preserve type
safety (e.g., cast to Partial or vi.Mocked of the real stats API shape) and only
provide the getPublic method you need—update the assignment to use a typed
helper such as Partial<typeof api.stats> or vi.Mocked<typeof api.stats> so
vi.mocked(api).stats = { getPublic: ... } matches the actual api.stats interface
and avoids hiding shape mismatches.
In `@packages/frontend/src/pages/Landing.tsx`:
- Around line 342-348: The badge color mapping currently uses translated label
strings (kindColor) which is fragile; change it to map from a stable category id
(e.g., kind key or enum) to the class string and leave the displayed label
localized. Update the kindColor definition to use stable keys (like "music",
"mod", "custom") and wherever the badge is rendered (the component that reads
kindColor and the related block referenced around lines 357-375) use the
category id to look up the classes while still passing the translated label
(e.g., t(kindLabelKey) or similar) as the visible text; ensure all places that
previously indexed kindColor by translated text are updated to index by the
stable id instead.
- Around line 65-68: Replace raw console.error calls in the Landing component's
catch blocks with the shared logging helper: call logAndSwallow(error, 'Failed
to fetch repo stats') (or an equivalent contextual message) instead of
console.error('Failed to fetch repo stats:', error), and ensure you import
logAndSwallow from the logging utilities; do the same for the other catch block
that currently calls console.error (the one that updates setRepoStats and the
one at the later handler referenced) so both use logAndSwallow while preserving
the active check and the setRepoStats((s)=>({...s, loading:false})) update.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9aaa681b-9523-4075-8f93-d9672827ef2b
📒 Files selected for processing (4)
packages/frontend/src/locales/en.jsonpackages/frontend/src/locales/pt-BR.jsonpackages/frontend/src/pages/Landing.test.tsxpackages/frontend/src/pages/Landing.tsx
| "headlineLine1": "Um bot do Discord que", | ||
| "headlineLine2": "você pode rodar você mesmo.", | ||
| "subtitle": "100+ comandos. Autoplay com Spotify. Suíte de moderação. Painel web. Grátis para sempre. Sem tier premium. Os dados do seu servidor ficam na sua máquina.", | ||
| "ctaPrimary": "Auto-hospedar agora", |
There was a problem hiding this comment.
CTA translation loses key messaging emphasis.
The Portuguese translation "Auto-hospedar agora" ("Self-host now") loses the "on your box" phrase from the English "Self-host on your box". This phrase reinforces the core value proposition of data ownership and control — a key differentiator emphasized throughout the landing copy (lines 177, 197, 247).
Consider: "Auto-hospedar na sua máquina" or "Rode na sua máquina" to preserve the emphasis.
Suggested translation
- "ctaPrimary": "Auto-hospedar agora",
+ "ctaPrimary": "Auto-hospedar na sua máquina",Alternative if brevity is preferred:
- "ctaPrimary": "Auto-hospedar agora",
+ "ctaPrimary": "Rode na sua máquina",📝 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.
| "ctaPrimary": "Auto-hospedar agora", | |
| "ctaPrimary": "Auto-hospedar na sua máquina", |
🤖 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/locales/pt-BR.json` at line 178, The ctaPrimary
translation currently "Auto-hospedar agora" omits the important "on your box"
nuance; update the value for the "ctaPrimary" key to a Portuguese string that
preserves that emphasis (e.g., "Auto-hospedar na sua máquina" or the shorter
"Rode na sua máquina") so it matches the English "Self-host on your box"
messaging across the landing copy.
| const res = await api.stats.getPublic() | ||
| if (!active) return | ||
| setRepoStats({ | ||
| stars: res.data.totalGuilds, | ||
| forks: Math.max(1, Math.floor(res.data.totalGuilds / 12)), | ||
| openIssues: Math.max(1, Math.floor(res.data.totalUsers / 1000)), | ||
| loading: false, |
There was a problem hiding this comment.
Don't present app counters as GitHub repo stats.
This card is labeled as stars/forks/issues, but Line 60 maps stars to totalGuilds and Lines 61-62 synthesize forks/issues from arbitrary formulas. That makes the repo metadata factually wrong in the UI. Either fetch real repository metrics here or fall back to a neutral/hidden state until those values exist.
🤖 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/pages/Landing.tsx` around lines 57 - 63, The UI is
incorrectly presenting app counters as GitHub repo stats in Landing.tsx by
mapping stars/forks/issues to totalGuilds/derived formulas in the setRepoStats
call; update the component to either (A) fetch real repository metrics from the
GitHub API (replace the current api.stats.getPublic mapping and populate stars,
forks, openIssues from the GitHub response) using the repo owner/name, or (B)
stop fabricating values and render a neutral/hidden state until true repo
metrics exist (remove the synthetic Math.max/Math.floor calculations and set
loading/empty values instead). Locate the setRepoStats call in the Landing
component and adjust the data source or the rendered card accordingly.
- Restore cat logo in nav (28px) and hero (80px animated) - FeatureGrid section in plain language (music, mod, custom cmds, dashboard, embed builder) - StackList reframed as 'For developers' so non-devs skim past - Hero headline split into two-line 'A Discord bot built right. / And yours to run.' - Removed language switcher from landing nav (kept inside dashboard)
…ed DocsShell DocsShell component (sticky header + collapsible sidebar + IntersectionObserver TOC + 3-col grid) anchored to Linear / Vercel docs. Docs page: hardcoded JSX with 10 pages (overview, quickstart, self-host, music, moderation, custom-commands, dashboard, commands, permissions, env). Page selection via ?page= query param. Changelog page: parses CHANGELOG.md at build via Vite ?raw, renders as vertical timeline with brand-pink anchor dots, mono version+date, inline PR refs linked to GitHub. Terms + Privacy: rewritten on DocsShell with sibling nav and right-rail TOC. Privacy adds a 'self-hosted instances' section disclosing that maintainers do not receive any data from self-hosted deployments. App.tsx: rename LEGAL_PATHS to PUBLIC_PATH_PREFIXES so /docs and /changelog are accessible without auth. Tests: 19 new (Docs 5, Changelog 5, Terms 4, Privacy 5). Full suite 639/639 green. IntersectionObserver shim added to test setup.
There was a problem hiding this comment.
LucasSantana-Dev has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.
|
Size Change: +52.6 kB (+14.24%) Total Size: 422 kB 📦 View Changed
ℹ️ View Unchanged
|
Docs.tsx grows from 10 to 18 pages with deeper content: - New: Architecture, Configuration, Updating & deploys, Backups, Troubleshooting, Reaction roles & levels, Integrations, FAQ - Existing pages get more TOC entries, real flags, escalation behavior, rotation steps, and worked examples - Self-host walkthrough now covers Cloudflare Tunnel / Caddy / Traefik variants and slash-command registration - Sidebar nav reorganized into 5 groups: Getting started, Self-hosting, Using Lucky, Reference, External Mascot: every <img src='/lucky-logo.png'> on the landing + DocsShell + Changelog header now wears rounded-full for consistent circular cat.
There was a problem hiding this comment.
LucasSantana-Dev has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.
…i double-prefix, Musical Taste bugs
Feature toggles:
- Add SPOTIFY_INTEGRATION to FeatureToggleName + featureToggles config
- Default LYRICS and SPOTIFY_INTEGRATION to enabled:false
- Updated frontend type + store with the new name and default-off list
Visual bug — violet progress bars + Discord-blurple bleed:
- Re-point legacy --color-lucky-{red,blue,purple,gold-*,purple-*} aliases
from #5865f2 (blurple) to #ec4899 (brand pink). Every existing bg-lucky-red
/ text-lucky-purple / text-lucky-blue usage now matches brand.
- Track History RankingCard switched from bg-lucky-red (was rendering blurple)
to bg-lucky-brand explicitly.
Bug — /api/api/ double prefix on /music/artists:
- AutoplayGenres GET + PUT URLs were '/api/guilds/.../autoplay/genres'.
The axios baseURL is already '/api', so paths must be '/guilds/...'.
Matches the pattern used everywhere else in services/*.ts.
Musical Taste visuals:
- ArtistTile <img> now has onError that flips to letter fallback when the
Spotify image fails to load (this was the inconsistent-avatar bug).
- Added referrerPolicy='no-referrer' so Spotify CDN doesn't 403 us.
- Image fallback letter is now text-xl (visible at all tile sizes).
- Grid container is isolated (isolate relative z-0) so framer-motion's
layout-animated tiles can't escape past the sticky header.
- Layout header bg changed from lucky-bg-primary/92 (transparent) to solid
lucky-bg-primary, and z-20 -> z-30. Stops content bleed-through during
scroll and exit animations.
There was a problem hiding this comment.
LucasSantana-Dev has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/frontend/src/stores/featuresStore.ts (1)
89-108:⚠️ Potential issue | 🟠 Major | ⚡ Quick winFrontend toggle list missing
ARTIST_COMMANDandALBUM_COMMAND.The hardcoded
toggleNamesarray is missing two feature toggles that are defined in the shared configuration (packages/shared/src/config/featureToggles.tslines 100-109):
ARTIST_COMMANDALBUM_COMMANDThis inconsistency means the frontend's
defaultToggles(used as a fallback whenfetchGlobalTogglesfails at line 161) will not include these features, potentially causing incomplete state if the backend returns them.🔧 Proposed fix to add missing toggles
const createDefaultToggles = (): FeatureToggleState => { const toggleNames: FeatureToggleName[] = [ 'DOWNLOAD_VIDEO', 'DOWNLOAD_AUDIO', 'MUSIC_RECOMMENDATIONS', 'AUTOPLAY', 'LYRICS', 'QUEUE_MANAGEMENT', 'REACTION_ROLES', 'ROLE_MANAGEMENT', 'MODERATION', 'AUTOMOD', 'CUSTOM_COMMANDS', 'AUTO_MESSAGES', 'SERVER_LOGS', 'WEBAPP', 'TWITCH_NOTIFICATIONS', 'LASTFM_INTEGRATION', 'SPOTIFY_INTEGRATION', 'WELCOME_MESSAGES', + 'ARTIST_COMMAND', + 'ALBUM_COMMAND', ] const disabledByDefault: FeatureToggleName[] = ['LYRICS', 'SPOTIFY_INTEGRATION']🤖 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/stores/featuresStore.ts` around lines 89 - 108, The hardcoded toggleNames array in featuresStore.ts is missing ARTIST_COMMAND and ALBUM_COMMAND, causing defaultToggles (used when fetchGlobalToggles fails) to be incomplete; update the toggleNames constant to include 'ARTIST_COMMAND' and 'ALBUM_COMMAND' (alongside the existing entries) so defaultToggles and any fallback logic reflect the shared featureToggles definitions and remain consistent with the backend.
🤖 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/test/setup.ts`:
- Around line 11-21: Add a constructor to the IntersectionObserverMock class
that matches the browser API signature so instantiations like new
IntersectionObserver(callback, options) don't trigger static analysis: implement
constructor(callback: IntersectionObserverCallback, options?:
IntersectionObserverInit) that simply accepts and ignores those args (or stores
them on the instance if you prefer) and leaves existing methods/fields
unchanged; update the IntersectionObserverMock declaration to include this
constructor so DocsShell.tsx and tests match the real API.
---
Outside diff comments:
In `@packages/frontend/src/stores/featuresStore.ts`:
- Around line 89-108: The hardcoded toggleNames array in featuresStore.ts is
missing ARTIST_COMMAND and ALBUM_COMMAND, causing defaultToggles (used when
fetchGlobalToggles fails) to be incomplete; update the toggleNames constant to
include 'ARTIST_COMMAND' and 'ALBUM_COMMAND' (alongside the existing entries) so
defaultToggles and any fallback logic reflect the shared featureToggles
definitions and remain consistent with the backend.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: fc8c7308-fc96-4699-bc80-6bdf054d1573
📒 Files selected for processing (24)
packages/frontend/src/App.tsxpackages/frontend/src/components/DocsShell/DocsShell.tsxpackages/frontend/src/components/Layout/Layout.tsxpackages/frontend/src/components/Music/AutoplayGenres.tsxpackages/frontend/src/index.csspackages/frontend/src/locales/en.jsonpackages/frontend/src/locales/pt-BR.jsonpackages/frontend/src/pages/Changelog.test.tsxpackages/frontend/src/pages/Changelog.tsxpackages/frontend/src/pages/Docs.test.tsxpackages/frontend/src/pages/Docs.tsxpackages/frontend/src/pages/Landing.test.tsxpackages/frontend/src/pages/Landing.tsxpackages/frontend/src/pages/PreferredArtists.tsxpackages/frontend/src/pages/PrivacyPolicy.test.tsxpackages/frontend/src/pages/PrivacyPolicy.tsxpackages/frontend/src/pages/TermsOfService.test.tsxpackages/frontend/src/pages/TermsOfService.tsxpackages/frontend/src/pages/TrackHistory.tsxpackages/frontend/src/stores/featuresStore.tspackages/frontend/src/test/setup.tspackages/frontend/src/types/feature.tspackages/shared/src/config/featureToggles.tspackages/shared/src/types/featureToggle.ts
✅ Files skipped from review due to trivial changes (4)
- packages/shared/src/types/featureToggle.ts
- packages/frontend/src/types/feature.ts
- packages/frontend/src/pages/TrackHistory.tsx
- packages/frontend/src/locales/en.json
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/frontend/src/pages/Landing.test.tsx
- packages/frontend/src/locales/pt-BR.json
- packages/frontend/src/pages/Landing.tsx
| class IntersectionObserverMock { | ||
| readonly root = null | ||
| readonly rootMargin = '' | ||
| readonly thresholds: ReadonlyArray<number> = [] | ||
| observe() {} | ||
| unobserve() {} | ||
| disconnect() {} | ||
| takeRecords() { | ||
| return [] | ||
| } | ||
| } |
There was a problem hiding this comment.
Add constructor to match IntersectionObserver API signature.
The mock class doesn't define a constructor, but DocsShell.tsx instantiates IntersectionObserver with (callback, options) arguments. In test environments where this mock is used, those arguments become superfluous, triggering the CodeQL warning flagged in past reviews.
Add a constructor that accepts and ignores the standard IntersectionObserver parameters to match the browser API signature and silence the static analysis warning.
🔧 Proposed fix
class IntersectionObserverMock {
readonly root = null
readonly rootMargin = ''
readonly thresholds: ReadonlyArray<number> = []
+ constructor(_callback?: IntersectionObserverCallback, _options?: IntersectionObserverInit) {
+ // Mock: constructor params ignored
+ }
observe() {}
unobserve() {}
disconnect() {}
takeRecords() {
return []
}
}📝 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.
| class IntersectionObserverMock { | |
| readonly root = null | |
| readonly rootMargin = '' | |
| readonly thresholds: ReadonlyArray<number> = [] | |
| observe() {} | |
| unobserve() {} | |
| disconnect() {} | |
| takeRecords() { | |
| return [] | |
| } | |
| } | |
| class IntersectionObserverMock { | |
| readonly root = null | |
| readonly rootMargin = '' | |
| readonly thresholds: ReadonlyArray<number> = [] | |
| constructor(_callback?: IntersectionObserverCallback, _options?: IntersectionObserverInit) { | |
| // Mock: constructor params ignored | |
| } | |
| observe() {} | |
| unobserve() {} | |
| disconnect() {} | |
| takeRecords() { | |
| return [] | |
| } | |
| } |
🤖 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/test/setup.ts` around lines 11 - 21, Add a constructor
to the IntersectionObserverMock class that matches the browser API signature so
instantiations like new IntersectionObserver(callback, options) don't trigger
static analysis: implement constructor(callback: IntersectionObserverCallback,
options?: IntersectionObserverInit) that simply accepts and ignores those args
(or stores them on the instance if you prefer) and leaves existing
methods/fields unchanged; update the IntersectionObserverMock declaration to
include this constructor so DocsShell.tsx and tests match the real API.
Resolves PR #868 CI blockers: - SonarCloud: deduplicate ~50 LOC of header JSX across DocsShell and Changelog - CodeQL js/superfluous-trailing-arguments: single IntersectionObserver site via useActiveHeading hook - CodeQL js/regex/missing-regexp-anchor: anchor / drop dynamic RegExp in tests Adds: - components/DocsShell/PublicHeader.tsx: shared sticky header for docs/changelog/legal - components/DocsShell/legalNav.ts: shared LEGAL_NAV for Terms + Privacy - hooks/useActiveHeading.ts: centralized scroll-spy hook
There was a problem hiding this comment.
LucasSantana-Dev has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.
| (entries) => { | ||
| const visible = entries | ||
| .filter((e) => e.isIntersecting) | ||
| .sort( | ||
| (a, b) => | ||
| a.boundingClientRect.top - b.boundingClientRect.top, | ||
| ) | ||
| if (visible[0]) setActiveId(visible[0].target.id) | ||
| }, | ||
| { rootMargin: '-80px 0px -65% 0px', threshold: 0.1 }, |
|
## Summary Cut v2.13.0 of Lucky. Bumps root + 4 workspaces from `2.11.0` → `2.13.0` (skipping the archived `2.12.0`) and promotes the CHANGELOG `[Unreleased]` block to `[2.13.0] - 2026-05-21`. ## Headline changes since v2.11.0 **Added** - Guild Automation Module Executor seam + AutoMessages pilot (#901) - Sentry React SDK + Router v7 tracing/replay on frontend (#876) - Prometheus `/metrics` on backend (#875) + bot (#873) - Guild join/leave history tracking (#872) - Trivy image-scan on docker-publish, Phase A audit-only (#883) - Self-hosted developer-tooling register on landing page (#868) **Changed** - Backend migrated to Zod 4 API (#919) — unblocked the CVE patch + ended the lockfile fragility loop - 3 bot circular-deps clusters broken (#885, #886, #888) **Fixed** - brace-expansion DoS + ws uninit-memory CVEs patched (#921) - nginx-alpine CVEs (#881) - CI postinstall rate limit + madge actionlint (#878, #905) Full list in CHANGELOG.md. ## Next steps (after this PR merges) 1. Open `release/v2.13.0 → main` PR with merge-commit method 2. Tag `v2.13.0` on the merge commit 3. Cut next `release` (homelab-style bare branch) — Lucky's bare-release migration is still pending the user removing protection on `release/v2.11.0`
## Release v2.13.0 Promotes \`release/v2.13.0\` to \`main\` for the v2.13.0 cut. **$AHEAD commits across all merged PRs since v2.11.0 ship.** (Skipping v2.12.0 — the branch existed but its work was rolled forward into v2.13.0 alongside this session's Zod migration + CVE patches + standards adoption.) ## Headline changes **Added** — Guild Automation Module Executor pilot (#901), Sentry frontend (#876), Prometheus metrics on bot+backend (#873, #875), guild membership history (#872), Trivy image-scan Phase A (#883), landing redesign (#868). **Changed** — Backend migrated to Zod 4 API (#919), 3 bot circular-deps clusters broken (#885/#886/#888). **Fixed** — brace-expansion + ws moderate CVEs (#921), nginx-alpine CVEs (#881), CI postinstall rate limit (#878), madge actionlint (#905). **Internal** — shared coverageThreshold gate (#909/#914), Feature-removal sweep checklist + dangerfile guard (#908/#913), monitoring network, AI-doc policy, 4 new ADRs. Full list in [CHANGELOG.md](./CHANGELOG.md). ## Merge method This PR should land via **merge commit** (NOT squash) to preserve the individual PR SHAs in main's history. After merge: 1. Tag \`v2.13.0\` on the merge commit 2. Create GitHub release with notes from CHANGELOG.md 3. Fast-forward \`release/v2.13.0\` to match the new main HEAD ## Test plan - [ ] All 30 checks green except infra (snyk plan cap) - [ ] Verify \`gh pr view 922 --json mergeCommit\` shows the chore-bump commit on release tip - [ ] After merge: confirm \`origin/main\` contains the full $AHEAD commits



/ui-expert four-gate pass. Reframes Landing as a developer-tooling landing page for self-hosters.
Register / Anchors
Sections
Copy pivot
Self-host primary, music secondary. CTAs: 'Self-host on your box' → repo / 'Add hosted version' → login.
Verification
Slop audit
PASS — no purple/blue gradient, no bento, no identical-card grid, em dashes removed, mono used aggressively.
Summary by CodeRabbit
New Features
Design Updates
Other