Introduce AutoMetabuilder core components and workflow packages:

- Implement core components: CLI argument parsing, environment loading, GitHub service creation, and logging configuration.
- Add support for OpenAI client setup and model resolution.
- Develop SDLC context loader from GitHub and repository files.
- Implement workflow context and engine builders.
- Introduce major workflow packages: `game_tick_loop` and `contextual_iterative_loop`.
- Update localization files with new package descriptions and labels.
- Streamline web navigation by loading items from a dedicated JSON file.
This commit is contained in:
2026-01-10 01:13:47 +00:00
parent 22c9306347
commit 7f495c97a9
11 changed files with 1000 additions and 170 deletions

View File

@@ -1,12 +1,14 @@
"use client";
import { useEffect, useMemo, useState } from "react";
import { Alert, Snackbar } from "@mui/material";
import DashboardSection from "../components/sections/DashboardSection";
import PromptSection from "../components/sections/PromptSection";
import SettingsSection from "../components/sections/SettingsSection";
import TranslationsSection from "../components/sections/TranslationsSection";
import WorkflowSection from "../components/sections/WorkflowSection";
import PageLayout from "../components/layout/PageLayout";
import useWebhook, { emitWebhook } from "../hooks/useWebhook";
import {
fetchContext,
fetchWorkflowPackage,
@@ -22,6 +24,8 @@ export default function HomePage() {
const [selectedSection, setSelectedSection] = useState("dashboard");
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
const [snack, setSnack] = useState("");
const [snackOpen, setSnackOpen] = useState(false);
const loadContext = async () => {
setLoading(true);
@@ -41,6 +45,16 @@ export default function HomePage() {
void loadContext();
}, []);
useWebhook(
"botRunComplete",
(detail) => {
const mode = (detail as { mode?: string })?.mode ?? "once";
setSnack(`Run finished: ${mode}`);
setSnackOpen(true);
},
[]
);
const t = useMemo(
() => (key: string, fallback?: string) => context?.messages[key] ?? fallback ?? key,
[context]
@@ -49,6 +63,7 @@ export default function HomePage() {
const handleRun = async (payload: Parameters<typeof runBot>[0]) => {
await runBot(payload);
await loadContext();
emitWebhook("runRequested", payload);
};
const handleWorkflowSave = async (content: string) => {
@@ -92,8 +107,9 @@ export default function HomePage() {
}
return (
<PageLayout
navItems={context.navigation}
<>
<PageLayout
navItems={context.navigation}
section={selectedSection}
onSectionChange={setSelectedSection}
t={t}
@@ -117,6 +133,12 @@ export default function HomePage() {
{selectedSection === "translations" && (
<TranslationsSection languages={context.translations} onRefresh={loadContext} t={t} />
)}
</PageLayout>
</PageLayout>
<Snackbar open={snackOpen} autoHideDuration={4000} onClose={() => setSnackOpen(false)}>
<Alert onClose={() => setSnackOpen(false)} severity="info" sx={{ width: "100%" }}>
{snack}
</Alert>
</Snackbar>
</>
);
}

View File

@@ -1,4 +1,5 @@
import { ReactNode } from "react";
import { Box, Toolbar, Typography } from "@mui/material";
import { NavigationItem } from "../../lib/types";
import Sidebar from "./Sidebar";
@@ -12,15 +13,21 @@ type PageLayoutProps = {
export default function PageLayout({ navItems, section, onSectionChange, t, children }: PageLayoutProps) {
return (
<div className="app-shell">
<Box sx={{ display: "flex" }}>
<Sidebar items={navItems} selected={section} onSelect={onSectionChange} t={t} />
<div className="content-shell">
<header className="content-shell__header">
<h1>{t("ui.app.title", "AutoMetabuilder Dashboard")}</h1>
<p>{t("ui.dashboard.subtitle", "Control the bot and monitor system activity")}</p>
</header>
<div className="content-shell__body">{children}</div>
</div>
</div>
<Box component="main" sx={{ flexGrow: 1, p: 3, bgcolor: "#04070f", minHeight: "100vh" }}>
<Toolbar disableGutters>
<div>
<Typography variant="h4" color="text.primary" gutterBottom>
{t("ui.app.title", "AutoMetabuilder Dashboard")}
</Typography>
<Typography variant="subtitle1" color="text.secondary">
{t("ui.dashboard.subtitle", "Control the bot and monitor system activity")}
</Typography>
</div>
</Toolbar>
<Box>{children}</Box>
</Box>
</Box>
);
}

View File

@@ -1,3 +1,4 @@
import { Box, Divider, Drawer, List, ListItemButton, ListItemText, Typography } from "@mui/material";
import { NavigationItem } from "../../lib/types";
type SidebarProps = {
@@ -9,23 +10,30 @@ type SidebarProps = {
export default function Sidebar({ items, selected, onSelect, t }: SidebarProps) {
return (
<aside className="sidebar">
<div className="sidebar__brand">
<span>{t("ui.app.name", "AutoMetabuilder")}</span>
</div>
<nav>
{items.map((item) => (
<button
key={item.section}
type="button"
className={`sidebar__item ${selected === item.section ? "active" : ""}`}
onClick={() => onSelect(item.section)}
data-section={item.section}
>
<span>{t(item.label_key, item.default_label)}</span>
</button>
))}
</nav>
</aside>
<Drawer variant="permanent" anchor="left" sx={{ width: 220, flexShrink: 0 }}>
<Box sx={{ height: "100%", backgroundColor: "#0f172a" }}>
<Box sx={{ px: 3, py: 2 }}>
<Typography variant="overline" color="text.secondary">
{t("ui.app.name", "AutoMetabuilder")}
</Typography>
</Box>
<Divider sx={{ borderColor: "rgba(255,255,255,0.08)" }} />
<List>
{items.map((item) => (
<ListItemButton
key={item.section}
selected={selected === item.section}
onClick={() => onSelect(item.section)}
data-section={item.section}
sx={{
color: selected === item.section ? "#fff" : "rgba(226,232,240,0.8)",
}}
>
<ListItemText primary={t(item.label_key, item.default_label)} primaryTypographyProps={{ fontSize: 14 }} />
</ListItemButton>
))}
</List>
</Box>
</Drawer>
);
}

View File

@@ -1,5 +1,19 @@
import { useState } from "react";
import {
Box,
Button,
Checkbox,
FormControl,
FormControlLabel,
Paper,
Radio,
RadioGroup,
Stack,
TextField,
Typography,
} from "@mui/material";
import { UIStatus } from "../../lib/types";
import { emitWebhook } from "../../hooks/useWebhook";
type DashboardSectionProps = {
status: UIStatus;
@@ -20,6 +34,7 @@ export default function DashboardSection({ status, logs, onRun, t }: DashboardSe
try {
await onRun({ mode, iterations, yolo: isYolo, stop_at_mvp: stopAtMvp });
setFeedback(t("ui.dashboard.start_bot", "Start Bot") + " " + t("ui.dashboard.status.running", "Running"));
emitWebhook("botRunComplete", { mode, iterations });
} catch (error) {
console.error(error);
setFeedback(t("ui.dashboard.status.idle", "Idle"));
@@ -27,52 +42,72 @@ export default function DashboardSection({ status, logs, onRun, t }: DashboardSe
};
return (
<section className="section-card" id="dashboard">
<div className="section-card__header">
<h2>{t("ui.dashboard.title", "Dashboard")}</h2>
<p>{t("ui.dashboard.subtitle", "Control the bot and monitor system activity")}</p>
</div>
<div className="dashboard-grid">
<div className="dashboard-panel">
<h3>{t("ui.dashboard.bot_control", "Bot Control")}</h3>
<div className="dashboard-panel__strategy">
<label>
<input type="radio" name="mode" value="once" checked={mode === "once"} onChange={() => setMode("once")} />
<span>{t("ui.dashboard.run.single.title", "Single Iteration")}</span>
</label>
<label>
<input type="radio" name="mode" value="iterations" checked={mode === "iterations"} onChange={() => setMode("iterations")} />
<span>{t("ui.dashboard.run.repeat.title", "Repeat")}</span>
</label>
<label>
<input type="radio" name="mode" value="yolo" checked={mode === "yolo"} onChange={() => setMode("yolo")} />
<span>{t("ui.dashboard.run.yolo.title", "YOLO")}</span>
</label>
</div>
<Paper id="dashboard" sx={{ p: 3, mb: 3, backgroundColor: "#0d111b" }}>
<Typography variant="h5" gutterBottom>
{t("ui.dashboard.title", "Dashboard")}
</Typography>
<Typography variant="body2" color="text.secondary" gutterBottom>
{t("ui.dashboard.subtitle", "Control the bot and monitor system activity")}
</Typography>
<Stack direction={{ xs: "column", md: "row" }} spacing={3} mt={2}>
<Paper sx={{ flex: 1, p: 2, backgroundColor: "#0b1221" }}>
<Typography variant="subtitle1" gutterBottom>
{t("ui.dashboard.bot_control", "Bot Control")}
</Typography>
<FormControl component="fieldset">
<RadioGroup row value={mode} onChange={(event) => setMode(event.target.value)} name="run-mode">
{["once", "iterations", "yolo"].map((value) => (
<FormControlLabel
key={value}
value={value}
control={<Radio size="small" />}
label={t(`ui.dashboard.run.${value}.title`, value === "iterations" ? "Repeat" : value.charAt(0).toUpperCase() + value.slice(1))}
/>
))}
</RadioGroup>
</FormControl>
{mode === "iterations" && (
<label className="field-group">
<span>{t("ui.dashboard.run.repeat.label", "Iterations")}</span>
<input type="number" min={1} value={iterations} onChange={(event) => setIterations(Number(event.target.value) || 1)} />
</label>
<TextField
type="number"
size="small"
label={t("ui.dashboard.run.repeat.label", "Iterations")}
value={iterations}
onChange={(event) => setIterations(Number(event.target.value) || 1)}
sx={{ mt: 1, width: 140 }}
/>
)}
<label className="field-group">
<input type="checkbox" checked={stopAtMvp} onChange={(event) => setStopAtMvp(event.target.checked)} />
<span>{t("ui.dashboard.stop_mvp.title", "Stop at MVP")}</span>
</label>
<button className="primary" type="button" onClick={handleRun} disabled={status.is_running}>
<FormControlLabel
control={<Checkbox checked={stopAtMvp} onChange={(event) => setStopAtMvp(event.target.checked)} />}
label={t("ui.dashboard.stop_mvp.title", "Stop at MVP")}
sx={{ mt: 1 }}
/>
<Button
variant="contained"
color="primary"
onClick={handleRun}
disabled={status.is_running}
sx={{ mt: 2 }}
>
{t("ui.dashboard.start_bot", "Start Bot")}
</button>
<p className="status-text">
{status.is_running ? t("ui.dashboard.status.running", "Running") : t("ui.dashboard.status.idle", "Idle")} {" "}
</Button>
<Typography variant="caption" color="text.secondary" display="block" mt={1}>
{status.is_running ? t("ui.dashboard.status.running", "Running") : t("ui.dashboard.status.idle", "Idle")}
{" "}
{status.mvp_reached ? t("ui.dashboard.status.mvp_reached", "Reached") : t("ui.dashboard.status.mvp_progress", "In Progress")}
</p>
<p className="status-feedback">{feedback}</p>
</div>
<div className="dashboard-panel">
<h3>{t("ui.dashboard.logs.title", "Recent Logs")}</h3>
<pre className="log-output">{logs.slice(-1200) || t("ui.dashboard.status.idle", "Idle")}</pre>
</div>
</div>
</section>
</Typography>
<Typography variant="caption" color="primary">
{feedback}
</Typography>
</Paper>
<Paper sx={{ flex: 1, p: 2, backgroundColor: "#0b1221" }}>
<Typography variant="subtitle1" gutterBottom>
{t("ui.dashboard.logs.title", "Recent Logs")}
</Typography>
<Box component="pre" sx={{ maxHeight: 240, overflow: "auto", fontSize: 12, color: "white" }}>
{logs.slice(-1200) || t("ui.dashboard.status.idle", "Idle")}
</Box>
</Paper>
</Stack>
</Paper>
);
}

View File

@@ -1,4 +1,5 @@
import { useEffect, useState } from "react";
import { Box, Button, Paper, Stack, TextField, Typography } from "@mui/material";
type PromptSectionProps = {
content: string;
@@ -21,18 +22,36 @@ export default function PromptSection({ content, onSave, t }: PromptSectionProps
};
return (
<section className="section-card" id="prompt">
<div className="section-card__header">
<h2>{t("ui.prompt.title", "Prompt Builder")}</h2>
<p>{t("ui.prompt.subtitle", "Shape how the assistant thinks, speaks, and decides")}</p>
</div>
<textarea className="prompt-editor" value={draft} onChange={(event) => setDraft(event.target.value)} rows={12} />
<div className="workflow-actions">
<button className="primary" type="button" onClick={handleSave}>
<Paper id="prompt" sx={{ p: 3, mb: 3, backgroundColor: "#0d111b" }}>
<Typography variant="h5" gutterBottom>
{t("ui.prompt.title", "Prompt Builder")}
</Typography>
<Typography variant="body2" color="text.secondary" gutterBottom>
{t("ui.prompt.subtitle", "Shape how the assistant thinks, speaks, and decides")}
</Typography>
<TextField
multiline
minRows={10}
value={draft}
onChange={(event) => setDraft(event.target.value)}
fullWidth
InputProps={{
sx: {
backgroundColor: "#030712",
borderRadius: 2,
color: "white",
fontFamily: "JetBrains Mono, monospace",
},
}}
/>
<Stack direction="row" spacing={2} alignItems="center" mt={2}>
<Button variant="contained" onClick={handleSave}>
{t("ui.prompt.save", "Save Prompt")}
</button>
<span className="workflow-message">{message}</span>
</div>
</section>
</Button>
<Typography variant="body2" color="success.main">
{message}
</Typography>
</Stack>
</Paper>
);
}

View File

@@ -1,4 +1,5 @@
import { useEffect, useState } from "react";
import { Box, Button, Paper, Stack, TextField, Typography } from "@mui/material";
type SettingsSectionProps = {
envVars: Record<string, string>;
@@ -34,32 +35,55 @@ export default function SettingsSection({ envVars, onSave, t }: SettingsSectionP
};
return (
<section className="section-card" id="settings">
<div className="section-card__header">
<h2>{t("ui.settings.title", "Settings")}</h2>
<p>{t("ui.settings.subtitle", "Configure services, security, and environment preferences")}</p>
</div>
<div className="settings-grid">
<Paper id="settings" sx={{ p: 3, mb: 3, backgroundColor: "#0d111b" }}>
<Typography variant="h5" gutterBottom>
{t("ui.settings.title", "Settings")}
</Typography>
<Typography variant="body2" color="text.secondary" gutterBottom>
{t("ui.settings.subtitle", "Configure services, security, and environment preferences")}
</Typography>
<Stack spacing={2} mt={2}>
{Object.entries(values).map(([key, value]) => (
<label key={key} className="field-group">
<span>{key}</span>
<input value={value} onChange={(event) => updateField(key, event.target.value)} />
</label>
<TextField
key={key}
label={key}
value={value}
onChange={(event) => updateField(key, event.target.value)}
InputProps={{
sx: {
backgroundColor: "#030712",
borderRadius: 1,
color: "white",
},
}}
/>
))}
</div>
<div className="settings-grid settings-grid--new">
<input placeholder={t("ui.settings.add.placeholder_key", "KEY")} value={newKey} onChange={(event) => setNewKey(event.target.value)} />
<input placeholder={t("ui.settings.add.placeholder_value", "Value")} value={newValue} onChange={(event) => setNewValue(event.target.value)} />
<button type="button" onClick={handleAdd}>
</Stack>
<Stack direction={{ xs: "column", sm: "row" }} spacing={2} sx={{ mt: 2 }}>
<TextField
label={t("ui.settings.add.placeholder_key", "KEY")}
value={newKey}
onChange={(event) => setNewKey(event.target.value)}
fullWidth
/>
<TextField
label={t("ui.settings.add.placeholder_value", "Value")}
value={newValue}
onChange={(event) => setNewValue(event.target.value)}
fullWidth
/>
<Button variant="outlined" onClick={handleAdd}>
{t("ui.actions.add", "Add")}
</button>
</div>
<div className="workflow-actions">
<button className="primary" type="button" onClick={handleSave}>
</Button>
</Stack>
<Stack direction="row" spacing={2} alignItems="center" mt={3}>
<Button variant="contained" onClick={handleSave}>
{t("ui.settings.save_all", "Save All Settings")}
</button>
<span className="workflow-message">{message}</span>
</div>
</section>
</Button>
<Typography variant="body2" color="success.main">
{message}
</Typography>
</Stack>
</Paper>
);
}

View File

@@ -1,4 +1,12 @@
import { FormEvent, useEffect, useState } from "react";
import {
Button,
Chip,
Paper,
Stack,
TextField,
Typography,
} from "@mui/material";
import {
createTranslation,
deleteTranslation,
@@ -25,7 +33,6 @@ export default function TranslationsSection({ languages, onRefresh, t }: Transla
setEditorValue(JSON.stringify(data.content, null, 2));
};
/* eslint-disable react-hooks/set-state-in-effect */
useEffect(() => {
if (!selected && Object.keys(languages).length) {
setSelected(Object.keys(languages)[0]);
@@ -37,7 +44,6 @@ export default function TranslationsSection({ languages, onRefresh, t }: Transla
loadContent(selected);
}
}, [selected]);
/* eslint-enable react-hooks/set-state-in-effect */
const handleSave = async () => {
if (!selected) return;
@@ -67,41 +73,64 @@ export default function TranslationsSection({ languages, onRefresh, t }: Transla
};
return (
<section className="section-card" id="translations">
<div className="section-card__header">
<h2>{t("ui.translations.title", "Translations")}</h2>
<p>{t("ui.translations.subtitle", "Create, edit, and maintain language files for bot messages")}</p>
</div>
<div className="translations-layout">
<div className="language-list">
<Paper id="translations" sx={{ p: 3, mb: 3, backgroundColor: "#0d111b" }}>
<Typography variant="h5" gutterBottom>
{t("ui.translations.title", "Translations")}
</Typography>
<Typography variant="body2" color="text.secondary" gutterBottom>
{t("ui.translations.subtitle", "Create, edit, and maintain language files for bot messages")}
</Typography>
<Stack spacing={2} sx={{ mt: 2 }}>
<Stack direction="row" spacing={1} flexWrap="wrap">
{Object.entries(languages).map(([lang, label]) => (
<button
<Chip
label={`${lang} (${label})`}
key={lang}
type="button"
className={`language-chip ${selected === lang ? "active" : ""}`}
variant={selected === lang ? "filled" : "outlined"}
onClick={() => setSelected(lang)}
>
{lang}
<span>{`(${label})`}</span>
</button>
clickable
/>
))}
</div>
<textarea value={editorValue} onChange={(event) => setEditorValue(event.target.value)} rows={12} />
</div>
<div className="translations-actions">
<button className="primary" type="button" onClick={handleSave} disabled={!selected}>
</Stack>
<TextField
multiline
minRows={12}
value={editorValue}
onChange={(event) => setEditorValue(event.target.value)}
InputProps={{
sx: {
backgroundColor: "#030712",
borderRadius: 2,
color: "white",
fontFamily: "JetBrains Mono, monospace",
},
}}
/>
</Stack>
<Stack direction="row" spacing={2} mt={2}>
<Button variant="contained" onClick={handleSave} disabled={!selected}>
{t("ui.actions.save", "Save")}
</button>
<button type="button" onClick={handleDelete} disabled={!selected}>
</Button>
<Button variant="outlined" onClick={handleDelete} disabled={!selected}>
{t("ui.actions.delete", "Delete")}
</button>
<form onSubmit={handleCreate} className="language-form">
<input placeholder={t("ui.translations.add_language_placeholder", "Add language...")} value={newLang} onChange={(event) => setNewLang(event.target.value)} />
<button type="submit">{t("ui.actions.add", "Add")}</button>
</form>
</div>
{message && <p className="workflow-message">{message}</p>}
{error && <p className="workflow-error">{error}</p>}
</section>
</Button>
<Stack component="form" onSubmit={handleCreate} direction="row" spacing={1} flex={1}>
<TextField
placeholder={t("ui.translations.add_language_placeholder", "Add language...")}
value={newLang}
onChange={(event) => setNewLang(event.target.value)}
fullWidth
/>
<Button type="submit" variant="contained">
{t("ui.actions.add", "Add")}
</Button>
</Stack>
</Stack>
{(message || error) && (
<Typography variant="body2" color={error ? "error.main" : "success.main"} mt={2}>
{message || error}
</Typography>
)}
</Paper>
);
}

View File

@@ -1,4 +1,5 @@
import { useEffect, useState } from "react";
import { Box, Button, Paper, Stack, Typography } from "@mui/material";
import { WorkflowPackageSummary } from "../../lib/types";
type WorkflowSectionProps = {
@@ -24,38 +25,60 @@ export default function WorkflowSection({ content, packages, onSave, onTemplateS
};
return (
<section className="section-card" id="workflow">
<div className="section-card__header">
<h2>{t("ui.workflow.title", "Workflow Builder")}</h2>
<p>{t("ui.workflow.subtitle", "Design the bot's task execution pipeline")}</p>
</div>
<div className="workflow-grid">
<div className="workflow-editor">
<textarea value={draft} onChange={(event) => setDraft(event.target.value)} />
<div className="workflow-actions">
<button type="button" className="primary" onClick={handleSave}>
<Paper id="workflow" sx={{ p: 3, mb: 3, backgroundColor: "#0d111b" }}>
<Typography variant="h5" gutterBottom>
{t("ui.workflow.title", "Workflow Builder")}
</Typography>
<Typography variant="body2" color="text.secondary" gutterBottom>
{t("ui.workflow.subtitle", "Design the bot's task execution pipeline")}
</Typography>
<Stack direction={{ xs: "column", md: "row" }} spacing={3}>
<Box sx={{ flex: 1 }}>
<Box
component="textarea"
value={draft}
onChange={(event) => setDraft(event.target.value)}
rows={18}
sx={{
width: "100%",
fontFamily: "JetBrains Mono, monospace",
backgroundColor: "#030712",
border: "1px solid rgba(148, 163, 184, 0.4)",
borderRadius: 2,
color: "white",
p: 2,
}}
/>
<Stack direction="row" spacing={1} alignItems="center" mt={2}>
<Button variant="contained" onClick={handleSave}>
{t("ui.workflow.save", "Save Workflow")}
</button>
<span className="workflow-message">{message}</span>
</div>
</div>
<div className="workflow-templates">
<h3>{t("ui.workflow.templates.title", "Workflow Templates")}</h3>
<div className="template-palette">
</Button>
<Typography variant="body2" color="success.main">
{message}
</Typography>
</Stack>
</Box>
<Paper sx={{ flex: 1, p: 2, backgroundColor: "#0b1221" }}>
<Typography variant="subtitle1" gutterBottom>
{t("ui.workflow.templates.title", "Workflow Templates")}
</Typography>
<Stack spacing={1}>
{packages.map((pkg) => (
<article key={pkg.id} className="template-card">
<div>
<strong>{pkg.label}</strong>
<p>{pkg.description}</p>
</div>
<button type="button" onClick={() => onTemplateSelect(pkg.id)}>
{t("ui.workflow.templates.apply", "Apply Template")}
</button>
</article>
<Paper key={pkg.id} variant="outlined" sx={{ p: 1 }}>
<Stack spacing={1}>
<Typography variant="subtitle2">{pkg.label}</Typography>
<Typography variant="body2" color="text.secondary">
{pkg.description}
</Typography>
<Button size="small" variant="text" onClick={() => onTemplateSelect(pkg.id)}>
{t("ui.workflow.templates.apply", "Apply Template")}
</Button>
</Stack>
</Paper>
))}
</div>
</div>
</div>
</section>
</Stack>
</Paper>
</Stack>
</Paper>
);
}

View File

@@ -0,0 +1,22 @@
import { useEffect } from "react";
const emitter = new EventTarget();
export function emitWebhook(event: string, detail?: unknown) {
emitter.dispatchEvent(new CustomEvent(event, { detail }));
}
export default function useWebhook(
name: string,
handler: (detail: unknown) => void,
deps: unknown[] = []
) {
useEffect(() => {
const listener = (evt: Event) => {
handler((evt as CustomEvent).detail);
};
emitter.addEventListener(name, listener);
return () => emitter.removeEventListener(name, listener);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [name, handler, ...deps]);
}

View File

@@ -13,6 +13,10 @@
"react-dom": "19.2.3"
},
"devDependencies": {
"@emotion/react": "^11.12.0",
"@emotion/styled": "^11.12.0",
"@mui/icons-material": "^5.14.4",
"@mui/material": "^5.15.0",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
@@ -213,6 +217,16 @@
"node": ">=6.0.0"
}
},
"node_modules/@babel/runtime": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
"integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/template": {
"version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
@@ -294,6 +308,172 @@
"tslib": "^2.4.0"
}
},
"node_modules/@emotion/babel-plugin": {
"version": "11.13.5",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz",
"integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.16.7",
"@babel/runtime": "^7.18.3",
"@emotion/hash": "^0.9.2",
"@emotion/memoize": "^0.9.0",
"@emotion/serialize": "^1.3.3",
"babel-plugin-macros": "^3.1.0",
"convert-source-map": "^1.5.0",
"escape-string-regexp": "^4.0.0",
"find-root": "^1.1.0",
"source-map": "^0.5.7",
"stylis": "4.2.0"
}
},
"node_modules/@emotion/babel-plugin/node_modules/convert-source-map": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
"dev": true,
"license": "MIT"
},
"node_modules/@emotion/cache": {
"version": "11.14.0",
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz",
"integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@emotion/memoize": "^0.9.0",
"@emotion/sheet": "^1.4.0",
"@emotion/utils": "^1.4.2",
"@emotion/weak-memoize": "^0.4.0",
"stylis": "4.2.0"
}
},
"node_modules/@emotion/hash": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
"integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
"dev": true,
"license": "MIT"
},
"node_modules/@emotion/is-prop-valid": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz",
"integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@emotion/memoize": "^0.9.0"
}
},
"node_modules/@emotion/memoize": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
"integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@emotion/react": {
"version": "11.14.0",
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
"@emotion/cache": "^11.14.0",
"@emotion/serialize": "^1.3.3",
"@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
"@emotion/utils": "^1.4.2",
"@emotion/weak-memoize": "^0.4.0",
"hoist-non-react-statics": "^3.3.1"
},
"peerDependencies": {
"react": ">=16.8.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@emotion/serialize": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz",
"integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@emotion/hash": "^0.9.2",
"@emotion/memoize": "^0.9.0",
"@emotion/unitless": "^0.10.0",
"@emotion/utils": "^1.4.2",
"csstype": "^3.0.2"
}
},
"node_modules/@emotion/sheet": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
"integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==",
"dev": true,
"license": "MIT"
},
"node_modules/@emotion/styled": {
"version": "11.14.1",
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz",
"integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
"@emotion/is-prop-valid": "^1.3.0",
"@emotion/serialize": "^1.3.3",
"@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
"@emotion/utils": "^1.4.2"
},
"peerDependencies": {
"@emotion/react": "^11.0.0-rc.0",
"react": ">=16.8.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@emotion/unitless": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
"integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==",
"dev": true,
"license": "MIT"
},
"node_modules/@emotion/use-insertion-effect-with-fallbacks": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz",
"integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@emotion/utils": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz",
"integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==",
"dev": true,
"license": "MIT"
},
"node_modules/@emotion/weak-memoize": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
"dev": true,
"license": "MIT"
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
@@ -1006,6 +1186,253 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@mui/core-downloads-tracker": {
"version": "5.18.0",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.18.0.tgz",
"integrity": "sha512-jbhwoQ1AY200PSSOrNXmrFCaSDSJWP7qk6urkTmIirvRXDROkqe+QwcLlUiw/PrREwsIF/vm3/dAXvjlMHF0RA==",
"dev": true,
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
}
},
"node_modules/@mui/icons-material": {
"version": "5.18.0",
"resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.18.0.tgz",
"integrity": "sha512-1s0vEZj5XFXDMmz3Arl/R7IncFqJ+WQ95LDp1roHWGDE2oCO3IS4/hmiOv1/8SD9r6B7tv9GLiqVZYHo+6PkTg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.23.9"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@mui/material": "^5.0.0",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/material": {
"version": "5.18.0",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.18.0.tgz",
"integrity": "sha512-bbH/HaJZpFtXGvWg3TsBWG4eyt3gah3E7nCNU8GLyRjVoWcA91Vm/T+sjHfUcwgJSw9iLtucfHBoq+qW/T30aA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@mui/core-downloads-tracker": "^5.18.0",
"@mui/system": "^5.18.0",
"@mui/types": "~7.2.15",
"@mui/utils": "^5.17.1",
"@popperjs/core": "^2.11.8",
"@types/react-transition-group": "^4.4.10",
"clsx": "^2.1.0",
"csstype": "^3.1.3",
"prop-types": "^15.8.1",
"react-is": "^19.0.0",
"react-transition-group": "^4.4.5"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
},
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/material/node_modules/react-is": {
"version": "19.2.3",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.3.tgz",
"integrity": "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA==",
"dev": true,
"license": "MIT"
},
"node_modules/@mui/private-theming": {
"version": "5.17.1",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.17.1.tgz",
"integrity": "sha512-XMxU0NTYcKqdsG8LRmSoxERPXwMbp16sIXPcLVgLGII/bVNagX0xaheWAwFv8+zDK7tI3ajllkuD3GZZE++ICQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@mui/utils": "^5.17.1",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/styled-engine": {
"version": "5.18.0",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.18.0.tgz",
"integrity": "sha512-BN/vKV/O6uaQh2z5rXV+MBlVrEkwoS/TK75rFQ2mjxA7+NBo8qtTAOA4UaM0XeJfn7kh2wZ+xQw2HAx0u+TiBg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@emotion/cache": "^11.13.5",
"@emotion/serialize": "^1.3.3",
"csstype": "^3.1.3",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
}
}
},
"node_modules/@mui/system": {
"version": "5.18.0",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.18.0.tgz",
"integrity": "sha512-ojZGVcRWqWhu557cdO3pWHloIGJdzVtxs3rk0F9L+x55LsUjcMUVkEhiF7E4TMxZoF9MmIHGGs0ZX3FDLAf0Xw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@mui/private-theming": "^5.17.1",
"@mui/styled-engine": "^5.18.0",
"@mui/types": "~7.2.15",
"@mui/utils": "^5.17.1",
"clsx": "^2.1.0",
"csstype": "^3.1.3",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
},
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/types": {
"version": "7.2.24",
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz",
"integrity": "sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/utils": {
"version": "5.17.1",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.17.1.tgz",
"integrity": "sha512-jEZ8FTqInt2WzxDV8bhImWBqeQRD99c/id/fq83H0ER9tFl+sfZlaAoCdznGvbSQQ9ividMxqSV2c7cC1vBcQg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@mui/types": "~7.2.15",
"@types/prop-types": "^15.7.12",
"clsx": "^2.1.1",
"prop-types": "^15.8.1",
"react-is": "^19.0.0"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/utils/node_modules/react-is": {
"version": "19.2.3",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.3.tgz",
"integrity": "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA==",
"dev": true,
"license": "MIT"
},
"node_modules/@napi-rs/wasm-runtime": {
"version": "0.2.12",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
@@ -1521,6 +1948,17 @@
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"dev": true,
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@rtsao/scc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
@@ -1579,6 +2017,20 @@
"undici-types": "~6.21.0"
}
},
"node_modules/@types/parse-json": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
"integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/prop-types": {
"version": "15.7.15",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/react": {
"version": "19.2.7",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
@@ -1599,6 +2051,16 @@
"@types/react": "^19.2.0"
}
},
"node_modules/@types/react-transition-group": {
"version": "4.4.12",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
"integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"@types/react": "*"
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.52.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.52.0.tgz",
@@ -2423,6 +2885,22 @@
"node": ">= 0.4"
}
},
"node_modules/babel-plugin-macros": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
"integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.12.5",
"cosmiconfig": "^7.0.0",
"resolve": "^1.19.0"
},
"engines": {
"node": ">=10",
"npm": ">=6"
}
},
"node_modules/babel-plugin-react-compiler": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz",
@@ -2627,6 +3105,16 @@
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
"license": "MIT"
},
"node_modules/clsx": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -2661,6 +3149,23 @@
"dev": true,
"license": "MIT"
},
"node_modules/cosmiconfig": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
"integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/parse-json": "^4.0.0",
"import-fresh": "^3.2.1",
"parse-json": "^5.0.0",
"path-type": "^4.0.0",
"yaml": "^1.10.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -2832,6 +3337,17 @@
"node": ">=0.10.0"
}
},
"node_modules/dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.8.7",
"csstype": "^3.0.2"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@@ -2861,6 +3377,16 @@
"dev": true,
"license": "MIT"
},
"node_modules/error-ex": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
"integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-arrayish": "^0.2.1"
}
},
"node_modules/es-abstract": {
"version": "1.24.1",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz",
@@ -3572,6 +4098,13 @@
"node": ">=8"
}
},
"node_modules/find-root": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
"dev": true,
"license": "MIT"
},
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -3924,6 +4457,16 @@
"hermes-estree": "0.25.1"
}
},
"node_modules/hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"react-is": "^16.7.0"
}
},
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -4001,6 +4544,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
"dev": true,
"license": "MIT"
},
"node_modules/is-async-function": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
@@ -4470,6 +5020,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
"dev": true,
"license": "MIT"
},
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -4557,6 +5114,13 @@
"node": ">= 0.8.0"
}
},
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
"dev": true,
"license": "MIT"
},
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -4980,6 +5544,25 @@
"node": ">=6"
}
},
"node_modules/parse-json": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.0.0",
"error-ex": "^1.3.1",
"json-parse-even-better-errors": "^2.3.0",
"lines-and-columns": "^1.1.6"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -5007,6 +5590,16 @@
"dev": true,
"license": "MIT"
},
"node_modules/path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -5145,6 +5738,23 @@
"dev": true,
"license": "MIT"
},
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"@babel/runtime": "^7.5.5",
"dom-helpers": "^5.0.1",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2"
},
"peerDependencies": {
"react": ">=16.6.0",
"react-dom": ">=16.6.0"
}
},
"node_modules/readdirp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
@@ -5587,6 +6197,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -5776,6 +6396,13 @@
}
}
},
"node_modules/stylis": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
"dev": true,
"license": "MIT"
},
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -6262,6 +6889,16 @@
"dev": true,
"license": "ISC"
},
"node_modules/yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">= 6"
}
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",

View File

@@ -17,6 +17,10 @@
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@emotion/react": "^11.12.0",
"@emotion/styled": "^11.12.0",
"@mui/icons-material": "^5.14.4",
"@mui/material": "^5.15.0",
"eslint": "^9",
"eslint-config-next": "16.1.1",
"sass": "^1.95.0"