// screens_menu.jsx — Player Menu
window.S = window.S || {};
(() => {
const { useState, useRef, useEffect } = React;
const { T, panelStyle, Btn, Tooltip, NarrativePanel,
IconFloppy, IconContinue, IconPlay, IconFileTransfer, IconSearch, IconJournal, IconTalking
} = window.UI;
const A = window.E.A;
const L = window.L;
// ── Feedback form as a separate component ────────────────────
const FeedbackPanel = ({ popPanel, state }) => {
const formRef = useRef(null);
const [includeSave, setIncludeSave] = useState(false);
// Detect itch.io embedding
const isOnItchio = window.self !== window.top || window.location.hostname.includes("itch.zone");
useEffect(() => {
if (!isOnItchio && formRef.current) {
const now = new Date().toISOString();
formRef.current.elements["date"].value = now;
formRef.current.elements["os"].value = navigator.platform || "unknown";
formRef.current.elements["browser"].value = navigator.userAgent;
formRef.current.elements["url"].value = window.location.href;
formRef.current.elements["playtime"].value = state.day + " days";
}
}, [isOnItchio]);
useEffect(() => {
if (!isOnItchio && formRef.current) {
formRef.current.elements["saveData"].value = includeSave
? JSON.stringify(state)
: "";
}
}, [includeSave, isOnItchio]);
if (isOnItchio) {
return (
← Back
External feedback forms are not supported inside itch.io. Please use the comments section at the bottom of the itch.io game page to share your feedback. Thank you!
);
}
return (
);
};
// ── Simple markdown‑to‑JSX for changelog ────────────────────
const renderChangelogContent = (md) => {
const lines = md.split("\n");
const elements = [];
let i = 0;
while (i < lines.length) {
const line = lines[i];
if (/^###\s/.test(line)) {
const heading = line.replace(/^###\s+/, "");
elements.push(
{heading}
);
i++;
continue;
}
if (line.trim() === "") { i++; continue; }
const processed = line.replace(/\*\*(.*?)\*\*/g, "$1 ");
elements.push(
);
i++;
}
return elements;
};
// ── Main menu modal ─────────────────────────────────────────
function MenuModal({ state, dispatch, onClose }) {
const [panel, setPanel] = useState("menu");
const [changelogContent, setChangelogContent] = useState(null);
const [isNarrow, setIsNarrow] = useState(window.innerWidth < 500);
const importRef = useRef(null);
useEffect(() => {
const h = () => setIsNarrow(window.innerWidth < 500);
window.addEventListener("resize", h);
return () => window.removeEventListener("resize", h);
}, []);
useEffect(() => {
if (panel === "changelog" && !changelogContent) {
fetch("docs/changelog.md")
.then(r => r.text())
.then(md => setChangelogContent(md))
.catch(() => setChangelogContent("*Changelog not available.*"));
}
}, [panel]);
const handleImport = (e) => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = () => {
dispatch({ type: A.IMPORT_SAVE, fileContent: reader.result });
onClose();
};
reader.readAsText(file);
e.target.value = "";
};
const pushPanel = (p) => setPanel(p);
const popPanel = () => setPanel("menu");
const closeAll = () => { setPanel("menu"); onClose(); };
// ── Panel renderers ─────────────────────────────────────
const renderMenu = () => (
<>
Resume
{ dispatch({ type: A.SAVE_GAME }); closeAll(); }}>
Save Game
{L.hasSave() && (
{ dispatch({ type: A.LOAD_GAME }); closeAll(); }}>
Load Game
)}
pushPanel("newGame")}>
Start New Game
{ dispatch({ type: A.EXPORT_SAVE }); closeAll(); }}>
Export Save
importRef.current?.click()}>
Import Save
{/* Auto‑save toggle */}
dispatch({ type: A.TOGGLE_AUTO_SAVE })} />
Auto‑save on port entry
Reference & Community
window.open("handbook.html", "_blank")}>
Captain's Handbook
pushPanel("changelog")}>
Changelog
pushPanel("feedback")}>
Send Feedback
>
);
const renderNewGame = () => (
Are you sure? Your current browser‑stored save will be lost. If you want to keep it, use the Export Game button.
{ dispatch({ type: A.NAVIGATE, screen: "newgame" }); closeAll(); }}>Yes, start a new game
Cancel
);
const renderChangelog = () => (
← Back
{changelogContent
? renderChangelogContent(changelogContent)
: Loading...
}
);
// ── Main render ─────────────────────────────────────────
return (
e.stopPropagation()}>
{panel === "menu" ? "Menu" :
panel === "changelog" ? "Changelog" :
panel === "feedback" ? "Send Feedback" :
panel === "newGame" ? "Start New Game" : ""}
{panel === "menu" && renderMenu()}
{panel === "newGame" && renderNewGame()}
{panel === "changelog" && renderChangelog()}
{panel === "feedback" &&
}
);
}
window.S.MenuModal = MenuModal;
})();