OG Barber Studio
A barbershop in Getafe: one page, two buttons, no backend.
- Astro 5
- React 18
- TypeScript
- Tailwind 3
OG Barber Studio is a barbershop in Getafe. The site is a single static page whose only job is to get you to the booking button: it doesn't handle appointments, it hands them to Booksy, and it keeps WhatsApp within reach in case you'd rather write than click. Astro and React, with JavaScript only in the bits that actually move.
Services and prices Gallery Location and hours Reviews
One page, one goal
The whole site is one route. Inside it, eight blocks in a fixed order — hero, services, booking CTA, gallery, barber, reviews, second CTA and location — plus a floating WhatsApp button that never leaves the corner. No cart, no form, no database: booking is a link to Booksy and getting in touch is a link to WhatsApp with the message already written. The address, the phone, the opening hours, Booksy, Instagram and TikTok live in a single object that every visible component pulls from: nav bar, hero, footer, the CTAs and the floating button. The two call-to-action blocks are the same component with different props, one after the prices and one before the footer, and the reason is written as a comment in the file itself.
It loads fast because almost none of it is JavaScript
The whole site is built before it's published, so what reaches the customer's phone is finished HTML: there's nothing to wait for while the page puts itself together. Only six pieces need code to work, and each one downloads when it's needed. The menu and the top of the page, straight away, because you see them the moment it opens. The services, the gallery, the barber's section and the map, only when you scroll down to them: if you never get there, they never download. The reviews and the two booking buttons need no code at all. The result is a site that opens almost instantly on a phone connection, which is how most people are going to see it.
The before/after slider and mobile scrolling
The before/after slider crops the photo with clip-path and lets you drag the divider. On desktop that's a bit of work and nothing more; on mobile it didn't work at all, because React registers onTouchStart passively at the root and the browser keeps the gesture for itself. The fix is in the file, with a comment next to it: the touchstart listener is attached by hand to the node with passive:false, touchmove the same on window, and the container gets touch-none to tell the browser that this gesture isn't its business. There's a commit that does nothing but that. Small things in the same block: the divider starts at 42% so you can see there are two sides, and the “drag to compare” hint disappears the first time you touch it.
Local SEO, photo weight and deployment
The head carries a HairSalon JSON-LD with the address, the coordinates, the Monday-to-Saturday hours — split into two sessions from Monday to Friday — and the ten services with their prices. On top of that, Open Graph, Twitter Card, canonical, robots.txt and sitemap. For weight, a script of our own runs the JPEGs through sharp with a different width and quality per file and prints how much each one dropped. The hero is preloaded with high fetchpriority and the content photos are lazy-loaded. The deploy config closes the loop: a one-year immutable cache for images and assets, and five security headers. Visually the whole thing holds together with two typefaces and a single gold accent, centralised in the Tailwind config.
Details
One route, no backend
The whole site is a static page: booking is a link to Booksy and getting in touch is a link to WhatsApp, so there's no server to maintain.
The business details live in one file
Address, phone, opening hours, Booksy, Instagram and TikTok in a single object that every visible component pulls from.
Each piece downloads when it's needed
The menu and the top of the page as soon as it opens; the rest only when you reach that section. The reviews and the booking buttons download nothing.
Touch dragging that doesn't fight the scroll
The slider attaches touchstart and touchmove with passive:false, so dragging on iOS and Android moves the divider and not the page.
The animations have no library behind them
Sections appear as they scroll into view, using forty lines of our own code, and the effect disconnects itself as soon as it's done.
Working on something similar?
If you need something like this — a landing page, a website, an ERP or a tool you can't find off the shelf — tell us about it and we'll come back with how we'd do it, how long it would take and what it would cost.
Tell us about your project