mirror of
https://github.com/misode/misode.github.io.git
synced 2026-04-24 15:47:08 +00:00
Projects (#192)
* Add file save UI and drafts project * Fix build * Create SearchList component as abstraction * Add project page and file tree view * Create Locale context * Create Theme context * Create Version context * Create Title context * Create Project context * Store current file in project context * Fix issues when renaming file and implement deleting * Style improvements * Make all project strings translatable * Fix z-index
This commit is contained in:
58
src/app/components/TreeView.tsx
Normal file
58
src/app/components/TreeView.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { useMemo, useState } from 'preact/hooks'
|
||||
import { Octicon } from '.'
|
||||
|
||||
const SEPARATOR = '/'
|
||||
|
||||
interface Props {
|
||||
entries: string[],
|
||||
onSelect: (entry: string) => unknown,
|
||||
indent?: number,
|
||||
}
|
||||
export function TreeView({ entries, onSelect, indent }: Props) {
|
||||
const roots = useMemo(() => {
|
||||
const groups: Record<string, string[]> = {}
|
||||
for (const entry of entries) {
|
||||
const i = entry.indexOf(SEPARATOR)
|
||||
if (i >= 0) {
|
||||
const root = entry.slice(0, i)
|
||||
;(groups[root] ??= []).push(entry.slice(i + 1))
|
||||
}
|
||||
}
|
||||
return Object.entries(groups)
|
||||
}, entries)
|
||||
|
||||
const leaves = useMemo(() => {
|
||||
return entries.filter(e => !e.includes(SEPARATOR))
|
||||
}, entries)
|
||||
|
||||
const [hidden, setHidden] = useState(new Set<string>())
|
||||
const toggle = (root: string) => {
|
||||
if (hidden.has(root)) {
|
||||
hidden.delete(root)
|
||||
} else {
|
||||
hidden.add(root)
|
||||
}
|
||||
setHidden(new Set(hidden))
|
||||
}
|
||||
|
||||
return <div class="tree-view" style={`--indent: ${indent ?? 0};`}>
|
||||
{roots.map(([r, entries]) => <div>
|
||||
<TreeViewEntry icon={hidden.has(r) ? 'chevron_right' : 'chevron_down'} key={r} label={r} onClick={() => toggle(r)}/>
|
||||
{!hidden.has(r) &&
|
||||
<TreeView entries={entries} onSelect={e => onSelect(`${r}/${e}`)} indent={(indent ?? 0) + 1} />}
|
||||
</div>)}
|
||||
{leaves.map(e => <TreeViewEntry icon="file" key={e} label={e} onClick={() => onSelect(e)} />)}
|
||||
</div>
|
||||
}
|
||||
|
||||
interface TreeViewEntryProps {
|
||||
icon: keyof typeof Octicon,
|
||||
label: string,
|
||||
onClick?: () => unknown,
|
||||
}
|
||||
function TreeViewEntry({ icon, label, onClick }: TreeViewEntryProps) {
|
||||
return <div class="entry" onClick={onClick} >
|
||||
{Octicon[icon]}
|
||||
{label}
|
||||
</div>
|
||||
}
|
||||
Reference in New Issue
Block a user