-
-
-
-
-
-
-
+
@@ -91,21 +89,6 @@ export function RecollectionViewSwitcher() {
{tooltipText}
-
-
-
- Logos
-
-
- Flux
-
-
-
)
}
diff --git a/frontend/src/app/recollections/layout/RenameRecollectionDialog.tsx b/frontend/src/app/recollections/layout/RenameRecollectionDialog.tsx
index 9118590..46c255d 100644
--- a/frontend/src/app/recollections/layout/RenameRecollectionDialog.tsx
+++ b/frontend/src/app/recollections/layout/RenameRecollectionDialog.tsx
@@ -1,5 +1,5 @@
/**
- * Shared modal for renaming a recollection. Used by RecollectionsPage and RecollectionTitleContent.
+ * Shared modal for renaming a recollection. Used by RecollectionsPage and RecollectionFileMenu.
*/
import React, { useCallback, useEffect, useRef, useState } from 'react'
diff --git a/frontend/src/app/recollections/layout/recollectionNav.ts b/frontend/src/app/recollections/layout/recollectionNav.ts
new file mode 100644
index 0000000..9f76d7e
--- /dev/null
+++ b/frontend/src/app/recollections/layout/recollectionNav.ts
@@ -0,0 +1,25 @@
+/**
+ * Recollection navigation helpers: current view mode from pathname, labels for breadcrumbs.
+ */
+
+export type RecollectionViewMode = 'logos' | 'katalogos' | 'flux'
+
+export function getMode(pathname: string): RecollectionViewMode {
+ if (pathname.endsWith('/flux')) return 'flux'
+ if (pathname.endsWith('/logos/katalogos')) return 'katalogos'
+ return 'logos'
+}
+
+export function viewLabel(mode: RecollectionViewMode): string {
+ if (mode === 'katalogos') return 'Katalogos'
+ if (mode === 'flux') return 'Flux'
+ return 'Logos'
+}
+
+export const RECOLLECTION_VIEW_MODES: RecollectionViewMode[] = ['logos', 'katalogos', 'flux']
+
+export function pathForMode(base: string, mode: RecollectionViewMode): string {
+ if (mode === 'flux') return `${base}/flux`
+ if (mode === 'katalogos') return `${base}/logos/katalogos`
+ return `${base}/logos`
+}
diff --git a/frontend/src/app/recollections/logos/LogosPage.tsx b/frontend/src/app/recollections/logos/LogosPage.tsx
index d4bc8b9..1ffc169 100644
--- a/frontend/src/app/recollections/logos/LogosPage.tsx
+++ b/frontend/src/app/recollections/logos/LogosPage.tsx
@@ -1,29 +1,23 @@
/**
- * Logos page: BlockNote editor for the recollection. Content persisted in recollection store.
- * Left sidebar for page/subpage hierarchy (one level). Layout and styling aligned with Flux.
+ * Logos page: BlockNote editor for the recollection. Content only; sidebar is at layout level.
+ * Content persisted in recollection store.
*/
import React, { useCallback, useEffect, useMemo, useRef, useState, forwardRef } from 'react'
-import { useParams, useLocation, useNavigate } from 'react-router-dom'
+import { useParams, useLocation, useSearchParams } from 'react-router-dom'
import { usePlatform } from '@/app/kosmos/KosmosContext'
import { FluxIcon } from '@/lib/icons'
import { useCreateBlockNote, getDefaultReactSlashMenuItems, SuggestionMenuController } from '@blocknote/react'
import { BlockNoteView } from '@blocknote/shadcn'
import { useTheme } from '@/lib/themeContext'
import { useRecollectionActions } from '../layout/RecollectionActionsContext'
+import { useRecollectionSidebar } from '../layout/RecollectionSidebarContext'
import {
- getLogosContent,
- getLogosPageTree,
- setLogosPageTree,
getLogosContentForPage,
setLogosContentForPage,
- removeLogosPageContent,
type StoredLogosContent,
- type LogosPageMeta,
- type LogosPageId,
} from '../state/recollectionStore'
import { logosSchema } from './logosSchema'
-import { LogosSidebar } from './LogosSidebar'
import { KatalogosPage } from '../katalogos/KatalogosPage'
import { toast } from 'sonner'
@@ -60,77 +54,30 @@ function patchBlockNoteRefWarning() {
}
}
-const MAIN_PAGE_ID: LogosPageId = 'main'
-
export function LogosPage() {
const { recollectionId } = useParams<{ recollectionId: string }>()
const { pathname } = useLocation()
- const navigate = useNavigate()
+ const [searchParams, setSearchParams] = useSearchParams()
const { recollections } = usePlatform()
const { theme } = useTheme()
const { setLogosSlot } = useRecollectionActions()
+ const { tree, activePageId } = useRecollectionSidebar()
const recollection = recollectionId ? recollections.find((p) => p.id === recollectionId) : null
- const [tree, setTree] = useState
([])
- const [activePageId, setActivePageId] = useState(null)
const [reloadKey, setReloadKey] = useState(0)
-
- const isKatalogosView = pathname.endsWith('/logos/katalogos')
- const baseLogosPath = recollectionId ? `/recollections/${recollectionId}/logos` : ''
-
- const handleSelectPage = useCallback(
- (id: LogosPageId) => {
- setActivePageId(id)
- if (recollectionId) navigate(`${baseLogosPath}`)
- },
- [recollectionId, baseLogosPath, navigate]
- )
-
- const handleSelectKatalogos = useCallback(() => {
- if (recollectionId) navigate(`${baseLogosPath}/katalogos`)
- }, [recollectionId, baseLogosPath, navigate])
const saveTimeoutRef = useRef | null>(null)
const [saveStatus, setSaveStatus] = useState<'saved' | 'unsaved' | 'saving'>('saved')
- // Load page tree and run migration when empty (treat existing single doc as "Main" page).
+ const isKatalogosView = pathname.endsWith('/logos/katalogos')
+
+ // When on Logos (not Katalogos) with a selected page but no page param, sync URL so refresh keeps the page.
useEffect(() => {
- if (!recollectionId) return
- let t = getLogosPageTree(recollectionId)
- if (t.length === 0) {
- const legacy = getLogosContent(recollectionId)
- const main: LogosPageMeta = { id: MAIN_PAGE_ID, title: 'Main', parentId: null, position: 0 }
- setLogosContentForPage(recollectionId, MAIN_PAGE_ID, legacy ?? [])
- setLogosPageTree(recollectionId, [main])
- t = [main]
- }
- setTree(t)
- setActivePageId((prev) => {
- const firstId = t[0]?.id ?? null
- if (prev != null && t.some((p) => p.id === prev)) return prev
- return firstId
- })
- }, [recollectionId])
-
- // Persist tree when sidebar changes it.
- useEffect(() => {
- if (!recollectionId || tree.length === 0) return
- setLogosPageTree(recollectionId, tree)
- }, [recollectionId, tree])
-
- const handleTreeChange = useCallback((newTree: LogosPageMeta[]) => {
- setTree(newTree)
- }, [])
-
- const handleDeletePage = useCallback(
- (pageId: LogosPageId) => {
- if (recollectionId) removeLogosPageContent(recollectionId, pageId)
- },
- [recollectionId]
- )
+ if (isKatalogosView || !activePageId || searchParams.get('page') === activePageId) return
+ setSearchParams({ page: activePageId }, { replace: true })
+ }, [isKatalogosView, activePageId, searchParams, setSearchParams])
const initialContent = useMemo(() => {
if (!recollectionId || !activePageId) return undefined
const content = getLogosContentForPage(recollectionId, activePageId)
- // BlockNote requires a non-empty array of blocks; use undefined for default empty doc.
if (!content || !Array.isArray(content) || content.length === 0) return undefined
return content
}, [recollectionId, activePageId, reloadKey])
@@ -226,7 +173,6 @@ export function LogosPage() {
[editor]
)
- // Render paths (no hooks below this point).
if (!recollectionId) {
return (
@@ -235,53 +181,33 @@ export function LogosPage() {
)
}
- const sidebarProps = {
- recollectionId: recollectionId!,
- tree,
- onTreeChange: handleTreeChange,
- activePageId,
- onSelectPage: handleSelectPage,
- onDeletePage: handleDeletePage,
- isKatalogosView,
- onSelectKatalogos: handleSelectKatalogos,
- }
-
if (isKatalogosView) {
return (
-
-
-
-
-
+
+
)
}
if (activePageId == null || !editor) {
return (
-
-
-
- {tree.length === 0 ? 'Loading…' : 'Select a page'}
-
+
+ {tree.length === 0 ? 'Loading…' : 'Select a page'}
)
}
return (
-
-
-
-
-
-
-
-
+
)
diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx
index de9d06a..4d31e98 100644
--- a/frontend/src/main.tsx
+++ b/frontend/src/main.tsx
@@ -10,6 +10,7 @@ import { RecollectionsPage } from './app/recollections/RecollectionsPage'
import { RecollectionLayout } from './app/recollections/RecollectionLayout'
import { LogosPage } from './app/recollections/logos/LogosPage'
import { FluxRoute } from './app/recollections/flux/FluxRoute'
+import { NotFoundPage } from './app/NotFoundPage'
import './lib/prismSetup'
import 'prismjs/themes/prism.css'
import './styles.css'
@@ -31,8 +32,10 @@ createRoot(document.getElementById('root')!).render(
} />
} />
} />
+
} />
+
} />