diff --git a/services/web-ui/public/screens-projects.jsx b/services/web-ui/public/screens-projects.jsx
index e0bdab3..02c4ef2 100644
--- a/services/web-ui/public/screens-projects.jsx
+++ b/services/web-ui/public/screens-projects.jsx
@@ -1,17 +1,67 @@
// screens-projects.jsx
+function NewProjectModal({ onClose, onCreated }) {
+ const [name, setName] = React.useState('');
+ const [saving, setSaving] = React.useState(false);
+ const [err, setErr] = React.useState(null);
+
+ const create = () => {
+ if (!name.trim()) { setErr('Name is required'); return; }
+ setSaving(true); setErr(null);
+ window.ZAMPP_API.fetch('/projects', { method: 'POST', body: JSON.stringify({ name: name.trim() }) })
+ .then(p => { onCreated(p); onClose(); })
+ .catch(e => { setSaving(false); setErr(e.message || 'Failed to create project'); });
+ };
+
+ return (
+
+
e.stopPropagation()}>
+
+
+
+
+ setName(e.target.value)}
+ placeholder="e.g. Sunday Night Game" autoFocus
+ onKeyDown={e => e.key === 'Enter' && !saving && create()} />
+
+ {err &&
{err}
}
+
+
+
+
+
+
+
+
+ );
+}
+
function Projects({ onOpenProject, navigate }) {
- const { PROJECTS: ALL_PROJECTS, ASSETS } = window.ZAMPP_DATA;
+ const [projects, setProjects] = React.useState(window.ZAMPP_DATA.PROJECTS);
+ const { ASSETS } = window.ZAMPP_DATA;
const [search, setSearch] = React.useState('');
const [view, setView] = React.useState('grid');
- let projects = ALL_PROJECTS;
- if (search) projects = projects.filter(p => p.name.toLowerCase().includes(search.toLowerCase()));
+ const [showNew, setShowNew] = React.useState(false);
+
+ const onCreated = (p) => {
+ const updated = [p, ...window.ZAMPP_DATA.PROJECTS];
+ window.ZAMPP_DATA.PROJECTS = updated;
+ setProjects(updated);
+ };
+
+ let filtered = projects;
+ if (search) filtered = filtered.filter(p => p.name.toLowerCase().includes(search.toLowerCase()));
return (
Projects
-
{projects.length} projects
+
{filtered.length} projects
@@ -21,35 +71,43 @@ function Projects({ onOpenProject, navigate }) {
-
+
- {projects.length === 0 ? (
-
No projects yet. Create one to get started.
+ {filtered.length === 0 ? (
+
+ {search ? 'No matching projects.' : 'No projects yet.'}
+ {!search && (
+
+
+
+ )}
+
) : view === 'grid' ? (
- {projects.map(p =>
onOpenProject(p)} />)}
+ {filtered.map(p => onOpenProject(p)} />)}
) : (
Project
Assets
Storage
Updated
- {projects.map(p => (
+ {filtered.map(p => (
onOpenProject(p)}>
-
{p.assets}
+
{p.assets || 0}
—
-
{p.updated}
+
{p.updated || '—'}
))}
)}
+ {showNew &&
setShowNew(false)} onCreated={onCreated} />}
);
}
@@ -69,16 +127,16 @@ function ProjectCard({ project, assets, onOpen }) {
-
+
{project.name}
- {project.assets} assets
+ {project.assets || 0} assets
·
- updated {project.updated}
+ updated {project.updated || '—'}