create-frootkit 1.2.8 → 1.2.10
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/dist/addons/database.d.ts +13 -5
- package/dist/addons/database.d.ts.map +1 -1
- package/dist/addons/database.js +496 -94
- package/dist/addons/database.js.map +1 -1
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +5 -1
- package/dist/scaffold.js.map +1 -1
- package/package.json +1 -1
- package/templates/auth/src/app/api/auth/route.ts +17 -12
- package/templates/auth/src/app/dashboard/layout.tsx +14 -9
- package/templates/auth/src/app/dashboard/page.tsx +55 -24
- package/templates/auth/src/app/layout.tsx +3 -3
- package/templates/auth/src/app/login/page.tsx +5 -1
- package/templates/auth/src/app/page.tsx +103 -45
- package/templates/auth/src/app/signup/page.tsx +5 -1
- package/templates/auth/src/components/AuthForm.tsx +34 -19
- package/templates/auth/src/components/DashboardNav.tsx +97 -56
- package/templates/auth/src/components/MetricCard.tsx +13 -6
- package/templates/auth/src/components/Navbar.tsx +13 -12
- package/templates/auth/src/lib/auth.ts +123 -0
- package/templates/auth/src/styles.css +27 -5
- package/templates/blog/src/app/api/posts/route.ts +10 -34
- package/templates/blog/src/app/blog/[slug]/page.tsx +22 -21
- package/templates/blog/src/app/layout.tsx +4 -4
- package/templates/blog/src/app/page.tsx +19 -17
- package/templates/blog/src/components/Footer.tsx +6 -6
- package/templates/blog/src/components/Navbar.tsx +17 -15
- package/templates/blog/src/components/Newsletter.tsx +11 -9
- package/templates/blog/src/components/PostCard.tsx +29 -27
- package/templates/blog/src/data/posts.ts +48 -0
- package/templates/blog/src/styles.css +14 -5
- package/templates/ecommerce/src/app/api/products/route.ts +10 -26
- package/templates/ecommerce/src/app/cart/page.tsx +3 -3
- package/templates/ecommerce/src/app/layout.tsx +2 -2
- package/templates/ecommerce/src/app/page.tsx +41 -18
- package/templates/ecommerce/src/app/products/[id]/page.tsx +37 -28
- package/templates/ecommerce/src/components/CartDrawer.tsx +20 -17
- package/templates/ecommerce/src/components/Footer.tsx +6 -6
- package/templates/ecommerce/src/components/Navbar.tsx +21 -14
- package/templates/ecommerce/src/components/ProductCard.tsx +22 -15
- package/templates/ecommerce/src/data/products.ts +55 -11
- package/templates/ecommerce/src/styles.css +29 -5
- package/templates/empty/src/app/layout.tsx +5 -5
- package/templates/empty/src/app/page.tsx +10 -9
- package/templates/empty/src/styles.css +13 -15
- package/templates/starter/src/app/layout.tsx +4 -4
- package/templates/starter/src/app/page.tsx +41 -33
- package/templates/starter/src/components/FeatureCard.tsx +5 -5
- package/templates/starter/src/components/Footer.tsx +6 -6
- package/templates/starter/src/components/Header.tsx +18 -14
- package/templates/starter/src/components/TerminalPreview.tsx +30 -30
- package/templates/starter/src/styles.css +14 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/addons/database.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/addons/database.ts"],"names":[],"mappings":"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"}
|
package/dist/scaffold.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAKA,OAAO,
|
|
1
|
+
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAKA,OAAO,EAA4C,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACrG,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAOzE,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;IAC7C,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAiFvF"}
|
package/dist/scaffold.js
CHANGED
|
@@ -3,7 +3,7 @@ import * as path from 'node:path';
|
|
|
3
3
|
import { exec } from 'node:child_process';
|
|
4
4
|
import { promisify } from 'node:util';
|
|
5
5
|
import { generateFrootKitTemplate, DEFAULT_GITIGNORE } from './template.js';
|
|
6
|
-
import { applyDatabaseAddon } from './addons/database.js';
|
|
6
|
+
import { applyDatabaseAddon, seedPhysicalDatabase } from './addons/database.js';
|
|
7
7
|
import { applyLinterAddon } from './addons/linter.js';
|
|
8
8
|
import { applyAgentAddon } from './addons/agent.js';
|
|
9
9
|
import { applyDockerAddon } from './addons/docker.js';
|
|
@@ -37,6 +37,10 @@ export async function scaffoldProject(options) {
|
|
|
37
37
|
await fs.mkdir(path.dirname(fullPath), { recursive: true });
|
|
38
38
|
await fs.writeFile(fullPath, files[relPath], 'utf8');
|
|
39
39
|
}
|
|
40
|
+
// Pre-seed physical SQLite database with complete schemas and actual data
|
|
41
|
+
if (db !== 'none') {
|
|
42
|
+
seedPhysicalDatabase(targetDir, db, template);
|
|
43
|
+
}
|
|
40
44
|
writeSpinner.stop(`Created ${filePaths.length} project files`);
|
|
41
45
|
let gitInitialized = false;
|
|
42
46
|
if (gitInit) {
|
package/dist/scaffold.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,kBAAkB,EAAuB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -5,8 +5,12 @@ import {
|
|
|
5
5
|
parseCookies,
|
|
6
6
|
createSessionCookie,
|
|
7
7
|
clearSessionCookie,
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
findUserByEmail,
|
|
9
|
+
findUserById,
|
|
10
|
+
saveUser,
|
|
11
|
+
findSession,
|
|
12
|
+
saveSession,
|
|
13
|
+
deleteSession,
|
|
10
14
|
type User,
|
|
11
15
|
} from '../../../lib/auth.js';
|
|
12
16
|
|
|
@@ -21,7 +25,7 @@ export async function GET(req: Request): Promise<Response> {
|
|
|
21
25
|
);
|
|
22
26
|
}
|
|
23
27
|
|
|
24
|
-
const session =
|
|
28
|
+
const session = await findSession(sessionToken);
|
|
25
29
|
if (!session) {
|
|
26
30
|
return Response.json(
|
|
27
31
|
{ authenticated: false, user: null },
|
|
@@ -29,8 +33,8 @@ export async function GET(req: Request): Promise<Response> {
|
|
|
29
33
|
);
|
|
30
34
|
}
|
|
31
35
|
|
|
32
|
-
const
|
|
33
|
-
if (!
|
|
36
|
+
const user = await findUserById(session.userId);
|
|
37
|
+
if (!user) {
|
|
34
38
|
return Response.json(
|
|
35
39
|
{ authenticated: false, user: null },
|
|
36
40
|
{ status: 401 }
|
|
@@ -38,7 +42,7 @@ export async function GET(req: Request): Promise<Response> {
|
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
return Response.json(
|
|
41
|
-
{ authenticated: true, user
|
|
45
|
+
{ authenticated: true, user },
|
|
42
46
|
{ status: 200 }
|
|
43
47
|
);
|
|
44
48
|
}
|
|
@@ -51,7 +55,7 @@ export async function POST(req: Request): Promise<Response> {
|
|
|
51
55
|
const cookies = parseCookies(req.headers.get('cookie'));
|
|
52
56
|
const token = cookies['froot_session'];
|
|
53
57
|
if (token) {
|
|
54
|
-
|
|
58
|
+
await deleteSession(token);
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
return new Response(null, {
|
|
@@ -87,7 +91,8 @@ export async function POST(req: Request): Promise<Response> {
|
|
|
87
91
|
}
|
|
88
92
|
|
|
89
93
|
if (action === 'signup') {
|
|
90
|
-
|
|
94
|
+
const existing = await findUserByEmail(email);
|
|
95
|
+
if (existing) {
|
|
91
96
|
return Response.json({ error: 'User already exists' }, { status: 409 });
|
|
92
97
|
}
|
|
93
98
|
|
|
@@ -100,10 +105,10 @@ export async function POST(req: Request): Promise<Response> {
|
|
|
100
105
|
createdAt: new Date().toISOString(),
|
|
101
106
|
};
|
|
102
107
|
|
|
103
|
-
|
|
108
|
+
await saveUser(user, passwordHash);
|
|
104
109
|
|
|
105
110
|
const token = createSessionToken();
|
|
106
|
-
|
|
111
|
+
await saveSession({
|
|
107
112
|
id: 'sess_' + Math.random().toString(36).substring(2, 9),
|
|
108
113
|
token,
|
|
109
114
|
userId: user.id,
|
|
@@ -120,7 +125,7 @@ export async function POST(req: Request): Promise<Response> {
|
|
|
120
125
|
}
|
|
121
126
|
|
|
122
127
|
// Default: Login
|
|
123
|
-
const record =
|
|
128
|
+
const record = await findUserByEmail(email);
|
|
124
129
|
if (!record) {
|
|
125
130
|
return Response.json({ error: 'Invalid credentials' }, { status: 401 });
|
|
126
131
|
}
|
|
@@ -131,7 +136,7 @@ export async function POST(req: Request): Promise<Response> {
|
|
|
131
136
|
}
|
|
132
137
|
|
|
133
138
|
const token = createSessionToken();
|
|
134
|
-
|
|
139
|
+
await saveSession({
|
|
135
140
|
id: 'sess_' + Math.random().toString(36).substring(2, 9),
|
|
136
141
|
token,
|
|
137
142
|
userId: record.user.id,
|
|
@@ -3,29 +3,34 @@ import { DashboardNav } from '../../components/DashboardNav.js';
|
|
|
3
3
|
|
|
4
4
|
export default function DashboardLayout({ children }: { children: ComponentChildren }) {
|
|
5
5
|
return (
|
|
6
|
-
<div class="min-h-screen flex bg-[#
|
|
6
|
+
<div class="min-h-screen flex bg-[#08090a] text-zinc-100 selection:bg-indigo-500/20 selection:text-indigo-300">
|
|
7
7
|
<DashboardNav />
|
|
8
8
|
<div class="flex-1 flex flex-col min-w-0">
|
|
9
|
-
<header class="h-
|
|
9
|
+
<header class="h-14 border-b border-white/[0.08] px-6 flex items-center justify-between bg-[#08090a]/80 backdrop-blur-md sticky top-0 z-40">
|
|
10
10
|
<div class="flex items-center gap-3">
|
|
11
|
-
<
|
|
12
|
-
<span class="
|
|
13
|
-
|
|
11
|
+
<span class="text-xs text-zinc-500">Workspace</span>
|
|
12
|
+
<span class="text-zinc-600 text-xs">/</span>
|
|
13
|
+
<h1 class="text-xs font-semibold text-zinc-200">Production Cluster</h1>
|
|
14
|
+
<span class="inline-flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-emerald-500/10 text-emerald-400 text-[10px] font-medium border border-emerald-500/20 ml-1">
|
|
15
|
+
<span class="w-1.5 h-1.5 rounded-full bg-emerald-400" />
|
|
16
|
+
99.99% Uptime
|
|
14
17
|
</span>
|
|
15
18
|
</div>
|
|
16
19
|
|
|
17
|
-
<div class="flex items-center gap-
|
|
18
|
-
<span class="text-slate-400">User: <strong class="text-white">admin@frootkit.dev</strong></span>
|
|
20
|
+
<div class="flex items-center gap-3 text-xs">
|
|
19
21
|
<a
|
|
20
22
|
href="/api/auth"
|
|
21
|
-
class="px-2.5 py-1 rounded bg-[
|
|
23
|
+
class="px-2.5 py-1 rounded-md bg-white/[0.04] border border-white/[0.08] text-zinc-400 hover:text-zinc-200 transition-colors font-mono text-[11px]"
|
|
22
24
|
>
|
|
23
25
|
/api/auth
|
|
24
26
|
</a>
|
|
27
|
+
<div class="hidden sm:flex items-center gap-1 text-[11px] text-zinc-500 border border-white/[0.06] bg-white/[0.02] px-2 py-0.5 rounded">
|
|
28
|
+
<span>⌘</span><span>K</span>
|
|
29
|
+
</div>
|
|
25
30
|
</div>
|
|
26
31
|
</header>
|
|
27
32
|
|
|
28
|
-
<div class="p-8 flex-1 overflow-y-auto">
|
|
33
|
+
<div class="p-6 sm:p-8 flex-1 overflow-y-auto">
|
|
29
34
|
{children}
|
|
30
35
|
</div>
|
|
31
36
|
</div>
|
|
@@ -13,20 +13,30 @@ export default function DashboardOverviewPage() {
|
|
|
13
13
|
];
|
|
14
14
|
|
|
15
15
|
const recentUsers = [
|
|
16
|
-
{ name: 'Sarah Connor', email: 'sarah@frootkit.dev', role: 'Owner', date: 'Just now' },
|
|
17
|
-
{ name: 'Marcus Chen', email: 'marcus@infra.org', role: 'Developer', date: '2 hours ago' },
|
|
18
|
-
{ name: 'Elena Rostova', email: 'elena@design.io', role: 'Staff Eng', date: '1 day ago' },
|
|
19
|
-
{ name: 'Alex Rivera', email: 'alex@systems.net', role: 'Admin', date: '3 days ago' },
|
|
16
|
+
{ name: 'Sarah Connor', email: 'sarah@frootkit.dev', role: 'Owner', date: 'Just now', status: 'online' },
|
|
17
|
+
{ name: 'Marcus Chen', email: 'marcus@infra.org', role: 'Developer', date: '2 hours ago', status: 'offline' },
|
|
18
|
+
{ name: 'Elena Rostova', email: 'elena@design.io', role: 'Staff Eng', date: '1 day ago', status: 'offline' },
|
|
19
|
+
{ name: 'Alex Rivera', email: 'alex@systems.net', role: 'Admin', date: '3 days ago', status: 'offline' },
|
|
20
20
|
];
|
|
21
21
|
|
|
22
22
|
return (
|
|
23
|
-
<div class="space-y-8">
|
|
24
|
-
<div>
|
|
25
|
-
<
|
|
26
|
-
|
|
23
|
+
<div class="space-y-8 max-w-6xl">
|
|
24
|
+
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
|
25
|
+
<div>
|
|
26
|
+
<h2 class="text-xl sm:text-2xl font-semibold text-white tracking-tight">Metrics & Telemetry</h2>
|
|
27
|
+
<p class="text-xs sm:text-sm text-zinc-400 mt-1">Real-time throughput and workspace subscriber analytics.</p>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="flex items-center gap-2">
|
|
30
|
+
<button class="px-3 py-1.5 rounded-lg bg-white/[0.04] border border-white/[0.08] text-xs font-medium text-zinc-300 hover:text-white hover:bg-white/[0.08] transition-colors flex items-center gap-1.5">
|
|
31
|
+
<svg style="width: 12px; height: 12px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
32
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
|
33
|
+
</svg>
|
|
34
|
+
<span>Refresh</span>
|
|
35
|
+
</button>
|
|
36
|
+
</div>
|
|
27
37
|
</div>
|
|
28
38
|
|
|
29
|
-
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-
|
|
39
|
+
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
30
40
|
{metrics.map((m) => (
|
|
31
41
|
<MetricCard
|
|
32
42
|
key={m.label}
|
|
@@ -38,29 +48,50 @@ export default function DashboardOverviewPage() {
|
|
|
38
48
|
))}
|
|
39
49
|
</div>
|
|
40
50
|
|
|
41
|
-
<div class="rounded-xl border border-[
|
|
42
|
-
<
|
|
51
|
+
<div class="rounded-xl border border-white/[0.08] bg-[#0f1117] shadow-[inset_0_1px_0_0_rgba(255,255,255,0.05)] overflow-hidden">
|
|
52
|
+
<div class="p-5 border-b border-white/[0.06] flex items-center justify-between">
|
|
53
|
+
<div>
|
|
54
|
+
<h3 class="text-sm font-semibold text-white">Recent Workspace Activity</h3>
|
|
55
|
+
<p class="text-xs text-zinc-500 mt-0.5">Active team member sessions and authentication audits</p>
|
|
56
|
+
</div>
|
|
57
|
+
<span class="text-xs text-zinc-400 bg-white/[0.04] px-2.5 py-1 rounded-md border border-white/[0.06]">
|
|
58
|
+
{recentUsers.length} active sessions
|
|
59
|
+
</span>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
43
62
|
<div class="overflow-x-auto">
|
|
44
|
-
<table class="w-full text-left text-
|
|
63
|
+
<table class="w-full text-left text-xs">
|
|
45
64
|
<thead>
|
|
46
|
-
<tr class="border-b border-[
|
|
47
|
-
<th class="
|
|
48
|
-
<th class="
|
|
49
|
-
<th class="
|
|
50
|
-
<th class="
|
|
65
|
+
<tr class="border-b border-white/[0.06] text-zinc-400 font-medium bg-white/[0.01]">
|
|
66
|
+
<th class="py-3 px-5 font-medium">User</th>
|
|
67
|
+
<th class="py-3 px-5 font-medium">Email</th>
|
|
68
|
+
<th class="py-3 px-5 font-medium">Role</th>
|
|
69
|
+
<th class="py-3 px-5 font-medium text-right">Last Active</th>
|
|
51
70
|
</tr>
|
|
52
71
|
</thead>
|
|
53
|
-
<tbody class="divide-y divide-[
|
|
72
|
+
<tbody class="divide-y divide-white/[0.04]">
|
|
54
73
|
{recentUsers.map((u) => (
|
|
55
|
-
<tr key={u.email} class="hover:bg-[
|
|
56
|
-
<td class="py-3.5
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
74
|
+
<tr key={u.email} class="hover:bg-white/[0.02] transition-colors group">
|
|
75
|
+
<td class="py-3.5 px-5">
|
|
76
|
+
<div class="flex items-center gap-2.5">
|
|
77
|
+
<div class="w-6 h-6 rounded-full bg-white/[0.06] border border-white/[0.08] flex items-center justify-center text-[10px] font-medium text-zinc-300">
|
|
78
|
+
{u.name.charAt(0)}
|
|
79
|
+
</div>
|
|
80
|
+
<span class="font-medium text-zinc-200 group-hover:text-white transition-colors">{u.name}</span>
|
|
81
|
+
</div>
|
|
82
|
+
</td>
|
|
83
|
+
<td class="py-3.5 px-5 text-zinc-400">{u.email}</td>
|
|
84
|
+
<td class="py-3.5 px-5">
|
|
85
|
+
<span class={`inline-flex items-center gap-1.5 px-2 py-0.5 rounded-md text-[11px] font-medium border ${
|
|
86
|
+
u.role === 'Owner'
|
|
87
|
+
? 'bg-indigo-500/10 text-indigo-400 border-indigo-500/20'
|
|
88
|
+
: 'bg-white/[0.04] text-zinc-300 border-white/[0.08]'
|
|
89
|
+
}`}>
|
|
90
|
+
{u.role === 'Owner' && <span class="w-1.5 h-1.5 rounded-full bg-indigo-400" />}
|
|
60
91
|
{u.role}
|
|
61
92
|
</span>
|
|
62
93
|
</td>
|
|
63
|
-
<td class="py-3.5 text-
|
|
94
|
+
<td class="py-3.5 px-5 text-zinc-500 text-right tabular-nums">{u.date}</td>
|
|
64
95
|
</tr>
|
|
65
96
|
))}
|
|
66
97
|
</tbody>
|
|
@@ -9,7 +9,7 @@ export interface RootLayoutProps {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export default function RootLayout({ children, metadata }: RootLayoutProps) {
|
|
12
|
-
const title = metadata?.title || '
|
|
12
|
+
const title = metadata?.title || 'FrootAuth — Modern Cloud Platform';
|
|
13
13
|
const description =
|
|
14
14
|
metadata?.description ||
|
|
15
15
|
'Fullstack SaaS application with authentication and real-time dashboard powered by Preact and FrootKit.';
|
|
@@ -24,12 +24,12 @@ export default function RootLayout({ children, metadata }: RootLayoutProps) {
|
|
|
24
24
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
25
25
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
|
26
26
|
<link
|
|
27
|
-
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700
|
|
27
|
+
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
|
|
28
28
|
rel="stylesheet"
|
|
29
29
|
/>
|
|
30
30
|
<link rel="stylesheet" href="/styles.css" />
|
|
31
31
|
</head>
|
|
32
|
-
<body class="bg-[#
|
|
32
|
+
<body class="bg-[#08090a] text-zinc-100 min-h-screen antialiased selection:bg-indigo-500/20 selection:text-indigo-300 font-sans">
|
|
33
33
|
{children}
|
|
34
34
|
</body>
|
|
35
35
|
</html>
|
|
@@ -7,12 +7,16 @@ export const metadata = {
|
|
|
7
7
|
|
|
8
8
|
export default function LoginPage() {
|
|
9
9
|
return (
|
|
10
|
-
<div class="min-h-screen bg-[#
|
|
10
|
+
<div class="min-h-screen bg-[#08090a] text-zinc-100 flex flex-col justify-between selection:bg-indigo-500/20 selection:text-indigo-300">
|
|
11
11
|
<Navbar />
|
|
12
12
|
|
|
13
13
|
<main class="max-w-md mx-auto px-6 py-16 flex-1 w-full flex flex-col justify-center">
|
|
14
14
|
<AuthForm mode="login" />
|
|
15
15
|
</main>
|
|
16
|
+
|
|
17
|
+
<footer class="py-6 text-center text-xs text-zinc-600">
|
|
18
|
+
FrootAuth • Web Crypto PBKDF2 Authentication
|
|
19
|
+
</footer>
|
|
16
20
|
</div>
|
|
17
21
|
);
|
|
18
22
|
}
|
|
@@ -7,92 +7,150 @@ export const metadata = {
|
|
|
7
7
|
|
|
8
8
|
export default function SaaSMarketingPage() {
|
|
9
9
|
return (
|
|
10
|
-
<div class="min-h-screen bg-[#
|
|
10
|
+
<div class="min-h-screen bg-[#08090a] text-zinc-100 flex flex-col justify-between selection:bg-indigo-500/20 selection:text-indigo-300">
|
|
11
11
|
<Navbar />
|
|
12
12
|
|
|
13
|
-
<main class="max-w-6xl mx-auto px-6 py-16 flex-1 flex flex-col justify-center">
|
|
14
|
-
<div class="grid grid-cols-1 lg:grid-cols-12 gap-12 items-center">
|
|
13
|
+
<main class="max-w-6xl mx-auto px-6 py-16 sm:py-24 flex-1 flex flex-col justify-center w-full">
|
|
14
|
+
<div class="grid grid-cols-1 lg:grid-cols-12 gap-12 lg:gap-16 items-center">
|
|
15
15
|
{/* Left Column (7 cols) */}
|
|
16
16
|
<div class="lg:col-span-7">
|
|
17
|
-
<div class="
|
|
18
|
-
|
|
17
|
+
<div class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-indigo-500/10 border border-indigo-500/20 text-indigo-400 text-xs font-medium mb-6">
|
|
18
|
+
<span class="w-1.5 h-1.5 rounded-full bg-indigo-400 animate-pulse" />
|
|
19
|
+
<span>Pure Web Crypto Architecture</span>
|
|
19
20
|
</div>
|
|
20
21
|
|
|
21
|
-
<h1 class="text-4xl sm:text-5xl lg:text-6xl font-
|
|
22
|
+
<h1 class="text-4xl sm:text-5xl lg:text-6xl font-semibold text-white tracking-[-0.03em] leading-[1.1] mb-6">
|
|
22
23
|
Fullstack Authentication & Administration.
|
|
23
24
|
</h1>
|
|
24
25
|
|
|
25
|
-
<p class="text-base sm:text-lg text-
|
|
26
|
-
Zero external C++ dependencies. Real PBKDF2 password hashing (100,000 iterations), cryptographically random session tokens, protected
|
|
26
|
+
<p class="text-base sm:text-lg text-zinc-400 leading-relaxed mb-8 max-w-xl">
|
|
27
|
+
Zero external C++ dependencies. Real PBKDF2 password hashing (100,000 iterations), cryptographically random session tokens, protected layouts, and high-density telemetry.
|
|
27
28
|
</p>
|
|
28
29
|
|
|
29
|
-
<div class="flex flex-wrap items-center gap-
|
|
30
|
+
<div class="flex flex-wrap items-center gap-3.5 mb-8">
|
|
30
31
|
<a
|
|
31
32
|
href="/signup"
|
|
32
|
-
class="px-
|
|
33
|
+
class="px-4 py-2.5 rounded-lg bg-white text-zinc-950 font-medium hover:bg-zinc-200 transition-all text-sm shadow-sm flex items-center gap-2 group"
|
|
33
34
|
>
|
|
34
35
|
<span>Create Account</span>
|
|
35
|
-
<span>→</span>
|
|
36
|
+
<span class="text-zinc-500 group-hover:translate-x-0.5 transition-transform">→</span>
|
|
36
37
|
</a>
|
|
37
38
|
<a
|
|
38
39
|
href="/dashboard"
|
|
39
|
-
class="px-
|
|
40
|
+
class="px-4 py-2.5 rounded-lg bg-white/[0.04] border border-white/[0.08] text-zinc-300 font-medium hover:bg-white/[0.08] hover:text-white transition-all text-sm"
|
|
40
41
|
>
|
|
41
|
-
|
|
42
|
+
Open Dashboard
|
|
42
43
|
</a>
|
|
43
44
|
</div>
|
|
44
45
|
|
|
45
|
-
<div class="
|
|
46
|
-
<span class="
|
|
47
|
-
<span>Demo Account ready
|
|
46
|
+
<div class="inline-flex items-center gap-2.5 px-3 py-1.5 rounded-md bg-white/[0.03] border border-white/[0.06] text-xs text-zinc-400">
|
|
47
|
+
<span class="w-2 h-2 rounded-full bg-emerald-400" />
|
|
48
|
+
<span>Demo Account ready:</span>
|
|
49
|
+
<code class="text-zinc-200 font-mono text-[11px] bg-white/[0.04] px-1.5 py-0.5 rounded">admin@frootkit.dev</code>
|
|
50
|
+
<span class="text-zinc-600">/</span>
|
|
51
|
+
<code class="text-zinc-200 font-mono text-[11px] bg-white/[0.04] px-1.5 py-0.5 rounded">password123</code>
|
|
48
52
|
</div>
|
|
49
53
|
</div>
|
|
50
54
|
|
|
51
|
-
{/* Right Column:
|
|
55
|
+
{/* Right Column: Linear-Grade Security Inspector Card (5 cols) */}
|
|
52
56
|
<div class="lg:col-span-5">
|
|
53
|
-
<div class="rounded-xl border border-[
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
<div class="rounded-xl border border-white/[0.08] bg-[#0f1117] p-6 shadow-2xl shadow-black/40 relative overflow-hidden">
|
|
58
|
+
{/* Subtle top edge highlight */}
|
|
59
|
+
<div class="absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-indigo-500/40 to-transparent" />
|
|
60
|
+
|
|
61
|
+
<div class="flex items-center justify-between pb-4 border-b border-white/[0.06] mb-5">
|
|
62
|
+
<div class="flex items-center gap-2">
|
|
63
|
+
<div class="w-2 h-2 rounded-full bg-emerald-400" />
|
|
64
|
+
<span class="text-xs font-medium text-zinc-300">Security Subsystem</span>
|
|
65
|
+
</div>
|
|
66
|
+
<span class="text-[11px] text-indigo-400 font-medium px-2 py-0.5 rounded-full bg-indigo-500/10 border border-indigo-500/20">
|
|
67
|
+
SubtleCrypto Active
|
|
58
68
|
</span>
|
|
59
69
|
</div>
|
|
60
70
|
|
|
61
|
-
<div class="space-y-3
|
|
62
|
-
<div class="flex justify-between">
|
|
63
|
-
<span class="text-
|
|
64
|
-
<span class="text-
|
|
71
|
+
<div class="space-y-3.5 text-xs">
|
|
72
|
+
<div class="flex justify-between items-center py-1">
|
|
73
|
+
<span class="text-zinc-400">Algorithm</span>
|
|
74
|
+
<span class="text-zinc-200 font-medium">PBKDF2-SHA256</span>
|
|
65
75
|
</div>
|
|
66
|
-
<div class="flex justify-between">
|
|
67
|
-
<span class="text-
|
|
68
|
-
<span class="text-
|
|
76
|
+
<div class="flex justify-between items-center py-1 border-t border-white/[0.04]">
|
|
77
|
+
<span class="text-zinc-400">Iterations</span>
|
|
78
|
+
<span class="text-zinc-200 font-medium tabular-nums">100,000 rounds</span>
|
|
69
79
|
</div>
|
|
70
|
-
<div class="flex justify-between">
|
|
71
|
-
<span class="text-
|
|
72
|
-
<span class="text-
|
|
80
|
+
<div class="flex justify-between items-center py-1 border-t border-white/[0.04]">
|
|
81
|
+
<span class="text-zinc-400">Salt Length</span>
|
|
82
|
+
<span class="text-zinc-200 font-medium tabular-nums">128-bit (16 bytes)</span>
|
|
73
83
|
</div>
|
|
74
|
-
<div class="flex justify-between">
|
|
75
|
-
<span class="text-
|
|
76
|
-
<span class="text-
|
|
84
|
+
<div class="flex justify-between items-center py-1 border-t border-white/[0.04]">
|
|
85
|
+
<span class="text-zinc-400">Key Derivation</span>
|
|
86
|
+
<span class="text-zinc-200 font-medium">256-bit SubtleCrypto</span>
|
|
87
|
+
</div>
|
|
88
|
+
<div class="flex justify-between items-center py-1 border-t border-white/[0.04]">
|
|
89
|
+
<span class="text-zinc-400">Cookie Security</span>
|
|
90
|
+
<span class="text-emerald-400 font-medium">HttpOnly; SameSite=Lax</span>
|
|
77
91
|
</div>
|
|
78
92
|
</div>
|
|
79
93
|
|
|
80
|
-
<div class="pt-
|
|
81
|
-
<span class="text-
|
|
82
|
-
<code class="text-
|
|
94
|
+
<div class="mt-5 pt-4 border-t border-white/[0.06] flex justify-between items-center text-xs">
|
|
95
|
+
<span class="text-zinc-500">Auth Route</span>
|
|
96
|
+
<code class="text-indigo-400 font-mono text-[11px] bg-indigo-500/5 px-2 py-0.5 rounded border border-indigo-500/15">
|
|
97
|
+
/api/auth?action=login
|
|
98
|
+
</code>
|
|
83
99
|
</div>
|
|
84
100
|
</div>
|
|
85
101
|
</div>
|
|
86
102
|
</div>
|
|
103
|
+
|
|
104
|
+
{/* Feature Grid Below */}
|
|
105
|
+
<div class="mt-20 pt-12 border-t border-white/[0.06] grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
106
|
+
<div class="p-5 rounded-lg border border-white/[0.06] bg-white/[0.02]">
|
|
107
|
+
<div class="w-8 h-8 rounded-md bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center text-indigo-400 mb-3">
|
|
108
|
+
<svg style="width: 16px; height: 16px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
109
|
+
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
|
|
110
|
+
</svg>
|
|
111
|
+
</div>
|
|
112
|
+
<h3 class="text-sm font-semibold text-zinc-100 mb-1">Standard Web Crypto</h3>
|
|
113
|
+
<p class="text-xs text-zinc-400 leading-relaxed">
|
|
114
|
+
Native PBKDF2 key derivation using the Web Cryptography API. Zero C++ native rebuilds across any architecture.
|
|
115
|
+
</p>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<div class="p-5 rounded-lg border border-white/[0.06] bg-white/[0.02]">
|
|
119
|
+
<div class="w-8 h-8 rounded-md bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center text-indigo-400 mb-3">
|
|
120
|
+
<svg style="width: 16px; height: 16px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
121
|
+
<rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
|
|
122
|
+
<line x1="9" y1="3" x2="9" y2="21" />
|
|
123
|
+
</svg>
|
|
124
|
+
</div>
|
|
125
|
+
<h3 class="text-sm font-semibold text-zinc-100 mb-1">Protected Layouts</h3>
|
|
126
|
+
<p class="text-xs text-zinc-400 leading-relaxed">
|
|
127
|
+
Deterministic server-side session checks in nested Preact layout trees with instant redirect fallbacks.
|
|
128
|
+
</p>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<div class="p-5 rounded-lg border border-white/[0.06] bg-white/[0.02]">
|
|
132
|
+
<div class="w-8 h-8 rounded-md bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center text-indigo-400 mb-3">
|
|
133
|
+
<svg style="width: 16px; height: 16px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
134
|
+
<line x1="18" y1="20" x2="18" y2="10" />
|
|
135
|
+
<line x1="12" y1="20" x2="12" y2="4" />
|
|
136
|
+
<line x1="6" y1="20" x2="6" y2="14" />
|
|
137
|
+
</svg>
|
|
138
|
+
</div>
|
|
139
|
+
<h3 class="text-sm font-semibold text-zinc-100 mb-1">SQLite Session Cache</h3>
|
|
140
|
+
<p class="text-xs text-zinc-400 leading-relaxed">
|
|
141
|
+
Local persistent storage with sub-millisecond lookup latency, automatic expiry purging, and single-file portability.
|
|
142
|
+
</p>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
87
145
|
</main>
|
|
88
146
|
|
|
89
|
-
<footer class="border-t border-[
|
|
90
|
-
<div class="max-w-6xl mx-auto px-6 flex justify-between">
|
|
91
|
-
<div>FrootAuth © {new Date().getFullYear()} OrbitNorth LLC
|
|
92
|
-
<div class="flex gap-
|
|
93
|
-
<a href="/login" class="hover:text-
|
|
94
|
-
<a href="/signup" class="hover:text-
|
|
95
|
-
<a href="/dashboard" class="hover:text-
|
|
147
|
+
<footer class="border-t border-white/[0.06] bg-[#08090a] py-6 text-xs text-zinc-500">
|
|
148
|
+
<div class="max-w-6xl mx-auto px-6 flex flex-col sm:flex-row items-center justify-between gap-4">
|
|
149
|
+
<div>FrootAuth © {new Date().getFullYear()} OrbitNorth LLC. Built with FrootKit.</div>
|
|
150
|
+
<div class="flex gap-5">
|
|
151
|
+
<a href="/login" class="hover:text-zinc-300 transition-colors">Sign In</a>
|
|
152
|
+
<a href="/signup" class="hover:text-zinc-300 transition-colors">Sign Up</a>
|
|
153
|
+
<a href="/dashboard" class="hover:text-zinc-300 transition-colors">Dashboard</a>
|
|
96
154
|
</div>
|
|
97
155
|
</div>
|
|
98
156
|
</footer>
|
|
@@ -7,12 +7,16 @@ export const metadata = {
|
|
|
7
7
|
|
|
8
8
|
export default function SignupPage() {
|
|
9
9
|
return (
|
|
10
|
-
<div class="min-h-screen bg-[#
|
|
10
|
+
<div class="min-h-screen bg-[#08090a] text-zinc-100 flex flex-col justify-between selection:bg-indigo-500/20 selection:text-indigo-300">
|
|
11
11
|
<Navbar />
|
|
12
12
|
|
|
13
13
|
<main class="max-w-md mx-auto px-6 py-16 flex-1 w-full flex flex-col justify-center">
|
|
14
14
|
<AuthForm mode="signup" />
|
|
15
15
|
</main>
|
|
16
|
+
|
|
17
|
+
<footer class="py-6 text-center text-xs text-zinc-600">
|
|
18
|
+
FrootAuth • Web Crypto PBKDF2 Authentication
|
|
19
|
+
</footer>
|
|
16
20
|
</div>
|
|
17
21
|
);
|
|
18
22
|
}
|