Commit 379cefca authored by Mahmoud Aglan's avatar Mahmoud Aglan

Website Builder V2 Phase A: theme engine, colors, typography, spacing, shapes

- Add 8 template presets with one-click color scheme application
- Expand color palette from 4 to 8 (add background, surface, border, muted)
- Add auto-palette generation from accent color (dark/light detection)
- Add typography controls: font size scale, heading weight, line height, letter spacing
- Add density control (compact/comfortable/spacious) affecting section padding and card gaps
- Add border radius presets (sharp/subtle/rounded/pill)
- Add card styles (flat/raised/bordered/glass)
- Add section dividers (none/line/wave/angle/curve) rendered as SVG between sections
- Add image shape control (square/rounded/circle/blob)
- Add animation toggle and speed control
- Add per-section: background type (solid/gradient/image/video), custom animation, padding override, mobile visibility toggle
- All new columns have defaults — existing sites render unchanged until admin modifies settings
- CSS variables drive all theming; public layout emits full token set
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 4343122d
......@@ -22,6 +22,17 @@ class WebsiteSection extends Model
'settings',
'sort_order',
'is_enabled',
'bg_type',
'bg_color',
'bg_gradient_from',
'bg_gradient_to',
'bg_gradient_angle',
'bg_image_path',
'bg_overlay_opacity',
'bg_video_url',
'animation',
'padding_y',
'hidden_on_mobile',
];
protected $casts = [
......@@ -29,6 +40,9 @@ class WebsiteSection extends Model
'settings' => 'array',
'sort_order' => 'integer',
'is_enabled' => 'boolean',
'bg_gradient_angle' => 'integer',
'bg_overlay_opacity' => 'integer',
'hidden_on_mobile' => 'boolean',
];
public function getSetting(string $key, $default = null)
......
......@@ -16,8 +16,23 @@ class WebsiteSetting extends Model
'secondary_color',
'accent_color',
'text_color',
'background_color',
'surface_color',
'border_color',
'muted_text_color',
'heading_font',
'body_font',
'font_size_scale',
'heading_weight',
'line_height',
'letter_spacing',
'density',
'border_radius_preset',
'card_style',
'section_divider',
'image_shape',
'animations_enabled',
'animation_speed',
'navbar_style',
'site_title',
'site_title_en',
......@@ -35,6 +50,7 @@ class WebsiteSetting extends Model
protected $casts = [
'social_links' => 'array',
'is_published' => 'boolean',
'animations_enabled' => 'boolean',
'published_at' => 'datetime',
];
}
......@@ -2,6 +2,7 @@
namespace App\Livewire\Website;
use App\Domain\Website\Services\WebsiteCacheService;
use App\Domain\Website\Services\WebsiteSettingService;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
......@@ -11,13 +12,42 @@
#[Title('تصميم الموقع')]
class ThemeEditor extends Component
{
// Template
public string $template = 'bold_athletic';
// Colors
public string $primary_color = '#1a1a2e';
public string $secondary_color = '#16213e';
public string $accent_color = '#e94560';
public string $text_color = '#ffffff';
public string $background_color = '#ffffff';
public string $surface_color = '#f8fafc';
public string $border_color = '#e2e8f0';
public string $muted_text_color = '#64748b';
// Typography
public string $heading_font = 'Cairo';
public string $body_font = 'Cairo';
public string $font_size_scale = 'medium';
public string $heading_weight = '700';
public string $line_height = 'normal';
public string $letter_spacing = 'normal';
// Spacing & Shapes
public string $density = 'comfortable';
public string $border_radius_preset = 'rounded';
public string $card_style = 'raised';
public string $section_divider = 'none';
public string $image_shape = 'rounded';
// Animation
public bool $animations_enabled = true;
public string $animation_speed = 'normal';
// Navbar
public string $navbar_style = 'transparent';
// General
public string $site_title = '';
public string $site_title_en = '';
public string $site_description = '';
......@@ -30,7 +60,19 @@ class ThemeEditor extends Component
public array $availableFonts = [
'Cairo', 'Tajawal', 'IBM Plex Sans Arabic', 'Noto Sans Arabic',
'Almarai', 'Readex Pro', 'Rubik', 'El Messiri',
'Almarai', 'Readex Pro', 'Rubik', 'El Messiri', 'Changa',
'Noto Kufi Arabic', 'Alexandria', 'Baloo Bhaijaan 2',
];
public array $templatePresets = [
'bold_athletic' => ['label' => 'رياضي جريء', 'primary' => '#1a1a2e', 'secondary' => '#16213e', 'accent' => '#e94560', 'text' => '#ffffff', 'bg' => '#0f0f1a', 'surface' => '#1a1a2e', 'border' => '#2d2d4a', 'muted' => '#94a3b8'],
'clean_professional' => ['label' => 'احترافي نظيف', 'primary' => '#ffffff', 'secondary' => '#f8fafc', 'accent' => '#2563eb', 'text' => '#1f2937', 'bg' => '#ffffff', 'surface' => '#f9fafb', 'border' => '#e5e7eb', 'muted' => '#6b7280'],
'vibrant_playful' => ['label' => 'حيوي ومرح', 'primary' => '#fef3c7', 'secondary' => '#ecfccb', 'accent' => '#f59e0b', 'text' => '#1c1917', 'bg' => '#fffbeb', 'surface' => '#fef9c3', 'border' => '#fde68a', 'muted' => '#78716c'],
'dark_sport' => ['label' => 'رياضي داكن', 'primary' => '#0a0a0a', 'secondary' => '#1c1c1c', 'accent' => '#22c55e', 'text' => '#ffffff', 'bg' => '#000000', 'surface' => '#111111', 'border' => '#2a2a2a', 'muted' => '#a1a1aa'],
'minimal_corporate' => ['label' => 'مؤسسي بسيط', 'primary' => '#f9fafb', 'secondary' => '#ffffff', 'accent' => '#6366f1', 'text' => '#111827', 'bg' => '#ffffff', 'surface' => '#f3f4f6', 'border' => '#d1d5db', 'muted' => '#9ca3af'],
'gradient_modern' => ['label' => 'عصري متدرج', 'primary' => '#1e1b4b', 'secondary' => '#312e81', 'accent' => '#a78bfa', 'text' => '#ffffff', 'bg' => '#0f0b2e', 'surface' => '#1e1b4b', 'border' => '#3730a3', 'muted' => '#a5b4fc'],
'neon_energy' => ['label' => 'نيون حيوي', 'primary' => '#18181b', 'secondary' => '#27272a', 'accent' => '#facc15', 'text' => '#ffffff', 'bg' => '#09090b', 'surface' => '#18181b', 'border' => '#3f3f46', 'muted' => '#a1a1aa'],
'earth_natural' => ['label' => 'طبيعي دافئ', 'primary' => '#fefce8', 'secondary' => '#f0fdf4', 'accent' => '#65a30d', 'text' => '#1c1917', 'bg' => '#fafaf9', 'surface' => '#f5f5f4', 'border' => '#d6d3d1', 'muted' => '#78716c'],
];
public function mount(): void
......@@ -39,12 +81,28 @@ public function mount(): void
$settings = app(WebsiteSettingService::class)->getOrCreate(app('current_academy'));
$this->template = $settings->template ?? 'bold_athletic';
$this->primary_color = $settings->primary_color;
$this->secondary_color = $settings->secondary_color;
$this->accent_color = $settings->accent_color;
$this->text_color = $settings->text_color;
$this->background_color = $settings->background_color ?? '#ffffff';
$this->surface_color = $settings->surface_color ?? '#f8fafc';
$this->border_color = $settings->border_color ?? '#e2e8f0';
$this->muted_text_color = $settings->muted_text_color ?? '#64748b';
$this->heading_font = $settings->heading_font;
$this->body_font = $settings->body_font;
$this->font_size_scale = $settings->font_size_scale ?? 'medium';
$this->heading_weight = $settings->heading_weight ?? '700';
$this->line_height = $settings->line_height ?? 'normal';
$this->letter_spacing = $settings->letter_spacing ?? 'normal';
$this->density = $settings->density ?? 'comfortable';
$this->border_radius_preset = $settings->border_radius_preset ?? 'rounded';
$this->card_style = $settings->card_style ?? 'raised';
$this->section_divider = $settings->section_divider ?? 'none';
$this->image_shape = $settings->image_shape ?? 'rounded';
$this->animations_enabled = $settings->animations_enabled ?? true;
$this->animation_speed = $settings->animation_speed ?? 'normal';
$this->navbar_style = $settings->navbar_style;
$this->site_title = $settings->site_title ?? '';
$this->site_title_en = $settings->site_title_en ?? '';
......@@ -57,15 +115,78 @@ public function mount(): void
$this->facebook_pixel_id = $settings->facebook_pixel_id ?? '';
}
public function applyTemplate(string $template): void
{
if (!isset($this->templatePresets[$template])) {
return;
}
$preset = $this->templatePresets[$template];
$this->template = $template;
$this->primary_color = $preset['primary'];
$this->secondary_color = $preset['secondary'];
$this->accent_color = $preset['accent'];
$this->text_color = $preset['text'];
$this->background_color = $preset['bg'];
$this->surface_color = $preset['surface'];
$this->border_color = $preset['border'];
$this->muted_text_color = $preset['muted'];
}
public function generatePaletteFromAccent(): void
{
$hex = ltrim($this->accent_color, '#');
$r = hexdec(substr($hex, 0, 2));
$g = hexdec(substr($hex, 2, 2));
$b = hexdec(substr($hex, 4, 2));
[$h, $s, $l] = $this->rgbToHsl($r, $g, $b);
$isDark = $l < 0.5;
if ($isDark) {
$this->background_color = '#ffffff';
$this->surface_color = '#f9fafb';
$this->text_color = '#111827';
$this->muted_text_color = '#6b7280';
$this->border_color = '#e5e7eb';
$this->primary_color = $this->hslToHex($h, max(0.1, $s * 0.3), 0.95);
$this->secondary_color = $this->hslToHex($h, max(0.05, $s * 0.2), 0.97);
} else {
$this->background_color = $this->hslToHex($h, max(0.05, $s * 0.4), 0.06);
$this->surface_color = $this->hslToHex($h, max(0.08, $s * 0.3), 0.10);
$this->text_color = '#ffffff';
$this->muted_text_color = $this->hslToHex($h, 0.1, 0.65);
$this->border_color = $this->hslToHex($h, 0.1, 0.20);
$this->primary_color = $this->hslToHex($h, max(0.1, $s * 0.4), 0.12);
$this->secondary_color = $this->hslToHex($h, max(0.1, $s * 0.35), 0.15);
}
}
public function save(): void
{
$this->validate([
'template' => 'required|in:bold_athletic,clean_professional,vibrant_playful,dark_sport,minimal_corporate,gradient_modern,neon_energy,earth_natural',
'primary_color' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'secondary_color' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'accent_color' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'text_color' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'background_color' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'surface_color' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'border_color' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'muted_text_color' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'heading_font' => 'required|string|max:50',
'body_font' => 'required|string|max:50',
'font_size_scale' => 'required|in:small,medium,large,xlarge',
'heading_weight' => 'required|in:400,500,600,700,800,900',
'line_height' => 'required|in:tight,normal,relaxed,loose',
'letter_spacing' => 'required|in:tight,normal,wide',
'density' => 'required|in:compact,comfortable,spacious',
'border_radius_preset' => 'required|in:sharp,subtle,rounded,pill',
'card_style' => 'required|in:flat,raised,bordered,glass',
'section_divider' => 'required|in:none,line,wave,angle,curve',
'image_shape' => 'required|in:square,rounded,circle,blob',
'animations_enabled' => 'boolean',
'animation_speed' => 'required|in:slow,normal,fast',
'navbar_style' => 'required|in:solid,transparent,floating',
'site_title' => 'nullable|string|max:255',
'site_description' => 'nullable|string|max:1000',
......@@ -73,12 +194,28 @@ public function save(): void
]);
app(WebsiteSettingService::class)->update(app('current_academy'), [
'template' => $this->template,
'primary_color' => $this->primary_color,
'secondary_color' => $this->secondary_color,
'accent_color' => $this->accent_color,
'text_color' => $this->text_color,
'background_color' => $this->background_color,
'surface_color' => $this->surface_color,
'border_color' => $this->border_color,
'muted_text_color' => $this->muted_text_color,
'heading_font' => $this->heading_font,
'body_font' => $this->body_font,
'font_size_scale' => $this->font_size_scale,
'heading_weight' => $this->heading_weight,
'line_height' => $this->line_height,
'letter_spacing' => $this->letter_spacing,
'density' => $this->density,
'border_radius_preset' => $this->border_radius_preset,
'card_style' => $this->card_style,
'section_divider' => $this->section_divider,
'image_shape' => $this->image_shape,
'animations_enabled' => $this->animations_enabled,
'animation_speed' => $this->animation_speed,
'navbar_style' => $this->navbar_style,
'site_title' => $this->site_title,
'site_title_en' => $this->site_title_en,
......@@ -91,9 +228,66 @@ public function save(): void
'facebook_pixel_id' => $this->facebook_pixel_id,
]);
app(WebsiteCacheService::class)->invalidateAll(app('current_academy'));
session()->flash('success', __('تم حفظ إعدادات التصميم بنجاح'));
}
private function rgbToHsl(int $r, int $g, int $b): array
{
$r /= 255;
$g /= 255;
$b /= 255;
$max = max($r, $g, $b);
$min = min($r, $g, $b);
$l = ($max + $min) / 2;
if ($max === $min) {
return [0, 0, $l];
}
$d = $max - $min;
$s = $l > 0.5 ? $d / (2 - $max - $min) : $d / ($max + $min);
$h = match ($max) {
$r => (($g - $b) / $d + ($g < $b ? 6 : 0)) / 6,
$g => (($b - $r) / $d + 2) / 6,
default => (($r - $g) / $d + 4) / 6,
};
return [$h, $s, $l];
}
private function hslToHex(float $h, float $s, float $l): string
{
$s = max(0, min(1, $s));
$l = max(0, min(1, $l));
if ($s === 0.0) {
$v = (int) round($l * 255);
return sprintf('#%02x%02x%02x', $v, $v, $v);
}
$q = $l < 0.5 ? $l * (1 + $s) : $l + $s - $l * $s;
$p = 2 * $l - $q;
$r = $this->hueToRgb($p, $q, $h + 1 / 3);
$g = $this->hueToRgb($p, $q, $h);
$b = $this->hueToRgb($p, $q, $h - 1 / 3);
return sprintf('#%02x%02x%02x', (int) round($r * 255), (int) round($g * 255), (int) round($b * 255));
}
private function hueToRgb(float $p, float $q, float $t): float
{
if ($t < 0) $t += 1;
if ($t > 1) $t -= 1;
if ($t < 1 / 6) return $p + ($q - $p) * 6 * $t;
if ($t < 1 / 2) return $q;
if ($t < 2 / 3) return $p + ($q - $p) * (2 / 3 - $t) * 6;
return $p;
}
public function render()
{
return view('livewire.website.theme-editor');
......
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
// --- website_settings: new columns for Phase A (template, colors, typography, density, shapes) ---
Schema::table('website_settings', function (Blueprint $table) {
$table->string('background_color', 7)->default('#ffffff')->after('text_color');
$table->string('surface_color', 7)->default('#f8fafc')->after('background_color');
$table->string('border_color', 7)->default('#e2e8f0')->after('surface_color');
$table->string('muted_text_color', 7)->default('#64748b')->after('border_color');
$table->string('font_size_scale', 10)->default('medium')->after('body_font');
$table->string('heading_weight', 10)->default('700')->after('font_size_scale');
$table->string('line_height', 10)->default('normal')->after('heading_weight');
$table->string('letter_spacing', 10)->default('normal')->after('line_height');
$table->string('density', 10)->default('comfortable')->after('letter_spacing');
$table->string('border_radius_preset', 10)->default('rounded')->after('density');
$table->string('card_style', 10)->default('raised')->after('border_radius_preset');
$table->string('section_divider', 10)->default('none')->after('card_style');
$table->string('image_shape', 10)->default('rounded')->after('section_divider');
$table->boolean('animations_enabled')->default(true)->after('image_shape');
$table->string('animation_speed', 10)->default('normal')->after('animations_enabled');
});
// Update template CHECK constraint to add new templates
DB::statement("ALTER TABLE website_settings DROP CONSTRAINT IF EXISTS website_settings_template_check");
DB::statement("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'))");
// Add CHECK constraints for new columns
DB::statement("ALTER TABLE website_settings ADD CONSTRAINT website_settings_font_size_scale_check CHECK (font_size_scale IN ('small', 'medium', 'large', 'xlarge'))");
DB::statement("ALTER TABLE website_settings ADD CONSTRAINT website_settings_heading_weight_check CHECK (heading_weight IN ('400', '500', '600', '700', '800', '900'))");
DB::statement("ALTER TABLE website_settings ADD CONSTRAINT website_settings_line_height_check CHECK (line_height IN ('tight', 'normal', 'relaxed', 'loose'))");
DB::statement("ALTER TABLE website_settings ADD CONSTRAINT website_settings_letter_spacing_check CHECK (letter_spacing IN ('tight', 'normal', 'wide'))");
DB::statement("ALTER TABLE website_settings ADD CONSTRAINT website_settings_density_check CHECK (density IN ('compact', 'comfortable', 'spacious'))");
DB::statement("ALTER TABLE website_settings ADD CONSTRAINT website_settings_border_radius_preset_check CHECK (border_radius_preset IN ('sharp', 'subtle', 'rounded', 'pill'))");
DB::statement("ALTER TABLE website_settings ADD CONSTRAINT website_settings_card_style_check CHECK (card_style IN ('flat', 'raised', 'bordered', 'glass'))");
DB::statement("ALTER TABLE website_settings ADD CONSTRAINT website_settings_section_divider_check CHECK (section_divider IN ('none', 'line', 'wave', 'angle', 'curve'))");
DB::statement("ALTER TABLE website_settings ADD CONSTRAINT website_settings_image_shape_check CHECK (image_shape IN ('square', 'rounded', 'circle', 'blob'))");
DB::statement("ALTER TABLE website_settings ADD CONSTRAINT website_settings_animation_speed_check CHECK (animation_speed IN ('slow', 'normal', 'fast'))");
// --- website_sections: per-section background + animation + padding ---
Schema::table('website_sections', function (Blueprint $table) {
$table->string('bg_type', 20)->default('inherit')->after('is_enabled');
$table->string('bg_color', 7)->nullable()->after('bg_type');
$table->string('bg_gradient_from', 7)->nullable()->after('bg_color');
$table->string('bg_gradient_to', 7)->nullable()->after('bg_gradient_from');
$table->smallInteger('bg_gradient_angle')->default(180)->after('bg_gradient_to');
$table->string('bg_image_path', 500)->nullable()->after('bg_gradient_angle');
$table->smallInteger('bg_overlay_opacity')->default(60)->after('bg_image_path');
$table->string('bg_video_url', 500)->nullable()->after('bg_overlay_opacity');
$table->string('animation', 20)->default('fade-up')->after('bg_video_url');
$table->string('padding_y', 10)->default('inherit')->after('animation');
$table->boolean('hidden_on_mobile')->default(false)->after('padding_y');
});
DB::statement("ALTER TABLE website_sections ADD CONSTRAINT website_sections_bg_type_check CHECK (bg_type IN ('inherit', 'solid', 'gradient', 'image', 'video'))");
DB::statement("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'))");
DB::statement("ALTER TABLE website_sections ADD CONSTRAINT website_sections_padding_y_check CHECK (padding_y IN ('inherit', 'none', 'small', 'medium', 'large', 'xlarge'))");
}
public function down(): void
{
DB::statement("ALTER TABLE website_settings DROP CONSTRAINT IF EXISTS website_settings_font_size_scale_check");
DB::statement("ALTER TABLE website_settings DROP CONSTRAINT IF EXISTS website_settings_heading_weight_check");
DB::statement("ALTER TABLE website_settings DROP CONSTRAINT IF EXISTS website_settings_line_height_check");
DB::statement("ALTER TABLE website_settings DROP CONSTRAINT IF EXISTS website_settings_letter_spacing_check");
DB::statement("ALTER TABLE website_settings DROP CONSTRAINT IF EXISTS website_settings_density_check");
DB::statement("ALTER TABLE website_settings DROP CONSTRAINT IF EXISTS website_settings_border_radius_preset_check");
DB::statement("ALTER TABLE website_settings DROP CONSTRAINT IF EXISTS website_settings_card_style_check");
DB::statement("ALTER TABLE website_settings DROP CONSTRAINT IF EXISTS website_settings_section_divider_check");
DB::statement("ALTER TABLE website_settings DROP CONSTRAINT IF EXISTS website_settings_image_shape_check");
DB::statement("ALTER TABLE website_settings DROP CONSTRAINT IF EXISTS website_settings_animation_speed_check");
Schema::table('website_settings', function (Blueprint $table) {
$table->dropColumn([
'background_color', 'surface_color', 'border_color', 'muted_text_color',
'font_size_scale', 'heading_weight', 'line_height', 'letter_spacing',
'density', 'border_radius_preset', 'card_style', 'section_divider', 'image_shape',
'animations_enabled', 'animation_speed',
]);
});
DB::statement("ALTER TABLE website_settings DROP CONSTRAINT IF EXISTS website_settings_template_check");
DB::statement("ALTER TABLE website_settings ADD CONSTRAINT website_settings_template_check CHECK (template IN ('bold_athletic', 'clean_professional', 'vibrant_playful'))");
DB::statement("ALTER TABLE website_sections DROP CONSTRAINT IF EXISTS website_sections_bg_type_check");
DB::statement("ALTER TABLE website_sections DROP CONSTRAINT IF EXISTS website_sections_animation_check");
DB::statement("ALTER TABLE website_sections DROP CONSTRAINT IF EXISTS website_sections_padding_y_check");
Schema::table('website_sections', function (Blueprint $table) {
$table->dropColumn([
'bg_type', 'bg_color', 'bg_gradient_from', 'bg_gradient_to',
'bg_gradient_angle', 'bg_image_path', 'bg_overlay_opacity', 'bg_video_url',
'animation', 'padding_y', 'hidden_on_mobile',
]);
});
}
};
......@@ -2,7 +2,7 @@
<div class="flex items-center justify-between mb-6">
<div>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">تصميم الموقع</h1>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">تخصيص الألوان والخطوط والروابط الاجتماعية</p>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">تخصيص القالب والألوان والخطوط والتأثيرات</p>
</div>
<a href="{{ route('website.manage.sections') }}" class="px-4 py-2 text-sm font-medium rounded-lg border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
← إدارة الأقسام
......@@ -16,137 +16,283 @@
@endif
<form wire:submit="save" class="space-y-6">
{{-- Template Presets --}}
<div class="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">القالب</h3>
<p class="text-sm text-gray-500 dark:text-gray-400 mb-4">اختر قالبًا جاهزًا كنقطة بداية — يمكنك تعديل الألوان بعدها</p>
<div class="grid grid-cols-2 md:grid-cols-4 gap-3">
@foreach($templatePresets as $key => $preset)
<button type="button" wire:click="applyTemplate('{{ $key }}')"
class="relative p-3 rounded-xl border-2 transition-all text-start {{ $template === $key ? 'border-blue-500 ring-2 ring-blue-200' : 'border-gray-200 dark:border-gray-600 hover:border-gray-300' }}">
<div class="flex gap-1 mb-2">
<span class="w-4 h-4 rounded-full" style="background-color: {{ $preset['primary'] }}"></span>
<span class="w-4 h-4 rounded-full" style="background-color: {{ $preset['accent'] }}"></span>
<span class="w-4 h-4 rounded-full" style="background-color: {{ $preset['bg'] }}"></span>
</div>
<span class="text-xs font-medium text-gray-700 dark:text-gray-300">{{ $preset['label'] }}</span>
@if($template === $key)
<span class="absolute top-1.5 end-1.5 w-4 h-4 bg-blue-500 rounded-full flex items-center justify-center">
<svg class="w-2.5 h-2.5 text-white" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/></svg>
</span>
@endif
</button>
@endforeach
</div>
</div>
{{-- Colors --}}
<div class="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">الألوان</h3>
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">الألوان</h3>
<button type="button" wire:click="generatePaletteFromAccent" class="text-xs px-3 py-1.5 bg-gray-100 dark:bg-gray-700 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors text-gray-700 dark:text-gray-300">
توليد تلقائي من اللون المميز
</button>
</div>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">اللون الرئيسي</label>
<div class="flex items-center gap-2">
<input type="color" wire:model="primary_color" class="w-10 h-10 rounded cursor-pointer border-0 p-0">
<input type="text" wire:model="primary_color" dir="ltr" class="flex-1 text-sm rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white" placeholder="#1e40af">
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">اللون الثانوي</label>
<div class="flex items-center gap-2">
<input type="color" wire:model="secondary_color" class="w-10 h-10 rounded cursor-pointer border-0 p-0">
<input type="text" wire:model="secondary_color" dir="ltr" class="flex-1 text-sm rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white" placeholder="#f59e0b">
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">اللون المميز</label>
<div class="flex items-center gap-2">
<input type="color" wire:model="accent_color" class="w-10 h-10 rounded cursor-pointer border-0 p-0">
<input type="text" wire:model="accent_color" dir="ltr" class="flex-1 text-sm rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white" placeholder="#10b981">
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">لون النص</label>
<div class="flex items-center gap-2">
<input type="color" wire:model="text_color" class="w-10 h-10 rounded cursor-pointer border-0 p-0">
<input type="text" wire:model="text_color" dir="ltr" class="flex-1 text-sm rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white" placeholder="#ffffff">
@foreach([
['primary_color', 'اللون الرئيسي'],
['secondary_color', 'اللون الثانوي'],
['accent_color', 'اللون المميز'],
['text_color', 'لون النص'],
['background_color', 'لون الخلفية'],
['surface_color', 'لون السطح'],
['border_color', 'لون الحدود'],
['muted_text_color', 'نص خافت'],
] as [$field, $label])
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">{{ $label }}</label>
<div class="flex items-center gap-2">
<input type="color" wire:model.live="{{ $field }}" class="w-10 h-10 rounded cursor-pointer border-0 p-0">
<input type="text" wire:model.live="{{ $field }}" dir="ltr" class="flex-1 text-sm rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
</div>
</div>
</div>
@endforeach
</div>
{{-- Color Preview --}}
<div class="mt-4 p-4 rounded-lg border border-gray-200 dark:border-gray-600" style="background-color: {{ $secondary_color }}">
<div class="flex items-center gap-3">
<span class="px-3 py-1 rounded text-sm font-medium" style="background-color: {{ $primary_color }}; color: {{ $text_color }}">رئيسي</span>
<span class="px-3 py-1 rounded text-sm font-medium" style="background-color: {{ $accent_color }}; color: {{ $text_color }}">مميز</span>
<span class="px-3 py-1 rounded text-sm font-medium" style="color: {{ $text_color }}; border: 1px solid {{ $text_color }}">نص</span>
<div class="mt-4 p-4 rounded-lg border" style="background-color: {{ $background_color }}; border-color: {{ $border_color }}">
<div class="flex items-center gap-3 flex-wrap">
<span class="px-3 py-1.5 rounded text-sm font-medium" style="background-color: {{ $primary_color }}; color: {{ $text_color }}">رئيسي</span>
<span class="px-3 py-1.5 rounded text-sm font-medium" style="background-color: {{ $secondary_color }}; color: {{ $text_color }}">ثانوي</span>
<span class="px-3 py-1.5 rounded text-sm font-medium" style="background-color: {{ $accent_color }}; color: {{ $text_color }}">مميز</span>
<span class="px-3 py-1.5 rounded text-sm font-medium" style="background-color: {{ $surface_color }}; color: {{ $muted_text_color }}; border: 1px solid {{ $border_color }}">سطح</span>
</div>
</div>
</div>
{{-- Fonts --}}
{{-- Typography --}}
<div class="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">الخطوط</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">الخطوط والنصوص</h3>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">خط العناوين</label>
<select wire:model="heading_font" class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
<option value="Cairo">Cairo</option>
<option value="Tajawal">Tajawal</option>
<option value="IBM Plex Sans Arabic">IBM Plex Sans Arabic</option>
<option value="Noto Sans Arabic">Noto Sans Arabic</option>
<option value="Almarai">Almarai</option>
<option value="Changa">Changa</option>
<option value="El Messiri">El Messiri</option>
@foreach($availableFonts as $font)
<option value="{{ $font }}">{{ $font }}</option>
@endforeach
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">خط النصوص</label>
<select wire:model="body_font" class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
<option value="Cairo">Cairo</option>
<option value="Tajawal">Tajawal</option>
<option value="IBM Plex Sans Arabic">IBM Plex Sans Arabic</option>
<option value="Noto Sans Arabic">Noto Sans Arabic</option>
<option value="Almarai">Almarai</option>
@foreach($availableFonts as $font)
<option value="{{ $font }}">{{ $font }}</option>
@endforeach
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">حجم الخط</label>
<select wire:model="font_size_scale" class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
<option value="small">صغير</option>
<option value="medium">متوسط</option>
<option value="large">كبير</option>
<option value="xlarge">كبير جدًا</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">وزن العنوان</label>
<select wire:model="heading_weight" class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
<option value="400">عادي (400)</option>
<option value="500">متوسط (500)</option>
<option value="600">شبه عريض (600)</option>
<option value="700">عريض (700)</option>
<option value="800">أعرض (800)</option>
<option value="900">أسود (900)</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">ارتفاع السطر</label>
<select wire:model="line_height" class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
<option value="tight">ضيق</option>
<option value="normal">عادي</option>
<option value="relaxed">مريح</option>
<option value="loose">واسع</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">تباعد الحروف</label>
<select wire:model="letter_spacing" class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
<option value="tight">ضيق</option>
<option value="normal">عادي</option>
<option value="wide">واسع</option>
</select>
</div>
</div>
</div>
{{-- Navbar Style --}}
{{-- Spacing & Density --}}
<div class="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">شريط التنقل</h3>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">المسافات والكثافة</h3>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">نمط الشريط</label>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">كثافة المحتوى</label>
<div class="grid grid-cols-3 gap-3">
<label class="relative cursor-pointer">
<input type="radio" wire:model="navbar_style" value="transparent" class="sr-only peer">
<div class="p-3 rounded-lg border-2 peer-checked:border-blue-500 border-gray-200 dark:border-gray-600 text-center transition-colors">
<span class="text-sm">شفاف</span>
</div>
</label>
<label class="relative cursor-pointer">
<input type="radio" wire:model="navbar_style" value="solid" class="sr-only peer">
<div class="p-3 rounded-lg border-2 peer-checked:border-blue-500 border-gray-200 dark:border-gray-600 text-center transition-colors">
<span class="text-sm">معتم</span>
</div>
</label>
<label class="relative cursor-pointer">
<input type="radio" wire:model="navbar_style" value="floating" class="sr-only peer">
<div class="p-3 rounded-lg border-2 peer-checked:border-blue-500 border-gray-200 dark:border-gray-600 text-center transition-colors">
<span class="text-sm">عائم</span>
</div>
</label>
@foreach([
['compact', 'مضغوط', 'عناصر متقاربة'],
['comfortable', 'مريح', 'التوازن الافتراضي'],
['spacious', 'واسع', 'مساحات كبيرة'],
] as [$val, $label, $desc])
<label class="relative cursor-pointer">
<input type="radio" wire:model="density" value="{{ $val }}" class="sr-only peer">
<div class="p-3 rounded-lg border-2 peer-checked:border-blue-500 border-gray-200 dark:border-gray-600 text-center transition-colors">
<span class="text-sm font-medium block">{{ $label }}</span>
<span class="text-xs text-gray-400">{{ $desc }}</span>
</div>
</label>
@endforeach
</div>
</div>
</div>
{{-- Social Links --}}
{{-- Shapes & Borders --}}
<div class="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">روابط التواصل الاجتماعي</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">الأشكال والحدود</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Facebook</label>
<input type="url" wire:model="social_links.facebook" dir="ltr" placeholder="https://facebook.com/..." class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">زوايا العناصر</label>
<div class="grid grid-cols-4 gap-2">
@foreach([
['sharp', 'حاد', 'rounded-none'],
['subtle', 'خفيف', 'rounded'],
['rounded', 'دائري', 'rounded-xl'],
['pill', 'كبسولة', 'rounded-full'],
] as [$val, $label, $class])
<label class="cursor-pointer">
<input type="radio" wire:model="border_radius_preset" value="{{ $val }}" class="sr-only peer">
<div class="p-2 border-2 peer-checked:border-blue-500 border-gray-200 dark:border-gray-600 text-center transition-colors {{ $class }}">
<div class="w-8 h-6 mx-auto bg-gray-300 dark:bg-gray-500 {{ $class }}"></div>
<span class="text-xs mt-1 block">{{ $label }}</span>
</div>
</label>
@endforeach
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">نمط البطاقات</label>
<div class="grid grid-cols-4 gap-2">
@foreach([
['flat', 'مسطح'],
['raised', 'مرتفع'],
['bordered', 'محدد'],
['glass', 'زجاجي'],
] as [$val, $label])
<label class="cursor-pointer">
<input type="radio" wire:model="card_style" value="{{ $val }}" class="sr-only peer">
<div class="p-2 rounded-lg border-2 peer-checked:border-blue-500 border-gray-200 dark:border-gray-600 text-center transition-colors">
<span class="text-xs">{{ $label }}</span>
</div>
</label>
@endforeach
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Instagram</label>
<input type="url" wire:model="social_links.instagram" dir="ltr" placeholder="https://instagram.com/..." class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">الفاصل بين الأقسام</label>
<select wire:model="section_divider" class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
<option value="none">بدون</option>
<option value="line">خط</option>
<option value="wave">موجة</option>
<option value="angle">زاوية</option>
<option value="curve">منحنى</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Twitter / X</label>
<input type="url" wire:model="social_links.twitter" dir="ltr" placeholder="https://x.com/..." class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">شكل الصور</label>
<select wire:model="image_shape" class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
<option value="square">مربع</option>
<option value="rounded">مستدير</option>
<option value="circle">دائري</option>
<option value="blob">عضوي</option>
</select>
</div>
</div>
</div>
{{-- Animations --}}
<div class="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">الحركة والتأثيرات</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">YouTube</label>
<input type="url" wire:model="social_links.youtube" dir="ltr" placeholder="https://youtube.com/@..." class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
<label class="flex items-center gap-3 cursor-pointer">
<input type="checkbox" wire:model="animations_enabled" class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">تفعيل الرسوم المتحركة</span>
</label>
<p class="text-xs text-gray-400 mt-1 ms-8">تأثيرات الظهور عند التمرير</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">TikTok</label>
<input type="url" wire:model="social_links.tiktok" dir="ltr" placeholder="https://tiktok.com/@..." class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">سرعة التأثيرات</label>
<select wire:model="animation_speed" class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white" @if(!$animations_enabled) disabled @endif>
<option value="slow">بطيء</option>
<option value="normal">عادي</option>
<option value="fast">سريع</option>
</select>
</div>
</div>
</div>
{{-- WhatsApp --}}
{{-- Navbar Style --}}
<div class="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">واتساب</h3>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">شريط التنقل</h3>
<div class="grid grid-cols-3 gap-3">
@foreach([
['transparent', 'شفاف'],
['solid', 'معتم'],
['floating', 'عائم'],
] as [$val, $label])
<label class="relative cursor-pointer">
<input type="radio" wire:model="navbar_style" value="{{ $val }}" class="sr-only peer">
<div class="p-3 rounded-lg border-2 peer-checked:border-blue-500 border-gray-200 dark:border-gray-600 text-center transition-colors">
<span class="text-sm">{{ $label }}</span>
</div>
</label>
@endforeach
</div>
</div>
{{-- Social Links --}}
<div class="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">روابط التواصل الاجتماعي</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
@foreach([
['facebook', 'Facebook', 'https://facebook.com/...'],
['instagram', 'Instagram', 'https://instagram.com/...'],
['twitter', 'Twitter / X', 'https://x.com/...'],
['youtube', 'YouTube', 'https://youtube.com/@...'],
['tiktok', 'TikTok', 'https://tiktok.com/@...'],
] as [$key, $label, $placeholder])
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">{{ $label }}</label>
<input type="url" wire:model="social_links.{{ $key }}" dir="ltr" placeholder="{{ $placeholder }}" class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
</div>
@endforeach
</div>
</div>
{{-- WhatsApp & Site Info --}}
<div class="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">معلومات الموقع</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">رقم واتساب</label>
......@@ -157,6 +303,10 @@
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">عنوان الموقع</label>
<input type="text" wire:model="site_title" placeholder="اسم الأكاديمية" class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
</div>
<div class="md:col-span-2">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">وصف الموقع</label>
<textarea wire:model="site_description" rows="2" placeholder="وصف قصير للموقع..." class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white"></textarea>
</div>
</div>
</div>
......@@ -175,13 +325,23 @@
</div>
</div>
{{-- Custom CSS --}}
<div class="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">CSS مخصص</h3>
<textarea wire:model="custom_css" dir="ltr" rows="6" placeholder="/* أضف تنسيقاتك هنا */" class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white font-mono text-sm"></textarea>
<p class="text-xs text-gray-500 mt-1">سيتم حقن هذا الكود مباشرة في صفحة الموقع</p>
</div>
{{-- Save Button --}}
<div class="flex items-center gap-3">
<div class="flex items-center gap-3 sticky bottom-4 bg-white dark:bg-gray-800 p-4 rounded-xl border border-gray-200 dark:border-gray-700 shadow-lg">
<button type="submit" class="px-8 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 font-medium transition-colors"
wire:loading.attr="disabled" wire:target="save">
<span wire:loading.remove wire:target="save">حفظ الإعدادات</span>
<span wire:loading wire:target="save">جارٍ الحفظ...</span>
</button>
<a href="{{ route('website.preview') }}" target="_blank" class="px-4 py-3 text-sm font-medium text-gray-700 dark:text-gray-300 rounded-lg border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
معاينة الموقع ↗
</a>
</div>
</form>
</div>
......@@ -2,13 +2,35 @@
@section('content')
@foreach($sections as $section)
<section id="section-{{ $section->section_key->value }}">
@include('website.sections.' . $section->section_key->value, [
'section' => $section,
'academy' => $academy,
'settings' => $settings,
'data' => $data,
])
@php
$paddingClass = match($section->padding_y) {
'none' => 'py-0',
'small' => 'py-8',
'medium' => 'py-16',
'large' => 'py-24',
'xlarge' => 'py-40',
default => '',
};
$mobileHidden = $section->hidden_on_mobile ? 'hidden md:block' : '';
$animAttr = ($settings->animations_enabled ?? true) ? $section->animation ?? 'fade-up' : 'none';
@endphp
<section id="section-{{ $section->section_key->value }}"
class="{{ $mobileHidden }} {{ $paddingClass }}"
@if($animAttr !== 'none') data-animation="{{ $animAttr }}" @endif>
@if($section->bg_type !== 'inherit')
@include('website.partials.section-bg', ['section' => $section])
@else
@include('website.sections.' . $section->section_key->value, [
'section' => $section,
'academy' => $academy,
'settings' => $settings,
'data' => $data,
])
@endif
</section>
@if(($settings->section_divider ?? 'none') !== 'none' && !$loop->last)
@include('website.partials.divider', ['settings' => $settings])
@endif
@endforeach
@endsection
......@@ -27,6 +27,26 @@
@livewireStyles
{{-- Dynamic CSS Variables from Academy Branding --}}
@php
$fontSizeMap = ['small' => '14px', 'medium' => '16px', 'large' => '18px', 'xlarge' => '20px'];
$h1Map = ['small' => '2rem', 'medium' => '2.5rem', 'large' => '3rem', 'xlarge' => '3.5rem'];
$h2Map = ['small' => '1.6rem', 'medium' => '2rem', 'large' => '2.4rem', 'xlarge' => '2.8rem'];
$h3Map = ['small' => '1.3rem', 'medium' => '1.5rem', 'large' => '1.75rem', 'xlarge' => '2rem'];
$lineHeightMap = ['tight' => '1.3', 'normal' => '1.6', 'relaxed' => '1.8', 'loose' => '2'];
$letterSpacingMap = ['tight' => '-0.02em', 'normal' => '0', 'wide' => '0.05em'];
$sectionPyMap = ['compact' => '3rem', 'comfortable' => '5rem', 'spacious' => '8rem'];
$cardGapMap = ['compact' => '1rem', 'comfortable' => '1.5rem', 'spacious' => '2.5rem'];
$radiusMap = ['sharp' => '0px', 'subtle' => '4px', 'rounded' => '12px', 'pill' => '9999px'];
$radiusLgMap = ['sharp' => '0px', 'subtle' => '8px', 'rounded' => '20px', 'pill' => '9999px'];
$animDurationMap = ['slow' => '1.2s', 'normal' => '0.8s', 'fast' => '0.4s'];
$fss = $settings->font_size_scale ?? 'medium';
$lh = $settings->line_height ?? 'normal';
$ls = $settings->letter_spacing ?? 'normal';
$dn = $settings->density ?? 'comfortable';
$br = $settings->border_radius_preset ?? 'rounded';
$as = $settings->animation_speed ?? 'normal';
@endphp
<style>
:root {
--site-primary: {{ $settings->primary_color ?? '#1e3a5f' }};
......@@ -34,11 +54,57 @@
--site-accent: {{ $settings->accent_color ?? '#2563eb' }};
--site-text: {{ $settings->text_color ?? '#1f2937' }};
--site-bg: {{ $settings->background_color ?? '#ffffff' }};
--site-surface: {{ $settings->surface_color ?? '#f8fafc' }};
--site-border: {{ $settings->border_color ?? '#e2e8f0' }};
--site-muted: {{ $settings->muted_text_color ?? '#64748b' }};
--site-heading-font: '{{ $settings->heading_font ?? 'Cairo' }}', 'Noto Sans Arabic', sans-serif;
--site-body-font: '{{ $settings->body_font ?? 'Cairo' }}', 'Noto Sans Arabic', sans-serif;
--site-text-base: {{ $fontSizeMap[$fss] }};
--site-h1: {{ $h1Map[$fss] }};
--site-h2: {{ $h2Map[$fss] }};
--site-h3: {{ $h3Map[$fss] }};
--site-heading-weight: {{ $settings->heading_weight ?? '700' }};
--site-line-height: {{ $lineHeightMap[$lh] }};
--site-letter-spacing: {{ $letterSpacingMap[$ls] }};
--section-py: {{ $sectionPyMap[$dn] }};
--card-gap: {{ $cardGapMap[$dn] }};
--site-radius: {{ $radiusMap[$br] }};
--site-radius-lg: {{ $radiusLgMap[$br] }};
--anim-duration: {{ $animDurationMap[$as] }};
}
.website-body {
font-family: var(--site-body-font);
font-size: var(--site-text-base);
line-height: var(--site-line-height);
letter-spacing: var(--site-letter-spacing);
background-color: var(--site-bg);
color: var(--site-text);
}
.hero-title, .section-title, .stat-number {
font-family: var(--site-heading-font);
font-weight: var(--site-heading-weight);
}
/* Card Styles */
.site-card {
border-radius: var(--site-radius-lg);
{{ match($settings->card_style ?? 'raised') {
'flat' => 'box-shadow: none; border: none; background: transparent;',
'raised' => 'box-shadow: 0 4px 20px rgba(0,0,0,0.15);',
'bordered' => 'box-shadow: none; border: 1px solid var(--site-border);',
'glass' => 'box-shadow: 0 8px 32px rgba(0,0,0,0.1); border: 1px solid rgba(255,255,255,0.1); backdrop-filter: blur(10px); background: rgba(255,255,255,0.05);',
default => '',
} }}
}
/* Image Shapes */
.site-img {
{{ match($settings->image_shape ?? 'rounded') {
'square' => 'border-radius: 0;',
'rounded' => 'border-radius: var(--site-radius-lg);',
'circle' => 'border-radius: 50%;',
'blob' => 'border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%;',
default => '',
} }}
}
.website-body { font-family: var(--site-body-font); }
.hero-title, .section-title, .stat-number { font-family: var(--site-heading-font); }
</style>
@if($settings->custom_css)
......@@ -71,7 +137,7 @@ function gtag(){dataLayer.push(arguments);}
</script>
@endif
</head>
<body class="website-body">
<body class="website-body" data-template="{{ $settings->template ?? 'bold_athletic' }}" data-density="{{ $settings->density ?? 'comfortable' }}" data-radius="{{ $settings->border_radius_preset ?? 'rounded' }}" data-card="{{ $settings->card_style ?? 'raised' }}" data-animations="{{ ($settings->animations_enabled ?? true) ? 'true' : 'false' }}" data-anim-speed="{{ $settings->animation_speed ?? 'normal' }}">
{{-- Navbar --}}
@include('website.navbar')
......
@switch($settings->section_divider)
@case('line')
<div class="w-full px-8">
<div class="border-t" style="border-color: var(--site-border)"></div>
</div>
@break
@case('wave')
<div class="w-full overflow-hidden" style="color: var(--site-bg)">
<svg viewBox="0 0 1200 60" preserveAspectRatio="none" class="w-full h-10 block">
<path d="M0,30 C200,60 400,0 600,30 C800,60 1000,0 1200,30 L1200,60 L0,60 Z" fill="currentColor"/>
</svg>
</div>
@break
@case('angle')
<div class="w-full overflow-hidden" style="color: var(--site-bg)">
<svg viewBox="0 0 1200 60" preserveAspectRatio="none" class="w-full h-10 block">
<polygon points="0,60 1200,0 1200,60" fill="currentColor"/>
</svg>
</div>
@break
@case('curve')
<div class="w-full overflow-hidden" style="color: var(--site-bg)">
<svg viewBox="0 0 1200 60" preserveAspectRatio="none" class="w-full h-10 block">
<path d="M0,60 Q600,0 1200,60 Z" fill="currentColor"/>
</svg>
</div>
@break
@endswitch
@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' => $section->bg_image_path ? "background-image: url('" . Storage::disk('public')->url($section->bg_image_path) . "'); background-size: cover; background-position: center;" : '',
default => '',
};
@endphp
<div class="relative" style="{{ $bgStyle }}">
@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">
@include('website.sections.' . $section->section_key->value, [
'section' => $section,
'academy' => $academy,
'settings' => $settings,
'data' => $data,
])
</div>
</div>
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