Upload files to "/"
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
# GEMINI_API_KEY: Required for Gemini AI API calls.
|
||||||
|
# AI Studio automatically injects this at runtime from user secrets.
|
||||||
|
# Users configure this via the Secrets panel in the AI Studio UI.
|
||||||
|
GEMINI_API_KEY="MY_GEMINI_API_KEY"
|
||||||
|
|
||||||
|
# APP_URL: The URL where this applet is hosted.
|
||||||
|
# AI Studio automatically injects this at runtime with the Cloud Run service URL.
|
||||||
|
# Used for self-referential links, OAuth callbacks, and API endpoints.
|
||||||
|
APP_URL="MY_APP_URL"
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
node_modules/
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
coverage/
|
||||||
|
.DS_Store
|
||||||
|
*.log
|
||||||
|
.env*
|
||||||
|
!.env.example
|
||||||
@@ -0,0 +1,334 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Flame, FlameKindle, MapPin, Search, Plus, Sparkles, Navigation, ArrowRight, Star, ShoppingBag, Truck, Camera, MessageSquareText, Timer, Bike, Banknote, Utensils } from 'lucide-react';
|
||||||
|
|
||||||
|
function Logo({ className = "h-8" }: { className?: string }) {
|
||||||
|
const [imgError, setImgError] = React.useState(false);
|
||||||
|
|
||||||
|
// Fallback to text if the image is not uploaded yet
|
||||||
|
if (imgError) {
|
||||||
|
return (
|
||||||
|
<span className="font-display font-extrabold text-3xl tracking-tighter text-white lowercase">
|
||||||
|
mealno
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
src="/logo.png"
|
||||||
|
alt="Mealno Logo"
|
||||||
|
className={`object-contain block ${className}`}
|
||||||
|
onError={() => setImgError(true)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Navbar() {
|
||||||
|
return (
|
||||||
|
<nav className="fixed top-0 inset-x-0 z-50 bg-background/80 backdrop-blur-xl border-b border-white/5">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-20 flex items-center justify-between">
|
||||||
|
<a href="#" className="flex items-center gap-1.5 cursor-pointer">
|
||||||
|
<Logo className="h-8 md:h-10" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div className="hidden md:flex items-center gap-8 font-medium text-sm">
|
||||||
|
<a href="#" className="hover:text-white transition-colors">Steals</a>
|
||||||
|
<a href="#" className="hover:text-white transition-colors">Community</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-6">
|
||||||
|
<a href="#" className="hidden md:block font-medium text-sm hover:text-white transition-colors">Contact Us</a>
|
||||||
|
<button className="bg-primary hover:bg-primary/90 text-on-primary font-bold text-sm px-6 py-2.5 rounded-full transition-all glow-primary">
|
||||||
|
Order Now
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Hero() {
|
||||||
|
return (
|
||||||
|
<section className="relative pt-32 pb-20 overflow-hidden">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
|
||||||
|
<div className="grid lg:grid-cols-2 gap-12 lg:gap-8 items-center">
|
||||||
|
|
||||||
|
{/* Left Content */}
|
||||||
|
<div className="max-w-xl">
|
||||||
|
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full border border-border bg-surface-container mb-8">
|
||||||
|
<div className="w-1.5 h-1.5 rounded-full bg-primary animate-pulse"></div>
|
||||||
|
<span className="text-[10px] font-bold uppercase tracking-wider text-primary">Dropping Soon</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 className="text-5xl sm:text-6xl lg:text-7xl font-extrabold leading-[1.1] mb-6">
|
||||||
|
Your Wallet Will Thank You.<br />
|
||||||
|
<span className="text-primary inline-block mt-2">Your Stomach Will Love You.</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p className="text-lg text-on-surface/80 mb-10 max-w-md leading-relaxed">
|
||||||
|
Newtown's ultimate student cloud kitchen is dropping soon. Insane flavor, unbelievable student discounts.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Countdown Box */}
|
||||||
|
<div className="relative mb-8 inline-block w-full sm:w-auto">
|
||||||
|
<div className="absolute inset-0 bg-secondary/10 blur-xl rounded-[2rem]"></div>
|
||||||
|
<div className="relative bg-[#171f33]/80 backdrop-blur-md border border-secondary/30 rounded-[1.5rem] px-6 py-6 md:px-10 md:py-8 flex items-center justify-between sm:justify-center gap-3 sm:gap-8 shadow-2xl">
|
||||||
|
|
||||||
|
<div className="flex flex-col items-center">
|
||||||
|
<span className="text-secondary font-display font-bold text-4xl md:text-5xl tracking-tight">05</span>
|
||||||
|
<span className="text-[9px] md:text-[10px] font-bold tracking-widest uppercase mt-2 text-on-surface/60">Days</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span className="text-on-surface/20 text-3xl md:text-4xl font-light mb-4">:</span>
|
||||||
|
|
||||||
|
<div className="flex flex-col items-center">
|
||||||
|
<span className="text-white font-display font-bold text-4xl md:text-5xl tracking-tight">12</span>
|
||||||
|
<span className="text-[9px] md:text-[10px] font-bold tracking-widest uppercase mt-2 text-on-surface/60">Hours</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span className="text-on-surface/20 text-3xl md:text-4xl font-light mb-4">:</span>
|
||||||
|
|
||||||
|
<div className="flex flex-col items-center">
|
||||||
|
<span className="text-white font-display font-bold text-4xl md:text-5xl tracking-tight">45</span>
|
||||||
|
<span className="text-[9px] md:text-[10px] font-bold tracking-widest uppercase mt-2 text-on-surface/60">Mins</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span className="text-on-surface/20 text-3xl md:text-4xl font-light mb-4">:</span>
|
||||||
|
|
||||||
|
<div className="flex flex-col items-center">
|
||||||
|
<span className="text-white font-display font-bold text-4xl md:text-5xl tracking-tight">08</span>
|
||||||
|
<span className="text-[9px] md:text-[10px] font-bold tracking-widest uppercase mt-2 text-on-surface/60">Secs</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Waitlist Input Row */}
|
||||||
|
<form className="flex flex-col sm:flex-row gap-4 mb-6" onSubmit={(e) => e.preventDefault()}>
|
||||||
|
<div className="relative flex-1">
|
||||||
|
<div className="absolute inset-y-0 left-5 flex items-center pointer-events-none">
|
||||||
|
<svg className="w-5 h-5 text-on-surface/40" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
placeholder="Enter your email"
|
||||||
|
className="w-full h-full min-h-[3.5rem] bg-[#131b2e] border border-transparent rounded-[2rem] pl-12 pr-6 py-4 text-sm text-white placeholder:text-on-surface/40 focus:outline-none focus:border-secondary transition-colors"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button className="bg-secondary hover:bg-secondary/90 text-on-secondary font-bold px-8 py-4 rounded-[2rem] transition-all flex items-center justify-center gap-2 whitespace-nowrap shadow-[0_0_15px_rgba(255,179,0,0.2)]">
|
||||||
|
Join Waitlist
|
||||||
|
<ArrowRight className="w-4 h-4" strokeWidth={3} />
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{/* Tiers Text */}
|
||||||
|
<div className="text-[13px] md:text-sm font-medium flex flex-col gap-1.5 pl-2">
|
||||||
|
<div className="flex items-start gap-2">
|
||||||
|
<Flame className="w-4 h-4 text-primary shrink-0 mt-0.5" />
|
||||||
|
<p>
|
||||||
|
<span className="text-primary">Waitlist Tier 1 (First 500):</span> <span className="text-on-surface/70">Free Delivery for one month.</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-start gap-2">
|
||||||
|
<div className="w-4 h-4 shrink-0 flex items-center justify-center pr-1">
|
||||||
|
<div className="w-1.5 h-1.5 rounded-full bg-secondary"></div>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
<span className="text-secondary">Tier 2 (Next 1000):</span> <span className="text-on-surface/70">Priority first access. Sign up now.</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Right Image */}
|
||||||
|
<div className="relative mt-8 lg:mt-0 xl:pl-12">
|
||||||
|
<div className="absolute inset-0 bg-primary/20 blur-[100px] rounded-full"></div>
|
||||||
|
<div className="relative rounded-[2.5rem] overflow-hidden border-2 border-white/5 shadow-2xl aspect-square lg:aspect-[4/5] object-cover bg-surface-container">
|
||||||
|
{/* Chip on Image */}
|
||||||
|
<div className="absolute top-6 right-6 z-20 bg-background/60 backdrop-blur-md border border-white/10 px-4 py-2 rounded-full flex items-center gap-2">
|
||||||
|
<Flame className="w-4 h-4 text-primary" />
|
||||||
|
<span className="text-primary font-bold text-xs">Spicy AF</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Using a high-quality dark-themed burger image as placeholder */}
|
||||||
|
<img
|
||||||
|
src="https://images.unsplash.com/photo-1631515243349-e0cb75fb8d3a?auto=format&fit=crop&w=1200&q=80"
|
||||||
|
alt="Delicious authentic Indian Biryani with spices"
|
||||||
|
className="absolute inset-0 w-full h-full object-cover"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Vignette Overlay for dark aesthetic */}
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-t from-background via-transparent to-transparent opacity-80"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function StealsSection() {
|
||||||
|
const steals = [
|
||||||
|
{
|
||||||
|
title: "Heavy Discounts",
|
||||||
|
description: "Daily flash sales and student-only pricing. Keep your ID ready.",
|
||||||
|
icon: <Flame className="w-5 h-5 text-primary" />,
|
||||||
|
iconBg: "bg-red-950/40 border-red-900/50"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Fresh & Fast",
|
||||||
|
description: "Cooked fresh, delivered straight to your hostel or flat before the craving dies.",
|
||||||
|
icon: <Bike className="w-5 h-5 text-secondary" />,
|
||||||
|
iconBg: "bg-amber-950/40 border-amber-900/50"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Zero Delivery Fees",
|
||||||
|
description: "Order minimums? We don't know them. Free delivery within Newtown campus zones.",
|
||||||
|
icon: <Banknote className="w-5 h-5 text-blue-400" />,
|
||||||
|
iconBg: "bg-blue-950/40 border-blue-900/50"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="py-24 bg-surface-dim relative border-t border-white/5">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="text-center mb-16">
|
||||||
|
<h2 className="text-4xl font-bold mb-4">Student Steals</h2>
|
||||||
|
<p className="text-on-surface/70 max-w-2xl mx-auto">
|
||||||
|
Because instant noodles shouldn't be your only late-night option.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid md:grid-cols-3 gap-6">
|
||||||
|
{steals.map((steal, i) => (
|
||||||
|
<div key={i} className="bg-surface rounded-3xl p-8 border border-border flex flex-col hover:border-white/20 transition-colors">
|
||||||
|
<div className={`w-12 h-12 rounded-full flex items-center justify-center border mb-6 ${steal.iconBg}`}>
|
||||||
|
{steal.icon}
|
||||||
|
</div>
|
||||||
|
<h3 className="text-white font-semibold text-xl mb-3">{steal.title}</h3>
|
||||||
|
<p className="text-on-surface/70 text-sm leading-relaxed">
|
||||||
|
{steal.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function FounderSection() {
|
||||||
|
const team = [
|
||||||
|
{
|
||||||
|
name: "Arnab Kapri",
|
||||||
|
role: "Founder",
|
||||||
|
quote: "\"Software dev by day, building your new favorite food brand by night to fix Newtown's late-night food scene.\"",
|
||||||
|
img: "https://images.unsplash.com/photo-1556157382-97eda2d62296?auto=format&fit=crop&w=800&q=80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Alex Rivera",
|
||||||
|
role: "Co-Founder & Head of Operations",
|
||||||
|
quote: "\"Ensuring your late-night cravings hit your doorstep before the movie gets to the good part.\"",
|
||||||
|
img: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=800&q=80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sarah Chen",
|
||||||
|
role: "Co-Founder & Culinary Lead",
|
||||||
|
quote: "\"Experimenting with flavors that'll make you rethink everything you know about midnight snacking.\"",
|
||||||
|
img: "https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?auto=format&fit=crop&w=800&q=80"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="py-24 bg-background relative z-10 border-t border-white/5">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative">
|
||||||
|
<div className="text-center mb-16">
|
||||||
|
<span className="text-[10px] font-bold uppercase tracking-[0.2em] mb-4 inline-block text-primary">The Hustle</span>
|
||||||
|
<h2 className="text-3xl lg:text-4xl font-bold mb-4">
|
||||||
|
Built by locals, for late-night cravings.
|
||||||
|
</h2>
|
||||||
|
<p className="text-on-surface/70 max-w-2xl mx-auto">
|
||||||
|
Meet the team bringing the heat to Newtown's after-hours food scene.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid md:grid-cols-3 gap-6 lg:gap-8">
|
||||||
|
{team.map((member, i) => (
|
||||||
|
<div key={i} className="bg-surface rounded-[2rem] border border-border overflow-hidden group hover:border-white/20 transition-all duration-300">
|
||||||
|
<div className="relative aspect-square sm:aspect-[4/3] md:aspect-square overflow-hidden bg-surface-container">
|
||||||
|
<img
|
||||||
|
src={member.img}
|
||||||
|
alt={member.name}
|
||||||
|
className="absolute inset-0 w-full h-full object-cover object-center grayscale opacity-80 group-hover:grayscale-0 transition duration-700 mix-blend-luminosity group-hover:scale-105"
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-t from-surface via-surface/40 to-transparent pointer-events-none"></div>
|
||||||
|
<div className="absolute bottom-4 left-4 right-4 flex gap-2 justify-end opacity-0 group-hover:opacity-100 transition-opacity duration-300 z-10">
|
||||||
|
<a href="#" className="w-10 h-10 rounded-full bg-background/80 backdrop-blur-md border border-white/10 flex items-center justify-center hover:bg-primary hover:border-primary transition-colors hover:text-white glow-primary text-white">
|
||||||
|
<Camera className="w-4 h-4" />
|
||||||
|
</a>
|
||||||
|
<a href="#" className="w-10 h-10 rounded-full bg-background/80 backdrop-blur-md border border-white/10 flex items-center justify-center hover:bg-primary hover:border-primary transition-colors hover:text-white glow-primary text-white">
|
||||||
|
<MessageSquareText className="w-4 h-4" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-8">
|
||||||
|
<h3 className="text-2xl font-bold text-white mb-1 tracking-tight">{member.name}</h3>
|
||||||
|
<p className="text-primary text-sm font-bold tracking-wide uppercase mb-6">{member.role}</p>
|
||||||
|
|
||||||
|
<div className="border-l-2 border-border pl-4">
|
||||||
|
<p className="italic text-on-surface/80 text-sm leading-relaxed">
|
||||||
|
{member.quote}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Footer() {
|
||||||
|
return (
|
||||||
|
<footer className="bg-background border-t border-white/5 py-16">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 flex flex-col items-center text-center">
|
||||||
|
<a href="#" className="flex items-center gap-1.5 mb-6 opacity-90 hover:opacity-100 transition-opacity cursor-pointer">
|
||||||
|
<Logo className="h-10" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<p className="text-on-surface/80 mb-2">Wanna chat or partner up? Drop us a line.</p>
|
||||||
|
<a href="mailto:hello@mealno.in" className="text-secondary hover:underline mb-12 inline-block">hello@mealno.in</a>
|
||||||
|
|
||||||
|
<div className="flex flex-wrap justify-center gap-6 text-sm text-on-surface/60 mb-10">
|
||||||
|
<a href="#" className="hover:text-white transition-colors underline underline-offset-4 decoration-white/20">Privacy Policy</a>
|
||||||
|
<a href="#" className="hover:text-white transition-colors underline underline-offset-4 decoration-white/20">Terms of Service</a>
|
||||||
|
<a href="#" className="hover:text-white transition-colors underline underline-offset-4 decoration-white/20">Partner with Us</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-xs text-on-surface/40">
|
||||||
|
© 2026 Mealno. Newtown, Kolkata. Built for the Newtown Hustle.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen">
|
||||||
|
<Navbar />
|
||||||
|
<main>
|
||||||
|
<Hero />
|
||||||
|
<StealsSection />
|
||||||
|
<FounderSection />
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<div align="center">
|
||||||
|
<img width="1200" height="475" alt="GHBanner" src="https://ai.google.dev/static/site-assets/images/share-ais-513315318.png" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
# Run and deploy your AI Studio app
|
||||||
|
|
||||||
|
This contains everything you need to run your app locally.
|
||||||
|
|
||||||
|
View your app in AI Studio: https://ai.studio/apps/3ee1668e-a64b-4275-bbd0-23ae0f558de6
|
||||||
|
|
||||||
|
## Run Locally
|
||||||
|
|
||||||
|
**Prerequisites:** Node.js
|
||||||
|
|
||||||
|
|
||||||
|
1. Install dependencies:
|
||||||
|
`npm install`
|
||||||
|
2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key
|
||||||
|
3. Run the app:
|
||||||
|
`npm run dev`
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--color-background: #0b1326;
|
||||||
|
--color-surface: #131b2e;
|
||||||
|
--color-surface-dim: #0b1326;
|
||||||
|
--color-surface-bright: #31394d;
|
||||||
|
--color-surface-container: #171f33;
|
||||||
|
--color-on-surface: #dae2fd;
|
||||||
|
|
||||||
|
--color-primary: #f93a4a;
|
||||||
|
--color-primary-text: #ff8c95;
|
||||||
|
--color-on-primary: #ffffff;
|
||||||
|
|
||||||
|
--color-secondary: #ffb300;
|
||||||
|
--color-on-secondary: #4d3600;
|
||||||
|
|
||||||
|
--color-border: #2d3449;
|
||||||
|
|
||||||
|
--font-sans: 'Inter', sans-serif;
|
||||||
|
--font-display: 'Plus Jakarta Sans', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
@apply bg-background text-on-surface font-sans antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6, .font-display {
|
||||||
|
@apply font-display tracking-tight text-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom glow utility */
|
||||||
|
.glow-primary {
|
||||||
|
box-shadow: 0 0 20px rgba(249, 58, 74, 0.2);
|
||||||
|
}
|
||||||
|
.glow-primary:hover {
|
||||||
|
box-shadow: 0 0 30px rgba(249, 58, 74, 0.4);
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Mealno - Cloud Kitchen</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@500;600;700;800&display=swap" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import {StrictMode} from 'react';
|
||||||
|
import {createRoot} from 'react-dom/client';
|
||||||
|
import App from './App.tsx';
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
createRoot(document.getElementById('root')!).render(
|
||||||
|
<StrictMode>
|
||||||
|
<App />
|
||||||
|
</StrictMode>,
|
||||||
|
);
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "Mealno",
|
||||||
|
"description": "Gen-Z cloud kitchen landing page for students with dark-tech-appetizing aesthetic.",
|
||||||
|
"requestFramePermissions": [],
|
||||||
|
"majorCapabilities": ["MAJOR_CAPABILITY_SERVER_SIDE_GEMINI_API"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "react-example",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite --port=3000 --host=0.0.0.0",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"clean": "rm -rf dist server.js",
|
||||||
|
"lint": "tsc --noEmit"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@google/genai": "^2.4.0",
|
||||||
|
"@tailwindcss/vite": "^4.1.14",
|
||||||
|
"@vitejs/plugin-react": "^5.0.4",
|
||||||
|
"lucide-react": "^0.546.0",
|
||||||
|
"react": "^19.0.1",
|
||||||
|
"react-dom": "^19.0.1",
|
||||||
|
"vite": "^6.2.3",
|
||||||
|
"express": "^4.21.2",
|
||||||
|
"dotenv": "^17.2.3",
|
||||||
|
"motion": "^12.23.24"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^22.14.0",
|
||||||
|
"autoprefixer": "^10.4.21",
|
||||||
|
"esbuild": "^0.25.0",
|
||||||
|
"tailwindcss": "^4.1.14",
|
||||||
|
"tsx": "^4.21.0",
|
||||||
|
"typescript": "~5.8.2",
|
||||||
|
"vite": "^6.2.3",
|
||||||
|
"@types/express": "^4.17.21"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"useDefineForClassFields": false,
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": [
|
||||||
|
"ES2022",
|
||||||
|
"DOM",
|
||||||
|
"DOM.Iterable"
|
||||||
|
],
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"isolatedModules": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"allowJs": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"./*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"noEmit": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import path from 'path';
|
||||||
|
import {defineConfig} from 'vite';
|
||||||
|
|
||||||
|
export default defineConfig(() => {
|
||||||
|
return {
|
||||||
|
plugins: [react(), tailwindcss()],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': path.resolve(__dirname, '.'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
// HMR is disabled in AI Studio via DISABLE_HMR env var.
|
||||||
|
// Do not modifyâfile watching is disabled to prevent flickering during agent edits.
|
||||||
|
hmr: process.env.DISABLE_HMR !== 'true',
|
||||||
|
// Disable file watching when DISABLE_HMR is true to save CPU during agent edits.
|
||||||
|
watch: process.env.DISABLE_HMR === 'true' ? null : {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user