2025-03-09 14:58:26 -07:00
|
|
|
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
|
|
|
|
2024-01-29 00:56:12 -08:00
|
|
|
type MaybeHTMLElement = HTMLElement | undefined
|
2023-09-17 22:04:44 +02:00
|
|
|
|
2025-03-09 14:58:26 -07:00
|
|
|
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"[]
|
|
|
|
}
|
2025-02-03 15:25:42 +01:00
|
|
|
|
2025-03-09 14:58:26 -07:00
|
|
|
type FolderState = {
|
|
|
|
path: string
|
|
|
|
collapsed: boolean
|
|
|
|
}
|
2024-01-29 00:56:12 -08:00
|
|
|
|
2025-03-09 14:58:26 -07:00
|
|
|
let currentExplorerState: Array<FolderState>
|
|
|
|
function toggleExplorer(this: HTMLElement) {
|
|
|
|
const explorers = document.querySelectorAll(".explorer")
|
|
|
|
for (const explorer of explorers) {
|
|
|
|
explorer.classList.toggle("collapsed")
|
|
|
|
explorer.setAttribute(
|
|
|
|
"aria-expanded",
|
|
|
|
explorer.getAttribute("aria-expanded") === "true" ? "false" : "true",
|
|
|
|
)
|
2025-02-03 15:25:42 +01:00
|
|
|
}
|
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()
|
2024-01-29 00:56:12 -08:00
|
|
|
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
|
|
|
|
2025-02-03 15:25:42 +01: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"
|
2025-02-03 15:25:42 +01:00
|
|
|
|
|
|
|
// corresponding <ul> element relative to clicked button/folder
|
2025-03-09 14:58:26 -07:00
|
|
|
const folderContainer = (
|
2024-01-29 00:56:12 -08:00
|
|
|
isSvg
|
2025-03-09 14:58:26 -07:00
|
|
|
? // svg -> div.folder-container
|
|
|
|
target.parentElement
|
|
|
|
: // button.folder-button -> div -> div.folder-container
|
|
|
|
target.parentElement?.parentElement
|
2024-01-29 00:56:12 -08:00
|
|
|
) as MaybeHTMLElement
|
2025-03-09 14:58:26 -07:00
|
|
|
if (!folderContainer) return
|
|
|
|
const childFolderContainer = folderContainer.nextElementSibling as MaybeHTMLElement
|
|
|
|
if (!childFolderContainer) return
|
|
|
|
|
2024-01-29 00:56:12 -08:00
|
|
|
childFolderContainer.classList.toggle("open")
|
2025-02-03 15:25:42 +01:00
|
|
|
|
|
|
|
// Collapse folder container
|
2025-03-09 14:58:26 -07:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
2025-02-03 15:25:42 +01:00
|
|
|
|
2024-01-29 00:56:12 -08:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2025-03-09 14:58:26 -07:00
|
|
|
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.data?.slug!)
|
|
|
|
a.dataset.for = node.data?.slug
|
|
|
|
a.textContent = node.displayName
|
|
|
|
|
|
|
|
if (currentSlug === node.data?.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.data?.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 = node.data?.slug
|
|
|
|
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.data
|
|
|
|
? createFileNode(currentSlug, child)
|
|
|
|
: createFolderNode(currentSlug, child, opts)
|
|
|
|
ul.appendChild(childNode)
|
|
|
|
}
|
|
|
|
|
|
|
|
return li
|
|
|
|
}
|
|
|
|
|
|
|
|
async function setupExplorer(currentSlug: FullSlug) {
|
|
|
|
const allExplorers = document.querySelectorAll(".explorer") as NodeListOf<HTMLElement>
|
2025-02-03 15:25:42 +01:00
|
|
|
|
|
|
|
for (const explorer of allExplorers) {
|
2025-03-09 14:58:26 -07:00
|
|
|
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"))(),
|
|
|
|
}
|
|
|
|
|
2025-02-03 15:25:42 +01:00
|
|
|
// Get folder state from local storage
|
|
|
|
const storageTree = localStorage.getItem("fileTree")
|
2025-03-09 14:58:26 -07:00
|
|
|
const serializedExplorerState = storageTree && opts.useSavedState ? JSON.parse(storageTree) : []
|
|
|
|
const oldIndex = new Map(
|
|
|
|
serializedExplorerState.map((entry: FolderState) => [entry.path, entry.collapsed]),
|
|
|
|
)
|
2025-02-03 15:25:42 +01:00
|
|
|
|
2025-03-09 14:58:26 -07:00
|
|
|
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
|
2025-02-03 15:25:42 +01:00
|
|
|
}
|
|
|
|
}
|
2024-01-29 00:56:12 -08:00
|
|
|
|
2025-03-09 14:58:26 -07:00
|
|
|
// Get folder paths for state management
|
|
|
|
const folderPaths = trie.getFolderPaths()
|
|
|
|
currentExplorerState = folderPaths.map((path) => ({
|
|
|
|
path,
|
|
|
|
collapsed: oldIndex.get(path) === 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
|
|
|
|
2025-03-09 14:58:26 -07:00
|
|
|
const explorerUl = document.getElementById("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)
|
2025-02-03 15:25:42 +01:00
|
|
|
}
|
2025-03-09 14:58:26 -07:00
|
|
|
explorerUl.insertBefore(fragment, explorerUl.firstChild)
|
2024-01-29 00:56:12 -08:00
|
|
|
|
2025-03-09 14:58:26 -07:00
|
|
|
// 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" })
|
2025-02-03 15:25:42 +01:00
|
|
|
}
|
2025-03-09 14:58:26 -07:00
|
|
|
}
|
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-09 14:58:26 -07:00
|
|
|
// Set up event handlers
|
|
|
|
const explorerButtons = explorer.querySelectorAll(
|
|
|
|
"button.explorer-toggle",
|
|
|
|
) as NodeListOf<HTMLElement>
|
|
|
|
if (explorerButtons) {
|
|
|
|
window.addCleanup(() =>
|
|
|
|
explorerButtons.forEach((button) => button.removeEventListener("click", toggleExplorer)),
|
|
|
|
)
|
|
|
|
explorerButtons.forEach((button) => button.addEventListener("click", toggleExplorer))
|
|
|
|
}
|
2024-01-29 00:56:12 -08:00
|
|
|
|
2025-03-09 14:58:26 -07:00
|
|
|
// Set up folder click handlers
|
|
|
|
if (opts.folderClickBehavior === "collapse") {
|
|
|
|
const folderButtons = explorer.getElementsByClassName(
|
|
|
|
"folder-button",
|
|
|
|
) as HTMLCollectionOf<HTMLElement>
|
|
|
|
for (const button of folderButtons) {
|
|
|
|
window.addCleanup(() => button.removeEventListener("click", toggleFolder))
|
|
|
|
button.addEventListener("click", toggleFolder)
|
2025-02-03 15:25:42 +01:00
|
|
|
}
|
2024-01-29 00:56:12 -08:00
|
|
|
}
|
2025-02-03 15:25:42 +01:00
|
|
|
|
2025-03-09 14:58:26 -07:00
|
|
|
const folderIcons = explorer.getElementsByClassName(
|
|
|
|
"folder-icon",
|
|
|
|
) as HTMLCollectionOf<HTMLElement>
|
|
|
|
for (const icon of folderIcons) {
|
|
|
|
window.addCleanup(() => icon.removeEventListener("click", toggleFolder))
|
|
|
|
icon.addEventListener("click", toggleFolder)
|
2025-02-03 15:25:42 +01:00
|
|
|
}
|
|
|
|
}
|
2025-03-09 14:58:26 -07:00
|
|
|
}
|
2025-02-03 15:25:42 +01:00
|
|
|
|
2025-03-09 14:58:26 -07:00
|
|
|
document.addEventListener("prenav", async (e: CustomEventMap["prenav"]) => {
|
|
|
|
// save explorer scrollTop position
|
|
|
|
const explorer = document.getElementById("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)
|
2023-11-17 10:29:07 -08:00
|
|
|
|
2025-03-09 14:58:26 -07:00
|
|
|
// if mobile hamburger is visible, collapse by default
|
|
|
|
const mobileExplorer = document.getElementById("mobile-explorer")
|
|
|
|
if (mobileExplorer && mobileExplorer.checkVisibility()) {
|
|
|
|
for (const explorer of document.querySelectorAll(".explorer")) {
|
|
|
|
explorer.classList.add("collapsed")
|
|
|
|
explorer.setAttribute("aria-expanded", "false")
|
|
|
|
}
|
2023-11-17 10:29:07 -08:00
|
|
|
}
|
2025-02-03 15:25:42 +01:00
|
|
|
|
|
|
|
const hiddenUntilDoneLoading = document.querySelector("#mobile-explorer")
|
|
|
|
hiddenUntilDoneLoading?.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) {
|
2024-01-29 00:56:12 -08:00
|
|
|
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
|
|
|
}
|