import { THEME_CSS, escapeHtml, escapeAttr, tabNavHTML } from "../render/layout"; import { listProjectsWithCounts, createProject, canAdminProject, StoreError, type ProjectWithCounts, type UserRow } from "../store"; import { relTime } from "../render/components"; import { getDefaultUpstreamUrl, webUrlFromClone } from "./projectUpstreams"; async function projectCard(p: ProjectWithCounts, viewer: UserRow | null): Promise { const issuesHref = `/${encodeURIComponent(p.owner)}/${encodeURIComponent(p.name)}/issues`; const settingsHref = `/${encodeURIComponent(p.owner)}/${encodeURIComponent(p.name)}/settings/upstreams`; const desc = p.description ? `
${escapeHtml(p.description)}
` : ""; const upstreamClone = getDefaultUpstreamUrl(p); const upstreamWebUrl = upstreamClone ? webUrlFromClone(upstreamClone) : null; const upstreamIcon = upstreamWebUrl ? `🔗` : ""; const adminIcon = await canAdminProject(p.id, viewer) ? `⚙️` : ""; const iconsHtml = (upstreamIcon || adminIcon) ? `${upstreamIcon}${adminIcon}` : ""; return `
${escapeHtml(p.owner)}/${escapeHtml(p.name)}
${desc}
📂 ${p.total_count} · 🟢 ${p.open_count} · ${relTime(p.updated_at)} ${iconsHtml}
`; } export async function buildHome( viewer: UserRow | null, flash: { kind: "ok" | "err"; msg: string } | null = null ): Promise { const projects = await listProjectsWithCounts(viewer); const cards = await Promise.all(projects.map((p) => projectCard(p, viewer))); const list = projects.length ? cards.join("") : `
还没有项目。在下面创建一个:
`; const flashHtml = flash ? `
${escapeHtml(flash.msg)}
` : ""; return ` ework-web · 项目
🏠
${tabNavHTML("projects", viewer ? { login: viewer.login, is_admin: viewer.is_admin } : undefined)}
${flashHtml}

项目

${list}

新建项目

`; } export async function handleCreateProject( form: Record, defaultModel: string, ): Promise<{ location: string; error?: string; projectId?: number }> { const owner = (form.owner ?? "").trim(); const name = (form.name ?? "").trim(); const description = (form.description ?? "").trim(); if (!owner || !name) return { location: "/projects", error: "owner 和 name 必填" }; try { const p = await createProject(owner, name, description, defaultModel); return { location: `/${encodeURIComponent(p.owner)}/${encodeURIComponent(p.name)}/issues`, projectId: p.id }; } catch (e) { return { location: "/projects", error: e instanceof StoreError ? e.message : e instanceof Error ? e.message : "创建失败", }; } }