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:

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 moduli
  • motion -- Libreria di animazioni
  • @zxcvbn-* -- Libreria per il controllo della forza delle password
  • embla-carousel-* -- Libreria per i caroselli (dove embla-carousel deve essere installato in devDependencies 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>
}
ParametroValore predefinitoSpiegazione
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)
emailEmail 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
socialHandlerFunzione 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
serverActionTutti i moduli (tranne il login social) inviano i dati al server tramite Server Actions
serverStateSuccessHandlerDi solito, dopo l'autenticazione lato server, avviene un reindirizzamento lato server. Se vuoi gestirlo lato client, utilizza questa callback

Note:

  1. socials -- Ogni template ha un file di configurazione config/social.tsx. Puoi modificarlo per aggiungere altri metodi di login social. Puoi modificare liberamente la key per adattarla al tuo framework di autenticazione o cambiare le icone SVG a tuo piacimento.
  2. email -- Nell'UI del modulo verify-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 parametro email 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>
}
ParametroValore predefinitoSpiegazione
emailEmail iniziale, utile anche per il pre-riempimento quando si torna dal modulo di verifica OTP dopo la modifica
serverActionInvia i dati del modulo al server tramite Server Actions
serverStateSuccessHandlerDi 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>
}
ParametroValore predefinitoSpiegazione
emailEmail 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
serverActionInvia i dati del modulo al server tramite Server Actions
serverStateSuccessHandlerDi 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>
}
ParametroValore predefinitoSpiegazione
emailL'email viene utilizzata solo per testare la forza della password (consigliato impostarla per migliorare la sicurezza)
resetTokenToken generato dal server per tracciare il flusso del modulo
serverActionInvia i dati del modulo al server tramite Server Actions
serverStateSuccessHandlerDi 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 un cookie. Quando il modulo viene inviato, il browser invierà automaticamente il cookie corrente.

Nel primo caso, puoi usare searchParams o useSearchParams() per ottenere il resetToken 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>
}
ParametroValore predefinitoSpiegazione
emailEmail iniziale che viene mostrata nell'interfaccia utente, permettendo all'utente di modificarla facilmente
verifyTokenToken generato dal server per tracciare il flusso del modulo
editEmailHandlerFunzione chiamata quando l'utente clicca sul pulsante per modificare l'email
codeResendActionFunzione per rinviare il codice (il conteggio dei secondi può essere impostato nella costante code_resend_max_seconds in verify-otp-form.tsx)
serverActionInvia i dati del modulo al server tramite Server Actions
serverStateSuccessHandlerDi 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 un cookie. Quando il modulo viene inviato, il browser invierà automaticamente il cookie corrente.

Nel primo caso, puoi usare searchParams o useSearchParams() per ottenere il verifyToken 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 }
}