The Trans Directory
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs(explorer): update to account for new client side explorer)

+47 -146
+47 -146
docs/features/explorer.md
··· 27 27 folderClickBehavior: "collapse", // what happens when you click a folder ("link" to navigate to folder page on click or "collapse" to collapse folder on click) 28 28 folderDefaultState: "collapsed", // default state of folders ("collapsed" or "open") 29 29 useSavedState: true, // whether to use local storage to save "state" (which folders are opened) of explorer 30 - // Sort order: folders first, then files. Sort folders and files alphabetically 31 - sortFn: (a, b) => { 32 - ... // default implementation shown later 33 - }, 34 - filterFn: filterFn: (node) => node.name !== "tags", // filters out 'tags' folder 35 - mapFn: undefined, 30 + // omitted but shown later 31 + sortFn: ..., 32 + filterFn: ..., 33 + mapFn: ..., 36 34 // what order to apply functions in 37 35 order: ["filter", "map", "sort"], 38 36 }) ··· 54 52 ## Advanced customization 55 53 56 54 This component allows you to fully customize all of its behavior. You can pass a custom `sort`, `filter` and `map` function. 57 - All functions you can pass work with the `FileNode` class, which has the following properties: 55 + All functions you can pass work with the `FileTrieNode` class, which has the following properties: 58 56 59 - ```ts title="quartz/components/ExplorerNode.tsx" {2-5} 60 - export class FileNode { 61 - children: FileNode[] // children of current node 62 - name: string // last part of slug 63 - displayName: string // what actually should be displayed in the explorer 64 - file: QuartzPluginData | null // if node is a file, this is the file's metadata. See `QuartzPluginData` for more detail 65 - depth: number // depth of current node 57 + ```ts title="quartz/components/Explorer.tsx" 58 + class FileTrieNode { 59 + isFolder: boolean 60 + children: Array<FileTrieNode> 61 + data: ContentDetails | null 62 + } 63 + ``` 66 64 67 - ... // rest of implementation 65 + ```ts title="quartz/plugins/emitters/contentIndex.tsx" 66 + export type ContentDetails = { 67 + slug: FullSlug 68 + title: string 69 + links: SimpleSlug[] 70 + tags: string[] 71 + content: string 68 72 } 69 73 ``` 70 74 ··· 74 78 // Sort order: folders first, then files. Sort folders and files alphabetically 75 79 Component.Explorer({ 76 80 sortFn: (a, b) => { 77 - if ((!a.file && !b.file) || (a.file && b.file)) { 78 - // sensitivity: "base": Only strings that differ in base letters compare as unequal. Examples: a โ‰  b, a = รก, a = A 79 - // numeric: true: Whether numeric collation should be used, such that "1" < "2" < "10" 81 + if ((!a.isFolder && !b.isFolder) || (a.isFolder && b.isFolder)) { 80 82 return a.displayName.localeCompare(b.displayName, undefined, { 81 83 numeric: true, 82 84 sensitivity: "base", 83 85 }) 84 86 } 85 - if (a.file && !b.file) { 87 + 88 + if (!a.isFolder && b.isFolder) { 86 89 return 1 87 90 } else { 88 91 return -1 ··· 100 103 Type definitions look like this: 101 104 102 105 ```ts 103 - sortFn: (a: FileNode, b: FileNode) => number 104 - filterFn: (node: FileNode) => boolean 105 - mapFn: (node: FileNode) => void 106 + type SortFn = (a: FileTrieNode, b: FileTrieNode) => number 107 + type FilterFn = (node: FileTrieNode) => boolean 108 + type MapFn = (node: FileTrieNode) => void 106 109 ``` 107 110 108 - > [!tip] 109 - > You can check if a `FileNode` is a folder or a file like this: 110 - > 111 - > ```ts 112 - > if (node.file) { 113 - > // node is a file 114 - > } else { 115 - > // node is a folder 116 - > } 117 - > ``` 118 - 119 111 ## Basic examples 120 112 121 113 These examples show the basic usage of `sort`, `map` and `filter`. 122 114 123 115 ### Use `sort` to put files first 124 116 125 - Using this example, the explorer will alphabetically sort everything, but put all **files** above all **folders**. 117 + Using this example, the explorer will alphabetically sort everything. 126 118 127 119 ```ts title="quartz.layout.ts" 128 120 Component.Explorer({ 129 121 sortFn: (a, b) => { 130 - if ((!a.file && !b.file) || (a.file && b.file)) { 131 - return a.displayName.localeCompare(b.displayName) 132 - } 133 - if (a.file && !b.file) { 134 - return -1 135 - } else { 136 - return 1 137 - } 122 + return a.displayName.localeCompare(b.displayName) 138 123 }, 139 124 }) 140 125 ``` ··· 146 131 ```ts title="quartz.layout.ts" 147 132 Component.Explorer({ 148 133 mapFn: (node) => { 149 - node.displayName = node.displayName.toUpperCase() 134 + return (node.displayName = node.displayName.toUpperCase()) 150 135 }, 151 136 }) 152 137 ``` 153 138 154 139 ### Remove list of elements (`filter`) 155 140 156 - Using this example, you can remove elements from your explorer by providing an array of folders/files using the `omit` set. 141 + Using this example, you can remove elements from your explorer by providing an array of folders/files to exclude. 142 + Note that this example filters on the title but you can also do it via slug or any other field available on `FileTrieNode`. 157 143 158 144 ```ts title="quartz.layout.ts" 159 145 Component.Explorer({ 160 146 filterFn: (node) => { 161 147 // set containing names of everything you want to filter out 162 148 const omit = new Set(["authoring content", "tags", "hosting"]) 163 - return !omit.has(node.name.toLowerCase()) 149 + return !omit.has(node.data.title.toLowerCase()) 164 150 }, 165 151 }) 166 152 ``` 167 153 168 - You can customize this by changing the entries of the `omit` set. Simply add all folder or file names you want to remove. 169 - 170 154 ### Remove files by tag 171 155 172 - You can access the frontmatter of a file by `node.file?.frontmatter?`. This allows you to filter out files based on their frontmatter, for example by their tags. 156 + You can access the tags of a file by `node.data.tags`. 173 157 174 158 ```ts title="quartz.layout.ts" 175 159 Component.Explorer({ 176 160 filterFn: (node) => { 177 161 // exclude files with the tag "explorerexclude" 178 - return node.file?.frontmatter?.tags?.includes("explorerexclude") !== true 162 + return node.data.tags.includes("explorerexclude") !== true 179 163 }, 180 164 }) 181 165 ``` 182 166 183 167 ### Show every element in explorer 184 168 185 - To override the default filter function that removes the `tags` folder from the explorer, you can set the filter function to `undefined`. 169 + By default, the explorer will filter out the `tags` folder. 170 + To override the default filter function, you can set the filter function to `undefined`. 186 171 187 172 ```ts title="quartz.layout.ts" 188 173 Component.Explorer({ ··· 194 179 195 180 > [!tip] 196 181 > When writing more complicated functions, the `layout` file can start to look very cramped. 197 - > You can fix this by defining your functions in another file. 182 + > You can fix this by defining your sort functions outside of the component 183 + > and passing it in. 198 184 > 199 - > ```ts title="functions.ts" 185 + > ```ts title="quartz.layout.ts" 200 186 > import { Options } from "./quartz/components/ExplorerNode" 187 + > 201 188 > export const mapFn: Options["mapFn"] = (node) => { 202 189 > // implement your function here 203 190 > } ··· 207 194 > export const sortFn: Options["sortFn"] = (a, b) => { 208 195 > // implement your function here 209 196 > } 210 - > ``` 211 - > 212 - > You can then import them like this: 213 197 > 214 - > ```ts title="quartz.layout.ts" 215 - > import { mapFn, filterFn, sortFn } from "./functions.ts" 216 198 > Component.Explorer({ 217 - > mapFn: mapFn, 218 - > filterFn: filterFn, 219 - > sortFn: sortFn, 199 + > // ... your other options 200 + > mapFn, 201 + > filterFn, 202 + > sortFn, 220 203 > }) 221 204 > ``` 222 205 ··· 227 210 ```ts title="quartz.layout.ts" 228 211 Component.Explorer({ 229 212 mapFn: (node) => { 230 - // dont change name of root node 231 - if (node.depth > 0) { 232 - // set emoji for file/folder 233 - if (node.file) { 234 - node.displayName = "๐Ÿ“„ " + node.displayName 235 - } else { 236 - node.displayName = "๐Ÿ“ " + node.displayName 237 - } 238 - } 239 - }, 240 - }) 241 - ``` 242 - 243 - ### Putting it all together 244 - 245 - In this example, we're going to customize the explorer by using functions from examples above to [[#Add emoji prefix | add emoji prefixes]], [[#remove-list-of-elements-filter| filter out some folders]] and [[#use-sort-to-put-files-first | sort with files above folders]]. 246 - 247 - ```ts title="quartz.layout.ts" 248 - Component.Explorer({ 249 - filterFn: sampleFilterFn, 250 - mapFn: sampleMapFn, 251 - sortFn: sampleSortFn, 252 - order: ["filter", "sort", "map"], 253 - }) 254 - ``` 255 - 256 - Notice how we customized the `order` array here. This is done because the default order applies the `sort` function last. While this normally works well, it would cause unintended behavior here, since we changed the first characters of all display names. In our example, `sort` would be applied based off the emoji prefix instead of the first _real_ character. 257 - 258 - To fix this, we just changed around the order and apply the `sort` function before changing the display names in the `map` function. 259 - 260 - ### Use `sort` with pre-defined sort order 261 - 262 - Here's another example where a map containing file/folder names (as slugs) is used to define the sort order of the explorer in quartz. All files/folders that aren't listed inside of `nameOrderMap` will appear at the top of that folders hierarchy level. 263 - 264 - It's also worth mentioning, that the smaller the number set in `nameOrderMap`, the higher up the entry will be in the explorer. Incrementing every folder/file by 100, makes ordering files in their folders a lot easier. Lastly, this example still allows you to use a `mapFn` or frontmatter titles to change display names, as it uses slugs for `nameOrderMap` (which is unaffected by display name changes). 265 - 266 - ```ts title="quartz.layout.ts" 267 - Component.Explorer({ 268 - sortFn: (a, b) => { 269 - const nameOrderMap: Record<string, number> = { 270 - "poetry-folder": 100, 271 - "essay-folder": 200, 272 - "research-paper-file": 201, 273 - "dinosaur-fossils-file": 300, 274 - "other-folder": 400, 275 - } 276 - 277 - let orderA = 0 278 - let orderB = 0 279 - 280 - if (a.file && a.file.slug) { 281 - orderA = nameOrderMap[a.file.slug] || 0 282 - } else if (a.name) { 283 - orderA = nameOrderMap[a.name] || 0 284 - } 285 - 286 - if (b.file && b.file.slug) { 287 - orderB = nameOrderMap[b.file.slug] || 0 288 - } else if (b.name) { 289 - orderB = nameOrderMap[b.name] || 0 213 + if (node.isFolder) { 214 + node.displayName = "๐Ÿ“ " + node.displayName 215 + } else { 216 + node.displayName = "๐Ÿ“„ " + node.displayName 290 217 } 291 - 292 - return orderA - orderB 293 218 }, 294 219 }) 295 220 ``` 296 - 297 - For reference, this is how the quartz explorer window would look like with that example: 298 - 299 - ``` 300 - ๐Ÿ“– Poetry Folder 301 - ๐Ÿ“‘ Essay Folder 302 - โš—๏ธ Research Paper File 303 - ๐Ÿฆด Dinosaur Fossils File 304 - ๐Ÿ”ฎ Other Folder 305 - ``` 306 - 307 - And this is how the file structure would look like: 308 - 309 - ``` 310 - index.md 311 - poetry-folder 312 - index.md 313 - essay-folder 314 - index.md 315 - research-paper-file.md 316 - dinosaur-fossils-file.md 317 - other-folder 318 - index.md 319 - ```