ss
@@ -0,0 +1,5 @@
|
||||
.git
|
||||
node_modules
|
||||
.next
|
||||
.env*
|
||||
README.md
|
||||
@@ -0,0 +1,41 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/versions
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# env files (can opt-in for committing if needed)
|
||||
.env*
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
@@ -0,0 +1,89 @@
|
||||
# Deployment Rehberi — demo.ayristech.com
|
||||
|
||||
## Yerel Geliştirme
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
# → http://localhost:3000/dogan-tip-merkezi
|
||||
```
|
||||
|
||||
## Yeni Demo Eklemek
|
||||
|
||||
`data/demos.ts` dosyasına yeni kayıt ekle:
|
||||
|
||||
```ts
|
||||
"yeni-klinik": {
|
||||
slug: "yeni-klinik",
|
||||
template: "klinik",
|
||||
firma: {
|
||||
adi: "Yeni Klinik",
|
||||
slogan: "...",
|
||||
sehir: "İstanbul",
|
||||
renkAna: "#0ea5e9", // Ana renk
|
||||
renkKoyu: "#0284c7", // Hover rengi
|
||||
renkAcik: "#e0f2fe", // Açık arka plan
|
||||
...
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Kaydettikten sonra → `demo.ayristech.com/yeni-klinik` otomatik canlı olur.
|
||||
|
||||
---
|
||||
|
||||
## Coolify ile Deploy
|
||||
|
||||
### 1. GitHub'a Push
|
||||
```bash
|
||||
git init && git add . && git commit -m "init"
|
||||
git remote add origin https://github.com/KULLANICI/demo-ayristech.git
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
### 2. Coolify Ayarları
|
||||
- **Source:** GitHub repo
|
||||
- **Build Pack:** Dockerfile
|
||||
- **Port:** 3000
|
||||
- **Domain:** demo.ayristech.com
|
||||
|
||||
### 3. Environment Variables (gerekirse)
|
||||
```
|
||||
NODE_ENV=production
|
||||
NEXT_TELEMETRY_DISABLED=1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cloudflare Pages ile Deploy (Alternatif)
|
||||
|
||||
`next.config.ts` içinde output'u değiştir:
|
||||
```ts
|
||||
output: "export" // standalone yerine
|
||||
```
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
# Çıktı: /out klasörü → Cloudflare Pages'e yükle
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Demo Tracking (Bildirim Sistemi)
|
||||
|
||||
`components/templates/KlinikTemplate.tsx` içindeki tracking comment'ini
|
||||
gerçek webhook'a çevir:
|
||||
|
||||
```ts
|
||||
// Demo tracking
|
||||
useEffect(() => {
|
||||
fetch("/api/track", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ slug: data.slug, ts: Date.now() })
|
||||
});
|
||||
}, []);
|
||||
```
|
||||
|
||||
`app/api/track/route.ts` oluştur → n8n veya Make.com webhook'una ilet →
|
||||
WhatsApp bildirimi gel.
|
||||
@@ -0,0 +1,55 @@
|
||||
# 1. Base image
|
||||
FROM node:20-alpine AS base
|
||||
|
||||
# 2. Dependencies
|
||||
FROM base AS deps
|
||||
RUN apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies based on the preferred package manager
|
||||
COPY package.json package-lock.json* ./
|
||||
RUN npm ci --legacy-peer-deps
|
||||
|
||||
|
||||
# 3. Builder
|
||||
FROM base AS builder
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
# Environment variables must be present at build time for Next.js
|
||||
# Coolify will provide these, but we can set defaults
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
RUN npm run build
|
||||
|
||||
# 4. Runner
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
||||
|
||||
# Set the correct permission for prerender cache
|
||||
RUN mkdir .next
|
||||
RUN chown nextjs:nodejs .next
|
||||
|
||||
# Automatically leverage output traces to reduce image size
|
||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENV PORT=3000
|
||||
# set hostname to localhost
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
@@ -0,0 +1,102 @@
|
||||
# Instagram 1x3 Grid Post — Yeni Müşteri Duyurusu
|
||||
### Ayris Tech — Nano Banana Prompt
|
||||
|
||||
---
|
||||
|
||||
## Değişkenleri Doldur
|
||||
|
||||
```
|
||||
FİRMA_ADI =
|
||||
SEKTÖR =
|
||||
ŞEHİR =
|
||||
YAPILAN_İŞ =
|
||||
```
|
||||
|
||||
**Örnekler:**
|
||||
- `FİRMA_ADI` → Gufo Gastro
|
||||
- `SEKTÖR` → Restoran & Bar
|
||||
- `ŞEHİR` → Muğla
|
||||
- `YAPILAN_İŞ` → Web Sitesi & Rezervasyon Sistemi
|
||||
|
||||
---
|
||||
|
||||
## Nano Banana Prompt
|
||||
|
||||
> Aşağıdaki metni kopyala, büyük harfli yerleri doldur, Nano Banana'ya gönder.
|
||||
|
||||
---
|
||||
|
||||
Create a premium Instagram 1x3 grid post (three 1080x1080 panels that form one seamless panoramic image when placed side by side on a profile grid).
|
||||
|
||||
**Brand:** Ayris Tech — a modern digital agency based in Turkey.
|
||||
**Announcement:** New client partnership with **[FİRMA_ADI]**, a **[SEKTÖR]** business from **[ŞEHİR]**. We are building their **[YAPILAN_İŞ]**.
|
||||
|
||||
---
|
||||
|
||||
**Visual Style:**
|
||||
- Background: deep navy-black `#080810`
|
||||
- Accent: violet `#7C3AED` flowing into cyan `#06B6D4` as a gradient
|
||||
- Typography: bold, modern sans-serif (Inter or similar)
|
||||
- Subtle film grain texture overlay at 4% opacity
|
||||
- No people, no stock photos — abstract geometric shapes and light leaks only
|
||||
- Overall feel: Awwwards-level tech agency, dark luxury, editorial
|
||||
|
||||
---
|
||||
|
||||
**Panel 1 — Client (left):**
|
||||
- Small all-caps label: `YENİ İŞ BİRLİĞİ`
|
||||
- Large bold text: `[FİRMA_ADI]`
|
||||
- Below: `[SEKTÖR] · [ŞEHİR]`
|
||||
- Visual element: soft glow blob in the client's industry color (warm amber for restaurant, teal for health, etc.)
|
||||
- Gradient edge on the right side blending into Panel 2
|
||||
|
||||
**Panel 2 — Hero message (center):**
|
||||
- This is the most eye-catching panel
|
||||
- Giant gradient text (violet→cyan): `HOŞGELDIN`
|
||||
- Smaller text below: `Dijital dönüşüm yolculuğu başlıyor`
|
||||
- Strong centered layout, lots of breathing room
|
||||
- Glowing radial light in the background
|
||||
- Seamlessly connects to Panel 1 on the left and Panel 3 on the right
|
||||
|
||||
**Panel 3 — Ayris Tech (right):**
|
||||
- Small all-caps label: `AYRIS TECH`
|
||||
- Work description: `[YAPILAN_İŞ]`
|
||||
- Bottom: `ayristech.com`
|
||||
- Visual element: subtle geometric grid pattern or the letter "A" as a large faint watermark
|
||||
- Gradient edge on the left side blending from Panel 2
|
||||
|
||||
---
|
||||
|
||||
**Continuity rule:** When all three panels are placed side by side, the gradient flows seamlessly from left to right across all panels — violet on the far left, mixed in the center, cyan on the far right. Each panel must also look complete and intentional on its own.
|
||||
|
||||
**Output:** Deliver as 3 separate square images (1080x1080px each), labeled Panel_1, Panel_2, Panel_3. Also deliver one combined panoramic preview (3240x1080px).
|
||||
|
||||
---
|
||||
|
||||
## Caption (Kopyala Yapıştır)
|
||||
|
||||
```
|
||||
[FİRMA_ADI] ile yeni bir yolculuğa çıkıyoruz 🚀
|
||||
|
||||
[SEKTÖR] alanında güçlü bir isim olan [FİRMA_ADI]'nın
|
||||
dijital kimliğini birlikte inşa ediyoruz.
|
||||
|
||||
→ [YAPILAN_İŞ]
|
||||
→ [ŞEHİR]'den dünyaya
|
||||
|
||||
#AyrisTech #WebTasarım #Dijital #[SEKTÖR]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Hızlı Referans — Sektöre Göre Renk
|
||||
|
||||
| Sektör | Glow Rengi |
|
||||
|---|---|
|
||||
| Restoran / Bar | `#F97316` (turuncu-amber) |
|
||||
| Otel / Resort | `#14B8A6` (teal) |
|
||||
| Klinik / Sağlık | `#0EA5E9` (mavi) |
|
||||
| Mimari / İnşaat | `#94A3B8` (slate) |
|
||||
| Teknoloji / SaaS | `#A78BFA` (violet) |
|
||||
| Taksi / Ulaşım | `#F5C518` (sarı) |
|
||||
| Hukuk / Finans | `#6366F1` (indigo) |
|
||||
@@ -0,0 +1,156 @@
|
||||
# SCC Enerji — Antigravity Design Prompt
|
||||
|
||||
---
|
||||
|
||||
## demos.ts Verisi
|
||||
|
||||
```typescript
|
||||
{
|
||||
slug: "scc-enerji",
|
||||
template: "enerji", // YENİ ŞABLON — aşağıda tarif edildi
|
||||
firma: {
|
||||
adi: "SCC Enerji",
|
||||
slogan: "Yeşil Enerji, Yeşil Dünya",
|
||||
sehir: "Ankara / İstanbul",
|
||||
adres: "Söğütözü Mah. Söğütözü Cad. No:2/A Çankaya, Ankara",
|
||||
adres2: "Yenişehir Mah. Millet Cad. No:4/19 Pendik, İstanbul",
|
||||
telefon: "0 (312) 945 04 24",
|
||||
email: "info@sccenerji.com",
|
||||
logoEmoji: "⚡",
|
||||
renkAna: "#2E7D32", // koyu yeşil (mevcut sitenin ana rengi)
|
||||
renkKoyu: "#1B5E20", // derin orman yeşili
|
||||
renkAcik: "#E8F5E9", // soluk yeşil bg
|
||||
renkVurgu: "#76FF03", // elektrik yeşili — enerji hissi için accent
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "16+", etiket: "Uluslararası Proje" },
|
||||
{ deger: "14", etiket: "Yıllık Deneyim" },
|
||||
{ deger: "7+", etiket: "Ülkede Aktif" },
|
||||
{ deger: "500+", etiket: "Desteklenen Firma" },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "🌱", baslik: "Yenilenebilir Enerji", aciklama: "Güneş, rüzgar ve biyokütle enerji sistemleri kurulum ve danışmanlığı" },
|
||||
{ ikon: "♻️", baslik: "Sürdürülebilirlik Danışmanlığı", aciklama: "Şirketlerin karbon ayak izi hesaplama ve azaltma stratejileri" },
|
||||
{ ikon: "📋", baslik: "Sertifikasyon & Fon", aciklama: "KOSGEB, TÜBİTAK, World Bank ve AB fon başvuru yönetimi" },
|
||||
{ ikon: "🎯", baslik: "NET Zero Karbon", aciklama: "2050 hedefleri doğrultusunda net sıfır karbon yol haritası" },
|
||||
{ ikon: "💡", baslik: "Dijital Dönüşüm & Yeşil Markalaşma", aciklama: "Kurumsal yeşil kimlik ve ESG raporlama" },
|
||||
{ ikon: "🏗️", baslik: "Kurumsal Mühendislik", aciklama: "Endüstriyel tesis ve altyapı için sürdürülebilirlik çözümleri" },
|
||||
],
|
||||
fonlar: [
|
||||
"KOSGEB", "TÜBİTAK", "World Bank", "Enerji Bakanlığı 1832/1833 VAP", "AB Fonları"
|
||||
],
|
||||
projeler: [
|
||||
{ ulke: "Bulgaristan", alan: "Yenilenebilir Enerji" },
|
||||
{ ulke: "Abu Dhabi", alan: "Sürdürülebilirlik" },
|
||||
{ ulke: "Danimarka", alan: "Net Zero" },
|
||||
{ ulke: "Kenya", alan: "Enerji Altyapısı" },
|
||||
{ ulke: "Hırvatistan", alan: "AB Fon Yönetimi" },
|
||||
{ ulke: "Almanya", alan: "Yeşil Markalaşma" },
|
||||
],
|
||||
yonetim: {
|
||||
ceo: "Serdar Kayhan",
|
||||
deneyim: "14 yıl",
|
||||
unvan: "Kurucu & CEO",
|
||||
},
|
||||
yorumlar: [
|
||||
{ yazar: "Ahmet Kara", unvan: "Fabrika Müdürü", yorum: "SCC Enerji sayesinde tesisimizin karbon emisyonunu %40 düşürdük ve TÜBİTAK hibesi aldık.", puan: 5, tarih: "2024", emoji: "🏭" },
|
||||
{ yazar: "Zeynep Arslan", unvan: "CFO, Lojistik Firması", yorum: "ESG raporlaması ve yeşil sertifikasyon sürecinde mükemmel bir rehberlik aldık.", puan: 5, tarih: "2024", emoji: "📊" },
|
||||
{ yazar: "Mehmet Yılmaz", unvan: "Genel Müdür, İnşaat", yorum: "AB fon başvurumuz SCC Enerji'nin desteğiyle onaylandı. Sonuç inanılmaz.", puan: 5, tarih: "2023", emoji: "🏗️" },
|
||||
],
|
||||
sosyal: {
|
||||
twitter: true,
|
||||
instagram: true,
|
||||
youtube: true,
|
||||
linkedin: true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mevcut Site Analizi
|
||||
|
||||
- **Platform:** WordPress (Caria Digital yapımı), eski, JS-rendered hero slider (yüklenmiyor)
|
||||
- **Renk paleti:** Beyaz zemin + koyu yeşil aksant
|
||||
- **His:** Kurumsal ama donuk — animasyon yok, fotoğraflar stock, hiyerarşi zayıf
|
||||
- **Güçlü yan:** İçerik zengin (6 hizmet, 16+ proje, fon listesi, CEO bilgisi)
|
||||
- **Dönüşüm fırsatı:** Bu firma Awwwards-level bir enerji sitesi hak ediyor — Tesla Energy veya Vestas seviyesi
|
||||
|
||||
---
|
||||
|
||||
## Antigravity Komutu
|
||||
|
||||
Aşağıdaki metni kopyala, Antigravity'e gönder:
|
||||
|
||||
---
|
||||
|
||||
TEMPLATE_BRIEF.md dosyasındaki tüm kurallara uy. Şimdi `EnerjiTemplate` adında yeni bir şablon yazıyoruz.
|
||||
|
||||
**Firma:** SCC Enerji — Ankara & İstanbul merkezli, 16+ uluslararası proje yapmış yenilenebilir enerji ve sürdürülebilirlik danışmanlık şirketi.
|
||||
|
||||
**Demos.ts verisi:** (Yukarıdaki TypeScript objesini yapıştır)
|
||||
|
||||
---
|
||||
|
||||
### İMZA MOMENT — Zorunlu
|
||||
|
||||
**"Enerji Akışı Parallax"**
|
||||
|
||||
Hero section'da tam ekran koyu arkaplan (`#030A03` — saf gece siyahı, yeşil tonu ile).
|
||||
Üzerinde **SVG parçacık ağı** — ince çizgilerle birbirine bağlı noktalar, mouse hareketi ile etkileşimli.
|
||||
Sayfa yüklenince büyük başlık kelime kelime yukarıdan düşer: **"YEŞİL ENERJİ"** — devasa, beyaz, cesur.
|
||||
Hemen altında elektrik yeşili (`#76FF03`) ince bir yatay çizgi soldan sağa çizilir (stroke animation, 1.2s).
|
||||
Bu çizginin altında küçük ve ince font ile: *"Sürdürülebilir geleceğin mühendisleri"*
|
||||
|
||||
Hero CTA butonu: yeşil outline, hover'da içi dolup metin rengi siyah olur (fill animation).
|
||||
|
||||
---
|
||||
|
||||
### Renk Paleti
|
||||
|
||||
```
|
||||
Arkaplan (hero): #030A03 — neredeyse siyah, yeşil tonu
|
||||
Arkaplan (sections): #F0F7F0 — çok açık yeşil beyaz (nefes verir)
|
||||
Ana yeşil: #2E7D32
|
||||
Koyu yeşil: #1B5E20
|
||||
Elektrik vurgu: #76FF03 — sadece accent olarak, aşırı kullanma
|
||||
Metin (açık bg): #0A1A0A
|
||||
Metin (koyu bg): #FFFFFF
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Section Sırası
|
||||
|
||||
1. **Hero** — imza moment (yukarıda tarif edildi), fullscreen, parçacık ağı
|
||||
2. **İstatistikler** — koyu arkaplan `#0A1A0A`, 4 sayaç yan yana, scroll-triggered AnimatedCounter
|
||||
3. **Hizmetler** — açık arkaplan, 6 kart, hover'da sol kenar `#76FF03` renk geçişi + kart hafifçe yukarı kalkar
|
||||
4. **Fon & Destek Logolar** — "Bu fonları size biz getirebiliriz" başlığı, 5 fon logosu/etiketi yatay sıra, subtle marquee animasyon
|
||||
5. **Küresel Projeler** — dünya haritası SVG üzerinde noktalar (Bulgaristan, Abu Dhabi, Danimarka, Kenya, Hırvatistan, Almanya, Adana) — Framer Motion ile tek tek belirir
|
||||
6. **CEO / Hakkımızda** — yarım bölüm metin + yarım büyük fotoğraf (placeholder), CEO quote büyük ve italik
|
||||
7. **Referanslar** — 3 yorum kartı, subtle yeşil border
|
||||
8. **İletişim** — iki adres (Ankara + İstanbul) yan yana, telefon ve e-posta, form
|
||||
9. **Footer** — sosyal medya ikonları, ince elektrik yeşili accent çizgisi
|
||||
|
||||
---
|
||||
|
||||
### Teknik Gereksinimler
|
||||
|
||||
- Next.js 14 App Router, TypeScript strict
|
||||
- Framer Motion v11 — `useInView`, `staggerChildren`, `viewport: { once: true }`
|
||||
- Lenis smooth scroll (TEMPLATE_BRIEF'teki setup kodu ile)
|
||||
- Tailwind CSS v3 — custom colors `energyGreen`, `electricLime` olarak `tailwind.config.ts`'e ekle
|
||||
- SVG parçacık ağı için vanilla JS Canvas veya basit CSS dots grid de kabul edilir
|
||||
- AnimatedCounter component'ini kullanan istatistik section
|
||||
- Komponent: `components/templates/EnerjiTemplate/index.tsx`
|
||||
- Routing: `app/[slug]/page.tsx`'e `if (data.template === "enerji") return <EnerjiTemplate data={data} />;` ekle
|
||||
- `data/demos.ts`'e interface ve veri ekle
|
||||
|
||||
---
|
||||
|
||||
### Kalite Hedefi
|
||||
|
||||
Bitince tarayıcıda açtığında şunu hissettirmeli:
|
||||
**"Bu Tesla Energy'nin Türk versiyonu gibi görünüyor."**
|
||||
|
||||
Eğer "idare eder" diyorsan — yeniden başla.
|
||||
@@ -0,0 +1,416 @@
|
||||
# Şablon Tasarım Rehberi
|
||||
### Ayris Tech — Premium Demo Sistemi
|
||||
|
||||
---
|
||||
|
||||
## Görevin
|
||||
|
||||
Potansiyel müşterilere gönderilecek demo siteleri için sektöre özel Next.js şablonları yazıyorsun.
|
||||
|
||||
Öncelik sırası: **1. Tasarım ve his → 2. Animasyon → 3. İçerik → 4. Teknik detaylar**
|
||||
|
||||
Müşteri linke tıkladığında ilk 3 saniyede "bu benim için yapılmış, bu çok pahalı görünüyor" hissini yaşamalı. Kod çalışıyor mu çalışmıyor mu ikinci plandır — önce göz kamaştır.
|
||||
|
||||
---
|
||||
|
||||
## Tasarım Felsefesi
|
||||
|
||||
### "Oha" Anı Zorunludur
|
||||
|
||||
Her şablonun sayfaya girince insanı duraksatan **bir imza momenti** olmalı. Bu an tasarlanmış, hesaplanmış, sektöre özgün olmalı. Genel bir animasyon değil — o sektörün ruhunu yansıtan bir hareket.
|
||||
|
||||
Referans seviye: **Awwwards Site of the Day**. Hedef his: "Bu siteyi kim yaptı, nasıl yaptı?"
|
||||
|
||||
### Tasarım Kararlarında Öncelik Sırası
|
||||
|
||||
```
|
||||
1. Boşluk ve nefes — section'lar arası ritim, padding cömertliği
|
||||
2. Tipografi gücü — başlıklar cesur ve büyük, hiyerarşi net
|
||||
3. Fotoğraf kalitesi — her fotoğraf kompozisyon düşünülerek seçilmeli
|
||||
4. Renk disiplini — max 2-3 renk, geri kalanı siyah/beyaz/gri
|
||||
5. Hareket kalitesi — az animasyon ama her biri mükemmel
|
||||
6. Detay titizliği — hover state'ler, geçişler, micro-interaction'lar
|
||||
```
|
||||
|
||||
### Nasıl Düşünmeli
|
||||
|
||||
Görseller verildiğinde şunu sor: **"Bu tasarımı 10.000 USD'ye satan ajans ne hissettirdi?"**
|
||||
|
||||
- Boşlukla mı ezdi? (luxury whitespace)
|
||||
- Tipografiyle mi şok etti? (devasa başlık, küçük body)
|
||||
- Fotoğrafla mı sardı? (fullscreen, parallax, overlay)
|
||||
- Hareketle mi büyüledi? (curtain, reveal, magnetic)
|
||||
- Detayla mı ikna etti? (custom cursor, subtle grain, line animation)
|
||||
|
||||
Cevap hangisi ise — oradan başla, diğerlerini o etrafına kur.
|
||||
|
||||
---
|
||||
|
||||
## İmza Moment Kütüphanesi
|
||||
|
||||
Her şablona aşağıdakilerden **en az bir** tane koy. Birden fazla koyacaksan aralarına yeterli "sessizlik" bırak.
|
||||
|
||||
### Sayfa Açılışı
|
||||
- **Curtain reveal** — siyah ekran ortadan ikiye ayrılır, fotoğraf ortaya çıkar
|
||||
- **Preloader çizgi** — ince bir çizgi soldan sağa ilerler, logo belirir, sahne açılır
|
||||
- **Staggered text entrance** — başlık kelime kelime veya karakter karakter düşer
|
||||
- **Scale-up reveal** — küçük merkezi bir görsel tam ekrana açılır
|
||||
|
||||
### Scroll Animasyonları
|
||||
- **Parallax hero** — scroll ettikçe fotoğraf daha yavaş iner, metin daha hızlı çıkar
|
||||
- **Sticky + akan metin** — fotoğraf sabit kalır, metin onun üzerinden akar
|
||||
- **Horizontal scroll bölüm** — kartlar/menü yatay ilerler, mouse/touch ile sürüklenir
|
||||
- **Pinned section** — section scroll boyunca sabit kalır, içeriği değişir (tablar gibi)
|
||||
- **Text scale on scroll** — başlık küçükten büyüğe veya büyükten küçüğe dönüşür
|
||||
|
||||
### Hover & Mikro
|
||||
- **Magnetic buton** — mouse yaklaştıkça buton sana doğru çekilir
|
||||
- **Custom cursor** — varsayılan cursor kaybolur, markaya özgü daire/metin gelir
|
||||
- **Image tilt** — kart hover'ında 3D perspektif eğimi (rotateX/Y)
|
||||
- **Clip-path reveal** — fotoğraf hover'da yukarıdan aşağı açılır
|
||||
- **Underline draw** — link hover'ında çizgi soldan sağa çizilir
|
||||
|
||||
### Atmosfer
|
||||
- **Scrolling marquee** — sonsuz döngü metin bandı (iki yönde farklı hızda olursa daha iyi)
|
||||
- **Grain texture overlay** — tüm sayfa üstünde ince film grain (opacity 0.03-0.06)
|
||||
- **Ambient glow** — arka planda renk blobları yavaşça hareket eder
|
||||
- **Video loop** — hero'da sessiz, döngü video (restoran, otel için)
|
||||
|
||||
---
|
||||
|
||||
## Tipografi Kuralları
|
||||
|
||||
Pahalı hissinin %40'ı tipografiden gelir.
|
||||
|
||||
```
|
||||
Başlık boyutu: clamp(48px, 8vw, 120px) — küçük ekranda küçülür, büyük ekranda büyür
|
||||
Body boyutu: 16px minimum, 18px ideal
|
||||
Satır yüksekliği: başlıklarda 0.9-1.0, body'de 1.6-1.8
|
||||
Harf aralığı: büyük harf başlıklarda tracking-widest, serif başlıklarda -0.02em
|
||||
```
|
||||
|
||||
**Font kombinasyonları (sektöre göre):**
|
||||
- Otel/Butik/Restoran → Playfair Display (serif) + Inter (sans) — klasik lüks
|
||||
- Mimari/Kurumsal → Inter Black + Inter Regular — modern güç
|
||||
- Bar/Gastro → Cormorant Garamond + Space Grotesk — sofistike
|
||||
- Klinik/SaaS → DM Sans veya Sora + monospace detay — temiz güven
|
||||
|
||||
Başlık tek satırda yoksa **satır kırılmalarını elle kontrol et** — otomatik kırılma çirkin görünür.
|
||||
|
||||
---
|
||||
|
||||
## Renk ve Atmosfer Kuralları
|
||||
|
||||
### Koyu Tema (restoran, bar, otel, gastro)
|
||||
- Arka plan: `#080810` veya `#0a0a0a` — tam siyah değil, hafif tonlu
|
||||
- Metin: `#ffffff` + `rgba(255,255,255,0.5)` ikincil
|
||||
- Aksant: firmanın ana rengi — sadece CTA, badge, vurgu için
|
||||
- Fotoğraflar üstünde: `rgba(0,0,0,0.3-0.5)` overlay — direkt koymadan
|
||||
|
||||
### Açık Tema (klinik, mimari, kurumsal, butik)
|
||||
- Arka plan: `#ffffff` veya `#f8f7f4` (hafif warm) veya `#f5f0e8` (krem)
|
||||
- Metin: `#0a0a0a` veya `#1a1a1a`
|
||||
- Aksant: firmanın ana rengi
|
||||
- İkincil yüzeyler: `#f0f0f0` veya `rgba(0,0,0,0.04)`
|
||||
|
||||
### Renk Disiplini
|
||||
- Ana renk: butonlar, başlık vurgusu, badge, aktif state
|
||||
- İkincil renk: hover state, border, gradient ikinci noktası
|
||||
- Nötr: arka planlar, kartlar, ayırıcılar
|
||||
- **Başka renk yok.** Emoji veya ikonlar nötr tutulur.
|
||||
|
||||
---
|
||||
|
||||
## Fotoğraf Kullanımı
|
||||
|
||||
Fotoğraflar kod kadar önemli. Kötü fotoğraf iyi tasarımı mahveder.
|
||||
|
||||
**Unsplash koleksiyonları (sektöre göre):**
|
||||
- Otel/Resort: `https://source.unsplash.com/1920x1080/?luxury,hotel,resort`
|
||||
- Restoran: `https://source.unsplash.com/1920x1080/?restaurant,food,gastronomy`
|
||||
- Bar: `https://source.unsplash.com/1920x1080/?cocktail,bar,dark`
|
||||
- Mimari: `https://source.unsplash.com/1920x1080/?architecture,interior,modern`
|
||||
- Klinik: `https://source.unsplash.com/1920x1080/?clinic,medical,clean`
|
||||
|
||||
**Kurallar:**
|
||||
- Hero fotoğrafı her zaman `object-cover` + `object-position: center`
|
||||
- Dikey fotoğraflar (portrait) kart içinde daha dramatik görünür — kullan
|
||||
- Birden fazla fotoğraf varsa renk tonu tutarlı olsun (hepsi sıcak veya hepsi soğuk)
|
||||
- `picsum.photos` sadece hızlı test için — final görünümde Unsplash parametreli URL kullan
|
||||
|
||||
---
|
||||
|
||||
## Animasyon Kalitesi
|
||||
|
||||
### Easing Değerleri
|
||||
```typescript
|
||||
// Smooth deceleration — genel kullanım
|
||||
ease: [0.25, 0.46, 0.45, 0.94] as [number,number,number,number]
|
||||
|
||||
// Dramatic entrance — hero başlıklar
|
||||
ease: [0.16, 1, 0.3, 1] as [number,number,number,number]
|
||||
|
||||
// Snappy — buton, badge, küçük elementler
|
||||
ease: [0.34, 1.56, 0.64, 1] as [number,number,number,number]
|
||||
|
||||
// Linear — marquee, döngüler
|
||||
ease: "linear"
|
||||
```
|
||||
|
||||
### Süre Kuralları
|
||||
```
|
||||
Micro (hover, badge): 0.15-0.25s
|
||||
Element entrance: 0.6-0.8s
|
||||
Section transition: 0.8-1.0s
|
||||
Page reveal / curtain: 1.0-1.4s
|
||||
Marquee döngü: 20-40s (içerik uzunluğuna göre)
|
||||
```
|
||||
|
||||
### Stagger Ritmi
|
||||
```typescript
|
||||
// Çocuk sayısına göre stagger ayarla
|
||||
3-4 element: staggerChildren: 0.15
|
||||
5-8 element: staggerChildren: 0.08
|
||||
9+ element: staggerChildren: 0.05
|
||||
```
|
||||
|
||||
### Animasyon Monotonluğu Kırma
|
||||
Her section aynı `fadeUp` ile başlarsa sayfa uyutur. Karıştır:
|
||||
- Hero: curtain veya scale reveal
|
||||
- Stats: sayaç animasyonu (AnimatedCounter)
|
||||
- Kartlar: stagger + hafif x offset (soldan veya sağdan)
|
||||
- Galeri: clip-path veya opacity-only (y hareketi olmadan)
|
||||
- CTA section: parallax arka plan + metin fade
|
||||
|
||||
---
|
||||
|
||||
## Lenis Smooth Scroll Kurulumu
|
||||
|
||||
Her şablona ekle:
|
||||
|
||||
```typescript
|
||||
"use client";
|
||||
import { useEffect } from "react";
|
||||
|
||||
// Component içinde:
|
||||
useEffect(() => {
|
||||
let lenis: any;
|
||||
import("@studio-freight/lenis").then(({ default: Lenis }) => {
|
||||
lenis = new Lenis({ duration: 1.2, easing: (t: number) => Math.min(1, 1.001 - Math.pow(2, -10 * t)) });
|
||||
function raf(time: number) { lenis.raf(time); requestAnimationFrame(raf); }
|
||||
requestAnimationFrame(raf);
|
||||
});
|
||||
return () => lenis?.destroy();
|
||||
}, []);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Section Tasarım Standartları
|
||||
|
||||
### Hero
|
||||
- Her zaman viewport yüksekliği: `min-h-screen`
|
||||
- Fotoğraf varsa: `position: absolute, inset: 0, object-fit: cover` + koyu overlay
|
||||
- Başlık: clamp ile responsive, viewport'un %60-70'ini kaplamalı
|
||||
- CTA buton: tek, net, aksant renkli — ikinci buton varsa ghost/outline
|
||||
|
||||
### Marquee Bandı (opsiyonel ama etkili)
|
||||
Hero ile sonraki section arasına koy. İki yönde farklı iki satır daha güçlü görünür.
|
||||
|
||||
### İki Kolonlu (Split) Section
|
||||
```
|
||||
Sol: metin + CTA Sağ: tall fotoğraf (aspect-ratio: 3/4)
|
||||
Metin sola hizalı Fotoğraf slight overlap (negatif margin)
|
||||
```
|
||||
|
||||
### Kart Grid'leri
|
||||
- 3'lü grid: her kart eşit, hover'da `y: -8` ve border glow
|
||||
- Masonry: sadece galeri için — CSS columns veya css-grid ile
|
||||
- Horizontal scroll: `overflow-x: auto`, `scrollbar-width: none`, touch-action: pan-x
|
||||
|
||||
### CTA Section (Son Bölüm)
|
||||
En az bir kez tam genişlikte, fotoğraf arka planlı olsun. Başlık büyük, CTA tek.
|
||||
|
||||
---
|
||||
|
||||
## Tech Stack
|
||||
|
||||
```json
|
||||
{
|
||||
"zorunlu": [
|
||||
"Next.js 14 App Router",
|
||||
"Framer Motion v11",
|
||||
"Tailwind CSS v3",
|
||||
"TypeScript strict",
|
||||
"@studio-freight/lenis"
|
||||
],
|
||||
"gerektiğinde": [
|
||||
"Three.js / @react-three/fiber (sadece ambient bg için, performans dikkat)",
|
||||
"react-lottie-player (loading, boş state ikonları için)",
|
||||
"usehooks-ts (useWindowSize, useIntersectionObserver)"
|
||||
],
|
||||
"yasak": [
|
||||
"jQuery",
|
||||
"Bootstrap",
|
||||
"CSS @keyframes animasyonları (Framer Motion kullan)",
|
||||
"inline style ile animasyon (transform, opacity — Framer Motion kullan)"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Framer Motion zorunlu kurallar:**
|
||||
- `ease` array'leri her zaman type assertion: `as [number,number,number,number]`
|
||||
- Scroll animasyonları: `useScroll` + `useTransform`
|
||||
- Section girişleri: `whileInView` + `viewport={{ once: true }}`
|
||||
- Layout animasyonları: `layout` prop — yükseklik değişimlerinde kullan
|
||||
|
||||
---
|
||||
|
||||
## Kalite Kontrol Listesi
|
||||
|
||||
Kodu teslim etmeden önce şunları kontrol et:
|
||||
|
||||
**Tasarım:**
|
||||
- [ ] Sayfaya girince ilk 3 saniyede "oha" dedirten bir şey var mı?
|
||||
- [ ] Boşluklar cömert mi — hiçbir element birbirine yapışık değil mi?
|
||||
- [ ] Başlıklar yeterince büyük mü — yarım metre uzaktan okunabilir mi?
|
||||
- [ ] Renk disiplini korunuyor mu — max 3 renk var mı?
|
||||
- [ ] Fotoğraflar kompozisyon olarak uygun mu?
|
||||
|
||||
**Animasyon:**
|
||||
- [ ] Her section farklı animasyon mu kullanıyor (monotonluk yok)?
|
||||
- [ ] Easing değerleri sert mi yoksa yumuşak mı? (Sert olmamalı)
|
||||
- [ ] Lenis smooth scroll çalışıyor mu?
|
||||
- [ ] Hover state'lerin hepsi var mı?
|
||||
|
||||
**Detay:**
|
||||
- [ ] Demo banner sabit mi: `"Bu site demo amaçlıdır — demo.ayristech.com"`
|
||||
- [ ] Mobile'da layout bozulmuyor mu?
|
||||
- [ ] TypeScript hataları var mı (`any` yok)?
|
||||
|
||||
---
|
||||
|
||||
## Proje Yapısı
|
||||
|
||||
```
|
||||
demo-ayristech/
|
||||
├── app/
|
||||
│ ├── page.tsx # Showcase index
|
||||
│ └── [slug]/page.tsx # Dynamic routing
|
||||
├── components/
|
||||
│ └── templates/
|
||||
│ └── [SektörTemplate]/
|
||||
│ └── index.tsx # Her şablon kendi klasöründe
|
||||
├── data/
|
||||
│ └── demos.ts # Tüm demo verisi
|
||||
└── components/ui/
|
||||
└── AnimatedCounter.tsx # Scroll-triggered sayaç
|
||||
```
|
||||
|
||||
Yeni şablon eklerken:
|
||||
1. `components/templates/YeniTemplate/index.tsx` oluştur
|
||||
2. `data/demos.ts` interface'ine yeni sektör tipini ve alanları ekle
|
||||
3. `app/[slug]/page.tsx` routing'e `if (data.template === "yeni") return <YeniTemplate data={data} />;`
|
||||
4. `app/page.tsx` `templateLabels`'a yeni badge ekle
|
||||
|
||||
---
|
||||
|
||||
## Müşteri Sitesi SS Analizi
|
||||
|
||||
Sana müşterinin mevcut sitesinin ekran görüntüleri verildiğinde şu sırayla ilerle:
|
||||
|
||||
### 1. İçerik Çıkarımı
|
||||
|
||||
Her SS'den şunları çıkar:
|
||||
|
||||
| Alan | Nereden Bulunur |
|
||||
|---|---|
|
||||
| Firma adı | Header, logo yanı, title |
|
||||
| Slogan | Hero başlığı veya alt metin |
|
||||
| Şehir / Adres | Footer, iletişim sayfası |
|
||||
| Telefon | Header, footer, iletişim |
|
||||
| E-posta | Footer, iletişim sayfası |
|
||||
| Çalışma saatleri | Footer veya iletişim |
|
||||
| Hizmetler | Hizmetler/servisler/poliklinikler sayfası |
|
||||
| Ekip / Doktorlar | Kadro/hakkımızda sayfası |
|
||||
| Yorumlar / Referanslar | Varsa ana sayfa veya ayrı sayfa |
|
||||
| Sosyal medya | Footer veya header ikonları |
|
||||
|
||||
### 2. Mevcut Tasarımı Değerlendir
|
||||
|
||||
SS'lere bakarak kısaca not al:
|
||||
- **Renk paleti:** Mevcut ana renk nedir?
|
||||
- **Genel his:** Profesyonel mi, eski mi, amatör mü?
|
||||
- **Eksikler:** Animasyon yok, mobile bozuk, fotoğraf kalitesi kötü vb.
|
||||
- **Güçlü yanlar:** Korunabilecek bir şey var mı?
|
||||
|
||||
Bu değerlendirmeyi şablona yansıt — mevcut siteyi taklit etme, **dönüştür**.
|
||||
|
||||
### 3. demos.ts Formatında Çıkar
|
||||
|
||||
Analiz sonucunu aşağıdaki formatta hazırla, eksik alanları makul şekilde doldur:
|
||||
|
||||
```typescript
|
||||
{
|
||||
slug: "firma-adi", // firma adından türet, küçük harf, tire ile
|
||||
template: "klinik", // sektöre göre seç
|
||||
firma: {
|
||||
adi: "Firma Adı",
|
||||
slogan: "SS'den alınan slogan veya uygun bir slogan üret",
|
||||
sehir: "Şehir",
|
||||
adres: "Tam adres",
|
||||
telefon: "+90 ...",
|
||||
email: "info@...",
|
||||
logoEmoji: "🏥", // sektöre uygun emoji
|
||||
renkAna: "#______", // mevcut sitenin ana rengi
|
||||
renkKoyu: "#______", // daha koyu tonu
|
||||
renkAcik: "#______", // çok açık tonu (bg için)
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "15+", etiket: "Yıllık Deneyim" },
|
||||
// SS'de rakam varsa al, yoksa sektöre uygun üret
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "🔬", baslik: "Hizmet Adı", aciklama: "Kısa açıklama" },
|
||||
// SS'deki hizmetler sayfasından çek
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "Ad Soyad", yorum: "...", puan: 5, tarih: "2024", emoji: "👤" },
|
||||
// SS'de yoksa 3 adet gerçekçi yorum üret
|
||||
],
|
||||
// Sektöre özel alanlar — SS'den çek, yoksa üret
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Şablon Seçimi
|
||||
|
||||
Sektöre göre hangi şablonun kullanılacağına karar ver:
|
||||
|
||||
| Sektör | Şablon |
|
||||
|---|---|
|
||||
| Klinik, hastane, sağlık merkezi | `klinik` |
|
||||
| Diş kliniği, estetik | `dental` |
|
||||
| Restoran, kafe, bistro | `restoran` veya `restoran2` |
|
||||
| Bar, meyhane, gece kulübü | `bar` veya `bar2` |
|
||||
| Otel, resort, apart | `hotel1`, `hotel2` veya `hotel3` |
|
||||
| Taksi, transfer, ulaşım | `taxi` veya `taxi2` |
|
||||
| Yazılım, SaaS, chatbot | `chatbot` |
|
||||
| İnşaat, mimarlık, kurumsal | `kurumsal` |
|
||||
|
||||
Mevcut şablonlardan hiçbiri uygun değilse: **yeni şablon yaz** — TEMPLATE_BRIEF'teki tasarım kurallarına uyarak.
|
||||
|
||||
### 5. Antigravity'e Ver
|
||||
|
||||
Analiz tamamlandığında şunu söyle:
|
||||
|
||||
> "Bu `demos.ts` verisini kullan. TEMPLATE_BRIEF.md'deki kurallara göre `[ŞabonAdı]` şablonunu yaz. Mevcut sitenin renk paletini koru ama tasarımı tamamen modernize et. İmza moment olarak `[seçilen imza moment]` kullan."
|
||||
|
||||
---
|
||||
|
||||
## Son Not
|
||||
|
||||
Amaç: müşteriye link atıp "bak, senin için yaptım" diyebilmek.
|
||||
|
||||
**Standart değil, özel. Güzel değil, etkileyici. Çalışıyor değil, hissettiriyor.**
|
||||
|
||||
Eğer şablona baktığında "bu idare eder" diyorsan — yeniden başla.
|
||||
@@ -0,0 +1,50 @@
|
||||
import { getDemoBySlug } from "@/data/demos";
|
||||
import KlinikTemplate from "@/components/templates/KlinikTemplate";
|
||||
import RestoranTemplate from "@/components/templates/RestoranTemplate";
|
||||
import KurumsalTemplate from "@/components/templates/KurumsalTemplate";
|
||||
import DentalTemplate from "@/components/templates/DentalTemplate";
|
||||
import RestoranTemplate2 from "@/components/templates/RestoranTemplate2";
|
||||
import TaxiTemplate from "@/components/templates/TaxiTemplate";
|
||||
import TaxiTemplate2 from "@/components/templates/TaxiTemplate2";
|
||||
import ChatbotTemplate from "@/components/templates/ChatbotTemplate";
|
||||
import BarTemplate from "@/components/templates/BarTemplate";
|
||||
import BarTemplate2 from "@/components/templates/BarTemplate2";
|
||||
import HotelTemplate1 from "@/components/templates/HotelTemplate1";
|
||||
import HotelTemplate2 from "@/components/templates/HotelTemplate2";
|
||||
import HotelTemplate3 from "@/components/templates/HotelTemplate3";
|
||||
import BodrumCerrahiTemplate from "@/components/templates/BodrumCerrahiTemplate";
|
||||
import ChatbotTemplate2 from "@/components/templates/ChatbotTemplate2";
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
|
||||
const { slug } = await params;
|
||||
const data = getDemoBySlug(slug);
|
||||
if (!data) return { title: "Demo bulunamadı" };
|
||||
return {
|
||||
title: `${data.firma.adi} — Ayris Tech Demo`,
|
||||
description: data.firma.slogan,
|
||||
};
|
||||
}
|
||||
|
||||
export default async function DemoPage({ params }: { params: Promise<{ slug: string }> }) {
|
||||
const { slug } = await params;
|
||||
const data = getDemoBySlug(slug);
|
||||
if (!data) notFound();
|
||||
|
||||
if (data.template === "klinik") return <KlinikTemplate data={data} />;
|
||||
if (data.template === "restoran") return <RestoranTemplate data={data} />;
|
||||
if (data.template === "kurumsal") return <KurumsalTemplate data={data} />;
|
||||
if (data.template === "dental") return <DentalTemplate data={data} />;
|
||||
if (data.template === "restoran2") return <RestoranTemplate2 data={data} />;
|
||||
if (data.template === "taxi") return <TaxiTemplate data={data} />;
|
||||
if (data.template === "taxi2") return <TaxiTemplate2 data={data} />;
|
||||
if (data.template === "chatbot") return <ChatbotTemplate data={data} />;
|
||||
if (data.template === "bar") return <BarTemplate data={data} />;
|
||||
if (data.template === "bar2") return <BarTemplate2 data={data} />;
|
||||
if (data.template === "hotel1") return <HotelTemplate1 data={data} />;
|
||||
if (data.template === "hotel2") return <HotelTemplate2 data={data} />;
|
||||
if (data.template === "hotel3") return <HotelTemplate3 data={data} />;
|
||||
if (data.template === "bodrumcerrahi") return <BodrumCerrahiTemplate data={data} />;
|
||||
if (data.template === "chatbot2") return <ChatbotTemplate2 data={data} />;
|
||||
notFound();
|
||||
}
|
||||
|
After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1,4 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
* { scroll-behavior: smooth; }
|
||||
html { scroll-padding-top: 80px; }
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { Metadata } from "next";
|
||||
import Script from "next/script";
|
||||
import "./globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Ayris Tech — Demo",
|
||||
description: "Ayris Tech tarafından hazırlanan demo sayfaları",
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="tr" className="antialiased">
|
||||
<head>
|
||||
<Script id="perf-measure-patch" strategy="beforeInteractive">
|
||||
{`
|
||||
(function() {
|
||||
if (typeof window !== 'undefined' && window.performance && window.performance.measure) {
|
||||
var _measure = window.performance.measure;
|
||||
window.performance.measure = function() {
|
||||
try {
|
||||
return _measure.apply(window.performance, arguments);
|
||||
} catch (e) {
|
||||
// Silently catch native timing measurement exceptions (e.g. negative timestamps or missing marks)
|
||||
}
|
||||
};
|
||||
}
|
||||
})();
|
||||
`}
|
||||
</Script>
|
||||
</head>
|
||||
<body className="font-sans">{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,338 @@
|
||||
"use client";
|
||||
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { demos } from "@/data/demos";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
|
||||
const fadeUp = {
|
||||
hidden: { opacity: 0, y: 30 },
|
||||
show: { opacity: 1, y: 0, transition: { duration: 0.65, ease: [0.25, 0.46, 0.45, 0.94] as [number, number, number, number] } },
|
||||
};
|
||||
const stagger = { hidden: {}, show: { transition: { staggerChildren: 0.08 } } };
|
||||
|
||||
const templateLabels: Record<string, { label: string; renk: string }> = {
|
||||
klinik: { label: "Klinik & Sağlık", renk: "#0ea5e9" },
|
||||
restoran: { label: "Restoran & Kafe", renk: "#f97316" },
|
||||
kurumsal: { label: "Kurumsal Çözüm", renk: "#6366f1" },
|
||||
dental: { label: "Dental Estetik", renk: "#10B981" },
|
||||
restoran2: { label: "Sicilya Trattoria", renk: "#3B82F6" },
|
||||
taxi: { label: "Cab Service (Dark)", renk: "#F5C518" },
|
||||
taxi2: { label: "Cab Service (Light)", renk: "#E5A900" },
|
||||
chatbot: { label: "AI Chatbot / SaaS", renk: "#00E5FF" },
|
||||
bar: { label: "Noir Velvet (Gold)", renk: "#D4AF37" },
|
||||
bar2: { label: "Chalk & Char (Red)", renk: "#E63946" },
|
||||
hotel1: { label: "Luxury Resort (Teal)", renk: "#14B8A6" },
|
||||
hotel2: { label: "Bunkhouse Lodge (Sand)", renk: "#D97706" },
|
||||
hotel3: { label: "Modernist Villa (Slate)", renk: "#94A3B8" },
|
||||
bodrumcerrahi: { label: "Cerrahi Tıp Merkezi", renk: "#1B6FA8" },
|
||||
chatbot2: { label: "Zenith AI (SaaS)", renk: "#8B5CF6" },
|
||||
};
|
||||
|
||||
function getTemplateIcon(template: string, color: string) {
|
||||
const iconProps = { className: "w-5 h-5", style: { color } };
|
||||
|
||||
switch(template) {
|
||||
case "klinik":
|
||||
case "dental":
|
||||
return (
|
||||
<svg {...iconProps} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12c0 1.268-.63 2.39-1.593 3.068a3.745 3.745 0 0 1-1.043 3.296 3.745 3.745 0 0 1-3.296 1.043A3.745 3.745 0 0 1 12 21c-1.268 0-2.39-.63-3.068-1.593a3.746 3.746 0 0 1-3.296-1.043 3.745 3.745 0 0 1-1.043-3.296A3.745 3.745 0 0 1 3 12c0-1.268.63-2.39 1.593-3.068a3.745 3.745 0 0 1 1.043-3.296 3.746 3.746 0 0 1 3.296-1.043A3.746 3.746 0 0 1 12 3c1.268 0 2.39.63 3.068 1.593a3.746 3.746 0 0 1 3.296 1.043 3.746 3.746 0 0 1 1.043 3.296A3.745 3.745 0 0 1 21 12Z" />
|
||||
</svg>
|
||||
);
|
||||
case "restoran":
|
||||
case "restoran2":
|
||||
return (
|
||||
<svg {...iconProps} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 6.042A8.967 8.967 0 0 0 6 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 0 1 6 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 0 1 6-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0 0 18 18a8.967 8.967 0 0 0-6 2.292m0-14.25v14.25" />
|
||||
</svg>
|
||||
);
|
||||
case "kurumsal":
|
||||
return (
|
||||
<svg {...iconProps} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M2.25 21h19.5m-18-18v18m10.5-18v18m6-13.5V21M6.75 6.75h.75m-.75 3h.75m-.75 3h.75m3-6h.75m-.75 3h.75m-.75 3h.75M6.75 21v-3.375c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21M3 3h18v3H3V3Z" />
|
||||
</svg>
|
||||
);
|
||||
case "taxi":
|
||||
case "taxi2":
|
||||
return (
|
||||
<svg {...iconProps} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M8.25 18.75a1.5 1.5 0 0 1-3 0m3 0a1.5 1.5 0 0 0-3 0m3 0h7.5m3 0a1.5 1.5 0 0 1-3 0m3 0a1.5 1.5 0 0 0-3 0m3 0h1.5m-1.5-3h-15M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||
</svg>
|
||||
);
|
||||
case "chatbot":
|
||||
case "chatbot2":
|
||||
return (
|
||||
<svg {...iconProps} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M8.625 12a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0H8.25m4.125 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0H12m4.125 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0h-.375M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 0 1-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8Z" />
|
||||
</svg>
|
||||
);
|
||||
case "bar":
|
||||
case "bar2":
|
||||
return (
|
||||
<svg {...iconProps} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 22V12m9-9H3l9 9 9-9Z" />
|
||||
</svg>
|
||||
);
|
||||
case "hotel1":
|
||||
case "hotel2":
|
||||
case "hotel3":
|
||||
return (
|
||||
<svg {...iconProps} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" />
|
||||
</svg>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<svg {...iconProps} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9.813 15.904 9 21l5-2.788L19 21l-.813-5.096L22 12.333l-5.116-.743L15 7l-1.884 4.59L8 12.333l3.813 3.571ZM15 3.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const demoList = Object.values(demos);
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [brandName, setBrandName] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
|
||||
return (
|
||||
<main className="min-h-screen bg-[#070913] text-slate-100 overflow-hidden relative selection:bg-indigo-500 selection:text-white pb-16">
|
||||
|
||||
{/* Premium Ambient Background Mesh */}
|
||||
<div className="absolute top-[-10%] left-[-20%] w-[140%] h-[60%] bg-[radial-gradient(ellipse_60%_50%_at_50%_0%,rgba(99,102,241,0.12),rgba(255,255,255,0))] pointer-events-none z-0" />
|
||||
<div className="absolute bottom-[10%] right-[-10%] w-[500px] h-[500px] bg-[radial-gradient(circle_at_center,rgba(6,182,212,0.02),transparent_70%)] pointer-events-none z-0" />
|
||||
|
||||
{/* ── HEADER & SHOWCASE INTRO ── */}
|
||||
<section className="relative z-10 px-6 pt-24 pb-16">
|
||||
<motion.div
|
||||
className="max-w-4xl mx-auto text-center"
|
||||
initial="hidden" animate="show" variants={stagger}>
|
||||
|
||||
<motion.div variants={fadeUp}
|
||||
className="inline-flex items-center gap-2.5 text-[10px] font-black uppercase tracking-[2px] px-5 py-2.5 rounded-full mb-8 border border-white/5 bg-white/[0.03] text-indigo-300">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-indigo-400 animate-pulse" />
|
||||
AYRIS TECH · DİJİTAL DENEYİM PORTFÖYÜ
|
||||
</motion.div>
|
||||
|
||||
<motion.h1 variants={fadeUp}
|
||||
className="text-4xl sm:text-6xl font-black text-white leading-[1.1] tracking-tight mb-8">
|
||||
Yüksek Etkileşimli
|
||||
<br />
|
||||
<span className="bg-gradient-to-r from-indigo-300 via-cyan-300 to-emerald-300 bg-clip-text text-transparent">
|
||||
Boutique Şablonlar
|
||||
</span>
|
||||
</motion.h1>
|
||||
|
||||
<motion.p variants={fadeUp} className="text-slate-400/80 text-sm sm:text-base leading-relaxed max-w-2xl mx-auto font-medium">
|
||||
Sektör lideri markalar için tasarladığımız son derece akıcı, zengin mikro animasyonlu ve yüksek sadakatli dijital arayüz prototiplerimizi aşağıdan canlı olarak deneyimleyin.
|
||||
</motion.p>
|
||||
</motion.div>
|
||||
</section>
|
||||
|
||||
{/* ── DYNAMIC EXPERIENCES SHOWCASE GRID ── */}
|
||||
<section className="relative z-10 px-6 max-w-7xl mx-auto">
|
||||
<motion.div
|
||||
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"
|
||||
initial="hidden" animate="show" variants={stagger}>
|
||||
|
||||
{demoList.map((demo) => {
|
||||
const tpl = templateLabels[demo.template] || { label: "Özel Tasarım", renk: "#6366f1" };
|
||||
|
||||
return (
|
||||
<motion.div key={demo.slug} variants={fadeUp}>
|
||||
<Link href={`/${demo.slug}`}>
|
||||
<motion.div
|
||||
className="group relative bg-[#0d111d]/40 border border-white/[0.04] rounded-3xl overflow-hidden cursor-pointer shadow-[0_20px_40px_rgba(0,0,0,0.3)] transition-all duration-300 hover:border-white/[0.12] hover:bg-[#121828]/50"
|
||||
whileHover={{ y: -6 }}
|
||||
>
|
||||
{/* Glowing highlight border on hover */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity duration-500 blur-2xl pointer-events-none"
|
||||
style={{
|
||||
background: `radial-gradient(130px circle at 50% 10%, ${demo.firma.renkAna}15, transparent)`
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Gradient top strip */}
|
||||
<div className="h-1.5 w-full transition-all group-hover:h-2"
|
||||
style={{ background: `linear-gradient(90deg, ${demo.firma.renkAna}, ${demo.firma.renkKoyu})` }} />
|
||||
|
||||
<div className="p-7">
|
||||
{/* Logo Frame & Label Type */}
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div className="w-12 h-12 rounded-2xl flex items-center justify-center transition-all group-hover:scale-102"
|
||||
style={{ background: `${demo.firma.renkAna}12`, border: `1px solid ${demo.firma.renkAna}20` }}>
|
||||
{getTemplateIcon(demo.template, demo.firma.renkAna)}
|
||||
</div>
|
||||
<span className="text-[9px] font-black px-3.5 py-1.5 rounded-full tracking-widest uppercase border border-white/[0.04]"
|
||||
style={{ background: `${tpl.renk}10`, color: tpl.renk }}>
|
||||
{tpl.label}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h2 className="font-bold text-white text-lg mb-1.5 group-hover:text-indigo-300 transition-colors uppercase font-sans tracking-wide">{demo.firma.adi}</h2>
|
||||
<p className="text-slate-400/50 text-[11px] font-bold tracking-widest uppercase mb-6 flex items-center gap-1.5">
|
||||
<svg className="w-3.5 h-3.5 text-indigo-400 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15 10.5a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M19.5 10.5c0 7.142-7.5 11.25-7.5 11.25S4.5 17.642 4.5 10.5a7.5 7.5 0 1 1 15 0Z" />
|
||||
</svg>
|
||||
{demo.firma.sehir}
|
||||
</p>
|
||||
|
||||
{/* Stat Dials inside Cards */}
|
||||
<div className="grid grid-cols-2 gap-3 mb-8">
|
||||
{demo.istatistikler.slice(0, 2).map((s, i) => (
|
||||
<div key={i} className="bg-white/[0.01] border border-white/[0.03] rounded-2xl p-4 flex flex-col justify-between h-20 hover:border-white/5 transition-colors">
|
||||
<span className="text-slate-400/40 text-[9px] uppercase tracking-widest font-black leading-none block mb-2">{s.etiket.substring(0, 20)}...</span>
|
||||
<span className="font-black text-white text-base leading-none block">{s.deger}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Premium CTA Row */}
|
||||
<div className="flex items-center justify-between border-t border-white/[0.03] pt-5">
|
||||
<span className="text-slate-400/30 text-xs font-mono select-none">/{demo.slug}</span>
|
||||
<motion.span
|
||||
className="text-[10px] font-black tracking-[2px] uppercase px-5 py-3 rounded-xl flex items-center gap-1.5 transition-all text-white"
|
||||
style={{ background: demo.firma.renkAna }}
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}>
|
||||
ÖNİZLE
|
||||
<svg className="w-3.5 h-3.5 text-white shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="3">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M13.5 4.5 21 12m0 0-7.5 7.5M21 12H3" />
|
||||
</svg>
|
||||
</motion.span>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</Link>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* ── CUSTOM INQUIRY REQUEST CARD (CLIENT FACING) ── */}
|
||||
<motion.div variants={fadeUp}>
|
||||
<div
|
||||
onClick={() => setShowModal(true)}
|
||||
className="group bg-[#0d111d]/20 border border-dashed border-white/10 rounded-3xl p-8 h-full flex flex-col justify-between min-h-[360px] hover:border-indigo-400/50 hover:bg-[#121828]/30 transition-all cursor-pointer shadow-[0_20px_40px_rgba(0,0,0,0.2)]"
|
||||
>
|
||||
<div>
|
||||
<div className="w-14 h-14 rounded-2xl bg-indigo-500/10 border border-indigo-400/20 flex items-center justify-center mb-6 group-hover:scale-102 transition-transform">
|
||||
<svg className="w-6 h-6 text-indigo-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="font-bold text-white text-lg mb-2 uppercase tracking-wide">Sıradaki Tasarım Sizin Olsun</h3>
|
||||
<p className="text-slate-400/60 text-xs leading-relaxed font-semibold">
|
||||
Kendi markanız veya projeniz için özel kurgulanmış, zengin mikro animasyonlara ve üst segment görsel kimliğe sahip bir dijital şablon önizlemesi talep edin.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<motion.button
|
||||
className="w-full py-4.5 rounded-xl border border-indigo-400/30 bg-indigo-500/5 hover:bg-indigo-500 text-indigo-300 hover:text-white font-black text-[9px] tracking-[2px] uppercase transition-all shadow-md mt-8"
|
||||
whileHover={{ scale: 1.01 }}
|
||||
>
|
||||
ÖZEL KONSEPT TALEP ET
|
||||
</motion.button>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
</motion.div>
|
||||
</section>
|
||||
|
||||
{/* ── MINIMALIST FOOTER ── */}
|
||||
<footer className="max-w-7xl mx-auto mt-24 pt-12 border-t border-white/[0.04] px-6 flex flex-col sm:flex-row items-center justify-between gap-6 relative z-10">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-indigo-500 to-cyan-500 flex items-center justify-center text-xs font-black text-white shadow-md shadow-indigo-500/25">
|
||||
A
|
||||
</div>
|
||||
<span className="text-slate-400/50 text-xs font-bold tracking-wider">AYRIS TECH EXPERIENCES</span>
|
||||
</div>
|
||||
<a href="https://ayristech.com" target="_blank"
|
||||
className="text-slate-400/30 text-xs hover:text-indigo-400 transition-colors font-bold tracking-wider uppercase">
|
||||
ayristech.com →
|
||||
</a>
|
||||
</footer>
|
||||
|
||||
{/* ── CUSTOM INQUIRY MODAL (CLIENT LEAD GENERATION) ── */}
|
||||
<AnimatePresence>
|
||||
{showModal && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 flex items-center justify-center p-6 bg-black/80 backdrop-blur-sm"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
<motion.div
|
||||
className="bg-[#0f1322] rounded-3xl p-8 max-w-md w-full relative shadow-2xl border border-indigo-400/20 text-white"
|
||||
initial={{ scale: 0.95, y: 20 }}
|
||||
animate={{ scale: 1, y: 0 }}
|
||||
exit={{ scale: 0.95, y: 20 }}
|
||||
>
|
||||
{/* Close Button */}
|
||||
<button
|
||||
className="absolute top-6 right-6 w-8 h-8 rounded-full bg-[#070913] border border-white/5 flex items-center justify-center text-white/40 hover:text-indigo-400 hover:border-indigo-400/20 transition-all cursor-pointer font-bold"
|
||||
onClick={() => setShowModal(false)}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
{/* Success Icon */}
|
||||
<div className="w-16 h-16 rounded-2xl bg-indigo-500/10 border border-indigo-400/20 flex items-center justify-center mb-6">
|
||||
<svg className="w-8 h-8 stroke-indigo-400 fill-none" viewBox="0 0 24 24" strokeWidth="1.5">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 0 1 3 12c0-.778.099-1.533.284-2.253" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h3 className="font-sans font-black text-white text-2xl mb-1 uppercase tracking-wider">
|
||||
Konsept Başvurusu
|
||||
</h3>
|
||||
<p className="text-indigo-400 font-mono text-[9px] mb-6 uppercase tracking-widest font-black">
|
||||
Ayris Tech Design Lab
|
||||
</p>
|
||||
|
||||
{/* Form Fields */}
|
||||
<div className="space-y-4 mb-8">
|
||||
<div>
|
||||
<label className="block text-[9px] font-black text-slate-400/50 mb-1.5 uppercase tracking-widest">Firma Adı</label>
|
||||
<input
|
||||
type="text"
|
||||
value={brandName}
|
||||
onChange={(e) => setBrandName(e.target.value)}
|
||||
placeholder="Örn. Vestam Wellness"
|
||||
className="w-full px-4 py-3 rounded-xl border border-white/5 bg-[#070913] text-xs text-white placeholder-white/20 focus:outline-none focus:border-indigo-400 focus:ring-1 focus:ring-indigo-400 transition-all font-semibold"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-[9px] font-black text-slate-400/50 mb-1.5 uppercase tracking-widest">E-Posta Adresi</label>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder="you@company.com"
|
||||
className="w-full px-4 py-3 rounded-xl border border-white/5 bg-[#070913] text-xs text-white placeholder-white/20 focus:outline-none focus:border-indigo-400 focus:ring-1 focus:ring-indigo-400 transition-all font-semibold"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.button
|
||||
className="w-full py-4.5 rounded-xl bg-indigo-500 hover:bg-indigo-600 text-white font-bold text-[9px] tracking-[2px] uppercase cursor-pointer shadow-md shadow-indigo-500/15"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
onClick={() => {
|
||||
setShowModal(false);
|
||||
alert("Başvurunuz başarıyla kaydedildi! En kısa sürede iletişime geçeceğiz.");
|
||||
}}
|
||||
>
|
||||
KONSEPT TALEBİNİ GÖNDER
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,778 @@
|
||||
"use client";
|
||||
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { useRef, useState, useEffect } from "react";
|
||||
import type { DemoData } from "@/data/demos";
|
||||
|
||||
const fadeUp = {
|
||||
hidden: { opacity: 0, y: 40 },
|
||||
show: { opacity: 1, y: 0, transition: { duration: 0.7, ease: [0.25, 0.46, 0.45, 0.94] as [number, number, number, number] } },
|
||||
};
|
||||
|
||||
const stagger = {
|
||||
hidden: {},
|
||||
show: { transition: { staggerChildren: 0.1 } },
|
||||
};
|
||||
|
||||
const translations = {
|
||||
tr: {
|
||||
navReserve: "Rezervasyon",
|
||||
navHours: "Çalışma Saatleri",
|
||||
navCurator: "Kokteyl Menüsü",
|
||||
navReviews: "Değerlendirmeler",
|
||||
bookTable: "Masa Ayırt",
|
||||
exclusiveLounge: "ÖZEL KOKTEYL SALONU",
|
||||
cocktailStage: "KOKTEYL SAHNESİ",
|
||||
evenings: "geceleri",
|
||||
heroDesc: "Noir Velvet Lounge'a adım atın. Klasik karışımlar, botanik aromalar ve yıllanmış özel içkilerin loş kehribar akustiği altındaki benzersiz sunumunu keşfedin.",
|
||||
discoverMenu: "MENÜYÜ KEŞFET",
|
||||
reserveTableTitle: "Stage Booking",
|
||||
reserveTableHeader: "MASA AYIRTIN",
|
||||
reserveTableDesc: "Ana sahne akustik çizgilerinin altında, size özel bar tezgahı veya lounge masanızı şimdiden ayırtın.",
|
||||
fieldsName: "İsim Soyisim",
|
||||
fieldsPhone: "İletişim Numarası",
|
||||
fieldsDate: "Tarih",
|
||||
fieldsTime: "Saat",
|
||||
guarantee: "Bu formu doldurarak doğrulanmış bir rezervasyon sağlarsınız. Masalar, rezervasyon saatinden itibaren 15 dakika boyunca adınıza tutulur.",
|
||||
secureRes: "REZERVASYON YAP",
|
||||
curatorSpecials: "Küratörün Seçtikleri",
|
||||
weRecommend: "TAVSİYE EDİLENLER",
|
||||
signature: "İmza",
|
||||
loungeStories: "LOUNGE HİKAYELERİ",
|
||||
loungeStoriesDesc: "Seçkin miksolojistlerin ve caz akustiği kuratörlerinin salon hakkındaki yorumlarını keşfedin.",
|
||||
loungeHours: "ÇALIŞMA SAATLERİ",
|
||||
loungeDials: "İMZA KOKTEYLLER",
|
||||
privacyRegs: "Gizlilik Sözleşmesi",
|
||||
termsStay: "Salon Koşulları",
|
||||
dismiss: "KAPAT",
|
||||
enquiryActive: "REZERVASYON YAPILDI",
|
||||
ambassadorActive: "Sahne Mihmandarı Aktif",
|
||||
enquirySuccess: "Bar tezgahı veya lounge masası rezervasyonunuzu başarıyla kaydettik. Özel mihmandarımız giriş koordinatlarınızı doğrulamak için sizinle iletişime geçecektir. Teşekkürler!",
|
||||
},
|
||||
en: {
|
||||
navReserve: "Reserve Table",
|
||||
navHours: "Hours",
|
||||
navCurator: "Curator's Specials",
|
||||
navReviews: "Reviews",
|
||||
bookTable: "Book a table",
|
||||
exclusiveLounge: "EXCLUSIVE LOUNGE SERVICE",
|
||||
cocktailStage: "COCKTAIL STAGE",
|
||||
evenings: "evenings",
|
||||
heroDesc: "Step into Noir Velvet Lounge. Indulge in classic mixes, botanic blends, and aged private reserve spirits staged under moody amber acoustics.",
|
||||
discoverMenu: "DISCOVER STAGE MENU",
|
||||
reserveTableTitle: "Stage Booking",
|
||||
reserveTableHeader: "RESERVE A TABLE",
|
||||
reserveTableDesc: "Allocate your private counter or lounge table under the main stage acoustic lines.",
|
||||
fieldsName: "Name",
|
||||
fieldsPhone: "Phone",
|
||||
fieldsDate: "Date",
|
||||
fieldsTime: "Time",
|
||||
guarantee: "By submitting this form, you secure a verified reservation. Tables are held for 15 minutes past the booking coordinates.",
|
||||
secureRes: "SECURE RESERVATION",
|
||||
curatorSpecials: "Curator's Specials",
|
||||
weRecommend: "WE RECOMMEND",
|
||||
signature: "Signature",
|
||||
loungeStories: "LOUNGE STORIES",
|
||||
loungeStoriesDesc: "Hear what prominent mixologists and jazz acoustic curators write about the lounge.",
|
||||
loungeHours: "OPEN HOURS",
|
||||
loungeDials: "SPECIAL DIALS",
|
||||
privacyRegs: "Privacy Regulations",
|
||||
termsStay: "Terms of Lounge",
|
||||
dismiss: "DISMISS",
|
||||
enquiryActive: "TABLE RESERVED",
|
||||
ambassadorActive: "Stage Concierge Active",
|
||||
enquirySuccess: "We have secured your counter or lounge table reservation. A private host has registered your parameters. Thank you!",
|
||||
}
|
||||
};
|
||||
|
||||
export default function BarTemplate({ data }: { data: DemoData }) {
|
||||
const { firma, istatistikler = [], hizmetler = [], yorumlar = [] } = data;
|
||||
const [showBookingModal, setShowBookingModal] = useState(false);
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
const [lang, setLang] = useState<"tr" | "en">("tr");
|
||||
const [preloader, setPreloader] = useState(true);
|
||||
|
||||
const t = translations[lang];
|
||||
|
||||
// 1. Lenis Smooth Scroll Integration
|
||||
useEffect(() => {
|
||||
let lenis: any;
|
||||
import("@studio-freight/lenis").then(({ default: Lenis }) => {
|
||||
lenis = new Lenis({ duration: 1.2, easing: (t: number) => Math.min(1, 1.001 - Math.pow(2, -10 * t)) });
|
||||
function raf(time: number) { lenis.raf(time); requestAnimationFrame(raf); }
|
||||
requestAnimationFrame(raf);
|
||||
});
|
||||
return () => lenis?.destroy();
|
||||
}, []);
|
||||
|
||||
// 2. Preloader Curtain Timer
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setPreloader(false);
|
||||
}, 1500);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
// Localized statistics/hours
|
||||
const getLocalizedStat = (deger: string, etiket: string) => {
|
||||
if (deger.toLowerCase().includes("weekdays") || etiket.toLowerCase().includes("weekdays") || etiket.toLowerCase().includes("pazartesi")) {
|
||||
return {
|
||||
deger: lang === "tr" ? "Hafta İçi" : "Weekdays",
|
||||
etiket: lang === "tr" ? "Pazartesi - Cuma · 16:00 - 02:00" : "Monday - Friday · 4:00 PM - 2:00 AM"
|
||||
};
|
||||
}
|
||||
if (deger.toLowerCase().includes("weekends") || etiket.toLowerCase().includes("weekends") || etiket.toLowerCase().includes("cumartesi")) {
|
||||
return {
|
||||
deger: lang === "tr" ? "Hafta Sonu" : "Weekends",
|
||||
etiket: lang === "tr" ? "Cumartesi - Pazar · 16:00 - 04:00" : "Saturday - Sunday · 4:00 PM - 4:00 AM"
|
||||
};
|
||||
}
|
||||
if (deger.toLowerCase().includes("happy") || etiket.toLowerCase().includes("happy")) {
|
||||
return {
|
||||
deger: lang === "tr" ? "Happy Hour" : "Happy Hour",
|
||||
etiket: lang === "tr" ? "Her gün 17:00 - 19:00 arası imza kokteyllerde %20 indirim" : "Daily 5:00 PM - 7:00 PM · 20% off signature mixology"
|
||||
};
|
||||
}
|
||||
return {
|
||||
deger: lang === "tr" ? "Özel Karışımlar" : deger,
|
||||
etiket: lang === "tr" ? "Taze botanik şuruplar ve el yapımı bitters infüzyonları." : etiket
|
||||
};
|
||||
};
|
||||
|
||||
// Localized services/beverages
|
||||
const getLocalizedService = (baslik: string, aciklama: string) => {
|
||||
if (baslik.toLowerCase().includes("velvet") || baslik.toLowerCase().includes("velvet kiss")) {
|
||||
return {
|
||||
title: lang === "tr" ? "VELVET KISS KOKTEYLİ" : "VELVET KISS COCKTAIL",
|
||||
desc: lang === "tr" ? "Kendi yapımımız taze vişne likörü, vanilya şurubu ve dumanlanmış ardıç aromaları ile hazırlanan imza içkimiz." : aciklama
|
||||
};
|
||||
}
|
||||
if (baslik.toLowerCase().includes("amber") || baslik.toLowerCase().includes("amber smoke") || baslik.toLowerCase().includes("smoke")) {
|
||||
return {
|
||||
title: lang === "tr" ? "KEHRİBAR DUMANI" : "AMBER SMOKE",
|
||||
desc: lang === "tr" ? "Ağaç talaşı isi ile tütsülenmiş viski, botanik acı otlar ve karamelize portakal dilimi." : aciklama
|
||||
};
|
||||
}
|
||||
return {
|
||||
title: lang === "tr" ? "BOTANİK RÜYA" : "BOTANICAL DREAM",
|
||||
desc: lang === "tr" ? "Taze biberiye infüzyonu, narenciye asidi ve organik zencefil gazozu ile canlandırıcı hafif bir karışım." : aciklama
|
||||
};
|
||||
};
|
||||
|
||||
// Custom visual styles & Google Fonts for our Classic Noir Velvet aesthetic
|
||||
const css = `
|
||||
@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,600;0,700;1,400&family=Space+Grotesk:wght@300;400;500;600;700&display=swap');
|
||||
|
||||
:root {
|
||||
--color-velvet-gold: #D4AF37;
|
||||
--color-velvet-black: #09090C;
|
||||
--color-velvet-card: #14141A;
|
||||
--color-text-white: #E8E8E8;
|
||||
--color-text-muted: rgba(232, 232, 232, 0.6);
|
||||
}
|
||||
|
||||
.font-serif-editorial {
|
||||
font-family: 'Cormorant Garamond', Georgia, serif;
|
||||
}
|
||||
|
||||
.font-serif-lux {
|
||||
font-family: 'Cormorant Garamond', Georgia, serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.font-sans-clean {
|
||||
font-family: 'Space Grotesk', sans-serif;
|
||||
}
|
||||
|
||||
.bg-mesh-velvet {
|
||||
background-image:
|
||||
radial-gradient(circle at 5% 5%, rgba(212, 175, 55, 0.03) 0%, transparent 40%),
|
||||
radial-gradient(circle at 95% 95%, rgba(212, 175, 55, 0.02) 0%, transparent 50%);
|
||||
}
|
||||
|
||||
.gold-glow {
|
||||
box-shadow: 0 0 20px rgba(212, 175, 55, 0.15);
|
||||
}
|
||||
|
||||
/* Slow pulse for active indicators */
|
||||
.pulse-gold {
|
||||
animation: goldPulse 2.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes goldPulse {
|
||||
0% { box-shadow: 0 0 0 0 rgba(212, 175, 55, 0.4); }
|
||||
70% { box-shadow: 0 0 0 10px rgba(212, 175, 55, 0); }
|
||||
100% { box-shadow: 0 0 0 0 rgba(212, 175, 55, 0); }
|
||||
}
|
||||
|
||||
.hero-title-clamp {
|
||||
font-size: clamp(48px, 8vw, 110px);
|
||||
letter-spacing: -0.03em;
|
||||
line-height: 0.9;
|
||||
}
|
||||
`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{css}</style>
|
||||
|
||||
{/* ── IMZA AN: CURTAIN REVEAL PRELOADER ── */}
|
||||
<AnimatePresence>
|
||||
{preloader && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 bg-[#09090C] flex flex-col items-center justify-center p-6"
|
||||
exit={{
|
||||
clipPath: "polygon(0 0, 100% 0, 100% 0, 0 0)",
|
||||
transition: { duration: 0.85, ease: [0.16, 1, 0.3, 1] }
|
||||
}}
|
||||
>
|
||||
<div className="max-w-md text-center space-y-6">
|
||||
<motion.span
|
||||
className="text-[9px] font-black tracking-[4px] uppercase text-[#D4AF37] block font-sans-clean"
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
NOIR VELVET LOUNGE
|
||||
</motion.span>
|
||||
<div className="h-[1px] w-48 bg-white/10 mx-auto relative overflow-hidden">
|
||||
<motion.div
|
||||
className="absolute inset-y-0 left-0 bg-[#D4AF37]"
|
||||
initial={{ width: "0%" }}
|
||||
animate={{ width: "100%" }}
|
||||
transition={{ duration: 1.2, ease: "easeInOut" }}
|
||||
/>
|
||||
</div>
|
||||
<motion.h2
|
||||
className="font-serif-editorial text-white text-lg italic font-light tracking-wider"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.4, duration: 0.5 }}
|
||||
>
|
||||
mixology & acoustic lounge
|
||||
</motion.h2>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* ── NOIR VELVET LOUNGE ── */}
|
||||
<div className="bg-[#09090C] text-[#E8E8E8] min-h-screen font-sans-clean selection:bg-[#D4AF37] selection:text-black overflow-hidden relative bg-mesh-velvet pb-20">
|
||||
|
||||
{/* Floating Ambient Gold Orbs */}
|
||||
<div className="absolute top-[25%] left-[-10%] w-[500px] h-[500px] bg-[#D4AF37]/3 blur-[120px] rounded-full pointer-events-none z-0" />
|
||||
<div className="absolute bottom-[25%] right-[-10%] w-[500px] h-[500px] bg-[#D4AF37]/3 blur-[130px] rounded-full pointer-events-none z-0" />
|
||||
|
||||
{/* ── MANDATORY FLOATING DEMO BANNER ── */}
|
||||
<div className="fixed bottom-4 left-4 z-40 bg-[#09090C]/95 backdrop-blur-md border border-white/5 px-4 py-2.5 rounded-xl shadow-2xl flex items-center gap-2.5 max-w-sm pointer-events-none select-none">
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-[#D4AF37] animate-pulse" />
|
||||
<span className="text-[9px] font-black uppercase tracking-[1.5px] text-white/90">
|
||||
{lang === "tr" ? "Bu web sitesi Ayris Tech tarafından hazırlanmış bir konsept çalışmasıdır." : "This website is a premium concept prototype designed by Ayris Tech."}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* ── GOLD FLOATING NAVBAR ── */}
|
||||
<motion.header
|
||||
className="fixed top-4 left-4 right-4 z-50 px-4"
|
||||
initial={{ y: -80, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.7, ease: "easeOut" }}
|
||||
>
|
||||
<div className="mx-auto max-w-7xl h-20 flex items-center justify-between px-8 bg-[#09090C]/80 backdrop-blur-xl border border-[#D4AF37]/10 rounded-2xl shadow-[0_15px_30px_rgba(0,0,0,0.6)]">
|
||||
{/* Logo */}
|
||||
<a href="#" className="flex items-center gap-2 group">
|
||||
<span className="text-xl font-bold tracking-[2px] text-white font-serif-lux flex items-center gap-2.5 uppercase">
|
||||
<svg className="w-5 h-5 text-[#D4AF37]" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M12 22V12" />
|
||||
<path d="M5 12h14" />
|
||||
<path d="M21 3H3l9 9Z" />
|
||||
<path d="M12 12H7.5" />
|
||||
</svg>
|
||||
{firma.adi}
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{/* Navigation Links */}
|
||||
<nav className="hidden lg:flex items-center gap-8">
|
||||
{[
|
||||
{ label: t.navReserve, href: "#booking-flow" },
|
||||
{ label: t.navHours, href: "#hours-happy" },
|
||||
{ label: t.navCurator, href: "#curated-menu" },
|
||||
{ label: t.navReviews, href: "#testimonials" }
|
||||
].map(item => (
|
||||
<a
|
||||
key={item.label}
|
||||
href={item.href}
|
||||
className="text-[10px] font-bold tracking-[2px] uppercase text-[#E8E8E8]/70 hover:text-[#D4AF37] transition-colors relative py-1 cursor-pointer group"
|
||||
>
|
||||
{item.label}
|
||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-[#D4AF37] transition-all group-hover:w-full" />
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
{/* Action button */}
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Language Switcher */}
|
||||
<div className="flex items-center gap-1 bg-white/5 border border-white/10 rounded-xl p-1 shrink-0">
|
||||
<button
|
||||
onClick={() => setLang("tr")}
|
||||
className={`text-[9px] font-black px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "tr" ? "bg-[#D4AF37] text-black shadow-sm" : "text-white/60 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
TR
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setLang("en")}
|
||||
className={`text-[9px] font-black px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "en" ? "bg-[#D4AF37] text-black shadow-sm" : "text-white/60 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
EN
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<motion.button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="text-[10px] font-bold tracking-[2.5px] uppercase text-black bg-[#D4AF37] hover:bg-white px-6 py-3.5 rounded-xl transition-all cursor-pointer shadow-[0_5px_15px_rgba(212,175,55,0.15)] hidden sm:block"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{t.bookTable}
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.header>
|
||||
|
||||
{/* ── HERO & HOURS BLOCK ── */}
|
||||
<section className="relative min-h-screen pt-32 pb-20 flex items-center z-10 px-6">
|
||||
<div className="max-w-7xl mx-auto w-full">
|
||||
<div className="grid lg:grid-cols-12 gap-12 items-center">
|
||||
|
||||
{/* Left Column: Headings & Hours details */}
|
||||
<motion.div
|
||||
className="lg:col-span-6 z-20"
|
||||
variants={stagger}
|
||||
initial="hidden"
|
||||
animate="show"
|
||||
>
|
||||
<motion.div
|
||||
variants={fadeUp}
|
||||
className="inline-flex items-center gap-2 text-[10px] font-bold uppercase tracking-widest text-[#D4AF37] mb-6 bg-[#D4AF37]/5 border border-[#D4AF37]/15 px-4 py-2 rounded-full"
|
||||
>
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-[#D4AF37]" />
|
||||
{t.exclusiveLounge}
|
||||
</motion.div>
|
||||
|
||||
<motion.h1
|
||||
variants={fadeUp}
|
||||
className="font-serif-lux text-white leading-[0.95] tracking-tight mb-8 uppercase hero-title-clamp"
|
||||
>
|
||||
{t.cocktailStage}
|
||||
<br />
|
||||
<span className="italic font-serif-editorial font-light text-[#D4AF37] lowercase">{t.evenings}</span>
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
variants={fadeUp}
|
||||
className="text-white/60 text-xs lg:text-sm leading-relaxed max-w-md mb-12 font-medium"
|
||||
>
|
||||
{t.heroDesc}
|
||||
</motion.p>
|
||||
|
||||
{/* Grid details (Open Hours & Happy Hour) */}
|
||||
<motion.div
|
||||
id="hours-happy"
|
||||
variants={fadeUp}
|
||||
className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-12"
|
||||
>
|
||||
{istatistikler.map((stat, idx) => {
|
||||
const locStat = getLocalizedStat(stat.deger, stat.etiket);
|
||||
return (
|
||||
<div key={idx} className="border-l border-[#D4AF37]/30 pl-4 py-1">
|
||||
<h4 className="font-serif-lux font-bold text-white text-xs uppercase tracking-widest mb-2 text-[#D4AF37]">
|
||||
{locStat.deger}
|
||||
</h4>
|
||||
<p className="text-white/50 text-[11px] leading-relaxed font-medium">
|
||||
{locStat.etiket}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</motion.div>
|
||||
|
||||
{/* Action CTA */}
|
||||
<motion.div variants={fadeUp}>
|
||||
<a
|
||||
href="#curated-menu"
|
||||
className="inline-flex items-center gap-3 px-8 py-4 rounded-xl bg-[#D4AF37] hover:bg-white text-black font-bold text-[10px] tracking-[2px] uppercase transition-all shadow-[0_5px_15px_rgba(212,175,55,0.2)] cursor-pointer animate-pulse"
|
||||
>
|
||||
{t.discoverMenu}
|
||||
</a>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Column: Parallax Moody Graphic Counter */}
|
||||
<div className="lg:col-span-6 relative flex justify-center lg:justify-end">
|
||||
<motion.div
|
||||
className="relative w-full max-w-md lg:max-w-lg h-[450px] lg:h-[520px] rounded-3xl overflow-hidden shadow-2xl border border-[#D4AF37]/15 group"
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.8, ease: "easeOut" }}
|
||||
>
|
||||
{/* Outer glowing gold ring */}
|
||||
<div className="absolute inset-4 rounded-[20px] border border-dashed border-[#D4AF37]/10 animate-[spin_80s_linear_infinite] pointer-events-none" />
|
||||
|
||||
{/* Using 8k Fresh Citrus flatlay to represent natural ingredients and botanical prep */}
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src="/sicilia_lemon_heritage.png"
|
||||
alt="Noir Velvet Fresh Citrus & Botanical Garnishes"
|
||||
className="w-full h-full object-cover scale-102 group-hover:scale-105 transition-transform duration-[4000ms] brightness-[0.75]"
|
||||
/>
|
||||
|
||||
{/* Overlay velvet glow */}
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black via-transparent to-transparent opacity-80" />
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── RESERVATION TABLE BUILDER ── */}
|
||||
<section id="booking-flow" className="py-24 relative z-10 px-6 border-t border-[#D4AF37]/15 bg-[#09090C]/90">
|
||||
<div className="max-w-5xl mx-auto">
|
||||
|
||||
<div className="bg-[#14141A] rounded-3xl border border-white/5 p-8 md:p-12 shadow-2xl relative">
|
||||
|
||||
{/* Thin gold line connector indicator */}
|
||||
<div className="absolute top-0 left-12 right-12 h-0.5 bg-gradient-to-r from-transparent via-[#D4AF37] to-transparent" />
|
||||
|
||||
<div className="text-center max-w-xl mx-auto mb-12">
|
||||
<span className="text-[#D4AF37] font-bold text-[10px] tracking-[2px] uppercase block mb-2 font-serif-lux">{t.reserveTableTitle}</span>
|
||||
<h2 className="font-serif-lux text-3xl font-black uppercase text-white">
|
||||
{t.reserveTableHeader}
|
||||
</h2>
|
||||
<p className="text-white/40 text-xs mt-2 font-medium">
|
||||
{t.reserveTableDesc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Form Grid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
{[
|
||||
{ label: t.fieldsName, placeholder: lang === "tr" ? "Adınız Soyadınız" : "Your Name", type: "text" },
|
||||
{ label: t.fieldsPhone, placeholder: lang === "tr" ? "İrtibat Numarası" : "Contact Number", type: "tel" },
|
||||
{ label: t.fieldsDate, placeholder: "", type: "date" },
|
||||
{ label: t.fieldsTime, placeholder: "", type: "time" },
|
||||
].map((field, idx) => (
|
||||
<div key={idx} className="flex flex-col">
|
||||
<label className="text-[10px] font-bold text-white/50 mb-1.5 uppercase tracking-widest">{field.label}</label>
|
||||
<input
|
||||
type={field.type}
|
||||
placeholder={field.placeholder}
|
||||
className="px-4 py-3.5 rounded-xl border border-white/5 bg-[#09090C] text-xs text-white placeholder-white/20 focus:outline-none focus:border-[#D4AF37] focus:ring-1 focus:ring-[#D4AF37] transition-all font-medium cursor-pointer"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Form Submit Row */}
|
||||
<div className="mt-8 pt-4 flex flex-col md:flex-row justify-between items-center gap-4">
|
||||
<p className="text-white/40 text-xs font-medium max-w-md text-center md:text-left">
|
||||
{t.guarantee}
|
||||
</p>
|
||||
<motion.button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="w-full md:w-auto px-10 py-4.5 rounded-xl bg-[#D4AF37] hover:bg-white text-black font-bold text-[10px] tracking-[2px] uppercase transition-all cursor-pointer shadow-[0_5px_15px_rgba(212,175,55,0.2)] shrink-0"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{t.secureRes}
|
||||
</motion.button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── CURATOR'S SPECIALS MENU (DOTTED CONNECTORS) ── */}
|
||||
<section id="curated-menu" className="py-32 relative z-10 px-6 bg-[#09090C]">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="grid lg:grid-cols-12 gap-16 items-center">
|
||||
|
||||
{/* Left Column: Fine dotted Menu lists */}
|
||||
<motion.div
|
||||
className="lg:col-span-7 flex flex-col justify-center"
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true, amount: 0.2 }}
|
||||
variants={stagger}
|
||||
>
|
||||
<motion.span
|
||||
variants={fadeUp}
|
||||
className="text-[#D4AF37] font-serif-lux italic text-xs tracking-[2px] uppercase block mb-4"
|
||||
>
|
||||
{t.curatorSpecials}
|
||||
</motion.span>
|
||||
<motion.h2
|
||||
variants={fadeUp}
|
||||
className="font-serif-lux text-4xl lg:text-5xl font-black tracking-tight text-white uppercase mb-16"
|
||||
>
|
||||
{t.weRecommend}
|
||||
</motion.h2>
|
||||
|
||||
{/* Dotted menu */}
|
||||
<div className="space-y-8">
|
||||
{hizmetler.map((item, idx) => {
|
||||
const locBeverage = getLocalizedService(item.baslik, item.aciklama);
|
||||
return (
|
||||
<motion.div
|
||||
key={idx}
|
||||
variants={fadeUp}
|
||||
className="flex flex-col cursor-pointer group"
|
||||
>
|
||||
<div className="flex items-end justify-between gap-4">
|
||||
<span className="font-serif-lux text-base lg:text-lg font-bold text-white group-hover:text-[#D4AF37] transition-colors uppercase tracking-wider">
|
||||
{locBeverage.title}
|
||||
</span>
|
||||
{/* Fine dotted line */}
|
||||
<div className="grow border-b border-dashed border-[#D4AF37]/25 mb-2.5 mx-2" />
|
||||
<span className="font-serif-lux text-base lg:text-lg font-black text-[#D4AF37]">
|
||||
$19
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-white/50 text-[11px] mt-1.5 leading-relaxed max-w-lg font-medium">
|
||||
{locBeverage.desc}
|
||||
</p>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Column: Close-up action image counter */}
|
||||
<div className="lg:col-span-5 relative flex justify-center lg:justify-end">
|
||||
<motion.div
|
||||
className="relative w-full max-w-sm h-[480px] lg:h-[550px] rounded-3xl overflow-hidden shadow-2xl border border-white/5 group"
|
||||
initial={{ opacity: 0, x: 40 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8, ease: "easeOut" }}
|
||||
>
|
||||
{/* Using 8k Chef Plating Smoke image to represent curator mixology and smoky vapor */}
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src="/chef_plating_smoke.png"
|
||||
alt="Curator liquid smoke mixology stage"
|
||||
className="w-full h-full object-cover scale-102 group-hover:scale-105 transition-transform duration-[4000ms] brightness-[0.8]"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black via-transparent to-transparent opacity-60" />
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── TESTIMONIALS ── */}
|
||||
<section id="testimonials" className="py-28 relative z-10 px-6 bg-[#09090C]/90 border-t border-[#D4AF37]/10">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="text-center max-w-xl mx-auto mb-20">
|
||||
<span className="text-[#D4AF37] font-bold text-[10px] tracking-[2px] uppercase block mb-2 font-serif-lux">{t.navReviews}</span>
|
||||
<h2 className="font-serif-lux text-3xl lg:text-4xl font-black uppercase text-white tracking-widest">
|
||||
{t.loungeStories}
|
||||
</h2>
|
||||
<p className="text-white/40 text-xs mt-2 font-medium">
|
||||
{t.loungeStoriesDesc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Testimonials 2-Column Grid */}
|
||||
<div className="grid md:grid-cols-2 gap-8">
|
||||
{yorumlar.map((y, yIdx) => (
|
||||
<motion.div
|
||||
key={yIdx}
|
||||
className="bg-[#14141A] border border-white/5 rounded-3xl p-8 flex flex-col justify-between transition-all duration-300 hover:border-[#D4AF37]/30 group shadow-lg"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: yIdx * 0.1 }}
|
||||
whileHover={{ y: -4 }}
|
||||
>
|
||||
{/* Rating Stars SVG */}
|
||||
<div className="flex gap-1.5 mb-6">
|
||||
{[...Array(y.puan)].map((_, starIdx) => (
|
||||
<svg key={starIdx} className="w-4 h-4 fill-[#D4AF37]" viewBox="0 0 24 24">
|
||||
<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
|
||||
</svg>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<p className="text-white/70 text-xs leading-relaxed italic mb-8 font-medium font-serif-editorial">
|
||||
“{y.yorum}”
|
||||
</p>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-full border border-white/10 flex items-center justify-center text-lg bg-[#09090C] font-sans-clean select-none font-bold">
|
||||
{y.yazar.charAt(0)}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-serif-lux text-white text-xs font-black uppercase tracking-wider">
|
||||
{y.yazar}
|
||||
</h4>
|
||||
<span className="text-[9px] text-white/40 uppercase tracking-widest font-bold font-sans-clean">
|
||||
{y.tarih}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── FOOTER ── */}
|
||||
<footer className="bg-[#09090C] border-t border-white/5 pt-24 pb-8 px-6 relative z-10">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="grid md:grid-cols-4 gap-12 pb-16 border-b border-white/5">
|
||||
|
||||
{/* About Column */}
|
||||
<div className="md:col-span-2">
|
||||
<span className="font-serif-lux text-2xl font-black text-white tracking-wider uppercase mb-4 block">
|
||||
Noir<span className="text-[#D4AF37]">Velvet</span>
|
||||
</span>
|
||||
<p className="text-white/50 text-xs leading-relaxed max-w-sm mb-8 font-medium">
|
||||
{firma.slogan} — Classic dark luxury lounge delivering organic mixology under curated acoustic stage lines.
|
||||
</p>
|
||||
<div className="text-white/60 text-xs font-medium space-y-3">
|
||||
<p className="flex items-center gap-2">
|
||||
<svg className="w-4 h-4 text-[#D4AF37] shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" />
|
||||
<circle cx="12" cy="10" r="3" />
|
||||
</svg>
|
||||
<span className="text-white/80">{firma.adres}</span>
|
||||
</p>
|
||||
<p className="flex items-center gap-2">
|
||||
<svg className="w-4 h-4 text-[#D4AF37] shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<rect width="20" height="16" x="2" y="4" rx="2" />
|
||||
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
|
||||
</svg>
|
||||
<span className="text-white/80">{firma.email}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Hours Column */}
|
||||
<div>
|
||||
<h4 className="font-serif-lux text-[#D4AF37] text-xs font-black uppercase tracking-wider mb-6">
|
||||
{t.loungeHours}
|
||||
</h4>
|
||||
<div className="space-y-4 text-xs text-white/50 font-medium">
|
||||
<p>{lang === "tr" ? "Pazartesi - Cuma" : "Monday - Friday"} <br /> <span className="text-white/70">4:00 PM - 2:00 AM</span></p>
|
||||
<p>{lang === "tr" ? "Cumartesi - Pazar" : "Saturday - Sunday"} <br /> <span className="text-white/70">4:00 PM - 4:00 AM</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Specials Column */}
|
||||
<div>
|
||||
<h4 className="font-serif-lux text-[#D4AF37] text-xs font-black uppercase tracking-wider mb-6">
|
||||
{t.loungeDials}
|
||||
</h4>
|
||||
<div className="space-y-4">
|
||||
{hizmetler.map((h, hIdx) => {
|
||||
const locB = getLocalizedService(h.baslik, h.aciklama);
|
||||
return (
|
||||
<a
|
||||
key={hIdx}
|
||||
href="#curated-menu"
|
||||
className="block text-white/50 hover:text-[#D4AF37] text-xs transition-colors font-medium"
|
||||
>
|
||||
{locB.title} {t.signature}
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col md:flex-row justify-between items-center pt-8 gap-4 text-white/30 text-xs font-medium">
|
||||
<p>© 2026 {firma.adi}. All rights reserved.</p>
|
||||
<div className="flex gap-4">
|
||||
<a href="#" className="hover:text-white transition-colors">{t.privacyRegs}</a>
|
||||
<span>·</span>
|
||||
<a href="#" className="hover:text-white transition-colors">{t.termsStay}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{/* ── FAST TABLE SUCCESS MODAL ── */}
|
||||
<AnimatePresence>
|
||||
{showBookingModal && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 flex items-center justify-center p-6 bg-black/85 backdrop-blur-sm"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
<motion.div
|
||||
className="bg-[#14141A] rounded-3xl p-8 max-w-md w-full relative shadow-2xl border border-[#D4AF37]/20"
|
||||
initial={{ scale: 0.95, y: 20 }}
|
||||
animate={{ scale: 1, y: 0 }}
|
||||
exit={{ scale: 0.95, y: 20 }}
|
||||
>
|
||||
{/* Close Button */}
|
||||
<button
|
||||
className="absolute top-6 right-6 w-8 h-8 rounded-full bg-[#09090C] border border-white/5 flex items-center justify-center text-white/40 hover:text-[#D4AF37] hover:border-[#D4AF37]/20 transition-all cursor-pointer font-bold"
|
||||
onClick={() => setShowBookingModal(false)}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
{/* Success check indicator */}
|
||||
<div className="w-16 h-16 rounded-2xl bg-[#D4AF37]/10 border border-[#D4AF37]/20 flex items-center justify-center mb-6">
|
||||
<svg className="w-8 h-8 stroke-[#D4AF37] fill-none" viewBox="0 0 24 24" strokeWidth="1.5">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h3 className="font-serif-lux font-black text-white text-2xl mb-1 uppercase tracking-wider">
|
||||
{t.enquiryActive}
|
||||
</h3>
|
||||
<p className="text-[#D4AF37] font-mono text-[10px] mb-6 uppercase tracking-widest font-bold">
|
||||
{t.ambassadorActive}
|
||||
</p>
|
||||
|
||||
<p className="text-white/60 text-xs leading-relaxed mb-8 font-medium">
|
||||
{t.enquirySuccess}
|
||||
</p>
|
||||
|
||||
<motion.button
|
||||
className="w-full py-4.5 rounded-xl bg-[#D4AF37] hover:bg-white text-black font-bold text-[10px] tracking-[2px] uppercase cursor-pointer shadow-md shadow-[#D4AF37]/15"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
onClick={() => setShowBookingModal(false)}
|
||||
>
|
||||
{t.dismiss}
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,873 @@
|
||||
"use client";
|
||||
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { useRef, useState, useEffect } from "react";
|
||||
import type { DemoData } from "@/data/demos";
|
||||
|
||||
const fadeUp = {
|
||||
hidden: { opacity: 0, y: 40 },
|
||||
show: { opacity: 1, y: 0, transition: { duration: 0.7, ease: [0.25, 0.46, 0.45, 0.94] as [number, number, number, number] } },
|
||||
};
|
||||
|
||||
const stagger = {
|
||||
hidden: {},
|
||||
show: { transition: { staggerChildren: 0.1 } },
|
||||
};
|
||||
|
||||
interface DrinkSpec {
|
||||
name: string;
|
||||
desc: string;
|
||||
capacity: string;
|
||||
alcohol: string;
|
||||
relax: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
const translations = {
|
||||
tr: {
|
||||
navSpecials: "İmza Serisi",
|
||||
navReserve: "Etkinlik Planla",
|
||||
navFlights: "Tadım Serileri",
|
||||
navReviews: "Gurme Yorumları",
|
||||
scheduleCall: "Görüşme Planla",
|
||||
ultimateExp: "EŞSİZ KOKTEYL DENEYİMİ",
|
||||
dedicationTitle: "PROFESYONEL MİKSOLOJİ VE",
|
||||
dedicationTail: "EL YAPIMI BAĞLILIK",
|
||||
heroDesc: "Zanaatkar viski tadım uçuşları, kişisel miksoloji eğitimleri ve kurumsal atölye buluşmalarına dahil olun. Ham meşe ağacı ve oyma taş tezgahlar üzerinde hazırlanır.",
|
||||
scheduleCallBtn: "GÖRÜŞME AYARLA",
|
||||
artisanalSelections: "SANATSAL SEÇENEKLER",
|
||||
signatureLiquors: "İmza İksirler",
|
||||
chooseDrink: "FAVORİ İÇKİNİZİ SEÇİN",
|
||||
sliderDesc: "Ustalıkla hazırlanan reçetelerimizi inceleyin. Aktif hacim, alkol derecesi ve gevşeme oranlarını görüntüleyin.",
|
||||
capacity: "HACİM",
|
||||
alcohol: "ALKOL",
|
||||
relax: "GEVŞEME",
|
||||
barrelhouseEvents: "Fıçı Evi Etkinlikleri",
|
||||
featuredServices: "SEÇKİN HİZMETLER",
|
||||
learnMore: "DAHA FAZLA KEŞFET →",
|
||||
masterclassBooking: "Rezervasyon",
|
||||
scheduleEvent: "BİR ETKİNLİK PLANLAYIN",
|
||||
formDesc: "Viski tadım serileri veya miksoloji dersleri organize etmek için sommelier koordinatörümüzle iletişime geçin.",
|
||||
fieldsName: "İsim Soyisim",
|
||||
fieldsEmail: "E-Posta Adresi",
|
||||
fieldsPhone: "İrtibat Numarası",
|
||||
fieldsEvent: "Etkinlik Kategorisi",
|
||||
fieldsNotes: "Özel İstekler",
|
||||
fieldsNotesPlaceholder: "Aroma tercihleri veya VIP mihmandar gereksinimleri...",
|
||||
dispatchRequest: "ETKİNLİK TALEBİNİ GÖNDER",
|
||||
sommelierReviews: "Gurme Yorumları",
|
||||
happyGuests: "MİSAFİR DENEYİMLERİ",
|
||||
happyGuestsDesc: "Yıllanmış tek malt ve fıçı serisi tadım etkinliklerimiz hakkında ne yazdıklarını keşfedin.",
|
||||
artisanalDials: "SANATSAL SERİ",
|
||||
vipServices: "VIP HİZMETLER",
|
||||
privacyRegs: "Gizlilik Sözleşmesi",
|
||||
termsStay: "Fıçı Koşulları",
|
||||
dismiss: "KAPAT",
|
||||
enquiryActive: "TALEBİNİZ GÖNDERİLDİ",
|
||||
ambassadorActive: "Mihmandar Sommelier Aktif",
|
||||
enquirySuccess: "Özel fıçı evi tadım/etkinlik talebinizi başarıyla kaydettik. Sertifikalı mihmandarımız tadım parametrelerinizi kesinleştirmek için sizinle iletişime geçecektir. Teşekkürler!",
|
||||
},
|
||||
en: {
|
||||
navSpecials: "Specials",
|
||||
navReserve: "Book experience",
|
||||
navFlights: "Sommelier flights",
|
||||
navReviews: "Sommelier reviews",
|
||||
scheduleCall: "Schedule call",
|
||||
ultimateExp: "THE ULTIMATE COCKTAIL EXPERIENCE",
|
||||
dedicationTitle: "DEDICATION TO",
|
||||
dedicationTail: "PROFESSIONAL CRAFT & SPIRIT",
|
||||
heroDesc: "Indulge in artisanal whiskey flights, custom mixology, and corporate masterclass gatherings. Staged on heavy raw oak and carved stones.",
|
||||
scheduleCallBtn: "SCHEDULE A CALL",
|
||||
artisanalSelections: "ARTISANAL SELECTIONS",
|
||||
signatureLiquors: "Signature Liquors",
|
||||
chooseDrink: "CHOOSE FAVORITE DRINK",
|
||||
sliderDesc: "Cycle through our mastercraft recipes. Toggle active stats, proof, and relax levels.",
|
||||
capacity: "CAPACITY",
|
||||
alcohol: "ALCOHOL",
|
||||
relax: "RELAX",
|
||||
barrelhouseEvents: "Barrelhouse Events",
|
||||
featuredServices: "FEATURED SERVICES",
|
||||
learnMore: "LEARN MORE →",
|
||||
masterclassBooking: "Masterclass booking",
|
||||
scheduleEvent: "SCHEDULE AN EVENT",
|
||||
formDesc: "Connect with our sommelier coordinator to arrange whiskey flights or mixology classes.",
|
||||
fieldsName: "Name",
|
||||
fieldsEmail: "Email",
|
||||
fieldsPhone: "Phone",
|
||||
fieldsEvent: "Event Type",
|
||||
fieldsNotes: "Special notes",
|
||||
fieldsNotesPlaceholder: "Flavor preferences or VIP requirements...",
|
||||
dispatchRequest: "DISPATCH EVENT REQUEST",
|
||||
sommelierReviews: "Sommelier Reviews",
|
||||
happyGuests: "HAPPY GUESTS",
|
||||
happyGuestsDesc: "Hear what craft enthusiasts write about our private aged single malt coordinates.",
|
||||
artisanalDials: "ARTISANAL DIALS",
|
||||
vipServices: "VIP SERVICES",
|
||||
privacyRegs: "Privacy Regulations",
|
||||
termsStay: "Terms of Cask",
|
||||
dismiss: "DISMISS",
|
||||
enquiryActive: "EVENT DISPATCHED",
|
||||
ambassadorActive: "Barrelhouse Sommelier Active",
|
||||
enquirySuccess: "We have registered your private barrelhouse coordinate request. A certified somatic host will contact you shortly to confirm whiskey flights or mixology parameters. Thank you!",
|
||||
}
|
||||
};
|
||||
|
||||
export default function BarTemplate2({ data }: { data: DemoData }) {
|
||||
const { firma, istatistikler = [], hizmetler = [], yorumlar = [] } = data;
|
||||
const [showBookingModal, setShowBookingModal] = useState(false);
|
||||
const [activeDrink, setActiveDrink] = useState<number>(1); // Mai Tai active by default
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
const [lang, setLang] = useState<"tr" | "en">("tr");
|
||||
const [preloader, setPreloader] = useState(true);
|
||||
|
||||
const t = translations[lang];
|
||||
|
||||
// 1. Lenis Smooth Scroll Integration
|
||||
useEffect(() => {
|
||||
let lenis: any;
|
||||
import("@studio-freight/lenis").then(({ default: Lenis }) => {
|
||||
lenis = new Lenis({ duration: 1.2, easing: (t: number) => Math.min(1, 1.001 - Math.pow(2, -10 * t)) });
|
||||
function raf(time: number) { lenis.raf(time); requestAnimationFrame(raf); }
|
||||
requestAnimationFrame(raf);
|
||||
});
|
||||
return () => lenis?.destroy();
|
||||
}, []);
|
||||
|
||||
// 2. Preloader Curtain Timer
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setPreloader(false);
|
||||
}, 1500);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
const getLocalizedDrinks = () => {
|
||||
return [
|
||||
{
|
||||
name: lang === "tr" ? "Mojito" : "Mojito",
|
||||
desc: lang === "tr" ? "Taze beyaz Küba romu, el ezmesi nane yaprakları, organik misket limonu suyu, ham kamış şekeri ve soğuk maden suyu." : "Fresh white cuban rum, hand-crushed spearmint, organic lime juice reduction, raw cane sugar, chilled splash of soda.",
|
||||
capacity: "350ml",
|
||||
alcohol: "12%",
|
||||
relax: "80%",
|
||||
color: "#00E5FF"
|
||||
},
|
||||
{
|
||||
name: lang === "tr" ? "Mai Tai" : "Mai Tai",
|
||||
desc: lang === "tr" ? "Premium Jamaika kehribar romu, üç kez damıtılmış portakal likörü, organik badem şurubu ve taze sıkılmış misket limonu." : "Premium Jamaican amber rum, triple-distilled orange curaçao, organic almond orgeat syrup, fresh lime squeeze.",
|
||||
capacity: "280ml",
|
||||
alcohol: "18%",
|
||||
relax: "90%",
|
||||
color: "#FF9F00"
|
||||
},
|
||||
{
|
||||
name: lang === "tr" ? "Rum Cosmo" : "Rum Cosmo",
|
||||
desc: lang === "tr" ? "Fıçıda yıllanmış koyu rom, dağ kızılcığı infüzyonu, organik portakal likörü ve portakal yağı buğusu." : "Cask-aged dark rum, wild mountain cranberry infusion, organic triple sec, orange oil mist garnish.",
|
||||
capacity: "200ml",
|
||||
alcohol: "22%",
|
||||
relax: "95%",
|
||||
color: "#FF007A"
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
const getLocalizedService = (baslik: string, aciklama: string) => {
|
||||
if (baslik.toLowerCase().includes("whiskey") || baslik.toLowerCase().includes("flight") || baslik.toLowerCase().includes("tadim")) {
|
||||
return {
|
||||
title: lang === "tr" ? "VİSKİ TADIM UÇUŞLARI" : "WHISKEY FLIGHTS",
|
||||
desc: lang === "tr" ? "Dünyanın en seçkin fıçılarından gelen yıllanmış tek malt ve burbon viski serilerinin özel sunumu." : aciklama
|
||||
};
|
||||
}
|
||||
if (baslik.toLowerCase().includes("mixology") || baslik.toLowerCase().includes("class") || baslik.toLowerCase().includes("ders")) {
|
||||
return {
|
||||
title: lang === "tr" ? "MİKSOLOJİ EĞİTİMLERİ" : "MIXOLOGY CLASSES",
|
||||
desc: lang === "tr" ? "Profesyonel barmenlerimiz eşliğinde kendi taze şuruplarınızı ve kokteyllerinizi yapmayı öğrenin." : aciklama
|
||||
};
|
||||
}
|
||||
return {
|
||||
title: lang === "tr" ? "ÖZEL KOKTEYL HİZMETİ" : "PRIVATE COCKTAIL CATERING",
|
||||
desc: lang === "tr" ? "Kurumsal lansmanlar, VIP davetler ve butik etkinlikler için özel miksoloji menüsü ve servis ekibi." : aciklama
|
||||
};
|
||||
};
|
||||
|
||||
const drinks = getLocalizedDrinks();
|
||||
|
||||
// Custom visual styles & Google Fonts for our Rustic Chalk & Char aesthetic
|
||||
const css = `
|
||||
@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,600;0,700;1,400&family=Space+Grotesk:wght@300;400;500;600;700&display=swap');
|
||||
|
||||
:root {
|
||||
--color-char-red: #E63946;
|
||||
--color-char-slate: #111215;
|
||||
--color-char-card: #18191E;
|
||||
--color-text-white: #FCFAF7;
|
||||
--color-text-muted: rgba(252, 252, 247, 0.5);
|
||||
}
|
||||
|
||||
.font-industrial {
|
||||
font-family: 'Cormorant Garamond', Georgia, serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.font-sans-clean {
|
||||
font-family: 'Space Grotesk', sans-serif;
|
||||
}
|
||||
|
||||
.bg-mesh-char {
|
||||
background-image:
|
||||
radial-gradient(circle at 10% 20%, rgba(230, 57, 70, 0.04) 0%, transparent 45%),
|
||||
radial-gradient(circle at 90% 80%, rgba(229, 169, 0, 0.03) 0%, transparent 50%),
|
||||
linear-gradient(rgba(255, 255, 255, 0.005) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(255, 255, 255, 0.005) 1px, transparent 1px);
|
||||
background-size: 100% 100%, 100% 100%, 40px 40px, 40px 40px;
|
||||
}
|
||||
|
||||
.crimson-glow {
|
||||
box-shadow: 0 0 20px rgba(230, 57, 70, 0.25);
|
||||
}
|
||||
|
||||
/* Pulse animation for CTA strip */
|
||||
.pulse-glow-crimson {
|
||||
animation: crimsonPulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes crimsonPulse {
|
||||
0% { box-shadow: 0 0 0 0 rgba(230, 57, 70, 0.4); }
|
||||
70% { box-shadow: 0 0 0 12px rgba(230, 57, 70, 0); }
|
||||
100% { box-shadow: 0 0 0 0 rgba(230, 57, 70, 0); }
|
||||
}
|
||||
|
||||
.hero-title-clamp {
|
||||
font-size: clamp(42px, 7.5vw, 100px);
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 0.95;
|
||||
}
|
||||
`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{css}</style>
|
||||
|
||||
{/* ── IMZA AN: CURTAIN REVEAL PRELOADER ── */}
|
||||
<AnimatePresence>
|
||||
{preloader && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 bg-[#111215] flex flex-col items-center justify-center p-6"
|
||||
exit={{
|
||||
clipPath: "polygon(0 0, 100% 0, 100% 0, 0 0)",
|
||||
transition: { duration: 0.85, ease: [0.16, 1, 0.3, 1] }
|
||||
}}
|
||||
>
|
||||
<div className="max-w-md text-center space-y-6">
|
||||
<motion.span
|
||||
className="text-[9px] font-black tracking-[4px] uppercase text-[#E63946] block font-sans-clean"
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
CHAR BARRELHOUSE
|
||||
</motion.span>
|
||||
<div className="h-[1px] w-48 bg-white/10 mx-auto relative overflow-hidden">
|
||||
<motion.div
|
||||
className="absolute inset-y-0 left-0 bg-[#E63946]"
|
||||
initial={{ width: "0%" }}
|
||||
animate={{ width: "100%" }}
|
||||
transition={{ duration: 1.2, ease: "easeInOut" }}
|
||||
/>
|
||||
</div>
|
||||
<motion.h2
|
||||
className="font-industrial text-white text-lg font-light tracking-wider"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.4, duration: 0.5 }}
|
||||
>
|
||||
barrel aged mixology
|
||||
</motion.h2>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* ── CHALK & CHAR BARRELHOUSE ── */}
|
||||
<div className="bg-[#111215] text-[#FCFAF7] min-h-screen font-sans-clean selection:bg-[#E63946] selection:text-white overflow-hidden relative bg-mesh-char pb-20">
|
||||
|
||||
{/* Floating Ambient Red Orbs */}
|
||||
<div className="absolute top-[15%] left-[-15%] w-[600px] h-[600px] bg-[#E63946]/4 blur-[130px] rounded-full pointer-events-none z-0" />
|
||||
<div className="absolute bottom-[15%] right-[-15%] w-[600px] h-[600px] bg-[#E5A900]/2 blur-[140px] rounded-full pointer-events-none z-0" />
|
||||
|
||||
{/* ── MANDATORY FLOATING DEMO BANNER ── */}
|
||||
<div className="fixed bottom-4 left-4 z-40 bg-[#18191E]/95 backdrop-blur-md border border-white/5 px-4 py-2.5 rounded-xl shadow-2xl flex items-center gap-2.5 max-w-sm pointer-events-none select-none">
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-[#E63946] animate-pulse" />
|
||||
<span className="text-[9px] font-black uppercase tracking-[1.5px] text-white/90">
|
||||
{lang === "tr" ? "Bu web sitesi Ayris Tech tarafından hazırlanmış bir konsept çalışmasıdır." : "This website is a premium concept prototype designed by Ayris Tech."}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* ── HIGH CONTRAST NAVBAR ── */}
|
||||
<motion.header
|
||||
className="fixed top-4 left-4 right-4 z-50 px-4"
|
||||
initial={{ y: -80, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.7, ease: "easeOut" }}
|
||||
>
|
||||
<div className="mx-auto max-w-7xl h-20 flex items-center justify-between px-8 bg-[#18191E]/95 backdrop-blur-xl border border-white/5 rounded-2xl shadow-[0_15px_30px_rgba(0,0,0,0.5)]">
|
||||
{/* Logo */}
|
||||
<a href="#" className="flex items-center gap-2 group">
|
||||
<span className="text-xl font-bold tracking-[1.5px] text-white font-industrial flex items-center gap-2.5 uppercase">
|
||||
<svg className="w-5 h-5 text-[#E63946]" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M5 3l1.5 15.5a2 2 0 0 0 2 1.5h7a2 2 0 0 0 2-1.5L19 3H5Z" />
|
||||
<path d="M6 10h12" />
|
||||
</svg>
|
||||
{firma.adi}
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{/* Navigation Links */}
|
||||
<nav className="hidden lg:flex items-center gap-8">
|
||||
{[
|
||||
{ label: t.navSpecials, href: "#drink-selector" },
|
||||
{ label: t.navReserve, href: "#booking-flow" },
|
||||
{ label: t.navFlights, href: "#experiences" },
|
||||
{ label: t.navReviews, href: "#testimonials" }
|
||||
].map(item => (
|
||||
<a
|
||||
key={item.label}
|
||||
href={item.href}
|
||||
className="text-[10px] font-bold tracking-[2px] uppercase text-[#FCFAF7]/70 hover:text-[#E63946] transition-colors relative py-1 cursor-pointer group"
|
||||
>
|
||||
{item.label}
|
||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-[#E63946] transition-all group-hover:w-full" />
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
{/* Action button */}
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Language Switcher */}
|
||||
<div className="flex items-center gap-1 bg-white/5 border border-white/10 rounded-xl p-1 shrink-0">
|
||||
<button
|
||||
onClick={() => setLang("tr")}
|
||||
className={`text-[9px] font-black px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "tr" ? "bg-[#E63946] text-white shadow-sm" : "text-white/60 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
TR
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setLang("en")}
|
||||
className={`text-[9px] font-black px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "en" ? "bg-[#E63946] text-white shadow-sm" : "text-white/60 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
EN
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<motion.button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="text-[10px] font-bold tracking-[2.5px] uppercase text-white bg-[#E63946] hover:bg-white hover:text-black px-6 py-3.5 rounded-xl transition-all cursor-pointer shadow-[0_5px_15px_rgba(230,57,70,0.2)] hidden sm:block"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{t.scheduleCall}
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.header>
|
||||
|
||||
{/* ── HERO SECTION ── */}
|
||||
<section className="relative min-h-screen pt-32 pb-20 flex items-center z-10 px-6">
|
||||
<div className="max-w-7xl mx-auto w-full">
|
||||
<div className="grid lg:grid-cols-12 gap-12 items-center">
|
||||
|
||||
{/* Left Column: Heading and description */}
|
||||
<motion.div
|
||||
className="lg:col-span-7 z-20"
|
||||
variants={stagger}
|
||||
initial="hidden"
|
||||
animate="show"
|
||||
>
|
||||
<motion.div
|
||||
variants={fadeUp}
|
||||
className="inline-flex items-center gap-2 text-[10px] font-bold uppercase tracking-widest text-[#E63946] mb-6 bg-[#E63946]/10 border border-[#E63946]/20 px-4 py-2 rounded-full"
|
||||
>
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-[#E63946]" />
|
||||
{t.ultimateExp}
|
||||
</motion.div>
|
||||
|
||||
<motion.h1
|
||||
variants={fadeUp}
|
||||
className="font-industrial text-white leading-[0.95] tracking-tight mb-6 uppercase hero-title-clamp"
|
||||
>
|
||||
{t.dedicationTitle}
|
||||
<br />
|
||||
<span className="text-[#E63946]">{t.dedicationTail}</span>
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
variants={fadeUp}
|
||||
className="text-white/60 text-xs lg:text-sm leading-relaxed max-w-xl mb-10 font-medium"
|
||||
>
|
||||
{t.heroDesc}
|
||||
</motion.p>
|
||||
|
||||
{/* Quick actions */}
|
||||
<motion.div variants={fadeUp} className="flex gap-4">
|
||||
<motion.button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="px-8 py-4 rounded-xl bg-[#E63946] hover:bg-white hover:text-black text-white font-bold text-[10px] tracking-[2px] uppercase transition-all shadow-[0_5px_15px_rgba(230,57,70,0.25)] cursor-pointer"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
>
|
||||
{t.scheduleCallBtn}
|
||||
</motion.button>
|
||||
<a
|
||||
href="#drink-selector"
|
||||
className="px-8 py-4 rounded-xl border border-white/10 bg-white/5 hover:bg-white/10 text-white font-bold text-[10px] tracking-[2px] uppercase transition-all cursor-pointer text-center"
|
||||
>
|
||||
{t.artisanalSelections}
|
||||
</a>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Column: High-fidelity image (steak/drink counter) */}
|
||||
<div className="lg:col-span-5 relative flex justify-center lg:justify-end">
|
||||
<motion.div
|
||||
className="relative w-full max-w-md lg:max-w-lg h-[400px] lg:h-[480px] rounded-3xl overflow-hidden shadow-2xl border border-white/5 group"
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.8, ease: "easeOut" }}
|
||||
>
|
||||
{/* Using 8k Chef Plating Smoke image to represent premium cask smoking counter */}
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src="/chef_plating_smoke.png"
|
||||
alt="Char Barrelhouse Cask-Aged Spirits Smoking Counter"
|
||||
className="w-full h-full object-cover scale-102 group-hover:scale-105 transition-transform duration-[4000ms]"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black via-transparent to-transparent opacity-50" />
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── ARTISANAL CAROUSEL SLIDER ── */}
|
||||
<section id="drink-selector" className="py-28 relative z-10 px-6 bg-[#18191E]/60 border-t border-white/5">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="text-center max-w-xl mx-auto mb-20">
|
||||
<span className="text-[#E63946] font-bold text-xs uppercase tracking-widest block mb-2 font-industrial">{t.signatureLiquors}</span>
|
||||
<h2 className="font-industrial text-3xl lg:text-4xl font-black uppercase text-white">
|
||||
{t.chooseDrink}
|
||||
</h2>
|
||||
<p className="text-white/40 text-xs mt-2 font-medium">
|
||||
{t.sliderDesc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Slider container */}
|
||||
<div className="grid lg:grid-cols-12 gap-12 items-center">
|
||||
|
||||
{/* Left Column: Drink Tabs & Specifications */}
|
||||
<div className="lg:col-span-7 space-y-8">
|
||||
{/* Tabs */}
|
||||
<div className="flex gap-3 flex-wrap">
|
||||
{drinks.map((d, dIdx) => (
|
||||
<button
|
||||
key={d.name}
|
||||
onClick={() => setActiveDrink(dIdx)}
|
||||
className={`px-6 py-3.5 rounded-xl border text-xs font-bold uppercase tracking-widest transition-all cursor-pointer ${
|
||||
activeDrink === dIdx
|
||||
? "bg-[#E63946] text-white border-[#E63946] shadow-[0_4px_12px_rgba(230,57,70,0.2)]"
|
||||
: "bg-white/[0.02] text-white/60 border-white/5 hover:border-white/10"
|
||||
}`}
|
||||
>
|
||||
{d.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Active Drink Info */}
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.div
|
||||
key={activeDrink}
|
||||
initial={{ opacity: 0, y: 15 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -15 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="space-y-6"
|
||||
>
|
||||
<h3 className="font-industrial text-4xl font-black text-white uppercase tracking-wider">
|
||||
{drinks[activeDrink].name}
|
||||
</h3>
|
||||
<p className="text-white/60 text-xs lg:text-sm leading-relaxed max-w-xl font-medium">
|
||||
{drinks[activeDrink].desc}
|
||||
</p>
|
||||
|
||||
{/* Circular Dials Indicators */}
|
||||
<div className="grid grid-cols-3 gap-4 pt-6 max-w-md">
|
||||
|
||||
{/* Dial 1: Capacity */}
|
||||
<div className="bg-white/[0.02] border border-white/5 p-4 rounded-xl flex flex-col items-center text-center">
|
||||
<span className="text-[#FCFAF7] font-industrial text-xl font-bold">{drinks[activeDrink].capacity}</span>
|
||||
<span className="text-white/30 text-[9px] uppercase tracking-widest font-bold mt-1">{t.capacity}</span>
|
||||
</div>
|
||||
|
||||
{/* Dial 2: Alcohol */}
|
||||
<div className="bg-white/[0.02] border border-white/5 p-4 rounded-xl flex flex-col items-center text-center">
|
||||
<span className="text-[#E63946] font-industrial text-xl font-bold">{drinks[activeDrink].alcohol}</span>
|
||||
<span className="text-white/30 text-[9px] uppercase tracking-widest font-bold mt-1">{t.alcohol}</span>
|
||||
</div>
|
||||
|
||||
{/* Dial 3: Relax */}
|
||||
<div className="bg-white/[0.02] border border-white/5 p-4 rounded-xl flex flex-col items-center text-center">
|
||||
<span className="text-[#E5A900] font-industrial text-xl font-bold">{drinks[activeDrink].relax}</span>
|
||||
<span className="text-white/30 text-[9px] uppercase tracking-widest font-bold mt-1">{t.relax}</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
{/* Right Column: Large closeup beverage display */}
|
||||
<div className="lg:col-span-5 relative flex justify-center lg:justify-end">
|
||||
<motion.div
|
||||
className="relative w-full max-w-xs h-[420px] rounded-3xl overflow-hidden shadow-2xl border border-white/5 group"
|
||||
initial={{ opacity: 0, x: 40 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.7 }}
|
||||
>
|
||||
{/* Using 8k lemon/citrus flatlay to represent fresh botanical drink prep */}
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src="/sicilia_lemon_heritage.png"
|
||||
alt="Fresh citrus botanic preparation"
|
||||
className="w-full h-full object-cover scale-102 group-hover:scale-105 transition-transform duration-[4000ms]"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black via-transparent to-transparent opacity-40" />
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── FEATURED EXPERIENCES ── */}
|
||||
<section id="experiences" className="py-28 relative z-10 px-6 bg-[#111215]">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="text-center max-w-xl mx-auto mb-20">
|
||||
<span className="text-[#E63946] font-bold text-xs uppercase tracking-widest block mb-2 font-industrial">{t.barrelhouseEvents}</span>
|
||||
<h2 className="font-industrial text-3xl lg:text-4xl font-black uppercase text-white">
|
||||
{t.featuredServices}
|
||||
</h2>
|
||||
<p className="text-white/40 text-xs mt-2 font-medium">
|
||||
{lang === "tr" ? "Özel viski tadım uçuşları ve sommelier eğitim paketleri ayırtın." : "Reserve custom whiskey flights and private sommelier masterclass packages."}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Bento Grid layout */}
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
{hizmetler.map((experience, idx) => {
|
||||
const locServ = getLocalizedService(experience.baslik, experience.aciklama);
|
||||
return (
|
||||
<motion.div
|
||||
key={idx}
|
||||
className="bg-[#18191E] rounded-3xl border border-white/5 overflow-hidden transition-all duration-300 hover:border-[#E63946]/30 flex flex-col justify-between group shadow-sm"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: idx * 0.1 }}
|
||||
whileHover={{ y: -4 }}
|
||||
>
|
||||
{/* Header cover using chef smoke image to represent luxury experience */}
|
||||
<div className="h-48 overflow-hidden relative border-b border-white/5">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={idx === 1 ? "/sicilia_lemon_heritage.png" : "/chef_plating_smoke.png"}
|
||||
alt={locServ.title}
|
||||
className="w-full h-full object-cover scale-102 group-hover:scale-105 transition-transform duration-1000"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/40" />
|
||||
</div>
|
||||
|
||||
<div className="p-8 space-y-4">
|
||||
<h3 className="font-industrial font-black text-xl text-white tracking-wider uppercase leading-snug">
|
||||
{locServ.title}
|
||||
</h3>
|
||||
<p className="text-white/50 text-[11px] leading-relaxed font-medium">
|
||||
{locServ.desc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="px-8 pb-8">
|
||||
<motion.button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="text-[#E63946] group-hover:text-white transition-colors text-[10px] font-bold tracking-[2px] uppercase flex items-center gap-1.5 cursor-pointer"
|
||||
>
|
||||
{t.learnMore}
|
||||
</motion.button>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── RESERVATION RESERVATION RESERVATION ── */}
|
||||
<section id="booking-flow" className="py-24 relative z-10 px-6 border-t border-white/5 bg-[#18191E]/40">
|
||||
<div className="max-w-3xl mx-auto">
|
||||
|
||||
<div className="bg-[#18191E] rounded-3xl p-8 md:p-12 shadow-2xl border border-white/5 relative">
|
||||
<div className="absolute top-0 left-12 right-12 h-0.5 bg-gradient-to-r from-transparent via-[#E63946] to-transparent glowing-bar" />
|
||||
|
||||
<div className="text-center mb-10">
|
||||
<span className="text-[#E63946] font-bold text-xs uppercase tracking-widest block mb-2 font-industrial">{t.masterclassBooking}</span>
|
||||
<h2 className="font-industrial text-3xl md:text-4xl font-black uppercase text-white">
|
||||
{t.scheduleEvent}
|
||||
</h2>
|
||||
<p className="text-white/40 text-xs mt-2 font-medium">
|
||||
{t.formDesc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-5">
|
||||
{[
|
||||
{ label: t.fieldsName, placeholder: lang === "tr" ? "Adınız Soyadınız" : "Your Name", type: "text", full: false },
|
||||
{ label: t.fieldsEmail, placeholder: "you@company.com", type: "email", full: false },
|
||||
{ label: t.fieldsPhone, placeholder: lang === "tr" ? "İrtibat Numarası" : "Contact Number", type: "tel", full: false },
|
||||
{ label: t.fieldsEvent, placeholder: lang === "tr" ? "Viski Tadım Serisi" : "Whiskey Tasting Flight", type: "text", full: false },
|
||||
{ label: t.fieldsNotes, placeholder: t.fieldsNotesPlaceholder, type: "text", full: true },
|
||||
].map((field, idx) => (
|
||||
<div key={idx} className={field.full ? "col-span-2" : "col-span-1"}>
|
||||
<label className="block text-[10px] font-bold text-white/50 mb-1.5 uppercase tracking-widest">{field.label}</label>
|
||||
<input
|
||||
type={field.type}
|
||||
placeholder={field.placeholder}
|
||||
className="w-full px-4 py-3 rounded-xl border border-white/5 bg-[#111215] text-xs text-white placeholder-white/20 focus:outline-none focus:border-[#E63946] focus:ring-1 focus:ring-[#E63946] transition-all font-medium cursor-pointer"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<motion.button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="mt-8 w-full py-4.5 rounded-xl bg-[#E63946] hover:bg-white hover:text-black text-white font-bold text-[10px] tracking-[2.5px] uppercase transition-colors cursor-pointer"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{t.dispatchRequest}
|
||||
</motion.button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── TESTIMONIALS ── */}
|
||||
<section id="testimonials" className="py-28 relative z-10 px-6 bg-[#111215] border-t border-white/5">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="text-center max-w-xl mx-auto mb-20">
|
||||
<span className="text-[#E63946] font-bold text-xs uppercase tracking-widest block mb-2 font-industrial">{t.sommelierReviews}</span>
|
||||
<h2 className="font-industrial text-3xl lg:text-4xl font-black uppercase text-white font-industrial tracking-widest">
|
||||
{t.happyGuests}
|
||||
</h2>
|
||||
<p className="text-white/40 text-xs mt-2 font-medium">
|
||||
{t.happyGuestsDesc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Testimonials 2-Column Grid */}
|
||||
<div className="grid md:grid-cols-2 gap-8">
|
||||
{yorumlar.map((y, yIdx) => (
|
||||
<motion.div
|
||||
key={yIdx}
|
||||
className="bg-[#18191E] border border-white/5 rounded-3xl p-8 flex flex-col justify-between transition-all duration-300 hover:border-[#E63946]/30 group shadow-lg"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: yIdx * 0.1 }}
|
||||
whileHover={{ y: -4 }}
|
||||
>
|
||||
{/* Rating Stars SVG */}
|
||||
<div className="flex gap-1.5 mb-6">
|
||||
{[...Array(5)].map((_, starIdx) => (
|
||||
<svg key={starIdx} className="w-4.5 h-4.5 fill-[#E63946]" viewBox="0 0 24 24">
|
||||
<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
|
||||
</svg>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<p className="text-white/70 text-xs leading-relaxed italic mb-8 font-medium font-serif-editorial">
|
||||
“{y.yorum}”
|
||||
</p>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-full border border-white/10 flex items-center justify-center text-lg bg-[#111215] font-sans-clean select-none font-bold">
|
||||
{y.yazar.charAt(0)}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-industrial text-white text-xs font-black uppercase tracking-wider">
|
||||
{y.yazar}
|
||||
</h4>
|
||||
<span className="text-[9px] text-white/40 uppercase tracking-widest font-bold font-sans-clean">
|
||||
{y.tarih}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── FOOTER ── */}
|
||||
<footer className="bg-[#18191E] border-t border-white/5 pt-24 pb-8 px-6 relative z-10">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="grid md:grid-cols-4 gap-12 pb-16 border-b border-white/5">
|
||||
|
||||
{/* About Column */}
|
||||
<div className="md:col-span-2">
|
||||
<span className="font-industrial text-2xl font-black text-white tracking-wider uppercase mb-4 block">
|
||||
Char<span className="text-[#E63946]">Barrel</span>
|
||||
</span>
|
||||
<p className="text-white/50 text-xs leading-relaxed max-w-sm mb-8 font-medium">
|
||||
{firma.slogan} — Heavy rustic slate-crimson themed barrelhouse coordinates offering masterclass mixology and corporate single malt tastings.
|
||||
</p>
|
||||
<div className="text-white/60 text-xs font-medium space-y-3">
|
||||
<p className="flex items-center gap-2">
|
||||
<svg className="w-4 h-4 text-[#E63946] shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" />
|
||||
<circle cx="12" cy="10" r="3" />
|
||||
</svg>
|
||||
<span className="text-white/80">{firma.adres}</span>
|
||||
</p>
|
||||
<p className="flex items-center gap-2">
|
||||
<svg className="w-4 h-4 text-[#E63946] shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<rect width="20" height="16" x="2" y="4" rx="2" />
|
||||
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
|
||||
</svg>
|
||||
<span className="text-white/80">{firma.email}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Dials Column */}
|
||||
<div>
|
||||
<h4 className="font-industrial text-[#E63946] text-xs font-black uppercase tracking-wider mb-6">
|
||||
{t.artisanalDials}
|
||||
</h4>
|
||||
<div className="space-y-4">
|
||||
{drinks.map(d => (
|
||||
<a
|
||||
key={d.name}
|
||||
href="#drink-selector"
|
||||
className="block text-white/50 hover:text-[#E63946] text-xs transition-colors font-medium uppercase tracking-wider font-industrial"
|
||||
>
|
||||
{d.name} Signature
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Experiences Column */}
|
||||
<div>
|
||||
<h4 className="font-industrial text-[#E63946] text-xs font-black uppercase tracking-wider mb-6">
|
||||
{t.vipServices}
|
||||
</h4>
|
||||
<div className="space-y-4">
|
||||
{hizmetler.map((h, hIdx) => {
|
||||
const locS = getLocalizedService(h.baslik, h.aciklama);
|
||||
return (
|
||||
<a
|
||||
key={hIdx}
|
||||
href="#experiences"
|
||||
className="block text-white/50 hover:text-[#E63946] text-xs transition-colors font-medium"
|
||||
>
|
||||
{locS.title}
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col md:flex-row justify-between items-center pt-8 gap-4 text-white/30 text-xs font-medium">
|
||||
<p>© 2026 {firma.adi}. All rights reserved.</p>
|
||||
<div className="flex gap-4">
|
||||
<a href="#" className="hover:text-white transition-colors">{t.privacyRegs}</a>
|
||||
<span>·</span>
|
||||
<a href="#" className="hover:text-white transition-colors">{t.termsStay}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{/* ── FAST BOOKING SUCCESS MODAL ── */}
|
||||
<AnimatePresence>
|
||||
{showBookingModal && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 flex items-center justify-center p-6 bg-black/80 backdrop-blur-sm"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
<motion.div
|
||||
className="bg-[#18191E] rounded-3xl p-8 max-w-md w-full relative shadow-2xl border border-[#E63946]/20"
|
||||
initial={{ scale: 0.95, y: 20 }}
|
||||
animate={{ scale: 1, y: 0 }}
|
||||
exit={{ scale: 0.95, y: 20 }}
|
||||
>
|
||||
{/* Close Button */}
|
||||
<button
|
||||
className="absolute top-6 right-6 w-8 h-8 rounded-full bg-[#111215] border border-white/5 flex items-center justify-center text-white/40 hover:text-[#E63946] hover:border-[#E63946]/20 transition-all cursor-pointer font-bold"
|
||||
onClick={() => setShowBookingModal(false)}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
{/* Success check indicator */}
|
||||
<div className="w-16 h-16 rounded-2xl bg-[#E63946]/10 border border-[#E63946]/20 flex items-center justify-center mb-6">
|
||||
<svg className="w-8 h-8 stroke-[#E63946] fill-none" viewBox="0 0 24 24" strokeWidth="1.5">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h3 className="font-industrial font-black text-white text-2xl mb-1 uppercase tracking-wider">
|
||||
{t.enquiryActive}
|
||||
</h3>
|
||||
<p className="text-[#E63946] font-mono text-[10px] mb-6 uppercase tracking-widest font-bold">
|
||||
{t.ambassadorActive}
|
||||
</p>
|
||||
|
||||
<p className="text-white/60 text-xs leading-relaxed mb-8 font-medium">
|
||||
{t.enquirySuccess}
|
||||
</p>
|
||||
|
||||
<motion.button
|
||||
className="w-full py-4.5 rounded-xl bg-[#E63946] hover:bg-black hover:text-white text-white font-bold text-[10px] tracking-[2.5px] uppercase cursor-pointer shadow-md shadow-[#E63946]/15"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
onClick={() => setShowBookingModal(false)}
|
||||
>
|
||||
{t.dismiss}
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,890 @@
|
||||
"use client";
|
||||
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { useState, useEffect } from "react";
|
||||
import type { DemoData } from "@/data/demos";
|
||||
|
||||
const fadeUp = {
|
||||
hidden: { opacity: 0, y: 35 },
|
||||
show: { opacity: 1, y: 0, transition: { duration: 0.75, ease: [0.25, 0.46, 0.45, 0.94] as [number, number, number, number] } },
|
||||
};
|
||||
|
||||
const stagger = {
|
||||
hidden: {},
|
||||
show: { transition: { staggerChildren: 0.1 } },
|
||||
};
|
||||
|
||||
const translations = {
|
||||
tr: {
|
||||
navMembership: "Üyelik Programı",
|
||||
navServices: "Hizmetlerimiz",
|
||||
navWorks: "Portföyümüz",
|
||||
navReviews: "Hasta Hikayeleri",
|
||||
navBooking: "Randevu Al",
|
||||
badge: "SEAMLESS DENTAL CLINIC",
|
||||
heroTitlePart1: "Kusursuz",
|
||||
heroTitlePart2: "Ağız ve Diş Sağlığı",
|
||||
heroTitlePart3: "Deneyimi",
|
||||
heroDesc: "Sağlıklı ve özgüvenli bir gülümseme için pürüzsüz ve stressiz bir diş hekimliği deneyimi. Odentries modern klinik koordinatları ile dijital sağlık lüksünü yaşayın.",
|
||||
bookNow: "Randevu Al",
|
||||
contactUs: "İletişim",
|
||||
statTitle1: "Özel Üye Tasarrufu",
|
||||
statDesc1: "Ağız Muayeneleri, Temizlik ve Röntgen dahil olmak üzere Diş Prosedürlerinde %60 - %80 arasında tasarruf sağlayın.",
|
||||
statTitle2: "Gelişmiş Üye Avantajları",
|
||||
statDesc2: "Kozmetik, Restoratif ve Uzmanlık Diş Tedavileri dahil olmak üzere Diğer Tüm Diş Hizmetlerinde %40 Tasarruf Sağlayın.",
|
||||
membershipHeader: "Aileniz İçin Erişilebilir Diş Hekimliği",
|
||||
membershipDesc: "Sevdikleriniz için en iyi diş sağlığı planlarını keşfedin. Muayene, temizlik ve özel estetik tedavilerde benzersiz fiyat avantajlarından yararlanın.",
|
||||
joinedText: "Bu ay 1.200'den fazla üye katıldı",
|
||||
joinBtn: "Üye Olun",
|
||||
servicesHeader: "Ayrıcalıklı Klinik Hizmetleri",
|
||||
worksHeader: "Sağlıklı Gülüşler Burada Başlar",
|
||||
worksDesc: "Daha parlak, daha sağlıklı bir gülümseme ve kalıcı özgüven için uzman diş bakımı ve profesyonel temizlik uygulamaları.",
|
||||
reviewsHeader: "Hasta Görüşleri",
|
||||
bookingHeader: "Online Randevu Oluşturun",
|
||||
bookingDesc: "Hayalinizdeki sağlıklı gülüşe kavuşmak için formu doldurun, sizi arayalım.",
|
||||
fieldsName: "Ad Soyad",
|
||||
fieldsPhone: "Telefon Numarası",
|
||||
fieldsEmail: "E-Posta Adresi",
|
||||
fieldsService: "Hizmet Türü",
|
||||
fieldsDate: "Tercih Edilen Tarih",
|
||||
fieldsNotes: "Şikayetiniz / Notunuz",
|
||||
fieldsNotesPlaceholder: "Belirtmek istediğiniz özel detaylar...",
|
||||
dispatchForm: "RANDEVU TALEP ET",
|
||||
footerDesc: "Ferah ve hijyenik modern klinik ortamında, ağrısız ve en son teknoloji tedavi yöntemleri ile size özel ağız sağlığı çözümleri.",
|
||||
privacyRegs: "Gizlilik Sözleşmesi",
|
||||
termsStay: "Kullanım Şartları",
|
||||
dismiss: "KAPAT",
|
||||
contactTitle: "Hızlı İletişim",
|
||||
contactDesc: "İletişim bilgilerinizi bırakın, en kısa sürede sizi arayalım.",
|
||||
submit: "Gönder",
|
||||
viewAllWorks: "PORTFÖYÜ KEŞFET • PORTFÖYÜ KEŞFET • ",
|
||||
preventTitle: "Diş Çürüklerini Önleme",
|
||||
preventDesc: "Kapsamlı diş muayeneleri ve koruyucu hekimlik uygulamaları ile dişlerinizi koruyoruz.",
|
||||
sparkleTitle: "Işıldayan Temizlik",
|
||||
sparkleDesc: "Profesyonel temizleme ve beyazlatma teknikleriyle parıldayan sağlıklı gülüşler yaratıyoruz.",
|
||||
detectionTitle: "Erken Teşhis İmkanı",
|
||||
detectionDesc: "İleri teknoloji röntgen ve teşhis araçlarıyla sorunları büyümeden yakalıyoruz.",
|
||||
},
|
||||
en: {
|
||||
navMembership: "Membership Plan",
|
||||
navServices: "Our Services",
|
||||
navWorks: "Our Works",
|
||||
navReviews: "Patient Stories",
|
||||
navBooking: "Book Now",
|
||||
badge: "SEAMLESS DENTAL CLINIC",
|
||||
heroTitlePart1: "Seamless",
|
||||
heroTitlePart2: "Dental Care",
|
||||
heroTitlePart3: "Experience",
|
||||
heroDesc: "A smooth and hassle-free dental care experience for a healthy and confident smile. Indulge in digital health luxury structured by Odentries clinic.",
|
||||
bookNow: "Book Now",
|
||||
contactUs: "Contact",
|
||||
statTitle1: "Exclusive Member Savings",
|
||||
statDesc1: "Save 60% - 80% on Dental Procedures, including Oral Exams, Cleanings, and X-Rays.",
|
||||
statTitle2: "Enhanced Member Benefits",
|
||||
statDesc2: "Save 40% on All Other Dental Services, including Cosmetic, Restorative, and Specialty Dental Procedures.",
|
||||
membershipHeader: "Affordable Dental Care for Your Family",
|
||||
membershipDesc: "Unlock optimal dental wellness for your loved ones. Get massive savings on check-ups, cleaning, and specialized cosmetic treatments.",
|
||||
joinedText: "Joined by 1,200+ members this month",
|
||||
joinBtn: "Join Membership",
|
||||
servicesHeader: "Exclusive Clinic Services",
|
||||
worksHeader: "A Healthy Smile Starts Here",
|
||||
worksDesc: "Expert Dental Care and Cleaning Procedures for a Brighter, Healthier Smile and Lasting Confidence.",
|
||||
reviewsHeader: "Patient Testimonials",
|
||||
bookingHeader: "Online Appointment",
|
||||
bookingDesc: "Fill out the appointment details to secure your priority consultation slot with our experts.",
|
||||
fieldsName: "Full Name",
|
||||
fieldsPhone: "Phone Number",
|
||||
fieldsEmail: "Email Address",
|
||||
fieldsService: "Service Category",
|
||||
fieldsDate: "Preferred Date",
|
||||
fieldsNotes: "Notes / Symptoms",
|
||||
fieldsNotesPlaceholder: "Any specific dental notes or requests...",
|
||||
dispatchForm: "REQUEST APPOINTMENT",
|
||||
footerDesc: "Custom dental care solutions designed in an ultra-clean, welcoming clinic layout using advanced high-tech treatment instruments.",
|
||||
privacyRegs: "Privacy Policy",
|
||||
termsStay: "Terms of Service",
|
||||
dismiss: "DISMISS",
|
||||
contactTitle: "Quick Consultation",
|
||||
contactDesc: "Leave your contact details and our medical coordinator will call you back within 15 minutes.",
|
||||
submit: "Submit",
|
||||
viewAllWorks: "VIEW ALL WORKS • VIEW ALL WORKS • ",
|
||||
preventTitle: "Prevent Cavities & Disease",
|
||||
preventDesc: "State-of-the-art checkups and preventative dentistry to protect your raw teeth structure.",
|
||||
sparkleTitle: "Keep Your Teeth Sparkling Clean",
|
||||
sparkleDesc: "Professional scale cleaning and premium laser whitening for an immediate aesthetic update.",
|
||||
detectionTitle: "Early Detection of Dental Issues",
|
||||
detectionDesc: "Advanced high-resolution diagnostic tools to intercept hidden micro-cavities before they expand.",
|
||||
}
|
||||
};
|
||||
|
||||
export default function DentalTemplate({ data }: { data: DemoData }) {
|
||||
const { firma, istatistikler = [], hizmetler = [], projeler = [], yorumlar = [] } = data;
|
||||
const [showBookingModal, setShowBookingModal] = useState(false);
|
||||
const [activeYorum, setActiveYorum] = useState(0);
|
||||
const [lang, setLang] = useState<"tr" | "en">("tr");
|
||||
const [preloader, setPreloader] = useState(true);
|
||||
|
||||
const t = translations[lang];
|
||||
|
||||
// Lenis Smooth Scroll Integration
|
||||
useEffect(() => {
|
||||
let lenis: any;
|
||||
import("@studio-freight/lenis").then(({ default: Lenis }) => {
|
||||
lenis = new Lenis({ duration: 1.2, easing: (x: number) => Math.min(1, 1.001 - Math.pow(2, -10 * x)) });
|
||||
function raf(time: number) { lenis.raf(time); requestAnimationFrame(raf); }
|
||||
requestAnimationFrame(raf);
|
||||
});
|
||||
return () => lenis?.destroy();
|
||||
}, []);
|
||||
|
||||
// Preloader Curtain Timer
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setPreloader(false);
|
||||
}, 1500);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
// Map service icons without generic emojis
|
||||
const getServiceIconSvg = (ikon: string) => {
|
||||
switch (ikon) {
|
||||
case "🦷":
|
||||
return (
|
||||
<svg className="w-6 h-6 stroke-[#1E2E38] fill-none" viewBox="0 0 24 24" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9s2.015-9 4.5-9" />
|
||||
</svg>
|
||||
);
|
||||
case "✨":
|
||||
return (
|
||||
<svg className="w-6 h-6 stroke-[#1E2E38] fill-none" viewBox="0 0 24 24" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9.813 15.904L9 21l-1.813-5.096L2.1 14.1 7.187 13.2 9 8.1l1.813 5.1 5.087.9-5.087.904zM19.071 4.929l-.707 1.414-.707-1.414-.707-.707 1.414-.707.707 1.414.707-1.414.707.707-1.414.707zm-12.02 0l-.707 1.414-.707-1.414-.707-.707 1.414-.707.707 1.414.707-1.414.707.707-1.414.707z" />
|
||||
</svg>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<svg className="w-6 h-6 stroke-[#1E2E38] fill-none" viewBox="0 0 24 24" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const getLocalizedServiceText = (baslik: string) => {
|
||||
if (baslik.includes("Prevent")) return { title: t.preventTitle, desc: t.preventDesc };
|
||||
if (baslik.includes("Sparkling")) return { title: t.sparkleTitle, desc: t.sparkleDesc };
|
||||
return { title: t.detectionTitle, desc: t.detectionDesc };
|
||||
};
|
||||
|
||||
const css = `
|
||||
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@300;400;500;600;700;800;900&family=Sora:wght@300;400;500;600;700;800&display=swap');
|
||||
|
||||
:root {
|
||||
--bg-ivory: #FAF7F2;
|
||||
--bg-mint: #EBF5F0;
|
||||
--text-slate: #1E2E38;
|
||||
--text-dark: #121C22;
|
||||
--color-gold: #D4AF37;
|
||||
}
|
||||
|
||||
.font-elegant {
|
||||
font-family: 'Sora', sans-serif;
|
||||
}
|
||||
|
||||
.font-sans-clean {
|
||||
font-family: 'DM Sans', sans-serif;
|
||||
}
|
||||
|
||||
.spinning-text {
|
||||
animation: spin 24s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.hero-title-clamp {
|
||||
font-size: clamp(38px, 6vw, 85px);
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 0.95;
|
||||
}
|
||||
`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{css}</style>
|
||||
|
||||
{/* ── IMZA AN: CURTAIN REVEAL PRELOADER ── */}
|
||||
<AnimatePresence>
|
||||
{preloader && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 bg-[#1E2E38] flex flex-col items-center justify-center p-6"
|
||||
exit={{
|
||||
clipPath: "polygon(0 0, 100% 0, 100% 0, 0 0)",
|
||||
transition: { duration: 0.85, ease: [0.16, 1, 0.3, 1] }
|
||||
}}
|
||||
>
|
||||
<div className="max-w-md text-center space-y-6">
|
||||
<motion.span
|
||||
className="text-[9px] font-elegant tracking-[4px] uppercase text-[#EBF5F0] block"
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
ODENTRIES CLINIC
|
||||
</motion.span>
|
||||
<div className="h-[1px] w-48 bg-white/10 mx-auto relative overflow-hidden">
|
||||
<motion.div
|
||||
className="absolute inset-y-0 left-0 bg-[#EBF5F0]"
|
||||
initial={{ width: "0%" }}
|
||||
animate={{ width: "100%" }}
|
||||
transition={{ duration: 1.2, ease: "easeInOut" }}
|
||||
/>
|
||||
</div>
|
||||
<motion.h2
|
||||
className="font-elegant text-white/50 text-xs tracking-wider uppercase"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.4, duration: 0.5 }}
|
||||
>
|
||||
interactive prototype
|
||||
</motion.h2>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
<div className="bg-[#FAF7F2] text-[#1E2E38] min-h-screen font-sans-clean selection:bg-[#1E2E38] selection:text-white overflow-hidden relative pb-20">
|
||||
|
||||
{/* Floating cross graphics (+) from reference design */}
|
||||
<div className="absolute inset-0 pointer-events-none z-10">
|
||||
<div className="absolute top-[25%] left-[8%] text-[#1E2E38]/20 text-3xl font-light select-none">+</div>
|
||||
<div className="absolute top-[35%] left-[30%] text-[#1E2E38]/30 text-lg font-light select-none">+</div>
|
||||
<div className="absolute bottom-[20%] left-[28%] text-[#1E2E38]/20 text-3xl font-light select-none">+</div>
|
||||
<div className="absolute top-[20%] right-[32%] text-[#1E2E38]/20 text-2xl font-light select-none">+</div>
|
||||
<div className="absolute bottom-[35%] right-[5%] text-[#1E2E38]/30 text-3xl font-light select-none">+</div>
|
||||
</div>
|
||||
|
||||
{/* ── FLOATING CONCEPT BANNER ── */}
|
||||
<div className="fixed bottom-4 left-4 z-40 bg-[#1E2E38]/90 backdrop-blur-md border border-white/10 px-4 py-2.5 rounded-xl shadow-2xl flex items-center gap-2.5 max-w-sm pointer-events-none select-none">
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-[#EBF5F0] animate-pulse" />
|
||||
<span className="text-[9px] font-elegant uppercase tracking-[1.5px] text-white/90">
|
||||
{lang === "tr" ? "Bu web sitesi Ayris Tech tarafından hazırlanmış bir konsept çalışmasıdır." : "This website is a premium concept prototype designed by Ayris Tech."}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* ── PREMIUM HEADER ── */}
|
||||
<motion.header
|
||||
className="fixed top-4 left-4 right-4 z-50 px-4"
|
||||
initial={{ y: -80, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.85, ease: [0.16, 1, 0.3, 1] }}
|
||||
>
|
||||
<div className="mx-auto max-w-7xl h-20 flex items-center justify-between px-8 bg-white/70 backdrop-blur-xl border border-white/40 rounded-2xl shadow-[0_10px_30px_rgba(30,46,56,0.03)]">
|
||||
{/* Logo */}
|
||||
<a href="#" className="flex items-center gap-2.5 group">
|
||||
<span className="text-lg font-black tracking-tight text-[#1E2E38] font-elegant flex items-center gap-2 uppercase">
|
||||
<svg className="w-5 h-5 text-[#1E2E38]" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z" />
|
||||
<path d="M12 6v12M6 12h12" />
|
||||
</svg>
|
||||
{firma.adi}
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{/* Links */}
|
||||
<nav className="hidden lg:flex items-center gap-8">
|
||||
{[
|
||||
{ label: t.navMembership, href: "#uyelik" },
|
||||
{ label: t.navServices, href: "#hizmetler" },
|
||||
{ label: t.navWorks, href: "#works" },
|
||||
{ label: t.navReviews, href: "#yorumlar" }
|
||||
].map(item => (
|
||||
<a
|
||||
key={item.label}
|
||||
href={item.href}
|
||||
className="text-[10px] font-black tracking-[2px] uppercase text-[#1E2E38]/70 hover:text-[#1E2E38] transition-colors relative py-1 cursor-pointer group"
|
||||
>
|
||||
{item.label}
|
||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-[#1E2E38] transition-all group-hover:w-full" />
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
{/* Language Selector + Action Button */}
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Language Switcher */}
|
||||
<div className="flex items-center gap-1 bg-[#1E2E38]/5 border border-[#1E2E38]/10 rounded-xl p-1 shrink-0">
|
||||
<button
|
||||
onClick={() => setLang("tr")}
|
||||
className={`text-[9px] font-elegant px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "tr" ? "bg-white text-slate-900 shadow-sm" : "text-[#1E2E38]/60 hover:text-[#1E2E38]"
|
||||
}`}
|
||||
>
|
||||
TR
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setLang("en")}
|
||||
className={`text-[9px] font-elegant px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "en" ? "bg-white text-slate-900 shadow-sm" : "text-[#1E2E38]/60 hover:text-[#1E2E38]"
|
||||
}`}
|
||||
>
|
||||
EN
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<motion.button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="text-[10px] font-black tracking-[2.5px] uppercase text-[#FAF7F2] bg-[#1E2E38] hover:bg-[#121C22] px-6 py-3.5 rounded-xl transition-all cursor-pointer shadow-[0_4px_12px_rgba(30,46,56,0.15)] hidden sm:block"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{t.bookNow}
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.header>
|
||||
|
||||
{/* ── HERO SECTION ── */}
|
||||
<section className="relative min-h-screen flex items-center overflow-hidden pt-32 pb-20 px-6">
|
||||
<div className="max-w-7xl mx-auto w-full">
|
||||
<div className="grid lg:grid-cols-12 gap-16 items-center">
|
||||
|
||||
{/* Left Col - Text Content */}
|
||||
<motion.div
|
||||
className="lg:col-span-6 z-20"
|
||||
variants={stagger}
|
||||
initial="hidden"
|
||||
animate="show"
|
||||
>
|
||||
<motion.div
|
||||
variants={fadeUp}
|
||||
className="inline-flex items-center gap-2 text-[10px] font-black uppercase tracking-widest text-[#1E2E38]/60 mb-6 bg-[#1E2E38]/5 border border-[#1E2E38]/10 px-4 py-2 rounded-full"
|
||||
>
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-[#1E2E38] animate-pulse" />
|
||||
{t.badge}
|
||||
</motion.div>
|
||||
|
||||
<motion.h1
|
||||
variants={fadeUp}
|
||||
className="font-elegant font-black text-[#1E2E38] mb-8 hero-title-clamp uppercase"
|
||||
>
|
||||
{t.heroTitlePart1}
|
||||
<br />
|
||||
<span className="italic font-light opacity-90 text-slate-600 lowercase">{t.heroTitlePart2}</span>
|
||||
<br />
|
||||
{t.heroTitlePart3}
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
variants={fadeUp}
|
||||
className="text-[#1E2E38]/70 text-xs lg:text-sm leading-relaxed max-w-md mb-10 font-semibold"
|
||||
>
|
||||
{t.heroDesc}
|
||||
</motion.p>
|
||||
|
||||
<motion.div variants={fadeUp}>
|
||||
<motion.button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="inline-flex items-center gap-3 px-8 py-4.5 rounded-xl bg-[#1E2E38] hover:bg-[#121C22] text-[#FAF7F2] font-black text-[10px] tracking-[2px] uppercase transition-all shadow-[0_5px_15px_rgba(30,46,56,0.1)] cursor-pointer"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{t.bookNow} <span className="text-[10px]">→</span>
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Col - Cropped Smiling Portrait Overlay */}
|
||||
<div className="lg:col-span-6 relative flex justify-center lg:justify-end">
|
||||
<motion.div
|
||||
className="relative w-full max-w-md lg:max-w-lg h-[460px] lg:h-[530px] rounded-3xl overflow-hidden shadow-2xl border border-white/60"
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.8, ease: "easeOut" }}
|
||||
>
|
||||
{/* Background soft lighting */}
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-[#FAF7F2] via-transparent to-transparent z-10 pointer-events-none" />
|
||||
|
||||
{/* Main Generated High-Fidelity Smiling Image */}
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src="/dental_hero.png"
|
||||
alt="Odentries Smiling Model"
|
||||
className="w-full h-full object-cover object-center scale-102 hover:scale-105 transition-transform duration-[4000ms]"
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── SECTION 001: AFFORDABLE CARE & BENTO CARDS ── */}
|
||||
<section id="uyelik" className="py-32 bg-[#FAF7F2] px-6 border-t border-[#1E2E38]/5">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="grid lg:grid-cols-12 gap-16 items-start">
|
||||
|
||||
{/* Left Content */}
|
||||
<motion.div
|
||||
className="lg:col-span-5"
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true }}
|
||||
variants={stagger}
|
||||
>
|
||||
<motion.span
|
||||
variants={fadeUp}
|
||||
className="inline-block text-[10px] font-black uppercase tracking-widest text-[#1E2E38]/50 mb-4"
|
||||
>
|
||||
001 - Join Membership
|
||||
</motion.span>
|
||||
<motion.h2
|
||||
variants={fadeUp}
|
||||
className="text-4xl lg:text-5xl font-elegant font-black text-[#1E2E38] leading-tight mb-6 uppercase"
|
||||
>
|
||||
{t.membershipHeader}
|
||||
</motion.h2>
|
||||
<motion.p
|
||||
variants={fadeUp}
|
||||
className="text-[#1E2E38]/70 text-xs lg:text-sm leading-relaxed mb-10 font-semibold"
|
||||
>
|
||||
{t.membershipDesc}
|
||||
</motion.p>
|
||||
|
||||
{/* Patient Pile from Reference Design */}
|
||||
<motion.div
|
||||
variants={fadeUp}
|
||||
className="flex items-center gap-6 mb-8 font-semibold"
|
||||
>
|
||||
<div className="flex -space-x-3 select-none">
|
||||
{["👨⚕️", "👩⚕️", "🧑⚕️", "✨"].map((emoji, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="w-9 h-9 rounded-full bg-white border-2 border-[#FAF7F2] flex items-center justify-center text-sm shadow-sm"
|
||||
>
|
||||
{emoji}
|
||||
</div>
|
||||
))}
|
||||
<div className="w-9 h-9 rounded-full bg-[#1E2E38] border-2 border-[#FAF7F2] flex items-center justify-center text-[10px] text-[#FAF7F2] font-black">
|
||||
+
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-xs text-[#1E2E38]/80">
|
||||
{t.joinedText}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="px-8 py-4 rounded-xl bg-[#1E2E38] hover:bg-[#121C22] text-[#FAF7F2] font-black text-[10px] tracking-[2.5px] uppercase transition-colors"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{t.joinBtn} <span className="text-[9px]">→</span>
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Bento Cards */}
|
||||
<div className="lg:col-span-7 grid md:grid-cols-2 gap-6 w-full">
|
||||
|
||||
{/* Card 1: 80% Savings */}
|
||||
<motion.div
|
||||
className="bg-[#EBF5F0] rounded-3xl p-8 border border-white flex flex-col justify-between h-[320px] relative overflow-hidden group shadow-sm"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6 }}
|
||||
whileHover={{ y: -6 }}
|
||||
>
|
||||
<div className="flex justify-between items-start">
|
||||
<span className="text-5xl font-black text-[#1E2E38] font-elegant group-hover:scale-102 transition-transform">
|
||||
{istatistikler[0]?.deger || "80%"}
|
||||
</span>
|
||||
<span className="text-2xl font-light text-[#1E2E38]/30 shrink-0 select-none">+</span>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-xs font-black text-[#1E2E38] mb-2 uppercase tracking-wide">{t.statTitle1}</h4>
|
||||
<p className="text-[#1E2E38]/60 text-[11px] leading-relaxed font-semibold">
|
||||
{t.statDesc1}
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Card 2: 40% Benefits */}
|
||||
<motion.div
|
||||
className="bg-[#1E2E38] rounded-3xl p-8 flex flex-col justify-between h-[320px] relative overflow-hidden group shadow-xl"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6, delay: 0.15 }}
|
||||
whileHover={{ y: -6 }}
|
||||
>
|
||||
<div className="flex justify-between items-start">
|
||||
<span className="text-5xl font-black text-[#FAF7F2] font-elegant group-hover:scale-102 transition-transform">
|
||||
{istatistikler[1]?.deger || "40%"}
|
||||
</span>
|
||||
<span className="text-2xl font-light text-[#FAF7F2]/30 shrink-0 select-none">+</span>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-xs font-black text-[#FAF7F2] mb-2 uppercase tracking-wide">{t.statTitle2}</h4>
|
||||
<p className="text-[#FAF7F2]/60 text-[11px] leading-relaxed font-semibold">
|
||||
{t.statDesc2}
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── CORE SERVICES CARD ROW ── */}
|
||||
<section id="hizmetler" className="py-24 bg-white px-6">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="text-center max-w-xl mx-auto mb-20">
|
||||
<span className="text-[#1E2E38]/50 font-black text-[10px] uppercase tracking-widest block mb-2 font-elegant">{t.navServices}</span>
|
||||
<h2 className="font-elegant text-3xl lg:text-4xl font-black uppercase text-[#1E2E38] tracking-tight">
|
||||
{t.servicesHeader}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-3 gap-6">
|
||||
{hizmetler.map((h, i) => {
|
||||
const item = getLocalizedServiceText(h.baslik);
|
||||
return (
|
||||
<motion.div
|
||||
key={i}
|
||||
className="bg-[#FAF7F2]/50 hover:bg-[#FAF7F2] rounded-3xl p-8 border border-gray-100 hover:border-[#1E2E38]/10 transition-all duration-300 flex flex-col justify-between h-80 group cursor-default"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: i * 0.1 }}
|
||||
whileHover={{ y: -4 }}
|
||||
>
|
||||
<div>
|
||||
<div className="w-12 h-12 rounded-2xl bg-white border border-[#1E2E38]/5 flex items-center justify-center mb-6 transition-transform group-hover:scale-105 shadow-sm">
|
||||
{getServiceIconSvg(h.ikon)}
|
||||
</div>
|
||||
<h3 className="font-elegant font-bold text-[#1E2E38] text-base mb-3 leading-snug">
|
||||
{item.title}
|
||||
</h3>
|
||||
<p className="text-gray-400 text-xs leading-relaxed font-semibold">
|
||||
{item.desc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="text-[#1E2E38] font-black text-[9px] tracking-[2.5px] uppercase flex items-center gap-1 cursor-pointer hover:text-opacity-80 transition-colors pt-4 border-t border-gray-100"
|
||||
>
|
||||
{lang === "tr" ? "DAHA FAZLA BİLGİ →" : "LEARN MORE →"}
|
||||
</button>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── SECTION 002: OUR WORKS / PORTFOLIO ── */}
|
||||
<section id="works" className="py-32 bg-[#EBF5F0] px-6 border-t border-[#1E2E38]/5">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex flex-col md:flex-row md:items-end justify-between mb-16 gap-6">
|
||||
<motion.div
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true }}
|
||||
variants={stagger}
|
||||
>
|
||||
<motion.span
|
||||
variants={fadeUp}
|
||||
className="inline-block text-[10px] font-black uppercase tracking-widest text-[#1E2E38]/50 mb-4"
|
||||
>
|
||||
002 - Our Works
|
||||
</motion.span>
|
||||
<motion.h2
|
||||
variants={fadeUp}
|
||||
className="text-4xl lg:text-5xl font-elegant font-black text-[#1E2E38] leading-tight uppercase"
|
||||
>
|
||||
{t.worksHeader}
|
||||
</motion.h2>
|
||||
</motion.div>
|
||||
|
||||
{/* Spinning Circle badge and text details */}
|
||||
<motion.div
|
||||
className="flex items-center gap-6 max-w-sm font-semibold"
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.7 }}
|
||||
>
|
||||
{/* Spinning Badge */}
|
||||
<div className="relative w-20 h-20 shrink-0 flex items-center justify-center select-none">
|
||||
<svg className="absolute w-full h-full spinning-text" viewBox="0 0 100 100">
|
||||
<path id="circlePath" d="M 50, 50 m -37, 0 a 37,37 0 1,1 74,0 a 37,37 0 1,1 -74,0" fill="none" />
|
||||
<text className="font-elegant font-black text-[8px] fill-[#1E2E38] tracking-[1px]">
|
||||
<textPath xlinkHref="#circlePath">
|
||||
{t.viewAllWorks}
|
||||
</textPath>
|
||||
</text>
|
||||
</svg>
|
||||
<span className="text-base text-[#1E2E38] font-bold">↗</span>
|
||||
</div>
|
||||
<p className="text-[#1E2E38]/70 text-xs leading-relaxed">
|
||||
{t.worksDesc}
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* 3 Column Image Cards Grid */}
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
{projeler.map((p, i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
className="flex flex-col group justify-between"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6, delay: i * 0.15 }}
|
||||
whileHover={{ y: -6 }}
|
||||
>
|
||||
<div>
|
||||
{/* Photo container */}
|
||||
<div className="h-[360px] rounded-3xl overflow-hidden mb-5 shadow-lg border border-white/20 relative">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={p.resim}
|
||||
alt={p.baslik}
|
||||
className="w-full h-full object-cover scale-102 group-hover:scale-105 transition-transform duration-1000"
|
||||
/>
|
||||
</div>
|
||||
{/* Text details */}
|
||||
<h3 className="font-elegant font-bold text-[#1E2E38] text-base mb-1 uppercase tracking-wide leading-tight">{p.baslik}</h3>
|
||||
<p className="text-gray-500 text-xs font-semibold">{lang === "tr" ? "Estetik ve Dayanıklı Sonuçlar" : "Impressive, high-durability smile aesthetics"}</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="text-[#1E2E38] font-black text-[9px] tracking-[2px] uppercase flex items-center gap-1 cursor-pointer hover:text-opacity-80 transition-colors pt-4 shrink-0"
|
||||
>
|
||||
{lang === "tr" ? "VAKAYI İNCELE →" : "VIEW CASE →"}
|
||||
</button>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── YORUMLAR (TESTIMONIALS) ── */}
|
||||
<section id="yorumlar" className="py-24 bg-white px-6">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="mb-16 text-center">
|
||||
<span className="inline-block text-[10px] font-black uppercase tracking-widest text-[#1E2E38]/50 mb-4 font-elegant">
|
||||
003 - Patient Stories
|
||||
</span>
|
||||
<h2 className="text-3xl lg:text-4xl font-elegant font-black text-[#1E2E38] uppercase">
|
||||
{t.reviewsHeader}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="relative">
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.div
|
||||
key={activeYorum}
|
||||
className="bg-[#FAF7F2] border border-[#1E2E38]/5 rounded-3xl p-10 max-w-2xl mx-auto shadow-sm"
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.95 }}
|
||||
transition={{ duration: 0.4 }}>
|
||||
<div className="flex gap-1.5 mb-6 justify-center">
|
||||
{[...Array(yorumlar[activeYorum]?.puan || 5)].map((_, i) => (
|
||||
<svg key={i} className="w-4.5 h-4.5 fill-[#1E2E38]" viewBox="0 0 24 24">
|
||||
<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
|
||||
</svg>
|
||||
))}
|
||||
</div>
|
||||
<p className="text-[#1E2E38]/80 text-base leading-relaxed italic text-center mb-8 font-semibold">
|
||||
“{yorumlar[activeYorum]?.yorum}”
|
||||
</p>
|
||||
<div className="flex items-center gap-3.5 justify-center">
|
||||
<div className="w-10 h-10 rounded-full flex items-center justify-center text-sm bg-white shadow-sm border border-[#1E2E38]/5 font-bold font-elegant select-none">
|
||||
{yorumlar[activeYorum]?.yazar.charAt(0)}
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-[#1E2E38] font-bold text-xs uppercase tracking-wide leading-tight">{yorumlar[activeYorum]?.yazar}</p>
|
||||
<p className="text-gray-400 text-[10px] uppercase font-black font-elegant tracking-wider mt-0.5">{yorumlar[activeYorum]?.tarih}</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
|
||||
<div className="flex justify-center gap-2.5 mt-8">
|
||||
{yorumlar.map((_, i) => (
|
||||
<button key={i} onClick={() => setActiveYorum(i)}
|
||||
className="w-2.5 h-2.5 rounded-full transition-all cursor-pointer"
|
||||
style={{ background: i === activeYorum ? "#1E2E38" : "rgba(30,46,56,0.15)",
|
||||
transform: i === activeYorum ? "scale(1.3)" : "scale(1)" }} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── RANDEVU AL (APPOINTMENT SECTION) ── */}
|
||||
<section id="randevu" className="py-24 bg-[#FAF7F2] px-6 border-t border-[#1E2E38]/5">
|
||||
<div className="max-w-3xl mx-auto">
|
||||
<div className="bg-white rounded-3xl p-8 md:p-12 shadow-premium border border-white">
|
||||
<div className="text-center mb-10">
|
||||
<span className="inline-block text-[10px] font-black uppercase tracking-widest text-[#1E2E38]/50 mb-4 font-elegant">
|
||||
004 - Online Appointment
|
||||
</span>
|
||||
<h2 className="text-3xl md:text-4xl font-elegant font-black text-[#1E2E38] uppercase tracking-tight">
|
||||
{t.bookingHeader}
|
||||
</h2>
|
||||
<p className="text-gray-400 text-xs mt-2 font-semibold">
|
||||
{t.bookingDesc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4 font-semibold">
|
||||
{[
|
||||
{ label: t.fieldsName, placeholder: lang === "tr" ? "Adınız Soyadınız" : "Your Full Name", type: "text", full: false },
|
||||
{ label: t.fieldsPhone, placeholder: "05xx xxx xx xx", type: "tel", full: false },
|
||||
{ label: t.fieldsEmail, placeholder: "ornek@mail.com", type: "email", full: false },
|
||||
{ label: t.fieldsService, placeholder: "", type: "select", full: false },
|
||||
{ label: t.fieldsDate, placeholder: "", type: "date", full: false },
|
||||
{ label: t.fieldsNotes, placeholder: t.fieldsNotesPlaceholder, type: "text", full: true },
|
||||
].map((field, i) => (
|
||||
<div key={i} className={field.full ? "col-span-2" : "col-span-2 sm:col-span-1"}>
|
||||
<label className="block text-[10px] font-black text-[#1E2E38]/60 mb-1.5 uppercase tracking-wider">{field.label}</label>
|
||||
{field.type === "select" ? (
|
||||
<select className="w-full px-4 py-3.5 rounded-xl border border-gray-200 text-xs text-slate-800 focus:outline-none focus:ring-2 focus:ring-[#1E2E38] bg-gray-50/50 transition-all font-semibold cursor-pointer">
|
||||
<option>{lang === "tr" ? "Diş Çürüklerini Önleme" : "Prevent Cavities & Disease"}</option>
|
||||
<option>{lang === "tr" ? "Işıldayan Temizlik" : "Teeth Sparkling Cleaning"}</option>
|
||||
<option>{lang === "tr" ? "Diş Düzeltme" : "Teeth Straightening"}</option>
|
||||
<option>{lang === "tr" ? "Diş İmplantı" : "Dental Implant"}</option>
|
||||
</select>
|
||||
) : (
|
||||
<input type={field.type} placeholder={field.placeholder}
|
||||
className="w-full px-4 py-3.5 rounded-xl border border-gray-200 text-xs focus:outline-none focus:ring-2 focus:ring-[#1E2E38] bg-gray-50/50 transition-all placeholder-[#1E2E38]/20 font-semibold" />
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<motion.button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="mt-8 w-full py-4.5 rounded-xl text-[#FAF7F2] font-black text-xs bg-[#1E2E38] hover:bg-[#121C22] uppercase tracking-widest cursor-pointer shadow-[0_5px_15px_rgba(30,46,56,0.15)]"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
📅 {t.dispatchForm}
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── FOOTER ── */}
|
||||
<footer className="bg-[#121C22] border-t border-white/10 px-6 pt-24 pb-8">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="grid md:grid-cols-4 gap-12 pb-16 border-b border-white/5">
|
||||
<div className="md:col-span-2">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<svg className="w-5 h-5 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z" />
|
||||
<path d="M12 6v12M6 12h12" />
|
||||
</svg>
|
||||
<span className="font-bold text-white text-lg font-elegant uppercase tracking-wide">{firma.adi}</span>
|
||||
</div>
|
||||
<p className="text-white/40 text-xs leading-relaxed max-w-sm mb-8 font-semibold">{t.footerDesc}</p>
|
||||
<div className="text-white/50 text-xs font-semibold space-y-3">
|
||||
<p className="flex items-center gap-2">📍 <span className="text-white/80">{firma.adres}</span></p>
|
||||
<p className="flex items-center gap-2">📞 <span className="text-white/80">{firma.telefon}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-elegant text-white font-bold text-xs uppercase tracking-wider mb-6">{t.navServices}</h4>
|
||||
{hizmetler.map((h, i) => {
|
||||
const s = getLocalizedServiceText(h.baslik);
|
||||
return (
|
||||
<a key={i} href="#hizmetler" className="block text-white/40 text-xs mb-3 hover:text-white transition-colors font-semibold">{s.title}</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-elegant text-white font-bold text-xs uppercase tracking-wider mb-6">Odentries</h4>
|
||||
{[t.navMembership, t.navServices, t.navWorks, t.navReviews].map((item) => (
|
||||
<a key={item} href="#" className="block text-white/40 text-xs mb-3 hover:text-white transition-colors font-semibold">{item}</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col md:flex-row justify-between items-center pt-8 gap-4 text-white/30 text-xs font-semibold">
|
||||
<p>© 2026 {firma.adi}. All rights reserved.</p>
|
||||
<div className="flex gap-4">
|
||||
<a href="#" className="hover:text-white transition-colors">{t.privacyRegs}</a>
|
||||
<span>·</span>
|
||||
<a href="#" className="hover:text-white transition-colors">{t.termsStay}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{/* ── BOOKING MODAL ── */}
|
||||
<AnimatePresence>
|
||||
{showBookingModal && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 flex items-center justify-center p-6 bg-black/60 backdrop-blur-sm"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
<motion.div
|
||||
className="bg-white rounded-3xl p-8 max-w-md w-full relative shadow-2xl border border-gray-100"
|
||||
initial={{ scale: 0.95, y: 20 }}
|
||||
animate={{ scale: 1, y: 0 }}
|
||||
exit={{ scale: 0.95, y: 20 }}
|
||||
>
|
||||
<button
|
||||
className="absolute top-6 right-6 w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center font-bold text-gray-500 hover:bg-gray-200 transition-colors cursor-pointer"
|
||||
onClick={() => setShowBookingModal(false)}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
<h3 className="font-elegant font-black text-[#1E2E38] text-2xl mb-1 uppercase tracking-wide">{t.contactTitle}</h3>
|
||||
<p className="text-gray-400 text-xs mb-6 font-semibold">{t.contactDesc}</p>
|
||||
|
||||
<div className="space-y-4 font-semibold">
|
||||
<div>
|
||||
<label className="block text-[10px] font-black text-gray-500 mb-1.5 uppercase tracking-wider">{t.fieldsName}</label>
|
||||
<input type="text" className="w-full px-4 py-3.5 rounded-xl border bg-gray-50/50 text-xs focus:outline-none focus:ring-2 focus:ring-[#1E2E38]" placeholder="John Doe" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-[10px] font-black text-gray-500 mb-1.5 uppercase tracking-wider">{t.fieldsPhone}</label>
|
||||
<input type="tel" className="w-full px-4 py-3.5 rounded-xl border bg-gray-50/50 text-xs focus:outline-none focus:ring-2 focus:ring-[#1E2E38]" placeholder="05xx xxx xx xx" />
|
||||
</div>
|
||||
<motion.button
|
||||
className="w-full py-4 rounded-xl bg-[#1E2E38] text-[#FAF7F2] font-black text-xs hover:bg-[#121C22] transition-colors mt-2 cursor-pointer shadow-[0_4px_12px_rgba(30,46,56,0.15)] uppercase tracking-widest"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
onClick={() => setShowBookingModal(false)}
|
||||
>
|
||||
{t.submit}
|
||||
</motion.button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,845 @@
|
||||
"use client";
|
||||
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { useState, useEffect } from "react";
|
||||
import type { DemoData } from "@/data/demos";
|
||||
|
||||
const fadeUp = {
|
||||
hidden: { opacity: 0, y: 35 },
|
||||
show: { opacity: 1, y: 0, transition: { duration: 0.75, ease: [0.25, 0.46, 0.45, 0.94] as [number, number, number, number] } },
|
||||
};
|
||||
|
||||
const stagger = {
|
||||
hidden: {},
|
||||
show: { transition: { staggerChildren: 0.1 } },
|
||||
};
|
||||
|
||||
const translations = {
|
||||
tr: {
|
||||
navBook: "Rezervasyon",
|
||||
navSuites: "Özel Süitler",
|
||||
navExp: "Deneyimler",
|
||||
navRev: "Yorumlar",
|
||||
badge: "BUTİK LÜKS RESORT",
|
||||
heroTail: "sizi bekliyor",
|
||||
heroDesc: "Cal Vestam'da eşsiz bir huzura dalın. Fethiye'nin nefes kesici mavi sırtlarının üzerinde, size özel cam kenarlı sonsuzluk havuzları ve organik zeytin yaprağı masaj terapileri sunuyoruz.",
|
||||
reserveNow: "Rezervasyon Yap",
|
||||
planEscape: "TATİLİ PLANLA",
|
||||
resortServices: "RESORT HİZMETLERİ",
|
||||
checkAvailability: "UYGUNLUK DURUMU",
|
||||
scheduleEscape: "RESORT TATİLİNİZİ PLANLAYIN",
|
||||
scheduleDesc: "Benzersiz deniz manzaralı teras süitinizde yerinizi ayırtmak için tarihlerinizi belirleyin.",
|
||||
checkin: "GİRİŞ TARİHİ",
|
||||
checkout: "ÇIKIŞ TARİHİ",
|
||||
adults: "YETİŞKİN",
|
||||
kids: "ÇOCUK (12 YAŞ ALTI)",
|
||||
guests: "Misafir",
|
||||
kidsLabel: "Çocuk",
|
||||
guarantee: "Rezervasyonlar, giriş esnasında taze toplanmış narenciye kokteyli ikramı ile en iyi fiyat garantisini kilitler.",
|
||||
confirmDetails: "TARİHLERİ ONAYLA",
|
||||
suitesTitle: "TERAS SÜİTLERİ",
|
||||
suitesHeader: "SEÇKİN SÜİTLER",
|
||||
suitesDesc: "Özel dokuma keten serimler, doğal zeytinyağlı sabunlar ve kesintisiz deniz panoraması ile mimari lüksü deneyimleyin.",
|
||||
secureRes: "REZERVASYON YAP →",
|
||||
diaries: "Misafir Defteri",
|
||||
lovedGuests: "LOVED BY GUESTS",
|
||||
lovedDesc: "Seçkin gezginlerin ve küresel mimari yazarlarının Cal Vestam deneyimlerini keşfedin.",
|
||||
vipCoords: "VIP KOORDİNATLAR",
|
||||
conciergeActive: "Resort Concierge Aktif",
|
||||
checkInOutDetails: "Giriş: 15:00 · Çıkış: 11:00",
|
||||
boutiqueLeisures: "BUTİK AYRICALIKLAR",
|
||||
privacyRegs: "Gizlilik Sözleşmesi",
|
||||
termsStay: "Konaklama Şartları",
|
||||
dismiss: "KAPAT",
|
||||
enquiryActive: "BAŞVURU ALINDI",
|
||||
ambassadorActive: "Cal Vestam Concierge Aktif",
|
||||
enquirySuccess: "Akdeniz resort rezervasyon koordinatlarınızı kaydettik. Özel misafir elçimiz giriş işlemlerinizi öncelikli olarak tamamlamak için sizinle iletişime geçecektir. Teşekkürler!",
|
||||
|
||||
// Suite details
|
||||
suite1Title: "PANORAMİK VESTAM SÜİT",
|
||||
suite1Desc: "Fethiye'nin mavi sırtlarına bakan özel havuzlu balkon ve premium pamuklu yatak tasarımı.",
|
||||
suite2Title: "NARENCİYE BAHÇE SÜİTİ",
|
||||
suite2Desc: "Çevreleyen zeytin ve limon bahçeleriyle entegre, gün ışığıyla dolu ferah konaklama deneyimi.",
|
||||
suite3Title: "AKDENİZ VİLLASI",
|
||||
suite3Desc: "Özel sonsuzluk havuzları, kişisel uşak hizmeti ve gün batımı terasları sunan tam villa kiralama.",
|
||||
|
||||
// Welcome orchards
|
||||
welcomeTitle: "Karşılama İkramları",
|
||||
welcomeDesc: "MİSAFİRLERİMİZ İÇİN TAZE NARENCİYE KOKTEYLLERİ",
|
||||
},
|
||||
en: {
|
||||
navBook: "Book stay",
|
||||
navSuites: "Exclusive suites",
|
||||
navExp: "Experiences",
|
||||
navRev: "Guest reviews",
|
||||
badge: "BOUTIQUE LUXURY RESORT",
|
||||
heroTail: "awaits your arrival",
|
||||
heroDesc: "Submerge into sheer tranquility at Cal Vestam. Situated directly above Muğla's gorgeous blue ridges, we stage exclusive glass-edge infinity pools and wellness stone therapy.",
|
||||
reserveNow: "Reserve Now",
|
||||
planEscape: "PLAN ESCAPE",
|
||||
resortServices: "RESORT SERVICES",
|
||||
checkAvailability: "Check availability",
|
||||
scheduleEscape: "SCHEDULE YOUR RESORT ESCAPE",
|
||||
scheduleDesc: "Allocate your exclusive sea-view panoramic terrace suite directly inside our luxury booking engine.",
|
||||
checkin: "CHECK-IN DATE",
|
||||
checkout: "CHECK-OUT DATE",
|
||||
adults: "ADULTS",
|
||||
kids: "KIDS (UNDER 12)",
|
||||
guests: "Guests",
|
||||
kidsLabel: "Kids",
|
||||
guarantee: "Reservations lock in our premium best-rate guarantee with local welcome orchard citrus cocktail packages upon check-in.",
|
||||
confirmDetails: "CONFIRM DETAILS",
|
||||
suitesTitle: "Terrace suites",
|
||||
suitesHeader: "EXCLUSIVE SUITES",
|
||||
suitesDesc: "Experience high-end architecture layered with bespoke linen, local natural olive oil soaps, and floor-to-ceiling sea panoramas.",
|
||||
secureRes: "SECURE RESERVATION →",
|
||||
diaries: "Guest Diaries",
|
||||
lovedGuests: "LOVED BY GUESTS",
|
||||
lovedDesc: "Hear what prominent travelers and global architecture writers experience inside Cal Vestam.",
|
||||
vipCoords: "VIP COORDINATES",
|
||||
conciergeActive: "Concierge 24 Hours Active",
|
||||
checkInOutDetails: "Check In: 3:00 PM · Check Out: 11:00 AM",
|
||||
boutiqueLeisures: "BOUTIQUE LEISURES",
|
||||
privacyRegs: "Privacy Regulations",
|
||||
termsStay: "Terms of Stay",
|
||||
dismiss: "DISMISS",
|
||||
enquiryActive: "ENQUIRY ACTIVE",
|
||||
ambassadorActive: "Cal Vestam Concierge Active",
|
||||
enquirySuccess: "We have registered your Mediterranean resort reservation coordinates. A personal guest ambassador has locked your priority check-in slot. Thank you!",
|
||||
|
||||
// Suite details
|
||||
suite1Title: "PANORAMIC VESTAM SUITE",
|
||||
suite1Desc: "Private pool balcony looking directly over Fethiye blue ridges with premium cotton layout.",
|
||||
suite2Title: "CITRUS GARDEN SUITE",
|
||||
suite2Desc: "Cozy light-filled suite integrated with surrounding organic welcome olive and lemon orchards.",
|
||||
suite3Title: "MEDITERRANEAN VILLA",
|
||||
suite3Desc: "Executive buyout layout offering private infinity pools, automated concierge, and sunset lounges.",
|
||||
|
||||
// Welcome orchards
|
||||
welcomeTitle: "Welcome Orchards",
|
||||
welcomeDesc: "CITRUS COCKTAILS FOR GUESTS",
|
||||
}
|
||||
};
|
||||
|
||||
export default function HotelTemplate1({ data }: { data: DemoData }) {
|
||||
const { firma, istatistikler = [], hizmetler = [], yorumlar = [] } = data;
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [adults, setAdults] = useState(2);
|
||||
const [kids, setKids] = useState(0);
|
||||
const [lang, setLang] = useState<"tr" | "en">("tr");
|
||||
const [preloader, setPreloader] = useState(true);
|
||||
|
||||
const t = translations[lang];
|
||||
|
||||
// 1. Lenis Smooth Scroll Integration
|
||||
useEffect(() => {
|
||||
let lenis: any;
|
||||
import("@studio-freight/lenis").then(({ default: Lenis }) => {
|
||||
lenis = new Lenis({ duration: 1.2, easing: (t: number) => Math.min(1, 1.001 - Math.pow(2, -10 * t)) });
|
||||
function raf(time: number) { lenis.raf(time); requestAnimationFrame(raf); }
|
||||
requestAnimationFrame(raf);
|
||||
});
|
||||
return () => lenis?.destroy();
|
||||
}, []);
|
||||
|
||||
// 2. Preloader Curtain Timer
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setPreloader(false);
|
||||
}, 1500);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
// Localized statistics
|
||||
const getLocalizedStat = (etiket: string) => {
|
||||
if (etiket.includes("Suites")) return lang === "tr" ? "İmza Deniz Süiti" : "Signature Sea Suites";
|
||||
if (etiket.includes("Pools")) return lang === "tr" ? "Panoramik Havuz" : "Panoramic Infinity Pools";
|
||||
if (etiket.includes("Experience")) return lang === "tr" ? "Misafir Memnuniyeti" : "Guest Experience Index";
|
||||
return lang === "tr" ? "Doğal Zeytinyağı Sabun & Spa" : "Natural Olive Oil Soap & Spa";
|
||||
};
|
||||
|
||||
// Localized services
|
||||
const getLocalizedService = (baslik: string, aciklama: string) => {
|
||||
if (baslik.includes("POOL")) {
|
||||
return {
|
||||
title: lang === "tr" ? "SONSUZLUK VESTAM HAVUZU" : "INFINITY VESTAM POOL",
|
||||
desc: lang === "tr" ? "Fethiye'nin mavi sırtlarına bakan cam kenarlı, ödüllü sonsuzluk havuzlarımızın keyfini çıkarın." : aciklama
|
||||
};
|
||||
}
|
||||
if (baslik.includes("SPA")) {
|
||||
return {
|
||||
title: lang === "tr" ? "REHIAL SPA TERAPİSİ" : "REHIAL SPA THERAPY",
|
||||
desc: lang === "tr" ? "Yerel uzmanlar tarafından tasarlanan organik zeytin yaprağı taş masajları ve mineral tuzlu hidroterapi ile yenilenin." : aciklama
|
||||
};
|
||||
}
|
||||
return {
|
||||
title: lang === "tr" ? "AÇIK HAVA TERAS YEMEĞİ" : "AL-FRESCO TERRACE DINING",
|
||||
desc: lang === "tr" ? "Akdeniz zeytin ağaçlarının altında taze bahçe malzemeleri ve soğuk sıkım narenciye lezzetlerinin tadını çıkarın." : aciklama
|
||||
};
|
||||
};
|
||||
|
||||
const css = `
|
||||
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;1,400&family=Inter:wght@300;400;500;600;700;800;900&display=swap');
|
||||
|
||||
:root {
|
||||
--color-resort-teal: #14B8A6;
|
||||
--color-resort-sand: #FAF8F5;
|
||||
--color-resort-charcoal: #0F172A;
|
||||
--color-resort-gold: #D4AF37;
|
||||
}
|
||||
|
||||
.font-serif-editorial {
|
||||
font-family: 'Playfair Display', Georgia, serif;
|
||||
}
|
||||
|
||||
.font-sans-resort {
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
|
||||
.bg-light-mesh {
|
||||
background-image:
|
||||
radial-gradient(circle at 0% 0%, rgba(20, 184, 166, 0.04) 0%, transparent 40%),
|
||||
radial-gradient(circle at 100% 100%, rgba(212, 175, 55, 0.03) 0%, transparent 50%);
|
||||
}
|
||||
|
||||
.shadow-premium {
|
||||
box-shadow: 0 20px 40px -15px rgba(15, 23, 42, 0.05);
|
||||
}
|
||||
|
||||
.hero-title-clamp {
|
||||
font-size: clamp(38px, 6vw, 90px);
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 0.95;
|
||||
}
|
||||
`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{css}</style>
|
||||
|
||||
{/* ── IMZA AN: CURTAIN REVEAL PRELOADER ── */}
|
||||
<AnimatePresence>
|
||||
{preloader && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 bg-[#0F172A] flex flex-col items-center justify-center p-6"
|
||||
exit={{
|
||||
clipPath: "polygon(0 0, 100% 0, 100% 0, 0 0)",
|
||||
transition: { duration: 0.85, ease: [0.16, 1, 0.3, 1] }
|
||||
}}
|
||||
>
|
||||
<div className="max-w-md text-center space-y-6">
|
||||
<motion.span
|
||||
className="text-[9px] font-black tracking-[4px] uppercase text-[#14B8A6] block"
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
CAL VESTAM RESORT
|
||||
</motion.span>
|
||||
<div className="h-[1px] w-48 bg-white/10 mx-auto relative overflow-hidden">
|
||||
<motion.div
|
||||
className="absolute inset-y-0 left-0 bg-[#14B8A6]"
|
||||
initial={{ width: "0%" }}
|
||||
animate={{ width: "100%" }}
|
||||
transition={{ duration: 1.2, ease: "easeInOut" }}
|
||||
/>
|
||||
</div>
|
||||
<motion.h2
|
||||
className="font-serif-editorial text-white text-lg italic font-light tracking-wider"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.4, duration: 0.5 }}
|
||||
>
|
||||
interactive prototype
|
||||
</motion.h2>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* MEDITERRANEAN RESORT LIGHT THEME */}
|
||||
<div className="bg-[#FAF8F5] text-[#0F172A] min-h-screen font-sans-resort selection:bg-[#14B8A6] selection:text-white overflow-hidden relative bg-light-mesh pb-20">
|
||||
|
||||
{/* Floating Ambient Orbs */}
|
||||
<div className="absolute top-[10%] left-[-15%] w-[600px] h-[600px] bg-[#14B8A6]/3 blur-[120px] rounded-full pointer-events-none z-0" />
|
||||
<div className="absolute bottom-[20%] right-[-15%] w-[600px] h-[600px] bg-[#D4AF37]/3 blur-[140px] rounded-full pointer-events-none z-0" />
|
||||
|
||||
{/* ── MANDATORY FLOATING DEMO BANNER ── */}
|
||||
<div className="fixed bottom-4 left-4 z-40 bg-[#0F172A]/90 backdrop-blur-md border border-white/10 px-4 py-2.5 rounded-xl shadow-2xl flex items-center gap-2.5 max-w-sm pointer-events-none select-none">
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-[#14B8A6] animate-pulse" />
|
||||
<span className="text-[9px] font-black uppercase tracking-[1.5px] text-white/90">
|
||||
{lang === "tr" ? "Bu web sitesi Ayris Tech tarafından hazırlanmış bir konsept çalışmasıdır." : "This website is a premium concept prototype designed by Ayris Tech."}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* ── PREMIUM FLOATING NAVBAR ── */}
|
||||
<motion.header
|
||||
className="fixed top-4 left-4 right-4 z-50 px-4"
|
||||
initial={{ y: -80, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.85, ease: [0.16, 1, 0.3, 1] }}
|
||||
>
|
||||
<div className="mx-auto max-w-7xl h-20 flex items-center justify-between px-8 bg-white/80 backdrop-blur-xl border border-white/40 rounded-2xl shadow-[0_10px_30px_rgba(15,23,42,0.03)]">
|
||||
{/* Logo */}
|
||||
<a href="#" className="flex items-center gap-2.5 group">
|
||||
<span className="text-xl font-bold tracking-[2px] text-[#0F172A] font-serif-editorial flex items-center gap-2.5 uppercase">
|
||||
<svg className="w-5 h-5 text-[#14B8A6]" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M12 22V12" />
|
||||
<path d="M5 12h14" />
|
||||
<path d="M21 3H3l9 9Z" />
|
||||
<path d="M12 12H7.5" />
|
||||
</svg>
|
||||
{firma.adi}
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{/* Links */}
|
||||
<nav className="hidden lg:flex items-center gap-8">
|
||||
{[
|
||||
{ label: t.navBook, href: "#booking-widget" },
|
||||
{ label: t.navSuites, href: "#suites-showcase" },
|
||||
{ label: t.navExp, href: "#experiences" },
|
||||
{ label: t.navRev, href: "#testimonials" }
|
||||
].map(item => (
|
||||
<a
|
||||
key={item.label}
|
||||
href={item.href}
|
||||
className="text-[10px] font-black tracking-[2px] uppercase text-[#0F172A]/70 hover:text-[#14B8A6] transition-colors relative py-1 cursor-pointer group"
|
||||
>
|
||||
{item.label}
|
||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-[#14B8A6] transition-all group-hover:w-full" />
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
{/* Language Selector + Booking Button */}
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Language Switcher */}
|
||||
<div className="flex items-center gap-1 bg-[#0F172A]/5 border border-[#0F172A]/10 rounded-xl p-1 shrink-0">
|
||||
<button
|
||||
onClick={() => setLang("tr")}
|
||||
className={`text-[9px] font-black px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "tr" ? "bg-white text-slate-900 shadow-sm" : "text-[#0F172A]/60 hover:text-[#0F172A]"
|
||||
}`}
|
||||
>
|
||||
TR
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setLang("en")}
|
||||
className={`text-[9px] font-black px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "en" ? "bg-white text-slate-900 shadow-sm" : "text-[#0F172A]/60 hover:text-[#0F172A]"
|
||||
}`}
|
||||
>
|
||||
EN
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<motion.button
|
||||
onClick={() => setShowModal(true)}
|
||||
className="text-[10px] font-black tracking-[2.5px] uppercase text-white bg-[#14B8A6] hover:bg-[#0D9488] px-6 py-3.5 rounded-xl transition-all cursor-pointer shadow-[0_4px_12px_rgba(20,184,166,0.15)] hidden sm:block"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{t.reserveNow}
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.header>
|
||||
|
||||
{/* ── HERO & SUITE QUICK LOOK ── */}
|
||||
<section className="relative min-h-screen pt-32 pb-20 flex items-center z-10 px-6">
|
||||
<div className="max-w-7xl mx-auto w-full">
|
||||
<div className="grid lg:grid-cols-12 gap-16 items-center">
|
||||
|
||||
{/* Left Column: Typography Details */}
|
||||
<motion.div
|
||||
className="lg:col-span-6 z-20"
|
||||
variants={stagger}
|
||||
initial="hidden"
|
||||
animate="show"
|
||||
>
|
||||
<motion.div
|
||||
variants={fadeUp}
|
||||
className="inline-flex items-center gap-2 text-[10px] font-black uppercase tracking-widest text-[#14B8A6] mb-6 bg-[#14B8A6]/5 border border-[#14B8A6]/15 px-4 py-2 rounded-full"
|
||||
>
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-[#14B8A6] animate-pulse" />
|
||||
{t.badge}
|
||||
</motion.div>
|
||||
|
||||
<motion.h1
|
||||
variants={fadeUp}
|
||||
className="font-serif-editorial font-bold text-[#0F172A] leading-[1.1] tracking-tight mb-8 hero-title-clamp"
|
||||
>
|
||||
{firma.slogan}
|
||||
<br />
|
||||
<span className="italic font-light text-[#14B8A6] lowercase">{t.heroTail}</span>
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
variants={fadeUp}
|
||||
className="text-[#0F172A]/60 text-xs lg:text-sm leading-relaxed max-w-md mb-12 font-medium"
|
||||
>
|
||||
{t.heroDesc}
|
||||
</motion.p>
|
||||
|
||||
{/* Statistics Grid */}
|
||||
<motion.div
|
||||
variants={fadeUp}
|
||||
className="grid grid-cols-2 md:grid-cols-4 gap-6 mb-12"
|
||||
>
|
||||
{istatistikler.map((stat, idx) => (
|
||||
<div key={idx} className="border-l border-[#14B8A6]/30 pl-4 py-1">
|
||||
<h4 className="font-serif-editorial font-bold text-[#0F172A] text-base uppercase tracking-wider mb-1">
|
||||
{stat.deger}
|
||||
</h4>
|
||||
<p className="text-[#0F172A]/50 text-[10px] leading-snug font-bold">
|
||||
{getLocalizedStat(stat.etiket)}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</motion.div>
|
||||
|
||||
{/* CTA buttons */}
|
||||
<motion.div variants={fadeUp} className="flex gap-4">
|
||||
<a
|
||||
href="#booking-widget"
|
||||
className="inline-flex items-center gap-3 px-8 py-4 rounded-xl bg-[#14B8A6] hover:bg-[#0D9488] text-white font-black text-[10px] tracking-[2px] uppercase transition-all shadow-[0_5px_15px_rgba(20,184,166,0.2)] cursor-pointer"
|
||||
>
|
||||
{t.planEscape}
|
||||
</a>
|
||||
<a
|
||||
href="#experiences"
|
||||
className="inline-flex items-center gap-3 px-8 py-4 rounded-xl border border-[#0F172A]/10 bg-white/40 hover:bg-white/80 text-[#0F172A] font-black text-[10px] tracking-[2px] uppercase transition-all cursor-pointer"
|
||||
>
|
||||
{t.resortServices}
|
||||
</a>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Column: Layered Boutique Showcase */}
|
||||
<div className="lg:col-span-6 relative flex justify-center lg:justify-end">
|
||||
<motion.div
|
||||
className="relative w-full max-w-md lg:max-w-lg h-[460px] lg:h-[530px] rounded-3xl overflow-hidden shadow-premium border border-white/60 group"
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.8, ease: "easeOut" }}
|
||||
>
|
||||
{/* Outer delicate lines */}
|
||||
<div className="absolute inset-4 rounded-[20px] border border-dashed border-[#14B8A6]/10 animate-[spin_100s_linear_infinite] pointer-events-none" />
|
||||
|
||||
{/* Main Mediterranean Dining / Pool Setup */}
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src="/sicilia_hero_table.png"
|
||||
alt="Cal Vestam Panoramic Dining Terrace"
|
||||
className="w-full h-full object-cover scale-102 group-hover:scale-105 transition-transform duration-[4000ms]"
|
||||
/>
|
||||
|
||||
{/* Floating Citrus Welcome Badge Overlay */}
|
||||
<div className="absolute bottom-6 left-6 right-6 bg-white/90 backdrop-blur-xl border border-white/50 rounded-2xl p-5 shadow-2xl flex items-center gap-4">
|
||||
{/* Miniature citrus close-up */}
|
||||
<div className="w-12 h-12 rounded-xl overflow-hidden shrink-0 border border-white">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img src="/sicilia_lemon_heritage.png" alt="Citrus welcome orchard" className="w-full h-full object-cover" />
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-[#14B8A6] text-[8px] font-black tracking-widest uppercase block mb-1">{t.welcomeTitle}</span>
|
||||
<h4 className="font-serif-editorial text-xs font-bold text-[#0F172A] uppercase">{t.welcomeDesc}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── INTERACTIVE BOOKING ENGINE ── */}
|
||||
<section id="booking-widget" className="py-24 relative z-10 px-6 bg-white/40 border-t border-white/60">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
|
||||
<div className="bg-white rounded-3xl border border-white p-8 md:p-12 shadow-premium relative">
|
||||
{/* Glowing Top Line */}
|
||||
<div className="absolute top-0 left-12 right-12 h-0.5 bg-gradient-to-r from-transparent via-[#14B8A6] to-transparent" />
|
||||
|
||||
<div className="text-center max-w-xl mx-auto mb-12">
|
||||
<span className="text-[#14B8A6] font-serif-editorial italic font-bold text-[11px] tracking-[2px] uppercase block mb-2">{t.checkAvailability}</span>
|
||||
<h2 className="font-serif-editorial text-3xl font-bold uppercase text-[#0F172A] tracking-wide">
|
||||
{t.scheduleEscape}
|
||||
</h2>
|
||||
<p className="text-[#0F172A]/50 text-xs mt-2 font-medium">
|
||||
{t.scheduleDesc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Booking Fields Grid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
{[
|
||||
{ label: t.checkin, type: "date" },
|
||||
{ label: t.checkout, type: "date" },
|
||||
].map((field, idx) => (
|
||||
<div key={idx} className="flex flex-col">
|
||||
<label className="text-[10px] font-black text-[#0F172A]/50 mb-1.5 uppercase tracking-widest">{field.label}</label>
|
||||
<input
|
||||
type={field.type}
|
||||
className="px-4 py-3.5 rounded-xl border border-gray-200 bg-[#FAF8F5] text-xs text-[#0F172A] focus:outline-none focus:border-[#14B8A6] focus:ring-1 focus:ring-[#14B8A6] transition-all font-semibold cursor-pointer"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Adults Count */}
|
||||
<div className="flex flex-col">
|
||||
<label className="text-[10px] font-black text-[#0F172A]/50 mb-1.5 uppercase tracking-widest">{t.adults}</label>
|
||||
<div className="flex items-center justify-between px-4 py-2.5 rounded-xl border border-gray-200 bg-[#FAF8F5]">
|
||||
<button
|
||||
onClick={() => setAdults(Math.max(1, adults - 1))}
|
||||
className="w-8 h-8 rounded-lg bg-white border border-gray-100 flex items-center justify-center font-bold text-xs text-[#0F172A] hover:bg-gray-50 cursor-pointer shadow-sm"
|
||||
>
|
||||
-
|
||||
</button>
|
||||
<span className="text-xs font-black text-[#0F172A]">{adults} {t.guests}</span>
|
||||
<button
|
||||
onClick={() => setAdults(adults + 1)}
|
||||
className="w-8 h-8 rounded-lg bg-white border border-gray-100 flex items-center justify-center font-bold text-xs text-[#0F172A] hover:bg-gray-50 cursor-pointer shadow-sm"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Kids Count */}
|
||||
<div className="flex flex-col">
|
||||
<label className="text-[10px] font-black text-[#0F172A]/50 mb-1.5 uppercase tracking-widest">{t.kids}</label>
|
||||
<div className="flex items-center justify-between px-4 py-2.5 rounded-xl border border-gray-200 bg-[#FAF8F5]">
|
||||
<button
|
||||
onClick={() => setKids(Math.max(0, kids - 1))}
|
||||
className="w-8 h-8 rounded-lg bg-white border border-gray-100 flex items-center justify-center font-bold text-xs text-[#0F172A] hover:bg-gray-50 cursor-pointer shadow-sm"
|
||||
>
|
||||
-
|
||||
</button>
|
||||
<span className="text-xs font-black text-[#0F172A]">{kids} {t.kidsLabel}</span>
|
||||
<button
|
||||
onClick={() => setKids(kids + 1)}
|
||||
className="w-8 h-8 rounded-lg bg-white border border-gray-100 flex items-center justify-center font-bold text-xs text-[#0F172A] hover:bg-gray-50 cursor-pointer shadow-sm"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Action row */}
|
||||
<div className="mt-8 pt-4 flex flex-col md:flex-row justify-between items-center gap-4">
|
||||
<p className="text-[#0F172A]/40 text-xs font-medium max-w-md text-center md:text-left">
|
||||
{t.guarantee}
|
||||
</p>
|
||||
<motion.button
|
||||
onClick={() => setShowModal(true)}
|
||||
className="w-full md:w-auto px-10 py-4 rounded-xl bg-[#14B8A6] hover:bg-[#0D9488] text-white font-black text-[10px] tracking-[2px] uppercase transition-all cursor-pointer shadow-[0_5px_15px_rgba(20,184,166,0.15)] shrink-0"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{t.confirmDetails}
|
||||
</motion.button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── SUITES GALLERY ── */}
|
||||
<section id="suites-showcase" className="py-32 relative z-10 px-6">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="flex flex-col md:flex-row md:items-end justify-between mb-16 gap-6">
|
||||
<div>
|
||||
<span className="text-[#14B8A6] font-serif-editorial italic font-bold text-sm tracking-[2px] uppercase block mb-3">{t.suitesTitle}</span>
|
||||
<h2 className="font-serif-editorial text-4xl lg:text-5xl font-bold tracking-tight text-[#0F172A] uppercase">
|
||||
{t.suitesHeader}
|
||||
</h2>
|
||||
</div>
|
||||
<p className="text-[#0F172A]/50 text-xs max-w-sm font-semibold leading-relaxed">
|
||||
{t.suitesDesc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Gallery Columns */}
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{[
|
||||
{ title: t.suite1Title, img: "/sicilia_hero_table.png", desc: t.suite1Desc },
|
||||
{ title: t.suite2Title, img: "/sicilia_lemon_heritage.png", desc: t.suite2Desc },
|
||||
{ title: t.suite3Title, img: "/sicilia_hero_table.png", desc: t.suite3Desc },
|
||||
].map((suite, idx) => (
|
||||
<motion.div
|
||||
key={idx}
|
||||
className="bg-white rounded-3xl border border-white overflow-hidden transition-all duration-300 hover:border-[#14B8A6]/30 flex flex-col justify-between group shadow-premium"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: idx * 0.1 }}
|
||||
whileHover={{ y: -6 }}
|
||||
>
|
||||
<div className="h-56 overflow-hidden relative border-b border-gray-100">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={suite.img}
|
||||
alt={suite.title}
|
||||
className="w-full h-full object-cover scale-102 group-hover:scale-105 transition-transform duration-1000"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/5" />
|
||||
</div>
|
||||
|
||||
<div className="p-8 space-y-4">
|
||||
<h3 className="font-serif-editorial font-bold text-lg text-[#0F172A] tracking-wider uppercase leading-snug">
|
||||
{suite.title}
|
||||
</h3>
|
||||
<p className="text-[#0F172A]/50 text-[11px] leading-relaxed font-semibold">
|
||||
{suite.desc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="px-8 pb-8">
|
||||
<button
|
||||
onClick={() => setShowModal(true)}
|
||||
className="text-[#14B8A6] font-black text-[10px] tracking-[2px] uppercase flex items-center gap-1.5 cursor-pointer hover:text-[#0D9488] transition-colors"
|
||||
>
|
||||
{t.secureRes}
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── RESORT EXPERIENCES ── */}
|
||||
<section id="experiences" className="py-24 relative z-10 px-6 bg-white/40 border-t border-white/60">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="grid lg:grid-cols-3 gap-8">
|
||||
{hizmetler.map((hizmet, idx) => {
|
||||
const locServ = getLocalizedService(hizmet.baslik, hizmet.aciklama);
|
||||
return (
|
||||
<div
|
||||
key={idx}
|
||||
className="bg-white p-8 rounded-3xl border border-white flex flex-col justify-between h-72 transition-all hover:shadow-premium group"
|
||||
>
|
||||
<div>
|
||||
<div className="w-12 h-12 rounded-2xl bg-[#14B8A6]/5 border border-[#14B8A6]/10 flex items-center justify-center mb-6">
|
||||
<svg className="w-5 h-5 text-[#14B8A6]" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="m9 12 2 2 4-4" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="font-serif-editorial font-bold text-lg text-[#0F172A] mb-2 uppercase">
|
||||
{locServ.title}
|
||||
</h3>
|
||||
<p className="text-[#0F172A]/60 text-[11px] leading-relaxed font-semibold">
|
||||
{locServ.desc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => setShowModal(true)}
|
||||
className="text-[#14B8A6] font-black text-[9px] tracking-[2.5px] uppercase flex items-center gap-1 cursor-pointer hover:text-[#0D9488] transition-colors"
|
||||
>
|
||||
{lang === "tr" ? "DAHA FAZLA KEŞFET →" : "DISCOVER MORE →"}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── TESTIMONIALS ── */}
|
||||
<section id="testimonials" className="py-28 relative z-10 px-6 border-t border-white/60">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="text-center max-w-xl mx-auto mb-20">
|
||||
<span className="text-[#14B8A6] font-serif-editorial italic font-bold text-sm tracking-[2px] uppercase block mb-2">{t.diaries}</span>
|
||||
<h2 className="font-serif-editorial font-bold text-3xl lg:text-4xl uppercase text-[#0F172A] tracking-wider">
|
||||
{t.lovedGuests}
|
||||
</h2>
|
||||
<p className="text-[#0F172A]/40 text-xs mt-2 font-medium">
|
||||
{t.lovedDesc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Testimonials 2-Column Grid */}
|
||||
<div className="grid md:grid-cols-2 gap-8">
|
||||
{yorumlar.map((y, yIdx) => (
|
||||
<div
|
||||
key={yIdx}
|
||||
className="bg-white border border-white rounded-3xl p-8 flex flex-col justify-between transition-all duration-300 hover:border-[#14B8A6]/30 group shadow-premium"
|
||||
>
|
||||
{/* Rating Stars SVG */}
|
||||
<div className="flex gap-1.5 mb-6">
|
||||
{[...Array(5)].map((_, starIdx) => (
|
||||
<svg key={starIdx} className="w-4 h-4 fill-[#14B8A6]" viewBox="0 0 24 24">
|
||||
<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
|
||||
</svg>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<p className="text-[#0F172A]/70 text-xs leading-relaxed italic mb-8 font-medium font-serif-editorial">
|
||||
“{y.yorum}”
|
||||
</p>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-full border border-gray-100 flex items-center justify-center text-lg bg-[#FAF8F5] select-none font-bold">
|
||||
{y.yazar.charAt(0)}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-serif-editorial text-[#0F172A] text-xs font-bold uppercase tracking-wider">
|
||||
{y.yazar}
|
||||
</h4>
|
||||
<span className="text-[9px] text-[#0F172A]/40 uppercase tracking-widest font-black">
|
||||
{y.tarih}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── FOOTER ── */}
|
||||
<footer className="bg-white border-t border-gray-100 pt-24 pb-8 px-6 relative z-10">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="grid md:grid-cols-4 gap-12 pb-16 border-b border-gray-100">
|
||||
|
||||
{/* About Column */}
|
||||
<div className="md:col-span-2">
|
||||
<span className="font-serif-editorial text-2xl font-bold text-[#0F172A] tracking-wider uppercase mb-4 block">
|
||||
Cal<span className="text-[#14B8A6]">Vestam</span>
|
||||
</span>
|
||||
<p className="text-[#0F172A]/50 text-xs leading-relaxed max-w-sm mb-8 font-medium">
|
||||
{firma.slogan} — Exclusive boutique resort nestled inside Ölüdeniz heights. Handcrafted sea suites, infinity pools, and organic salt therapy.
|
||||
</p>
|
||||
<div className="text-[#0F172A]/60 text-xs font-medium space-y-3">
|
||||
<p className="flex items-center gap-2">
|
||||
<svg className="w-4 h-4 text-[#14B8A6] shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" />
|
||||
<circle cx="12" cy="10" r="3" />
|
||||
</svg>
|
||||
<span className="text-[#0F172A]/80">{firma.adres}</span>
|
||||
</p>
|
||||
<p className="flex items-center gap-2">
|
||||
<svg className="w-4 h-4 text-[#14B8A6] shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<rect width="20" height="16" x="2" y="4" rx="2" />
|
||||
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
|
||||
</svg>
|
||||
<span className="text-[#0F172A]/80">{firma.email}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Coordinates Column */}
|
||||
<div>
|
||||
<h4 className="font-serif-editorial text-[#14B8A6] text-xs font-bold uppercase tracking-wider mb-6">
|
||||
{t.vipCoords}
|
||||
</h4>
|
||||
<div className="space-y-4 text-xs text-[#0F172A]/50 font-semibold">
|
||||
<p>{t.conciergeActive} <br /> <span className="text-[#0F172A]/80">24 Hours Active</span></p>
|
||||
<p>Check-In/Out <br /> <span className="text-[#0F172A]/80">{t.checkInOutDetails}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Leisure Services Column */}
|
||||
<div>
|
||||
<h4 className="font-serif-editorial text-[#14B8A6] text-xs font-bold uppercase tracking-wider mb-6">
|
||||
{t.boutiqueLeisures}
|
||||
</h4>
|
||||
<div className="space-y-4">
|
||||
{hizmetler.map((h, hIdx) => {
|
||||
const locS = getLocalizedService(h.baslik, h.aciklama);
|
||||
return (
|
||||
<a
|
||||
key={hIdx}
|
||||
href="#suites-showcase"
|
||||
className="block text-[#0F172A]/50 hover:text-[#14B8A6] text-xs transition-colors font-semibold"
|
||||
>
|
||||
{locS.title}
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col md:flex-row justify-between items-center pt-8 gap-4 text-[#0F172A]/30 text-xs font-semibold">
|
||||
<p>© 2026 {firma.adi}. All rights reserved.</p>
|
||||
<div className="flex gap-4">
|
||||
<a href="#" className="hover:text-[#0F172A] transition-colors">{t.privacyRegs}</a>
|
||||
<span>·</span>
|
||||
<a href="#" className="hover:text-[#0F172A] transition-colors">{t.termsStay}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{/* ── CONFIRM SUCCESS MODAL ── */}
|
||||
<AnimatePresence>
|
||||
{showModal && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 flex items-center justify-center p-6 bg-black/30 backdrop-blur-sm"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
<motion.div
|
||||
className="bg-white rounded-3xl p-8 max-w-md w-full relative shadow-2xl border border-gray-100"
|
||||
initial={{ scale: 0.95, y: 20 }}
|
||||
animate={{ scale: 1, y: 0 }}
|
||||
exit={{ scale: 0.95, y: 20 }}
|
||||
>
|
||||
{/* Close Button */}
|
||||
<button
|
||||
className="absolute top-6 right-6 w-8 h-8 rounded-full bg-[#FAF8F5] border border-gray-100 flex items-center justify-center text-[#0F172A]/40 hover:text-[#14B8A6] hover:border-[#14B8A6]/20 transition-all cursor-pointer font-bold"
|
||||
onClick={() => setShowModal(false)}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
{/* Success check indicator */}
|
||||
<div className="w-16 h-16 rounded-2xl bg-[#14B8A6]/10 border border-[#14B8A6]/20 flex items-center justify-center mb-6">
|
||||
<svg className="w-8 h-8 stroke-[#14B8A6] fill-none" viewBox="0 0 24 24" strokeWidth="1.5">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h3 className="font-serif-editorial font-bold text-[#0F172A] text-2xl mb-1 uppercase tracking-wider">
|
||||
{t.enquiryActive}
|
||||
</h3>
|
||||
<p className="text-[#14B8A6] font-sans-resort text-[10px] mb-6 uppercase tracking-widest font-black">
|
||||
{t.ambassadorActive}
|
||||
</p>
|
||||
|
||||
<p className="text-[#0F172A]/60 text-xs leading-relaxed mb-8 font-semibold">
|
||||
{t.enquirySuccess}
|
||||
</p>
|
||||
|
||||
<motion.button
|
||||
className="w-full py-4 rounded-xl bg-[#14B8A6] hover:bg-[#0D9488] text-white font-black text-[10px] tracking-[2px] uppercase cursor-pointer shadow-md shadow-[#14B8A6]/15"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
onClick={() => setShowModal(false)}
|
||||
>
|
||||
{t.dismiss}
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,747 @@
|
||||
"use client";
|
||||
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { useState, useEffect } from "react";
|
||||
import type { DemoData } from "@/data/demos";
|
||||
|
||||
const fadeUp = {
|
||||
hidden: { opacity: 0, y: 35 },
|
||||
show: { opacity: 1, y: 0, transition: { duration: 0.65, ease: [0.25, 0.46, 0.45, 0.94] as [number, number, number, number] } },
|
||||
};
|
||||
|
||||
const stagger = {
|
||||
hidden: {},
|
||||
show: { transition: { staggerChildren: 0.08 } },
|
||||
};
|
||||
|
||||
const translations = {
|
||||
tr: {
|
||||
navCabin: "Kulübemiz",
|
||||
navHosts: "Hizmetlerimiz",
|
||||
navChannels: "Rezervasyon",
|
||||
navReviews: "Misafir Günlüğü",
|
||||
bookWilderness: "Kulübeyi Ayırt",
|
||||
est: "2015'TEN BERİ",
|
||||
heroDesc: "Şebekeden bağımsız lüks dağ kulübesi inzivalarına dalın. Odun ateşinde taze ekmek fırın sabahları, rustik açık şömine salonları ve serin dağ nehrinde alabalık avı koordinatları.",
|
||||
secureCabin: "REZERVASYON YAP",
|
||||
cabinUnits: "Dağ Kulübeleri",
|
||||
cabinWood: "Darby Kırmızı Sedir",
|
||||
fireplaceUnit: "Tütsülü Şömine",
|
||||
fireplaceType: "Doğal Taş Ocak",
|
||||
aboutTitle: "Darby Dağ Yaşamı",
|
||||
aboutHeader: "KULÜBE HAKKINDA",
|
||||
aboutSub: "DOĞAL MT. LOGWOOD AKUSTİĞİ ALTINDA HUZUR",
|
||||
aboutDesc: "Bitterroot Bunkhouse, Darby milli orman koordinatlarının derinliklerinde el işçiliğiyle inşa edilmiş iki adet kırmızı sedir dağ kulübesi sunar. Her kulübe döküm demir mutfak gereçleri, kurutulmuş huş odunları ve yerel gölleri keşfetmeniz için dağ rehberleriyle donatılmıştır.",
|
||||
feat1Title: "YABANİ YÜRÜYÜŞ YOLLARI",
|
||||
feat1Desc: "Arka terasınızdan doğrudan yaban çiçeği orman yollarına adım atın.",
|
||||
feat2Title: "ODUN ATEŞİNDE SABAHLAR",
|
||||
feat2Desc: "Her gün ücretsiz temin edilen şömine odunlarının ve döküm fırın ikramlarının keyfini çıkarın.",
|
||||
channelsTitle: "Entegre Platformlar",
|
||||
channelsHeader: "REZERVASYON YÖNTEMLERİ",
|
||||
channelsDesc: "Senkronize edilmiş kanallarimizi aşağidan inceleyin. Komisyonsuz konaklamalar için Airbnb, VRBO veya doğrudan kurumsal web sitemiz üzerinden rezervasyon yapin.",
|
||||
chAirbnb: "AIRBNB İLE REZERVE ET",
|
||||
chVrbo: "VRBO İLE REZERVE ET",
|
||||
chDirect: "DOĞRUDAN REZERVE (%15 TASARRUF)",
|
||||
airbnbTitle: "Airbnb Superhost Kanalı",
|
||||
airbnbDesc: "Giriş ve konaklama takvimlerini doğrudan Superhost sayfamızdan anlık doğrulayın. Klasik platform güvencesi arayan gezginler için idealdir.",
|
||||
vrboTitle: "VRBO Premier Host Kanalı",
|
||||
vrboDesc: "Aileler veya geniş gruplar için Premier Host statüsünde listelemeler. Grup iptal ve iade ayrıcalıkları çıkış esnasında otomatik olarak uygulanır.",
|
||||
directTitle: "Doğrudan Kulübe Rezervasyonu",
|
||||
directDesc: "Rezervasyon hizmet bedellerini tamamen atlayın. Girişte size özel taze ekşi mayalı sabah ekmeği, ücretsiz şömine odunu ve doğrudan VIP mihmandar desteği alın.",
|
||||
launchPortal: "REZERVASYON PORTALINI BAŞLAT",
|
||||
diaries: "Yaban Günlükleri",
|
||||
lovedGuests: "MİSAFİRLERİMİZDEN KELİMELER",
|
||||
vipServices: "VIP HİZMETLER",
|
||||
mountainHelp: "Dağ Desteği",
|
||||
mountainActive: "Her Gün 08:00 - 20:00 Aktif",
|
||||
privacyRegs: "Gizlilik Sözleşmesi",
|
||||
termsStay: "Kulübe Şartları",
|
||||
dismiss: "KAPAT",
|
||||
enquiryActive: "REZERVASYON ALINDI",
|
||||
ambassadorActive: "Yaban Concierge Aktif",
|
||||
enquirySuccess: "Darby dağ kulübesi rezervasyon talebinizi kaydettik. Sertifikalı yaban mihmandarımız geliş, sıcak ekmek ve kano yolları detaylarını planlamak için sizinle iletişime geçecektir. Teşekkürler!",
|
||||
},
|
||||
en: {
|
||||
navCabin: "Our cabin",
|
||||
navHosts: "Host guides",
|
||||
navChannels: "Book channels",
|
||||
navReviews: "Guest diaries",
|
||||
bookWilderness: "Book wilderness",
|
||||
est: "ESTABLISHED IN 2015",
|
||||
heroDesc: "Immerse in off-grid luxury cabin retreats. Wood-fired bakery mornings, rustic open fireplace lounges, and cold mountain river trout coordinates.",
|
||||
secureCabin: "SECURE CABIN SLOTS",
|
||||
cabinUnits: "A-frame lodges",
|
||||
cabinWood: "Darby Cedar Wood",
|
||||
fireplaceUnit: "Stocked fireplace",
|
||||
fireplaceType: "Open Stone Hearth",
|
||||
aboutTitle: "Darby Mountain Life",
|
||||
aboutHeader: "ABOUT THE CABIN",
|
||||
aboutSub: "OFF-GRID HEAVEN UNDER MT. LOGWOOD ACOUSTICS",
|
||||
aboutDesc: "Bitterroot Bunkhouse provides two hand-crafted A-frame cedar lodges deep in the Darby forest coordinates. Each lodge is stocked with cast-iron cookware, seasoned logwood reserves, and local guides to explore hidden mountain lakes.",
|
||||
feat1Title: "WILDERNESS TRAIL PATHS",
|
||||
feat1Desc: "Walk directly from your back deck onto wildflower forest lines.",
|
||||
feat2Title: "WOOD-FIRED MORNINGS",
|
||||
feat2Desc: "Enjoy complimentary firewood logs and hot stone iron bakers daily.",
|
||||
channelsTitle: "Integrated Platforms",
|
||||
channelsHeader: "HOW TO SECURE BOOKINGS",
|
||||
channelsDesc: "Toggle our synced channels below. Syncing Airbnb, VRBO, or our premium Direct reservation for commission-free stays.",
|
||||
chAirbnb: "BOOK ON AIRBNB",
|
||||
chVrbo: "BOOK ON VRBO",
|
||||
chDirect: "BOOK DIRECT (SAVE 15%)",
|
||||
airbnbTitle: "Airbnb Superhost Channel",
|
||||
airbnbDesc: "Verify lodging calendars dynamically directly on our superhost page listing. Perfect for travelers seeking classic platform protection.",
|
||||
vrboTitle: "VRBO Premier Host Channel",
|
||||
vrboDesc: "Premier hosts status listings for families or large groups. All group cancellation benefits apply automatically upon checkout.",
|
||||
directTitle: "Bunkhouse Direct Booking",
|
||||
directDesc: "Skip booking service fees completely. Receive customized fresh morning sourdough, complimentary firewood, and direct VIP coordination.",
|
||||
launchPortal: "LAUNCH RESERVATION PORTAL",
|
||||
diaries: "Wilderness Diaries",
|
||||
lovedGuests: "KIND WORDS FROM PAST GUESTS",
|
||||
vipServices: "VIP SERVICES",
|
||||
mountainHelp: "Mountain Help",
|
||||
mountainActive: "Available 8 AM - 8 PM",
|
||||
privacyRegs: "Privacy Regulations",
|
||||
termsStay: "Terms of Cabin",
|
||||
dismiss: "DISMISS",
|
||||
enquiryActive: "CABIN REQUEST FILED",
|
||||
ambassadorActive: "Wilderness Concierge Active",
|
||||
enquirySuccess: "We have registered your Darby wilderness cabin coordinate request. A certified somatic host will contact you shortly to coordinate arrival, hot bread baking, and kayak paths. Thank you!",
|
||||
}
|
||||
};
|
||||
|
||||
export default function HotelTemplate2({ data }: { data: DemoData }) {
|
||||
const { firma, istatistikler = [], hizmetler = [], yorumlar = [] } = data;
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [channel, setChannel] = useState<string>("direct");
|
||||
const [lang, setLang] = useState<"tr" | "en">("tr");
|
||||
const [preloader, setPreloader] = useState(true);
|
||||
|
||||
const t = translations[lang];
|
||||
|
||||
// 1. Lenis Smooth Scroll Integration
|
||||
useEffect(() => {
|
||||
let lenis: any;
|
||||
import("@studio-freight/lenis").then(({ default: Lenis }) => {
|
||||
lenis = new Lenis({ duration: 1.2, easing: (t: number) => Math.min(1, 1.001 - Math.pow(2, -10 * t)) });
|
||||
function raf(time: number) { lenis.raf(time); requestAnimationFrame(raf); }
|
||||
requestAnimationFrame(raf);
|
||||
});
|
||||
return () => lenis?.destroy();
|
||||
}, []);
|
||||
|
||||
// 2. Preloader Curtain Timer
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setPreloader(false);
|
||||
}, 1500);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
// Localized services
|
||||
const getLocalizedService = (baslik: string, aciklama: string) => {
|
||||
if (baslik.includes("HOSTS")) {
|
||||
return {
|
||||
title: lang === "tr" ? "EV SAHİBİ REHBERLİĞİ" : "MEET YOUR HOSTS",
|
||||
desc: lang === "tr" ? "Yerel dağ rehberlerimiz; alabalık avı yolları, yaban çiçeği rotaları ve gizli nehir haritaları koordinasyonunu üstlenir." : aciklama
|
||||
};
|
||||
}
|
||||
if (baslik.includes("POLICIES")) {
|
||||
return {
|
||||
title: lang === "tr" ? "KULÜBE KURALLARI" : "CABIN POLICIES",
|
||||
desc: lang === "tr" ? "Evcil hayvan dostu konaklama koşulları. Döküm demir tava ve her zaman dolu odunluk güvenceleri." : aciklama
|
||||
};
|
||||
}
|
||||
return {
|
||||
title: lang === "tr" ? "DOĞRUDAN REZERVE" : "DIRECT RESERVATION",
|
||||
desc: lang === "tr" ? "Airbnb veya VRBO ile anlık takvim senkronizasyonu; dilerseniz komisyonsuz doğrudan rezervasyon avantajı." : aciklama
|
||||
};
|
||||
};
|
||||
|
||||
const css = `
|
||||
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;1,400&family=Inter:wght@300;400;500;600;700;800;900&display=swap');
|
||||
|
||||
:root {
|
||||
--color-bunkhouse-gold: #854D0E;
|
||||
--color-bunkhouse-sand: #F5F2EB;
|
||||
--color-bunkhouse-stone: #1C1917;
|
||||
--color-bunkhouse-card: #FAF8F5;
|
||||
}
|
||||
|
||||
.font-serif-bunkhouse {
|
||||
font-family: 'Playfair Display', Georgia, serif;
|
||||
}
|
||||
|
||||
.font-industrial-bunkhouse {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.font-sans-bunkhouse {
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
|
||||
.bg-rustic-mesh {
|
||||
background-image:
|
||||
radial-gradient(circle at 10% 10%, rgba(133, 77, 14, 0.02) 0%, transparent 40%),
|
||||
radial-gradient(circle at 90% 90%, rgba(28, 25, 23, 0.02) 0%, transparent 50%),
|
||||
linear-gradient(rgba(28, 25, 23, 0.005) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(28, 25, 23, 0.005) 1px, transparent 1px);
|
||||
background-size: 100% 100%, 100% 100%, 30px 30px, 30px 30px;
|
||||
}
|
||||
|
||||
.border-bunkhouse {
|
||||
border-color: rgba(28, 25, 23, 0.15);
|
||||
}
|
||||
|
||||
.hero-title-clamp {
|
||||
font-size: clamp(34px, 5vw, 85px);
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 0.95;
|
||||
}
|
||||
`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{css}</style>
|
||||
|
||||
{/* ── IMZA AN: CURTAIN REVEAL PRELOADER ── */}
|
||||
<AnimatePresence>
|
||||
{preloader && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 bg-[#1C1917] flex flex-col items-center justify-center p-6"
|
||||
exit={{
|
||||
clipPath: "polygon(0 0, 100% 0, 100% 0, 0 0)",
|
||||
transition: { duration: 0.85, ease: [0.16, 1, 0.3, 1] }
|
||||
}}
|
||||
>
|
||||
<div className="max-w-md text-center space-y-6">
|
||||
<motion.span
|
||||
className="text-[9px] font-black tracking-[4px] uppercase text-[#854D0E] block font-sans-bunkhouse"
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
BITTERROOT BUNKHOUSE
|
||||
</motion.span>
|
||||
<div className="h-[1px] w-48 bg-white/10 mx-auto relative overflow-hidden">
|
||||
<motion.div
|
||||
className="absolute inset-y-0 left-0 bg-[#854D0E]"
|
||||
initial={{ width: "0%" }}
|
||||
animate={{ width: "100%" }}
|
||||
transition={{ duration: 1.2, ease: "easeInOut" }}
|
||||
/>
|
||||
</div>
|
||||
<motion.h2
|
||||
className="font-serif-bunkhouse text-white text-lg italic font-light tracking-wider"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.4, duration: 0.5 }}
|
||||
>
|
||||
wilderness sanctuary
|
||||
</motion.h2>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* COZY RUSTIC WILDERNESS LODGE THEME */}
|
||||
<div className="bg-[#F5F2EB] text-[#1C1917] min-h-screen font-sans-bunkhouse selection:bg-[#854D0E] selection:text-white overflow-hidden relative bg-rustic-mesh pb-24">
|
||||
|
||||
{/* Floating Woody Ambience Orbs */}
|
||||
<div className="absolute top-[20%] left-[-10%] w-[500px] h-[500px] bg-[#854D0E]/2 blur-[130px] rounded-full pointer-events-none z-0" />
|
||||
<div className="absolute bottom-[20%] right-[-10%] w-[500px] h-[500px] bg-[#854D0E]/1 blur-[150px] rounded-full pointer-events-none z-0" />
|
||||
|
||||
{/* ── MANDATORY FLOATING DEMO BANNER ── */}
|
||||
<div className="fixed bottom-4 left-4 z-40 bg-[#1C1917]/95 backdrop-blur-md border border-white/10 px-4 py-2.5 rounded-xl shadow-2xl flex items-center gap-2.5 max-w-sm pointer-events-none select-none">
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-[#854D0E] animate-pulse" />
|
||||
<span className="text-[9px] font-black uppercase tracking-[1.5px] text-white/90">
|
||||
{lang === "tr" ? "Bu web sitesi Ayris Tech tarafından hazırlanmış bir konsept çalışmasıdır." : "This website is a premium concept prototype designed by Ayris Tech."}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{/* ── COZY HEADER ── */}
|
||||
<motion.header
|
||||
className="w-full border-b border-[#1C1917]/10 px-8 py-6 relative z-50 bg-[#F5F2EB]/90 backdrop-blur-xl"
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
>
|
||||
<div className="max-w-7xl mx-auto flex items-center justify-between">
|
||||
{/* Logo */}
|
||||
<a href="#" className="flex items-center gap-2.5 group">
|
||||
<span className="text-lg font-bold tracking-[2px] text-[#1C1917] font-serif-bunkhouse flex items-center gap-2 uppercase">
|
||||
<svg className="w-5 h-5 text-[#854D0E]" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="m8 3 4 8 5-5 5 15H2L8 3Z" />
|
||||
</svg>
|
||||
{firma.adi}
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{/* Links */}
|
||||
<nav className="hidden md:flex items-center gap-8">
|
||||
{[
|
||||
{ label: t.navCabin, href: "#about-cabin" },
|
||||
{ label: t.navHosts, href: "#host-details" },
|
||||
{ label: t.navChannels, href: "#booking-channels" },
|
||||
{ label: t.navReviews, href: "#testimonials" }
|
||||
].map(item => (
|
||||
<a
|
||||
key={item.label}
|
||||
href={item.href}
|
||||
className="text-[9px] font-bold tracking-[2.5px] uppercase text-[#1C1917]/70 hover:text-[#854D0E] transition-colors relative py-1 cursor-pointer"
|
||||
>
|
||||
{item.label}
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
{/* Language Selector + Booking Button */}
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Language Switcher */}
|
||||
<div className="flex items-center gap-1 bg-[#1C1917]/5 border border-[#1C1917]/10 rounded-xl p-1 shrink-0">
|
||||
<button
|
||||
onClick={() => setLang("tr")}
|
||||
className={`text-[9px] font-black px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "tr" ? "bg-[#1C1917] text-white shadow-sm" : "text-[#1C1917]/60 hover:text-[#1C1917]"
|
||||
}`}
|
||||
>
|
||||
TR
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setLang("en")}
|
||||
className={`text-[9px] font-black px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "en" ? "bg-[#1C1917] text-white shadow-sm" : "text-[#1C1917]/60 hover:text-[#1C1917]"
|
||||
}`}
|
||||
>
|
||||
EN
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<motion.button
|
||||
onClick={() => setShowModal(true)}
|
||||
className="text-[9px] font-bold tracking-[2.5px] uppercase text-white bg-[#1C1917] hover:bg-[#854D0E] px-6 py-3.5 rounded-lg transition-all cursor-pointer shadow-md hidden sm:block"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{t.bookWilderness}
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.header>
|
||||
|
||||
{/* ── COZY HERO BANNER (DARK CONTRAST) ── */}
|
||||
<section className="relative z-10 max-w-7xl mx-auto px-6 mt-8">
|
||||
<motion.div
|
||||
className="w-full min-h-[500px] rounded-3xl bg-[#1C1917] text-[#FAF8F5] p-8 md:p-16 flex flex-col justify-between relative overflow-hidden shadow-2xl"
|
||||
initial={{ opacity: 0, scale: 0.98 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
>
|
||||
{/* Ambient fire glow background */}
|
||||
<div className="absolute top-0 right-0 w-[450px] h-[450px] bg-[#854D0E]/20 blur-[100px] rounded-full pointer-events-none" />
|
||||
|
||||
{/* Banner top */}
|
||||
<div className="flex justify-between items-start z-10">
|
||||
<span className="text-[9px] font-bold uppercase tracking-[3px] text-[#FAF8F5]/50 border border-white/10 px-3 py-1.5 rounded-full">
|
||||
BITTERROOT VALLEY · MONTANA
|
||||
</span>
|
||||
<span className="text-[9px] font-bold uppercase tracking-[3px] text-[#FAF8F5]/50">
|
||||
{t.est}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Banner headings */}
|
||||
<div className="max-w-2xl my-16 z-10">
|
||||
<h1 className="font-serif-bunkhouse text-4xl md:text-6xl font-normal leading-[1.08] tracking-wider mb-6 text-white uppercase">
|
||||
{firma.slogan}
|
||||
</h1>
|
||||
<p className="text-[#FAF8F5]/60 text-xs md:text-sm leading-relaxed font-normal max-w-md">
|
||||
{t.heroDesc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Banner bottom details */}
|
||||
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-6 border-t border-white/10 pt-8 z-10">
|
||||
<div className="flex gap-12">
|
||||
<div>
|
||||
<span className="text-[#FAF8F5]/40 text-[9px] uppercase tracking-widest font-bold block mb-1">{t.cabinUnits}</span>
|
||||
<span className="font-industrial-bunkhouse text-lg font-bold">{t.cabinWood}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-[#FAF8F5]/40 text-[9px] uppercase tracking-widest font-bold block mb-1">{t.fireplaceUnit}</span>
|
||||
<span className="font-industrial-bunkhouse text-lg font-bold">{t.fireplaceType}</span>
|
||||
</div>
|
||||
</div>
|
||||
<motion.button
|
||||
onClick={() => setShowModal(true)}
|
||||
className="px-8 py-4 bg-[#854D0E] hover:bg-white hover:text-[#1C1917] text-white font-bold text-[9px] tracking-[2.5px] uppercase rounded-xl transition-all cursor-pointer shadow-lg"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
>
|
||||
{t.secureCabin}
|
||||
</motion.button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</section>
|
||||
|
||||
{/* ── ABOUT THE CABIN WITH LAYERED GRAPHICS ── */}
|
||||
<section id="about-cabin" className="py-28 relative z-10 px-6">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="text-center max-w-xl mx-auto mb-20">
|
||||
<span className="text-[#854D0E] font-serif-bunkhouse italic text-sm tracking-[2px] block mb-2">{t.aboutTitle}</span>
|
||||
<h2 className="font-serif-bunkhouse text-3xl md:text-4xl uppercase tracking-wider text-[#1C1917]">
|
||||
{t.aboutHeader}
|
||||
</h2>
|
||||
<div className="w-16 h-0.5 bg-[#854D0E]/20 mx-auto mt-4" />
|
||||
</div>
|
||||
|
||||
{/* Layered images grid */}
|
||||
<div className="grid lg:grid-cols-12 gap-12 items-center">
|
||||
|
||||
{/* Left Column: 3 detailed pictures layered */}
|
||||
<div className="lg:col-span-7 grid grid-cols-12 gap-4 items-center">
|
||||
{/* 1st image: Sourdough fresh bakery */}
|
||||
<div className="col-span-5 rounded-2xl overflow-hidden shadow-lg border border-[#1C1917]/10 aspect-[3/4] group">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src="/bakery_heritage.png"
|
||||
alt="Wilderness breakfast sourdough bakery"
|
||||
className="w-full h-full object-cover scale-102 group-hover:scale-105 transition-transform duration-1000"
|
||||
/>
|
||||
</div>
|
||||
{/* 2nd image: Cozy fireside cooking */}
|
||||
<div className="col-span-7 rounded-2xl overflow-hidden shadow-xl border border-[#1C1917]/10 aspect-square group">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src="/chef_plating_smoke.png"
|
||||
alt="Cozy lodge stone fireplace cooking"
|
||||
className="w-full h-full object-cover scale-102 group-hover:scale-105 transition-transform duration-1000"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Column: Cabin text details */}
|
||||
<div className="lg:col-span-5 space-y-8">
|
||||
<span className="text-[9px] font-bold tracking-[3px] text-[#854D0E] uppercase block">EXCLUSIVELY HAND-CRAFTED</span>
|
||||
<h3 className="font-serif-bunkhouse text-2xl md:text-3xl text-[#1C1917] leading-snug">
|
||||
{t.aboutSub}
|
||||
</h3>
|
||||
<p className="text-[#1C1917]/70 text-xs leading-relaxed font-medium">
|
||||
{t.aboutDesc}
|
||||
</p>
|
||||
|
||||
{/* Details list */}
|
||||
<div className="space-y-4 pt-4 border-t border-[#1C1917]/15">
|
||||
{[
|
||||
{ title: t.feat1Title, text: t.feat1Desc },
|
||||
{ title: t.feat2Title, text: t.feat2Desc },
|
||||
].map((feat, idx) => (
|
||||
<div key={idx} className="flex gap-4">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-[#854D0E] shrink-0 mt-1.5" />
|
||||
<div>
|
||||
<h4 className="text-[10px] font-black uppercase text-[#1C1917] tracking-wider mb-1">{feat.title}</h4>
|
||||
<p className="text-[#1C1917]/50 text-[10px] font-bold leading-relaxed">{feat.text}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── CHANNELS & HOST GUIDES ── */}
|
||||
<section id="host-details" className="py-24 relative z-10 px-6 bg-[#FAF8F5] border-y border-[#1C1917]/10">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="grid lg:grid-cols-3 gap-8">
|
||||
{hizmetler.map((hizmet, idx) => {
|
||||
const locServ = getLocalizedService(hizmet.baslik, hizmet.aciklama);
|
||||
return (
|
||||
<div
|
||||
key={idx}
|
||||
className="bg-[#F5F2EB] p-8 rounded-3xl border border-[#1C1917]/10 flex flex-col justify-between h-72 transition-all hover:shadow-premium group"
|
||||
>
|
||||
<div>
|
||||
<div className="w-12 h-12 rounded-2xl bg-white border border-[#1C1917]/10 flex items-center justify-center mb-6">
|
||||
<svg className="w-5 h-5 text-[#854D0E]" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="m9 12 2 2 4-4" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="font-serif-bunkhouse text-lg font-black uppercase tracking-wider text-[#1C1917] mb-2">
|
||||
{locServ.title}
|
||||
</h3>
|
||||
<p className="text-[#1C1917]/60 text-[11px] leading-relaxed font-semibold">
|
||||
{locServ.desc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => setShowModal(true)}
|
||||
className="text-[#854D0E] font-bold text-[9px] tracking-[2.5px] uppercase flex items-center gap-1 cursor-pointer hover:text-[#5F3507]"
|
||||
>
|
||||
{lang === "tr" ? "DAHA FAZLA KEŞFET →" : "DISCOVER MORE →"}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── CHANNEL BOOKING INTEGRATION ── */}
|
||||
<section id="booking-channels" className="py-32 relative z-10 px-6">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
|
||||
<div className="bg-[#1C1917] text-white rounded-3xl p-8 md:p-12 shadow-2xl relative border border-white/5">
|
||||
<div className="absolute top-0 left-12 right-12 h-0.5 bg-gradient-to-r from-transparent via-[#854D0E] to-transparent" />
|
||||
|
||||
<div className="text-center mb-12">
|
||||
<span className="text-[#854D0E] font-serif-bunkhouse uppercase tracking-widest text-xs block mb-2">{t.channelsTitle}</span>
|
||||
<h2 className="font-serif-bunkhouse text-3xl font-normal tracking-wide text-white uppercase">
|
||||
{t.channelsHeader}
|
||||
</h2>
|
||||
<p className="text-white/40 text-xs mt-2 max-w-md mx-auto leading-relaxed">
|
||||
{t.channelsDesc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Toggle channels buttons */}
|
||||
<div className="grid grid-cols-3 gap-3 mb-10">
|
||||
{[
|
||||
{ id: "airbnb", label: t.chAirbnb },
|
||||
{ id: "vrbo", label: t.chVrbo },
|
||||
{ id: "direct", label: t.chDirect },
|
||||
].map(item => (
|
||||
<button
|
||||
key={item.id}
|
||||
onClick={() => setChannel(item.id)}
|
||||
className={`px-4 py-3.5 rounded-xl border text-[9px] font-bold uppercase tracking-widest transition-all cursor-pointer text-center ${
|
||||
channel === item.id
|
||||
? "bg-[#854D0E] border-[#854D0E] text-white shadow-md"
|
||||
: "bg-white/[0.02] border-white/5 text-white/50 hover:text-white hover:border-white/10"
|
||||
}`}
|
||||
>
|
||||
{item.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Active channel info */}
|
||||
<div className="bg-white/5 rounded-2xl p-6 border border-white/5">
|
||||
<h3 className="font-serif-bunkhouse text-white text-lg font-black uppercase tracking-wider mb-2">
|
||||
{channel === "airbnb" ? t.airbnbTitle : channel === "vrbo" ? t.vrboTitle : t.directTitle}
|
||||
</h3>
|
||||
<p className="text-white/50 text-[11px] leading-relaxed mb-6 font-medium">
|
||||
{channel === "airbnb"
|
||||
? t.airbnbDesc
|
||||
: channel === "vrbo"
|
||||
? t.vrboDesc
|
||||
: t.directDesc}
|
||||
</p>
|
||||
<motion.button
|
||||
onClick={() => setShowModal(true)}
|
||||
className="w-full py-4.5 rounded-xl bg-[#854D0E] hover:bg-white hover:text-[#1C1917] text-white font-bold text-[9px] tracking-[2px] uppercase cursor-pointer transition-colors shadow-md"
|
||||
whileHover={{ scale: 1.01 }}
|
||||
>
|
||||
{t.launchPortal}
|
||||
</motion.button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── TESTIMONIALS ── */}
|
||||
<section id="testimonials" className="py-24 relative z-10 px-6 bg-[#FAF8F5] border-t border-[#1C1917]/10">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="text-center max-w-xl mx-auto mb-20">
|
||||
<span className="text-[#854D0E] font-serif-bunkhouse text-xs uppercase tracking-widest block mb-2">{t.diaries}</span>
|
||||
<h2 className="font-serif-bunkhouse text-3xl font-black uppercase text-[#1C1917]">
|
||||
{t.lovedGuests}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
{/* Grid */}
|
||||
<div className="grid md:grid-cols-2 gap-8">
|
||||
{yorumlar.map((y, yIdx) => (
|
||||
<div
|
||||
key={yIdx}
|
||||
className="bg-white border border-[#1C1917]/10 rounded-3xl p-8 flex flex-col justify-between transition-all hover:shadow-premium group"
|
||||
>
|
||||
<div className="flex gap-1.5 mb-6">
|
||||
{[...Array(5)].map((_, starIdx) => (
|
||||
<svg key={starIdx} className="w-4 h-4 fill-[#854D0E]" viewBox="0 0 24 24">
|
||||
<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
|
||||
</svg>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<p className="text-[#1C1917]/70 text-xs leading-relaxed italic mb-8 font-medium font-serif-bunkhouse">
|
||||
“{y.yorum}”
|
||||
</p>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-full border border-[#1C1917]/10 flex items-center justify-center text-lg bg-[#FAF8F5] select-none font-bold">
|
||||
{y.yazar.charAt(0)}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-serif-bunkhouse text-[#1C1917] text-xs font-black uppercase tracking-wider">
|
||||
{y.yazar}
|
||||
</h4>
|
||||
<span className="text-[9px] text-[#1C1917]/40 uppercase tracking-widest font-black">
|
||||
{y.tarih}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── FOOTER ── */}
|
||||
<footer className="bg-[#1C1917] text-white pt-24 pb-8 px-6 relative z-10">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="grid md:grid-cols-4 gap-12 pb-16 border-b border-white/10">
|
||||
|
||||
{/* About Column */}
|
||||
<div className="md:col-span-2">
|
||||
<span className="font-serif-bunkhouse text-2xl font-black text-white tracking-wider uppercase mb-4 block">
|
||||
Bitterroot<span className="text-[#854D0E]">Bunkhouse</span>
|
||||
</span>
|
||||
<p className="text-white/50 text-xs leading-relaxed max-w-sm mb-8 font-medium">
|
||||
{firma.slogan} — Cozy hand-built rustic cedar cabins deep inside Darby forest valley. High-end off-grid luxury.
|
||||
</p>
|
||||
<div className="text-white/60 text-xs font-medium space-y-3">
|
||||
<p className="flex items-center gap-2">
|
||||
<svg className="w-4 h-4 text-[#854D0E] shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" />
|
||||
<circle cx="12" cy="10" r="3" />
|
||||
</svg>
|
||||
<span className="text-white/80">{firma.adres}</span>
|
||||
</p>
|
||||
<p className="flex items-center gap-2">
|
||||
<svg className="w-4 h-4 text-[#854D0E] shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<rect width="20" height="16" x="2" y="4" rx="2" />
|
||||
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
|
||||
</svg>
|
||||
<span className="text-white/80">{firma.email}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Coordinates Column */}
|
||||
<div>
|
||||
<h4 className="font-serif-bunkhouse text-[#854D0E] text-xs font-black uppercase tracking-wider mb-6">
|
||||
{lang === "tr" ? "KULÜBE KOORDİNATLARI" : "CABIN COORDINATES"}
|
||||
</h4>
|
||||
<div className="space-y-4 text-xs text-white/50 font-semibold">
|
||||
<p>{t.mountainHelp} <br /> <span className="text-white/80">{t.mountainActive}</span></p>
|
||||
<p>Check-In/Out <br /> <span className="text-white/80">{lang === "tr" ? "Giriş: 16:00 · Çıkış: 10:00" : "Check In: 4:00 PM · Check Out: 10:00 AM"}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Services Column */}
|
||||
<div>
|
||||
<h4 className="font-serif-bunkhouse text-[#854D0E] text-xs font-black uppercase tracking-wider mb-6">
|
||||
{t.vipServices}
|
||||
</h4>
|
||||
<div className="space-y-4">
|
||||
{hizmetler.map((h, hIdx) => {
|
||||
const locS = getLocalizedService(h.baslik, h.aciklama);
|
||||
return (
|
||||
<a
|
||||
key={hIdx}
|
||||
href="#host-details"
|
||||
className="block text-white/50 hover:text-[#854D0E] text-xs transition-colors font-semibold"
|
||||
>
|
||||
{locS.title}
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col md:flex-row justify-between items-center pt-8 gap-4 text-white/30 text-xs font-semibold">
|
||||
<p>© 2026 {firma.adi}. All rights reserved.</p>
|
||||
<div className="flex gap-4">
|
||||
<a href="#" className="hover:text-white transition-colors">{t.privacyRegs}</a>
|
||||
<span>·</span>
|
||||
<a href="#" className="hover:text-white transition-colors">{t.termsStay}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{/* ── BOOKING MODAL ── */}
|
||||
<AnimatePresence>
|
||||
{showModal && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 flex items-center justify-center p-6 bg-black/40 backdrop-blur-sm"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
<motion.div
|
||||
className="bg-white rounded-3xl p-8 max-w-md w-full relative shadow-2xl border border-gray-100 text-[#1C1917]"
|
||||
initial={{ scale: 0.95, y: 20 }}
|
||||
animate={{ scale: 1, y: 0 }}
|
||||
exit={{ scale: 0.95, y: 20 }}
|
||||
>
|
||||
{/* Close Button */}
|
||||
<button
|
||||
className="absolute top-6 right-6 w-8 h-8 rounded-full bg-[#F5F2EB] border border-gray-100 flex items-center justify-center text-[#1C1917]/40 hover:text-[#854D0E] hover:border-[#854D0E]/20 transition-all cursor-pointer font-bold"
|
||||
onClick={() => setShowModal(false)}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
{/* Success check indicator */}
|
||||
<div className="w-16 h-16 rounded-2xl bg-[#854D0E]/10 border border-[#854D0E]/20 flex items-center justify-center mb-6">
|
||||
<svg className="w-8 h-8 stroke-[#854D0E] fill-none" viewBox="0 0 24 24" strokeWidth="1.5">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h3 className="font-serif-bunkhouse font-black text-[#1C1917] text-2xl mb-1 uppercase tracking-wider">
|
||||
{t.enquiryActive}
|
||||
</h3>
|
||||
<p className="text-[#854D0E] font-sans-bunkhouse text-[10px] mb-6 uppercase tracking-widest font-black">
|
||||
{t.ambassadorActive}
|
||||
</p>
|
||||
|
||||
<p className="text-[#1C1917]/60 text-xs leading-relaxed mb-8 font-semibold">
|
||||
{t.enquirySuccess}
|
||||
</p>
|
||||
|
||||
<motion.button
|
||||
className="w-full py-4.5 rounded-xl bg-[#854D0E] hover:bg-[#1C1917] text-white font-bold text-[9px] tracking-[2.5px] uppercase cursor-pointer shadow-md shadow-[#854D0E]/15"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
onClick={() => setShowModal(false)}
|
||||
>
|
||||
{t.dismiss}
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,750 @@
|
||||
"use client";
|
||||
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { useState, useEffect } from "react";
|
||||
import type { DemoData } from "@/data/demos";
|
||||
|
||||
const fadeUp = {
|
||||
hidden: { opacity: 0, y: 35 },
|
||||
show: { opacity: 1, y: 0, transition: { duration: 0.65, ease: [0.25, 0.46, 0.45, 0.94] as [number, number, number, number] } },
|
||||
};
|
||||
|
||||
const stagger = {
|
||||
hidden: {},
|
||||
show: { transition: { staggerChildren: 0.08 } },
|
||||
};
|
||||
|
||||
const translations = {
|
||||
tr: {
|
||||
navIdeology: "Tasarım Felsefesi",
|
||||
navServices: "Seçkin Hizmetler",
|
||||
navPortfolio: "Portföyümüz",
|
||||
navEnquire: "Ziyaret Başvurusu",
|
||||
scheduleAccess: "Giriş Planla",
|
||||
badge: "MİNİMAL MONOLİTİK VİLLA",
|
||||
sloganTail: "BRÜT BETON ÇİZGİLERİYLE",
|
||||
heroDesc: "Bodrum Yalıkavak kıyılarında saf yapısal lüksü yaşayın. Brüt monolitik beton formlar, sıfır kenar taşmalı sonsuzluk havuzları ve akıllı ev ses sistemleriyle tasarlandı.",
|
||||
scheduleVisit: "ZİYARET PLANLA",
|
||||
estatePortfolio: "VİLLA PORTFÖYÜ",
|
||||
statTitle1: "PARAMETRE 1",
|
||||
statTitle2: "PARAMETRE 2",
|
||||
statTitle3: "PARAMETRE 3",
|
||||
privateAmenities: "Özel Ayrıcalıklar",
|
||||
bespokeServices: "SEÇKİN VİLLA HİZMETLERİ",
|
||||
secureRes: "GİRİŞ BAŞVURUSU YAP →",
|
||||
privilegedRequest: "Ayrıcalıklı Talep",
|
||||
enquirePrivate: "ZİYARET VE EMLAK BAŞVURUSU",
|
||||
formDesc: "Özel mimari koordinatörlerimizle iletişime geçerek yapılandırılmış villa gezilerini planlayın.",
|
||||
fieldsName: "İsim Soyisim",
|
||||
fieldsEmail: "E-Posta Adresi",
|
||||
fieldsPhone: "İletişim Numarası",
|
||||
fieldsProperty: "Mülk Kategorisi",
|
||||
fieldsNotes: "Özel istekler",
|
||||
fieldsNotesPlaceholder: "Helikopter pisti talepleri, kişisel güvenlik önlemleri...",
|
||||
dispatchForm: "GÜVENLİK FORMUNU GÖNDER",
|
||||
diaries: "Görüşler",
|
||||
trustedOwners: "MÜLK SAHİPLERİNİN GÜVENCESİ",
|
||||
vipCoords: "VIP KOORDİNATLAR",
|
||||
securityHours: "Güvenlik Birimi",
|
||||
securityActive: "24 Saat Kesintisiz Aktif",
|
||||
heliport: "Özel Helikopter Pisti",
|
||||
heliportActive: "Otomatik rötar senkronizasyonu",
|
||||
estateServices: "VİLLA HİZMETLERİ",
|
||||
privacyRegs: "Gizlilik Sözleşmesi",
|
||||
termsStay: "Brüt Beton Koşulları",
|
||||
dismiss: "KAPAT",
|
||||
enquiryActive: "ZİYARET ONAYLANDI",
|
||||
ambassadorActive: "Güvenlik Doğrulaması Başlatıldı",
|
||||
enquirySuccess: "Yalıkavak brüt beton villa gezi talebinizi kaydettik. Güvenlik doğrulama koordinatörümüz, giriş detaylarını onaylamak için en kısa sürede sizinle iletişime geçecektir. Teşekkürler!",
|
||||
},
|
||||
en: {
|
||||
navIdeology: "Design ideology",
|
||||
navServices: "Bespoke services",
|
||||
navPortfolio: "Bento portfolio",
|
||||
navEnquire: "Enquire access",
|
||||
scheduleAccess: "Schedule Access",
|
||||
badge: "MINIMAL MONOLITHIC VILLA",
|
||||
sloganTail: "WITH CONCRETE LINES",
|
||||
heroDesc: "Indulge in sheer structural luxury at Bodrum Yalıkavak coast lines. Designed with raw monolithic architectural concrete forms, zero-edge pools, and smart voice systems.",
|
||||
scheduleVisit: "SCHEDULE VISIT",
|
||||
estatePortfolio: "ESTATE PORTFOLIO",
|
||||
statTitle1: "PARAMETER 1",
|
||||
statTitle2: "PARAMETER 2",
|
||||
statTitle3: "PARAMETER 3",
|
||||
privateAmenities: "Private Amenities",
|
||||
bespokeServices: "BESPOKE VILLA SERVICES",
|
||||
secureRes: "ENQUIRE ACCESS →",
|
||||
privilegedRequest: "Privileged Request",
|
||||
enquirePrivate: "ENQUIRE PRIVATE ACCESS",
|
||||
formDesc: "Connect with our somatic architectural coordinators to schedule structured property walkthroughs.",
|
||||
fieldsName: "Name",
|
||||
fieldsEmail: "Email",
|
||||
fieldsPhone: "Phone",
|
||||
fieldsProperty: "Property Category",
|
||||
fieldsNotes: "Special details",
|
||||
fieldsNotesPlaceholder: "Helipad requirements, personalized security levels...",
|
||||
dispatchForm: "DISPATCH SECURITY FORM",
|
||||
diaries: "Sommelier Reviews",
|
||||
trustedOwners: "TRUSTED BY OWNERS",
|
||||
vipCoords: "VIP COORDINATES",
|
||||
securityHours: "Security Hours",
|
||||
securityActive: "Active 24 Hours",
|
||||
heliport: "Lounge Heliport",
|
||||
heliportActive: "Automated delay syncing",
|
||||
estateServices: "ESTATE SERVICES",
|
||||
privacyRegs: "Privacy Regulations",
|
||||
termsStay: "Terms of Concrete",
|
||||
dismiss: "DISMISS",
|
||||
enquiryActive: "VISIT GRANTED",
|
||||
ambassadorActive: "Security Clearing Initiated",
|
||||
enquirySuccess: "We have registered your executive Yalıkavak concrete villa walkthrough request. A security clearance coordinator will contact you shortly to authorize access parameters. Thank you!",
|
||||
}
|
||||
};
|
||||
|
||||
export default function HotelTemplate3({ data }: { data: DemoData }) {
|
||||
const { firma, istatistikler = [], hizmetler = [], yorumlar = [] } = data;
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [lang, setLang] = useState<"tr" | "en">("tr");
|
||||
const [preloader, setPreloader] = useState(true);
|
||||
|
||||
const t = translations[lang];
|
||||
|
||||
// 1. Lenis Smooth Scroll Integration
|
||||
useEffect(() => {
|
||||
let lenis: any;
|
||||
import("@studio-freight/lenis").then(({ default: Lenis }) => {
|
||||
lenis = new Lenis({ duration: 1.2, easing: (t: number) => Math.min(1, 1.001 - Math.pow(2, -10 * t)) });
|
||||
function raf(time: number) { lenis.raf(time); requestAnimationFrame(raf); }
|
||||
requestAnimationFrame(raf);
|
||||
});
|
||||
return () => lenis?.destroy();
|
||||
}, []);
|
||||
|
||||
// 2. Preloader Curtain Timer
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setPreloader(false);
|
||||
}, 1500);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
// Localized statistics
|
||||
const getLocalizedStat = (deger: string, etiket: string) => {
|
||||
if (deger.includes("Concrete")) {
|
||||
return {
|
||||
deger: lang === "tr" ? "Brüt Beton" : "Concrete",
|
||||
etiket: lang === "tr" ? "Tik ağacı zemin kaplamaları ile birleştirilmiş brüt monolitik beton formlar." : etiket
|
||||
};
|
||||
}
|
||||
if (deger.includes("Smart")) {
|
||||
return {
|
||||
deger: lang === "tr" ? "Akıllı Konut" : "Smart Estate",
|
||||
etiket: lang === "tr" ? "Tam entegre ses arayüzleri, otomatik havalandırma ve yedek güneş enerjisi." : etiket
|
||||
};
|
||||
}
|
||||
return {
|
||||
deger: lang === "tr" ? "Deniz Manzarası" : "Sea View",
|
||||
etiket: lang === "tr" ? "Yerden tavana kadar kesintisiz cam panellerle tasarlanmış konsol yatak odaları." : etiket
|
||||
};
|
||||
};
|
||||
|
||||
// Localized services
|
||||
const getLocalizedService = (baslik: string, aciklama: string) => {
|
||||
if (baslik.includes("ARCHITECTURAL")) {
|
||||
return {
|
||||
title: lang === "tr" ? "MİMARİ TURLAR" : "ARCHITECTURAL TOURS",
|
||||
desc: lang === "tr" ? "Karbon yapılar, brüt beton dokular ve taşmalı havuzları gösteren özel emlak turları." : aciklama
|
||||
};
|
||||
}
|
||||
if (baslik.includes("MASTERCLASSES")) {
|
||||
return {
|
||||
title: lang === "tr" ? "TASARIM EĞİTİMLERİ" : "DESIGN MASTERCLASSES",
|
||||
desc: lang === "tr" ? "Minimalist yaşam, özel mobilya yerleşimi ve sürdürülebilir brüt beton tasarımı atölyelerimiz." : aciklama
|
||||
};
|
||||
}
|
||||
return {
|
||||
title: lang === "tr" ? "ÖZEL LÜKS VİLLA" : "EXECUTIVE LUXURY VILLA",
|
||||
desc: lang === "tr" ? "Kişisel sommelier desteği, otomatik helikopter pisti ve üst düzey güvenlik ile tam mülk kiralama." : aciklama
|
||||
};
|
||||
};
|
||||
|
||||
const css = `
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
|
||||
|
||||
:root {
|
||||
--color-apex-emerald: #059669;
|
||||
--color-apex-slate: #09090C;
|
||||
--color-apex-card: #14141A;
|
||||
--color-apex-white: #FAF8F5;
|
||||
--color-apex-muted: rgba(250, 248, 245, 0.5);
|
||||
}
|
||||
|
||||
.font-apex-heading {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
|
||||
.font-sans-apex {
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
|
||||
.bg-apex-mesh {
|
||||
background-image:
|
||||
radial-gradient(circle at 10% 20%, rgba(5, 150, 105, 0.04) 0%, transparent 45%),
|
||||
radial-gradient(circle at 90% 80%, rgba(250, 248, 245, 0.01) 0%, transparent 50%),
|
||||
linear-gradient(rgba(255, 255, 255, 0.005) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(255, 255, 255, 0.005) 1px, transparent 1px);
|
||||
background-size: 100% 100%, 100% 100%, 40px 40px, 40px 40px;
|
||||
}
|
||||
|
||||
.emerald-glow {
|
||||
box-shadow: 0 0 25px rgba(5, 150, 105, 0.15);
|
||||
}
|
||||
|
||||
.hero-title-clamp {
|
||||
font-size: clamp(34px, 5.5vw, 85px);
|
||||
line-height: 0.95;
|
||||
}
|
||||
`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{css}</style>
|
||||
|
||||
{/* ── IMZA AN: CURTAIN REVEAL PRELOADER ── */}
|
||||
<AnimatePresence>
|
||||
{preloader && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 bg-[#09090C] flex flex-col items-center justify-center p-6"
|
||||
exit={{
|
||||
clipPath: "polygon(0 0, 100% 0, 100% 0, 0 0)",
|
||||
transition: { duration: 0.85, ease: [0.16, 1, 0.3, 1] }
|
||||
}}
|
||||
>
|
||||
<div className="max-w-md text-center space-y-6">
|
||||
<motion.span
|
||||
className="text-[9px] font-black tracking-[4px] uppercase text-[#059669] block font-sans-apex"
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
APEX ARC MONOLITHIC
|
||||
</motion.span>
|
||||
<div className="h-[1px] w-48 bg-white/10 mx-auto relative overflow-hidden">
|
||||
<motion.div
|
||||
className="absolute inset-y-0 left-0 bg-[#059669]"
|
||||
initial={{ width: "0%" }}
|
||||
animate={{ width: "100%" }}
|
||||
transition={{ duration: 1.2, ease: "easeInOut" }}
|
||||
/>
|
||||
</div>
|
||||
<motion.h2
|
||||
className="font-apex-heading text-white text-lg font-light tracking-wider"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.4, duration: 0.5 }}
|
||||
>
|
||||
brutalist villa estate
|
||||
</motion.h2>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* SLEEK BRUTALIST ARCHITECTURAL ESTATE THEME */}
|
||||
<div className="bg-[#09090C] text-[#FAF8F5] min-h-screen font-sans-apex selection:bg-[#059669] selection:text-white overflow-hidden relative bg-apex-mesh pb-24">
|
||||
|
||||
{/* Floating Ambient Emerald Orbs */}
|
||||
<div className="absolute top-[15%] left-[-15%] w-[600px] h-[600px] bg-[#059669]/4 blur-[130px] rounded-full pointer-events-none z-0" />
|
||||
<div className="absolute bottom-[20%] right-[-15%] w-[600px] h-[600px] bg-[#FAF8F5]/1 blur-[140px] rounded-full pointer-events-none z-0" />
|
||||
|
||||
{/* ── MANDATORY FLOATING DEMO BANNER ── */}
|
||||
<div className="fixed bottom-4 left-4 z-40 bg-[#14141A]/95 backdrop-blur-md border border-white/5 px-4 py-2.5 rounded-xl shadow-2xl flex items-center gap-2.5 max-w-sm pointer-events-none select-none">
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-[#059669] animate-pulse" />
|
||||
<span className="text-[9px] font-black uppercase tracking-[1.5px] text-white/90">
|
||||
{lang === "tr" ? "Bu web sitesi Ayris Tech tarafından hazırlanmış bir konsept çalışmasıdır." : "This website is a premium concept prototype designed by Ayris Tech."}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{/* ── HIGH CONTRAST SLATE NAVBAR ── */}
|
||||
<motion.header
|
||||
className="fixed top-4 left-4 right-4 z-50 px-4"
|
||||
initial={{ y: -80, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.7, ease: "easeOut" }}
|
||||
>
|
||||
<div className="mx-auto max-w-7xl h-20 flex items-center justify-between px-8 bg-[#14141A]/95 backdrop-blur-xl border border-white/5 rounded-2xl shadow-[0_15px_30px_rgba(0,0,0,0.5)]">
|
||||
{/* Logo */}
|
||||
<a href="#" className="flex items-center gap-2 group">
|
||||
<span className="text-xl font-bold tracking-[1.5px] text-white font-apex-heading flex items-center gap-2.5 uppercase">
|
||||
<svg className="w-5 h-5 text-[#059669]" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<rect x="3" y="3" width="18" height="18" rx="2" />
|
||||
<path d="M9 3v18" />
|
||||
<path d="M15 3v18" />
|
||||
<path d="M3 9h18" />
|
||||
<path d="M3 15h18" />
|
||||
</svg>
|
||||
{firma.adi}
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{/* Links */}
|
||||
<nav className="hidden lg:flex items-center gap-8">
|
||||
{[
|
||||
{ label: t.navIdeology, href: "#ideology" },
|
||||
{ label: t.navServices, href: "#services" },
|
||||
{ label: t.navPortfolio, href: "#portfolio" },
|
||||
{ label: t.navEnquire, href: "#booking-flow" }
|
||||
].map(item => (
|
||||
<a
|
||||
key={item.label}
|
||||
href={item.href}
|
||||
className="text-[10px] font-black tracking-[2px] uppercase text-[#FAF8F5]/70 hover:text-[#059669] transition-colors relative py-1 cursor-pointer group"
|
||||
>
|
||||
{item.label}
|
||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-[#059669] transition-all group-hover:w-full" />
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
{/* Language Selector + Booking Button */}
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Language Switcher */}
|
||||
<div className="flex items-center gap-1 bg-white/5 border border-white/10 rounded-xl p-1 shrink-0">
|
||||
<button
|
||||
onClick={() => setLang("tr")}
|
||||
className={`text-[9px] font-black px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "tr" ? "bg-white text-slate-900 shadow-sm" : "text-white/60 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
TR
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setLang("en")}
|
||||
className={`text-[9px] font-black px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "en" ? "bg-white text-slate-900 shadow-sm" : "text-white/60 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
EN
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<motion.button
|
||||
onClick={() => setShowModal(true)}
|
||||
className="text-[10px] font-black tracking-[2.5px] uppercase text-white bg-[#059669] hover:bg-white hover:text-black px-6 py-3.5 rounded-xl transition-all cursor-pointer shadow-[0_5px_15px_rgba(5,150,105,0.2)] hidden sm:block"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{t.scheduleAccess}
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.header>
|
||||
|
||||
{/* ── ARCHITECTURAL HERO BANNER ── */}
|
||||
<section className="relative min-h-screen pt-32 pb-20 flex items-center z-10 px-6">
|
||||
<div className="max-w-7xl mx-auto w-full">
|
||||
<div className="grid lg:grid-cols-12 gap-16 items-center">
|
||||
|
||||
{/* Left Column: Heading and Brutalist descriptions */}
|
||||
<motion.div
|
||||
className="lg:col-span-7 z-20"
|
||||
variants={stagger}
|
||||
initial="hidden"
|
||||
animate="show"
|
||||
>
|
||||
<motion.div
|
||||
variants={fadeUp}
|
||||
className="inline-flex items-center gap-2 text-[10px] font-black uppercase tracking-widest text-[#059669] mb-6 bg-[#059669]/10 border border-[#059669]/20 px-4 py-2 rounded-full"
|
||||
>
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-[#059669]" />
|
||||
{t.badge}
|
||||
</motion.div>
|
||||
|
||||
<motion.h1
|
||||
variants={fadeUp}
|
||||
className="font-apex-heading text-white leading-[0.95] tracking-tight mb-8 uppercase hero-title-clamp"
|
||||
>
|
||||
{firma.slogan}
|
||||
<br />
|
||||
<span className="text-[#059669]">{t.sloganTail}</span>
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
variants={fadeUp}
|
||||
className="text-[#FAF8F5]/60 text-xs lg:text-sm leading-relaxed max-w-xl mb-12 font-medium"
|
||||
>
|
||||
{t.heroDesc}
|
||||
</motion.p>
|
||||
|
||||
{/* Quick actions */}
|
||||
<motion.div variants={fadeUp} className="flex gap-4">
|
||||
<motion.button
|
||||
onClick={() => setShowModal(true)}
|
||||
className="px-8 py-4 rounded-xl bg-[#059669] hover:bg-white hover:text-[#09090C] text-white font-black text-[10px] tracking-[2px] uppercase transition-all shadow-[0_5px_15px_rgba(5,150,105,0.25)] cursor-pointer"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
>
|
||||
{t.scheduleVisit}
|
||||
</motion.button>
|
||||
<a
|
||||
href="#portfolio"
|
||||
className="px-8 py-4 rounded-xl border border-white/10 bg-white/5 hover:bg-white/10 text-white font-black text-[10px] tracking-[2px] uppercase transition-all cursor-pointer text-center"
|
||||
>
|
||||
{t.estatePortfolio}
|
||||
</a>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Column: High-fidelity image (brutalist fireplace oven) */}
|
||||
<div className="lg:col-span-5 relative flex justify-center lg:justify-end">
|
||||
<motion.div
|
||||
className="relative w-full max-w-md lg:max-w-lg h-[430px] lg:h-[510px] rounded-3xl overflow-hidden shadow-2xl border border-white/5 group"
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.8, ease: "easeOut" }}
|
||||
>
|
||||
{/* Raw concrete fireplace oven representing structural concrete warmth */}
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src="/sicilia_wood_oven.png"
|
||||
alt="Apex Arc Monolithic Architectural Fireplace"
|
||||
className="w-full h-full object-cover scale-102 group-hover:scale-105 transition-transform duration-[4000ms]"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black via-transparent to-transparent opacity-50" />
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── IDEOLOGY STATISTICS BLOCK ── */}
|
||||
<section id="ideology" className="py-24 relative z-10 px-6 bg-[#14141A]/60 border-y border-white/5">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
{istatistikler.map((stat, idx) => {
|
||||
const locStat = getLocalizedStat(stat.deger, stat.etiket);
|
||||
return (
|
||||
<div
|
||||
key={idx}
|
||||
className="bg-[#14141A] p-8 rounded-3xl border border-white/5 flex flex-col justify-between h-48 transition-all hover:border-[#059669]/30"
|
||||
>
|
||||
<span className="text-[10px] font-black tracking-[3px] text-[#059669] uppercase block mb-2">{idx === 0 ? t.statTitle1 : idx === 1 ? t.statTitle2 : t.statTitle3}</span>
|
||||
<h3 className="font-apex-heading text-2xl font-bold uppercase text-white tracking-wider">
|
||||
{locStat.deger}
|
||||
</h3>
|
||||
<p className="text-[#FAF8F5]/50 text-[10px] font-semibold leading-relaxed">
|
||||
{locStat.etiket}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── BESPOKE SERVICES ── */}
|
||||
<section id="services" className="py-28 relative z-10 px-6">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="text-center max-w-xl mx-auto mb-20">
|
||||
<span className="text-[#059669] font-apex-heading text-xs uppercase tracking-widest block mb-2">{t.privateAmenities}</span>
|
||||
<h2 className="font-apex-heading text-3xl lg:text-4xl font-bold uppercase text-white">
|
||||
{t.bespokeServices}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
{/* Bento services grid */}
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
{hizmetler.map((hizmet, idx) => {
|
||||
const locServ = getLocalizedService(hizmet.baslik, hizmet.aciklama);
|
||||
return (
|
||||
<motion.div
|
||||
key={idx}
|
||||
className="bg-[#14141A] rounded-3xl border border-white/5 overflow-hidden transition-all duration-300 hover:border-[#059669]/30 flex flex-col justify-between group shadow-sm"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: idx * 0.1 }}
|
||||
whileHover={{ y: -4 }}
|
||||
>
|
||||
{/* Cover image using dark upscale culinary smoke or organic lemon */}
|
||||
<div className="h-44 overflow-hidden relative border-b border-white/5">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={idx === 0 ? "/sicilia_wood_oven.png" : idx === 1 ? "/chef_plating_smoke.png" : "/sicilia_lemon_heritage.png"}
|
||||
alt={hizmet.baslik}
|
||||
className="w-full h-full object-cover scale-102 group-hover:scale-105 transition-transform duration-1000"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/40" />
|
||||
</div>
|
||||
|
||||
<div className="p-8 space-y-4">
|
||||
<h3 className="font-apex-heading font-bold text-lg text-white tracking-wider uppercase leading-snug">
|
||||
{locServ.title}
|
||||
</h3>
|
||||
<p className="text-[#FAF8F5]/50 text-[11px] leading-relaxed font-semibold">
|
||||
{locServ.desc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="px-8 pb-8">
|
||||
<button
|
||||
onClick={() => setShowModal(true)}
|
||||
className="text-[#059669] group-hover:text-white transition-colors text-[10px] font-black tracking-[2px] uppercase flex items-center gap-1.5 cursor-pointer"
|
||||
>
|
||||
{t.secureRes}
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── RESERVATION FLOW ── */}
|
||||
<section id="booking-flow" className="py-24 relative z-10 px-6 border-t border-white/5 bg-[#14141A]/40">
|
||||
<div className="max-w-3xl mx-auto">
|
||||
|
||||
<div className="bg-[#14141A] rounded-3xl p-8 md:p-12 shadow-2xl border border-white/5 relative">
|
||||
<div className="absolute top-0 left-12 right-12 h-0.5 bg-gradient-to-r from-transparent via-[#059669] to-transparent glowing-bar" />
|
||||
|
||||
<div className="text-center mb-10">
|
||||
<span className="text-[#059669] font-apex-heading text-xs uppercase tracking-widest block mb-2">{t.privilegedRequest}</span>
|
||||
<h2 className="font-apex-heading text-3xl md:text-4xl font-bold uppercase text-white">
|
||||
{t.enquirePrivate}
|
||||
</h2>
|
||||
<p className="text-[#FAF8F5]/40 text-xs mt-2 font-medium">
|
||||
{t.formDesc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-5">
|
||||
{[
|
||||
{ label: t.fieldsName, placeholder: lang === "tr" ? "Adınız Soyadınız" : "Your Name", type: "text", full: false },
|
||||
{ label: t.fieldsEmail, placeholder: "you@company.com", type: "email", full: false },
|
||||
{ label: t.fieldsPhone, placeholder: lang === "tr" ? "İrtibat Numarası" : "Contact Number", type: "tel", full: false },
|
||||
{ label: t.fieldsProperty, placeholder: lang === "tr" ? "Yalıkavak Beton Villa" : "Yalıkavak Concrete Villa", type: "text", full: false },
|
||||
{ label: t.fieldsNotes, placeholder: t.fieldsNotesPlaceholder, type: "text", full: true },
|
||||
].map((field, idx) => (
|
||||
<div key={idx} className={field.full ? "col-span-2" : "col-span-1"}>
|
||||
<label className="block text-[10px] font-black text-[#FAF8F5]/50 mb-1.5 uppercase tracking-widest">{field.label}</label>
|
||||
<input
|
||||
type={field.type}
|
||||
placeholder={field.placeholder}
|
||||
className="w-full px-4 py-3.5 rounded-xl border border-white/5 bg-[#09090C] text-xs text-white placeholder-white/20 focus:outline-none focus:border-[#059669] focus:ring-1 focus:ring-[#059669] transition-all font-semibold"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<motion.button
|
||||
onClick={() => setShowModal(true)}
|
||||
className="mt-8 w-full py-4 rounded-xl bg-[#059669] hover:bg-white hover:text-[#09090C] text-white font-bold text-[10px] tracking-[2.5px] uppercase transition-colors cursor-pointer"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{t.dispatchForm}
|
||||
</motion.button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── TESTIMONIALS ── */}
|
||||
<section id="testimonials" className="py-28 relative z-10 px-6 border-t border-white/5">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="text-center max-w-xl mx-auto mb-20">
|
||||
<span className="text-[#059669] font-apex-heading text-xs uppercase tracking-widest block mb-2">{t.diaries}</span>
|
||||
<h2 className="font-apex-heading text-3xl lg:text-4xl font-bold uppercase text-white">
|
||||
{t.trustedOwners}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
{/* Testimonials */}
|
||||
<div className="grid md:grid-cols-2 gap-8">
|
||||
{yorumlar.map((y, yIdx) => (
|
||||
<motion.div
|
||||
key={yIdx}
|
||||
className="bg-[#14141A] border border-white/5 rounded-3xl p-8 flex flex-col justify-between transition-all duration-300 hover:border-[#059669]/30 group"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: yIdx * 0.1 }}
|
||||
whileHover={{ y: -4 }}
|
||||
>
|
||||
<div className="flex gap-1.5 mb-6">
|
||||
{[...Array(5)].map((_, starIdx) => (
|
||||
<svg key={starIdx} className="w-4 h-4 fill-[#059669]" viewBox="0 0 24 24">
|
||||
<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
|
||||
</svg>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<p className="text-[#FAF8F5]/70 text-xs leading-relaxed italic mb-8 font-medium font-serif-bunkhouse">
|
||||
“{y.yorum}”
|
||||
</p>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-full border border-white/10 flex items-center justify-center text-lg bg-[#09090C] select-none font-bold">
|
||||
{y.yazar.charAt(0)}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-apex-heading text-white text-xs font-black uppercase tracking-wider">
|
||||
{y.yazar}
|
||||
</h4>
|
||||
<span className="text-[9px] text-[#FAF8F5]/40 uppercase tracking-widest font-black">
|
||||
{y.tarih}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── FOOTER ── */}
|
||||
<footer className="bg-[#14141A] border-t border-white/5 pt-24 pb-8 px-6 relative z-10">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<div className="grid md:grid-cols-4 gap-12 pb-16 border-b border-white/5">
|
||||
|
||||
{/* About Column */}
|
||||
<div className="md:col-span-2">
|
||||
<span className="font-apex-heading text-2xl font-black text-white tracking-wider uppercase mb-4 block">
|
||||
Apex<span className="text-[#059669]">Arc</span>
|
||||
</span>
|
||||
<p className="text-[#FAF8F5]/50 text-xs leading-relaxed max-w-sm mb-8 font-medium">
|
||||
{firma.slogan} — Monolithic concrete-Teak luxury estates looking over Muğla coastlines. High-end voice smart interfaces.
|
||||
</p>
|
||||
<div className="text-[#FAF8F5]/60 text-xs font-medium space-y-3">
|
||||
<p className="flex items-center gap-2">
|
||||
<svg className="w-4 h-4 text-[#059669] shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" />
|
||||
<circle cx="12" cy="10" r="3" />
|
||||
</svg>
|
||||
<span className="text-[#FAF8F5]/80">{firma.adres}</span>
|
||||
</p>
|
||||
<p className="flex items-center gap-2">
|
||||
<svg className="w-4 h-4 text-[#059669] shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<rect width="20" height="16" x="2" y="4" rx="2" />
|
||||
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
|
||||
</svg>
|
||||
<span className="text-[#FAF8F5]/80">{firma.email}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Coordinates Column */}
|
||||
<div>
|
||||
<h4 className="font-apex-heading text-[#059669] text-xs font-black uppercase tracking-wider mb-6">
|
||||
{t.vipCoords}
|
||||
</h4>
|
||||
<div className="space-y-4 text-xs text-[#FAF8F5]/50 font-semibold">
|
||||
<p>{t.securityHours} <br /> <span className="text-white/80">{t.securityActive}</span></p>
|
||||
<p>{t.heliport} <br /> <span className="text-white/80">{t.heliportActive}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Services Column */}
|
||||
<div>
|
||||
<h4 className="font-apex-heading text-[#059669] text-xs font-black uppercase tracking-wider mb-6">
|
||||
{t.estateServices}
|
||||
</h4>
|
||||
<div className="space-y-4">
|
||||
{hizmetler.map((h, hIdx) => {
|
||||
const locS = getLocalizedService(h.baslik, h.aciklama);
|
||||
return (
|
||||
<a
|
||||
key={hIdx}
|
||||
href="#services"
|
||||
className="block text-[#FAF8F5]/50 hover:text-[#059669] text-xs transition-colors font-semibold"
|
||||
>
|
||||
{locS.title}
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col md:flex-row justify-between items-center pt-8 gap-4 text-[#FAF8F5]/30 text-xs font-semibold">
|
||||
<p>© 2026 {firma.adi}. All rights reserved.</p>
|
||||
<div className="flex gap-4">
|
||||
<a href="#" className="hover:text-white transition-colors">{t.privacyRegs}</a>
|
||||
<span>·</span>
|
||||
<a href="#" className="hover:text-white transition-colors">{t.termsStay}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{/* ── ENQUIRY MODAL ── */}
|
||||
<AnimatePresence>
|
||||
{showModal && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 flex items-center justify-center p-6 bg-black/80 backdrop-blur-sm"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
<motion.div
|
||||
className="bg-[#14141A] rounded-3xl p-8 max-w-md w-full relative shadow-2xl border border-[#059669]/20 text-white"
|
||||
initial={{ scale: 0.95, y: 20 }}
|
||||
animate={{ scale: 1, y: 0 }}
|
||||
exit={{ scale: 0.95, y: 20 }}
|
||||
>
|
||||
{/* Close Button */}
|
||||
<button
|
||||
className="absolute top-6 right-6 w-8 h-8 rounded-full bg-[#09090C] border border-white/5 flex items-center justify-center text-white/40 hover:text-[#059669] hover:border-[#059669]/20 transition-all cursor-pointer font-bold"
|
||||
onClick={() => setShowModal(false)}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
{/* Success check indicator */}
|
||||
<div className="w-16 h-16 rounded-2xl bg-[#059669]/10 border border-[#059669]/20 flex items-center justify-center mb-6">
|
||||
<svg className="w-8 h-8 stroke-[#059669] fill-none" viewBox="0 0 24 24" strokeWidth="1.5">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h3 className="font-apex-heading font-black text-white text-2xl mb-1 uppercase tracking-wider">
|
||||
{t.enquiryActive}
|
||||
</h3>
|
||||
<p className="text-[#059669] font-sans-apex text-[10px] mb-6 uppercase tracking-widest font-black">
|
||||
{t.ambassadorActive}
|
||||
</p>
|
||||
|
||||
<p className="text-[#FAF8F5]/60 text-xs leading-relaxed mb-8 font-semibold">
|
||||
{t.enquirySuccess}
|
||||
</p>
|
||||
|
||||
<motion.button
|
||||
className="w-full py-4.5 rounded-xl bg-[#059669] hover:bg-black hover:text-white text-white font-bold text-[9px] tracking-[2.5px] uppercase cursor-pointer shadow-md shadow-[#059669]/15"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
onClick={() => setShowModal(false)}
|
||||
>
|
||||
{t.dismiss}
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,945 @@
|
||||
"use client";
|
||||
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { useState, useEffect } from "react";
|
||||
import type { DemoData } from "@/data/demos";
|
||||
|
||||
const fadeUp = {
|
||||
hidden: { opacity: 0, y: 35 },
|
||||
show: { opacity: 1, y: 0, transition: { duration: 0.75, ease: [0.25, 0.46, 0.45, 0.94] as [number, number, number, number] } },
|
||||
};
|
||||
|
||||
const stagger = {
|
||||
hidden: {},
|
||||
show: { transition: { staggerChildren: 0.1 } },
|
||||
};
|
||||
|
||||
const translations = {
|
||||
tr: {
|
||||
navServices: "Hizmetlerimiz",
|
||||
navDoctors: "Uzman Kadromuz",
|
||||
navReviews: "Hasta Yorumları",
|
||||
navContact: "İletişim",
|
||||
navBooking: "Randevu Al",
|
||||
badge: "GÜVENİLİR SAĞLIK MERKEZİ",
|
||||
heroTitlePart1: "Sağlığınız İçin",
|
||||
heroTitlePart2: "En İyi Ellerde",
|
||||
heroTitlePart3: "Olun",
|
||||
heroDesc: "Uzman hekim kadromuz, modern tıbbi donanımımız ve kişiye özel tedavi yaklaşımlarımızla sağlığınızı korumak için buradayız. Doğan Tıp Merkezi güvenilir koordinatları.",
|
||||
appointmentsToday: "Bugünkü Randevular",
|
||||
saturday: "Cumartesi, 28 Mayıs 2026",
|
||||
appointmentList: [
|
||||
{ saat: "09:30", tip: "Genel Muayene", dolu: true },
|
||||
{ saat: "11:00", tip: "Check-Up Kontrolü", dolu: false },
|
||||
{ saat: "13:30", tip: "Kardiyoloji Muayenesi", dolu: true },
|
||||
{ saat: "15:00", tip: "Göz Muayenesi", dolu: false },
|
||||
],
|
||||
statusDolu: "Dolu",
|
||||
statusMusait: "Müsait",
|
||||
ratingText: "4.9 / 5 • 620+ Hasta Değerlendirmesi",
|
||||
smsReminder: "SMS Hatırlatma",
|
||||
smsDesc: "Randevularınızı asla kaçırmayın",
|
||||
servicesTitle: "Hizmetlerimiz",
|
||||
servicesHeader: "UZMAN KADROMUZLA HER ALANDA YANINIZDAYIZ",
|
||||
learnMore: "Detaylı Bilgi →",
|
||||
doctorsTitle: "Ekibimiz",
|
||||
doctorsHeader: "ALANINDA UZMAN DOKTORLARIMIZ",
|
||||
yearsExp: "Yıl Deneyim",
|
||||
patientsTreated: "Hasta Tedavisi",
|
||||
bookingTitle: "Online Randevu",
|
||||
bookingHeader: "HEMEN RANDEVU OLUŞTURUN",
|
||||
bookingDesc: "Formu doldurun, randevu koordinatörümüz sizi 15 dakika içinde arayıp gününüzü kesinleştirsin.",
|
||||
fieldsName: "Ad Soyad",
|
||||
fieldsPhone: "Telefon Numarası",
|
||||
fieldsEmail: "E-Posta Adresi",
|
||||
fieldsDepartment: "Bölüm / Klinik",
|
||||
fieldsDate: "Randevu Tarihi",
|
||||
fieldsNotes: "Notunuz / Şikayetiniz",
|
||||
fieldsNotesPlaceholder: "Belirtmek istediğiniz tıbbi şikayetler veya özel notlar...",
|
||||
dispatchForm: "RANDEVU TALEP ET",
|
||||
contactDetails: "İLETİŞİM BİLGİLERİMİZ",
|
||||
callCenter: "7/24 Çağrı Merkezi",
|
||||
addressLabel: "Klinik Adresi",
|
||||
emailLabel: "E-Posta",
|
||||
footerDesc: "İleri tanı ve tedavi yöntemleri, hasta odaklı hizmet anlayışı ve seçkin hekim kadrosuyla sağlığınız için en güvenilir koordinat.",
|
||||
privacyRegs: "Gizlilik Sözleşmesi",
|
||||
termsStay: "Kullanım Şartları",
|
||||
dismiss: "KAPAT",
|
||||
contactTitle: "Hızlı Danışma",
|
||||
contactDesc: "İletişim bilgilerinizi bırakın, tıbbi danışmanımız sizi hemen arasın.",
|
||||
submit: "Gönder",
|
||||
serviceDahiliye: "Dahiliye",
|
||||
serviceDahiliyeDesc: "Erişkin hastalıklarında kapsamlı tanı ve tedavi hizmetleri.",
|
||||
serviceKardiyoloji: "Kardiyoloji",
|
||||
serviceKardiyolojiDesc: "Kalp ve damar sağlığı için ileri tanı ve tedavi yöntemleri.",
|
||||
serviceDis: "Diş Hekimliği",
|
||||
serviceDisDesc: "İmplant, ortodonti ve estetik gülüş tasarımı uygulamaları.",
|
||||
serviceGoz: "Göz Sağlığı",
|
||||
serviceGozDesc: "Lazer tedavileri, katarakt ve mikro cerrahi operasyonları.",
|
||||
serviceLab: "Laboratuvar",
|
||||
serviceLabDesc: "Hızlı, güvenilir ve tam kapsamlı tahlil sonuçları.",
|
||||
serviceRad: "Radyoloji",
|
||||
serviceRadDesc: "MR, bilgisayarlı tomografi ve ileri ultrason görüntüleme.",
|
||||
},
|
||||
en: {
|
||||
navServices: "Our Services",
|
||||
navDoctors: "Our Doctors",
|
||||
navReviews: "Testimonials",
|
||||
navContact: "Contact",
|
||||
navBooking: "Book Appointment",
|
||||
badge: "TRUSTED MEDICAL CENTER",
|
||||
heroTitlePart1: "Your Health",
|
||||
heroTitlePart2: "In The Safest Hands",
|
||||
heroTitlePart3: "Always",
|
||||
heroDesc: "We protect your health with our expert physicians, state-of-the-art diagnostic systems, and customized treatment plans. Trusted coordinates of Doğan Medical Center.",
|
||||
appointmentsToday: "Today's Schedule",
|
||||
saturday: "Saturday, May 28, 2026",
|
||||
appointmentList: [
|
||||
{ saat: "09:30", tip: "General Checkup", dolu: true },
|
||||
{ saat: "11:00", tip: "Prevention Review", dolu: false },
|
||||
{ saat: "13:30", tip: "Cardiology Consult", dolu: true },
|
||||
{ saat: "15:00", tip: "Ophthalmology Exam", dolu: false },
|
||||
],
|
||||
statusDolu: "Booked",
|
||||
statusMusait: "Available",
|
||||
ratingText: "4.9 / 5 • 620+ Patient Feedbacks",
|
||||
smsReminder: "SMS Reminder",
|
||||
smsDesc: "Never miss your medical checks",
|
||||
servicesTitle: "Our Services",
|
||||
servicesHeader: "COMPREHENSIVE MEDICAL CARE IN EVERY SPECIALTY",
|
||||
learnMore: "Learn More →",
|
||||
doctorsTitle: "Our Team",
|
||||
doctorsHeader: "MEET OUR ACCOMPLISHED PHYSICIANS",
|
||||
yearsExp: "Years Experience",
|
||||
patientsTreated: "Patients Treated",
|
||||
bookingTitle: "Online Booking",
|
||||
bookingHeader: "SCHEDULE A MEDICAL APPOINTMENT",
|
||||
bookingDesc: "Fill in the details and our patient representative will call you back within 15 minutes to lock your slot.",
|
||||
fieldsName: "Full Name",
|
||||
fieldsPhone: "Phone Number",
|
||||
fieldsEmail: "Email Address",
|
||||
fieldsDepartment: "Specialty / Department",
|
||||
fieldsDate: "Preferred Date",
|
||||
fieldsNotes: "Symptoms / Clinical Notes",
|
||||
fieldsNotesPlaceholder: "Briefly describe your symptoms or specific notes for the doctor...",
|
||||
dispatchForm: "REQUEST APPOINTMENT",
|
||||
contactDetails: "CONTACT CHANNELS",
|
||||
callCenter: "24/7 Call Center",
|
||||
addressLabel: "Clinic Coordinates",
|
||||
emailLabel: "Support Email",
|
||||
footerDesc: "Trusted medical hub offering comprehensive diagnosis and advanced therapy protocols utilizing the latest patient care systems.",
|
||||
privacyRegs: "Privacy Policy",
|
||||
termsStay: "Terms of Service",
|
||||
dismiss: "DISMISS",
|
||||
contactTitle: "Quick Consultation",
|
||||
contactDesc: "Leave your contact coordinates and our medical coordinator will call you back shortly.",
|
||||
submit: "Submit",
|
||||
serviceDahiliye: "Internal Medicine",
|
||||
serviceDahiliyeDesc: "Comprehensive diagnostics and advanced therapies for adult diseases.",
|
||||
serviceKardiyoloji: "Cardiology",
|
||||
serviceKardiyolojiDesc: "Advanced diagnostics and treatment plans for cardiovascular wellness.",
|
||||
serviceDis: "Dentistry",
|
||||
serviceDisDesc: "Modern implants, clear aligners, and aesthetic smile design applications.",
|
||||
serviceGoz: "Ophthalmology",
|
||||
serviceGozDesc: "State-of-the-art laser corrections, cataract surgeries, and microsurgery.",
|
||||
serviceLab: "Medical Laboratory",
|
||||
serviceLabDesc: "Ultra-fast, certified, and fully automated biological analysis protocols.",
|
||||
serviceRad: "Advanced Radiology",
|
||||
serviceRadDesc: "High-resolution MRI, computerized tomography, and diagnostic ultrasound.",
|
||||
}
|
||||
};
|
||||
|
||||
export default function KlinikTemplate({ data }: { data: DemoData }) {
|
||||
const { firma, istatistikler = [], hizmetler = [], doktorlar = [], yorumlar = [] } = data;
|
||||
const [showBookingModal, setShowBookingModal] = useState(false);
|
||||
const [activeYorum, setActiveYorum] = useState(0);
|
||||
const [lang, setLang] = useState<"tr" | "en">("tr");
|
||||
const [preloader, setPreloader] = useState(true);
|
||||
|
||||
const t = translations[lang];
|
||||
|
||||
// Lenis Smooth Scroll Integration
|
||||
useEffect(() => {
|
||||
let lenis: any;
|
||||
import("@studio-freight/lenis").then(({ default: Lenis }) => {
|
||||
lenis = new Lenis({ duration: 1.2, easing: (x: number) => Math.min(1, 1.001 - Math.pow(2, -10 * x)) });
|
||||
function raf(time: number) { lenis.raf(time); requestAnimationFrame(raf); }
|
||||
requestAnimationFrame(raf);
|
||||
});
|
||||
return () => lenis?.destroy();
|
||||
}, []);
|
||||
|
||||
// Preloader Curtain Timer
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setPreloader(false);
|
||||
}, 1500);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
// Localized statistics labels
|
||||
const getLocalizedStatLabel = (deger: string) => {
|
||||
if (deger === "4200") return lang === "tr" ? "Mutlu Hasta" : "Happy Patients";
|
||||
if (deger === "14") return lang === "tr" ? "Uzman Hekim" : "Expert Physicians";
|
||||
if (deger === "12") return lang === "tr" ? "Yıl Deneyim" : "Years of Experience";
|
||||
return lang === "tr" ? "Hasta Yorumu" : "Patient Reviews";
|
||||
};
|
||||
|
||||
// Maps services text based on data
|
||||
const getLocalizedServiceText = (baslik: string) => {
|
||||
if (baslik.includes("Dahiliye")) return { title: t.serviceDahiliye, desc: t.serviceDahiliyeDesc };
|
||||
if (baslik.includes("Kardiyoloji")) return { title: t.serviceKardiyoloji, desc: t.serviceKardiyolojiDesc };
|
||||
if (baslik.includes("Diş")) return { title: t.serviceDis, desc: t.serviceDisDesc };
|
||||
if (baslik.includes("Göz")) return { title: t.serviceGoz, desc: t.serviceGozDesc };
|
||||
if (baslik.includes("Laboratuvar")) return { title: t.serviceLab, desc: t.serviceLabDesc };
|
||||
return { title: t.serviceRad, desc: t.serviceRadDesc };
|
||||
};
|
||||
|
||||
// Maps service icons
|
||||
const getServiceIconSvg = (baslik: string) => {
|
||||
if (baslik.includes("Dahiliye")) {
|
||||
return (
|
||||
<svg className="w-6 h-6 stroke-[#0ea5e9] fill-none" viewBox="0 0 24 24" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
if (baslik.includes("Kardiyoloji")) {
|
||||
return (
|
||||
<svg className="w-6 h-6 stroke-[#0ea5e9] fill-none" viewBox="0 0 24 24" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
if (baslik.includes("Diş")) {
|
||||
return (
|
||||
<svg className="w-6 h-6 stroke-[#0ea5e9] fill-none" viewBox="0 0 24 24" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9s2.015-9 4.5-9" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
if (baslik.includes("Göz")) {
|
||||
return (
|
||||
<svg className="w-6 h-6 stroke-[#0ea5e9] fill-none" viewBox="0 0 24 24" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
if (baslik.includes("Laboratuvar")) {
|
||||
return (
|
||||
<svg className="w-6 h-6 stroke-[#0ea5e9] fill-none" viewBox="0 0 24 24" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<svg className="w-6 h-6 stroke-[#0ea5e9] fill-none" viewBox="0 0 24 24" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z" />
|
||||
<circle cx="12" cy="13" r="3" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
const getLocalizedDoctor = (ad: string) => {
|
||||
if (ad.includes("Ahmet")) {
|
||||
return {
|
||||
name: lang === "tr" ? "Dr. Ahmet Yılmaz" : "Dr. Ahmet Yilmaz",
|
||||
title: lang === "tr" ? "Dahiliye Uzmanı" : "Internal Medicine Specialist",
|
||||
};
|
||||
}
|
||||
if (ad.includes("Ayşe")) {
|
||||
return {
|
||||
name: lang === "tr" ? "Dr. Ayşe Kaya" : "Dr. Ayse Kaya",
|
||||
title: lang === "tr" ? "Kardiyolog" : "Cardiologist",
|
||||
};
|
||||
}
|
||||
if (ad.includes("Mehmet")) {
|
||||
return {
|
||||
name: lang === "tr" ? "Dr. Mehmet Demir" : "Dr. Mehmet Demir",
|
||||
title: lang === "tr" ? "Göz Sağlığı Uzmanı" : "Ophthalmology Specialist",
|
||||
};
|
||||
}
|
||||
return {
|
||||
name: lang === "tr" ? "Dr. Zeynep Arslan" : "Dr. Zeynep Arslan",
|
||||
title: lang === "tr" ? "Estetik Diş Hekimi" : "Aesthetic Dentist",
|
||||
};
|
||||
};
|
||||
|
||||
const css = `
|
||||
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@300;400;500;600;700;800;900&family=Sora:wght@300;400;500;600;700;800&display=swap');
|
||||
|
||||
:root {
|
||||
--color-klinik-sky: #0ea5e9;
|
||||
--color-klinik-sky-dark: #0284c7;
|
||||
--color-klinik-sky-light: #e0f2fe;
|
||||
--color-klinik-charcoal: #0F172A;
|
||||
--color-klinik-sand: #FAF8F5;
|
||||
}
|
||||
|
||||
.font-sora-editorial {
|
||||
font-family: 'Sora', sans-serif;
|
||||
}
|
||||
|
||||
.font-sans-clean {
|
||||
font-family: 'DM Sans', sans-serif;
|
||||
}
|
||||
|
||||
.shadow-premium {
|
||||
box-shadow: 0 20px 40px -15px rgba(15, 23, 42, 0.05);
|
||||
}
|
||||
|
||||
.hero-title-clamp {
|
||||
font-size: clamp(38px, 6vw, 85px);
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 0.95;
|
||||
}
|
||||
`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{css}</style>
|
||||
|
||||
{/* ── IMZA AN: CURTAIN REVEAL PRELOADER ── */}
|
||||
<AnimatePresence>
|
||||
{preloader && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 bg-[#0F172A] flex flex-col items-center justify-center p-6"
|
||||
exit={{
|
||||
clipPath: "polygon(0 0, 100% 0, 100% 0, 0 0)",
|
||||
transition: { duration: 0.85, ease: [0.16, 1, 0.3, 1] }
|
||||
}}
|
||||
>
|
||||
<div className="max-w-md text-center space-y-6">
|
||||
<motion.span
|
||||
className="text-[9px] font-sora-editorial tracking-[4px] uppercase text-[#0ea5e9] block"
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
DOĞAN TIP MERKEZİ
|
||||
</motion.span>
|
||||
<div className="h-[1px] w-48 bg-white/10 mx-auto relative overflow-hidden">
|
||||
<motion.div
|
||||
className="absolute inset-y-0 left-0 bg-[#0ea5e9]"
|
||||
initial={{ width: "0%" }}
|
||||
animate={{ width: "100%" }}
|
||||
transition={{ duration: 1.2, ease: "easeInOut" }}
|
||||
/>
|
||||
</div>
|
||||
<motion.h2
|
||||
className="font-sora-editorial text-white/50 text-xs tracking-wider uppercase"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.4, duration: 0.5 }}
|
||||
>
|
||||
interactive prototype
|
||||
</motion.h2>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
<div className="bg-[#FAF8F5] text-[#0F172A] min-h-screen font-sans-clean selection:bg-[#0ea5e9] selection:text-white overflow-hidden relative pb-20">
|
||||
|
||||
{/* Floating Ambient Orbs */}
|
||||
<div className="absolute top-[10%] left-[-15%] w-[600px] h-[600px] bg-[#0ea5e9]/3 blur-[120px] rounded-full pointer-events-none z-0" />
|
||||
<div className="absolute bottom-[20%] right-[-15%] w-[600px] h-[600px] bg-[#0284c7]/3 blur-[140px] rounded-full pointer-events-none z-0" />
|
||||
|
||||
{/* ── FLOATING CONCEPT BANNER ── */}
|
||||
<div className="fixed bottom-4 left-4 z-40 bg-[#0F172A]/90 backdrop-blur-md border border-white/10 px-4 py-2.5 rounded-xl shadow-2xl flex items-center gap-2.5 max-w-sm pointer-events-none select-none">
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-[#0ea5e9] animate-pulse" />
|
||||
<span className="text-[9px] font-sora-editorial uppercase tracking-[1.5px] text-white/90">
|
||||
{lang === "tr" ? "Bu web sitesi Ayris Tech tarafından hazırlanmış bir konsept çalışmasıdır." : "This website is a premium concept prototype designed by Ayris Tech."}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* ── PREMIUM NAVBAR ── */}
|
||||
<motion.header
|
||||
className="fixed top-4 left-4 right-4 z-50 px-4"
|
||||
initial={{ y: -80, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.85, ease: [0.16, 1, 0.3, 1] }}
|
||||
>
|
||||
<div className="mx-auto max-w-7xl h-20 flex items-center justify-between px-8 bg-white/80 backdrop-blur-xl border border-white/40 rounded-2xl shadow-[0_10px_30px_rgba(15,23,42,0.03)]">
|
||||
{/* Logo */}
|
||||
<a href="#" className="flex items-center gap-2.5 group">
|
||||
<span className="text-lg font-black tracking-tight text-[#0F172A] font-sora-editorial flex items-center gap-2.5 uppercase">
|
||||
<svg className="w-5 h-5 text-[#0ea5e9]" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z" />
|
||||
<path d="M12 6v12M6 12h12" />
|
||||
</svg>
|
||||
{firma.adi}
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{/* Links */}
|
||||
<nav className="hidden lg:flex items-center gap-8">
|
||||
{[
|
||||
{ label: t.navServices, href: "#hizmetler" },
|
||||
{ label: t.navDoctors, href: "#doktorlar" },
|
||||
{ label: t.navReviews, href: "#testimonials" },
|
||||
{ label: t.navContact, href: "#randevu" }
|
||||
].map(item => (
|
||||
<a
|
||||
key={item.label}
|
||||
href={item.href}
|
||||
className="text-[10px] font-black tracking-[2px] uppercase text-[#0F172A]/70 hover:text-[#0ea5e9] transition-colors relative py-1 cursor-pointer group"
|
||||
>
|
||||
{item.label}
|
||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-[#0ea5e9] transition-all group-hover:w-full" />
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
{/* Language Selector + Booking Button */}
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Language Switcher */}
|
||||
<div className="flex items-center gap-1 bg-[#0F172A]/5 border border-[#0F172A]/10 rounded-xl p-1 shrink-0">
|
||||
<button
|
||||
onClick={() => setLang("tr")}
|
||||
className={`text-[9px] font-sora-editorial px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "tr" ? "bg-white text-slate-900 shadow-sm" : "text-[#0F172A]/60 hover:text-[#0F172A]"
|
||||
}`}
|
||||
>
|
||||
TR
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setLang("en")}
|
||||
className={`text-[9px] font-sora-editorial px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "en" ? "bg-white text-slate-900 shadow-sm" : "text-[#0F172A]/60 hover:text-[#0F172A]"
|
||||
}`}
|
||||
>
|
||||
EN
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<motion.button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="text-[10px] font-black tracking-[2.5px] uppercase text-white bg-[#0ea5e9] hover:bg-[#0284c7] px-6 py-3.5 rounded-xl transition-all cursor-pointer shadow-[0_4px_12px_rgba(14,165,233,0.15)] hidden sm:block"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{t.navBooking}
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.header>
|
||||
|
||||
{/* ── HERO & INTERACTIVE APPOINTMENT TRACKER ── */}
|
||||
<section className="relative min-h-screen pt-32 pb-20 flex items-center z-10 px-6">
|
||||
<div className="max-w-7xl mx-auto w-full">
|
||||
<div className="grid lg:grid-cols-12 gap-16 items-center">
|
||||
|
||||
{/* Left Column: Heading and clinic stats */}
|
||||
<motion.div
|
||||
className="lg:col-span-6 z-20"
|
||||
variants={stagger}
|
||||
initial="hidden"
|
||||
animate="show"
|
||||
>
|
||||
<motion.div
|
||||
variants={fadeUp}
|
||||
className="inline-flex items-center gap-2 text-[10px] font-black uppercase tracking-widest text-[#0ea5e9] mb-6 bg-[#0ea5e9]/5 border border-[#0ea5e9]/10 px-4 py-2 rounded-full"
|
||||
>
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-[#0ea5e9] animate-pulse" />
|
||||
{t.badge}
|
||||
</motion.div>
|
||||
|
||||
<motion.h1
|
||||
variants={fadeUp}
|
||||
className="font-sora-editorial font-black text-[#0F172A] leading-[1.1] mb-8 hero-title-clamp uppercase"
|
||||
>
|
||||
{t.heroTitlePart1}
|
||||
<br />
|
||||
<span className="italic font-light text-[#0ea5e9] lowercase">{t.heroTitlePart2}</span>
|
||||
<br />
|
||||
{t.heroTitlePart3}
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
variants={fadeUp}
|
||||
className="text-[#0F172A]/60 text-xs lg:text-sm leading-relaxed max-w-md mb-12 font-semibold"
|
||||
>
|
||||
{t.heroDesc}
|
||||
</motion.p>
|
||||
|
||||
{/* Statistics Grid */}
|
||||
<motion.div
|
||||
variants={fadeUp}
|
||||
className="grid grid-cols-2 sm:grid-cols-4 gap-6 mb-12 font-semibold"
|
||||
>
|
||||
{istatistikler.map((stat, idx) => (
|
||||
<div key={idx} className="border-l border-[#0ea5e9]/30 pl-4 py-1">
|
||||
<h4 className="font-sora-editorial font-black text-[#0F172A] text-lg uppercase tracking-wider mb-1 leading-none">
|
||||
{stat.deger === "4200" || stat.deger === "620" ? `${stat.deger}+` : stat.deger}
|
||||
</h4>
|
||||
<p className="text-[#0F172A]/50 text-[10px] leading-snug">
|
||||
{getLocalizedStatLabel(stat.deger)}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</motion.div>
|
||||
|
||||
{/* CTA buttons */}
|
||||
<motion.div variants={fadeUp} className="flex gap-4">
|
||||
<a
|
||||
href="#randevu"
|
||||
className="inline-flex items-center gap-3 px-8 py-4.5 rounded-xl bg-[#0ea5e9] hover:bg-[#0284c7] text-white font-black text-[10px] tracking-[2px] uppercase transition-all shadow-[0_5px_15px_rgba(14,165,233,0.2)] cursor-pointer"
|
||||
>
|
||||
📅 {t.navBooking}
|
||||
</a>
|
||||
<a
|
||||
href="#hizmetler"
|
||||
className="inline-flex items-center gap-3 px-8 py-4.5 rounded-xl border border-[#0F172A]/10 bg-white/40 hover:bg-white/80 text-[#0F172A] font-black text-[10px] tracking-[2px] uppercase transition-all cursor-pointer"
|
||||
>
|
||||
{t.navServices}
|
||||
</a>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Column: Layered Live Tracker Mockup */}
|
||||
<div className="lg:col-span-6 relative flex justify-center lg:justify-end">
|
||||
<motion.div
|
||||
className="relative w-full max-w-md bg-white rounded-3xl p-8 border border-white shadow-premium z-10"
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
>
|
||||
<div className="flex items-center justify-between mb-6 pb-4 border-b border-gray-100">
|
||||
<div>
|
||||
<h4 className="font-sora-editorial font-black text-[#0F172A] text-sm uppercase leading-tight">{t.appointmentsToday}</h4>
|
||||
<span className="text-[10px] text-[#0F172A]/40 uppercase tracking-widest font-black mt-1.5 block">{t.saturday}</span>
|
||||
</div>
|
||||
<div className="w-10 h-10 rounded-xl bg-[#0ea5e9]/10 flex items-center justify-center shrink-0">
|
||||
<svg className="w-5 h-5 text-[#0ea5e9]" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3 font-semibold">
|
||||
{t.appointmentList.map((r, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="flex items-center justify-between p-3.5 rounded-2xl bg-gray-50 border border-gray-100/50 hover:bg-[#0ea5e9]/5 transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className={`w-2 h-2 rounded-full ${r.dolu ? "bg-red-500 animate-pulse" : "bg-emerald-500"}`} />
|
||||
<div>
|
||||
<h5 className="text-[12px] font-black text-[#0F172A]">{r.saat}</h5>
|
||||
<span className="text-[10px] text-[#0F172A]/50 mt-0.5 block">{r.tip}</span>
|
||||
</div>
|
||||
</div>
|
||||
<span className={`text-[9px] font-black uppercase tracking-wider px-2.5 py-1 rounded-full ${r.dolu ? "bg-red-500/10 text-red-500" : "bg-emerald-500/10 text-emerald-500"}`}>
|
||||
{r.dolu ? t.statusDolu : t.statusMusait}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Rating Badge Overlay */}
|
||||
<motion.div
|
||||
className="absolute -top-6 -right-6 bg-white border border-gray-100 rounded-2xl px-5 py-3.5 shadow-2xl flex items-center gap-3 select-none"
|
||||
animate={{ y: [0, -6, 0] }}
|
||||
transition={{ duration: 4, repeat: Infinity, ease: "easeInOut" }}
|
||||
>
|
||||
<span className="text-xl">⭐</span>
|
||||
<div>
|
||||
<h5 className="font-sora-editorial font-black text-slate-800 text-[13px] uppercase leading-none">{t.ratingText.split("•")[0]}</h5>
|
||||
<span className="text-[9px] text-[#0F172A]/40 uppercase tracking-widest font-black mt-1 block">{t.ratingText.split("•")[1]}</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* SMS Reminder Overlay */}
|
||||
<motion.div
|
||||
className="absolute -bottom-6 -left-6 bg-white border border-gray-100 rounded-2xl px-5 py-3.5 shadow-2xl flex items-center gap-3 select-none"
|
||||
animate={{ y: [0, 6, 0] }}
|
||||
transition={{ duration: 4.5, repeat: Infinity, ease: "easeInOut", delay: 0.5 }}
|
||||
>
|
||||
<span className="text-xl">🔔</span>
|
||||
<div>
|
||||
<h5 className="font-sora-editorial font-black text-slate-800 text-[13px] uppercase leading-none">{t.smsReminder}</h5>
|
||||
<span className="text-[9px] text-[#0F172A]/40 uppercase tracking-widest font-black mt-1 block">{t.smsDesc}</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── HİZMETLER ── */}
|
||||
<section id="hizmetler" className="py-32 bg-white px-6 border-t border-[#0f172a]/5">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<motion.div
|
||||
className="mb-20"
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true }}
|
||||
variants={stagger}
|
||||
>
|
||||
<motion.span
|
||||
variants={fadeUp}
|
||||
className="inline-block text-[10px] font-black uppercase tracking-widest px-4 py-2 rounded-full mb-4 bg-[#0ea5e9]/5 text-[#0ea5e9] border border-[#0ea5e9]/10"
|
||||
>
|
||||
{t.servicesTitle}
|
||||
</motion.span>
|
||||
<motion.h2 variants={fadeUp} className="text-4xl lg:text-5xl font-sora-premium font-black text-gray-900 leading-tight uppercase">
|
||||
{t.servicesHeader}
|
||||
</motion.h2>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="grid sm:grid-cols-2 lg:grid-cols-3 gap-6"
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true }}
|
||||
variants={stagger}
|
||||
>
|
||||
{hizmetler.map((h, i) => {
|
||||
const item = getLocalizedServiceText(h.baslik);
|
||||
return (
|
||||
<motion.div
|
||||
key={i}
|
||||
variants={fadeUp}
|
||||
className="group p-8 rounded-3xl border border-gray-100 hover:border-transparent transition-all duration-300 cursor-default bg-white flex flex-col justify-between h-80"
|
||||
whileHover={{ y: -6, boxShadow: `0 24px 60px rgba(14,165,233,0.1)` }}
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="w-14 h-14 rounded-2xl flex items-center justify-center mb-6 transition-transform group-hover:scale-105 shadow-sm border border-gray-100 bg-gray-50"
|
||||
>
|
||||
{getServiceIconSvg(h.baslik)}
|
||||
</div>
|
||||
<h3 className="font-sora-premium font-bold text-base text-gray-900 mb-2 leading-snug uppercase tracking-wide">{item.title}</h3>
|
||||
<p className="text-gray-500 text-xs leading-relaxed font-semibold">{item.desc}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="text-[#0ea5e9] font-black text-[9px] tracking-[2.5px] uppercase flex items-center gap-1 cursor-pointer hover:text-opacity-80 transition-colors pt-4 border-t border-gray-100 shrink-0"
|
||||
>
|
||||
{t.learnMore}
|
||||
</button>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── DOKTORLAR ── */}
|
||||
<section id="doktorlar" className="py-32 px-6 bg-[#f8fafc] border-t border-gray-100">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<motion.div
|
||||
className="mb-20"
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true }}
|
||||
variants={stagger}
|
||||
>
|
||||
<motion.span
|
||||
variants={fadeUp}
|
||||
className="inline-block text-[10px] font-black uppercase tracking-widest px-4 py-2 rounded-full mb-4 bg-[#0ea5e9]/5 text-[#0ea5e9] border border-[#0ea5e9]/10"
|
||||
>
|
||||
{t.doctorsTitle}
|
||||
</motion.span>
|
||||
<motion.h2 variants={fadeUp} className="text-4xl lg:text-5xl font-sora-premium font-black text-gray-900 uppercase">
|
||||
{t.doctorsHeader}
|
||||
</motion.h2>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="grid sm:grid-cols-2 lg:grid-cols-4 gap-6 font-semibold"
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true }}
|
||||
variants={stagger}
|
||||
>
|
||||
{doktorlar.map((d, i) => {
|
||||
const doc = getLocalizedDoctor(d.ad);
|
||||
return (
|
||||
<motion.div
|
||||
key={i}
|
||||
variants={fadeUp}
|
||||
className="bg-white rounded-3xl overflow-hidden border border-gray-100/60 shadow-premium flex flex-col justify-between"
|
||||
whileHover={{ y: -8 }}
|
||||
>
|
||||
<div
|
||||
className="h-48 flex items-center justify-center text-7xl relative overflow-hidden select-none"
|
||||
style={{ background: `linear-gradient(135deg, ${firma.renkAcik}, rgba(14,165,233,0.15))` }}
|
||||
>
|
||||
<motion.span whileHover={{ scale: 1.15 }} transition={{ type: "spring", stiffness: 300 }}>
|
||||
{d.emoji}
|
||||
</motion.span>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<h3 className="font-sora-premium font-black text-gray-900 text-sm uppercase leading-tight">{doc.name}</h3>
|
||||
<p className="text-[11px] font-bold mt-1.5 mb-4 text-[#0ea5e9] uppercase tracking-wide">{doc.title}</p>
|
||||
<div className="flex items-center justify-between text-[9px] text-gray-500 border-t border-gray-100 pt-3 font-black uppercase tracking-widest">
|
||||
<span>⭐ {d.puan}</span>
|
||||
<span>🏥 {d.yil} {lang === "tr" ? "YIL" : "YRS"}</span>
|
||||
<span>👥 {d.hasta}+ {lang === "tr" ? "HASTA" : "PATS"}</span>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── ONLINE APPOINTMENT FORM ── */}
|
||||
<section id="randevu" className="py-32 px-6 relative overflow-hidden"
|
||||
style={{ background: `linear-gradient(135deg, ${firma.renkKoyu} 0%, ${firma.renkAna} 100%)` }}>
|
||||
|
||||
{/* Subtle cosmic grid layout */}
|
||||
<div className="absolute inset-0 opacity-[0.03] pointer-events-none"
|
||||
style={{ backgroundImage: "linear-gradient(#fff 1px,transparent 1px),linear-gradient(90deg,#fff 1px,transparent 1px)", backgroundSize: "40px 40px" }} />
|
||||
|
||||
<div className="max-w-7xl mx-auto relative z-10">
|
||||
<div className="grid lg:grid-cols-2 gap-16 items-start">
|
||||
|
||||
{/* Left Column: Contact details */}
|
||||
<motion.div initial="hidden" whileInView="show" viewport={{ once: true }} variants={stagger}>
|
||||
<motion.span
|
||||
variants={fadeUp}
|
||||
className="inline-block text-[9px] font-black uppercase tracking-widest px-4 py-2 rounded-full mb-4 bg-white/20 text-white border border-white/10"
|
||||
>
|
||||
{t.bookingTitle}
|
||||
</motion.span>
|
||||
<motion.h2 variants={fadeUp} className="text-4xl lg:text-5xl font-sora-premium font-black text-white leading-tight mb-6 uppercase">
|
||||
{t.bookingHeader}
|
||||
</motion.h2>
|
||||
<motion.p variants={fadeUp} className="text-white/70 text-xs lg:text-sm mb-10 font-semibold leading-relaxed">
|
||||
{t.bookingDesc}
|
||||
</motion.p>
|
||||
|
||||
<motion.div variants={fadeUp} className="space-y-4 font-semibold">
|
||||
{[
|
||||
{ ikon: "📞", baslik: t.callCenter, aciklama: firma.telefon },
|
||||
{ ikon: "📍", baslik: t.addressLabel, aciklama: firma.adres },
|
||||
{ ikon: "✉️", baslik: t.emailLabel, aciklama: firma.email },
|
||||
].map((item) => (
|
||||
<div key={item.baslik} className="flex items-start gap-4 bg-white/10 rounded-2xl p-4 border border-white/5">
|
||||
<span className="text-xl mt-0.5 shrink-0 select-none">{item.ikon}</span>
|
||||
<div>
|
||||
<p className="text-white/60 text-[9px] font-black uppercase tracking-wider">{item.baslik}</p>
|
||||
<p className="text-white text-xs mt-1 leading-snug">{item.aciklama}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Column: Appointment Form */}
|
||||
<motion.div
|
||||
className="bg-white rounded-3xl p-8 shadow-2xl border border-white/10"
|
||||
initial={{ opacity: 0, y: 40 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.7, delay: 0.2 }}
|
||||
>
|
||||
<h3 className="font-sora-premium font-black text-gray-900 text-lg mb-6 uppercase tracking-wide">{t.bookingTitle}</h3>
|
||||
<div className="grid grid-cols-2 gap-4 font-semibold">
|
||||
{[
|
||||
{ label: t.fieldsName, placeholder: lang === "tr" ? "Adınız Soyadınız" : "Your Full Name", type: "text", full: false },
|
||||
{ label: t.fieldsPhone, placeholder: "05xx xxx xx xx", type: "tel", full: false },
|
||||
{ label: t.fieldsEmail, placeholder: "ornek@mail.com", type: "email", full: false },
|
||||
{ label: t.fieldsDepartment, placeholder: "", type: "select", full: false },
|
||||
{ label: t.fieldsDate, placeholder: "", type: "date", full: false },
|
||||
{ label: t.fieldsNotes, placeholder: t.fieldsNotesPlaceholder, type: "text", full: true },
|
||||
].map((field, i) => (
|
||||
<div key={i} className={field.full ? "col-span-2" : "col-span-2 sm:col-span-1"}>
|
||||
<label className="block text-[10px] font-black text-gray-700 mb-1.5 uppercase tracking-wider">{field.label}</label>
|
||||
{field.type === "select" ? (
|
||||
<select className="w-full px-4 py-3.5 rounded-xl border border-gray-200 text-xs text-slate-800 focus:outline-none focus:ring-2 focus:ring-[#0ea5e9] bg-gray-50/50 transition-all font-semibold cursor-pointer">
|
||||
<option>{t.serviceDahiliye}</option>
|
||||
<option>{t.serviceKardiyoloji}</option>
|
||||
<option>{t.serviceDis}</option>
|
||||
<option>{t.serviceGoz}</option>
|
||||
<option>{t.serviceLab}</option>
|
||||
</select>
|
||||
) : (
|
||||
<input type={field.type} placeholder={field.placeholder}
|
||||
className="w-full px-4 py-3.5 rounded-xl border border-gray-200 text-xs focus:outline-none focus:ring-2 focus:ring-[#0ea5e9] bg-gray-50/50 transition-all placeholder-slate-300 font-semibold" />
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<motion.button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="mt-6 w-full py-4.5 rounded-xl text-white font-black text-xs uppercase tracking-widest cursor-pointer shadow-[0_5px_15px_rgba(14,165,233,0.2)]"
|
||||
style={{ background: `linear-gradient(135deg, ${firma.renkAna}, ${firma.renkKoyu})` }}
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
📅 {t.dispatchForm}
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── TESTIMONIALS ── */}
|
||||
<section id="testimonials" className="py-32 px-6 bg-gray-950 border-t border-white/5 relative z-10">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<motion.div
|
||||
className="mb-20 text-center"
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true }}
|
||||
variants={stagger}
|
||||
>
|
||||
<motion.span
|
||||
variants={fadeUp}
|
||||
className="inline-block text-[10px] font-black uppercase tracking-widest px-4 py-2 rounded-full mb-4 bg-white/5 text-[#0ea5e9] border border-white/10"
|
||||
>
|
||||
{t.navReviews}
|
||||
</motion.span>
|
||||
<h2 className="text-3xl lg:text-4xl font-sora-premium font-black text-white uppercase tracking-tight">
|
||||
{t.bookingTitle}
|
||||
</h2>
|
||||
</motion.div>
|
||||
|
||||
<div className="relative">
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.div
|
||||
key={activeYorum}
|
||||
className="bg-white/5 backdrop-blur-xl border border-white/10 rounded-3xl p-10 max-w-2xl mx-auto shadow-2xl"
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.95 }}
|
||||
transition={{ duration: 0.4 }}
|
||||
>
|
||||
<div className="flex gap-1.5 mb-6 justify-center">
|
||||
{[...Array(yorumlar[activeYorum]?.puan || 5)].map((_, i) => (
|
||||
<svg key={i} className="w-4 h-4 fill-[#0ea5e9]" viewBox="0 0 24 24">
|
||||
<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
|
||||
</svg>
|
||||
))}
|
||||
</div>
|
||||
<p className="text-white/80 text-base leading-relaxed italic text-center mb-8 font-semibold">
|
||||
“{yorumlar[activeYorum]?.yorum}”
|
||||
</p>
|
||||
<div className="flex items-center gap-3.5 justify-center font-semibold">
|
||||
<div className="w-10 h-10 rounded-full flex items-center justify-center text-sm bg-white/10 border border-white/10 font-bold select-none text-white">
|
||||
{yorumlar[activeYorum]?.yazar.charAt(0)}
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-white font-bold text-xs uppercase tracking-wide leading-tight">{yorumlar[activeYorum]?.yazar}</p>
|
||||
<p className="text-gray-500 text-[9px] uppercase tracking-wider font-black font-sora-premium mt-0.5">{yorumlar[activeYorum]?.tarih}</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
|
||||
<div className="flex justify-center gap-2.5 mt-8">
|
||||
{yorumlar.map((_, i) => (
|
||||
<button key={i} onClick={() => setActiveYorum(i)}
|
||||
className="w-2.5 h-2.5 rounded-full transition-all cursor-pointer"
|
||||
style={{ background: i === activeYorum ? "#0ea5e9" : "rgba(255,255,255,0.15)",
|
||||
transform: i === activeYorum ? "scale(1.3)" : "scale(1)" }} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── FOOTER ── */}
|
||||
<footer className="bg-gray-950 border-t border-white/5 px-6 pt-24 pb-8 relative z-10">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="grid md:grid-cols-4 gap-12 pb-16 border-b border-white/5">
|
||||
<div className="md:col-span-2">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<svg className="w-5 h-5 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z" />
|
||||
<path d="M12 6v12M6 12h12" />
|
||||
</svg>
|
||||
<span className="font-bold text-white text-lg font-sora-premium uppercase tracking-wide">{firma.adi}</span>
|
||||
</div>
|
||||
<p className="text-white/40 text-xs leading-relaxed max-w-sm mb-8 font-semibold">{t.footerDesc}</p>
|
||||
<div className="text-white/50 text-xs font-semibold space-y-3">
|
||||
<p className="flex items-center gap-2">📍 <span className="text-white/80">{firma.adres}</span></p>
|
||||
<p className="flex items-center gap-2">📞 <span className="text-white/80">{firma.telefon}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-sora-premium text-white font-bold text-xs uppercase tracking-wider mb-6">{t.navServices}</h4>
|
||||
{hizmetler.slice(0, 4).map((h, i) => {
|
||||
const s = getLocalizedServiceText(h.baslik);
|
||||
return (
|
||||
<a key={i} href="#hizmetler" className="block text-white/40 text-xs mb-3 hover:text-white transition-colors font-semibold">{s.title}</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-sora-premium text-white font-bold text-xs uppercase tracking-wider mb-6">Klinik</h4>
|
||||
{[t.navServices, t.navDoctors, t.navReviews, t.navContact].map((item) => (
|
||||
<a key={item} href="#" className="block text-white/40 text-xs mb-3 hover:text-white transition-colors font-semibold">{item}</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col md:flex-row justify-between items-center pt-8 gap-4 text-white/30 text-xs font-semibold">
|
||||
<p>© 2026 {firma.adi}. All rights reserved.</p>
|
||||
<div className="flex gap-4">
|
||||
<a href="#" className="hover:text-white transition-colors">{t.privacyRegs}</a>
|
||||
<span>·</span>
|
||||
<a href="#" className="hover:text-white transition-colors">{t.termsStay}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{/* ── BOOKING MODAL ── */}
|
||||
<AnimatePresence>
|
||||
{showBookingModal && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 flex items-center justify-center p-6 bg-black/60 backdrop-blur-sm"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
<motion.div
|
||||
className="bg-white rounded-3xl p-8 max-w-md w-full relative shadow-2xl border border-gray-100"
|
||||
initial={{ scale: 0.95, y: 20 }}
|
||||
animate={{ scale: 1, y: 0 }}
|
||||
exit={{ scale: 0.95, y: 20 }}
|
||||
>
|
||||
<button
|
||||
className="absolute top-6 right-6 w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center font-bold text-gray-500 hover:bg-gray-200 transition-colors cursor-pointer"
|
||||
onClick={() => setShowBookingModal(false)}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
<h3 className="font-sora-premium font-black text-[#0F172A] text-2xl mb-1 uppercase tracking-wide">{t.contactTitle}</h3>
|
||||
<p className="text-gray-400 text-xs mb-6 font-semibold">{t.contactDesc}</p>
|
||||
|
||||
<div className="space-y-4 font-semibold">
|
||||
<div>
|
||||
<label className="block text-[10px] font-black text-gray-500 mb-1.5 uppercase tracking-wider">{t.fieldsName}</label>
|
||||
<input type="text" className="w-full px-4 py-3.5 rounded-xl border bg-gray-50/50 text-xs focus:outline-none focus:ring-2 focus:ring-[#0ea5e9]" placeholder="John Doe" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-[10px] font-black text-gray-500 mb-1.5 uppercase tracking-wider">{t.fieldsPhone}</label>
|
||||
<input type="tel" className="w-full px-4 py-3.5 rounded-xl border bg-gray-50/50 text-xs focus:outline-none focus:ring-2 focus:ring-[#0ea5e9]" placeholder="05xx xxx xx xx" />
|
||||
</div>
|
||||
<motion.button
|
||||
className="w-full py-4 rounded-xl bg-[#0ea5e9] text-white font-black text-xs hover:bg-[#0284c7] transition-colors mt-2 cursor-pointer shadow-[0_4px_12px_rgba(14,165,233,0.15)] uppercase tracking-widest"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
onClick={() => setShowBookingModal(false)}
|
||||
>
|
||||
{t.submit}
|
||||
</motion.button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,964 @@
|
||||
"use client";
|
||||
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { useState, useEffect } from "react";
|
||||
import type { DemoData } from "@/data/demos";
|
||||
|
||||
const fadeUp = {
|
||||
hidden: { opacity: 0, y: 35 },
|
||||
show: { opacity: 1, y: 0, transition: { duration: 0.75, ease: [0.25, 0.46, 0.45, 0.94] as [number, number, number, number] } },
|
||||
};
|
||||
|
||||
const stagger = {
|
||||
hidden: {},
|
||||
show: { transition: { staggerChildren: 0.08 } },
|
||||
};
|
||||
|
||||
const translations = {
|
||||
tr: {
|
||||
navServices: "Hizmetlerimiz",
|
||||
navProjects: "Referanslarımız",
|
||||
navTeam: "Ekibimiz",
|
||||
navReviews: "Görüşler",
|
||||
navBooking: "Teklif Al",
|
||||
badge: "PREMIUM LOJİSTİK OPERATÖRÜ",
|
||||
heroTitlePart1: "Lojistikte",
|
||||
heroTitlePart2: "Fark Yaratan",
|
||||
heroTitlePart3: "Çözümler",
|
||||
heroDesc: "Güvenli taşımacılık ve zamanında teslimat çözümleri. Teknoloji destekli operasyon yönetimi ve küresel tedarik zinciri entegrasyonu ile işinizi büyütüyoruz. Atlas Lojistik premium ağı.",
|
||||
getQuote: "Teklif Al",
|
||||
learnMore: "Referanslar",
|
||||
projectsTitle: "Referanslarımız",
|
||||
projectsHeader: "BİRLİKTE BÜYÜDÜĞÜMÜZ KÜRESEL MARKALAR",
|
||||
teamTitle: "Ekibimiz",
|
||||
teamHeader: "YÖNETİM VE OPERASYON KADROMUZ",
|
||||
reviewsTitle: "Müşteri Görüşleri",
|
||||
reviewsHeader: "GÜVENİLİR İŞ ORTAKLARIMIZ",
|
||||
bookingTitle: "Teklif Talebi",
|
||||
bookingHeader: "BİRLİKTE ÇALIŞALIM",
|
||||
bookingDesc: "Tedarik zincirinizi veya lojistik operasyonunuzu optimize etmek için bilgilerinizi bırakın, uzmanlarımız özel çalışma planıyla geri dönsün.",
|
||||
fieldsName: "Ad Soyad",
|
||||
fieldsPhone: "Telefon Numarası",
|
||||
fieldsEmail: "E-Posta Adresi",
|
||||
fieldsCategory: "Hizmet Kategorisi",
|
||||
fieldsDate: "Planlanan Tarih",
|
||||
fieldsNotes: "Operasyon Notları / Detaylar",
|
||||
fieldsNotesPlaceholder: "Yıllık sevkiyat hacmi, depo alanı veya özel taşıma ihtiyaçları...",
|
||||
dispatchForm: "TEKLİF TALEBİ GÖNDER",
|
||||
contactChannels: "İLETİŞİM KANALLARI",
|
||||
callCenter: "Destek Hattı",
|
||||
addressLabel: "Lojistik Merkezi",
|
||||
emailLabel: "Kurumsal E-Posta",
|
||||
footerDesc: "Tedarik zinciri yönetiminde JIT (Just-In-Time) modelleri, GDP sertifikalı soğuk zincir lojistiği ve 7/24 anlık takip güvencesi.",
|
||||
privacyRegs: "Gizlilik Sözleşmesi",
|
||||
termsStay: "Kullanım Şartları",
|
||||
dismiss: "KAPAT",
|
||||
contactTitle: "Hızlı Teklif Danışmanlığı",
|
||||
contactDesc: "Lojistik gereksinimlerinizi bırakın, operasyon yöneticimiz 15 dakika içinde arasın.",
|
||||
submit: "Gönder",
|
||||
statExp: "Yıl Deneyim",
|
||||
statClients: "Aktif Müşteri",
|
||||
statCities: "Şehir Ağı",
|
||||
statDelivery: "Zamanında Teslimat",
|
||||
|
||||
// Services Localized
|
||||
serviceKarayolu: "Karayolu Taşımacılığı",
|
||||
serviceKarayoluDesc: "Yurtiçi ve uluslararası karayolu ile güvenli ve hızlı komple/parsiyel taşımacılık.",
|
||||
serviceDepolama: "Depolama & Lojistik",
|
||||
serviceDepolamaDesc: "Modern antrepolarımızda güvenli stok yönetimi, etiketleme ve dağıtım.",
|
||||
serviceEticaret: "E-ticaret Lojistiği",
|
||||
serviceEticaretDesc: "Son mile teslimat, iade yönetimi ve tam entegre fulfillment çözümleri.",
|
||||
serviceUlusal: "Uluslararası Nakliye",
|
||||
serviceUlusalDesc: "Gümrükleme, evrak takibi dahil kapıdan kapıya uluslararası taşımacılık.",
|
||||
serviceSoguk: "Soğuk Zincir Lojistiği",
|
||||
serviceSogukDesc: "Gıda ve ilaç sektörü için kontrollü sıcaklıkta GDP sertifikalı taşıma.",
|
||||
serviceTakip: "7/24 Anlık Takip",
|
||||
serviceTakipDesc: "Yüklerinizi ve sevkiyat rotalarınızı uydu üzerinden anlık takip edin.",
|
||||
|
||||
// Projects Localized
|
||||
projMigros: "Migros Dağıtım Ağı",
|
||||
projMigrosDesc: "12 şehirde günlük 400+ perakende noktasına kesintisiz soğuk zincir dağıtım yönetimi.",
|
||||
projTrendyol: "Trendyol Fulfillment",
|
||||
projTrendyolDesc: "Günlük 8.000+ e-ticaret sipariş işleme, paketleme ve son mile hızlı teslimat.",
|
||||
projFord: "Ford Otosan Tedarik",
|
||||
projFordDesc: "JIT (Just-In-Time) metodolojisiyle otomotiv üretim fabrikasına parça tedarik zinciri lojistiği.",
|
||||
projPfizer: "Pfizer İlaç Dağıtımı",
|
||||
projPfizerDesc: "GDP standartlarında, tam ısı kontrollü soğuk zincir ile ilaç ve aşı lojistiği.",
|
||||
},
|
||||
en: {
|
||||
navServices: "Our Services",
|
||||
navProjects: "References",
|
||||
navTeam: "Our Team",
|
||||
navReviews: "Testimonials",
|
||||
navBooking: "Get Quote",
|
||||
badge: "PREMIUM LOGISTICS OPERATOR",
|
||||
heroTitlePart1: "Logistics",
|
||||
heroTitlePart2: "Redefined With",
|
||||
heroTitlePart3: "Precision",
|
||||
heroDesc: "Secured transportation and JIT delivery frameworks. We optimize your supply chain with modern tech tracking, integrated warehousing, and global networks. Premium Atlas logistics hub.",
|
||||
getQuote: "Get Quote",
|
||||
learnMore: "References",
|
||||
projectsTitle: "Our Works",
|
||||
projectsHeader: "GLOBAL PARTNERS WE ARE PROUD TO GROW WITH",
|
||||
teamTitle: "Our Team",
|
||||
teamHeader: "OUR EXECUTIVE AND OPERATIONS DIRECTORS",
|
||||
reviewsTitle: "Client Reviews",
|
||||
reviewsHeader: "TRUSTED BY SECTOR LEADERS",
|
||||
bookingTitle: "Quote Request",
|
||||
bookingHeader: "WORK WITH US",
|
||||
bookingDesc: "To optimize your supply chain or schedule specialized cargo coordination, leave your credentials and our managers will draft a customized execution plan.",
|
||||
fieldsName: "Full Name",
|
||||
fieldsPhone: "Phone Number",
|
||||
fieldsEmail: "Email Address",
|
||||
fieldsCategory: "Service Category",
|
||||
fieldsDate: "Target Date",
|
||||
fieldsNotes: "Operations Details",
|
||||
fieldsNotesPlaceholder: "Annual volume, cold storage requests, or specific cargo dimensions...",
|
||||
dispatchForm: "SEND QUOTE REQUEST",
|
||||
contactChannels: "CONTACT CHANNELS",
|
||||
callCenter: "Support Helpline",
|
||||
addressLabel: "Logistics Hub",
|
||||
emailLabel: "Corporate Email",
|
||||
footerDesc: "Just-In-Time (JIT) manufacturing workflows, GDP certified cold chain facilities, and 7/24 satellite tracking systems.",
|
||||
privacyRegs: "Privacy Policy",
|
||||
termsStay: "Terms of Service",
|
||||
dismiss: "DISMISS",
|
||||
contactTitle: "Quick Consultation",
|
||||
contactDesc: "Outline your logistics coordinates and our transport managers will reach back in 15 minutes.",
|
||||
submit: "Submit",
|
||||
statExp: "Years Experience",
|
||||
statClients: "Active Clients",
|
||||
statCities: "City Hubs",
|
||||
statDelivery: "On-Time Delivery",
|
||||
|
||||
// Services Localized
|
||||
serviceKarayolu: "Road Transportation",
|
||||
serviceKarayoluDesc: "Secured and rapid domestic/international full or partial truckload transport.",
|
||||
serviceDepolama: "Warehousing & Logistics",
|
||||
serviceDepolamaDesc: "Bespoke inventory management, labeling, and retail cross-docking.",
|
||||
serviceEticaret: "E-Commerce Fulfillment",
|
||||
serviceEticaretDesc: "Last-mile courier integration, automated return flows, and fulfillment.",
|
||||
serviceUlusal: "Global Air/Ocean Cargo",
|
||||
serviceUlusalDesc: "Door-to-door global shipping routes with integrated custom clearance clearance.",
|
||||
serviceSoguk: "Cold Chain Transport",
|
||||
serviceSogukDesc: "GDP certified multi-temp fleet specifically for food and pharmaceutical sectors.",
|
||||
serviceTakip: "7/24 Satellite Tracking",
|
||||
serviceTakipDesc: "Real-time satellite path tracking and automated delay coordination.",
|
||||
|
||||
// Projects Localized
|
||||
projMigros: "Migros Retail Supply",
|
||||
projMigrosDesc: "Daily cold chain distribution routing to over 400+ points across 12 cities.",
|
||||
projTrendyol: "Trendyol Fulfillment Hub",
|
||||
projTrendyolDesc: "Handling 8,000+ daily e-commerce order dispatches with priority last-mile courier lanes.",
|
||||
projFord: "Ford Otosan JIT Tedarik",
|
||||
projFordDesc: "JIT manufacturing line support, synchronizing auto parts arrival exactly within scheduled shifts.",
|
||||
projPfizer: "Pfizer Cold Chain Pharma",
|
||||
projPfizerDesc: "GDP certified pharmaceutical transport using automated multi-temperature thermal cargo.",
|
||||
}
|
||||
};
|
||||
|
||||
export default function KurumsalTemplate({ data }: { data: DemoData }) {
|
||||
const { firma, istatistikler = [], hizmetler = [], yorumlar = [], projeler = [], ekip = [] } = data;
|
||||
const [showBookingModal, setShowBookingModal] = useState(false);
|
||||
const [lang, setLang] = useState<"tr" | "en">("tr");
|
||||
const [preloader, setPreloader] = useState(true);
|
||||
|
||||
const t = translations[lang];
|
||||
|
||||
// Lenis Smooth Scroll Integration
|
||||
useEffect(() => {
|
||||
let lenis: any;
|
||||
import("@studio-freight/lenis").then(({ default: Lenis }) => {
|
||||
lenis = new Lenis({ duration: 1.2, easing: (x: number) => Math.min(1, 1.001 - Math.pow(2, -10 * x)) });
|
||||
function raf(time: number) { lenis.raf(time); requestAnimationFrame(raf); }
|
||||
requestAnimationFrame(raf);
|
||||
});
|
||||
return () => lenis?.destroy();
|
||||
}, []);
|
||||
|
||||
// Preloader Curtain Timer
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setPreloader(false);
|
||||
}, 1500);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
// Localized stats label mappings
|
||||
const getLocalizedStatLabel = (etiket: string) => {
|
||||
if (etiket.includes("Deneyim")) return t.statExp;
|
||||
if (etiket.includes("Müşteri")) return t.statClients;
|
||||
if (etiket.includes("Şehir")) return t.statCities;
|
||||
return t.statDelivery;
|
||||
};
|
||||
|
||||
// Localized services text mappings
|
||||
const getLocalizedServiceText = (baslik: string) => {
|
||||
if (baslik.includes("Karayolu")) return { title: t.serviceKarayolu, desc: t.serviceKarayoluDesc };
|
||||
if (baslik.includes("Depolama")) return { title: t.serviceDepolama, desc: t.serviceDepolamaDesc };
|
||||
if (baslik.includes("E-ticaret")) return { title: t.serviceEticaret, desc: t.serviceEticaretDesc };
|
||||
if (baslik.includes("Uluslararası")) return { title: t.serviceUlusal, desc: t.serviceUlusalDesc };
|
||||
if (baslik.includes("Soğuk")) return { title: t.serviceSoguk, desc: t.serviceSogukDesc };
|
||||
return { title: t.serviceTakip, desc: t.serviceTakipDesc };
|
||||
};
|
||||
|
||||
// Localized projects text mappings
|
||||
const getLocalizedProjectText = (baslik: string) => {
|
||||
if (baslik.includes("Migros")) return { title: t.projMigros, desc: t.projMigrosDesc, sector: lang === "tr" ? "Perakende" : "Retail" };
|
||||
if (baslik.includes("Trendyol")) return { title: t.projTrendyol, desc: t.projTrendyolDesc, sector: lang === "tr" ? "E-Ticaret" : "E-Commerce" };
|
||||
if (baslik.includes("Ford")) return { title: t.projFord, desc: t.projFordDesc, sector: lang === "tr" ? "Otomotiv" : "Automotive" };
|
||||
return { title: t.projPfizer, desc: t.projPfizerDesc, sector: lang === "tr" ? "İlaç" : "Pharmaceutical" };
|
||||
};
|
||||
|
||||
// Custom vector icons for services (No generic emojis)
|
||||
const getServiceIconSvg = (baslik: string) => {
|
||||
if (baslik.includes("Karayolu")) {
|
||||
return (
|
||||
<svg className="w-6 h-6 stroke-[#6366f1] fill-none" viewBox="0 0 24 24" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9 17a2 2 0 11-4 0 2 2 0 014 0zM19 17a2 2 0 11-4 0 2 2 0 014 0z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M13 16V6a1 1 0 00-1-1H4a1 1 0 00-1 1v10a1 1 0 001 1h1M21 16V10a1 1 0 00-1-1h-7m8 7h-1m-6 0h-2" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
if (baslik.includes("Depolama")) {
|
||||
return (
|
||||
<svg className="w-6 h-6 stroke-[#6366f1] fill-none" viewBox="0 0 24 24" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
if (baslik.includes("E-ticaret")) {
|
||||
return (
|
||||
<svg className="w-6 h-6 stroke-[#6366f1] fill-none" viewBox="0 0 24 24" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
if (baslik.includes("Uluslararası")) {
|
||||
return (
|
||||
<svg className="w-6 h-6 stroke-[#6366f1] fill-none" viewBox="0 0 24 24" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 002 2h2.945M12 2a10 10 0 110 20 10 10 0 010-20z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
if (baslik.includes("Soğuk")) {
|
||||
return (
|
||||
<svg className="w-6 h-6 stroke-[#6366f1] fill-none" viewBox="0 0 24 24" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 3v18M3 12h18m-3-3l3 3-3 3M6 9l-3 3 3 3M9 6l3-3 3 3m-6 12l3 3 3-3" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<svg className="w-6 h-6 stroke-[#6366f1] fill-none" viewBox="0 0 24 24" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
const getLocalizedTeam = (ad: string) => {
|
||||
if (ad.includes("Murat")) return { name: "Murat Yıldız", role: lang === "tr" ? "Genel Müdür" : "Managing Director" };
|
||||
if (ad.includes("Hande")) return { name: "Hande Çelik", role: lang === "tr" ? "Operasyon Direktörü" : "Operations Director" };
|
||||
if (ad.includes("Serkan")) return { name: "Serkan Aydın", role: lang === "tr" ? "Teknoloji Müdürü" : "Technology Director" };
|
||||
return { name: "Neslihan Kara", role: lang === "tr" ? "Müşteri Deneyimi Yöneticisi" : "Customer Success Lead" };
|
||||
};
|
||||
|
||||
const css = `
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
|
||||
|
||||
:root {
|
||||
--color-kurumsal-indigo: #6366f1;
|
||||
--color-kurumsal-indigo-dark: #4f46e5;
|
||||
--color-kurumsal-indigo-light: #eef2ff;
|
||||
--color-kurumsal-charcoal: #0F172A;
|
||||
--color-kurumsal-sand: #FAF8F5;
|
||||
}
|
||||
|
||||
.font-heavy-sans {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.font-sans-clean {
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
|
||||
.shadow-premium {
|
||||
box-shadow: 0 20px 40px -15px rgba(15, 23, 42, 0.05);
|
||||
}
|
||||
|
||||
.hero-title-clamp {
|
||||
font-size: clamp(38px, 6vw, 90px);
|
||||
letter-spacing: -0.03em;
|
||||
line-height: 0.95;
|
||||
}
|
||||
`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{css}</style>
|
||||
|
||||
{/* ── IMZA AN: CURTAIN REVEAL PRELOADER ── */}
|
||||
<AnimatePresence>
|
||||
{preloader && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 bg-[#0F172A] flex flex-col items-center justify-center p-6"
|
||||
exit={{
|
||||
clipPath: "polygon(0 0, 100% 0, 100% 0, 0 0)",
|
||||
transition: { duration: 0.85, ease: [0.16, 1, 0.3, 1] }
|
||||
}}
|
||||
>
|
||||
<div className="max-w-md text-center space-y-6">
|
||||
<motion.span
|
||||
className="text-[9px] font-heavy-sans tracking-[4px] uppercase text-[#6366f1] block"
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
ATLAS LOGISTICS
|
||||
</motion.span>
|
||||
<div className="h-[1px] w-48 bg-white/10 mx-auto relative overflow-hidden">
|
||||
<motion.div
|
||||
className="absolute inset-y-0 left-0 bg-[#6366f1]"
|
||||
initial={{ width: "0%" }}
|
||||
animate={{ width: "100%" }}
|
||||
transition={{ duration: 1.2, ease: "easeInOut" }}
|
||||
/>
|
||||
</div>
|
||||
<motion.h2
|
||||
className="font-sans-clean text-white/50 text-xs tracking-wider uppercase font-semibold"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.4, duration: 0.5 }}
|
||||
>
|
||||
interactive prototype
|
||||
</motion.h2>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
<div className="bg-[#FAF8F5] text-[#0F172A] min-h-screen font-sans-clean selection:bg-[#6366f1] selection:text-white overflow-hidden relative pb-20">
|
||||
|
||||
{/* Floating Ambient Orbs */}
|
||||
<div className="absolute top-[10%] left-[-15%] w-[600px] h-[600px] bg-[#6366f1]/3 blur-[120px] rounded-full pointer-events-none z-0" />
|
||||
<div className="absolute bottom-[20%] right-[-15%] w-[600px] h-[600px] bg-[#4f46e5]/3 blur-[140px] rounded-full pointer-events-none z-0" />
|
||||
|
||||
{/* ── FLOATING CONCEPT BANNER ── */}
|
||||
<div className="fixed bottom-4 left-4 z-40 bg-[#0F172A]/90 backdrop-blur-md border border-white/10 px-4 py-2.5 rounded-xl shadow-2xl flex items-center gap-2.5 max-w-sm pointer-events-none select-none">
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-[#6366f1] animate-pulse" />
|
||||
<span className="text-[9px] font-sans-clean uppercase tracking-[1.5px] text-white/90 font-bold">
|
||||
{lang === "tr" ? "Bu web sitesi Ayris Tech tarafından hazırlanmış bir konsept çalışmasıdır." : "This website is a premium concept prototype designed by Ayris Tech."}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* ── PREMIUM HEADER ── */}
|
||||
<motion.header
|
||||
className="fixed top-4 left-4 right-4 z-50 px-4"
|
||||
initial={{ y: -80, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.85, ease: [0.16, 1, 0.3, 1] }}
|
||||
>
|
||||
<div className="mx-auto max-w-7xl h-20 flex items-center justify-between px-8 bg-white/80 backdrop-blur-xl border border-white/40 rounded-2xl shadow-[0_10px_30px_rgba(15,23,42,0.03)]">
|
||||
{/* Logo */}
|
||||
<a href="#" className="flex items-center gap-2.5 group">
|
||||
<span className="text-lg font-black tracking-tight text-[#0F172A] font-heavy-sans flex items-center gap-2.5 uppercase">
|
||||
<svg className="w-5 h-5 text-[#6366f1]" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z" />
|
||||
<path d="M12 6v12M6 12h12" />
|
||||
</svg>
|
||||
{firma.adi}
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{/* Links */}
|
||||
<nav className="hidden lg:flex items-center gap-8">
|
||||
{[
|
||||
{ label: t.navServices, href: "#hizmetler" },
|
||||
{ label: t.navProjects, href: "#projeler" },
|
||||
{ label: t.navTeam, href: "#ekip" },
|
||||
{ label: t.navReviews, href: "#testimonials" }
|
||||
].map(item => (
|
||||
<a
|
||||
key={item.label}
|
||||
href={item.href}
|
||||
className="text-[10px] font-black tracking-[2px] uppercase text-[#0F172A]/70 hover:text-[#6366f1] transition-colors relative py-1 cursor-pointer group"
|
||||
>
|
||||
{item.label}
|
||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-[#6366f1] transition-all group-hover:w-full" />
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
{/* Language Selector + Quote Button */}
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Language Switcher */}
|
||||
<div className="flex items-center gap-1 bg-[#0F172A]/5 border border-[#0F172A]/10 rounded-xl p-1 shrink-0">
|
||||
<button
|
||||
onClick={() => setLang("tr")}
|
||||
className={`text-[9px] font-sans-clean font-black px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "tr" ? "bg-white text-slate-900 shadow-sm" : "text-[#0F172A]/60 hover:text-[#0F172A]"
|
||||
}`}
|
||||
>
|
||||
TR
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setLang("en")}
|
||||
className={`text-[9px] font-sans-clean font-black px-2 py-1.5 rounded-lg transition-all cursor-pointer ${
|
||||
lang === "en" ? "bg-white text-slate-900 shadow-sm" : "text-[#0F172A]/60 hover:text-[#0F172A]"
|
||||
}`}
|
||||
>
|
||||
EN
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<motion.button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="text-[10px] font-black tracking-[2.5px] uppercase text-white bg-[#6366f1] hover:bg-[#4f46e5] px-6 py-3.5 rounded-xl transition-all cursor-pointer shadow-[0_4px_12px_rgba(99,102,241,0.15)] hidden sm:block"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{t.navBooking}
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.header>
|
||||
|
||||
{/* ── HERO & BENTO HIGHLIGHTS ── */}
|
||||
<section className="relative min-h-screen pt-32 pb-20 flex items-center z-10 px-6">
|
||||
<div className="max-w-7xl mx-auto w-full">
|
||||
<div className="grid lg:grid-cols-12 gap-16 items-center">
|
||||
|
||||
{/* Left Column: Heavy typography and stats */}
|
||||
<motion.div
|
||||
className="lg:col-span-6 z-20"
|
||||
variants={stagger}
|
||||
initial="hidden"
|
||||
animate="show"
|
||||
>
|
||||
<motion.div
|
||||
variants={fadeUp}
|
||||
className="inline-flex items-center gap-2 text-[10px] font-black uppercase tracking-widest text-[#6366f1] mb-6 bg-[#6366f1]/5 border border-[#6366f1]/10 px-4 py-2 rounded-full"
|
||||
>
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-[#6366f1] animate-pulse" />
|
||||
{t.badge}
|
||||
</motion.div>
|
||||
|
||||
<motion.h1
|
||||
variants={fadeUp}
|
||||
className="font-heavy-sans text-[#0F172A] leading-[1.1] mb-8 hero-title-clamp uppercase"
|
||||
>
|
||||
{t.heroTitlePart1}
|
||||
<br />
|
||||
<span className="text-[#6366f1] font-light italic">{t.heroTitlePart2}</span>
|
||||
<br />
|
||||
{t.heroTitlePart3}
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
variants={fadeUp}
|
||||
className="text-[#0F172A]/60 text-xs lg:text-sm leading-relaxed max-w-md mb-12 font-semibold"
|
||||
>
|
||||
{t.heroDesc}
|
||||
</motion.p>
|
||||
|
||||
{/* Statistics Grid */}
|
||||
<motion.div
|
||||
variants={fadeUp}
|
||||
className="grid grid-cols-2 sm:grid-cols-4 gap-6 mb-12 font-semibold"
|
||||
>
|
||||
{istatistikler.map((stat, idx) => (
|
||||
<div key={idx} className="border-l border-[#6366f1]/30 pl-4 py-1">
|
||||
<h4 className="font-heavy-sans text-[#0F172A] text-lg uppercase tracking-wider mb-1 leading-none">
|
||||
{stat.deger}
|
||||
</h4>
|
||||
<p className="text-[#0F172A]/50 text-[10px] leading-snug">
|
||||
{getLocalizedStatLabel(stat.etiket)}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</motion.div>
|
||||
|
||||
{/* CTA buttons */}
|
||||
<motion.div variants={fadeUp} className="flex gap-4">
|
||||
<motion.button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="inline-flex items-center gap-3 px-8 py-4.5 rounded-xl bg-[#6366f1] hover:bg-[#4f46e5] text-white font-black text-[10px] tracking-[2px] uppercase transition-all shadow-[0_5px_15px_rgba(99,102,241,0.2)] cursor-pointer"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
>
|
||||
📅 {t.getQuote}
|
||||
</motion.button>
|
||||
<a
|
||||
href="#projeler"
|
||||
className="inline-flex items-center gap-3 px-8 py-4.5 rounded-xl border border-[#0F172A]/10 bg-white/40 hover:bg-white/80 text-[#0F172A] font-black text-[10px] tracking-[2px] uppercase transition-all cursor-pointer"
|
||||
>
|
||||
{t.learnMore}
|
||||
</a>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Column: Bento style highlights preview */}
|
||||
<div className="lg:col-span-6 grid sm:grid-cols-2 gap-4 w-full">
|
||||
{hizmetler.slice(0, 4).map((h, i) => {
|
||||
const s = getLocalizedServiceText(h.baslik);
|
||||
return (
|
||||
<motion.div
|
||||
key={i}
|
||||
className="bg-white rounded-3xl p-6 shadow-premium border border-white hover:border-[#6366f1]/30 transition-all duration-300 flex flex-col justify-between group h-64"
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.5, delay: i * 0.1 }}
|
||||
whileHover={{ y: -4 }}
|
||||
>
|
||||
<div className="w-12 h-12 rounded-2xl flex items-center justify-center transition-transform group-hover:scale-105 shadow-sm border border-gray-100 bg-gray-50 shrink-0">
|
||||
{getServiceIconSvg(h.baslik)}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-heavy-sans text-gray-900 text-xs uppercase tracking-wide leading-tight mb-2">{s.title}</h4>
|
||||
<p className="text-gray-400 text-[10px] leading-relaxed font-semibold">{s.desc}</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── HİZMETLER FULL BENTO GRID ── */}
|
||||
<section id="hizmetler" className="py-32 bg-white px-6 border-t border-gray-100 relative z-10">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<motion.div
|
||||
className="mb-20"
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true }}
|
||||
variants={stagger}
|
||||
>
|
||||
<motion.span
|
||||
variants={fadeUp}
|
||||
className="inline-block text-[10px] font-black uppercase tracking-widest px-4 py-2 rounded-full mb-4 bg-[#6366f1]/5 text-[#6366f1] border border-[#6366f1]/10"
|
||||
>
|
||||
{t.navServices}
|
||||
</motion.span>
|
||||
<motion.h2 variants={fadeUp} className="text-4xl lg:text-5xl font-heavy-sans text-gray-900 leading-tight uppercase">
|
||||
{lang === "tr" ? "Kapsamlı Lojistik Çözüm Paketi" : "Comprehensive Logistics Solutions"}
|
||||
</motion.h2>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="grid sm:grid-cols-2 lg:grid-cols-3 gap-6"
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true }}
|
||||
variants={stagger}
|
||||
>
|
||||
{hizmetler.map((h, i) => {
|
||||
const s = getLocalizedServiceText(h.baslik);
|
||||
return (
|
||||
<motion.div
|
||||
key={i}
|
||||
variants={fadeUp}
|
||||
className="bg-white rounded-3xl p-8 border border-gray-100 group flex flex-col justify-between h-80 transition-all duration-300"
|
||||
whileHover={{ y: -6, boxShadow: `0 24px 60px rgba(99,102,241,0.08)`, borderColor: `${firma.renkAna}30` }}
|
||||
>
|
||||
<div>
|
||||
<div className="w-14 h-14 rounded-2xl flex items-center justify-center transition-transform group-hover:scale-105 shadow-sm border border-gray-100 bg-gray-50 mb-6 shrink-0">
|
||||
{getServiceIconSvg(h.baslik)}
|
||||
</div>
|
||||
<h3 className="font-heavy-sans text-gray-900 text-sm uppercase tracking-wide leading-tight mb-3">{s.title}</h3>
|
||||
<p className="text-gray-500 text-xs leading-relaxed font-semibold">{s.desc}</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="text-[#6366f1] font-black text-[9px] tracking-[2.5px] uppercase flex items-center gap-1 cursor-pointer hover:text-opacity-80 transition-colors pt-4 border-t border-gray-100 shrink-0"
|
||||
>
|
||||
{lang === "tr" ? "DETAYLI BİLGİ →" : "MORE DETAILS →"}
|
||||
</button>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── REFERANSLAR (PROJELER) ── */}
|
||||
<section id="projeler" className="py-32 px-6 bg-gray-950 border-t border-white/5 relative z-10">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<motion.div
|
||||
className="mb-20"
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true }}
|
||||
variants={stagger}
|
||||
>
|
||||
<motion.span
|
||||
variants={fadeUp}
|
||||
className="inline-block text-[10px] font-black uppercase tracking-widest px-4 py-2 rounded-full mb-4 bg-white/5 text-[#6366f1] border border-white/10"
|
||||
>
|
||||
{t.projectsTitle}
|
||||
</motion.span>
|
||||
<motion.h2 variants={fadeUp} className="text-4xl lg:text-5xl font-heavy-sans text-white uppercase">
|
||||
{t.projectsHeader}
|
||||
</motion.h2>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="grid sm:grid-cols-2 gap-6"
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true }}
|
||||
variants={stagger}
|
||||
>
|
||||
{projeler.map((p, i) => {
|
||||
const proj = getLocalizedProjectText(p.baslik);
|
||||
return (
|
||||
<motion.div
|
||||
key={i}
|
||||
variants={fadeUp}
|
||||
className="bg-white/5 border border-white/10 rounded-3xl p-8 group flex flex-col justify-between h-56 transition-all duration-300"
|
||||
whileHover={{ y: -4, background: "rgba(255,255,255,0.08)", borderColor: "rgba(255,255,255,0.2)" }}
|
||||
>
|
||||
<div className="flex items-start gap-5">
|
||||
<div className="w-14 h-14 rounded-2xl flex items-center justify-center text-xl shrink-0"
|
||||
style={{ background: `${p.renk}20` }}>
|
||||
<span className="select-none text-2xl">{p.ikon}</span>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center gap-3 mb-2 flex-wrap">
|
||||
<h3 className="font-heavy-sans text-white text-[15px] uppercase tracking-wide">{proj.title}</h3>
|
||||
<span className="text-[9px] font-black uppercase tracking-widest px-2.5 py-1 rounded-full border border-white/10"
|
||||
style={{ background: `${p.renk}20`, color: p.renk }}>
|
||||
{proj.sector}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-white/50 text-xs leading-relaxed font-semibold">{proj.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="text-white/80 font-black text-[9px] tracking-[2.5px] uppercase flex items-center gap-1 cursor-pointer hover:text-white transition-colors pt-4 border-t border-white/5 shrink-0"
|
||||
>
|
||||
{lang === "tr" ? "VAKAYI İNCELE →" : "VIEW CASE STUDY →"}
|
||||
</button>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── EKİP (TEAM) ── */}
|
||||
{ekip.length > 0 && (
|
||||
<section id="ekip" className="py-32 px-6 bg-[#f8fafc] border-t border-gray-100 relative z-10">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
|
||||
<motion.div
|
||||
className="mb-20"
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true }}
|
||||
variants={stagger}
|
||||
>
|
||||
<motion.span
|
||||
variants={fadeUp}
|
||||
className="inline-block text-[10px] font-black uppercase tracking-widest px-4 py-2 rounded-full mb-4 bg-[#6366f1]/5 text-[#6366f1] border border-[#6366f1]/10"
|
||||
>
|
||||
{t.teamTitle}
|
||||
</motion.span>
|
||||
<motion.h2 variants={fadeUp} className="text-4xl lg:text-5xl font-heavy-sans text-gray-900 uppercase">
|
||||
{t.teamHeader}
|
||||
</motion.h2>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="grid sm:grid-cols-2 lg:grid-cols-4 gap-6 font-semibold"
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true }}
|
||||
variants={stagger}
|
||||
>
|
||||
{ekip.map((k, i) => {
|
||||
const member = getLocalizedTeam(k.ad);
|
||||
return (
|
||||
<motion.div
|
||||
key={i}
|
||||
variants={fadeUp}
|
||||
className="bg-white rounded-3xl overflow-hidden border border-gray-100/60 shadow-premium flex flex-col justify-between"
|
||||
whileHover={{ y: -6 }}
|
||||
>
|
||||
<div
|
||||
className="h-44 flex items-center justify-center text-6xl select-none"
|
||||
style={{ background: `linear-gradient(135deg, ${firma.renkAcik}, rgba(99,102,241,0.15))` }}
|
||||
>
|
||||
<motion.span whileHover={{ scale: 1.15 }} transition={{ type: "spring", stiffness: 300 }}>
|
||||
{k.emoji}
|
||||
</motion.span>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<h3 className="font-heavy-sans text-gray-900 text-sm uppercase leading-tight">{member.name}</h3>
|
||||
<p className="text-[11px] font-bold mt-1.5 text-[#6366f1] uppercase tracking-wide">{member.role}</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* ── YORUMLAR (TESTIMONIALS) ── */}
|
||||
<section id="testimonials" className="py-32 px-6 bg-white border-t border-gray-100 relative z-10">
|
||||
<div className="max-w-7xl mx-auto font-semibold">
|
||||
|
||||
<motion.div
|
||||
className="mb-20"
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true }}
|
||||
variants={stagger}
|
||||
>
|
||||
<motion.span
|
||||
variants={fadeUp}
|
||||
className="inline-block text-[10px] font-black uppercase tracking-widest px-4 py-2 rounded-full mb-4 bg-[#6366f1]/5 text-[#6366f1] border border-[#6366f1]/10"
|
||||
>
|
||||
{t.reviewsTitle}
|
||||
</motion.span>
|
||||
<motion.h2 variants={fadeUp} className="text-4xl lg:text-5xl font-heavy-sans text-gray-900 uppercase">
|
||||
{t.reviewsHeader}
|
||||
</motion.h2>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="grid md:grid-cols-3 gap-6"
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true }}
|
||||
variants={stagger}
|
||||
>
|
||||
{yorumlar.map((y, i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
variants={fadeUp}
|
||||
className="bg-gray-50 rounded-3xl p-8 border border-gray-100 flex flex-col justify-between h-80"
|
||||
whileHover={{ y: -4, boxShadow: `0 20px 40px rgba(99,102,241,0.06)`, borderColor: `${firma.renkAna}30` }}
|
||||
>
|
||||
<div>
|
||||
<div className="flex gap-1.5 mb-5">
|
||||
{[...Array(y.puan || 5)].map((_, j) => (
|
||||
<svg key={j} className="w-4.5 h-4.5 fill-[#6366f1]" viewBox="0 0 24 24">
|
||||
<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
|
||||
</svg>
|
||||
))}
|
||||
</div>
|
||||
<p className="text-gray-600 text-xs leading-relaxed italic mb-6">“{y.yorum}”</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3.5 pt-4 border-t border-gray-200/60 shrink-0">
|
||||
<div className="w-9 h-9 rounded-full flex items-center justify-center text-base bg-white shadow-sm border border-gray-100 select-none">
|
||||
{y.emoji}
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-gray-900 font-bold text-xs uppercase tracking-wide leading-tight">{y.yazar.split("—")[0]}</p>
|
||||
<p className="text-gray-400 text-[9px] uppercase tracking-widest font-black mt-0.5">{y.yazar.split("—")[1] || t.reviewsTitle}</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── İLETİŞİM / TEKLİF AL ── */}
|
||||
<section id="iletisim" className="py-32 px-6 relative overflow-hidden"
|
||||
style={{ background: `linear-gradient(135deg, ${firma.renkKoyu} 0%, ${firma.renkAna} 100%)` }}>
|
||||
|
||||
{/* Subtle cosmic grid layout */}
|
||||
<div className="absolute inset-0 opacity-[0.03] pointer-events-none"
|
||||
style={{ backgroundImage: "linear-gradient(#fff 1px,transparent 1px),linear-gradient(90deg,#fff 1px,transparent 1px)", backgroundSize: "40px 40px" }} />
|
||||
|
||||
<div className="max-w-7xl mx-auto relative z-10">
|
||||
<div className="grid lg:grid-cols-2 gap-16 items-start">
|
||||
|
||||
{/* Left Column: contact information */}
|
||||
<motion.div initial="hidden" whileInView="show" viewport={{ once: true }} variants={stagger}>
|
||||
<motion.span
|
||||
variants={fadeUp}
|
||||
className="inline-block text-[9px] font-black uppercase tracking-widest px-4 py-2 rounded-full mb-4 bg-white/20 text-white border border-white/10"
|
||||
>
|
||||
{t.bookingTitle}
|
||||
</motion.span>
|
||||
<motion.h2 variants={fadeUp} className="text-4xl lg:text-5xl font-heavy-sans text-white leading-tight mb-6 uppercase">
|
||||
{t.bookingHeader}
|
||||
</motion.h2>
|
||||
<motion.p variants={fadeUp} className="text-white/70 text-xs lg:text-sm mb-10 font-semibold leading-relaxed">
|
||||
{t.bookingDesc}
|
||||
</motion.p>
|
||||
|
||||
<motion.div variants={fadeUp} className="space-y-4 font-semibold">
|
||||
{[
|
||||
{ ikon: "📞", baslik: t.callCenter, aciklama: firma.telefon },
|
||||
{ ikon: "📍", baslik: t.addressLabel, aciklama: firma.adres },
|
||||
{ ikon: "✉️", baslik: t.emailLabel, aciklama: firma.email },
|
||||
].map((item) => (
|
||||
<div key={item.baslik} className="flex items-start gap-4 bg-white/10 rounded-2xl p-4 border border-white/5">
|
||||
<span className="text-xl mt-0.5 shrink-0 select-none">{item.ikon}</span>
|
||||
<div>
|
||||
<p className="text-white/60 text-[9px] font-black uppercase tracking-wider">{item.baslik}</p>
|
||||
<p className="text-white text-xs mt-1 leading-snug">{item.aciklama}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Column: Quote Form */}
|
||||
<motion.div
|
||||
className="bg-white rounded-3xl p-8 shadow-2xl border border-white/10"
|
||||
initial={{ opacity: 0, y: 40 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.7, delay: 0.2 }}
|
||||
>
|
||||
<h3 className="font-heavy-sans text-gray-900 text-lg mb-6 uppercase tracking-wide">{t.bookingTitle}</h3>
|
||||
<div className="grid grid-cols-2 gap-4 font-semibold">
|
||||
{[
|
||||
{ label: t.fieldsName, placeholder: lang === "tr" ? "Adınız Soyadınız" : "Your Full Name", type: "text", full: false },
|
||||
{ label: t.fieldsPhone, placeholder: "05xx xxx xx xx", type: "tel", full: false },
|
||||
{ label: t.fieldsEmail, placeholder: "ornek@mail.com", type: "email", full: false },
|
||||
{ label: t.fieldsCategory, placeholder: "", type: "select", full: false },
|
||||
{ label: t.fieldsDate, placeholder: "", type: "date", full: false },
|
||||
{ label: t.fieldsNotes, placeholder: t.fieldsNotesPlaceholder, type: "text", full: true },
|
||||
].map((field, i) => (
|
||||
<div key={i} className={field.full ? "col-span-2" : "col-span-2 sm:col-span-1"}>
|
||||
<label className="block text-[10px] font-black text-gray-700 mb-1.5 uppercase tracking-wider">{field.label}</label>
|
||||
{field.type === "select" ? (
|
||||
<select className="w-full px-4 py-3.5 rounded-xl border border-gray-200 text-xs text-slate-800 focus:outline-none focus:ring-2 focus:ring-[#6366f1] bg-gray-50/50 transition-all font-semibold cursor-pointer">
|
||||
<option>{t.serviceKarayolu}</option>
|
||||
<option>{t.serviceDepolama}</option>
|
||||
<option>{t.serviceEticaret}</option>
|
||||
<option>{t.serviceUlusal}</option>
|
||||
<option>{t.serviceSoguk}</option>
|
||||
</select>
|
||||
) : (
|
||||
<input type={field.type} placeholder={field.placeholder}
|
||||
className="w-full px-4 py-3.5 rounded-xl border border-gray-200 text-xs focus:outline-none focus:ring-2 focus:ring-[#6366f1] bg-gray-50/50 transition-all placeholder-slate-300 font-semibold" />
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<motion.button
|
||||
onClick={() => setShowBookingModal(true)}
|
||||
className="mt-6 w-full py-4.5 rounded-xl text-white font-black text-xs uppercase tracking-widest cursor-pointer shadow-[0_5px_15px_rgba(99,102,241,0.2)]"
|
||||
style={{ background: `linear-gradient(135deg, ${firma.renkAna}, ${firma.renkKoyu})` }}
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
📅 {t.dispatchForm}
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── FOOTER ── */}
|
||||
<footer className="bg-gray-950 border-t border-white/5 px-6 pt-24 pb-8 relative z-10">
|
||||
<div className="max-w-7xl mx-auto font-semibold">
|
||||
<div className="grid md:grid-cols-4 gap-12 pb-16 border-b border-white/5">
|
||||
<div className="md:col-span-2">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<svg className="w-5 h-5 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z" />
|
||||
<path d="M12 6v12M6 12h12" />
|
||||
</svg>
|
||||
<span className="font-bold text-white text-lg font-heavy-sans uppercase tracking-wide">{firma.adi}</span>
|
||||
</div>
|
||||
<p className="text-white/40 text-xs leading-relaxed max-w-sm mb-8">{firma.slogan} — {t.footerDesc}</p>
|
||||
<div className="text-white/50 text-xs space-y-3">
|
||||
<p className="flex items-center gap-2">📍 <span className="text-white/80">{firma.adres}</span></p>
|
||||
<p className="flex items-center gap-2">📞 <span className="text-white/80">{firma.telefon}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-heavy-sans text-white font-bold text-xs uppercase tracking-wider mb-6">{t.navServices}</h4>
|
||||
{hizmetler.slice(0, 4).map((h, i) => {
|
||||
const s = getLocalizedServiceText(h.baslik);
|
||||
return (
|
||||
<a key={i} href="#hizmetler" className="block text-white/40 text-xs mb-3 hover:text-white transition-colors">{s.title}</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-heavy-sans text-white font-bold text-xs uppercase tracking-wider mb-6">Company</h4>
|
||||
{[t.navServices, t.navProjects, t.navTeam, t.navReviews].map((item) => (
|
||||
<a key={item} href="#" className="block text-white/40 text-xs mb-3 hover:text-white transition-colors">{item}</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col md:flex-row justify-between items-center pt-8 gap-4 text-white/30 text-xs">
|
||||
<p>© 2026 {firma.adi}. All rights reserved.</p>
|
||||
<div className="flex gap-4">
|
||||
<a href="#" className="hover:text-white transition-colors">{t.privacyRegs}</a>
|
||||
<span>·</span>
|
||||
<a href="#" className="hover:text-white transition-colors">{t.termsStay}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{/* ── CONSULTATION SUCCESS MODAL ── */}
|
||||
<AnimatePresence>
|
||||
{showBookingModal && (
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 flex items-center justify-center p-6 bg-black/60 backdrop-blur-sm"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
<motion.div
|
||||
className="bg-white rounded-3xl p-8 max-w-md w-full relative shadow-2xl border border-gray-100"
|
||||
initial={{ scale: 0.95, y: 20 }}
|
||||
animate={{ scale: 1, y: 0 }}
|
||||
exit={{ scale: 0.95, y: 20 }}
|
||||
>
|
||||
<button
|
||||
className="absolute top-6 right-6 w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center font-bold text-gray-500 hover:bg-gray-200 transition-colors cursor-pointer"
|
||||
onClick={() => setShowBookingModal(false)}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
<h3 className="font-heavy-sans text-[#0F172A] text-2xl mb-1 uppercase tracking-wide leading-none">{t.contactTitle}</h3>
|
||||
<p className="text-gray-400 text-xs mb-6 font-semibold">{t.contactDesc}</p>
|
||||
|
||||
<div className="space-y-4 font-semibold">
|
||||
<div>
|
||||
<label className="block text-[10px] font-black text-gray-500 mb-1.5 uppercase tracking-wider">{t.fieldsName}</label>
|
||||
<input type="text" className="w-full px-4 py-3.5 rounded-xl border bg-gray-50/50 text-xs focus:outline-none focus:ring-2 focus:ring-[#6366f1]" placeholder="John Doe" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-[10px] font-black text-gray-500 mb-1.5 uppercase tracking-wider">{t.fieldsPhone}</label>
|
||||
<input type="tel" className="w-full px-4 py-3.5 rounded-xl border bg-gray-50/50 text-xs focus:outline-none focus:ring-2 focus:ring-[#6366f1]" placeholder="05xx xxx xx xx" />
|
||||
</div>
|
||||
<motion.button
|
||||
className="w-full py-4 rounded-xl bg-[#6366f1] text-white font-black text-xs hover:bg-[#4f46e5] transition-colors mt-2 cursor-pointer shadow-[0_4px_12px_rgba(99,102,241,0.15)] uppercase tracking-widest"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
onClick={() => setShowBookingModal(false)}
|
||||
>
|
||||
{t.submit}
|
||||
</motion.button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
"use client";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useInView } from "framer-motion";
|
||||
|
||||
export default function AnimatedCounter({ target, suffix = "" }: { target: number; suffix?: string }) {
|
||||
const [count, setCount] = useState(0);
|
||||
const ref = useRef(null);
|
||||
const inView = useInView(ref, { once: true });
|
||||
|
||||
useEffect(() => {
|
||||
if (!inView) return;
|
||||
const duration = 1800;
|
||||
const steps = 60;
|
||||
const increment = target / steps;
|
||||
let current = 0;
|
||||
const timer = setInterval(() => {
|
||||
current += increment;
|
||||
if (current >= target) {
|
||||
setCount(target);
|
||||
clearInterval(timer);
|
||||
} else {
|
||||
setCount(Math.floor(current));
|
||||
}
|
||||
}, duration / steps);
|
||||
return () => clearInterval(timer);
|
||||
}, [inView, target]);
|
||||
|
||||
return (
|
||||
<span ref={ref}>
|
||||
{count.toLocaleString("tr-TR")}
|
||||
{suffix}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,610 @@
|
||||
export interface DemoData {
|
||||
slug: string;
|
||||
template: "klinik" | "restoran" | "kurumsal" | "dental" | "restoran2" | "taxi" | "taxi2" | "chatbot" | "bar" | "bar2" | "hotel1" | "hotel2" | "hotel3" | "bodrumcerrahi" | "chatbot2";
|
||||
firma: {
|
||||
adi: string;
|
||||
slogan: string;
|
||||
sehir: string;
|
||||
adres: string;
|
||||
telefon: string;
|
||||
email: string;
|
||||
logoEmoji: string;
|
||||
renkAna: string;
|
||||
renkKoyu: string;
|
||||
renkAcik: string;
|
||||
};
|
||||
// Flexible stats — her şablon kendi anahtarlarını kullanır
|
||||
istatistikler: { deger: string; etiket: string }[];
|
||||
hizmetler: { ikon: string; baslik: string; aciklama: string }[];
|
||||
yorumlar: { yazar: string; yorum: string; puan: number; tarih: string; emoji: string }[];
|
||||
|
||||
// Klinik
|
||||
doktorlar?: { ad: string; uzmanlik: string; puan: string; yil: string; hasta: string; emoji: string }[];
|
||||
|
||||
// Restoran
|
||||
menu?: { kategori: string; ikon: string; urunler: { ad: string; aciklama: string; fiyat: string }[] }[];
|
||||
|
||||
// Kurumsal
|
||||
projeler?: { baslik: string; sektor: string; aciklama: string; ikon: string; renk: string; resim?: string }[];
|
||||
ekip?: { ad: string; rol: string; emoji: string }[];
|
||||
}
|
||||
|
||||
export const demos: Record<string, DemoData> = {
|
||||
"dogan-tip-merkezi": {
|
||||
slug: "dogan-tip-merkezi",
|
||||
template: "klinik",
|
||||
firma: {
|
||||
adi: "Doğan Tıp Merkezi",
|
||||
slogan: "Sağlığınız, En Değerli Varlığınız",
|
||||
sehir: "İstanbul",
|
||||
adres: "Bağcılar Mah. Sağlık Cad. No:12, Bağcılar / İstanbul",
|
||||
telefon: "0212 555 44 33",
|
||||
email: "info@dogantip.com",
|
||||
logoEmoji: "🏥",
|
||||
renkAna: "#0ea5e9",
|
||||
renkKoyu: "#0284c7",
|
||||
renkAcik: "#e0f2fe",
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "4200", etiket: "Mutlu Hasta" },
|
||||
{ deger: "14", etiket: "Uzman Doktor" },
|
||||
{ deger: "12", etiket: "Yıl Deneyim" },
|
||||
{ deger: "620", etiket: "Yorum" },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "🩺", baslik: "Dahiliye", aciklama: "Erişkin hastalıklarında kapsamlı tanı ve tedavi hizmetleri." },
|
||||
{ ikon: "❤️", baslik: "Kardiyoloji", aciklama: "Kalp ve damar sağlığı için ileri tanı ve tedavi." },
|
||||
{ ikon: "🦷", baslik: "Diş Hekimliği", aciklama: "İmplant, ortodonti ve estetik diş uygulamaları." },
|
||||
{ ikon: "👁️", baslik: "Göz Sağlığı", aciklama: "Lazer tedavileri ve göz cerrahisi." },
|
||||
{ ikon: "🧪", baslik: "Laboratuvar", aciklama: "Hızlı ve güvenilir tahlil sonuçları." },
|
||||
{ ikon: "📷", baslik: "Radyoloji", aciklama: "MR, tomografi ve ultrason görüntüleme." },
|
||||
],
|
||||
doktorlar: [
|
||||
{ ad: "Dr. Ahmet Yılmaz", uzmanlik: "Dahiliye Uzmanı", puan: "4.9", yil: "15", hasta: "2400", emoji: "👨⚕️" },
|
||||
{ ad: "Dr. Ayşe Kaya", uzmanlik: "Kardiyoloji", puan: "4.8", yil: "12", hasta: "1800", emoji: "👩⚕️" },
|
||||
{ ad: "Dr. Mehmet Demir", uzmanlik: "Göz Hastalıkları", puan: "5.0", yil: "10", hasta: "1200", emoji: "👨⚕️" },
|
||||
{ ad: "Dr. Zeynep Arslan", uzmanlik: "Diş Hekimi", puan: "4.9", yil: "8", hasta: "900", emoji: "👩⚕️" },
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "Fatma K.", yorum: "Çok iyi hizmet aldım. Doktorlar son derece ilgili ve profesyonel. Randevu sistemi de çok pratik.", puan: 5, tarih: "2 hafta önce", emoji: "😊" },
|
||||
{ yazar: "Mustafa A.", yorum: "Temiz, modern ortam. Muayenemi çok hızlı yaptılar ve sonuçları aynı gün aldım.", puan: 5, tarih: "1 ay önce", emoji: "🙂" },
|
||||
{ yazar: "Elif T.", yorum: "Online randevu sistemi harikaydı. Güvenilir ve kaliteli bir klinik. Tüm ailemle tercih ediyoruz.", puan: 5, tarih: "3 hafta önce", emoji: "😄" },
|
||||
],
|
||||
},
|
||||
|
||||
// ── RESTORAN ──────────────────────────────────────────────────────────────
|
||||
"lezzet-mutfagi": {
|
||||
slug: "lezzet-mutfagi",
|
||||
template: "restoran",
|
||||
firma: {
|
||||
adi: "Lezzet Mutfağı",
|
||||
slogan: "Taste The Difference",
|
||||
sehir: "İstanbul",
|
||||
adres: "Karaköy Mah. Liman Cad. No:7, Beyoğlu / İstanbul",
|
||||
telefon: "0212 444 55 66",
|
||||
email: "rezervasyon@lezzetmutfagi.com",
|
||||
logoEmoji: "🍽️",
|
||||
renkAna: "#C5A880",
|
||||
renkKoyu: "#0A0B0D",
|
||||
renkAcik: "#14161B",
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "12", etiket: "Years of Heritage" },
|
||||
{ deger: "48+", etiket: "Signature Dishes" },
|
||||
{ deger: "4.9", etiket: "Average Guest Rating" },
|
||||
{ deger: "18k+", etiket: "Monthly Diners" },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "alacarte", baslik: "À la Carte", aciklama: "Seçkin malzemelerle hazırlanan imza yemeklerimizi keşfedin." },
|
||||
{ ikon: "special", baslik: "Özel Günler", aciklama: "Doğum günü, evlilik yıldönümü ve kutlamalar için özel menüler." },
|
||||
{ ikon: "catering", baslik: "Kurumsal Etkinlik", aciklama: "İş yemekleri ve kurumsal organizasyonlar için catering hizmeti." },
|
||||
{ ikon: "delivery", baslik: "Paket Servis", aciklama: "Şehrin her köşesine hızlı ve sıcak teslimat." },
|
||||
],
|
||||
menu: [
|
||||
{
|
||||
kategori: "Başlangıçlar", ikon: "salad",
|
||||
urunler: [
|
||||
{ ad: "Ev Yapımı Hummus", aciklama: "Fırından taze lavaş ve trüf yağı ile", fiyat: "₺180" },
|
||||
{ ad: "Karidesli Bruschetta", aciklama: "Taze domates, fesleğen, marine sarımsak", fiyat: "₺220" },
|
||||
{ ad: "Burrata Salatası", aciklama: "Cherry domates, pesto, taze roka yaprakları", fiyat: "₺240" },
|
||||
],
|
||||
},
|
||||
{
|
||||
kategori: "Ana Yemekler", ikon: "steak",
|
||||
urunler: [
|
||||
{ ad: "Wagyu Bonfile", aciklama: "Fırınlanmış kuşkonmaz, trüf mantarlı patates püresi", fiyat: "₺680" },
|
||||
{ ad: "Levrek Fileto", aciklama: "Limonlu tereyağı sosu, kapari ve taze otlar", fiyat: "₺420" },
|
||||
{ ad: "Mantar Risotto", aciklama: "Yabani orman mantarları ve Parmigiano Reggiano", fiyat: "₺360" },
|
||||
],
|
||||
},
|
||||
{
|
||||
kategori: "Tatlılar", ikon: "dessert",
|
||||
urunler: [
|
||||
{ ad: "Crème Brûlée", aciklama: "Gerçek Madagaskar vanilyası, karamelize şeker kıtırı", fiyat: "₺160" },
|
||||
{ ad: "Çikolatalı Fondant", aciklama: "Belçika çikolatası dolgulu sıcak kek, vanilyalı dondurma", fiyat: "₺180" },
|
||||
{ ad: "Künefe", aciklama: "Halis tereyağlı çıtır tel kadayıf, manda kaymağı", fiyat: "₺200" },
|
||||
],
|
||||
},
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "Selin A.", yorum: "Hayatımda yediğim en iyi bonfile. Servis mükemmeldi, ortam son derece loş ve şık. Kesinlikle tekrar geleceğiz.", puan: 5, tarih: "1 hafta önce", emoji: "🍷" },
|
||||
{ yazar: "Burak T.", yorum: "Yıldönümümüzü burada kutladık. Detaylara gösterilen özen, menü kalitesi ve ambiyans harikaydı.", puan: 5, tarih: "2 hafta önce", emoji: "🥂" },
|
||||
{ yazar: "Canan M.", yorum: "Karaköy'ün en iyi restoranı. Risotto ve tatlılar inanılmazdı. Şefin ellerine sağlık.", puan: 5, tarih: "1 ay önce", emoji: "✨" },
|
||||
],
|
||||
},
|
||||
|
||||
// ── KURUMSAL ──────────────────────────────────────────────────────────────
|
||||
"atlas-lojistik": {
|
||||
slug: "atlas-lojistik",
|
||||
template: "kurumsal",
|
||||
firma: {
|
||||
adi: "Atlas Lojistik",
|
||||
slogan: "Güvenli Taşımacılık, Zamanında Teslimat",
|
||||
sehir: "İstanbul",
|
||||
adres: "Esenyurt Lojistik Merkezi, Esenyurt / İstanbul",
|
||||
telefon: "0212 333 22 11",
|
||||
email: "info@atlaslojistik.com",
|
||||
logoEmoji: "🚛",
|
||||
renkAna: "#6366f1",
|
||||
renkKoyu: "#4f46e5",
|
||||
renkAcik: "#eef2ff",
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "15", etiket: "Yıl Deneyim" },
|
||||
{ deger: "850+", etiket: "Aktif Müşteri" },
|
||||
{ deger: "12", etiket: "Şehir" },
|
||||
{ deger: "%99.2", etiket: "Zamanında Teslimat" },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "🚛", baslik: "Karayolu Taşımacılığı", aciklama: "Yurtiçi ve uluslararası karayolu ile güvenli ve hızlı taşımacılık." },
|
||||
{ ikon: "🏭", baslik: "Depolama & Lojistik", aciklama: "Modern depolarımızda güvenli stok yönetimi ve dağıtım hizmetleri." },
|
||||
{ ikon: "📦", baslik: "E-ticaret Lojistiği", aciklama: "Son mile teslimat, iade yönetimi ve fulfillment çözümleri." },
|
||||
{ ikon: "🌍", baslik: "Uluslararası Nakliye", aciklama: "Gümrük işlemleri dahil kapıdan kapıya uluslararası taşımacılık." },
|
||||
{ ikon: "❄️", baslik: "Soğuk Zincir", aciklama: "Gıda ve ilaç sektörü için kontrollü sıcaklıkta taşıma." },
|
||||
{ ikon: "📱", baslik: "Anlık Takip", aciklama: "Yükünüzü 7/24 gerçek zamanlı olarak takip edin." },
|
||||
],
|
||||
projeler: [
|
||||
{ baslik: "Migros Dağıtım Ağı", sektor: "Perakende", aciklama: "12 şehirde günlük 400+ noktaya soğuk zincir dağıtım yönetimi.", ikon: "🛒", renk: "#10b981" },
|
||||
{ baslik: "Trendyol Fulfillment", sektor: "E-ticaret", aciklama: "Günlük 8.000+ sipariş işleme ve son mile teslimat operasyonu.", ikon: "📦", renk: "#f97316" },
|
||||
{ baslik: "Ford Otosan Tedarik", sektor: "Otomotiv", aciklama: "JIT modeli ile fabrikaya zamanında parça tedarik lojistiği.", ikon: "🚗", renk: "#6366f1" },
|
||||
{ baslik: "Pfizer İlaç Lojistiği", sektor: "İlaç", aciklama: "GDP sertifikalı soğuk zincir ile ilaç dağıtım ağı yönetimi.", ikon: "💊", renk: "#0ea5e9" },
|
||||
],
|
||||
ekip: [
|
||||
{ ad: "Murat Yıldız", rol: "Genel Müdür", emoji: "👨💼" },
|
||||
{ ad: "Hande Çelik", rol: "Operasyon Direktörü", emoji: "👩💼" },
|
||||
{ ad: "Serkan Aydın", rol: "Teknoloji Müdürü", emoji: "👨💻" },
|
||||
{ ad: "Neslihan Kara", rol: "Müşteri Deneyimi", emoji: "👩💼" },
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "Kemal B. — Tedarik Zinciri Müdürü", yorum: "3 yıldır çalışıyoruz, tek bir gecikmemiz olmadı. Gerçek anlamda güvenilir bir iş ortağı.", puan: 5, tarih: "1 ay önce", emoji: "👍" },
|
||||
{ yazar: "Derya S. — E-ticaret Direktörü", yorum: "E-ticaret operasyonumuzu tamamen Atlas'a devrettik. Müşteri memnuniyetimiz %94'e çıktı.", puan: 5, tarih: "2 ay önce", emoji: "🙌" },
|
||||
{ yazar: "Tahir A. — Satın Alma Müdürü", yorum: "Anlık takip sistemi ve proaktif iletişim anlayışı sektörde fark yaratıyor.", puan: 5, tarih: "3 hafta önce", emoji: "⭐" },
|
||||
],
|
||||
},
|
||||
|
||||
"odentries": {
|
||||
slug: "odentries",
|
||||
template: "dental",
|
||||
firma: {
|
||||
adi: "Odentries",
|
||||
slogan: "Seamless Dental Care",
|
||||
sehir: "İstanbul",
|
||||
adres: "Nişantaşı Mah. Valikonağı Cad. No:45, Şişli / İstanbul",
|
||||
telefon: "0212 999 88 77",
|
||||
email: "hello@odentries.com",
|
||||
logoEmoji: "🦷",
|
||||
renkAna: "#1E2E38",
|
||||
renkKoyu: "#121C22",
|
||||
renkAcik: "#EBF5F0",
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "80%", etiket: "Exclusive Member Savings: Save 60% - 80% on Dental Procedures, including Oral Exams, Cleanings, and X-Rays." },
|
||||
{ deger: "40%", etiket: "Enhanced Member Benefits: Save 40% on All Other Dental Services, including Cosmetic, Restorative, and Specialty Dental Procedures." },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "🦷", baslik: "Prevent cavities and gum disease", aciklama: "Kapsamlı diş muayeneleri ve koruyucu hekimlik uygulamaları ile dişlerinizi koruyoruz." },
|
||||
{ ikon: "✨", baslik: "Keep your teeth sparkling clean", aciklama: "Profesyonel temizleme ve beyazlatma teknikleriyle parıldayan sağlıklı gülüşler yaratıyoruz." },
|
||||
{ ikon: "🔍", baslik: "Early detection of dental issues", aciklama: "İleri teknoloji röntgen ve teşhis araçlarıyla sorunları büyümeden yakalıyoruz." },
|
||||
],
|
||||
projeler: [
|
||||
{ baslik: "Teeth Straightening", sektor: "002 - Our Works", aciklama: "Impressive results with cleaning.", ikon: "✨", renk: "#EBF5F0", resim: "/teeth_straightening.png" },
|
||||
{ baslik: "Revitalized Cleaning", sektor: "002 - Our Works", aciklama: "A simple way to enhance your smile.", ikon: "🦷", renk: "#FAF7F2", resim: "/revitalized_cleaning.png" },
|
||||
{ baslik: "Dental Implant", sektor: "002 - Our Works", aciklama: "Gorgeous and durable smile updates.", ikon: "🔬", renk: "#EBF5F0", resim: "/dental_implant.png" },
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "Melis Y.", yorum: "Harika bir diş sağlığı deneyimiydi. Tasarım muhteşem, ekip inanılmaz profesyonel. Odentries bir numara!", puan: 5, tarih: "1 hafta önce", emoji: "😊" },
|
||||
{ yazar: "Arda K.", yorum: "Klinik çok temiz ve ferah. Tedavi süresince hiçbir acı hissetmedim. Herkese tavsiye ederim.", puan: 5, tarih: "3 hafta önce", emoji: "👍" },
|
||||
],
|
||||
},
|
||||
|
||||
"sicilia-tavola": {
|
||||
slug: "sicilia-tavola",
|
||||
template: "restoran2",
|
||||
firma: {
|
||||
adi: "Sicilia Tavola",
|
||||
slogan: "Linen, Lemons & Wood-fired Heritage",
|
||||
sehir: "İstanbul",
|
||||
adres: "Karaköy Mah. Gümrük Sok. No:14, Beyoğlu / İstanbul",
|
||||
telefon: "0212 555 77 88",
|
||||
email: "ciao@siciliatavola.com",
|
||||
logoEmoji: "🍋",
|
||||
renkAna: "#0038A8",
|
||||
renkKoyu: "#002266",
|
||||
renkAcik: "#FDFBF7",
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "1892", etiket: "Sicilian Baking Roots" },
|
||||
{ deger: "100%", etiket: "Organic Cold Pressed Oil" },
|
||||
{ deger: "4.9", etiket: "Average Gastronomy Rating" },
|
||||
{ deger: "12k+", etiket: "Happy Diners Annually" },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "alacarte", baslik: "À la Carte Gastronomy", aciklama: "Odun ateşinde pişen taze makarnalar, taze deniz mahsulleri ve Sicilya klasikleri." },
|
||||
{ ikon: "special", baslik: "Trattoria Geceleri", aciklama: "Özel canlı akordeon dinletileri ve şefin tadım menüleri eşliğinde Sicilya akşamları." },
|
||||
{ ikon: "catering", baslik: "Zeytinyağı Tadımı", aciklama: "Kendi bahçelerimizden gelen %100 soğuk sıkım sızma zeytinyağlarımızı keşfedin." },
|
||||
{ ikon: "delivery", baslik: "Tavola Evinizde", aciklama: "Özel korumalı kuryelerimizle en taze gurme lezzetleri kapınıza getiriyoruz." },
|
||||
],
|
||||
menu: [
|
||||
{
|
||||
kategori: "Primi Piatti", ikon: "salad",
|
||||
urunler: [
|
||||
{ ad: "Caprese di Burrata", aciklama: "Manda burrata, pembe domates dilimleri, taze fesleğen ve zeytinyağı", fiyat: "₺280" },
|
||||
{ ad: "Carpaccio di Polpo", aciklama: "İnce dilimlenmiş marine ahtapot, kapari, bebek roka ve limon emülsiyonu", fiyat: "₺340" },
|
||||
{ ad: "Focaccia al Rosmarino", aciklama: "Taş fırından yeni çıkmış deniz tuzu, taze biberiye ve sızma zeytinyağlı", fiyat: "₺180" },
|
||||
],
|
||||
},
|
||||
{
|
||||
kategori: "Secondi", ikon: "steak",
|
||||
urunler: [
|
||||
{ ad: "Tagliatelle al Ragu di Polpo", aciklama: "Ağır ateşte pişmiş ahtapot ragu, taze el yapımı tagliatelle", fiyat: "₺460" },
|
||||
{ ad: "Pizza Margherita DOP", aciklama: "Odun ateşinde taş fırın pizza, San Marzano domates, taze mozzarella di bufala", fiyat: "₺380" },
|
||||
{ ad: "Polpo alla Griglia", aciklama: "Izgara ahtapot kolları, kapari, cherry domates ve ezilmiş sarımsaklı bebek patates", fiyat: "₺680" },
|
||||
],
|
||||
},
|
||||
{
|
||||
kategori: "Dolci", ikon: "dessert",
|
||||
urunler: [
|
||||
{ ad: "Cannoli Siciliani", aciklama: "Çıtır hamur tüpleri içinde tatlı ricotta kreması, çikolata parçacıkları ve Antep fıstığı", fiyat: "₺190" },
|
||||
{ ad: "Tiramisu al Limone", aciklama: "Limon likörlü hafif mascarpone kreması, taze limon kabuğu rendesi ile", fiyat: "₺210" },
|
||||
{ ad: "Gelato di Pistacchio", aciklama: "Kendi imalatımız gerçek Bronte Antep fıstıklı İtalyan dondurması", fiyat: "₺160" },
|
||||
],
|
||||
},
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "Ender M.", yorum: "Limon kokuları ve çalan müzikler eşliğinde kendimizi Sicilya'da hissettik. Ahtapot makarna tek kelimeyle kusursuzdu.", puan: 5, tarih: "3 gün önce", emoji: "🍋" },
|
||||
{ yazar: "Zeynep S.", yorum: "Focaccia ekmeği ve sızma zeytinyağının kalitesi buranın zanaatkarlığını kanıtlıyor. Mutlaka rezervasyon yaptırın.", puan: 5, tarih: "2 hafta önce", emoji: "✨" },
|
||||
],
|
||||
},
|
||||
"cabhub-nyc": {
|
||||
slug: "cabhub-nyc",
|
||||
template: "taxi",
|
||||
firma: {
|
||||
adi: "CabHub NYC",
|
||||
slogan: "Trusted & Premium Cab Services in New York",
|
||||
sehir: "New York",
|
||||
adres: "450 7th Ave, New York, NY 10123",
|
||||
telefon: "+1 234 567 8900",
|
||||
email: "booking@cabhubnyc.com",
|
||||
logoEmoji: "🚕",
|
||||
renkAna: "#F5C518",
|
||||
renkKoyu: "#0B0C0E",
|
||||
renkAcik: "#14161C",
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "Economy Class", etiket: "Within the city. We run services within the city to any destination you want to go. $1.5/MI" },
|
||||
{ deger: "Standard Class", etiket: "Within the state. We run services within the state to any destination you want to go. $1.5/MI" },
|
||||
{ deger: "Business Class", etiket: "Within the country. We run services within the country to any destination you want to go. $1.5/MI" },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "pickup", baslik: "HOME PICKUP", aciklama: "We run services to serve you more better and to your convenience." },
|
||||
{ ikon: "booking", baslik: "FAST BOOKING", aciklama: "Our book method is very fast and easy. It won't stress you." },
|
||||
{ ikon: "bonus", baslik: "BONUSES FOR RIDE", aciklama: "When you run services frequently we give you different bonuses that can put a smile on your face." },
|
||||
{ ikon: "gps", baslik: "GPS SEARCHING", aciklama: "We run services incase you aren't sure of your destination. So you don't have to worry." },
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "John Doe", yorum: "CabHub NYC provided the most reliable ride during my business trip. The standard class vehicle was pristine and the driver knew all the shortcuts.", puan: 5, tarih: "2 days ago", emoji: "⭐" },
|
||||
{ yazar: "Sarah Jenkins", yorum: "The fast booking system works like a charm. Home pickup was exactly on time and the GPS tracking made me feel incredibly secure.", puan: 5, tarih: "1 week ago", emoji: "⭐" }
|
||||
]
|
||||
},
|
||||
"cabhub-premium": {
|
||||
slug: "cabhub-premium",
|
||||
template: "taxi2",
|
||||
firma: {
|
||||
adi: "CabHub Premium",
|
||||
slogan: "Minimalist & Chic Airport Transfers in NYC",
|
||||
sehir: "New York",
|
||||
adres: "500 5th Ave, New York, NY 10110",
|
||||
telefon: "+1 800 555 0199",
|
||||
email: "premium@cabhub.com",
|
||||
logoEmoji: "⚡",
|
||||
renkAna: "#E5A900",
|
||||
renkKoyu: "#111317",
|
||||
renkAcik: "#FCFAF7",
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "Economy Class", etiket: "Chic city rides. Comfortable zero-emission trips to any destination within boroughs. $1.5/MI" },
|
||||
{ deger: "Standard Class", etiket: "Premium transfers. Verified luxury sedans covering tri-state airport hubs. $1.5/MI" },
|
||||
{ deger: "Business Class", etiket: "First class executive. Top-tier luxury vehicles with priority lane dispatch. $1.5/MI" },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "pickup", baslik: "LOUNGE PICKUP", aciklama: "Direct lounge or doorstep coordination for all airport coordinates." },
|
||||
{ ikon: "booking", baslik: "TAP RESERVATION", aciklama: "Ultra-fast smartphone booking client. Secure scheduling under 60 seconds." },
|
||||
{ ikon: "bonus", baslik: "MEMBER BENEFITS", aciklama: "Collect mileage dynamically. Redeem up to 40% savings on specialty trips." },
|
||||
{ ikon: "gps", baslik: "TRACKING GPS", aciklama: "Real-time satellite path tracking and automated flight delay syncing." },
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "Alexander Wright", yorum: "The airport transfer from JFK was absolutely seamless. The driver met me at the lounge gate and the electric vehicle was in pristine condition.", puan: 5, tarih: "3 days ago", emoji: "👤" },
|
||||
{ yazar: "Emily Vance", yorum: "CabHub Premium is my absolute go-to for corporate travel. The light theme app booking is simple and the delay syncing works perfectly.", puan: 5, tarih: "2 weeks ago", emoji: "👤" }
|
||||
]
|
||||
},
|
||||
"vaatbot-ai": {
|
||||
slug: "vaatbot-ai",
|
||||
template: "chatbot",
|
||||
firma: {
|
||||
adi: "VaatBot AI",
|
||||
slogan: "Supercharge Your Team with AI Conversations",
|
||||
sehir: "Istanbul",
|
||||
adres: "Levent Loft 1C, Buyukdere Cad. No:201, Sisli / Istanbul",
|
||||
telefon: "+90 212 999 5544",
|
||||
email: "hello@vaatbot.ai",
|
||||
logoEmoji: "🤖",
|
||||
renkAna: "#00E5FF",
|
||||
renkKoyu: "#080710",
|
||||
renkAcik: "#FF007A",
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "Accuracy 100%", etiket: "Trained directly on your database, docs, and custom web URLs to guarantee zero hallucination." },
|
||||
{ deger: "3x Faster Response", etiket: "Sub-second low-latency instant response times across Slack, WhatsApp, and Web widgets." },
|
||||
{ deger: "-20% Bounce Rate", etiket: "Keep visitors deeply engaged and double visitor-to-lead subscription conversions." },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "languages", baslik: "50+ Languages", aciklama: "Speaks your customer's native tongue fluently, spanning English, Spanish, Turkish, and more." },
|
||||
{ ikon: "customizer", baslik: "Brand Customizer", aciklama: "Tailor colors, names, avatars, and greetings to fully respect your corporate branding system." },
|
||||
{ ikon: "widgets", baslik: "Flexible Widget", aciklama: "Deploy in seconds using our clean copy-paste JS script tag or customizable iframe containers." },
|
||||
{ ikon: "industries", baslik: "Any Industry", aciklama: "Highly optimized for E-commerce, SaaS, Real Estate, Health Clinics, and Customer Support channels." },
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "Sahil Dobariya", yorum: "VaatBot transformed our customer feedback loop. We connected the AI widget in under 2 minutes, and it handles 80% of routine questions without any developer overhead.", puan: 5, tarih: "1 day ago", emoji: "⚡" },
|
||||
{ yazar: "Michael Vance", yorum: "The accuracy rate is astonishing. It indexes our Zendesk support articles and guides customers directly to links in real-time.", puan: 5, tarih: "1 week ago", emoji: "🤖" }
|
||||
]
|
||||
},
|
||||
"noir-velvet": {
|
||||
slug: "noir-velvet",
|
||||
template: "bar",
|
||||
firma: {
|
||||
adi: "Noir Velvet Lounge",
|
||||
slogan: "Cocktail Stage Evenings",
|
||||
sehir: "Istanbul",
|
||||
adres: "Karakoy Cad. No:88, Beyoglu / Istanbul",
|
||||
telefon: "+90 212 555 9090",
|
||||
email: "cheers@noirvelvet.com",
|
||||
logoEmoji: "🍸",
|
||||
renkAna: "#D4AF37",
|
||||
renkKoyu: "#0A0A0C",
|
||||
renkAcik: "#1C1C22",
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "Open Hours", etiket: "Weekday: 4:00 PM - 2:00 AM. Weekend: 4:00 PM - 4:00 AM." },
|
||||
{ deger: "Happy Hour", etiket: "Everyday: 5:00 PM - 8:00 PM. 20% off classic mixology cocktails." },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "signature", baslik: "Coco Spice", aciklama: "Spiced rum, pressed pineapple nectar, organic ginger syrup, grated nutmeg." },
|
||||
{ ikon: "signature", baslik: "Tequila Sunrise", aciklama: "Reposado tequila, fresh orange reduction, grenadine, lime wheel." },
|
||||
{ ikon: "signature", baslik: "Cuba Libre", aciklama: "Dark cask rum, fresh squeezed lime, house cola bitters." },
|
||||
{ ikon: "signature", baslik: "Gin Fizz", aciklama: "Botanical gin, fresh lemon juice, simple syrup, soda splash, egg white foam." },
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "David K.", yorum: "The cocktails are meticulously staged. A perfect moody obsidian lounge with jazz chords and exceptional botanical gin selections.", puan: 5, tarih: "3 days ago", emoji: "🍸" },
|
||||
{ yazar: "Elena R.", yorum: "We booked the VIP counter. Watching the mixologist mist the crystal glassware with citrus zest was an absolute work of art.", puan: 5, tarih: "1 week ago", emoji: "✨" }
|
||||
]
|
||||
},
|
||||
"char-barrelhouse": {
|
||||
slug: "char-barrelhouse",
|
||||
template: "bar2",
|
||||
firma: {
|
||||
adi: "Char Barrelhouse",
|
||||
slogan: "The Ultimate Craft & Spirit Experience",
|
||||
sehir: "Istanbul",
|
||||
adres: "Kadikoy Ritim Sok. No:19, Kadikoy / Istanbul",
|
||||
telefon: "+90 216 444 8822",
|
||||
email: "hello@charbarrel.com",
|
||||
logoEmoji: "🥃",
|
||||
renkAna: "#E63946",
|
||||
renkKoyu: "#111215",
|
||||
renkAcik: "#1E1F24",
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "Mojito", etiket: "Capacity: 350ml • Alcohol: 12% • Relax: 80% • Fresh white rum, crushed spearmint, lime juice." },
|
||||
{ deger: "Mai Tai", etiket: "Capacity: 280ml • Alcohol: 18% • Relax: 90% • Jamaican amber rum, orange curaçao, orgeat syrup." },
|
||||
{ deger: "Rum Cosmo", etiket: "Capacity: 200ml • Alcohol: 22% • Relax: 95% • Cask-aged dark rum, cranberry infusion, triple sec." },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "experience", baslik: "WHISKEY TASTINGS", aciklama: "Explore curated flights of single malt scotch, bourbon, and rye guided by certified sommeliers." },
|
||||
{ ikon: "experience", baslik: "MASTERCLASS MIXOLOGY", aciklama: "Step behind the heavy oak bar counter and craft signature historical formulas under expert tuition." },
|
||||
{ ikon: "experience", baslik: "VIP PRIVATE BOOKING", aciklama: "Reserve the entire rustic stone fireplace chamber for corporate launches or private bachelorettes." },
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "Marcus V.", yorum: "The heavy wooden barrels and charcoal smoke aroma set an outstanding vibe. The single malt tastings are second to none.", puan: 5, tarih: "2 days ago", emoji: "🥃" },
|
||||
{ yazar: "Sophia T.", yorum: "Outstanding Mai Tais! You can taste the quality of the raw Jamaican aged rum. We scheduled a private corporate masterclass.", puan: 5, tarih: "2 weeks ago", emoji: "⭐" }
|
||||
]
|
||||
},
|
||||
"cal-vestam-resort": {
|
||||
slug: "cal-vestam-resort",
|
||||
template: "hotel1",
|
||||
firma: {
|
||||
adi: "Cal Vestam Resort",
|
||||
slogan: "Cal Vestam Rehial Felgor",
|
||||
sehir: "Muğla",
|
||||
adres: "Ölüdeniz Mah. Akdeniz Bulvarı No:140, Fethiye / Muğla",
|
||||
telefon: "+90 252 666 4422",
|
||||
email: "stay@calvestam.com",
|
||||
logoEmoji: "🌴",
|
||||
renkAna: "#14B8A6",
|
||||
renkKoyu: "#0D9488",
|
||||
renkAcik: "#F0FDFA",
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "120+", etiket: "Signature Sea Suites" },
|
||||
{ deger: "3", etiket: "Panoramic Infinity Pools" },
|
||||
{ deger: "4.9", etiket: "Guest Experience Index" },
|
||||
{ deger: "100%", etiket: "Natural Olive Oil Soap & Spa" },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "pool", baslik: "INFINITY VESTAM POOL", aciklama: "Dive into our award-winning glass-edge infinity pools looking directly over Fethiye blue ridges." },
|
||||
{ ikon: "spa", baslik: "REHIAL SPA THERAPY", aciklama: "Indulge in organic olive leaf stone massages and mineral salt hydrotherapy curated by local experts." },
|
||||
{ ikon: "cuisine", baslik: "AL-FRESCO TERRACE DINING", aciklama: "Savor fresh garden ingredients and cold pressed citrus recipes under Mediterranean olive trees." },
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "Clara M.", yorum: "The infinity pools at Cal Vestam are absolutely magical. Watching the sunset while looking over the mountains of Muğla felt like a dream.", puan: 5, tarih: "3 days ago", emoji: "🌴" },
|
||||
{ yazar: "Tobias W.", yorum: "Clean, elegant, and filled with Mediterranean light. The local citrus cocktails and al-fresco terrace dining were exceptional.", puan: 5, tarih: "1 week ago", emoji: "✨" },
|
||||
],
|
||||
},
|
||||
"bitterroot-bunkhouse": {
|
||||
slug: "bitterroot-bunkhouse",
|
||||
template: "hotel2",
|
||||
firma: {
|
||||
adi: "Bitterroot Bunkhouse",
|
||||
slogan: "Book Your Cozy Wilderness Getaway Today",
|
||||
sehir: "Montana",
|
||||
adres: "Bitterroot Valley National Forest, Darby, MT 59829",
|
||||
telefon: "+1 406 555 0122",
|
||||
email: "cabin@bitterrootbunkhouse.com",
|
||||
logoEmoji: "🌲",
|
||||
renkAna: "#854D0E",
|
||||
renkKoyu: "#1C1917",
|
||||
renkAcik: "#F5F2EB",
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "A-Frame", etiket: "Rustic hand-crafted red cedar cabins situated deep in Darby forest." },
|
||||
{ deger: "Fireplace", etiket: "Organic stone hearth fireplaces stocked with seasoned birch logwood." },
|
||||
{ deger: "Wilderness", etiket: "Direct access to river trout fishing, forest trails, and kayak lakes." },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "hosts", baslik: "MEET YOUR HOSTS", aciklama: "Local mountain guides coordinate custom trout fishing trips, wildflower paths, and local map secrets." },
|
||||
{ ikon: "cabin", baslik: "CABIN POLICIES", aciklama: "Respectful pet-friendly lodge parameters. Stocked kitchens with cast iron skillets and firewood reserves." },
|
||||
{ ikon: "booking", baslik: "DIRECT RESERVATION", aciklama: "Direct calendar sync with Airbnb, VRBO, or secure bunkhouse booking triggers without commissions." },
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "Ethan R.", yorum: "The Bitterroot Bunkhouse is the ultimate mountain escape. The A-frame architecture combined with the stone fireplace was so cozy.", puan: 5, tarih: "4 days ago", emoji: "🔥" },
|
||||
{ yazar: "Sophia J.", yorum: "Waking up to the smell of pine trees and hot sourdough was incredible. The hosts were incredibly helpful with kayak trails.", puan: 5, tarih: "2 weeks ago", emoji: "🌲" },
|
||||
],
|
||||
},
|
||||
"apex-arc-hotel": {
|
||||
slug: "apex-arc-hotel",
|
||||
template: "hotel3",
|
||||
firma: {
|
||||
adi: "Apex Arc Estate",
|
||||
slogan: "Designing Spaces That Inspire & Endure",
|
||||
sehir: "Bodrum",
|
||||
adres: "Yalıkavak Yat Limanı Yolu No:8, Bodrum / Muğla",
|
||||
telefon: "+90 252 777 5533",
|
||||
email: "villas@apexarcestate.com",
|
||||
logoEmoji: "📐",
|
||||
renkAna: "#0F172A",
|
||||
renkKoyu: "#020617",
|
||||
renkAcik: "#F8FAFC",
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "Concrete", etiket: "Raw monolithic architectural concrete forms coupled with warm teak decking." },
|
||||
{ deger: "Smart Estate", etiket: "Fully integrated voice interfaces, automated ventilation, and solar grid reserves." },
|
||||
{ deger: "Sea View", etiket: "Cantilevered master chambers designed with absolute panoramic floor-to-ceiling glass." },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "arch", baslik: "ARCHITECTURAL TOURS", aciklama: "Private property walkthroughs showcasing carbon structures, raw concrete textures, and zero-edge pools." },
|
||||
{ ikon: "interior", baslik: "DESIGN MASTERCLASSES", aciklama: "Join our masterclasses on minimalist living, bespoke furniture layout, and sustainable concrete styling." },
|
||||
{ ikon: "vip", baslik: "EXECUTIVE LUXURY VILLA", aciklama: "Full estate buyouts with personal sommelier coordination, automated helipad dispatch, and high-security details." },
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "David V.", yorum: "An absolute masterpiece of modern architecture. The raw concrete lines and cantilevered ocean deck at Apex Arc took our breath away.", puan: 5, tarih: "5 days ago", emoji: "📐" },
|
||||
{ yazar: "Zoe K.", yorum: "Elegant, brutalist-inspired minimalism at its absolute finest. Floor-to-ceiling glass and smart automated automation worked flawlessly.", puan: 5, tarih: "3 weeks ago", emoji: "✨" },
|
||||
],
|
||||
},
|
||||
|
||||
// ── BODRUM CERRAHİ ────────────────────────────────────────────────────────
|
||||
"bodrum-cerrahi": {
|
||||
slug: "bodrum-cerrahi",
|
||||
template: "bodrumcerrahi",
|
||||
firma: {
|
||||
adi: "Bodrum Cerrahi",
|
||||
slogan: "Güven, Teknoloji, Sağlık",
|
||||
sehir: "Bodrum",
|
||||
adres: "Eskiçeşme Mah. Sadi Irmak Cad. No:17, Gümbet / Bodrum – Muğla",
|
||||
telefon: "+90 252 319 4800",
|
||||
email: "info@bodrumcerrahi.com",
|
||||
logoEmoji: "🏥",
|
||||
renkAna: "#1B6FA8",
|
||||
renkKoyu: "#0D3F65",
|
||||
renkAcik: "#EBF5FF",
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "15+", etiket: "Yıllık Deneyim" },
|
||||
{ deger: "12", etiket: "Uzman Hekim" },
|
||||
{ deger: "4.7", etiket: "Google Puanı" },
|
||||
{ deger: "7/24", etiket: "Acil Servis" },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "surgery", baslik: "Genel Cerrahi", aciklama: "Ameliyathane, yatan hasta servisi ve cerrahi operasyonlarında tam donanımlı hizmet." },
|
||||
{ ikon: "orthopedics", baslik: "Ortopedi ve Travmatoloji", aciklama: "Menüsküs yırtığı, kırık tedavisi ve eklem cerrahisi alanlarında uzman yaklaşım." },
|
||||
{ ikon: "pediatrics", baslik: "Çocuk Sağlığı", aciklama: "Pediatri alanında çocuk gelişimi takibi ve hastalık tedavisi hizmetleri." },
|
||||
{ ikon: "gynecology", baslik: "Kadın Hastalıkları", aciklama: "Jinekoloji, gebelik takibi ve kadın sağlığına özel poliklinik hizmetleri." },
|
||||
{ ikon: "neurology", baslik: "Nöroloji", aciklama: "Baş ağrısı, epilepsi ve nörolojik hastalıkların tanı ve tedavisi." },
|
||||
{ ikon: "laboratory", baslik: "Tıbbi Laboratuvar", aciklama: "Hızlı ve güvenilir tahlil sonuçlarıyla kapsamlı laboratuvar hizmetleri." },
|
||||
{ ikon: "radiology", baslik: "Radyoloji", aciklama: "MR, bilgisayarlı tomografi ve ultrason ile ileri görüntüleme." },
|
||||
{ ikon: "gastro", baslik: "Gastroenteroloji", aciklama: "Endoskopi, kolonoskopi ve sindirim sistemi hastalıklarında uzman tanı." },
|
||||
{ ikon: "dietitian", baslik: "Beslenme ve Diyet", aciklama: "Uzman diyetisyen eşliğinde kişiye özel beslenme programları." },
|
||||
],
|
||||
doktorlar: [
|
||||
{ ad: "Op. Dr. Erdal Kaleli", uzmanlik: "Genel Cerrah — Mesul Müdür", puan: "5.0", yil: "20", hasta: "3800", emoji: "👨⚕️" },
|
||||
{ ad: "Op. Dr. Murat Bozlar", uzmanlik: "Ortopedi ve Travmatoloji", puan: "4.9", yil: "15", hasta: "2200", emoji: "👨⚕️" },
|
||||
{ ad: "Dyt. Fulden Yürek", uzmanlik: "Beslenme ve Diyet", puan: "4.8", yil: "8", hasta: "1200", emoji: "👩⚕️" },
|
||||
{ ad: "Dr. Tatiana Arslan", uzmanlik: "Geleneksel ve Tamamlayıcı Tıp", puan: "4.9", yil: "12", hasta: "980", emoji: "👩⚕️" },
|
||||
{ ad: "Uzm. Dr. M. Hüsnücan İşgüven", uzmanlik: "Radyoloji", puan: "4.8", yil: "10", hasta: "1500", emoji: "👨⚕️" },
|
||||
{ ad: "Y. Doç. Dr. Hikmet Kerem Çağlayan", uzmanlik: "Anestezi ve Reanimasyon", puan: "5.0", yil: "14", hasta: "2100", emoji: "👨⚕️" },
|
||||
{ ad: "Uzm. Dr. Suat Kahraman", uzmanlik: "İç Hastalıkları — Dahiliye", puan: "4.9", yil: "11", hasta: "1800", emoji: "👨⚕️" },
|
||||
{ ad: "Uzm. Dr. İrfan Güler", uzmanlik: "Anestezi ve Reanimasyon", puan: "4.7", yil: "9", hasta: "1100", emoji: "👨⚕️" },
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "Aylin K.", yorum: "Bodrum'da bu kalitede bir özel hastane bulmak gerçekten şaşırtıcı. Doktorlar çok ilgili, ameliyat süreci çok iyi yönetildi. Kesinlikle tavsiye ederim.", puan: 5, tarih: "2 hafta önce", emoji: "😊" },
|
||||
{ yazar: "Michael T.", yorum: "As a foreign patient I was amazed by the level of English spoken at the international desk. The orthopedic team was exceptional.", puan: 5, tarih: "1 ay önce", emoji: "🙂" },
|
||||
{ yazar: "Hasan B.", yorum: "Acil servise gece geldiğimizde anında ilgilendiler. 7/24 hizmet verdiklerini bu gece deneyimledim. Çok teşekkürler.", puan: 5, tarih: "3 hafta önce", emoji: "😄" },
|
||||
{ yazar: "Claudia R.", yorum: "The radiology department had state-of-the-art equipment and results came within the hour. Highly professional staff throughout.", puan: 5, tarih: "2 ay önce", emoji: "👍" },
|
||||
],
|
||||
},
|
||||
|
||||
// ── ZENITH AI CHATBOT ───────────────────────────────────────────────────
|
||||
"zenith-ai": {
|
||||
slug: "zenith-ai",
|
||||
template: "chatbot2",
|
||||
firma: {
|
||||
adi: "Zenith AI",
|
||||
slogan: "Next-Generation Conversational Intelligence",
|
||||
sehir: "Istanbul",
|
||||
adres: "Kanyon Office Tower 12B, Buyukdere Cad. No:185, Sisli / Istanbul",
|
||||
telefon: "+90 212 888 7755",
|
||||
email: "hello@zenithai.com",
|
||||
logoEmoji: "🧬",
|
||||
renkAna: "#8B5CF6", // Premium Purple accent
|
||||
renkKoyu: "#09090B", // Dark neutral
|
||||
renkAcik: "#F4F4F5", // Neutral warm grey
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "99.4%", etiket: "Doğruluk oranıyla halüsinasyonsuz AI konuşmaları garanti edilir." },
|
||||
{ deger: "240ms", etiket: "Yanıt gecikmesiyle Slack, WhatsApp ve web widget'larında anında cevaplar." },
|
||||
{ deger: "4.8x", etiket: "Müşteri etkileşimi ve dönüşüm oranlarında kanıtlanmış artış." },
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "brain", baslik: "Akıllı Semantik İndeksleme", aciklama: "Notion, Zendesk, PDF'ler ve tüm web URL'lerinizi otomatik olarak analiz ederek markanızın kendi bilgi tabanını oluşturur." },
|
||||
{ ikon: "channel", baslik: "Çoklu Kanal Entegrasyonu", aciklama: "Web siteniz, Slack, WhatsApp, Telegram ve Discord kanallarınızda saniyeler içinde yayına alın." },
|
||||
{ ikon: "brand", baslik: "Kurumsal Özelleştirme", aciklama: "Renklerinizi, avatarınızı, bot isminizi ve tonunu kurumsal kimliğinize göre tamamen uyarlayın." },
|
||||
{ ikon: "sync", baslik: "Anlık Bilgi Senkronizasyonu", aciklama: "Web siteniz güncellendiğinde veya yeni dökümanlar yüklendiğinde, Zenith AI bilgiyi anında senkronize eder." },
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "Alican Y.", yorum: "Kendi dökümanlarımızla eğitmemiz sadece 1 dakika sürdü. Dönüşüm oranlarımız %35 arttı.", puan: 5, tarih: "3 gün önce", emoji: "⚡" },
|
||||
{ yazar: "Sarah Mitchell", yorum: "The API integration is lightning-fast and the customer workspace matches our corporate branding flawlessly.", puan: 5, tarih: "2 hafta önce", emoji: "🤖" },
|
||||
]
|
||||
},
|
||||
};
|
||||
|
||||
export function getDemoBySlug(slug: string): DemoData | null {
|
||||
return demos[slug] ?? null;
|
||||
}
|
||||
@@ -0,0 +1,416 @@
|
||||
# Şablon Tasarım Rehberi
|
||||
### Ayris Tech — Premium Demo Sistemi
|
||||
|
||||
---
|
||||
|
||||
## Görevin
|
||||
|
||||
Potansiyel müşterilere gönderilecek demo siteleri için sektöre özel Next.js şablonları yazıyorsun.
|
||||
|
||||
Öncelik sırası: **1. Tasarım ve his → 2. Animasyon → 3. İçerik → 4. Teknik detaylar**
|
||||
|
||||
Müşteri linke tıkladığında ilk 3 saniyede "bu benim için yapılmış, bu çok pahalı görünüyor" hissini yaşamalı. Kod çalışıyor mu çalışmıyor mu ikinci plandır — önce göz kamaştır.
|
||||
|
||||
---
|
||||
|
||||
## Tasarım Felsefesi
|
||||
|
||||
### "Oha" Anı Zorunludur
|
||||
|
||||
Her şablonun sayfaya girince insanı duraksatan **bir imza momenti** olmalı. Bu an tasarlanmış, hesaplanmış, sektöre özgün olmalı. Genel bir animasyon değil — o sektörün ruhunu yansıtan bir hareket.
|
||||
|
||||
Referans seviye: **Awwwards Site of the Day**. Hedef his: "Bu siteyi kim yaptı, nasıl yaptı?"
|
||||
|
||||
### Tasarım Kararlarında Öncelik Sırası
|
||||
|
||||
```
|
||||
1. Boşluk ve nefes — section'lar arası ritim, padding cömertliği
|
||||
2. Tipografi gücü — başlıklar cesur ve büyük, hiyerarşi net
|
||||
3. Fotoğraf kalitesi — her fotoğraf kompozisyon düşünülerek seçilmeli
|
||||
4. Renk disiplini — max 2-3 renk, geri kalanı siyah/beyaz/gri
|
||||
5. Hareket kalitesi — az animasyon ama her biri mükemmel
|
||||
6. Detay titizliği — hover state'ler, geçişler, micro-interaction'lar
|
||||
```
|
||||
|
||||
### Nasıl Düşünmeli
|
||||
|
||||
Görseller verildiğinde şunu sor: **"Bu tasarımı 10.000 USD'ye satan ajans ne hissettirdi?"**
|
||||
|
||||
- Boşlukla mı ezdi? (luxury whitespace)
|
||||
- Tipografiyle mi şok etti? (devasa başlık, küçük body)
|
||||
- Fotoğrafla mı sardı? (fullscreen, parallax, overlay)
|
||||
- Hareketle mi büyüledi? (curtain, reveal, magnetic)
|
||||
- Detayla mı ikna etti? (custom cursor, subtle grain, line animation)
|
||||
|
||||
Cevap hangisi ise — oradan başla, diğerlerini o etrafına kur.
|
||||
|
||||
---
|
||||
|
||||
## İmza Moment Kütüphanesi
|
||||
|
||||
Her şablona aşağıdakilerden **en az bir** tane koy. Birden fazla koyacaksan aralarına yeterli "sessizlik" bırak.
|
||||
|
||||
### Sayfa Açılışı
|
||||
- **Curtain reveal** — siyah ekran ortadan ikiye ayrılır, fotoğraf ortaya çıkar
|
||||
- **Preloader çizgi** — ince bir çizgi soldan sağa ilerler, logo belirir, sahne açılır
|
||||
- **Staggered text entrance** — başlık kelime kelime veya karakter karakter düşer
|
||||
- **Scale-up reveal** — küçük merkezi bir görsel tam ekrana açılır
|
||||
|
||||
### Scroll Animasyonları
|
||||
- **Parallax hero** — scroll ettikçe fotoğraf daha yavaş iner, metin daha hızlı çıkar
|
||||
- **Sticky + akan metin** — fotoğraf sabit kalır, metin onun üzerinden akar
|
||||
- **Horizontal scroll bölüm** — kartlar/menü yatay ilerler, mouse/touch ile sürüklenir
|
||||
- **Pinned section** — section scroll boyunca sabit kalır, içeriği değişir (tablar gibi)
|
||||
- **Text scale on scroll** — başlık küçükten büyüğe veya büyükten küçüğe dönüşür
|
||||
|
||||
### Hover & Mikro
|
||||
- **Magnetic buton** — mouse yaklaştıkça buton sana doğru çekilir
|
||||
- **Custom cursor** — varsayılan cursor kaybolur, markaya özgü daire/metin gelir
|
||||
- **Image tilt** — kart hover'ında 3D perspektif eğimi (rotateX/Y)
|
||||
- **Clip-path reveal** — fotoğraf hover'da yukarıdan aşağı açılır
|
||||
- **Underline draw** — link hover'ında çizgi soldan sağa çizilir
|
||||
|
||||
### Atmosfer
|
||||
- **Scrolling marquee** — sonsuz döngü metin bandı (iki yönde farklı hızda olursa daha iyi)
|
||||
- **Grain texture overlay** — tüm sayfa üstünde ince film grain (opacity 0.03-0.06)
|
||||
- **Ambient glow** — arka planda renk blobları yavaşça hareket eder
|
||||
- **Video loop** — hero'da sessiz, döngü video (restoran, otel için)
|
||||
|
||||
---
|
||||
|
||||
## Tipografi Kuralları
|
||||
|
||||
Pahalı hissinin %40'ı tipografiden gelir.
|
||||
|
||||
```
|
||||
Başlık boyutu: clamp(48px, 8vw, 120px) — küçük ekranda küçülür, büyük ekranda büyür
|
||||
Body boyutu: 16px minimum, 18px ideal
|
||||
Satır yüksekliği: başlıklarda 0.9-1.0, body'de 1.6-1.8
|
||||
Harf aralığı: büyük harf başlıklarda tracking-widest, serif başlıklarda -0.02em
|
||||
```
|
||||
|
||||
**Font kombinasyonları (sektöre göre):**
|
||||
- Otel/Butik/Restoran → Playfair Display (serif) + Inter (sans) — klasik lüks
|
||||
- Mimari/Kurumsal → Inter Black + Inter Regular — modern güç
|
||||
- Bar/Gastro → Cormorant Garamond + Space Grotesk — sofistike
|
||||
- Klinik/SaaS → DM Sans veya Sora + monospace detay — temiz güven
|
||||
|
||||
Başlık tek satırda yoksa **satır kırılmalarını elle kontrol et** — otomatik kırılma çirkin görünür.
|
||||
|
||||
---
|
||||
|
||||
## Renk ve Atmosfer Kuralları
|
||||
|
||||
### Koyu Tema (restoran, bar, otel, gastro)
|
||||
- Arka plan: `#080810` veya `#0a0a0a` — tam siyah değil, hafif tonlu
|
||||
- Metin: `#ffffff` + `rgba(255,255,255,0.5)` ikincil
|
||||
- Aksant: firmanın ana rengi — sadece CTA, badge, vurgu için
|
||||
- Fotoğraflar üstünde: `rgba(0,0,0,0.3-0.5)` overlay — direkt koymadan
|
||||
|
||||
### Açık Tema (klinik, mimari, kurumsal, butik)
|
||||
- Arka plan: `#ffffff` veya `#f8f7f4` (hafif warm) veya `#f5f0e8` (krem)
|
||||
- Metin: `#0a0a0a` veya `#1a1a1a`
|
||||
- Aksant: firmanın ana rengi
|
||||
- İkincil yüzeyler: `#f0f0f0` veya `rgba(0,0,0,0.04)`
|
||||
|
||||
### Renk Disiplini
|
||||
- Ana renk: butonlar, başlık vurgusu, badge, aktif state
|
||||
- İkincil renk: hover state, border, gradient ikinci noktası
|
||||
- Nötr: arka planlar, kartlar, ayırıcılar
|
||||
- **Başka renk yok.** Emoji veya ikonlar nötr tutulur.
|
||||
|
||||
---
|
||||
|
||||
## Fotoğraf Kullanımı
|
||||
|
||||
Fotoğraflar kod kadar önemli. Kötü fotoğraf iyi tasarımı mahveder.
|
||||
|
||||
**Unsplash koleksiyonları (sektöre göre):**
|
||||
- Otel/Resort: `https://source.unsplash.com/1920x1080/?luxury,hotel,resort`
|
||||
- Restoran: `https://source.unsplash.com/1920x1080/?restaurant,food,gastronomy`
|
||||
- Bar: `https://source.unsplash.com/1920x1080/?cocktail,bar,dark`
|
||||
- Mimari: `https://source.unsplash.com/1920x1080/?architecture,interior,modern`
|
||||
- Klinik: `https://source.unsplash.com/1920x1080/?clinic,medical,clean`
|
||||
|
||||
**Kurallar:**
|
||||
- Hero fotoğrafı her zaman `object-cover` + `object-position: center`
|
||||
- Dikey fotoğraflar (portrait) kart içinde daha dramatik görünür — kullan
|
||||
- Birden fazla fotoğraf varsa renk tonu tutarlı olsun (hepsi sıcak veya hepsi soğuk)
|
||||
- `picsum.photos` sadece hızlı test için — final görünümde Unsplash parametreli URL kullan
|
||||
|
||||
---
|
||||
|
||||
## Animasyon Kalitesi
|
||||
|
||||
### Easing Değerleri
|
||||
```typescript
|
||||
// Smooth deceleration — genel kullanım
|
||||
ease: [0.25, 0.46, 0.45, 0.94] as [number,number,number,number]
|
||||
|
||||
// Dramatic entrance — hero başlıklar
|
||||
ease: [0.16, 1, 0.3, 1] as [number,number,number,number]
|
||||
|
||||
// Snappy — buton, badge, küçük elementler
|
||||
ease: [0.34, 1.56, 0.64, 1] as [number,number,number,number]
|
||||
|
||||
// Linear — marquee, döngüler
|
||||
ease: "linear"
|
||||
```
|
||||
|
||||
### Süre Kuralları
|
||||
```
|
||||
Micro (hover, badge): 0.15-0.25s
|
||||
Element entrance: 0.6-0.8s
|
||||
Section transition: 0.8-1.0s
|
||||
Page reveal / curtain: 1.0-1.4s
|
||||
Marquee döngü: 20-40s (içerik uzunluğuna göre)
|
||||
```
|
||||
|
||||
### Stagger Ritmi
|
||||
```typescript
|
||||
// Çocuk sayısına göre stagger ayarla
|
||||
3-4 element: staggerChildren: 0.15
|
||||
5-8 element: staggerChildren: 0.08
|
||||
9+ element: staggerChildren: 0.05
|
||||
```
|
||||
|
||||
### Animasyon Monotonluğu Kırma
|
||||
Her section aynı `fadeUp` ile başlarsa sayfa uyutur. Karıştır:
|
||||
- Hero: curtain veya scale reveal
|
||||
- Stats: sayaç animasyonu (AnimatedCounter)
|
||||
- Kartlar: stagger + hafif x offset (soldan veya sağdan)
|
||||
- Galeri: clip-path veya opacity-only (y hareketi olmadan)
|
||||
- CTA section: parallax arka plan + metin fade
|
||||
|
||||
---
|
||||
|
||||
## Lenis Smooth Scroll Kurulumu
|
||||
|
||||
Her şablona ekle:
|
||||
|
||||
```typescript
|
||||
"use client";
|
||||
import { useEffect } from "react";
|
||||
|
||||
// Component içinde:
|
||||
useEffect(() => {
|
||||
let lenis: any;
|
||||
import("@studio-freight/lenis").then(({ default: Lenis }) => {
|
||||
lenis = new Lenis({ duration: 1.2, easing: (t: number) => Math.min(1, 1.001 - Math.pow(2, -10 * t)) });
|
||||
function raf(time: number) { lenis.raf(time); requestAnimationFrame(raf); }
|
||||
requestAnimationFrame(raf);
|
||||
});
|
||||
return () => lenis?.destroy();
|
||||
}, []);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Section Tasarım Standartları
|
||||
|
||||
### Hero
|
||||
- Her zaman viewport yüksekliği: `min-h-screen`
|
||||
- Fotoğraf varsa: `position: absolute, inset: 0, object-fit: cover` + koyu overlay
|
||||
- Başlık: clamp ile responsive, viewport'un %60-70'ini kaplamalı
|
||||
- CTA buton: tek, net, aksant renkli — ikinci buton varsa ghost/outline
|
||||
|
||||
### Marquee Bandı (opsiyonel ama etkili)
|
||||
Hero ile sonraki section arasına koy. İki yönde farklı iki satır daha güçlü görünür.
|
||||
|
||||
### İki Kolonlu (Split) Section
|
||||
```
|
||||
Sol: metin + CTA Sağ: tall fotoğraf (aspect-ratio: 3/4)
|
||||
Metin sola hizalı Fotoğraf slight overlap (negatif margin)
|
||||
```
|
||||
|
||||
### Kart Grid'leri
|
||||
- 3'lü grid: her kart eşit, hover'da `y: -8` ve border glow
|
||||
- Masonry: sadece galeri için — CSS columns veya css-grid ile
|
||||
- Horizontal scroll: `overflow-x: auto`, `scrollbar-width: none`, touch-action: pan-x
|
||||
|
||||
### CTA Section (Son Bölüm)
|
||||
En az bir kez tam genişlikte, fotoğraf arka planlı olsun. Başlık büyük, CTA tek.
|
||||
|
||||
---
|
||||
|
||||
## Tech Stack
|
||||
|
||||
```json
|
||||
{
|
||||
"zorunlu": [
|
||||
"Next.js 14 App Router",
|
||||
"Framer Motion v11",
|
||||
"Tailwind CSS v3",
|
||||
"TypeScript strict",
|
||||
"@studio-freight/lenis"
|
||||
],
|
||||
"gerektiğinde": [
|
||||
"Three.js / @react-three/fiber (sadece ambient bg için, performans dikkat)",
|
||||
"react-lottie-player (loading, boş state ikonları için)",
|
||||
"usehooks-ts (useWindowSize, useIntersectionObserver)"
|
||||
],
|
||||
"yasak": [
|
||||
"jQuery",
|
||||
"Bootstrap",
|
||||
"CSS @keyframes animasyonları (Framer Motion kullan)",
|
||||
"inline style ile animasyon (transform, opacity — Framer Motion kullan)"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Framer Motion zorunlu kurallar:**
|
||||
- `ease` array'leri her zaman type assertion: `as [number,number,number,number]`
|
||||
- Scroll animasyonları: `useScroll` + `useTransform`
|
||||
- Section girişleri: `whileInView` + `viewport={{ once: true }}`
|
||||
- Layout animasyonları: `layout` prop — yükseklik değişimlerinde kullan
|
||||
|
||||
---
|
||||
|
||||
## Kalite Kontrol Listesi
|
||||
|
||||
Kodu teslim etmeden önce şunları kontrol et:
|
||||
|
||||
**Tasarım:**
|
||||
- [ ] Sayfaya girince ilk 3 saniyede "oha" dedirten bir şey var mı?
|
||||
- [ ] Boşluklar cömert mi — hiçbir element birbirine yapışık değil mi?
|
||||
- [ ] Başlıklar yeterince büyük mü — yarım metre uzaktan okunabilir mi?
|
||||
- [ ] Renk disiplini korunuyor mu — max 3 renk var mı?
|
||||
- [ ] Fotoğraflar kompozisyon olarak uygun mu?
|
||||
|
||||
**Animasyon:**
|
||||
- [ ] Her section farklı animasyon mu kullanıyor (monotonluk yok)?
|
||||
- [ ] Easing değerleri sert mi yoksa yumuşak mı? (Sert olmamalı)
|
||||
- [ ] Lenis smooth scroll çalışıyor mu?
|
||||
- [ ] Hover state'lerin hepsi var mı?
|
||||
|
||||
**Detay:**
|
||||
- [ ] Demo banner sabit mi: `"Bu site demo amaçlıdır — demo.ayristech.com"`
|
||||
- [ ] Mobile'da layout bozulmuyor mu?
|
||||
- [ ] TypeScript hataları var mı (`any` yok)?
|
||||
|
||||
---
|
||||
|
||||
## Proje Yapısı
|
||||
|
||||
```
|
||||
demo-ayristech/
|
||||
├── app/
|
||||
│ ├── page.tsx # Showcase index
|
||||
│ └── [slug]/page.tsx # Dynamic routing
|
||||
├── components/
|
||||
│ └── templates/
|
||||
│ └── [SektörTemplate]/
|
||||
│ └── index.tsx # Her şablon kendi klasöründe
|
||||
├── data/
|
||||
│ └── demos.ts # Tüm demo verisi
|
||||
└── components/ui/
|
||||
└── AnimatedCounter.tsx # Scroll-triggered sayaç
|
||||
```
|
||||
|
||||
Yeni şablon eklerken:
|
||||
1. `components/templates/YeniTemplate/index.tsx` oluştur
|
||||
2. `data/demos.ts` interface'ine yeni sektör tipini ve alanları ekle
|
||||
3. `app/[slug]/page.tsx` routing'e `if (data.template === "yeni") return <YeniTemplate data={data} />;`
|
||||
4. `app/page.tsx` `templateLabels`'a yeni badge ekle
|
||||
|
||||
---
|
||||
|
||||
## Müşteri Sitesi SS Analizi
|
||||
|
||||
Sana müşterinin mevcut sitesinin ekran görüntüleri verildiğinde şu sırayla ilerle:
|
||||
|
||||
### 1. İçerik Çıkarımı
|
||||
|
||||
Her SS'den şunları çıkar:
|
||||
|
||||
| Alan | Nereden Bulunur |
|
||||
|---|---|
|
||||
| Firma adı | Header, logo yanı, title |
|
||||
| Slogan | Hero başlığı veya alt metin |
|
||||
| Şehir / Adres | Footer, iletişim sayfası |
|
||||
| Telefon | Header, footer, iletişim |
|
||||
| E-posta | Footer, iletişim sayfası |
|
||||
| Çalışma saatleri | Footer veya iletişim |
|
||||
| Hizmetler | Hizmetler/servisler/poliklinikler sayfası |
|
||||
| Ekip / Doktorlar | Kadro/hakkımızda sayfası |
|
||||
| Yorumlar / Referanslar | Varsa ana sayfa veya ayrı sayfa |
|
||||
| Sosyal medya | Footer veya header ikonları |
|
||||
|
||||
### 2. Mevcut Tasarımı Değerlendir
|
||||
|
||||
SS'lere bakarak kısaca not al:
|
||||
- **Renk paleti:** Mevcut ana renk nedir?
|
||||
- **Genel his:** Profesyonel mi, eski mi, amatör mü?
|
||||
- **Eksikler:** Animasyon yok, mobile bozuk, fotoğraf kalitesi kötü vb.
|
||||
- **Güçlü yanlar:** Korunabilecek bir şey var mı?
|
||||
|
||||
Bu değerlendirmeyi şablona yansıt — mevcut siteyi taklit etme, **dönüştür**.
|
||||
|
||||
### 3. demos.ts Formatında Çıkar
|
||||
|
||||
Analiz sonucunu aşağıdaki formatta hazırla, eksik alanları makul şekilde doldur:
|
||||
|
||||
```typescript
|
||||
{
|
||||
slug: "firma-adi", // firma adından türet, küçük harf, tire ile
|
||||
template: "klinik", // sektöre göre seç
|
||||
firma: {
|
||||
adi: "Firma Adı",
|
||||
slogan: "SS'den alınan slogan veya uygun bir slogan üret",
|
||||
sehir: "Şehir",
|
||||
adres: "Tam adres",
|
||||
telefon: "+90 ...",
|
||||
email: "info@...",
|
||||
logoEmoji: "🏥", // sektöre uygun emoji
|
||||
renkAna: "#______", // mevcut sitenin ana rengi
|
||||
renkKoyu: "#______", // daha koyu tonu
|
||||
renkAcik: "#______", // çok açık tonu (bg için)
|
||||
},
|
||||
istatistikler: [
|
||||
{ deger: "15+", etiket: "Yıllık Deneyim" },
|
||||
// SS'de rakam varsa al, yoksa sektöre uygun üret
|
||||
],
|
||||
hizmetler: [
|
||||
{ ikon: "🔬", baslik: "Hizmet Adı", aciklama: "Kısa açıklama" },
|
||||
// SS'deki hizmetler sayfasından çek
|
||||
],
|
||||
yorumlar: [
|
||||
{ yazar: "Ad Soyad", yorum: "...", puan: 5, tarih: "2024", emoji: "👤" },
|
||||
// SS'de yoksa 3 adet gerçekçi yorum üret
|
||||
],
|
||||
// Sektöre özel alanlar — SS'den çek, yoksa üret
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Şablon Seçimi
|
||||
|
||||
Sektöre göre hangi şablonun kullanılacağına karar ver:
|
||||
|
||||
| Sektör | Şablon |
|
||||
|---|---|
|
||||
| Klinik, hastane, sağlık merkezi | `klinik` |
|
||||
| Diş kliniği, estetik | `dental` |
|
||||
| Restoran, kafe, bistro | `restoran` veya `restoran2` |
|
||||
| Bar, meyhane, gece kulübü | `bar` veya `bar2` |
|
||||
| Otel, resort, apart | `hotel1`, `hotel2` veya `hotel3` |
|
||||
| Taksi, transfer, ulaşım | `taxi` veya `taxi2` |
|
||||
| Yazılım, SaaS, chatbot | `chatbot` |
|
||||
| İnşaat, mimarlık, kurumsal | `kurumsal` |
|
||||
|
||||
Mevcut şablonlardan hiçbiri uygun değilse: **yeni şablon yaz** — TEMPLATE_BRIEF'teki tasarım kurallarına uyarak.
|
||||
|
||||
### 5. Antigravity'e Ver
|
||||
|
||||
Analiz tamamlandığında şunu söyle:
|
||||
|
||||
> "Bu `demos.ts` verisini kullan. TEMPLATE_BRIEF.md'deki kurallara göre `[ŞabonAdı]` şablonunu yaz. Mevcut sitenin renk paletini koru ama tasarımı tamamen modernize et. İmza moment olarak `[seçilen imza moment]` kullan."
|
||||
|
||||
---
|
||||
|
||||
## Son Not
|
||||
|
||||
Amaç: müşteriye link atıp "bak, senin için yaptım" diyebilmek.
|
||||
|
||||
**Standart değil, özel. Güzel değil, etkileyici. Çalışıyor değil, hissettiriyor.**
|
||||
|
||||
Eğer şablona baktığında "bu idare eder" diyorsan — yeniden başla.
|
||||
|
After Width: | Height: | Size: 376 KiB |
|
After Width: | Height: | Size: 212 KiB |
|
After Width: | Height: | Size: 339 KiB |
|
After Width: | Height: | Size: 590 KiB |
|
After Width: | Height: | Size: 277 KiB |
|
After Width: | Height: | Size: 500 KiB |
|
After Width: | Height: | Size: 596 KiB |
|
After Width: | Height: | Size: 378 KiB |
@@ -0,0 +1,246 @@
|
||||
{
|
||||
"name": "Partner Sheets → Analiz → PostgreSQL",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"rule": {
|
||||
"interval": [
|
||||
{
|
||||
"field": "cronExpression",
|
||||
"expression": "0 9 * * *"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "n8n-nodes-base.scheduleTrigger",
|
||||
"typeVersion": 1.2,
|
||||
"position": [0, 0],
|
||||
"id": "aaa00001-0000-0000-0000-000000000001",
|
||||
"name": "Her Gün Saat 09:00"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"operation": "getAll",
|
||||
"documentId": {
|
||||
"__rl": true,
|
||||
"value": "SHEETS_DOCUMENT_ID",
|
||||
"mode": "id"
|
||||
},
|
||||
"sheetName": {
|
||||
"__rl": true,
|
||||
"value": "Sheet1",
|
||||
"mode": "name"
|
||||
},
|
||||
"returnAll": true,
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.googleSheets",
|
||||
"typeVersion": 4.5,
|
||||
"position": [240, 0],
|
||||
"id": "aaa00002-0000-0000-0000-000000000002",
|
||||
"name": "Sheets - Tüm Satırları Çek",
|
||||
"credentials": {
|
||||
"googleSheetsOAuth2Api": {
|
||||
"id": "SHEETS_CREDENTIAL_ID",
|
||||
"name": "Google Sheets account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Sadece completed = FALSE veya boş olanları döndür\nconst rows = $input.all();\nconst pending = rows.filter(item => {\n const completed = String(item.json.completed || '').toUpperCase();\n return completed !== 'TRUE' && completed !== 'TAMAMLANDI' && completed !== '1';\n});\n\nif (pending.length === 0) {\n // İşlenecek satır yok\n return [];\n}\n\nreturn pending;"
|
||||
},
|
||||
"id": "aaa00003-0000-0000-0000-000000000003",
|
||||
"name": "Bekleyenleri Filtrele",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [480, 0]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.splitInBatches",
|
||||
"typeVersion": 3,
|
||||
"position": [720, 0],
|
||||
"id": "aaa00004-0000-0000-0000-000000000004",
|
||||
"name": "Loop Over Items"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"modelId": {
|
||||
"__rl": true,
|
||||
"value": "models/gemini-2.5-flash",
|
||||
"mode": "list",
|
||||
"cachedResultName": "models/gemini-2.5-flash"
|
||||
},
|
||||
"messages": {
|
||||
"values": [
|
||||
{
|
||||
"content": "={{ $json.domain }}\n\nSen bir full-stack yazılım ve teknoloji şirketinin admin paneli için veri otomasyon asistanısın. Görevin, şirketin web sitesi tasarımı veya yazılım hizmeti sunduğu partner firmaların (müşterilerin) web sitelerini analiz etmek ve bunları \"Partnerler\" sayfasındaki grid yapısına uygun şekilde JSON formatına dönüştürmektir.\n\nSana gönderilen web sitesi adresini analiz et ve YALNIZCA aşağıdaki JSON formatında çıktı ver. JSON dışında hiçbir açıklama, markdown kodu (```json vb.) veya ön söz/son söz ekleme.\n\n### ÇIKTI FORMATI:\n{\n \"partner_ismi\": \"Firma adı (örn: MUĞLA SÜRÜCÜ KURSU)\",\n \"monogram\": \"Firmanın baş harflerinden oluşan 3 harfli büyük harf kombinasyonu (örn: MSK)\",\n \"kategori\": \"Yazılım şirketinin o firmaya sunduğu hizmet odağı. Tek veya iki kelime, dikkat çekici, teknolojik alt başlık (Örn: TEKNOLOJİ, WEB3 ALTYAPISI, TEDARİK ZİNCİRİ, KÜRESEL ÖDEMELER, GERÇEK ZAMANLI VERİ, HEADLESS WEB)\",\n \"aciklama\": \"Yazılım şirketinin bu partner ile olan teknolojik ortaklığını, sağladığı altyapıyı veya geliştirdiği çözümü anlatan, kurumsal, havalı ve 'ortaklığa' vurgu yapan tek cümlelik tanım.\"\n}\n\n### KURALLAR:\n1. \"partner_ismi\" kısmında firmanın resmi veya jenerik tam adını yaz.\n2. \"monogram\" her zaman 3 harfli ve tamamen BÜYÜK harf olmalı.\n3. \"kategori\" firmanın kendi sektörü DEĞİL, yazılımcı olarak senin ona dokunduğun teknolojik dikey olmalı.\n4. \"aciklama\" cümlesi kesinlikle profesyonel, ajans dilinde olmalı.\n5. \"yil\" alanı EKLEME — sistem otomatik ekleyecek.\n6. Çıktıda temiz JSON dışında hiçbir şey bulunmamalıdır."
|
||||
}
|
||||
]
|
||||
},
|
||||
"builtInTools": {},
|
||||
"options": {}
|
||||
},
|
||||
"type": "@n8n/n8n-nodes-langchain.googleGemini",
|
||||
"typeVersion": 1.1,
|
||||
"position": [960, 0],
|
||||
"id": "aaa00005-0000-0000-0000-000000000005",
|
||||
"name": "Gemini Analiz",
|
||||
"credentials": {
|
||||
"googlePalmApi": {
|
||||
"id": "Bu5nSnIxNY3DvfGa",
|
||||
"name": "n8nautomation"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "const input = $input.first().json;\n\nconst raw = input.text \n || input.content?.parts?.[0]?.text \n || (typeof input.content === 'string' ? input.content : '')\n || '';\n\nconst cleaned = String(raw).replace(/```json/g, '').replace(/```/g, '').trim();\n\nlet parsed;\ntry {\n parsed = JSON.parse(cleaned);\n} catch(e) {\n const domain = $('Loop Over Items').item.json.domain || '';\n parsed = {\n partner_ismi: domain,\n monogram: domain.replace(/https?:\\/\\//, '').substring(0, 3).toUpperCase(),\n kategori: 'Diğer',\n aciklama: 'Otomatik analiz başarısız oldu.'\n };\n}\n\n// Yılı her zaman sistem üzerinden al — Gemini'ye bırakma\nparsed.yil = new Date().getFullYear().toString();\n\n// Row number'ı da taşı (Sheets güncellemesi için)\nparsed._rowNumber = $('Loop Over Items').item.json.row_number \n || $('Loop Over Items').item.json._rowNumber\n || null;\n\nreturn [{ json: parsed }];"
|
||||
},
|
||||
"id": "aaa00006-0000-0000-0000-000000000006",
|
||||
"name": "Parse JSON",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [1200, 0]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"schema": {
|
||||
"__rl": true,
|
||||
"mode": "list",
|
||||
"value": "public"
|
||||
},
|
||||
"table": {
|
||||
"__rl": true,
|
||||
"value": "Partner",
|
||||
"mode": "list",
|
||||
"cachedResultName": "Partner"
|
||||
},
|
||||
"columns": {
|
||||
"mappingMode": "defineBelow",
|
||||
"value": {
|
||||
"name": "={{ $json.partner_ismi }}",
|
||||
"desc": "={{ $json.aciklama }}",
|
||||
"mono": "={{ $json.monogram }}",
|
||||
"tag": "={{ $json.kategori }}",
|
||||
"year": "={{ $json.yil }}"
|
||||
},
|
||||
"matchingColumns": ["id"],
|
||||
"schema": [
|
||||
{ "id": "id", "displayName": "id", "required": false, "defaultMatch": true, "display": true, "type": "number", "canBeUsedToMatch": true, "removed": true },
|
||||
{ "id": "name", "displayName": "name", "required": true, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true },
|
||||
{ "id": "tag", "displayName": "tag", "required": true, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true },
|
||||
{ "id": "mono", "displayName": "mono", "required": true, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true },
|
||||
{ "id": "year", "displayName": "year", "required": true, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true },
|
||||
{ "id": "desc", "displayName": "desc", "required": true, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }
|
||||
],
|
||||
"attemptToConvertTypes": false,
|
||||
"convertFieldsToString": false
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.postgres",
|
||||
"typeVersion": 2.6,
|
||||
"position": [1440, 0],
|
||||
"id": "aaa00007-0000-0000-0000-000000000007",
|
||||
"name": "PostgreSQL Insert",
|
||||
"credentials": {
|
||||
"postgres": {
|
||||
"id": "T6YReSQ3PnkNwvnZ",
|
||||
"name": "AyrisTech"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"operation": "update",
|
||||
"documentId": {
|
||||
"__rl": true,
|
||||
"value": "SHEETS_DOCUMENT_ID",
|
||||
"mode": "id"
|
||||
},
|
||||
"sheetName": {
|
||||
"__rl": true,
|
||||
"value": "Sheet1",
|
||||
"mode": "name"
|
||||
},
|
||||
"columns": {
|
||||
"mappingMode": "defineBelow",
|
||||
"value": {
|
||||
"completed": "TRUE"
|
||||
},
|
||||
"matchingColumns": ["domain"],
|
||||
"schema": [
|
||||
{ "id": "domain", "displayName": "domain", "required": false, "defaultMatch": true, "display": true, "type": "string", "canBeUsedToMatch": true },
|
||||
{ "id": "completed", "displayName": "completed", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": false }
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.googleSheets",
|
||||
"typeVersion": 4.5,
|
||||
"position": [1680, 0],
|
||||
"id": "aaa00008-0000-0000-0000-000000000008",
|
||||
"name": "Sheets - Completed Yap",
|
||||
"credentials": {
|
||||
"googleSheetsOAuth2Api": {
|
||||
"id": "SHEETS_CREDENTIAL_ID",
|
||||
"name": "Google Sheets account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.noOp",
|
||||
"typeVersion": 1,
|
||||
"position": [1680, -200],
|
||||
"id": "aaa00009-0000-0000-0000-000000000009",
|
||||
"name": "İşlenecek kayıt yok"
|
||||
}
|
||||
],
|
||||
"pinData": {},
|
||||
"connections": {
|
||||
"Her Gün Saat 09:00": {
|
||||
"main": [[{ "node": "Sheets - Tüm Satırları Çek", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"Sheets - Tüm Satırları Çek": {
|
||||
"main": [[{ "node": "Bekleyenleri Filtrele", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"Bekleyenleri Filtrele": {
|
||||
"main": [[{ "node": "Loop Over Items", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"Loop Over Items": {
|
||||
"main": [
|
||||
[{ "node": "İşlenecek kayıt yok", "type": "main", "index": 0 }],
|
||||
[{ "node": "Gemini Analiz", "type": "main", "index": 0 }]
|
||||
]
|
||||
},
|
||||
"Gemini Analiz": {
|
||||
"main": [[{ "node": "Parse JSON", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"Parse JSON": {
|
||||
"main": [[{ "node": "PostgreSQL Insert", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"PostgreSQL Insert": {
|
||||
"main": [[{ "node": "Sheets - Completed Yap", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"Sheets - Completed Yap": {
|
||||
"main": [[{ "node": "Loop Over Items", "type": "main", "index": 0 }]]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1",
|
||||
"binaryMode": "separate",
|
||||
"availableInMCP": false
|
||||
},
|
||||
"meta": {
|
||||
"templateCredsSetupCompleted": true,
|
||||
"instanceId": "79d13d1a6fcae5c2e451a2b02247a15904071a685f973aa3c0464bf9f4cd5f82"
|
||||
},
|
||||
"id": "triMzeBHtCmmToakgy6Ri",
|
||||
"tags": []
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
{
|
||||
"name": "Site Scraper → Screenshot → Partner Analiz",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [240, 300],
|
||||
"id": "10cf88d5-0df8-4b39-ba6b-5507bc5cfeb0",
|
||||
"name": "When clicking 'Execute workflow'"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "domain-field",
|
||||
"name": "domain",
|
||||
"value": "muglasurucukursu.com",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "90ed9042-f1e0-4b75-a986-06d266974b9a",
|
||||
"name": "Set Domain",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"position": [480, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "http://sbq038z8y8yb8z4s2whet0q0.65.109.236.58.sslip.io/scrape",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "x-api-key",
|
||||
"value": "AyrisScraperSecr3tKey2026"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"url\": \"https://{{ $json.domain }}\"\n}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "d19cc658-e65e-489e-b23c-ea02a23a9b94",
|
||||
"name": "Link Scraper API",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.1,
|
||||
"position": [720, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "folder",
|
||||
"name": "={{ $('Set Domain').first().json.domain }}",
|
||||
"driveId": {
|
||||
"__rl": true,
|
||||
"mode": "list",
|
||||
"value": "My Drive"
|
||||
},
|
||||
"folderId": {
|
||||
"__rl": true,
|
||||
"value": "1jNcMOUaTZmi7SJIF4xShGjEvEymENDZ0",
|
||||
"mode": "list",
|
||||
"cachedResultName": "WebSiteScrenShots",
|
||||
"cachedResultUrl": "https://drive.google.com/drive/folders/1jNcMOUaTZmi7SJIF4xShGjEvEymENDZ0"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.googleDrive",
|
||||
"typeVersion": 3,
|
||||
"position": [960, 300],
|
||||
"id": "e0fb79cd-8adc-449a-b0de-800e3451e5f2",
|
||||
"name": "Create Folder",
|
||||
"credentials": {
|
||||
"googleDriveOAuth2Api": {
|
||||
"id": "UobQnjEvaIAp1tOm",
|
||||
"name": "Google Drive account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "const links = $('Link Scraper API').first().json.links || [];\nconst folderId = $('Create Folder').first().json.id;\n\nreturn links.slice(0, 10).map(l => ({\n json: {\n label: l.label,\n url: l.url,\n folderId: folderId\n }\n}));"
|
||||
},
|
||||
"id": "8e0dea68-2437-416b-b963-ab1d1f97eca1",
|
||||
"name": "Prepare URLs",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [1200, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.splitInBatches",
|
||||
"typeVersion": 3,
|
||||
"position": [1440, 300],
|
||||
"id": "daf4a716-92bf-497d-b017-bdca05485a9f",
|
||||
"name": "Loop Over Items"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "https://api.screencapr.com/api/screenshot",
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"url\": \"{{ $('Prepare URLs').first().json.url }}\",\n \"options\": {\n \"width\": 1440,\n \"height\": 900,\n \"format\": \"jpeg\",\n \"quality\": 85,\n \"fullPage\": true,\n \"timeout\": 30000\n }\n}",
|
||||
"options": {
|
||||
"response": {
|
||||
"response": {
|
||||
"responseFormat": "file",
|
||||
"outputPropertyName": "screenshot"
|
||||
}
|
||||
},
|
||||
"timeout": 60000
|
||||
}
|
||||
},
|
||||
"id": "ce61f453-59da-4592-8bf3-ff269debb57f",
|
||||
"name": "ScreenCapr Screenshot",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.1,
|
||||
"position": [1680, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"inputDataFieldName": "screenshot",
|
||||
"name": "={{ $('Loop Over Items').item.json.label }}.jpg",
|
||||
"driveId": {
|
||||
"__rl": true,
|
||||
"mode": "list",
|
||||
"value": "My Drive"
|
||||
},
|
||||
"folderId": {
|
||||
"__rl": true,
|
||||
"value": "={{ $('Loop Over Items').item.json.folderId }}",
|
||||
"mode": "id"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.googleDrive",
|
||||
"typeVersion": 3,
|
||||
"position": [1920, 300],
|
||||
"id": "8b087127-57f8-430e-b3d2-8a66c57561fa",
|
||||
"name": "Upload to Drive",
|
||||
"credentials": {
|
||||
"googleDriveOAuth2Api": {
|
||||
"id": "UobQnjEvaIAp1tOm",
|
||||
"name": "Google Drive account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "file",
|
||||
"operation": "list",
|
||||
"driveId": {
|
||||
"__rl": true,
|
||||
"mode": "list",
|
||||
"value": "My Drive"
|
||||
},
|
||||
"folderId": {
|
||||
"__rl": true,
|
||||
"value": "={{ $('Create Folder').first().json.id }}",
|
||||
"mode": "id"
|
||||
},
|
||||
"returnAll": false,
|
||||
"limit": 2,
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.googleDrive",
|
||||
"typeVersion": 3,
|
||||
"position": [1680, 80],
|
||||
"id": "f1a23456-0001-4abc-8def-111111111111",
|
||||
"name": "List Drive Files",
|
||||
"credentials": {
|
||||
"googleDriveOAuth2Api": {
|
||||
"id": "UobQnjEvaIAp1tOm",
|
||||
"name": "Google Drive account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Sadece ilk dosyayı al\nreturn [$input.first()];"
|
||||
},
|
||||
"id": "f2b34567-0002-4abc-8def-222222222222",
|
||||
"name": "Get First File",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [1920, 80]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "file",
|
||||
"operation": "download",
|
||||
"fileId": {
|
||||
"__rl": true,
|
||||
"value": "={{ $json.id }}",
|
||||
"mode": "id"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.googleDrive",
|
||||
"typeVersion": 3,
|
||||
"position": [2160, 80],
|
||||
"id": "f3c45678-0003-4abc-8def-333333333333",
|
||||
"name": "Download Screenshot",
|
||||
"credentials": {
|
||||
"googleDriveOAuth2Api": {
|
||||
"id": "UobQnjEvaIAp1tOm",
|
||||
"name": "Google Drive account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "image",
|
||||
"operation": "analyze",
|
||||
"modelId": {
|
||||
"__rl": true,
|
||||
"value": "models/gemini-2.5-flash",
|
||||
"mode": "list",
|
||||
"cachedResultName": "models/gemini-2.5-flash"
|
||||
},
|
||||
"text": "Bu web sitesi ekran görüntüsünü analiz et ve aşağıdaki JSON formatında döndür. Sadece JSON döndür, başka açıklama ekleme:\n\n{\n \"partner_ismi\": \"Firmanın tam adı\",\n \"monogram\": \"2-3 harfli kısaltma (örn: AYR, SCC)\",\n \"kategori\": \"Tek kelime sektör (Sağlık, Enerji, Restoran, Eğitim, Ulaşım, İnşaat, Teknoloji vb.)\",\n \"aciklama\": \"Firmayı anlatan 1-2 cümle\"\n}",
|
||||
"inputType": "binary",
|
||||
"options": {}
|
||||
},
|
||||
"type": "@n8n/n8n-nodes-langchain.googleGemini",
|
||||
"typeVersion": 1.1,
|
||||
"position": [2400, 80],
|
||||
"id": "f4d56789-0004-4abc-8def-444444444444",
|
||||
"name": "Gemini Analiz",
|
||||
"credentials": {
|
||||
"googlePalmApi": {
|
||||
"id": "Bu5nSnIxNY3DvfGa",
|
||||
"name": "n8nautomation"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "const raw = $input.first().json.text || $input.first().json.content || '';\n\n// JSON bloğunu temizle\nconst cleaned = raw.replace(/```json/g, '').replace(/```/g, '').trim();\n\nlet parsed;\ntry {\n parsed = JSON.parse(cleaned);\n} catch(e) {\n // JSON parse başarısız olursa fallback\n parsed = {\n partner_ismi: $('Set Domain').first().json.domain,\n monogram: $('Set Domain').first().json.domain.substring(0, 3).toUpperCase(),\n kategori: 'Diğer',\n aciklama: 'Otomatik analiz başarısız oldu.'\n };\n}\n\nreturn [{ json: parsed }];"
|
||||
},
|
||||
"id": "f5e67890-0005-4abc-8def-555555555555",
|
||||
"name": "Parse JSON",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [2640, 80]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"operation": "insert",
|
||||
"schema": {
|
||||
"__rl": true,
|
||||
"mode": "list",
|
||||
"value": "public"
|
||||
},
|
||||
"table": {
|
||||
"__rl": true,
|
||||
"mode": "list",
|
||||
"value": "partners"
|
||||
},
|
||||
"columns": {
|
||||
"mappingMode": "defineBelow",
|
||||
"value": {
|
||||
"name": "={{ $json.partner_ismi }}",
|
||||
"monogram": "={{ $json.monogram }}",
|
||||
"category": "={{ $json.kategori }}",
|
||||
"bio": "={{ $json.aciklama }}",
|
||||
"start_year": 2026,
|
||||
"domain": "={{ $('Set Domain').first().json.domain }}"
|
||||
}
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.postgres",
|
||||
"typeVersion": 2.5,
|
||||
"position": [2880, 80],
|
||||
"id": "f6f78901-0006-4abc-8def-666666666666",
|
||||
"name": "PostgreSQL Insert",
|
||||
"credentials": {
|
||||
"postgres": {
|
||||
"id": "POSTGRES_CREDENTIAL_ID",
|
||||
"name": "Postgres account"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"pinData": {},
|
||||
"connections": {
|
||||
"When clicking 'Execute workflow'": {
|
||||
"main": [[{ "node": "Set Domain", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"Set Domain": {
|
||||
"main": [[{ "node": "Link Scraper API", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"Link Scraper API": {
|
||||
"main": [[{ "node": "Create Folder", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"Create Folder": {
|
||||
"main": [[{ "node": "Prepare URLs", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"Prepare URLs": {
|
||||
"main": [[{ "node": "Loop Over Items", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"Loop Over Items": {
|
||||
"main": [
|
||||
[{ "node": "List Drive Files", "type": "main", "index": 0 }],
|
||||
[{ "node": "ScreenCapr Screenshot", "type": "main", "index": 0 }]
|
||||
]
|
||||
},
|
||||
"ScreenCapr Screenshot": {
|
||||
"main": [[{ "node": "Upload to Drive", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"Upload to Drive": {
|
||||
"main": [[{ "node": "Loop Over Items", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"List Drive Files": {
|
||||
"main": [[{ "node": "Get First File", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"Get First File": {
|
||||
"main": [[{ "node": "Download Screenshot", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"Download Screenshot": {
|
||||
"main": [[{ "node": "Gemini Analiz", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"Gemini Analiz": {
|
||||
"main": [[{ "node": "Parse JSON", "type": "main", "index": 0 }]]
|
||||
},
|
||||
"Parse JSON": {
|
||||
"main": [[{ "node": "PostgreSQL Insert", "type": "main", "index": 0 }]]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1",
|
||||
"binaryMode": "separate",
|
||||
"availableInMCP": false
|
||||
},
|
||||
"meta": {
|
||||
"templateCredsSetupCompleted": true,
|
||||
"instanceId": "79d13d1a6fcae5c2e451a2b02247a15904071a685f973aa3c0464bf9f4cd5f82"
|
||||
},
|
||||
"id": "UDHv1qTfRRi1Q-Vqt47m1",
|
||||
"tags": []
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
output: "standalone", // Dockerfile için gerekli
|
||||
images: {
|
||||
remotePatterns: [],
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "demo-ayristech",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@studio-freight/lenis": "^1.0.42",
|
||||
"framer-motion": "^12.40.0",
|
||||
"next": "16.2.6",
|
||||
"react": "19.2.4",
|
||||
"react-dom": "19.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"description": "This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).",
|
||||
"main": "index.js",
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
const config = {
|
||||
plugins: {
|
||||
"@tailwindcss/postcss": {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 661 KiB |
|
After Width: | Height: | Size: 723 KiB |
|
After Width: | Height: | Size: 760 KiB |
|
After Width: | Height: | Size: 973 KiB |
|
After Width: | Height: | Size: 819 KiB |
|
After Width: | Height: | Size: 783 KiB |
|
After Width: | Height: | Size: 582 KiB |
|
After Width: | Height: | Size: 646 KiB |
@@ -0,0 +1 @@
|
||||
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 391 B |
@@ -0,0 +1 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 844 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 802 KiB |
|
After Width: | Height: | Size: 612 KiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 927 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 889 KiB |
|
After Width: | Height: | Size: 616 KiB |
@@ -0,0 +1 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 128 B |
@@ -0,0 +1 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||
|
After Width: | Height: | Size: 385 B |
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
".next/dev/types/**/*.ts",
|
||||
"**/*.mts"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||