diff --git a/src/app/converter.tsx b/src/app/converter.tsx index 29788c3..cbb9e66 100644 --- a/src/app/converter.tsx +++ b/src/app/converter.tsx @@ -1,15 +1,25 @@ -import React, { useState } from "react"; +import { useState } from "react"; +import AppFileSelect from "@/components/libresplit/AppFileSelect"; +import { AppSplitPreview } from "@/components/libresplit/AppSplitPreview"; import init, { convert } from "@libresplit/libresplit-converter"; import wasmUrl from "@libresplit/libresplit-converter/libresplit_converter_bg.wasm?url"; export function Converter() { const [selectedFile, setSelectedFile] = useState(null); + const [fileText, setFileText] = useState(null); const [result, setResult] = useState(null); - const handleFileChange = (event: React.ChangeEvent) => { - const file = event.target.files?.[0] || null; + const handleSelectChange = async (files: File | File[] | null) => { + const file = Array.isArray(files) ? (files[0] ?? null) : files; setSelectedFile(file); + setResult(null); + setFileText(null); + + if (file) { + const text = await file.text(); + setFileText(text); + } }; const handleSubmit = async () => { @@ -20,11 +30,8 @@ export function Converter() { try { const text = await selectedFile.text(); - await init(wasmUrl); - const converted = convert(text); - setResult(converted); } catch (error) { console.error("Error processing file: ", error); @@ -36,7 +43,6 @@ export function Converter() { if (!result || !selectedFile) return; const fileName = selectedFile.name.replace(/\.[^/.]+$/, ".json"); - const blob = new Blob([result], { type: "application/json" }); const url = URL.createObjectURL(blob); @@ -44,47 +50,54 @@ export function Converter() { link.href = url; link.download = fileName; link.click(); - URL.revokeObjectURL(url); }; return ( -
-
-

- LibreSplit Converter -

-
- - +
+
+ +
+ +
+ + +
+ +
+
+ {fileText && ( +
+ LiveSplit: + +
+ )} + {result && ( +
+ + LibreSplit: + + +
+ )}
- {result && ( -
-

- Conversion successful! Click the button below to download your - LibreSplit file. -

- -
- )}
); diff --git a/src/components/libresplit/AppFileSelect.tsx b/src/components/libresplit/AppFileSelect.tsx new file mode 100644 index 0000000..4bdfe98 --- /dev/null +++ b/src/components/libresplit/AppFileSelect.tsx @@ -0,0 +1,76 @@ +import { useMemo, useRef } from "react"; + +import { Button } from "../ui/button"; +import { Input } from "../ui/input"; + +interface AppFileSelectProps { + label?: string; + value: File | File[] | null; + onChange: (files: File | File[] | null) => void; + multiple?: boolean; + filters?: { name: string; extensions: string[] }[]; +} + +export default function AppFileSelect({ + label = "Select file:", + value, + onChange, + multiple = false, + filters, +}: AppFileSelectProps) { + const inputRef = useRef(null); + + const display = useMemo(() => { + if (!value) return "No file chosen."; + if (Array.isArray(value)) { + return value.map((f) => f.name).join(", "); + } + return value.name; + }, [value]); + + const handlePick = () => { + inputRef.current?.click(); + }; + + const handleChange = (e: React.ChangeEvent) => { + const files = e.target.files; + if (!files || files.length === 0) { + onChange(null); + return; + } + + if (multiple) { + onChange(Array.from(files)); + } else { + onChange(files[0]); + } + }; + + const accept = filters + ? filters.flatMap((f) => f.extensions.map((ext) => `.${ext}`)).join(",") + : undefined; + + return ( +
+ {label} +
+ + +
+ +
+ ); +} diff --git a/src/components/libresplit/AppSplitPreview.tsx b/src/components/libresplit/AppSplitPreview.tsx new file mode 100644 index 0000000..f5dafcf --- /dev/null +++ b/src/components/libresplit/AppSplitPreview.tsx @@ -0,0 +1,17 @@ +interface AppSplitPreviewProps { + text: string; + className?: string; +} + +export function AppSplitPreview({ text, className }: AppSplitPreviewProps) { + return ( +