LoginGen ドキュメント
紹介
LoginGenはログインページのテンプレートサイトです。このプロジェクトを開発した理由は、市場には多くのテンプレートサイトがありますが、ログインページのサポートが不足しているか、単純な1〜2つのテンプレートしかなく、完全なフロントエンドロジックを持たないものが多いためです。インタラクションの重要度では、ランディングページほどではありませんが、美しいログインページはユーザーの第一印象を深めることができます。
技術スタックは主にNext.jsとShadcn/uiに基づいて開発されており、テンプレートデザインを提供するだけでなく、完全なフロントエンドロジックも提供します。また、Next.jsが提供するServer Actions機能を使用して統一されたサーバーサイド認証処理を行います*(ソーシャルログインは除く。利便性のためクライアントイベントに配置されています)*。
すべてのコードはオープンであり、Shadcnのようにコピー&ペーストして使用できます。そのため、プロジェクトの要件に応じてコードを自由に変更でき、これが推奨されています。もちろん、利便性を考慮して、フォームコンポーネントにもいくつかの一般的な属性が抽出されており、すぐに使用できます。
今後もテンプレートの追加、改善、最適化を続けていく予定ですので、ご期待ください。
インストール
テンプレートはNext.jsとShadcnに基づいて開発されているため、まずこのプロジェクト環境が必要です:
- "next": "^14.2+"
- "tailwindcss": "^3.4+"
- "react-hook-form: 7.52.2" - 現時点ではより高いバージョンを使用しないでください。高いバージョンにはレンダリング時のバグがあります(issues: https://github.com/react-hook-form/react-hook-form/issues/12518)
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-carousel
はdevDependencies
にインストールする必要があります。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'] | ソーシャルログインのタイプ(レイアウトは選択された数とフォームの幅に基づいて自動的に調整されます) |
初期化メールアドレス。OTP認証フォームからメールアドレスを編集して戻った際の事前入力表示にも使用可能 | ||
emailStrategy | 'magic-link' | メール送信タイプ。'magic-link'の場合、ページ遷移せずsonnerポップアップが表示されます。それ以外の場合はOTP認証フォームに遷移する必要があります |
socialHandler | ソーシャルログインボタンクリック時のコールバック関数。Auth.jsなどのライブラリを使用して実装できます | |
forgetHandler | '#' | 'パスワードを忘れた場合'ボタンクリック時のコールバック。利便性のためこのパラメータが用意されています |
serverAction | ソーシャルログイン以外のすべてのフォームは、Server Actionsを介してサーバーサイドに統一して送信されます | |
serverStateSuccessHandler | 通常、サーバーサイド認証が完了するとサーバーサイドで直接リダイレクトされますが、クライアントサイドでリダイレクトロジックを実装したい場合はこのコールバックパラメータで実装できます |
説明:
socials
-- 各テンプレートにはconfig/social.tsx
設定ファイルがあります。このファイルを編集して必要なソーシャルログイン方法を拡張できます。使用する認証フレームワークに合わせてkey
を自由に変更したり、お好みのアイコンSVGに変更したりできます。email
--verify-otp
フォームUIには、メールアドレスを変更するボタンがあります。ユーザーがこのボタンをクリックすると、前のページに戻って正しいメールアドレスを変更できるようにする必要があります。このemail
属性は、戻った際に事前にメールアドレスを表示するために設計されています。
登録
インターフェース定義は以下の通りです:
export interface SignUpFormProps {
email?: string
serverAction: (currentState: SignUpActionState, formData: FormData) => Promise<SignUpActionState>
serverStateSuccessHandler?: (email: string) => void | Promise<void>
}
パラメータ | デフォルト値 | 説明 |
---|---|---|
初期化メールアドレス。OTP認証フォームからメールアドレスを編集して戻った際の事前入力表示にも使用可能 | ||
serverAction | Server 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>
}
パラメータ | デフォルト値 | 説明 |
---|---|---|
初期化メールアドレス。OTP認証フォームからメールアドレスを編集して戻った際の事前入力表示にも使用可能 | ||
emailStrategy | 'magic-link' | メール送信タイプ。'magic-link'の場合、ページ遷移せずsonnerポップアップが表示されます。それ以外の場合はOTP認証フォームに遷移する必要があります |
serverAction | Server 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>
}
パラメータ | デフォルト値 | 説明 |
---|---|---|
このメールアドレスはパスワード強度テストのみに使用されます(ユーザーが入力するパスワードの強度を向上させるため設定することを推奨します) | ||
resetToken | サーバーサイドで生成され、フォームフローを追跡するためのtoken | |
serverAction | Server 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>
}
パラメータ | デフォルト値 | 説明 |
---|---|---|
初期化メールアドレス。このメールアドレスはUIに表示され、ユーザーが編集しやすくなります | ||
verifyToken | サーバーサイドで生成され、フォームフローを追跡するためのtoken | |
editEmailHandler | メールアドレス編集ボタンがクリックされたときのイベント関数 | |
codeResendAction | コード再送信のイベント関数(秒数はverify-otp-form.tsx 内のcode_resend_max_seconds 定数で設定可能) | |
serverAction | Server Actionsを介してフォームデータをサーバーサイドに送信 | |
serverStateSuccessHandler | 通常、サーバーサイド認証が完了するとサーバーサイドで直接リダイレクトされますが、クライアントサイドでリダイレクトロジックを実装したい場合はこのコールバックパラメータで実装できます |
verifyToken one-time password認証フローでは、通常サーバーサイドが
token
を生成し、現在のフォーム送信者と状態を安全に追跡・確認するために使用されます。サーバーサイドは通常、
token
を渡すために2つの方法を使用します。1つはURLのクエリパラメータに配置する方法、もう1つはcookie
に配置する方法です。フォームが送信されると、ブラウザは現在のcookie
を自動的に持ちます。前者の場合、
searchParams
またはuseSearchParams()
を使用してクエリパラメータからverifyToken
を取得し、フォームに渡すことができます。フォームは送信時に自動的にこのverifyToken
をサーバーサイドのServer Actionに渡します。後者の場合、このパラメータを無視できます。
サーバーサイド
ソーシャルログインを除き、他のすべてのログインオプションはクライアントサイドでの検証が完了した後、Server
Actionsに統一して送信され、サーバーサイドロジックが処理されます。ReactのuseFormState
とuseFormStatus
を使用してフォーム送信操作を行います。
テンプレートコードの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 }
}