aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web/components/settings/ReaderSettings.tsx
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2025-12-18 05:08:15 +0000
committerMohamed Bassem <me@mbassem.com>2025-12-18 05:08:15 +0000
commit3955f91a6f5fa0566a6cc0efc94bad538d34cdd9 (patch)
tree03c6fca3598329e4aeca915efde62038f07c0ff2 /apps/web/components/settings/ReaderSettings.tsx
parent9021822a0533e5091927f9b8cfa42b208d448474 (diff)
downloadkarakeep-3955f91a6f5fa0566a6cc0efc94bad538d34cdd9.tar.zst
fix: collapse reader settings by default
Diffstat (limited to 'apps/web/components/settings/ReaderSettings.tsx')
-rw-r--r--apps/web/components/settings/ReaderSettings.tsx395
1 files changed, 209 insertions, 186 deletions
diff --git a/apps/web/components/settings/ReaderSettings.tsx b/apps/web/components/settings/ReaderSettings.tsx
index ce4017c7..28cc847e 100644
--- a/apps/web/components/settings/ReaderSettings.tsx
+++ b/apps/web/components/settings/ReaderSettings.tsx
@@ -4,7 +4,13 @@ import { useState } from "react";
import { useClientConfig } from "@/lib/clientConfig";
import { useTranslation } from "@/lib/i18n/client";
import { useReaderSettings } from "@/lib/readerSettings";
-import { AlertTriangle, BookOpen, Laptop, RotateCcw } from "lucide-react";
+import {
+ AlertTriangle,
+ BookOpen,
+ ChevronDown,
+ Laptop,
+ RotateCcw,
+} from "lucide-react";
import {
formatFontSize,
@@ -23,6 +29,11 @@ import {
CardHeader,
CardTitle,
} from "../ui/card";
+import {
+ Collapsible,
+ CollapsibleContent,
+ CollapsibleTrigger,
+} from "../ui/collapsible";
import { Label } from "../ui/label";
import {
Select,
@@ -47,6 +58,9 @@ export default function ReaderSettings() {
updateServerSetting,
} = useReaderSettings();
+ // Local state for collapsible
+ const [isOpen, setIsOpen] = useState(false);
+
// Local state for slider dragging (null = not dragging, use server value)
const [draggingFontSize, setDraggingFontSize] = useState<number | null>(null);
const [draggingLineHeight, setDraggingLineHeight] = useState<number | null>(
@@ -92,197 +106,206 @@ export default function ReaderSettings() {
};
return (
- <Card>
- <CardHeader>
- <CardTitle className="flex items-center gap-2 text-xl">
- <BookOpen className="h-5 w-5" />
- {t("settings.info.reader_settings.title")}
- </CardTitle>
- <CardDescription>
- {t("settings.info.reader_settings.description")}
- </CardDescription>
- </CardHeader>
- <CardContent className="space-y-6">
- {/* Local Overrides Warning */}
- {hasLocalOverrides && (
- <Alert>
- <AlertTriangle className="h-4 w-4" />
- <AlertDescription className="flex flex-col gap-3">
- <div>
- <p className="font-medium">
- {t("settings.info.reader_settings.local_overrides_title")}
- </p>
- <p className="mt-1 text-sm text-muted-foreground">
- {t(
- "settings.info.reader_settings.local_overrides_description",
- )}
+ <Collapsible open={isOpen} onOpenChange={setIsOpen}>
+ <Card>
+ <CardHeader>
+ <CollapsibleTrigger className="flex w-full items-center justify-between [&[data-state=open]>svg]:rotate-180">
+ <div className="flex flex-col items-start gap-1 text-left">
+ <CardTitle className="flex items-center gap-2 text-xl">
+ <BookOpen className="h-5 w-5" />
+ {t("settings.info.reader_settings.title")}
+ </CardTitle>
+ <CardDescription>
+ {t("settings.info.reader_settings.description")}
+ </CardDescription>
+ </div>
+ <ChevronDown className="h-5 w-5 shrink-0 transition-transform duration-200" />
+ </CollapsibleTrigger>
+ </CardHeader>
+ <CollapsibleContent>
+ <CardContent className="space-y-6">
+ {/* Local Overrides Warning */}
+ {hasLocalOverrides && (
+ <Alert>
+ <AlertTriangle className="h-4 w-4" />
+ <AlertDescription className="flex flex-col gap-3">
+ <div>
+ <p className="font-medium">
+ {t("settings.info.reader_settings.local_overrides_title")}
+ </p>
+ <p className="mt-1 text-sm text-muted-foreground">
+ {t(
+ "settings.info.reader_settings.local_overrides_description",
+ )}
+ </p>
+ <ul className="mt-2 text-sm text-muted-foreground">
+ {localOverrides.fontFamily !== undefined && (
+ <li>
+ {t("settings.info.reader_settings.font_family")}:{" "}
+ {formatLocalOverride("fontFamily")}
+ </li>
+ )}
+ {localOverrides.fontSize !== undefined && (
+ <li>
+ {t("settings.info.reader_settings.font_size")}:{" "}
+ {formatLocalOverride("fontSize")}
+ </li>
+ )}
+ {localOverrides.lineHeight !== undefined && (
+ <li>
+ {t("settings.info.reader_settings.line_height")}:{" "}
+ {formatLocalOverride("lineHeight")}
+ </li>
+ )}
+ </ul>
+ </div>
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={handleClearLocalOverrides}
+ className="w-fit"
+ >
+ <Laptop className="mr-2 h-4 w-4" />
+ {t("settings.info.reader_settings.clear_local_overrides")}
+ </Button>
+ </AlertDescription>
+ </Alert>
+ )}
+
+ {/* Font Family */}
+ <div className="space-y-2">
+ <Label className="text-sm font-medium">
+ {t("settings.info.reader_settings.font_family")}
+ </Label>
+ <Select
+ disabled={!!clientConfig.demoMode}
+ value={serverSettings.fontFamily ?? "not-set"}
+ onValueChange={(value) => {
+ if (value !== "not-set") {
+ updateServerSetting({
+ fontFamily: value as "serif" | "sans" | "mono",
+ });
+ }
+ }}
+ >
+ <SelectTrigger className="h-11">
+ <SelectValue
+ placeholder={t("settings.info.reader_settings.not_set")}
+ />
+ </SelectTrigger>
+ <SelectContent>
+ <SelectItem value="not-set" disabled>
+ {t("settings.info.reader_settings.not_set")} (
+ {t("common.default")}: {READER_DEFAULTS.fontFamily})
+ </SelectItem>
+ <SelectItem value="serif">
+ {t("settings.info.reader_settings.serif")}
+ </SelectItem>
+ <SelectItem value="sans">
+ {t("settings.info.reader_settings.sans")}
+ </SelectItem>
+ <SelectItem value="mono">
+ {t("settings.info.reader_settings.mono")}
+ </SelectItem>
+ </SelectContent>
+ </Select>
+ {serverSettings.fontFamily === null && (
+ <p className="text-xs text-muted-foreground">
+ {t("settings.info.reader_settings.using_default")}:{" "}
+ {READER_DEFAULTS.fontFamily}
</p>
- <ul className="mt-2 text-sm text-muted-foreground">
- {localOverrides.fontFamily !== undefined && (
- <li>
- {t("settings.info.reader_settings.font_family")}:{" "}
- {formatLocalOverride("fontFamily")}
- </li>
- )}
- {localOverrides.fontSize !== undefined && (
- <li>
- {t("settings.info.reader_settings.font_size")}:{" "}
- {formatLocalOverride("fontSize")}
- </li>
- )}
- {localOverrides.lineHeight !== undefined && (
- <li>
- {t("settings.info.reader_settings.line_height")}:{" "}
- {formatLocalOverride("lineHeight")}
- </li>
- )}
- </ul>
+ )}
+ </div>
+
+ {/* Font Size */}
+ <div className="space-y-2">
+ <div className="flex items-center justify-between">
+ <Label className="text-sm font-medium">
+ {t("settings.info.reader_settings.font_size")}
+ </Label>
+ <span className="text-sm text-muted-foreground">
+ {formatFontSize(draggingFontSize ?? settings.fontSize)}
+ {serverSettings.fontSize === null &&
+ draggingFontSize === null &&
+ ` (${t("common.default").toLowerCase()})`}
+ </span>
+ </div>
+ <Slider
+ disabled={!!clientConfig.demoMode}
+ value={[draggingFontSize ?? settings.fontSize]}
+ onValueChange={([value]) => setDraggingFontSize(value)}
+ onValueCommit={([value]) => {
+ updateServerSetting({ fontSize: value });
+ setDraggingFontSize(null);
+ }}
+ max={READER_SETTING_CONSTRAINTS.fontSize.max}
+ min={READER_SETTING_CONSTRAINTS.fontSize.min}
+ step={READER_SETTING_CONSTRAINTS.fontSize.step}
+ />
+ </div>
+
+ {/* Line Height */}
+ <div className="space-y-2">
+ <div className="flex items-center justify-between">
+ <Label className="text-sm font-medium">
+ {t("settings.info.reader_settings.line_height")}
+ </Label>
+ <span className="text-sm text-muted-foreground">
+ {formatLineHeight(draggingLineHeight ?? settings.lineHeight)}
+ {serverSettings.lineHeight === null &&
+ draggingLineHeight === null &&
+ ` (${t("common.default").toLowerCase()})`}
+ </span>
</div>
+ <Slider
+ disabled={!!clientConfig.demoMode}
+ value={[draggingLineHeight ?? settings.lineHeight]}
+ onValueChange={([value]) => setDraggingLineHeight(value)}
+ onValueCommit={([value]) => {
+ updateServerSetting({ lineHeight: value });
+ setDraggingLineHeight(null);
+ }}
+ max={READER_SETTING_CONSTRAINTS.lineHeight.max}
+ min={READER_SETTING_CONSTRAINTS.lineHeight.min}
+ step={READER_SETTING_CONSTRAINTS.lineHeight.step}
+ />
+ </div>
+
+ {/* Clear Defaults Button */}
+ {hasServerSettings && (
<Button
variant="outline"
- size="sm"
- onClick={handleClearLocalOverrides}
- className="w-fit"
+ onClick={handleClearDefaults}
+ className="w-full"
+ disabled={!!clientConfig.demoMode}
>
- <Laptop className="mr-2 h-4 w-4" />
- {t("settings.info.reader_settings.clear_local_overrides")}
+ <RotateCcw className="mr-2 h-4 w-4" />
+ {t("settings.info.reader_settings.clear_defaults")}
</Button>
- </AlertDescription>
- </Alert>
- )}
-
- {/* Font Family */}
- <div className="space-y-2">
- <Label className="text-sm font-medium">
- {t("settings.info.reader_settings.font_family")}
- </Label>
- <Select
- disabled={!!clientConfig.demoMode}
- value={serverSettings.fontFamily ?? "not-set"}
- onValueChange={(value) => {
- if (value !== "not-set") {
- updateServerSetting({
- fontFamily: value as "serif" | "sans" | "mono",
- });
- }
- }}
- >
- <SelectTrigger className="h-11">
- <SelectValue
- placeholder={t("settings.info.reader_settings.not_set")}
- />
- </SelectTrigger>
- <SelectContent>
- <SelectItem value="not-set" disabled>
- {t("settings.info.reader_settings.not_set")} (
- {t("common.default")}: {READER_DEFAULTS.fontFamily})
- </SelectItem>
- <SelectItem value="serif">
- {t("settings.info.reader_settings.serif")}
- </SelectItem>
- <SelectItem value="sans">
- {t("settings.info.reader_settings.sans")}
- </SelectItem>
- <SelectItem value="mono">
- {t("settings.info.reader_settings.mono")}
- </SelectItem>
- </SelectContent>
- </Select>
- {serverSettings.fontFamily === null && (
- <p className="text-xs text-muted-foreground">
- {t("settings.info.reader_settings.using_default")}:{" "}
- {READER_DEFAULTS.fontFamily}
- </p>
- )}
- </div>
+ )}
- {/* Font Size */}
- <div className="space-y-2">
- <div className="flex items-center justify-between">
- <Label className="text-sm font-medium">
- {t("settings.info.reader_settings.font_size")}
- </Label>
- <span className="text-sm text-muted-foreground">
- {formatFontSize(draggingFontSize ?? settings.fontSize)}
- {serverSettings.fontSize === null &&
- draggingFontSize === null &&
- ` (${t("common.default").toLowerCase()})`}
- </span>
- </div>
- <Slider
- disabled={!!clientConfig.demoMode}
- value={[draggingFontSize ?? settings.fontSize]}
- onValueChange={([value]) => setDraggingFontSize(value)}
- onValueCommit={([value]) => {
- updateServerSetting({ fontSize: value });
- setDraggingFontSize(null);
- }}
- max={READER_SETTING_CONSTRAINTS.fontSize.max}
- min={READER_SETTING_CONSTRAINTS.fontSize.min}
- step={READER_SETTING_CONSTRAINTS.fontSize.step}
- />
- </div>
-
- {/* Line Height */}
- <div className="space-y-2">
- <div className="flex items-center justify-between">
- <Label className="text-sm font-medium">
- {t("settings.info.reader_settings.line_height")}
- </Label>
- <span className="text-sm text-muted-foreground">
- {formatLineHeight(draggingLineHeight ?? settings.lineHeight)}
- {serverSettings.lineHeight === null &&
- draggingLineHeight === null &&
- ` (${t("common.default").toLowerCase()})`}
- </span>
- </div>
- <Slider
- disabled={!!clientConfig.demoMode}
- value={[draggingLineHeight ?? settings.lineHeight]}
- onValueChange={([value]) => setDraggingLineHeight(value)}
- onValueCommit={([value]) => {
- updateServerSetting({ lineHeight: value });
- setDraggingLineHeight(null);
- }}
- max={READER_SETTING_CONSTRAINTS.lineHeight.max}
- min={READER_SETTING_CONSTRAINTS.lineHeight.min}
- step={READER_SETTING_CONSTRAINTS.lineHeight.step}
- />
- </div>
-
- {/* Clear Defaults Button */}
- {hasServerSettings && (
- <Button
- variant="outline"
- onClick={handleClearDefaults}
- className="w-full"
- disabled={!!clientConfig.demoMode}
- >
- <RotateCcw className="mr-2 h-4 w-4" />
- {t("settings.info.reader_settings.clear_defaults")}
- </Button>
- )}
-
- {/* Preview */}
- <div className="rounded-lg border p-4">
- <p className="mb-2 text-sm font-medium text-muted-foreground">
- {t("settings.info.reader_settings.preview")}
- </p>
- <p
- style={{
- fontFamily: READER_FONT_FAMILIES[settings.fontFamily],
- fontSize: `${draggingFontSize ?? settings.fontSize}px`,
- lineHeight: draggingLineHeight ?? settings.lineHeight,
- }}
- >
- {t("settings.info.reader_settings.preview_text")}
- <br />
- {t("settings.info.reader_settings.preview_text")}
- <br />
- {t("settings.info.reader_settings.preview_text")}
- </p>
- </div>
- </CardContent>
- </Card>
+ {/* Preview */}
+ <div className="rounded-lg border p-4">
+ <p className="mb-2 text-sm font-medium text-muted-foreground">
+ {t("settings.info.reader_settings.preview")}
+ </p>
+ <p
+ style={{
+ fontFamily: READER_FONT_FAMILIES[settings.fontFamily],
+ fontSize: `${draggingFontSize ?? settings.fontSize}px`,
+ lineHeight: draggingLineHeight ?? settings.lineHeight,
+ }}
+ >
+ {t("settings.info.reader_settings.preview_text")}
+ <br />
+ {t("settings.info.reader_settings.preview_text")}
+ <br />
+ {t("settings.info.reader_settings.preview_text")}
+ </p>
+ </div>
+ </CardContent>
+ </CollapsibleContent>
+ </Card>
+ </Collapsible>
);
}