basic search implementation
This commit is contained in:
		@@ -1,20 +1,7 @@
 | 
			
		||||
import { visit } from "unist-util-visit"
 | 
			
		||||
import { QuartzEmitterPlugin } from "../types"
 | 
			
		||||
import { Element } from "hast"
 | 
			
		||||
import path from "path"
 | 
			
		||||
import { trimPathSuffix } from "../../path"
 | 
			
		||||
 | 
			
		||||
interface Options {
 | 
			
		||||
  indexAnchorLinks: boolean,
 | 
			
		||||
  indexExternalLinks: boolean,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const defaultOptions: Options = {
 | 
			
		||||
  indexAnchorLinks: false,
 | 
			
		||||
  indexExternalLinks: false,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type ContentIndex = Map<string, ContentDetails> 
 | 
			
		||||
export type ContentIndex = Map<string, ContentDetails>
 | 
			
		||||
export type ContentDetails = {
 | 
			
		||||
  title: string,
 | 
			
		||||
  links?: string[],
 | 
			
		||||
@@ -22,39 +9,17 @@ export type ContentDetails = {
 | 
			
		||||
  content: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const ContentIndex: QuartzEmitterPlugin<Options> = (userOpts) => {
 | 
			
		||||
  const opts = { ...userOpts, ...defaultOptions }
 | 
			
		||||
export const ContentIndex: QuartzEmitterPlugin = () => {
 | 
			
		||||
  return {
 | 
			
		||||
    name: "ContentIndex",
 | 
			
		||||
    async emit(_contentDir, _cfg, content, _resources, emit) {
 | 
			
		||||
      const fp = path.join("static", "contentIndex")
 | 
			
		||||
      const linkIndex: ContentIndex = new Map()
 | 
			
		||||
      for (const [tree, file] of content) {
 | 
			
		||||
        let slug = trimPathSuffix(file.data.slug!)
 | 
			
		||||
 | 
			
		||||
        const outgoing: Set<string> = new Set()
 | 
			
		||||
        visit(tree, 'element', (node: Element) => {
 | 
			
		||||
          if (node.tagName === 'a' && node.properties && typeof node.properties.href === 'string') {
 | 
			
		||||
            let dest = node.properties.href
 | 
			
		||||
            if (dest.startsWith(".")) {
 | 
			
		||||
              const normalizedPath = path.normalize(path.join(slug, dest))
 | 
			
		||||
              dest = trimPathSuffix(normalizedPath)
 | 
			
		||||
              outgoing.add(dest)
 | 
			
		||||
            } else if (dest.startsWith("#")) {
 | 
			
		||||
              if (opts.indexAnchorLinks) {
 | 
			
		||||
                outgoing.add(dest)
 | 
			
		||||
              }
 | 
			
		||||
            } else {
 | 
			
		||||
              if (opts.indexExternalLinks) {
 | 
			
		||||
                outgoing.add(dest)
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
      for (const [_tree, file] of content) {
 | 
			
		||||
        let slug = file.data.slug!
 | 
			
		||||
        linkIndex.set(slug, {
 | 
			
		||||
          title: file.data.frontmatter?.title!,
 | 
			
		||||
          links: [...outgoing],
 | 
			
		||||
          links: file.data.links ?? [],
 | 
			
		||||
          tags: file.data.frontmatter?.tags,
 | 
			
		||||
          content: file.data.text ?? ""
 | 
			
		||||
        })
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ export const ContentPage: QuartzEmitterPlugin<Options> = (opts) => {
 | 
			
		||||
    },
 | 
			
		||||
    async emit(_contentDir, cfg, content, resources, emit): Promise<string[]> {
 | 
			
		||||
      const fps: string[] = []
 | 
			
		||||
 | 
			
		||||
      const allFiles = content.map(c => c[1].data)
 | 
			
		||||
      for (const [tree, file] of content) {
 | 
			
		||||
        const baseDir = resolveToRoot(file.data.slug!)
 | 
			
		||||
        const pageResources: StaticResources = {
 | 
			
		||||
@@ -50,13 +50,14 @@ export const ContentPage: QuartzEmitterPlugin<Options> = (opts) => {
 | 
			
		||||
          externalResources: pageResources,
 | 
			
		||||
          cfg,
 | 
			
		||||
          children: [],
 | 
			
		||||
          tree
 | 
			
		||||
          tree,
 | 
			
		||||
          allFiles
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const Content = opts.content
 | 
			
		||||
        const doc = <html>
 | 
			
		||||
          <Head {...componentData} />
 | 
			
		||||
          <body data-slug={trimPathSuffix(file.data.slug ?? "")}>
 | 
			
		||||
          <body data-slug={file.data.slug ?? ""}>
 | 
			
		||||
            <div id="quartz-root" class="page">
 | 
			
		||||
              <Header {...componentData} >
 | 
			
		||||
                {header.map(HeaderComponent => <HeaderComponent {...componentData} />)}
 | 
			
		||||
 
 | 
			
		||||
@@ -51,6 +51,7 @@ export function emitComponentResources(cfg: GlobalConfiguration, resources: Stat
 | 
			
		||||
    componentResources.afterDOMLoaded.push(spaRouterScript)
 | 
			
		||||
  } else {
 | 
			
		||||
    componentResources.afterDOMLoaded.push(`
 | 
			
		||||
      window.spaNavigate = (url, _) => window.location.assign(url)
 | 
			
		||||
      const event = new CustomEvent("nav", { detail: { slug: document.body.dataset.slug } })
 | 
			
		||||
      document.dispatchEvent(event)`
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ export { GitHubFlavoredMarkdown } from './gfm'
 | 
			
		||||
export { CreatedModifiedDate } from './lastmod'
 | 
			
		||||
export { Katex } from './latex'
 | 
			
		||||
export { Description } from './description'
 | 
			
		||||
export { ResolveLinks } from './links'
 | 
			
		||||
export { CrawlLinks } from './links'
 | 
			
		||||
export { ObsidianFlavoredMarkdown } from './ofm'
 | 
			
		||||
export { SyntaxHighlighting } from './syntax'
 | 
			
		||||
export { TableOfContents } from './toc'
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import { QuartzTransformerPlugin } from "../types"
 | 
			
		||||
import { relative, relativeToRoot, slugify } from "../../path"
 | 
			
		||||
import { relative, relativeToRoot, slugify, trimPathSuffix } from "../../path"
 | 
			
		||||
import path from "path"
 | 
			
		||||
import { visit } from 'unist-util-visit'
 | 
			
		||||
import isAbsoluteUrl from "is-absolute-url"
 | 
			
		||||
@@ -9,14 +9,18 @@ interface Options {
 | 
			
		||||
  markdownLinkResolution: 'absolute' | 'relative'
 | 
			
		||||
  /** Strips folders from a link so that it looks nice */
 | 
			
		||||
  prettyLinks: boolean
 | 
			
		||||
  indexAnchorLinks: boolean
 | 
			
		||||
  indexExternalLinks: boolean
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const defaultOptions: Options = {
 | 
			
		||||
  markdownLinkResolution: 'absolute',
 | 
			
		||||
  prettyLinks: true
 | 
			
		||||
  prettyLinks: true,
 | 
			
		||||
  indexAnchorLinks: false,
 | 
			
		||||
  indexExternalLinks: false,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const ResolveLinks: QuartzTransformerPlugin<Partial<Options> | undefined> = (userOpts) => {
 | 
			
		||||
export const CrawlLinks: QuartzTransformerPlugin<Partial<Options> | undefined> = (userOpts) => {
 | 
			
		||||
  const opts = { ...defaultOptions, ...userOpts }
 | 
			
		||||
  return {
 | 
			
		||||
    name: "LinkProcessing",
 | 
			
		||||
@@ -36,6 +40,7 @@ export const ResolveLinks: QuartzTransformerPlugin<Partial<Options> | undefined>
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          const outgoing: Set<string> = new Set()
 | 
			
		||||
          visit(tree, 'element', (node, _index, _parent) => {
 | 
			
		||||
            // rewrite all links
 | 
			
		||||
            if (
 | 
			
		||||
@@ -43,13 +48,27 @@ export const ResolveLinks: QuartzTransformerPlugin<Partial<Options> | undefined>
 | 
			
		||||
              node.properties &&
 | 
			
		||||
              typeof node.properties.href === 'string'
 | 
			
		||||
            ) {
 | 
			
		||||
              node.properties.className = isAbsoluteUrl(node.properties.href) ? "external" : "internal"
 | 
			
		||||
              let dest = node.properties.href
 | 
			
		||||
              node.properties.className = isAbsoluteUrl(dest) ? "external" : "internal"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
              // don't process external links or intra-document anchors
 | 
			
		||||
              if (!(isAbsoluteUrl(node.properties.href) || node.properties.href.startsWith("#"))) {
 | 
			
		||||
                node.properties.href = transformLink(node.properties.href)
 | 
			
		||||
              if (!(isAbsoluteUrl(dest) || dest.startsWith("#"))) {
 | 
			
		||||
                node.properties.href = transformLink(dest)
 | 
			
		||||
              }
 | 
			
		||||
              
 | 
			
		||||
              dest = node.properties.href
 | 
			
		||||
              if (dest.startsWith(".")) {
 | 
			
		||||
                const normalizedPath = path.normalize(path.join(curSlug, dest))
 | 
			
		||||
                outgoing.add(trimPathSuffix(normalizedPath))
 | 
			
		||||
              } else if (dest.startsWith("#")) {
 | 
			
		||||
                if (opts.indexAnchorLinks) {
 | 
			
		||||
                  outgoing.add(dest)
 | 
			
		||||
                }
 | 
			
		||||
              } else {
 | 
			
		||||
 | 
			
		||||
                if (opts.indexExternalLinks) {
 | 
			
		||||
                  outgoing.add(dest)
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              // rewrite link internals if prettylinks is on
 | 
			
		||||
@@ -70,8 +89,16 @@ export const ResolveLinks: QuartzTransformerPlugin<Partial<Options> | undefined>
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
 | 
			
		||||
          file.data.links = [...outgoing]
 | 
			
		||||
        }
 | 
			
		||||
      }]
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
declare module 'vfile' {
 | 
			
		||||
  interface DataMap {
 | 
			
		||||
    links: string[]
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user