Documentazione di LoginGen
Introduzione
LoginGen è un sito web di template per pagine di login. Il motivo per cui ho sviluppato questo progetto è che, sebbene ci siano molti siti web di template sul mercato, la maggior parte manca di supporto per le pagine di login o offre solo uno o due template semplici, spesso senza una logica frontend completa. Sebbene in termini di peso dell'interazione, la pagina di login possa non essere importante come una Landing Page, una pagina di login ben progettata può comunque lasciare una buona prima impressione agli utenti.
La stack tecnologica si basa principalmente su Next.js e Shadcn/ui. Oltre a fornire design di template, offre anche una logica frontend completa e utilizza la funzionalità Server Actions di Next.js per unificare l'autenticazione lato server (ad eccezione del login social, che per comodità è gestito come evento lato client).
Tutto il codice è open source, proprio come Shadcn, quindi puoi copiare e incollare direttamente il codice per utilizzarlo e modificarlo in base alle esigenze del tuo progetto, cosa che è anche consigliata. Per comodità, i componenti del modulo estraggono anche alcune proprietà comuni, consentendo un utilizzo immediato.
In futuro verranno continuamente aggiunti, perfezionati e ottimizzati i template. Restate sintonizzati.
Installazione
I template sono sviluppati su Next.js e Shadcn, quindi è necessario disporre prima di un ambiente di progetto con:
- "next": "^14.2+"
- "tailwindcss": "^3.4+"
- "react-hook-form: 7.52.2" - Non utilizzare versioni superiori per ora, poiché nelle versioni più recenti è presente un bug durante il rendering (issues: https://github.com/react-hook-form/react-hook-form/issues/12518)
Componenti shadcn
Se utilizzi altri strumenti di gestione dei pacchetti o vuoi installarli manualmente, consulta la documentazione di shadcn.
pnpm dlx shadcn@latest add card tabs form button input input-otp separator sonner
Aggiungi le seguenti animazioni CSS al tuo file tailwind.config.js
:
// per input-otp
/** @type {import('tailwindcss').Config} */
module.exports = {
theme: {
extend: {
keyframes: {
'caret-blink': {
'0%,70%,100%': { opacity: '1' },
'20%,50%': { opacity: '0' }
}
},
animation: {
'caret-blink': 'caret-blink 1.25s ease-out infinite'
}
}
}
}
Per sonner, devi aggiungere il seguente componente:
import { Toaster } from '@/components/ui/sonner'
export default function RootLayout({ children }) {
return (
<html lang='en'>
<head />
<body>
<main>{children}</main>
<Toaster />
</body>
</html>
)
}
Librerie di terze parti
pnpm add react-hook-form@7.52.2 zod motion @zxcvbn-ts/core @zxcvbn-ts/language-common @zxcvbn-ts/language-en embla-carousel-react embla-carousel-autoplay embla-carousel-fade lucide-react
pnpm add -D embla-carousel
react-hook-form
+zod
-- Validazione lato client dei modulimotion
-- Libreria di animazioni@zxcvbn-*
-- Libreria per il controllo della forza delle passwordembla-carousel-*
-- Libreria per i caroselli (doveembla-carousel
deve essere installato indevDependencies
per ottenere correttamente i tipi TypeScript)lucide-react
-- Libreria di icone
Copia e incolla il codice
Ogni pagina di anteprima del template mostra il codice completo. Puoi semplicemente copiare e incollare il codice necessario nella posizione corrispondente del tuo progetto. Le immagini incluse nei template possono essere scaricate direttamente, mentre i video sono forniti tramite CDN.
Al momento non è disponibile un'installazione con un solo comando simile a npx
, ma potrebbe essere
considerata in futuro.
Tema
Ogni template include un file di tema styles/theme.module.css
, che contiene tutte le variabili del tema e
gli stili/animazioni necessari per il template. Puoi modificare gli stili in questo file per adattare il tema
o renderlo coerente con l'UI del tuo sito.
Modalità scura
Per la modalità scura, segui la documentazione di shadcn. Nei
file di tema theme.module.css
dei template, il tema scuro utilizza il prefisso CSS :global(.dark)
per
rispondere alla modalità scura globale del sito.
I18n (TODO)
Al momento non è supportata la configurazione multilingua, ma puoi comunque aggiungerla manualmente, anche se potrebbe richiedere un po' più di lavoro. Questa funzionalità potrebbe essere aggiunta in futuro.
Proprietà del modulo
Ci sono cinque moduli: login, registrazione, recupero password, reimpostazione password e verifica OTP (one-time password). Ogni modulo ha alcuni parametri per un utilizzo immediato, molti dei quali sono comuni.
Sebbene nel codice del template ogni pagina del modulo sia una route separata con reindirizzamenti lato server per la navigazione tra le pagine, tutti i componenti sono progettati per essere utilizzati tramite il passaggio di proprietà. Ciò significa che puoi utilizzare tranquillamente il routing lato client.
Login
L'interfaccia è definita come segue:
const _auths = ['social', 'email', 'password'] as const
type Auth = (typeof _auths)[number]
export interface SignInFormProps {
auths?: Readonly<Auth[]>
socials?: SocialKey[]
email?: string
emailStrategy?: 'magic-link' | 'one-time-pwd'
socialHandler?: (event: MouseEvent<HTMLButtonElement>, key: SocialKey) => void | Promise<void>
forgetHandler?: string | ((event: React.MouseEvent<HTMLAnchorElement>) => void | Promise<void>) // per un utilizzo più comodo
serverAction?: (
formType: 'email' | 'password',
currentState: SignInActionState,
formData: FormData
) => Promise<SignInActionState>
serverStateSuccessHandler?: (formType: 'email' | 'password', email: string) => void | Promise<void>
}
Parametro | Valore predefinito | Spiegazione |
---|---|---|
auths | ['social', 'password', 'email'] | Metodi di autenticazione: login social, login tramite email, login con password |
socials | ['google', 'github'] | Tipi di login social (il layout si adatta automaticamente in base al numero selezionato e alla larghezza del modulo) |
Email iniziale, utile anche per il pre-riempimento quando si torna dal modulo di verifica OTP dopo la modifica | ||
emailStrategy | 'magic-link' | Tipo di email inviata. Se è 'magic-link', non avviene un reindirizzamento ma viene mostrato un popup Sonner |
socialHandler | Funzione di callback per il pulsante di login social. Puoi utilizzare librerie come Auth.js | |
forgetHandler | '#' | Callback per il pulsante "Password dimenticata". Questo parametro è pensato per un utilizzo semplificato |
serverAction | Tutti i moduli (tranne il login social) inviano i dati al server tramite Server Actions | |
serverStateSuccessHandler | Di solito, dopo l'autenticazione lato server, avviene un reindirizzamento lato server. Se vuoi gestirlo lato client, utilizza questa callback |
Note:
socials
-- Ogni template ha un file di configurazioneconfig/social.tsx
. Puoi modificarlo per aggiungere altri metodi di login social. Puoi modificare liberamente lakey
per adattarla al tuo framework di autenticazione o cambiare le icone SVG a tuo piacimento.email
-- Nell'UI del moduloverify-otp
, c'è un pulsante per modificare l'email. Quando l'utente clicca su di esso, dovrebbe tornare alla pagina precedente per consentire la modifica. Il parametroemail
serve a pre-compilare l'email in questa situazione.
Registrazione
L'interfaccia è definita come segue:
export interface SignUpFormProps {
email?: string
serverAction: (currentState: SignUpActionState, formData: FormData) => Promise<SignUpActionState>
serverStateSuccessHandler?: (email: string) => void | Promise<void>
}
Parametro | Valore predefinito | Spiegazione |
---|---|---|
Email iniziale, utile anche per il pre-riempimento quando si torna dal modulo di verifica OTP dopo la modifica | ||
serverAction | Invia i dati del modulo al server tramite Server Actions | |
serverStateSuccessHandler | Di solito, dopo l'autenticazione lato server, avviene un reindirizzamento lato server. Se vuoi gestirlo lato client, utilizza questa callback |
Password dimenticata
L'interfaccia è definita come segue:
export interface ForgetPasswordProps {
email?: string
emailStrategy?: 'magic-link' | 'one-time-pwd'
serverAction: (
currentState: ForgetPasswordActionState,
formData: FormData
) => Promise<ForgetPasswordActionState>
serverStateSuccessHandler?: (email: string) => void | Promise<void>
}
Parametro | Valore predefinito | Spiegazione |
---|---|---|
Email iniziale, utile anche per il pre-riempimento quando si torna dal modulo di verifica OTP dopo la modifica | ||
emailStrategy | 'magic-link' | Tipo di email inviata. Se è 'magic-link', non avviene un reindirizzamento ma viene mostrato un popup Sonner |
serverAction | Invia i dati del modulo al server tramite Server Actions | |
serverStateSuccessHandler | Di solito, dopo l'autenticazione lato server, avviene un reindirizzamento lato server. Se vuoi gestirlo lato client, utilizza questa callback |
Reimpostazione password
L'interfaccia è definita come segue:
export interface ResetPasswordFormProps {
email?: string // Only used to test password strength
resetToken?: string
serverAction: (
resetToken: string,
currentState: ResetPasswordActionState,
formData: FormData
) => Promise<ResetPasswordActionState>
serverStateSuccessHandler?: () => void | Promise<void>
}
Parametro | Valore predefinito | Spiegazione |
---|---|---|
L'email viene utilizzata solo per testare la forza della password (consigliato impostarla per migliorare la sicurezza) | ||
resetToken | Token generato dal server per tracciare il flusso del modulo | |
serverAction | Invia i dati del modulo al server tramite Server Actions | |
serverStateSuccessHandler | Di solito, dopo l'autenticazione lato server, avviene un reindirizzamento lato server. Se vuoi gestirlo lato client, utilizza questa callback |
resetToken Nel flusso di reimpostazione password, il server genera generalmente un
token
per tracciare in modo sicuro lo stato e l'utente che sta inviando il modulo.Il server di solito passa il
token
in due modi: o nei parametri di query dell'URL o in uncookie
. Quando il modulo viene inviato, il browser invierà automaticamente ilcookie
corrente.Nel primo caso, puoi usare
searchParams
ouseSearchParams()
per ottenere ilresetToken
dai parametri di query e passarlo al modulo, che lo invierà automaticamente al Server Action del server durante l'invio.Nel secondo caso, puoi ignorare questo parametro.
Verifica OTP
L'interfaccia è definita come segue:
export interface VerifyOTPFormProps {
email: string
verifyToken?: string
editEmailHandler?: (event: MouseEvent<HTMLButtonElement>) => void
serverAction: (
email: string,
verifyToken: string,
currentState: VerifyOTPActionState,
formData: FormData
) => Promise<VerifyOTPActionState>
codeResendAction: (email: string, verifyToken: string) => Promise<VerifyOTPActionState>
serverStateSuccessHandler?: () => void | Promise<void>
}
Parametro | Valore predefinito | Spiegazione |
---|---|---|
Email iniziale che viene mostrata nell'interfaccia utente, permettendo all'utente di modificarla facilmente | ||
verifyToken | Token generato dal server per tracciare il flusso del modulo | |
editEmailHandler | Funzione chiamata quando l'utente clicca sul pulsante per modificare l'email | |
codeResendAction | Funzione per rinviare il codice (il conteggio dei secondi può essere impostato nella costante code_resend_max_seconds in verify-otp-form.tsx ) | |
serverAction | Invia i dati del modulo al server tramite Server Actions | |
serverStateSuccessHandler | Di solito, dopo l'autenticazione lato server, avviene un reindirizzamento lato server. Se vuoi gestirlo lato client, utilizza questa callback |
verifyToken Nel flusso di verifica one-time password, il server genera generalmente un
token
per tracciare in modo sicuro lo stato e l'utente che sta inviando il modulo.Il server di solito passa il
token
in due modi: o nei parametri di query dell'URL o in uncookie
. Quando il modulo viene inviato, il browser invierà automaticamente ilcookie
corrente.Nel primo caso, puoi usare
searchParams
ouseSearchParams()
per ottenere ilverifyToken
dai parametri di query e passarlo al modulo, che lo invierà automaticamente al Server Action del server durante l'invio.Nel secondo caso, puoi ignorare questo parametro.
Lato server
Tutte le opzioni di login (tranne il login social) dopo la validazione lato client vengono inviate alle Server
Actions per l'elaborazione lato server. L'invio del modulo viene gestito utilizzando useFormState
e
useFormStatus
di React.
Nel file types/action-state.ts
del codice del template è definito un semplice formato per i dati inviati
alle Server Actions, che puoi estendere secondo necessità.
Ecco un esempio di codice per l'operazione in una server action:
sign-in-action.ts
'use server'
import type { FormType, SignInActionState } from '@/types/server'
import { redirect } from 'next/navigation'
import { revalidatePath } from 'next/cache'
export async function signInAction(
formType: FormType,
currentState: SignInActionState,
formData: FormData
): Promise<SignInActionState> {
switch (formType) {
case 'email':
return await emailAction(formData)
case 'password':
return await passwordAction(formData)
}
}
async function emailAction(formData: FormData): Promise<SignInActionState> {
const data = Object.fromEntries(formData)
const parsed = signInSchemas.email.safeParse(data)
// La validazione del modulo è necessaria anche lato server
if (!parsed.success) {
const issues: Record<string, string> = {}
parsed.error.issues.map((issue) => (issues[issue.path[0]] = issue.message))
return {
success: false,
formIssues: issues
}
}
// Esegui alcune operazioni lato server, come l'invio di email, operazioni sul database, ecc.
// Il reindirizzamento può essere eseguito lato server
revalidatePath('/auth/sign-in')
redirect(`/auth/verify-otp`)
// Oppure restituiscilo direttamente al client
// return { success: true }
}
async function passwordAction(formData: FormData): Promise<SignInActionState> {
const data = Object.fromEntries(formData)
// mock delay
await new Promise((resolve) => setTimeout(resolve, 2000))
console.log('Sign in password server action form data : ' + JSON.stringify(data, null, 2))
return { success: true }
}