LoginGen ドキュメント

紹介

LoginGenはログインページのテンプレートサイトです。このプロジェクトを開発した理由は、市場には多くのテンプレートサイトがありますが、ログインページのサポートが不足しているか、単純な1〜2つのテンプレートしかなく、完全なフロントエンドロジックを持たないものが多いためです。インタラクションの重要度では、ランディングページほどではありませんが、美しいログインページはユーザーの第一印象を深めることができます。

技術スタックは主にNext.jsShadcn/uiに基づいて開発されており、テンプレートデザインを提供するだけでなく、完全なフロントエンドロジックも提供します。また、Next.jsが提供するServer Actions機能を使用して統一されたサーバーサイド認証処理を行います*(ソーシャルログインは除く。利便性のためクライアントイベントに配置されています)*。

すべてのコードはオープンであり、Shadcnのようにコピー&ペーストして使用できます。そのため、プロジェクトの要件に応じてコードを自由に変更でき、これが推奨されています。もちろん、利便性を考慮して、フォームコンポーネントにもいくつかの一般的な属性が抽出されており、すぐに使用できます。

今後もテンプレートの追加、改善、最適化を続けていく予定ですので、ご期待ください。

インストール

テンプレートはNext.jsとShadcnに基づいて開発されているため、まずこのプロジェクト環境が必要です:

shadcn コンポーネント

他のパッケージ管理ツールを使用する場合や手動でインストールしたい場合は、shadcnのドキュメントを参照してください。

pnpm dlx shadcn@latest add card tabs form button input input-otp separator sonner

以下のCSSアニメーションをtailwind.config.jsファイルに追加してください

// for 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'
      }
    }
  }
}

sonnerには以下のコンポーネントを追加する必要があります

import { Toaster } from '@/components/ui/sonner'
 
export default function RootLayout({ children }) {
  return (
    <html lang='en'>
      <head />
      <body>
        <main>{children}</main>
        <Toaster />
      </body>
    </html>
  )
}

サードパーティ依存ライブラリ

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 -- フォームクライアントサイドバリデーション
  • motion -- アニメーションライブラリ
  • @zxcvbn-* -- パスワード強度検出ライブラリ
  • embla-carousel-* -- カルーセルライブラリ(embla-carouseldevDependenciesにインストールする必要があります。TypeScriptタイプを正しく取得するため
  • lucide-react -- アイコンライブラリ

コードのコピー&ペースト

各テンプレートのプレビューページには完全なコードが表示されています。必要なコードをコピーしてプロジェクトの対応する場所に貼り付けるだけです。テンプレートに含まれる画像はすべて元の画像を直接ダウンロードでき、ビデオはCDN方式で提供されています。

現在のところ、npxのようなワンクリックインストール機能はサポートされていませんが、後期に検討する可能性があります。

テーマ

各テンプレートにはstyles/theme.module.cssテーマファイルがあり、このファイルにはすべてのテーマ変数とそのテンプレートに必要なスタイル、アニメーションなどが含まれています。このファイルのスタイルを変更してテーマを変更したり、サイトのUI美学に合わせたりできます。

ダークモード

ダークモードはshadcnのドキュメントに従って設定してください。各テンプレートのtheme.module.cssテーマファイルでは、ダークテーマは:global(.dark) CSSセレクタプレフィックスを使用し、サイト全体のダークモードに応答します。

I18n(TODO)

現在、多言語設定はサポートされていませんが、手動で追加することは可能です。少し面倒かもしれませんが、後期にこの設定機能を追加する予定です。

フォーム属性

5つのフォームがあります: ログイン、登録、パスワード忘れ、パスワードリセット、OTP(one-time password)認証。各フォームにはすぐに使用できるようにいくつかのパラメータがあり、ほとんどのパラメータは共通です。

テンプレートコードでは、デフォルトで各フォームページは個別のルートであり、サーバーサイドリダイレクトを使用してフォームページ間のナビゲーションを行います。ただし、すべてのコンポーネントはプロパティを渡す方式で使用するように設計されているため、クライアントサイドルーティングを使用することも完全に可能です。

ログイン

インターフェース定義は以下の通りです:

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>) // for more convenient use
  serverAction?: (
    formType: 'email' | 'password',
    currentState: SignInActionState,
    formData: FormData
  ) => Promise<SignInActionState>
  serverStateSuccessHandler?: (formType: 'email' | 'password', email: string) => void | Promise<void>
}
パラメータデフォルト値説明
auths['social', 'password', 'email']認証方式: ソーシャルログイン、メールログイン、パスワードログイン
socials['google', 'github']ソーシャルログインのタイプ(レイアウトは選択された数とフォームの幅に基づいて自動的に調整されます)
email初期化メールアドレス。OTP認証フォームからメールアドレスを編集して戻った際の事前入力表示にも使用可能
emailStrategy'magic-link'メール送信タイプ。'magic-link'の場合、ページ遷移せずsonnerポップアップが表示されます。それ以外の場合はOTP認証フォームに遷移する必要があります
socialHandlerソーシャルログインボタンクリック時のコールバック関数。Auth.jsなどのライブラリを使用して実装できます
forgetHandler'#''パスワードを忘れた場合'ボタンクリック時のコールバック。利便性のためこのパラメータが用意されています
serverActionソーシャルログイン以外のすべてのフォームは、Server Actionsを介してサーバーサイドに統一して送信されます
serverStateSuccessHandler通常、サーバーサイド認証が完了するとサーバーサイドで直接リダイレクトされますが、クライアントサイドでリダイレクトロジックを実装したい場合はこのコールバックパラメータで実装できます

説明:

  1. socials -- 各テンプレートにはconfig/social.tsx設定ファイルがあります。このファイルを編集して必要なソーシャルログイン方法を拡張できます。使用する認証フレームワークに合わせてkeyを自由に変更したり、お好みのアイコンSVGに変更したりできます。
  2. email -- verify-otpフォームUIには、メールアドレスを変更するボタンがあります。ユーザーがこのボタンをクリックすると、前のページに戻って正しいメールアドレスを変更できるようにする必要があります。このemail属性は、戻った際に事前にメールアドレスを表示するために設計されています。

登録

インターフェース定義は以下の通りです:

export interface SignUpFormProps {
  email?: string
  serverAction: (currentState: SignUpActionState, formData: FormData) => Promise<SignUpActionState>
  serverStateSuccessHandler?: (email: string) => void | Promise<void>
}
パラメータデフォルト値説明
email初期化メールアドレス。OTP認証フォームからメールアドレスを編集して戻った際の事前入力表示にも使用可能
serverActionServer Actionsを介してフォームデータをサーバーサイドに送信
serverStateSuccessHandler通常、サーバーサイド認証が完了するとサーバーサイドで直接リダイレクトされますが、クライアントサイドでリダイレクトロジックを実装したい場合はこのコールバックパラメータで実装できます

パスワード忘れ

インターフェース定義は以下の通りです:

export interface ForgetPasswordProps {
  email?: string
  emailStrategy?: 'magic-link' | 'one-time-pwd'
  serverAction: (
    currentState: ForgetPasswordActionState,
    formData: FormData
  ) => Promise<ForgetPasswordActionState>
  serverStateSuccessHandler?: (email: string) => void | Promise<void>
}
パラメータデフォルト値説明
email初期化メールアドレス。OTP認証フォームからメールアドレスを編集して戻った際の事前入力表示にも使用可能
emailStrategy'magic-link'メール送信タイプ。'magic-link'の場合、ページ遷移せずsonnerポップアップが表示されます。それ以外の場合はOTP認証フォームに遷移する必要があります
serverActionServer Actionsを介してフォームデータをサーバーサイドに送信
serverStateSuccessHandler通常、サーバーサイド認証が完了するとサーバーサイドで直接リダイレクトされますが、クライアントサイドでリダイレクトロジックを実装したい場合はこのコールバックパラメータで実装できます

パスワードリセット

インターフェース定義は以下の通りです:

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>
}
パラメータデフォルト値説明
emailこのメールアドレスはパスワード強度テストのみに使用されます(ユーザーが入力するパスワードの強度を向上させるため設定することを推奨します)
resetTokenサーバーサイドで生成され、フォームフローを追跡するためのtoken
serverActionServer Actionsを介してフォームデータをサーバーサイドに送信
serverStateSuccessHandler通常、サーバーサイド認証が完了するとサーバーサイドで直接リダイレクトされますが、クライアントサイドでリダイレクトロジックを実装したい場合はこのコールバックパラメータで実装できます

resetToken パスワードリセットフローでは、通常サーバーサイドがtokenを生成し、現在のフォーム送信者と状態を安全に追跡・確認するために使用されます。

サーバーサイドは通常、tokenを渡すために2つの方法を使用します。1つはURLのクエリパラメータに配置する方法、もう1つはcookieに配置する方法です。フォームが送信されると、ブラウザは現在のcookieを自動的に持ちます。

前者の場合、searchParamsまたはuseSearchParams()を使用してクエリパラメータからresetTokenを取得し、フォームに渡すことができます。フォームは送信時に自動的にこのresetTokenをサーバーサイドのServer Actionに渡します。

後者の場合、このパラメータを無視できます。

OTP認証

インターフェース定義は以下の通りです:

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>
}
パラメータデフォルト値説明
email初期化メールアドレス。このメールアドレスはUIに表示され、ユーザーが編集しやすくなります
verifyTokenサーバーサイドで生成され、フォームフローを追跡するためのtoken
editEmailHandlerメールアドレス編集ボタンがクリックされたときのイベント関数
codeResendActionコード再送信のイベント関数(秒数はverify-otp-form.tsx内のcode_resend_max_seconds定数で設定可能)
serverActionServer Actionsを介してフォームデータをサーバーサイドに送信
serverStateSuccessHandler通常、サーバーサイド認証が完了するとサーバーサイドで直接リダイレクトされますが、クライアントサイドでリダイレクトロジックを実装したい場合はこのコールバックパラメータで実装できます

verifyToken one-time password認証フローでは、通常サーバーサイドがtokenを生成し、現在のフォーム送信者と状態を安全に追跡・確認するために使用されます。

サーバーサイドは通常、tokenを渡すために2つの方法を使用します。1つはURLのクエリパラメータに配置する方法、もう1つはcookieに配置する方法です。フォームが送信されると、ブラウザは現在のcookieを自動的に持ちます。

前者の場合、searchParamsまたはuseSearchParams()を使用してクエリパラメータからverifyTokenを取得し、フォームに渡すことができます。フォームは送信時に自動的にこのverifyTokenをサーバーサイドのServer Actionに渡します。

後者の場合、このパラメータを無視できます。

サーバーサイド

ソーシャルログインを除き、他のすべてのログインオプションはクライアントサイドでの検証が完了した後、Server Actionsに統一して送信され、サーバーサイドロジックが処理されます。ReactのuseFormStateuseFormStatusを使用してフォーム送信操作を行います。

テンプレートコードのtypes/action-state.tsでは、Server Actionに送信するデータ形式が簡単に定義されています。必要に応じて拡張できます。

以下は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)
 
  // サーバーサイドでもフォームバリデーションが必要です
  if (!parsed.success) {
    const issues: Record<string, string> = {}
    parsed.error.issues.map((issue) => (issues[issue.path[0]] = issue.message))
    return {
      success: false,
      formIssues: issues
    }
  }
 
  // メール送信、データベース操作などのサーバーサイド操作を実行
 
  // サーバーサイドでリダイレクトを実行可能
  revalidatePath('/auth/sign-in')
  redirect(`/auth/verify-otp`)
 
  // または直接クライアントに返す
  // return { success: true }
}
 
async function passwordAction(formData: FormData): Promise<SignInActionState> {
  const data = Object.fromEntries(formData)
  // モック遅延
  await new Promise((resolve) => setTimeout(resolve, 2000))
  console.log('Sign in password server action form data : ' + JSON.stringify(data, null, 2))
 
  return { success: true }
}