Commit b98c1c14 authored by Mahmoud Aglan's avatar Mahmoud Aglan

GO THERE

parent 7f5b59a3
......@@ -606,7 +606,7 @@ class TutorialController extends Controller
@unlink($tmpOutput);
$response = new Response();
return $response->html($pdfContent, 200, [
return $response->html($pdfContent, 200)->withHeaders([
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'attachment; filename="Book-of-the-ERP.pdf"',
'Content-Length' => (string) strlen($pdfContent),
......@@ -616,7 +616,7 @@ class TutorialController extends Controller
}
$response = new Response();
return $response->html($html, 200, [
return $response->html($html, 200)->withHeaders([
'Content-Type' => 'text/html; charset=utf-8',
'Content-Disposition' => 'attachment; filename="Book-of-the-ERP.html"',
]);
......
......@@ -4,236 +4,518 @@
<meta charset="UTF-8">
<title>Book of the ERP - كتاب النظام</title>
<style>
/* ═══════════════════════════════════════════════════════════════════
DESIGN FEATURES:
1. Full-page module divider pages with gradient backgrounds
2. page-break-inside:avoid on all tutorial blocks (no split)
3. Orphan/widow control (min 3 lines before/after break)
4. Professional TOC with numbered sections & dot leaders
5. Color-coded section accents (unique color per module)
6. Running footer with page numbers
7. Cover page with geometric SVG pattern
8. Category sub-dividers with thick colored left border
9. Tutorial numbering with gradient badges
10. Screenshot frames with drop shadow effect
11. Step cards with colored side accent bar
12. Styled callout boxes (info/warning/success/tip)
13. Professional typography hierarchy (8pt grid)
14. Decorative corner elements on divider pages
15. Tutorial metadata tags (colored chips)
16. Subtle diagonal stripe background on divider pages
17. Proper print margins with gutters
18. Back cover page with branding
19. Section summary stats on divider pages
20. Consistent vertical rhythm (8px base unit)
═══════════════════════════════════════════════════════════════════ */
@page {
size: A4;
margin: 20mm 15mm 25mm 15mm;
margin: 22mm 18mm 28mm 18mm;
}
@page :first {
margin: 0;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
/* ── Feature 13: Typography hierarchy ── */
body {
font-family: 'Noto Sans Arabic', 'Noto Sans', 'Segoe UI', Tahoma, Arial, sans-serif;
font-size: 13px;
line-height: 1.7;
color: #1A1A2E;
font-size: 12px;
line-height: 1.8;
color: #1F2937;
direction: rtl;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
/* ── Feature 3: Orphan/Widow control ── */
p, li, .tut-step-body {
orphans: 3;
widows: 3;
}
/* Cover Page */
/* ══════════════════════════════════════
Feature 7: COVER PAGE
══════════════════════════════════════ */
.cover-page {
page-break-after: always;
height: 100vh;
width: 210mm;
height: 297mm;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #1A1A2E 0%, #2D1B69 50%, #4C1D95 100%);
background: linear-gradient(160deg, #0F0A2A 0%, #1A1145 25%, #2D1B69 50%, #4C1D95 75%, #6D28D9 100%);
color: #fff;
text-align: center;
padding: 40px;
padding: 60px 50px;
position: relative;
overflow: hidden;
}
.cover-page::before {
content: '';
position: absolute;
top: -50%;
right: -30%;
width: 120%;
height: 120%;
background: radial-gradient(ellipse at center, rgba(139,92,246,0.15) 0%, transparent 60%);
}
.cover-page::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, #8B5CF6, #EC4899, #F59E0B, #10B981, #3B82F6);
}
.cover-geometric {
position: absolute;
top: 40px;
left: 40px;
right: 40px;
bottom: 40px;
border: 1px solid rgba(255,255,255,0.06);
border-radius: 24px;
}
.cover-geometric::before {
content: '';
position: absolute;
top: 20px;
left: 20px;
right: 20px;
bottom: 20px;
border: 1px solid rgba(255,255,255,0.04);
border-radius: 20px;
}
.cover-logo {
width: 120px;
height: 120px;
background: rgba(255,255,255,0.1);
border-radius: 30px;
width: 140px;
height: 140px;
background: rgba(255,255,255,0.08);
border-radius: 36px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 40px;
border: 2px solid rgba(255,255,255,0.2);
margin-bottom: 48px;
border: 2px solid rgba(255,255,255,0.15);
position: relative;
z-index: 1;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
}
.cover-logo svg {
width: 60px;
height: 60px;
width: 70px;
height: 70px;
fill: none;
stroke: #fff;
stroke-width: 1.5;
}
.cover-title {
font-size: 48px;
font-size: 56px;
font-weight: 900;
margin-bottom: 12px;
letter-spacing: -1px;
margin-bottom: 8px;
letter-spacing: -2px;
position: relative;
z-index: 1;
text-shadow: 0 4px 20px rgba(0,0,0,0.3);
}
.cover-subtitle {
font-size: 22px;
font-weight: 300;
opacity: 0.85;
margin-bottom: 8px;
font-size: 26px;
font-weight: 600;
opacity: 0.9;
margin-bottom: 12px;
position: relative;
z-index: 1;
}
.cover-desc {
font-size: 16px;
font-size: 15px;
opacity: 0.6;
margin-bottom: 80px;
max-width: 400px;
line-height: 2;
position: relative;
z-index: 1;
}
.cover-stats {
display: flex;
gap: 40px;
margin-bottom: 60px;
position: relative;
z-index: 1;
}
.cover-meta {
font-size: 12px;
.cover-stat {
text-align: center;
}
.cover-stat-num {
font-size: 36px;
font-weight: 900;
display: block;
background: linear-gradient(135deg, #C4B5FD, #fff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.cover-stat-label {
font-size: 11px;
opacity: 0.5;
border-top: 1px solid rgba(255,255,255,0.15);
text-transform: uppercase;
letter-spacing: 1px;
}
.cover-meta {
font-size: 11px;
opacity: 0.4;
position: relative;
z-index: 1;
border-top: 1px solid rgba(255,255,255,0.1);
padding-top: 20px;
width: 100%;
max-width: 400px;
}
/* Table of Contents */
/* ══════════════════════════════════════
Feature 4: TABLE OF CONTENTS
══════════════════════════════════════ */
.toc-page {
page-break-after: always;
padding: 40px 0;
padding: 0;
}
.toc-title {
font-size: 28px;
font-weight: 800;
.toc-header {
text-align: center;
margin-bottom: 40px;
padding-bottom: 24px;
border-bottom: 2px solid #E5E7EB;
}
.toc-header h1 {
font-size: 32px;
font-weight: 900;
color: #1A1A2E;
margin-bottom: 30px;
padding-bottom: 12px;
border-bottom: 3px solid #8B5CF6;
margin-bottom: 8px;
}
.toc-header p {
font-size: 13px;
color: #6B7280;
}
.toc-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px 32px;
}
.toc-section {
margin-bottom: 20px;
margin-bottom: 8px;
padding: 12px 16px;
background: #F9FAFB;
border-radius: 10px;
border-right: 4px solid #8B5CF6;
}
.toc-section-title {
font-size: 16px;
font-size: 13px;
font-weight: 700;
color: #4C1D95;
margin-bottom: 6px;
color: #1A1A2E;
margin-bottom: 4px;
display: flex;
align-items: center;
gap: 8px;
justify-content: space-between;
}
.toc-section-title::before {
content: '';
width: 8px;
height: 8px;
.toc-section-num {
width: 22px;
height: 22px;
background: #8B5CF6;
border-radius: 50%;
flex-shrink: 0;
color: #fff;
border-radius: 6px;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 10px;
font-weight: 800;
margin-left: 8px;
}
.toc-badge {
display: inline-block;
background: #EDE9FE;
color: #7C3AED;
font-size: 9px;
font-weight: 700;
padding: 2px 8px;
border-radius: 10px;
}
.toc-items {
padding-right: 24px;
list-style: none;
padding: 0;
margin: 6px 0 0;
}
.toc-items li {
font-size: 12px;
color: #374151;
padding: 2px 0;
display: flex;
align-items: center;
gap: 6px;
font-size: 10px;
color: #6B7280;
padding: 1px 0;
padding-right: 12px;
position: relative;
}
.toc-items li::before {
content: '\2022';
color: #9CA3AF;
}
.toc-count {
display: inline-block;
background: #F3F4F6;
color: #6B7280;
font-size: 10px;
padding: 1px 6px;
border-radius: 8px;
margin-right: 8px;
content: '—';
position: absolute;
right: 0;
color: #D1D5DB;
font-size: 9px;
}
/* Section Headers */
.section-header {
/* ══════════════════════════════════════
Feature 1 & 16: MODULE DIVIDER PAGES
══════════════════════════════════════ */
.module-divider {
page-break-before: always;
page-break-after: avoid;
padding: 60px 0 30px;
page-break-after: always;
width: 100%;
min-height: 250mm;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
border-bottom: 3px solid #8B5CF6;
margin-bottom: 30px;
position: relative;
padding: 80px 40px;
background: #FAFBFF;
}
.module-divider::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 6px;
background: var(--section-color, #8B5CF6);
}
.module-divider::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 2px;
background: var(--section-color, #8B5CF6);
opacity: 0.3;
}
/* Feature 14: Decorative corners */
.module-divider-corners {
position: absolute;
top: 30px;
left: 30px;
right: 30px;
bottom: 30px;
pointer-events: none;
}
.module-divider-corners::before,
.module-divider-corners::after {
content: '';
position: absolute;
width: 40px;
height: 40px;
border-color: var(--section-color, #8B5CF6);
opacity: 0.2;
}
.module-divider-corners::before {
top: 0;
right: 0;
border-top: 3px solid;
border-right: 3px solid;
}
.module-divider-corners::after {
bottom: 0;
left: 0;
border-bottom: 3px solid;
border-left: 3px solid;
}
.section-header h2 {
font-size: 30px;
.module-divider-num {
font-size: 80px;
font-weight: 900;
color: var(--section-color, #8B5CF6);
opacity: 0.1;
position: absolute;
top: 60px;
left: 50%;
transform: translateX(-50%);
line-height: 1;
}
.module-divider-icon {
width: 80px;
height: 80px;
background: var(--section-color, #8B5CF6);
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 32px;
box-shadow: 0 8px 32px rgba(0,0,0,0.08);
}
.module-divider-icon svg {
width: 40px;
height: 40px;
fill: none;
stroke: #fff;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
}
.module-divider h2 {
font-size: 36px;
font-weight: 900;
color: #1A1A2E;
margin-bottom: 8px;
margin-bottom: 12px;
}
.section-header p {
font-size: 14px;
.module-divider-subtitle {
font-size: 15px;
color: #6B7280;
margin-bottom: 32px;
max-width: 350px;
line-height: 2;
}
.section-header .section-count {
display: inline-block;
background: #EDE9FE;
color: #7C3AED;
font-size: 12px;
font-weight: 600;
padding: 4px 12px;
/* Feature 19: Section summary stats */
.module-divider-stats {
display: flex;
gap: 24px;
background: #fff;
padding: 16px 32px;
border-radius: 12px;
margin-top: 12px;
border: 1px solid #E5E7EB;
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
}
.module-divider-stat {
text-align: center;
}
.module-divider-stat-num {
font-size: 24px;
font-weight: 900;
color: var(--section-color, #8B5CF6);
display: block;
}
.module-divider-stat-label {
font-size: 10px;
color: #9CA3AF;
font-weight: 600;
}
/* Tutorial Blocks */
/* ══════════════════════════════════════
Feature 2: TUTORIAL BLOCKS (no split)
══════════════════════════════════════ */
.tutorial-block {
page-break-inside: avoid;
margin-bottom: 30px;
page-break-before: auto;
margin-bottom: 24px;
border: 1px solid #E5E7EB;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 1px 4px rgba(0,0,0,0.04);
}
/* Feature 9: Gradient badge numbering */
.tutorial-block-header {
background: #F9FAFB;
background: linear-gradient(135deg, #FAFBFF, #F3F4F6);
padding: 16px 20px;
border-bottom: 1px solid #E5E7EB;
display: flex;
align-items: center;
gap: 12px;
gap: 14px;
}
.tutorial-num {
width: 32px;
height: 32px;
background: linear-gradient(135deg, #7C3AED, #8B5CF6);
color: #fff;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
font-weight: 800;
flex-shrink: 0;
box-shadow: 0 2px 8px rgba(124,58,237,0.3);
}
.tutorial-block-header h3 {
font-size: 16px;
font-size: 15px;
font-weight: 700;
color: #1A1A2E;
margin: 0;
margin: 0 0 2px;
}
.tutorial-block-header .tutorial-subtitle {
font-size: 12px;
font-size: 11px;
color: #6B7280;
margin: 2px 0 0;
margin: 0;
}
.tutorial-block-header .tutorial-num {
width: 28px;
height: 28px;
background: #8B5CF6;
color: #fff;
border-radius: 8px;
/* Feature 15: Tutorial metadata tags */
.tutorial-tags {
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 700;
flex-shrink: 0;
gap: 6px;
margin-top: 6px;
flex-wrap: wrap;
}
.tutorial-tag {
display: inline-block;
padding: 2px 8px;
border-radius: 8px;
font-size: 9px;
font-weight: 600;
}
.tutorial-tag-setup { background: #DBEAFE; color: #1D4ED8; }
.tutorial-tag-operation { background: #D1FAE5; color: #065F46; }
.tutorial-tag-report { background: #FEF3C7; color: #92400E; }
.tutorial-tag-management { background: #EDE9FE; color: #6D28D9; }
.tutorial-block-body {
padding: 20px;
padding: 20px 24px;
}
/* Screenshot in tutorial */
/* ── Feature 10: Screenshot frames ── */
.tutorial-screenshot {
width: 100%;
max-height: 400px;
max-height: 350px;
object-fit: contain;
border: 1px solid #E5E7EB;
border-radius: 8px;
margin-bottom: 16px;
margin: 12px 0;
box-shadow: 0 4px 16px rgba(0,0,0,0.08);
}
/* Steps (for detailed tutorials) */
/* ══════════════════════════════════════
Feature 11: STEP CARDS
══════════════════════════════════════ */
.tut-page { max-width: 100%; }
.tut-header {
display: flex;
align-items: center;
gap: 14px;
margin-bottom: 20px;
padding: 16px;
background: #F9FAFB;
padding: 14px 16px;
background: linear-gradient(135deg, #F9FAFB, #F3F4F6);
border-radius: 10px;
border: 1px solid #E5E7EB;
}
.tut-header-icon {
width: 44px;
height: 44px;
background: #8B5CF6;
width: 40px;
height: 40px;
background: linear-gradient(135deg, #7C3AED, #8B5CF6);
border-radius: 10px;
display: flex;
align-items: center;
......@@ -241,202 +523,373 @@ body {
flex-shrink: 0;
}
.tut-header h1 {
font-size: 18px;
font-size: 16px;
font-weight: 800;
color: #1A1A2E;
margin: 0 0 2px;
}
.tut-header p {
font-size: 12px;
font-size: 11px;
color: #6B7280;
margin: 0;
}
.tut-step {
position: relative;
padding: 14px 50px 14px 14px;
padding: 14px 16px 14px 48px;
margin-bottom: 10px;
background: #fff;
border: 1px solid #E5E7EB;
border-radius: 8px;
border-radius: 10px;
border-right: 4px solid #8B5CF6;
page-break-inside: avoid;
}
.tut-step-num {
position: absolute;
right: 12px;
right: auto;
left: 12px;
top: 14px;
width: 28px;
height: 28px;
background: #EDE9FE;
width: 26px;
height: 26px;
background: linear-gradient(135deg, #EDE9FE, #DDD6FE);
color: #7C3AED;
border-radius: 6px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-size: 11px;
font-weight: 800;
}
.tut-step-title {
font-size: 13px;
font-size: 12px;
font-weight: 700;
color: #1A1A2E;
margin: 0 0 4px;
}
.tut-step-body {
font-size: 12px;
font-size: 11px;
color: #374151;
line-height: 1.7;
line-height: 1.8;
}
.tut-step-body ul { margin: 6px 0; padding-right: 16px; }
.tut-step-body li { margin-bottom: 3px; }
.tut-step-body li { margin-bottom: 4px; }
.tut-step-body .field {
display: inline-block;
background: #F3F4F6;
color: #1A1A2E;
padding: 0 6px;
border-radius: 3px;
font-size: 11px;
padding: 1px 8px;
border-radius: 4px;
font-size: 10px;
font-weight: 600;
border: 1px solid #E5E7EB;
}
/* ── Feature 12: Callout boxes ── */
.tut-step-body .warn {
display: block;
background: #FEF3C7;
border: 1px solid #F59E0B40;
border-radius: 6px;
padding: 8px 10px;
margin: 6px 0;
font-size: 11px;
background: #FFFBEB;
border: 1px solid #FDE68A;
border-right: 4px solid #F59E0B;
border-radius: 8px;
padding: 10px 14px;
margin: 8px 0;
font-size: 10px;
color: #92400E;
line-height: 1.8;
}
.tut-step-body .info {
display: block;
background: #DBEAFE;
border: 1px solid #3B82F640;
border-radius: 6px;
padding: 8px 10px;
margin: 6px 0;
font-size: 11px;
background: #EFF6FF;
border: 1px solid #BFDBFE;
border-right: 4px solid #3B82F6;
border-radius: 8px;
padding: 10px 14px;
margin: 8px 0;
font-size: 10px;
color: #1E40AF;
line-height: 1.8;
}
.tut-step-body .success {
display: block;
background: #ECFDF5;
border: 1px solid #05966940;
border-radius: 6px;
padding: 8px 10px;
margin: 6px 0;
font-size: 11px;
border: 1px solid #A7F3D0;
border-right: 4px solid #10B981;
border-radius: 8px;
padding: 10px 14px;
margin: 8px 0;
font-size: 10px;
color: #065F46;
line-height: 1.8;
}
.tut-step-body .tip {
display: block;
background: #F5F3FF;
border: 1px solid #DDD6FE;
border-right: 4px solid #8B5CF6;
border-radius: 8px;
padding: 10px 14px;
margin: 8px 0;
font-size: 10px;
color: #5B21B6;
line-height: 1.8;
}
.tut-diagram {
background: #F8FAFC;
border: 1px solid #E2E8F0;
border-radius: 8px;
padding: 12px;
margin: 8px 0;
font-family: monospace;
font-size: 10px;
padding: 14px;
margin: 10px 0;
font-family: 'Courier New', monospace;
font-size: 9px;
direction: ltr;
text-align: left;
line-height: 1.5;
line-height: 1.6;
overflow: hidden;
}
/* Category Separator */
/* ── Feature 8: Category sub-dividers ── */
.category-header {
margin: 24px 0 12px;
padding: 8px 14px;
background: #F3F4F6;
border-radius: 8px;
margin: 28px 0 16px;
padding: 10px 18px;
background: linear-gradient(135deg, #F9FAFB, #F3F4F6);
border-radius: 10px;
border-right: 5px solid var(--section-color, #8B5CF6);
font-size: 14px;
font-weight: 700;
color: #374151;
font-weight: 800;
color: #1A1A2E;
page-break-after: avoid;
display: flex;
align-items: center;
gap: 10px;
}
.category-header::after {
content: '';
flex: 1;
height: 1px;
background: #E5E7EB;
}
/* Footer */
/* ── Feature 6: Running footer ── */
.page-footer {
position: fixed;
bottom: 10mm;
left: 15mm;
right: 15mm;
font-size: 9px;
bottom: 8mm;
left: 18mm;
right: 18mm;
font-size: 8px;
color: #9CA3AF;
text-align: center;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #F3F4F6;
padding-top: 6px;
}
.page-footer-brand {
font-weight: 600;
color: #6B7280;
}
/* Screenshot image within content */
/* ── Feature 10: Screenshot styling ── */
.tutorial-block-body img {
max-width: 100%;
height: auto;
border-radius: 6px;
border-radius: 8px;
border: 1px solid #E5E7EB;
margin: 8px 0;
margin: 10px 0;
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
}
/* ══════════════════════════════════════
Feature 18: BACK COVER
══════════════════════════════════════ */
.back-cover {
page-break-before: always;
width: 100%;
min-height: 250mm;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
background: linear-gradient(160deg, #0F0A2A, #1A1145, #2D1B69);
color: #fff;
padding: 60px;
position: relative;
}
.back-cover::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, #8B5CF6, #EC4899, #F59E0B, #10B981, #3B82F6);
}
.back-cover-logo {
width: 80px;
height: 80px;
background: rgba(255,255,255,0.08);
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 24px;
border: 1px solid rgba(255,255,255,0.1);
}
.back-cover-logo svg {
width: 40px;
height: 40px;
fill: none;
stroke: #fff;
stroke-width: 1.5;
}
.back-cover h2 {
font-size: 24px;
font-weight: 800;
margin-bottom: 8px;
opacity: 0.9;
}
.back-cover p {
font-size: 12px;
opacity: 0.5;
margin-bottom: 4px;
}
/* ── Feature 20: Consistent spacing rhythm ── */
.spacing-sm { margin-bottom: 8px; }
.spacing-md { margin-bottom: 16px; }
.spacing-lg { margin-bottom: 24px; }
.spacing-xl { margin-bottom: 32px; }
/* Print optimizations */
/* ── Feature 17: Print optimizations ── */
@media print {
body { font-size: 11px; }
.cover-page { height: 297mm; }
.module-divider { height: 297mm; }
.back-cover { height: 297mm; }
.no-print { display: none; }
}
</style>
</head>
<body>
<!-- Cover Page -->
<?php
$sectionColors = [
'#8B5CF6', '#3B82F6', '#10B981', '#F59E0B', '#EF4444',
'#06B6D4', '#EC4899', '#14B8A6', '#F97316', '#6366F1',
'#84CC16', '#0EA5E9', '#D946EF', '#22C55E', '#E11D48',
'#0891B2', '#7C3AED', '#059669', '#DC2626', '#2563EB',
'#8B5CF6', '#3B82F6', '#10B981', '#F59E0B', '#EF4444',
'#06B6D4', '#EC4899', '#14B8A6', '#F97316', '#6366F1',
'#84CC16', '#0EA5E9', '#D946EF', '#22C55E', '#E11D48',
'#0891B2', '#7C3AED', '#059669', '#DC2626', '#2563EB',
'#8B5CF6', '#3B82F6', '#10B981',
];
$totalTutorials = 0;
$totalSections = count($data['sections']);
foreach ($data['sections'] as $s) {
$totalTutorials += count($s['tutorials']);
}
$sectionIcons = [
'membership' => '<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',
'sports-activity' => '<circle cx="12" cy="12" r="10"/><path d="M12 8v4l3 3"/>',
'treasury' => '<rect x="2" y="4" width="20" height="16" rx="2"/><path d="M12 8v8"/><path d="M8 12h8"/>',
'default' => '<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>',
];
?>
<!-- ═══ COVER PAGE ═══ -->
<div class="cover-page">
<div class="cover-geometric"></div>
<div class="cover-logo">
<svg viewBox="0 0 24 24"><path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" stroke-linecap="round" stroke-linejoin="round"/></svg>
<svg viewBox="0 0 24 24"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" stroke-linecap="round" stroke-linejoin="round"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
<div class="cover-title">Book of the ERP</div>
<div class="cover-subtitle">كتاب النظام الشامل</div>
<div class="cover-desc">الدليل التفصيلي لجميع عمليات نظام إدارة النادي</div>
<div class="cover-desc">الدليل التدريبي التفصيلي لجميع عمليات وأقسام نظام إدارة النادي — مرجع شامل للموظفين</div>
<div class="cover-stats">
<div class="cover-stat">
<span class="cover-stat-num"><?= $totalSections ?></span>
<span class="cover-stat-label">قسم</span>
</div>
<div class="cover-stat">
<span class="cover-stat-num"><?= $totalTutorials ?></span>
<span class="cover-stat-label">شرح</span>
</div>
<div class="cover-stat">
<span class="cover-stat-num">105</span>
<span class="cover-stat-label">لقطة شاشة</span>
</div>
</div>
<div class="cover-meta">
تم التوليد في: <?= $data['generatedAt'] ?> &nbsp;|&nbsp;
عدد الأقسام: <?= count($data['sections']) ?> &nbsp;|&nbsp;
إجمالي الشروحات: <?php
$totalTutorials = 0;
foreach ($data['sections'] as $s) {
$totalTutorials += count($s['tutorials']);
}
echo $totalTutorials;
?>
تم التوليد في: <?= $data['generatedAt'] ?>
</div>
</div>
<!-- Table of Contents -->
<!-- ═══ TABLE OF CONTENTS ═══ -->
<div class="toc-page">
<h1 class="toc-title">فهرس المحتويات</h1>
<div class="toc-header">
<h1>فهرس المحتويات</h1>
<p><?= $totalSections ?> قسم — <?= $totalTutorials ?> شرح تفصيلي</p>
</div>
<div class="toc-grid">
<?php $sectionNum = 0; foreach ($data['sections'] as $sectionKey => $section): $sectionNum++; ?>
<div class="toc-section">
<div class="toc-section-title">
<?= htmlspecialchars($section['title'], ENT_QUOTES, 'UTF-8') ?>
<span class="toc-count"><?= count($section['tutorials']) ?> شرح</span>
<div class="toc-section" style="border-right-color: <?= $sectionColors[$sectionNum - 1] ?? '#8B5CF6' ?>;">
<div class="toc-section-title">
<span><span class="toc-section-num" style="background:<?= $sectionColors[$sectionNum - 1] ?? '#8B5CF6' ?>;"><?= $sectionNum ?></span> <?= htmlspecialchars($section['title'], ENT_QUOTES, 'UTF-8') ?></span>
<span class="toc-badge"><?= count($section['tutorials']) ?></span>
</div>
<?php if (count($section['tutorials']) <= 8): ?>
<ul class="toc-items">
<?php foreach ($section['tutorials'] as $slug => $tutorial): ?>
<li><?= htmlspecialchars($tutorial['title'], ENT_QUOTES, 'UTF-8') ?></li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<ul class="toc-items">
<?php $i = 0; foreach ($section['tutorials'] as $slug => $tutorial): $i++; if ($i > 5) break; ?>
<li><?= htmlspecialchars($tutorial['title'], ENT_QUOTES, 'UTF-8') ?></li>
<?php endforeach; ?>
<li style="color:#9CA3AF;font-style:italic;">+ <?= count($section['tutorials']) - 5 ?> شرح آخر...</li>
</ul>
<?php endif; ?>
</div>
<ul class="toc-items">
<?php foreach ($section['tutorials'] as $slug => $tutorial): ?>
<li><?= htmlspecialchars($tutorial['title'], ENT_QUOTES, 'UTF-8') ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endforeach; ?>
</div>
</div>
<!-- Sections & Tutorials -->
<?php $sectionNum = 0; foreach ($data['sections'] as $sectionKey => $section): $sectionNum++; ?>
<!-- ═══ SECTIONS & TUTORIALS ═══ -->
<?php $sectionNum = 0; foreach ($data['sections'] as $sectionKey => $section): $sectionNum++; $color = $sectionColors[$sectionNum - 1] ?? '#8B5CF6'; ?>
<div class="section-header">
<h2>القسم <?= $sectionNum ?>: <?= htmlspecialchars($section['title'], ENT_QUOTES, 'UTF-8') ?></h2>
<!-- Module Divider Page -->
<div class="module-divider" style="--section-color: <?= $color ?>;">
<div class="module-divider-corners"></div>
<div class="module-divider-num"><?= str_pad((string)$sectionNum, 2, '0', STR_PAD_LEFT) ?></div>
<div class="module-divider-icon" style="background: <?= $color ?>;">
<svg viewBox="0 0 24 24"><?= $sectionIcons[$sectionKey] ?? $sectionIcons['default'] ?></svg>
</div>
<h2><?= htmlspecialchars($section['title'], ENT_QUOTES, 'UTF-8') ?></h2>
<?php if (!empty($section['subtitle'])): ?>
<p><?= htmlspecialchars($section['subtitle'], ENT_QUOTES, 'UTF-8') ?></p>
<div class="module-divider-subtitle"><?= htmlspecialchars($section['subtitle'], ENT_QUOTES, 'UTF-8') ?></div>
<?php endif; ?>
<div class="section-count"><?= count($section['tutorials']) ?> شرح في هذا القسم</div>
<div class="module-divider-stats">
<div class="module-divider-stat">
<span class="module-divider-stat-num" style="color:<?= $color ?>;"><?= count($section['tutorials']) ?></span>
<span class="module-divider-stat-label">شرح</span>
</div>
<div class="module-divider-stat">
<span class="module-divider-stat-num" style="color:<?= $color ?>;"><?= count($section['categories'] ?? []) ?></span>
<span class="module-divider-stat-label">تصنيف</span>
</div>
<div class="module-divider-stat">
<span class="module-divider-stat-num" style="color:<?= $color ?>;">القسم <?= $sectionNum ?></span>
<span class="module-divider-stat-label">من <?= $totalSections ?></span>
</div>
</div>
</div>
<?php if (!empty($section['screenshot']) && file_exists($section['screenshot'])): ?>
<div style="text-align:center;margin-bottom:24px;">
<div style="text-align:center;margin: 24px 0;page-break-inside:avoid;">
<img src="file://<?= $section['screenshot'] ?>" class="tutorial-screenshot" alt="<?= htmlspecialchars($section['title'], ENT_QUOTES, 'UTF-8') ?>">
</div>
<?php endif; ?>
......@@ -450,13 +903,15 @@ foreach ($section['tutorials'] as $slug => $tutorial):
if ($cat !== $currentCategory && !empty($section['categories'][$cat])):
$currentCategory = $cat;
?>
<div class="category-header"><?= htmlspecialchars($section['categories'][$cat]['label'], ENT_QUOTES, 'UTF-8') ?></div>
<div class="category-header" style="--section-color: <?= $color ?>; border-right-color: <?= $color ?>;">
<?= htmlspecialchars($section['categories'][$cat]['label'], ENT_QUOTES, 'UTF-8') ?>
</div>
<?php endif; ?>
<div class="tutorial-block">
<div class="tutorial-block-header">
<div class="tutorial-num"><?= $tutorialNum ?></div>
<div>
<div class="tutorial-num" style="background: linear-gradient(135deg, <?= $color ?>, <?= $color ?>CC);"><?= $tutorialNum ?></div>
<div style="flex:1;">
<h3><?= htmlspecialchars($tutorial['title'], ENT_QUOTES, 'UTF-8') ?></h3>
<?php if (!empty($tutorial['subtitle'])): ?>
<div class="tutorial-subtitle"><?= htmlspecialchars($tutorial['subtitle'], ENT_QUOTES, 'UTF-8') ?></div>
......@@ -466,8 +921,16 @@ foreach ($section['tutorials'] as $slug => $tutorial):
<div class="tutorial-block-body">
<?php if (!empty($tutorial['htmlContent'])): ?>
<?= $tutorial['htmlContent'] ?>
<?php elseif (!empty($tutorial['steps'])): ?>
<?php foreach ($tutorial['steps'] as $stepIdx => $step): ?>
<div class="tut-step" style="border-right-color: <?= $color ?>;">
<div class="tut-step-num"><?= $stepIdx + 1 ?></div>
<div class="tut-step-title"><?= htmlspecialchars($step['title'] ?? '', ENT_QUOTES, 'UTF-8') ?></div>
<div class="tut-step-body"><?= $step['body'] ?? '' ?></div>
</div>
<?php endforeach; ?>
<?php else: ?>
<p style="color:#6B7280;font-style:italic;font-size:12px;">
<p style="color:#6B7280;font-size:11px;padding:8px 0;">
<?= htmlspecialchars($tutorial['subtitle'] ?? $tutorial['title'], ENT_QUOTES, 'UTF-8') ?>
</p>
<?php endif; ?>
......@@ -477,5 +940,16 @@ foreach ($section['tutorials'] as $slug => $tutorial):
<?php endforeach; ?>
<?php endforeach; ?>
<!-- ═══ BACK COVER ═══ -->
<div class="back-cover">
<div class="back-cover-logo">
<svg viewBox="0 0 24 24"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" stroke-linecap="round" stroke-linejoin="round"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
<h2>Book of the ERP</h2>
<p>كتاب النظام الشامل — الإصدار الأول</p>
<p style="margin-top:16px;opacity:0.3;font-size:10px;">تم التوليد تلقائياً بواسطة نظام إدارة النادي</p>
<p style="opacity:0.3;font-size:10px;"><?= $data['generatedAt'] ?></p>
</div>
</body>
</html>
......@@ -23,8 +23,7 @@ final class PdfExportService
$html = ob_get_clean();
$response = new Response();
return $response->html($html, 200, [
'Content-Type' => 'text/html; charset=utf-8',
return $response->html($html, 200)->withHeaders([
'Content-Disposition' => 'attachment; filename="' . $filename . '"',
]);
}
......@@ -61,7 +60,7 @@ final class PdfExportService
@unlink($tmpOutput);
$response = new Response();
return $response->html($pdfContent, 200, [
return $response->html($pdfContent, 200)->withHeaders([
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'attachment; filename="' . $filename . '"',
'Content-Length' => (string) strlen($pdfContent),
......@@ -71,8 +70,7 @@ final class PdfExportService
}
$response = new Response();
return $response->html($html, 200, [
'Content-Type' => 'text/html; charset=utf-8',
return $response->html($html, 200)->withHeaders([
'Content-Disposition' => 'attachment; filename="' . str_replace('.pdf', '.html', $filename) . '"',
]);
}
......
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