

View Details
ギャラリー
フィーチャードギャラリー
#ミニマル#ホバーエフェクト+1
左右ナビゲーションとサムネイル一覧を備えたカルーセル型のプロジェクトギャラリー
1"use client";23import { useState } from "react";45const projects = [6 {7 title: "デジタルプロダクト",8 category: "プロダクトデザイン",9 year: "2024",10 description: "直感的なインターフェースを追求した、次世代のプロダクト体験。",11 },12 {13 title: "ブランドリニューアル",14 category: "ブランディング",15 year: "2024",16 description: "企業の本質を捉え直し、新たなビジュアル言語で再構築。",17 },18 {19 title: "空間デザイン",20 category: "インテリア",21 year: "2023",22 description: "光と素材の対話から生まれる、静謐で上質な空間設計。",23 },24 {25 title: "エディトリアル",26 category: "グラフィック",27 year: "2024",28 description: "情報の階層を丁寧に整理し、読む体験そのものをデザイン。",29 },30 {31 title: "ウェブプラットフォーム",32 category: "ウェブデザイン",33 year: "2023",34 description: "複雑な機能を簡潔に提示する、洗練されたインターフェース。",35 },36];3738export function GalleryCarousel001() {39 const [current, setCurrent] = useState(0);4041 const goTo = (index: number) => {42 if (index < 0) {43 setCurrent(projects.length - 1);44 } else if (index >= projects.length) {45 setCurrent(0);46 } else {47 setCurrent(index);48 }49 };5051 return (52 <section className="bg-background py-28 border-t border-border">53 <div className="mx-auto max-w-6xl px-4 sm:px-6 lg:px-8">54 {/* ヘッダー */}55 <div className="flex flex-col gap-6 sm:flex-row sm:items-end sm:justify-between">56 <div>57 <p className="text-[10px] uppercase tracking-[0.3em] text-muted-foreground">58 Gallery59 </p>60 <h2 className="mt-3 text-2xl font-medium tracking-wide text-foreground sm:text-3xl">61 厳選されたプロジェクト62 </h2>63 </div>6465 {/* ナビゲーション */}66 <div className="flex items-center gap-4">67 <span className="text-xs tabular-nums tracking-[0.2em] text-muted-foreground/60">68 {String(current + 1).padStart(2, "0")} / {String(projects.length).padStart(2, "0")}69 </span>70 <div className="flex items-center gap-2">71 <button72 onClick={() => goTo(current - 1)}73 className="flex h-9 w-9 items-center justify-center rounded-full border border-border text-foreground/60 transition-colors duration-200 hover:border-foreground/40 hover:text-foreground"74 aria-label="前のプロジェクト"75 >76 <svg className="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">77 <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M15 19l-7-7 7-7" />78 </svg>79 </button>80 <button81 onClick={() => goTo(current + 1)}82 className="flex h-9 w-9 items-center justify-center rounded-full border border-border text-foreground/60 transition-colors duration-200 hover:border-foreground/40 hover:text-foreground"83 aria-label="次のプロジェクト"84 >85 <svg className="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">86 <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M9 5l7 7-7 7" />87 </svg>88 </button>89 </div>90 </div>91 </div>9293 <div className="mt-4 h-px bg-border/40" />9495 {/* カルーセル本体 */}96 <div className="mt-12">97 <div className="grid grid-cols-1 gap-8 lg:grid-cols-2">98 {/* ビジュアルエリア */}99 <div className="relative aspect-[4/3] overflow-hidden rounded-lg border border-border bg-muted">100 <div className="absolute inset-0 bg-gradient-to-br from-foreground/5 to-foreground/10 transition-all duration-700" />101 {/* コーナードット */}102 <div className="absolute left-4 top-4 h-1.5 w-1.5 rounded-full bg-foreground/20" />103 <div className="absolute right-4 top-4 h-1.5 w-1.5 rounded-full bg-foreground/20" />104 <div className="absolute bottom-4 left-4 h-1.5 w-1.5 rounded-full bg-foreground/20" />105 <div className="absolute bottom-4 right-4 h-1.5 w-1.5 rounded-full bg-foreground/20" />106 {/* 中央ラベル */}107 <div className="absolute inset-0 flex flex-col items-center justify-center gap-3">108 <span className="text-[10px] uppercase tracking-[0.3em] text-foreground/30">109 {projects[current].category}110 </span>111 <span className="text-lg font-medium tracking-wide text-foreground/40">112 {projects[current].title}113 </span>114 </div>115 </div>116117 {/* テキストエリア */}118 <div className="flex flex-col justify-between py-2">119 <div>120 <div className="flex items-center gap-4">121 <span className="text-[10px] uppercase tracking-[0.2em] text-muted-foreground/50">122 {projects[current].year}123 </span>124 <div className="h-px flex-1 bg-border/40" />125 </div>126 <h3 className="mt-6 text-xl font-medium tracking-wide text-foreground sm:text-2xl">127 {projects[current].title}128 </h3>129 <p className="mt-2 text-xs uppercase tracking-[0.2em] text-muted-foreground">130 {projects[current].category}131 </p>132 <p className="mt-6 text-sm font-light leading-relaxed text-muted-foreground">133 {projects[current].description}134 </p>135 </div>136137 {/* 下部のインジケーター */}138 <div className="mt-8 flex items-center gap-2">139 {projects.map((_, index) => (140 <button141 key={index}142 onClick={() => setCurrent(index)}143 className={`h-px transition-all duration-300 ${144 index === current145 ? "w-8 bg-foreground"146 : "w-4 bg-border/60 hover:bg-foreground/30"147 }`}148 aria-label={`プロジェクト ${index + 1}`}149 />150 ))}151 </div>152 </div>153 </div>154 </div>155156 {/* サムネイルリスト */}157 <div className="mt-12 grid grid-cols-5 gap-3">158 {projects.map((project, index) => (159 <button160 key={project.title}161 onClick={() => setCurrent(index)}162 className={`group text-left transition-opacity duration-200 ${163 index === current ? "opacity-100" : "opacity-40 hover:opacity-70"164 }`}165 >166 <div className="aspect-[3/2] overflow-hidden rounded border border-border bg-muted">167 <div className="h-full w-full bg-gradient-to-br from-foreground/5 to-foreground/10" />168 </div>169 <p className="mt-2 truncate text-[10px] tracking-[0.15em] text-muted-foreground">170 {project.title}171 </p>172 </button>173 ))}174 </div>175 </div>176 </section>177 );178}