css fixes, add recent notes, more robust quartz update
2 files added
6 files modified
| | |
| | | |
| | | function gitPull(origin, branch) { |
| | | const flags = ["--no-rebase", "--autostash", "-s", "recursive", "-X", "ours", "--no-edit"] |
| | | spawnSync("git", ["pull", ...flags, origin, branch], { stdio: "inherit" }) |
| | | const out = spawnSync("git", ["pull", ...flags, origin, branch], { stdio: "inherit" }) |
| | | if (out.stderr) { |
| | | throw new Error(`Error while pulling updates: ${out.stderr}`) |
| | | } |
| | | } |
| | | |
| | | yargs(hideBin(process.argv)) |
| | |
| | | const contentFolder = path.join(cwd, argv.directory) |
| | | console.log(chalk.bgGreen.black(`\n Quartz v${version} \n`)) |
| | | console.log("Backing up your content") |
| | | execSync( |
| | | `git remote show upstream || git remote add upstream https://github.com/jackyzha0/quartz.git`, |
| | | ) |
| | | await stashContentFolder(contentFolder) |
| | | console.log( |
| | | "Pulling updates... you may need to resolve some `git` conflicts if you've made changes to components or plugins.", |
| | | ) |
| | | execSync( |
| | | `git remote show upstream || git remote add upstream https://github.com/jackyzha0/quartz.git`, |
| | | ) |
| | | gitPull(UPSTREAM_NAME, QUARTZ_SOURCE_BRANCH) |
| | | await popContentFolder(contentFolder) |
| | | console.log("Ensuring dependencies are up to date") |
| | |
| | | import { Date } from "./Date" |
| | | import { QuartzComponentProps } from "./types" |
| | | |
| | | function byDateAndAlphabetical(f1: QuartzPluginData, f2: QuartzPluginData): number { |
| | | export function byDateAndAlphabetical(f1: QuartzPluginData, f2: QuartzPluginData): number { |
| | | if (f1.dates && f2.dates) { |
| | | // sort descending by last modified |
| | | return f2.dates.modified.getTime() - f1.dates.modified.getTime() |
| New file |
| | |
| | | import { QuartzComponentConstructor, QuartzComponentProps } from "./types" |
| | | import { FullSlug, SimpleSlug, resolveRelative } from "../util/path" |
| | | import { QuartzPluginData } from "../plugins/vfile" |
| | | import { byDateAndAlphabetical } from "./PageList" |
| | | import style from "./styles/recentNotes.scss" |
| | | import { Date } from "./Date" |
| | | |
| | | interface Options { |
| | | title: string |
| | | limit: number |
| | | linkToMore: SimpleSlug | false |
| | | filter: (f: QuartzPluginData) => boolean |
| | | sort: (f1: QuartzPluginData, f2: QuartzPluginData) => number |
| | | } |
| | | |
| | | const defaultOptions: Options = { |
| | | title: "Recent Notes", |
| | | limit: 3, |
| | | linkToMore: false, |
| | | filter: () => true, |
| | | sort: byDateAndAlphabetical, |
| | | } |
| | | |
| | | export default ((userOpts?: Partial<Options>) => { |
| | | const opts = { ...defaultOptions, ...userOpts } |
| | | function RecentNotes(props: QuartzComponentProps) { |
| | | const { allFiles, fileData } = props |
| | | const pages = allFiles.filter(opts.filter).sort(opts.sort).slice(0, opts.limit) |
| | | const remaining = Math.max(0, pages.length - opts.limit) |
| | | return ( |
| | | <div class="recent-notes"> |
| | | <h3>{opts.title}</h3> |
| | | <ul class="recent-ul"> |
| | | {pages.map((page) => { |
| | | const title = page.frontmatter?.title |
| | | const tags = page.frontmatter?.tags ?? [] |
| | | |
| | | return ( |
| | | <li class="recent-li"> |
| | | <div class="section"> |
| | | <div class="desc"> |
| | | <h3> |
| | | <a href={resolveRelative(fileData.slug!, page.slug!)} class="internal"> |
| | | {title} |
| | | </a> |
| | | </h3> |
| | | </div> |
| | | {page.dates && ( |
| | | <p class="meta"> |
| | | <Date date={page.dates.modified} /> |
| | | </p> |
| | | )} |
| | | <ul class="tags"> |
| | | {tags.map((tag) => ( |
| | | <li> |
| | | <a |
| | | class="internal tag-link" |
| | | href={resolveRelative(fileData.slug!, `tags/${tag}` as FullSlug)} |
| | | > |
| | | #{tag} |
| | | </a> |
| | | </li> |
| | | ))} |
| | | </ul> |
| | | </div> |
| | | </li> |
| | | ) |
| | | })} |
| | | </ul> |
| | | {opts.linkToMore && remaining > 0 && ( |
| | | <p> |
| | | <a href={resolveRelative(fileData.slug!, opts.linkToMore)}>See {remaining} more →</a> |
| | | </p> |
| | | )} |
| | | </div> |
| | | ) |
| | | } |
| | | |
| | | RecentNotes.css = style |
| | | return RecentNotes |
| | | }) satisfies QuartzComponentConstructor |
| | |
| | | import Footer from "./Footer" |
| | | import DesktopOnly from "./DesktopOnly" |
| | | import MobileOnly from "./MobileOnly" |
| | | import RecentNotes from "./RecentNotes" |
| | | |
| | | export { |
| | | ArticleTitle, |
| | |
| | | Footer, |
| | | DesktopOnly, |
| | | MobileOnly, |
| | | RecentNotes, |
| | | } |
| | |
| | | allFiles: allPagesInFolder, |
| | | } |
| | | |
| | | const content = (tree as Root).children.length === 0 ? |
| | | fileData.description : |
| | | // @ts-ignore |
| | | toJsxRuntime(tree, { Fragment, jsx, jsxs, elementAttributeNameCase: "html" }) |
| | | const content = |
| | | (tree as Root).children.length === 0 |
| | | ? fileData.description |
| | | : // @ts-ignore |
| | | toJsxRuntime(tree, { Fragment, jsx, jsxs, elementAttributeNameCase: "html" }) |
| | | |
| | | return ( |
| | | <div class="popover-hint"> |
| | |
| | | (file.frontmatter?.tags ?? []).flatMap(getAllSegmentPrefixes).includes(tag), |
| | | ) |
| | | |
| | | const content = (tree as Root).children.length === 0 ? |
| | | fileData.description : |
| | | // @ts-ignore |
| | | toJsxRuntime(tree, { Fragment, jsx, jsxs, elementAttributeNameCase: "html" }) |
| | | const content = |
| | | (tree as Root).children.length === 0 |
| | | ? fileData.description |
| | | : // @ts-ignore |
| | | toJsxRuntime(tree, { Fragment, jsx, jsxs, elementAttributeNameCase: "html" }) |
| | | |
| | | if (tag === "") { |
| | | const tags = [...new Set(allFiles.flatMap((data) => data.frontmatter?.tags ?? []))] |
| | |
| | | ...props, |
| | | allFiles: pages, |
| | | } |
| | | |
| | | const contentPage = allFiles.filter((file) => file.slug === `tags/${tag}`)[0] |
| | | const content = contentPage?.description |
| | | return ( |
| | | <div> |
| | | <h2> |
| | |
| | | #{tag} |
| | | </a> |
| | | </h2> |
| | | {content && <p>{content}</p>} |
| | | <p> |
| | | {pages.length} items with this tag.{" "} |
| | | {pages.length > numPages && `Showing first ${numPages}.`} |
| New file |
| | |
| | | .recent-notes { |
| | | & > h3 { |
| | | font-size: 1rem; |
| | | } |
| | | |
| | | & > ul.recent-ul { |
| | | list-style: none; |
| | | margin-top: 1.5rem; |
| | | padding-left: 0; |
| | | |
| | | & > li { |
| | | margin: 1rem 0; |
| | | .section > .desc > h3 > a { |
| | | background-color: transparent; |
| | | } |
| | | |
| | | .section > .meta { |
| | | margin: 0 0 0.5rem 0; |
| | | opacity: 0.6; |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | border-radius: 5px; |
| | | overflow-x: auto; |
| | | border: 1px solid var(--lightgray); |
| | | position: relative; |
| | | |
| | | &:has(> code.mermaid) { |
| | | border: none; |