style: Fixed styling according to prettier

This commit is contained in:
Stefan Genov 2026-01-08 21:32:01 +02:00
parent 34ca053936
commit 15ff47b82d
4 changed files with 220 additions and 219 deletions

View File

@ -69,8 +69,8 @@ Multiple parents:
```yaml
parent:
- [[Basics]]
- [[Reference]]
- [[Basics]]
- [[Reference]]
```
### Configuration
@ -81,10 +81,10 @@ Default configuration:
```ts
Component.ParentBreadcrumbs({
spacerSymbol: "", // symbol displayed between breadcrumb levels
rootName: "Home", // label for the root (index) page
spacerSymbol: "", // symbol displayed between breadcrumb levels
rootName: "Home", // label for the root (index) page
resolveFrontmatterTitle: true, // use frontmatter.title instead of slug
parentKey: "parent", // frontmatter key used to resolve parents
parentKey: "parent", // frontmatter key used to resolve parents
})
```

View File

@ -1,68 +1,68 @@
import { PageLayout, SharedLayout } from "./quartz/cfg";
import * as Component from "./quartz/components";
import { PageLayout, SharedLayout } from "./quartz/cfg"
import * as Component from "./quartz/components"
// components shared across all pages
export const sharedPageComponents: SharedLayout = {
head: Component.Head(),
header: [],
afterBody: [],
footer: Component.Footer({
links: {
GitHub: "https://github.com/jackyzha0/quartz",
"Discord Community": "https://discord.gg/cRFFHYye7t",
},
}),
};
head: Component.Head(),
header: [],
afterBody: [],
footer: Component.Footer({
links: {
GitHub: "https://github.com/jackyzha0/quartz",
"Discord Community": "https://discord.gg/cRFFHYye7t",
},
}),
}
// components for pages that display a single page (e.g. a single note)
export const defaultContentPageLayout: PageLayout = {
beforeBody: [
Component.ConditionalRender({
component: Component.ParentBreadcrumbs(),
condition: (page) => page.fileData.slug !== "index",
}),
Component.ArticleTitle(),
Component.ContentMeta(),
Component.TagList(),
],
left: [
Component.PageTitle(),
Component.MobileOnly(Component.Spacer()),
Component.Flex({
components: [
{
Component: Component.Search(),
grow: true,
},
{ Component: Component.Darkmode() },
{ Component: Component.ReaderMode() },
],
}),
Component.Explorer(),
],
right: [
Component.Graph(),
Component.DesktopOnly(Component.TableOfContents()),
Component.Backlinks(),
],
};
beforeBody: [
Component.ConditionalRender({
component: Component.ParentBreadcrumbs(),
condition: (page) => page.fileData.slug !== "index",
}),
Component.ArticleTitle(),
Component.ContentMeta(),
Component.TagList(),
],
left: [
Component.PageTitle(),
Component.MobileOnly(Component.Spacer()),
Component.Flex({
components: [
{
Component: Component.Search(),
grow: true,
},
{ Component: Component.Darkmode() },
{ Component: Component.ReaderMode() },
],
}),
Component.Explorer(),
],
right: [
Component.Graph(),
Component.DesktopOnly(Component.TableOfContents()),
Component.Backlinks(),
],
}
// components for pages that display lists of pages (e.g. tags or folders)
export const defaultListPageLayout: PageLayout = {
beforeBody: [Component.Breadcrumbs(), Component.ArticleTitle(), Component.ContentMeta()],
left: [
Component.PageTitle(),
Component.MobileOnly(Component.Spacer()),
Component.Flex({
components: [
{
Component: Component.Search(),
grow: true,
},
{ Component: Component.Darkmode() },
],
}),
Component.Explorer(),
],
right: [],
};
beforeBody: [Component.Breadcrumbs(), Component.ArticleTitle(), Component.ContentMeta()],
left: [
Component.PageTitle(),
Component.MobileOnly(Component.Spacer()),
Component.Flex({
components: [
{
Component: Component.Search(),
grow: true,
},
{ Component: Component.Darkmode() },
],
}),
Component.Explorer(),
],
right: [],
}

View File

@ -1,125 +1,126 @@
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types";
import { QuartzPluginData } from "../plugins/vfile";
import { classNames } from "../util/lang";
import { resolveRelative, simplifySlug, FullSlug, SimpleSlug } from "../util/path";
import style from "./styles/breadcrumbs.scss";
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
import { QuartzPluginData } from "../plugins/vfile"
import { classNames } from "../util/lang"
import { resolveRelative, simplifySlug, FullSlug, SimpleSlug } from "../util/path"
import style from "./styles/breadcrumbs.scss"
interface ParentBreadcrumbsOptions {
spacerSymbol?: string;
rootName?: string;
resolveFrontmatterTitle?: boolean;
frontmatterProp?: string,
spacerSymbol?: string
rootName?: string
resolveFrontmatterTitle?: boolean
frontmatterProp?: string
}
const defaultOptions: ParentBreadcrumbsOptions = {
spacerSymbol: "",
rootName: "Home",
resolveFrontmatterTitle: true,
frontmatterProp: "parent",
};
spacerSymbol: "",
rootName: "Home",
resolveFrontmatterTitle: true,
frontmatterProp: "parent",
}
export default ((opts?: ParentBreadcrumbsOptions) => {
const options = { ...defaultOptions, ...opts };
const parentKey = options.frontmatterProp;
const options = { ...defaultOptions, ...opts }
const parentKey = options.frontmatterProp
const ParentBreadcrumbs: QuartzComponent = ({
fileData,
allFiles,
displayClass,
}: QuartzComponentProps) => {
const ParentBreadcrumbs: QuartzComponent = ({
fileData,
allFiles,
displayClass,
}: QuartzComponentProps) => {
const parseWikiLink = (content: string): string => {
if (!content) return ""
let clean = content.trim().replace(/^["']|["']$/g, "")
clean = clean.replace(/^\[\[|\]\]$/g, "")
return clean.split("|")[0]
}
const parseWikiLink = (content: string): string => {
if (!content) return "";
let clean = content.trim().replace(/^["']|["']$/g, "");
clean = clean.replace(/^\[\[|\]\]$/g, "");
return clean.split("|")[0];
};
const findFile = (name: string) => {
const targetSlug = simplifySlug(name as FullSlug)
return allFiles.find((f: QuartzPluginData) => {
const fSlug = simplifySlug(f.slug!)
return fSlug === targetSlug || fSlug.endsWith(targetSlug) || f.frontmatter?.title === name
})
}
const findFile = (name: string) => {
const targetSlug = simplifySlug(name as FullSlug);
return allFiles.find((f: QuartzPluginData) => {
const fSlug = simplifySlug(f.slug!);
return fSlug === targetSlug || fSlug.endsWith(targetSlug) || f.frontmatter?.title === name;
});
};
type BreadcrumbNode = { displayName: string; path: string }
const crumbs: Array<BreadcrumbNode[]> = []
type BreadcrumbNode = { displayName: string; path: string; };
const crumbs: Array<BreadcrumbNode[]> = [];
let current = fileData
const visited = new Set<string>()
if (current.slug) visited.add(current.slug)
let current = fileData;
const visited = new Set<string>();
if (current.slug) visited.add(current.slug);
while (current && current.frontmatter?.[parentKey!]) {
const rawParent = current.frontmatter[parentKey!]
const parentList = Array.isArray(rawParent) ? rawParent : [rawParent]
while (current && current.frontmatter?.[parentKey!]) {
const rawParent = current.frontmatter[parentKey!];
const parentList = Array.isArray(rawParent) ? rawParent : [rawParent];
const currentLevelNodes: BreadcrumbNode[] = []
let nextParent: QuartzPluginData | undefined = undefined
const currentLevelNodes: BreadcrumbNode[] = [];
let nextParent: QuartzPluginData | undefined = undefined;
for (const p of parentList) {
const linkStr = parseWikiLink(p as string)
const parentFile = findFile(linkStr)
for (const p of parentList) {
const linkStr = parseWikiLink(p as string);
const parentFile = findFile(linkStr);
if (parentFile && parentFile.slug) {
currentLevelNodes.push({
displayName: options.resolveFrontmatterTitle
? (parentFile.frontmatter?.title ?? parentFile.slug)
: parentFile.slug,
path: resolveRelative(fileData.slug!, parentFile.slug!),
})
if (parentFile && parentFile.slug) {
currentLevelNodes.push({
displayName: options.resolveFrontmatterTitle
? parentFile.frontmatter?.title ?? parentFile.slug
: parentFile.slug,
path: resolveRelative(fileData.slug!, parentFile.slug!)
});
if (!nextParent && !visited.has(parentFile.slug)) {
nextParent = parentFile
}
}
}
if (!nextParent && !visited.has(parentFile.slug)) {
nextParent = parentFile;
}
}
}
if (currentLevelNodes.length > 0) {
crumbs.push(currentLevelNodes)
}
if (currentLevelNodes.length > 0) {
crumbs.push(currentLevelNodes);
}
if (nextParent) {
visited.add(nextParent.slug!)
current = nextParent
} else {
break
}
}
if (nextParent) {
visited.add(nextParent.slug!);
current = nextParent;
} else {
break;
}
}
if (current.slug !== "index") {
crumbs.push([
{
displayName: options.rootName!,
path: resolveRelative(fileData.slug!, "index" as SimpleSlug),
},
])
}
if (current.slug !== "index") {
crumbs.push([{
displayName: options.rootName!,
path: resolveRelative(fileData.slug!, "index" as SimpleSlug)
}]);
}
crumbs.reverse()
crumbs.reverse();
if (crumbs.length === 0 && fileData.slug === "index") {
return <></>
}
if (crumbs.length === 0 && fileData.slug === "index") {
return <></>;
}
return (
<nav class={classNames(displayClass, "breadcrumb-container")} aria-label="breadcrumbs">
{crumbs.map((crumbLevel, levelIndex) => (
<div class="breadcrumb-element">
{crumbLevel.map((node, nodeIndex) => (
<>
<a href={node.path}>{node.displayName}</a>
{nodeIndex < crumbLevel.length - 1 && <span style={{ opacity: 0.5 }}> / </span>}
</>
))}
{levelIndex !== crumbs.length && <p>{options.spacerSymbol}</p>}
</div>
))}
<div class="breadcrumb-element">
<p>{fileData.frontmatter?.title}</p>
</div>
</nav>
)
}
return (
<nav class={classNames(displayClass, "breadcrumb-container")} aria-label="breadcrumbs">
{crumbs.map((crumbLevel, levelIndex) => (
<div class="breadcrumb-element">
{crumbLevel.map((node, nodeIndex) => (
<>
<a href={node.path}>{node.displayName}</a>
{nodeIndex < crumbLevel.length - 1 && <span style={{ opacity: 0.5 }}> / </span>}
</>
))}
{levelIndex !== crumbs.length && <p>{options.spacerSymbol}</p>}
</div>
))}
<div class="breadcrumb-element">
<p>{fileData.frontmatter?.title}</p>
</div>
</nav>
);
};
ParentBreadcrumbs.css = style;
return ParentBreadcrumbs;
}) satisfies QuartzComponentConstructor;
ParentBreadcrumbs.css = style
return ParentBreadcrumbs
}) satisfies QuartzComponentConstructor

View File

@ -1,55 +1,55 @@
import Content from "./pages/Content";
import TagContent from "./pages/TagContent";
import FolderContent from "./pages/FolderContent";
import NotFound from "./pages/404";
import ArticleTitle from "./ArticleTitle";
import Darkmode from "./Darkmode";
import ReaderMode from "./ReaderMode";
import Head from "./Head";
import PageTitle from "./PageTitle";
import ContentMeta from "./ContentMeta";
import Spacer from "./Spacer";
import TableOfContents from "./TableOfContents";
import Explorer from "./Explorer";
import TagList from "./TagList";
import Graph from "./Graph";
import Backlinks from "./Backlinks";
import Search from "./Search";
import Footer from "./Footer";
import DesktopOnly from "./DesktopOnly";
import MobileOnly from "./MobileOnly";
import RecentNotes from "./RecentNotes";
import Breadcrumbs from "./Breadcrumbs";
import Comments from "./Comments";
import Flex from "./Flex";
import ConditionalRender from "./ConditionalRender";
import ParentBreadcrumbs from "./ParentBreadcrumbs";
import Content from "./pages/Content"
import TagContent from "./pages/TagContent"
import FolderContent from "./pages/FolderContent"
import NotFound from "./pages/404"
import ArticleTitle from "./ArticleTitle"
import Darkmode from "./Darkmode"
import ReaderMode from "./ReaderMode"
import Head from "./Head"
import PageTitle from "./PageTitle"
import ContentMeta from "./ContentMeta"
import Spacer from "./Spacer"
import TableOfContents from "./TableOfContents"
import Explorer from "./Explorer"
import TagList from "./TagList"
import Graph from "./Graph"
import Backlinks from "./Backlinks"
import Search from "./Search"
import Footer from "./Footer"
import DesktopOnly from "./DesktopOnly"
import MobileOnly from "./MobileOnly"
import RecentNotes from "./RecentNotes"
import Breadcrumbs from "./Breadcrumbs"
import Comments from "./Comments"
import Flex from "./Flex"
import ConditionalRender from "./ConditionalRender"
import ParentBreadcrumbs from "./ParentBreadcrumbs"
export {
ParentBreadcrumbs,
ArticleTitle,
Content,
TagContent,
FolderContent,
Darkmode,
ReaderMode,
Head,
PageTitle,
ContentMeta,
Spacer,
TableOfContents,
Explorer,
TagList,
Graph,
Backlinks,
Search,
Footer,
DesktopOnly,
MobileOnly,
RecentNotes,
NotFound,
Breadcrumbs,
Comments,
Flex,
ConditionalRender,
};
ParentBreadcrumbs,
ArticleTitle,
Content,
TagContent,
FolderContent,
Darkmode,
ReaderMode,
Head,
PageTitle,
ContentMeta,
Spacer,
TableOfContents,
Explorer,
TagList,
Graph,
Backlinks,
Search,
Footer,
DesktopOnly,
MobileOnly,
RecentNotes,
NotFound,
Breadcrumbs,
Comments,
Flex,
ConditionalRender,
}