126 lines
4.5 KiB
TypeScript
126 lines
4.5 KiB
TypeScript
/**
|
|
* Renders the "settings" tab of the signed-in user's own profile, where they
|
|
* change their password and this browser's preferences.
|
|
*
|
|
* @module
|
|
*/
|
|
|
|
import { useState } from "react";
|
|
import { Trans } from "@lingui/react/macro";
|
|
import type { ColorScheme, StyleName } from "../../../shared/theme.ts";
|
|
import type { FeedTab } from "../../config/feedTabs.ts";
|
|
import { useTheme } from "../../hooks/theme/useTheme.ts";
|
|
import { useDefaultFeedTab } from "../../hooks/feed/useDefaultFeedTab.ts";
|
|
import { useSoundsEnabled } from "../../hooks/shared/useSoundsEnabled.ts";
|
|
import { previewChime } from "../../utils/shared/sound.ts";
|
|
import { Segmented, type SegmentedOption } from "../shared/Segmented.tsx";
|
|
import { ChangePasswordModal } from "./ChangePasswordModal.tsx";
|
|
import { ProfileSection } from "./ProfileSection.tsx";
|
|
import { SettingRow } from "./SettingRow.tsx";
|
|
|
|
// The styles' names are their own, in every language.
|
|
const STYLE_OPTIONS: SegmentedOption<StyleName>[] = [
|
|
{ value: "smooth", label: "Smooth" },
|
|
{ value: "brutalist", label: "Brutalist" },
|
|
{ value: "geocities", label: "GeoCities" },
|
|
{ value: "nyt", label: "Times" },
|
|
{ value: "kanagawa", label: "Kanagawa" },
|
|
{ value: "melange", label: "Melange" },
|
|
];
|
|
|
|
const COLOR_SCHEME_OPTIONS: SegmentedOption<ColorScheme>[] = [
|
|
{ value: "auto", label: <Trans>Auto</Trans> },
|
|
{ value: "light", label: <Trans>Light</Trans> },
|
|
{ value: "dark", label: <Trans>Dark</Trans> },
|
|
];
|
|
|
|
const FEED_TAB_OPTIONS: SegmentedOption<FeedTab>[] = [
|
|
{ value: "hot", label: <Trans>Hot</Trans> },
|
|
{ value: "new", label: <Trans>New</Trans> },
|
|
{ value: "journal", label: <Trans>Journal</Trans> },
|
|
{ value: "followed", label: <Trans>Followed</Trans> },
|
|
];
|
|
|
|
const ON_OFF_OPTIONS: SegmentedOption<boolean>[] = [
|
|
{ value: true, label: <Trans>On</Trans> },
|
|
{ value: false, label: <Trans>Off</Trans> },
|
|
];
|
|
|
|
/**
|
|
* Renders the password change, which opens {@link ChangePasswordModal}, and
|
|
* the style, color scheme, default feed tab and sounds, each stored for this
|
|
* browser as soon as it is clicked. `UserPublicProfile` renders it on one's
|
|
* own profile only.
|
|
*/
|
|
export function ProfileSettingsTab(): React.JSX.Element {
|
|
const { style, colorScheme, setStyle, setColorScheme } = useTheme();
|
|
const [defaultFeedTab, setDefaultFeedTab] = useDefaultFeedTab();
|
|
const [soundsEnabled, setSoundsEnabled] = useSoundsEnabled();
|
|
const [changePasswordOpen, setChangePasswordOpen] = useState(false);
|
|
|
|
return (
|
|
<>
|
|
<ProfileSection title={<Trans>Account</Trans>}>
|
|
<div className="profile-appearance-grid">
|
|
<SettingRow label={<Trans>Password</Trans>}>
|
|
<button
|
|
type="button"
|
|
className="btn btn--ghost"
|
|
onClick={() => setChangePasswordOpen(true)}
|
|
>
|
|
<Trans>Change password…</Trans>
|
|
</button>
|
|
</SettingRow>
|
|
</div>
|
|
</ProfileSection>
|
|
<ProfileSection title={<Trans>Appearance</Trans>}>
|
|
<div className="profile-appearance-grid">
|
|
<SettingRow label={<Trans>Style</Trans>}>
|
|
<Segmented
|
|
options={STYLE_OPTIONS}
|
|
value={style}
|
|
onChange={setStyle}
|
|
/>
|
|
</SettingRow>
|
|
<SettingRow label={<Trans>Color scheme</Trans>}>
|
|
<Segmented
|
|
options={COLOR_SCHEME_OPTIONS}
|
|
value={colorScheme}
|
|
onChange={setColorScheme}
|
|
/>
|
|
</SettingRow>
|
|
</div>
|
|
</ProfileSection>
|
|
<ProfileSection title={<Trans>Feeds</Trans>}>
|
|
<div className="profile-appearance-grid">
|
|
<SettingRow label={<Trans>Default tab</Trans>}>
|
|
<Segmented
|
|
options={FEED_TAB_OPTIONS}
|
|
value={defaultFeedTab}
|
|
onChange={setDefaultFeedTab}
|
|
/>
|
|
</SettingRow>
|
|
</div>
|
|
</ProfileSection>
|
|
<ProfileSection title={<Trans>Notifications</Trans>}>
|
|
<div className="profile-appearance-grid">
|
|
<SettingRow label={<Trans>Sounds</Trans>}>
|
|
<Segmented
|
|
options={ON_OFF_OPTIONS}
|
|
value={soundsEnabled}
|
|
onChange={(on) => {
|
|
setSoundsEnabled(on);
|
|
// Let the user hear what they just turned on.
|
|
if (on) previewChime("notify");
|
|
}}
|
|
/>
|
|
</SettingRow>
|
|
</div>
|
|
</ProfileSection>
|
|
{changePasswordOpen && (
|
|
<ChangePasswordModal onClose={() => setChangePasswordOpen(false)} />
|
|
)}
|
|
</>
|
|
);
|
|
}
|