Merge version_2_1782113692699 into main #2

Merged
bender merged 2 commits from version_2_1782113692699 into main 2026-06-22 07:38:48 +00:00
4 changed files with 174 additions and 1 deletions

View File

@@ -2,11 +2,13 @@ import { Routes, Route } from 'react-router-dom';
import Layout from './components/Layout';
import HomePage from './pages/HomePage';
import RegisterPage from "@/pages/RegisterPage";
export default function App() {
return (
<Routes>
<Route element={<Layout />}>
<Route path="/" element={<HomePage />} />
<Route path="/register" element={<RegisterPage />} />
</Route>
</Routes>
);

View File

@@ -27,7 +27,9 @@ export default function Layout() {
},
{
"name": "Testimonials", "href": "#testimonials"
}
},
{ name: "Register", href: "/register" },
];
return (

168
src/pages/RegisterPage.tsx Normal file
View File

@@ -0,0 +1,168 @@
import React, { useState } from "react";
import { routes } from "@/routes";
import Input from "@/components/ui/Input";
import Label from "@/components/ui/Label";
import Button from "@/components/ui/Button";
import { Check } from "lucide-react";
export default function RegisterPage() {
const [step, setStep] = useState(1);
const [formData, setFormData] = useState({
companyName: "",
email: "",
password: "",
theme: "light",
});
const handleNext = () => setStep((s) => Math.min(s + 1, 3));
const handlePrev = () => setStep((s) => Math.max(s - 1, 1));
const handleRegister = () => {
console.log("Mock Firebase Submission:"); console.log("-> Writing to 'tenant' collection:", { companyName: formData.companyName, theme: formData.theme }); console.log("-> Writing to 'registration' collection:", { email: formData.email, password: formData.password }); alert("登録が完了しました! (Registration Complete)");
};
const steps = [
{ id: 1, label: "基本情報" },
{ id: 2, label: "テーマ選択" },
{ id: 3, label: "完了" },
];
return (
<div className="min-h-svh bg-background text-foreground flex flex-col">
<main className="flex-grow flex items-center justify-center p-6">
<div className="w-full max-w-content-width bg-card text-foreground p-8 rounded-xl border border-foreground/10 shadow-sm card">
<h1 className="text-2xl font-bold text-center"></h1>
{/* Stepper UI */}
<div className="flex items-center justify-between relative">
<div className="absolute left-0 top-5 -translate-y-1/2 w-full h-1 bg-foreground/10 -z-10 rounded-full"></div>
<div
className="absolute left-0 top-5 -translate-y-1/2 h-1 bg-primary-cta -z-10 rounded-full transition-all duration-500 ease-in-out"
style={{ width: `${((step - 1) / 2) * 100}%` }}
></div>
{steps.map((s) => (
<div key={s.id} className="flex flex-col items-center gap-3 bg-card px-2">
<div
className={`w-10 h-10 rounded-full flex items-center justify-center text-sm font-bold transition-colors duration-300 ${ step >= s.id ?"bg-primary-cta text-primary-cta-text"
: "bg-card text-foreground/50 border-2 border-foreground/10"
}`}
>
{step > s.id ? <Check className="w-5 h-5" /> : s.id}
</div>
<span className={`text-xs font-medium ${step >= s.id ?"text-foreground" : "text-foreground/50"}`}>
{s.label}
</span>
</div>
))}
</div>
{/* Step 1: Basic Info */}
{step === 1 && (
<div className="space-y-5 animate-in fade-in slide-in-from-bottom-4 duration-500">
<h2 className="text-lg font-semibold mb-4"> 1: 基本情報</h2>
<div>
<Label className="mb-2 block"> ()</Label>
<Input
value={formData.companyName}
onChange={(e) => setFormData({ ...formData, companyName: e.target.value })}
placeholder="株式会社蟹江電機"
/>
</div>
<div>
<Label className="mb-2 block"></Label>
<Input
type="email"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
placeholder="admin@example.com"
/>
</div>
<div>
<Label className="mb-2 block"></Label>
<Input
type="password"
value={formData.password}
onChange={(e) => setFormData({ ...formData, password: e.target.value })}
placeholder="••••••••"
/>
</div>
<div className="pt-6">
<Button text="次へ" onClick={handleNext} animate={false} className="w-full" />
</div>
</div>
)}
{/* Step 2: Theme Selection */}
{step === 2 && (
<div className="space-y-5 animate-in fade-in slide-in-from-bottom-4 duration-500">
<h2 className="text-lg font-semibold mb-4"> 2: テーマ選択</h2>
<div className="grid grid-cols-3 gap-4">
{["light", "dark", "system"].map((t) => (
<div
key={t}
role="button"
tabIndex={0}
onClick={() => setFormData({ ...formData, theme: t })}
className={`p-4 border rounded-lg text-center cursor-pointer transition-all ${ formData.theme === t ?"border-primary-cta bg-primary-cta/10 text-primary-cta"
: "border-foreground/10 hover:bg-foreground/5 text-foreground"
}`}
>
<div className="font-medium capitalize">
{t === "light" ? "ライト" : t === "dark" ? "ダーク" : "システム"}
</div>
</div>
))}
</div>
<div className="pt-6 flex gap-4">
<div className="w-1/2">
<Button text="戻る" variant="secondary" onClick={handlePrev} animate={false} className="w-full" />
</div>
<div className="w-1/2">
<Button text="次へ" onClick={handleNext} animate={false} className="w-full" />
</div>
</div>
</div>
)}
{/* Step 3: Complete */}
{step === 3 && (
<div className="space-y-5 animate-in fade-in slide-in-from-bottom-4 duration-500 text-center">
<div className="w-16 h-16 bg-primary-cta/10 text-primary-cta rounded-full flex items-center justify-center mx-auto mb-4">
<Check className="w-8 h-8" />
</div>
<h2 className="text-xl font-semibold mb-2"></h2>
<p className="text-sm text-foreground/60 mb-6">
</p>
<div className="bg-foreground/5 p-4 rounded-lg text-left space-y-2 text-sm mb-8 border border-foreground/10">
<div className="flex justify-between">
<span className="text-foreground/60">:</span>
<span className="font-medium">{formData.companyName || "未入力"}</span>
</div>
<div className="flex justify-between">
<span className="text-foreground/60">:</span>
<span className="font-medium">{formData.email || "未入力"}</span>
</div>
<div className="flex justify-between">
<span className="text-foreground/60">:</span>
<span className="font-medium capitalize">{formData.theme}</span>
</div>
</div>
<div className="pt-2 flex gap-4">
<div className="w-1/2">
<Button text="戻る" variant="secondary" onClick={handlePrev} animate={false} className="w-full" />
</div>
<div className="w-1/2">
<Button text="登録する" onClick={handleRegister} animate={false} className="w-full" />
</div>
</div>
</div>
)}
</div>
</main>
</div>
);
}

View File

@@ -6,4 +6,5 @@ export interface Route {
export const routes: Route[] = [
{ path: '/', label: 'Home', pageFile: 'HomePage' },
{ path: '/register', label: 'Register', pageFile: 'RegisterPage' },
];