Commit ·
e7a38b2
1
Parent(s): b201fcd
feat: Add Quran + Dialect product links to footer
Browse files- src/index.html +2 -0
- verify_all.py +99 -0
src/index.html
CHANGED
|
@@ -1100,6 +1100,8 @@
|
|
| 1100 |
<li><button onclick="showPage('editor')" class="text-sm transition-colors footer-link-hover" style="color: var(--text-secondary); background: none; border: none; cursor: pointer; font-family: inherit;">المحرر</button></li>
|
| 1101 |
<li><button onclick="showPage('features')" class="text-sm transition-colors footer-link-hover" style="color: var(--text-secondary); background: none; border: none; cursor: pointer; font-family: inherit;">الميزات</button></li>
|
| 1102 |
<li><button onclick="showPage('pricing')" class="text-sm transition-colors footer-link-hover" style="color: var(--text-secondary); background: none; border: none; cursor: pointer; font-family: inherit;">الأسعار</button></li>
|
|
|
|
|
|
|
| 1103 |
</ul>
|
| 1104 |
</div>
|
| 1105 |
<div>
|
|
|
|
| 1100 |
<li><button onclick="showPage('editor')" class="text-sm transition-colors footer-link-hover" style="color: var(--text-secondary); background: none; border: none; cursor: pointer; font-family: inherit;">المحرر</button></li>
|
| 1101 |
<li><button onclick="showPage('features')" class="text-sm transition-colors footer-link-hover" style="color: var(--text-secondary); background: none; border: none; cursor: pointer; font-family: inherit;">الميزات</button></li>
|
| 1102 |
<li><button onclick="showPage('pricing')" class="text-sm transition-colors footer-link-hover" style="color: var(--text-secondary); background: none; border: none; cursor: pointer; font-family: inherit;">الأسعار</button></li>
|
| 1103 |
+
<li><button onclick="showPage('editor')" class="text-sm transition-colors footer-link-hover" style="color: var(--text-secondary); background: none; border: none; cursor: pointer; font-family: inherit;">تدقيق القرآن</button></li>
|
| 1104 |
+
<li><button onclick="showPage('editor')" class="text-sm transition-colors footer-link-hover" style="color: var(--text-secondary); background: none; border: none; cursor: pointer; font-family: inherit;">تحويل اللهجات</button></li>
|
| 1105 |
</ul>
|
| 1106 |
</div>
|
| 1107 |
<div>
|
verify_all.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import re
|
| 2 |
+
|
| 3 |
+
content = open('src/index.html', encoding='utf-8').read()
|
| 4 |
+
ui_js = open('src/js/ui.js', encoding='utf-8').read()
|
| 5 |
+
docs_ui = open('src/js/documents-cloud/documents-ui.js', encoding='utf-8').read()
|
| 6 |
+
editor_js = open('src/js/editor.js', encoding='utf-8').read()
|
| 7 |
+
format_js = open('src/js/format.js', encoding='utf-8').read()
|
| 8 |
+
comp_css = open('src/css/components.css', encoding='utf-8').read()
|
| 9 |
+
|
| 10 |
+
print('=' * 60)
|
| 11 |
+
print('PHASE 6 (cont): EDITOR COMPONENTS')
|
| 12 |
+
print('=' * 60)
|
| 13 |
+
checks = [
|
| 14 |
+
('6.2 Format tooltip Bold Arabic', 'title="\u063a\u0627\u0645\u0642' in content),
|
| 15 |
+
('6.2 Dropdowns close on click outside', 'closeAllFmtDropdowns' in format_js),
|
| 16 |
+
('6.2 Dropdowns close on Escape', 'Escape' in format_js),
|
| 17 |
+
('6.2 Active item highlight class', 'fmt-dropdown__item--active' in format_js),
|
| 18 |
+
('6.2 Smooth dropdown animation', 'translateY(-8px)' in comp_css),
|
| 19 |
+
('6.3 Placeholder exists', 'placeholder' in content.lower()),
|
| 20 |
+
('6.4 Popover hint text', '\u0627\u062e\u062a\u0631 \u0627\u0644\u062a\u0635\u062d\u064a\u062d' in content),
|
| 21 |
+
('6.5 Empty state (has text - positive)', '\u0646\u0635\u0643 \u0645\u0645\u062a\u0627\u0632' in ui_js),
|
| 22 |
+
('6.5 Empty state (no text)', '\u0644\u0627 \u062a\u0648\u062c\u062f \u0627\u0642\u062a\u0631\u0627\u062d\u0627\u062a' in ui_js),
|
| 23 |
+
('6.5 Apply All shows count', 'countLabel' in ui_js),
|
| 24 |
+
('6.5 Shimmer skeleton in analysis', 'skeleton' in ui_js),
|
| 25 |
+
('6.6 Stats char-count', 'char-count' in content),
|
| 26 |
+
('6.6 Stats sentence-count', 'sentence-count' in content),
|
| 27 |
+
('6.6 Stats reading-time', 'reading-time' in content),
|
| 28 |
+
('6.7 Docs empty state with icon', 'empty-state__icon' in docs_ui),
|
| 29 |
+
('6.7 Docs delete uses custom dialog', 'showConfirmDialog' in docs_ui),
|
| 30 |
+
('6.8 Summary loading state', '\u062c\u0627\u0631\u064a \u062a\u0648\u0644\u064a\u062f' in content),
|
| 31 |
+
('6.8 Summary error state', '\u062d\u062f\u062b \u062e\u0637\u0623' in content),
|
| 32 |
+
('6.9 Dialect char counter', 'dialect-char-count' in content or 'charCount' in content),
|
| 33 |
+
('6.10 Quran Escape closes', 'Escape' in content),
|
| 34 |
+
('6.10 Quran Ctrl+Q shortcut', 'KeyQ' in content),
|
| 35 |
+
]
|
| 36 |
+
for name, result in checks:
|
| 37 |
+
print(f' {"OK" if result else "MISS"} {name}')
|
| 38 |
+
|
| 39 |
+
print()
|
| 40 |
+
print('=' * 60)
|
| 41 |
+
print('PHASE 7: USER FLOWS & EDGE CASES')
|
| 42 |
+
print('=' * 60)
|
| 43 |
+
checks = [
|
| 44 |
+
('7.1 Auth gate exists', 'auth-gate' in content),
|
| 45 |
+
('7.1 Google sign-in', 'linkGoogle' in content),
|
| 46 |
+
('7.1 Guest flow', 'continueAsGuest' in content or '\u0627\u0644\u062a\u062c\u0631\u0628\u0629 \u0628\u062f\u0648\u0646' in content),
|
| 47 |
+
('7.1 Offline banner', 'offline-banner' in content),
|
| 48 |
+
('7.2 Doc save toast', '\u062a\u0645 \u0627\u0644\u062d\u0641\u0638' in content or '\u062a\u0645 \u0627\u0644\u062d\u0641\u0638' in docs_ui),
|
| 49 |
+
('7.2 Doc delete custom confirm', 'showConfirmDialog' in docs_ui),
|
| 50 |
+
('7.3 Summary loading spinner', 'summary-loading' in content),
|
| 51 |
+
('7.4 Auto-sync settings', 'settings-sync' in content or 'localStorage' in content),
|
| 52 |
+
('7.5 Draft restore on refresh', 'bayan_editor_draft' in editor_js),
|
| 53 |
+
('7.5 Theme persists', 'localStorage' in content and 'theme' in content.lower()),
|
| 54 |
+
('7.6 Analyze error toast', '\u062a\u0639\u0630\u0651\u0631 \u0627\u0644\u062a\u062d\u0644\u064a\u0644' in editor_js),
|
| 55 |
+
('7.6 Summary error in panel', '\u062d\u062f\u062b \u062e\u0637\u0623' in content),
|
| 56 |
+
('7.6 Dialect error handled', 'error' in content.split('dialect')[1][:2000] if 'dialect' in content else False),
|
| 57 |
+
('7.6 Quran error handled', 'catch' in content.split('quran')[2][:3000] if content.count('quran') > 2 else False),
|
| 58 |
+
]
|
| 59 |
+
for name, result in checks:
|
| 60 |
+
print(f' {"OK" if result else "MISS"} {name}')
|
| 61 |
+
|
| 62 |
+
print()
|
| 63 |
+
print('=' * 60)
|
| 64 |
+
print('PHASE 9: GLOBAL POLISH')
|
| 65 |
+
print('=' * 60)
|
| 66 |
+
# Count toast types
|
| 67 |
+
all_toasts = re.findall(r"showToast\([^)]+\)", content + editor_js)
|
| 68 |
+
success_toasts = [t for t in all_toasts if "'success'" in t or "type" not in t]
|
| 69 |
+
error_toasts = [t for t in all_toasts if "'error'" in t]
|
| 70 |
+
warning_toasts = [t for t in all_toasts if "'warning'" in t]
|
| 71 |
+
checks = [
|
| 72 |
+
('Meta desc includes Quran', '\u0627\u0644\u0642\u0631\u0622\u0646' in content.split('</head>')[0]),
|
| 73 |
+
('Meta desc includes dialects', '\u0627\u0644\u0644\u0647\u062c\u0627\u062a' in content.split('</head>')[0]),
|
| 74 |
+
('Footer has Quran link', '\u062a\u062f\u0642\u064a\u0642 \u0627\u0644\u0642\u0631\u0622\u0646' in content.split('footer')[1] if 'footer' in content.lower() else False),
|
| 75 |
+
('Footer has Dialect link', '\u062a\u062d\u0648\u064a\u0644 \u0627\u0644\u0644\u0647\u062c\u0627\u062a' in content.split('footer')[1] if 'footer' in content.lower() else False),
|
| 76 |
+
('404 arrow correct direction', '\u2192 \u0627\u0644\u0639\u0648\u062f\u0629' in content),
|
| 77 |
+
('Scroll-to-top button', 'scroll-top-btn' in content),
|
| 78 |
+
(f'Toast types: {len(error_toasts)} error, {len(warning_toasts)} warning', len(error_toasts) >= 4 and len(warning_toasts) >= 3),
|
| 79 |
+
]
|
| 80 |
+
for name, result in checks:
|
| 81 |
+
print(f' {"OK" if result else "MISS"} {name}')
|
| 82 |
+
|
| 83 |
+
print()
|
| 84 |
+
print('=' * 60)
|
| 85 |
+
print('ARCHITECTURAL SAFETY')
|
| 86 |
+
print('=' * 60)
|
| 87 |
+
renderer = open('src/js/renderer.js', encoding='utf-8').read()
|
| 88 |
+
selection = open('src/js/selection.js', encoding='utf-8').read()
|
| 89 |
+
checks = [
|
| 90 |
+
('renderer.js NOT modified (has render fn)', 'function' in renderer),
|
| 91 |
+
('selection.js NOT modified (has save/restore)', 'saveSelection' in selection or 'restoreSelection' in selection),
|
| 92 |
+
('No React/Vue/Angular', 'react' not in content.lower().split('<script')[0]),
|
| 93 |
+
('No TypeScript', '.ts' not in content),
|
| 94 |
+
('Core flow intact: getEditorText', 'getEditorText' in editor_js),
|
| 95 |
+
('Core flow intact: /api/analyze', '/api/analyze' in editor_js),
|
| 96 |
+
('Core flow intact: restoreSelection', 'restoreSelection' in editor_js),
|
| 97 |
+
]
|
| 98 |
+
for name, result in checks:
|
| 99 |
+
print(f' {"OK" if result else "MISS"} {name}')
|