Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 17f213efe1 | |||
| e38b325e8c | |||
| 7330565550 | |||
| 124bd70528 | |||
| 43f6f4c8c5 | |||
| 8c020e6fcf | |||
| 834170a114 | |||
| c9d2287d60 | |||
| 50a66a5434 | |||
| 4f4846c706 | |||
| e3e4bde638 | |||
| 0ef5592042 |
337
src/app/chef-profile/page.tsx
Normal file
337
src/app/chef-profile/page.tsx
Normal file
@@ -0,0 +1,337 @@
|
||||
"use client"
|
||||
|
||||
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 { useState } from "react";
|
||||
import { Upload, Edit2, Trash2, Play, Pause, MoreVertical } from "lucide-react";
|
||||
|
||||
interface Video {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
thumbnail: string;
|
||||
duration: string;
|
||||
uploadDate: string;
|
||||
views: number;
|
||||
status: "published" | "draft" | "archived";
|
||||
}
|
||||
|
||||
export default function ChefProfilePage() {
|
||||
const [videos, setVideos] = useState<Video[]>([
|
||||
{
|
||||
id: "1", title: "Signature Skincare Routine", description: "Learn our 5-step skincare routine for glowing skin", thumbnail: "http://img.b2bpic.net/free-photo/model-career-kit-still-life-flat-lay_23-2150218023.jpg", duration: "12:34", uploadDate: "Jan 15, 2025", views: 2543,
|
||||
status: "published"
|
||||
},
|
||||
{
|
||||
id: "2", title: "Ingredient Spotlight: Natural Botanicals", description: "Deep dive into our premium organic ingredients", thumbnail: "http://img.b2bpic.net/free-photo/flat-lay-hands-holding-body-care-product-wooden-background_23-2148241876.jpg", duration: "8:45", uploadDate: "Jan 12, 2025", views: 1876,
|
||||
status: "published"
|
||||
},
|
||||
{
|
||||
id: "3", title: "Product Application Techniques", description: "Master the art of applying skincare products", thumbnail: "http://img.b2bpic.net/free-photo/product-branding-packaging_23-2150965833.jpg", duration: "15:22", uploadDate: "Jan 10, 2025", views: 3421,
|
||||
status: "published"
|
||||
},
|
||||
{
|
||||
id: "4", title: "Winter Skincare Tips", description: "Keep your skin glowing during cold months", thumbnail: "http://img.b2bpic.net/free-photo/woman-applying-moisturizer-her-beauty-routine_23-2150166464.jpg", duration: "10:15", uploadDate: "Jan 8, 2025", views: 0,
|
||||
status: "draft"
|
||||
}
|
||||
]);
|
||||
|
||||
const [editingId, setEditingId] = useState<string | null>(null);
|
||||
const [editData, setEditData] = useState({ title: "", description: "" });
|
||||
|
||||
const handleEdit = (video: Video) => {
|
||||
setEditingId(video.id);
|
||||
setEditData({ title: video.title, description: video.description });
|
||||
};
|
||||
|
||||
const handleSaveEdit = (id: string) => {
|
||||
setVideos(videos.map(v =>
|
||||
v.id === id ? { ...v, title: editData.title, description: editData.description } : v
|
||||
));
|
||||
setEditingId(null);
|
||||
};
|
||||
|
||||
const handleDelete = (id: string) => {
|
||||
setVideos(videos.filter(v => v.id !== id));
|
||||
};
|
||||
|
||||
const publishedVideos = videos.filter(v => v.status === "published");
|
||||
const draftVideos = videos.filter(v => v.status === "draft");
|
||||
const totalViews = videos.reduce((sum, v) => sum + v.views, 0);
|
||||
|
||||
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: "Contact", id: "contact" }
|
||||
]}
|
||||
button={{ text: "Shop Now", href: "/" }}
|
||||
brandName="Lumière Skin"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="hero" data-section="hero">
|
||||
<HeroLogoBillboard
|
||||
logoText="Chef Profile & Video Management"
|
||||
description="Manage and showcase your video content. Track performance, edit details, and grow your audience."
|
||||
buttons={[
|
||||
{ text: "Upload New Video", href: "#" },
|
||||
{ text: "Back to Home", href: "/" }
|
||||
]}
|
||||
background={{ variant: "sparkles-gradient" }}
|
||||
imageSrc="http://img.b2bpic.net/free-photo/woman-applying-moisturizer-her-beauty-routine_23-2150166464.jpg"
|
||||
imageAlt="Chef profile"
|
||||
mediaAnimation="slide-up"
|
||||
frameStyle="card"
|
||||
buttonAnimation="blur-reveal"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<section className="py-20 px-4">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
{/* Stats Section */}
|
||||
<div className="mb-12 grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div className="p-6 rounded-lg bg-card border border-card">
|
||||
<h3 className="text-sm font-semibold text-foreground/60 mb-2">Total Videos</h3>
|
||||
<p className="text-4xl font-bold text-foreground">{videos.length}</p>
|
||||
</div>
|
||||
<div className="p-6 rounded-lg bg-card border border-card">
|
||||
<h3 className="text-sm font-semibold text-foreground/60 mb-2">Total Views</h3>
|
||||
<p className="text-4xl font-bold text-foreground">{totalViews.toLocaleString()}</p>
|
||||
</div>
|
||||
<div className="p-6 rounded-lg bg-card border border-card">
|
||||
<h3 className="text-sm font-semibold text-foreground/60 mb-2">Published</h3>
|
||||
<p className="text-4xl font-bold text-foreground">{publishedVideos.length}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Published Videos */}
|
||||
<div className="mb-12">
|
||||
<h2 className="text-2xl font-bold text-foreground mb-6">Published Videos</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{publishedVideos.map(video => (
|
||||
<div key={video.id} className="rounded-lg overflow-hidden bg-card border border-card hover:border-primary-cta/50 transition-all">
|
||||
{/* Thumbnail */}
|
||||
<div className="relative aspect-video overflow-hidden bg-background">
|
||||
<img
|
||||
src={video.thumbnail}
|
||||
alt={video.title}
|
||||
className="w-full h-full object-cover hover:scale-105 transition-transform"
|
||||
/>
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-black/30 opacity-0 hover:opacity-100 transition-opacity">
|
||||
<Play className="w-12 h-12 text-white fill-white" />
|
||||
</div>
|
||||
<div className="absolute bottom-2 right-2 bg-black/70 px-2 py-1 rounded text-xs text-white">
|
||||
{video.duration}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="p-4">
|
||||
{editingId === video.id ? (
|
||||
<div className="space-y-3">
|
||||
<input
|
||||
type="text"
|
||||
value={editData.title}
|
||||
onChange={(e) => setEditData({...editData, title: e.target.value})}
|
||||
className="w-full bg-background border border-foreground/20 rounded px-2 py-1 text-foreground text-sm"
|
||||
/>
|
||||
<textarea
|
||||
value={editData.description}
|
||||
onChange={(e) => setEditData({...editData, description: e.target.value})}
|
||||
className="w-full bg-background border border-foreground/20 rounded px-2 py-1 text-foreground text-xs resize-none h-16"
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => handleSaveEdit(video.id)}
|
||||
className="flex-1 bg-primary-cta text-background px-3 py-1 rounded text-sm font-medium hover:opacity-90"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setEditingId(null)}
|
||||
className="flex-1 bg-secondary-cta text-foreground px-3 py-1 rounded text-sm font-medium hover:opacity-90"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<h3 className="font-semibold text-foreground mb-1 line-clamp-2">{video.title}</h3>
|
||||
<p className="text-xs text-foreground/60 mb-3 line-clamp-2">{video.description}</p>
|
||||
<div className="flex justify-between items-center mb-3 text-xs text-foreground/60">
|
||||
<span>{video.uploadDate}</span>
|
||||
<span>{video.views.toLocaleString()} views</span>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => handleEdit(video)}
|
||||
className="flex-1 flex items-center justify-center gap-1 bg-secondary-cta text-foreground px-2 py-1 rounded text-xs font-medium hover:opacity-90 transition-opacity"
|
||||
>
|
||||
<Edit2 className="w-3 h-3" />
|
||||
Edit
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleDelete(video.id)}
|
||||
className="flex-1 flex items-center justify-center gap-1 bg-accent/20 text-accent px-2 py-1 rounded text-xs font-medium hover:opacity-90 transition-opacity"
|
||||
>
|
||||
<Trash2 className="w-3 h-3" />
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Draft Videos */}
|
||||
{draftVideos.length > 0 && (
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-foreground mb-6">Draft Videos</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{draftVideos.map(video => (
|
||||
<div key={video.id} className="rounded-lg overflow-hidden bg-card border border-card border-dashed opacity-75 hover:border-primary-cta/50 transition-all">
|
||||
{/* Thumbnail */}
|
||||
<div className="relative aspect-video overflow-hidden bg-background">
|
||||
<img
|
||||
src={video.thumbnail}
|
||||
alt={video.title}
|
||||
className="w-full h-full object-cover opacity-75"
|
||||
/>
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-black/50">
|
||||
<span className="text-white font-semibold">DRAFT</span>
|
||||
</div>
|
||||
<div className="absolute bottom-2 right-2 bg-black/70 px-2 py-1 rounded text-xs text-white">
|
||||
{video.duration}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="p-4">
|
||||
{editingId === video.id ? (
|
||||
<div className="space-y-3">
|
||||
<input
|
||||
type="text"
|
||||
value={editData.title}
|
||||
onChange={(e) => setEditData({...editData, title: e.target.value})}
|
||||
className="w-full bg-background border border-foreground/20 rounded px-2 py-1 text-foreground text-sm"
|
||||
/>
|
||||
<textarea
|
||||
value={editData.description}
|
||||
onChange={(e) => setEditData({...editData, description: e.target.value})}
|
||||
className="w-full bg-background border border-foreground/20 rounded px-2 py-1 text-foreground text-xs resize-none h-16"
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => handleSaveEdit(video.id)}
|
||||
className="flex-1 bg-primary-cta text-background px-3 py-1 rounded text-sm font-medium hover:opacity-90"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setEditingId(null)}
|
||||
className="flex-1 bg-secondary-cta text-foreground px-3 py-1 rounded text-sm font-medium hover:opacity-90"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<h3 className="font-semibold text-foreground mb-1 line-clamp-2">{video.title}</h3>
|
||||
<p className="text-xs text-foreground/60 mb-3 line-clamp-2">{video.description}</p>
|
||||
<div className="flex justify-between items-center mb-3 text-xs text-foreground/60">
|
||||
<span>{video.uploadDate}</span>
|
||||
<span>Not published</span>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => handleEdit(video)}
|
||||
className="flex-1 flex items-center justify-center gap-1 bg-secondary-cta text-foreground px-2 py-1 rounded text-xs font-medium hover:opacity-90 transition-opacity"
|
||||
>
|
||||
<Edit2 className="w-3 h-3" />
|
||||
Edit
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleDelete(video.id)}
|
||||
className="flex-1 flex items-center justify-center gap-1 bg-accent/20 text-accent px-2 py-1 rounded text-xs font-medium hover:opacity-90 transition-opacity"
|
||||
>
|
||||
<Trash2 className="w-3 h-3" />
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<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>
|
||||
);
|
||||
}
|
||||
@@ -1,59 +1,35 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Halant } from "next/font/google";
|
||||
import { Inter } from "next/font/google";
|
||||
import { Raleway } 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"],
|
||||
});
|
||||
import { Inter } from "next/font/google";
|
||||
|
||||
const inter = Inter({
|
||||
variable: "--font-inter", subsets: ["latin"],
|
||||
});
|
||||
|
||||
const raleway = Raleway({
|
||||
variable: "--font-raleway", 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: "Food Homes", description: "Discover premium food delivery and catering services"};
|
||||
|
||||
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={`${inter.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 +1397,6 @@ export default function RootLayout({
|
||||
}}
|
||||
/>
|
||||
</body>
|
||||
</ServiceWrapper>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -36,21 +36,21 @@ export default function LandingPage() {
|
||||
{ name: "Contact", id: "contact" }
|
||||
]}
|
||||
button={{ text: "Shop Now", href: "products" }}
|
||||
brandName="Lumière Skin"
|
||||
brandName="Food Homes"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="hero" data-section="hero">
|
||||
<HeroLogoBillboard
|
||||
logoText="Lumière Skin"
|
||||
description="Radiant, healthy skin starts with premium, science-backed skincare. Discover our luxurious collection crafted for your most beautiful glow."
|
||||
logoText="Food Homes"
|
||||
description="Delicious, freshly prepared meals delivered to your door. Discover premium culinary creations crafted for your table."
|
||||
buttons={[
|
||||
{ text: "Explore Collection", href: "products" },
|
||||
{ text: "Explore Menu", href: "products" },
|
||||
{ text: "Learn Our Story", href: "about" }
|
||||
]}
|
||||
background={{ variant: "sparkles-gradient" }}
|
||||
imageSrc="http://img.b2bpic.net/free-photo/model-career-kit-still-life-flat-lay_23-2150218023.jpg"
|
||||
imageAlt="Premium skincare collection"
|
||||
imageAlt="Premium food delivery"
|
||||
mediaAnimation="slide-up"
|
||||
frameStyle="card"
|
||||
buttonAnimation="blur-reveal"
|
||||
@@ -62,7 +62,7 @@ export default function LandingPage() {
|
||||
heading={[
|
||||
{ type: "text", content: "Crafted with" },
|
||||
{ type: "image", src: "http://img.b2bpic.net/free-photo/people-working-elegant-cozy-office-space_23-2149548692.jpg", alt: "Brand heritage" },
|
||||
{ type: "text", content: "integrity and innovation" }
|
||||
{ type: "text", content: "passion for exceptional food" }
|
||||
]}
|
||||
buttons={[
|
||||
{ text: "Discover Our Mission", href: "#contact" }
|
||||
@@ -76,17 +76,17 @@ export default function LandingPage() {
|
||||
<ProductCardOne
|
||||
products={[
|
||||
{
|
||||
id: "1", name: "Hydra Essence Moisturizer", price: "$68", imageSrc: "http://img.b2bpic.net/free-photo/make-up-concept-with-pink-nail-polish_23-2149030370.jpg", imageAlt: "Hydra Essence Moisturizer"
|
||||
id: "1", name: "Grilled Salmon Bowl", price: "$18", imageSrc: "http://img.b2bpic.net/free-photo/make-up-concept-with-pink-nail-polish_23-2149030370.jpg?_wi=1", imageAlt: "Grilled Salmon Bowl"
|
||||
},
|
||||
{
|
||||
id: "2", name: "Luminous Glow Serum", price: "$82", imageSrc: "http://img.b2bpic.net/free-photo/flat-lay-hands-holding-body-care-product-wooden-background_23-2148241876.jpg", imageAlt: "Luminous Glow Serum"
|
||||
id: "2", name: "Vegetarian Delight", price: "$14", imageSrc: "http://img.b2bpic.net/free-photo/flat-lay-hands-holding-body-care-product-wooden-background_23-2148241876.jpg?_wi=1", imageAlt: "Vegetarian Delight"
|
||||
},
|
||||
{
|
||||
id: "3", name: "Pure Silk Cleanser", price: "$45", imageSrc: "http://img.b2bpic.net/free-photo/product-branding-packaging_23-2150965833.jpg", imageAlt: "Pure Silk Cleanser"
|
||||
id: "3", name: "Classic Pasta Primavera", price: "$12", imageSrc: "http://img.b2bpic.net/free-photo/product-branding-packaging_23-2150965833.jpg?_wi=1", imageAlt: "Classic Pasta Primavera"
|
||||
}
|
||||
]}
|
||||
title="Our Signature Collection"
|
||||
description="Each product is thoughtfully formulated to deliver visible results. From cleansing to hydration, we've got your skincare routine covered."
|
||||
title="Our Featured Menu"
|
||||
description="Each meal is carefully prepared with fresh, locally-sourced ingredients. From classic favorites to innovative creations, we have something for every palate."
|
||||
gridVariant="three-columns-all-equal-width"
|
||||
animationType="slide-up"
|
||||
textboxLayout="default"
|
||||
@@ -96,21 +96,21 @@ export default function LandingPage() {
|
||||
|
||||
<div id="features" data-section="features">
|
||||
<FeatureBento
|
||||
title="Why Choose Lumière Skin"
|
||||
description="We combine nature's finest ingredients with cutting-edge skincare science to create products that truly transform your skin."
|
||||
title="Why Choose Food Homes"
|
||||
description="We combine premium ingredients with culinary expertise to create meals that delight your senses and nourish your body."
|
||||
features={[
|
||||
{
|
||||
title: "Natural Ingredients", description: "Sourced from organic farms and botanical gardens worldwide", bentoComponent: "globe"
|
||||
title: "Fresh Ingredients", description: "Sourced daily from trusted local suppliers and farms", bentoComponent: "globe"
|
||||
},
|
||||
{
|
||||
title: "Dermatologist Tested", description: "Clinically proven formulas safe for all skin types", bentoComponent: "icon-info-cards", items: [
|
||||
{ icon: CheckCircle, label: "Hypoallergenic", value: "100%" },
|
||||
{ icon: Shield, label: "Cruelty-Free", value: "Certified" },
|
||||
{ icon: Sparkles, label: "Effective", value: "Proven" }
|
||||
title: "Expert Chefs", description: "Experienced culinary professionals preparing every meal", bentoComponent: "icon-info-cards", items: [
|
||||
{ icon: CheckCircle, label: "Award-Winning", value: "Chef Team" },
|
||||
{ icon: Shield, label: "Food Safe", value: "Certified" },
|
||||
{ icon: Sparkles, label: "Quality", value: "Guaranteed" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Visible Results", description: "See radiant, glowing skin in just weeks of consistent use", bentoComponent: "animated-bar-chart"
|
||||
title: "Quick Delivery", description: "Hot, fresh meals delivered within minutes of preparation", bentoComponent: "animated-bar-chart"
|
||||
}
|
||||
]}
|
||||
animationType="slide-up"
|
||||
@@ -121,9 +121,9 @@ export default function LandingPage() {
|
||||
|
||||
<div id="testimonials" data-section="testimonials">
|
||||
<TestimonialCardFifteen
|
||||
testimonial="Lumière Skin has completely transformed my skincare routine. My skin feels nourished, looks radiant, and I've never felt more confident. These products are worth every penny."
|
||||
testimonial="Food Homes has revolutionized how I eat. The meals are absolutely delicious, beautifully presented, and always delivered fresh. I've never felt better about the quality of my meals."
|
||||
rating={5}
|
||||
author="Sarah Mitchell, Beauty Enthusiast"
|
||||
author="James Anderson, Food Enthusiast"
|
||||
avatars={[
|
||||
{ src: "http://img.b2bpic.net/free-photo/woman-smiles-toothily-keeps-palms-pressed-together-looks-away-joyfully-wears-casual-t-shirt-isolated-beige-copy-space-away-positive-emotions-concept_273609-56517.jpg", alt: "Customer 1" },
|
||||
{ src: "http://img.b2bpic.net/free-photo/young-beautiful-woman-having-online-meeting_23-2149116347.jpg", alt: "Customer 2" },
|
||||
@@ -138,30 +138,30 @@ export default function LandingPage() {
|
||||
|
||||
<div id="faq" data-section="faq">
|
||||
<FaqSplitMedia
|
||||
title="Skincare Questions Answered"
|
||||
description="Find answers to common questions about our products, ingredients, and how to get the best results for your skin."
|
||||
title="Frequently Asked Questions"
|
||||
description="Find answers to common questions about our meals, delivery, and ordering process."
|
||||
faqs={[
|
||||
{
|
||||
id: "1", title: "How long before I see results?", content: "Most customers notice improvements in skin texture and hydration within 2-3 weeks of consistent use. Visible changes in brightness and clarity typically appear within 4-6 weeks. For best results, use our complete routine morning and night."
|
||||
id: "1", title: "How fresh are the meals?", content: "All our meals are prepared fresh daily using ingredients sourced that morning. We prepare orders to specification and deliver within 30 minutes of completion to ensure maximum freshness and optimal temperature."
|
||||
},
|
||||
{
|
||||
id: "2", title: "Are your products suitable for sensitive skin?", content: "Yes! All Lumière Skin products are hypoallergenic, dermatologist-tested, and free from harsh chemicals. We recommend starting with our gentle cleanser and moisturizer. If you have specific concerns, our beauty experts are happy to recommend personalized solutions."
|
||||
id: "2", title: "Do you accommodate dietary restrictions?", content: "Absolutely! We offer vegetarian, vegan, gluten-free, and keto options. Our chefs are trained to handle allergies and specific dietary needs. Contact us with your requirements, and we'll create the perfect meal for you."
|
||||
},
|
||||
{
|
||||
id: "3", title: "What makes your ingredients special?", content: "We source premium, organic ingredients from trusted suppliers worldwide. Our formulas combine traditional botanicals with advanced skincare science, ensuring maximum efficacy without compromise. Every ingredient is chosen for its proven benefits."
|
||||
id: "3", title: "What makes your ingredients special?", content: "We partner exclusively with local, sustainable farms and suppliers who share our commitment to quality. Every ingredient is hand-selected for freshness, flavor, and nutritional value. We never compromise on quality."
|
||||
},
|
||||
{
|
||||
id: "4", title: "Do you offer a satisfaction guarantee?", content: "Absolutely! We're confident you'll love our products. If you're not completely satisfied within 60 days, we offer a full refund, no questions asked. Your skin's health and happiness are our priority."
|
||||
id: "4", title: "What's your satisfaction guarantee?", content: "We stand behind every meal. If you're not completely satisfied, we'll replace your order or provide a full refund, no questions asked. Your satisfaction is our highest priority."
|
||||
},
|
||||
{
|
||||
id: "5", title: "Are your products cruelty-free and vegan?", content: "Yes! All Lumière Skin products are certified cruelty-free and we never test on animals. Many of our formulas are also vegan, though some contain beeswax for their nourishing properties. Check individual product pages for specific details."
|
||||
id: "5", title: "Do you offer catering services?", content: "Yes! We offer full catering services for events, corporate functions, and special occasions. Our team can customize menus to match your preferences and guest count. Contact our catering department for details."
|
||||
},
|
||||
{
|
||||
id: "6", title: "How should I store my skincare products?", content: "Store all products in a cool, dry place away from direct sunlight. Our serums and creams are best kept at room temperature. Avoid storing in bathrooms with high humidity when possible, as moisture can affect product integrity."
|
||||
id: "6", title: "How should I store leftover meals?", content: "Store meals in airtight containers in the refrigerator at 40°F or below. Most meals stay fresh for 3-4 days. For best flavor and texture, we recommend enjoying meals within 24 hours. Reheat gently to preserve quality."
|
||||
}
|
||||
]}
|
||||
imageSrc="http://img.b2bpic.net/free-photo/woman-applying-moisturizer-her-beauty-routine_23-2150166464.jpg"
|
||||
imageAlt="Skincare consultation"
|
||||
imageAlt="Gourmet meal preparation"
|
||||
mediaAnimation="slide-up"
|
||||
mediaPosition="left"
|
||||
textboxLayout="default"
|
||||
@@ -174,8 +174,8 @@ export default function LandingPage() {
|
||||
<ContactCenter
|
||||
tag="Newsletter"
|
||||
tagIcon={Mail}
|
||||
title="Join Our Skincare Community"
|
||||
description="Subscribe to receive exclusive skincare tips, product launches, and special offers. Become part of the Lumière Skin family."
|
||||
title="Join the Food Homes Family"
|
||||
description="Subscribe to receive exclusive recipes, special menu previews, and delivery promotions. Be the first to know about new culinary creations."
|
||||
background={{ variant: "sparkles-gradient" }}
|
||||
useInvertedBackground={false}
|
||||
inputPlaceholder="Enter your email"
|
||||
@@ -186,14 +186,14 @@ export default function LandingPage() {
|
||||
|
||||
<div id="footer" data-section="footer">
|
||||
<FooterBaseCard
|
||||
logoText="Lumière Skin"
|
||||
logoText="Food Homes"
|
||||
columns={[
|
||||
{
|
||||
title: "Shop", items: [
|
||||
{ label: "All Products", href: "#products" },
|
||||
{ label: "Skincare Routine", href: "#products" },
|
||||
{ label: "Collections", href: "#products" },
|
||||
{ label: "Gift Sets", href: "#products" }
|
||||
title: "Menu", items: [
|
||||
{ label: "All Items", href: "#products" },
|
||||
{ label: "Specials", href: "#products" },
|
||||
{ label: "Meal Plans", href: "#products" },
|
||||
{ label: "Catering", href: "#products" }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -208,7 +208,7 @@ export default function LandingPage() {
|
||||
title: "Support", items: [
|
||||
{ label: "Contact Us", href: "#contact" },
|
||||
{ label: "FAQ", href: "#faq" },
|
||||
{ label: "Shipping Info", href: "#" },
|
||||
{ label: "Delivery Info", href: "#" },
|
||||
{ label: "Returns", href: "#" }
|
||||
]
|
||||
},
|
||||
@@ -216,12 +216,12 @@ export default function LandingPage() {
|
||||
title: "Connect", items: [
|
||||
{ label: "Instagram", href: "https://instagram.com" },
|
||||
{ label: "Facebook", href: "https://facebook.com" },
|
||||
{ label: "Pinterest", href: "https://pinterest.com" },
|
||||
{ label: "Twitter", href: "https://twitter.com" },
|
||||
{ label: "TikTok", href: "https://tiktok.com" }
|
||||
]
|
||||
}
|
||||
]}
|
||||
copyrightText="© 2025 Lumière Skin. All rights reserved."
|
||||
copyrightText="© 2025 Food Homes. All rights reserved."
|
||||
/>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
|
||||
403
src/app/video-upload/page.tsx
Normal file
403
src/app/video-upload/page.tsx
Normal file
@@ -0,0 +1,403 @@
|
||||
"use client"
|
||||
|
||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||
import NavbarStyleCentered from '@/components/navbar/NavbarStyleCentered/NavbarStyleCentered';
|
||||
import FooterBaseCard from '@/components/sections/footer/FooterBaseCard';
|
||||
import { useState } from "react";
|
||||
import { Upload, CheckCircle, AlertCircle, X } from "lucide-react";
|
||||
|
||||
interface VideoFile {
|
||||
file: File;
|
||||
preview: string;
|
||||
title: string;
|
||||
description: string;
|
||||
chefName: string;
|
||||
duration: number | null;
|
||||
size: number;
|
||||
}
|
||||
|
||||
export default function VideoUploadPage() {
|
||||
const [videos, setVideos] = useState<VideoFile[]>([]);
|
||||
const [uploadProgress, setUploadProgress] = useState<Record<string, number>>({});
|
||||
const [uploadStatus, setUploadStatus] = useState<Record<string, 'success' | 'error' | 'uploading'>>({});
|
||||
const [isProcessing, setIsProcessing] = useState(false);
|
||||
|
||||
const MAX_FILE_SIZE = 500 * 1024 * 1024; // 500MB
|
||||
const ALLOWED_FORMATS = ['video/mp4', 'video/quicktime', 'video/x-msvideo', 'video/webm'];
|
||||
const MAX_DURATION = 30 * 60; // 30 minutes in seconds
|
||||
|
||||
const validateVideo = (file: File): { valid: boolean; error?: string } => {
|
||||
if (!ALLOWED_FORMATS.includes(file.type)) {
|
||||
return { valid: false, error: 'Invalid file format. Please upload MP4, MOV, AVI, or WebM.' };
|
||||
}
|
||||
if (file.size > MAX_FILE_SIZE) {
|
||||
return { valid: false, error: 'File size exceeds 500MB limit.' };
|
||||
}
|
||||
return { valid: true };
|
||||
};
|
||||
|
||||
const getVideoDuration = (file: File): Promise<number> => {
|
||||
return new Promise((resolve) => {
|
||||
const video = document.createElement('video');
|
||||
const blob = URL.createObjectURL(file);
|
||||
video.src = blob;
|
||||
video.onloadedmetadata = () => {
|
||||
URL.revokeObjectURL(blob);
|
||||
resolve(video.duration);
|
||||
};
|
||||
video.onerror = () => {
|
||||
URL.revokeObjectURL(blob);
|
||||
resolve(0);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const handleFileSelect = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const files = e.currentTarget.files;
|
||||
if (!files) return;
|
||||
|
||||
const newVideos: VideoFile[] = [];
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
const validation = validateVideo(file);
|
||||
|
||||
if (!validation.valid) {
|
||||
alert(`${file.name}: ${validation.error}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const duration = await getVideoDuration(file);
|
||||
|
||||
if (duration > MAX_DURATION) {
|
||||
alert(`${file.name}: Video exceeds 30-minute limit (${Math.round(duration / 60)} minutes).`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const preview = URL.createObjectURL(file);
|
||||
newVideos.push({
|
||||
file,
|
||||
preview,
|
||||
title: '',
|
||||
description: '',
|
||||
chefName: '',
|
||||
duration,
|
||||
size: file.size,
|
||||
});
|
||||
}
|
||||
|
||||
setVideos([...videos, ...newVideos]);
|
||||
};
|
||||
|
||||
const updateVideo = (index: number, field: string, value: string) => {
|
||||
const updatedVideos = [...videos];
|
||||
updatedVideos[index] = { ...updatedVideos[index], [field]: value };
|
||||
setVideos(updatedVideos);
|
||||
};
|
||||
|
||||
const removeVideo = (index: number) => {
|
||||
const updatedVideos = videos.filter((_, i) => i !== index);
|
||||
URL.revokeObjectURL(videos[index].preview);
|
||||
setVideos(updatedVideos);
|
||||
};
|
||||
|
||||
const formatFileSize = (bytes: number): string => {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
const k = 1024;
|
||||
const sizes = ['Bytes', 'KB', 'MB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
|
||||
};
|
||||
|
||||
const formatDuration = (seconds: number | null): string => {
|
||||
if (!seconds) return '0:00';
|
||||
const mins = Math.floor(seconds / 60);
|
||||
const secs = Math.floor(seconds % 60);
|
||||
return `${mins}:${secs < 10 ? '0' : ''}${secs}`;
|
||||
};
|
||||
|
||||
const handleUpload = async (index: number) => {
|
||||
const video = videos[index];
|
||||
|
||||
if (!video.title || !video.chefName) {
|
||||
alert('Please fill in title and chef name.');
|
||||
return;
|
||||
}
|
||||
|
||||
const id = `video-${index}`;
|
||||
setUploadStatus((prev) => ({ ...prev, [id]: 'uploading' }));
|
||||
setUploadProgress((prev) => ({ ...prev, [id]: 0 }));
|
||||
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('file', video.file);
|
||||
formData.append('title', video.title);
|
||||
formData.append('description', video.description);
|
||||
formData.append('chefName', video.chefName);
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.upload.addEventListener('progress', (e) => {
|
||||
if (e.lengthComputable) {
|
||||
const percentComplete = (e.loaded / e.total) * 100;
|
||||
setUploadProgress((prev) => ({ ...prev, [id]: Math.round(percentComplete) }));
|
||||
}
|
||||
});
|
||||
|
||||
xhr.addEventListener('load', () => {
|
||||
if (xhr.status === 200 || xhr.status === 201) {
|
||||
setUploadStatus((prev) => ({ ...prev, [id]: 'success' }));
|
||||
setUploadProgress((prev) => ({ ...prev, [id]: 100 }));
|
||||
} else {
|
||||
setUploadStatus((prev) => ({ ...prev, [id]: 'error' }));
|
||||
}
|
||||
});
|
||||
|
||||
xhr.addEventListener('error', () => {
|
||||
setUploadStatus((prev) => ({ ...prev, [id]: 'error' }));
|
||||
});
|
||||
|
||||
xhr.open('POST', '/api/videos/upload');
|
||||
xhr.send(formData);
|
||||
} catch (error) {
|
||||
setUploadStatus((prev) => ({ ...prev, [id]: 'error' }));
|
||||
}
|
||||
};
|
||||
|
||||
const handleUploadAll = async () => {
|
||||
setIsProcessing(true);
|
||||
for (let i = 0; i < videos.length; i++) {
|
||||
await handleUpload(i);
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
}
|
||||
setIsProcessing(false);
|
||||
};
|
||||
|
||||
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: "Upload Video", id: "/video-upload" },
|
||||
{ name: "Contact", id: "contact" }
|
||||
]}
|
||||
button={{ text: "Shop Now", href: "/" }}
|
||||
brandName="Lumière Skin"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="video-upload" data-section="video-upload" className="w-full py-20 px-4 md:px-8">
|
||||
<div className="w-full max-w-4xl mx-auto">
|
||||
<div className="mb-12 text-center">
|
||||
<h1 className="text-4xl md:text-5xl font-bold mb-4 text-foreground">Share Your Cooking Video</h1>
|
||||
<p className="text-lg text-foreground/75 mb-2">Help our community by uploading your favorite cooking recipe or technique videos</p>
|
||||
<p className="text-sm text-foreground/50">Maximum file size: 500MB | Maximum duration: 30 minutes | Formats: MP4, MOV, AVI, WebM</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-card rounded-lg border border-primary-cta/20 p-8 mb-8">
|
||||
<label className="block mb-6">
|
||||
<div className="flex items-center justify-center w-full h-48 border-2 border-dashed border-primary-cta/30 rounded-lg cursor-pointer hover:border-primary-cta/50 transition">
|
||||
<div className="flex flex-col items-center justify-center pt-5 pb-6">
|
||||
<Upload className="w-12 h-12 text-primary-cta mb-2" />
|
||||
<p className="text-sm text-foreground/75"><span className="font-semibold">Click to upload</span> or drag and drop</p>
|
||||
<p className="text-xs text-foreground/50 mt-1">MP4, MOV, AVI or WebM</p>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
type="file"
|
||||
multiple
|
||||
accept="video/mp4,video/quicktime,video/x-msvideo,video/webm"
|
||||
onChange={handleFileSelect}
|
||||
className="hidden"
|
||||
disabled={isProcessing}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{videos.length > 0 && (
|
||||
<div className="space-y-6">
|
||||
{videos.map((video, index) => {
|
||||
const id = `video-${index}`;
|
||||
const status = uploadStatus[id];
|
||||
const progress = uploadProgress[id] || 0;
|
||||
|
||||
return (
|
||||
<div key={index} className="bg-card rounded-lg border border-primary-cta/20 p-6 overflow-hidden">
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
<div className="md:col-span-1">
|
||||
<video
|
||||
src={video.preview}
|
||||
className="w-full h-32 object-cover rounded-lg bg-background"
|
||||
/>
|
||||
<p className="text-xs text-foreground/50 mt-2">Duration: {formatDuration(video.duration)}</p>
|
||||
<p className="text-xs text-foreground/50">Size: {formatFileSize(video.size)}</p>
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-3">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-foreground mb-1">Video Title</label>
|
||||
<input
|
||||
type="text"
|
||||
value={video.title}
|
||||
onChange={(e) => updateVideo(index, 'title', e.target.value)}
|
||||
placeholder="Enter video title"
|
||||
className="w-full px-3 py-2 border border-primary-cta/20 rounded-lg bg-background text-foreground placeholder-foreground/50 focus:outline-none focus:border-primary-cta"
|
||||
disabled={status === 'uploading' || status === 'success'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-foreground mb-1">Chef Name</label>
|
||||
<input
|
||||
type="text"
|
||||
value={video.chefName}
|
||||
onChange={(e) => updateVideo(index, 'chefName', e.target.value)}
|
||||
placeholder="Your name"
|
||||
className="w-full px-3 py-2 border border-primary-cta/20 rounded-lg bg-background text-foreground placeholder-foreground/50 focus:outline-none focus:border-primary-cta"
|
||||
disabled={status === 'uploading' || status === 'success'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-foreground mb-1">Description (Optional)</label>
|
||||
<textarea
|
||||
value={video.description}
|
||||
onChange={(e) => updateVideo(index, 'description', e.target.value)}
|
||||
placeholder="Add a description for your video"
|
||||
rows={3}
|
||||
className="w-full px-3 py-2 border border-primary-cta/20 rounded-lg bg-background text-foreground placeholder-foreground/50 focus:outline-none focus:border-primary-cta resize-none"
|
||||
disabled={status === 'uploading' || status === 'success'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{status === 'uploading' && (
|
||||
<div>
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<span className="text-sm text-foreground/75">Uploading...</span>
|
||||
<span className="text-sm font-semibold text-primary-cta">{progress}%</span>
|
||||
</div>
|
||||
<div className="w-full h-2 bg-background rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full bg-primary-cta transition-all duration-300"
|
||||
style={{ width: `${progress}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status === 'success' && (
|
||||
<div className="flex items-center gap-2 p-3 rounded-lg bg-green-500/10 border border-green-500/20">
|
||||
<CheckCircle className="w-5 h-5 text-green-500" />
|
||||
<span className="text-sm text-green-600">Upload successful!</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status === 'error' && (
|
||||
<div className="flex items-center gap-2 p-3 rounded-lg bg-red-500/10 border border-red-500/20">
|
||||
<AlertCircle className="w-5 h-5 text-red-500" />
|
||||
<span className="text-sm text-red-600">Upload failed. Please try again.</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex gap-3 pt-2">
|
||||
<button
|
||||
onClick={() => handleUpload(index)}
|
||||
disabled={status === 'uploading' || status === 'success' || isProcessing}
|
||||
className="flex-1 px-4 py-2 bg-primary-cta text-white rounded-lg font-medium hover:opacity-90 disabled:opacity-50 transition"
|
||||
>
|
||||
{status === 'success' ? 'Uploaded' : status === 'error' ? 'Retry' : 'Upload'}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => removeVideo(index)}
|
||||
disabled={status === 'uploading' || status === 'success'}
|
||||
className="px-4 py-2 bg-red-500/10 text-red-600 rounded-lg font-medium hover:bg-red-500/20 disabled:opacity-50 transition"
|
||||
>
|
||||
<X className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
{videos.some((_, i) => !uploadStatus[`video-${i}`] || uploadStatus[`video-${i}`] === 'error') && (
|
||||
<button
|
||||
onClick={handleUploadAll}
|
||||
disabled={isProcessing}
|
||||
className="w-full px-6 py-3 bg-primary-cta text-white rounded-lg font-semibold hover:opacity-90 disabled:opacity-50 transition"
|
||||
>
|
||||
{isProcessing ? 'Uploading All Videos...' : 'Upload All Videos'}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{videos.length === 0 && (
|
||||
<div className="text-center py-12">
|
||||
<p className="text-foreground/50">No videos selected yet. Upload your cooking videos to get started!</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer" data-section="footer" className="mt-20">
|
||||
<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>
|
||||
);
|
||||
}
|
||||
100
src/app/videos/page.tsx
Normal file
100
src/app/videos/page.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
"use client"
|
||||
|
||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||
import NavbarStyleCentered from '@/components/navbar/NavbarStyleCentered/NavbarStyleCentered';
|
||||
import BlogCardTwo from '@/components/sections/blog/BlogCardTwo';
|
||||
import FooterBaseCard from '@/components/sections/footer/FooterBaseCard';
|
||||
|
||||
export default function VideosPage() {
|
||||
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: "Contact", id: "contact" }
|
||||
]}
|
||||
button={{ text: "Shop Now", href: "products" }}
|
||||
brandName="Food Homes"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="blog" data-section="blog">
|
||||
<BlogCardTwo
|
||||
blogs={[
|
||||
{
|
||||
id: "1", category: "Recipe", title: "How to Prepare the Perfect Grilled Salmon", excerpt: "Learn the secrets to preparing restaurant-quality grilled salmon at home with our step-by-step guide.", imageSrc: "http://img.b2bpic.net/free-photo/make-up-concept-with-pink-nail-polish_23-2149030370.jpg?_wi=2", imageAlt: "Grilled Salmon", authorName: "Chef Maria", authorAvatar: "http://img.b2bpic.net/free-photo/woman-smiles-toothily-keeps-palms-pressed-together-looks-away-joyfully-wears-casual-t-shirt-isolated-beige-copy-space-away-positive-emotions-concept_273609-56517.jpg", date: "15 Jan 2025"
|
||||
},
|
||||
{
|
||||
id: "2", category: "Nutrition", title: "The Benefits of Eating Fresh, Local Ingredients", excerpt: "Discover why locally-sourced ingredients are better for your health and the environment.", imageSrc: "http://img.b2bpic.net/free-photo/flat-lay-hands-holding-body-care-product-wooden-background_23-2148241876.jpg?_wi=2", imageAlt: "Fresh Ingredients", authorName: "Dr. James", authorAvatar: "http://img.b2bpic.net/free-photo/young-beautiful-woman-having-online-meeting_23-2149116347.jpg", date: "12 Jan 2025"
|
||||
},
|
||||
{
|
||||
id: "3", category: "Lifestyle", title: "Meal Planning Tips for Busy Professionals", excerpt: "Simplify your week with our practical meal planning strategies that save time and reduce stress.", imageSrc: "http://img.b2bpic.net/free-photo/product-branding-packaging_23-2150965833.jpg?_wi=2", imageAlt: "Meal Planning", authorName: "Sarah Chen", authorAvatar: "http://img.b2bpic.net/free-photo/young-women-polishing-nails-bed_23-2147770248.jpg", date: "10 Jan 2025"
|
||||
}
|
||||
]}
|
||||
title="Featured Food Articles"
|
||||
description="Read our latest insights about food, nutrition, and culinary experiences."
|
||||
animationType="slide-up"
|
||||
textboxLayout="default"
|
||||
useInvertedBackground={false}
|
||||
carouselMode="buttons"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="footer" data-section="footer">
|
||||
<FooterBaseCard
|
||||
logoText="Food Homes"
|
||||
columns={[
|
||||
{
|
||||
title: "Menu", items: [
|
||||
{ label: "All Items", href: "#products" },
|
||||
{ label: "Specials", href: "#products" },
|
||||
{ label: "Meal Plans", href: "#products" },
|
||||
{ label: "Catering", 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: "Delivery Info", href: "#" },
|
||||
{ label: "Returns", href: "#" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Connect", items: [
|
||||
{ label: "Instagram", href: "https://instagram.com" },
|
||||
{ label: "Facebook", href: "https://facebook.com" },
|
||||
{ label: "Twitter", href: "https://twitter.com" },
|
||||
{ label: "TikTok", href: "https://tiktok.com" }
|
||||
]
|
||||
}
|
||||
]}
|
||||
copyrightText="© 2025 Food Homes. All rights reserved."
|
||||
/>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user