1
+ import { Button } from "@follow/components/ui/button/index.js"
1
2
import {
2
3
Select ,
3
4
SelectContent ,
@@ -8,20 +9,31 @@ import {
8
9
import { useIsDark , useThemeAtomValue } from "@follow/hooks"
9
10
import { IN_ELECTRON } from "@follow/shared/constants"
10
11
import { getOS } from "@follow/utils/utils"
12
+ import { useForceUpdate } from "framer-motion"
13
+ import { useEffect , useRef } from "react"
11
14
import { useTranslation } from "react-i18next"
12
15
import { bundledThemesInfo } from "shiki/themes"
13
16
14
17
import {
18
+ getUISettings ,
15
19
setUISetting ,
16
20
useUISettingKey ,
17
21
useUISettingSelector ,
18
22
useUISettingValue ,
19
23
} from "~/atoms/settings/ui"
20
24
import { setFeedColumnShow , useFeedColumnShow } from "~/atoms/sidebar"
25
+ import { useCurrentModal , useModalStack } from "~/components/ui/modal/stacked/hooks"
21
26
import { isElectronBuild } from "~/constants"
22
27
import { useSetTheme } from "~/hooks/common"
23
28
24
- import { SettingDescription , SettingSwitch , SettingTabbedSegment } from "../control"
29
+ import { CSSEditor } from "../../editor/css-editor"
30
+ import { SETTING_MODAL_ID } from "../constants"
31
+ import {
32
+ SettingActionItem ,
33
+ SettingDescription ,
34
+ SettingSwitch ,
35
+ SettingTabbedSegment ,
36
+ } from "../control"
25
37
import { createDefineSettingItem } from "../helper/builder"
26
38
import { createSettingBuilder } from "../helper/setting-builder"
27
39
import { SettingItemGroup } from "../section"
@@ -71,6 +83,7 @@ export const SettingAppearance = () => {
71
83
} ) ,
72
84
ZenMode ,
73
85
ThumbnailRatio ,
86
+ CustomCSS ,
74
87
75
88
{
76
89
type : "title" ,
@@ -290,3 +303,90 @@ const ThumbnailRatio = () => {
290
303
</ SettingItemGroup >
291
304
)
292
305
}
306
+
307
+ const CustomCSS = ( ) => {
308
+ const { t } = useTranslation ( "settings" )
309
+ const { present } = useModalStack ( )
310
+ return (
311
+ < SettingItemGroup >
312
+ < SettingActionItem
313
+ label = { t ( "appearance.custom_css.label" ) }
314
+ action = { ( ) => {
315
+ present ( {
316
+ title : t ( "appearance.custom_css.label" ) ,
317
+ content : CustomCSSModal ,
318
+ clickOutsideToDismiss : false ,
319
+ overlay : false ,
320
+ resizeable : true ,
321
+ resizeDefaultSize : {
322
+ width : 700 ,
323
+ height : 400 ,
324
+ } ,
325
+ } )
326
+ } }
327
+ buttonText = { t ( "appearance.custom_css.button" ) }
328
+ />
329
+ < SettingDescription > { t ( "appearance.custom_css.description" ) } </ SettingDescription >
330
+ </ SettingItemGroup >
331
+ )
332
+ }
333
+
334
+ const CustomCSSModal = ( ) => {
335
+ const initialCSS = useRef ( getUISettings ( ) . customCSS )
336
+ const { t } = useTranslation ( "common" )
337
+ const { dismiss } = useCurrentModal ( )
338
+ useEffect ( ( ) => {
339
+ return ( ) => {
340
+ setUISetting ( "customCSS" , initialCSS . current )
341
+ }
342
+ } , [ ] )
343
+ useEffect ( ( ) => {
344
+ const modal = document . querySelector ( `#${ SETTING_MODAL_ID } ` ) as HTMLDivElement
345
+ if ( ! modal ) return
346
+ const prevOverlay = getUISettings ( ) . modalOverlay
347
+ setUISetting ( "modalOverlay" , false )
348
+
349
+ modal . style . display = "none"
350
+ return ( ) => {
351
+ setUISetting ( "modalOverlay" , prevOverlay )
352
+
353
+ modal . style . display = "block"
354
+ }
355
+ } , [ ] )
356
+ const [ forceUpdate , key ] = useForceUpdate ( )
357
+ return (
358
+ < form
359
+ className = "relative flex h-full max-w-full flex-col"
360
+ onSubmit = { ( e ) => {
361
+ e . preventDefault ( )
362
+ if ( initialCSS . current !== getUISettings ( ) . customCSS ) {
363
+ initialCSS . current = getUISettings ( ) . customCSS
364
+ }
365
+ dismiss ( )
366
+ } }
367
+ >
368
+ < CSSEditor
369
+ defaultValue = { initialCSS . current }
370
+ key = { key }
371
+ className = "h-0 grow rounded-lg border p-3 font-mono"
372
+ onChange = { ( value ) => {
373
+ setUISetting ( "customCSS" , value )
374
+ } }
375
+ />
376
+
377
+ < div className = "mt-2 flex shrink-0 justify-end gap-2" >
378
+ < Button
379
+ variant = "outline"
380
+ onClick = { ( e ) => {
381
+ e . preventDefault ( )
382
+ setUISetting ( "customCSS" , initialCSS . current )
383
+ forceUpdate ( )
384
+ } }
385
+ >
386
+ { t ( "words.reset" ) }
387
+ </ Button >
388
+ < Button type = "submit" > { t ( "words.save" ) } </ Button >
389
+ </ div >
390
+ </ form >
391
+ )
392
+ }
0 commit comments