diff --git a/apps/web/src/app/App.tsx b/apps/web/src/app/App.tsx index 8a2dbe53..37c3a552 100644 --- a/apps/web/src/app/App.tsx +++ b/apps/web/src/app/App.tsx @@ -3,7 +3,6 @@ import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { Navigate, Route, Routes, useNavigate } from "react-router"; import { useTranslation } from "react-i18next"; import { PwaUpdateNotice } from "@/components/PwaUpdateNotice"; -import { ReleaseUpdateNotice } from "@/components/ReleaseUpdateNotice"; import { PwaInstallProvider } from "@/components/PwaInstallContext"; import { PwaIosPrompt } from "@/components/PwaIosPrompt"; import { Button } from "@/components/ui/button"; @@ -199,16 +198,13 @@ const AuthenticatedWorkspace = () => { return ( }> - <> - logoutMutation.mutate()} - /> - - + logoutMutation.mutate()} + /> ); }; diff --git a/apps/web/src/components/EditorPane.tsx b/apps/web/src/components/EditorPane.tsx index 0c1ed5cb..314da2b2 100644 --- a/apps/web/src/components/EditorPane.tsx +++ b/apps/web/src/components/EditorPane.tsx @@ -133,7 +133,6 @@ import { copyEditorToWeChat, copyMarkdownToWeChat } from "@/lib/wechat-copy"; import { ThemeBlock } from "./ThemeBlock"; import { SystemInfoDialog } from "./SystemInfoDialog"; import { fetchLatestRelease, isVersionOutdated } from "@/lib/version-check"; -import { RELEASE_STATUS_EVENT } from "@/lib/release-notice"; import { downloadMarkdownFile } from "@/lib/note-markdown-export"; import { NOTE_HTML_FULL_STYLES } from "@/lib/note-html-export-assets"; import { downloadNoteHtmlFile, getHtmlImageEmbedNoticeKind } from "@/lib/note-html-export"; @@ -851,12 +850,7 @@ const RichEditorPane = ({ void fetchLatestRelease(controller.signal) .then((release) => setUpdateAvailable(isVersionOutdated(__EDGEEVER_APP_VERSION__, release.version))) .catch(() => undefined); - const handleReleaseStatus = () => setUpdateAvailable(true); - window.addEventListener(RELEASE_STATUS_EVENT, handleReleaseStatus); - return () => { - controller.abort(); - window.removeEventListener(RELEASE_STATUS_EVENT, handleReleaseStatus); - }; + return () => controller.abort(); }, []); const effectiveReadOnly = readOnly || (isMobileViewport && !mobileEditingActive); const useMobilePlainTextEditor = isMobileViewport && mobileEditingActive && !readOnly; diff --git a/apps/web/src/components/ReleaseUpdateNotice.tsx b/apps/web/src/components/ReleaseUpdateNotice.tsx deleted file mode 100644 index 66fa2293..00000000 --- a/apps/web/src/components/ReleaseUpdateNotice.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { useEffect, useState } from "react"; -import { ArrowUpCircle, Download, ExternalLink, RefreshCw, X } from "lucide-react"; -import { useTranslation } from "react-i18next"; -import { fetchLatestRelease, isVersionOutdated, type LatestRelease } from "@/lib/version-check"; -import { dismissRelease, getDismissedRelease } from "@/lib/release-notice"; -import { UpdateAvailableDescription } from "./UpdateAvailableDescription"; - -const AUTO_DISMISS_MS = 3_000; - -export const ReleaseUpdateNotice = () => { - const { t } = useTranslation(); - const [release, setRelease] = useState(null); - const [dismissed, setDismissed] = useState(false); - const [nativeUpdateState, setNativeUpdateState] = useState<"idle" | "available" | "downloading" | "downloaded" | "error">("idle"); - const desktopBridge = window.edgeeverDesktop; - - useEffect(() => { - const controller = new AbortController(); - void fetchLatestRelease(controller.signal) - .then((latest) => { - if (isVersionOutdated(__EDGEEVER_APP_VERSION__, latest.version)) setRelease(latest); - }) - .catch(() => undefined); - return () => controller.abort(); - }, []); - - useEffect(() => { - if (!desktopBridge?.isAvailable) return; - let active = true; - const readStatus = async () => { - try { - const { state } = await desktopBridge.updateStatus(); - if (active && (state === "available" || state === "downloaded")) setNativeUpdateState(state); - } catch { - // The release link remains available when the native updater is unavailable. - } - }; - void readStatus(); - const timer = window.setInterval(() => void readStatus(), 5_000); - return () => { - active = false; - window.clearInterval(timer); - }; - }, [desktopBridge]); - - useEffect(() => { - if (!release || nativeUpdateState !== "idle") return; - - const timer = window.setTimeout(() => setDismissed(true), AUTO_DISMISS_MS); - return () => window.clearTimeout(timer); - }, [nativeUpdateState, release?.tagName]); - - if ((!release && nativeUpdateState === "idle") || dismissed || (release && getDismissedRelease() === release.tagName)) return null; - - const handleNativeUpdate = async () => { - if (!desktopBridge?.isAvailable) return; - try { - if (nativeUpdateState === "available") { - setNativeUpdateState("downloading"); - await desktopBridge.downloadUpdate(); - } else if (nativeUpdateState === "downloaded") { - await desktopBridge.installUpdate(); - } - } catch { - setNativeUpdateState("error"); - } - }; - - const isNativeUpdate = nativeUpdateState !== "idle"; - - return ( - - ); -}; diff --git a/apps/web/src/lib/release-notice.ts b/apps/web/src/lib/release-notice.ts deleted file mode 100644 index 29343aa6..00000000 --- a/apps/web/src/lib/release-notice.ts +++ /dev/null @@ -1,19 +0,0 @@ -const DISMISSED_RELEASE_KEY = "edgeever:dismissed-release"; -export const RELEASE_STATUS_EVENT = "edgeever:release-status"; - -export const getDismissedRelease = () => { - try { - return window.localStorage.getItem(DISMISSED_RELEASE_KEY); - } catch { - return null; - } -}; - -export const dismissRelease = (tagName: string) => { - try { - window.localStorage.setItem(DISMISSED_RELEASE_KEY, tagName); - } catch { - // Storage can be unavailable in restricted browsing modes. - } - window.dispatchEvent(new CustomEvent(RELEASE_STATUS_EVENT, { detail: { tagName, dismissed: true } })); -};