Make pages full width and center count options

This commit is contained in:
FengLee
2026-05-12 20:11:17 +08:00
parent 618e58b04a
commit c674f79f07
11 changed files with 19 additions and 18 deletions

View File

@@ -29,6 +29,7 @@ Use this guide when the user reports behavior. Start from the symptom row, inspe
| Footer content missing or not Markdown-rendered | `src/components/site-footer.tsx`, `src/components/site-policy-page.tsx`, `src/lib/site-config.ts`, `src/app/api/site-config/route.ts` | Config response fields, Markdown renderer, fallback defaults, PUT persistence. |
| Policy pages start mid-page after navigation | `src/components/site-policy-page.tsx`, `src/app/about/page.tsx`, `src/app/terms/page.tsx`, `src/app/privacy/page.tsx`, `src/app/help/page.tsx` | Scroll reset behavior and shared policy page wrapper. |
| Site name/logo/favicon not updating | `src/components/site-config-sync.tsx`, `src/components/site-brand.tsx`, `src/app/api/site-config/route.ts`, `src/lib/local-storage.ts` | `site_config` row, base64 image save, generated `/api/local-storage/*` URL. |
| Page content leaves large unused horizontal margins or does not fill browser width | `src/components/app-shell.tsx`, `src/components/navbar.tsx`, `src/components/site-footer.tsx`, page-level wrappers under `src/app/*/page.tsx`, `src/components/site-policy-page.tsx` | Page-level wrappers should use `w-full` with responsive padding rather than `mx-auto max-w-*`; keep only local cards/dialogs/readability blocks constrained. |
| Announcement not popping up | `src/components/announcement-popup.tsx`, `src/app/api/announcements/route.ts`, `src/components/app-shell.tsx` | App shell includes popup, active date range, local/session dismissal behavior, GET payload shape. |
| Announcement admin edit fails | `src/components/admin/announcement-tab.tsx`, `src/app/api/announcements/route.ts` | Admin token, required fields, `starts_at`/`expires_at` compatibility. |

View File

@@ -8,10 +8,10 @@ Use this document to jump directly to code before broad searching.
| Feature | Primary Files | Notes |
| --- | --- | --- |
| Root layout and providers | `src/app/layout.tsx`, `src/components/app-shell.tsx` | App shell wires navbar, site config sync, visit tracking, theme/account sync, and toaster. |
| Root layout and providers | `src/app/layout.tsx`, `src/components/app-shell.tsx` | App shell wires navbar, site config sync, visit tracking, theme/account sync, toaster, and full-width page mounting. |
| Home page | `src/app/page.tsx` | Landing/dashboard-like public entry. Check site config dependencies when changing brand text. |
| Navbar | `src/components/navbar.tsx`, `src/components/site-brand.tsx` | Navigation, brand display, auth-aware links. |
| Footer | `src/components/site-footer.tsx` | Uses site config for policy/help/about links and filing text. |
| Footer | `src/components/site-footer.tsx` | Uses site config for policy/help/about links and filing text; page-level footer content should span browser width. |
| Announcement popup | `src/components/announcement-popup.tsx`, `src/app/api/announcements/route.ts` | Frontend popup behavior plus backend announcement CRUD. |
| Site config sync | `src/components/site-config-sync.tsx`, `src/lib/site-config.ts`, `src/app/api/site-config/route.ts` | Site name, tab title, logo, favicon, policy Markdown, filing, membership switch. |
| Visit tracking | `src/components/visit-tracker.tsx`, `src/app/api/site-stats/route.ts` | Public visit counter. |

View File

@@ -26,7 +26,7 @@ function CreateContent() {
return (
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-6">
<TabsList className="grid w-full grid-cols-5 max-w-4xl">
<TabsList className="grid w-full grid-cols-5">
<TabsTrigger value="text2img" className="gap-2">
<Brush className="h-4 w-4" />
<span className="hidden sm:inline"></span>
@@ -74,7 +74,7 @@ function CreateContent() {
export default function CreatePage() {
return (
<div className="min-h-screen bg-background">
<div className="mx-auto max-w-7xl px-4 sm:px-6 py-8">
<div className="w-full px-4 sm:px-6 py-8">
<div className="mb-8">
<h1 className="font-serif text-3xl font-bold"></h1>
<p className="mt-2 text-muted-foreground">

View File

@@ -424,7 +424,7 @@ export default function GalleryPage() {
return (
<div className="min-h-screen bg-background">
<div className="mx-auto max-w-7xl px-4 sm:px-6 py-8">
<div className="w-full px-4 sm:px-6 py-8">
{/* Header */}
<div className="mb-8">
<div className="flex items-center gap-3">

View File

@@ -107,7 +107,7 @@ export default function HomePage() {
<div className="absolute bottom-0 right-0 w-[400px] h-[400px] bg-primary/3 rounded-full blur-[100px]" />
</div>
<div className="mx-auto max-w-7xl px-4 sm:px-6 pt-20 pb-24 text-center">
<div className="w-full px-4 sm:px-6 pt-20 pb-24 text-center">
<Badge variant="secondary" className="mb-6 px-4 py-1.5 text-sm font-medium gap-2">
<SiteLogo className="h-5 w-5 rounded" />
AI多模态创作平台
@@ -157,7 +157,7 @@ export default function HomePage() {
{/* Core Features */}
<section className="py-24 bg-muted/20">
<div className="mx-auto max-w-7xl px-4 sm:px-6">
<div className="w-full px-4 sm:px-6">
<div className="text-center mb-16">
<h2 className="font-serif text-3xl sm:text-4xl font-bold"></h2>
<p className="mt-4 text-muted-foreground text-lg">AI创作体验</p>
@@ -193,7 +193,7 @@ export default function HomePage() {
{/* Highlights */}
<section className="py-24">
<div className="mx-auto max-w-7xl px-4 sm:px-6">
<div className="w-full px-4 sm:px-6">
<div className="text-center mb-16">
<h2 className="font-serif text-3xl sm:text-4xl font-bold"></h2>
<p className="mt-4 text-muted-foreground text-lg"></p>
@@ -219,7 +219,7 @@ export default function HomePage() {
{/* Pricing */}
<BillingPlanGuard>
<section className="py-24 bg-muted/20">
<div className="mx-auto max-w-7xl px-4 sm:px-6">
<div className="w-full px-4 sm:px-6">
<div className="text-center mb-16">
<h2 className="font-serif text-3xl sm:text-4xl font-bold"></h2>
<p className="mt-4 text-muted-foreground text-lg"></p>
@@ -271,7 +271,7 @@ export default function HomePage() {
{/* CTA */}
<section className="py-24">
<div className="mx-auto max-w-4xl px-4 sm:px-6 text-center">
<div className="w-full px-4 sm:px-6 text-center">
<h2 className="font-serif text-3xl sm:text-4xl font-bold"></h2>
<p className="mt-4 text-lg text-muted-foreground">
AI开启你的创作之旅

View File

@@ -411,7 +411,7 @@ export default function ProfilePage() {
if (!mounted) {
return (
<div className="min-h-screen bg-background">
<div className="mx-auto max-w-7xl px-4 sm:px-6 py-8">
<div className="w-full px-4 sm:px-6 py-8">
<div className="mb-8">
<div className="flex items-center gap-4">
<div className="h-16 w-16 rounded-full bg-muted animate-pulse" />
@@ -428,7 +428,7 @@ export default function ProfilePage() {
return (
<div className="min-h-screen bg-background">
<div className="mx-auto max-w-7xl px-4 sm:px-6 py-8">
<div className="w-full px-4 sm:px-6 py-8">
{/* Profile Header */}
<div className="mb-8">
<div className="flex items-center justify-between">
@@ -518,7 +518,7 @@ export default function ProfilePage() {
{/* Tabs */}
<Tabs value={activeTab} onValueChange={setActiveTab}>
<TabsList className={`grid w-full grid-cols-3 ${membershipEnabled ? 'sm:grid-cols-6' : 'sm:grid-cols-3'} max-w-3xl`}>
<TabsList className={`grid w-full grid-cols-3 ${membershipEnabled ? 'sm:grid-cols-6' : 'sm:grid-cols-3'}`}>
<TabsTrigger value="account" className="gap-1.5"><User className="h-4 w-4" /><span className="hidden sm:inline"></span></TabsTrigger>
{membershipEnabled && <TabsTrigger value="membership" className="gap-1.5"><Crown className="h-4 w-4" /><span className="hidden sm:inline"></span></TabsTrigger>}
{membershipEnabled && <TabsTrigger value="credits" className="gap-1.5"><Coins className="h-4 w-4" /><span className="hidden sm:inline"></span></TabsTrigger>}

View File

@@ -18,7 +18,7 @@ export function AppShell({ children }: { children: ReactNode }) {
<AccountThemeSync />
{!isConsole && <VisitTracker />}
{!isConsole && <Navbar />}
<main>{children}</main>
<main className="min-w-0 w-full">{children}</main>
<Toaster />
</>
);

View File

@@ -87,7 +87,7 @@ export function ImageCountCombobox({ value, onChange, className }: ImageCountCom
role="option"
aria-selected={value === option.value}
className={cn(
'focus:bg-accent focus:text-accent-foreground flex min-h-8 w-full items-center rounded-sm px-2 text-sm outline-none',
'focus:bg-accent focus:text-accent-foreground flex min-h-8 w-full items-center justify-center rounded-sm px-2 text-center text-sm outline-none',
value === option.value && 'bg-accent text-accent-foreground',
)}
onMouseDown={event => event.preventDefault()}

View File

@@ -94,7 +94,7 @@ export function Navbar() {
return (
<header className="sticky top-0 z-50 w-full border-b border-border/50 bg-background/80 backdrop-blur-xl">
<div className="mx-auto flex h-16 max-w-7xl items-center justify-between px-4 sm:px-6">
<div className="flex h-16 w-full items-center justify-between px-4 sm:px-6">
{/* Logo */}
<Link href="/" className="flex items-center gap-2.5 group">
<img

View File

@@ -18,7 +18,7 @@ export function SiteFooter() {
return (
<footer className="border-t border-border/50 py-12">
<div className="mx-auto max-w-7xl px-4 sm:px-6">
<div className="w-full px-4 sm:px-6">
<div className="flex flex-col gap-5 sm:flex-row sm:items-start sm:justify-between">
<div className="flex flex-col gap-2 text-center sm:text-left">
<div className="flex items-center justify-center gap-2 sm:justify-start">

View File

@@ -21,7 +21,7 @@ export function SitePolicyPage({ kind }: { kind: PolicyPageKind }) {
return (
<main className="min-h-screen bg-background">
<div className="mx-auto flex min-h-screen w-full max-w-3xl flex-col px-4 py-10 sm:px-6">
<div className="flex min-h-screen w-full flex-col px-4 py-10 sm:px-6">
<header className="mb-10 flex items-center justify-between gap-4">
<Link href="/" className="inline-flex items-center gap-2">
<SiteLogo className="h-8 w-8 rounded" />