181 lines
6.0 KiB
TypeScript
181 lines
6.0 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useRef } from "react";
|
|
import { useDoomOverlay } from "@/app/providers/DoomOverlayProvider";
|
|
import { Modal } from "@/app/components/overlay/Modal";
|
|
import { JsDosPlayer } from "./JsDosPlayer";
|
|
|
|
export enum DoomEngine {
|
|
JsDos = "js-dos",
|
|
}
|
|
|
|
export type DoomConfig = {
|
|
engine: DoomEngine;
|
|
jsdos?: { zipUrl?: string };
|
|
};
|
|
|
|
export function DoomOverlay() {
|
|
const { isOpen, close } = useDoomOverlay();
|
|
const [selectedZipUrl, setSelectedZipUrl] = useState<string | null>(null);
|
|
const [loadError, setLoadError] = useState<string | null>(null);
|
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
|
|
const remoteDemoUrl = "https://v8.js-dos.com/v7/build/doom.jsdos";
|
|
|
|
const handleRemoteLoad = async () => {
|
|
try {
|
|
setLoadError(null);
|
|
setSelectedZipUrl(remoteDemoUrl);
|
|
} catch (error) {
|
|
console.error("Failed to load remote demo:", error);
|
|
setLoadError("Failed to load remote demo. Please try selecting a local file.");
|
|
}
|
|
};
|
|
|
|
const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
const file = event.target.files?.[0];
|
|
if (file && file.name.endsWith(".jsdos")) {
|
|
const url = URL.createObjectURL(file);
|
|
setSelectedZipUrl(url);
|
|
setLoadError(null);
|
|
} else {
|
|
setLoadError("Please select a valid .jsdos file");
|
|
}
|
|
};
|
|
|
|
const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
|
|
event.preventDefault();
|
|
const file = event.dataTransfer.files[0];
|
|
if (file && file.name.endsWith(".jsdos")) {
|
|
const url = URL.createObjectURL(file);
|
|
setSelectedZipUrl(url);
|
|
setLoadError(null);
|
|
} else {
|
|
setLoadError("Please drop a valid .jsdos file");
|
|
}
|
|
};
|
|
|
|
const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {
|
|
event.preventDefault();
|
|
};
|
|
|
|
const handleReset = () => {
|
|
setSelectedZipUrl(null);
|
|
setLoadError(null);
|
|
if (fileInputRef.current) {
|
|
fileInputRef.current.value = "";
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Modal open={isOpen} onClose={close} title="Doom Emulator">
|
|
<div className="p-6">
|
|
{!selectedZipUrl ? (
|
|
<div className="space-y-6">
|
|
<div className="text-center">
|
|
<h3 className="text-xl font-semibold text-neutral-100 mb-2">
|
|
Running on a Potato
|
|
</h3>
|
|
<p className="text-neutral-400 mb-6">
|
|
Choose how you'd like to run Doom:
|
|
</p>
|
|
</div>
|
|
|
|
<div className="space-y-4">
|
|
<button
|
|
onClick={handleRemoteLoad}
|
|
className="w-full px-4 py-3 rounded-lg glass text-neutral-200 font-medium transition-colors hover:opacity-95 focus:outline-none focus:ring-2 focus:ring-[color:var(--accent)]"
|
|
>
|
|
Load Demo from Internet
|
|
</button>
|
|
|
|
<div className="relative">
|
|
<div className="absolute inset-0 flex items-center">
|
|
<div className="w-full border-t border-white/20"></div>
|
|
</div>
|
|
<div className="relative flex justify-center text-sm">
|
|
<span className="px-4 bg-transparent text-neutral-400">or</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
onDrop={handleDrop}
|
|
onDragOver={handleDragOver}
|
|
className="border-2 border-dashed border-white/20 rounded-lg p-8 text-center hover:border-white/30 transition-colors"
|
|
>
|
|
<div className="space-y-4">
|
|
<div className="text-neutral-400">
|
|
<p className="mb-2">Drag and drop a .jsdos file here</p>
|
|
<p className="text-sm">or</p>
|
|
</div>
|
|
<input
|
|
ref={fileInputRef}
|
|
type="file"
|
|
accept=".jsdos"
|
|
onChange={handleFileSelect}
|
|
className="hidden"
|
|
id="file-input"
|
|
/>
|
|
<label
|
|
htmlFor="file-input"
|
|
className="inline-block px-4 py-2 rounded-lg glass text-neutral-200 font-medium cursor-pointer transition-colors hover:opacity-95"
|
|
>
|
|
Browse Files
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{loadError && (
|
|
<div className="p-4 glass text-red-400 rounded-lg text-sm">
|
|
{loadError}
|
|
</div>
|
|
)}
|
|
|
|
<div className="text-xs text-neutral-500 space-y-1">
|
|
<p>
|
|
You can create .jsdos files using the{" "}
|
|
<a
|
|
href="https://js-dos.com/tools"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="text-[color:var(--accent)] hover:underline"
|
|
>
|
|
js-dos tools
|
|
</a>
|
|
.
|
|
</p>
|
|
<p>
|
|
The demo requires internet connection and may take a moment to load.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<div className="space-y-4">
|
|
<div className="flex justify-between items-center">
|
|
<div className="text-sm text-neutral-400">
|
|
{selectedZipUrl === remoteDemoUrl
|
|
? "Running demo from internet"
|
|
: "Running local file"}
|
|
</div>
|
|
<button
|
|
onClick={handleReset}
|
|
className="px-3 py-1 text-sm rounded-md border border-white/10 text-neutral-300 hover:bg-white/5 transition-colors"
|
|
>
|
|
Change Source
|
|
</button>
|
|
</div>
|
|
|
|
<JsDosPlayer zipUrl={selectedZipUrl} className="w-full" />
|
|
|
|
<div className="text-xs text-neutral-500">
|
|
<p>Use keyboard controls to play. ESC to exit fullscreen mode.</p>
|
|
<p>Close this modal to stop the emulator.</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</Modal>
|
|
);
|
|
}
|