diff --git a/islands/DirList.tsx b/islands/DirList.tsx
index 7e8fc5c..40af353 100644
--- a/islands/DirList.tsx
+++ b/islands/DirList.tsx
@@ -4,6 +4,7 @@ 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: {
@@ -34,10 +35,15 @@ interface DirListProps {
path: string;
files: EntryInfo[];
}
+const natsortCompare = natsort();
export function DirList(props: DirListProps) {
const data = props;
- const [files, setFiles] = useState(data.files);
+ const [files, setFiles] = useState(
+ data.files.toSorted(
+ (a,b)=> natsortCompare(a.name,b.name)
+ )
+ );
return (
@@ -95,7 +101,7 @@ export function DirList(props: DirListProps) {
const sorted_files = files.map((x, i) => ([x, i] as [EntryInfo, number]))
.sort(
([a, ai], [b, bi]) => {
- const ret = a.name.localeCompare(b.name);
+ const ret = natsortCompare(a.name, b.name);
if (ret === 0) {
return ai - bi;
} else {
@@ -107,4 +113,6 @@ export function DirList(props: DirListProps) {
}
}
-export default DirList;
+export default function DirListIsland(props: DirListProps){
+ return
+}
diff --git a/src/natsort.ts b/src/natsort.ts
new file mode 100644
index 0000000..eef07fb
--- /dev/null
+++ b/src/natsort.ts
@@ -0,0 +1,174 @@
+/**
+The MIT License (MIT)
+
+Copyright (c) 2016 W.Y.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+export type OptionsType = {
+ /*
+ * Desc sorting.
+ */
+ desc?: boolean,
+ /*
+ * Case-Insensitive sorting.
+ */
+ insensitive?: boolean,
+}
+
+export default function natsort(options: OptionsType = {}) {
+
+ const ore = /^0/
+ const sre = /\s+/g
+ const tre = /^\s+|\s+$/g
+ // unicode
+ const ure = /[^\x00-\x80]/
+ // hex
+ const hre = /^0x[0-9a-f]+$/i
+ // numeric
+ const nre = /(0x[\da-fA-F]+|(^[\+\-]?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?(?=\D|\s|$))|\d+)/g
+ // datetime
+ const dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/ // tslint:disable-line
+ const toLowerCase = String.prototype.toLocaleLowerCase || String.prototype.toLowerCase
+
+ const GREATER = options.desc ? -1 : 1
+ const SMALLER = -GREATER
+ const normalize = options.insensitive
+ ? (s: string | number) => toLowerCase.call(`${s}`).replace(tre, '')
+ : (s: string | number) => (`${s}`).replace(tre, '')
+
+ function tokenize(s: string): string[] {
+ return s.replace(nre, '\0$1\0')
+ .replace(/\0$/, '')
+ .replace(/^\0/, '')
+ .split('\0')
+ }
+
+ function parse(s: string, l: number) {
+ // normalize spaces; find floats not starting with '0',
+ // string or 0 if not defined (Clint Priest)
+ return (!s.match(ore) || l === 1)
+ && parseFloat(s)
+ || s.replace(sre, ' ').replace(tre, '')
+ || 0
+ }
+
+ return function (
+ a: string | number,
+ b: string | number,
+ ): number {
+
+ // trim pre-post whitespace
+ const aa = normalize(a)
+ const bb = normalize(b)
+
+ // return immediately if at least one of the values is empty.
+ // empty string < any others
+ if (!aa && !bb) {
+ return 0
+ }
+
+ if (!aa && bb) {
+ return SMALLER
+ }
+
+ if (aa && !bb) {
+ return GREATER
+ }
+
+ // tokenize: split numeric strings and default strings
+ const aArr = tokenize(aa)
+ const bArr = tokenize(bb)
+
+ // hex or date detection
+ const aHex = aa.match(hre)
+ const bHex = bb.match(hre)
+ const av = (aHex && bHex) ? parseInt(aHex[0], 16) : (aArr.length !== 1 && Date.parse(aa))
+ const bv = (aHex && bHex)
+ ? parseInt(bHex[0], 16)
+ : av && bb.match(dre) && Date.parse(bb) || null
+
+ // try and sort Hex codes or Dates
+ if (bv) {
+ if (av === bv) {
+ return 0
+ }
+
+ if (av < bv) {
+ return SMALLER
+ }
+
+ if (av > bv) {
+ return GREATER
+ }
+ }
+
+ const al = aArr.length
+ const bl = bArr.length
+
+ // handle numeric strings and default strings
+ for (let i = 0, l = Math.max(al, bl); i < l; i += 1) {
+
+ const af = parse(aArr[i] || '', al)
+ const bf = parse(bArr[i] || '', bl)
+
+ // handle numeric vs string comparison.
+ // numeric < string
+ if (isNaN(af as number) !== isNaN(bf as number)) {
+ return isNaN(af as number) ? GREATER : SMALLER
+ }
+
+ // if unicode use locale comparison
+ if (ure.test((af as string) + (bf as string)) && (af as string).localeCompare) {
+ const comp = (af as string).localeCompare(bf as string)
+
+ if (comp > 0) {
+ return GREATER
+ }
+
+ if (comp < 0) {
+ return SMALLER
+ }
+
+ if (i === l - 1) {
+ return 0
+ }
+ }
+
+ if (af < bf) {
+ return SMALLER
+ }
+
+ if (af > bf) {
+ return GREATER
+ }
+
+ if (`${af}` < `${bf}`) {
+ return SMALLER
+ }
+
+ if (`${af}` > `${bf}`) {
+ return GREATER
+ }
+ }
+
+ return 0
+ }
+}
\ No newline at end of file