import { Undo2Icon } from "lucide-react";import { type ComponentPropsWithoutRef, type ReactNode, useEffect, useState } from "react"; import { cn } from "../../lib/utils";import { Button } from "../ui/button";import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; /** Re-render every `intervalMs`; return a stable timestamp snapshot for render-time relative labels. */export function useRelativeTimeTick(intervalMs = 1_000) { const [nowMs, setNowMs] = useState(() => Date.now()); useEffect(() => { const id = setInterval(() => setNowMs(Date.now()), intervalMs); return () => clearInterval(id); }, [intervalMs]); return nowMs;} export function SettingsSection({ title, icon, headerAction, children, className, ...sectionProps}: ComponentPropsWithoutRef<"section"> & { title: string; icon?: ReactNode; headerAction?: ReactNode; children: ReactNode;}) { return ( <section {...sectionProps} className={cn("space-y-3", className)}> <div className="flex min-h-8 items-center justify-between gap-4 px-3 sm:px-4"> <h2 className="flex items-center gap-2 text-lg font-semibold tracking-[-0.025em] text-foreground"> {icon} {title} </h2> <div className="flex min-h-7 min-w-7 items-center justify-end">{headerAction}</div> </div> <div className="relative space-y-1 overflow-visible text-foreground">{children}</div> </section> );} export function SettingsRow({ title, description, status, resetAction, control, children, className, ...rowProps}: Omit<ComponentPropsWithoutRef<"div">, "title"> & { title: ReactNode; description: ReactNode; status?: ReactNode; resetAction?: ReactNode; control?: ReactNode; children?: ReactNode;}) { return ( <div {...rowProps} className={cn("rounded-xl px-3 sm:px-4", children ? "pt-3 pb-1" : "py-3", className)} > <div className="flex flex-col gap-3 sm:grid sm:grid-cols-[minmax(0,1fr)_minmax(10rem,auto)] sm:items-center sm:gap-8"> <div className="min-w-0 flex-1 space-y-1"> <div className="flex min-h-5 items-center gap-1.5"> <h3 className="text-sm font-medium tracking-[-0.005em] text-foreground">{title}</h3> <span className="inline-flex h-5 w-5 shrink-0 items-center justify-center"> {resetAction} </span> </div> <p className="max-w-xl text-[13px] leading-[1.45] text-muted-foreground/80"> {description} </p> {status ? <div className="pt-0.5 text-xs text-muted-foreground">{status}</div> : null} </div> {control ? ( <div className="flex w-full shrink-0 items-center gap-2 sm:w-auto sm:justify-end"> {control} </div> ) : null} </div> {children} </div> );} export function SettingResetButton({ label, onClick }: { label: string; onClick: () => void }) { return ( <Tooltip> <TooltipTrigger render={ <Button size="icon-xs" variant="ghost" aria-label={`Reset ${label} to default`} className="size-5 rounded-sm p-0 text-muted-foreground hover:text-foreground" onClick={(event) => { event.stopPropagation(); onClick(); }} > <Undo2Icon className="size-3" /> </Button> } /> <TooltipPopup side="top">Reset to default</TooltipPopup> </Tooltip> );} export function SettingsPageContainer({ children, className,}: { children: ReactNode; className?: string;}) { return ( <div className="settings-page-scroll-fade scrollbar-gutter-both flex-1 overflow-y-auto px-4 pt-10 pb-7 sm:px-8 sm:pt-12 sm:pb-10"> <div className={cn("mx-auto flex w-full max-w-4xl flex-col gap-12", className)}> {children} </div> </div> );}
import { Undo2Icon } from "lucide-react";
import { type ComponentPropsWithoutRef, type ReactNode, useEffect, useState } from "react";
import { cn } from "../../lib/utils";
import { Button } from "../ui/button";
import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";
/** Re-render every `intervalMs`; return a stable timestamp snapshot for render-time relative labels. */
export function useRelativeTimeTick(intervalMs = 1_000) {
const [nowMs, setNowMs] = useState(() => Date.now());
useEffect(() => {
const id = setInterval(() => setNowMs(Date.now()), intervalMs);
return () => clearInterval(id);
}, [intervalMs]);
return nowMs;
}
export function SettingsSection({
title,
icon,
headerAction,
children,
className,
...sectionProps
}: ComponentPropsWithoutRef<"section"> & {
title: string;
icon?: ReactNode;
headerAction?: ReactNode;
children: ReactNode;
}) {
return (
<section {...sectionProps} className={cn("space-y-3", className)}>
<div className="flex min-h-8 items-center justify-between gap-4 px-3 sm:px-4">
<h2 className="flex items-center gap-2 text-lg font-semibold tracking-[-0.025em] text-foreground">
{icon}
{title}
</h2>
<div className="flex min-h-7 min-w-7 items-center justify-end">{headerAction}</div>
</div>
<div className="relative space-y-1 overflow-visible text-foreground">{children}</div>
</section>
);
}
export function SettingsRow({
title,
description,
status,
resetAction,
control,
children,
className,
...rowProps
}: Omit<ComponentPropsWithoutRef<"div">, "title"> & {
title: ReactNode;
description: ReactNode;
status?: ReactNode;
resetAction?: ReactNode;
control?: ReactNode;
children?: ReactNode;
}) {
return (
<div
{...rowProps}
className={cn("rounded-xl px-3 sm:px-4", children ? "pt-3 pb-1" : "py-3", className)}
>
<div className="flex flex-col gap-3 sm:grid sm:grid-cols-[minmax(0,1fr)_minmax(10rem,auto)] sm:items-center sm:gap-8">
<div className="min-w-0 flex-1 space-y-1">
<div className="flex min-h-5 items-center gap-1.5">
<h3 className="text-sm font-medium tracking-[-0.005em] text-foreground">{title}</h3>
<span className="inline-flex h-5 w-5 shrink-0 items-center justify-center">
{resetAction}
</span>
</div>
<p className="max-w-xl text-[13px] leading-[1.45] text-muted-foreground/80">
{description}
</p>
{status ? <div className="pt-0.5 text-xs text-muted-foreground">{status}</div> : null}
</div>
{control ? (
<div className="flex w-full shrink-0 items-center gap-2 sm:w-auto sm:justify-end">
{control}
</div>
) : null}
</div>
{children}
</div>
);
}
export function SettingResetButton({ label, onClick }: { label: string; onClick: () => void }) {
return (
<Tooltip>
<TooltipTrigger
render={
<Button
size="icon-xs"
variant="ghost"
aria-label={`Reset ${label} to default`}
className="size-5 rounded-sm p-0 text-muted-foreground hover:text-foreground"
onClick={(event) => {
event.stopPropagation();
onClick();
}}
>
<Undo2Icon className="size-3" />
</Button>
}
/>
<TooltipPopup side="top">Reset to default</TooltipPopup>
</Tooltip>
);
}
export function SettingsPageContainer({
children,
className,
}: {
children: ReactNode;
className?: string;
}) {
return (
<div className="settings-page-scroll-fade scrollbar-gutter-both flex-1 overflow-y-auto px-4 pt-10 pb-7 sm:px-8 sm:pt-12 sm:pb-10">
<div className={cn("mx-auto flex w-full max-w-4xl flex-col gap-12", className)}>
{children}
</div>
</div>
);
}