Breadcrumbs (#296)
* add breadcrumbs * rm space * move breadcrumbs to ui
This commit is contained in:
1 parent
ad9695127a
commit
98dcaaa237
11 files changed
+91
-11
No files matched your search
@@ -5,12 +5,11 @@ import s from "./app.module.css"
|
||||
import { Wrapper } from "../Wrapper"
|
||||
import { Footer } from "../Footer"
|
||||
import { Content } from "../Content"
|
||||
import { Breadcrumbs } from "../Breadcrumbs"
|
||||
import type { BreadcrumbPart } from "@/types"
|
||||
import { usePathname } from "next/navigation"
|
||||
import { useMobile } from "@hudozka/hooks"
|
||||
import { Navigation } from "@/components/Navigation"
|
||||
import { Box, Panel, Title } from "@hudozka/ui"
|
||||
import { Box, Breadcrumbs, Panel, Title } from "@hudozka/ui"
|
||||
import { AccessibilityButton } from "../AccessibilityButton"
|
||||
import { Copyright } from "@/components/Copyright"
|
||||
import { yearRange } from "@/const"
|
||||
|
||||
@@ -2,7 +2,43 @@ import { pb } from "./pb"
|
||||
import { createPage, createHomeCards, createMenu, createFeedPages } from "./factory"
|
||||
import type { PbPage, PbImage, PbFile, PbTag, PbHomeData, PbMenuData } from "./types"
|
||||
import type { DocV1Block } from "./doc"
|
||||
import type { MenuItem, Page, PageCardDto, FeedPage } from "@/types"
|
||||
import type { BreadcrumbPart, MenuItem, Page, PageCardDto, FeedPage } from "@/types"
|
||||
import { menu } from "@/const"
|
||||
|
||||
const MAX_PARENT_DEPTH = 10
|
||||
|
||||
function getParentId(parent: string | string[] | undefined): string | undefined {
|
||||
if (!parent) return undefined
|
||||
if (Array.isArray(parent)) return parent[0]
|
||||
return parent
|
||||
}
|
||||
|
||||
async function fetchParentChain(startId: string | undefined): Promise<PbPage[]> {
|
||||
if (!startId) return []
|
||||
const chain: PbPage[] = []
|
||||
const visited = new Set<string>()
|
||||
let currentId: string | undefined = startId
|
||||
while (currentId && chain.length < MAX_PARENT_DEPTH) {
|
||||
if (visited.has(currentId)) break
|
||||
visited.add(currentId)
|
||||
try {
|
||||
const parent = await pb.collection("pages").getOne<PbPage>(currentId)
|
||||
chain.unshift(parent)
|
||||
currentId = getParentId(parent.parent)
|
||||
} catch {
|
||||
break
|
||||
}
|
||||
}
|
||||
return chain
|
||||
}
|
||||
|
||||
function buildBreadcrumb(record: PbPage, parents: PbPage[]): BreadcrumbPart[] {
|
||||
if (parents.length === 0) return []
|
||||
const home: BreadcrumbPart = { name: menu[0].name, href: "/" }
|
||||
const ancestors: BreadcrumbPart[] = parents.map(p => ({ name: p.title, href: p.slug }))
|
||||
const current: BreadcrumbPart = { name: record.title, href: record.slug }
|
||||
return [home, ...ancestors, current]
|
||||
}
|
||||
|
||||
function buildIdFilter(ids: string[]): string {
|
||||
return ids.map(id => `id="${id}"`).join(" || ")
|
||||
@@ -90,12 +126,13 @@ export async function getPageBySlug(slug: string): Promise<Page | null> {
|
||||
refs.imageIds.add(record.cover)
|
||||
}
|
||||
|
||||
// Round 2: fetch images, files, tags, card-grid pages in parallel
|
||||
const [images, files, tags, cardGridPages] = await Promise.all([
|
||||
// Round 2: fetch images, files, tags, card-grid pages, parent chain in parallel
|
||||
const [images, files, tags, cardGridPages, parentChain] = await Promise.all([
|
||||
fetchImagesByIds([...refs.imageIds]),
|
||||
fetchFilesByIds([...refs.fileIds]),
|
||||
fetchTagsByIds(record.tags),
|
||||
fetchPagesByIds([...refs.pageIds]),
|
||||
fetchParentChain(getParentId(record.parent)),
|
||||
])
|
||||
|
||||
// Round 3: fetch cover images for card-grid pages
|
||||
@@ -112,7 +149,8 @@ export async function getPageBySlug(slug: string): Promise<Page | null> {
|
||||
// Merge all images for card-grid covers
|
||||
const allCardGridImages = new Map([...images, ...cardGridImages])
|
||||
|
||||
return createPage(record, images, files, tags, cardGridPages, allCardGridImages)
|
||||
const breadcrumb = buildBreadcrumb(record, parentChain)
|
||||
return createPage(record, images, files, tags, cardGridPages, allCardGridImages, breadcrumb)
|
||||
} catch (error) {
|
||||
console.error(`Failed to fetch page: ${error}`)
|
||||
return null
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { MenuItem, Page, Tag, PageCardDto, Pic, Token, FeedPage } from "@/types"
|
||||
import type { MenuItem, Page, Tag, PageCardDto, Pic, Token, FeedPage, BreadcrumbPart } from "@/types"
|
||||
import type { PbPage, PbImage, PbFile, PbTag, PbHomeData, PbMenuData } from "./types"
|
||||
import type { DocV1Block } from "./doc"
|
||||
import { typograf, markdownToHtml } from "@hudozka/text"
|
||||
@@ -159,6 +159,7 @@ export function createPage(
|
||||
tags: PbTag[],
|
||||
cardGridPages: Map<string, PbPage>,
|
||||
cardGridImages: Map<string, PbImage>,
|
||||
breadcrumb: BreadcrumbPart[] = [],
|
||||
): Page {
|
||||
const cover = getCoverPic(record.cover, images)
|
||||
|
||||
@@ -190,6 +191,7 @@ export function createPage(
|
||||
...tokens,
|
||||
],
|
||||
tags: pageTags,
|
||||
breadcrumb,
|
||||
featured: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ export type PbPage = PbRecord & {
|
||||
doc: DocV1
|
||||
tags: string[]
|
||||
draft: boolean
|
||||
parent?: string | string[]
|
||||
}
|
||||
|
||||
export type PbTag = PbRecord & {
|
||||
|
||||
Generated
+1
@@ -9633,6 +9633,7 @@
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@hudozka/hooks": "*",
|
||||
"@hudozka/utils": "*",
|
||||
"classnames": "^2.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"classnames": "^2.5.0",
|
||||
"@hudozka/hooks": "*"
|
||||
"@hudozka/hooks": "*",
|
||||
"@hudozka/utils": "*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=19",
|
||||
|
||||
File renamed without changes.
+7
-3
@@ -1,12 +1,16 @@
|
||||
import s from "./styles.module.css"
|
||||
|
||||
import type { BreadcrumbPart } from "@/types"
|
||||
import { Button } from "@hudozka/ui"
|
||||
import { Button } from "../Button"
|
||||
import { insertBetween } from "@hudozka/utils"
|
||||
|
||||
export type Crumb = {
|
||||
name: string
|
||||
href: string
|
||||
}
|
||||
|
||||
export type BreadcrumbsProps = {
|
||||
style?: React.CSSProperties
|
||||
items: BreadcrumbPart[]
|
||||
items: Crumb[]
|
||||
path: string
|
||||
}
|
||||
|
||||
+4
@@ -11,3 +11,7 @@
|
||||
.breadcrumbs li {
|
||||
margin-bottom: var(--size-xs);
|
||||
}
|
||||
|
||||
.breadcrumbs a {
|
||||
text-decoration: none;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from "./Box"
|
||||
export * from "./Breadcrumbs"
|
||||
export * from "./Button"
|
||||
export * from "./Panel"
|
||||
export * from "./Title"
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1125843985")
|
||||
|
||||
// add field
|
||||
collection.fields.addAt(5, new Field({
|
||||
"cascadeDelete": false,
|
||||
"collectionId": "pbc_1125843985",
|
||||
"help": "",
|
||||
"hidden": false,
|
||||
"id": "relation1032740943",
|
||||
"maxSelect": 0,
|
||||
"minSelect": 0,
|
||||
"name": "parent",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "relation"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1125843985")
|
||||
|
||||
// remove field
|
||||
collection.fields.removeById("relation1032740943")
|
||||
|
||||
return app.save(collection)
|
||||
})
|
||||
Reference in new issue
Block a user