22 Commits

Author SHA1 Message Date
85992ecd52 Merge version_12_1782114468346 into main
Merge version_12_1782114468346 into main
2026-06-22 07:51:58 +00:00
kudinDmitriyUp
344271ec91 Bob AI: Removed placeholder images from pricing section 2026-06-22 07:51:10 +00:00
ec54718e99 Merge version_11_1782114381506 into main
Merge version_11_1782114381506 into main
2026-06-22 07:46:34 +00:00
dd5be57d65 Update src/pages/HomePage/sections/Hero.tsx 2026-06-22 07:46:30 +00:00
592cdc01be Merge version_10_1782114096259 into main
Merge version_10_1782114096259 into main
2026-06-22 07:43:48 +00:00
kudinDmitriyUp
470b15ff55 Bob AI: <ATTACHED_BLOCKS>
The user attached the section/component ca
2026-06-22 07:43:16 +00:00
3d0d788d85 Merge version_9_1782113871773 into main
Merge version_9_1782113871773 into main
2026-06-22 07:40:02 +00:00
kudinDmitriyUp
76371ff0b6 Bob AI: <ATTACHED_BLOCKS>
The user attached the section/component ca
2026-06-22 07:39:26 +00:00
060d6c2bb7 Merge version_8_1782113660794 into main
Merge version_8_1782113660794 into main
2026-06-22 07:36:23 +00:00
kudinDmitriyUp
d1d5ef1e4d Bob AI: Populate src/pages/PricingPage.tsx (snippet builder, 3 sections) 2026-06-22 07:35:48 +00:00
kudinDmitriyUp
c462a2fe58 Bob AI: Add pricing page 2026-06-22 07:35:08 +00:00
4afe570963 Merge version_7_1782113408837 into main
Merge version_7_1782113408837 into main
2026-06-22 07:31:46 +00:00
kudinDmitriyUp
cb525cb66c Bob AI: <ATTACHED_BLOCKS>
The user attached the section/component ca
2026-06-22 07:31:13 +00:00
fcb960463e Merge version_6_1782112785164 into main
Merge version_6_1782112785164 into main
2026-06-22 07:21:20 +00:00
kudinDmitriyUp
548c1a9407 Bob AI: Added Google Maps embed and address to contact section 2026-06-22 07:20:42 +00:00
8334987958 Merge version_5_1782112757512 into main
Merge version_5_1782112757512 into main
2026-06-22 07:19:29 +00:00
1c96547032 Update src/pages/HomePage.tsx 2026-06-22 07:19:26 +00:00
237e3433e9 Merge version_4_1782112709976 into main
Merge version_4_1782112709976 into main
2026-06-22 07:19:01 +00:00
kudinDmitriyUp
6c9198c7d1 Bob AI: Rewrite the hero headline to emphasize the 'bespoke' and luxury nature of the ex 2026-06-22 07:18:58 +00:00
562de3da2e Merge version_3_1782112558483 into main
Merge version_3_1782112558483 into main
2026-06-22 07:16:01 +00:00
c875a7a4f5 Merge version_2_1782112497077 into main
Merge version_2_1782112497077 into main
2026-06-22 07:15:00 +00:00
7aac108862 Merge version_1_1782112286302 into main
Merge version_1_1782112286302 into main
2026-06-22 07:12:33 +00:00
15 changed files with 377 additions and 217 deletions

View File

@@ -2,11 +2,13 @@ import { Routes, Route } from 'react-router-dom';
import Layout from './components/Layout';
import HomePage from './pages/HomePage';
import PricingPage from "@/pages/PricingPage";
export default function App() {
return (
<Routes>
<Route element={<Layout />}>
<Route path="/" element={<HomePage />} />
<Route path="/pricing" element={<PricingPage />} />
</Route>
</Routes>
);

View File

@@ -27,7 +27,9 @@ export default function Layout() {
},
{
"name": "Faq", "href": "#faq"
}
},
{ name: "Pricing", href: "/pricing" },
];
return (

View File

@@ -1,227 +1,33 @@
import AboutFeaturesSplit from '@/components/sections/about/AboutFeaturesSplit';
import ContactCta from '@/components/sections/contact/ContactCta';
import FaqSimple from '@/components/sections/faq/FaqSimple';
import FeaturesMediaCards from '@/components/sections/features/FeaturesMediaCards';
import HeroSplit from '@/components/sections/hero/HeroSplit';
import PricingHighlightedCards from '@/components/sections/pricing/PricingHighlightedCards';
import TestimonialColumnMarqueeCards from '@/components/sections/testimonial/TestimonialColumnMarqueeCards';
import { Award, Shield, Sparkles } from "lucide-react";
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
// AUTO-GENERATED shell by per-section-migrate.
// Section bodies live in ./<PageBase>/sections/<X>.tsx. Edit the section
// files directly. Non-block content (wrappers, non-inlinable sections) is
// preserved inline; extracted section blocks become <XSection/> refs.
export default function HomePage() {
import React from 'react';
import HeroSection from './HomePage/sections/Hero';
import AboutSection from './HomePage/sections/About';
import ServicesSection from './HomePage/sections/Services';
import PricingSection from './HomePage/sections/Pricing';
import TestimonialsSection from './HomePage/sections/Testimonials';
import FaqSection from './HomePage/sections/Faq';
import ContactSection from './HomePage/sections/Contact';
export default function HomePage(): React.JSX.Element {
return (
<>
<div id="hero" data-section="hero">
<SectionErrorBoundary name="hero">
<HeroSplit
tag="Est. 2016 · Helsinki"
title="Quiet Luxury for Your Hands"
description="LA BOHÉM offers bespoke nail care in the heart of Kamppi. Experience Japanese-inspired minimalism designed for the discerning individual."
primaryButton={{
text: "Book Appointment",
href: "#contact",
}}
secondaryButton={{
text: "Our Services",
href: "#services",
}}
imageSrc="http://img.b2bpic.net/free-photo/woman-s-arms-posing-with-peach_23-2149640614.jpg"
/>
</SectionErrorBoundary>
</div>
<>
<HeroSection />
<div id="about" data-section="about">
<SectionErrorBoundary name="about">
<AboutFeaturesSplit
tag="Philosophy"
title="Artistry & Serenity"
description="Located at Lönnrotinkatu 16, LA BOHÉM is more than a salon. We focus on natural health, architectural precision, and the quiet beauty of Japanese minimalism."
items={[
{
icon: Sparkles,
title: "Premium Products",
description: "We only use high-end formulas.",
},
{
icon: Shield,
title: "Hygiene First",
description: "Impeccable standards for your safety.",
},
{
icon: Award,
title: "Expert Care",
description: "Trained professionals since 2016.",
},
]}
imageSrc="http://img.b2bpic.net/free-photo/nail-care-manicure-process_23-2149130315.jpg"
/>
</SectionErrorBoundary>
</div>
<AboutSection />
<div id="services" data-section="services">
<SectionErrorBoundary name="services">
<FeaturesMediaCards
tag="Expertise"
title="Refined Services"
description="From natural wellness manicures to artistic long extensions, every detail is considered."
items={[
{
title: "Artistic Manicures",
description: "From classic to spa experiences.",
imageSrc: "http://img.b2bpic.net/free-photo/client-manicure-appointment-close-up_23-2149171319.jpg",
},
{
title: "Gel Sculpting",
description: "Precision filling and shaping.",
imageSrc: "http://img.b2bpic.net/free-photo/manicurist-doing-gel-nail-design-client-close-up_127675-2638.jpg",
},
{
title: "Bespoke Extensions",
description: "Long-lasting luxury extensions.",
imageSrc: "http://img.b2bpic.net/free-photo/portrait-pretty-woman-black-sweater-standing-posing_114579-58758.jpg",
},
]}
/>
</SectionErrorBoundary>
</div>
<ServicesSection />
<div id="pricing" data-section="pricing">
<SectionErrorBoundary name="pricing">
<PricingHighlightedCards
tag="Investment"
title="Selected Services"
plans={[
{
tag: "Essentials",
price: "40€",
description: "Classic Manicure",
features: [
"Nail shaping",
"Cuticle work",
"Natural buffing",
],
primaryButton: {
text: "Book",
href: "#contact",
},
},
{
tag: "Signature",
price: "70€",
description: "Gel Polish Fill",
features: [
"Refill process",
"Shape correction",
"High-gloss finish",
],
highlight: "Most Popular",
primaryButton: {
text: "Book",
href: "#contact",
},
},
{
tag: "Premium",
price: "95€",
description: "Long Extensions",
features: [
"Full set creation",
"Length extension",
"Custom shaping",
],
primaryButton: {
text: "Book",
href: "#contact",
},
},
]}
description="Transparent pricing for our signature treatments."
/>
</SectionErrorBoundary>
</div>
<PricingSection />
<div id="testimonials" data-section="testimonials">
<SectionErrorBoundary name="testimonials">
<TestimonialColumnMarqueeCards
tag="Clients"
title="Stories of Elegance"
testimonials={[
{
name: "Elina H.",
role: "Fashion Editor",
quote: "The most refined studio in Helsinki.",
imageSrc: "http://img.b2bpic.net/free-photo/headshot-portrait-smiling-young-woman_1153-7291.jpg",
},
{
name: "Sofia R.",
role: "Architect",
quote: "Absolute precision and serenity.",
imageSrc: "http://img.b2bpic.net/free-photo/portrait-woman-with-pink-sweater_23-2148749909.jpg",
},
{
name: "Minna K.",
role: "Entrepreneur",
quote: "My nails have never looked healthier.",
imageSrc: "http://img.b2bpic.net/free-photo/side-view-woman-couch-with-man-holding-her-head_23-2148857585.jpg",
},
{
name: "Sara V.",
role: "Designer",
quote: "The ultimate luxury experience.",
imageSrc: "http://img.b2bpic.net/free-photo/woman-dancing-listening-music_23-2148919852.jpg",
},
{
name: "Kaisa L.",
role: "Consultant",
quote: "Exquisite quality and atmosphere.",
imageSrc: "http://img.b2bpic.net/free-photo/attractive-woman-yellow-summer-dress-with-short-hairstyle-interior-room-concrete-wall-background-posing-sunny-shadows_285396-10430.jpg",
},
]}
description="Hear from our community of discerning clients."
/>
</SectionErrorBoundary>
</div>
<TestimonialsSection />
<div id="faq" data-section="faq">
<SectionErrorBoundary name="faq">
<FaqSimple
tag="Help"
title="Studio Policies"
items={[
{
question: "What is the cancellation policy?",
answer: "Please provide 24h notice.",
},
{
question: "Where are you located?",
answer: "Lönnrotinkatu 16, Helsinki.",
},
{
question: "Do you offer removal?",
answer: "Yes, we offer removal services at 30€.",
},
]}
description="Common inquiries about your visit."
/>
</SectionErrorBoundary>
</div>
<FaqSection />
<div id="contact" data-section="contact">
<SectionErrorBoundary name="contact">
<ContactCta
tag="Book Now"
text="Ready to experience LA BOHÉM? Secure your appointment today."
primaryButton={{
text: "Schedule Online",
href: "#",
}}
secondaryButton={{
text: "Call +358 00 000 000",
href: "tel:+35800000000",
}}
/>
</SectionErrorBoundary>
</div>
<ContactSection />
</>
);
}

View File

@@ -0,0 +1,39 @@
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
// file as the canonical source for the "about" section.
import React from 'react';
import AboutFeaturesSplit from '@/components/sections/about/AboutFeaturesSplit';
import { Award, Shield, Sparkles } from "lucide-react";
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
export default function AboutSection(): React.JSX.Element {
return (
<div id="about" data-section="about">
<SectionErrorBoundary name="about">
<AboutFeaturesSplit
tag="Philosophy"
title="Artistry & Serenity"
description="Located at Lönnrotinkatu 16, LA BOHÉM is more than a salon. We focus on natural health, architectural precision, and the quiet beauty of Japanese minimalism."
items={[
{
icon: Sparkles,
title: "Premium Products",
description: "We only use high-end formulas.",
},
{
icon: Shield,
title: "Hygiene First",
description: "Impeccable standards for your safety.",
},
{
icon: Award,
title: "Expert Care",
description: "Trained professionals since 2016.",
},
]}
imageSrc="http://img.b2bpic.net/free-photo/nail-care-manicure-process_23-2149130315.jpg"
/>
</SectionErrorBoundary>
</div>
);
}

View File

@@ -0,0 +1,72 @@
/* eslint-disable */
// @ts-nocheck — generated by catalog-eject; runtime-correct but TS strict-mode false-positives on inlined catalog body
import ScrollReveal from "@/components/ui/ScrollReveal";
import TextAnimation from "@/components/ui/TextAnimation";
import Button from "@/components/ui/Button";
const primaryButton = {
text: "Schedule Online",
href: "#"
};
const secondaryButton = {
text: "Call +358 00 000 000",
href: "tel:+35800000000"
};
const ContactInline = () => {
return (
<section aria-label="Contact section" className="py-20">
<div className="w-content-width mx-auto">
<ScrollReveal variant="fade-blur">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 md:gap-12 p-8 md:p-12 rounded card items-center">
<div className="flex flex-col items-start gap-6">
<div className="px-3 py-1 text-sm bg-background rounded w-fit">
<p>{"Book Now"}</p>
</div>
<TextAnimation
text={"Ready to experience LA BOHÉM? Secure your appointment today."}
variant="fade"
gradientText={true}
tag="h2"
className="text-4xl md:text-5xl leading-[1.15] font-semibold text-balance"
/>
<div className="flex flex-col gap-1 text-accent">
<p className="font-medium text-foreground">LA BOHÉM Luxury Nail Studio</p>
<p>Lönnrotinkatu 16</p>
<p>Kamppi, Helsinki</p>
</div>
<div className="flex flex-wrap gap-3 mt-2">
<Button text={primaryButton.text} href={primaryButton.href} variant="primary" />
<Button text={secondaryButton.text} href={secondaryButton.href} variant="secondary" animationDelay={0.1} />
</div>
</div>
<div className="w-full h-[300px] lg:h-[400px] rounded overflow-hidden bg-background">
<iframe
src="https://maps.google.com/maps?q=L%C3%B6nnrotinkatu%2016%2C%20Kamppi%2C%20Helsinki&t=&z=15&ie=UTF8&iwloc=&output=embed"
width="100%"
height="100%"
style={{ border: 0 }}
allowFullScreen
loading="lazy"
referrerPolicy="no-referrer-when-downgrade"
title="LA BOHÉM Location"
></iframe>
</div>
</div>
</ScrollReveal>
</div>
</section>
);
};
export default function ContactSection() {
return (
<div data-webild-section="contact" id="contact">
<ContactInline />
</div>
);
}

View File

@@ -0,0 +1,34 @@
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
// file as the canonical source for the "faq" section.
import React from 'react';
import FaqSimple from '@/components/sections/faq/FaqSimple';
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
export default function FaqSection(): React.JSX.Element {
return (
<div id="faq" data-section="faq">
<SectionErrorBoundary name="faq">
<FaqSimple
tag="Help"
title="Studio Policies"
items={[
{
question: "What is the cancellation policy?",
answer: "Please provide 24h notice.",
},
{
question: "Where are you located?",
answer: "Lönnrotinkatu 16, Helsinki.",
},
{
question: "Do you offer removal?",
answer: "Yes, we offer removal services at 30€.",
},
]}
description="Common inquiries about your visit."
/>
</SectionErrorBoundary>
</div>
);
}

View File

@@ -0,0 +1,18 @@
// Created by add_section_from_catalog (HeroBrand).
import React from 'react';
import HeroBrand from '@/components/sections/hero/HeroBrand';
export default function HeroSection(): React.JSX.Element {
return (
<div data-webild-section="hero" id="hero">
<HeroBrand
description="Bespoke Nail Artistry & Uncompromising Luxury. LA BOHÉM offers an unparalleled, personalized nail care experience in the heart of Kamppi. Discover Japanese-inspired minimalism crafted exclusively for you."
imageSrc="https://storage.googleapis.com/webild/users/user_3FTsgssZm5IGsI0zqyxS0M8E8vA/uploaded-1782114375681-3ecb7aln.png"
secondaryButton={{"href":"#services","text":"Our Services"}}
primaryButton={{"text":"Book Appointment","href":"#contact"}}
brand="LA BOHÉM"
/>
</div>
);
}

View File

@@ -0,0 +1,17 @@
// Created by add_section_from_catalog (ProductVariantCards).
import React from 'react';
import ProductVariantCards from '@/components/sections/product/ProductVariantCards';
export default function PricingSection(): React.JSX.Element {
return (
<div data-webild-section="pricing" id="pricing">
<ProductVariantCards
products={[{"name":"Geelilakkaus uudet","price":"alk. 60€","imageSrc":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=","variant":"Gel polish new"},{"imageSrc":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=","variant":"Hard gel fill","price":"alk. 80€","name":"Rakennekynnet huolto"},{"name":"Geelilakkaus huolto","price":"alk. 70€","variant":"Gel polish fill","imageSrc":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="},{"variant":"New set tip","imageSrc":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=","name":"Rakennekynnet uudet","price":"alk. 85€"},{"name":"Geelilakkaus poisto","price":"alk. 30€","variant":"Gel polish remove","imageSrc":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="},{"imageSrc":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=","variant":"Long extensions","price":"alk. 95€","name":"Rakennekynnet uudet (Pitkät)"},{"name":"Extension remove","price":"30€","variant":"Removing gel, shaping","imageSrc":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="},{"imageSrc":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=","variant":"Shape, deep cleaning cuticle, shine, cream","price":"40€","name":"Manicure"},{"price":"alk. 60€","name":"Spa Manicure","imageSrc":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=","variant":"Exfoliation, massage, scrub, hand cream"},{"name":"Wedding Nails","price":"60€","imageSrc":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=","variant":"Geelilakkaus Uudet"},{"price":"85€","name":"Wedding Nails","variant":"Rakennekynnet uudet","imageSrc":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="},{"name":"Nail repair","price":"5€","variant":"Kynnen korjaus","imageSrc":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="},{"name":"Hailey Bieber Nails","price":"10€","variant":"Add-on","imageSrc":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="},{"variant":"All fingers","imageSrc":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=","price":"20€","name":"French, ombre, design"},{"variant":"Add-on","imageSrc":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=","name":"Removal of old gel","price":"15€"}]}
title="Services & Pricing"
tag="Pricing"
description="I choose to work only with high quality products. Note: If you currently have acrylic made elsewhere, I cant remove it because I dont have the corresponding machine."
/>
</div>
);
}

View File

@@ -0,0 +1,37 @@
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
// file as the canonical source for the "services" section.
import React from 'react';
import FeaturesMediaCards from '@/components/sections/features/FeaturesMediaCards';
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
export default function ServicesSection(): React.JSX.Element {
return (
<div id="services" data-section="services">
<SectionErrorBoundary name="services">
<FeaturesMediaCards
tag="Expertise"
title="Refined Services"
description="From natural wellness manicures to artistic long extensions, every detail is considered."
items={[
{
title: "Artistic Manicures",
description: "From classic to spa experiences.",
imageSrc: "http://img.b2bpic.net/free-photo/client-manicure-appointment-close-up_23-2149171319.jpg",
},
{
title: "Gel Sculpting",
description: "Precision filling and shaping.",
imageSrc: "http://img.b2bpic.net/free-photo/manicurist-doing-gel-nail-design-client-close-up_127675-2638.jpg",
},
{
title: "Bespoke Extensions",
description: "Long-lasting luxury extensions.",
imageSrc: "http://img.b2bpic.net/free-photo/portrait-pretty-woman-black-sweater-standing-posing_114579-58758.jpg",
},
]}
/>
</SectionErrorBoundary>
</div>
);
}

View File

@@ -0,0 +1,52 @@
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
// file as the canonical source for the "testimonials" section.
import React from 'react';
import TestimonialColumnMarqueeCards from '@/components/sections/testimonial/TestimonialColumnMarqueeCards';
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
export default function TestimonialsSection(): React.JSX.Element {
return (
<div id="testimonials" data-section="testimonials">
<SectionErrorBoundary name="testimonials">
<TestimonialColumnMarqueeCards
tag="Clients"
title="Stories of Elegance"
testimonials={[
{
name: "Elina H.",
role: "Fashion Editor",
quote: "The most refined studio in Helsinki.",
imageSrc: "http://img.b2bpic.net/free-photo/headshot-portrait-smiling-young-woman_1153-7291.jpg",
},
{
name: "Sofia R.",
role: "Architect",
quote: "Absolute precision and serenity.",
imageSrc: "http://img.b2bpic.net/free-photo/portrait-woman-with-pink-sweater_23-2148749909.jpg",
},
{
name: "Minna K.",
role: "Entrepreneur",
quote: "My nails have never looked healthier.",
imageSrc: "http://img.b2bpic.net/free-photo/side-view-woman-couch-with-man-holding-her-head_23-2148857585.jpg",
},
{
name: "Sara V.",
role: "Designer",
quote: "The ultimate luxury experience.",
imageSrc: "http://img.b2bpic.net/free-photo/woman-dancing-listening-music_23-2148919852.jpg",
},
{
name: "Kaisa L.",
role: "Consultant",
quote: "Exquisite quality and atmosphere.",
imageSrc: "http://img.b2bpic.net/free-photo/attractive-woman-yellow-summer-dress-with-short-hairstyle-interior-room-concrete-wall-background-posing-sunny-shadows_285396-10430.jpg",
},
]}
description="Hear from our community of discerning clients."
/>
</SectionErrorBoundary>
</div>
);
}

19
src/pages/PricingPage.tsx Normal file
View File

@@ -0,0 +1,19 @@
// AUTO-GENERATED shell by per-section-migrate.
// Section bodies live in ./<PageBase>/sections/<X>.tsx. Edit the section
// files directly. Non-block content (wrappers, non-inlinable sections) is
// preserved inline; extracted section blocks become <XSection/> refs.
import React from 'react';
import HeroBillboardSection from './PricingPage/sections/HeroBillboard';
import PricingSplitCardsSection from './PricingPage/sections/PricingSplitCards';
import PricingSimpleCardsSection from './PricingPage/sections/PricingSimpleCards';
export default function PricingPage(): React.JSX.Element {
return (
<>
<HeroBillboardSection />
<PricingSplitCardsSection />
<PricingSimpleCardsSection />
</>
);
}

View File

@@ -0,0 +1,15 @@
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
// file as the canonical source for the "HeroBillboard" section.
import React from 'react';
import Button from "@/components/ui/Button";
import HeroBackgroundSlot from "@/components/ui/HeroBackgroundSlot";
import TextAnimation from "@/components/ui/TextAnimation";
import ImageOrVideo from "@/components/ui/ImageOrVideo";
import ScrollReveal from "@/components/ui/ScrollReveal";
export default function HeroBillboardSection(): React.JSX.Element {
return (
<div data-webild-section="HeroBillboard"><section aria-label="Hero section" className="relative pt-25 pb-20 md:pt-30"><HeroBackgroundSlot /><div className="flex flex-col gap-12 md:gap-15 w-content-width mx-auto"><div className="flex flex-col items-center gap-3 text-center"><div className="px-3 py-1 mb-1 text-sm card rounded w-fit"><p>Service Menu</p></div><TextAnimation text="Making Your Hands Feel" variant="fade" gradientText={true} tag="h1" className="md:max-w-8/10 text-7xl 2xl:text-8xl leading-[1.15] font-semibold text-center text-balance" /><TextAnimation text="Explore our curated selection of gel treatments, extensions, and manicures. Experience architectural precision and the quiet beauty of Japanese minimalism." variant="fade" gradientText={false} tag="p" className="md:max-w-7/10 text-lg md:text-xl leading-snug text-balance" /><div className="flex flex-wrap justify-center gap-3 mt-2 md:mt-3"><Button text="Book Appointment" href="#booking" variant="primary" /><Button text="View Pricing" href="#services" variant="secondary" animationDelay={0.1} /></div></div><ScrollReveal variant="fade-blur" delay={0.2} className="w-full p-2 xl:p-3 2xl:p-4 card rounded overflow-hidden"><ImageOrVideo imageSrc="https://img.freepik.com/free-photo/close-up-woman-getting-manicure_23-2148873327.jpg" className="aspect-4/5 md:aspect-video" /></ScrollReveal></div></section></div>
);
}

View File

@@ -0,0 +1,18 @@
// Created by add_section_from_catalog (ProductVariantCards).
import React from 'react';
import ProductVariantCards from '@/components/sections/product/ProductVariantCards';
export default function PricingSimpleCardsSection(): React.JSX.Element {
return (
<div data-webild-section="pricing-simple-cards" id="pricing-simple-cards">
<ProductVariantCards
description="Tutustu kattavaan kynsipalveluiden valikoimaamme ja varaa aikasi. Valitse itsellesi sopivin palvelu ja anna meidän hemmotella käsiäsi."
tag="Hinnasto"
primaryButton={{"text":"Varaa aika","href":"/booking"}}
products={[{"name":"Geelilakkaus uudet / gel polish new","variant":"Geelilakkaus antaa upean ja kestävän lakan jopa 4-5 viikoksi. Ei sisällä vanhan geelilakkauksen poistoa tai huoltoa.","imageSrc":"https://images.unsplash.com/photo-1519014816548-bf5fe059e98b?auto=format&fit=crop&q=80","price":"alk. 60€"},{"imageSrc":"https://images.unsplash.com/photo-1522337660859-02fbefca4702?auto=format&fit=crop&q=80","name":"Rakennekynnet huolto / Hard gel fill","variant":"Geelilakkaus huolto. Sisältää kynsinauhojen syväpuhdistuksen. Kestää hyvänä jopa 6-7 viikkoa.","price":"alk. 80€"},{"price":"alk. 70€","name":"Geelilakkaus huolto / gel polish fill","variant":"Geelilakkaus antaa upean ja kestävän lakan jopa 6 viikoksi. Ei sisällä vanhan lakan poistoa/huoltoa.","imageSrc":"https://images.unsplash.com/photo-1604654894610-df63bc536371?auto=format&fit=crop&q=80"},{"price":"alk. 85€","variant":"Rakennekynnet tehdään omien kynsien päälle geelillä. Pidennyskynsillä saa pidennettyä oman kynnen pituutta.","name":"Rakennekynnet uudet / New set tip","imageSrc":"https://images.unsplash.com/photo-1519014816548-bf5fe059e98b?auto=format&fit=crop&q=80"},{"imageSrc":"https://images.unsplash.com/photo-1522337660859-02fbefca4702?auto=format&fit=crop&q=80","name":"Geelilakkaus poisto / gel polish remove","variant":"Poistamme vain omat laadukkaat tuotteemme.","price":"alk. 30€"},{"variant":"Rakennekynnet tehdään omien kynsien päälle geelillä tai akryylillä. Pidennyskynsillä saa pidennettyä oman kynnen pituutta.","name":"Rakennekynnet uudet (Pitkät)","imageSrc":"https://images.unsplash.com/photo-1604654894610-df63bc536371?auto=format&fit=crop&q=80","price":"alk. 95€"},{"imageSrc":"https://images.unsplash.com/photo-1519014816548-bf5fe059e98b?auto=format&fit=crop&q=80","name":"Extension remove","variant":"Removing gel, shaping.","price":"30€"},{"imageSrc":"https://images.unsplash.com/photo-1522337660859-02fbefca4702?auto=format&fit=crop&q=80","variant":"Shape, deep cleaning cuticle, shine, cream.","name":"Manicure","price":"40€"},{"imageSrc":"https://images.unsplash.com/photo-1604654894610-df63bc536371?auto=format&fit=crop&q=80","variant":"Exfoliation, massage, scrub, hand cream, trimming of nails and cuticles.","name":"Spa Manicure","price":"alk. 60€"},{"price":"60€","imageSrc":"https://images.unsplash.com/photo-1519014816548-bf5fe059e98b?auto=format&fit=crop&q=80","name":"Wedding Nails / Geelilakkaus Uudet","variant":"Make your day special trusting your hands me! 😍🪄"},{"name":"Wedding Nails / Rakennekynnet uudet","variant":"Make your day special trusting your hands me! 🥰🪄","imageSrc":"https://images.unsplash.com/photo-1522337660859-02fbefca4702?auto=format&fit=crop&q=80","price":"85€"},{"price":"alk. 5€","variant":"Nail repair (5€), Hailey Bieber Nails (10€), French/ombre/design (20€), Removal of old gel (15€)","name":"Lisäpalvelut","imageSrc":"https://images.unsplash.com/photo-1604654894610-df63bc536371?auto=format&fit=crop&q=80"}]}
title="Kynnet ja kynsien hinnat"
/>
</div>
);
}

View File

@@ -0,0 +1,28 @@
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
// file as the canonical source for the "PricingSplitCards" section.
import React from 'react';
import Button from "@/components/ui/Button";
import TextAnimation from "@/components/ui/TextAnimation";
import ScrollReveal from "@/components/ui/ScrollReveal";
import { Check } from "lucide-react";
export default function PricingSplitCardsSection(): React.JSX.Element {
return (
<div data-webild-section="PricingSplitCards"><section aria-label="Pricing section" className="py-20"><div className="flex flex-col gap-8 md:gap-10"><div className="flex flex-col items-center gap-2 w-content-width mx-auto"><div className="px-3 py-1 mb-1 text-sm card rounded w-fit"><p>Services & Pricing</p></div><TextAnimation text="Making your hands feel" variant="fade" gradientText={true} tag="h2" className="md:max-w-8/10 text-6xl 2xl:text-7xl leading-[1.15] font-semibold text-center text-balance" /><TextAnimation text="Discover our range of meticulous nail services, from natural gel overlays to architectural extensions, all performed with Japanese precision and care." variant="fade" gradientText={false} tag="p" className="md:max-w-7/10 text-lg md:text-xl leading-snug text-center text-balance" /><div className="flex flex-wrap justify-center gap-3 mt-2 md:mt-3"><Button text="Book an Appointment" href="/booking" variant="primary" /><Button text="View Gallery" href="/gallery" variant="secondary" animationDelay={0.1} /></div></div><div className="flex flex-col gap-5 w-content-width mx-auto"><ScrollReveal variant="fade" key="Natural Care" className="flex flex-col md:flex-row gap-5 md:gap-12 p-5 md:p-12 card rounded"><div className="flex flex-col gap-2 justify-between w-full md:w-1/2"><div className="flex flex-col gap-2"><div className="px-3 py-1 mb-2 w-fit text-sm card rounded"><p>Natural Care</p></div><div className="flex items-baseline gap-1"><span className="text-5xl md:text-6xl font-semibold">From 65</span><span className="text-2xl font-medium">per session</span></div><p className="text-xl md:text-2xl leading-snug text-balance">Enhance your natural nails with our strengthening gel overlays and meticulous cuticle care.</p></div><div className="flex flex-col gap-3"><Button text="Book Natural Gel" href="/booking" variant="primary" className="w-full" /></div></div><div className="w-full h-px bg-foreground/20 md:hidden" /><div className="flex flex-col gap-3 w-full md:w-1/2"><h3 className="text-xl font-medium truncate">Included Services</h3><div className="w-full h-px bg-foreground/5" /><div key="Japanese manicure techniques" className="flex items-start gap-3"><div className="flex items-center justify-center shrink-0 size-6 primary-button rounded"><Check className="size-3 text-primary-cta-text" strokeWidth={2} /></div><span className="text-base leading-snug">Japanese manicure techniques</span></div>
<div key="Strengthening gel overlay" className="flex items-start gap-3"><div className="flex items-center justify-center shrink-0 size-6 primary-button rounded"><Check className="size-3 text-primary-cta-text" strokeWidth={2} /></div><span className="text-base leading-snug">Strengthening gel overlay</span></div>
<div key="Precision cuticle care" className="flex items-start gap-3"><div className="flex items-center justify-center shrink-0 size-6 primary-button rounded"><Check className="size-3 text-primary-cta-text" strokeWidth={2} /></div><span className="text-base leading-snug">Precision cuticle care</span></div>
<div key="Custom color application" className="flex items-start gap-3"><div className="flex items-center justify-center shrink-0 size-6 primary-button rounded"><Check className="size-3 text-primary-cta-text" strokeWidth={2} /></div><span className="text-base leading-snug">Custom color application</span></div>
<div key="Nourishing oil treatment" className="flex items-start gap-3"><div className="flex items-center justify-center shrink-0 size-6 primary-button rounded"><Check className="size-3 text-primary-cta-text" strokeWidth={2} /></div><span className="text-base leading-snug">Nourishing oil treatment</span></div></div></ScrollReveal>
<ScrollReveal variant="fade" key="Extensions" className="flex flex-col md:flex-row gap-5 md:gap-12 p-5 md:p-12 card rounded"><div className="flex flex-col gap-2 justify-between w-full md:w-1/2"><div className="flex flex-col gap-2"><div className="px-3 py-1 mb-2 w-fit text-sm card rounded"><p>Extensions</p></div><div className="flex items-baseline gap-1"><span className="text-5xl md:text-6xl font-semibold">From 95</span><span className="text-2xl font-medium">per session</span></div><p className="text-xl md:text-2xl leading-snug text-balance">Flawless, durable nail extensions crafted with architectural precision for a natural look.</p></div><div className="flex flex-col gap-3"><Button text="Book Extensions" href="/booking" variant="primary" className="w-full" /></div></div><div className="w-full h-px bg-foreground/20 md:hidden" /><div className="flex flex-col gap-3 w-full md:w-1/2"><h3 className="text-xl font-medium truncate">Included Services</h3><div className="w-full h-px bg-foreground/5" /><div key="Custom length and shape" className="flex items-start gap-3"><div className="flex items-center justify-center shrink-0 size-6 primary-button rounded"><Check className="size-3 text-primary-cta-text" strokeWidth={2} /></div><span className="text-base leading-snug">Custom length and shape</span></div>
<div key="Architectural gel building" className="flex items-start gap-3"><div className="flex items-center justify-center shrink-0 size-6 primary-button rounded"><Check className="size-3 text-primary-cta-text" strokeWidth={2} /></div><span className="text-base leading-snug">Architectural gel building</span></div>
<div key="Seamless cuticle blending" className="flex items-start gap-3"><div className="flex items-center justify-center shrink-0 size-6 primary-button rounded"><Check className="size-3 text-primary-cta-text" strokeWidth={2} /></div><span className="text-base leading-snug">Seamless cuticle blending</span></div>
<div key="Minimalist art options" className="flex items-start gap-3"><div className="flex items-center justify-center shrink-0 size-6 primary-button rounded"><Check className="size-3 text-primary-cta-text" strokeWidth={2} /></div><span className="text-base leading-snug">Minimalist art options</span></div>
<div key="Long-lasting finish" className="flex items-start gap-3"><div className="flex items-center justify-center shrink-0 size-6 primary-button rounded"><Check className="size-3 text-primary-cta-text" strokeWidth={2} /></div><span className="text-base leading-snug">Long-lasting finish</span></div></div></ScrollReveal>
<ScrollReveal variant="fade" key="Bridal" className="flex flex-col md:flex-row gap-5 md:gap-12 p-5 md:p-12 card rounded"><div className="flex flex-col gap-2 justify-between w-full md:w-1/2"><div className="flex flex-col gap-2"><div className="px-3 py-1 mb-2 w-fit text-sm card rounded"><p>Bridal</p></div><div className="flex items-baseline gap-1"><span className="text-5xl md:text-6xl font-semibold">From 120</span><span className="text-2xl font-medium">per session</span></div><p className="text-xl md:text-2xl leading-snug text-balance">Bespoke nail artistry designed to complement your special day with serene elegance.</p></div><div className="flex flex-col gap-3"><Button text="Book Bridal" href="/booking" variant="primary" className="w-full" /></div></div><div className="w-full h-px bg-foreground/20 md:hidden" /><div className="flex flex-col gap-3 w-full md:w-1/2"><h3 className="text-xl font-medium truncate">Included Services</h3><div className="w-full h-px bg-foreground/5" /><div key="In-depth consultation" className="flex items-start gap-3"><div className="flex items-center justify-center shrink-0 size-6 primary-button rounded"><Check className="size-3 text-primary-cta-text" strokeWidth={2} /></div><span className="text-base leading-snug">In-depth consultation</span></div>
<div key="Trial session available" className="flex items-start gap-3"><div className="flex items-center justify-center shrink-0 size-6 primary-button rounded"><Check className="size-3 text-primary-cta-text" strokeWidth={2} /></div><span className="text-base leading-snug">Trial session available</span></div>
<div key="Intricate minimalist art" className="flex items-start gap-3"><div className="flex items-center justify-center shrink-0 size-6 primary-button rounded"><Check className="size-3 text-primary-cta-text" strokeWidth={2} /></div><span className="text-base leading-snug">Intricate minimalist art</span></div>
<div key="Premium gel products" className="flex items-start gap-3"><div className="flex items-center justify-center shrink-0 size-6 primary-button rounded"><Check className="size-3 text-primary-cta-text" strokeWidth={2} /></div><span className="text-base leading-snug">Premium gel products</span></div>
<div key="Relaxing hand massage" className="flex items-start gap-3"><div className="flex items-center justify-center shrink-0 size-6 primary-button rounded"><Check className="size-3 text-primary-cta-text" strokeWidth={2} /></div><span className="text-base leading-snug">Relaxing hand massage</span></div></div></ScrollReveal></div></div></section></div>
);
}

View File

@@ -6,4 +6,5 @@ export interface Route {
export const routes: Route[] = [
{ path: '/', label: 'Home', pageFile: 'HomePage' },
{ path: '/pricing', label: 'Pricing', pageFile: 'PricingPage' },
];