Skip to content

Commit

Permalink
merge
Browse files Browse the repository at this point in the history
  • Loading branch information
bluerosegarden committed Nov 13, 2023
2 parents 4c32fcf + 8223465 commit d5c00d6
Show file tree
Hide file tree
Showing 13 changed files with 129 additions and 59 deletions.
6 changes: 3 additions & 3 deletions docs/features/breadcrumbs.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ For example, here's what the default configuration looks like:

```typescript title="quartz.layout.ts"
Component.Breadcrumbs({
spacerSymbol: ">", // symbol between crumbs
spacerSymbol: "", // symbol between crumbs
rootName: "Home", // name of first/root element
resolveFrontmatterTitle: false, // wether to resolve folder names through frontmatter titles (more computationally expensive)
hideOnRoot: true, // wether to hide breadcrumbs on root `index.md` page
resolveFrontmatterTitle: true, // whether to resolve folder names through frontmatter titles
hideOnRoot: true, // whether to hide breadcrumbs on root `index.md` page
})
```

Expand Down
2 changes: 1 addition & 1 deletion docs/features/callouts.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ See [documentation on supported types and syntax here](https://help.obsidian.md
> [!question]+ Can callouts be nested?
>
> > [!todo]- Yes!, they can.
> > [!todo]- Yes!, they can. And collapsed!
> >
> > > [!example] You can even use multiple layers of nesting.
Expand Down
5 changes: 5 additions & 0 deletions quartz/cli/args.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ export const SyncArgv = {
default: true,
describe: "create a git commit for your unsaved changes",
},
message: {
string: true,
alias: ["m"],
describe: "option to override the default Quartz commit message",
},
push: {
boolean: true,
default: true,
Expand Down
3 changes: 2 additions & 1 deletion quartz/cli/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -483,8 +483,9 @@ export async function handleSync(argv) {
dateStyle: "medium",
timeStyle: "short",
})
const commitMessage = argv.message ?? `Quartz sync: ${currentTimestamp}`
spawnSync("git", ["add", "."], { stdio: "inherit" })
spawnSync("git", ["commit", "-m", `Quartz sync: ${currentTimestamp}`], { stdio: "inherit" })
spawnSync("git", ["commit", "-m", commitMessage], { stdio: "inherit" })

if (contentStat.isSymbolicLink()) {
// put symlink back
Expand Down
51 changes: 25 additions & 26 deletions quartz/components/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ interface BreadcrumbOptions {
}

const defaultOptions: BreadcrumbOptions = {
spacerSymbol: ">",
spacerSymbol: "",
rootName: "Home",
resolveFrontmatterTitle: false,
resolveFrontmatterTitle: true,
hideOnRoot: true,
}

Expand All @@ -41,25 +41,13 @@ function formatCrumb(displayName: string, baseSlug: FullSlug, currentSlug: Simpl
}
}

// given a folderName (e.g. "features"), search for the corresponding `index.md` file
function findCurrentFile(allFiles: QuartzPluginData[], folderName: string) {
return allFiles.find((file) => {
if (file.slug?.endsWith("index")) {
const folderParts = file.filePath?.split("/")
if (folderParts) {
const name = folderParts[folderParts?.length - 2]
if (name === folderName) {
return true
}
}
}
})
}

export default ((opts?: Partial<BreadcrumbOptions>) => {
// Merge options with defaults
const options: BreadcrumbOptions = { ...defaultOptions, ...opts }

// computed index of folder name to its associated file data
let folderIndex: Map<string, QuartzPluginData> | undefined

function Breadcrumbs({ fileData, allFiles, displayClass }: QuartzComponentProps) {
// Hide crumbs on root if enabled
if (options.hideOnRoot && fileData.slug === "index") {
Expand All @@ -70,28 +58,39 @@ export default ((opts?: Partial<BreadcrumbOptions>) => {
const firstEntry = formatCrumb(options.rootName, fileData.slug!, "/" as SimpleSlug)
const crumbs: CrumbData[] = [firstEntry]

if (!folderIndex && options.resolveFrontmatterTitle) {
folderIndex = new Map()
// construct the index for the first time
for (const file of allFiles) {
if (file.slug?.endsWith("index")) {
const folderParts = file.filePath?.split("/")
if (folderParts) {
const folderName = folderParts[folderParts?.length - 2]
folderIndex.set(folderName, file)
}
}
}
}

// Split slug into hierarchy/parts
const slugParts = fileData.slug?.split("/")
if (slugParts) {
// full path until current part
let currentPath = ""
for (let i = 0; i < slugParts.length - 1; i++) {
let currentTitle = slugParts[i]
let curPathSegment = slugParts[i]

// TODO: performance optimizations/memoizing
// Try to resolve frontmatter folder title
if (options?.resolveFrontmatterTitle) {
// try to find file for current path
const currentFile = findCurrentFile(allFiles, currentTitle)
if (currentFile) {
currentTitle = currentFile.frontmatter!.title
}
const currentFile = folderIndex?.get(curPathSegment)
if (currentFile) {
curPathSegment = currentFile.frontmatter!.title
}

// Add current slug to full path
currentPath += slugParts[i] + "/"

// Format and add current crumb
const crumb = formatCrumb(currentTitle, fileData.slug!, currentPath as SimpleSlug)
const crumb = formatCrumb(curPathSegment, fileData.slug!, currentPath as SimpleSlug)
crumbs.push(crumb)
}

Expand Down
2 changes: 1 addition & 1 deletion quartz/components/pages/TagContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function TagContent(props: QuartzComponentProps) {
return (
<div>
<h2>
<a class="internal tag-link" href={`./${tag}`}>
<a class="internal tag-link" href={`../tags/${tag}`}>
#{tag}
</a>
</h2>
Expand Down
10 changes: 9 additions & 1 deletion quartz/components/scripts/popover.inline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@ async function mouseEnterHandler(
})
}

const hasAlreadyBeenFetched = () =>
[...link.children].some((child) => child.classList.contains("popover"))

// dont refetch if there's already a popover
if ([...link.children].some((child) => child.classList.contains("popover"))) {
if (hasAlreadyBeenFetched()) {
return setPosition(link.lastChild as HTMLElement)
}

Expand All @@ -49,6 +52,11 @@ async function mouseEnterHandler(
console.error(err)
})

// bailout if another popover exists
if (hasAlreadyBeenFetched()) {
return
}

if (!contents) return
const html = p.parseFromString(contents, "text/html")
normalizeRelativeURLs(html, targetUrl)
Expand Down
18 changes: 18 additions & 0 deletions quartz/components/scripts/spa.inline.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import micromorph from "micromorph"
import { FullSlug, RelativeURL, getFullSlug } from "../../util/path"
import { normalizeRelativeURLs } from "./popover.inline"

// adapted from `micromorph`
// https://github.com/natemoo-re/micromorph
Expand All @@ -18,6 +19,12 @@ const isLocalUrl = (href: string) => {
return false
}

const isSamePage = (url: URL): boolean => {
const sameOrigin = url.origin === window.location.origin
const samePath = url.pathname === window.location.pathname
return sameOrigin && samePath
}

const getOpts = ({ target }: Event): { url: URL; scroll?: boolean } | undefined => {
if (!isElement(target)) return
if (target.attributes.getNamedItem("target")?.value === "_blank") return
Expand Down Expand Up @@ -46,6 +53,8 @@ async function navigate(url: URL, isBack: boolean = false) {
if (!contents) return

const html = p.parseFromString(contents, "text/html")
normalizeRelativeURLs(html, url)

let title = html.querySelector("title")?.textContent
if (title) {
document.title = title
Expand Down Expand Up @@ -93,8 +102,16 @@ function createRouter() {
if (typeof window !== "undefined") {
window.addEventListener("click", async (event) => {
const { url } = getOpts(event) ?? {}
// dont hijack behaviour, just let browser act normally
if (!url || event.ctrlKey || event.metaKey) return
event.preventDefault()

if (isSamePage(url) && url.hash) {
const el = document.getElementById(decodeURIComponent(url.hash.substring(1)))
el?.scrollIntoView()
return
}

try {
navigate(url, false)
} catch (e) {
Expand Down Expand Up @@ -140,6 +157,7 @@ if (!customElements.get("route-announcer")) {
style:
"position: absolute; left: 0; top: 0; clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; white-space: nowrap; width: 1px; height: 1px",
}

customElements.define(
"route-announcer",
class RouteAnnouncer extends HTMLElement {
Expand Down
9 changes: 7 additions & 2 deletions quartz/plugins/emitters/aliases.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FilePath, FullSlug, resolveRelative, simplifySlug } from "../../util/path"
import { FilePath, FullSlug, joinSegments, resolveRelative, simplifySlug } from "../../util/path"
import { QuartzEmitterPlugin } from "../types"
import path from "path"

Expand All @@ -25,7 +25,12 @@ export const AliasRedirects: QuartzEmitterPlugin = () => ({
slugs.push(permalink as FullSlug)
}

for (const slug of slugs) {
for (let slug of slugs) {
// fix any slugs that have trailing slash
if (slug.endsWith("/")) {
slug = joinSegments(slug, "index") as FullSlug
}

const redirUrl = resolveRelative(slug, file.data.slug!)
const fp = await emit({
content: `
Expand Down
11 changes: 11 additions & 0 deletions quartz/plugins/emitters/contentIndex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ function generateRSSFeed(cfg: GlobalConfiguration, idx: ContentIndex, limit?: nu
</item>`

const items = Array.from(idx)
.sort(([_, f1], [__, f2]) => {
if (f1.date && f2.date) {
return f2.date.getTime() - f1.date.getTime()
} else if (f1.date && !f2.date) {
return -1
} else if (!f1.date && f2.date) {
return 1
}

return f1.title.localeCompare(f2.title)
})
.map(([slug, content]) => createURLEntry(simplifySlug(slug), content))
.slice(0, limit ?? idx.size)
.join("")
Expand Down
28 changes: 19 additions & 9 deletions quartz/styles/base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ a {
color: var(--tertiary) !important;
}

&.internal {
&.internal:not(:has(> img)) {
text-decoration: none;
background-color: var(--highlight);
padding: 0 0.1rem;
Expand Down Expand Up @@ -390,23 +390,33 @@ p {
line-height: 1.6rem;
}

table {
margin: 1rem;
padding: 1.5rem;
border-collapse: collapse;
& > * {
line-height: 2rem;
.table-container {
overflow-x: auto;

& > table {
margin: 1rem;
padding: 1.5rem;
border-collapse: collapse;

th,
td {
min-width: 75px;
}

& > * {
line-height: 2rem;
}
}
}

th {
text-align: left;
padding: 0.4rem 1rem;
padding: 0.4rem 0.7rem;
border-bottom: 2px solid var(--gray);
}

td {
padding: 0.2rem 1rem;
padding: 0.2rem 0.7rem;
}

tr {
Expand Down
15 changes: 0 additions & 15 deletions quartz/util/jsx.ts

This file was deleted.

28 changes: 28 additions & 0 deletions quartz/util/jsx.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Components, Jsx, toJsxRuntime } from "hast-util-to-jsx-runtime"
import { QuartzPluginData } from "../plugins/vfile"
import { Node, Root } from "hast"
import { Fragment, jsx, jsxs } from "preact/jsx-runtime"
import { trace } from "./trace"
import { type FilePath } from "./path"

const customComponents: Components = {
table: (props) => (
<div class="table-container">
<table {...props} />
</div>
),
}

export function htmlToJsx(fp: FilePath, tree: Node<QuartzPluginData>) {
try {
return toJsxRuntime(tree as Root, {
Fragment,
jsx: jsx as Jsx,
jsxs: jsxs as Jsx,
elementAttributeNameCase: "html",
components: customComponents,
})
} catch (e) {
trace(`Failed to parse Markdown in \`${fp}\` into JSX`, e as Error)
}
}

0 comments on commit d5c00d6

Please sign in to comment.