Skip to content

Commit ac9db05

Browse files
committed
Create file selector
1 parent a41e1ba commit ac9db05

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

src/app/converter.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, { useState } from "react";
22

3+
import AppFileSelect from "@/components/libresplit/AppFileSelect";
34
import init, { convert } from "@libresplit/libresplit-converter";
45
import wasmUrl from "@libresplit/libresplit-converter/libresplit_converter_bg.wasm?url";
56

@@ -50,7 +51,7 @@ export function Converter() {
5051

5152
return (
5253
<div>
53-
<p>Placeholder</p>
54+
<AppFileSelect />
5455
</div>
5556
);
5657
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { useMemo, useRef } from "react";
2+
3+
import { Button } from "../ui/button";
4+
import { Input } from "../ui/input";
5+
6+
interface AppFileSelectProps {
7+
label?: string;
8+
value: File | File[] | null;
9+
onChange: (files: File | File[] | null) => void;
10+
multiple?: boolean;
11+
filters?: { name: string; extensions: string[] }[];
12+
}
13+
14+
export default function AppFileSelect({
15+
label = "Select file:",
16+
value,
17+
onChange,
18+
multiple = false,
19+
filters,
20+
}: AppFileSelectProps) {
21+
const inputRef = useRef<HTMLInputElement | null>(null);
22+
23+
const display = useMemo(() => {
24+
if (!value) return "No file chosen.";
25+
if (Array.isArray(value)) {
26+
return value.map((f) => f.name).join(", ");
27+
}
28+
return value.name;
29+
}, [value]);
30+
31+
const handlePick = () => {
32+
inputRef.current?.click();
33+
};
34+
35+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
36+
const files = e.target.files;
37+
if (!files || files.length === 0) {
38+
onChange(null);
39+
return;
40+
}
41+
42+
if (multiple) {
43+
onChange(Array.from(files));
44+
} else {
45+
onChange(files[0]);
46+
}
47+
};
48+
49+
const accept = filters
50+
? filters.flatMap((f) => f.extensions.map((ext) => `.${ext}`)).join(",")
51+
: undefined;
52+
53+
return (
54+
<div className="space-y-2 px-8">
55+
<span className="text-white">{label}</span>
56+
<div className="flex items-center">
57+
<Input className="flex-1 rounded-r-none" value={display} readOnly />
58+
<Button
59+
type="button"
60+
onClick={handlePick}
61+
className="rounded-l-none bg-gray-200 text-black hover:bg-blue-200"
62+
>
63+
Open
64+
</Button>
65+
</div>
66+
<input
67+
ref={inputRef}
68+
type="file"
69+
className="hidden"
70+
multiple={multiple}
71+
accept={accept}
72+
onChange={handleChange}
73+
/>
74+
</div>
75+
);
76+
}

0 commit comments

Comments
 (0)