|
3 | 3 | <head> |
4 | 4 | <meta charset="UTF-8"> |
5 | 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
6 | | - <title>Quiz Admin Editor</title> |
7 | | -<link rel="stylesheet" href="admin.css"> |
8 | | -<script src="admin.app.js"></script> |
9 | | - <!-- Supabase JS client --> |
| 6 | + <title>3c-quiz-admin · Dark Purple Edition</title> |
| 7 | + |
| 8 | + <!-- Styles — Google Fonts loaded via @import inside admin.css --> |
| 9 | + <link rel="stylesheet" href="admin.css"> |
| 10 | + |
| 11 | + <!-- Supabase JS client (must load before admin_app.js) --> |
10 | 12 | <script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js"></script> |
11 | | - <style> |
12 | | - /* Additional text direction fixes */ |
13 | | - * { |
14 | | - direction: ltr !important; |
15 | | - text-align: left; |
16 | | - } |
17 | | - input[type="text"], textarea, [contenteditable] { |
18 | | - direction: ltr !important; |
19 | | - text-align: left !important; |
20 | | - unicode-bidi: normal !important; |
21 | | - } |
22 | | - /* Ensure proper text input behavior */ |
23 | | - .text-block .block-content { |
24 | | - direction: ltr !important; |
25 | | - text-align: left !important; |
26 | | - unicode-bidi: normal !important; |
27 | | - writing-mode: horizontal-tb !important; |
28 | | - } |
29 | | - </style> |
30 | 13 | </head> |
31 | 14 | <body dir="ltr"> |
32 | | - <!-- Main application container: used by admin.app.js --> |
| 15 | + |
| 16 | + <!-- Main application container — rendered entirely by admin_app.js --> |
33 | 17 | <div id="app" dir="ltr"></div> |
34 | | - <!-- Fatal error display, only shown if JS can't render UI --> |
35 | | - <div id="fatal-error" style="display:none;color:#c00;font-size:1.2em;margin:32px;"></div> |
| 18 | + |
| 19 | + <!-- Fatal error fallback — only shown if JS fails to mount --> |
| 20 | + <div id="fatal-error" style="display:none;color:#f87171;font-size:1.2em;margin:32px;font-family:sans-serif;"></div> |
| 21 | + |
36 | 22 | <script> |
37 | | - // Defensive JS: check for #app container before loading app logic |
| 23 | + // Defensive check before app loads |
38 | 24 | if (!document.getElementById('app')) { |
39 | | - document.getElementById('fatal-error').innerText = "Fatal Error: #app container not found in HTML."; |
40 | | - document.getElementById('fatal-error').style.display = "block"; |
41 | | - throw new Error("Fatal Error: #app container not found in HTML."); |
| 25 | + const el = document.getElementById('fatal-error'); |
| 26 | + el.innerText = 'Fatal Error: #app container not found.'; |
| 27 | + el.style.display = 'block'; |
| 28 | + throw new Error('Fatal Error: #app container not found.'); |
42 | 29 | } |
43 | | - |
44 | | - // Force LTR direction globally |
| 30 | + |
| 31 | + // Enforce LTR globally — counteracts any browser/OS RTL auto-detection |
45 | 32 | document.documentElement.setAttribute('dir', 'ltr'); |
46 | 33 | document.body.setAttribute('dir', 'ltr'); |
47 | | - |
48 | | - // Additional text direction enforcement |
49 | | - document.addEventListener('DOMContentLoaded', function() { |
50 | | - // Force all input elements to be LTR |
51 | | - const styleSheet = document.createElement('style'); |
52 | | - styleSheet.textContent = ` |
53 | | - input, textarea, [contenteditable="true"] { |
54 | | - direction: ltr !important; |
55 | | - text-align: left !important; |
56 | | - unicode-bidi: normal !important; |
57 | | - } |
58 | | - .text-block .block-content { |
59 | | - direction: ltr !important; |
60 | | - text-align: left !important; |
61 | | - } |
62 | | - `; |
63 | | - document.head.appendChild(styleSheet); |
64 | | - }); |
65 | | - |
66 | | - // Override any RTL behavior |
67 | | - document.addEventListener('keydown', function(e) { |
68 | | - if (e.target.contentEditable === 'true' || e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { |
69 | | - e.target.style.direction = 'ltr'; |
70 | | - e.target.style.textAlign = 'left'; |
71 | | - } |
72 | | - }); |
73 | | - |
74 | | - document.addEventListener('input', function(e) { |
75 | | - if (e.target.contentEditable === 'true' || e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { |
76 | | - e.target.style.direction = 'ltr'; |
77 | | - e.target.style.textAlign = 'left'; |
| 34 | + |
| 35 | + // Keep all inputs LTR on keydown and input events |
| 36 | + function enforceLTR(e) { |
| 37 | + const t = e.target; |
| 38 | + if (t.contentEditable === 'true' || t.tagName === 'INPUT' || t.tagName === 'TEXTAREA') { |
| 39 | + t.style.direction = 'ltr'; |
| 40 | + t.style.textAlign = 'left'; |
| 41 | + t.style.unicodeBidi = 'normal'; |
78 | 42 | } |
79 | | - }); |
| 43 | + } |
| 44 | + document.addEventListener('keydown', enforceLTR); |
| 45 | + document.addEventListener('input', enforceLTR); |
80 | 46 | </script> |
81 | | - <!-- Admin app logic should reference #app and handle quiz numbering via Supabase --> |
| 47 | + |
| 48 | + <!-- Admin app — single load, at end of body --> |
82 | 49 | <script src="admin.app.js"></script> |
| 50 | + |
83 | 51 | </body> |
84 | 52 | </html> |
85 | | - |
0 commit comments