From 99ed11fa3610a23b1b42a1f1267be8d5a4f17487 Mon Sep 17 00:00:00 2001 From: Michelle Date: Wed, 31 Dec 2025 21:40:33 +0400 Subject: [PATCH 01/11] refactor: standardise navigation file naming and relocate right-sidebar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit File renames: - desktop-top-bar β†’ desktop-topbar - mobile-top-bar β†’ mobile-topbar - mobile-nav-link β†’ mobile-navlink Structure: - Move right-sidebar.tsx to dedicated components/right-sidebar/ folder - Update import paths in layout.tsx and mobile-nav.tsx Standardises compound word naming (removing hyphens). The right-sidebar folder prepares for Phase II components (question-link.tsx, tag-badge.tsx). πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- app/(root)/layout.tsx | 6 +++--- .../navigation/{desktop-top-bar.tsx => desktop-topbar.tsx} | 0 components/navigation/mobile-nav.tsx | 2 +- .../navigation/{mobile-nav-link.tsx => mobile-navlink.tsx} | 0 .../navigation/{mobile-top-bar.tsx => mobile-topbar.tsx} | 0 components/{navigation => right-sidebar}/right-sidebar.tsx | 0 6 files changed, 4 insertions(+), 4 deletions(-) rename components/navigation/{desktop-top-bar.tsx => desktop-topbar.tsx} (100%) rename components/navigation/{mobile-nav-link.tsx => mobile-navlink.tsx} (100%) rename components/navigation/{mobile-top-bar.tsx => mobile-topbar.tsx} (100%) rename components/{navigation => right-sidebar}/right-sidebar.tsx (100%) diff --git a/app/(root)/layout.tsx b/app/(root)/layout.tsx index f8d842c..aefd44e 100644 --- a/app/(root)/layout.tsx +++ b/app/(root)/layout.tsx @@ -1,8 +1,8 @@ import { cookies } from "next/headers"; -import { DesktopTopBar } from "@/components/navigation/desktop-top-bar"; +import { DesktopTopBar } from "@/components/navigation/desktop-topbar"; import { LeftSidebar } from "@/components/navigation/left-sidebar"; -import { MobileTopBar } from "@/components/navigation/mobile-top-bar"; -import { RightSidebar } from "@/components/navigation/right-sidebar"; +import { MobileTopBar } from "@/components/navigation/mobile-topbar"; +import { RightSidebar } from "@/components/right-sidebar/right-sidebar"; import { SidebarProvider } from "@/components/ui/sidebar"; const RootLayout = async ({ children }: { children: React.ReactNode }) => { diff --git a/components/navigation/desktop-top-bar.tsx b/components/navigation/desktop-topbar.tsx similarity index 100% rename from components/navigation/desktop-top-bar.tsx rename to components/navigation/desktop-topbar.tsx diff --git a/components/navigation/mobile-nav.tsx b/components/navigation/mobile-nav.tsx index a527616..2c6197f 100644 --- a/components/navigation/mobile-nav.tsx +++ b/components/navigation/mobile-nav.tsx @@ -10,7 +10,7 @@ import { import { Menu, X } from "lucide-react"; import Link from "next/link"; import { useState } from "react"; -import { MobileNavLink } from "@/components/navigation/mobile-nav-link"; +import { MobileNavLink } from "@/components/navigation/mobile-navlink"; import { NAV_LINKS } from "@/components/navigation/nav-links.constants"; import { ThemedFullLogo } from "@/components/navigation/themed-full-logo"; import { Button } from "@/components/ui/button"; diff --git a/components/navigation/mobile-nav-link.tsx b/components/navigation/mobile-navlink.tsx similarity index 100% rename from components/navigation/mobile-nav-link.tsx rename to components/navigation/mobile-navlink.tsx diff --git a/components/navigation/mobile-top-bar.tsx b/components/navigation/mobile-topbar.tsx similarity index 100% rename from components/navigation/mobile-top-bar.tsx rename to components/navigation/mobile-topbar.tsx diff --git a/components/navigation/right-sidebar.tsx b/components/right-sidebar/right-sidebar.tsx similarity index 100% rename from components/navigation/right-sidebar.tsx rename to components/right-sidebar/right-sidebar.tsx From 1b0189fb71d431d01274e86876b86f5f679c0ebd Mon Sep 17 00:00:00 2001 From: Michelle Date: Thu, 1 Jan 2026 01:32:57 +0400 Subject: [PATCH 02/11] chore: install shadcn Badge component MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds Badge component from shadcn/ui registry with CVA variants (default, secondary, destructive, outline) and asChild polymorphism via Radix Slot. πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- components/ui/badge.tsx | 46 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 components/ui/badge.tsx diff --git a/components/ui/badge.tsx b/components/ui/badge.tsx new file mode 100644 index 0000000..ccfa4e7 --- /dev/null +++ b/components/ui/badge.tsx @@ -0,0 +1,46 @@ +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; +import type * as React from "react"; + +import { cn } from "@/lib/utils"; + +const badgeVariants = cva( + "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: + "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +); + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : "span"; + + return ( + + ); +} + +export { Badge, badgeVariants }; From d6a2a99192532b530e535f0b5166fe25b90a2c49 Mon Sep 17 00:00:00 2001 From: Michelle Date: Thu, 1 Jan 2026 02:59:59 +0400 Subject: [PATCH 03/11] rules: allow additional Playwright and CLI commands Playwright MCP: - Add browser_fill_form, browser_hover, browser_press_key, browser_type Bash commands: - Add git diff, gh pr view, npx vercel wildcards Expands Claude's auto-approved tool permissions for browser testing and CLI operations, reducing interaction prompts during development workflows. --- .claude/settings.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.claude/settings.json b/.claude/settings.json index 4e595ab..79f72e0 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -8,14 +8,18 @@ "mcp__playwright__browser_close", "mcp__playwright__browser_console_messages", "mcp__playwright__browser_evaluate", + "mcp__playwright__browser_fill_form", + "mcp__playwright__browser_hover", "mcp__playwright__browser_navigate", "mcp__playwright__browser_navigate_back", "mcp__playwright__browser_network_requests", + "mcp__playwright__browser_press_key", "mcp__playwright__browser_resize", "mcp__playwright__browser_run_code", "mcp__playwright__browser_snapshot", "mcp__playwright__browser_tabs", "mcp__playwright__browser_take_screenshot", + "mcp__playwright__browser_type", "mcp__playwright__browser_wait_for", "Bash(cat:*)", "Bash(echo:*)", @@ -26,9 +30,11 @@ "Bash(tree:*)", "Bash(wc:*)", "Bash(xargs:*)", + "Bash(git diff:*)", "Bash(git log:*)", "Bash(gh pr checks:*)", "Bash(gh pr list:*)", + "Bash(gh pr view:*)", "Bash(gh run list:*)", "Bash(gh run view:*)", "Bash(npm run build)", @@ -44,6 +50,7 @@ "Bash(npx @biomejs/biome:*)", "Bash(npx lefthook:*)", "Bash(npx playwright:*)", + "Bash(npx vercel:*)", "Bash(vercel --help)", "Bash(vercel env --help)", "Bash(vercel env ls:*)", From b2e852b2cb08cef15f21f68095308d22d8f61ce4 Mon Sep 17 00:00:00 2001 From: Michelle Date: Thu, 1 Jan 2026 03:01:11 +0400 Subject: [PATCH 04/11] feat: add right-sidebar content with data layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Components: - Add QuestionLink with multi-line title and ChevronRight icon - Add TagLink with Badge toptag variant and question count - Add toptag Badge variant (uppercase, secondary colours) Data Layer: - Add lib/data/questions.ts with getTopQuestions() async function - Add lib/data/tags.ts with getPopularTags() async function - Export Question and Tag types for reuse Routes: - Add /question/[id] placeholder page - Add /tags/[slug] placeholder page Replace skeleton placeholders with functional content. Data layer uses async functions ready for MongoDB integration. RightSidebar now fetches data via Promise.all for parallel loading. πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/(root)/question/[id]/page.tsx | 8 +++++ app/(root)/tags/[slug]/page.tsx | 8 +++++ components/right-sidebar/question-link.tsx | 21 +++++++++++ components/right-sidebar/right-sidebar.tsx | 42 +++++++++++++--------- components/right-sidebar/tag-link.tsx | 23 ++++++++++++ components/ui/badge.tsx | 2 ++ lib/data/questions.ts | 33 +++++++++++++++++ lib/data/tags.ts | 21 +++++++++++ 8 files changed, 141 insertions(+), 17 deletions(-) create mode 100644 app/(root)/question/[id]/page.tsx create mode 100644 app/(root)/tags/[slug]/page.tsx create mode 100644 components/right-sidebar/question-link.tsx create mode 100644 components/right-sidebar/tag-link.tsx create mode 100644 lib/data/questions.ts create mode 100644 lib/data/tags.ts diff --git a/app/(root)/question/[id]/page.tsx b/app/(root)/question/[id]/page.tsx new file mode 100644 index 0000000..dd2111e --- /dev/null +++ b/app/(root)/question/[id]/page.tsx @@ -0,0 +1,8 @@ +type QuestionPageProps = { + params: Promise<{ id: string }>; +}; + +export default async function QuestionPage({ params }: QuestionPageProps) { + const { id } = await params; + return

Question {id}

; +} diff --git a/app/(root)/tags/[slug]/page.tsx b/app/(root)/tags/[slug]/page.tsx new file mode 100644 index 0000000..9c41f51 --- /dev/null +++ b/app/(root)/tags/[slug]/page.tsx @@ -0,0 +1,8 @@ +type TagPageProps = { + params: Promise<{ slug: string }>; +}; + +export default async function TagPage({ params }: TagPageProps) { + const { slug } = await params; + return

Tag: {slug}

; +} diff --git a/components/right-sidebar/question-link.tsx b/components/right-sidebar/question-link.tsx new file mode 100644 index 0000000..6af3092 --- /dev/null +++ b/components/right-sidebar/question-link.tsx @@ -0,0 +1,21 @@ +import { ChevronRight } from "lucide-react"; +import Link from "next/link"; + +type QuestionLinkProps = { + id: string; + title: string; +}; + +export function QuestionLink({ id, title }: QuestionLinkProps) { + return ( + + + {title} + + + + ); +} diff --git a/components/right-sidebar/right-sidebar.tsx b/components/right-sidebar/right-sidebar.tsx index 50f8aed..3acd881 100644 --- a/components/right-sidebar/right-sidebar.tsx +++ b/components/right-sidebar/right-sidebar.tsx @@ -1,15 +1,23 @@ +import { QuestionLink } from "@/components/right-sidebar/question-link"; +import { TagLink } from "@/components/right-sidebar/tag-link"; import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, } from "@/components/ui/sidebar"; -import { Skeleton } from "@/components/ui/skeleton"; +import { getTopQuestions } from "@/lib/data/questions"; +import { getPopularTags } from "@/lib/data/tags"; /** Asymmetric padding: more on left, less on right (scrollbar side), reduced bottom */ const GROUP_PADDING = "pt-6 pb-2 pl-6 pr-3"; -export function RightSidebar() { +export async function RightSidebar() { + const [topQuestions, popularTags] = await Promise.all([ + getTopQuestions(5), + getPopularTags(5), + ]); + return (