feat: reset appearance settings to their defaults

This commit is contained in:
Tautvydas Derzinskas committed 2026-10-20 19:22:30 +02:00
1 parent 292c6b1f65
commit 3c3d19a3b7
6 files changed
+85 -9

No files matched your search

@@ -1,5 +1,7 @@
import React from "react";
import { useTranslation } from "react-i18next";
import RestartAltIcon from "@mui/icons-material/RestartAlt";
import Button from "@mui/material/Button";
import MenuItem from "@mui/material/MenuItem";
import Select from "@mui/material/Select";
import Stack from "@mui/material/Stack";
@@ -9,6 +11,7 @@ import { settingsApi, type CardPreview } from "../../../api/settings";
import { matchLanguage, SUPPORTED_LANGUAGES } from "../../../constants/languages";
import {
ACCENT_COLORS,
DEFAULT_ACCENT,
RENDER_COLORS,
renderColorLabelKey,
type AccentColor,
@@ -26,12 +29,15 @@ import { setCachedAuthorPreviewEnabled, useAuthorPreviewEnabled } from "../../..
import { useCardPreview } from "../../../hooks/useCardPreview";
import { useHoverSlideshowEnabled } from "../../../hooks/useHoverSlideshowEnabled";
import { accentSwatch, renderSwatch } from "../../../theme";
import { useConfirm } from "../../ConfirmProvider";
import ColorSwatches from "../../controls/ColorSwatches";
import Segmented from "../../controls/Segmented";
import HelpTip from "../../HelpTip";
import { PanelHeader, SectionLabel } from "./parts";
const THEMES: ThemeSelection[] = ["light", "dark", "system"];
const DEFAULT_THEME: ThemeSelection = "system";
const DEFAULT_CARD_PREVIEW: CardPreview = "images";
// More languages than this no longer fit a segmented control comfortably.
const MAX_SEGMENTED_LANGUAGES = 4;
@@ -66,6 +72,7 @@ export default function AppearancePanel({ theme, onThemeChange, onUnauthorized }
const [cardPreviewError, setCardPreviewError] = React.useState<string | null>(null);
const [hoverSlideshow, setHoverSlideshow] = useHoverSlideshowEnabled();
const [hoverSlideshowError, setHoverSlideshowError] = React.useState<string | null>(null);
const confirm = useConfirm();
const changeCardPreview = async (next: CardPreview) => {
setCardPreviewError(null);
@@ -138,9 +145,47 @@ export default function AppearancePanel({ theme, onThemeChange, onUnauthorized }
}
};
// Language is left alone: it's the one choice a reset could leave someone unable to read.
const accentAtDefault = accent === DEFAULT_ACCENT && getCachedRenderColor() === null;
const atDefaults =
theme === DEFAULT_THEME &&
accentAtDefault &&
(cardPreview ?? DEFAULT_CARD_PREVIEW) === DEFAULT_CARD_PREVIEW &&
hoverSlideshow &&
authorPreview;
const resetToDefaults = async () => {
const confirmed = await confirm({
title: t("appearance.reset.title"),
message: t("appearance.reset.message"),
confirmLabel: t("appearance.reset.action"),
});
if (!confirmed) return;
// Only what differs is saved; each keeps its own error message if its save fails.
if (theme !== DEFAULT_THEME) onThemeChange(DEFAULT_THEME);
// A new accent puts the render colour back to following it.
if (!accentAtDefault) void changeAccent(DEFAULT_ACCENT);
if (cardPreview !== null && cardPreview !== DEFAULT_CARD_PREVIEW) void changeCardPreview(DEFAULT_CARD_PREVIEW);
if (!hoverSlideshow) void toggleHoverSlideshow(true);
if (!authorPreview) void toggleAuthorPreview(true);
};
return (
<>
<PanelHeader title={t("appearance.title")} subtitle={t("appearance.subtitle")} />
<PanelHeader
title={t("appearance.title")}
subtitle={t("appearance.subtitle")}
action={
<Button
size="small"
disabled={atDefaults}
startIcon={<RestartAltIcon fontSize="small" />}
onClick={() => void resetToDefaults()}
>
{t("appearance.reset.action")}
</Button>
}
/>
<Stack spacing={2.5}>
<div>
<SectionLabel>{t("profile.language.heading")}</SectionLabel>
@@ -2,15 +2,26 @@ import React from "react";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
export function PanelHeader({ title, subtitle }: { title: string; subtitle: string }) {
export function PanelHeader({
title,
subtitle,
action,
}: {
title: string;
subtitle: string;
action?: React.ReactNode;
}) {
return (
<Box sx={{ mb: 2.5 }}>
<Typography variant="body1" fontWeight={600} sx={{ color: (muiTheme) => muiTheme.thingport.headingText }}>
{title}
</Typography>
<Typography variant="caption" color="text.secondary">
{subtitle}
</Typography>
<Box sx={{ mb: 2.5, display: "flex", alignItems: "flex-start", gap: 2 }}>
<Box sx={{ flex: 1, minWidth: 0 }}>
<Typography variant="body1" fontWeight={600} sx={{ color: (muiTheme) => muiTheme.thingport.headingText }}>
{title}
</Typography>
<Typography variant="caption" color="text.secondary">
{subtitle}
</Typography>
</Box>
{action && <Box sx={{ flexShrink: 0 }}>{action}</Box>}
</Box>
);
}
+5
View File
@@ -1564,6 +1564,11 @@
"appearance": {
"title": "Appearance",
"subtitle": "Choose how Thingport looks and behaves.",
"reset": {
"action": "Reset to defaults",
"title": "Reset appearance?",
"message": "Theme, colors, model cards, hover slideshow and author preview go back to their defaults. Your language stays as it is."
},
"themes": {
"light": "Light",
"dark": "Dark",
+5
View File
@@ -1564,6 +1564,11 @@
"appearance": {
"title": "Apariencia",
"subtitle": "Elige cómo se ve y se comporta Thingport.",
"reset": {
"action": "Restablecer valores predeterminados",
"title": "¿Restablecer la apariencia?",
"message": "El tema, los colores, las tarjetas de modelos, la presentación al pasar el cursor y la vista previa del autor vuelven a sus valores predeterminados. Tu idioma no cambia."
},
"themes": {
"light": "Claro",
"dark": "Oscuro",
+5
View File
@@ -1577,6 +1577,11 @@
"appearance": {
"title": "Apparence",
"subtitle": "Choisissez l’apparence et le comportement de Thingport.",
"reset": {
"action": "Rétablir les valeurs par défaut",
"title": "Réinitialiser l'apparence ?",
"message": "Le thème, les couleurs, les cartes de modèle, le diaporama au survol et l'aperçu de l'auteur reviennent à leurs valeurs par défaut. Votre langue reste inchangée."
},
"themes": {
"light": "Clair",
"dark": "Sombre",
+5
View File
@@ -1630,6 +1630,11 @@
"appearance": {
"title": "Išvaizda",
"subtitle": "Pasirinkite, kaip Thingport atrodo ir veikia.",
"reset": {
"action": "Atkurti numatytuosius",
"title": "Atkurti išvaizdą?",
"message": "Tema, spalvos, modelių kortelės, skaidrių peržiūra užvedus ir autoriaus peržiūra grįš į numatytąsias reikšmes. Kalba liks tokia pati."
},
"themes": {
"light": "Šviesi",
"dark": "Tamsi",