notes/quartz/components/scripts/explorer.inline.ts

282 lines
9.7 KiB
TypeScript
Raw Normal View History

import { FileTrieNode } from "../../util/fileTrie"
import { FullSlug, resolveRelative, simplifySlug } from "../../util/path"
import { ContentDetails } from "../../plugins/emitters/contentIndex"
feat: implement file explorer component (closes #201) (#452) * feat: add basic explorer structure„ * feat: integrate new component/plugin * feat: add basic explorer structure * feat: add sort to FileNodes * style: improve style for explorer * refactor: remove unused explorer plugin * refactor: clean explorer structure, fix base (toc) * refactor: clean css, respect displayClass * style: add styling to chevron * refactor: clean up debug statements * refactor: remove unused import * fix: clicking folder icon sometimes turns invisible * refactor: clean css * feat(explorer): add config for title * feat: add config for folder click behavior * fix: `no-pointer` not being set for all elements new approach, have one `no-pointer` class, that removes pointer events and one `clickable` class on the svg and button (everything that can normally be clicked). then, find all children with `clickable` and toggle `no-pointer` * fix: bug where nested folders got incorrect height this fixes the bug where nested folders weren't calculating their total height correctly. done by adding class to main container of all children and calculating total * feat: introduce `folderDefaultState` config * feat: store depth for explorer nodes * feat: implement option for collapsed state + bug fixes folderBehavior: "link" still has bad styling, but major bugs with pointers fixed (not clean yet, but working) * fix: default folder icon rotation * fix: hitbox problem with folder links, fix style * fix: redirect url for nested folders * fix: inconsistent behavior with 'collapseFolders' opt * chore: add comments to `ExplorerNode` * feat: save explorer state to local storage (not clean) * feat: rework `getFolders()`, fix localstorage read + write * feat: set folder state from localStorage needs serious refactoring but functional (except folder icon orientation) * fix: folder icon orientation after local storage * feat: add config for `useSavedState` * refactor: clean `explorer.inline.ts` remove unused functions, comments, unused code, add types to EventHandler * refactor: clean explorer merge `isSvg` paths, remove console logs * refactor: add documentation, remove unused funcs * feat: rework folder collapse logic use grids instead of jank scuffed solution with calculating total heights * refactor: remove depth arg from insert * feat: restore collapse functionality to clicks allow folder icon + folder label to collapse folders again * refactor: remove `pointer-event` jank * feat: improve svg viewbox + remove unused props * feat: use css selector to toggle icon rework folder icon to work purely with css instead of JS manipulation * refactor: remove unused cfg * feat: move TOC to right sidebar * refactor: clean css * style: fix overflow + overflow margin * fix: use `resolveRelative` to resolve file paths * fix: `defaultFolderState` config option * refactor: rename import, rename `folderLi` + ul * fix: use `QuartzPluginData` type * docs: add explorer documentation
2023-09-15 18:39:16 +02:00
type MaybeHTMLElement = HTMLElement | undefined
interface ParsedOptions {
folderClickBehavior: "collapse" | "link"
folderDefaultState: "collapsed" | "open"
useSavedState: boolean
sortFn: (a: FileTrieNode, b: FileTrieNode) => number
filterFn: (node: FileTrieNode) => boolean
mapFn: (node: FileTrieNode) => void
order: "sort" | "filter" | "map"[]
}
type FolderState = {
path: string
collapsed: boolean
}
let currentExplorerState: Array<FolderState>
function toggleExplorer(this: HTMLElement) {
2025-03-10 15:13:04 -07:00
const nearestExplorer = this.closest(".explorer") as HTMLElement
if (!nearestExplorer) return
nearestExplorer.classList.toggle("collapsed")
nearestExplorer.setAttribute(
"aria-expanded",
nearestExplorer.getAttribute("aria-expanded") === "true" ? "false" : "true",
)
feat: implement file explorer component (closes #201) (#452) * feat: add basic explorer structure„ * feat: integrate new component/plugin * feat: add basic explorer structure * feat: add sort to FileNodes * style: improve style for explorer * refactor: remove unused explorer plugin * refactor: clean explorer structure, fix base (toc) * refactor: clean css, respect displayClass * style: add styling to chevron * refactor: clean up debug statements * refactor: remove unused import * fix: clicking folder icon sometimes turns invisible * refactor: clean css * feat(explorer): add config for title * feat: add config for folder click behavior * fix: `no-pointer` not being set for all elements new approach, have one `no-pointer` class, that removes pointer events and one `clickable` class on the svg and button (everything that can normally be clicked). then, find all children with `clickable` and toggle `no-pointer` * fix: bug where nested folders got incorrect height this fixes the bug where nested folders weren't calculating their total height correctly. done by adding class to main container of all children and calculating total * feat: introduce `folderDefaultState` config * feat: store depth for explorer nodes * feat: implement option for collapsed state + bug fixes folderBehavior: "link" still has bad styling, but major bugs with pointers fixed (not clean yet, but working) * fix: default folder icon rotation * fix: hitbox problem with folder links, fix style * fix: redirect url for nested folders * fix: inconsistent behavior with 'collapseFolders' opt * chore: add comments to `ExplorerNode` * feat: save explorer state to local storage (not clean) * feat: rework `getFolders()`, fix localstorage read + write * feat: set folder state from localStorage needs serious refactoring but functional (except folder icon orientation) * fix: folder icon orientation after local storage * feat: add config for `useSavedState` * refactor: clean `explorer.inline.ts` remove unused functions, comments, unused code, add types to EventHandler * refactor: clean explorer merge `isSvg` paths, remove console logs * refactor: add documentation, remove unused funcs * feat: rework folder collapse logic use grids instead of jank scuffed solution with calculating total heights * refactor: remove depth arg from insert * feat: restore collapse functionality to clicks allow folder icon + folder label to collapse folders again * refactor: remove `pointer-event` jank * feat: improve svg viewbox + remove unused props * feat: use css selector to toggle icon rework folder icon to work purely with css instead of JS manipulation * refactor: remove unused cfg * feat: move TOC to right sidebar * refactor: clean css * style: fix overflow + overflow margin * fix: use `resolveRelative` to resolve file paths * fix: `defaultFolderState` config option * refactor: rename import, rename `folderLi` + ul * fix: use `QuartzPluginData` type * docs: add explorer documentation
2023-09-15 18:39:16 +02:00
}
function toggleFolder(evt: MouseEvent) {
evt.stopPropagation()
const target = evt.target as MaybeHTMLElement
if (!target) return
feat: implement file explorer component (closes #201) (#452) * feat: add basic explorer structure„ * feat: integrate new component/plugin * feat: add basic explorer structure * feat: add sort to FileNodes * style: improve style for explorer * refactor: remove unused explorer plugin * refactor: clean explorer structure, fix base (toc) * refactor: clean css, respect displayClass * style: add styling to chevron * refactor: clean up debug statements * refactor: remove unused import * fix: clicking folder icon sometimes turns invisible * refactor: clean css * feat(explorer): add config for title * feat: add config for folder click behavior * fix: `no-pointer` not being set for all elements new approach, have one `no-pointer` class, that removes pointer events and one `clickable` class on the svg and button (everything that can normally be clicked). then, find all children with `clickable` and toggle `no-pointer` * fix: bug where nested folders got incorrect height this fixes the bug where nested folders weren't calculating their total height correctly. done by adding class to main container of all children and calculating total * feat: introduce `folderDefaultState` config * feat: store depth for explorer nodes * feat: implement option for collapsed state + bug fixes folderBehavior: "link" still has bad styling, but major bugs with pointers fixed (not clean yet, but working) * fix: default folder icon rotation * fix: hitbox problem with folder links, fix style * fix: redirect url for nested folders * fix: inconsistent behavior with 'collapseFolders' opt * chore: add comments to `ExplorerNode` * feat: save explorer state to local storage (not clean) * feat: rework `getFolders()`, fix localstorage read + write * feat: set folder state from localStorage needs serious refactoring but functional (except folder icon orientation) * fix: folder icon orientation after local storage * feat: add config for `useSavedState` * refactor: clean `explorer.inline.ts` remove unused functions, comments, unused code, add types to EventHandler * refactor: clean explorer merge `isSvg` paths, remove console logs * refactor: add documentation, remove unused funcs * feat: rework folder collapse logic use grids instead of jank scuffed solution with calculating total heights * refactor: remove depth arg from insert * feat: restore collapse functionality to clicks allow folder icon + folder label to collapse folders again * refactor: remove `pointer-event` jank * feat: improve svg viewbox + remove unused props * feat: use css selector to toggle icon rework folder icon to work purely with css instead of JS manipulation * refactor: remove unused cfg * feat: move TOC to right sidebar * refactor: clean css * style: fix overflow + overflow margin * fix: use `resolveRelative` to resolve file paths * fix: `defaultFolderState` config option * refactor: rename import, rename `folderLi` + ul * fix: use `QuartzPluginData` type * docs: add explorer documentation
2023-09-15 18:39:16 +02:00
// Check if target was svg icon or button
feat: implement file explorer component (closes #201) (#452) * feat: add basic explorer structure„ * feat: integrate new component/plugin * feat: add basic explorer structure * feat: add sort to FileNodes * style: improve style for explorer * refactor: remove unused explorer plugin * refactor: clean explorer structure, fix base (toc) * refactor: clean css, respect displayClass * style: add styling to chevron * refactor: clean up debug statements * refactor: remove unused import * fix: clicking folder icon sometimes turns invisible * refactor: clean css * feat(explorer): add config for title * feat: add config for folder click behavior * fix: `no-pointer` not being set for all elements new approach, have one `no-pointer` class, that removes pointer events and one `clickable` class on the svg and button (everything that can normally be clicked). then, find all children with `clickable` and toggle `no-pointer` * fix: bug where nested folders got incorrect height this fixes the bug where nested folders weren't calculating their total height correctly. done by adding class to main container of all children and calculating total * feat: introduce `folderDefaultState` config * feat: store depth for explorer nodes * feat: implement option for collapsed state + bug fixes folderBehavior: "link" still has bad styling, but major bugs with pointers fixed (not clean yet, but working) * fix: default folder icon rotation * fix: hitbox problem with folder links, fix style * fix: redirect url for nested folders * fix: inconsistent behavior with 'collapseFolders' opt * chore: add comments to `ExplorerNode` * feat: save explorer state to local storage (not clean) * feat: rework `getFolders()`, fix localstorage read + write * feat: set folder state from localStorage needs serious refactoring but functional (except folder icon orientation) * fix: folder icon orientation after local storage * feat: add config for `useSavedState` * refactor: clean `explorer.inline.ts` remove unused functions, comments, unused code, add types to EventHandler * refactor: clean explorer merge `isSvg` paths, remove console logs * refactor: add documentation, remove unused funcs * feat: rework folder collapse logic use grids instead of jank scuffed solution with calculating total heights * refactor: remove depth arg from insert * feat: restore collapse functionality to clicks allow folder icon + folder label to collapse folders again * refactor: remove `pointer-event` jank * feat: improve svg viewbox + remove unused props * feat: use css selector to toggle icon rework folder icon to work purely with css instead of JS manipulation * refactor: remove unused cfg * feat: move TOC to right sidebar * refactor: clean css * style: fix overflow + overflow margin * fix: use `resolveRelative` to resolve file paths * fix: `defaultFolderState` config option * refactor: rename import, rename `folderLi` + ul * fix: use `QuartzPluginData` type * docs: add explorer documentation
2023-09-15 18:39:16 +02:00
const isSvg = target.nodeName === "svg"
// corresponding <ul> element relative to clicked button/folder
const folderContainer = (
isSvg
? // svg -> div.folder-container
target.parentElement
: // button.folder-button -> div -> div.folder-container
target.parentElement?.parentElement
) as MaybeHTMLElement
if (!folderContainer) return
const childFolderContainer = folderContainer.nextElementSibling as MaybeHTMLElement
if (!childFolderContainer) return
childFolderContainer.classList.toggle("open")
// Collapse folder container
const isCollapsed = !childFolderContainer.classList.contains("open")
setFolderState(childFolderContainer, isCollapsed)
const currentFolderState = currentExplorerState.find(
(item) => item.path === folderContainer.dataset.folderpath,
)
if (currentFolderState) {
currentFolderState.collapsed = isCollapsed
} else {
currentExplorerState.push({
path: folderContainer.dataset.folderpath as FullSlug,
collapsed: isCollapsed,
})
}
const stringifiedFileTree = JSON.stringify(currentExplorerState)
feat: implement file explorer component (closes #201) (#452) * feat: add basic explorer structure„ * feat: integrate new component/plugin * feat: add basic explorer structure * feat: add sort to FileNodes * style: improve style for explorer * refactor: remove unused explorer plugin * refactor: clean explorer structure, fix base (toc) * refactor: clean css, respect displayClass * style: add styling to chevron * refactor: clean up debug statements * refactor: remove unused import * fix: clicking folder icon sometimes turns invisible * refactor: clean css * feat(explorer): add config for title * feat: add config for folder click behavior * fix: `no-pointer` not being set for all elements new approach, have one `no-pointer` class, that removes pointer events and one `clickable` class on the svg and button (everything that can normally be clicked). then, find all children with `clickable` and toggle `no-pointer` * fix: bug where nested folders got incorrect height this fixes the bug where nested folders weren't calculating their total height correctly. done by adding class to main container of all children and calculating total * feat: introduce `folderDefaultState` config * feat: store depth for explorer nodes * feat: implement option for collapsed state + bug fixes folderBehavior: "link" still has bad styling, but major bugs with pointers fixed (not clean yet, but working) * fix: default folder icon rotation * fix: hitbox problem with folder links, fix style * fix: redirect url for nested folders * fix: inconsistent behavior with 'collapseFolders' opt * chore: add comments to `ExplorerNode` * feat: save explorer state to local storage (not clean) * feat: rework `getFolders()`, fix localstorage read + write * feat: set folder state from localStorage needs serious refactoring but functional (except folder icon orientation) * fix: folder icon orientation after local storage * feat: add config for `useSavedState` * refactor: clean `explorer.inline.ts` remove unused functions, comments, unused code, add types to EventHandler * refactor: clean explorer merge `isSvg` paths, remove console logs * refactor: add documentation, remove unused funcs * feat: rework folder collapse logic use grids instead of jank scuffed solution with calculating total heights * refactor: remove depth arg from insert * feat: restore collapse functionality to clicks allow folder icon + folder label to collapse folders again * refactor: remove `pointer-event` jank * feat: improve svg viewbox + remove unused props * feat: use css selector to toggle icon rework folder icon to work purely with css instead of JS manipulation * refactor: remove unused cfg * feat: move TOC to right sidebar * refactor: clean css * style: fix overflow + overflow margin * fix: use `resolveRelative` to resolve file paths * fix: `defaultFolderState` config option * refactor: rename import, rename `folderLi` + ul * fix: use `QuartzPluginData` type * docs: add explorer documentation
2023-09-15 18:39:16 +02:00
localStorage.setItem("fileTree", stringifiedFileTree)
}
function createFileNode(currentSlug: FullSlug, node: FileTrieNode): HTMLLIElement {
const template = document.getElementById("template-file") as HTMLTemplateElement
const clone = template.content.cloneNode(true) as DocumentFragment
const li = clone.querySelector("li") as HTMLLIElement
const a = li.querySelector("a") as HTMLAnchorElement
a.href = resolveRelative(currentSlug, node.slug)
a.dataset.for = node.slug
a.textContent = node.displayName
if (currentSlug === node.slug) {
a.classList.add("active")
}
return li
}
function createFolderNode(
currentSlug: FullSlug,
node: FileTrieNode,
opts: ParsedOptions,
): HTMLLIElement {
const template = document.getElementById("template-folder") as HTMLTemplateElement
const clone = template.content.cloneNode(true) as DocumentFragment
const li = clone.querySelector("li") as HTMLLIElement
const folderContainer = li.querySelector(".folder-container") as HTMLElement
const titleContainer = folderContainer.querySelector("div") as HTMLElement
const folderOuter = li.querySelector(".folder-outer") as HTMLElement
const ul = folderOuter.querySelector("ul") as HTMLUListElement
const folderPath = node.slug
folderContainer.dataset.folderpath = folderPath
if (opts.folderClickBehavior === "link") {
// Replace button with link for link behavior
const button = titleContainer.querySelector(".folder-button") as HTMLElement
const a = document.createElement("a")
a.href = resolveRelative(currentSlug, folderPath)
a.dataset.for = folderPath
a.className = "folder-title"
a.textContent = node.displayName
button.replaceWith(a)
} else {
const span = titleContainer.querySelector(".folder-title") as HTMLElement
span.textContent = node.displayName
}
// if the saved state is collapsed or the default state is collapsed
const isCollapsed =
currentExplorerState.find((item) => item.path === folderPath)?.collapsed ??
opts.folderDefaultState === "collapsed"
// if this folder is a prefix of the current path we
// want to open it anyways
const simpleFolderPath = simplifySlug(folderPath)
const folderIsPrefixOfCurrentSlug =
simpleFolderPath === currentSlug.slice(0, simpleFolderPath.length)
if (!isCollapsed || folderIsPrefixOfCurrentSlug) {
folderOuter.classList.add("open")
}
for (const child of node.children) {
const childNode = child.isFolder
? createFolderNode(currentSlug, child, opts)
: createFileNode(currentSlug, child)
ul.appendChild(childNode)
}
return li
}
async function setupExplorer(currentSlug: FullSlug) {
2025-03-10 15:13:04 -07:00
const allExplorers = document.querySelectorAll("div.explorer") as NodeListOf<HTMLElement>
for (const explorer of allExplorers) {
const dataFns = JSON.parse(explorer.dataset.dataFns || "{}")
const opts: ParsedOptions = {
folderClickBehavior: (explorer.dataset.behavior || "collapse") as "collapse" | "link",
folderDefaultState: (explorer.dataset.collapsed || "collapsed") as "collapsed" | "open",
useSavedState: explorer.dataset.savestate === "true",
order: dataFns.order || ["filter", "map", "sort"],
sortFn: new Function("return " + (dataFns.sortFn || "undefined"))(),
filterFn: new Function("return " + (dataFns.filterFn || "undefined"))(),
mapFn: new Function("return " + (dataFns.mapFn || "undefined"))(),
}
// Get folder state from local storage
const storageTree = localStorage.getItem("fileTree")
const serializedExplorerState = storageTree && opts.useSavedState ? JSON.parse(storageTree) : []
const oldIndex = new Map<string, boolean>(
serializedExplorerState.map((entry: FolderState) => [entry.path, entry.collapsed]),
)
const data = await fetchData
const entries = [...Object.entries(data)] as [FullSlug, ContentDetails][]
const trie = FileTrieNode.fromEntries(entries)
// Apply functions in order
for (const fn of opts.order) {
switch (fn) {
case "filter":
if (opts.filterFn) trie.filter(opts.filterFn)
break
case "map":
if (opts.mapFn) trie.map(opts.mapFn)
break
case "sort":
if (opts.sortFn) trie.sort(opts.sortFn)
break
}
}
// Get folder paths for state management
const folderPaths = trie.getFolderPaths()
currentExplorerState = folderPaths.map((path) => {
const previousState = oldIndex.get(path)
return {
path,
collapsed:
previousState === undefined ? opts.folderDefaultState === "collapsed" : previousState,
}
})
feat: implement file explorer component (closes #201) (#452) * feat: add basic explorer structure„ * feat: integrate new component/plugin * feat: add basic explorer structure * feat: add sort to FileNodes * style: improve style for explorer * refactor: remove unused explorer plugin * refactor: clean explorer structure, fix base (toc) * refactor: clean css, respect displayClass * style: add styling to chevron * refactor: clean up debug statements * refactor: remove unused import * fix: clicking folder icon sometimes turns invisible * refactor: clean css * feat(explorer): add config for title * feat: add config for folder click behavior * fix: `no-pointer` not being set for all elements new approach, have one `no-pointer` class, that removes pointer events and one `clickable` class on the svg and button (everything that can normally be clicked). then, find all children with `clickable` and toggle `no-pointer` * fix: bug where nested folders got incorrect height this fixes the bug where nested folders weren't calculating their total height correctly. done by adding class to main container of all children and calculating total * feat: introduce `folderDefaultState` config * feat: store depth for explorer nodes * feat: implement option for collapsed state + bug fixes folderBehavior: "link" still has bad styling, but major bugs with pointers fixed (not clean yet, but working) * fix: default folder icon rotation * fix: hitbox problem with folder links, fix style * fix: redirect url for nested folders * fix: inconsistent behavior with 'collapseFolders' opt * chore: add comments to `ExplorerNode` * feat: save explorer state to local storage (not clean) * feat: rework `getFolders()`, fix localstorage read + write * feat: set folder state from localStorage needs serious refactoring but functional (except folder icon orientation) * fix: folder icon orientation after local storage * feat: add config for `useSavedState` * refactor: clean `explorer.inline.ts` remove unused functions, comments, unused code, add types to EventHandler * refactor: clean explorer merge `isSvg` paths, remove console logs * refactor: add documentation, remove unused funcs * feat: rework folder collapse logic use grids instead of jank scuffed solution with calculating total heights * refactor: remove depth arg from insert * feat: restore collapse functionality to clicks allow folder icon + folder label to collapse folders again * refactor: remove `pointer-event` jank * feat: improve svg viewbox + remove unused props * feat: use css selector to toggle icon rework folder icon to work purely with css instead of JS manipulation * refactor: remove unused cfg * feat: move TOC to right sidebar * refactor: clean css * style: fix overflow + overflow margin * fix: use `resolveRelative` to resolve file paths * fix: `defaultFolderState` config option * refactor: rename import, rename `folderLi` + ul * fix: use `QuartzPluginData` type * docs: add explorer documentation
2023-09-15 18:39:16 +02:00
2025-03-10 15:13:04 -07:00
const explorerUl = explorer.querySelector(".explorer-ul")
if (!explorerUl) continue
// Create and insert new content
const fragment = document.createDocumentFragment()
for (const child of trie.children) {
const node = child.isFolder
? createFolderNode(currentSlug, child, opts)
: createFileNode(currentSlug, child)
fragment.appendChild(node)
}
explorerUl.insertBefore(fragment, explorerUl.firstChild)
// restore explorer scrollTop position if it exists
const scrollTop = sessionStorage.getItem("explorerScrollTop")
if (scrollTop) {
explorerUl.scrollTop = parseInt(scrollTop)
} else {
// try to scroll to the active element if it exists
const activeElement = explorerUl.querySelector(".active")
if (activeElement) {
activeElement.scrollIntoView({ behavior: "smooth" })
}
}
feat: implement file explorer component (closes #201) (#452) * feat: add basic explorer structure„ * feat: integrate new component/plugin * feat: add basic explorer structure * feat: add sort to FileNodes * style: improve style for explorer * refactor: remove unused explorer plugin * refactor: clean explorer structure, fix base (toc) * refactor: clean css, respect displayClass * style: add styling to chevron * refactor: clean up debug statements * refactor: remove unused import * fix: clicking folder icon sometimes turns invisible * refactor: clean css * feat(explorer): add config for title * feat: add config for folder click behavior * fix: `no-pointer` not being set for all elements new approach, have one `no-pointer` class, that removes pointer events and one `clickable` class on the svg and button (everything that can normally be clicked). then, find all children with `clickable` and toggle `no-pointer` * fix: bug where nested folders got incorrect height this fixes the bug where nested folders weren't calculating their total height correctly. done by adding class to main container of all children and calculating total * feat: introduce `folderDefaultState` config * feat: store depth for explorer nodes * feat: implement option for collapsed state + bug fixes folderBehavior: "link" still has bad styling, but major bugs with pointers fixed (not clean yet, but working) * fix: default folder icon rotation * fix: hitbox problem with folder links, fix style * fix: redirect url for nested folders * fix: inconsistent behavior with 'collapseFolders' opt * chore: add comments to `ExplorerNode` * feat: save explorer state to local storage (not clean) * feat: rework `getFolders()`, fix localstorage read + write * feat: set folder state from localStorage needs serious refactoring but functional (except folder icon orientation) * fix: folder icon orientation after local storage * feat: add config for `useSavedState` * refactor: clean `explorer.inline.ts` remove unused functions, comments, unused code, add types to EventHandler * refactor: clean explorer merge `isSvg` paths, remove console logs * refactor: add documentation, remove unused funcs * feat: rework folder collapse logic use grids instead of jank scuffed solution with calculating total heights * refactor: remove depth arg from insert * feat: restore collapse functionality to clicks allow folder icon + folder label to collapse folders again * refactor: remove `pointer-event` jank * feat: improve svg viewbox + remove unused props * feat: use css selector to toggle icon rework folder icon to work purely with css instead of JS manipulation * refactor: remove unused cfg * feat: move TOC to right sidebar * refactor: clean css * style: fix overflow + overflow margin * fix: use `resolveRelative` to resolve file paths * fix: `defaultFolderState` config option * refactor: rename import, rename `folderLi` + ul * fix: use `QuartzPluginData` type * docs: add explorer documentation
2023-09-15 18:39:16 +02:00
// Set up event handlers
2025-03-10 15:13:04 -07:00
const explorerButtons = explorer.getElementsByClassName(
"explorer-toggle",
) as HTMLCollectionOf<HTMLElement>
for (const button of explorerButtons) {
button.addEventListener("click", toggleExplorer)
window.addCleanup(() => button.removeEventListener("click", toggleExplorer))
}
// Set up folder click handlers
if (opts.folderClickBehavior === "collapse") {
const folderButtons = explorer.getElementsByClassName(
"folder-button",
) as HTMLCollectionOf<HTMLElement>
for (const button of folderButtons) {
button.addEventListener("click", toggleFolder)
2025-03-10 15:13:04 -07:00
window.addCleanup(() => button.removeEventListener("click", toggleFolder))
}
}
const folderIcons = explorer.getElementsByClassName(
"folder-icon",
) as HTMLCollectionOf<HTMLElement>
for (const icon of folderIcons) {
icon.addEventListener("click", toggleFolder)
2025-03-10 15:13:04 -07:00
window.addCleanup(() => icon.removeEventListener("click", toggleFolder))
}
}
}
2025-03-10 15:13:04 -07:00
document.addEventListener("prenav", async () => {
// save explorer scrollTop position
2025-03-10 15:13:04 -07:00
const explorer = document.querySelector(".explorer-ul")
if (!explorer) return
sessionStorage.setItem("explorerScrollTop", explorer.scrollTop.toString())
})
document.addEventListener("nav", async (e: CustomEventMap["nav"]) => {
const currentSlug = e.detail.url
await setupExplorer(currentSlug)
// if mobile hamburger is visible, collapse by default
for (const explorer of document.getElementsByClassName("explorer")) {
const mobileExplorer = explorer.querySelector(".mobile-explorer")
if (!mobileExplorer) return
if (mobileExplorer.checkVisibility()) {
explorer.classList.add("collapsed")
explorer.setAttribute("aria-expanded", "false")
}
mobileExplorer.classList.remove("hide-until-loaded")
}
feat: implement file explorer component (closes #201) (#452) * feat: add basic explorer structure„ * feat: integrate new component/plugin * feat: add basic explorer structure * feat: add sort to FileNodes * style: improve style for explorer * refactor: remove unused explorer plugin * refactor: clean explorer structure, fix base (toc) * refactor: clean css, respect displayClass * style: add styling to chevron * refactor: clean up debug statements * refactor: remove unused import * fix: clicking folder icon sometimes turns invisible * refactor: clean css * feat(explorer): add config for title * feat: add config for folder click behavior * fix: `no-pointer` not being set for all elements new approach, have one `no-pointer` class, that removes pointer events and one `clickable` class on the svg and button (everything that can normally be clicked). then, find all children with `clickable` and toggle `no-pointer` * fix: bug where nested folders got incorrect height this fixes the bug where nested folders weren't calculating their total height correctly. done by adding class to main container of all children and calculating total * feat: introduce `folderDefaultState` config * feat: store depth for explorer nodes * feat: implement option for collapsed state + bug fixes folderBehavior: "link" still has bad styling, but major bugs with pointers fixed (not clean yet, but working) * fix: default folder icon rotation * fix: hitbox problem with folder links, fix style * fix: redirect url for nested folders * fix: inconsistent behavior with 'collapseFolders' opt * chore: add comments to `ExplorerNode` * feat: save explorer state to local storage (not clean) * feat: rework `getFolders()`, fix localstorage read + write * feat: set folder state from localStorage needs serious refactoring but functional (except folder icon orientation) * fix: folder icon orientation after local storage * feat: add config for `useSavedState` * refactor: clean `explorer.inline.ts` remove unused functions, comments, unused code, add types to EventHandler * refactor: clean explorer merge `isSvg` paths, remove console logs * refactor: add documentation, remove unused funcs * feat: rework folder collapse logic use grids instead of jank scuffed solution with calculating total heights * refactor: remove depth arg from insert * feat: restore collapse functionality to clicks allow folder icon + folder label to collapse folders again * refactor: remove `pointer-event` jank * feat: improve svg viewbox + remove unused props * feat: use css selector to toggle icon rework folder icon to work purely with css instead of JS manipulation * refactor: remove unused cfg * feat: move TOC to right sidebar * refactor: clean css * style: fix overflow + overflow margin * fix: use `resolveRelative` to resolve file paths * fix: `defaultFolderState` config option * refactor: rename import, rename `folderLi` + ul * fix: use `QuartzPluginData` type * docs: add explorer documentation
2023-09-15 18:39:16 +02:00
})
function setFolderState(folderElement: HTMLElement, collapsed: boolean) {
return collapsed ? folderElement.classList.remove("open") : folderElement.classList.add("open")
feat: implement file explorer component (closes #201) (#452) * feat: add basic explorer structure„ * feat: integrate new component/plugin * feat: add basic explorer structure * feat: add sort to FileNodes * style: improve style for explorer * refactor: remove unused explorer plugin * refactor: clean explorer structure, fix base (toc) * refactor: clean css, respect displayClass * style: add styling to chevron * refactor: clean up debug statements * refactor: remove unused import * fix: clicking folder icon sometimes turns invisible * refactor: clean css * feat(explorer): add config for title * feat: add config for folder click behavior * fix: `no-pointer` not being set for all elements new approach, have one `no-pointer` class, that removes pointer events and one `clickable` class on the svg and button (everything that can normally be clicked). then, find all children with `clickable` and toggle `no-pointer` * fix: bug where nested folders got incorrect height this fixes the bug where nested folders weren't calculating their total height correctly. done by adding class to main container of all children and calculating total * feat: introduce `folderDefaultState` config * feat: store depth for explorer nodes * feat: implement option for collapsed state + bug fixes folderBehavior: "link" still has bad styling, but major bugs with pointers fixed (not clean yet, but working) * fix: default folder icon rotation * fix: hitbox problem with folder links, fix style * fix: redirect url for nested folders * fix: inconsistent behavior with 'collapseFolders' opt * chore: add comments to `ExplorerNode` * feat: save explorer state to local storage (not clean) * feat: rework `getFolders()`, fix localstorage read + write * feat: set folder state from localStorage needs serious refactoring but functional (except folder icon orientation) * fix: folder icon orientation after local storage * feat: add config for `useSavedState` * refactor: clean `explorer.inline.ts` remove unused functions, comments, unused code, add types to EventHandler * refactor: clean explorer merge `isSvg` paths, remove console logs * refactor: add documentation, remove unused funcs * feat: rework folder collapse logic use grids instead of jank scuffed solution with calculating total heights * refactor: remove depth arg from insert * feat: restore collapse functionality to clicks allow folder icon + folder label to collapse folders again * refactor: remove `pointer-event` jank * feat: improve svg viewbox + remove unused props * feat: use css selector to toggle icon rework folder icon to work purely with css instead of JS manipulation * refactor: remove unused cfg * feat: move TOC to right sidebar * refactor: clean css * style: fix overflow + overflow margin * fix: use `resolveRelative` to resolve file paths * fix: `defaultFolderState` config option * refactor: rename import, rename `folderLi` + ul * fix: use `QuartzPluginData` type * docs: add explorer documentation
2023-09-15 18:39:16 +02:00
}