Add responsive game filters and hybrid toolbox drawer
All checks were successful
Deploy Sokko G / deploy (push) Successful in 20s

This commit is contained in:
Shinuwa 2026-09-27 18:00:49 +02:00
parent 1ee460b94f
commit 00e73f0062
32 changed files with 1202 additions and 241 deletions

View file

@ -9,7 +9,6 @@ import { ToastPositionSwitch } from "../../components/ToastPositionSwitch.jsx";
import { useGroupedReorder } from "../../hooks/useGroupedReorder.js";
import { useInlineEdit } from "../../hooks/useInlineEdit.js";
import { compressImage } from "../../utils/imageCompression.js";
import { getSetting as dbGetSetting, setSetting as dbSetSetting } from "../../utils/indexedDbStorage.js";
import { getGameCardCover, ToolboxCard, ToolboxGameIcon, ToolboxIconPicker } from "./ToolboxCard.jsx";
import { AddToolControls, ToolboxModules } from "./modules/index.jsx";
import {
@ -37,7 +36,11 @@ import {
uid
} from "./storage/toolboxStorage.js";
const DRAWER_WIDTH_SETTING = "drawerWidth";
const DRAWER_INITIAL_WIDTH = 700;
function getDrawerMaxWidth() {
return Math.max(DRAWER_INITIAL_WIDTH, Math.floor(window.innerWidth * 0.94));
}
function addModuleToOrder(moduleOrder, modules, moduleId) {
const order = normalizeModuleOrder(moduleOrder, modules);
@ -347,19 +350,16 @@ export function ToolboxDrawer({ gameId, game, siteContent, toolboxes, links, act
const guideChecklist = checklist.available && checklist.guideId.split("/")[0] === gameId ? checklist : undefined;
const selectedId = links[gameId] || "";
const toolbox = toolboxes.find((item) => item.id === selectedId);
const [width, setWidth] = useState("");
const [width, setWidth] = useState(DRAWER_INITIAL_WIDTH);
const panelRef = useRef(null);
useEffect(() => {
let cancelled = false;
dbGetSetting(DRAWER_WIDTH_SETTING, "")
.then((storedWidth) => {
if (cancelled) return;
const value = Number(storedWidth);
if (Number.isFinite(value) && value > 0) setWidth(Math.min(Math.max(value, 360), Math.floor(window.innerWidth * 0.94)));
})
.catch(() => {});
return () => { cancelled = true; };
const clampToViewport = () => {
if (window.innerWidth < DRAWER_INITIAL_WIDTH) return;
setWidth((currentWidth) => Math.min(currentWidth, getDrawerMaxWidth()));
};
window.addEventListener("resize", clampToViewport);
return () => window.removeEventListener("resize", clampToViewport);
}, []);
function startResize(event) {
@ -368,13 +368,11 @@ export function ToolboxDrawer({ gameId, game, siteContent, toolboxes, links, act
event.preventDefault();
const startX = event.clientX;
const startWidth = panel.getBoundingClientRect().width;
const minWidth = 360;
const maxWidth = Math.floor(window.innerWidth * 0.94);
const maxWidth = getDrawerMaxWidth();
document.body.classList.add("is-resizing-drawer");
const onMove = (moveEvent) => {
const nextWidth = Math.min(Math.max(startWidth + startX - moveEvent.clientX, minWidth), maxWidth);
const nextWidth = Math.min(Math.max(startWidth + startX - moveEvent.clientX, DRAWER_INITIAL_WIDTH), maxWidth);
setWidth(nextWidth);
dbSetSetting(DRAWER_WIDTH_SETTING, Math.round(nextWidth)).catch(() => {});
};
const stop = () => {
document.body.classList.remove("is-resizing-drawer");
@ -388,10 +386,9 @@ export function ToolboxDrawer({ gameId, game, siteContent, toolboxes, links, act
}
return (
<aside className="drawer" id="toolbox-drawer" aria-hidden="false" style={width ? { "--drawer-panel-width": `${width}px` } : undefined}>
<div className="drawer-backdrop" onClick={() => actions.setDrawerGameId("")} />
<aside className="drawer" id="toolbox-drawer" aria-hidden="false" style={{ "--drawer-panel-width": `${width}px` }}>
<span className="drawer-resize-handle nds-drawer-resize-handle" aria-hidden="true" onPointerDown={startResize} />
<section className="drawer-panel nds-drawer-panel legacy-scrollbar" ref={panelRef} style={width ? { width } : undefined}>
<section className="drawer-panel nds-drawer-panel legacy-scrollbar" ref={panelRef}>
<div className="drawer-content">
<header>
<div>