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.
- package/README.md +48 -18
- package/dist/cli.js +1161 -114
- package/package.json +34 -9
- package/templates/agent/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/agent/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/agent/app/admin/agent/page.tsx.hbs +127 -0
- package/templates/agent/app/globals.css.hbs +87 -0
- package/templates/agent/app/layout.tsx.hbs +41 -0
- package/templates/agent/app/page.tsx.hbs +100 -0
- package/templates/agent/next.config.ts.hbs +8 -0
- package/templates/agent/postcss.config.mjs.hbs +14 -0
- package/templates/agent/proxy.ts.hbs +10 -0
- package/templates/agent/tsconfig.json.hbs +21 -0
- package/templates/base/.env.example.hbs +2 -2
- package/templates/base/.env.local.example.hbs +20 -0
- package/templates/base/.env.local.hbs +13 -2
- package/templates/base/.github/CODEOWNERS.hbs +1 -0
- package/templates/base/.github/SECURITY.md +10 -0
- package/templates/base/.github/dependabot.yml +19 -0
- package/templates/base/.github/workflows/ci.yml.hbs +77 -0
- package/templates/base/.github/workflows/githat-policy.yml +51 -0
- package/templates/base/.gitignore.hbs +17 -2
- package/templates/base/README.md.hbs +31 -52
- package/templates/classroom/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/classroom/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/classroom/app/globals.css.hbs +87 -0
- package/templates/classroom/app/layout.tsx.hbs +41 -0
- package/templates/classroom/app/page.tsx.hbs +103 -0
- package/templates/classroom/app/projects/[id]/feedback/page.tsx.hbs +159 -0
- package/templates/classroom/app/projects/[id]/present/page.tsx.hbs +113 -0
- package/templates/classroom/next.config.ts.hbs +8 -0
- package/templates/classroom/postcss.config.mjs.hbs +14 -0
- package/templates/classroom/proxy.ts.hbs +10 -0
- package/templates/classroom/tsconfig.json.hbs +21 -0
- package/templates/content/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/content/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/content/app/globals.css.hbs +87 -0
- package/templates/content/app/layout.tsx.hbs +41 -0
- package/templates/content/app/newsletter/page.tsx.hbs +90 -0
- package/templates/content/app/page.tsx.hbs +105 -0
- package/templates/content/app/posts/[slug]/page.tsx.hbs +119 -0
- package/templates/content/next.config.ts.hbs +8 -0
- package/templates/content/postcss.config.mjs.hbs +14 -0
- package/templates/content/proxy.ts.hbs +10 -0
- package/templates/content/tsconfig.json.hbs +21 -0
- package/templates/dashboard/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/dashboard/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/dashboard/app/admin/data/[entity]/page.tsx.hbs +68 -0
- package/templates/dashboard/app/admin/page.tsx.hbs +59 -0
- package/templates/dashboard/app/globals.css.hbs +87 -0
- package/templates/dashboard/app/layout.tsx.hbs +41 -0
- package/templates/dashboard/app/page.tsx.hbs +57 -0
- package/templates/dashboard/next.config.ts.hbs +8 -0
- package/templates/dashboard/postcss.config.mjs.hbs +14 -0
- package/templates/dashboard/proxy.ts.hbs +10 -0
- package/templates/dashboard/src/lib/db.ts.hbs +39 -0
- package/templates/dashboard/tsconfig.json.hbs +21 -0
- package/templates/fullstack/apps-api-express/.env.example.hbs +6 -0
- package/templates/fullstack/apps-api-express/.env.local.hbs +6 -0
- package/templates/fullstack/apps-api-express/package.json.hbs +24 -0
- package/templates/fullstack/apps-api-express/src/index.ts.hbs +41 -0
- package/templates/fullstack/apps-api-express/src/routes/health.ts.hbs +11 -0
- package/templates/fullstack/apps-api-express/src/routes/users.ts.hbs +43 -0
- package/templates/fullstack/apps-api-express/tsconfig.json.hbs +16 -0
- package/templates/fullstack/apps-api-fastify/.env.example.hbs +6 -0
- package/templates/fullstack/apps-api-fastify/.env.local.hbs +6 -0
- package/templates/fullstack/apps-api-fastify/package.json.hbs +22 -0
- package/templates/fullstack/apps-api-fastify/src/index.ts.hbs +28 -0
- package/templates/fullstack/apps-api-fastify/src/routes/health.ts.hbs +11 -0
- package/templates/fullstack/apps-api-fastify/src/routes/users.ts.hbs +43 -0
- package/templates/fullstack/apps-api-fastify/tsconfig.json.hbs +16 -0
- package/templates/fullstack/apps-api-hono/.env.example.hbs +6 -0
- package/templates/fullstack/apps-api-hono/.env.local.hbs +6 -0
- package/templates/fullstack/apps-api-hono/package.json.hbs +22 -0
- package/templates/fullstack/apps-api-hono/src/index.ts.hbs +35 -0
- package/templates/fullstack/apps-api-hono/src/routes/health.ts.hbs +11 -0
- package/templates/fullstack/apps-api-hono/src/routes/users.ts.hbs +43 -0
- package/templates/fullstack/apps-api-hono/tsconfig.json.hbs +16 -0
- package/templates/fullstack/apps-web-nextjs/.env.example.hbs +5 -0
- package/templates/fullstack/apps-web-nextjs/.env.local.hbs +5 -0
- package/templates/fullstack/apps-web-nextjs/app/(auth)/forgot-password/page.tsx.hbs +11 -0
- package/templates/fullstack/apps-web-nextjs/app/(auth)/reset-password/page.tsx.hbs +39 -0
- package/templates/fullstack/apps-web-nextjs/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/fullstack/apps-web-nextjs/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/fullstack/apps-web-nextjs/app/(auth)/verify-email/page.tsx.hbs +11 -0
- package/templates/fullstack/apps-web-nextjs/app/dashboard/layout.tsx.hbs +15 -0
- package/templates/fullstack/apps-web-nextjs/app/dashboard/page.tsx.hbs +27 -0
- package/templates/fullstack/apps-web-nextjs/app/globals.css.hbs +21 -0
- package/templates/fullstack/apps-web-nextjs/app/layout.tsx.hbs +30 -0
- package/templates/fullstack/apps-web-nextjs/app/page.tsx.hbs +17 -0
- package/templates/fullstack/apps-web-nextjs/next.config.ts.hbs +16 -0
- package/templates/fullstack/apps-web-nextjs/package.json.hbs +34 -0
- package/templates/fullstack/apps-web-nextjs/postcss.config.mjs.hbs +9 -0
- package/templates/fullstack/apps-web-nextjs/tsconfig.json.hbs +21 -0
- package/templates/fullstack/root/.gitignore.hbs +42 -0
- package/templates/fullstack/root/githat.yaml.hbs +17 -0
- package/templates/fullstack/root/package.json.hbs +15 -0
- package/templates/fullstack/root/turbo.json.hbs +20 -0
- package/templates/marketplace/CULTURE.md +74 -0
- package/templates/marketplace/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/marketplace/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/marketplace/app/(shop)/[slug]/p/[productId]/page.tsx.hbs +99 -0
- package/templates/marketplace/app/(shop)/[slug]/page.tsx.hbs +90 -0
- package/templates/marketplace/app/admin/page.tsx.hbs +95 -0
- package/templates/marketplace/app/cart/page.tsx.hbs +157 -0
- package/templates/marketplace/app/globals.css.hbs +87 -0
- package/templates/marketplace/app/layout.tsx.hbs +77 -0
- package/templates/marketplace/app/page.tsx.hbs +178 -0
- package/templates/marketplace/app/sell/page.tsx.hbs +78 -0
- package/templates/marketplace/next.config.ts.hbs +8 -0
- package/templates/marketplace/postcss.config.mjs.hbs +14 -0
- package/templates/marketplace/proxy.ts.hbs +10 -0
- package/templates/marketplace/src/lib/anon-session.ts.hbs +117 -0
- package/templates/marketplace/src/lib/categories.ts.hbs +35 -0
- package/templates/marketplace/tsconfig.json.hbs +21 -0
- package/templates/nextjs/.github/workflows/deploy.yml.hbs +107 -0
- package/templates/nextjs/app/(auth)/reset-password/page.tsx.hbs +106 -0
- package/templates/nextjs/app/globals.css.hbs +4 -3
- package/templates/nextjs/app/layout.tsx.hbs +5 -1
- package/templates/nextjs/app/page.tsx.hbs +3 -6
- package/templates/nextjs/next.config.ts.hbs +5 -2
- package/templates/nextjs/proxy.ts.hbs +1 -1
- package/templates/plain/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/plain/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/plain/app/globals.css.hbs +87 -0
- package/templates/plain/app/layout.tsx.hbs +41 -0
- package/templates/plain/app/page.tsx.hbs +123 -0
- package/templates/plain/next.config.ts.hbs +8 -0
- package/templates/plain/postcss.config.mjs.hbs +14 -0
- package/templates/plain/proxy.ts.hbs +10 -0
- package/templates/plain/tsconfig.json.hbs +21 -0
- package/templates/portfolio/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/portfolio/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/portfolio/app/globals.css.hbs +87 -0
- package/templates/portfolio/app/layout.tsx.hbs +41 -0
- package/templates/portfolio/app/page.tsx.hbs +86 -0
- package/templates/portfolio/next.config.ts.hbs +8 -0
- package/templates/portfolio/postcss.config.mjs.hbs +14 -0
- package/templates/portfolio/proxy.ts.hbs +10 -0
- package/templates/portfolio/tsconfig.json.hbs +21 -0
- package/templates/react-vite/src/App.tsx.hbs +11 -9
- package/templates/react-vite/src/index.css.hbs +4 -3
- package/templates/react-vite/src/pages/Home.tsx.hbs +3 -6
- package/templates/saas/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/saas/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/saas/app/admin/billing/page.tsx.hbs +145 -0
- package/templates/saas/app/admin/page.tsx.hbs +106 -0
- package/templates/saas/app/admin/team/page.tsx.hbs +134 -0
- package/templates/saas/app/globals.css.hbs +87 -0
- package/templates/saas/app/layout.tsx.hbs +41 -0
- package/templates/saas/app/page.tsx.hbs +108 -0
- package/templates/saas/app/pricing/page.tsx.hbs +131 -0
- package/templates/saas/next.config.ts.hbs +8 -0
- package/templates/saas/postcss.config.mjs.hbs +14 -0
- package/templates/saas/proxy.ts.hbs +10 -0
- package/templates/saas/tsconfig.json.hbs +21 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import Link from 'next/link';
|
|
5
|
+
import { SignInButton, SignUpButton, useAuth } from '@githat/nextjs';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Tu funda — anonymous-aware cart.
|
|
9
|
+
*
|
|
10
|
+
* Three checkout choices, in the order they should appear:
|
|
11
|
+
* 1. Continue as guest (the DEFAULT) — primary button.
|
|
12
|
+
* 2. Sign in (existing GitHat user).
|
|
13
|
+
* 3. Sign up (new GitHat user, gets cart history).
|
|
14
|
+
*
|
|
15
|
+
* The order matters: the colmado UX promise is "you don't have to
|
|
16
|
+
* make an account to shop." If you're tempted to make sign-up the
|
|
17
|
+
* primary button "for the data," re-read CULTURE.md.
|
|
18
|
+
*
|
|
19
|
+
* Real cart line items should come from your backend (read by the
|
|
20
|
+
* anon-session id from `src/lib/anon-session.ts`). The hard-coded
|
|
21
|
+
* sample below is just the shell.
|
|
22
|
+
*/
|
|
23
|
+
export default function CartPage() {
|
|
24
|
+
const { isSignedIn } = useAuth();
|
|
25
|
+
const [emailForReceipt, setEmailForReceipt] = useState('');
|
|
26
|
+
const sampleItems = [
|
|
27
|
+
{ id: '1', name: 'Plátanos verdes (3)', price: 1.5, store: "Doña Yolanda" },
|
|
28
|
+
{ id: '2', name: 'Presidente fría (6-pack)', price: 9.0, store: "Don Tito" },
|
|
29
|
+
{ id: '3', name: 'Recarga Claro $5', price: 5.0, store: "Doña Yolanda" },
|
|
30
|
+
];
|
|
31
|
+
const total = sampleItems.reduce((s, i) => s + i.price, 0);
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div style=\{{ background: 'var(--bg)', color: 'var(--fg)', minHeight: 'calc(100vh - 64px)' }}>
|
|
35
|
+
<div style=\{{ maxWidth: '40rem', margin: '0 auto', padding: 'var(--space-8) var(--space-4)' }}>
|
|
36
|
+
<h1 style=\{{ fontFamily: 'var(--font-wordmark)', fontSize: '2rem', marginBottom: 'var(--space-2)' }}>
|
|
37
|
+
Tu funda
|
|
38
|
+
</h1>
|
|
39
|
+
<p style=\{{ color: 'var(--fg-muted)', marginBottom: 'var(--space-6)' }}>
|
|
40
|
+
Your bag. Edit, then choose how you want to pay.
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
<ul style=\{{ listStyle: 'none', display: 'flex', flexDirection: 'column', gap: 'var(--space-3)', marginBottom: 'var(--space-6)' }}>
|
|
44
|
+
{sampleItems.map((it) => (
|
|
45
|
+
<li key={it.id} style=\{{
|
|
46
|
+
display: 'flex',
|
|
47
|
+
justifyContent: 'space-between',
|
|
48
|
+
alignItems: 'center',
|
|
49
|
+
padding: 'var(--space-3) var(--space-4)',
|
|
50
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
51
|
+
border: '1px solid var(--border)',
|
|
52
|
+
background: 'var(--surface)',
|
|
53
|
+
}}>
|
|
54
|
+
<div>
|
|
55
|
+
<div style=\{{ fontWeight: 600 }}>{it.name}</div>
|
|
56
|
+
<div style=\{{ fontSize: '0.75rem', color: 'var(--fg-muted)' }}>De tu colmadero, {it.store}</div>
|
|
57
|
+
</div>
|
|
58
|
+
<div style=\{{ fontWeight: 600 }}>${it.price.toFixed(2)}</div>
|
|
59
|
+
</li>
|
|
60
|
+
))}
|
|
61
|
+
</ul>
|
|
62
|
+
|
|
63
|
+
<div style=\{{
|
|
64
|
+
display: 'flex',
|
|
65
|
+
justifyContent: 'space-between',
|
|
66
|
+
fontSize: '1.125rem',
|
|
67
|
+
fontWeight: 600,
|
|
68
|
+
paddingTop: 'var(--space-3)',
|
|
69
|
+
borderTop: '1px solid var(--border)',
|
|
70
|
+
marginBottom: 'var(--space-8)',
|
|
71
|
+
}}>
|
|
72
|
+
<span>Total</span>
|
|
73
|
+
<span>${total.toFixed(2)}</span>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
{/* The auth choice — guest is the default, sign-in is opt-in */}
|
|
77
|
+
<section style=\{{
|
|
78
|
+
padding: 'var(--space-6)',
|
|
79
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
80
|
+
border: '1px solid var(--border)',
|
|
81
|
+
background: 'var(--surface-sub)',
|
|
82
|
+
}}>
|
|
83
|
+
<h2 style=\{{ fontSize: '1.25rem', marginBottom: 'var(--space-2)' }}>¿Cómo lo pagamos?</h2>
|
|
84
|
+
<p style=\{{ color: 'var(--fg-muted)', marginBottom: 'var(--space-4)', fontSize: '0.875rem' }}>
|
|
85
|
+
How would you like to pay? You don't need an account.
|
|
86
|
+
</p>
|
|
87
|
+
|
|
88
|
+
{!isSignedIn && (
|
|
89
|
+
<>
|
|
90
|
+
{/* Primary: continue as guest */}
|
|
91
|
+
<form
|
|
92
|
+
onSubmit={(e) => { e.preventDefault(); /* TODO: submit guest order */ }}
|
|
93
|
+
style=\{{ marginBottom: 'var(--space-4)' }}
|
|
94
|
+
>
|
|
95
|
+
<label htmlFor="email" style=\{{ display: 'block', marginBottom: 'var(--space-2)', fontSize: '0.875rem' }}>
|
|
96
|
+
Email para el recibo (we'll send the receipt and that's it)
|
|
97
|
+
</label>
|
|
98
|
+
<div style=\{{ display: 'flex', gap: 'var(--space-2)' }}>
|
|
99
|
+
<input
|
|
100
|
+
id="email"
|
|
101
|
+
type="email"
|
|
102
|
+
required
|
|
103
|
+
value={emailForReceipt}
|
|
104
|
+
onChange={(e) => setEmailForReceipt(e.target.value)}
|
|
105
|
+
placeholder="tu@email.com"
|
|
106
|
+
style=\{{
|
|
107
|
+
flex: 1,
|
|
108
|
+
padding: 'var(--space-3)',
|
|
109
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
110
|
+
border: '1px solid var(--border)',
|
|
111
|
+
background: 'var(--surface)',
|
|
112
|
+
color: 'var(--fg)',
|
|
113
|
+
}}
|
|
114
|
+
/>
|
|
115
|
+
<button type="submit" style=\{{
|
|
116
|
+
padding: 'var(--space-3) var(--space-5)',
|
|
117
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
118
|
+
border: 'none',
|
|
119
|
+
background: 'var(--primary)',
|
|
120
|
+
color: 'var(--bg)',
|
|
121
|
+
fontWeight: 600,
|
|
122
|
+
cursor: 'pointer',
|
|
123
|
+
}}>
|
|
124
|
+
Pagar como invitado
|
|
125
|
+
</button>
|
|
126
|
+
</div>
|
|
127
|
+
<p style=\{{ marginTop: 'var(--space-2)', fontSize: '0.75rem', color: 'var(--fg-subtle)' }}>
|
|
128
|
+
Continue as guest. No password, no account, no saved data.
|
|
129
|
+
</p>
|
|
130
|
+
</form>
|
|
131
|
+
|
|
132
|
+
<div style=\{{ display: 'flex', gap: 'var(--space-3)', flexWrap: 'wrap', alignItems: 'center', marginTop: 'var(--space-4)', paddingTop: 'var(--space-4)', borderTop: '1px dashed var(--border)' }}>
|
|
133
|
+
<span style=\{{ fontSize: '0.875rem', color: 'var(--fg-muted)' }}>O si quieres guardar tus datos:</span>
|
|
134
|
+
<SignInButton />
|
|
135
|
+
<SignUpButton />
|
|
136
|
+
</div>
|
|
137
|
+
</>
|
|
138
|
+
)}
|
|
139
|
+
|
|
140
|
+
{isSignedIn && (
|
|
141
|
+
<Link href="/checkout" style=\{{
|
|
142
|
+
display: 'inline-block',
|
|
143
|
+
padding: 'var(--space-3) var(--space-5)',
|
|
144
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
145
|
+
background: 'var(--primary)',
|
|
146
|
+
color: 'var(--bg)',
|
|
147
|
+
fontWeight: 600,
|
|
148
|
+
textDecoration: 'none',
|
|
149
|
+
}}>
|
|
150
|
+
Pagar →
|
|
151
|
+
</Link>
|
|
152
|
+
)}
|
|
153
|
+
</section>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Tailwind v4 — required because @githat/nextjs/styles is processed
|
|
3
|
+
* through @tailwindcss/postcss. Plain doesn't ship utility classes,
|
|
4
|
+
* but the import is needed for the auth pages to render styled.
|
|
5
|
+
*/
|
|
6
|
+
@import "tailwindcss";
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* Plain template — self-contained globals.
|
|
10
|
+
*
|
|
11
|
+
* Defines the minimum CSS variables a GitHat app uses for layout and
|
|
12
|
+
* the auth-page styling that ships with @githat/nextjs/styles.
|
|
13
|
+
* Override these in your own files when you want a real theme.
|
|
14
|
+
*
|
|
15
|
+
* Light theme by default; flip --bg/--fg for dark.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
:root {
|
|
19
|
+
/* Surface */
|
|
20
|
+
--bg: #ffffff;
|
|
21
|
+
--surface: #fafafa;
|
|
22
|
+
--surface-sub: #f4f4f5;
|
|
23
|
+
|
|
24
|
+
/* Borders */
|
|
25
|
+
--border: #e5e7eb;
|
|
26
|
+
|
|
27
|
+
/* Foreground */
|
|
28
|
+
--fg: #0a0a0a;
|
|
29
|
+
--fg-muted: #525252;
|
|
30
|
+
--fg-subtle: #737373;
|
|
31
|
+
|
|
32
|
+
/* Brand — change these two to re-skin the whole auth flow */
|
|
33
|
+
--primary: #6366f1;
|
|
34
|
+
--accent: #f59e0b;
|
|
35
|
+
|
|
36
|
+
/* Semantic */
|
|
37
|
+
--success: #16a34a;
|
|
38
|
+
--warn: #d97706;
|
|
39
|
+
--danger: #dc2626;
|
|
40
|
+
|
|
41
|
+
/* Spacing — used by @githat/nextjs/styles */
|
|
42
|
+
--space-1: 0.25rem;
|
|
43
|
+
--space-2: 0.5rem;
|
|
44
|
+
--space-3: 0.75rem;
|
|
45
|
+
--space-4: 1rem;
|
|
46
|
+
--space-6: 1.5rem;
|
|
47
|
+
--space-8: 2rem;
|
|
48
|
+
|
|
49
|
+
/* Radius */
|
|
50
|
+
--radius: 0.5rem;
|
|
51
|
+
--radius-md: 0.5rem;
|
|
52
|
+
--radius-lg: 0.75rem;
|
|
53
|
+
|
|
54
|
+
/* Fonts */
|
|
55
|
+
--font-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
|
|
56
|
+
--font-wordmark: 'Instrument Serif', Georgia, serif;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@media (prefers-color-scheme: dark) {
|
|
60
|
+
:root {
|
|
61
|
+
--bg: #0a0a0a;
|
|
62
|
+
--surface: #18181b;
|
|
63
|
+
--surface-sub: #27272a;
|
|
64
|
+
--border: #3f3f46;
|
|
65
|
+
--fg: #fafafa;
|
|
66
|
+
--fg-muted: #a1a1aa;
|
|
67
|
+
--fg-subtle: #71717a;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
* {
|
|
72
|
+
box-sizing: border-box;
|
|
73
|
+
margin: 0;
|
|
74
|
+
padding: 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
body {
|
|
78
|
+
font-family: var(--font-sans);
|
|
79
|
+
background: var(--bg);
|
|
80
|
+
color: var(--fg);
|
|
81
|
+
line-height: 1.5;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
a {
|
|
85
|
+
color: inherit;
|
|
86
|
+
text-decoration: none;
|
|
87
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { GitHatProvider } from '@githat/nextjs';
|
|
2
|
+
import '@githat/nextjs/styles';
|
|
3
|
+
import Link from 'next/link';
|
|
4
|
+
import './globals.css';
|
|
5
|
+
|
|
6
|
+
export const metadata = {
|
|
7
|
+
title: '{{businessName}} — el colmado de tu barrio',
|
|
8
|
+
description: '{{description}}',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Root layout for the marketplace template.
|
|
13
|
+
*
|
|
14
|
+
* Header has three slots, in order of importance:
|
|
15
|
+
* 1. Wordmark (always visible)
|
|
16
|
+
* 2. Tu funda — cart icon, anonymous-aware
|
|
17
|
+
* 3. "Save my stuff" / Sign in — low contrast, never a gate
|
|
18
|
+
*
|
|
19
|
+
* The "Vende en {{businessName}}" link sits in the footer, not the
|
|
20
|
+
* header. Sellers are a small minority of visitors; shoppers come first.
|
|
21
|
+
*/
|
|
22
|
+
export default function RootLayout({ children }{{#if typescript}}: { children: React.ReactNode }{{/if}}) {
|
|
23
|
+
return (
|
|
24
|
+
<html lang="es">
|
|
25
|
+
<body>
|
|
26
|
+
<GitHatProvider config=\{{
|
|
27
|
+
publishableKey: process.env.NEXT_PUBLIC_GITHAT_PUBLISHABLE_KEY || '',
|
|
28
|
+
signInUrl: '/sign-in',
|
|
29
|
+
signUpUrl: '/sign-up',
|
|
30
|
+
afterSignInUrl: '/',
|
|
31
|
+
afterSignOutUrl: '/',
|
|
32
|
+
}}>
|
|
33
|
+
<header style=\{{
|
|
34
|
+
display: 'flex',
|
|
35
|
+
alignItems: 'center',
|
|
36
|
+
justifyContent: 'space-between',
|
|
37
|
+
padding: 'var(--space-4, 1rem) var(--space-6, 1.5rem)',
|
|
38
|
+
borderBottom: '1px solid var(--border, #e5e7eb)',
|
|
39
|
+
background: 'var(--surface, #fafafa)',
|
|
40
|
+
}}>
|
|
41
|
+
<Link href="/" style=\{{
|
|
42
|
+
fontFamily: 'var(--font-wordmark, Georgia, serif)',
|
|
43
|
+
fontSize: '1.5rem',
|
|
44
|
+
color: 'var(--fg, inherit)',
|
|
45
|
+
textDecoration: 'none',
|
|
46
|
+
}}>
|
|
47
|
+
{{businessName}}
|
|
48
|
+
</Link>
|
|
49
|
+
<nav style=\{{ display: 'flex', alignItems: 'center', gap: 'var(--space-4, 1rem)', fontSize: '0.875rem' }}>
|
|
50
|
+
<Link href="/cart" style=\{{ color: 'var(--fg, inherit)', textDecoration: 'none' }}>
|
|
51
|
+
Tu funda
|
|
52
|
+
</Link>
|
|
53
|
+
<Link href="/sign-in" style=\{{ color: 'var(--fg-subtle, #71717a)', textDecoration: 'none' }}>
|
|
54
|
+
Save my stuff
|
|
55
|
+
</Link>
|
|
56
|
+
</nav>
|
|
57
|
+
</header>
|
|
58
|
+
<main>{children}</main>
|
|
59
|
+
<footer style=\{{
|
|
60
|
+
padding: 'var(--space-6, 1.5rem)',
|
|
61
|
+
borderTop: '1px solid var(--border, #e5e7eb)',
|
|
62
|
+
fontSize: '0.75rem',
|
|
63
|
+
color: 'var(--fg-subtle, #71717a)',
|
|
64
|
+
textAlign: 'center',
|
|
65
|
+
}}>
|
|
66
|
+
<Link href="/sell" style=\{{ color: 'var(--fg-muted, #525252)', textDecoration: 'none' }}>
|
|
67
|
+
¿Tienes un colmado? Vende aquí →
|
|
68
|
+
</Link>
|
|
69
|
+
<span style=\{{ display: 'block', marginTop: 'var(--space-2, 0.5rem)' }}>
|
|
70
|
+
{{businessName}} — built on GitHat + Sebastn.
|
|
71
|
+
</span>
|
|
72
|
+
</footer>
|
|
73
|
+
</GitHatProvider>
|
|
74
|
+
</body>
|
|
75
|
+
</html>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import Link from 'next/link';
|
|
5
|
+
import { useAuth } from '@githat/nextjs';
|
|
6
|
+
import { CATEGORIES } from '../src/lib/categories';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Marketplace homepage — colmado-flavored.
|
|
10
|
+
*
|
|
11
|
+
* Anonymous-first: visitors browse and search without signing in.
|
|
12
|
+
* The header has a low-contrast "Save my stuff" link that opens
|
|
13
|
+
* GitHat sign-in, but it's never a gate. See CULTURE.md for the
|
|
14
|
+
* cultural framing — this is a colmado, not a checkout terminal.
|
|
15
|
+
*
|
|
16
|
+
* Real product data should come from your backend (Postgres,
|
|
17
|
+
* DynamoDB, Sebastn-stored inventory) — this file just renders
|
|
18
|
+
* the shell + seed categories.
|
|
19
|
+
*/
|
|
20
|
+
export default function Home() {
|
|
21
|
+
const { isSignedIn } = useAuth();
|
|
22
|
+
const [query, setQuery] = useState('');
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div style=\{{ background: 'var(--bg)', color: 'var(--fg)', minHeight: 'calc(100vh - 64px)' }}>
|
|
26
|
+
{/* Hero — bilingual, warm, anti-Amazon */}
|
|
27
|
+
<section style=\{{
|
|
28
|
+
padding: 'var(--space-8) var(--space-4)',
|
|
29
|
+
background: 'linear-gradient(180deg, var(--surface-sub), var(--bg))',
|
|
30
|
+
textAlign: 'center',
|
|
31
|
+
}}>
|
|
32
|
+
<h1 style=\{{
|
|
33
|
+
fontFamily: 'var(--font-wordmark, Georgia, serif)',
|
|
34
|
+
fontSize: 'clamp(2rem, 5vw, 3rem)',
|
|
35
|
+
lineHeight: 1.1,
|
|
36
|
+
marginBottom: 'var(--space-3)',
|
|
37
|
+
}}>
|
|
38
|
+
Cerquita de ti, todo lo que necesitas.
|
|
39
|
+
</h1>
|
|
40
|
+
<p style=\{{ color: 'var(--fg-muted)', marginBottom: 'var(--space-6)', fontSize: '1.125rem' }}>
|
|
41
|
+
{{businessName}} — el colmado de tu barrio, ahora en tu teléfono.
|
|
42
|
+
<br />
|
|
43
|
+
<span style=\{{ fontSize: '0.875rem', opacity: 0.7 }}>
|
|
44
|
+
Pídelo y te lo llevamos. <em>Order it, we'll bring it to you.</em>
|
|
45
|
+
</span>
|
|
46
|
+
</p>
|
|
47
|
+
|
|
48
|
+
<form
|
|
49
|
+
onSubmit={(e) => { e.preventDefault(); window.location.href = `/buscar?q=${encodeURIComponent(query)}`; }}
|
|
50
|
+
style=\{{ maxWidth: '32rem', margin: '0 auto' }}
|
|
51
|
+
>
|
|
52
|
+
<label htmlFor="q" style=\{{ display: 'block', textAlign: 'left', marginBottom: 'var(--space-2)', fontSize: '0.875rem', color: 'var(--fg-muted)' }}>
|
|
53
|
+
Busca lo que te haga falta
|
|
54
|
+
</label>
|
|
55
|
+
<div style=\{{ display: 'flex', gap: 'var(--space-2)' }}>
|
|
56
|
+
<input
|
|
57
|
+
id="q"
|
|
58
|
+
type="search"
|
|
59
|
+
value={query}
|
|
60
|
+
onChange={(e) => setQuery(e.target.value)}
|
|
61
|
+
placeholder="Plátano, Presidente fría, recargas Claro…"
|
|
62
|
+
style=\{{
|
|
63
|
+
flex: 1,
|
|
64
|
+
padding: 'var(--space-3) var(--space-4)',
|
|
65
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
66
|
+
border: '1px solid var(--border)',
|
|
67
|
+
background: 'var(--surface)',
|
|
68
|
+
color: 'var(--fg)',
|
|
69
|
+
fontSize: '1rem',
|
|
70
|
+
}}
|
|
71
|
+
/>
|
|
72
|
+
<button type="submit" style=\{{
|
|
73
|
+
padding: 'var(--space-3) var(--space-6)',
|
|
74
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
75
|
+
border: 'none',
|
|
76
|
+
background: 'var(--primary)',
|
|
77
|
+
color: 'var(--bg)',
|
|
78
|
+
fontWeight: 600,
|
|
79
|
+
cursor: 'pointer',
|
|
80
|
+
}}>
|
|
81
|
+
Buscar
|
|
82
|
+
</button>
|
|
83
|
+
</div>
|
|
84
|
+
</form>
|
|
85
|
+
|
|
86
|
+
{isSignedIn && (
|
|
87
|
+
<p style=\{{ marginTop: 'var(--space-6)', fontSize: '0.875rem' }}>
|
|
88
|
+
<Link href="/cart" style=\{{ color: 'var(--primary)' }}>
|
|
89
|
+
Lo de siempre →
|
|
90
|
+
</Link>
|
|
91
|
+
<span style=\{{ color: 'var(--fg-subtle)' }}> (your usual order, one click away)</span>
|
|
92
|
+
</p>
|
|
93
|
+
)}
|
|
94
|
+
</section>
|
|
95
|
+
|
|
96
|
+
<section style=\{{ padding: 'var(--space-8) var(--space-4)' }}>
|
|
97
|
+
<div style=\{{ maxWidth: '64rem', margin: '0 auto' }}>
|
|
98
|
+
<h2 style=\{{ fontSize: '1.5rem', marginBottom: 'var(--space-4)' }}>Categorías</h2>
|
|
99
|
+
<div style=\{{
|
|
100
|
+
display: 'grid',
|
|
101
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))',
|
|
102
|
+
gap: 'var(--space-3)',
|
|
103
|
+
}}>
|
|
104
|
+
{CATEGORIES.map((cat) => (
|
|
105
|
+
<Link
|
|
106
|
+
key={cat.slug}
|
|
107
|
+
href={`/buscar?cat=${cat.slug}`}
|
|
108
|
+
style=\{{
|
|
109
|
+
display: 'flex',
|
|
110
|
+
flexDirection: 'column',
|
|
111
|
+
alignItems: 'center',
|
|
112
|
+
gap: 'var(--space-2)',
|
|
113
|
+
padding: 'var(--space-4)',
|
|
114
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
115
|
+
border: '1px solid var(--border)',
|
|
116
|
+
background: 'var(--surface)',
|
|
117
|
+
textAlign: 'center',
|
|
118
|
+
textDecoration: 'none',
|
|
119
|
+
color: 'inherit',
|
|
120
|
+
}}
|
|
121
|
+
>
|
|
122
|
+
<span style=\{{ fontSize: '2rem' }} aria-hidden>{cat.emoji}</span>
|
|
123
|
+
<span style=\{{ fontWeight: 600, fontSize: '0.875rem' }}>{cat.es}</span>
|
|
124
|
+
<span style=\{{ fontSize: '0.75rem', color: 'var(--fg-muted)' }}>{cat.en}</span>
|
|
125
|
+
</Link>
|
|
126
|
+
))}
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
</section>
|
|
130
|
+
|
|
131
|
+
<section style=\{{ padding: 'var(--space-8) var(--space-4)', background: 'var(--surface-sub)' }}>
|
|
132
|
+
<div style=\{{
|
|
133
|
+
maxWidth: '64rem',
|
|
134
|
+
margin: '0 auto',
|
|
135
|
+
display: 'grid',
|
|
136
|
+
gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))',
|
|
137
|
+
gap: 'var(--space-6)',
|
|
138
|
+
}}>
|
|
139
|
+
<div>
|
|
140
|
+
<h3 style=\{{ fontFamily: 'var(--font-wordmark)', fontSize: '1.5rem', marginBottom: 'var(--space-2)' }}>
|
|
141
|
+
¿Tienes un colmado?
|
|
142
|
+
</h3>
|
|
143
|
+
<p style=\{{ color: 'var(--fg-muted)', marginBottom: 'var(--space-3)' }}>
|
|
144
|
+
Pon tu tienda online en cinco minutos. Tu propia página,
|
|
145
|
+
tus precios, tus pedidos. Te quedas con el 96%.
|
|
146
|
+
</p>
|
|
147
|
+
<Link href="/sell" style=\{{
|
|
148
|
+
display: 'inline-block',
|
|
149
|
+
padding: 'var(--space-3) var(--space-5)',
|
|
150
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
151
|
+
background: 'var(--accent)',
|
|
152
|
+
color: 'var(--bg)',
|
|
153
|
+
fontWeight: 600,
|
|
154
|
+
textDecoration: 'none',
|
|
155
|
+
}}>
|
|
156
|
+
Vende en {{businessName}} →
|
|
157
|
+
</Link>
|
|
158
|
+
</div>
|
|
159
|
+
<div>
|
|
160
|
+
<h3 style=\{{ fontFamily: 'var(--font-wordmark)', fontSize: '1.5rem', marginBottom: 'var(--space-2)' }}>
|
|
161
|
+
Buying without signing in?
|
|
162
|
+
</h3>
|
|
163
|
+
<p style=\{{ color: 'var(--fg-muted)', marginBottom: 'var(--space-3)' }}>
|
|
164
|
+
Adelante. You don't need an account to browse, add to your
|
|
165
|
+
funda, or check out. Sign up only if you want to save
|
|
166
|
+
addresses, see past orders, or use store credit.
|
|
167
|
+
</p>
|
|
168
|
+
{!isSignedIn && (
|
|
169
|
+
<Link href="/sign-in" style=\{{ fontSize: '0.875rem', color: 'var(--primary)' }}>
|
|
170
|
+
Save my stuff (optional) →
|
|
171
|
+
</Link>
|
|
172
|
+
)}
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</section>
|
|
176
|
+
</div>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import Link from 'next/link';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Seller pitch page — `/sell`.
|
|
5
|
+
*
|
|
6
|
+
* Bodega owners land here from the homepage CTA "Vende en
|
|
7
|
+
* {{businessName}}." The job of this page is to convince a small
|
|
8
|
+
* shop owner — often someone who's never used a SaaS — that the
|
|
9
|
+
* platform is worth five minutes of their time.
|
|
10
|
+
*
|
|
11
|
+
* Three commitments worth making explicit:
|
|
12
|
+
* 1. They keep 96% (we take 4% as the platform fee)
|
|
13
|
+
* 2. Sebastn handles payouts directly to their bank
|
|
14
|
+
* 3. No lock-in — they can leave any time
|
|
15
|
+
*/
|
|
16
|
+
export default function SellPage() {
|
|
17
|
+
return (
|
|
18
|
+
<div style=\{{ background: 'var(--bg)', color: 'var(--fg)', minHeight: 'calc(100vh - 64px)' }}>
|
|
19
|
+
<section style=\{{ padding: 'var(--space-12) var(--space-4)', textAlign: 'center', maxWidth: '48rem', margin: '0 auto' }}>
|
|
20
|
+
<h1 style=\{{
|
|
21
|
+
fontFamily: 'var(--font-wordmark)',
|
|
22
|
+
fontSize: 'clamp(2rem, 5vw, 3rem)',
|
|
23
|
+
lineHeight: 1.1,
|
|
24
|
+
marginBottom: 'var(--space-3)',
|
|
25
|
+
}}>
|
|
26
|
+
Tu colmado, online en 5 minutos.
|
|
27
|
+
</h1>
|
|
28
|
+
<p style=\{{ color: 'var(--fg-muted)', fontSize: '1.125rem', marginBottom: 'var(--space-6)' }}>
|
|
29
|
+
Take orders from your block, take payment to your bank. We handle
|
|
30
|
+
the website, the cart, the receipts. You handle the colmado.
|
|
31
|
+
</p>
|
|
32
|
+
<Link href="/sign-up?role=seller" style=\{{
|
|
33
|
+
display: 'inline-block',
|
|
34
|
+
padding: 'var(--space-4) var(--space-8)',
|
|
35
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
36
|
+
background: 'var(--primary)',
|
|
37
|
+
color: 'var(--bg)',
|
|
38
|
+
fontWeight: 600,
|
|
39
|
+
fontSize: '1.125rem',
|
|
40
|
+
textDecoration: 'none',
|
|
41
|
+
}}>
|
|
42
|
+
Empieza gratis →
|
|
43
|
+
</Link>
|
|
44
|
+
</section>
|
|
45
|
+
|
|
46
|
+
<section style=\{{ padding: 'var(--space-8) var(--space-4)', background: 'var(--surface-sub)' }}>
|
|
47
|
+
<div style=\{{ maxWidth: '48rem', margin: '0 auto', display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 'var(--space-6)' }}>
|
|
48
|
+
<Promise emoji="💵" title="Te quedas con el 96%" body="We take a flat 4% on each order. No monthly fee on the free tier. No surprise charges." />
|
|
49
|
+
<Promise emoji="🏦" title="Pagos directo a tu cuenta" body="Sebastn pays you to your bank the next business day. You keep your existing bank account." />
|
|
50
|
+
<Promise emoji="🚪" title="Sin contratos" body="Cancel any time. Export your customers, your products, your orders. They're yours." />
|
|
51
|
+
</div>
|
|
52
|
+
</section>
|
|
53
|
+
|
|
54
|
+
<section style=\{{ padding: 'var(--space-12) var(--space-4)', textAlign: 'center', maxWidth: '40rem', margin: '0 auto' }}>
|
|
55
|
+
<h2 style=\{{ fontFamily: 'var(--font-wordmark)', fontSize: '1.75rem', marginBottom: 'var(--space-3)' }}>
|
|
56
|
+
¿Cómo funciona?
|
|
57
|
+
</h2>
|
|
58
|
+
<ol style=\{{ textAlign: 'left', color: 'var(--fg-muted)', lineHeight: 1.8, paddingLeft: 'var(--space-6)' }}>
|
|
59
|
+
<li>Te creas tu cuenta de {{businessName}} (es gratis).</li>
|
|
60
|
+
<li>Conectas tu banco (a través de Sebastn).</li>
|
|
61
|
+
<li>Subes tus productos — o los importas de un CSV.</li>
|
|
62
|
+
<li>Tu colmado vive en <code>{{businessName}}/tu-tienda</code>.</li>
|
|
63
|
+
<li>Los pedidos te llegan por email. Tú decides cómo entregar.</li>
|
|
64
|
+
</ol>
|
|
65
|
+
</section>
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function Promise({ emoji, title, body }: { emoji: string; title: string; body: string }) {
|
|
71
|
+
return (
|
|
72
|
+
<div>
|
|
73
|
+
<div style=\{{ fontSize: '2rem', marginBottom: 'var(--space-2)' }} aria-hidden>{emoji}</div>
|
|
74
|
+
<h3 style=\{{ fontWeight: 600, marginBottom: 'var(--space-2)' }}>{title}</h3>
|
|
75
|
+
<p style=\{{ color: 'var(--fg-muted)', fontSize: '0.875rem' }}>{body}</p>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Plain template — Tailwind v4 PostCSS plugin is required even though
|
|
3
|
+
* the plain scaffold doesn't use Tailwind utility classes. The auth
|
|
4
|
+
* page CSS shipped by `@githat/nextjs/styles` is processed through
|
|
5
|
+
* @tailwindcss/postcss at build time. Drop this config and the
|
|
6
|
+
* auth pages render unstyled.
|
|
7
|
+
*/
|
|
8
|
+
const config = {
|
|
9
|
+
plugins: {
|
|
10
|
+
'@tailwindcss/postcss': {},
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default config;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { authProxy } from '@githat/nextjs/proxy';
|
|
2
|
+
|
|
3
|
+
export const proxy = authProxy({
|
|
4
|
+
publicRoutes: ['/', '/sign-in', '/sign-up'{{#if includeForgotPassword}}, '/forgot-password', '/reset-password'{{/if}}{{#if includeEmailVerification}}, '/verify-email'{{/if}}],
|
|
5
|
+
signInUrl: '/sign-in',
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export const config = {
|
|
9
|
+
matcher: ['/((?!_next|api|.*\\..*).*)'],
|
|
10
|
+
};
|