Spaces:
Sleeping
Sleeping
Commit Β·
ceeaf3d
1
Parent(s): b148513
Add dark mode toggle with system preference detection
Browse filesToggle in the header switches between light and dark themes.
Preference is saved to localStorage and restored on reload.
Falls back to the OS color scheme on first visit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main.py
CHANGED
|
@@ -167,11 +167,66 @@ _HTML = """<!DOCTYPE html>
|
|
| 167 |
.img-modal.open { display: flex; }
|
| 168 |
.img-modal img { max-width: min(1100px, 96vw); max-height: 90vh; border-radius: 8px; box-shadow: 0 16px 40px rgba(15, 23, 42, 0.45); background: white; object-fit: contain; }
|
| 169 |
.img-modal-close { position: absolute; top: 14px; right: 14px; border: 1px solid #94a3b8; background: #0f172a; color: white; border-radius: 6px; font-size: 0.78rem; padding: 6px 10px; cursor: pointer; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
</style>
|
| 171 |
</head>
|
| 172 |
<body>
|
| 173 |
<div class="container">
|
| 174 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
<p class="subtitle">Extract text → Gemini structures problems → review & export.</p>
|
| 176 |
|
| 177 |
<div id="error-box" class="error-box"></div>
|
|
@@ -311,7 +366,28 @@ _HTML = """<!DOCTYPE html>
|
|
| 311 |
document.getElementById('pdf-ready-name').textContent = name;
|
| 312 |
}
|
| 313 |
|
| 314 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 315 |
|
| 316 |
var KATEX_OPTS = {
|
| 317 |
delimiters: [
|
|
|
|
| 167 |
.img-modal.open { display: flex; }
|
| 168 |
.img-modal img { max-width: min(1100px, 96vw); max-height: 90vh; border-radius: 8px; box-shadow: 0 16px 40px rgba(15, 23, 42, 0.45); background: white; object-fit: contain; }
|
| 169 |
.img-modal-close { position: absolute; top: 14px; right: 14px; border: 1px solid #94a3b8; background: #0f172a; color: white; border-radius: 6px; font-size: 0.78rem; padding: 6px 10px; cursor: pointer; }
|
| 170 |
+
/* Dark mode toggle */
|
| 171 |
+
.dm-toggle { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 6px; border: 1px solid #e2e8f0; background: #f1f5f9; color: #475569; cursor: pointer; transition: background 0.15s, border-color 0.15s, color 0.15s; flex-shrink: 0; }
|
| 172 |
+
.dm-toggle:hover { background: #e2e8f0; color: #1e293b; }
|
| 173 |
+
/* Dark mode */
|
| 174 |
+
body.dark { background: #0f172a; color: #e2e8f0; }
|
| 175 |
+
body.dark .card { background: #1e293b; border-color: #334155; }
|
| 176 |
+
body.dark .btn-secondary { background: #1e293b; color: #94a3b8; border-color: #334155; }
|
| 177 |
+
body.dark .btn-secondary:hover { background: #334155; color: #e2e8f0; }
|
| 178 |
+
body.dark .btn-danger { background: #450a0a; color: #f87171; border-color: #7f1d1d; }
|
| 179 |
+
body.dark .subtitle { color: #64748b; }
|
| 180 |
+
body.dark .card-title { color: #64748b; }
|
| 181 |
+
body.dark .config-sep { color: #475569; }
|
| 182 |
+
body.dark #extract-status { color: #64748b; }
|
| 183 |
+
body.dark .config-bar input[type=number] { background: #0f172a; border-color: #334155; color: #e2e8f0; }
|
| 184 |
+
body.dark .pdf-picker-btn { background: #1e293b; border-color: #475569; color: #94a3b8; }
|
| 185 |
+
body.dark .pdf-picker-btn:hover { border-color: #2563eb; color: #93c5fd; background: #1e3a5f; }
|
| 186 |
+
body.dark .pdf-change-link { color: #64748b; }
|
| 187 |
+
body.dark .pdf-change-link:hover { color: #93c5fd; }
|
| 188 |
+
body.dark .info-box { background: #1e3a5f; border-color: #1d4ed8; color: #93c5fd; }
|
| 189 |
+
body.dark .error-box { background: #450a0a; border-color: #7f1d1d; color: #f87171; }
|
| 190 |
+
body.dark .step-label { color: #64748b; }
|
| 191 |
+
body.dark textarea.paste-area { background: #0f172a; border-color: #334155; color: #e2e8f0; }
|
| 192 |
+
body.dark .images-toggle { color: #64748b; }
|
| 193 |
+
body.dark .images-toggle:hover { color: #94a3b8; }
|
| 194 |
+
body.dark .filter-btn { background: #1e293b; color: #64748b; border-color: #334155; }
|
| 195 |
+
body.dark .filter-btn.active { background: #2563eb; color: white; border-color: #2563eb; }
|
| 196 |
+
body.dark .q-section-title { color: #64748b; }
|
| 197 |
+
body.dark .q-card { background: #1e293b; border-color: #334155; }
|
| 198 |
+
body.dark .q-card.active-card { border-color: #2563eb; box-shadow: 0 0 0 4px #1e3a5f; background: #172554; }
|
| 199 |
+
body.dark .q-num { background: #0f172a; color: #93c5fd; }
|
| 200 |
+
body.dark .badge-page { background: #1e3a5f; color: #93c5fd; }
|
| 201 |
+
body.dark .badge-warn { background: #422006; color: #fcd34d; }
|
| 202 |
+
body.dark .badge-ready { background: #14532d; color: #86efac; }
|
| 203 |
+
body.dark .badge-skip { background: #1e293b; color: #64748b; }
|
| 204 |
+
body.dark .q-rendered { color: #e2e8f0; }
|
| 205 |
+
body.dark .q-text { background: #0f172a; border-color: #334155; color: #e2e8f0; }
|
| 206 |
+
body.dark .q-text:focus { background: #0f172a; }
|
| 207 |
+
body.dark .q-notes { color: #475569; }
|
| 208 |
+
body.dark .exam-toggle { color: #64748b; }
|
| 209 |
+
body.dark .img-chip { background: #0f172a; border-color: #334155; color: #94a3b8; }
|
| 210 |
+
body.dark .img-chip img { border-color: #334155; }
|
| 211 |
+
body.dark .paste-target-pill { background: #1e3a5f; border-color: #1d4ed8; color: #93c5fd; }
|
| 212 |
+
body.dark .export-bar { background: #1e293b; border-color: #334155; }
|
| 213 |
+
body.dark .export-bar-left { color: #64748b; }
|
| 214 |
+
body.dark .export-bar input[type=number], body.dark .export-bar input[type=text] { background: #0f172a; border-color: #334155; color: #e2e8f0; }
|
| 215 |
+
body.dark .paste-hint { background: #1e3a5f; color: #93c5fd; }
|
| 216 |
+
body.dark .dm-toggle { background: #1e293b; border-color: #334155; color: #94a3b8; }
|
| 217 |
+
body.dark .dm-toggle:hover { background: #334155; color: #e2e8f0; }
|
| 218 |
+
body.dark .workflow-busy { color: #64748b; }
|
| 219 |
</style>
|
| 220 |
</head>
|
| 221 |
<body>
|
| 222 |
<div class="container">
|
| 223 |
+
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:3px;">
|
| 224 |
+
<h1>Problem Extractor</h1>
|
| 225 |
+
<button class="dm-toggle" id="dm-toggle-btn" onclick="toggleDark()" title="Toggle dark mode" aria-label="Toggle dark mode">
|
| 226 |
+
<svg id="dm-icon-moon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
|
| 227 |
+
<svg id="dm-icon-sun" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:none;"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
|
| 228 |
+
</button>
|
| 229 |
+
</div>
|
| 230 |
<p class="subtitle">Extract text → Gemini structures problems → review & export.</p>
|
| 231 |
|
| 232 |
<div id="error-box" class="error-box"></div>
|
|
|
|
| 366 |
document.getElementById('pdf-ready-name').textContent = name;
|
| 367 |
}
|
| 368 |
|
| 369 |
+
// ββ Dark mode βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 370 |
+
|
| 371 |
+
function applyDark(dark) {
|
| 372 |
+
document.body.classList.toggle('dark', dark);
|
| 373 |
+
document.getElementById('dm-icon-moon').style.display = dark ? 'none' : '';
|
| 374 |
+
document.getElementById('dm-icon-sun').style.display = dark ? '' : 'none';
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
function toggleDark() {
|
| 378 |
+
var isDark = document.body.classList.contains('dark');
|
| 379 |
+
applyDark(!isDark);
|
| 380 |
+
try { localStorage.setItem('dm', !isDark ? '1' : '0'); } catch(e) {}
|
| 381 |
+
}
|
| 382 |
+
|
| 383 |
+
window.addEventListener('DOMContentLoaded', function() {
|
| 384 |
+
initPdfState();
|
| 385 |
+
try {
|
| 386 |
+
var saved = localStorage.getItem('dm');
|
| 387 |
+
var prefersDark = saved !== null ? saved === '1' : window.matchMedia('(prefers-color-scheme: dark)').matches;
|
| 388 |
+
applyDark(prefersDark);
|
| 389 |
+
} catch(e) {}
|
| 390 |
+
});
|
| 391 |
|
| 392 |
var KATEX_OPTS = {
|
| 393 |
delimiters: [
|