dragonflight/services/web-ui/public/screens-projects.jsx

89 lines
4 KiB
JavaScript

// screens-projects.jsx
function Projects({ onOpenProject, navigate }) {
const { PROJECTS: ALL_PROJECTS, 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()));
return (
<div className="page">
<div className="page-header">
<h1>Projects</h1>
<span className="subtitle">{projects.length} projects</span>
<div className="spacer" />
<div className="search" style={{ width: 240 }}>
<Icon name="search" className="search-icon" />
<input value={search} onChange={e => setSearch(e.target.value)} placeholder="Search projects…" />
</div>
<div className="tab-group">
<button className={view === 'grid' ? 'active' : ''} onClick={() => setView('grid')}><Icon name="grid" size={12} /></button>
<button className={view === 'list' ? 'active' : ''} onClick={() => setView('list')}><Icon name="list" size={12} /></button>
</div>
<button className="btn primary"><Icon name="plus" />New project</button>
</div>
<div className="page-body">
{projects.length === 0 ? (
<div style={{ padding: 40, textAlign: 'center', color: 'var(--text-3)' }}>No projects yet. Create one to get started.</div>
) : view === 'grid' ? (
<div className="projects-grid">
{projects.map(p => <ProjectCard key={p.id} project={p} assets={ASSETS} onOpen={() => onOpenProject(p)} />)}
</div>
) : (
<div className="panel">
<div className="list-row head" style={{ padding: '12px 16px', gridTemplateColumns: '1fr 100px 120px 120px 80px' }}>
<div>Project</div><div>Assets</div><div>Storage</div><div>Updated</div><div></div>
</div>
{projects.map(p => (
<div key={p.id} className="list-row" style={{ padding: '12px 16px', gridTemplateColumns: '1fr 100px 120px 120px 80px', borderBottom: '1px solid var(--border)', cursor: 'pointer' }} onClick={() => onOpenProject(p)}>
<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
<div style={{ width: 8, height: 32, borderRadius: 2, background: p.color }} />
<div>{p.name}</div>
</div>
<div className="col-sub">{p.assets}</div>
<div className="col-sub"></div>
<div className="col-sub">{p.updated}</div>
<button className="icon-btn" onClick={e => e.stopPropagation()}><Icon name="more" /></button>
</div>
))}
</div>
)}
</div>
</div>
);
}
function ProjectCard({ project, assets, onOpen }) {
const thumbAssets = assets.filter(a => a.project_id === project.id).slice(0, 4);
return (
<div className="project-card" onClick={onOpen}>
<div className="project-thumb-grid">
{Array.from({ length: 4 }).map((_, i) => (
<div key={i} className="project-thumb-cell">
{thumbAssets[i]
? <AssetThumb asset={thumbAssets[i]} />
: <FauxFrame />}
</div>
))}
</div>
<div className="project-card-body">
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<span style={{ width: 10, height: 10, borderRadius: 2, background: project.color }} />
<span style={{ fontWeight: 600, fontSize: 14 }}>{project.name}</span>
</div>
<div className="project-meta">
<span>{project.assets} assets</span>
<span>·</span>
<span>updated {project.updated}</span>
</div>
<div className="project-bar">
<div className="project-segment" style={{ width: '70%', background: project.color }} />
<div className="project-segment" style={{ width: '20%', background: 'var(--bg-4)' }} />
</div>
</div>
</div>
);
}
window.Projects = Projects;