Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ed7ed6ec7e | |||
| 8a951092b0 | |||
| 2a830e6c24 | |||
| cf7a8842c5 | |||
| 3af1d9d9f5 | |||
| bcfd01265a | |||
| 0b064fdd08 | |||
| f99e0d80eb | |||
| 8f5ace10d9 | |||
| f44c9c40b3 | |||
| cff8aa84d5 | |||
| 49f4f4a6a3 | |||
| a545a8edbe | |||
| d6c2f75b2c | |||
| 5a69f33498 | |||
| 21a4b6a64a | |||
| b97270b14e | |||
| 70cbb9bb7b | |||
| 91b67973ba | |||
| b25ee3ade6 | |||
| 60f09ad641 | |||
| e44ead1e99 | |||
| fba1a578bc | |||
| 7330565550 | |||
| 004f008065 | |||
| 9887b9eded | |||
| 124bd70528 | |||
| 2fa8fa3b0d | |||
| 43f6f4c8c5 | |||
| 8c020e6fcf | |||
| 834170a114 | |||
| c9d2287d60 | |||
| 50a66a5434 | |||
| 4f4846c706 | |||
| e3e4bde638 | |||
| 0ef5592042 |
72
src/app/api/upload-video/route.ts
Normal file
72
src/app/api/upload-video/route.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
const MAX_FILE_SIZE = 500 * 1024 * 1024; // 500MB
|
||||
const ALLOWED_FORMATS = ['video/mp4', 'video/mpeg', 'video/quicktime', 'video/x-msvideo'];
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const formData = await request.formData();
|
||||
const file = formData.get('file') as File;
|
||||
const title = formData.get('title') as string;
|
||||
const description = formData.get('description') as string;
|
||||
|
||||
// Validation
|
||||
if (!file) {
|
||||
return NextResponse.json(
|
||||
{ message: 'No file provided' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
if (!title || title.trim().length === 0) {
|
||||
return NextResponse.json(
|
||||
{ message: 'Video title is required' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
if (file.size > MAX_FILE_SIZE) {
|
||||
return NextResponse.json(
|
||||
{ message: `File size exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit` },
|
||||
{ status: 413 }
|
||||
);
|
||||
}
|
||||
|
||||
if (!ALLOWED_FORMATS.includes(file.type)) {
|
||||
return NextResponse.json(
|
||||
{ message: 'Invalid file format. Supported: MP4, MPEG, MOV, AVI' },
|
||||
{ status: 415 }
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Implement actual file storage
|
||||
// This could be:
|
||||
// 1. Cloud storage (AWS S3, Google Cloud Storage, etc.)
|
||||
// 2. Local file system (with proper permissions)
|
||||
// 3. Database blob storage
|
||||
// 4. CDN integration
|
||||
|
||||
// For now, return success response
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: true,
|
||||
message: 'Video uploaded successfully',
|
||||
video: {
|
||||
title,
|
||||
description,
|
||||
fileName: file.name,
|
||||
fileSize: file.size,
|
||||
mimeType: file.type,
|
||||
uploadedAt: new Date().toISOString(),
|
||||
},
|
||||
},
|
||||
{ status: 201 }
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Video upload error:', error);
|
||||
return NextResponse.json(
|
||||
{ message: 'Internal server error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
170
src/app/chef-profile/page.tsx
Normal file
170
src/app/chef-profile/page.tsx
Normal file
@@ -0,0 +1,170 @@
|
||||
"use client";
|
||||
|
||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||
import NavbarStyleCentered from '@/components/navbar/NavbarStyleCentered/NavbarStyleCentered';
|
||||
import HeroLogoBillboard from '@/components/sections/hero/HeroLogoBillboard';
|
||||
import TeamCardOne from '@/components/sections/team/TeamCardOne';
|
||||
import MetricCardThree from '@/components/sections/metrics/MetricCardThree';
|
||||
import TestimonialCardThirteen from '@/components/sections/testimonial/TestimonialCardThirteen';
|
||||
import FooterBaseCard from '@/components/sections/footer/FooterBaseCard';
|
||||
import { Star, Users, Heart, Mail } from "lucide-react";
|
||||
|
||||
export default function ChefProfilePage() {
|
||||
return (
|
||||
<ThemeProvider
|
||||
defaultButtonVariant="hover-bubble"
|
||||
defaultTextAnimation="reveal-blur"
|
||||
borderRadius="rounded"
|
||||
contentWidth="small"
|
||||
sizing="largeSmallSizeLargeTitles"
|
||||
background="circleGradient"
|
||||
cardStyle="gradient-bordered"
|
||||
primaryButtonStyle="double-inset"
|
||||
secondaryButtonStyle="solid"
|
||||
headingFontWeight="extrabold"
|
||||
>
|
||||
<div id="nav" data-section="nav">
|
||||
<NavbarStyleCentered
|
||||
navItems={[
|
||||
{ name: "Home", id: "/" },
|
||||
{ name: "About", id: "about" },
|
||||
{ name: "Products", id: "products" },
|
||||
{ name: "Features", id: "features" },
|
||||
{ name: "Reviews", id: "testimonials" },
|
||||
{ name: "Contact", id: "contact" }
|
||||
]}
|
||||
button={{ text: "Follow Chef", href: "#" }}
|
||||
brandName="Chef Profile"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="chef-info" data-section="chef-info">
|
||||
<HeroLogoBillboard
|
||||
logoText="Chef Marcus"
|
||||
description="Award-winning culinary expert with 15+ years of experience in modern gastronomy. Specializing in innovative techniques and sustainable ingredient sourcing."
|
||||
buttons={[
|
||||
{ text: "View Video History", href: "#videos" },
|
||||
{ text: "Subscribe", href: "#" }
|
||||
]}
|
||||
background={{ variant: "sparkles-gradient" }}
|
||||
imageSrc="http://img.b2bpic.net/free-photo/portrait-successful-man-chef-wearing-hat-standing-against-blurred-kitchen_23-2148381812.jpg"
|
||||
imageAlt="Chef Marcus Professional Portrait"
|
||||
mediaAnimation="slide-up"
|
||||
frameStyle="card"
|
||||
buttonAnimation="blur-reveal"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="stats" data-section="stats">
|
||||
<MetricCardThree
|
||||
metrics={[
|
||||
{ id: "1", icon: Users, title: "Followers", value: "245.8K" },
|
||||
{ id: "2", icon: Heart, title: "Engagement", value: "98.5%" },
|
||||
{ id: "3", icon: Star, title: "Chef Rating", value: "4.9/5" },
|
||||
{ id: "4", icon: Mail, title: "Videos", value: "156" }
|
||||
]}
|
||||
title="Chef Performance"
|
||||
description="Outstanding metrics showcasing chef excellence and community engagement."
|
||||
textboxLayout="default"
|
||||
animationType="slide-up"
|
||||
useInvertedBackground={false}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="videos" data-section="videos">
|
||||
<TeamCardOne
|
||||
members={[
|
||||
{
|
||||
id: "1", name: "Mastering Sauces", role: "Cooking Technique", imageSrc: "http://img.b2bpic.net/free-photo/professional-chef-preparing-delicious-food-kitchen-restaurant_23-2150887345.jpg", imageAlt: "Mastering Sauces Tutorial"
|
||||
},
|
||||
{
|
||||
id: "2", name: "Plating Perfection", role: "Presentation Guide", imageSrc: "http://img.b2bpic.net/free-photo/chef-preparing-gourmet-dish-plating_23-2150887201.jpg", imageAlt: "Plating Perfection Workshop"
|
||||
},
|
||||
{
|
||||
id: "3", name: "Farm to Table", role: "Sustainability Focus", imageSrc: "http://img.b2bpic.net/free-photo/fresh-vegetables-farm-market_23-2150887102.jpg", imageAlt: "Farm to Table Preparation"
|
||||
},
|
||||
{
|
||||
id: "4", name: "Molecular Gastronomy", role: "Advanced Techniques", imageSrc: "http://img.b2bpic.net/free-photo/innovative-cooking-laboratory-style_23-2150887456.jpg", imageAlt: "Molecular Gastronomy Demo"
|
||||
}
|
||||
]}
|
||||
title="Recent Video History"
|
||||
description="Explore Chef Marcus's latest cooking tutorials and technique demonstrations."
|
||||
gridVariant="two-columns-alternating-heights"
|
||||
animationType="slide-up"
|
||||
textboxLayout="default"
|
||||
useInvertedBackground={false}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="ratings" data-section="ratings">
|
||||
<TestimonialCardThirteen
|
||||
testimonials={[
|
||||
{
|
||||
id: "1", name: "Emma Wilson", handle: "@emmachef", testimonial: "Chef Marcus's tutorials completely transformed my cooking skills. His attention to detail and passion for food is truly inspiring!", rating: 5,
|
||||
icon: Star
|
||||
},
|
||||
{
|
||||
id: "2", name: "James Chen", handle: "@jameskit", testimonial: "The molecular gastronomy series is mind-blowing. Professional, educational, and entertaining. Highly recommend!", rating: 5,
|
||||
icon: Star
|
||||
},
|
||||
{
|
||||
id: "3", name: "Sarah Johnson", handle: "@foodlover_sarah", testimonial: "I've learned more from Chef Marcus in two weeks than I did in a year of other cooking channels. Pure expertise!", rating: 5,
|
||||
icon: Star
|
||||
},
|
||||
{
|
||||
id: "4", name: "Michael Rodriguez", handle: "@mikecooking", testimonial: "The farm-to-table episode changed how I think about ingredient sourcing. Best culinary content creator out there.", rating: 5,
|
||||
icon: Star
|
||||
}
|
||||
]}
|
||||
showRating={true}
|
||||
title="Community Ratings & Reviews"
|
||||
description="See what followers love most about Chef Marcus's content and expertise."
|
||||
textboxLayout="default"
|
||||
animationType="slide-up"
|
||||
useInvertedBackground={false}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="footer" data-section="footer">
|
||||
<FooterBaseCard
|
||||
logoText="Chef Marcus"
|
||||
columns={[
|
||||
{
|
||||
title: "Content", items: [
|
||||
{ label: "Cooking Tutorials", href: "#videos" },
|
||||
{ label: "Recipe Collections", href: "#" },
|
||||
{ label: "Technique Guides", href: "#" },
|
||||
{ label: "Live Streams", href: "#" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "About", items: [
|
||||
{ label: "Bio", href: "#chef-info" },
|
||||
{ label: "Achievements", href: "#" },
|
||||
{ label: "Experience", href: "#" },
|
||||
{ label: "Philosophy", href: "#" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Connect", items: [
|
||||
{ label: "YouTube", href: "https://youtube.com" },
|
||||
{ label: "Instagram", href: "https://instagram.com" },
|
||||
{ label: "TikTok", href: "https://tiktok.com" },
|
||||
{ label: "Twitter", href: "https://twitter.com" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Resources", items: [
|
||||
{ label: "Merchandise", href: "#" },
|
||||
{ label: "Cookbooks", href: "#" },
|
||||
{ label: "Collaborations", href: "#" },
|
||||
{ label: "Contact", href: "#" }
|
||||
]
|
||||
}
|
||||
]}
|
||||
copyrightText="© 2025 Chef Marcus. All rights reserved. Culinary Excellence Worldwide."
|
||||
/>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
263
src/app/dashboard/page.tsx
Normal file
263
src/app/dashboard/page.tsx
Normal file
@@ -0,0 +1,263 @@
|
||||
"use client";
|
||||
|
||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||
import NavbarStyleCentered from '@/components/navbar/NavbarStyleCentered/NavbarStyleCentered';
|
||||
import HeroLogoBillboard from '@/components/sections/hero/HeroLogoBillboard';
|
||||
import FeatureBento from '@/components/sections/feature/FeatureBento';
|
||||
import FooterBaseCard from '@/components/sections/footer/FooterBaseCard';
|
||||
import { Video, Upload, Edit3, Trash2, Eye, Settings } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
interface DashboardVideo {
|
||||
id: string;
|
||||
title: string;
|
||||
thumbnail: string;
|
||||
duration: string;
|
||||
uploadDate: string;
|
||||
views: string;
|
||||
status: 'published' | 'draft' | 'processing';
|
||||
}
|
||||
|
||||
export default function Dashboard() {
|
||||
const [videos, setVideos] = useState<DashboardVideo[]>([
|
||||
{
|
||||
id: '1',
|
||||
title: 'Michelin-Star Pasta Carbonara Masterclass',
|
||||
thumbnail: 'http://img.b2bpic.net/free-photo/woman-applying-moisturizer-her-beauty-routine_23-2150166464.jpg',
|
||||
duration: '12:45',
|
||||
uploadDate: 'Jan 15, 2025',
|
||||
views: '2.4K',
|
||||
status: 'published'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: 'Advanced Plating Techniques for Fine Dining',
|
||||
thumbnail: 'http://img.b2bpic.net/free-photo/model-career-kit-still-life-flat-lay_23-2150218023.jpg',
|
||||
duration: '18:30',
|
||||
uploadDate: 'Jan 12, 2025',
|
||||
views: '1.8K',
|
||||
status: 'published'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: 'Sustainable Sourcing for Restaurant Kitchens',
|
||||
thumbnail: 'http://img.b2bpic.net/free-photo/people-working-elegant-cozy-office-space_23-2149548692.jpg',
|
||||
duration: '15:20',
|
||||
uploadDate: 'Jan 10, 2025',
|
||||
views: '892',
|
||||
status: 'draft'
|
||||
}
|
||||
]);
|
||||
|
||||
const handleEdit = (id: string) => {
|
||||
console.log('Edit video:', id);
|
||||
};
|
||||
|
||||
const handleDelete = (id: string) => {
|
||||
setVideos(videos.filter(v => v.id !== id));
|
||||
};
|
||||
|
||||
const handleUpload = () => {
|
||||
console.log('Upload new video');
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
defaultButtonVariant="hover-bubble"
|
||||
defaultTextAnimation="reveal-blur"
|
||||
borderRadius="rounded"
|
||||
contentWidth="small"
|
||||
sizing="largeSmallSizeLargeTitles"
|
||||
background="circleGradient"
|
||||
cardStyle="gradient-bordered"
|
||||
primaryButtonStyle="double-inset"
|
||||
secondaryButtonStyle="solid"
|
||||
headingFontWeight="extrabold"
|
||||
>
|
||||
<div id="nav" data-section="nav">
|
||||
<NavbarStyleCentered
|
||||
navItems={[
|
||||
{ name: "Home", id: "/" },
|
||||
{ name: "My Videos", id: "/dashboard" },
|
||||
{ name: "Analytics", id: "#" },
|
||||
{ name: "Settings", id: "#" },
|
||||
{ name: "Support", id: "#" }
|
||||
]}
|
||||
button={{ text: "Upload Video", href: "#" }}
|
||||
brandName="Chef Studio"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="hero" data-section="hero">
|
||||
<HeroLogoBillboard
|
||||
logoText="Chef Studio"
|
||||
description="Manage your culinary videos with professional tools. Upload, edit, and share your cooking expertise with the world."
|
||||
buttons={[
|
||||
{ text: "Upload New Video", onClick: handleUpload },
|
||||
{ text: "View Analytics", href: "#" }
|
||||
]}
|
||||
background={{ variant: "sparkles-gradient" }}
|
||||
imageSrc="http://img.b2bpic.net/free-photo/model-career-kit-still-life-flat-lay_23-2150218023.jpg"
|
||||
imageAlt="Chef Studio Dashboard"
|
||||
mediaAnimation="slide-up"
|
||||
frameStyle="card"
|
||||
buttonAnimation="blur-reveal"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="features" data-section="features">
|
||||
<FeatureBento
|
||||
title="Powerful Video Management Tools"
|
||||
description="Everything you need to create, manage, and grow your culinary content library."
|
||||
features={[
|
||||
{
|
||||
title: "Upload & Organize", description: "Upload videos in multiple formats with automatic processing and organization", bentoComponent: "icon-info-cards", items: [
|
||||
{ icon: Upload, label: "Formats", value: "4K Ready" },
|
||||
{ icon: Video, label: "Duration", value: "Unlimited" },
|
||||
{ icon: Settings, label: "Quality", value: "Auto-Optimize" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Edit & Customize", description: "Built-in editing tools to trim, add captions, and personalize your videos", bentoComponent: "icon-info-cards", items: [
|
||||
{ icon: Edit3, label: "Trim", value: "Frame-Precise" },
|
||||
{ icon: Video, label: "Effects", value: "50+ Built-in" },
|
||||
{ icon: Eye, label: "Preview", value: "Real-Time" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Track Analytics", description: "Monitor views, engagement, and audience growth with detailed metrics", bentoComponent: "animated-bar-chart"
|
||||
},
|
||||
{
|
||||
title: "Publish & Share", description: "Share your videos across multiple platforms with one click", bentoComponent: "icon-info-cards", items: [
|
||||
{ icon: Video, label: "Platforms", value: "10+" },
|
||||
{ icon: Settings, label: "Scheduling", value: "Auto-Post" },
|
||||
{ icon: Eye, label: "Analytics", value: "Real-Time" }
|
||||
]
|
||||
}
|
||||
]}
|
||||
animationType="slide-up"
|
||||
textboxLayout="default"
|
||||
useInvertedBackground={false}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="videos" data-section="videos" className="py-20">
|
||||
<div className="container mx-auto px-4 max-w-6xl">
|
||||
<div className="mb-12">
|
||||
<h2 className="text-4xl font-bold mb-4">Your Video Library</h2>
|
||||
<p className="text-lg text-gray-600">Manage and monitor your uploaded culinary content</p>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-6">
|
||||
{videos.map((video) => (
|
||||
<div
|
||||
key={video.id}
|
||||
className="bg-white rounded-lg shadow-lg overflow-hidden hover:shadow-xl transition-shadow"
|
||||
>
|
||||
<div className="flex flex-col md:flex-row">
|
||||
{/* Thumbnail */}
|
||||
<div className="md:w-48 flex-shrink-0 relative group">
|
||||
<img
|
||||
src={video.thumbnail}
|
||||
alt={video.title}
|
||||
className="w-full h-48 object-cover"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-50 transition-all flex items-center justify-center">
|
||||
<Video className="w-12 h-12 text-white opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
</div>
|
||||
<div className="absolute bottom-2 right-2 bg-black bg-opacity-75 text-white text-sm px-2 py-1 rounded">
|
||||
{video.duration}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex-1 p-6 flex flex-col justify-between">
|
||||
<div>
|
||||
<div className="flex items-start justify-between mb-2">
|
||||
<h3 className="text-xl font-bold">{video.title}</h3>
|
||||
<span
|
||||
className={`px-3 py-1 rounded-full text-xs font-semibold ${
|
||||
video.status === 'published'
|
||||
? 'bg-green-100 text-green-800'
|
||||
: video.status === 'draft'
|
||||
? 'bg-yellow-100 text-yellow-800'
|
||||
: 'bg-blue-100 text-blue-800'
|
||||
}`}
|
||||
>
|
||||
{video.status.charAt(0).toUpperCase() + video.status.slice(1)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex gap-6 text-sm text-gray-600">
|
||||
<span>📅 {video.uploadDate}</span>
|
||||
<span>👁️ {video.views} views</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="flex gap-2 mt-4">
|
||||
<button
|
||||
onClick={() => handleEdit(video.id)}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors"
|
||||
>
|
||||
<Edit3 size={16} />
|
||||
Edit
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleDelete(video.id)}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600 transition-colors"
|
||||
>
|
||||
<Trash2 size={16} />
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer" data-section="footer">
|
||||
<FooterBaseCard
|
||||
logoText="Chef Studio"
|
||||
columns={[
|
||||
{
|
||||
title: "Dashboard", items: [
|
||||
{ label: "My Videos", href: "/dashboard" },
|
||||
{ label: "Analytics", href: "#" },
|
||||
{ label: "Settings", href: "#" },
|
||||
{ label: "Upload", href: "#" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Resources", items: [
|
||||
{ label: "Help Center", href: "#" },
|
||||
{ label: "Guidelines", href: "#" },
|
||||
{ label: "Best Practices", href: "#" },
|
||||
{ label: "FAQ", href: "#" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Account", items: [
|
||||
{ label: "Profile", href: "#" },
|
||||
{ label: "Preferences", href: "#" },
|
||||
{ label: "Billing", href: "#" },
|
||||
{ label: "Logout", href: "#" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Connect", items: [
|
||||
{ label: "Twitter", href: "https://twitter.com" },
|
||||
{ label: "Instagram", href: "https://instagram.com" },
|
||||
{ label: "YouTube", href: "https://youtube.com" },
|
||||
{ label: "TikTok", href: "https://tiktok.com" }
|
||||
]
|
||||
}
|
||||
]}
|
||||
copyrightText="© 2025 Chef Studio. All rights reserved."
|
||||
/>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
@@ -1,59 +1,39 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Halant } from "next/font/google";
|
||||
import { Inter } from "next/font/google";
|
||||
import { Raleway } from "next/font/google";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import { ServiceWrapper } from "@/components/ServiceWrapper";
|
||||
import Tag from "@/tag/Tag";
|
||||
|
||||
const halant = Halant({
|
||||
variable: "--font-halant", subsets: ["latin"],
|
||||
weight: ["300", "400", "500", "600", "700"],
|
||||
const geist = Geist({
|
||||
variable: "--font-geist-sans", subsets: ["latin"],
|
||||
});
|
||||
|
||||
const inter = Inter({
|
||||
variable: "--font-inter", subsets: ["latin"],
|
||||
});
|
||||
|
||||
const raleway = Raleway({
|
||||
variable: "--font-raleway", subsets: ["latin"],
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono", subsets: ["latin"],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Lumière Skin | Premium Skincare & Beauty Products", description: "Discover luxurious, science-backed skincare products. Natural ingredients meet dermatology expertise for radiant, healthy skin. Shop our signature collection today.", keywords: "skincare, beauty products, organic skincare, luxury cosmetics, dermatologist tested, natural ingredients, skincare routine", metadataBase: new URL("https://lumiereskin.com"),
|
||||
alternates: {
|
||||
canonical: "https://lumiereskin.com"
|
||||
},
|
||||
openGraph: {
|
||||
title: "Lumière Skin | Premium Skincare Collection", description: "Transform your skin with premium, science-backed skincare. Crafted from organic ingredients for visible results.", url: "https://lumiereskin.com", siteName: "Lumière Skin", type: "website", images: [
|
||||
{
|
||||
url: "http://img.b2bpic.net/free-photo/model-career-kit-still-life-flat-lay_23-2150218023.jpg", alt: "Premium skincare collection"
|
||||
}
|
||||
]
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image", title: "Lumière Skin | Premium Skincare", description: "Discover radiant skin with luxury, dermatologist-tested skincare products.", images: ["http://img.b2bpic.net/free-photo/model-career-kit-still-life-flat-lay_23-2150218023.jpg"]
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true
|
||||
}
|
||||
};
|
||||
title: "Video Management Dashboard | Chef Studio", description: "Professional video management dashboard for chefs to upload, edit, and manage their culinary content."};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
}) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<ServiceWrapper>
|
||||
<body
|
||||
className={`${halant.variable} ${inter.variable} ${raleway.variable} antialiased`}
|
||||
>
|
||||
<Tag />
|
||||
{children}
|
||||
|
||||
<body className={`${geist.variable} ${geistMono.variable} antialiased`}>
|
||||
{children}
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||
document.documentElement.classList.add('dark')
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
}
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
@@ -1421,7 +1401,6 @@ export default function RootLayout({
|
||||
}}
|
||||
/>
|
||||
</body>
|
||||
</ServiceWrapper>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"use client"
|
||||
"use client";
|
||||
|
||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||
import NavbarStyleCentered from '@/components/navbar/NavbarStyleCentered/NavbarStyleCentered';
|
||||
@@ -33,7 +33,8 @@ export default function LandingPage() {
|
||||
{ name: "Products", id: "products" },
|
||||
{ name: "Features", id: "features" },
|
||||
{ name: "Reviews", id: "testimonials" },
|
||||
{ name: "Contact", id: "contact" }
|
||||
{ name: "Contact", id: "contact" },
|
||||
{ name: "Dashboard", id: "/dashboard" }
|
||||
]}
|
||||
button={{ text: "Shop Now", href: "products" }}
|
||||
brandName="Lumière Skin"
|
||||
|
||||
318
src/app/video-upload/page.tsx
Normal file
318
src/app/video-upload/page.tsx
Normal file
@@ -0,0 +1,318 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||
import NavbarStyleCentered from '@/components/navbar/NavbarStyleCentered/NavbarStyleCentered';
|
||||
import FooterBaseCard from '@/components/sections/footer/FooterBaseCard';
|
||||
import { Upload, AlertCircle, CheckCircle, Video } from "lucide-react";
|
||||
|
||||
export default function VideoUploadPage() {
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
const [isDragActive, setIsDragActive] = useState(false);
|
||||
const [uploadStatus, setUploadStatus] = useState<"idle" | "uploading" | "success" | "error">("idle");
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
const [videoTitle, setVideoTitle] = useState("");
|
||||
const [videoDescription, setVideoDescription] = useState("");
|
||||
|
||||
const MAX_FILE_SIZE = 500 * 1024 * 1024; // 500MB
|
||||
const ALLOWED_FORMATS = ["video/mp4", "video/mpeg", "video/quicktime", "video/x-msvideo"];
|
||||
|
||||
const handleDrag = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (e.type === "dragenter" || e.type === "dragover") {
|
||||
setIsDragActive(true);
|
||||
} else if (e.type === "dragleave") {
|
||||
setIsDragActive(false);
|
||||
}
|
||||
};
|
||||
|
||||
const validateFile = (selectedFile: File): boolean => {
|
||||
if (selectedFile.size > MAX_FILE_SIZE) {
|
||||
setErrorMessage("File size exceeds 500MB limit");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ALLOWED_FORMATS.includes(selectedFile.type)) {
|
||||
setErrorMessage("Invalid file format. Please upload MP4, MPEG, MOV, or AVI");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleDrop = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragActive(false);
|
||||
|
||||
const droppedFiles = e.dataTransfer.files;
|
||||
if (droppedFiles && droppedFiles.length > 0) {
|
||||
const selectedFile = droppedFiles[0];
|
||||
if (validateFile(selectedFile)) {
|
||||
setFile(selectedFile);
|
||||
setErrorMessage("");
|
||||
setUploadStatus("idle");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.files && e.target.files.length > 0) {
|
||||
const selectedFile = e.target.files[0];
|
||||
if (validateFile(selectedFile)) {
|
||||
setFile(selectedFile);
|
||||
setErrorMessage("");
|
||||
setUploadStatus("idle");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpload = async () => {
|
||||
if (!file || !videoTitle.trim()) {
|
||||
setErrorMessage("Please select a video and enter a title");
|
||||
return;
|
||||
}
|
||||
|
||||
setUploadStatus("uploading");
|
||||
setErrorMessage("");
|
||||
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
formData.append("title", videoTitle);
|
||||
formData.append("description", videoDescription);
|
||||
|
||||
const response = await fetch("/api/upload-video", {
|
||||
method: "POST", body: formData,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.message || "Upload failed");
|
||||
}
|
||||
|
||||
setUploadStatus("success");
|
||||
setFile(null);
|
||||
setVideoTitle("");
|
||||
setVideoDescription("");
|
||||
|
||||
setTimeout(() => {
|
||||
setUploadStatus("idle");
|
||||
}, 3000);
|
||||
} catch (error) {
|
||||
setUploadStatus("error");
|
||||
setErrorMessage(error instanceof Error ? error.message : "Upload failed");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
defaultButtonVariant="hover-bubble"
|
||||
defaultTextAnimation="reveal-blur"
|
||||
borderRadius="rounded"
|
||||
contentWidth="small"
|
||||
sizing="largeSmallSizeLargeTitles"
|
||||
background="circleGradient"
|
||||
cardStyle="gradient-bordered"
|
||||
primaryButtonStyle="double-inset"
|
||||
secondaryButtonStyle="solid"
|
||||
headingFontWeight="extrabold"
|
||||
>
|
||||
<div id="nav" data-section="nav">
|
||||
<NavbarStyleCentered
|
||||
navItems={[
|
||||
{ name: "Home", id: "/" },
|
||||
{ name: "About", id: "about" },
|
||||
{ name: "Products", id: "products" },
|
||||
{ name: "Features", id: "features" },
|
||||
{ name: "Reviews", id: "testimonials" },
|
||||
{ name: "Contact", id: "contact" }
|
||||
]}
|
||||
button={{ text: "Shop Now", href: "/" }}
|
||||
brandName="Lumière Skin"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="min-h-screen bg-gradient-to-b from-background to-background/50 py-16 px-4">
|
||||
<div className="max-w-2xl mx-auto">
|
||||
{/* Header */}
|
||||
<div className="text-center mb-12">
|
||||
<div className="flex items-center justify-center mb-4">
|
||||
<Video className="w-12 h-12 text-primary-cta" />
|
||||
</div>
|
||||
<h1 className="text-4xl md:text-5xl font-bold text-foreground mb-4">
|
||||
Submit Your Cooking Video
|
||||
</h1>
|
||||
<p className="text-lg text-foreground/70">
|
||||
Share your culinary creations and showcase your chef skills with our community
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Upload Area */}
|
||||
<div className="bg-card rounded-lg p-8 mb-8 border border-accent/20">
|
||||
<div
|
||||
onDragEnter={handleDrag}
|
||||
onDragLeave={handleDrag}
|
||||
onDragOver={handleDrag}
|
||||
onDrop={handleDrop}
|
||||
className={`border-2 border-dashed rounded-lg p-12 text-center cursor-pointer transition-colors ${
|
||||
isDragActive
|
||||
? "border-primary-cta bg-primary-cta/5"
|
||||
: "border-accent/30 hover:border-accent/50"
|
||||
}`}
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
accept="video/*"
|
||||
onChange={handleFileSelect}
|
||||
className="hidden"
|
||||
id="video-input"
|
||||
/>
|
||||
<label htmlFor="video-input" className="cursor-pointer">
|
||||
<Upload className="w-12 h-12 text-accent mx-auto mb-4" />
|
||||
<p className="text-xl font-semibold text-foreground mb-2">
|
||||
Drag and drop your video here
|
||||
</p>
|
||||
<p className="text-foreground/60 mb-4">
|
||||
or click to browse your files
|
||||
</p>
|
||||
<p className="text-sm text-foreground/50">
|
||||
Supported formats: MP4, MPEG, MOV, AVI (Max 500MB)
|
||||
</p>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Selected File Info */}
|
||||
{file && (
|
||||
<div className="mt-6 p-4 bg-background rounded-lg border border-accent/20">
|
||||
<p className="text-foreground font-medium">✓ File selected: {file.name}</p>
|
||||
<p className="text-foreground/60 text-sm mt-1">
|
||||
Size: {(file.size / 1024 / 1024).toFixed(2)} MB
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Form Fields */}
|
||||
<div className="bg-card rounded-lg p-8 mb-8 border border-accent/20">
|
||||
<div className="mb-6">
|
||||
<label className="block text-foreground font-semibold mb-2">
|
||||
Video Title *
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={videoTitle}
|
||||
onChange={(e) => setVideoTitle(e.target.value)}
|
||||
placeholder="e.g., Classic French Coq au Vin"
|
||||
className="w-full px-4 py-3 bg-background border border-accent/20 rounded-lg text-foreground placeholder-foreground/40 focus:outline-none focus:border-primary-cta focus:ring-2 focus:ring-primary-cta/20"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-6">
|
||||
<label className="block text-foreground font-semibold mb-2">
|
||||
Video Description
|
||||
</label>
|
||||
<textarea
|
||||
value={videoDescription}
|
||||
onChange={(e) => setVideoDescription(e.target.value)}
|
||||
placeholder="Describe your recipe, ingredients, and cooking process..."
|
||||
rows={5}
|
||||
className="w-full px-4 py-3 bg-background border border-accent/20 rounded-lg text-foreground placeholder-foreground/40 focus:outline-none focus:border-primary-cta focus:ring-2 focus:ring-primary-cta/20"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Status Messages */}
|
||||
{errorMessage && (
|
||||
<div className="flex items-center gap-3 p-4 bg-red-500/10 border border-red-500/30 rounded-lg mb-6">
|
||||
<AlertCircle className="w-5 h-5 text-red-500 flex-shrink-0" />
|
||||
<p className="text-red-600 font-medium">{errorMessage}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{uploadStatus === "success" && (
|
||||
<div className="flex items-center gap-3 p-4 bg-green-500/10 border border-green-500/30 rounded-lg mb-6">
|
||||
<CheckCircle className="w-5 h-5 text-green-500 flex-shrink-0" />
|
||||
<p className="text-green-600 font-medium">Video uploaded successfully!</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Upload Button */}
|
||||
<button
|
||||
onClick={handleUpload}
|
||||
disabled={!file || uploadStatus === "uploading"}
|
||||
className={`w-full py-4 px-6 rounded-lg font-semibold text-lg transition-all ${
|
||||
uploadStatus === "uploading"
|
||||
? "bg-primary-cta/50 text-white cursor-not-allowed"
|
||||
: !file
|
||||
? "bg-foreground/10 text-foreground/50 cursor-not-allowed"
|
||||
: "bg-primary-cta text-white hover:bg-primary-cta/90 active:scale-95"
|
||||
}`}
|
||||
>
|
||||
{uploadStatus === "uploading"
|
||||
? "Uploading..."
|
||||
: uploadStatus === "success"
|
||||
? "Upload Complete!"
|
||||
: "Upload Video"}
|
||||
</button>
|
||||
|
||||
{/* Guidelines */}
|
||||
<div className="mt-12 p-6 bg-background rounded-lg border border-accent/20">
|
||||
<h3 className="text-lg font-semibold text-foreground mb-4">Upload Guidelines</h3>
|
||||
<ul className="space-y-2 text-foreground/70">
|
||||
<li>• Videos must be between 30 seconds and 10 minutes long</li>
|
||||
<li>• Use high-quality video (1080p or higher recommended)</li>
|
||||
<li>• Ensure good lighting and clear audio</li>
|
||||
<li>• Title should be descriptive and engaging</li>
|
||||
<li>• Include ingredients and cooking instructions in the description</li>
|
||||
<li>• Respect copyright and intellectual property rights</li>
|
||||
<li>• Videos are subject to moderation before publishing</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer" data-section="footer">
|
||||
<FooterBaseCard
|
||||
logoText="Lumière Skin"
|
||||
columns={[
|
||||
{
|
||||
title: "Shop", items: [
|
||||
{ label: "All Products", href: "#products" },
|
||||
{ label: "Skincare Routine", href: "#products" },
|
||||
{ label: "Collections", href: "#products" },
|
||||
{ label: "Gift Sets", href: "#products" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Company", items: [
|
||||
{ label: "About Us", href: "#about" },
|
||||
{ label: "Our Story", href: "#about" },
|
||||
{ label: "Sustainability", href: "#" },
|
||||
{ label: "Careers", href: "#" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Support", items: [
|
||||
{ label: "Contact Us", href: "#contact" },
|
||||
{ label: "FAQ", href: "#faq" },
|
||||
{ label: "Shipping Info", href: "#" },
|
||||
{ label: "Returns", href: "#" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Connect", items: [
|
||||
{ label: "Instagram", href: "https://instagram.com" },
|
||||
{ label: "Facebook", href: "https://facebook.com" },
|
||||
{ label: "Pinterest", href: "https://pinterest.com" },
|
||||
{ label: "TikTok", href: "https://tiktok.com" }
|
||||
]
|
||||
}
|
||||
]}
|
||||
copyrightText="© 2025 Lumière Skin. All rights reserved."
|
||||
/>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
280
src/app/videos/page.tsx
Normal file
280
src/app/videos/page.tsx
Normal file
@@ -0,0 +1,280 @@
|
||||
"use client"
|
||||
|
||||
import { useState, useMemo } from "react";
|
||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||
import NavbarStyleCentered from '@/components/navbar/NavbarStyleCentered/NavbarStyleCentered';
|
||||
import HeroLogoBillboard from '@/components/sections/hero/HeroLogoBillboard';
|
||||
import FooterBaseCard from '@/components/sections/footer/FooterBaseCard';
|
||||
import { Play, X } from "lucide-react";
|
||||
|
||||
interface Video {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
thumbnail: string;
|
||||
videoUrl: string;
|
||||
cuisine: string;
|
||||
chef: string;
|
||||
duration: string;
|
||||
}
|
||||
|
||||
const videos: Video[] = [
|
||||
{
|
||||
id: "1", title: "Luxurious Night Skincare Routine", description: "Learn the perfect evening skincare regimen for deep hydration and overnight repair.", thumbnail: "http://img.b2bpic.net/free-photo/woman-applying-moisturizer-her-beauty-routine_23-2150166464.jpg", videoUrl: "https://commondatastorage.googleapis.com/gtv-videos-library/sample/ElephantsDream.mp4", cuisine: "Skincare Tutorial", chef: "Dr. Sarah Chen", duration: "12:45"
|
||||
},
|
||||
{
|
||||
id: "2", title: "Anti-Aging Serum Application Guide", description: "Master the technique for maximum anti-aging benefits with our premium serum.", thumbnail: "http://img.b2bpic.net/free-photo/make-up-concept-with-pink-nail-polish_23-2149030370.jpg", videoUrl: "https://commondatastorage.googleapis.com/gtv-videos-library/sample/BigBuckBunny.mp4", cuisine: "Product Guide", chef: "Elena Rodriguez", duration: "8:30"
|
||||
},
|
||||
{
|
||||
id: "3", title: "Hydration Secrets for Dry Skin", description: "Discover professional techniques to combat dryness and achieve radiant skin.", thumbnail: "http://img.b2bpic.net/free-photo/flat-lay-hands-holding-body-care-product-wooden-background_23-2148241876.jpg", videoUrl: "https://commondatastorage.googleapis.com/gtv-videos-library/sample/ForBiggerBlazes.mp4", cuisine: "Skincare Tutorial", chef: "Dr. James Wilson", duration: "15:20"
|
||||
},
|
||||
{
|
||||
id: "4", title: "Natural Ingredients Deep Dive", description: "Explore the science behind our carefully selected natural ingredients.", thumbnail: "http://img.b2bpic.net/free-photo/product-branding-packaging_23-2150965833.jpg", videoUrl: "https://commondatastorage.googleapis.com/gtv-videos-library/sample/ForBiggerJoyrides.mp4", cuisine: "Educational", chef: "Dr. Lisa Martinez", duration: "18:10"
|
||||
},
|
||||
{
|
||||
id: "5", title: "Minimalist Skincare Routine", description: "Less is more: build an effective skincare routine with just essentials.", thumbnail: "http://img.b2bpic.net/free-photo/model-career-kit-still-life-flat-lay_23-2150218023.jpg", videoUrl: "https://commondatastorage.googleapis.com/gtv-videos-library/sample/ForBiggerEscapes.mp4", cuisine: "Skincare Tutorial", chef: "Emma Thompson", duration: "10:15"
|
||||
},
|
||||
{
|
||||
id: "6", title: "Acne Treatment Protocol", description: "Professional advice on treating acne-prone skin with our product line.", thumbnail: "http://img.b2bpic.net/free-photo/close-perfection-closeup-peaceful-relaxed-redhead-happy-woman-closed-eyes-pure-delighted-smile-sh_1258-139766.jpg", videoUrl: "https://commondatastorage.googleapis.com/gtv-videos-library/sample/ElephantsDream.mp4", cuisine: "Product Guide", chef: "Dr. Michael Lee", duration: "14:05"
|
||||
},
|
||||
{
|
||||
id: "7", title: "Sensitive Skin Solutions", description: "Gentle approaches to care for sensitive and reactive skin types.", thumbnail: "http://img.b2bpic.net/free-photo/young-beautiful-woman-having-online-meeting_23-2149116347.jpg", videoUrl: "https://commondatastorage.googleapis.com/gtv-videos-library/sample/BigBuckBunny.mp4", cuisine: "Skincare Tutorial", chef: "Dr. Sophie Brown", duration: "11:40"
|
||||
},
|
||||
{
|
||||
id: "8", title: "Seasonal Skincare Adjustments", description: "How to adapt your skincare routine for different seasons and climates.", thumbnail: "http://img.b2bpic.net/free-photo/young-women-polishing-nails-bed_23-2147770248.jpg", videoUrl: "https://commondatastorage.googleapis.com/gtv-videos-library/sample/ForBiggerBlazes.mp4", cuisine: "Educational", chef: "Dr. Amanda White", duration: "16:25"
|
||||
}
|
||||
];
|
||||
|
||||
export default function VideosPage() {
|
||||
const [selectedVideo, setSelectedVideo] = useState<Video | null>(null);
|
||||
const [cuisineFilter, setCuisineFilter] = useState<string>("All");
|
||||
const [chefFilter, setChefFilter] = useState<string>("All");
|
||||
|
||||
const cuisines = ["All", ...Array.from(new Set(videos.map(v => v.cuisine)))];
|
||||
const chefs = ["All", ...Array.from(new Set(videos.map(v => v.chef)))];
|
||||
|
||||
const filteredVideos = useMemo(() => {
|
||||
return videos.filter(video => {
|
||||
const cuisineMatch = cuisineFilter === "All" || video.cuisine === cuisineFilter;
|
||||
const chefMatch = chefFilter === "All" || video.chef === chefFilter;
|
||||
return cuisineMatch && chefMatch;
|
||||
});
|
||||
}, [cuisineFilter, chefFilter]);
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
defaultButtonVariant="hover-bubble"
|
||||
defaultTextAnimation="reveal-blur"
|
||||
borderRadius="rounded"
|
||||
contentWidth="small"
|
||||
sizing="largeSmallSizeLargeTitles"
|
||||
background="circleGradient"
|
||||
cardStyle="gradient-bordered"
|
||||
primaryButtonStyle="double-inset"
|
||||
secondaryButtonStyle="solid"
|
||||
headingFontWeight="extrabold"
|
||||
>
|
||||
<div id="nav" data-section="nav">
|
||||
<NavbarStyleCentered
|
||||
navItems={[
|
||||
{ name: "About", id: "about" },
|
||||
{ name: "Products", id: "products" },
|
||||
{ name: "Features", id: "features" },
|
||||
{ name: "Reviews", id: "testimonials" },
|
||||
{ name: "Videos", id: "videos" },
|
||||
{ name: "Contact", id: "contact" }
|
||||
]}
|
||||
button={{ text: "Shop Now", href: "/" }}
|
||||
brandName="Lumière Skin"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="hero" data-section="hero">
|
||||
<HeroLogoBillboard
|
||||
logoText="Skincare Videos"
|
||||
description="Expert tutorials, product guides, and educational content to help you master your skincare routine."
|
||||
buttons={[
|
||||
{ text: "Back to Home", href: "/" },
|
||||
{ text: "Shop Collection", href: "/" }
|
||||
]}
|
||||
background={{ variant: "sparkles-gradient" }}
|
||||
imageSrc="http://img.b2bpic.net/free-photo/woman-applying-moisturizer-her-beauty-routine_23-2150166464.jpg"
|
||||
imageAlt="Video Gallery"
|
||||
mediaAnimation="slide-up"
|
||||
frameStyle="card"
|
||||
buttonAnimation="blur-reveal"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="videos" data-section="videos" className="py-20">
|
||||
<div className="w-full max-w-7xl mx-auto px-6">
|
||||
{/* Filters */}
|
||||
<div className="mb-12">
|
||||
<div className="grid md:grid-cols-2 gap-8">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold mb-4">Filter by Category</h3>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{cuisines.map(cuisine => (
|
||||
<button
|
||||
key={cuisine}
|
||||
onClick={() => setCuisineFilter(cuisine)}
|
||||
className={`px-4 py-2 rounded-lg transition-all ${
|
||||
cuisineFilter === cuisine
|
||||
? "bg-gradient-to-r from-pink-500 to-rose-500 text-white"
|
||||
: "bg-gray-200 text-gray-700 hover:bg-gray-300"
|
||||
}`}
|
||||
>
|
||||
{cuisine}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold mb-4">Filter by Expert</h3>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{chefs.map(chef => (
|
||||
<button
|
||||
key={chef}
|
||||
onClick={() => setChefFilter(chef)}
|
||||
className={`px-4 py-2 rounded-lg transition-all ${
|
||||
chefFilter === chef
|
||||
? "bg-gradient-to-r from-pink-500 to-rose-500 text-white"
|
||||
: "bg-gray-200 text-gray-700 hover:bg-gray-300"
|
||||
}`}
|
||||
>
|
||||
{chef}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Video Grid */}
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
|
||||
{filteredVideos.map(video => (
|
||||
<div
|
||||
key={video.id}
|
||||
className="group cursor-pointer rounded-xl overflow-hidden bg-white shadow-lg hover:shadow-xl transition-shadow"
|
||||
onClick={() => setSelectedVideo(video)}
|
||||
>
|
||||
<div className="relative aspect-video bg-gray-900 overflow-hidden">
|
||||
<img
|
||||
src={video.thumbnail}
|
||||
alt={video.title}
|
||||
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/40 flex items-center justify-center group-hover:bg-black/50 transition-colors">
|
||||
<Play className="w-16 h-16 text-white fill-white" />
|
||||
</div>
|
||||
<div className="absolute top-2 right-2 bg-black/70 px-3 py-1 rounded text-white text-sm">
|
||||
{video.duration}
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-4">
|
||||
<h3 className="font-semibold text-gray-900 mb-2 line-clamp-2 group-hover:text-pink-600 transition-colors">
|
||||
{video.title}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600 mb-3 line-clamp-2">{video.description}</p>
|
||||
<div className="flex flex-wrap gap-2 mb-3">
|
||||
<span className="text-xs bg-pink-100 text-pink-700 px-2 py-1 rounded">
|
||||
{video.cuisine}
|
||||
</span>
|
||||
<span className="text-xs bg-blue-100 text-blue-700 px-2 py-1 rounded">
|
||||
{video.chef}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{filteredVideos.length === 0 && (
|
||||
<div className="text-center py-12">
|
||||
<p className="text-gray-600 text-lg">No videos found with the selected filters.</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Video Player Modal */}
|
||||
{selectedVideo && (
|
||||
<div className="fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-4">
|
||||
<div className="bg-white rounded-xl overflow-hidden max-w-4xl w-full">
|
||||
<div className="flex justify-between items-center p-6 border-b">
|
||||
<h2 className="text-xl font-semibold">{selectedVideo.title}</h2>
|
||||
<button
|
||||
onClick={() => setSelectedVideo(null)}
|
||||
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
>
|
||||
<X className="w-6 h-6" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="aspect-video bg-black">
|
||||
<video
|
||||
src={selectedVideo.videoUrl}
|
||||
controls
|
||||
autoPlay
|
||||
className="w-full h-full"
|
||||
/>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<p className="text-gray-700 mb-4">{selectedVideo.description}</p>
|
||||
<div className="grid grid-cols-2 gap-4 text-sm">
|
||||
<div>
|
||||
<p className="text-gray-600 font-medium">Category</p>
|
||||
<p className="text-gray-900">{selectedVideo.cuisine}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-gray-600 font-medium">Expert</p>
|
||||
<p className="text-gray-900">{selectedVideo.chef}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div id="footer" data-section="footer">
|
||||
<FooterBaseCard
|
||||
logoText="Lumière Skin"
|
||||
columns={[
|
||||
{
|
||||
title: "Shop", items: [
|
||||
{ label: "All Products", href: "/" },
|
||||
{ label: "Skincare Routine", href: "/" },
|
||||
{ label: "Collections", href: "/" },
|
||||
{ label: "Gift Sets", href: "/" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Company", items: [
|
||||
{ label: "About Us", href: "/" },
|
||||
{ label: "Our Story", href: "/" },
|
||||
{ label: "Sustainability", href: "#" },
|
||||
{ label: "Careers", href: "#" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Support", items: [
|
||||
{ label: "Contact Us", href: "/" },
|
||||
{ label: "FAQ", href: "/" },
|
||||
{ label: "Shipping Info", href: "#" },
|
||||
{ label: "Returns", href: "#" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Connect", items: [
|
||||
{ label: "Instagram", href: "https://instagram.com" },
|
||||
{ label: "Facebook", href: "https://facebook.com" },
|
||||
{ label: "Pinterest", href: "https://pinterest.com" },
|
||||
{ label: "TikTok", href: "https://tiktok.com" }
|
||||
]
|
||||
}
|
||||
]}
|
||||
copyrightText="© 2025 Lumière Skin. All rights reserved."
|
||||
/>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user