mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React from 'react'
2import {ScrollView, View} from 'react-native'
3import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
4import {ViewHeader} from '../com/util/ViewHeader'
5import {ThemeProvider, PaletteColorName} from 'lib/ThemeContext'
6import {usePalette} from 'lib/hooks/usePalette'
7import {s} from 'lib/styles'
8import * as Toast from 'view/com/util/Toast'
9import {Text} from '../com/util/text/Text'
10import {ViewSelector} from '../com/util/ViewSelector'
11import {EmptyState} from '../com/util/EmptyState'
12import * as LoadingPlaceholder from '../com/util/LoadingPlaceholder'
13import {Button, ButtonType} from '../com/util/forms/Button'
14import {DropdownButton, DropdownItem} from '../com/util/forms/DropdownButton'
15import {ToggleButton} from '../com/util/forms/ToggleButton'
16import {RadioGroup} from '../com/util/forms/RadioGroup'
17import {ErrorScreen} from '../com/util/error/ErrorScreen'
18import {ErrorMessage} from '../com/util/error/ErrorMessage'
19import {msg} from '@lingui/macro'
20import {useLingui} from '@lingui/react'
21
22const MAIN_VIEWS = ['Base', 'Controls', 'Error', 'Notifs']
23
24export const DebugScreen = ({}: NativeStackScreenProps<
25 CommonNavigatorParams,
26 'Debug'
27>) => {
28 const [colorScheme, setColorScheme] = React.useState<'light' | 'dark'>(
29 'light',
30 )
31 const onToggleColorScheme = () => {
32 setColorScheme(colorScheme === 'light' ? 'dark' : 'light')
33 }
34 return (
35 <ThemeProvider theme={colorScheme}>
36 <DebugInner
37 colorScheme={colorScheme}
38 onToggleColorScheme={onToggleColorScheme}
39 />
40 </ThemeProvider>
41 )
42}
43
44function DebugInner({
45 colorScheme,
46 onToggleColorScheme,
47}: {
48 colorScheme: 'light' | 'dark'
49 onToggleColorScheme: () => void
50}) {
51 const [currentView, setCurrentView] = React.useState<number>(0)
52 const pal = usePalette('default')
53 const {_} = useLingui()
54
55 const renderItem = (item: any) => {
56 return (
57 <View key={`view-${item.currentView}`}>
58 <View style={[s.pt10, s.pl10, s.pr10]}>
59 <ToggleButton
60 type="default-light"
61 onPress={onToggleColorScheme}
62 isSelected={colorScheme === 'dark'}
63 label={_(msg`Dark mode`)}
64 />
65 </View>
66 {item.currentView === 3 ? (
67 <NotifsView />
68 ) : item.currentView === 2 ? (
69 <ErrorView />
70 ) : item.currentView === 1 ? (
71 <ControlsView />
72 ) : (
73 <BaseView />
74 )}
75 </View>
76 )
77 }
78
79 const items = [{currentView}]
80
81 return (
82 <View style={[s.hContentRegion, pal.view]}>
83 <ViewHeader title={_(msg`Debug panel`)} />
84 <ViewSelector
85 swipeEnabled
86 sections={MAIN_VIEWS}
87 items={items}
88 renderItem={renderItem}
89 onSelectView={setCurrentView}
90 />
91 </View>
92 )
93}
94
95function Heading({label}: {label: string}) {
96 const pal = usePalette('default')
97 return (
98 <View style={[s.pt10, s.pb5]}>
99 <Text type="title-lg" style={pal.text}>
100 {label}
101 </Text>
102 </View>
103 )
104}
105
106function BaseView() {
107 return (
108 <View style={[s.pl10, s.pr10]}>
109 <Heading label="Typography" />
110 <TypographyView />
111 <Heading label="Palettes" />
112 <PaletteView palette="default" />
113 <PaletteView palette="primary" />
114 <PaletteView palette="secondary" />
115 <PaletteView palette="inverted" />
116 <PaletteView palette="error" />
117 <Heading label="Empty state" />
118 <EmptyStateView />
119 <Heading label="Loading placeholders" />
120 <LoadingPlaceholderView />
121 <View style={s.footerSpacer} />
122 </View>
123 )
124}
125
126function ControlsView() {
127 return (
128 <ScrollView style={[s.pl10, s.pr10]}>
129 <Heading label="Buttons" />
130 <ButtonsView />
131 <Heading label="Dropdown Buttons" />
132 <DropdownButtonsView />
133 <Heading label="Toggle Buttons" />
134 <ToggleButtonsView />
135 <Heading label="Radio Buttons" />
136 <RadioButtonsView />
137 <View style={s.footerSpacer} />
138 </ScrollView>
139 )
140}
141
142function ErrorView() {
143 return (
144 <View style={s.p10}>
145 <View style={s.mb5}>
146 <ErrorScreen
147 title="Error screen"
148 message="A major error occurred that led the entire screen to fail"
149 details="Here are some details"
150 onPressTryAgain={() => {}}
151 />
152 </View>
153 <View style={s.mb5}>
154 <ErrorMessage message="This is an error that occurred while things were being done" />
155 </View>
156 <View style={s.mb5}>
157 <ErrorMessage
158 message="This is an error that occurred while things were being done"
159 numberOfLines={1}
160 />
161 </View>
162 <View style={s.mb5}>
163 <ErrorMessage
164 message="This is an error that occurred while things were being done"
165 onPressTryAgain={() => {}}
166 />
167 </View>
168 <View style={s.mb5}>
169 <ErrorMessage
170 message="This is an error that occurred while things were being done"
171 onPressTryAgain={() => {}}
172 numberOfLines={1}
173 />
174 </View>
175 </View>
176 )
177}
178
179function NotifsView() {
180 const triggerPush = () => {
181 // TODO: implement local notification for testing
182 }
183 const triggerToast = () => {
184 Toast.show('The task has been completed')
185 }
186 const triggerToast2 = () => {
187 Toast.show('The task has been completed successfully and with no problems')
188 }
189 return (
190 <View style={s.p10}>
191 <View style={s.flexRow}>
192 <Button onPress={triggerPush} label="Trigger Push" />
193 <Button onPress={triggerToast} label="Trigger Toast" />
194 <Button onPress={triggerToast2} label="Trigger Toast 2" />
195 </View>
196 </View>
197 )
198}
199
200function PaletteView({palette}: {palette: PaletteColorName}) {
201 const defaultPal = usePalette('default')
202 const pal = usePalette(palette)
203 return (
204 <View style={[pal.view, pal.border, s.p10, s.mb5, s.border1]}>
205 <Text style={[pal.text]}>{palette} colors</Text>
206 <Text style={[pal.textLight]}>Light text</Text>
207 <Text style={[pal.link]}>Link text</Text>
208 {palette !== 'default' && (
209 <View style={[defaultPal.view]}>
210 <Text style={[pal.textInverted]}>Inverted text</Text>
211 </View>
212 )}
213 </View>
214 )
215}
216
217function TypographyView() {
218 const pal = usePalette('default')
219 return (
220 <View style={[pal.view]}>
221 <Text type="2xl-thin" style={[pal.text]}>
222 '2xl-thin' lorem ipsum dolor
223 </Text>
224 <Text type="2xl" style={[pal.text]}>
225 '2xl' lorem ipsum dolor
226 </Text>
227 <Text type="2xl-medium" style={[pal.text]}>
228 '2xl-medium' lorem ipsum dolor
229 </Text>
230 <Text type="2xl-bold" style={[pal.text]}>
231 '2xl-bold' lorem ipsum dolor
232 </Text>
233 <Text type="2xl-heavy" style={[pal.text]}>
234 '2xl-heavy' lorem ipsum dolor
235 </Text>
236 <Text type="xl-thin" style={[pal.text]}>
237 'xl-thin' lorem ipsum dolor
238 </Text>
239 <Text type="xl" style={[pal.text]}>
240 'xl' lorem ipsum dolor
241 </Text>
242 <Text type="xl-medium" style={[pal.text]}>
243 'xl-medium' lorem ipsum dolor
244 </Text>
245 <Text type="xl-bold" style={[pal.text]}>
246 'xl-bold' lorem ipsum dolor
247 </Text>
248 <Text type="xl-heavy" style={[pal.text]}>
249 'xl-heavy' lorem ipsum dolor
250 </Text>
251 <Text type="lg-thin" style={[pal.text]}>
252 'lg-thin' lorem ipsum dolor
253 </Text>
254 <Text type="lg" style={[pal.text]}>
255 'lg' lorem ipsum dolor
256 </Text>
257 <Text type="lg-medium" style={[pal.text]}>
258 'lg-medium' lorem ipsum dolor
259 </Text>
260 <Text type="lg-bold" style={[pal.text]}>
261 'lg-bold' lorem ipsum dolor
262 </Text>
263 <Text type="lg-heavy" style={[pal.text]}>
264 'lg-heavy' lorem ipsum dolor
265 </Text>
266 <Text type="md-thin" style={[pal.text]}>
267 'md-thin' lorem ipsum dolor
268 </Text>
269 <Text type="md" style={[pal.text]}>
270 'md' lorem ipsum dolor
271 </Text>
272 <Text type="md-medium" style={[pal.text]}>
273 'md-medium' lorem ipsum dolor
274 </Text>
275 <Text type="md-bold" style={[pal.text]}>
276 'md-bold' lorem ipsum dolor
277 </Text>
278 <Text type="md-heavy" style={[pal.text]}>
279 'md-heavy' lorem ipsum dolor
280 </Text>
281 <Text type="sm-thin" style={[pal.text]}>
282 'sm-thin' lorem ipsum dolor
283 </Text>
284 <Text type="sm" style={[pal.text]}>
285 'sm' lorem ipsum dolor
286 </Text>
287 <Text type="sm-medium" style={[pal.text]}>
288 'sm-medium' lorem ipsum dolor
289 </Text>
290 <Text type="sm-bold" style={[pal.text]}>
291 'sm-bold' lorem ipsum dolor
292 </Text>
293 <Text type="sm-heavy" style={[pal.text]}>
294 'sm-heavy' lorem ipsum dolor
295 </Text>
296 <Text type="xs-thin" style={[pal.text]}>
297 'xs-thin' lorem ipsum dolor
298 </Text>
299 <Text type="xs" style={[pal.text]}>
300 'xs' lorem ipsum dolor
301 </Text>
302 <Text type="xs-medium" style={[pal.text]}>
303 'xs-medium' lorem ipsum dolor
304 </Text>
305 <Text type="xs-bold" style={[pal.text]}>
306 'xs-bold' lorem ipsum dolor
307 </Text>
308 <Text type="xs-heavy" style={[pal.text]}>
309 'xs-heavy' lorem ipsum dolor
310 </Text>
311
312 <Text type="title-2xl" style={[pal.text]}>
313 'title-2xl' lorem ipsum dolor
314 </Text>
315 <Text type="title-xl" style={[pal.text]}>
316 'title-xl' lorem ipsum dolor
317 </Text>
318 <Text type="title-lg" style={[pal.text]}>
319 'title-lg' lorem ipsum dolor
320 </Text>
321 <Text type="title" style={[pal.text]}>
322 'title' lorem ipsum dolor
323 </Text>
324 <Text type="button" style={[pal.text]}>
325 Button
326 </Text>
327 <Text type="button-lg" style={[pal.text]}>
328 Button-lg
329 </Text>
330 </View>
331 )
332}
333
334function EmptyStateView() {
335 return <EmptyState icon="bars" message="This is an empty state" />
336}
337
338function LoadingPlaceholderView() {
339 return (
340 <>
341 <LoadingPlaceholder.PostLoadingPlaceholder />
342 <LoadingPlaceholder.NotificationLoadingPlaceholder />
343 </>
344 )
345}
346
347function ButtonsView() {
348 const defaultPal = usePalette('default')
349 const buttonStyles = {marginRight: 5}
350 return (
351 <View style={[defaultPal.view]}>
352 <View style={[s.flexRow, s.mb5]}>
353 <Button type="primary" label="Primary solid" style={buttonStyles} />
354 <Button type="secondary" label="Secondary solid" style={buttonStyles} />
355 </View>
356 <View style={[s.flexRow, s.mb5]}>
357 <Button type="default" label="Default solid" style={buttonStyles} />
358 <Button type="inverted" label="Inverted solid" style={buttonStyles} />
359 </View>
360 <View style={s.flexRow}>
361 <Button
362 type="primary-outline"
363 label="Primary outline"
364 style={buttonStyles}
365 />
366 <Button
367 type="secondary-outline"
368 label="Secondary outline"
369 style={buttonStyles}
370 />
371 </View>
372 <View style={s.flexRow}>
373 <Button
374 type="primary-light"
375 label="Primary light"
376 style={buttonStyles}
377 />
378 <Button
379 type="secondary-light"
380 label="Secondary light"
381 style={buttonStyles}
382 />
383 </View>
384 <View style={s.flexRow}>
385 <Button
386 type="default-light"
387 label="Default light"
388 style={buttonStyles}
389 />
390 </View>
391 </View>
392 )
393}
394
395const DROPDOWN_ITEMS: DropdownItem[] = [
396 {
397 icon: ['far', 'paste'],
398 label: 'Copy post text',
399 onPress() {},
400 },
401 {
402 icon: 'share',
403 label: 'Share...',
404 onPress() {},
405 },
406 {
407 icon: 'circle-exclamation',
408 label: 'Report post',
409 onPress() {},
410 },
411]
412function DropdownButtonsView() {
413 const defaultPal = usePalette('default')
414 return (
415 <View style={[defaultPal.view]}>
416 <View style={s.mb5}>
417 <DropdownButton
418 type="primary"
419 items={DROPDOWN_ITEMS}
420 menuWidth={200}
421 label="Primary button"
422 />
423 </View>
424 <View style={s.mb5}>
425 <DropdownButton type="bare" items={DROPDOWN_ITEMS} menuWidth={200}>
426 <Text>Bare</Text>
427 </DropdownButton>
428 </View>
429 </View>
430 )
431}
432
433function ToggleButtonsView() {
434 const defaultPal = usePalette('default')
435 const buttonStyles = s.mb5
436 const [isSelected, setIsSelected] = React.useState(false)
437 const onToggle = () => setIsSelected(!isSelected)
438 return (
439 <View style={[defaultPal.view]}>
440 <ToggleButton
441 type="primary"
442 label="Primary solid"
443 style={buttonStyles}
444 isSelected={isSelected}
445 onPress={onToggle}
446 />
447 <ToggleButton
448 type="secondary"
449 label="Secondary solid"
450 style={buttonStyles}
451 isSelected={isSelected}
452 onPress={onToggle}
453 />
454 <ToggleButton
455 type="inverted"
456 label="Inverted solid"
457 style={buttonStyles}
458 isSelected={isSelected}
459 onPress={onToggle}
460 />
461 <ToggleButton
462 type="primary-outline"
463 label="Primary outline"
464 style={buttonStyles}
465 isSelected={isSelected}
466 onPress={onToggle}
467 />
468 <ToggleButton
469 type="secondary-outline"
470 label="Secondary outline"
471 style={buttonStyles}
472 isSelected={isSelected}
473 onPress={onToggle}
474 />
475 <ToggleButton
476 type="primary-light"
477 label="Primary light"
478 style={buttonStyles}
479 isSelected={isSelected}
480 onPress={onToggle}
481 />
482 <ToggleButton
483 type="secondary-light"
484 label="Secondary light"
485 style={buttonStyles}
486 isSelected={isSelected}
487 onPress={onToggle}
488 />
489 <ToggleButton
490 type="default-light"
491 label="Default light"
492 style={buttonStyles}
493 isSelected={isSelected}
494 onPress={onToggle}
495 />
496 </View>
497 )
498}
499
500const RADIO_BUTTON_ITEMS = [
501 {key: 'default-light', label: 'Default Light'},
502 {key: 'primary', label: 'Primary'},
503 {key: 'secondary', label: 'Secondary'},
504 {key: 'inverted', label: 'Inverted'},
505 {key: 'primary-outline', label: 'Primary Outline'},
506 {key: 'secondary-outline', label: 'Secondary Outline'},
507 {key: 'primary-light', label: 'Primary Light'},
508 {key: 'secondary-light', label: 'Secondary Light'},
509]
510function RadioButtonsView() {
511 const defaultPal = usePalette('default')
512 const [rgType, setRgType] = React.useState<ButtonType>('default-light')
513 return (
514 <View style={[defaultPal.view]}>
515 <RadioGroup
516 type={rgType}
517 items={RADIO_BUTTON_ITEMS}
518 initialSelection="default-light"
519 onSelect={v => setRgType(v as ButtonType)}
520 />
521 </View>
522 )
523}