Adds a 'narrow' prop that wraps the body in 'max-w-2xl mx-auto' while keeping the header chrome at the standard 5xl. Settings is the first consumer — its rows are dense text and look adrift at full width. The header still aligns with the other tabs so the title position stays consistent. Covered by 2 SSR tests (narrow path adds the inner wrapper, default path doesn't). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
66 lines
2.2 KiB
TypeScript
66 lines
2.2 KiB
TypeScript
import { getSeededOperator } from "@/lib/operator";
|
|
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
|
|
import { Separator } from "@/components/ui/separator";
|
|
import { ThemeToggle } from "@/components/theme-toggle";
|
|
import { NotificationsToggle } from "@/components/notifications-toggle";
|
|
import { PageShell } from "@/components/page-shell";
|
|
|
|
export default async function SettingsPage() {
|
|
const op = await getSeededOperator();
|
|
return (
|
|
<PageShell title="Settings" narrow>
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Operator</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-3 text-sm">
|
|
<Row label="Display name" value={op.displayName} />
|
|
<Separator />
|
|
<Row label="Operator ID" value={String(op.telegramUserId)} mono />
|
|
<Separator />
|
|
<Row label="Default timezone" value={op.defaultTimezone} mono />
|
|
<Separator />
|
|
<Row label="Role" value={op.role} mono />
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Notifications</CardTitle>
|
|
<CardDescription>
|
|
Browser notifications when a reminder fires successfully or a
|
|
test message is sent. Uses the in-tab Notification API — works
|
|
while the app is open. Background push is on the roadmap.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<NotificationsToggle />
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Appearance</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="flex items-center justify-between">
|
|
<div className="text-sm text-muted-foreground">Theme</div>
|
|
<ThemeToggle />
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<p className="text-center text-xs text-muted-foreground">
|
|
cm WhatsApp Bot · self-hosted
|
|
</p>
|
|
</PageShell>
|
|
);
|
|
}
|
|
|
|
function Row({ label, value, mono }: { label: string; value: string; mono?: boolean }) {
|
|
return (
|
|
<div className="flex items-center justify-between gap-3">
|
|
<dt className="text-muted-foreground">{label}</dt>
|
|
<dd className={mono ? "font-mono text-xs" : ""}>{value}</dd>
|
|
</div>
|
|
);
|
|
}
|