@main12/auth-login 0.1.2 → 0.1.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/README.md +218 -97
- package/dist/components/AuthLayout.d.ts +2 -1
- package/dist/components/AuthLayout.js +15 -3
- package/dist/config.d.ts +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @main12/auth-login
|
|
2
2
|
|
|
3
|
-
**Payload CMS authentication plugin** — login, signup, OTP, forgot password, branded emails, and "Powered by Main 12" footer. Install once,
|
|
3
|
+
**Payload CMS authentication plugin** — login, signup, OTP, forgot password, branded emails, and "Powered by Main 12" footer. Install once, done.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
// payload.config.ts
|
|
@@ -10,7 +10,8 @@ plugins: [
|
|
|
10
10
|
authLoginPlugin({
|
|
11
11
|
projectName: 'My SaaS',
|
|
12
12
|
domain: 'https://myapp.com',
|
|
13
|
-
|
|
13
|
+
logo: 'https://myapp.com/logo.png', // shown in all auth pages + emails
|
|
14
|
+
style: 'hero-ui', // 'tailwind' (default) | 'hero-ui'
|
|
14
15
|
}),
|
|
15
16
|
]
|
|
16
17
|
```
|
|
@@ -24,7 +25,8 @@ plugins: [
|
|
|
24
25
|
- **5 API endpoints** — `check-email`, `otp/send`, `otp/verify`, `set-password`, `signup`
|
|
25
26
|
- **OTP engine** — SHA-256 hashing + `timingSafeEqual` comparison, 10-min expiry, 3 attempts
|
|
26
27
|
- **Email templates** — welcome, OTP login, password reset, password changed (EN/ES)
|
|
27
|
-
- **Powered by Main 12** — bundled inline SVG, linked to main12.com by default
|
|
28
|
+
- **Powered by Main 12** — bundled inline SVG, linked to main12.com by default (URL overridable)
|
|
29
|
+
- **Global logo** — pass once in plugin config, automatically shown on all pages and email headers
|
|
28
30
|
- **Zero runtime deps** (Tailwind mode) — Next.js + React are peer dependencies
|
|
29
31
|
|
|
30
32
|
---
|
|
@@ -35,9 +37,9 @@ plugins: [
|
|
|
35
37
|
pnpm add @main12/auth-login
|
|
36
38
|
```
|
|
37
39
|
|
|
38
|
-
### Tailwind mode (default, zero UI deps)
|
|
40
|
+
### Tailwind mode (default, zero UI deps — also ShadCN compatible)
|
|
39
41
|
|
|
40
|
-
No extra dependencies needed.
|
|
42
|
+
No extra dependencies needed. The Tailwind style uses standard utility classes that work in any Tailwind project, including ShadCN-based ones.
|
|
41
43
|
|
|
42
44
|
### HeroUI mode
|
|
43
45
|
|
|
@@ -49,191 +51,310 @@ pnpm add @heroui/react framer-motion @iconify/react
|
|
|
49
51
|
|
|
50
52
|
## Quick Start
|
|
51
53
|
|
|
52
|
-
### 1. Add the plugin
|
|
54
|
+
### 1. Add the plugin + Users collection
|
|
53
55
|
|
|
54
56
|
```ts
|
|
55
57
|
import { authLoginPlugin } from '@main12/auth-login'
|
|
56
58
|
|
|
57
59
|
export default buildConfig({
|
|
60
|
+
collections: [
|
|
61
|
+
{
|
|
62
|
+
slug: 'users',
|
|
63
|
+
auth: { tokenExpiration: 7200, verify: false, maxLoginAttempts: 5 },
|
|
64
|
+
fields: [
|
|
65
|
+
{ name: 'name', type: 'text' },
|
|
66
|
+
{ name: 'otpHash', type: 'text', admin: { hidden: true } },
|
|
67
|
+
{ name: 'otpAttempts', type: 'number', admin: { hidden: true } },
|
|
68
|
+
{ name: 'otpExpiresAt', type: 'text', admin: { hidden: true } },
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
],
|
|
58
72
|
plugins: [
|
|
59
73
|
authLoginPlugin({
|
|
60
74
|
projectName: 'My App',
|
|
61
75
|
domain: 'https://myapp.com',
|
|
62
|
-
|
|
63
|
-
style: '
|
|
76
|
+
logo: '/logo.png',
|
|
77
|
+
style: 'hero-ui',
|
|
64
78
|
}),
|
|
65
79
|
],
|
|
66
|
-
// ... rest of your config
|
|
67
80
|
})
|
|
68
81
|
```
|
|
69
82
|
|
|
70
|
-
### 2.
|
|
71
|
-
|
|
72
|
-
Create one-line route files under `src/app/(frontend)/(auth)/`:
|
|
83
|
+
### 2. Create one-line route files
|
|
73
84
|
|
|
74
85
|
```tsx
|
|
75
|
-
// login/page.tsx
|
|
86
|
+
// src/app/(frontend)/(auth)/login/page.tsx
|
|
76
87
|
export { LoginPage as default } from '@main12/auth-login/client'
|
|
77
88
|
|
|
78
|
-
// signup/page.tsx
|
|
89
|
+
// src/app/(frontend)/(auth)/signup/page.tsx
|
|
79
90
|
export { SignupPage as default } from '@main12/auth-login/client'
|
|
80
91
|
|
|
81
|
-
// forgot-password/page.tsx
|
|
92
|
+
// src/app/(frontend)/(auth)/forgot-password/page.tsx
|
|
82
93
|
export { ForgotPasswordPage as default } from '@main12/auth-login/client'
|
|
83
94
|
|
|
84
|
-
// verify-otp/page.tsx
|
|
95
|
+
// src/app/(frontend)/(auth)/verify-otp/page.tsx
|
|
85
96
|
export { VerifyOtpPage as default } from '@main12/auth-login/client'
|
|
86
97
|
|
|
87
|
-
// set-password/page.tsx
|
|
98
|
+
// src/app/(frontend)/(auth)/set-password/page.tsx
|
|
88
99
|
export { SetPasswordPage as default } from '@main12/auth-login/client'
|
|
89
100
|
```
|
|
90
101
|
|
|
91
102
|
### 3. Wire up the login action
|
|
92
103
|
|
|
93
|
-
The plugin needs a `login` function. Pass yours from Payload's `useAuth()`:
|
|
94
|
-
|
|
95
104
|
```tsx
|
|
96
105
|
// login/page.tsx
|
|
97
106
|
'use client'
|
|
98
107
|
import { LoginPage } from '@main12/auth-login/client'
|
|
99
108
|
import { useAuth } from '@/providers/Auth'
|
|
100
|
-
import AppLogo from '@/components/Logo/AppLogo'
|
|
101
109
|
|
|
102
110
|
export default function Page() {
|
|
103
111
|
const { login } = useAuth()
|
|
104
|
-
return
|
|
105
|
-
<LoginPage
|
|
106
|
-
logo={<AppLogo width={180} height={42} />}
|
|
107
|
-
onPasswordLogin={login}
|
|
108
|
-
redirectTo="/dashboard"
|
|
109
|
-
poweredBy={{ enabled: true }}
|
|
110
|
-
/>
|
|
111
|
-
)
|
|
112
|
+
return <LoginPage onPasswordLogin={login} redirectTo="/dashboard" />
|
|
112
113
|
}
|
|
113
114
|
```
|
|
114
115
|
|
|
116
|
+
### 4. Visit `/login` — done.
|
|
117
|
+
|
|
115
118
|
---
|
|
116
119
|
|
|
117
|
-
## Configuration
|
|
120
|
+
## Configuration
|
|
118
121
|
|
|
119
122
|
```ts
|
|
120
123
|
authLoginPlugin({
|
|
121
|
-
//
|
|
122
|
-
projectName: 'My App', // Used in email subjects and footers
|
|
124
|
+
projectName: 'My App', // Email subjects + footers
|
|
123
125
|
contactEmail: 'hi@myapp.com', // Email footer contact
|
|
124
126
|
domain: 'https://myapp.com', // Links in emails
|
|
125
|
-
|
|
126
|
-
// === Style ===
|
|
127
|
+
logo: '/logo.png', // All auth pages + email headers
|
|
127
128
|
style: 'tailwind', // 'tailwind' | 'hero-ui'
|
|
128
|
-
|
|
129
|
-
// === Enable/Disable ===
|
|
130
|
-
enabled: true, // Set false to disable the plugin
|
|
129
|
+
enabled: true,
|
|
131
130
|
})
|
|
132
131
|
```
|
|
133
132
|
|
|
134
|
-
|
|
133
|
+
### Per-page overrides
|
|
135
134
|
|
|
136
|
-
```
|
|
135
|
+
```tsx
|
|
137
136
|
<LoginPage
|
|
138
|
-
logo={
|
|
139
|
-
onPasswordLogin={login}
|
|
140
|
-
redirectTo="/dashboard"
|
|
141
|
-
showGoogleOAuth={true}
|
|
142
|
-
signupUrl="/signup"
|
|
143
|
-
poweredBy={{
|
|
144
|
-
enabled: true,
|
|
145
|
-
logoUrl: '/custom-logo.png', // Override the default Main12 logo
|
|
146
|
-
linkUrl: 'https://your-site.com',
|
|
147
|
-
width: 28,
|
|
148
|
-
height: 28,
|
|
149
|
-
}}
|
|
137
|
+
logo={<AppLogo width={180} />} // Override global logo (optional)
|
|
138
|
+
onPasswordLogin={login} // Required
|
|
139
|
+
redirectTo="/dashboard"
|
|
140
|
+
showGoogleOAuth={true}
|
|
141
|
+
signupUrl="/signup"
|
|
142
|
+
poweredBy={{ enabled: true, logoUrl: '/custom.png', linkUrl: 'https://...' }}
|
|
150
143
|
/>
|
|
151
144
|
```
|
|
152
145
|
|
|
153
146
|
---
|
|
154
147
|
|
|
155
|
-
##
|
|
148
|
+
## Building Custom Pages
|
|
149
|
+
|
|
150
|
+
Use the plugin's hooks to build your own UI with any component library (HeroUI, shadcn, plain Tailwind).
|
|
151
|
+
|
|
152
|
+
### Hook Quick-Reference
|
|
153
|
+
|
|
154
|
+
| Hook | Returns | Key inputs |
|
|
155
|
+
|------|---------|------------|
|
|
156
|
+
| `useLoginFlow({ redirectTo, onPasswordLogin })` | `step, email, password, error, isLoading, handleEmailSubmit, handlePasswordSubmit, handleSendOtp, handleEditEmail` | `redirectTo: string`, `onPasswordLogin: (creds) => Promise<void>` |
|
|
157
|
+
| `useSignupFlow()` | `name, email, error, isLoading, setName, setEmail, handleSubmit` | none — manages its own state |
|
|
158
|
+
| `useForgotPasswordFlow()` | `email, error, isLoading, setEmail, handleSubmit` | none |
|
|
159
|
+
| `useVerifyOtpFlow({ email, purpose, redirectTo })` | `otp, error, isLoading, isResending, resendCooldown, setOtp, handleSubmit, handleResendCode` | `email: string`, `purpose: 'login'\|'signup'\|'password-reset'` |
|
|
160
|
+
| `useSetPasswordFlow({ redirectTo })` | `password, confirmPassword, error, isLoading, strength, setPassword, setConfirmPassword, handleSubmit` | `redirectTo: string` |
|
|
161
|
+
| `useAuth()` (from Payload) | `user, login, logout, create` | (your existing Payload auth provider) |
|
|
156
162
|
|
|
157
|
-
|
|
163
|
+
### Full Example: Custom Login Page
|
|
158
164
|
|
|
159
165
|
```tsx
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
'use client'
|
|
167
|
+
import { useLoginFlow } from '@main12/auth-login/client'
|
|
168
|
+
import { useAuth } from '@/providers/Auth'
|
|
169
|
+
|
|
170
|
+
export default function CustomLogin() {
|
|
171
|
+
const { login } = useAuth()
|
|
172
|
+
const {
|
|
173
|
+
step, email, password, error, isLoading, showPassword,
|
|
174
|
+
setEmail, setPassword, setShowPassword,
|
|
175
|
+
handleEmailSubmit, handlePasswordSubmit, handleSendOtp, handleEditEmail,
|
|
176
|
+
} = useLoginFlow({ redirectTo: '/dashboard', onPasswordLogin: login })
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<div className="min-h-screen flex items-center justify-center bg-gray-50">
|
|
180
|
+
<div className="w-full max-w-md p-8 bg-white rounded-2xl shadow-xl">
|
|
181
|
+
<img src="/logo.png" className="mx-auto mb-6" width={180} alt="" />
|
|
182
|
+
|
|
183
|
+
{/* Step 1: Email */}
|
|
184
|
+
{step === 'email' && (
|
|
185
|
+
<form onSubmit={handleEmailSubmit} className="space-y-4">
|
|
186
|
+
<h1 className="text-xl font-semibold text-center">Welcome Back</h1>
|
|
187
|
+
{error && <p className="text-red-600 text-sm">{error}</p>}
|
|
188
|
+
<input type="email" value={email} onChange={e => setEmail(e.target.value)}
|
|
189
|
+
placeholder="Email" required className="w-full h-12 px-4 border rounded-xl" />
|
|
190
|
+
<button type="submit" disabled={isLoading}
|
|
191
|
+
className="w-full h-12 bg-[#D5E855] rounded-full font-semibold">
|
|
192
|
+
{isLoading ? 'Loading...' : 'Continue'}
|
|
193
|
+
</button>
|
|
194
|
+
</form>
|
|
195
|
+
)}
|
|
196
|
+
|
|
197
|
+
{/* Step 2a: Password */}
|
|
198
|
+
{step === 'password' && (
|
|
199
|
+
<form onSubmit={handlePasswordSubmit} className="space-y-4">
|
|
200
|
+
<div className="flex justify-between border rounded-xl px-4 py-3">
|
|
201
|
+
<span>{email}</span>
|
|
202
|
+
<button type="button" onClick={handleEditEmail} className="text-sm">Edit</button>
|
|
203
|
+
</div>
|
|
204
|
+
{error && <p className="text-red-600 text-sm">{error}</p>}
|
|
205
|
+
<input type={showPassword ? 'text' : 'password'} value={password}
|
|
206
|
+
onChange={e => setPassword(e.target.value)} placeholder="Password" required
|
|
207
|
+
className="w-full h-12 px-4 border rounded-xl" autoFocus />
|
|
208
|
+
<button type="submit" disabled={isLoading}
|
|
209
|
+
className="w-full h-12 bg-[#D5E855] rounded-full font-semibold">
|
|
210
|
+
{isLoading ? 'Loading...' : 'Sign In'}
|
|
211
|
+
</button>
|
|
212
|
+
</form>
|
|
213
|
+
)}
|
|
214
|
+
|
|
215
|
+
{/* Step 2b: OTP Prompt (migrated users without password) */}
|
|
216
|
+
{step === 'otp-prompt' && (
|
|
217
|
+
<div className="space-y-4">
|
|
218
|
+
<div className="flex justify-between border rounded-xl px-4 py-3">
|
|
219
|
+
<span>{email}</span>
|
|
220
|
+
<button type="button" onClick={handleEditEmail}>Edit</button>
|
|
221
|
+
</div>
|
|
222
|
+
{error && <p className="text-red-600 text-sm">{error}</p>}
|
|
223
|
+
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4 text-sm text-blue-700">
|
|
224
|
+
We'll send a verification code to this email.
|
|
225
|
+
</div>
|
|
226
|
+
<button onClick={handleSendOtp} disabled={isLoading}
|
|
227
|
+
className="w-full h-12 bg-[#D5E855] rounded-full font-semibold">
|
|
228
|
+
{isLoading ? 'Sending...' : 'Send Code'}
|
|
229
|
+
</button>
|
|
230
|
+
</div>
|
|
231
|
+
)}
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
)
|
|
168
235
|
}
|
|
169
236
|
```
|
|
170
237
|
|
|
171
|
-
###
|
|
238
|
+
### Custom Signup
|
|
172
239
|
|
|
173
|
-
|
|
174
|
-
|------|---------|
|
|
175
|
-
| `useLoginFlow` | Multi-step login state machine (email → password/OTP) |
|
|
176
|
-
| `useVerifyOtpFlow` | OTP input, verify, resend with cooldown |
|
|
177
|
-
| `useForgotPasswordFlow` | Email → check → send OTP |
|
|
178
|
-
| `useSetPasswordFlow` | Set password with strength indicator |
|
|
240
|
+
Same pattern — call `onSignup(name, email)` from your form, redirect to `/verify-otp?email=...&purpose=signup` on success.
|
|
179
241
|
|
|
180
|
-
###
|
|
242
|
+
### Custom Verify OTP
|
|
181
243
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
244
|
+
Use `useVerifyOtpFlow({ email, purpose, redirectTo })`. It manages the 6-digit input, verification, resend cooldown (60s), and auto-redirect. All you need is an `<input>` or `<InputOtp>` for the code and a verify button.
|
|
245
|
+
|
|
246
|
+
### Custom Forgot Password
|
|
247
|
+
|
|
248
|
+
Use `useForgotPasswordFlow()`. Collect email, call `handleSubmit(e)`. It checks user exists, sends OTP, and redirects to `/verify-otp?email=...&purpose=password-reset`.
|
|
249
|
+
|
|
250
|
+
### Custom Set Password
|
|
251
|
+
|
|
252
|
+
Use `useSetPasswordFlow({ redirectTo })`. Two password fields (new + confirm). The hook validates strength (≥8 chars, 3/4 criteria) and matches. Returns `strength.score` (0-5) for a visual indicator.
|
|
190
253
|
|
|
191
254
|
---
|
|
192
255
|
|
|
193
|
-
##
|
|
256
|
+
## Custom Email Templates
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
import { generateWelcomeEmail, getEmailTranslations } from '@main12/auth-login/rsc'
|
|
260
|
+
|
|
261
|
+
// Override translations
|
|
262
|
+
const t = getEmailTranslations('en')
|
|
263
|
+
t.welcome.subject = 'Welcome to My SaaS! 🚀'
|
|
264
|
+
|
|
265
|
+
// Or wrap template generators
|
|
266
|
+
function myWelcome(params) {
|
|
267
|
+
const base = generateWelcomeEmail(params)
|
|
268
|
+
return { ...base, html: base.html.replace('Get Started', 'Launch Now') }
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Use in hooks/endpoints
|
|
272
|
+
await payload.sendEmail({
|
|
273
|
+
to: user.email,
|
|
274
|
+
...myWelcome({ userName: user.name, userEmail: user.email }),
|
|
275
|
+
})
|
|
276
|
+
```
|
|
194
277
|
|
|
195
|
-
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## API Endpoints
|
|
196
281
|
|
|
197
282
|
| Method | Path | Description |
|
|
198
283
|
|--------|------|-------------|
|
|
199
284
|
| POST | `/api/auth/check-email` | Check if email is registered |
|
|
200
|
-
| POST | `/api/auth/otp/send` | Generate + send OTP |
|
|
201
|
-
| POST | `/api/auth/otp/verify` | Verify OTP + login |
|
|
285
|
+
| POST | `/api/auth/otp/send` | Generate + send OTP via Payload email adapter |
|
|
286
|
+
| POST | `/api/auth/otp/verify` | Verify OTP + login (sets httpOnly cookie) |
|
|
202
287
|
| POST | `/api/auth/set-password` | Set/update password |
|
|
203
|
-
| POST | `/api/auth/signup` | Create account |
|
|
288
|
+
| POST | `/api/auth/signup` | Create account + send welcome email |
|
|
204
289
|
|
|
205
290
|
---
|
|
206
291
|
|
|
207
|
-
##
|
|
292
|
+
## ShadCN Compatibility
|
|
208
293
|
|
|
209
|
-
|
|
294
|
+
The `tailwind` style works in ShadCN projects out of the box. For ShadCN components, build a [custom page](#building-custom-pages) — import the plugin's hooks and use your `@/components/ui/button`, `@/components/ui/input`, etc.
|
|
210
295
|
|
|
211
|
-
|
|
212
|
-
- **OTP** — 6-digit code for login or password reset
|
|
213
|
-
- **Password Reset** — OTP email for forgot password flow
|
|
214
|
-
- **Password Changed** — confirmation after password update
|
|
296
|
+
---
|
|
215
297
|
|
|
216
|
-
|
|
298
|
+
## 🤖 AI Agent Prompts
|
|
299
|
+
|
|
300
|
+
Copy these prompts into Claude, Cursor, Copilot, or any AI agent.
|
|
301
|
+
|
|
302
|
+
### Prompt: Set up the auth plugin in a new Payload project
|
|
303
|
+
|
|
304
|
+
```
|
|
305
|
+
Add @main12/auth-login to this Payload project:
|
|
306
|
+
|
|
307
|
+
1. Install: pnpm add @main12/auth-login
|
|
308
|
+
2. In payload.config.ts, add:
|
|
309
|
+
- Users collection with auth enabled + otpHash, otpAttempts, otpExpiresAt fields
|
|
310
|
+
- Plugin: authLoginPlugin({ projectName: "<PROJECT>", domain: "<URL>", logo: "/logo.png", style: "hero-ui" })
|
|
311
|
+
3. Create route files under src/app/(frontend)/(auth)/:
|
|
312
|
+
- login/page.tsx → export { LoginPage as default } from '@main12/auth-login/client'
|
|
313
|
+
- signup/page.tsx → export { SignupPage as default } from '@main12/auth-login/client'
|
|
314
|
+
- forgot-password/page.tsx → export { ForgotPasswordPage as default } from '@main12/auth-login/client'
|
|
315
|
+
- verify-otp/page.tsx → export { VerifyOtpPage as default } from '@main12/auth-login/client'
|
|
316
|
+
- set-password/page.tsx → export { SetPasswordPage as default } from '@main12/auth-login/client'
|
|
317
|
+
4. In login/page.tsx, wrap LoginPage with useAuth() to pass onPasswordLogin={login}.
|
|
318
|
+
5. Verify: visit /login
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Prompt: Build a custom login page with HeroUI components
|
|
322
|
+
|
|
323
|
+
```
|
|
324
|
+
Build a custom login page using @main12/auth-login hooks and @heroui/react:
|
|
325
|
+
|
|
326
|
+
- Import useLoginFlow from '@main12/auth-login/client'
|
|
327
|
+
- Use useAuth() from Payload's Auth provider for the login function
|
|
328
|
+
- Render 3 steps: email input → password input / OTP prompt
|
|
329
|
+
- Use HeroUI <Button>, <Input> with variant="bordered", rounded-full
|
|
330
|
+
- Add "Continue with Google" button using initiateGoogleLogin from the plugin
|
|
331
|
+
- Add "Powered by Main12" footer from the plugin's PoweredBy component
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Prompt: Customize email templates for my project
|
|
335
|
+
|
|
336
|
+
```
|
|
337
|
+
Customize the email templates from @main12/auth-login for my project "<PROJECT_NAME>":
|
|
338
|
+
|
|
339
|
+
- Import generateWelcomeEmail, generateOtpEmail, generatePasswordResetEmail, generatePasswordChangedEmail from '@main12/auth-login/rsc'
|
|
340
|
+
- Override each to use my brand colors (primary: <COLOR>, accent: <COLOR>)
|
|
341
|
+
- Change the welcome email CTA text to "<CUSTOM_TEXT>"
|
|
342
|
+
- Change the OTP email purpose text to "<CUSTOM_TEXT>"
|
|
343
|
+
- Add my project's social media links to the footer
|
|
344
|
+
```
|
|
217
345
|
|
|
218
346
|
---
|
|
219
347
|
|
|
220
348
|
## Dev Testing
|
|
221
349
|
|
|
222
|
-
This repo ships with a dev harness. To test locally:
|
|
223
|
-
|
|
224
350
|
```bash
|
|
351
|
+
git clone https://github.com/MAIN-12/auth-login-plugin.git
|
|
225
352
|
cd auth-login-plugin
|
|
226
353
|
pnpm install
|
|
227
354
|
pnpm dev
|
|
228
355
|
```
|
|
229
356
|
|
|
230
|
-
|
|
231
|
-
- `http://localhost:3000/login` — multi-step login
|
|
232
|
-
- `http://localhost:3000/signup` — create account
|
|
233
|
-
- `http://localhost:3000/forgot-password` — password reset
|
|
234
|
-
- `http://localhost:3000/admin` — Payload admin panel
|
|
235
|
-
|
|
236
|
-
The dev config uses SQLite (no external DB needed) with a Users collection pre-configured.
|
|
357
|
+
Visit `http://localhost:3000/login` — all 5 auth pages wired with SQLite.
|
|
237
358
|
|
|
238
359
|
---
|
|
239
360
|
|
|
@@ -3,7 +3,19 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { Card, CardContent, CardFooter } from './ui/index.js';
|
|
5
5
|
import { PoweredBy } from './PoweredBy.js';
|
|
6
|
+
import { pluginConfig } from '../config.js';
|
|
7
|
+
function DefaultLogo() {
|
|
8
|
+
if (!pluginConfig.logoUrl) return null;
|
|
9
|
+
return /*#__PURE__*/ _jsx("img", {
|
|
10
|
+
src: pluginConfig.logoUrl,
|
|
11
|
+
alt: "",
|
|
12
|
+
width: 180,
|
|
13
|
+
height: 42,
|
|
14
|
+
className: "object-contain"
|
|
15
|
+
});
|
|
16
|
+
}
|
|
6
17
|
export const AuthLayout = ({ children, logo, title, subtitle, footer, poweredBy, cardClassName = '', backgroundClass = 'bg-white md:bg-[#191919]' })=>{
|
|
18
|
+
const displayLogo = logo || /*#__PURE__*/ _jsx(DefaultLogo, {});
|
|
7
19
|
return /*#__PURE__*/ _jsx("main", {
|
|
8
20
|
className: `flex flex-col min-h-screen ${backgroundClass}`,
|
|
9
21
|
children: /*#__PURE__*/ _jsx("div", {
|
|
@@ -14,12 +26,12 @@ export const AuthLayout = ({ children, logo, title, subtitle, footer, poweredBy,
|
|
|
14
26
|
/*#__PURE__*/ _jsxs(Card, {
|
|
15
27
|
className: cardClassName,
|
|
16
28
|
children: [
|
|
17
|
-
(
|
|
29
|
+
(displayLogo || title) && /*#__PURE__*/ _jsxs("div", {
|
|
18
30
|
className: "flex flex-col items-center gap-2 pt-6 pb-2 px-6",
|
|
19
31
|
children: [
|
|
20
|
-
|
|
32
|
+
displayLogo && /*#__PURE__*/ _jsx("div", {
|
|
21
33
|
className: "flex justify-center mb-2",
|
|
22
|
-
children:
|
|
34
|
+
children: displayLogo
|
|
23
35
|
}),
|
|
24
36
|
title && /*#__PURE__*/ _jsx("h1", {
|
|
25
37
|
className: "text-xl font-semibold text-gray-900 text-center",
|
package/dist/config.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export interface AuthLoginPluginOptions {
|
|
|
7
7
|
domain?: string;
|
|
8
8
|
/** UI style for auth pages: 'tailwind' (default) or 'hero-ui' */
|
|
9
9
|
style?: AuthStyle;
|
|
10
|
+
/** Logo shown in all auth pages and email headers. Can be a URL string. */
|
|
11
|
+
logo?: string;
|
|
10
12
|
}
|
|
11
13
|
export declare const authLoginPlugin: (options?: AuthLoginPluginOptions) => (config: Config) => Config;
|
|
12
14
|
export { pluginConfig };
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export const authLoginPlugin = (options = {})=>(config)=>{
|
|
|
4
4
|
if (options.enabled === false) return config;
|
|
5
5
|
// Set global style config — all page components read this at render time
|
|
6
6
|
pluginConfig.style = options.style || 'tailwind';
|
|
7
|
+
pluginConfig.logoUrl = options.logo;
|
|
7
8
|
// Register auth API endpoints
|
|
8
9
|
config.endpoints = [
|
|
9
10
|
...config.endpoints || [],
|
package/package.json
CHANGED