diff --git a/CHANGELOG.md b/CHANGELOG.md index 194c29b..040ebe2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ All notable changes to `doc` are documented here. ### Fixed +- Add an in-app back button to the TopBar that appears only after the first in-app navigation, + and scope the entry-document flag to `sessionStorage` so it survives SPA navigation but resets + on full page reload (#66). - Replace hardcoded `timeAgo` strings with `next-intl` translation keys and return ISO-8601 `createdAt` from the version API so clients can format timestamps with `Intl.DateTimeFormat`. Remove unused `useTimeAgo` hook export and use real `messages/zh-cn.json` in `dt.test.ts` diff --git a/messages/en.json b/messages/en.json index 4f59012..e2d3f04 100644 --- a/messages/en.json +++ b/messages/en.json @@ -9,7 +9,8 @@ "documentActions": "Document actions", "moreDocumentActions": "More document actions", "changeLanguage": "Change language, current {locale}", - "closeDialog": "Close dialog" + "closeDialog": "Close dialog", + "goBack": "Go back" }, "metadata": { "title": "doc — self-hosted collaborative document infrastructure", diff --git a/messages/zh-cn.json b/messages/zh-cn.json index ea6bf72..c3f632e 100644 --- a/messages/zh-cn.json +++ b/messages/zh-cn.json @@ -9,7 +9,8 @@ "documentActions": "文档操作", "moreDocumentActions": "更多文档操作", "changeLanguage": "切换语言,当前为 {locale}", - "closeDialog": "关闭对话框" + "closeDialog": "关闭对话框", + "goBack": "返回上一页" }, "metadata": { "title": "doc — 自托管协作文档基础设施", diff --git a/src/app/[locale]/work/[id]/(content)/content-for-my-doc.tsx b/src/app/[locale]/work/[id]/(content)/content-for-my-doc.tsx index cccfc08..7551aaa 100644 --- a/src/app/[locale]/work/[id]/(content)/content-for-my-doc.tsx +++ b/src/app/[locale]/work/[id]/(content)/content-for-my-doc.tsx @@ -27,9 +27,13 @@ export default function ContentForMyDoc() { const updateDocTitle = useDocsStore((s) => s.updateDocTitle) const updateDocIcon = useDocsStore((s) => s.updateDocIcon) - // record last doc id + // Record entry doc id only once per page session. + // Uses sessionStorage to survive SPA navigation but reset on full page reload. useEffect(() => { - localStorage.setItem(LAST_DOC_ID_KEY, id) // 保存最后一次打开的文档 id + if (!sessionStorage.getItem('hasRecordedEntryDoc')) { + localStorage.setItem(LAST_DOC_ID_KEY, id) + sessionStorage.setItem('hasRecordedEntryDoc', 'true') + } }, [id]) useEffect(() => { diff --git a/src/app/[locale]/work/[id]/top-bar.tsx b/src/app/[locale]/work/[id]/top-bar.tsx index 61aa73c..c35c18e 100644 --- a/src/app/[locale]/work/[id]/top-bar.tsx +++ b/src/app/[locale]/work/[id]/top-bar.tsx @@ -1,7 +1,7 @@ 'use client' -import { useMemo, useState } from 'react' -import { Ellipsis } from 'lucide-react' +import { useMemo, useState, useEffect } from 'react' +import { ArrowLeft, Ellipsis } from 'lucide-react' import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' import { Button } from '@/components/ui/button' import Logo from '@/components/logo-component' @@ -24,6 +24,8 @@ import { useUserStore } from '@/stores/user-store' import { Topbar } from '@fullstack-ai-infra/ui' import { useTranslations } from 'next-intl' import { useCompactWorkspace } from '@/hooks/use-compact-workspace' +import emitter from '@/lib/emitter' +import { EVENT_KEY_NAV_DOC } from '@/constants' export default function TopBar() { const t = useTranslations('common') @@ -33,12 +35,33 @@ export default function TopBar() { const doc = useMemo(() => docs.find((d) => d.id === id), [docs, id]) const userInfo = useUserStore((s) => s.userInfo) + // Track whether there's in-app navigation history for the back button. + const [hasHistory, setHasHistory] = useState(false) + useEffect(() => { + const onNav = () => setHasHistory(true) + emitter.on(EVENT_KEY_NAV_DOC, onNav) + return () => { + emitter.off(EVENT_KEY_NAV_DOC, onNav) + } + }, []) + return ( + {hasHistory && ( + + )}