

View Details
ギャラリー
カルーセルギャラリー
#インタラクティブ#ミニマル+1
クリックで拡大表示できるモーダル付きの洗練されたギャラリーセクション。前後ナビゲーションで作品を順に閲覧可能
1"use client";23import { useState } from "react";45const galleryItems = [6 {7 id: 1,8 title: "幾何学パターン",9 category: "グラフィック",10 color: "from-foreground/5 to-foreground/10",11 accent: "bg-foreground/20",12 },13 {14 id: 2,15 title: "都市の輪郭",16 category: "建築",17 color: "from-foreground/8 to-foreground/3",18 accent: "bg-foreground/15",19 },20 {21 id: 3,22 title: "静寂の水面",23 category: "自然",24 color: "from-foreground/3 to-foreground/12",25 accent: "bg-foreground/25",26 },27 {28 id: 4,29 title: "構造と秩序",30 category: "建築",31 color: "from-foreground/10 to-foreground/5",32 accent: "bg-foreground/10",33 },34 {35 id: 5,36 title: "光と影の対話",37 category: "グラフィック",38 color: "from-foreground/6 to-foreground/14",39 accent: "bg-foreground/18",40 },41 {42 id: 6,43 title: "風の記憶",44 category: "自然",45 color: "from-foreground/12 to-foreground/4",46 accent: "bg-foreground/22",47 },48];4950export function GalleryLightbox001() {51 const [selectedId, setSelectedId] = useState<number | null>(null);5253 const selectedItem = galleryItems.find((item) => item.id === selectedId);5455 return (56 <section className="bg-background py-28 border-t border-border">57 <div className="mx-auto max-w-6xl px-4 sm:px-6 lg:px-8">58 {/* ヘッダー */}59 <div className="text-center">60 <div className="mx-auto flex items-center justify-center gap-4">61 <div className="h-px w-8 bg-border/40" />62 <div className="h-1.5 w-1.5 rounded-full bg-foreground/20" />63 <div className="h-px w-8 bg-border/40" />64 </div>6566 <p className="mt-8 text-[10px] uppercase tracking-[0.3em] text-muted-foreground">67 Gallery68 </p>69 <h2 className="mt-3 text-2xl font-medium tracking-wide text-foreground sm:text-3xl">70 作品コレクション71 </h2>72 <p className="mt-4 text-sm font-light leading-relaxed text-muted-foreground">73 厳選されたクリエイティブワークの数々をご覧ください74 </p>75 </div>7677 {/* グリッド */}78 <div className="mt-16 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">79 {galleryItems.map((item) => (80 <button81 key={item.id}82 onClick={() => setSelectedId(item.id)}83 className="group relative aspect-[4/3] overflow-hidden rounded-lg border border-border text-left transition-all duration-300 hover:border-foreground/20"84 >85 {/* プレースホルダー背景 */}86 <div87 className={`absolute inset-0 bg-gradient-to-br ${item.color}`}88 />8990 {/* 装飾パターン */}91 <div className="absolute inset-0 flex items-center justify-center">92 <div93 className={`h-16 w-16 rounded-full ${item.accent} transition-transform duration-500 group-hover:scale-110`}94 />95 </div>96 <div className="absolute left-6 top-6">97 <div className="h-px w-6 bg-foreground/10 transition-all duration-300 group-hover:w-10 group-hover:bg-foreground/20" />98 </div>99 <div className="absolute bottom-6 right-6">100 <div className="h-px w-6 bg-foreground/10 transition-all duration-300 group-hover:w-10 group-hover:bg-foreground/20" />101 </div>102103 {/* オーバーレイ情報 */}104 <div className="absolute inset-x-0 bottom-0 p-6">105 <p className="text-[10px] uppercase tracking-[0.2em] text-muted-foreground">106 {item.category}107 </p>108 <h3 className="mt-1.5 text-sm font-medium tracking-wide text-foreground">109 {item.title}110 </h3>111 </div>112113 {/* 拡大アイコン */}114 <div className="absolute right-4 top-4 flex h-8 w-8 items-center justify-center rounded-full border border-border/60 bg-background/80 opacity-0 backdrop-blur-sm transition-all duration-300 group-hover:opacity-100">115 <svg116 className="h-3.5 w-3.5 text-foreground"117 fill="none"118 stroke="currentColor"119 viewBox="0 0 24 24"120 >121 <path122 strokeLinecap="round"123 strokeLinejoin="round"124 strokeWidth={1.5}125 d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0zM10 7v3m0 0v3m0-3h3m-3 0H7"126 />127 </svg>128 </div>129 </button>130 ))}131 </div>132133 {/* 件数表示 */}134 <div className="mt-10 flex items-center justify-center gap-6">135 <p className="text-[10px] tracking-[0.15em] text-muted-foreground/50">136 6 作品を表示中137 </p>138 <div className="h-3 w-px bg-border/40" />139 <p className="text-[10px] tracking-[0.15em] text-muted-foreground/50">140 全コレクション141 </p>142 </div>143 </div>144145 {/* ライトボックスモーダル */}146 {selectedItem && (147 <div148 className="fixed inset-0 z-50 flex items-center justify-center bg-background/90 backdrop-blur-sm"149 onClick={() => setSelectedId(null)}150 >151 <div152 className="relative mx-4 w-full max-w-3xl"153 onClick={(e) => e.stopPropagation()}154 >155 {/* 閉じるボタン */}156 <button157 onClick={() => setSelectedId(null)}158 className="absolute -top-12 right-0 flex h-8 w-8 items-center justify-center rounded-full border border-border text-muted-foreground transition-colors duration-200 hover:text-foreground"159 >160 <svg161 className="h-4 w-4"162 fill="none"163 stroke="currentColor"164 viewBox="0 0 24 24"165 >166 <path167 strokeLinecap="round"168 strokeLinejoin="round"169 strokeWidth={1.5}170 d="M6 18L18 6M6 6l12 12"171 />172 </svg>173 </button>174175 {/* メインコンテンツ */}176 <div className="overflow-hidden rounded-lg border border-border">177 <div178 className={`relative aspect-[16/10] bg-gradient-to-br ${selectedItem.color}`}179 >180 <div className="absolute inset-0 flex items-center justify-center">181 <div182 className={`h-32 w-32 rounded-full ${selectedItem.accent}`}183 />184 </div>185186 {/* コーナー装飾 */}187 <div className="absolute left-8 top-8">188 <div className="h-1.5 w-1.5 rounded-full bg-foreground/20" />189 </div>190 <div className="absolute right-8 top-8">191 <div className="h-1.5 w-1.5 rounded-full bg-foreground/20" />192 </div>193 <div className="absolute bottom-8 left-8">194 <div className="h-1.5 w-1.5 rounded-full bg-foreground/20" />195 </div>196 <div className="absolute bottom-8 right-8">197 <div className="h-1.5 w-1.5 rounded-full bg-foreground/20" />198 </div>199 </div>200201 {/* 情報パネル */}202 <div className="border-t border-border bg-background p-6">203 <div className="flex items-start justify-between">204 <div>205 <p className="text-[10px] uppercase tracking-[0.3em] text-muted-foreground">206 {selectedItem.category}207 </p>208 <h3 className="mt-2 text-lg font-medium tracking-wide text-foreground">209 {selectedItem.title}210 </h3>211 </div>212 <div className="flex items-center gap-1.5 text-[10px] tracking-[0.15em] text-muted-foreground/50">213 <span>{selectedItem.id}</span>214 <span>/</span>215 <span>{galleryItems.length}</span>216 </div>217 </div>218 </div>219 </div>220221 {/* ナビゲーション */}222 <div className="mt-4 flex items-center justify-between">223 <button224 onClick={() => {225 const currentIndex = galleryItems.findIndex(226 (item) => item.id === selectedId227 );228 const prevIndex =229 (currentIndex - 1 + galleryItems.length) %230 galleryItems.length;231 setSelectedId(galleryItems[prevIndex].id);232 }}233 className="flex items-center gap-2 text-[10px] uppercase tracking-[0.2em] text-muted-foreground transition-colors duration-200 hover:text-foreground"234 >235 <svg236 className="h-3.5 w-3.5"237 fill="none"238 stroke="currentColor"239 viewBox="0 0 24 24"240 >241 <path242 strokeLinecap="round"243 strokeLinejoin="round"244 strokeWidth={1.5}245 d="M7 16l-4-4m0 0l4-4m-4 4h18"246 />247 </svg>248 前へ249 </button>250 <button251 onClick={() => {252 const currentIndex = galleryItems.findIndex(253 (item) => item.id === selectedId254 );255 const nextIndex =256 (currentIndex + 1) % galleryItems.length;257 setSelectedId(galleryItems[nextIndex].id);258 }}259 className="flex items-center gap-2 text-[10px] uppercase tracking-[0.2em] text-muted-foreground transition-colors duration-200 hover:text-foreground"260 >261 次へ262 <svg263 className="h-3.5 w-3.5"264 fill="none"265 stroke="currentColor"266 viewBox="0 0 24 24"267 >268 <path269 strokeLinecap="round"270 strokeLinejoin="round"271 strokeWidth={1.5}272 d="M17 8l4 4m0 0l-4 4m4-4H3"273 />274 </svg>275 </button>276 </div>277 </div>278 </div>279 )}280 </section>281 );282}