コンタクト/

カード付きコンタクトフォーム

Preview

連絡先情報をカードで表示し、右側にお問い合わせフォームを配置したコンタクトセクション。営業時間や所在地などの情報をコンパクトにまとめ、フォームと並べて表示。

Source Code
tsx
266 lines
1"use client";
2
3import { useState } from "react";
4
5export function ContactCard001() {
6 const [formData, setFormData] = useState({
7 name: "",
8 email: "",
9 subject: "",
10 message: "",
11 });
12
13 const handleSubmit = (e: React.FormEvent) => {
14 e.preventDefault();
15 };
16
17 const handleChange = (
18 e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>
19 ) => {
20 setFormData((prev) => ({
21 ...prev,
22 [e.target.name]: e.target.value,
23 }));
24 };
25
26 const contactInfo = [
27 {
28 label: "Email",
29 value: "hello@example.com",
30 icon: (
31 <svg
32 className="h-4 w-4"
33 fill="none"
34 stroke="currentColor"
35 viewBox="0 0 24 24"
36 >
37 <path
38 strokeLinecap="round"
39 strokeLinejoin="round"
40 strokeWidth={1.5}
41 d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75"
42 />
43 </svg>
44 ),
45 },
46 {
47 label: "Phone",
48 value: "03-1234-5678",
49 icon: (
50 <svg
51 className="h-4 w-4"
52 fill="none"
53 stroke="currentColor"
54 viewBox="0 0 24 24"
55 >
56 <path
57 strokeLinecap="round"
58 strokeLinejoin="round"
59 strokeWidth={1.5}
60 d="M2.25 6.75c0 8.284 6.716 15 15 15h2.25a2.25 2.25 0 002.25-2.25v-1.372c0-.516-.351-.966-.852-1.091l-4.423-1.106c-.44-.11-.902.055-1.173.417l-.97 1.293c-.282.376-.769.542-1.21.38a12.035 12.035 0 01-7.143-7.143c-.162-.441.004-.928.38-1.21l1.293-.97c.363-.271.527-.734.417-1.173L6.963 3.102a1.125 1.125 0 00-1.091-.852H4.5A2.25 2.25 0 002.25 4.5v2.25z"
61 />
62 </svg>
63 ),
64 },
65 {
66 label: "Location",
67 value: "東京都渋谷区神南1-2-3",
68 icon: (
69 <svg
70 className="h-4 w-4"
71 fill="none"
72 stroke="currentColor"
73 viewBox="0 0 24 24"
74 >
75 <path
76 strokeLinecap="round"
77 strokeLinejoin="round"
78 strokeWidth={1.5}
79 d="M15 10.5a3 3 0 11-6 0 3 3 0 016 0z"
80 />
81 <path
82 strokeLinecap="round"
83 strokeLinejoin="round"
84 strokeWidth={1.5}
85 d="M19.5 10.5c0 7.142-7.5 11.25-7.5 11.25S4.5 17.642 4.5 10.5a7.5 7.5 0 1115 0z"
86 />
87 </svg>
88 ),
89 },
90 ];
91
92 return (
93 <section className="bg-background py-28 border-t border-border">
94 <div className="mx-auto max-w-6xl px-4 sm:px-6 lg:px-8">
95 {/* ヘッダー */}
96 <div className="text-center">
97 <p className="text-[10px] uppercase tracking-[0.3em] text-muted-foreground">
98 Contact Us
99 </p>
100 <h2 className="mt-3 text-2xl font-medium tracking-wide text-foreground sm:text-3xl">
101 お問い合わせ
102 </h2>
103 <p className="mx-auto mt-4 max-w-lg text-sm font-light leading-relaxed text-muted-foreground">
104 プロジェクトのご相談やお見積りなど、お気軽にお問い合わせください。通常2営業日以内にご返信いたします。
105 </p>
106 </div>
107
108 <div className="mt-4 h-px bg-border/40" />
109
110 {/* コンテンツ */}
111 <div className="mt-12 grid grid-cols-1 gap-12 lg:grid-cols-3">
112 {/* 連絡先情報カード */}
113 <div className="space-y-6 lg:col-span-1">
114 {contactInfo.map((info) => (
115 <div
116 key={info.label}
117 className="group relative rounded-lg border border-border p-6 transition-colors duration-200 hover:border-border/80 hover:bg-muted/30"
118 >
119 {/* コーナードット */}
120 <div className="absolute left-2 top-2 h-1 w-1 rounded-full bg-foreground/15" />
121 <div className="absolute right-2 top-2 h-1 w-1 rounded-full bg-foreground/15" />
122 <div className="absolute bottom-2 left-2 h-1 w-1 rounded-full bg-foreground/15" />
123 <div className="absolute bottom-2 right-2 h-1 w-1 rounded-full bg-foreground/15" />
124
125 <div className="flex items-start gap-4">
126 <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-border bg-muted/50 text-muted-foreground transition-colors duration-200 group-hover:text-foreground">
127 {info.icon}
128 </div>
129 <div>
130 <p className="text-[10px] uppercase tracking-[0.2em] text-muted-foreground/70">
131 {info.label}
132 </p>
133 <p className="mt-1.5 text-sm font-medium tracking-wide text-foreground">
134 {info.value}
135 </p>
136 </div>
137 </div>
138 </div>
139 ))}
140
141 {/* 営業時間 */}
142 <div className="rounded-lg border border-border p-6">
143 <p className="text-[10px] uppercase tracking-[0.2em] text-muted-foreground/70">
144 Business Hours
145 </p>
146 <div className="mt-3 space-y-2">
147 <div className="flex items-center justify-between text-xs tracking-wide">
148 <span className="text-muted-foreground">月曜 - 金曜</span>
149 <span className="text-foreground">9:00 - 18:00</span>
150 </div>
151 <div className="h-px bg-border/30" />
152 <div className="flex items-center justify-between text-xs tracking-wide">
153 <span className="text-muted-foreground">土曜・日曜</span>
154 <span className="text-muted-foreground/60">休業</span>
155 </div>
156 </div>
157 </div>
158 </div>
159
160 {/* フォーム */}
161 <div className="lg:col-span-2">
162 <form onSubmit={handleSubmit} className="space-y-6">
163 <div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
164 <div>
165 <label
166 htmlFor="contact-card-name"
167 className="block text-[10px] uppercase tracking-[0.2em] text-muted-foreground"
168 >
169 お名前
170 </label>
171 <input
172 type="text"
173 id="contact-card-name"
174 name="name"
175 value={formData.name}
176 onChange={handleChange}
177 className="mt-3 block w-full border-b border-border bg-transparent py-3 text-sm tracking-wide text-foreground placeholder-muted-foreground/40 transition-colors duration-200 focus:border-foreground focus:outline-none"
178 placeholder="山田 太郎"
179 />
180 </div>
181 <div>
182 <label
183 htmlFor="contact-card-email"
184 className="block text-[10px] uppercase tracking-[0.2em] text-muted-foreground"
185 >
186 メールアドレス
187 </label>
188 <input
189 type="email"
190 id="contact-card-email"
191 name="email"
192 value={formData.email}
193 onChange={handleChange}
194 className="mt-3 block w-full border-b border-border bg-transparent py-3 text-sm tracking-wide text-foreground placeholder-muted-foreground/40 transition-colors duration-200 focus:border-foreground focus:outline-none"
195 placeholder="your@email.com"
196 />
197 </div>
198 </div>
199
200 <div>
201 <label
202 htmlFor="contact-card-subject"
203 className="block text-[10px] uppercase tracking-[0.2em] text-muted-foreground"
204 >
205 件名
206 </label>
207 <input
208 type="text"
209 id="contact-card-subject"
210 name="subject"
211 value={formData.subject}
212 onChange={handleChange}
213 className="mt-3 block w-full border-b border-border bg-transparent py-3 text-sm tracking-wide text-foreground placeholder-muted-foreground/40 transition-colors duration-200 focus:border-foreground focus:outline-none"
214 placeholder="お問い合わせの内容"
215 />
216 </div>
217
218 <div>
219 <label
220 htmlFor="contact-card-message"
221 className="block text-[10px] uppercase tracking-[0.2em] text-muted-foreground"
222 >
223 メッセージ
224 </label>
225 <textarea
226 id="contact-card-message"
227 name="message"
228 rows={5}
229 value={formData.message}
230 onChange={handleChange}
231 className="mt-3 block w-full resize-none border-b border-border bg-transparent py-3 text-sm tracking-wide text-foreground placeholder-muted-foreground/40 transition-colors duration-200 focus:border-foreground focus:outline-none"
232 placeholder="プロジェクトの概要やご要望をお聞かせください..."
233 />
234 </div>
235
236 <div className="flex items-center justify-between pt-4">
237 <p className="text-[10px] tracking-wide text-muted-foreground/50">
238 * すべての項目は必須です
239 </p>
240 <button
241 type="submit"
242 className="inline-flex items-center gap-2 rounded-sm border border-foreground bg-foreground px-6 py-3 text-xs font-medium uppercase tracking-[0.15em] text-background transition-all duration-200 hover:bg-foreground/90"
243 >
244 送信する
245 <svg
246 className="h-3.5 w-3.5"
247 fill="none"
248 stroke="currentColor"
249 viewBox="0 0 24 24"
250 >
251 <path
252 strokeLinecap="round"
253 strokeLinejoin="round"
254 strokeWidth={1.5}
255 d="M6 12L3.269 3.126A59.768 59.768 0 0121.485 12 59.77 59.77 0 013.27 20.876L5.999 12zm0 0h7.5"
256 />
257 </svg>
258 </button>
259 </div>
260 </form>
261 </div>
262 </div>
263 </div>
264 </section>
265 );
266}