create-githat-app 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +48 -18
  2. package/dist/cli.js +1161 -114
  3. package/package.json +34 -9
  4. package/templates/agent/app/(auth)/sign-in/page.tsx.hbs +9 -0
  5. package/templates/agent/app/(auth)/sign-up/page.tsx.hbs +9 -0
  6. package/templates/agent/app/admin/agent/page.tsx.hbs +127 -0
  7. package/templates/agent/app/globals.css.hbs +87 -0
  8. package/templates/agent/app/layout.tsx.hbs +41 -0
  9. package/templates/agent/app/page.tsx.hbs +100 -0
  10. package/templates/agent/next.config.ts.hbs +8 -0
  11. package/templates/agent/postcss.config.mjs.hbs +14 -0
  12. package/templates/agent/proxy.ts.hbs +10 -0
  13. package/templates/agent/tsconfig.json.hbs +21 -0
  14. package/templates/base/.env.example.hbs +2 -2
  15. package/templates/base/.env.local.example.hbs +20 -0
  16. package/templates/base/.env.local.hbs +13 -2
  17. package/templates/base/.github/CODEOWNERS.hbs +1 -0
  18. package/templates/base/.github/SECURITY.md +10 -0
  19. package/templates/base/.github/dependabot.yml +19 -0
  20. package/templates/base/.github/workflows/ci.yml.hbs +77 -0
  21. package/templates/base/.github/workflows/githat-policy.yml +51 -0
  22. package/templates/base/.gitignore.hbs +17 -2
  23. package/templates/base/README.md.hbs +31 -52
  24. package/templates/classroom/app/(auth)/sign-in/page.tsx.hbs +9 -0
  25. package/templates/classroom/app/(auth)/sign-up/page.tsx.hbs +9 -0
  26. package/templates/classroom/app/globals.css.hbs +87 -0
  27. package/templates/classroom/app/layout.tsx.hbs +41 -0
  28. package/templates/classroom/app/page.tsx.hbs +103 -0
  29. package/templates/classroom/app/projects/[id]/feedback/page.tsx.hbs +159 -0
  30. package/templates/classroom/app/projects/[id]/present/page.tsx.hbs +113 -0
  31. package/templates/classroom/next.config.ts.hbs +8 -0
  32. package/templates/classroom/postcss.config.mjs.hbs +14 -0
  33. package/templates/classroom/proxy.ts.hbs +10 -0
  34. package/templates/classroom/tsconfig.json.hbs +21 -0
  35. package/templates/content/app/(auth)/sign-in/page.tsx.hbs +9 -0
  36. package/templates/content/app/(auth)/sign-up/page.tsx.hbs +9 -0
  37. package/templates/content/app/globals.css.hbs +87 -0
  38. package/templates/content/app/layout.tsx.hbs +41 -0
  39. package/templates/content/app/newsletter/page.tsx.hbs +90 -0
  40. package/templates/content/app/page.tsx.hbs +105 -0
  41. package/templates/content/app/posts/[slug]/page.tsx.hbs +119 -0
  42. package/templates/content/next.config.ts.hbs +8 -0
  43. package/templates/content/postcss.config.mjs.hbs +14 -0
  44. package/templates/content/proxy.ts.hbs +10 -0
  45. package/templates/content/tsconfig.json.hbs +21 -0
  46. package/templates/dashboard/app/(auth)/sign-in/page.tsx.hbs +9 -0
  47. package/templates/dashboard/app/(auth)/sign-up/page.tsx.hbs +9 -0
  48. package/templates/dashboard/app/admin/data/[entity]/page.tsx.hbs +68 -0
  49. package/templates/dashboard/app/admin/page.tsx.hbs +59 -0
  50. package/templates/dashboard/app/globals.css.hbs +87 -0
  51. package/templates/dashboard/app/layout.tsx.hbs +41 -0
  52. package/templates/dashboard/app/page.tsx.hbs +57 -0
  53. package/templates/dashboard/next.config.ts.hbs +8 -0
  54. package/templates/dashboard/postcss.config.mjs.hbs +14 -0
  55. package/templates/dashboard/proxy.ts.hbs +10 -0
  56. package/templates/dashboard/src/lib/db.ts.hbs +39 -0
  57. package/templates/dashboard/tsconfig.json.hbs +21 -0
  58. package/templates/fullstack/apps-api-express/.env.example.hbs +6 -0
  59. package/templates/fullstack/apps-api-express/.env.local.hbs +6 -0
  60. package/templates/fullstack/apps-api-express/package.json.hbs +24 -0
  61. package/templates/fullstack/apps-api-express/src/index.ts.hbs +41 -0
  62. package/templates/fullstack/apps-api-express/src/routes/health.ts.hbs +11 -0
  63. package/templates/fullstack/apps-api-express/src/routes/users.ts.hbs +43 -0
  64. package/templates/fullstack/apps-api-express/tsconfig.json.hbs +16 -0
  65. package/templates/fullstack/apps-api-fastify/.env.example.hbs +6 -0
  66. package/templates/fullstack/apps-api-fastify/.env.local.hbs +6 -0
  67. package/templates/fullstack/apps-api-fastify/package.json.hbs +22 -0
  68. package/templates/fullstack/apps-api-fastify/src/index.ts.hbs +28 -0
  69. package/templates/fullstack/apps-api-fastify/src/routes/health.ts.hbs +11 -0
  70. package/templates/fullstack/apps-api-fastify/src/routes/users.ts.hbs +43 -0
  71. package/templates/fullstack/apps-api-fastify/tsconfig.json.hbs +16 -0
  72. package/templates/fullstack/apps-api-hono/.env.example.hbs +6 -0
  73. package/templates/fullstack/apps-api-hono/.env.local.hbs +6 -0
  74. package/templates/fullstack/apps-api-hono/package.json.hbs +22 -0
  75. package/templates/fullstack/apps-api-hono/src/index.ts.hbs +35 -0
  76. package/templates/fullstack/apps-api-hono/src/routes/health.ts.hbs +11 -0
  77. package/templates/fullstack/apps-api-hono/src/routes/users.ts.hbs +43 -0
  78. package/templates/fullstack/apps-api-hono/tsconfig.json.hbs +16 -0
  79. package/templates/fullstack/apps-web-nextjs/.env.example.hbs +5 -0
  80. package/templates/fullstack/apps-web-nextjs/.env.local.hbs +5 -0
  81. package/templates/fullstack/apps-web-nextjs/app/(auth)/forgot-password/page.tsx.hbs +11 -0
  82. package/templates/fullstack/apps-web-nextjs/app/(auth)/reset-password/page.tsx.hbs +39 -0
  83. package/templates/fullstack/apps-web-nextjs/app/(auth)/sign-in/page.tsx.hbs +9 -0
  84. package/templates/fullstack/apps-web-nextjs/app/(auth)/sign-up/page.tsx.hbs +9 -0
  85. package/templates/fullstack/apps-web-nextjs/app/(auth)/verify-email/page.tsx.hbs +11 -0
  86. package/templates/fullstack/apps-web-nextjs/app/dashboard/layout.tsx.hbs +15 -0
  87. package/templates/fullstack/apps-web-nextjs/app/dashboard/page.tsx.hbs +27 -0
  88. package/templates/fullstack/apps-web-nextjs/app/globals.css.hbs +21 -0
  89. package/templates/fullstack/apps-web-nextjs/app/layout.tsx.hbs +30 -0
  90. package/templates/fullstack/apps-web-nextjs/app/page.tsx.hbs +17 -0
  91. package/templates/fullstack/apps-web-nextjs/next.config.ts.hbs +16 -0
  92. package/templates/fullstack/apps-web-nextjs/package.json.hbs +34 -0
  93. package/templates/fullstack/apps-web-nextjs/postcss.config.mjs.hbs +9 -0
  94. package/templates/fullstack/apps-web-nextjs/tsconfig.json.hbs +21 -0
  95. package/templates/fullstack/root/.gitignore.hbs +42 -0
  96. package/templates/fullstack/root/githat.yaml.hbs +17 -0
  97. package/templates/fullstack/root/package.json.hbs +15 -0
  98. package/templates/fullstack/root/turbo.json.hbs +20 -0
  99. package/templates/marketplace/CULTURE.md +74 -0
  100. package/templates/marketplace/app/(auth)/sign-in/page.tsx.hbs +9 -0
  101. package/templates/marketplace/app/(auth)/sign-up/page.tsx.hbs +9 -0
  102. package/templates/marketplace/app/(shop)/[slug]/p/[productId]/page.tsx.hbs +99 -0
  103. package/templates/marketplace/app/(shop)/[slug]/page.tsx.hbs +90 -0
  104. package/templates/marketplace/app/admin/page.tsx.hbs +95 -0
  105. package/templates/marketplace/app/cart/page.tsx.hbs +157 -0
  106. package/templates/marketplace/app/globals.css.hbs +87 -0
  107. package/templates/marketplace/app/layout.tsx.hbs +77 -0
  108. package/templates/marketplace/app/page.tsx.hbs +178 -0
  109. package/templates/marketplace/app/sell/page.tsx.hbs +78 -0
  110. package/templates/marketplace/next.config.ts.hbs +8 -0
  111. package/templates/marketplace/postcss.config.mjs.hbs +14 -0
  112. package/templates/marketplace/proxy.ts.hbs +10 -0
  113. package/templates/marketplace/src/lib/anon-session.ts.hbs +117 -0
  114. package/templates/marketplace/src/lib/categories.ts.hbs +35 -0
  115. package/templates/marketplace/tsconfig.json.hbs +21 -0
  116. package/templates/nextjs/.github/workflows/deploy.yml.hbs +107 -0
  117. package/templates/nextjs/app/(auth)/reset-password/page.tsx.hbs +106 -0
  118. package/templates/nextjs/app/globals.css.hbs +4 -3
  119. package/templates/nextjs/app/layout.tsx.hbs +5 -1
  120. package/templates/nextjs/app/page.tsx.hbs +3 -6
  121. package/templates/nextjs/next.config.ts.hbs +5 -2
  122. package/templates/nextjs/proxy.ts.hbs +1 -1
  123. package/templates/plain/app/(auth)/sign-in/page.tsx.hbs +9 -0
  124. package/templates/plain/app/(auth)/sign-up/page.tsx.hbs +9 -0
  125. package/templates/plain/app/globals.css.hbs +87 -0
  126. package/templates/plain/app/layout.tsx.hbs +41 -0
  127. package/templates/plain/app/page.tsx.hbs +123 -0
  128. package/templates/plain/next.config.ts.hbs +8 -0
  129. package/templates/plain/postcss.config.mjs.hbs +14 -0
  130. package/templates/plain/proxy.ts.hbs +10 -0
  131. package/templates/plain/tsconfig.json.hbs +21 -0
  132. package/templates/portfolio/app/(auth)/sign-in/page.tsx.hbs +9 -0
  133. package/templates/portfolio/app/(auth)/sign-up/page.tsx.hbs +9 -0
  134. package/templates/portfolio/app/globals.css.hbs +87 -0
  135. package/templates/portfolio/app/layout.tsx.hbs +41 -0
  136. package/templates/portfolio/app/page.tsx.hbs +86 -0
  137. package/templates/portfolio/next.config.ts.hbs +8 -0
  138. package/templates/portfolio/postcss.config.mjs.hbs +14 -0
  139. package/templates/portfolio/proxy.ts.hbs +10 -0
  140. package/templates/portfolio/tsconfig.json.hbs +21 -0
  141. package/templates/react-vite/src/App.tsx.hbs +11 -9
  142. package/templates/react-vite/src/index.css.hbs +4 -3
  143. package/templates/react-vite/src/pages/Home.tsx.hbs +3 -6
  144. package/templates/saas/app/(auth)/sign-in/page.tsx.hbs +9 -0
  145. package/templates/saas/app/(auth)/sign-up/page.tsx.hbs +9 -0
  146. package/templates/saas/app/admin/billing/page.tsx.hbs +145 -0
  147. package/templates/saas/app/admin/page.tsx.hbs +106 -0
  148. package/templates/saas/app/admin/team/page.tsx.hbs +134 -0
  149. package/templates/saas/app/globals.css.hbs +87 -0
  150. package/templates/saas/app/layout.tsx.hbs +41 -0
  151. package/templates/saas/app/page.tsx.hbs +108 -0
  152. package/templates/saas/app/pricing/page.tsx.hbs +131 -0
  153. package/templates/saas/next.config.ts.hbs +8 -0
  154. package/templates/saas/postcss.config.mjs.hbs +14 -0
  155. package/templates/saas/proxy.ts.hbs +10 -0
  156. package/templates/saas/tsconfig.json.hbs +21 -0
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@{{projectName}}/web",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev --port 3000",
7
+ "build": "next build",
8
+ "start": "next start",
9
+ "lint": "next lint",
10
+ "typecheck": "tsc --noEmit"
11
+ },
12
+ "dependencies": {
13
+ "@githat/nextjs": "^0.2.6",
14
+ "@githat/ui": "^1.0.0",
15
+ "next": "^16.0.0",
16
+ "react": "^19.0.0",
17
+ "react-dom": "^19.0.0"
18
+ },
19
+ "devDependencies": {
20
+ {{#if typescript}}
21
+ "@types/node": "^22.0.0",
22
+ "@types/react": "^19.0.0",
23
+ "@types/react-dom": "^19.0.0",
24
+ "typescript": "^5.9.0",
25
+ {{/if}}
26
+ {{#if useTailwind}}
27
+ "@tailwindcss/postcss": "^4.0.0",
28
+ "postcss": "^8.4.0",
29
+ "tailwindcss": "^4.0.0"
30
+ {{else}}
31
+ "@types/node": "^22.0.0"
32
+ {{/if}}
33
+ }
34
+ }
@@ -0,0 +1,9 @@
1
+ {{#if useTailwind}}
2
+ const config = {
3
+ plugins: {
4
+ '@tailwindcss/postcss': {},
5
+ },
6
+ };
7
+
8
+ export default config;
9
+ {{/if}}
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "preserve",
15
+ "incremental": true,
16
+ "plugins": [{ "name": "next" }],
17
+ "paths": { "@/*": ["./*"] }
18
+ },
19
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
20
+ "exclude": ["node_modules"]
21
+ }
@@ -0,0 +1,42 @@
1
+ # Dependencies
2
+ node_modules/
3
+ .pnp
4
+ .pnp.js
5
+
6
+ # Build
7
+ dist/
8
+ .next/
9
+ out/
10
+ build/
11
+
12
+ # Turbo
13
+ .turbo/
14
+
15
+ # Environment
16
+ .env
17
+ .env.local
18
+ .env.*.local
19
+
20
+ # IDE
21
+ .idea/
22
+ .vscode/
23
+ *.swp
24
+ *.swo
25
+
26
+ # OS
27
+ .DS_Store
28
+ Thumbs.db
29
+
30
+ # Logs
31
+ *.log
32
+ npm-debug.log*
33
+ yarn-debug.log*
34
+ yarn-error.log*
35
+ pnpm-debug.log*
36
+
37
+ # Testing
38
+ coverage/
39
+ .nyc_output/
40
+
41
+ # TypeScript
42
+ *.tsbuildinfo
@@ -0,0 +1,17 @@
1
+ version: 1
2
+ name: {{projectName}}
3
+
4
+ apps:
5
+ web:
6
+ type: {{framework}}
7
+ path: apps/web
8
+ domain: {{projectName}}.githat.io
9
+ env:
10
+ NEXT_PUBLIC_API_URL: $\{{apps.api.url}}
11
+
12
+ api:
13
+ type: {{backendFramework}}
14
+ path: apps/api
15
+ domain: api.{{projectName}}.githat.io
16
+ env:
17
+ GITHAT_PUBLISHABLE_KEY: $\{{secrets.GITHAT_PUBLISHABLE_KEY}}
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "private": true,
4
+ "workspaces": ["apps/*", "packages/*"],
5
+ "scripts": {
6
+ "dev": "turbo dev",
7
+ "build": "turbo build",
8
+ "lint": "turbo lint",
9
+ "typecheck": "turbo typecheck"
10
+ },
11
+ "devDependencies": {
12
+ "turbo": "^2.3.0"
13
+ },
14
+ "packageManager": "{{packageManager}}@10.9.2"
15
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "https://turbo.build/schema.json",
3
+ "ui": "tui",
4
+ "tasks": {
5
+ "build": {
6
+ "dependsOn": ["^build"],
7
+ "outputs": [".next/**", "!.next/cache/**", "dist/**"]
8
+ },
9
+ "dev": {
10
+ "cache": false,
11
+ "persistent": true
12
+ },
13
+ "lint": {
14
+ "dependsOn": ["^lint"]
15
+ },
16
+ "typecheck": {
17
+ "dependsOn": ["^typecheck"]
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,74 @@
1
+ # Marketplace template — culture notes
2
+
3
+ This template ships with Latin American framing by default: bilingual
4
+ microcopy (Spanish primary, English gloss), a category seed list
5
+ suited to a Caribbean *colmado*, warm-amber + produce-green palette.
6
+ That's because the first real consumer is **Colmado**, a Dominican-
7
+ flavored bodega marketplace. Anglo developers will get bilingual
8
+ copy out of the box — most US neighborhoods that *need* a
9
+ marketplace template are multilingual anyway.
10
+
11
+ If you're targeting a different region, change these in order:
12
+
13
+ 1. `src/lib/categories.ts` — category seed data
14
+ 2. `app/page.tsx` — hero strings
15
+ 3. `src/components/AuthChoice.tsx` — checkout copy
16
+ 4. `app/globals.css` — `--brand-primary` / `--brand-secondary`
17
+
18
+ Everything else is region-agnostic.
19
+
20
+ ## What "colmado" means
21
+
22
+ A *colmado* in Latin America (Caribbean especially — Dominican
23
+ Republic, Puerto Rico) is a corner store, but more than a corner
24
+ store: it's the social anchor of a city block. Music plays. Domino
25
+ tables out front. The shopkeeper (*colmadero*) knows your kids by
26
+ name and gives you *fiao* — store credit on a handshake — when
27
+ you're between paychecks. Recargas (phone top-ups) are universal.
28
+ Single eggs, single cigarettes, loose rice by the pound — sold by
29
+ the *menudeo*, not in pre-packed quantities.
30
+
31
+ Cuban *bodegas* and Mexican *misceláneas* / *tienditas* fill the
32
+ same social slot but with different vocab and different drink
33
+ brands.
34
+
35
+ ## Microcopy that matters
36
+
37
+ These strings are baked into the template. Don't translate them
38
+ literally if you reskin — find local equivalents.
39
+
40
+ | Spanish | English gloss | Where it appears |
41
+ |---|---|---|
42
+ | **Pídelo y te lo llevamos** | Order it, we'll bring it to you | Cart CTA |
43
+ | **Tu colmadero** | Your shopkeeper (NOT "vendor") | Vendor profile label |
44
+ | **Tu funda** | Your bag (Dominican; replaces "Cart") | Top nav cart icon label |
45
+ | **Recargas** | Phone top-ups (universally understood, keep Spanish) | Category tile |
46
+ | **Cerquita de ti** | Right near you (warmer than "near you") | Homepage hero |
47
+ | **Lo de siempre** | The usual (for re-order) | Saved-cart shortcut |
48
+ | **Está fresquecito** | Nice and fresh (for produce) | Freshness tag |
49
+ | **Abierto ahorita** | Open right now (colloquial) | Open/closed badge |
50
+ | **Un momentico…** | One moment… | Loading state |
51
+ | **Llegó tu pedido, ¡buen provecho!** | Your order is here, enjoy! | Delivery confirmation |
52
+
53
+ ## Patterns to avoid (Latin American context)
54
+
55
+ - "Carrito de compras" — too Anglo-translated. Use **"Tu funda."**
56
+ - "Vendedor" — clinical. Use **"Tu colmadero"** or **"Doña/Don [Nombre]."**
57
+ - *Usted* everywhere — formal, distancing. Use *tú* unless the audience is older.
58
+ - Cartoon sombreros / maracas / "spicy" tropes — condescending.
59
+ - Demanding a credit card up front — kills the *fiao* spirit. Cash
60
+ on delivery and tab-based payment must be first-class options.
61
+ - Sterile English category names like "Beverages." Use **"Bebidas /
62
+ Cervezas frías"** with the freshness signal preserved.
63
+ - Treating *menudeo* (single egg, single cigarette) as broken data.
64
+ These are real SKUs.
65
+
66
+ ## Why the bilingual default helps US adoption too
67
+
68
+ The template's first audience is Latin American, but the second is
69
+ the **US Latino diaspora and the Anglo neighborhoods buying from
70
+ local bodegas**. NYC bodegas, Texas tienditas, halal corner stores
71
+ in every borough — same DNA, same UX needs. Shipping bilingual by
72
+ default means the diaspora developer doesn't fight the template,
73
+ and Anglo developers building locally get an honest representation
74
+ of who their users are.
@@ -0,0 +1,9 @@
1
+ import { SignInForm } from '@githat/nextjs';
2
+
3
+ export default function SignInPage() {
4
+ return (
5
+ <main {{#if useTailwind}}className="flex items-center justify-center min-h-screen bg-[#09090b]"{{else}}style=\{{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', background: '#09090b' }}{{/if}}>
6
+ <SignInForm signUpUrl="/sign-up" {{#if includeForgotPassword}}forgotPasswordUrl="/forgot-password"{{/if}} />
7
+ </main>
8
+ );
9
+ }
@@ -0,0 +1,9 @@
1
+ import { SignUpForm } from '@githat/nextjs';
2
+
3
+ export default function SignUpPage() {
4
+ return (
5
+ <main {{#if useTailwind}}className="flex items-center justify-center min-h-screen bg-[#09090b]"{{else}}style=\{{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', background: '#09090b' }}{{/if}}>
6
+ <SignUpForm signInUrl="/sign-in" />
7
+ </main>
8
+ );
9
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Product detail — `/<slug>/p/<productId>`.
3
+ *
4
+ * Server component. Fetch by (slug, productId), render. The starter
5
+ * ships sample content so the route works even before a backend
6
+ * exists. Cart writes go through `/api/cart/add` (you build that
7
+ * route handler against your data layer).
8
+ */
9
+
10
+ import Link from 'next/link';
11
+
12
+ interface PageProps {
13
+ params: Promise<{ slug: string; productId: string }>;
14
+ }
15
+
16
+ export default async function ProductPage({ params }: PageProps) {
17
+ const { slug, productId } = await params;
18
+
19
+ // TODO: replace with a real fetch
20
+ const product = {
21
+ id: productId,
22
+ name: 'Plátanos verdes (libra)',
23
+ price: 0.5,
24
+ description:
25
+ 'Plátanos verdes recién llegados, perfectos para mangú. Vendido por libra.',
26
+ fresh: true,
27
+ storeName: 'Colmado de ejemplo',
28
+ storeOwner: 'Don Tito',
29
+ storeSlug: slug,
30
+ };
31
+
32
+ return (
33
+ <div style=\{{ background: 'var(--bg)', color: 'var(--fg)', minHeight: 'calc(100vh - 64px)' }}>
34
+ <div style=\{{ maxWidth: '40rem', margin: '0 auto', padding: 'var(--space-8) var(--space-4)' }}>
35
+ <Link href={`/${product.storeSlug}`} style=\{{
36
+ fontSize: '0.875rem',
37
+ color: 'var(--fg-muted)',
38
+ marginBottom: 'var(--space-4)',
39
+ display: 'inline-block',
40
+ }}>
41
+ ← {product.storeName}
42
+ </Link>
43
+
44
+ <h1 style=\{{ fontFamily: 'var(--font-wordmark)', fontSize: '2rem', marginBottom: 'var(--space-2)' }}>
45
+ {product.name}
46
+ </h1>
47
+
48
+ {product.fresh && (
49
+ <p style=\{{
50
+ display: 'inline-block',
51
+ padding: 'var(--space-1) var(--space-3)',
52
+ borderRadius: 'var(--radius-full, 9999px)',
53
+ background: 'var(--success)',
54
+ color: 'var(--bg)',
55
+ fontSize: '0.75rem',
56
+ fontWeight: 600,
57
+ marginBottom: 'var(--space-3)',
58
+ }}>
59
+ Está fresquecito
60
+ </p>
61
+ )}
62
+
63
+ <p style=\{{ fontSize: '1.5rem', fontWeight: 600, marginBottom: 'var(--space-4)' }}>
64
+ ${product.price.toFixed(2)}
65
+ </p>
66
+
67
+ <p style=\{{ color: 'var(--fg-muted)', marginBottom: 'var(--space-6)', lineHeight: 1.6 }}>
68
+ {product.description}
69
+ </p>
70
+
71
+ <p style=\{{ fontSize: '0.875rem', color: 'var(--fg-subtle)', marginBottom: 'var(--space-6)' }}>
72
+ De tu colmadero: <strong>{product.storeOwner}</strong>
73
+ </p>
74
+
75
+ {/*
76
+ Cart-add is a real fetch in production — you wire it to
77
+ /api/cart/add against your data layer + the anon-session
78
+ cookie from src/lib/anon-session.ts.
79
+ */}
80
+ <form action="/api/cart/add" method="POST">
81
+ <input type="hidden" name="productId" value={product.id} />
82
+ <input type="hidden" name="slug" value={product.storeSlug} />
83
+ <button type="submit" style=\{{
84
+ padding: 'var(--space-3) var(--space-6)',
85
+ borderRadius: 'var(--radius-md, 0.5rem)',
86
+ border: 'none',
87
+ background: 'var(--primary)',
88
+ color: 'var(--bg)',
89
+ fontWeight: 600,
90
+ fontSize: '1rem',
91
+ cursor: 'pointer',
92
+ }}>
93
+ Echar a la funda — Add to bag
94
+ </button>
95
+ </form>
96
+ </div>
97
+ </div>
98
+ );
99
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * A single colmadero's storefront — `/<slug>`.
3
+ *
4
+ * Server component. Take the slug, fetch the colmado's profile +
5
+ * products from your data layer, render. The starter ships static
6
+ * sample content so the route renders even without a backend.
7
+ *
8
+ * Real implementations:
9
+ * - Read by slug from your `colmados` table (Postgres, DynamoDB,
10
+ * whatever)
11
+ * - 404 via `notFound()` from 'next/navigation' if the slug is
12
+ * unknown
13
+ * - Pre-render the popular ones via `generateStaticParams()`
14
+ */
15
+
16
+ import Link from 'next/link';
17
+
18
+ interface PageProps {
19
+ params: Promise<{ slug: string }>;
20
+ }
21
+
22
+ export default async function ShopPage({ params }: PageProps) {
23
+ const { slug } = await params;
24
+
25
+ // TODO: replace with a real fetch
26
+ const colmado = {
27
+ name: 'Colmado de ejemplo',
28
+ slug,
29
+ owner: 'Don Tito',
30
+ address: 'Calle Duarte #42',
31
+ open: true,
32
+ products: [
33
+ { id: '1', name: 'Plátanos verdes (libra)', price: 0.5, fresh: true },
34
+ { id: '2', name: 'Café Santo Domingo (1lb)', price: 6.99, fresh: false },
35
+ { id: '3', name: 'Salami Induveca', price: 4.5, fresh: false },
36
+ { id: '4', name: 'Recarga Claro $5', price: 5.0, fresh: false },
37
+ ],
38
+ };
39
+
40
+ return (
41
+ <div style=\{{ background: 'var(--bg)', color: 'var(--fg)', minHeight: 'calc(100vh - 64px)' }}>
42
+ <div style=\{{ maxWidth: '48rem', margin: '0 auto', padding: 'var(--space-8) var(--space-4)' }}>
43
+ <header style=\{{ marginBottom: 'var(--space-8)' }}>
44
+ <h1 style=\{{ fontFamily: 'var(--font-wordmark)', fontSize: '2.25rem', marginBottom: 'var(--space-2)' }}>
45
+ {colmado.name}
46
+ </h1>
47
+ <p style=\{{ color: 'var(--fg-muted)', marginBottom: 'var(--space-2)' }}>
48
+ Tu colmadero: <strong>{colmado.owner}</strong>
49
+ </p>
50
+ <p style=\{{ color: 'var(--fg-subtle)', fontSize: '0.875rem', display: 'flex', gap: 'var(--space-3)', alignItems: 'center' }}>
51
+ <span>{colmado.address}</span>
52
+ <span>·</span>
53
+ <span style=\{{ color: colmado.open ? 'var(--success)' : 'var(--danger)' }}>
54
+ {colmado.open ? 'Abierto ahorita' : 'Cerrado'}
55
+ </span>
56
+ </p>
57
+ </header>
58
+
59
+ <section>
60
+ <h2 style=\{{ fontSize: '1.5rem', marginBottom: 'var(--space-4)' }}>Productos</h2>
61
+ <ul style=\{{ listStyle: 'none', display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))', gap: 'var(--space-3)' }}>
62
+ {colmado.products.map((p) => (
63
+ <li key={p.id}>
64
+ <Link href={`/${slug}/p/${p.id}`} style=\{{
65
+ display: 'block',
66
+ padding: 'var(--space-4)',
67
+ borderRadius: 'var(--radius-md, 0.5rem)',
68
+ border: '1px solid var(--border)',
69
+ background: 'var(--surface)',
70
+ color: 'inherit',
71
+ textDecoration: 'none',
72
+ }}>
73
+ <div style=\{{ fontWeight: 600, marginBottom: 'var(--space-1)' }}>{p.name}</div>
74
+ {p.fresh && (
75
+ <div style=\{{ fontSize: '0.75rem', color: 'var(--success)', marginBottom: 'var(--space-1)' }}>
76
+ Está fresquecito
77
+ </div>
78
+ )}
79
+ <div style=\{{ fontSize: '0.875rem', color: 'var(--fg-muted)' }}>
80
+ ${p.price.toFixed(2)}
81
+ </div>
82
+ </Link>
83
+ </li>
84
+ ))}
85
+ </ul>
86
+ </section>
87
+ </div>
88
+ </div>
89
+ );
90
+ }
@@ -0,0 +1,95 @@
1
+ 'use client';
2
+
3
+ import { useAuth } from '@githat/nextjs';
4
+
5
+ /**
6
+ * Seller dashboard — `/admin`.
7
+ *
8
+ * Auth-gated: a logged-in colmadero lands here to manage products,
9
+ * orders, hours, and bank payouts. This is a placeholder shell —
10
+ * wire the data fetches in your own backend.
11
+ *
12
+ * The four sections below mirror what a real bodega owner asks first:
13
+ * 1. ¿Quién me debe? (today's pending orders)
14
+ * 2. ¿Qué se está vendiendo? (this week's revenue)
15
+ * 3. ¿Qué tengo en stock? (inventory)
16
+ * 4. ¿Cuándo me pagan? (next payout date)
17
+ */
18
+ export default function AdminPage() {
19
+ const { isSignedIn, user, isLoading } = useAuth();
20
+
21
+ if (isLoading) {
22
+ return <Loading />;
23
+ }
24
+ if (!isSignedIn) {
25
+ return <SignInPrompt />;
26
+ }
27
+
28
+ return (
29
+ <div style=\{{ background: 'var(--bg)', color: 'var(--fg)', minHeight: 'calc(100vh - 64px)' }}>
30
+ <div style=\{{ maxWidth: '64rem', margin: '0 auto', padding: 'var(--space-8) var(--space-4)' }}>
31
+ <h1 style=\{{ fontFamily: 'var(--font-wordmark)', fontSize: '2rem', marginBottom: 'var(--space-2)' }}>
32
+ Hola, {user?.name || 'colmadero'}.
33
+ </h1>
34
+ <p style=\{{ color: 'var(--fg-muted)', marginBottom: 'var(--space-8)' }}>
35
+ Esto es lo que está pasando hoy en tu colmado.
36
+ </p>
37
+
38
+ <div style=\{{
39
+ display: 'grid',
40
+ gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))',
41
+ gap: 'var(--space-4)',
42
+ }}>
43
+ <Stat label="Pedidos pendientes" value="—" hint="Today's open orders" />
44
+ <Stat label="Ventas esta semana" value="$—" hint="This week's revenue" />
45
+ <Stat label="Productos activos" value="—" hint="In stock right now" />
46
+ <Stat label="Próximo pago" value="—" hint="Next bank payout" />
47
+ </div>
48
+
49
+ <p style=\{{ marginTop: 'var(--space-12)', fontSize: '0.875rem', color: 'var(--fg-subtle)' }}>
50
+ This dashboard is a starter shell — wire each tile to your
51
+ real data layer (Postgres, DynamoDB, Sebastn webhooks).
52
+ See <code>src/lib/anon-session.ts</code> for the cart-side
53
+ model.
54
+ </p>
55
+ </div>
56
+ </div>
57
+ );
58
+ }
59
+
60
+ function Stat({ label, value, hint }: { label: string; value: string; hint: string }) {
61
+ return (
62
+ <div style=\{{
63
+ padding: 'var(--space-5)',
64
+ borderRadius: 'var(--radius-md, 0.5rem)',
65
+ border: '1px solid var(--border)',
66
+ background: 'var(--surface)',
67
+ }}>
68
+ <div style=\{{ fontSize: '0.875rem', color: 'var(--fg-muted)', marginBottom: 'var(--space-1)' }}>{label}</div>
69
+ <div style=\{{ fontSize: '2rem', fontWeight: 600, marginBottom: 'var(--space-1)' }}>{value}</div>
70
+ <div style=\{{ fontSize: '0.75rem', color: 'var(--fg-subtle)' }}>{hint}</div>
71
+ </div>
72
+ );
73
+ }
74
+
75
+ function Loading() {
76
+ return (
77
+ <div style=\{{ display: 'flex', minHeight: 'calc(100vh - 64px)', alignItems: 'center', justifyContent: 'center', color: 'var(--fg-muted)' }}>
78
+ Un momentico…
79
+ </div>
80
+ );
81
+ }
82
+
83
+ function SignInPrompt() {
84
+ return (
85
+ <div style=\{{ display: 'flex', minHeight: 'calc(100vh - 64px)', alignItems: 'center', justifyContent: 'center' }}>
86
+ <div style=\{{ textAlign: 'center', maxWidth: '24rem' }}>
87
+ <h2 style=\{{ fontFamily: 'var(--font-wordmark)', marginBottom: 'var(--space-3)' }}>Inicia sesión</h2>
88
+ <p style=\{{ color: 'var(--fg-muted)', marginBottom: 'var(--space-4)' }}>
89
+ Sign in to see your colmado's dashboard.
90
+ </p>
91
+ <a href="/sign-in" style=\{{ color: 'var(--primary)' }}>Sign in →</a>
92
+ </div>
93
+ </div>
94
+ );
95
+ }