Commit d61babad authored by Mahmoud Aglan's avatar Mahmoud Aglan

Add Website Builder V2 implementation spec (30 upgrades)

Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 379cefca
# Website Builder V2 — Full Implementation Spec
## Current State Summary
The website builder is a single-page scrollable site per academy at `/site/{slug}`. It has 16 section types, 4 color pickers, 2 font selectors, 3 navbar styles, and a `template` column with 3 values (`bold_athletic`, `clean_professional`, `vibrant_playful`) that is **NOT implemented in rendering** — only one template renders regardless.
### Current DB Tables
- `website_settings` — one row per academy (colors, fonts, navbar_style, social_links JSON, custom_css, analytics IDs, is_published)
- `website_sections` — per-academy sections (section_key, title/title_en, subtitle/subtitle_en, content/content_en, settings JSON, sort_order, is_enabled)
- `website_testimonials` — name, role, content, rating, is_featured, sort_order
- `website_faqs` — question, answer, is_published, sort_order
- `website_news` — title, body, excerpt, slug, is_featured, published_at
- `website_partners` — name, website_url, sort_order, is_active
- `contact_submissions` — name, phone, email, message, status
- `media` — polymorphic (mediable_type/mediable_id), collection enum, disk_path, dimensions
### Current Files
- **Models**: `app/Domain/Website/Models/` — WebsiteSetting, WebsiteSection, WebsiteTestimonial, WebsiteNews, WebsiteFaq, WebsitePartner, ContactSubmission, Media
- **Services**: `app/Domain/Website/Services/` — WebsiteSettingService, WebsiteSectionService, WebsiteDataService, WebsiteCacheService, MediaService
- **Enums**: `app/Domain/Website/Enums/` — SectionKey (16 cases), MediaCollection (13 cases), ContactSubmissionStatus
- **Livewire Admin**: `app/Livewire/Website/` — SectionManager, ThemeEditor, GalleryManager, NewsManager, FaqManager, TestimonialManager, PartnerManager, ContactSubmissionList
- **Public Views**: `resources/views/website/` — layout.blade.php, index.blade.php, navbar.blade.php, footer.blade.php, + `sections/` (16 partials)
- **CSS**: `resources/css/website.css` (481 lines, Tailwind v4, CSS variables)
- **JS**: `resources/js/website.js` (104 lines, scroll effects, counters, smooth scroll)
- **Controller**: `app/Http/Controllers/PublicWebsiteController.php` — renders using WebsiteDataService
- **Routes**: `/site/{slug}` with `ResolveAcademyFromSlug` middleware
### Current CSS Variables (in layout.blade.php)
```css
:root {
--site-primary: {{ $settings->primary_color }};
--site-secondary: {{ $settings->secondary_color }};
--site-accent: {{ $settings->accent_color }};
--site-text: {{ $settings->text_color }};
--site-bg: {{ $settings->background_color ?? '#ffffff' }};
--site-heading-font: '{{ $settings->heading_font }}', 'Noto Sans Arabic', sans-serif;
--site-body-font: '{{ $settings->body_font }}', 'Noto Sans Arabic', sans-serif;
}
```
### What Does NOT Exist (must build from scratch)
- No WYSIWYG / rich text editor
- No visual page builder / drag-drop blocks
- No live side-by-side preview
- No template switcher UI (DB column exists, rendering doesn't branch)
- No per-section background/color customization
- No typography size/weight/spacing controls
- No spacing/padding controls
- No animation controls
- No multi-page support
- No video embed support
- No map integration
- No custom domain support
- No blog detail page (model has slug but no public show route)
- No language switcher on public site
---
## The 30 Upgrades
---
### UPGRADE 1: Template Switcher (3 → 8 Themes)
**What**: Implement the template system that already has a DB column but no UI or rendering logic. Add 5 more templates beyond the 3 in the CHECK constraint.
**Database Changes**:
```sql
-- Migration: alter website_settings template CHECK constraint
ALTER TABLE website_settings DROP CONSTRAINT website_settings_template_check;
ALTER TABLE website_settings ADD CONSTRAINT website_settings_template_check
CHECK (template IN (
'bold_athletic', 'clean_professional', 'vibrant_playful',
'dark_sport', 'minimal_corporate', 'gradient_modern',
'neon_energy', 'earth_natural'
));
```
**Files to Modify**:
- `app/Livewire/Website/ThemeEditor.php` — add `$template` property, add template picker UI with preview thumbnails
- `resources/views/livewire/website/theme-editor.blade.php` — add template selection grid at top
- `resources/views/website/layout.blade.php` — add `data-template="{{ $settings->template }}"` to `<html>` tag
- `resources/css/website.css` — add template-specific CSS overrides using `[data-template="..."]` selectors
**Template Definitions** (each sets default colors + spacing + border-radius + shadow philosophy):
| Template | Primary | Secondary | Accent | BG | Border Radius | Shadows | Vibe |
|----------|---------|-----------|--------|-----|---------------|---------|------|
| bold_athletic | #1a1a2e | #16213e | #e94560 | #0f0f1a | 12px | heavy | Dark, dramatic, stadium lights |
| clean_professional | #ffffff | #f8fafc | #2563eb | #ffffff | 8px | subtle | Light, corporate, trustworthy |
| vibrant_playful | #fef3c7 | #ecfccb | #f59e0b | #fffbeb | 16px | colored | Bright, fun, kids-focused |
| dark_sport | #0a0a0a | #1c1c1c | #22c55e | #000000 | 4px | none | Ultra-dark, neon accent, sleek |
| minimal_corporate | #f9fafb | #ffffff | #6366f1 | #ffffff | 2px | xs | Ultra-clean, lots of whitespace |
| gradient_modern | #1e1b4b | #312e81 | #a78bfa | #0f0b2e | 20px | glow | Gradients everywhere, glass |
| neon_energy | #18181b | #27272a | #facc15 | #09090b | 0px | neon | Cyberpunk, electric, bold |
| earth_natural | #fefce8 | #f0fdf4 | #65a30d | #fafaf9 | 24px | soft | Organic, warm, nature |
**When applying a template**: Pre-fill the 4 colors + set CSS variables. User can still override individual colors after.
**Implementation Notes**:
- Template selection triggers `$this->primary_color = $presets[$template]['primary']` etc. in ThemeEditor
- Each template loads additional CSS class on `<body>` that overrides spacing, radius, shadow tokens
- Preview thumbnails: store as static images in `public/images/templates/` (screenshot each theme at 400x250)
---
### UPGRADE 2: Advanced Color Palette (4 → 8 Colors + Auto-Generate)
**What**: Expand from 4 color pickers to 8, add auto-palette generation from a single accent color.
**Database Changes**:
```sql
-- Migration: add columns to website_settings
ALTER TABLE website_settings ADD COLUMN background_color VARCHAR(7) DEFAULT '#ffffff';
ALTER TABLE website_settings ADD COLUMN surface_color VARCHAR(7) DEFAULT '#f8fafc';
ALTER TABLE website_settings ADD COLUMN border_color VARCHAR(7) DEFAULT '#e2e8f0';
ALTER TABLE website_settings ADD COLUMN muted_text_color VARCHAR(7) DEFAULT '#64748b';
```
**Files to Modify**:
- `app/Domain/Website/Models/WebsiteSetting.php` — add to $fillable: `background_color`, `surface_color`, `border_color`, `muted_text_color`
- `app/Livewire/Website/ThemeEditor.php` — add 4 new color properties, add `generatePalette()` method
- `resources/views/livewire/website/theme-editor.blade.php` — add 4 more color pickers + "Auto-generate from accent" button
- `resources/views/website/layout.blade.php` — add CSS variables: `--site-surface`, `--site-border`, `--site-muted`, `--site-bg`
- `resources/css/website.css` — replace hardcoded colors with new variables
**Auto-Generate Algorithm** (in ThemeEditor.php):
```php
public function generatePalette(): void
{
// From accent color, derive full palette
$accent = $this->accent_color; // e.g. '#e94560'
$hsl = $this->hexToHsl($accent);
// Dark mode (hue preserved, saturation reduced for backgrounds)
$this->primary_color = $this->hslToHex($hsl[0], max(10, $hsl[1] - 40), 12);
$this->secondary_color = $this->hslToHex($hsl[0], max(10, $hsl[1] - 35), 16);
$this->background_color = $this->hslToHex($hsl[0], max(5, $hsl[1] - 50), 8);
$this->surface_color = $this->hslToHex($hsl[0], max(8, $hsl[1] - 42), 14);
$this->text_color = '#ffffff';
$this->muted_text_color = $this->hslToHex($hsl[0], 10, 60);
$this->border_color = $this->hslToHex($hsl[0], 10, 22);
}
```
Provide a toggle: "Dark mode" vs "Light mode" which reverses the palette generation (light = white bg, dark text; dark = navy bg, white text).
---
### UPGRADE 3: Typography System (Font Size + Weight + Spacing)
**What**: Add font size scale, line height, letter spacing, and heading weight controls.
**Database Changes**:
```sql
-- Migration: add typography columns to website_settings
ALTER TABLE website_settings ADD COLUMN font_size_scale VARCHAR(10) DEFAULT 'medium';
ALTER TABLE website_settings ADD COLUMN heading_weight VARCHAR(10) DEFAULT '700';
ALTER TABLE website_settings ADD COLUMN line_height VARCHAR(10) DEFAULT 'normal';
ALTER TABLE website_settings ADD COLUMN letter_spacing VARCHAR(10) DEFAULT 'normal';
ALTER TABLE website_settings ADD CONSTRAINT website_settings_font_size_scale_check
CHECK (font_size_scale IN ('small', 'medium', 'large', 'xlarge'));
ALTER TABLE website_settings ADD CONSTRAINT website_settings_heading_weight_check
CHECK (heading_weight IN ('400', '500', '600', '700', '800', '900'));
ALTER TABLE website_settings ADD CONSTRAINT website_settings_line_height_check
CHECK (line_height IN ('tight', 'normal', 'relaxed', 'loose'));
ALTER TABLE website_settings ADD CONSTRAINT website_settings_letter_spacing_check
CHECK (letter_spacing IN ('tight', 'normal', 'wide'));
```
**Font Size Scale Mapping** (CSS variables):
```css
/* small */ --site-text-base: 14px; --site-h1: 2rem; --site-h2: 1.6rem; --site-h3: 1.3rem;
/* medium */ --site-text-base: 16px; --site-h1: 2.5rem; --site-h2: 2rem; --site-h3: 1.5rem;
/* large */ --site-text-base: 18px; --site-h1: 3rem; --site-h2: 2.4rem; --site-h3: 1.75rem;
/* xlarge */ --site-text-base: 20px; --site-h1: 3.5rem; --site-h2: 2.8rem; --site-h3: 2rem;
```
**Files to Modify**:
- `app/Domain/Website/Models/WebsiteSetting.php` — add to $fillable
- `app/Livewire/Website/ThemeEditor.php` — add properties + dropdown options
- `resources/views/livewire/website/theme-editor.blade.php` — add 4 new selects in Typography section
- `resources/views/website/layout.blade.php` — emit CSS variables from these settings
- `resources/css/website.css` — use the variables for all text sizing
**Additional Fonts to Add** (expand from 8 to 15):
Cairo, Tajawal, IBM Plex Sans Arabic, Noto Sans Arabic, Almarai, Readex Pro, Rubik, El Messiri, Changa, Noto Kufi Arabic, Amiri, Lateef, Baloo Bhaijaan 2, Scheherazade New, Alexandria
---
### UPGRADE 4: Section Backgrounds (Per-Section Customization)
**What**: Each section can have its own background: solid color, gradient, image with overlay, or video.
**Database Changes**:
```sql
-- Migration: add columns to website_sections
ALTER TABLE website_sections ADD COLUMN bg_type VARCHAR(20) DEFAULT 'inherit';
ALTER TABLE website_sections ADD COLUMN bg_color VARCHAR(7);
ALTER TABLE website_sections ADD COLUMN bg_gradient_from VARCHAR(7);
ALTER TABLE website_sections ADD COLUMN bg_gradient_to VARCHAR(7);
ALTER TABLE website_sections ADD COLUMN bg_gradient_angle SMALLINT DEFAULT 180;
ALTER TABLE website_sections ADD COLUMN bg_image_path VARCHAR(500);
ALTER TABLE website_sections ADD COLUMN bg_overlay_opacity SMALLINT DEFAULT 60;
ALTER TABLE website_sections ADD COLUMN bg_video_url VARCHAR(500);
ALTER TABLE website_sections ADD CONSTRAINT website_sections_bg_type_check
CHECK (bg_type IN ('inherit', 'solid', 'gradient', 'image', 'video'));
```
**Files to Modify**:
- `app/Domain/Website/Models/WebsiteSection.php` — add to $fillable + $casts
- `app/Livewire/Website/SectionManager.php` — add bg editing fields to section editor modal
- `resources/views/livewire/website/section-manager.blade.php` — add background config panel (shown per-section in edit mode)
- All 16 section partials in `resources/views/website/sections/*.blade.php` — wrap content in a container that applies the background
**Rendering Logic** (create a shared partial `resources/views/website/partials/section-bg.blade.php`):
```blade
@php
$bgStyle = match($section->bg_type) {
'solid' => "background-color: {$section->bg_color};",
'gradient' => "background: linear-gradient({$section->bg_gradient_angle}deg, {$section->bg_gradient_from}, {$section->bg_gradient_to});",
'image' => "background-image: url('" . Storage::disk('public')->url($section->bg_image_path) . "'); background-size: cover; background-position: center;",
default => '',
};
@endphp
<div style="{{ $bgStyle }}" class="relative">
@if($section->bg_type === 'image' && $section->bg_overlay_opacity > 0)
<div class="absolute inset-0 bg-black" style="opacity: {{ $section->bg_overlay_opacity / 100 }}"></div>
@endif
@if($section->bg_type === 'video' && $section->bg_video_url)
<video autoplay muted loop playsinline class="absolute inset-0 w-full h-full object-cover">
<source src="{{ $section->bg_video_url }}" type="video/mp4">
</video>
<div class="absolute inset-0 bg-black" style="opacity: {{ $section->bg_overlay_opacity / 100 }}"></div>
@endif
<div class="relative z-10">
{{ $slot }}
</div>
</div>
```
---
### UPGRADE 5: Spacing & Density Control
**What**: Global density slider + per-section padding override.
**Database Changes**:
```sql
-- Migration: add to website_settings
ALTER TABLE website_settings ADD COLUMN density VARCHAR(10) DEFAULT 'comfortable';
ALTER TABLE website_settings ADD CONSTRAINT website_settings_density_check
CHECK (density IN ('compact', 'comfortable', 'spacious'));
-- Add to website_sections
ALTER TABLE website_sections ADD COLUMN padding_y VARCHAR(10) DEFAULT 'inherit';
ALTER TABLE website_sections ADD CONSTRAINT website_sections_padding_y_check
CHECK (padding_y IN ('inherit', 'none', 'small', 'medium', 'large', 'xlarge'));
```
**Density CSS Mapping**:
```css
[data-density="compact"] { --section-py: 3rem; --card-gap: 1rem; --element-gap: 0.5rem; }
[data-density="comfortable"]{ --section-py: 5rem; --card-gap: 1.5rem; --element-gap: 1rem; }
[data-density="spacious"] { --section-py: 8rem; --card-gap: 2.5rem; --element-gap: 1.5rem; }
```
**Per-section padding_y override**:
```css
.section-pad-none { padding-top: 0; padding-bottom: 0; }
.section-pad-small { padding-top: 2rem; padding-bottom: 2rem; }
.section-pad-medium { padding-top: 4rem; padding-bottom: 4rem; }
.section-pad-large { padding-top: 6rem; padding-bottom: 6rem; }
.section-pad-xlarge { padding-top: 10rem; padding-bottom: 10rem; }
```
**Files to Modify**:
- `app/Domain/Website/Models/WebsiteSetting.php` — add `density` to $fillable
- `app/Domain/Website/Models/WebsiteSection.php` — add `padding_y` to $fillable
- `app/Livewire/Website/ThemeEditor.php` — add density radio group
- `app/Livewire/Website/SectionManager.php` — add padding_y select in section editor
- `resources/views/website/layout.blade.php` — add `data-density="{{ $settings->density }}"` to `<body>`
- `resources/views/website/index.blade.php` — add padding class to each section wrapper
---
### UPGRADE 6: Border & Shape System
**What**: Global border-radius preset, card styles, section dividers, image shapes.
**Database Changes**:
```sql
-- Migration: add to website_settings
ALTER TABLE website_settings ADD COLUMN border_radius_preset VARCHAR(10) DEFAULT 'rounded';
ALTER TABLE website_settings ADD COLUMN card_style VARCHAR(10) DEFAULT 'raised';
ALTER TABLE website_settings ADD COLUMN section_divider VARCHAR(10) DEFAULT 'none';
ALTER TABLE website_settings ADD COLUMN image_shape VARCHAR(10) DEFAULT 'rounded';
ALTER TABLE website_settings ADD CONSTRAINT website_settings_border_radius_preset_check
CHECK (border_radius_preset IN ('sharp', 'subtle', 'rounded', 'pill'));
ALTER TABLE website_settings ADD CONSTRAINT website_settings_card_style_check
CHECK (card_style IN ('flat', 'raised', 'bordered', 'glass'));
ALTER TABLE website_settings ADD CONSTRAINT website_settings_section_divider_check
CHECK (section_divider IN ('none', 'line', 'wave', 'angle', 'curve'));
ALTER TABLE website_settings ADD CONSTRAINT website_settings_image_shape_check
CHECK (image_shape IN ('square', 'rounded', 'circle', 'blob'));
```
**CSS Token Mapping**:
```css
[data-radius="sharp"] { --site-radius: 0px; --site-radius-lg: 0px; }
[data-radius="subtle"] { --site-radius: 4px; --site-radius-lg: 8px; }
[data-radius="rounded"] { --site-radius: 12px; --site-radius-lg: 20px; }
[data-radius="pill"] { --site-radius: 9999px; --site-radius-lg: 9999px; }
[data-card="flat"] { --card-shadow: none; --card-border: none; --card-bg: transparent; }
[data-card="raised"] { --card-shadow: 0 4px 20px rgba(0,0,0,0.15); --card-border: none; }
[data-card="bordered"] { --card-shadow: none; --card-border: 1px solid var(--site-border); }
[data-card="glass"] { --card-shadow: 0 8px 32px rgba(0,0,0,0.1); --card-border: 1px solid rgba(255,255,255,0.1); --card-bg: rgba(255,255,255,0.05); backdrop-filter: blur(10px); }
```
**Section Dividers**: SVG shapes rendered between sections. Create `resources/views/website/partials/divider.blade.php`:
```blade
@if($settings->section_divider !== 'none')
@include("website.partials.dividers.{$settings->section_divider}")
@endif
```
Each divider is an SVG: `wave.blade.php`, `angle.blade.php`, `curve.blade.php`, `line.blade.php`.
**Files to Modify**:
- `app/Domain/Website/Models/WebsiteSetting.php` — add 4 new columns to $fillable
- `app/Livewire/Website/ThemeEditor.php` — add 4 new properties with select options
- `resources/views/website/layout.blade.php` — add data attributes to body
- `resources/css/website.css` — use CSS tokens throughout
- `resources/views/website/index.blade.php` — include divider between sections
- Create: `resources/views/website/partials/dividers/{wave,angle,curve,line}.blade.php`
---
### UPGRADE 7: Animation & Motion Control
**What**: Per-section entrance animations with timing control + global motion toggle.
**Database Changes**:
```sql
-- Migration: add to website_settings
ALTER TABLE website_settings ADD COLUMN animations_enabled BOOLEAN DEFAULT true;
ALTER TABLE website_settings ADD COLUMN animation_speed VARCHAR(10) DEFAULT 'normal';
ALTER TABLE website_settings ADD CONSTRAINT website_settings_animation_speed_check
CHECK (animation_speed IN ('slow', 'normal', 'fast'));
-- Add to website_sections
ALTER TABLE website_sections ADD COLUMN animation VARCHAR(20) DEFAULT 'fade-up';
ALTER TABLE website_sections ADD CONSTRAINT website_sections_animation_check
CHECK (animation IN ('none', 'fade-up', 'fade-down', 'fade-left', 'fade-right', 'zoom-in', 'flip', 'bounce'));
```
**Animation Speed CSS**:
```css
[data-anim-speed="slow"] { --anim-duration: 1.2s; --anim-delay-step: 200ms; }
[data-anim-speed="normal"] { --anim-duration: 0.8s; --anim-delay-step: 100ms; }
[data-anim-speed="fast"] { --anim-duration: 0.4s; --anim-delay-step: 50ms; }
```
**Files to Modify**:
- `app/Domain/Website/Models/WebsiteSetting.php` — add to $fillable
- `app/Domain/Website/Models/WebsiteSection.php` — add `animation` to $fillable
- `app/Livewire/Website/ThemeEditor.php` — add animations_enabled toggle + speed select
- `app/Livewire/Website/SectionManager.php` — add animation select per section
- `resources/views/website/index.blade.php` — add `data-animation="{{ $section->animation }}"` to section wrapper
- `resources/js/website.js` — refactor IntersectionObserver to read animation type from data attr, respect `animations_enabled` via `data-animations` on body
- `resources/css/website.css` — define keyframes for each animation type
---
### UPGRADE 8: Hero Section Variants (1 → 8 Layouts)
**What**: Multiple hero layout options selectable from admin.
**Implementation**: Store hero variant in section settings JSON (no migration needed — `settings` is already JSONB).
**Settings JSON for hero section**:
```json
{
"variant": "split_right",
"overlay_opacity": 60,
"cta_text": "ابدأ الآن",
"cta_link": "#contact",
"show_scroll_indicator": true,
"text_alignment": "start"
}
```
**Variants**:
| Variant | Description |
|---------|-------------|
| `fullscreen` | Full viewport bg image, centered text overlay, CTA (current default) |
| `split_right` | Text left 50%, image right 50% |
| `split_left` | Image left 50%, text right 50% |
| `centered_minimal` | No image, centered text on solid/gradient bg, large typography |
| `video_bg` | Video background with text overlay |
| `slideshow` | Multiple images auto-rotating (images from gallery with tag 'hero') |
| `text_typing` | Animated typing effect on subtitle, minimal bg |
| `countdown` | Event-focused with countdown timer to a date |
**Files to Create**:
- `resources/views/website/sections/hero/fullscreen.blade.php`
- `resources/views/website/sections/hero/split_right.blade.php`
- `resources/views/website/sections/hero/split_left.blade.php`
- `resources/views/website/sections/hero/centered_minimal.blade.php`
- `resources/views/website/sections/hero/video_bg.blade.php`
- `resources/views/website/sections/hero/slideshow.blade.php`
- `resources/views/website/sections/hero/text_typing.blade.php`
- `resources/views/website/sections/hero/countdown.blade.php`
**Files to Modify**:
- `resources/views/website/sections/hero.blade.php` — change to: `@include("website.sections.hero.{$section->getSetting('variant', 'fullscreen')}")`
- `app/Livewire/Website/SectionManager.php` — add variant picker when editing hero section
---
### UPGRADE 9: Multi-Column Layout Per Section
**What**: Each content section gets a layout picker for how its items are arranged.
**Implementation**: Store in section `settings` JSON under key `layout`.
**Available Layouts** (per section type that shows multiple items: activities, programs, branches, trainers, news, pricing, partners):
```json
{
"layout": "grid_3",
"items_per_row": 3
}
```
| Layout | Description |
|--------|-------------|
| `grid_2` | 2-column grid |
| `grid_3` | 3-column grid (current default) |
| `grid_4` | 4-column grid |
| `list` | Single column, horizontal cards |
| `masonry` | Pinterest-style staggered |
| `carousel` | Horizontal slider with arrows |
| `alternating` | Zigzag left-right |
**Files to Modify**:
- `app/Livewire/Website/SectionManager.php` — add layout select for applicable sections
- `resources/views/website/sections/activities.blade.php` — switch grid class based on `$section->getSetting('layout', 'grid_3')`
- Same for: `programs.blade.php`, `branches.blade.php`, `trainers.blade.php`, `news.blade.php`, `pricing.blade.php`
- `resources/css/website.css` — add masonry and carousel styles
**Grid CSS**:
```css
.site-grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); }
.site-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); }
.site-grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); }
.site-list { display: flex; flex-direction: column; }
.site-masonry { columns: 3; column-gap: var(--card-gap); }
.site-carousel { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; }
```
All grids collapse to 1 column on mobile (< 640px) and 2 on tablet (< 1024px).
---
### UPGRADE 10: Navbar Variants (3 → 8 Styles)
**What**: Expand navbar options with more visual styles and configuration.
**Database Changes**:
```sql
-- Migration: update CHECK constraint
ALTER TABLE website_settings DROP CONSTRAINT website_settings_navbar_style_check;
ALTER TABLE website_settings ADD CONSTRAINT website_settings_navbar_style_check
CHECK (navbar_style IN ('solid', 'transparent', 'floating', 'centered', 'hamburger_always', 'side_drawer', 'minimal', 'mega'));
ALTER TABLE website_settings ADD COLUMN navbar_cta_text VARCHAR(100);
ALTER TABLE website_settings ADD COLUMN navbar_cta_link VARCHAR(500);
ALTER TABLE website_settings ADD COLUMN navbar_show_language BOOLEAN DEFAULT true;
ALTER TABLE website_settings ADD COLUMN navbar_show_social BOOLEAN DEFAULT false;
ALTER TABLE website_settings ADD COLUMN navbar_logo_position VARCHAR(10) DEFAULT 'start';
ALTER TABLE website_settings ADD CONSTRAINT website_settings_navbar_logo_position_check
CHECK (navbar_logo_position IN ('start', 'center'));
```
**Navbar Variants**:
| Style | Description |
|-------|-------------|
| `solid` | Solid background always visible (current) |
| `transparent` | Transparent on hero, solid on scroll (current) |
| `floating` | Detached from top with margin and rounded corners (current) |
| `centered` | Logo centered, nav links split left/right |
| `hamburger_always` | Always shows hamburger menu even on desktop |
| `side_drawer` | Permanent sidebar navigation |
| `minimal` | Only logo + CTA button, no section links |
| `mega` | Full-width dropdown with rich content panels |
**Files to Create**:
- `resources/views/website/navbars/solid.blade.php`
- `resources/views/website/navbars/transparent.blade.php`
- `resources/views/website/navbars/floating.blade.php`
- `resources/views/website/navbars/centered.blade.php`
- `resources/views/website/navbars/hamburger_always.blade.php`
- `resources/views/website/navbars/side_drawer.blade.php`
- `resources/views/website/navbars/minimal.blade.php`
- `resources/views/website/navbars/mega.blade.php`
**Files to Modify**:
- `resources/views/website/navbar.blade.php` — change to: `@include("website.navbars.{$settings->navbar_style}")`
- `app/Livewire/Website/ThemeEditor.php` — add new navbar config fields
- `app/Domain/Website/Models/WebsiteSetting.php` — add new columns to $fillable
---
### UPGRADE 11: Footer Builder
**What**: Configurable footer with column layout and content blocks.
**Database Changes**:
```sql
-- Migration: add to website_settings
ALTER TABLE website_settings ADD COLUMN footer_columns SMALLINT DEFAULT 4;
ALTER TABLE website_settings ADD COLUMN footer_blocks JSONB DEFAULT '[]';
ALTER TABLE website_settings ADD COLUMN footer_bottom_text VARCHAR(500);
ALTER TABLE website_settings ADD COLUMN footer_style VARCHAR(10) DEFAULT 'dark';
ALTER TABLE website_settings ADD CONSTRAINT website_settings_footer_style_check
CHECK (footer_style IN ('dark', 'light', 'accent', 'transparent'));
```
**Footer Blocks JSON Schema**:
```json
[
{"type": "about", "content": "نبذة مختصرة عن الأكاديمية..."},
{"type": "links", "title": "روابط سريعة", "links": [{"label": "الرئيسية", "url": "#hero"}, ...]},
{"type": "contact", "title": "تواصل معنا"},
{"type": "social", "title": "تابعنا"},
{"type": "hours", "title": "ساعات العمل", "hours": [{"day": "السبت - الخميس", "time": "8ص - 10م"}]},
{"type": "newsletter", "title": "النشرة البريدية"}
]
```
Block types: `about`, `links`, `contact`, `social`, `hours`, `newsletter`, `map_embed`
**Files to Create**:
- `resources/views/website/footers/dark.blade.php`
- `resources/views/website/footers/light.blade.php`
- `resources/views/website/footers/accent.blade.php`
- `resources/views/website/footers/transparent.blade.php`
**Files to Modify**:
- `resources/views/website/footer.blade.php` — change to include footer style variant
- `app/Livewire/Website/ThemeEditor.php` — add footer configuration section
- `app/Domain/Website/Models/WebsiteSetting.php` — add columns to $fillable, cast `footer_blocks` as array
---
### UPGRADE 12: Floating Elements & Overlays
**What**: Configurable floating buttons, announcement bar, and popup modals.
**Database Changes**:
```sql
-- Migration: add to website_settings
ALTER TABLE website_settings ADD COLUMN floating_elements JSONB DEFAULT '{}';
ALTER TABLE website_settings ADD COLUMN announcement_bar JSONB DEFAULT '{}';
ALTER TABLE website_settings ADD COLUMN popup_config JSONB DEFAULT '{}';
```
**Floating Elements JSON**:
```json
{
"whatsapp": {"enabled": true, "number": "+201012345678", "message": "مرحبا، أريد الاستفسار عن..."},
"scroll_to_top": {"enabled": true, "style": "circle"},
"custom_button": {"enabled": false, "text": "سجل الآن", "url": "#contact", "color": "#e94560", "icon": "phone"}
}
```
**Announcement Bar JSON**:
```json
{
"enabled": true,
"text": "خصم 20% على التسجيل المبكر!",
"link": "#pricing",
"bg_color": "#e94560",
"text_color": "#ffffff",
"dismissible": true,
"show_until": "2026-08-01"
}
```
**Popup Config JSON**:
```json
{
"enabled": false,
"trigger": "timer",
"delay_seconds": 5,
"title": "لا تفوت العرض!",
"body": "سجل الآن واحصل على خصم...",
"cta_text": "سجل الآن",
"cta_link": "#contact",
"image_path": null,
"show_once": true
}
```
**Files to Create**:
- `resources/views/website/partials/announcement-bar.blade.php`
- `resources/views/website/partials/popup-modal.blade.php`
- `resources/views/website/partials/floating-elements.blade.php`
**Files to Modify**:
- `resources/views/website/layout.blade.php` — include the 3 partials
- `app/Livewire/Website/ThemeEditor.php` — add sections for floating elements, announcement bar, popup
- `app/Domain/Website/Models/WebsiteSetting.php` — add to $fillable, cast as array
- `resources/js/website.js` — popup trigger logic (timer, scroll %, exit-intent)
---
### UPGRADE 13: Statistics/Counters Section Enhancement
**What**: Allow manual counter values with icons + auto-pull from system data.
**Implementation**: Enhance the existing `stats` section settings JSON.
**Current state**: Stats section already exists and auto-pulls (participants, trainers, branches, programs, activities) from `WebsiteDataService::getStats()`.
**Upgrade**: Allow admin to define custom counters OR override auto values.
**Settings JSON for stats section**:
```json
{
"mode": "custom",
"counters": [
{"icon": "users", "value": 500, "label": "لاعب مسجل", "suffix": "+"},
{"icon": "trophy", "value": 15, "label": "بطولة", "suffix": ""},
{"icon": "map-pin", "value": 4, "label": "فرع", "suffix": ""},
{"icon": "calendar", "value": 8, "label": "سنوات خبرة", "suffix": "+"}
],
"auto_counters": ["participants", "trainers", "branches", "programs"]
}
```
Mode: `auto` (pulls from DB), `custom` (admin enters numbers), `mixed` (some auto + some custom).
**Files to Modify**:
- `app/Livewire/Website/SectionManager.php` — add counter CRUD UI when editing stats section
- `resources/views/livewire/website/section-manager.blade.php` — add counter list with add/remove/edit
- `resources/views/website/sections/stats.blade.php` — render based on mode, support custom icons
**Available Icons** (heroicons solid names): `users`, `trophy`, `map-pin`, `calendar`, `academic-cap`, `heart`, `star`, `bolt`, `clock`, `globe-alt`, `building-office`, `shield-check`
---
### UPGRADE 14: Schedule/Timetable Widget Enhancement
**What**: Replace the raw JSON table with a proper visual timetable that can auto-pull from training group schedules.
**Implementation**: Add auto-pull mode from actual `group_schedules` table.
**Settings JSON for schedule section**:
```json
{
"mode": "auto",
"display": "weekly_grid",
"filter_by_branch": null,
"show_age_groups": true,
"color_by": "activity"
}
```
Display modes: `weekly_grid` (calendar-like), `list` (simple table like current), `cards_by_day`
**When mode = "auto"**:
- Query `training_groups` with status='active', join `group_schedules` for day_of_week + start_time + end_time
- Group by day, show activity name + time + trainer + age range
- Respect branch filter if set
**Files to Modify**:
- `app/Domain/Website/Services/WebsiteDataService.php` — add `getScheduleData()` method that queries real group_schedules
- `app/Livewire/Website/SectionManager.php` — add schedule config options
- `resources/views/website/sections/schedule.blade.php` — rewrite with 3 display modes
- `resources/css/website.css` — add timetable grid styles
---
### UPGRADE 15: Pricing Section Enhancement
**What**: Proper CRUD UI for pricing plans (currently raw JSON in settings), toggle period options, connect to real pricing engine data.
**Current state**: Pricing section stores plans in `settings` JSON as a raw JSON string that admin types. No proper form UI.
**Upgrade**: Build a proper plan editor with form fields.
**Settings JSON for pricing section**:
```json
{
"mode": "manual",
"show_period_toggle": true,
"periods": ["monthly", "quarterly", "annual"],
"plans": [
{
"name": "البرنامج الأساسي",
"prices": {"monthly": 150000, "quarterly": 400000, "annual": 1400000},
"features": ["3 حصص أسبوعيًا", "زي التمرين", "شهادة إتمام"],
"highlighted": false,
"badge": null,
"cta_text": "اشترك الآن",
"cta_link": "#contact"
}
]
}
```
Note: prices stored in piasters (integer). Display with `format_money()`.
Mode `auto`: pull from `base_prices` table + `training_programs` and display active program prices.
**Files to Modify**:
- `app/Livewire/Website/SectionManager.php` — build Alpine.js plan editor (add/remove plans, add/remove features, price inputs per period)
- `resources/views/livewire/website/section-manager.blade.php` — plan editor UI
- `resources/views/website/sections/pricing.blade.php` — add period toggle, badge, and proper rendering
- `resources/js/website.js` — period toggle interaction
---
### UPGRADE 16: Trainers/Team Section Enhancement
**What**: Proper team CRUD (currently raw JSON) with photo upload and linking to actual system trainers.
**Current state**: Trainers section stores team in `settings` JSON. No photo upload.
**Upgrade**: Two modes — manual (admin enters) or auto (pull from `employees` table where role = trainer).
**Settings JSON**:
```json
{
"mode": "auto",
"max_display": 8,
"show_bio": true,
"show_certifications": false,
"layout": "grid_4",
"card_style": "hover_reveal"
}
```
Card styles: `simple` (photo + name + role), `hover_reveal` (bio shows on hover), `full_card` (always shows everything)
**When mode = "auto"**:
- Query employees with active trainer_profile, join person for name/photo
- Use team_photo media collection for images
- Show: name, role/specialization, certifications if enabled
**Files to Modify**:
- `app/Domain/Website/Services/WebsiteDataService.php` — add `getTrainersData()` method
- `app/Livewire/Website/SectionManager.php` — add team mode toggle + config
- `resources/views/website/sections/trainers.blade.php` — rewrite with auto/manual modes + card styles
---
### UPGRADE 17: Gallery Section Enhancement
**What**: Filterable gallery with categories, lightbox improvements, video support, and layout options.
**Database Changes**:
```sql
-- Migration: add category to media
ALTER TABLE media ADD COLUMN gallery_category VARCHAR(50);
```
**Implementation**:
- Gallery images get optional `gallery_category` (e.g., "تدريبات", "بطولات", "معسكرات")
- Public view shows filter tabs
- Support video items (YouTube/MP4 URL stored in media alt_text_ar field or a new json metadata column)
**Settings JSON for gallery section**:
```json
{
"layout": "masonry",
"show_filters": true,
"categories": ["تدريبات", "بطولات", "معسكرات", "الفريق"],
"show_captions": false,
"items_per_page": 12,
"lightbox_style": "full"
}
```
Layouts: `masonry`, `grid`, `slider`, `justified`
**Files to Modify**:
- `app/Domain/Website/Models/Media.php` — add `gallery_category` to $fillable
- `app/Livewire/Website/GalleryManager.php` — add category assignment per image, caption editing, video URL field
- `resources/views/livewire/website/gallery-manager.blade.php` — add category dropdown per image
- `resources/views/website/sections/gallery.blade.php` — add filter tabs + layout variants + video support
- `resources/css/website.css` — masonry, justified, slider styles
- `resources/js/website.js` — filter tab click handler, video lightbox
---
### UPGRADE 18: Testimonials Section Enhancement
**What**: Multiple display layouts, video testimonials, avatar upload in admin.
**Current state**: Testimonial model exists with CRUD. Public renders as carousel. Avatar morphOne exists but no upload UI.
**Upgrade**:
**Settings JSON for testimonials section**:
```json
{
"layout": "carousel",
"show_rating": true,
"show_avatar": true,
"auto_rotate": true,
"rotate_speed": 5000
}
```
Layouts: `carousel` (current), `grid`, `wall_of_love` (masonry of quotes), `featured_quote` (one big + smaller ones), `video_carousel`
**Database Changes**:
```sql
-- Migration: add video_url to website_testimonials
ALTER TABLE website_testimonials ADD COLUMN video_url VARCHAR(500);
```
**Files to Modify**:
- `app/Domain/Website/Models/WebsiteTestimonial.php` — add `video_url` to $fillable
- `app/Livewire/Website/TestimonialManager.php` — add avatar upload (use MediaService), add video_url field
- `resources/views/livewire/website/testimonial-manager.blade.php` — add avatar upload + video URL input
- `resources/views/website/sections/testimonials.blade.php` — switch layout variants, render video embeds
- `app/Livewire/Website/SectionManager.php` — add testimonial section layout settings
---
### UPGRADE 19: FAQ Section Enhancement
**What**: Categorized FAQs, search within FAQs, multiple visual styles.
**Database Changes**:
```sql
-- Migration: add category to website_faqs
ALTER TABLE website_faqs ADD COLUMN category VARCHAR(100);
ALTER TABLE website_faqs ADD COLUMN category_en VARCHAR(100);
```
**Settings JSON for FAQ section**:
```json
{
"layout": "accordion",
"show_categories": true,
"show_search": true,
"expand_first": true
}
```
Layouts: `accordion` (current), `two_column`, `tabbed_categories`, `cards`
**Files to Modify**:
- `app/Domain/Website/Models/WebsiteFaq.php` — add `category`, `category_en` to $fillable
- `app/Livewire/Website/FaqManager.php` — add category field
- `resources/views/website/sections/faq.blade.php` — add search input (Alpine.js x-model filter), category tabs, layout variants
- `resources/js/website.js` — FAQ search filtering logic (client-side)
---
### UPGRADE 20: News/Blog Section Enhancement
**What**: Blog detail pages, featured image upload, excerpt display, categories.
**Database Changes**:
```sql
-- Migration: add category to website_news
ALTER TABLE website_news ADD COLUMN category VARCHAR(100);
ALTER TABLE website_news ADD COLUMN category_en VARCHAR(100);
```
**Routes to Add** (in web.php under the public site group):
```php
Route::get('/site/{slug}/news', [PublicWebsiteController::class, 'newsList'])->name('website.news.index');
Route::get('/site/{slug}/news/{newsSlug}', [PublicWebsiteController::class, 'newsShow'])->name('website.news.show');
```
**Files to Create**:
- `resources/views/website/news-list.blade.php` — paginated news listing page
- `resources/views/website/news-show.blade.php` — single article detail page with image, body, related articles
**Files to Modify**:
- `app/Http/Controllers/PublicWebsiteController.php` — add `newsList()` and `newsShow()` methods
- `app/Domain/Website/Models/WebsiteNews.php` — add `category`, `category_en` to $fillable
- `app/Livewire/Website/NewsManager.php` — add featured image upload (use MediaService), category field
- `resources/views/website/sections/news.blade.php` — add "View All" link to news listing page
- `resources/views/website/navbar.blade.php` — add conditional "News" nav link
---
### UPGRADE 21: Contact Section Enhancement
**What**: Multiple form layouts, configurable fields, map embed, branch selector.
**Current state**: Fixed form with name, phone, email, message fields. Alpine.js AJAX submit.
**Upgrade**:
**Settings JSON for contact section**:
```json
{
"layout": "split",
"show_map": true,
"map_embed_url": "https://maps.google.com/maps?q=...",
"show_branch_selector": true,
"fields": [
{"key": "name", "type": "text", "label": "الاسم", "required": true},
{"key": "phone", "type": "tel", "label": "الهاتف", "required": true},
{"key": "email", "type": "email", "label": "البريد", "required": false},
{"key": "sport", "type": "select", "label": "الرياضة", "required": false, "options": ["كرة قدم", "سباحة", "كاراتيه"]},
{"key": "message", "type": "textarea", "label": "الرسالة", "required": true}
],
"success_message": "شكرًا! سنتواصل معك قريبًا"
}
```
Layouts: `split` (form left + info right, current), `centered` (form only, centered), `full_width` (form + map side by side), `cards` (form in a card with branch cards)
**Files to Modify**:
- `resources/views/website/sections/contact.blade.php` — rewrite with dynamic field rendering, layout switch, map embed
- `app/Livewire/Website/SectionManager.php` — add contact form field builder (add/remove fields, set type/required)
- `app/Http/Controllers/ContactFormController.php` — validate dynamically based on section settings fields config
- `resources/js/website.js` — update AJAX handler to collect dynamic fields
---
### UPGRADE 22: Multi-Page Support
**What**: Allow academies to have multiple pages beyond the single scrolling homepage.
**Database Changes**:
```sql
-- New table: website_pages
CREATE TABLE website_pages (
id BIGSERIAL PRIMARY KEY,
uuid UUID UNIQUE NOT NULL,
academy_id BIGINT NOT NULL REFERENCES academies(id),
title VARCHAR(255) NOT NULL,
title_en VARCHAR(255),
slug VARCHAR(100) NOT NULL,
page_type VARCHAR(20) NOT NULL DEFAULT 'custom',
sections JSONB DEFAULT '[]',
seo_title VARCHAR(255),
seo_description TEXT,
og_image_path VARCHAR(500),
is_in_nav BOOLEAN DEFAULT true,
nav_order SMALLINT DEFAULT 0,
is_published BOOLEAN DEFAULT true,
created_at TIMESTAMP,
updated_at TIMESTAMP,
deleted_at TIMESTAMP,
UNIQUE(academy_id, slug)
);
ALTER TABLE website_pages ADD CONSTRAINT website_pages_page_type_check
CHECK (page_type IN ('home', 'custom', 'about', 'gallery', 'team', 'contact', 'blank'));
```
**Sections column**: Array of section_key strings that appear on this page. The existing `website_sections` table remains the source of section content — pages just reference which sections to show and in what order.
**For homepage**: `page_type = 'home'`, uses existing section ordering from `website_sections.sort_order`.
**Routes to Add**:
```php
Route::get('/site/{slug}/{pageSlug}', [PublicWebsiteController::class, 'page'])->name('website.page');
```
**Files to Create**:
- `app/Domain/Website/Models/WebsitePage.php`
- `app/Livewire/Website/PageManager.php` — CRUD for pages, section assignment, nav order
- `resources/views/livewire/website/page-manager.blade.php`
- `resources/views/website/page.blade.php` — renders a custom page with its assigned sections
**Files to Modify**:
- `app/Http/Controllers/PublicWebsiteController.php` — add `page()` method
- `resources/views/website/navbar.blade.php` — dynamically render nav links from `website_pages` where `is_in_nav = true`
- `routes/web.php` — add page route
---
### UPGRADE 23: Video Embed Support
**What**: Allow embedding YouTube/Vimeo videos in any section + a dedicated video section.
**Database Changes**:
```sql
-- Add new section_key
-- Migration: update CHECK constraint on website_sections.section_key
ALTER TABLE website_sections DROP CONSTRAINT website_sections_section_key_check;
ALTER TABLE website_sections ADD CONSTRAINT website_sections_section_key_check
CHECK (section_key IN (
'hero', 'about', 'activities', 'programs', 'branches', 'schedule',
'trainers', 'gallery', 'testimonials', 'pricing', 'partners',
'contact', 'faq', 'cta', 'stats', 'news', 'video'
));
```
**Add to SectionKey enum**: `Video` case with label "فيديو" and icon "play-circle".
**Settings JSON for video section**:
```json
{
"layout": "featured",
"videos": [
{"url": "https://youtube.com/watch?v=...", "title": "حفل التكريم", "thumbnail": null},
{"url": "https://youtube.com/watch?v=...", "title": "ملخص الموسم", "thumbnail": null}
],
"autoplay": false,
"show_titles": true
}
```
Layouts: `featured` (one big + thumbnails below), `grid` (equal-size grid), `carousel`, `single` (just one video, full-width)
**Helper to extract YouTube/Vimeo embed URL**:
```php
function video_embed_url(string $url): ?string
{
// YouTube
if (preg_match('/(?:youtube\.com\/watch\?v=|youtu\.be\/)([\w-]+)/', $url, $m)) {
return "https://www.youtube.com/embed/{$m[1]}";
}
// Vimeo
if (preg_match('/vimeo\.com\/(\d+)/', $url, $m)) {
return "https://player.vimeo.com/video/{$m[1]}";
}
return null;
}
```
**Files to Create**:
- `resources/views/website/sections/video.blade.php`
**Files to Modify**:
- `app/Domain/Website/Enums/SectionKey.php` — add `Video` case
- `app/Domain/Website/Services/WebsiteSectionService.php` — include video in seedDefaults
- `app/Livewire/Website/SectionManager.php` — add video URL list editor for video section
- Potentially `app/helpers.php` — add `video_embed_url()` helper
---
### UPGRADE 24: Branch Locator with Map
**What**: Interactive branch display with map, directions, and per-branch details.
**Current state**: Branches section exists and pulls from `branches` table (name, address, phone via WebsiteDataService).
**Upgrade**:
**Database Changes**:
```sql
-- Migration: add lat/lng to branches if not exists
ALTER TABLE branches ADD COLUMN IF NOT EXISTS latitude DECIMAL(10, 8);
ALTER TABLE branches ADD COLUMN IF NOT EXISTS longitude DECIMAL(11, 8);
ALTER TABLE branches ADD COLUMN IF NOT EXISTS operating_hours JSONB DEFAULT '{}';
```
**Settings JSON for branches section**:
```json
{
"layout": "map_and_cards",
"show_map": true,
"show_hours": true,
"show_phone": true,
"show_directions_link": true,
"map_zoom": 12,
"map_style": "default"
}
```
Layouts: `cards` (current), `map_and_cards` (map on one side + card list), `map_fullwidth` (map top + cards below), `list`
**Map Implementation**: Use Leaflet.js (free, no API key) with OpenStreetMap tiles. Markers for each branch with lat/lng.
**Files to Modify**:
- `resources/views/website/sections/branches.blade.php` — add map div + cards layout variant
- `resources/js/website.js` — add Leaflet map initialization (conditionally loaded)
- `resources/views/website/layout.blade.php` — conditionally load Leaflet CSS/JS
- `app/Domain/Website/Services/WebsiteDataService.php` — include lat/lng/hours in branch data
---
### UPGRADE 25: Social Proof & Trust Signals Enhancement
**What**: Upgrade partners section with animated carousel, add achievements/awards display, media mentions.
**Current state**: Partners section shows logo images in a static/animated track.
**Upgrade**:
**Settings JSON for partners section**:
```json
{
"layout": "auto_scroll",
"scroll_speed": 30,
"show_names": false,
"grayscale_until_hover": true,
"rows": 1,
"achievements": [
{"icon": "trophy", "title": "بطل الجمهورية", "year": "2024"},
{"icon": "medal", "title": "أفضل أكاديمية", "year": "2023"}
],
"certifications": [
{"name": "وزارة الشباب والرياضة", "image_path": null}
]
}
```
Layouts: `auto_scroll` (infinite horizontal scroll), `grid` (static grid), `carousel` (with arrows), `featured` (one large + others small)
**Files to Modify**:
- `resources/views/website/sections/partners.blade.php` — add grayscale effect, layout variants, achievements subsection
- `resources/css/website.css` — grayscale hover effect, scroll animation speed variable
- `app/Livewire/Website/SectionManager.php` — add achievements CRUD in partners section settings
- `app/Livewire/Website/PartnerManager.php` — ensure logo upload works (currently logo morphOne exists but verify upload UI)
---
### UPGRADE 26: Language Switcher on Public Site
**What**: Add a functional AR/EN language toggle on the public website.
**Current state**: Content is stored bilingually (title + title_en, etc.) but the public site always renders Arabic. The English URL `oc-sport.com/en` comes from their external WordPress — NOT from our system.
**Implementation**:
**Routes**:
```php
Route::get('/site/{slug}', ...); // Default (Arabic)
Route::get('/site/{slug}/en', [PublicWebsiteController::class, 'show'])->name('website.show.en');
```
Or simpler: use query param `?lang=en` and session storage.
**Rendering Logic** (in all section views):
```blade
@php $isEn = app()->getLocale() === 'en'; @endphp
{{ $isEn ? ($section->title_en ?: $section->title) : $section->title }}
```
**Files to Modify**:
- `app/Http/Controllers/PublicWebsiteController.php` — detect locale from route/query/session, set `app()->setLocale()`
- `resources/views/website/navbar.blade.php` — add language toggle button (AR/EN)
- All 16+ section views — use locale-aware field rendering
- `resources/views/website/layout.blade.php` — set `dir` and `lang` based on locale
- `routes/web.php` — add English variant route or middleware-based locale detection
**Language Toggle UI**:
```html
<button onclick="window.location.search = '?lang=' + (currentLang === 'ar' ? 'en' : 'ar')">
{{ app()->getLocale() === 'ar' ? 'EN' : 'عربي' }}
</button>
```
---
### UPGRADE 27: SEO & Performance Controls
**What**: Per-section SEO controls, auto sitemap, structured data enhancement, image optimization toggle.
**Database Changes**:
```sql
-- Migration: add SEO columns to website_settings
ALTER TABLE website_settings ADD COLUMN seo_keywords TEXT;
ALTER TABLE website_settings ADD COLUMN og_image_path VARCHAR(500);
ALTER TABLE website_settings ADD COLUMN favicon_path VARCHAR(500);
ALTER TABLE website_settings ADD COLUMN structured_data_type VARCHAR(20) DEFAULT 'SportsActivityLocation';
ALTER TABLE website_settings ADD CONSTRAINT website_settings_structured_data_type_check
CHECK (structured_data_type IN ('SportsActivityLocation', 'SportsClub', 'Organization', 'LocalBusiness'));
```
**Files to Create**:
- `resources/views/website/partials/seo-head.blade.php` — consolidated SEO meta tags partial
**Files to Modify**:
- `app/Livewire/Website/ThemeEditor.php` — add SEO section (OG image upload, keywords, favicon upload, structured data type)
- `resources/views/website/layout.blade.php` — use seo-head partial, favicon, conditional structured data
- `app/Http/Controllers/PublicWebsiteController.php` — add `sitemap()` method that generates XML sitemap
- `routes/web.php` — add `/site/{slug}/sitemap.xml` route
**Auto-sitemap includes**: homepage, news articles (if blog pages exist), event pages.
---
### UPGRADE 28: Mobile-Specific Overrides
**What**: Hide sections on mobile, different content on mobile, responsive preview in admin.
**Database Changes**:
```sql
-- Migration: add to website_sections
ALTER TABLE website_sections ADD COLUMN hidden_on_mobile BOOLEAN DEFAULT false;
ALTER TABLE website_sections ADD COLUMN mobile_sort_order SMALLINT;
```
**Files to Modify**:
- `app/Domain/Website/Models/WebsiteSection.php` — add to $fillable, $casts
- `app/Livewire/Website/SectionManager.php` — add "hide on mobile" toggle, mobile sort order
- `resources/views/website/index.blade.php` — add `class="{{ $section->hidden_on_mobile ? 'hidden md:block' : '' }}"` to section wrapper
- `resources/views/livewire/website/section-manager.blade.php` — add mobile visibility toggle icon per section
**Admin Preview**: Add a device toggle (phone/tablet/desktop) that wraps the preview iframe in a sized container:
```html
<div x-data="{ device: 'desktop' }">
<button @click="device = 'phone'">📱</button>
<button @click="device = 'tablet'">📋</button>
<button @click="device = 'desktop'">🖥️</button>
<iframe :style="{ width: device === 'phone' ? '375px' : device === 'tablet' ? '768px' : '100%' }"
src="{{ route('website.preview') }}" class="mx-auto border"></iframe>
</div>
```
---
### UPGRADE 29: Custom Code Injection (Advanced Mode)
**What**: Header/footer code injection for tracking pixels, custom HTML blocks, enhanced custom CSS.
**Database Changes**:
```sql
-- Migration: add to website_settings
ALTER TABLE website_settings ADD COLUMN head_code TEXT;
ALTER TABLE website_settings ADD COLUMN body_start_code TEXT;
ALTER TABLE website_settings ADD COLUMN body_end_code TEXT;
```
**Current state**: `custom_css`, `google_analytics_id`, `facebook_pixel_id` already exist.
**Upgrade**: Add generic code injection areas that replace the specific GA/FB fields (keep those for backward compat but mark as "legacy" in UI).
**Custom HTML Block Section** — add new section_key:
```sql
ALTER TABLE website_sections DROP CONSTRAINT website_sections_section_key_check;
ALTER TABLE website_sections ADD CONSTRAINT website_sections_section_key_check
CHECK (section_key IN (
'hero', 'about', 'activities', 'programs', 'branches', 'schedule',
'trainers', 'gallery', 'testimonials', 'pricing', 'partners',
'contact', 'faq', 'cta', 'stats', 'news', 'video', 'custom_html'
));
```
The `custom_html` section renders its `content` field as raw HTML (admin responsibility for correctness).
**Files to Modify**:
- `app/Domain/Website/Models/WebsiteSetting.php` — add to $fillable
- `app/Livewire/Website/ThemeEditor.php` — add code injection textareas (head_code, body_start_code, body_end_code)
- `resources/views/website/layout.blade.php` — inject: `{!! $settings->head_code !!}` in `<head>`, `{!! $settings->body_start_code !!}` after `<body>`, `{!! $settings->body_end_code !!}` before `</body>`
- `app/Domain/Website/Enums/SectionKey.php` — add `CustomHtml` case
- Create: `resources/views/website/sections/custom_html.blade.php``{!! $section->content !!}`
**Security Note**: Only users with `settings.manage` permission can edit these fields. Display a warning: "الكود المخصص يُحقن مباشرة — تأكد من مصدره".
---
### UPGRADE 30: Live Preview (Side-by-Side Editor)
**What**: Replace the current "open preview in new tab" with an inline side-by-side editor that shows changes in real-time.
**Implementation**: Embed an iframe of the public site next to the editor, refresh it on save.
**Files to Create**:
- `app/Livewire/Website/LiveEditor.php` — a combined component that shows section list + theme options on one side and preview iframe on the other
- `resources/views/livewire/website/live-editor.blade.php`
**Route**:
```php
Route::get('/website/editor', \App\Livewire\Website\LiveEditor::class)->name('website.live-editor')
->middleware('permission:settings.manage');
```
**Component Logic**:
```php
class LiveEditor extends Component
{
public string $previewUrl;
public string $device = 'desktop'; // phone, tablet, desktop
public function mount(): void
{
$this->authorize('settings.manage');
$academy = app('current_academy');
$this->previewUrl = route('website.preview');
}
public function refreshPreview(): void
{
// Dispatch browser event to reload iframe
$this->dispatch('refresh-preview');
}
}
```
**View Layout**:
```html
<div class="flex h-screen">
<!-- Left: Editor Panel (scrollable) -->
<div class="w-1/3 overflow-y-auto border-e p-4">
<!-- Section list, theme controls, inline edits -->
<livewire:website.section-manager :inline="true" />
</div>
<!-- Right: Preview -->
<div class="flex-1 flex flex-col">
<div class="flex items-center gap-2 p-2 border-b">
<!-- Device toggles -->
</div>
<iframe id="preview-frame" src="{{ $previewUrl }}"
@refresh-preview.window="$el.src = $el.src"
class="flex-1 mx-auto border-0"
:style="{ width: device === 'phone' ? '375px' : device === 'tablet' ? '768px' : '100%' }">
</iframe>
</div>
</div>
```
**SectionManager modification**: Add an `$inline` property. When `true`, render a compact version suitable for the side panel (no full page layout). On every save action, dispatch `refresh-preview` event.
---
## Migration Consolidation
All database changes should be in ONE migration file per upgrade phase:
**Phase A Migration** (Upgrades 1-7):
- `database/migrations/2026_07_25_000001_website_builder_v2_theme_and_visuals.php`
**Phase B Migration** (Upgrades 8-14):
- `database/migrations/2026_07_25_000002_website_builder_v2_sections_and_layouts.php`
**Phase C Migration** (Upgrades 15-21):
- `database/migrations/2026_07_25_000003_website_builder_v2_content_enhancements.php`
**Phase D Migration** (Upgrades 22-26):
- `database/migrations/2026_07_25_000004_website_builder_v2_interactive_features.php`
**Phase E Migration** (Upgrades 27-30):
- `database/migrations/2026_07_25_000005_website_builder_v2_pro_features.php`
---
## Build Order (Phases)
| Phase | Upgrades | Description | Est. Effort |
|-------|----------|-------------|-------------|
| A | 1, 2, 3, 5, 6 | Theme engine + typography + spacing + shapes | 2 weeks |
| B | 4, 7, 8, 9, 10, 11 | Backgrounds + animations + hero variants + layouts + navbars + footer | 3 weeks |
| C | 13, 14, 15, 16, 17, 18, 19, 20, 21 | All section content enhancements | 3 weeks |
| D | 12, 22, 23, 24, 25, 26 | Floating elements + multi-page + video + map + social proof + language | 3 weeks |
| E | 27, 28, 29, 30 | SEO + mobile overrides + code injection + live editor | 2 weeks |
---
## Important Rules for Implementation
1. **NEVER break existing sites** — all new columns have defaults. Existing sections render exactly as before until admin changes settings.
2. **CSS variables are the theming backbone** — every visual property that can change must be a CSS variable set in `layout.blade.php`.
3. **Settings JSON is for section-specific config** — don't add DB columns for things that only apply to one section type. Use the existing `settings` JSONB column.
4. **Respect the BelongsToAcademy scope** — all new models/queries must be tenant-scoped.
5. **Cache invalidation** — every save in admin must call `WebsiteCacheService::invalidateAll()`.
6. **No JavaScript frameworks** — Alpine.js only for interactivity. No React/Vue.
7. **Tailwind CSS only** — no Bootstrap, no custom CSS frameworks.
8. **Mobile-first** — all layouts must be responsive. Test at 375px width.
9. **RTL-first** — use logical properties (ms/me/ps/pe), never ml/mr/pl/pr.
10. **Bilingual** — every user-facing string uses `__()`. Every content field has `_en` variant.
11. **Piasters for money** — pricing plans store integers (piasters). Display with `format_money()`.
12. **No external API dependencies** — maps use Leaflet+OSM (free), no Google Maps API key needed.
13. **Image optimization** — all uploaded images should be processed (resize to max 1920px width, compress to 80% quality) via `MediaService`.
14. **Lazy loading** — all images below the fold get `loading="lazy"`.
15. **Existing section partials** — when adding layout variants, keep the existing view as the default. Add new variants as sub-partials, selected by settings.
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