feat(conversion): Google-first login, truthful dashboard, SSR marketplace, template seeding
- login: OAuth/email on top, phone collapsed behind 'Sign in with phone instead' (prod providers: google on, email off, sms on — a developer should never see a phone field as the front door) - dashboard: plan card wired to GET /v1/billing/status; calls card shows '—' + pointer to per-server metrics (no user-facing usage endpoint exists; previous card showed invented '0 of 100,000 / Hobby') - templates: server-rendered grid (revalidate 300) via fetchPublicTemplates, client browser hydrates with initial data; inviting empty state with labeled starter ideas instead of 'No templates yet' - servers/new: removed upgrade nag from first analyze wait - scripts/seed-templates.mjs: idempotent dry-run-by-default seeder driving the real preview->create->live->publish flow for 6 first-party templates Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SXUwmPVRTD8AKQtio6gCN5
This commit is contained in:
@@ -58,6 +58,44 @@ export async function fetchTemplate(slug: string): Promise<TemplateDetail | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface TemplateSummary {
|
||||
id: string;
|
||||
slug: string;
|
||||
title: string;
|
||||
shortDescription: string;
|
||||
category: string;
|
||||
status: 'draft' | 'public' | 'hidden' | 'takedown';
|
||||
verified: boolean;
|
||||
forkCount: number;
|
||||
activeDeployments: number;
|
||||
ownerName: string | null;
|
||||
ownerOrgName: string | null;
|
||||
sourceServerId: string | null;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full public template list for server-rendering the marketplace grid so
|
||||
* crawlers see the templates in the initial HTML. Best-effort: returns empty
|
||||
* lists on error so the page still renders (the client component refetches
|
||||
* on filter changes anyway).
|
||||
*/
|
||||
export async function fetchPublicTemplates(): Promise<{
|
||||
templates: TemplateSummary[];
|
||||
categories: string[];
|
||||
}> {
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/v1/templates?sort=trending`, {
|
||||
next: { revalidate: 300 },
|
||||
});
|
||||
if (!res.ok) return { templates: [], categories: [] };
|
||||
const data = (await res.json()) as { templates?: TemplateSummary[]; categories?: string[] };
|
||||
return { templates: data.templates ?? [], categories: data.categories ?? [] };
|
||||
} catch {
|
||||
return { templates: [], categories: [] };
|
||||
}
|
||||
}
|
||||
|
||||
/** Slugs of public templates, for the sitemap. Best-effort: returns [] on error. */
|
||||
export async function fetchPublicTemplateSlugs(): Promise<string[]> {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user