Commit aeca9efa authored by Mahmoud Aglan's avatar Mahmoud Aglan

Add marketing site (Next.js 16 + Tailwind + Framer Motion)

Arabic-first landing page with pricing, features, about, and contact pages.
Includes business model docs and infrastructure capacity planning.
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 0d159f8c
# 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
<!-- BEGIN:nextjs-agent-rules -->
# This is NOT the Next.js you know
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
<!-- END:nextjs-agent-rules -->
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).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "base-nova",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"rtl": false,
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"menuColor": "default",
"menuAccent": "subtle",
"registries": {}
}
# El Captain — Marketing Website
Premium marketing site for the El Captain Sports Management SaaS platform.
## Concept
**"The Command Center"** — A clean, authoritative marketing site that sells control and clarity to Egyptian sports academy owners. The site demonstrates the product's power through interactive dashboard mockups, scroll-driven animations, and confident Arabic-first copy.
## Design Direction
- **Emotion:** Power & Control
- **Visual:** Clean & Trustworthy (Stripe-level clarity)
- **Audience:** Academy owners/directors in Egypt
- **Language:** Arabic-first (RTL), English toggle
## Stack
| Layer | Tech |
|-------|------|
| Framework | Next.js 14 (App Router) |
| Styling | Tailwind CSS 3.4 |
| Components | shadcn/ui (branded) |
| Animation | Framer Motion 11 |
| Icons | Lucide React |
| Fonts | Cairo (AR) + Inter (EN) |
| Deploy | Vercel |
## Documentation
| Document | Purpose |
|----------|---------|
| [Brand Guidelines](docs/brand-guidelines.md) | Colors, typography, voice, imagery rules |
| [Design System](docs/design-system.md) | Tokens, Tailwind config, component specs |
| [Site Specification](docs/site-specification.md) | Pages, SEO, performance, i18n, deploy |
| [Messaging Framework](docs/messaging-framework.md) | Copy strategy, elevator pitches, objection handling |
| [UX Strategy](docs/ux-strategy.md) | User journey, conversion, accessibility |
| [Animation Spec](docs/animation-spec.md) | Framer Motion variants, timing, scroll orchestration |
| [Wireframes](docs/wireframes.md) | ASCII layout wireframes (desktop + mobile) |
| [Implementation Plan](docs/implementation-plan.md) | Phased build schedule + decisions needed |
## Quick Start
```bash
# When ready to build:
npx create-next-app@latest . --typescript --tailwind --app --src-dir
npm install framer-motion lucide-react class-variance-authority clsx tailwind-merge
npx shadcn-ui@latest init
npm run dev
```
## Key Design Decisions
1. **No stock photos** — Product screenshots and geometric illustrations only
2. **No video autoplay** — Respects bandwidth (Egyptian mobile networks)
3. **Numbers as heroes** — Stats count up on scroll (builds credibility)
4. **WhatsApp floating** — Egyptian users expect instant messaging access
5. **Progressive disclosure** — Show 6 modules on homepage, full 14 on features page
6. **Scroll as narrative** — Problem → Solution → Proof → Action flow
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# El Captain Marketing Site — Implementation Plan
## Phase 1: Foundation (Week 1)
### Setup
- [ ] Initialize Next.js 14 with App Router + TypeScript
- [ ] Configure Tailwind with custom theme (design tokens)
- [ ] Set up Cairo + Inter fonts via next/font
- [ ] Configure i18n routing (ar/en with ar as default)
- [ ] Install: framer-motion, lucide-react, shadcn/ui
- [ ] Set up RTL layout wrapper
- [ ] Create base components: Button, Card, Container, Section
### Layout
- [ ] Build Navbar (sticky, glass effect, RTL)
- [ ] Build Footer
- [ ] Build MobileMenu (slide overlay)
- [ ] Build LanguageToggle component
- [ ] Create AnimateOnScroll wrapper component
- [ ] Create CountUpNumber component
---
## Phase 2: Homepage (Week 2-3)
### Sections (in order)
- [ ] Hero section (headline + dashboard mockup + stats bar)
- [ ] Problem → Solution scroll transition
- [ ] Module Showcase (6 cards grid)
- [ ] Feature Deep-Dive #1: Financial Command
- [ ] Feature Deep-Dive #2: Smart Enrollment
- [ ] Feature Deep-Dive #3: Attendance Intelligence
- [ ] Testimonials carousel
- [ ] Stats section (counting numbers)
- [ ] CTA section (dark gradient)
### Content
- [ ] Write all Arabic copy (from messaging framework)
- [ ] Create dashboard mockup images (screenshot from real app)
- [ ] Design 6 module icons (SVG, outlined)
- [ ] Create feature section mockups (3 screenshots)
---
## Phase 3: Secondary Pages (Week 3-4)
- [ ] Features page (14 module detail cards)
- [ ] Pricing page (3-tier cards + FAQ accordion)
- [ ] About page (mission + values + team placeholder)
- [ ] Contact page (form + calendar embed)
- [ ] 404 page (branded)
---
## Phase 4: Polish & Performance (Week 4-5)
- [ ] All animations tuned and tested
- [ ] Responsive testing (320px → 2560px)
- [ ] RTL testing thoroughness
- [ ] Performance optimization (< 2.5s LCP)
- [ ] SEO: meta tags, OG images, structured data
- [ ] Accessibility audit (axe-core, VoiceOver)
- [ ] Cross-browser testing (Chrome, Safari, Firefox, Samsung Internet)
- [ ] Form backend connection (demo request → email/CRM)
- [ ] WhatsApp floating button integration
- [ ] Analytics setup (Plausible or PostHog)
---
## Phase 5: Launch (Week 5-6)
- [ ] Domain setup (DNS → Vercel)
- [ ] Final content review (Arabic proofreading)
- [ ] Lighthouse scores all green (90+ across board)
- [ ] Social sharing preview correct (OG images)
- [ ] Google Search Console submission
- [ ] Launch announcement prep
---
## Dependencies & Decisions Still Needed
| Decision | Options | Impact |
|----------|---------|--------|
| Domain name | elcaptain.com / elcaptain.app / elcaptain.io | SEO, branding |
| Pricing numbers | Final EGP amounts per tier | Pricing page content |
| Testimonials | Need 3-5 real quotes from existing users | Social proof section |
| Demo booking tool | Cal.com / Calendly / custom | Contact page |
| Analytics | Plausible (simple) / PostHog (powerful) | Privacy vs. features |
| Blog (phase 2) | MDX in repo / Sanity CMS / Contentlayer | Content workflow |
| Logo | Need final designed logo files | Header, favicon, OG |
---
## Quick Start Commands
```bash
cd marketing-site
# Initialize (when ready to code)
npx create-next-app@latest . --typescript --tailwind --app --src-dir
npm install framer-motion lucide-react class-variance-authority clsx tailwind-merge
npx shadcn-ui@latest init
# Development
npm run dev # localhost:3000
npm run build # Production build
npm run lint # ESLint
npm run lighthouse # Performance audit
```
This diff is collapsed.
# El Captain — Messaging Framework
## Core Statements
### Mission
We build the command center for sports organizations — giving academy owners total operational control so they can focus on developing athletes, not managing spreadsheets.
### Vision
A world where every sports academy in the Arab region operates with the precision, intelligence, and professionalism of an elite club.
### Value Proposition
For **sports academy owners** who struggle with scattered operations, manual tracking, and financial blind spots —
**El Captain** is the all-in-one management platform that puts every player, every pound, and every session under one command center.
Unlike generic ERPs, scattered Excel sheets, or WhatsApp groups,
**we're purpose-built for how sports academies actually work** — from the first enrollment to graduation.
### Positioning Statement
El Captain is the sports operations platform for academy directors who demand complete visibility and control, built by people who understand the Egyptian sports business from the inside.
---
## Message Architecture
### Primary Message
**"كل شيء تحت إدارتك"** — Everything under your command.
One platform gives you total operational control: financial clarity, player tracking, attendance automation, and real-time performance data.
### Supporting Messages
| # | Message | Audience Need | Proof Point |
|---|---------|---------------|-------------|
| 1 | **تحكم مالي كامل** — Track every pound from enrollment to report | Financial visibility | Double-entry accounting, real-time dashboards |
| 2 | **صفر ورق، صفر فوضى** — Replace papers, WhatsApp, and Excel chaos | Operational efficiency | Automated enrollment, attendance, billing |
| 3 | **مصمم للرياضة** — Not a generic tool adapted, built for academies | Domain fit | Sports-specific workflows, Arabic-first |
| 4 | **ينمو معك** — Start with 50 players or 5000, same power | Scalability | Multi-branch, unlimited modules, API |
| 5 | **كل لاعب، كل تفصيلة** — Complete player lifecycle management | Data completeness | Enrollment → attendance → billing → graduation |
---
## Elevator Pitches
### 10 Seconds (Arabic)
> الكابتن هو منصة إدارة متكاملة للأكاديميات الرياضية — كل شيء من التسجيل للحضور للمالية في مكان واحد.
### 10 Seconds (English)
> El Captain is an all-in-one management platform for sports academies — enrollment, attendance, and finance in one place.
### 30 Seconds (Arabic)
> لو بتدير أكاديمية رياضية وزهقت من الإكسيل والورق والواتساب — الكابتن يحل المشكلة دي.
> منصة واحدة فيها تسجيل اللاعبين، الحضور الآلي، المالية، نقاط البيع، والتقارير.
> مصممة خصيصاً للأكاديميات الرياضية المصرية. ٤٧ أكاديمية شغالة عليها دلوقتي.
### 60 Seconds (Arabic)
> تخيل إنك تفتح تطبيق واحد وتشوف: كام لاعب حاضر النهاردة، كام جنيه دخل، مين متأخر في الدفع، وأي مجموعة محتاجة مدرب بديل.
>
> الكابتن بيديك كل ده — من غير ورق، من غير واتساب، من غير إكسيل.
>
> المنصة فيها: تسجيل لاعبين ذكي، حضور آلي بتنبيهات، نظام مالي بالقرش، نقاط بيع، مخزون، وتقارير لحظية.
>
> الفرق بيننا وبين أي نظام تاني: إحنا مصممين للأكاديمية الرياضية من الأول. مش نظام عام حد عدّله. كل تفصيلة — من الاشتراك الشهري لنظام التسعير للحضور — مبنية على فهم حقيقي لشغل الأكاديمية.
>
> ٤٧ أكاديمية بتدير عملياتها عبر المنصة. جرب مجاناً ١٤ يوم.
---
## Message by Audience Segment
| Audience | Pain Point | Key Message | CTA |
|----------|------------|-------------|-----|
| Academy Owner | "I don't know my real numbers" | تحكم مالي كامل — شوف أرقامك الحقيقية لحظياً | احجز عرض |
| Operations Manager | "I'm drowning in manual work" | وفر ٨٠% من الشغل اليدوي مع أتمتة ذكية | ابدأ تجربة مجانية |
| Head Trainer | "Attendance tracking is chaos" | حضور آلي — بتنبيهات فورية وتقارير أسبوعية | شوف المميزات |
| Accountant | "Reconciliation is a nightmare" | نظام محاسبي بالقرش — قيد مزدوج تلقائي | اطلب عرض |
| Parent (future) | "I never know what's happening with my child" | تابع ابنك — حضور، تقييم، ومواعيد | حمّل التطبيق |
---
## Objection Handling
| Objection | Response |
|-----------|----------|
| "Excel شغال معايا" | Excel مش بيتابع الحضور، مش بيبعت تنبيهات، ومش بيقفل الورديات. الكابتن بيعمل اللي الإكسيل مش قادر عليه. |
| "أنا أكاديميتي صغيرة" | الباقة الأساسية مصممة لحد ٢٠٠ لاعب. لما تكبر، المنصة تكبر معاك — من غير ما تغير نظامك. |
| "أنظمة ERP غالية ومعقدة" | إحنا مش ERP عام. مش هتحتاج مستشار يشتغل ٣ شهور. تبدأ في يوم واحد وتشتغل بكرة. |
| "فريقي مش بيتعامل مع تكنولوجيا" | الواجهة عربي ١٠٠% وبسيطة. المدرب مش محتاج غير يضغط "حاضر" بدل ما يكتب في ورقة. |
| "بياناتي أمان؟" | سيرفرات أوروبية، تشفير كامل، ونسخ احتياطي يومي. بياناتك ملكك وبس. |
---
## Content Tone Examples
### Headlines (Commanding, Short)
- ✅ كل شيء تحت إدارتك
- ✅ تحكم. تتبع. تنمو.
- ✅ أكاديميتك تستحق أفضل
- ✅ من الفوضى للنظام في يوم
- ❌ أفضل نظام إدارة أكاديميات في مصر!! (too salesy, exclamation)
- ❌ هل تعاني من إدارة أكاديميتك؟ (question-based, weak)
### Feature Descriptions (Clear, Benefit-First)
- ✅ تتبع كل جنيه من لحظة الدفع حتى التقرير الشهري
- ✅ حضور آلي — يسجل اللاعب ويبلغك عن الغياب فوراً
- ❌ نظام حضور متطور يستخدم أحدث التقنيات (vague, doesn't say what it does)
- ❌ إدارة مالية شاملة ومتكاملة (means nothing specific)
### CTAs (Direct, No Fluff)
- ✅ ابدأ مجاناً
- ✅ احجز عرض تجريبي
- ✅ شوف المميزات
- ✅ تحدث مع فريقنا
- ❌ اكتشف المزيد الآن! (vague + exclamation)
- ❌ لا تفوت الفرصة (fear-based, prohibited)
---
## Competitive Positioning
### vs. Excel / Google Sheets
"Excel doesn't send absence alerts. Doesn't auto-generate invoices. Doesn't track who owes what. El Captain does all that — and you set it up in a day, not a month."
### vs. WhatsApp Groups
"WhatsApp is for chatting, not for running a business. When you need to find who paid last month, or which trainer was absent Tuesday — good luck searching 4,000 messages."
### vs. Generic ERP (Odoo, etc.)
"Generic ERPs need months of customization and a consultant. El Captain is ready for sports academies out of the box — training groups, attendance, enrollment, pricing rules — all built in."
### vs. Competitor Academy Apps
"Most 'academy apps' are just attendance trackers with a payment reminder. El Captain is the full business: double-entry finance, POS, inventory, facility scheduling, smart pricing — the complete operations platform."
This diff is collapsed.
# El Captain Marketing Site — UX Strategy
## User Journey Map
### Primary Persona: Academy Owner / Director
- **Name:** أحمد (Ahmed), 38
- **Role:** Owns/runs a mid-size sports academy (200-500 players)
- **Tech level:** Uses smartphone daily, comfortable with apps, not a developer
- **Current tools:** Excel + WhatsApp + paper receipts + maybe a basic accounting app
- **Pain:** Doesn't know real-time numbers, spends evenings reconciling, trainers forget attendance
- **Goal:** Run a professional operation without being chained to paperwork
### Journey Stages
```
Awareness → Interest → Evaluation → Decision → Onboarding
↓ ↓ ↓ ↓ ↓
Google/ Landing Features/ Pricing Demo/
Referral Page Demo Video Page Trial
```
---
## Page-by-Page UX Flows
### Homepage Flow (120 seconds target dwell time)
```
[0-3s] Hero catches attention — bold Arabic headline + dashboard visual
[3-8s] Scans stats bar — social proof numbers build trust
[8-15s] Scrolls — problem statement resonates ("أنا كده!")
[15-25s] Sees solution transition — "ok this solves MY problem"
[25-45s] Module cards — understands breadth without reading details
[45-70s] Feature spotlight — sees actual product depth (1 of 3 resonates)
[70-90s] Testimonial — someone like them validates the choice
[90-110s] Stats section — scale/trust reinforced
[110-120s] CTA section — ready to act (demo or trial)
```
### Key UX Decisions
| Decision | Choice | Why |
|----------|--------|-----|
| Above-fold CTA | Yes (2 options) | Don't make them scroll to act |
| Module count visible | Show "١٤ وحدة" badge | Communicates completeness |
| Pricing on homepage | No (link in nav) | Don't distract from value story |
| Live demo embed | No | Too complex, breaks flow. Video or interactive mockup instead. |
| WhatsApp button | Yes (floating) | Egyptian users expect instant messaging |
| Phone number | Yes (in header) | Trust signal for Egyptian market |
---
## Interaction Design Principles
### 1. Progressive Disclosure
Don't dump all 14 modules at once. Show 6 key ones → "وأكثر..." link → Features page.
Feature deep-dives: title + one-liner visible, expand for full detail.
### 2. Scroll as Narrative
Each scroll section builds on the previous one:
- Problem (pain) → Solution (relief) → Proof (trust) → Action (conversion)
- Never show a feature without first establishing WHY they need it
### 3. Micro-Interactions That Build Confidence
- Numbers counting up = "this is real, this is measurable"
- Dashboard elements responding to cursor = "this is interactive, alive"
- Smooth transitions = "this is polished, professional"
- Instant language toggle = "they care about Arabic users"
### 4. Mobile-First Affordances
- Large tap targets (minimum 44px)
- Thumb-zone CTAs (bottom of screen)
- Sticky mobile CTA bar on scroll (appears after hero)
- Swipeable testimonial cards
- Collapsible FAQ sections
---
## Conversion Optimization
### Primary Conversion Goals (Priority Order)
1. **Demo booking** — highest intent, personal touch
2. **Free trial signup** — self-serve, lower friction
3. **WhatsApp inquiry** — low commitment, very Egyptian
4. **Newsletter** — nurture for later
### CTA Placement Strategy
| Location | CTA | Type |
|----------|-----|------|
| Navbar (always visible) | ابدأ مجاناً | Primary button |
| Hero section | ابدأ تجربة مجانية + احجز عرض | Primary + Secondary |
| After module showcase | اكتشف كل المميزات | Ghost link |
| After feature deep-dive | جرب بنفسك | Primary button |
| After testimonials | ابدأ مجاناً | Primary button |
| CTA section (bottom) | ابدأ مجاناً + تحدث مع فريقنا | Primary + Ghost |
| Floating (mobile) | WhatsApp icon | FAB |
| Exit intent (desktop) | Modal with offer | Form |
### Trust Signals
- Stats bar (academies, players, uptime)
- Customer logos (if available)
- "١٤ يوم تجربة مجانية — بدون بطاقة ائتمان"
- Security badges (SSL, EU servers)
- Arabic-first interface (shows they understand the market)
### Friction Reducers
- Demo form: 4 fields max (name, phone, academy name, player count)
- Trial signup: email + password only (academy details on onboarding)
- No credit card required for trial
- WhatsApp as escape valve for anyone uncomfortable with forms
---
## Accessibility & Inclusivity
### RTL-First Implementation
- All layouts flow right-to-left by default
- Navigation: logo on right, CTA on left (RTL visual flow)
- Text alignment: right-aligned by default
- Bidirectional icons: arrows/chevrons flip for RTL
- Numbers: always LTR within RTL text
### Egyptian Market Considerations
- Phone numbers in +20 format
- Currency: EGP (ج.م)
- Date format: DD/MM/YYYY (Arabic)
- Performance: optimize for 4G (not fiber)
- WhatsApp Business integration (support channel)
- Social proof: Egyptian academies specifically
- Imagery: Egyptian sports contexts (not Western stock)
### Screen Reader & Keyboard
- Semantic HTML5 landmarks throughout
- All images have Arabic alt text
- Skip navigation link
- Focus indicators visible and branded
- ARIA labels on interactive elements
- Tab order: logical RTL flow
---
## Content Strategy
### Content Types
1. **Static pages** — Home, Features, Pricing, About, Contact
2. **Blog** (phase 2) — SEO content, product updates, sports management tips
3. **Case studies** (phase 2) — Customer success stories with data
4. **Help center** (phase 3) — User documentation, onboarding guides
### SEO Content Calendar (Blog Topics)
| Month | Topic (AR) | Target Keyword |
|-------|-----------|----------------|
| 1 | كيف تدير أكاديمية رياضية ناجحة | إدارة أكاديمية رياضية |
| 2 | ٥ علامات إن أكاديميتك محتاجة نظام إدارة | نظام إدارة نادي |
| 3 | دليل تسعير الاشتراكات للأكاديميات | تسعير أكاديمية |
| 4 | كيف تتابع حضور اللاعبين بدون ورق | نظام حضور لاعبين |
| 5 | إزاي تزود إيرادات أكاديميتك ٣٠% | زيادة إيرادات أكاديمية |
| 6 | مقارنة: إكسيل vs نظام إدارة متخصص | برنامج إدارة نادي رياضي |
### Social Proof Strategy
- Collect 3-5 testimonials before launch (WhatsApp messages work as source)
- Screenshot real dashboard data (anonymized) for mockups
- "X أكاديمية تثق بنا" counter (update monthly)
- Video testimonial from 1 happy customer (60s, Arabic, real)
---
## Technical UX Patterns
### Loading States
- Skeleton screens for dynamic content (not spinners)
- Route transitions: progress bar top of page
- Form submission: button text changes + spinner inside button
- Image loading: blur placeholder → sharp (next/image handles this)
### Error States
- Form validation: inline Arabic errors below each field, red border
- Network error: toast notification with retry button
- 404 page: branded, helpful, links to homepage
### Empty States
- N/A for marketing site (all content is static)
- Demo/trial state: redirect to app with welcome flow
### Performance Perception
- Critical CSS inlined (hero renders instantly)
- Fonts: display:swap (text visible immediately, font loads async)
- Above-fold images: priority loading
- Below-fold: intersection observer lazy loading
- Animations: only trigger when element enters viewport
This diff is collapsed.
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";
const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
".next/**",
"out/**",
"build/**",
"next-env.d.ts",
]),
]);
export default eslintConfig;
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;
This diff is collapsed.
{
"name": "marketing-site",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint"
},
"dependencies": {
"@base-ui/react": "^1.6.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"framer-motion": "^12.42.2",
"lucide-react": "^1.23.0",
"next": "16.2.10",
"react": "19.2.4",
"react-dom": "19.2.4",
"shadcn": "^4.12.0",
"tailwind-merge": "^3.6.0",
"tw-animate-css": "^1.4.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.2.10",
"tailwindcss": "^4",
"typescript": "^5"
}
}
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};
export default config;
<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>
\ No newline at end of file
<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>
\ No newline at end of file
<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>
\ No newline at end of file
<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>
\ No newline at end of file
<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>
\ No newline at end of file
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "عن الكابتن — منصة إدارة الأكاديميات الرياضية",
description:
"نبني مركز القيادة للمنظمات الرياضية — نمنح أصحاب الأكاديميات تحكماً تشغيلياً كاملاً ليركزوا على ما يهم: تطوير الرياضيين.",
};
export default function AboutLayout({
children,
}: {
children: React.ReactNode;
}) {
return children;
}
"use client";
import { Target, Eye, Sparkles, Shield, TrendingUp, Heart } from "lucide-react";
import Navbar from "@/components/layout/Navbar";
import Footer from "@/components/layout/Footer";
import Container from "@/components/shared/Container";
import AnimateOnScroll from "@/components/shared/AnimateOnScroll";
import { content } from "@/lib/content";
import { staggerContainer, staggerItem } from "@/lib/animations";
import { motion } from "framer-motion";
const about = content.ar.about;
const valueIcons = [Sparkles, Shield, Heart, TrendingUp];
export default function AboutPage() {
return (
<>
<Navbar />
<main className="min-h-screen">
{/* Hero */}
<section className="pt-24 pb-16 bg-gradient-to-b from-sky-50/50 to-white">
<Container className="text-center">
<AnimateOnScroll>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-bold text-navy-800">
{about.title}
</h1>
</AnimateOnScroll>
</Container>
</section>
{/* Mission */}
<section className="py-16">
<Container className="max-w-4xl">
<AnimateOnScroll>
<div className="flex flex-col items-center text-center">
<div className="flex items-center justify-center w-14 h-14 rounded-full bg-sky-100 mb-6">
<Target className="h-7 w-7 text-sky-600" />
</div>
<h2 className="text-2xl sm:text-3xl font-bold text-navy-800 mb-4">
{about.mission.title}
</h2>
<p className="text-lg sm:text-xl text-slate-600 leading-relaxed max-w-3xl">
{about.mission.text}
</p>
</div>
</AnimateOnScroll>
</Container>
</section>
{/* Vision */}
<section className="py-16 bg-slate-50">
<Container className="max-w-4xl">
<AnimateOnScroll>
<div className="flex flex-col items-center text-center">
<div className="flex items-center justify-center w-14 h-14 rounded-full bg-amber-100 mb-6">
<Eye className="h-7 w-7 text-amber-600" />
</div>
<h2 className="text-2xl sm:text-3xl font-bold text-navy-800 mb-4">
{about.vision.title}
</h2>
<p className="text-lg sm:text-xl text-slate-600 leading-relaxed max-w-3xl">
{about.vision.text}
</p>
</div>
</AnimateOnScroll>
</Container>
</section>
{/* Values */}
<section className="py-16">
<Container>
<AnimateOnScroll>
<h2 className="text-2xl sm:text-3xl font-bold text-navy-800 text-center mb-12">
قيمنا
</h2>
</AnimateOnScroll>
<motion.div
variants={staggerContainer}
initial="hidden"
whileInView="visible"
viewport={{ once: true, amount: 0.2 }}
className="grid grid-cols-1 sm:grid-cols-2 gap-6 lg:gap-8 max-w-4xl mx-auto"
>
{about.values.map((value, index) => {
const Icon = valueIcons[index];
return (
<motion.div
key={value.title}
variants={staggerItem}
className="rounded-xl border border-slate-200 bg-white p-6 lg:p-8 hover:shadow-md transition-shadow"
>
<div className="flex items-center justify-center w-11 h-11 rounded-lg bg-sky-50 mb-4">
<Icon className="h-5 w-5 text-sky-600" />
</div>
<h3 className="text-lg font-bold text-navy-800 mb-2">
{value.title}
</h3>
<p className="text-sm text-slate-600 leading-relaxed">
{value.description}
</p>
</motion.div>
);
})}
</motion.div>
</Container>
</section>
</main>
<Footer />
</>
);
}
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "احجز عرض تجريبي — الكابتن | منصة إدارة الأكاديميات الرياضية",
description:
"شوف المنصة بنفسك في ٣٠ دقيقة. احجز عرض تجريبي مجاني وهنوريك كل المميزات.",
};
export default function ContactLayout({
children,
}: {
children: React.ReactNode;
}) {
return children;
}
This diff is collapsed.
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "المميزات — الكابتن | ١٤ وحدة متكاملة لإدارة أكاديميتك",
description:
"كل ما تحتاجه في منصة واحدة — ١٤ وحدة تغطي المالية واللاعبين والحضور والمخزون والتسعير وأكثر.",
};
export default function FeaturesLayout({
children,
}: {
children: React.ReactNode;
}) {
return children;
}
"use client";
import Link from "next/link";
import {
Wallet,
Users,
Calendar,
CheckCircle,
ShoppingCart,
Building,
Package,
MapPin,
Clock,
BarChart3,
Bell,
Shield,
CreditCard,
Zap,
} from "lucide-react";
import { motion } from "framer-motion";
import Navbar from "@/components/layout/Navbar";
import Footer from "@/components/layout/Footer";
import Container from "@/components/shared/Container";
import AnimateOnScroll from "@/components/shared/AnimateOnScroll";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { staggerContainer, staggerItem } from "@/lib/animations";
import { content } from "@/lib/content";
const modules = [
{
icon: Wallet,
title: "الإدارة المالية",
description: "قيد مزدوج، فواتير، أقساط، وتقارير مالية شاملة",
},
{
icon: Users,
title: "إدارة اللاعبين",
description: "ملفات شاملة لكل لاعب مع تاريخ كامل",
},
{
icon: Calendar,
title: "البرامج التدريبية",
description: "إنشاء وإدارة برامج تدريبية بمستويات متعددة",
},
{
icon: Users,
title: "المجموعات",
description: "تنظيم اللاعبين في مجموعات مع جدولة تلقائية",
},
{
icon: CheckCircle,
title: "الحضور والغياب",
description: "تسجيل آلي مع تنبيهات وتقارير فورية",
},
{
icon: ShoppingCart,
title: "نقاط البيع",
description: "بيع وتحصيل وإدارة مخزون في شاشة واحدة",
},
{
icon: Package,
title: "المخزون",
description: "تتبع المنتجات والمشتريات وحركة المخزون",
},
{
icon: Building,
title: "إدارة المنشآت",
description: "حجز وجدولة وتخصيص الملاعب والقاعات",
},
{
icon: Clock,
title: "الجدولة",
description: "جدولة ذكية للحصص مع كشف التعارضات",
},
{
icon: BarChart3,
title: "التقارير",
description: "تقارير تفصيلية وإحصائيات لحظية لكل الأقسام",
},
{
icon: Bell,
title: "الإشعارات",
description: "تنبيهات ذكية عبر التطبيق والإيميل والرسائل",
},
{
icon: Shield,
title: "الأدوار والصلاحيات",
description: "تحكم كامل في صلاحيات كل مستخدم",
},
{
icon: CreditCard,
title: "المحافظ الإلكترونية",
description: "محفظة لكل لاعب مع تتبع الرصيد والحركات",
},
{
icon: Zap,
title: "التسعير الذكي",
description: "قواعد تسعير مرنة وخصومات تلقائية حسب الشروط",
},
];
export default function FeaturesPage() {
return (
<>
<Navbar />
<main className="min-h-screen">
{/* Hero */}
<section className="pt-24 pb-16 bg-gradient-to-b from-sky-50/50 to-white">
<Container className="text-center">
<AnimateOnScroll>
<Badge className="bg-sky-100 text-sky-700 px-3 py-1 text-xs mb-4">
١٤ وحدة
</Badge>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-bold text-navy-800">
كل ما تحتاجه في منصة واحدة
</h1>
<p className="mt-4 text-lg text-slate-600 max-w-2xl mx-auto">
{content.ar.modules.sectionSubtitle}
</p>
</AnimateOnScroll>
</Container>
</section>
{/* Modules Grid */}
<section className="py-16">
<Container>
<motion.div
variants={staggerContainer}
initial="hidden"
whileInView="visible"
viewport={{ once: true, amount: 0.1 }}
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5 lg:gap-6"
>
{modules.map((module) => {
const Icon = module.icon;
return (
<motion.div
key={module.title}
variants={staggerItem}
className="group rounded-xl border border-slate-200 bg-white p-5 lg:p-6 hover:shadow-md hover:border-sky-200 transition-all"
>
<div className="flex items-center justify-center w-10 h-10 rounded-lg bg-sky-50 group-hover:bg-sky-100 transition-colors mb-4">
<Icon className="h-5 w-5 text-sky-600" />
</div>
<h3 className="text-base font-bold text-navy-800 mb-1.5">
{module.title}
</h3>
<p className="text-sm text-slate-600 leading-relaxed">
{module.description}
</p>
</motion.div>
);
})}
</motion.div>
</Container>
</section>
{/* CTA Section */}
<section className="py-16 bg-navy-800">
<Container className="text-center">
<AnimateOnScroll>
<h2 className="text-2xl sm:text-3xl font-bold text-white mb-4">
{content.ar.cta.headline}
</h2>
<p className="text-slate-300 mb-8 max-w-xl mx-auto">
{content.ar.cta.subheadline}
</p>
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
<Link
href="/contact"
className="inline-flex items-center justify-center rounded-lg bg-sky-500 px-6 py-3 text-sm font-semibold text-white shadow-sm transition-all hover:bg-sky-600 hover:shadow-md active:scale-[0.98]"
>
{content.ar.cta.ctaPrimary}
</Link>
<Link
href="/pricing"
className="inline-flex items-center justify-center rounded-lg border border-white/20 bg-white/10 px-6 py-3 text-sm font-semibold text-white backdrop-blur-sm transition-all hover:bg-white/20"
>
{content.ar.cta.ctaSecondary}
</Link>
</div>
</AnimateOnScroll>
</Container>
</section>
</main>
<Footer />
</>
);
}
@import "tailwindcss";
@import "tw-animate-css";
@import "shadcn/tailwind.css";
@custom-variant dark (&:is(.dark *));
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-cairo), var(--font-inter), system-ui, sans-serif;
--font-mono: var(--font-geist-mono);
--font-heading: var(--font-cairo), var(--font-inter), system-ui, sans-serif;
--font-cairo: var(--font-cairo);
--font-inter: var(--font-inter);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-border: var(--border);
--color-destructive: var(--destructive);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-muted-foreground: var(--muted-foreground);
--color-muted: var(--muted);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary: var(--secondary);
--color-primary-foreground: var(--primary-foreground);
--color-primary: var(--primary);
--color-popover-foreground: var(--popover-foreground);
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
--radius-sm: calc(var(--radius) * 0.6);
--radius-md: calc(var(--radius) * 0.8);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) * 1.4);
--radius-2xl: calc(var(--radius) * 1.8);
--radius-3xl: calc(var(--radius) * 2.2);
--radius-4xl: calc(var(--radius) * 2.6);
/* Brand Colors */
--color-navy-50: #f0f4f8;
--color-navy-100: #d9e2ec;
--color-navy-200: #bcccdc;
--color-navy-300: #9fb3c8;
--color-navy-400: #6b8aad;
--color-navy-500: #3d6b99;
--color-navy-600: #2d5280;
--color-navy-700: #264a70;
--color-navy-800: #1e3a5f;
--color-navy-900: #162b45;
--color-navy-950: #0f1d2f;
--color-sky-50: #f0f9ff;
--color-sky-100: #e0f2fe;
--color-sky-200: #bae6fd;
--color-sky-300: #7dd3fc;
--color-sky-400: #38bdf8;
--color-sky-500: #0ea5e9;
--color-sky-600: #0284c7;
--color-sky-700: #0369a1;
--color-sky-800: #075985;
--color-sky-900: #0c4a6e;
--color-emerald-50: #ecfdf5;
--color-emerald-100: #d1fae5;
--color-emerald-200: #a7f3d0;
--color-emerald-300: #6ee7b7;
--color-emerald-400: #34d399;
--color-emerald-500: #10b981;
--color-emerald-600: #059669;
--color-emerald-700: #047857;
--color-emerald-800: #065f46;
--color-emerald-900: #064e3b;
--color-amber-50: #fffbeb;
--color-amber-100: #fef3c7;
--color-amber-200: #fde68a;
--color-amber-300: #fcd34d;
--color-amber-400: #fbbf24;
--color-amber-500: #f59e0b;
--color-amber-600: #d97706;
--color-amber-700: #b45309;
--color-amber-800: #92400e;
--color-amber-900: #78350f;
}
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.87 0 0);
--chart-2: oklch(0.556 0 0);
--chart-3: oklch(0.439 0 0);
--chart-4: oklch(0.371 0 0);
--chart-5: oklch(0.269 0 0);
--radius: 0.625rem;
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.87 0 0);
--chart-2: oklch(0.556 0 0);
--chart-3: oklch(0.439 0 0);
--chart-4: oklch(0.371 0 0);
--chart-5: oklch(0.269 0 0);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
html {
@apply font-sans scroll-smooth;
}
::selection {
background-color: #0ea5e9;
color: white;
}
}
import type { Metadata } from "next";
import { cairo, inter } from "@/lib/fonts";
import WhatsAppButton from "@/components/shared/WhatsAppButton";
import "./globals.css";
export const metadata: Metadata = {
title: {
default: "الكابتن — منصة إدارة الأكاديميات الرياضية",
template: "%s | الكابتن",
},
description:
"منصة إدارة رياضية متكاملة تضع كل لاعب وكل جنيه وكل حصة تحت تحكمك الكامل. مصممة خصيصاً للأكاديميات الرياضية في مصر والعالم العربي.",
keywords: [
"إدارة أكاديمية رياضية",
"برنامج إدارة نادي رياضي",
"نظام حضور لاعبين",
"برنامج محاسبة أكاديمية",
"تسجيل لاعبين أونلاين",
],
openGraph: {
type: "website",
locale: "ar_EG",
siteName: "الكابتن",
title: "الكابتن — منصة إدارة الأكاديميات الرياضية",
description:
"منصة متكاملة لإدارة الأكاديميات الرياضية: تسجيل اللاعبين، الحضور، المالية، نقاط البيع.",
},
twitter: {
card: "summary_large_image",
title: "الكابتن — منصة إدارة الأكاديميات الرياضية",
description:
"منصة متكاملة لإدارة الأكاديميات الرياضية: تسجيل اللاعبين، الحضور، المالية، نقاط البيع.",
},
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html
lang="ar"
dir="rtl"
className={`${cairo.variable} ${inter.variable} antialiased`}
>
<body className="min-h-screen bg-background">
{children}
<WhatsAppButton />
</body>
</html>
);
}
import Link from "next/link";
export default function NotFound() {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-b from-sky-50/50 to-white">
<div className="text-center px-4">
<p className="text-8xl font-bold text-sky-500 mb-4">404</p>
<h1 className="text-2xl font-bold text-navy-800 mb-2">
الصفحة غير موجودة
</h1>
<p className="text-slate-500 mb-8">
الصفحة التي تبحث عنها غير موجودة أو تم نقلها.
</p>
<Link
href="/"
className="inline-flex items-center justify-center rounded-lg bg-sky-500 px-6 py-3 text-sm font-semibold text-white shadow-sm transition-all hover:bg-sky-600"
>
العودة للرئيسية
</Link>
</div>
</div>
);
}
import Navbar from "@/components/layout/Navbar";
import Footer from "@/components/layout/Footer";
import Hero from "@/components/sections/Hero";
import ProblemSolution from "@/components/sections/ProblemSolution";
import ModuleShowcase from "@/components/sections/ModuleShowcase";
import FeatureDeepDive from "@/components/sections/FeatureDeepDive";
import Testimonials from "@/components/sections/Testimonials";
import StatsSection from "@/components/sections/StatsSection";
import CTASection from "@/components/sections/CTASection";
export default function Home() {
return (
<>
<Navbar />
<main>
<Hero />
<ProblemSolution />
<ModuleShowcase />
<FeatureDeepDive />
<Testimonials />
<StatsSection />
<CTASection />
</main>
<Footer />
</>
);
}
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "الأسعار — الكابتن | منصة إدارة الأكاديميات الرياضية",
description:
"اختر الباقة المناسبة لأكاديميتك. ١٤ يوم تجربة مجانية على كل الباقات بدون بطاقة ائتمان.",
};
export default function PricingLayout({
children,
}: {
children: React.ReactNode;
}) {
return children;
}
"use client";
import { useState } from "react";
import { Check, X } from "lucide-react";
import { motion } from "framer-motion";
import Navbar from "@/components/layout/Navbar";
import Footer from "@/components/layout/Footer";
import Container from "@/components/shared/Container";
import AnimateOnScroll from "@/components/shared/AnimateOnScroll";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
Accordion,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from "@/components/ui/accordion";
import { content } from "@/lib/content";
import { fadeUp, staggerContainer, staggerItem } from "@/lib/animations";
const pricing = content.ar.pricing;
export default function PricingPage() {
const [billingCycle, setBillingCycle] = useState<"monthly" | "yearly">(
"monthly"
);
return (
<>
<Navbar />
<main className="min-h-screen">
{/* Hero */}
<section className="pt-24 pb-12 bg-gradient-to-b from-sky-50/50 to-white">
<Container className="text-center">
<AnimateOnScroll>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-bold text-navy-800">
{pricing.title}
</h1>
<p className="mt-4 text-lg text-slate-600 max-w-2xl mx-auto">
{pricing.subtitle}
</p>
</AnimateOnScroll>
{/* Billing Toggle */}
<AnimateOnScroll delay={0.2}>
<div className="mt-8 inline-flex items-center gap-1 rounded-lg bg-slate-100 p-1">
<button
onClick={() => setBillingCycle("monthly")}
className={`rounded-md px-5 py-2 text-sm font-medium transition-all ${
billingCycle === "monthly"
? "bg-white text-navy-800 shadow-sm"
: "text-slate-600 hover:text-slate-900"
}`}
>
{pricing.monthly}
</button>
<button
onClick={() => setBillingCycle("yearly")}
className={`rounded-md px-5 py-2 text-sm font-medium transition-all flex items-center gap-2 ${
billingCycle === "yearly"
? "bg-white text-navy-800 shadow-sm"
: "text-slate-600 hover:text-slate-900"
}`}
>
{pricing.yearly}
<Badge className="bg-emerald-100 text-emerald-700 text-[10px]">
{pricing.yearlyDiscount}
</Badge>
</button>
</div>
</AnimateOnScroll>
</Container>
</section>
{/* Pricing Cards */}
<section className="py-16">
<Container>
<motion.div
variants={staggerContainer}
initial="hidden"
whileInView="visible"
viewport={{ once: true, amount: 0.2 }}
className="grid grid-cols-1 md:grid-cols-3 gap-6 lg:gap-8 items-stretch"
>
{pricing.plans.map((plan, index) => (
<motion.div
key={plan.name}
variants={staggerItem}
className={`relative flex flex-col rounded-2xl border bg-white p-6 lg:p-8 shadow-sm transition-shadow hover:shadow-md ${
plan.highlighted
? "border-2 border-sky-500 shadow-sky-100"
: "border-slate-200"
}`}
>
{/* Badge for highlighted plan */}
{"badge" in plan && plan.badge && (
<div className="absolute -top-3 start-1/2 -translate-x-1/2 rtl:translate-x-1/2">
<Badge className="bg-sky-500 text-white px-3 py-1 text-xs">
{plan.badge}
</Badge>
</div>
)}
{/* Plan Header */}
<div className="text-center mb-6">
<h3 className="text-xl font-bold text-navy-800">
{plan.name}
</h3>
<p className="mt-1 text-sm text-slate-500">
{plan.description}
</p>
</div>
{/* Price */}
<div className="text-center mb-2">
<span className="text-4xl lg:text-5xl font-bold text-navy-800" dir="ltr">
{plan.price}
</span>
{plan.period && (
<span className="text-sm text-slate-500 ms-1">
{plan.period}
</span>
)}
</div>
{/* Platform Fee */}
{"platformFee" in plan && plan.platformFee && (
<div className="text-center mb-6">
<span className="inline-flex items-center gap-1.5 rounded-full bg-sky-50 px-3 py-1 text-xs font-medium text-sky-700">
{pricing.platformFeeLabel}: {plan.platformFee}
</span>
</div>
)}
{/* Features */}
<ul className="flex-1 space-y-3 mb-8">
{plan.features.map((feature) => (
<li
key={feature.text}
className="flex items-center gap-3"
>
{feature.included ? (
<Check className="h-4 w-4 text-emerald-500 shrink-0" />
) : (
<X className="h-4 w-4 text-slate-300 shrink-0" />
)}
<span
className={`text-sm ${
feature.included
? "text-slate-700"
: "text-slate-400"
}`}
>
{feature.text}
</span>
</li>
))}
</ul>
{/* CTA */}
<Button
className={`w-full py-3 h-11 text-sm font-semibold ${
plan.highlighted
? "bg-sky-500 text-white hover:bg-sky-600"
: "bg-slate-100 text-navy-800 hover:bg-slate-200"
}`}
>
{plan.cta}
</Button>
</motion.div>
))}
</motion.div>
</Container>
</section>
{/* FAQ */}
<section className="py-16 bg-slate-50">
<Container className="max-w-3xl">
<AnimateOnScroll>
<h2 className="text-2xl sm:text-3xl font-bold text-navy-800 text-center mb-10">
الأسئلة الشائعة
</h2>
</AnimateOnScroll>
<AnimateOnScroll delay={0.1}>
<Accordion className="space-y-2">
{pricing.faq.map((item, index) => (
<AccordionItem
key={index}
className="rounded-lg border border-slate-200 bg-white px-4"
>
<AccordionTrigger className="py-4 text-base font-medium text-navy-800 hover:no-underline">
{item.q}
</AccordionTrigger>
<AccordionContent className="text-slate-600 leading-relaxed">
{item.a}
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</AnimateOnScroll>
</Container>
</section>
</main>
<Footer />
</>
);
}
import Link from "next/link";
import { content } from "@/lib/content";
const quickLinks = [
{ label: content.ar.nav.home, href: "/" },
{ label: content.ar.nav.features, href: "/features" },
{ label: content.ar.nav.pricing, href: "/pricing" },
{ label: content.ar.nav.about, href: "/about" },
{ label: content.ar.nav.contact, href: "/contact" },
];
export default function Footer() {
return (
<footer className="bg-navy-800 text-white">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-12 lg:py-16">
<div className="grid grid-cols-1 md:grid-cols-3 gap-10 lg:gap-16">
{/* Brand Info */}
<div className="space-y-4">
<Link href="/" className="inline-flex items-center gap-2 text-xl font-bold">
<span className="text-sky-400">&#9670;</span>
الكابتن
</Link>
<p className="text-slate-300 text-sm leading-relaxed max-w-xs">
{content.ar.footer.description}
</p>
</div>
{/* Quick Links */}
<div className="space-y-4">
<h3 className="text-base font-semibold">{content.ar.footer.quickLinks}</h3>
<ul className="space-y-2.5">
{quickLinks.map((link) => (
<li key={link.href}>
<Link
href={link.href}
className="text-sm text-slate-300 transition-colors hover:text-white"
>
{link.label}
</Link>
</li>
))}
</ul>
</div>
{/* Contact Info */}
<div className="space-y-4">
<h3 className="text-base font-semibold">{content.ar.footer.contactUs}</h3>
<ul className="space-y-2.5 text-sm text-slate-300">
<li>
<a
href={`tel:${content.ar.contact.info.phone.replace(/\s/g, "")}`}
className="transition-colors hover:text-white"
dir="ltr"
>
{content.ar.contact.info.phone}
</a>
</li>
<li>
<a
href={`mailto:${content.ar.contact.info.email}`}
className="transition-colors hover:text-white"
dir="ltr"
>
{content.ar.contact.info.email}
</a>
</li>
<li>
<a
href={`https://wa.me/${content.ar.contact.info.phone.replace(/[\s+]/g, "")}`}
className="transition-colors hover:text-white"
target="_blank"
rel="noopener noreferrer"
>
{content.ar.contact.info.whatsapp}
</a>
</li>
</ul>
</div>
</div>
</div>
{/* Bottom Bar */}
<div className="border-t border-white/10">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-5">
<div className="flex flex-col sm:flex-row items-center justify-between gap-3 text-sm text-slate-400">
<p>
&copy; {new Date().getFullYear()} الكابتن. {content.ar.footer.rights}
</p>
<div className="flex items-center gap-4">
<Link href="/privacy" className="transition-colors hover:text-white">
{content.ar.footer.privacy}
</Link>
<Link href="/terms" className="transition-colors hover:text-white">
{content.ar.footer.terms}
</Link>
</div>
</div>
</div>
</div>
</footer>
);
}
"use client";
import { useState, useEffect } from "react";
import Link from "next/link";
import { Menu, X } from "lucide-react";
import { motion, AnimatePresence } from "framer-motion";
import { content } from "@/lib/content";
const navLinks = [
{ label: content.ar.nav.home, href: "/" },
{ label: content.ar.nav.features, href: "/features" },
{ label: content.ar.nav.pricing, href: "/pricing" },
{ label: content.ar.nav.about, href: "/about" },
{ label: content.ar.nav.contact, href: "/contact" },
];
export default function Navbar() {
const [isScrolled, setIsScrolled] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 10);
};
window.addEventListener("scroll", handleScroll, { passive: true });
return () => window.removeEventListener("scroll", handleScroll);
}, []);
useEffect(() => {
if (isMobileMenuOpen) {
document.body.style.overflow = "hidden";
} else {
document.body.style.overflow = "";
}
return () => {
document.body.style.overflow = "";
};
}, [isMobileMenuOpen]);
return (
<header
className={`sticky top-0 z-50 w-full backdrop-blur-xl transition-all duration-300 ${
isScrolled
? "bg-white/80 border-b border-slate-200/60 shadow-sm"
: "bg-white/60"
}`}
>
<nav className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div className="flex h-16 items-center justify-between">
{/* Logo */}
<Link
href="/"
className="flex items-center gap-2 text-xl font-bold text-navy-800"
>
<span className="text-sky-500">&#9670;</span>
الكابتن
</Link>
{/* Desktop Nav Links */}
<div className="hidden md:flex items-center gap-8">
{navLinks.map((link) => (
<Link
key={link.href}
href={link.href}
className="text-sm font-medium text-slate-600 transition-colors hover:text-navy-800"
>
{link.label}
</Link>
))}
</div>
{/* Desktop CTA */}
<div className="hidden md:block">
<Link
href="/contact"
className="inline-flex items-center justify-center rounded-lg bg-sky-500 px-5 py-2.5 text-sm font-semibold text-white shadow-sm transition-all hover:bg-sky-600 hover:shadow-md active:scale-[0.98]"
>
{content.ar.nav.cta}
</Link>
</div>
{/* Mobile Menu Button */}
<button
type="button"
className="md:hidden inline-flex items-center justify-center rounded-md p-2 text-slate-600 hover:bg-slate-100 hover:text-slate-900 transition-colors"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
aria-label={isMobileMenuOpen ? "إغلاق القائمة" : "فتح القائمة"}
aria-expanded={isMobileMenuOpen}
>
{isMobileMenuOpen ? (
<X className="h-6 w-6" />
) : (
<Menu className="h-6 w-6" />
)}
</button>
</div>
</nav>
{/* Mobile Menu Overlay */}
<AnimatePresence>
{isMobileMenuOpen && (
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.2, ease: "easeOut" }}
className="fixed inset-0 top-16 z-40 bg-white md:hidden"
>
<div className="flex flex-col gap-1 px-4 py-6">
{navLinks.map((link) => (
<Link
key={link.href}
href={link.href}
onClick={() => setIsMobileMenuOpen(false)}
className="rounded-lg px-4 py-3 text-base font-medium text-slate-700 transition-colors hover:bg-slate-50 hover:text-navy-800"
>
{link.label}
</Link>
))}
<div className="mt-4 pt-4 border-t border-slate-200">
<Link
href="/contact"
onClick={() => setIsMobileMenuOpen(false)}
className="flex w-full items-center justify-center rounded-lg bg-sky-500 px-5 py-3 text-base font-semibold text-white shadow-sm transition-all hover:bg-sky-600"
>
{content.ar.nav.cta}
</Link>
</div>
</div>
</motion.div>
)}
</AnimatePresence>
</header>
);
}
"use client";
import { motion } from "framer-motion";
import { content } from "@/lib/content";
import { fadeUp, staggerContainer, staggerItem } from "@/lib/animations";
const cta = content.ar.cta;
export default function CTASection() {
return (
<section className="py-20 md:py-28 bg-slate-900 relative overflow-hidden">
{/* Decorative grid dots pattern */}
<div
className="absolute inset-0 opacity-[0.07]"
style={{
backgroundImage:
"radial-gradient(circle, rgba(255,255,255,0.8) 1px, transparent 1px)",
backgroundSize: "32px 32px",
}}
/>
{/* Gradient overlay */}
<div className="absolute inset-0 bg-gradient-to-b from-slate-900/80 via-transparent to-slate-900/80" />
<div className="container mx-auto px-4 md:px-6 relative z-10">
<motion.div
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-80px" }}
variants={staggerContainer}
className="bg-slate-800/50 border border-slate-700/50 backdrop-blur-sm rounded-2xl p-10 md:p-16 max-w-3xl mx-auto text-center"
>
<motion.h2
variants={staggerItem}
className="text-3xl md:text-4xl lg:text-5xl font-bold text-white mb-4"
>
{cta.headline}
</motion.h2>
<motion.p
variants={staggerItem}
className="text-lg md:text-xl text-slate-300 mb-10 max-w-xl mx-auto"
>
{cta.subheadline}
</motion.p>
<motion.div
variants={staggerItem}
className="flex flex-col sm:flex-row items-center justify-center gap-4"
>
<a
href="#contact"
className="inline-flex items-center justify-center px-8 py-4 text-lg font-bold bg-white text-slate-900 rounded-xl hover:bg-slate-100 transition-colors w-full sm:w-auto"
>
{cta.ctaPrimary}
</a>
<a
href="#contact"
className="inline-flex items-center justify-center px-8 py-4 text-lg font-medium border-2 border-white/30 text-white rounded-xl hover:bg-white/10 transition-colors w-full sm:w-auto"
>
{cta.ctaSecondary}
</a>
</motion.div>
</motion.div>
</div>
</section>
);
}
"use client";
import { motion } from "framer-motion";
import { Check } from "lucide-react";
import { content } from "@/lib/content";
import { fadeUp, staggerContainer, staggerItem } from "@/lib/animations";
const features = content.ar.features;
const mockupColors = [
{ bg: "bg-blue-50", accent: "bg-blue-500", secondary: "bg-blue-200" },
{ bg: "bg-emerald-50", accent: "bg-emerald-500", secondary: "bg-emerald-200" },
{ bg: "bg-purple-50", accent: "bg-purple-500", secondary: "bg-purple-200" },
];
function FeatureMockup({ colorIndex }: { colorIndex: number }) {
const colors = mockupColors[colorIndex];
return (
<div
className={`${colors.bg} rounded-2xl p-6 w-full max-w-md aspect-[4/3] flex flex-col gap-4 shadow-lg`}
>
{/* Header bar */}
<div className="flex items-center gap-3">
<div className={`${colors.accent} w-3 h-3 rounded-full`} />
<div className={`${colors.secondary} h-3 rounded-full flex-1 max-w-[60%]`} />
</div>
{/* Content rows */}
<div className="flex-1 flex flex-col gap-3 justify-center">
<div className="flex gap-3 items-center">
<div className={`${colors.accent} w-10 h-10 rounded-lg opacity-80`} />
<div className="flex-1 space-y-2">
<div className={`${colors.secondary} h-3 rounded-full w-3/4`} />
<div className={`${colors.secondary} h-2 rounded-full w-1/2 opacity-60`} />
</div>
</div>
<div className="flex gap-3 items-center">
<div className={`${colors.accent} w-10 h-10 rounded-lg opacity-60`} />
<div className="flex-1 space-y-2">
<div className={`${colors.secondary} h-3 rounded-full w-2/3`} />
<div className={`${colors.secondary} h-2 rounded-full w-2/5 opacity-60`} />
</div>
</div>
<div className="flex gap-3 items-center">
<div className={`${colors.accent} w-10 h-10 rounded-lg opacity-40`} />
<div className="flex-1 space-y-2">
<div className={`${colors.secondary} h-3 rounded-full w-4/5`} />
<div className={`${colors.secondary} h-2 rounded-full w-1/3 opacity-60`} />
</div>
</div>
</div>
{/* Bottom bar */}
<div className="flex gap-2">
<div className={`${colors.accent} h-8 rounded-lg flex-1 opacity-90`} />
<div className={`${colors.secondary} h-8 rounded-lg w-20`} />
</div>
</div>
);
}
export default function FeatureDeepDive() {
return (
<section className="py-16 md:py-24">
<div className="container mx-auto px-4 md:px-6">
{features.map((feature, index) => {
const isReversed = index % 2 !== 0;
return (
<motion.div
key={index}
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-100px" }}
variants={staggerContainer}
className={`flex flex-col ${
isReversed ? "md:flex-row-reverse" : "md:flex-row"
} items-center gap-10 md:gap-16 py-16 md:py-20`}
>
{/* Text side */}
<motion.div variants={fadeUp} className="flex-1 space-y-6">
<span className="inline-block px-3 py-1 text-sm font-medium bg-sky-100 text-sky-700 rounded-full">
{feature.tag}
</span>
<h3 className="text-3xl md:text-4xl font-bold text-slate-900">
{feature.title}
</h3>
<p className="text-lg text-slate-600 leading-relaxed">
{feature.description}
</p>
<motion.ul
variants={staggerContainer}
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
className="space-y-3 pt-2"
>
{feature.points.map((point, i) => (
<motion.li
key={i}
variants={staggerItem}
className="flex items-center gap-3"
>
<span className="flex-shrink-0 w-6 h-6 bg-emerald-100 text-emerald-600 rounded-full flex items-center justify-center">
<Check size={14} strokeWidth={3} />
</span>
<span className="text-slate-700 font-medium">{point}</span>
</motion.li>
))}
</motion.ul>
</motion.div>
{/* Mockup side */}
<motion.div
variants={fadeUp}
className="flex-1 flex justify-center"
>
<FeatureMockup colorIndex={index} />
</motion.div>
</motion.div>
);
})}
</div>
</section>
);
}
"use client";
import { motion } from "framer-motion";
import { content } from "@/lib/content";
import { staggerContainer, staggerItem, fadeUp, scaleIn } from "@/lib/animations";
import CountUpNumber from "@/components/shared/CountUpNumber";
import { ArrowLeft, TrendingUp, Users, BarChart3 } from "lucide-react";
const heroContent = content.ar.hero;
function DashboardMockup() {
return (
<motion.div
variants={scaleIn}
className="relative"
style={{ perspective: "1200px" }}
>
<motion.div
animate={{ y: [0, -8, 0] }}
transition={{ duration: 4, repeat: Infinity, ease: "easeInOut" }}
className="relative rounded-2xl border border-slate-200 bg-white p-4 shadow-2xl"
style={{
transform: "rotateY(-5deg) rotateX(3deg)",
transformStyle: "preserve-3d",
}}
>
{/* Browser header */}
<div className="mb-4 flex items-center gap-2 border-b border-slate-100 pb-3">
<div className="h-3 w-3 rounded-full bg-red-400" />
<div className="h-3 w-3 rounded-full bg-yellow-400" />
<div className="h-3 w-3 rounded-full bg-green-400" />
<div className="ms-3 h-5 flex-1 rounded-md bg-slate-100" />
</div>
{/* Dashboard content */}
<div className="space-y-4">
{/* Revenue card */}
<div className="rounded-xl bg-gradient-to-l from-sky-50 to-white p-4 border border-sky-100">
<div className="flex items-center justify-between">
<div>
<p className="text-xs text-slate-400 mb-1">الإيرادات الشهرية</p>
<p className="text-2xl font-bold text-slate-900">١٢٥,٠٠٠ ج.م</p>
</div>
<div className="flex items-center gap-1 rounded-full bg-emerald-50 px-2 py-1">
<TrendingUp className="h-3 w-3 text-emerald-600" />
<span className="text-xs font-medium text-emerald-600">+١٢%</span>
</div>
</div>
</div>
{/* Chart placeholder */}
<div className="rounded-xl border border-slate-100 p-4">
<div className="flex items-center justify-between mb-3">
<p className="text-xs text-slate-400">إحصائيات الأسبوع</p>
<BarChart3 className="h-4 w-4 text-slate-300" />
</div>
<svg
viewBox="0 0 200 60"
className="h-16 w-full"
fill="none"
preserveAspectRatio="none"
>
<path
d="M0 50 C20 45, 40 30, 60 35 S100 15, 120 20 S160 10, 180 15 L200 8"
stroke="rgb(14 165 233)"
strokeWidth="2"
strokeLinecap="round"
/>
<path
d="M0 50 C20 45, 40 30, 60 35 S100 15, 120 20 S160 10, 180 15 L200 8 L200 60 L0 60 Z"
fill="url(#chartGradient)"
opacity="0.15"
/>
<defs>
<linearGradient id="chartGradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="rgb(14 165 233)" />
<stop offset="100%" stopColor="rgb(14 165 233)" stopOpacity="0" />
</linearGradient>
</defs>
</svg>
</div>
{/* Bottom stats row */}
<div className="grid grid-cols-2 gap-3">
<div className="rounded-lg bg-slate-50 p-3">
<div className="flex items-center gap-2 mb-1">
<Users className="h-3.5 w-3.5 text-sky-500" />
<span className="text-xs text-slate-400">اللاعبين</span>
</div>
<p className="text-lg font-bold text-slate-800">٢,٤٥٠</p>
</div>
<div className="rounded-lg bg-slate-50 p-3">
<div className="flex items-center gap-2 mb-1">
<div className="h-3.5 w-3.5 rounded-full bg-emerald-400" />
<span className="text-xs text-slate-400">نسبة الحضور</span>
</div>
<p className="text-lg font-bold text-slate-800">٩٢%</p>
</div>
</div>
</div>
</motion.div>
</motion.div>
);
}
export default function Hero() {
return (
<section className="relative min-h-[90vh] flex items-center overflow-hidden bg-gradient-to-b from-white to-sky-50">
<div className="container mx-auto px-4 py-20 lg:py-24">
<motion.div
variants={staggerContainer}
initial="hidden"
animate="visible"
className="grid items-center gap-12 lg:grid-cols-2 lg:gap-16"
>
{/* Text content (visually right in RTL) */}
<div className="order-2 lg:order-1">
<motion.div variants={staggerContainer} initial="hidden" animate="visible">
<motion.h1
variants={staggerItem}
className="text-5xl font-extrabold leading-tight text-slate-900 md:text-6xl lg:text-7xl"
>
{heroContent.headline}
</motion.h1>
<motion.p
variants={staggerItem}
className="mt-6 max-w-xl text-lg leading-relaxed text-slate-500"
>
{heroContent.subheadline}
</motion.p>
<motion.div
variants={staggerItem}
className="mt-8 flex flex-wrap items-center gap-4"
>
<button className="inline-flex items-center gap-2 rounded-xl bg-sky-500 px-6 py-3.5 text-base font-semibold text-white shadow-lg shadow-sky-200 transition-all hover:bg-sky-600 hover:shadow-xl hover:shadow-sky-200">
{heroContent.ctaPrimary}
<ArrowLeft className="h-4 w-4" />
</button>
<button className="inline-flex items-center gap-2 rounded-xl border-2 border-slate-200 bg-white px-6 py-3.5 text-base font-semibold text-slate-700 transition-all hover:border-sky-200 hover:text-sky-600">
{heroContent.ctaSecondary}
</button>
</motion.div>
</motion.div>
</div>
{/* Dashboard mockup (visually left in RTL) */}
<motion.div
variants={scaleIn}
initial="hidden"
animate="visible"
className="order-1 lg:order-2"
>
<DashboardMockup />
</motion.div>
</motion.div>
{/* Bottom stats bar */}
<motion.div
variants={fadeUp}
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
className="mt-16 rounded-2xl border border-slate-100 bg-white/80 p-6 shadow-sm backdrop-blur-sm lg:mt-20"
>
<div className="grid grid-cols-1 divide-y divide-slate-100 md:grid-cols-3 md:divide-x md:divide-x-reverse md:divide-y-0">
{heroContent.stats.map((stat, index) => (
<div key={index} className="flex flex-col items-center py-4 md:py-0">
<span className="text-3xl font-bold text-sky-600 lg:text-4xl">
<CountUpNumber value={parseFloat(stat.value)} suffix={stat.suffix} />
</span>
<span className="mt-1 text-sm text-slate-500">{stat.label}</span>
</div>
))}
</div>
</motion.div>
</div>
</section>
);
}
This diff is collapsed.
This diff is collapsed.
"use client";
import { motion } from "framer-motion";
import { content } from "@/lib/content";
import { fadeUp, staggerContainer, staggerItem } from "@/lib/animations";
import CountUpNumber from "@/components/shared/CountUpNumber";
const stats = content.ar.stats.items;
export default function StatsSection() {
return (
<section className="py-20 md:py-28 bg-sky-50 relative overflow-hidden">
<div className="container mx-auto px-4 md:px-6">
<motion.div
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-80px" }}
variants={staggerContainer}
className="grid grid-cols-1 md:grid-cols-3 gap-10 md:gap-8"
>
{stats.map((stat, index) => (
<motion.div
key={index}
variants={staggerItem}
className="flex flex-col items-center text-center relative"
>
{/* Subtle glow behind number */}
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-40 h-40 bg-sky-200/40 rounded-full blur-3xl pointer-events-none" />
<CountUpNumber
value={parseFloat(stat.value)}
suffix={stat.suffix}
className="relative text-4xl md:text-5xl font-bold text-slate-900"
/>
<p className="mt-3 text-lg text-slate-600 font-medium relative">
{stat.label}
</p>
</motion.div>
))}
</motion.div>
</div>
</section>
);
}
This diff is collapsed.
This diff is collapsed.
interface ContainerProps {
children: React.ReactNode;
className?: string;
}
export default function Container({ children, className = "" }: ContainerProps) {
return (
<div className={`mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 ${className}`}>
{children}
</div>
);
}
This diff is collapsed.
"use client";
import { MessageCircle } from "lucide-react";
export default function WhatsAppButton() {
return (
<a
href="https://wa.me/201000000000"
target="_blank"
rel="noopener noreferrer"
aria-label="تواصل عبر واتساب"
className="fixed bottom-6 start-6 z-50 flex h-14 w-14 items-center justify-center rounded-full bg-emerald-500 text-white shadow-lg shadow-emerald-200 transition-all hover:bg-emerald-600 hover:scale-110 hover:shadow-xl"
>
<MessageCircle className="h-6 w-6" />
</a>
);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment