Skip to content

Commit

Permalink
Merge branch 'RSSNext:dev' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
cuikaipeng authored Sep 25, 2024
2 parents 3d290db + ea6fbc2 commit c9944ee
Show file tree
Hide file tree
Showing 12 changed files with 158 additions and 62 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/auto-fix-lint-format-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ on:
jobs:
auto-fix:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand Down
18 changes: 4 additions & 14 deletions apps/main/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { electronApp, optimizer } from "@electron-toolkit/utils"
import { APP_PROTOCOL, DEEPLINK_SCHEME } from "@follow/shared/constants"
import { extractElectronWindowOptions } from "@follow/shared/electron"
import { APP_PROTOCOL } from "@follow/shared/constants"
import { env } from "@follow/shared/env"
import { app, BrowserWindow, session } from "electron"
import squirrelStartup from "electron-squirrel-startup"

import { isDev, isMacOS } from "./env"
import { initializeAppStage0, initializeAppStage1 } from "./init"
import { updateProxy } from "./lib/proxy"
import { handleUrlRouting } from "./lib/router"
import { setAuthSessionToken } from "./lib/user"
import { registerUpdater } from "./updater"
import { createMainWindow, createWindow } from "./window"
import { createMainWindow } from "./window"

if (isDev) console.info("[main] env loaded:", env)

Expand Down Expand Up @@ -138,17 +138,7 @@ function bootstrap() {
mainWindow.reload()
}
} else {
const options = extractElectronWindowOptions(url)

const { height, resizable = true, width } = options || {}
createWindow({
extraPath: `#${url.replace(DEEPLINK_SCHEME, "/")}`,
width: width ?? 800,
height: height ?? 700,
minWidth: 600,
minHeight: 600,
resizable,
})
handleUrlRouting(url)
}
}

Expand Down
51 changes: 51 additions & 0 deletions apps/main/src/lib/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { callWindowExpose } from "@follow/shared/bridge"
import { DEEPLINK_SCHEME } from "@follow/shared/constants"
import { extractElectronWindowOptions } from "@follow/shared/electron"

import { logger } from "~/logger"
import { createMainWindow, createWindow, getMainWindow } from "~/window"

export const handleUrlRouting = (url: string) => {
const options = extractElectronWindowOptions(url)

const uri = url.replace(DEEPLINK_SCHEME, "/")
try {
const { pathname, searchParams } = new URL(uri, "https://follow.dev")

switch (pathname) {
case "/add": {
const mainWindow = getMainWindow()
if (!mainWindow) {
createMainWindow()

return handleUrlRouting(url)
}
mainWindow.restore()
mainWindow.focus()
const caller = callWindowExpose(mainWindow)

const id = searchParams.get("id")
const isList = searchParams.get("type") === "list"
if (!id) return
caller.follow(id, { isList })
return
}
default: {
break
}
}

return
} catch (err) {
logger.error("routing error:", err)
}
const { height, resizable = true, width } = options || {}
createWindow({
extraPath: `#${uri}`,
width: width ?? 800,
height: height ?? 700,
minWidth: 600,
minHeight: 600,
resizable,
})
}
4 changes: 2 additions & 2 deletions apps/main/src/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ export const createMainWindow = () => {
}

const caller = callWindowExpose(window)
caller.electronClose()
caller.onWindowClose()
} else {
windows.mainWindow = null
}
Expand All @@ -230,7 +230,7 @@ export const createMainWindow = () => {
cancelPollingUpdateUnreadCount()

const caller = callWindowExpose(window)
caller.electronShow()
caller.onWindowShow()
})

window.on("hide", async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const MarkdownBlockImage = (
"rounded",
size.w < Number.parseInt(props.width as string) && "w-full",
)}
showFallback
popper
className="inline-flex justify-center"
/>
Expand Down
44 changes: 28 additions & 16 deletions apps/renderer/src/components/ui/media.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const MediaImpl: FC<MediaProps> = ({
...props
}) => {
const { src, style, type, previewImageUrl, showFallback, ...rest } = props
const [hidden, setHidden] = useState(!src)

const [imgSrc, setImgSrc] = useState(() =>
proxy && src && !failedList.has(src)
? getImageProxyUrl({
Expand All @@ -61,15 +61,17 @@ const MediaImpl: FC<MediaProps> = ({

const [mediaLoadState, setMediaLoadState] = useState<"loading" | "loaded" | "error">("loading")
const errorHandle: React.ReactEventHandler<HTMLImageElement> = useEventCallback((e) => {
setMediaLoadState("error")
if (imgSrc !== props.src) {
setImgSrc(props.src)
failedList.add(props.src)
} else {
setHidden(true)
setMediaLoadState("error")

props.onError?.(e as any)
}
})

const isError = mediaLoadState === "error"
const previewMedia = usePreviewMedia()
const handleClick = useEventCallback((e: React.MouseEvent) => {
if (popper && src) {
Expand Down Expand Up @@ -156,20 +158,30 @@ const MediaImpl: FC<MediaProps> = ({

if (!type || !src) return null

if (hidden && (showFallback || (!showFallback && mediaLoadState === "error"))) {
return (
<FallbackMedia
mediaContainerClassName={mediaContainerClassName}
className={className}
style={style}
{...props}
/>
)
if (isError) {
if (showFallback) {
return (
<FallbackMedia
mediaContainerClassName={mediaContainerClassName}
className={className}
style={style}
{...props}
/>
)
} else {
return (
<div
className={cn("rounded bg-zinc-100 dark:bg-neutral-900", className)}
style={props.style}
/>
)
}
}

return (
<span
data-state={type !== "video" ? mediaLoadState : undefined}
className={cn("block overflow-hidden rounded", hidden && "hidden", className)}
className={cn("block overflow-hidden rounded", className)}
style={style}
>
{InnerContent}
Expand All @@ -184,14 +196,14 @@ const FallbackMedia: FC<MediaProps> = ({ type, mediaContainerClassName, classNam
<div
className={cn(
!(props.width || props.height) && "size-full",
"center relative rounded bg-zinc-100 object-cover dark:bg-neutral-900",
"not-prose flex max-h-full flex-col space-y-1 p-4",
"center rounded bg-zinc-100 dark:bg-neutral-900",
"not-prose !flex max-h-full flex-col space-y-1 p-4",

mediaContainerClassName,
)}
style={{
height: props.height ? `${props.height}px` : "",
width: props.width ? `${props.width}px` : "100%",
...props.style,
}}
>
<i className="i-mgc-close-cute-re text-xl text-red-500" />
Expand Down
21 changes: 0 additions & 21 deletions apps/renderer/src/initialize/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { registerGlobalContext } from "@follow/shared/bridge"
import { env } from "@follow/shared/env"
import { authConfigManager } from "@hono/auth-js/react"
import { repository } from "@pkg"
Expand All @@ -9,14 +8,11 @@ import relativeTime from "dayjs/plugin/relativeTime"
import { enableMapSet } from "immer"
import React from "react"
import ReactDOM from "react-dom"
import { toast } from "sonner"

import { getUISettings } from "~/atoms/settings/ui"
import { isElectronBuild } from "~/constants"
import { browserDB } from "~/database"
import { initI18n } from "~/i18n"
import { settingSyncQueue } from "~/modules/settings/helper/sync-queue"
import { ElectronCloseEvent, ElectronShowEvent } from "~/providers/invalidate-query-provider"
import { CleanerService } from "~/services/cleaner"

import { subscribeNetworkStatus } from "../atoms/network"
Expand Down Expand Up @@ -72,23 +68,6 @@ export const initializeApp = async () => {

subscribeNetworkStatus()

registerGlobalContext({
showSetting: (path) => window.router.showSettings(path),
getGeneralSettings,
getUISettings,
/**
* Electron app only
*/
electronClose() {
document.dispatchEvent(new ElectronCloseEvent())
},
electronShow() {
document.dispatchEvent(new ElectronShowEvent())
},

toast,
})

apm("hydrateSettings", hydrateSettings)

apm("setting sync", () => {
Expand Down
2 changes: 1 addition & 1 deletion apps/renderer/src/modules/entry-column/translation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const EntryTranslation: Component<{
<HoverCard.Portal>
<HoverCard.Content
className={cn(
"group relative text-sm",
"group relative z-[1] text-sm",
"animate-in fade-in-0 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
)}
style={useOverlay ? { width: bounds.width } : undefined}
Expand Down
2 changes: 1 addition & 1 deletion apps/renderer/src/pages/(main)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export function Component() {
Your device width is <b>{`${window.innerWidth}`}px</b> less than minimum supported width
1024px.
</div>
<div>Please using desktop app to using {APP_NAME}</div>
<div>Please use desktop app to using {APP_NAME}</div>

<div>
Download:{" "}
Expand Down
50 changes: 50 additions & 0 deletions apps/renderer/src/providers/extension-expose-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { registerGlobalContext } from "@follow/shared/bridge"
import { useEffect, useLayoutEffect } from "react"
import { useTranslation } from "react-i18next"
import { toast } from "sonner"

import { getGeneralSettings } from "~/atoms/settings/general"
import { getUISettings } from "~/atoms/settings/ui"
import { useModalStack } from "~/components/ui/modal"
import { FeedForm } from "~/modules/discover/feed-form"

import { ElectronCloseEvent, ElectronShowEvent } from "./invalidate-query-provider"

export const ExtensionExposeProvider = () => {
const { present } = useModalStack()
useLayoutEffect(() => {
registerGlobalContext({
showSetting: (path) => window.router.showSettings(path),
getGeneralSettings,
getUISettings,
/**
* Electron app only
*/
onWindowClose() {
document.dispatchEvent(new ElectronCloseEvent())
},
onWindowShow() {
document.dispatchEvent(new ElectronShowEvent())
},

toast,
})
}, [])

const { t } = useTranslation()
useEffect(() => {
registerGlobalContext({
follow(id, options) {
present({
title: options?.isList
? t("sidebar.feed_actions.edit_list")
: t("sidebar.feed_actions.edit_feed"),
content: ({ dismiss }) => (
<FeedForm asWidget id={id} onSuccess={dismiss} isList={options?.isList} />
),
})
},
})
}, [present, t])
return null
}
2 changes: 2 additions & 0 deletions apps/renderer/src/providers/root-providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { FeatureFlagDebugger } from "~/modules/ab/providers"

import { ContextMenuProvider } from "./context-menu-provider"
import { EventProvider } from "./event-provider"
import { ExtensionExposeProvider } from "./extension-expose-provider"
import { I18nProvider } from "./i18n-provider"
import { InvalidateQueryProvider } from "./invalidate-query-provider"
import { SettingSync } from "./setting-sync"
Expand All @@ -35,6 +36,7 @@ export const RootProviders: FC<PropsWithChildren> = ({ children }) => (
<HotkeysProvider initiallyActiveScopes={HotKeyScopeMap.Home}>
<Provider store={jotaiStore}>
<I18nProvider>
<ExtensionExposeProvider />
<EventProvider />
<UserProvider />
<SettingSync />
Expand Down
22 changes: 18 additions & 4 deletions packages/shared/src/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,32 @@ import type { GeneralSettings, UISettings } from "./interface/settings"
const PREFIX = "__follow"

interface RenderGlobalContext {
/// Access Settings
showSetting: (path?: string) => void
getGeneralSettings: () => GeneralSettings
getUISettings: () => UISettings

electronClose: () => void
electronShow: () => void
/**
* @description only work in electron app
*/
onWindowClose: () => void
/**
* @description only work in electron app
*/
onWindowShow: () => void

/// Actions
follow: (id: string, options?: { isList: boolean }) => void

/// Utils
toast: typeof toast
}

export const registerGlobalContext = (context: RenderGlobalContext) => {
globalThis[PREFIX] = context
export const registerGlobalContext = (context: Partial<RenderGlobalContext>) => {
globalThis[PREFIX] = {
...globalThis[PREFIX],
...context,
}
}

function createProxy<T extends RenderGlobalContext>(window: BrowserWindow, path: string[] = []): T {
Expand Down

0 comments on commit c9944ee

Please sign in to comment.