125 lines
3.3 KiB
TypeScript
125 lines
3.3 KiB
TypeScript
import { asset, Head } from "$fresh/runtime.ts";
|
|
import { useState } from "preact/hooks";
|
|
import { extname, join } from "path/posix.ts";
|
|
import { ComponentChild } from "preact";
|
|
import UpList from "./UpList.tsx";
|
|
import { extToIcon } from "../src/media.ts";
|
|
import natsort from "../src/natsort.ts";
|
|
import { encodePath } from "../util/util.ts";
|
|
|
|
function ListItem(props: {
|
|
href: string;
|
|
icon: string;
|
|
children: ComponentChild;
|
|
}) {
|
|
return (
|
|
<li class="p-1 hover:bg-gray-400 transition-colors">
|
|
<a class="flex gap-2" href={props.href}>
|
|
<div class="bg-black dark:bg-white w-4 h-4" style={`mask: url(${asset(props.icon)})`}></div>
|
|
<p class="">{props.children}</p>
|
|
</a>
|
|
</li>
|
|
);
|
|
}
|
|
|
|
export interface EntryInfo {
|
|
name: string;
|
|
isFile: boolean;
|
|
isDirectory: boolean;
|
|
isSymlink: boolean;
|
|
size: number;
|
|
lastModified?: Date;
|
|
}
|
|
|
|
interface DirListProps {
|
|
path: string;
|
|
files: EntryInfo[];
|
|
}
|
|
const natsortCompare = natsort();
|
|
|
|
function toSorted<T>(arr: T[], compareFn: (a:T,b:T) => number): T[]{
|
|
const ret = Array.from(arr);
|
|
ret.sort(compareFn);
|
|
return ret;
|
|
}
|
|
|
|
export function DirList(props: DirListProps) {
|
|
const data = props;
|
|
const [files, setFiles] = useState(
|
|
toSorted(data.files,(
|
|
(a,b)=> natsortCompare(a.name,b.name)
|
|
))
|
|
);
|
|
|
|
return (
|
|
<div>
|
|
<UpList path={data.path}></UpList>
|
|
<ul class="border-2 rounded-md">
|
|
<li class="p-1 flex gap-2">
|
|
<button class="flex" onClick={sortDir}>
|
|
<img src={asset("/icon/sort-down.svg")} /> Sort Directory
|
|
</button>
|
|
<button class="flex" onClick={sortAlpha}>
|
|
<img src={asset("/icon/sort-alpha-down.svg")} /> Sort Alphabet
|
|
</button>
|
|
</li>
|
|
<ListItem
|
|
key=".."
|
|
href={`/dir/${encodePath(join(data.path, ".."))}/?pretty`}
|
|
icon="/icon/back.svg"
|
|
>
|
|
...
|
|
</ListItem>
|
|
{files.map((file) => (
|
|
<ListItem
|
|
key={file.name}
|
|
href={`/dir/${
|
|
encodePath(join(data.path, file.name))
|
|
}${(file.isDirectory ? "/" : "")}?pretty`}
|
|
icon={file.isDirectory
|
|
? "/icon/folder.svg"
|
|
: extToIcon(extname(file.name))}
|
|
>
|
|
{file.name}
|
|
</ListItem>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
);
|
|
function sortDir() {
|
|
// sort by directory first then by index
|
|
const sorted_files = files.map((x, i) => ([x, i] as [EntryInfo, number]))
|
|
.sort(
|
|
([a, ai], [b, bi]) => {
|
|
if (a.isDirectory && !b.isDirectory) {
|
|
return -1;
|
|
} else if (!a.isDirectory && b.isDirectory) {
|
|
return 1;
|
|
} else {
|
|
return ai - bi;
|
|
}
|
|
},
|
|
);
|
|
setFiles(sorted_files.map(([x, _]) => x));
|
|
}
|
|
function sortAlpha() {
|
|
// sort by alphabet first then by index
|
|
const sorted_files = files.map((x, i) => ([x, i] as [EntryInfo, number]))
|
|
.sort(
|
|
([a, ai], [b, bi]) => {
|
|
const ret = natsortCompare(a.name, b.name);
|
|
if (ret === 0) {
|
|
return ai - bi;
|
|
} else {
|
|
return ret;
|
|
}
|
|
},
|
|
);
|
|
setFiles(sorted_files.map(([x, _]) => x));
|
|
}
|
|
}
|
|
|
|
export default function DirListIsland(props: DirListProps){
|
|
return <DirList {...props}/>
|
|
}
|