chore: use `IN_ELECTRON` constant

Signed-off-by: Innei <i@innei.in>
This commit is contained in:
Innei 2024-10-08 14:14:42 +08:00
parent 892ceb2269
commit 6ef652f7b2
No known key found for this signature in database
GPG Key ID: 0F62D33977F021F7
33 changed files with 96 additions and 66 deletions

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { env } from "@follow/shared/env"
import { useEffect, useLayoutEffect } from "react"
import { Outlet } from "react-router-dom"
@ -29,7 +30,7 @@ function App() {
useLayoutEffect(() => {
// Electron app register in app scope, but web app should register in window scope
if (window.electron) return
if (IN_ELECTRON) return
const handleOpenSettings = (e) => {
if (e.key === "," && (e.metaKey || e.ctrlKey)) {
window.router.showSettings()
@ -43,10 +44,10 @@ function App() {
}
}, [])
const windowsElectron = window.electron && getOS() === "Windows"
const windowsElectron = IN_ELECTRON && getOS() === "Windows"
return (
<RootProviders>
{window.electron && (
{IN_ELECTRON && (
<div
className={cn(
"drag-region fixed inset-x-0 top-0 h-12 shrink-0",

View File

@ -1,17 +0,0 @@
import type { ReactNode } from "react"
import { useState } from "react"
function Versions(): ReactNode {
const [versions] = useState(window.electron?.process.versions)
if (!versions) return null
return (
<ul className="versions">
<li className="electron-version">Electron v{versions.electron}</li>
<li className="chrome-version">Chromium v{versions.chrome}</li>
<li className="node-version">Node v{versions.node}</li>
</ul>
)
}
export default Versions

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import type { MediaModel } from "@follow/shared/hono"
import type { FC } from "react"
import { Fragment, useCallback, useEffect, useRef, useState } from "react"
@ -52,7 +53,7 @@ const Wrapper: Component<{
>
{showActions && (
<Fragment>
{!!window.electron && (
{IN_ELECTRON && (
<ActionButton
tooltip={t("external:header.download")}
onClick={() => {

View File

@ -1,5 +1,7 @@
import { IN_ELECTRON } from "@follow/shared/constants"
const OpenInBrowser = (_t?: any) =>
window.electron ? "keys.entry.openInBrowser" : "keys.entry.openInNewTab"
IN_ELECTRON ? "keys.entry.openInBrowser" : "keys.entry.openInNewTab"
export const COPY_MAP = {
OpenInBrowser,

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { useMutation, useQuery } from "@tanstack/react-query"
import type { FetchError } from "ofetch"
import { ofetch } from "ofetch"
@ -362,7 +363,7 @@ export const useEntryActions = ({
{
key: "openInBrowser",
name: t("entry_actions.open_in_browser", {
which: t(window.electron ? "words.browser" : "words.newTab"),
which: t(IN_ELECTRON ? "words.browser" : "words.newTab"),
}),
shortcut: shortcuts.entry.openInBrowser.key,
className: "i-mgc-world-2-cute-re",
@ -406,12 +407,12 @@ export const useEntryActions = ({
key: "share",
className: getOS() === "macOS" ? `i-mgc-share-3-cute-re` : "i-mgc-share-forward-cute-re",
shortcut: shortcuts.entry.share.key,
hide: !window.electron && !navigator.share,
hide: !IN_ELECTRON && !navigator.share,
onClick: () => {
if (!populatedEntry.entries.url) return
if (window.electron) {
if (IN_ELECTRON) {
return tipcClient?.showShareMenu(populatedEntry.entries.url)
} else {
navigator.share({

View File

@ -1,4 +1,4 @@
import { WEB_URL } from "@follow/shared/constants"
import { IN_ELECTRON, WEB_URL } from "@follow/shared/constants"
import { env } from "@follow/shared/env"
import { useMemo } from "react"
import { useTranslation } from "react-i18next"
@ -169,7 +169,7 @@ export const useFeedActions = ({
{
type: "text" as const,
label: t("sidebar.feed_actions.open_feed_in_browser", {
which: t(window.electron ? "words.browser" : "words.newTab"),
which: t(IN_ELECTRON ? "words.browser" : "words.newTab"),
}),
disabled: isEntryList,
shortcut: "O",
@ -178,7 +178,7 @@ export const useFeedActions = ({
{
type: "text" as const,
label: t("sidebar.feed_actions.open_site_in_browser", {
which: t(window.electron ? "words.browser" : "words.newTab"),
which: t(IN_ELECTRON ? "words.browser" : "words.newTab"),
}),
shortcut: "Meta+O",
disabled: isEntryList,
@ -292,7 +292,7 @@ export const useListActions = ({ listId, view }: { listId: string; view: FeedVie
{
type: "text" as const,
label: t("sidebar.feed_actions.open_list_in_browser", {
which: t(window.electron ? "words.browser" : "words.newTab"),
which: t(IN_ELECTRON ? "words.browser" : "words.newTab"),
}),
disabled: false,
shortcut: "O",

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { atom, useAtomValue } from "jotai"
import { atomWithStorage } from "jotai/utils"
import { useCallback, useLayoutEffect } from "react"
@ -10,7 +11,7 @@ import { getStorageNS } from "~/lib/ns"
const useDarkQuery = () => useMediaQuery("(prefers-color-scheme: dark)")
type ColorMode = "light" | "dark" | "system"
const themeAtom = !window.electron
const themeAtom = !IN_ELECTRON
? atomWithStorage(getStorageNS("color-mode"), "system" as ColorMode, undefined, {
getOnInit: true,
})
@ -55,13 +56,13 @@ const useSyncThemeWebApp = () => {
}, [colorMode, systemIsDark])
}
export const useSyncThemeark = window.electron ? useSyncThemeElectron : useSyncThemeWebApp
export const useSyncThemeark = IN_ELECTRON ? useSyncThemeElectron : useSyncThemeWebApp
export const useSetTheme = () =>
useCallback((colorMode: ColorMode) => {
jotaiStore.set(themeAtom, colorMode)
if (window.electron) {
if (IN_ELECTRON) {
tipcClient?.setAppearance(colorMode)
}
}, [])

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { atom, useAtomValue, useSetAtom } from "jotai"
import { useCallback } from "react"
@ -17,7 +18,7 @@ export const useSetProxy = () => {
const setProxy = useSetAtom(proxyAtom)
return useCallback(
(proxyString: string) => {
if (!window.electron) {
if (!IN_ELECTRON) {
return
}
setProxy(proxyString)

View File

@ -1,6 +1,7 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { useEffect, useRef } from "react"
const titleTemplate = window.electron ? `%s` : `%s | ${APP_NAME}`
const titleTemplate = IN_ELECTRON ? `%s` : `%s | ${APP_NAME}`
export const useTitle = (title?: Nullable<string>) => {
const currentTitleRef = useRef(document.title)

View File

@ -1,4 +1,5 @@
import { registerGlobalContext } from "@follow/shared/bridge"
import { IN_ELECTRON } from "@follow/shared/constants"
import { env } from "@follow/shared/env"
import { authConfigManager } from "@hono/auth-js/react"
import { repository } from "@pkg"
@ -106,7 +107,7 @@ export const initializeApp = async () => {
appLog(`Initialize ${APP_NAME} done,`, `${loadingTime}ms`)
window.posthog?.capture("app_init", {
electron: !!window.electron,
electron: IN_ELECTRON,
loading_time: loadingTime,
using_indexed_db: enabledDataPersist,
data_hydrated_time: dataHydratedTime,

View File

@ -1,10 +1,10 @@
import { WEB_URL } from "@follow/shared/constants"
import { IN_ELECTRON, WEB_URL } from "@follow/shared/constants"
import { signIn } from "@hono/auth-js/react"
export const LOGIN_CALLBACK_URL = `${WEB_URL}/redirect?app=follow`
export type LoginRuntime = "browser" | "app"
export const loginHandler = (provider: string, runtime: LoginRuntime = "app") => {
if (window.electron) {
if (IN_ELECTRON) {
window.open(`${WEB_URL}/login?provider=${provider}`)
} else {
signIn(provider, {

View File

@ -1,9 +1,11 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { detectBrowser, getOS } from "./utils"
export const getCurrentEnvironment = () => {
const ua = navigator.userAgent
const appVersion = APP_VERSION
const env = window.electron ? "electron" : "web"
const env = IN_ELECTRON ? "electron" : "web"
const os = getOS()
const browser = detectBrowser()

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import dayjs from "dayjs"
import i18next from "i18next"
import { toast } from "sonner"
@ -70,7 +71,7 @@ export const loadLanguageAndApply = async (lang: string) => {
} else {
let importFilePath = ""
if (window.electron) {
if (IN_ELECTRON) {
importFilePath =
(await tipcClient?.resolveAppAsarPath(`dist/renderer/locales/${lang}.js`)) || ""

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { get } from "lodash-es"
import { tipcClient } from "./client"
@ -58,8 +59,7 @@ export const showNativeMenu = async (
}
// only show native menu on macOS electron, because in other platform, the native ui is not good
if (!window.electron || getOS() !== "macOS") {
if (!IN_ELECTRON || getOS() !== "macOS") {
document.dispatchEvent(
new CustomEvent(CONTEXT_MENU_SHOW_EVENT_KEY, {
detail: {

View File

@ -1,6 +1,8 @@
import { IN_ELECTRON } from "@follow/shared/constants"
export const urlToIframe = (url?: string | null, mini?: boolean) => {
if (url?.match(/\/\/www.bilibili.com\/video\/BV\w+/)) {
const player = window.electron
const player = IN_ELECTRON
? "https://www.bilibili.com/blackboard/newplayer.html"
: "https://player.bilibili.com/player.html"
return `${player}?${new URLSearchParams({

View File

@ -1,5 +1,6 @@
import "./styles/main.css"
import { IN_ELECTRON } from "@follow/shared/constants"
import { ClickToComponent } from "click-to-react-component"
import * as React from "react"
import ReactDOM from "react-dom/client"
@ -17,7 +18,7 @@ initializeApp().finally(() => {
const $container = document.querySelector("#root") as HTMLElement
if (window.electron && getOS() === "Windows") {
if (IN_ELECTRON && getOS() === "Windows") {
document.body.style.cssText += `--fo-window-padding-top: ${ElECTRON_CUSTOM_TITLEBAR_HEIGHT}px;`
}
ReactDOM.createRoot($container).render(

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { useHover } from "@use-gesture/react"
import { useEffect, useMemo, useRef, useState } from "react"
@ -17,7 +18,7 @@ import { ReactVirtuosoItemPlaceholder } from "../../../components/ui/placeholder
import { GridItem } from "../templates/grid-item-template"
import type { UniversalItemProps } from "../types"
const ViewTag = window.electron ? "webview" : "iframe"
const ViewTag = IN_ELECTRON ? "webview" : "iframe"
export function VideoItem({ entryId, entryPreview, translation }: UniversalItemProps) {
const entry = useEntry(entryId) || entryPreview

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import type { FC } from "react"
import * as React from "react"
import { useTranslation } from "react-i18next"
@ -40,7 +41,7 @@ export const EntryListHeader: FC<{
const headerTitle = useFeedHeaderTitle()
const os = getOS()
const titleAtBottom = window.electron && os === "macOS"
const titleAtBottom = IN_ELECTRON && os === "macOS"
const isInCollectionList = feedId === FEED_COLLECTION_LIST
const titleInfo = !!headerTitle && (

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { AnimatePresence } from "framer-motion"
import { useEffect, useRef, useState } from "react"
import { useTranslation } from "react-i18next"
@ -8,7 +9,7 @@ import { softSpringPreset } from "~/components/ui/constants/spring"
import { EntryContentLoading } from "../loading"
const ViewTag = window.electron ? "webview" : "iframe"
const ViewTag = IN_ELECTRON ? "webview" : "iframe"
const variants = {
hidden: { x: "100%" },
visible: { x: 0 },
@ -49,7 +50,7 @@ export const SourceContentView = ({ src }: { src: string }) => {
return (
<>
{!window.electron && <Banner />}
{!IN_ELECTRON && <Banner />}
<div className="relative flex size-full flex-col">
{loading && (
<div className="center mt-16 min-w-0">

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { Slot } from "@radix-ui/react-slot"
import { noop } from "foxact/noop"
import { AnimatePresence, m } from "framer-motion"
@ -119,7 +120,7 @@ function EntryHeaderImpl({
)
}
const ElectronAdditionActions = window.electron
const ElectronAdditionActions = IN_ELECTRON
? ({
view = FeedViewType.Articles,
entry,

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import type { FallbackRender } from "@sentry/react"
import { ErrorBoundary } from "@sentry/react"
import type { FC } from "react"
@ -376,7 +377,7 @@ const NoContent: FC<{
<span>{t("entry_content.web_app_notice")}</span>
</div>
)}
{url && window.electron && <ReadabilityAutoToggleEffect url={url} id={id} />}
{url && IN_ELECTRON && <ReadabilityAutoToggleEffect url={url} id={id} />}
</div>
</div>
)

View File

@ -1,8 +1,9 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import clsx from "clsx"
export const feedColumnStyles = {
item: clsx(
!window.electron && tw`duration-200 hover:bg-theme-item-hover`,
!IN_ELECTRON && tw`duration-200 hover:bg-theme-item-hover`,
tw`data-[active=true]:!bg-theme-item-active`,
),
}

View File

@ -1,4 +1,5 @@
/* eslint-disable @eslint-react/hooks-extra/ensure-custom-hooks-using-other-hooks */
import { IN_ELECTRON } from "@follow/shared/constants"
import { useQuery } from "@tanstack/react-query"
import { useCallback, useEffect, useMemo, useRef } from "react"
import * as React from "react"
@ -36,6 +37,7 @@ const useFontDataElectron = () => {
)
}
// eslint-disable-next-line @eslint-react/hooks-extra/no-redundant-custom-hook
const useFontDataWeb = () => [
{ label: FALLBACK_FONT, value: "inherit" },
{ label: "System UI", value: "system-ui" },
@ -50,7 +52,7 @@ const useFontDataWeb = () => [
},
]
const useFontData = window.electron ? useFontDataElectron : useFontDataWeb
const useFontData = IN_ELECTRON ? useFontDataElectron : useFontDataWeb
export const ContentFontSelector = () => {
const { t } = useTranslation("settings")
const data = useFontData()

View File

@ -63,6 +63,7 @@ export const createSettingBuilder =
}
const assertSetting = setting as SettingItem<T> | SectionSettingItem | ActionSettingItem
if (!assertSetting) return null
if (assertSetting.disabled) return null
if ("type" in assertSetting && assertSetting.type === "title" && assertSetting.value) {

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { useTranslation } from "react-i18next"
import { bundledThemesInfo } from "shiki/themes"
@ -50,7 +51,7 @@ export const SettingAppearance = () => {
defineItem("showDockBadge", {
label: t("appearance.show_dock_badge.label"),
hide: !window.electron || !["macOS", "Linux"].includes(getOS()),
hide: !IN_ELECTRON || !["macOS", "Linux"].includes(getOS()),
}),
defineItem("sidebarShowUnreadCount", {

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { useQuery } from "@tanstack/react-query"
import { useAtom } from "jotai"
import { useCallback, useEffect } from "react"
@ -98,9 +99,9 @@ export const SettingGeneral = () => {
description: t("general.mark_as_read.render.description"),
}),
{ type: "title", value: "TTS", disabled: !window.electron },
{ type: "title", value: "TTS", disabled: !IN_ELECTRON },
window.electron && VoiceSelector,
IN_ELECTRON && VoiceSelector,
// { type: "title", value: "Secure" },
// defineSettingItem("jumpOutLinkWarn", {
@ -159,8 +160,8 @@ export const SettingGeneral = () => {
buttonText: t("general.rebuild_database.button"),
},
{ type: "title", value: t("general.network"), disabled: !window.electron },
window.electron && NettingSetting,
{ type: "title", value: t("general.network"), disabled: !IN_ELECTRON },
IN_ELECTRON && NettingSetting,
]}
/>
</div>

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { zodResolver } from "@hookform/resolvers/zod"
import type { DotLottie } from "@lottiefiles/dotlottie-react"
import { DotLottieReact } from "@lottiefiles/dotlottie-react"
@ -140,7 +141,7 @@ export function Component() {
variant="ghost"
type="button"
onClick={() => {
if (window.electron) {
if (IN_ELECTRON) {
tipcClient?.clearAllData().then(() => {
window.location.href = "/"
})

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { repository } from "@pkg"
import { Slot } from "@radix-ui/react-slot"
import { throttle } from "lodash-es"
@ -87,8 +88,7 @@ export function Component() {
useDailyTask()
const supportMinWidth = 1024
const isNotSupportWidth =
useViewport((v) => v.w < supportMinWidth && v.w !== 0) && !window.electron
const isNotSupportWidth = useViewport((v) => v.w < supportMinWidth && v.w !== 0) && !IN_ELECTRON
if (isNotSupportWidth) {
return (
@ -166,7 +166,7 @@ export function Component() {
canClose={false}
clickOutsideToDismiss={false}
>
<LoginModalContent canClose={false} runtime={window.electron ? "app" : "browser"} />
<LoginModalContent canClose={false} runtime={IN_ELECTRON ? "app" : "browser"} />
</DeclarativeModal>
</RootPortal>
)}

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { useQueryClient } from "@tanstack/react-query"
import { useEffect, useRef } from "react"
@ -96,6 +97,6 @@ const InvalidateQueryProviderWebApp = () => {
return null
}
export const InvalidateQueryProvider = window.electron
export const InvalidateQueryProvider = IN_ELECTRON
? InvalidateQueryProviderElectron
: InvalidateQueryProviderWebApp

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
import { PersistQueryClientProvider } from "@tanstack/react-query-persist-client"
import { LazyMotion, MotionConfig } from "framer-motion"
@ -59,7 +60,5 @@ export const RootProviders: FC<PropsWithChildren> = ({ children }) => (
)
const Devtools = () => (
<>
{!window.electron && <ReactQueryDevtools buttonPosition="bottom-left" client={queryClient} />}
</>
<>{!IN_ELECTRON && <ReactQueryDevtools buttonPosition="bottom-left" client={queryClient} />}</>
)

View File

@ -1,3 +1,4 @@
import { IN_ELECTRON } from "@follow/shared/constants"
import { wrapCreateBrowserRouter } from "@sentry/react"
import { createBrowserRouter, createHashRouter } from "react-router-dom"
@ -10,7 +11,7 @@ const globTree = import.meta.glob("./pages/**/*.tsx")
const tree = buildGlobRoutes(globTree)
let routerCreator =
window.electron || globalThis["__DEBUG_PROXY__"] ? createHashRouter : createBrowserRouter
IN_ELECTRON || globalThis["__DEBUG_PROXY__"] ? createHashRouter : createBrowserRouter
if (window.SENTRY_RELEASE) {
routerCreator = wrapCreateBrowserRouter(routerCreator)
}

View File

@ -12,9 +12,16 @@ declare const globalThis: {
export const APP_PROTOCOL = import.meta.env.DEV ? "follow-dev" : "follow"
export const DEEPLINK_SCHEME = `${APP_PROTOCOL}://`
// export const WEB_URL = import.meta.env.VITE_VERCEL_URL ?? import.meta.env.VITE_WEB_URL
export const WEB_URL = env.VITE_WEB_URL
export const SYSTEM_CAN_UNDER_BLUR_WINDOW = globalThis?.window?.electron
? globalThis?.window.api?.canWindowBlur
: false
export const IN_ELECTRON = !!globalThis["electron"]
declare const ELECTRON: boolean
/**
* Current build type for electron
*/
export const ELECTRON_BUILD = !!ELECTRON

12
packages/shared/src/global.d.ts vendored Normal file
View File

@ -0,0 +1,12 @@
import type { ElectronAPI } from "@electron-toolkit/preload"
declare global {
interface Window {
electron?: ElectronAPI
api?: { canWindowBlur: boolean }
}
export const ELECTRON: boolean
}
export {}