Skip to content

Commit

Permalink
refactor: setting atoms and support disable scroll to mark read (#108)
Browse files Browse the repository at this point in the history
* refactor: setting atoms

Signed-off-by: Innei <i@innei.in>

* fix: export

Signed-off-by: Innei <i@innei.in>

* feat: show settings hotkey in web app

Signed-off-by: Innei <i@innei.in>

* feat: mark unread when scroll switch

Signed-off-by: Innei <i@innei.in>

* chore: pin electron builder.

electron-userland/electron-builder#8175
Signed-off-by: Innei <i@innei.in>

---------

Signed-off-by: Innei <i@innei.in>
  • Loading branch information
Innei committed Jul 4, 2024
1 parent 63b1926 commit 7c10ddb
Show file tree
Hide file tree
Showing 33 changed files with 373 additions and 1,191 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
"@vercel/ncc": "0.38.1",
"@vitejs/plugin-react": "^4.3.1",
"electron": "^30.1.2",
"electron-builder": "^24.9.1",
"electron-builder": "24.9.1",
"electron-devtools-installer": "3.2.0",
"electron-vite": "^2.3.0",
"eslint": "^9.6.0",
Expand Down
1,064 changes: 65 additions & 999 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

29 changes: 20 additions & 9 deletions src/renderer/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { queryClient } from "@renderer/lib/query-client"
import { registerGlobalContext } from "@shared/bridge"
import { useEffect } from "react"
import { useEffect, useLayoutEffect } from "react"
import { Outlet } from "react-router-dom"
import { toast } from "sonner"

import { useAppIsReady } from "./atoms/app"
import { useUISettingKey } from "./atoms/ui"
import { useUISettingKey } from "./atoms/settings/ui"
import { useDark } from "./hooks/common/useDark"
import { RootProviders } from "./providers/root-providers"
import { handlers } from "./tipc"
Expand All @@ -20,13 +18,24 @@ function App() {
})
})

registerGlobalContext({
showSetting: window.router.showSettings,
toast,
})
return cleanup
}, [])

useLayoutEffect(() => {
// Electron app register in app scope, but web app should register in window scope
if (window.electron) return
const handleOpenSettings = (e) => {
if (e.key === "," && (e.metaKey || e.ctrlKey)) {
window.router.showSettings()
e.preventDefault()
}
}
document.addEventListener("keydown", handleOpenSettings)

return () => {
document.removeEventListener("keydown", handleOpenSettings)
}
}, [])
return (
<>
{window.electron && (
Expand All @@ -35,7 +44,9 @@ function App() {
aria-hidden
/>
)}
<RootProviders><AppLayer /></RootProviders>
<RootProviders>
<AppLayer />
</RootProviders>
</>
)
}
Expand Down
28 changes: 28 additions & 0 deletions src/renderer/src/atoms/settings/general.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { jotaiStore } from "@renderer/lib/jotai"

import { createSettingAtom } from "./helper"

const createDefaultSettings = () => ({
dataPersist: true,

// mark unread
scrollMarkUnread: true,

})
export const {
useSettingKey: useGeneralSettingKey,
useSettingSelector: useGeneralSettingSelector,
setSetting: setGeneralSetting,
clearSettings: clearGeneralSettings,
initializeDefaultSettings: initializeDefaultGeneralSettings,
getSettings: getGeneralSettings,
useSettingValue: useGeneralSettingValue,

settingAtom: __generalSettingAtom,
} = createSettingAtom("general", createDefaultSettings)

export const subscribeShouldUseIndexedDB = (
callback: (value: boolean) => void,
) =>
jotaiStore.sub(__generalSettingAtom, () =>
callback(getGeneralSettings().dataPersist))
76 changes: 76 additions & 0 deletions src/renderer/src/atoms/settings/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { useRefValue } from "@renderer/hooks/common"
import { createAtomHooks } from "@renderer/lib/jotai"
import { getStorageNS } from "@renderer/lib/ns"
import { useAtomValue } from "jotai"
import { atomWithStorage, selectAtom } from "jotai/utils"
import { useMemo } from "react"

export const createSettingAtom = <T extends Record<string, unknown>>(
settingKey: string,
createDefaultSettings: () => T,
) => {
const atom = atomWithStorage(
getStorageNS(settingKey),
createDefaultSettings(),
undefined,
{
getOnInit: true,
},
)
const [, , useSettingValue, , getSettings, setSettings] =
createAtomHooks(atom)

const initializeDefaultSettings = () => {
const currentSettings = getSettings()
const defaultSettings = createDefaultSettings()
if (typeof currentSettings !== "object") setSettings(defaultSettings)
const newSettings = { ...defaultSettings, ...currentSettings }
setSettings(newSettings)
}

const useSettingKey = <T extends keyof ReturnType<typeof getSettings>>(
key: T,
) => useAtomValue(useMemo(() => selectAtom(atom, (s) => s[key]), [key]))

const useSettingSelector = <
T extends keyof ReturnType<typeof getSettings>,
S extends ReturnType<typeof getSettings>,
R = S[T],
>(
selector: (s: S) => R,
): R => {
const stableSelector = useRefValue(selector)

return useAtomValue(
// @ts-expect-error

Check warning on line 45 in src/renderer/src/atoms/settings/helper.ts

View workflow job for this annotation

GitHub Actions / Lint and Typecheck (18.x)

Include a description after the "@ts-expect-error" directive to explain why the @ts-expect-error is necessary. The description must be 3 characters or longer
useMemo(() => selectAtom(atom, stableSelector.current), [stableSelector]),
)
}

const setSetting = <K extends keyof ReturnType<typeof getSettings>>(
key: K,
value: ReturnType<typeof getSettings>[K],
) => {
setSettings({
...getSettings(),
[key]: value,
})
}

const clearSettings = () => {
setSettings(createDefaultSettings())
}

return {
useSettingKey,
useSettingSelector,
setSetting,
clearSettings,
initializeDefaultSettings,

useSettingValue,
getSettings,

settingAtom: atom,
}
}
7 changes: 7 additions & 0 deletions src/renderer/src/atoms/settings/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { initializeDefaultGeneralSettings } from "./general"
import { initializeDefaultUISettings } from "./ui"

export const initializeSettings = () => {
initializeDefaultUISettings()
initializeDefaultGeneralSettings()
}
32 changes: 32 additions & 0 deletions src/renderer/src/atoms/settings/ui.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { createSettingAtom } from "./helper"

const createDefaultSettings = () => ({
// Sidebar
entryColWidth: 340,
opaqueSidebar: false,
sidebarShowUnreadCount: true,

// Global UI
uiTextSize: 16,
// System
showDockBadge: true,
// Misc
modalOverlay: true,
modalDraggable: true,
modalOpaque: true,
reduceMotion: false,

// Content
readerFontFamily: "SN Pro",
readerRenderInlineStyle: false,
codeHighlightTheme: "github-dark",
})
export const {
useSettingKey: useUISettingKey,
useSettingSelector: useUISettingSelector,
setSetting: setUISetting,
clearSettings: clearUISettings,
initializeDefaultSettings: initializeDefaultUISettings,
getSettings: getUISettings,
useSettingValue: useUISettingValue,
} = createSettingAtom("ui", createDefaultSettings)
82 changes: 0 additions & 82 deletions src/renderer/src/atoms/ui.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/renderer/src/components/ui/background/vibrancy.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useUISettingKey } from "@renderer/atoms/ui"
import { useUISettingKey } from "@renderer/atoms/settings/ui"
import { useDark } from "@renderer/hooks/common"
import { cn } from "@renderer/lib/utils"
import { useMediaQuery } from "usehooks-ts"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable @eslint-react/dom/no-dangerously-set-innerhtml */
import { useUISettingSelector } from "@renderer/atoms/ui"
import { useUISettingSelector } from "@renderer/atoms/settings/ui"
import { cn } from "@renderer/lib/utils"
import type { FC } from "react"
import { useLayoutEffect, useMemo, useRef, useState } from "react"
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/components/ui/modal/stacked/hooks.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getUISettings } from "@renderer/atoms/ui"
import { getUISettings } from "@renderer/atoms/settings/ui"
import { jotaiStore } from "@renderer/lib/jotai"
import { useCallback, useContext, useEffect, useId, useRef } from "react"
import { useLocation } from "react-router-dom"
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/components/ui/modal/stacked/modal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as Dialog from "@radix-ui/react-dialog"
import { useUISettingKey } from "@renderer/atoms/ui"
import { useUISettingKey } from "@renderer/atoms/settings/ui"
import { m } from "@renderer/components/common/Motion"
import { stopPropagation } from "@renderer/lib/dom"
import { cn } from "@renderer/lib/utils"
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/components/ui/modal/stacked/provider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useUISettingKey } from "@renderer/atoms/ui"
import { useUISettingKey } from "@renderer/atoms/settings/ui"
import { AnimatePresence } from "framer-motion"
import { useAtomValue } from "jotai"
import type { FC, PropsWithChildren } from "react"
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/components/user-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const LoginButton: FC<LoginProps> = (props) => {
modalStack.present({
CustomModalComponent: NoopChildren,
title: "Login",
id: "login",
content: () => (
<LoginModalContent
runtime={window.electron ? "app" : "browser"}
Expand Down
16 changes: 0 additions & 16 deletions src/renderer/src/database/hooks.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/renderer/src/database/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from "./db"
export * from "./hooks"
export * from "./models"
export * from "./schemas"
2 changes: 1 addition & 1 deletion src/renderer/src/hooks/biz/useReduceMotion.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useUISettingKey } from "@renderer/atoms/ui"
import { useUISettingKey } from "@renderer/atoms/settings/ui"
import { useReducedMotion } from "framer-motion"

export const useReduceMotion = () => {
Expand Down
Loading

0 comments on commit 7c10ddb

Please sign in to comment.