luxlabs 1.0.2 → 1.0.4
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/package.json +1 -1
- package/templates/interface-boilerplate/app/dashboard/page.tsx +10 -6
- package/templates/interface-boilerplate/app/page.tsx +11 -6
- package/templates/interface-boilerplate/app/settings/page.tsx +12 -8
- package/templates/interface-boilerplate/components/auth/sign-in-form.tsx +11 -4
- package/templates/interface-boilerplate/components/auth/sign-up-form.tsx +15 -4
- package/templates/interface-boilerplate/lib/lux.ts +8 -0
package/package.json
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
import { useEffect } from "react";
|
|
4
4
|
import { useSession, signOut } from "@/lib/auth-client";
|
|
5
5
|
import { useRouter } from "next/navigation";
|
|
6
|
+
import { createLux } from "@/lib/lux";
|
|
7
|
+
|
|
8
|
+
const lux = createLux("Dashboard");
|
|
6
9
|
|
|
7
10
|
export default function DashboardPage() {
|
|
8
11
|
const { data: session, isPending } = useSession();
|
|
@@ -16,7 +19,7 @@ export default function DashboardPage() {
|
|
|
16
19
|
|
|
17
20
|
if (isPending) {
|
|
18
21
|
return (
|
|
19
|
-
<div className="min-h-screen flex items-center justify-center">
|
|
22
|
+
<div className="min-h-screen flex items-center justify-center" data-lux={lux("loading")}>
|
|
20
23
|
<p>Loading...</p>
|
|
21
24
|
</div>
|
|
22
25
|
);
|
|
@@ -32,17 +35,18 @@ export default function DashboardPage() {
|
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
return (
|
|
35
|
-
<div className="min-h-screen bg-zinc-50 p-8">
|
|
36
|
-
<div className="max-w-2xl mx-auto bg-white p-8 rounded-lg shadow-md">
|
|
37
|
-
<h1 className="text-2xl font-semibold mb-4">Dashboard</h1>
|
|
38
|
-
<p className="text-zinc-600 mb-2">
|
|
38
|
+
<div className="min-h-screen bg-zinc-50 p-8" data-lux={lux("container")}>
|
|
39
|
+
<div className="max-w-2xl mx-auto bg-white p-8 rounded-lg shadow-md" data-lux={lux("card")}>
|
|
40
|
+
<h1 className="text-2xl font-semibold mb-4" data-lux={lux("title")}>Dashboard</h1>
|
|
41
|
+
<p className="text-zinc-600 mb-2" data-lux={lux("welcome")}>
|
|
39
42
|
Welcome, <span className="font-medium">{session.user.name}</span>!
|
|
40
43
|
</p>
|
|
41
|
-
<p className="text-zinc-600 mb-6">
|
|
44
|
+
<p className="text-zinc-600 mb-6" data-lux={lux("email")}>
|
|
42
45
|
Email: {session.user.email}
|
|
43
46
|
</p>
|
|
44
47
|
<button
|
|
45
48
|
onClick={handleSignOut}
|
|
49
|
+
data-lux={lux("signout-button")}
|
|
46
50
|
className="px-4 py-2 bg-black text-white rounded-md hover:bg-zinc-800"
|
|
47
51
|
>
|
|
48
52
|
Sign Out
|
|
@@ -1,36 +1,41 @@
|
|
|
1
1
|
import Link from "next/link";
|
|
2
|
+
import { createLux } from "@/lib/lux";
|
|
3
|
+
|
|
4
|
+
const lux = createLux("Home");
|
|
2
5
|
|
|
3
6
|
export default function Home() {
|
|
4
7
|
return (
|
|
5
|
-
<div className="min-h-screen flex flex-col bg-white">
|
|
8
|
+
<div className="min-h-screen flex flex-col bg-white" data-lux={lux("container")}>
|
|
6
9
|
<main className="flex-1 flex flex-col items-center justify-center px-6">
|
|
7
10
|
<div className="max-w-2xl w-full text-center">
|
|
8
|
-
<p className="text-sm font-medium tracking-widest text-zinc-400 uppercase mb-4">
|
|
11
|
+
<p className="text-sm font-medium tracking-widest text-zinc-400 uppercase mb-4" data-lux={lux("tagline")}>
|
|
9
12
|
Boilerplate
|
|
10
13
|
</p>
|
|
11
|
-
<h1 className="text-6xl font-semibold tracking-tight text-black mb-6">
|
|
14
|
+
<h1 className="text-6xl font-semibold tracking-tight text-black mb-6" data-lux={lux("title")}>
|
|
12
15
|
Lux
|
|
13
16
|
</h1>
|
|
14
|
-
<p className="text-lg text-zinc-500 mb-12 max-w-md mx-auto">
|
|
17
|
+
<p className="text-lg text-zinc-500 mb-12 max-w-md mx-auto" data-lux={lux("description")}>
|
|
15
18
|
Authentication, database, and UI components. Everything you need to start building.
|
|
16
19
|
</p>
|
|
17
20
|
|
|
18
21
|
<div className="flex gap-4 justify-center mb-16">
|
|
19
22
|
<Link
|
|
20
23
|
href="/sign-in"
|
|
24
|
+
data-lux={lux("signin-button")}
|
|
21
25
|
className="px-8 py-3 bg-black text-white text-sm font-medium rounded-full hover:bg-zinc-800 transition-colors"
|
|
22
26
|
>
|
|
23
27
|
Sign In
|
|
24
28
|
</Link>
|
|
25
29
|
<Link
|
|
26
30
|
href="/sign-up"
|
|
31
|
+
data-lux={lux("signup-button")}
|
|
27
32
|
className="px-8 py-3 border border-zinc-200 text-black text-sm font-medium rounded-full hover:bg-zinc-50 transition-colors"
|
|
28
33
|
>
|
|
29
34
|
Sign Up
|
|
30
35
|
</Link>
|
|
31
36
|
</div>
|
|
32
37
|
|
|
33
|
-
<div className="flex items-center justify-center gap-8 text-sm text-zinc-400">
|
|
38
|
+
<div className="flex items-center justify-center gap-8 text-sm text-zinc-400" data-lux={lux("features")}>
|
|
34
39
|
<span>Next.js</span>
|
|
35
40
|
<span className="w-1 h-1 bg-zinc-300 rounded-full" />
|
|
36
41
|
<span>Auth</span>
|
|
@@ -42,7 +47,7 @@ export default function Home() {
|
|
|
42
47
|
</div>
|
|
43
48
|
</main>
|
|
44
49
|
|
|
45
|
-
<footer className="py-6 text-center text-sm text-zinc-400">
|
|
50
|
+
<footer className="py-6 text-center text-sm text-zinc-400" data-lux={lux("footer")}>
|
|
46
51
|
<p>Ready to ship.</p>
|
|
47
52
|
</footer>
|
|
48
53
|
</div>
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
import { useSession, signOut } from "@/lib/auth-client";
|
|
4
4
|
import { useRouter } from "next/navigation";
|
|
5
5
|
import { useEffect } from "react";
|
|
6
|
+
import { createLux } from "@/lib/lux";
|
|
7
|
+
|
|
8
|
+
const lux = createLux("Settings");
|
|
6
9
|
|
|
7
10
|
export default function SettingsPage() {
|
|
8
11
|
const { data: session, isPending } = useSession();
|
|
@@ -16,7 +19,7 @@ export default function SettingsPage() {
|
|
|
16
19
|
|
|
17
20
|
if (isPending) {
|
|
18
21
|
return (
|
|
19
|
-
<div className="min-h-screen flex items-center justify-center">
|
|
22
|
+
<div className="min-h-screen flex items-center justify-center" data-lux={lux("loading")}>
|
|
20
23
|
<div className="text-gray-500">Loading...</div>
|
|
21
24
|
</div>
|
|
22
25
|
);
|
|
@@ -32,25 +35,25 @@ export default function SettingsPage() {
|
|
|
32
35
|
};
|
|
33
36
|
|
|
34
37
|
return (
|
|
35
|
-
<div className="min-h-screen bg-gray-50">
|
|
38
|
+
<div className="min-h-screen bg-gray-50" data-lux={lux("container")}>
|
|
36
39
|
<div className="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
37
40
|
<div className="mb-8">
|
|
38
|
-
<h1 className="text-3xl font-bold text-gray-900">Settings</h1>
|
|
39
|
-
<p className="mt-2 text-sm text-gray-600">
|
|
41
|
+
<h1 className="text-3xl font-bold text-gray-900" data-lux={lux("title")}>Settings</h1>
|
|
42
|
+
<p className="mt-2 text-sm text-gray-600" data-lux={lux("subtitle")}>
|
|
40
43
|
Manage your account settings
|
|
41
44
|
</p>
|
|
42
45
|
</div>
|
|
43
46
|
|
|
44
|
-
<div className="bg-white shadow rounded-lg p-6">
|
|
45
|
-
<h2 className="text-lg font-medium text-gray-900 mb-4">Account</h2>
|
|
47
|
+
<div className="bg-white shadow rounded-lg p-6" data-lux={lux("card")}>
|
|
48
|
+
<h2 className="text-lg font-medium text-gray-900 mb-4" data-lux={lux("section-title")}>Account</h2>
|
|
46
49
|
|
|
47
50
|
<div className="space-y-4">
|
|
48
|
-
<div>
|
|
51
|
+
<div data-lux={lux("name-field")}>
|
|
49
52
|
<label className="block text-sm font-medium text-gray-700">Name</label>
|
|
50
53
|
<p className="mt-1 text-sm text-gray-900">{session.user.name}</p>
|
|
51
54
|
</div>
|
|
52
55
|
|
|
53
|
-
<div>
|
|
56
|
+
<div data-lux={lux("email-field")}>
|
|
54
57
|
<label className="block text-sm font-medium text-gray-700">Email</label>
|
|
55
58
|
<p className="mt-1 text-sm text-gray-900">{session.user.email}</p>
|
|
56
59
|
</div>
|
|
@@ -59,6 +62,7 @@ export default function SettingsPage() {
|
|
|
59
62
|
<div className="mt-6 pt-6 border-t border-gray-200">
|
|
60
63
|
<button
|
|
61
64
|
onClick={handleSignOut}
|
|
65
|
+
data-lux={lux("signout-button")}
|
|
62
66
|
className="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
|
|
63
67
|
>
|
|
64
68
|
Sign Out
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import { authClient } from "@/lib/auth-client";
|
|
5
5
|
import { useRouter } from "next/navigation";
|
|
6
|
+
import { createLux } from "@/lib/lux";
|
|
7
|
+
|
|
8
|
+
const lux = createLux("SignInForm");
|
|
6
9
|
|
|
7
10
|
export function SignInForm() {
|
|
8
11
|
const router = useRouter();
|
|
@@ -44,10 +47,11 @@ export function SignInForm() {
|
|
|
44
47
|
};
|
|
45
48
|
|
|
46
49
|
return (
|
|
47
|
-
<div className="space-y-6">
|
|
50
|
+
<div className="space-y-6" data-lux={lux("container")}>
|
|
48
51
|
{/* Google Sign In */}
|
|
49
52
|
<button
|
|
50
53
|
onClick={handleGoogleSignIn}
|
|
54
|
+
data-lux={lux("google-button")}
|
|
51
55
|
className="w-full flex items-center justify-center gap-3 px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
|
|
52
56
|
>
|
|
53
57
|
<svg className="w-5 h-5" viewBox="0 0 24 24">
|
|
@@ -81,7 +85,7 @@ export function SignInForm() {
|
|
|
81
85
|
</div>
|
|
82
86
|
|
|
83
87
|
{/* Email/Password Form */}
|
|
84
|
-
<form onSubmit={handleEmailPassword} className="space-y-4">
|
|
88
|
+
<form onSubmit={handleEmailPassword} className="space-y-4" data-lux={lux("form")}>
|
|
85
89
|
<div>
|
|
86
90
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
87
91
|
Email
|
|
@@ -91,6 +95,7 @@ export function SignInForm() {
|
|
|
91
95
|
value={email}
|
|
92
96
|
onChange={(e) => setEmail(e.target.value)}
|
|
93
97
|
required
|
|
98
|
+
data-lux={lux("email-input")}
|
|
94
99
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-gray-900 focus:border-gray-900"
|
|
95
100
|
placeholder="you@example.com"
|
|
96
101
|
/>
|
|
@@ -105,13 +110,14 @@ export function SignInForm() {
|
|
|
105
110
|
value={password}
|
|
106
111
|
onChange={(e) => setPassword(e.target.value)}
|
|
107
112
|
required
|
|
113
|
+
data-lux={lux("password-input")}
|
|
108
114
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-gray-900 focus:border-gray-900"
|
|
109
115
|
placeholder="••••••••"
|
|
110
116
|
/>
|
|
111
117
|
</div>
|
|
112
118
|
|
|
113
119
|
{error && (
|
|
114
|
-
<div className="text-sm text-red-600 bg-red-50 border border-red-200 rounded px-3 py-2">
|
|
120
|
+
<div className="text-sm text-red-600 bg-red-50 border border-red-200 rounded px-3 py-2" data-lux={lux("error")}>
|
|
115
121
|
{error}
|
|
116
122
|
</div>
|
|
117
123
|
)}
|
|
@@ -119,6 +125,7 @@ export function SignInForm() {
|
|
|
119
125
|
<button
|
|
120
126
|
type="submit"
|
|
121
127
|
disabled={isLoading}
|
|
128
|
+
data-lux={lux("submit-button")}
|
|
122
129
|
className="w-full px-4 py-2 bg-gray-900 text-white rounded-lg hover:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
|
123
130
|
>
|
|
124
131
|
{isLoading ? "Signing in..." : "Sign in"}
|
|
@@ -128,7 +135,7 @@ export function SignInForm() {
|
|
|
128
135
|
{/* Sign Up Link */}
|
|
129
136
|
<div className="text-center text-sm text-gray-600">
|
|
130
137
|
Don't have an account?{" "}
|
|
131
|
-
<a href="/sign-up" className="text-gray-900 hover:underline font-medium">
|
|
138
|
+
<a href="/sign-up" className="text-gray-900 hover:underline font-medium" data-lux={lux("signup-link")}>
|
|
132
139
|
Sign up
|
|
133
140
|
</a>
|
|
134
141
|
</div>
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import { authClient } from "@/lib/auth-client";
|
|
5
5
|
import { useRouter } from "next/navigation";
|
|
6
|
+
import { createLux } from "@/lib/lux";
|
|
7
|
+
|
|
8
|
+
const lux = createLux("SignUpForm");
|
|
6
9
|
|
|
7
10
|
export function SignUpForm() {
|
|
8
11
|
const router = useRouter();
|
|
@@ -63,10 +66,11 @@ export function SignUpForm() {
|
|
|
63
66
|
};
|
|
64
67
|
|
|
65
68
|
return (
|
|
66
|
-
<div className="space-y-6">
|
|
69
|
+
<div className="space-y-6" data-lux={lux("container")}>
|
|
67
70
|
{/* Google Sign Up */}
|
|
68
71
|
<button
|
|
69
72
|
onClick={handleGoogleSignUp}
|
|
73
|
+
data-lux={lux("google-button")}
|
|
70
74
|
className="w-full flex items-center justify-center gap-3 px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
|
|
71
75
|
>
|
|
72
76
|
<svg className="w-5 h-5" viewBox="0 0 24 24">
|
|
@@ -100,7 +104,7 @@ export function SignUpForm() {
|
|
|
100
104
|
</div>
|
|
101
105
|
|
|
102
106
|
{/* Sign Up Form */}
|
|
103
|
-
<form onSubmit={handleAccountSubmit} className="space-y-4">
|
|
107
|
+
<form onSubmit={handleAccountSubmit} className="space-y-4" data-lux={lux("form")}>
|
|
104
108
|
<div>
|
|
105
109
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
106
110
|
Name
|
|
@@ -110,6 +114,7 @@ export function SignUpForm() {
|
|
|
110
114
|
value={name}
|
|
111
115
|
onChange={(e) => setName(e.target.value)}
|
|
112
116
|
required
|
|
117
|
+
data-lux={lux("name-input")}
|
|
113
118
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-gray-900 focus:border-gray-900"
|
|
114
119
|
placeholder="John Doe"
|
|
115
120
|
/>
|
|
@@ -124,6 +129,7 @@ export function SignUpForm() {
|
|
|
124
129
|
value={email}
|
|
125
130
|
onChange={(e) => setEmail(e.target.value)}
|
|
126
131
|
required
|
|
132
|
+
data-lux={lux("email-input")}
|
|
127
133
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-gray-900 focus:border-gray-900"
|
|
128
134
|
placeholder="you@example.com"
|
|
129
135
|
/>
|
|
@@ -140,12 +146,14 @@ export function SignUpForm() {
|
|
|
140
146
|
onChange={(e) => setPassword(e.target.value)}
|
|
141
147
|
required
|
|
142
148
|
minLength={8}
|
|
149
|
+
data-lux={lux("password-input")}
|
|
143
150
|
className="w-full px-3 py-2 pr-10 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-gray-900 focus:border-gray-900"
|
|
144
151
|
placeholder="••••••••"
|
|
145
152
|
/>
|
|
146
153
|
<button
|
|
147
154
|
type="button"
|
|
148
155
|
onClick={() => setShowPassword(!showPassword)}
|
|
156
|
+
data-lux={lux("toggle-password")}
|
|
149
157
|
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-gray-600"
|
|
150
158
|
>
|
|
151
159
|
{showPassword ? (
|
|
@@ -176,12 +184,14 @@ export function SignUpForm() {
|
|
|
176
184
|
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
177
185
|
required
|
|
178
186
|
minLength={8}
|
|
187
|
+
data-lux={lux("confirm-password-input")}
|
|
179
188
|
className="w-full px-3 py-2 pr-10 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-gray-900 focus:border-gray-900"
|
|
180
189
|
placeholder="••••••••"
|
|
181
190
|
/>
|
|
182
191
|
<button
|
|
183
192
|
type="button"
|
|
184
193
|
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
|
|
194
|
+
data-lux={lux("toggle-confirm-password")}
|
|
185
195
|
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-gray-600"
|
|
186
196
|
>
|
|
187
197
|
{showConfirmPassword ? (
|
|
@@ -199,7 +209,7 @@ export function SignUpForm() {
|
|
|
199
209
|
</div>
|
|
200
210
|
|
|
201
211
|
{error && (
|
|
202
|
-
<div className="text-sm text-red-600 bg-red-50 border border-red-200 rounded px-3 py-2">
|
|
212
|
+
<div className="text-sm text-red-600 bg-red-50 border border-red-200 rounded px-3 py-2" data-lux={lux("error")}>
|
|
203
213
|
{error}
|
|
204
214
|
</div>
|
|
205
215
|
)}
|
|
@@ -207,6 +217,7 @@ export function SignUpForm() {
|
|
|
207
217
|
<button
|
|
208
218
|
type="submit"
|
|
209
219
|
disabled={isLoading}
|
|
220
|
+
data-lux={lux("submit-button")}
|
|
210
221
|
className="w-full px-4 py-2 bg-gray-900 text-white rounded-lg hover:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
|
211
222
|
>
|
|
212
223
|
{isLoading ? "Creating account..." : "Sign Up"}
|
|
@@ -216,7 +227,7 @@ export function SignUpForm() {
|
|
|
216
227
|
{/* Sign In Link */}
|
|
217
228
|
<div className="text-center text-sm text-gray-600">
|
|
218
229
|
Already have an account?{" "}
|
|
219
|
-
<a href="/sign-in" className="text-gray-900 hover:underline font-medium">
|
|
230
|
+
<a href="/sign-in" className="text-gray-900 hover:underline font-medium" data-lux={lux("signin-link")}>
|
|
220
231
|
Sign in
|
|
221
232
|
</a>
|
|
222
233
|
</div>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a lux helper for generating data-lux attribute values
|
|
3
|
+
* @param componentName - The name of the component
|
|
4
|
+
* @returns A function that generates prefixed element IDs
|
|
5
|
+
*/
|
|
6
|
+
export function createLux(componentName: string) {
|
|
7
|
+
return (elementId: string) => `${componentName}__${elementId}`;
|
|
8
|
+
}
|