diff --git a/public/images/shitaye-logo-mono.png b/public/images/shitaye-logo-mono.png new file mode 100644 index 0000000..4da5dec Binary files /dev/null and b/public/images/shitaye-logo-mono.png differ diff --git a/public/images/shitaye-logo.png b/public/images/shitaye-logo.png new file mode 100644 index 0000000..d6051d9 Binary files /dev/null and b/public/images/shitaye-logo.png differ diff --git a/src/app/globals.css b/src/app/globals.css index 0bfd105..aa7ce8c 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -173,3 +173,33 @@ body { animation: mock3d-rotate 8s ease-in-out infinite alternate; transform-style: preserve-3d; } + +/* Branded route loader — /services and similar */ +@keyframes shitaye-logo-breathe { + 0%, + 100% { + transform: scale(1); + opacity: 1; + } + 50% { + transform: scale(1.045); + opacity: 0.94; + } +} + +@keyframes shitaye-logo-ring { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +.animate-shitaye-logo { + animation: shitaye-logo-breathe 2.4s ease-in-out infinite; +} + +.animate-shitaye-ring { + animation: shitaye-logo-ring 12s linear infinite; +} diff --git a/src/app/page.tsx b/src/app/page.tsx index f334e9c..809dd36 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -4,6 +4,7 @@ import { AmenityItem } from "@/components/AmenityItem"; import { BookingSearchWidget } from "@/components/BookingSearchWidget"; import { OutletCard } from "@/components/OutletCard"; import { RoomCard } from "@/components/RoomCard"; +import { GoogleMapEmbed } from "@/components/GoogleMapEmbed"; import { VirtualTourBlock } from "@/components/VirtualTourBlock"; import { roomAmenities } from "@/lib/mocks/amenities"; import { bookingStyleReviews } from "@/lib/mocks/bookingReviews"; @@ -64,10 +65,11 @@ export default function HomePage() { Guest trust

- What guests say before they book + What our guests say after their stay

- Real feedback from recent stays helps new visitors book directly with confidence. + Honest reviews from people who’ve stayed with us — so you can book directly with + confidence.

-
-
-
-

- About us -

-

- Geo-convenient. Unmistakably Shitaye. -

-

- Close to key places of attraction and major businesses or institutions — your base - for work, culture, and rest. Begin your journey with us. -

- - View rooms - -
-
-
- Shitaye Suite Hotel lobby and lounge -
-
- Luxury suite interior +
+
+
+
+

+ Find us +

+

+ Location & directions +

+

+ {siteConfig.address}. Search “Shitaye Suite Hotel” on Google Maps or use + the map below. +

+
+
@@ -171,6 +172,29 @@ export default function HomePage() {
+
+
+
+

+ Spa & gym +

+

+ Treatments & fitness sessions +

+

+ Browse our spa menu and gym add-ons — build a mock selection and send a request from the + dedicated services page. +

+
+ + View spa & gym services + +
+
+
+
+
+
+

+ About us +

+

+ Geo-convenient. Unmistakably Shitaye. +

+

+ Close to key places of attraction and major businesses or institutions — your base + for work, culture, and rest. Begin your journey with us. +

+ + View rooms + +
+
+
+ Shitaye Suite Hotel lobby and lounge +
+
+ Luxury suite interior +
+
+
+
+

All rooms include

diff --git a/src/app/services/ServicesPageClient.tsx b/src/app/services/ServicesPageClient.tsx new file mode 100644 index 0000000..fb573fc --- /dev/null +++ b/src/app/services/ServicesPageClient.tsx @@ -0,0 +1,283 @@ +"use client"; + +import Image from "next/image"; +import Link from "next/link"; +import { useMemo, useState } from "react"; +import { + spaGymFilters, + spaGymServices, + type SpaGymFilterId, + type SpaGymService, +} from "@/lib/mocks/services"; +import { siteConfig } from "@/lib/mocks/site"; + +function ServiceCard({ + service, + selected, + onToggle, +}: { + service: SpaGymService; + selected: boolean; + onToggle: () => void; +}) { + const kindLabel = service.kind === "spa" ? "Spa" : "Gym"; + + return ( +
+
+ +
+ + {kindLabel} + + + ${service.priceUsd} + · {service.priceNote} + +
+
+

+ {service.duration} +

+

+ {service.title} +

+

+ {service.description} +

+ +
+
+ ); +} + +function SelectionPanel({ + items, + onRemove, + onClear, +}: { + items: SpaGymService[]; + onRemove: (id: string) => void; + onClear: () => void; +}) { + const total = useMemo( + () => items.reduce((sum, s) => sum + s.priceUsd, 0), + [items], + ); + + return ( +
+

+ Your selection +

+

+ Mock basket — pick services to preview a request (no real payment). +

+ + {items.length === 0 ? ( +

+ Tap “Add to selection” on any spa or gym service to build your list. +

+ ) : ( +
    + {items.map((s) => ( +
  • +
    +

    {s.title}

    +

    + {s.kind === "spa" ? "Spa" : "Gym"} · {s.duration} +

    +
    +
    + ${s.priceUsd} + +
    +
  • + ))} +
+ )} + + {items.length > 0 ? ( +
+
+ Subtotal (mock) + + ${total.toFixed(0)} + +
+
+ `- ${s.title} ($${s.priceUsd})`).join("\n")}\n\nTotal (estimate): $${total}`, + )}`} + className="btn-mustard px-4 py-3 text-center text-sm" + > + Email request + + +
+
+ ) : null} +
+ ); +} + +export function ServicesPageClient() { + const [filter, setFilter] = useState("all"); + const [selected, setSelected] = useState>(new Set()); + + const filtered = useMemo(() => { + if (filter === "all") return spaGymServices; + return spaGymServices.filter((s) => s.kind === filter); + }, [filter]); + + const selectedItems = useMemo( + () => spaGymServices.filter((s) => selected.has(s.id)), + [selected], + ); + + function toggle(id: string) { + setSelected((prev) => { + const next = new Set(prev); + if (next.has(id)) next.delete(id); + else next.add(id); + return next; + }); + } + + function remove(id: string) { + setSelected((prev) => { + const next = new Set(prev); + next.delete(id); + return next; + }); + } + + function clear() { + setSelected(new Set()); + } + + return ( +
+
+
+ +

+ Spa & gym services +

+

+ Choose treatments and gym sessions — your selection is shown on the right (desktop) or + below on mobile. This is a demo flow; confirm times and pricing at the desk. +

+

+ Taxes and service charges may apply. Prices shown in USD (mock). +

+
+
+ +
0 ? "pb-28 lg:pb-14" : ""}`} + > +
+ {spaGymFilters.map((f) => { + const active = filter === f.id; + return ( + + ); + })} +
+ +
+
+ {filtered.map((service) => ( + toggle(service.id)} + /> + ))} +
+ + +
+ + {/* Mobile sticky summary bar */} + {selectedItems.length > 0 ? ( +
+
+

+ {selectedItems.length}{" "} + selected +

+ + Email request + +
+
+ ) : null} +
+
+ ); +} diff --git a/src/app/services/loading.tsx b/src/app/services/loading.tsx new file mode 100644 index 0000000..eba66db --- /dev/null +++ b/src/app/services/loading.tsx @@ -0,0 +1,9 @@ +import { ShitayeLogoLoader } from "@/components/ShitayeLogoLoader"; + +export default function ServicesLoading() { + return ( +
+ +
+ ); +} diff --git a/src/app/services/page.tsx b/src/app/services/page.tsx new file mode 100644 index 0000000..3033cc0 --- /dev/null +++ b/src/app/services/page.tsx @@ -0,0 +1,12 @@ +import type { Metadata } from "next"; +import { ServicesPageClient } from "./ServicesPageClient"; + +export const metadata: Metadata = { + title: "Spa & gym services", + description: + "Browse spa treatments and gym sessions at Shitaye Suite Hotel — build a mock selection and send a request.", +}; + +export default function ServicesPage() { + return ; +} diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index 4ad6cba..f1cf9d5 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -1,3 +1,4 @@ +import Image from "next/image"; import Link from "next/link"; import { siteConfig } from "@/lib/mocks/site"; @@ -10,9 +11,25 @@ export function Footer() {
-

{siteConfig.name}

-

{siteConfig.address}

-

{siteConfig.city}, Ethiopia

+ Shitaye Suite Hotel +

{siteConfig.address}

+

{siteConfig.city}, Ethiopia

+

+ + Directions on Google Maps + +

@@ -128,6 +145,11 @@ export function Footer() { Rooms +
  • + + Spa & gym services + +
  • Gym & Spa @@ -138,6 +160,11 @@ export function Footer() { Dining
  • +
  • + + Location & map + +
  • Serenity meeting room diff --git a/src/components/GoogleMapEmbed.tsx b/src/components/GoogleMapEmbed.tsx new file mode 100644 index 0000000..2504627 --- /dev/null +++ b/src/components/GoogleMapEmbed.tsx @@ -0,0 +1,22 @@ +import { siteConfig } from "@/lib/mocks/site"; + +/** + * Google Maps embed (search result for the hotel). Uses the same pattern as + * Maps “Share → Embed” without requiring an API key. + */ +export function GoogleMapEmbed({ className = "" }: { className?: string }) { + return ( +
    +