feat: initialize frontend application with landing page components and event listings
This commit is contained in:
98
src/App.tsx
98
src/App.tsx
@@ -1,89 +1,21 @@
|
||||
import { useState } from 'react'
|
||||
import { CheckCircle2, Terminal, Layers, Sparkles } from 'lucide-react'
|
||||
|
||||
export default function App() {
|
||||
const [count, setCount] = useState<number>(0)
|
||||
import Navbar from './components/Navbar';
|
||||
import Hero from './components/Hero';
|
||||
import EventSection from './components/EventSection';
|
||||
import Footer from './components/Footer';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="min-h-screen bg-slate-950 flex flex-col items-center justify-center relative overflow-hidden px-4 selection:bg-indigo-500 selection:text-white">
|
||||
{/* Background Glowing Effects */}
|
||||
<div className="absolute top-1/4 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[500px] h-[500px] bg-indigo-500/10 rounded-full blur-[120px] pointer-events-none" />
|
||||
<div className="absolute bottom-1/4 left-1/3 w-[300px] h-[300px] bg-emerald-500/10 rounded-full blur-[100px] pointer-events-none" />
|
||||
<div className="min-h-screen bg-[#0a0c10] text-slate-300 font-sans selection:bg-purple-500/30 selection:text-white flex flex-col">
|
||||
<Navbar />
|
||||
|
||||
{/* Main Glassmorphic Container */}
|
||||
<div className="relative max-w-lg w-full bg-slate-900/60 backdrop-blur-xl border border-slate-800/80 rounded-3xl p-8 sm:p-10 shadow-2xl transition-all duration-300 hover:border-slate-700/60">
|
||||
<main className="flex-1 flex flex-col">
|
||||
<Hero />
|
||||
<EventSection />
|
||||
</main>
|
||||
|
||||
{/* Status Badge */}
|
||||
<div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-xs font-semibold tracking-wide mb-8 animate-pulse">
|
||||
<CheckCircle2 className="w-3.5 h-3.5" />
|
||||
<span>SETUP SUCCESSFUL (TSX)</span>
|
||||
</div>
|
||||
|
||||
{/* Heading using Google Font 'Outfit' */}
|
||||
<h1 className="font-display text-4xl sm:text-5xl font-bold tracking-tight text-white leading-tight mb-4">
|
||||
Smart<span className="bg-gradient-to-r from-indigo-400 via-purple-400 to-emerald-400 bg-clip-text text-transparent">Tiket</span>
|
||||
</h1>
|
||||
|
||||
{/* Body using Google Font 'Plus Jakarta Sans' */}
|
||||
<p className="font-sans text-slate-400 text-base sm:text-lg leading-relaxed mb-8">
|
||||
Welcome to your new development environment. React 19, Tailwind CSS v4, TypeScript, and Google Fonts are successfully configured and ready.
|
||||
</p>
|
||||
|
||||
{/* Feature Checkmarks */}
|
||||
<div className="space-y-4 mb-8">
|
||||
<div className="flex items-center gap-3 text-slate-300">
|
||||
<div className="w-5 h-5 rounded-md bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center">
|
||||
<Sparkles className="w-3.5 h-3.5 text-indigo-400" />
|
||||
</div>
|
||||
<span className="font-sans text-sm font-medium">React 19 & Vite 6 Setup</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3 text-slate-300">
|
||||
<div className="w-5 h-5 rounded-md bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center">
|
||||
<Layers className="w-3.5 h-3.5 text-indigo-400" />
|
||||
</div>
|
||||
<span className="font-sans text-sm font-medium">Tailwind CSS v4 & TypeScript</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3 text-slate-300">
|
||||
<div className="w-5 h-5 rounded-md bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center">
|
||||
<CheckCircle2 className="w-3.5 h-3.5 text-indigo-400" />
|
||||
</div>
|
||||
<span className="font-sans text-sm font-medium">Outfit & Plus Jakarta Sans Google Fonts</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Interactive React Verification State */}
|
||||
<div className="p-4 rounded-2xl bg-slate-950/60 border border-slate-800/80 flex items-center justify-between gap-4 mb-8">
|
||||
<div className="text-left">
|
||||
<p className="font-sans text-xs text-slate-500 uppercase tracking-wider font-semibold">Test React State</p>
|
||||
<p className="font-display text-lg font-bold text-white mt-0.5">Clicked {count} times</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setCount(c => c + 1)}
|
||||
className="px-4 py-2 bg-indigo-600 hover:bg-indigo-500 active:scale-95 text-white text-sm font-semibold rounded-xl transition-all duration-200 cursor-pointer shadow-lg shadow-indigo-600/20"
|
||||
>
|
||||
Increment
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Console / Start Instructions */}
|
||||
<div className="bg-slate-950 border border-slate-900 rounded-2xl p-4 font-mono text-xs text-slate-400 flex items-start gap-3">
|
||||
<Terminal className="w-4 h-4 text-emerald-400 shrink-0 mt-0.5" />
|
||||
<div className="text-left space-y-1">
|
||||
<p className="text-slate-500"># Next steps to start coding:</p>
|
||||
<p>1. Open workspace directory</p>
|
||||
<p>2. Run <span className="text-indigo-400">npm install</span></p>
|
||||
<p>3. Run <span className="text-emerald-400">npm run dev</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="mt-12 text-slate-600 font-sans text-xs tracking-wide">
|
||||
© {new Date().getFullYear()} SmartTiket Setup • Built with Google DeepMind Antigravity
|
||||
</footer>
|
||||
<Footer />
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
96
src/components/EventCard.tsx
Normal file
96
src/components/EventCard.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
import { MapPin, Calendar, ArrowRight } from 'lucide-react';
|
||||
|
||||
interface EventCardProps {
|
||||
title: string;
|
||||
image: string;
|
||||
date: string;
|
||||
location: string;
|
||||
price: string;
|
||||
organizer: string;
|
||||
status?: string;
|
||||
isAvailable?: boolean;
|
||||
}
|
||||
|
||||
export default function EventCard({
|
||||
title,
|
||||
image,
|
||||
date,
|
||||
location,
|
||||
price,
|
||||
organizer,
|
||||
status = "ON SALE",
|
||||
isAvailable = true,
|
||||
}: EventCardProps) {
|
||||
return (
|
||||
<div className="group flex flex-col bg-slate-900 border border-slate-800 rounded-3xl overflow-hidden hover:border-slate-700 hover:shadow-2xl hover:shadow-purple-500/10 transition-all duration-300">
|
||||
|
||||
{/* Image Container */}
|
||||
<div className="relative h-48 sm:h-56 overflow-hidden">
|
||||
<div className="absolute inset-0 bg-slate-800 animate-pulse" /> {/* Placeholder background */}
|
||||
<img
|
||||
src={image}
|
||||
alt={title}
|
||||
className={`absolute inset-0 w-full h-full object-cover transition-transform duration-500 group-hover:scale-105 ${!isAvailable ? 'grayscale opacity-60' : ''}`}
|
||||
loading="lazy"
|
||||
/>
|
||||
|
||||
{/* Status Badge */}
|
||||
<div className="absolute top-4 left-4 z-10">
|
||||
<span className={`px-3 py-1 text-xs font-bold rounded-full backdrop-blur-md ${
|
||||
isAvailable
|
||||
? 'bg-purple-600/80 text-white border border-purple-500/50'
|
||||
: 'bg-slate-800/80 text-slate-300 border border-slate-600/50'
|
||||
}`}>
|
||||
{status}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content Container */}
|
||||
<div className="flex flex-col flex-1 p-5 sm:p-6">
|
||||
<h3 className="font-display text-xl font-bold text-white mb-4 line-clamp-2 leading-tight">
|
||||
{title}
|
||||
</h3>
|
||||
|
||||
<div className="space-y-2 mb-6 mt-auto">
|
||||
<div className="flex items-center gap-2 text-slate-400 text-sm">
|
||||
<MapPin className="w-4 h-4 shrink-0" />
|
||||
<span className="truncate">{location}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-slate-400 text-sm">
|
||||
<Calendar className="w-4 h-4 shrink-0" />
|
||||
<span>{date}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer Area */}
|
||||
<div className="pt-4 mt-auto border-t border-slate-800 flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-xs text-slate-500 mb-0.5">START FROM</p>
|
||||
{isAvailable ? (
|
||||
<p className="font-display font-bold text-lg text-white">
|
||||
{price}
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-sm font-medium text-slate-400">
|
||||
Ticket Belum Tersedia
|
||||
</p>
|
||||
)}
|
||||
<p className="text-xs text-slate-500 mt-0.5">By: {organizer}</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
className={`flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-semibold transition-all ${
|
||||
isAvailable
|
||||
? 'bg-slate-800 text-white hover:bg-slate-700'
|
||||
: 'bg-transparent border border-slate-800 text-slate-500 cursor-not-allowed'
|
||||
}`}
|
||||
>
|
||||
{isAvailable ? 'Beli' : 'Close'}
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
95
src/components/EventSection.tsx
Normal file
95
src/components/EventSection.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
import EventCard from './EventCard';
|
||||
import { ArrowRight } from 'lucide-react';
|
||||
|
||||
const MOCK_EVENTS = [
|
||||
{
|
||||
id: '1',
|
||||
title: 'PURNAMA BERSANTAI 2026',
|
||||
image: 'https://images.unsplash.com/photo-1459749411175-04bf5292ceea?q=80&w=1000&auto=format&fit=crop',
|
||||
date: '2026-08-21 15:00',
|
||||
location: 'Medan, Sumatera Utara',
|
||||
price: 'Rp 185.000',
|
||||
organizer: 'Puber2026',
|
||||
status: 'ON SALE',
|
||||
isAvailable: true,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: 'MEDAN GLOWFEST 2024',
|
||||
image: 'https://images.unsplash.com/photo-1540039155732-6761b54f6cce?q=80&w=1000&auto=format&fit=crop',
|
||||
date: '2024-12-31 18:30',
|
||||
location: 'Lakeside Garden Royal...',
|
||||
price: '-',
|
||||
organizer: 'Glowfest 2024',
|
||||
status: 'CLOSE',
|
||||
isAvailable: false,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: 'HI REV ENDURANCE OTOFEST',
|
||||
image: 'https://images.unsplash.com/photo-1514525253161-7a46d19cd819?q=80&w=1000&auto=format&fit=crop',
|
||||
date: '2024-09-13 10:00',
|
||||
location: 'Jl. Negara, Petapahan...',
|
||||
price: 'Rp 50.000',
|
||||
organizer: 'Hirevendurance',
|
||||
status: 'CLOSE',
|
||||
isAvailable: false,
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
title: 'Tamasya lebaran',
|
||||
image: 'https://images.unsplash.com/photo-1493225457124-a1a2a5956093?q=80&w=1000&auto=format&fit=crop',
|
||||
date: '2024-04-18 18:00',
|
||||
location: 'PRSU, Medan',
|
||||
price: 'Rp 100.000',
|
||||
organizer: 'Tamasya Lebaran',
|
||||
status: 'CLOSE',
|
||||
isAvailable: false,
|
||||
}
|
||||
];
|
||||
|
||||
export default function EventSection() {
|
||||
return (
|
||||
<section className="bg-[#0a0c10] py-24 px-4 sm:px-6 lg:px-8">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
{/* Section Header */}
|
||||
<div className="flex flex-col md:flex-row md:items-end justify-between mb-12 gap-6">
|
||||
<div>
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<div className="w-8 h-1 bg-purple-500 rounded-full"></div>
|
||||
<span className="text-purple-400 font-semibold tracking-wider text-sm uppercase">Event Terbaru</span>
|
||||
</div>
|
||||
<h2 className="font-display text-3xl md:text-5xl font-bold text-white tracking-tight">
|
||||
Temukan Acaramu
|
||||
</h2>
|
||||
<p className="text-slate-400 mt-3 text-lg">
|
||||
Temukan acara favorit Anda, dan mari bersenang-senang
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button className="hidden md:flex items-center gap-2 px-6 py-3 rounded-full border border-slate-700 text-slate-300 hover:text-white hover:border-slate-500 hover:bg-slate-800 transition-all text-sm font-medium shrink-0">
|
||||
View All Events
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Events Grid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
||||
{MOCK_EVENTS.map((event) => (
|
||||
<EventCard key={event.id} {...event} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Mobile View All Button */}
|
||||
<div className="mt-10 flex justify-center md:hidden">
|
||||
<button className="flex items-center gap-2 px-6 py-3 rounded-full border border-slate-700 text-slate-300 hover:text-white hover:border-slate-500 transition-all text-sm font-medium">
|
||||
View All Events
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
73
src/components/Footer.tsx
Normal file
73
src/components/Footer.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import { Facebook, Instagram, Mail, MessageCircle } from 'lucide-react';
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className="bg-[#0f111a] border-t border-white/5 pt-16 pb-8 px-4 sm:px-6 lg:px-8">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-12 mb-16">
|
||||
|
||||
{/* Brand Col */}
|
||||
<div className="col-span-1 md:col-span-2">
|
||||
<div className="flex items-center gap-2 mb-6">
|
||||
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center">
|
||||
<span className="text-white font-bold text-lg font-display">ST</span>
|
||||
</div>
|
||||
<span className="font-display font-bold text-2xl text-white tracking-tight">
|
||||
Smart<span className="text-purple-400">Ticketing</span>
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-slate-400 text-sm leading-relaxed max-w-sm mb-8">
|
||||
Platform tiket konser dan event terpercaya di Indonesia. Pembayaran online lebih gampang.
|
||||
</p>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<a href="#" className="w-10 h-10 rounded-full bg-slate-800 flex items-center justify-center text-slate-400 hover:bg-purple-600 hover:text-white transition-all">
|
||||
<Facebook className="w-5 h-5" />
|
||||
</a>
|
||||
<a href="#" className="w-10 h-10 rounded-full bg-slate-800 flex items-center justify-center text-slate-400 hover:bg-purple-600 hover:text-white transition-all">
|
||||
<Instagram className="w-5 h-5" />
|
||||
</a>
|
||||
<a href="#" className="w-10 h-10 rounded-full bg-slate-800 flex items-center justify-center text-slate-400 hover:bg-purple-600 hover:text-white transition-all">
|
||||
<Mail className="w-5 h-5" />
|
||||
</a>
|
||||
<a href="#" className="w-10 h-10 rounded-full bg-slate-800 flex items-center justify-center text-slate-400 hover:bg-purple-600 hover:text-white transition-all">
|
||||
<MessageCircle className="w-5 h-5" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Links Col 1 */}
|
||||
<div>
|
||||
<h4 className="font-display font-bold text-white mb-6 uppercase tracking-wider text-sm">Platform</h4>
|
||||
<ul className="space-y-4">
|
||||
<li><a href="#" className="text-slate-400 hover:text-purple-400 transition-colors text-sm">Beranda</a></li>
|
||||
<li><a href="#" className="text-slate-400 hover:text-purple-400 transition-colors text-sm">Event Terbaru</a></li>
|
||||
<li><a href="#" className="text-slate-400 hover:text-purple-400 transition-colors text-sm">Semua Event</a></li>
|
||||
<li><a href="#" className="text-slate-400 hover:text-purple-400 transition-colors text-sm">Kategori</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Links Col 2 */}
|
||||
<div>
|
||||
<h4 className="font-display font-bold text-white mb-6 uppercase tracking-wider text-sm">Bantuan</h4>
|
||||
<ul className="space-y-4">
|
||||
<li><a href="#" className="text-slate-400 hover:text-purple-400 transition-colors text-sm">Hubungi Kami</a></li>
|
||||
<li><a href="#" className="text-slate-400 hover:text-purple-400 transition-colors text-sm">Syarat & Ketentuan</a></li>
|
||||
<li><a href="#" className="text-slate-400 hover:text-purple-400 transition-colors text-sm">Kebijakan Privasi</a></li>
|
||||
<li><a href="#" className="text-slate-400 hover:text-purple-400 transition-colors text-sm">FAQ</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-8 border-t border-slate-800 flex flex-col md:flex-row items-center justify-between gap-4">
|
||||
<p className="text-slate-500 text-xs">
|
||||
© {new Date().getFullYear()} Smart Ticketing. All rights reserved.
|
||||
</p>
|
||||
<p className="text-slate-500 text-xs">
|
||||
Made with love in Indonesia
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
132
src/components/Hero.tsx
Normal file
132
src/components/Hero.tsx
Normal file
@@ -0,0 +1,132 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||||
|
||||
const SLIDES = [
|
||||
{
|
||||
id: 1,
|
||||
title1: "Music Festival",
|
||||
title2: "Concert",
|
||||
subtitle: "Jual Ticket di Smart Ticketing Aja",
|
||||
gradientText: "from-cyan-400 via-indigo-400 to-purple-400",
|
||||
gradientSub: "from-emerald-400 to-cyan-400",
|
||||
blob1: "bg-purple-600/30",
|
||||
blob2: "bg-cyan-500/20",
|
||||
blob3: "bg-indigo-600/20"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title1: "Standup Comedy",
|
||||
title2: "Special Show",
|
||||
subtitle: "Pesan Kursi Terbaikmu Sekarang",
|
||||
gradientText: "from-pink-400 via-rose-400 to-red-500",
|
||||
gradientSub: "from-orange-400 to-amber-400",
|
||||
blob1: "bg-pink-600/30",
|
||||
blob2: "bg-rose-500/20",
|
||||
blob3: "bg-red-600/20"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title1: "E-Sports",
|
||||
title2: "Tournament",
|
||||
subtitle: "Dukung Tim Favoritmu Langsung",
|
||||
gradientText: "from-blue-400 via-cyan-400 to-teal-400",
|
||||
gradientSub: "from-lime-400 to-emerald-400",
|
||||
blob1: "bg-blue-600/30",
|
||||
blob2: "bg-teal-500/20",
|
||||
blob3: "bg-cyan-600/20"
|
||||
}
|
||||
];
|
||||
|
||||
export default function Hero() {
|
||||
const [currentSlide, setCurrentSlide] = useState(0);
|
||||
|
||||
// Auto-play
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
setCurrentSlide((prev) => (prev + 1) % SLIDES.length);
|
||||
}, 5000);
|
||||
return () => clearInterval(timer);
|
||||
}, []);
|
||||
|
||||
const nextSlide = () => {
|
||||
setCurrentSlide((prev) => (prev + 1) % SLIDES.length);
|
||||
};
|
||||
|
||||
const prevSlide = () => {
|
||||
setCurrentSlide((prev) => (prev - 1 + SLIDES.length) % SLIDES.length);
|
||||
};
|
||||
|
||||
const slide = SLIDES[currentSlide];
|
||||
|
||||
return (
|
||||
<div className="relative min-h-[90vh] flex items-center justify-center overflow-hidden bg-slate-950 pt-20 transition-colors duration-1000">
|
||||
{/* Abstract Backgrounds (Dynamic based on slide) */}
|
||||
<div className="absolute inset-0 w-full h-full transition-all duration-1000">
|
||||
<div className={`absolute top-0 left-1/4 w-[800px] h-[800px] ${slide.blob1} rounded-full blur-[150px] mix-blend-screen animate-pulse transition-colors duration-1000`} />
|
||||
<div className={`absolute bottom-0 right-1/4 w-[600px] h-[600px] ${slide.blob2} rounded-full blur-[120px] mix-blend-screen transition-colors duration-1000`} />
|
||||
<div className={`absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[1000px] h-[500px] ${slide.blob3} rounded-full blur-[150px] transition-colors duration-1000`} />
|
||||
</div>
|
||||
|
||||
{/* Content Container */}
|
||||
<div className="relative z-10 text-center px-4 max-w-5xl mx-auto flex flex-col items-center">
|
||||
|
||||
{/* Large Decorative Text */}
|
||||
<h1
|
||||
key={`title1-${slide.id}`}
|
||||
className={`font-display font-black text-6xl md:text-8xl lg:text-9xl text-transparent bg-clip-text bg-gradient-to-r ${slide.gradientText} drop-shadow-2xl mb-2 tracking-tighter uppercase animate-in fade-in slide-in-from-bottom-4 duration-700`}
|
||||
>
|
||||
{slide.title1}
|
||||
</h1>
|
||||
<h2
|
||||
key={`title2-${slide.id}`}
|
||||
className="font-display font-black text-6xl md:text-8xl lg:text-9xl text-slate-100 drop-shadow-2xl tracking-tighter uppercase mb-8 animate-in fade-in slide-in-from-bottom-4 duration-700 delay-100 fill-mode-backwards"
|
||||
>
|
||||
{slide.title2}
|
||||
</h2>
|
||||
|
||||
{/* Subtitle Call to action */}
|
||||
<div className="inline-block relative animate-in fade-in slide-in-from-bottom-4 duration-700 delay-200 fill-mode-backwards" key={`sub-${slide.id}`}>
|
||||
<div className={`absolute inset-0 bg-gradient-to-r ${slide.gradientSub} blur-xl opacity-30 transition-colors duration-1000`}></div>
|
||||
<h3 className={`relative font-display font-extrabold text-3xl md:text-5xl text-transparent bg-clip-text bg-gradient-to-r ${slide.gradientSub} tracking-tight uppercase transition-colors duration-1000`}>
|
||||
{slide.subtitle}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
{/* Decorative Elements */}
|
||||
<div className="absolute top-1/4 left-10 md:left-20 animate-bounce delay-100 hidden lg:block">
|
||||
<div className="w-16 h-16 rounded-3xl bg-gradient-to-tr from-cyan-400 to-blue-500 rotate-12 shadow-[0_0_30px_rgba(34,211,238,0.4)]" />
|
||||
</div>
|
||||
<div className="absolute bottom-1/4 right-10 md:right-20 animate-bounce delay-300 hidden lg:block">
|
||||
<div className="w-20 h-20 rounded-full bg-gradient-to-tr from-yellow-400 to-orange-500 shadow-[0_0_30px_rgba(250,204,21,0.4)]" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Slide Indicators */}
|
||||
<div className="absolute bottom-10 left-1/2 -translate-x-1/2 flex items-center gap-3 z-20">
|
||||
{SLIDES.map((_, index) => (
|
||||
<button
|
||||
key={index}
|
||||
onClick={() => setCurrentSlide(index)}
|
||||
className={`w-3 h-3 rounded-full transition-all duration-300 ${
|
||||
currentSlide === index ? 'bg-white w-8' : 'bg-white/30 hover:bg-white/60'
|
||||
}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Carousel Controls */}
|
||||
<button
|
||||
onClick={prevSlide}
|
||||
className="absolute left-4 md:left-10 top-1/2 -translate-y-1/2 w-12 h-12 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-white/50 hover:text-white hover:bg-white/10 transition-all backdrop-blur-md z-20"
|
||||
>
|
||||
<ChevronLeft className="w-6 h-6" />
|
||||
</button>
|
||||
<button
|
||||
onClick={nextSlide}
|
||||
className="absolute right-4 md:right-10 top-1/2 -translate-y-1/2 w-12 h-12 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-white/50 hover:text-white hover:bg-white/10 transition-all backdrop-blur-md z-20"
|
||||
>
|
||||
<ChevronRight className="w-6 h-6" />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
49
src/components/Navbar.tsx
Normal file
49
src/components/Navbar.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Search, User } from 'lucide-react';
|
||||
|
||||
export default function Navbar() {
|
||||
return (
|
||||
<nav className="fixed top-0 w-full z-50 bg-[#0f111a]/80 backdrop-blur-md border-b border-white/5 transition-all">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex items-center justify-between h-20">
|
||||
|
||||
{/* Logo */}
|
||||
<div className="flex-shrink-0 flex items-center gap-2 cursor-pointer">
|
||||
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center">
|
||||
<span className="text-white font-bold text-lg font-display">ST</span>
|
||||
</div>
|
||||
<span className="font-display font-bold text-2xl text-white tracking-tight">
|
||||
Smart<span className="text-purple-400">Ticketing</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Search Bar */}
|
||||
<div className="hidden md:flex flex-1 max-w-xl mx-8">
|
||||
<div className="relative w-full">
|
||||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<Search className="h-4 w-4 text-slate-400" />
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
className="block w-full pl-10 pr-3 py-2.5 border-transparent rounded-2xl bg-slate-800/50 text-slate-300 placeholder-slate-400 focus:outline-none focus:bg-slate-800 focus:ring-2 focus:ring-purple-500/50 sm:text-sm transition-all"
|
||||
placeholder="Cari event, konser, festival..."
|
||||
/>
|
||||
<div className="absolute inset-y-1 right-1">
|
||||
<button className="h-full px-4 rounded-xl bg-purple-600 hover:bg-purple-500 text-white text-xs font-semibold transition-colors">
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Navigation */}
|
||||
<div className="flex items-center gap-4">
|
||||
<button className="flex items-center gap-2 text-slate-300 hover:text-white transition-colors px-4 py-2 rounded-xl hover:bg-slate-800/50 font-medium text-sm">
|
||||
<User className="w-4 h-4" />
|
||||
Sign In
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
11
vite.config.ts
Normal file
11
vite.config.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
tailwindcss(),
|
||||
react()
|
||||
],
|
||||
})
|
||||
Reference in New Issue
Block a user