personal fork of bluesky app
bsky.kelinci.net
6.3 kB
151 lines
1import { useState } from 'react';
2
3import { clsx } from 'clsx';
4
5import { useTitle } from '#/lib/hooks/useTitle';
6
7import { logoutEveryAccount } from '#/state/session';
8
9import { Accessibility_Stroke2_Corner2_Rounded as AccessibilityIcon } from '#/components/icons/Accessibility';
10import { Bell_Stroke2_Corner0_Rounded as NotificationIcon } from '#/components/icons/Bell';
11import { CodeBrackets_Stroke2_Corner2_Rounded as CodeBracketsIcon } from '#/components/icons/CodeBrackets';
12import { CodeLines_Stroke2_Corner2_Rounded as CodeLinesIcon } from '#/components/icons/CodeLines';
13import { Earth_Stroke2_Corner2_Rounded as EarthIcon } from '#/components/icons/Globe';
14import { PaintRoller_Stroke2_Corner2_Rounded as PaintRollerIcon } from '#/components/icons/PaintRoller';
15import { Person_Stroke2_Corner2_Rounded as PersonIcon } from '#/components/icons/Person';
16import { RaisingHand4Finger_Stroke2_Corner2_Rounded as HandIcon } from '#/components/icons/RaisingHand';
17import { Window_Stroke2_Corner2_Rounded as WindowIcon } from '#/components/icons/Window';
18import * as Prompt from '#/components/Prompt';
19import * as Settings from '#/components/SettingsCards';
20import * as cardStyles from '#/components/SettingsCards.css';
21import { Text } from '#/components/Text';
22import * as Layout from '#/components/web/Layout';
23
24import { m } from '#/paraglide/messages';
25import { useDebugFeedContextEnabled } from '#/storage/hooks/debug';
26import { useDevMode } from '#/storage/hooks/dev-mode';
27
28import { AccountsSection } from './components/AccountsSection';
29import { ServiceWorkerSection } from './components/ServiceWorkerSection';
30
31export function SettingsScreen() {
32 useTitle(m['common.nav.settings']());
33
34 const signOutPromptHandle = Prompt.usePromptHandle();
35
36 return (
37 <Layout.Screen>
38 <Layout.Header.Outer>
39 <Layout.Header.BackButton />
40 <Layout.Header.Content>
41 <Layout.Header.TitleText>{m['common.nav.settings']()}</Layout.Header.TitleText>
42 </Layout.Header.Content>
43 </Layout.Header.Outer>
44 <Layout.Content>
45 <Settings.List>
46 <AccountsSection />
47
48 <Settings.Section titleText={m['screens.settings.preferences.title']()}>
49 <Settings.LinkRow label={m['screens.settings.account.privacyTitle']()} to="/settings/account">
50 <Settings.Icon icon={PersonIcon} />
51 <Settings.Label titleText={m['common.account.privacy']()} />
52 </Settings.LinkRow>
53 <Settings.LinkRow label={m['screens.settings.moderation.title']()} to="/moderation">
54 <Settings.Icon icon={HandIcon} />
55 <Settings.Label titleText={m['screens.settings.moderation.title']()} />
56 </Settings.LinkRow>
57 <Settings.LinkRow label={m['common.nav.notifications']()} to="/settings/notifications">
58 <Settings.Icon icon={NotificationIcon} />
59 <Settings.Label titleText={m['common.nav.notifications']()} />
60 </Settings.LinkRow>
61 <Settings.LinkRow label={m['screens.settings.media.title']()} to="/settings/content-and-media">
62 <Settings.Icon icon={WindowIcon} />
63 <Settings.Label titleText={m['screens.settings.media.title']()} />
64 </Settings.LinkRow>
65 <Settings.LinkRow label={m['common.appearance.label']()} to="/settings/appearance">
66 <Settings.Icon icon={PaintRollerIcon} />
67 <Settings.Label titleText={m['common.appearance.label']()} />
68 </Settings.LinkRow>
69 <Settings.LinkRow
70 label={m['screens.settings.accessibility.title']()}
71 to="/settings/accessibility"
72 >
73 <Settings.Icon icon={AccessibilityIcon} />
74 <Settings.Label titleText={m['screens.settings.accessibility.title']()} />
75 </Settings.LinkRow>
76 <Settings.LinkRow label={m['screens.settings.language.title']()} to="/settings/language">
77 <Settings.Icon icon={EarthIcon} />
78 <Settings.Label titleText={m['screens.settings.language.title']()} />
79 </Settings.LinkRow>
80 </Settings.Section>
81
82 {/* dev builds emit no service worker (see ServiceWorkerPrecachePlugin), so the install row is inert there — see registerServiceWorker */}
83 <ServiceWorkerSection />
84
85 <Settings.Section>
86 <button
87 aria-label={m['common.session.action.signOut']()}
88 className={clsx(cardStyles.row, cardStyles.rowInteractive)}
89 onClick={() => signOutPromptHandle.open(null)}
90 type="button"
91 >
92 <Text className={cardStyles.title} color="negative_500" size="md" weight="medium">
93 {m['common.session.action.signOut']()}
94 </Text>
95 </button>
96 </Settings.Section>
97
98 <Settings.Section>
99 <Settings.LinkRow label={m['common.developer.systemLog']()} to="/sys/log">
100 <Settings.Icon icon={CodeLinesIcon} />
101 <Settings.Label titleText={m['common.developer.systemLog']()} />
102 </Settings.LinkRow>
103 <DevOptionsRow />
104 </Settings.Section>
105 </Settings.List>
106 </Layout.Content>
107
108 <Prompt.Basic
109 cancelButtonCta={m['common.action.cancel']()}
110 confirmButtonColor="negative"
111 confirmButtonCta={m['common.session.action.signOut']()}
112 description={m['common.session.signOut.message']()}
113 handle={signOutPromptHandle}
114 onConfirm={() => logoutEveryAccount()}
115 title={m['common.session.signOut.title']()}
116 />
117 </Layout.Screen>
118 );
119}
120
121function DevOptionsRow({ className }: { className?: string }) {
122 const [debugFeedContextEnabled, setDebugFeedContextEnabled] = useDebugFeedContextEnabled();
123 const [devModeEnabled, setDevModeEnabled] = useDevMode();
124 const [open, setOpen] = useState(false);
125
126 return (
127 <Settings.CollapsibleRow
128 className={className}
129 icon={CodeBracketsIcon}
130 label={m['screens.settings.developer.title']()}
131 onOpenChange={setOpen}
132 open={open}
133 titleText={m['screens.settings.developer.title']()}
134 >
135 <Settings.SwitchRow
136 label={m['screens.settings.developer.mode']()}
137 onChange={setDevModeEnabled}
138 value={devModeEnabled}
139 >
140 <Settings.Label titleText={m['screens.settings.developer.mode']()} />
141 </Settings.SwitchRow>
142 <Settings.SwitchRow
143 label={m['screens.settings.developer.showFeedContext']()}
144 onChange={setDebugFeedContextEnabled}
145 value={debugFeedContextEnabled}
146 >
147 <Settings.Label titleText={m['screens.settings.developer.showFeedContext']()} />
148 </Settings.SwitchRow>
149 </Settings.CollapsibleRow>
150 );
151}