mirror of
https://codeberg.org/listyantidewi/your-everyday-tools.git
synced 2026-07-01 23:17:37 +08:00
Implement theme switcher functionality and enhance styling with CSS variables. Add dark and light theme support, update UI elements for better accessibility, and ensure consistent theming across tools.
This commit is contained in:
+89
-14
@@ -7,17 +7,57 @@
|
||||
--success: #2ec4b6;
|
||||
--danger: #e63946;
|
||||
--warning: #f4a261;
|
||||
/* surface palette */
|
||||
--bg: #f5f6fa;
|
||||
--surface: #ffffff;
|
||||
--text: #2d3436;
|
||||
--text-light: #636e72;
|
||||
--muted: var(--text-light);
|
||||
--border: #dfe6e9;
|
||||
--shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
/* semantic accent */
|
||||
--accent-soft: #eef1ff;
|
||||
--accent-soft-hover: #dde3ff;
|
||||
/* notes/warning block */
|
||||
--note-bg: #fff8e1;
|
||||
--note-border: #f5b700;
|
||||
--note-text: #5a4200;
|
||||
--note-summary: #8a6300;
|
||||
--note-link: #b26f00;
|
||||
--note-code-bg: rgba(0,0,0,.06);
|
||||
/* upload hover */
|
||||
--upload-hover-bg: #f0f3ff;
|
||||
/* result states */
|
||||
--result-success-bg: #e8faf8;
|
||||
--result-success-text: #1a7a6d;
|
||||
--result-error-bg: #fdeaea;
|
||||
/* layout */
|
||||
--sidebar-w: 260px;
|
||||
--radius: 8px;
|
||||
--shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
--font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--bg: #1a1d23;
|
||||
--surface: #22262e;
|
||||
--text: #e4e6eb;
|
||||
--text-light: #9aa0ac;
|
||||
--border: #3a3f4b;
|
||||
--shadow: 0 2px 8px rgba(0,0,0,0.35);
|
||||
--accent-soft: rgba(67,97,238,.2);
|
||||
--accent-soft-hover: rgba(67,97,238,.35);
|
||||
--note-bg: #2a2000;
|
||||
--note-border: #c49a00;
|
||||
--note-text: #f0c040;
|
||||
--note-summary: #d4a800;
|
||||
--note-link: #e8c000;
|
||||
--note-code-bg: rgba(255,255,255,.08);
|
||||
--upload-hover-bg: rgba(67,97,238,.12);
|
||||
--result-success-bg: #082e2a;
|
||||
--result-success-text: #4ecdc4;
|
||||
--result-error-bg: #2d0a0a;
|
||||
}
|
||||
|
||||
html { font-size: 15px; }
|
||||
body {
|
||||
font-family: var(--font);
|
||||
@@ -98,7 +138,7 @@ a { color: var(--primary); text-decoration: none; }
|
||||
transition: background .15s, color .15s;
|
||||
}
|
||||
.nav-item:hover, .nav-item.active {
|
||||
background: #eef1ff;
|
||||
background: var(--accent-soft);
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
@@ -132,6 +172,38 @@ a { color: var(--primary); text-decoration: none; }
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* ── Theme Switcher ───────────────────────────── */
|
||||
.theme-switcher {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 20px;
|
||||
padding: 3px;
|
||||
margin-left: auto;
|
||||
}
|
||||
.theme-btn {
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
color: var(--text-light);
|
||||
border-radius: 16px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: .9rem;
|
||||
transition: background .15s, color .15s;
|
||||
}
|
||||
.theme-btn:hover { background: var(--border); color: var(--text); }
|
||||
.theme-btn.active {
|
||||
background: var(--surface);
|
||||
color: var(--primary);
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,.15);
|
||||
}
|
||||
|
||||
.content-area {
|
||||
flex: 1;
|
||||
padding: 2rem;
|
||||
@@ -227,19 +299,19 @@ a { color: var(--primary); text-decoration: none; }
|
||||
.tool-header p { color: var(--text-light); }
|
||||
|
||||
.tool-notes {
|
||||
background: #fff8e1;
|
||||
border-left: 3px solid #f5b700;
|
||||
background: var(--note-bg);
|
||||
border-left: 3px solid var(--note-border);
|
||||
border-radius: 4px;
|
||||
padding: .75rem 1rem;
|
||||
margin-bottom: 1.25rem;
|
||||
font-size: .88rem;
|
||||
line-height: 1.5;
|
||||
color: #5a4200;
|
||||
color: var(--note-text);
|
||||
}
|
||||
.tool-notes p { margin: 0 0 .5rem; }
|
||||
.tool-notes p:last-child { margin-bottom: 0; }
|
||||
.tool-notes code {
|
||||
background: rgba(0,0,0,.06);
|
||||
background: var(--note-code-bg);
|
||||
padding: .1rem .35rem;
|
||||
border-radius: 3px;
|
||||
font-size: .82rem;
|
||||
@@ -248,12 +320,12 @@ a { color: var(--primary); text-decoration: none; }
|
||||
.tool-notes details > summary {
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
color: #8a6300;
|
||||
color: var(--note-summary);
|
||||
}
|
||||
.tool-notes details[open] > summary { margin-bottom: .5rem; }
|
||||
.tool-notes ol, .tool-notes ul { margin: .25rem 0 .5rem 1.2rem; padding: 0; }
|
||||
.tool-notes li { margin-bottom: .2rem; }
|
||||
.tool-notes a { color: #b26f00; }
|
||||
.tool-notes a { color: var(--note-link); }
|
||||
|
||||
.capability-status {
|
||||
border: 1px solid var(--border);
|
||||
@@ -308,7 +380,7 @@ a { color: var(--primary); text-decoration: none; }
|
||||
}
|
||||
.upload-zone:hover, .upload-zone.dragover {
|
||||
border-color: var(--primary);
|
||||
background: #f0f3ff;
|
||||
background: var(--upload-hover-bg);
|
||||
}
|
||||
.upload-zone input[type="file"] {
|
||||
position: absolute;
|
||||
@@ -362,6 +434,7 @@ textarea {
|
||||
font: inherit;
|
||||
font-size: .9rem;
|
||||
background: var(--surface);
|
||||
color: var(--text);
|
||||
transition: border-color .15s;
|
||||
}
|
||||
input:focus, select:focus, textarea:focus {
|
||||
@@ -397,12 +470,12 @@ textarea { resize: vertical; }
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.result-success {
|
||||
background: #e8faf8;
|
||||
color: #1a7a6d;
|
||||
background: var(--result-success-bg);
|
||||
color: var(--result-success-text);
|
||||
}
|
||||
.result-success .btn { margin-left: auto; }
|
||||
.result-error {
|
||||
background: #fdeaea;
|
||||
background: var(--result-error-bg);
|
||||
color: var(--danger);
|
||||
}
|
||||
.result-text-box {
|
||||
@@ -474,6 +547,8 @@ textarea { resize: vertical; }
|
||||
font-family: "Consolas", "Monaco", monospace;
|
||||
font-size: .85rem;
|
||||
outline: none;
|
||||
background: var(--surface);
|
||||
color: var(--text);
|
||||
}
|
||||
.pane-body pre {
|
||||
min-height: 250px;
|
||||
@@ -511,8 +586,8 @@ textarea { resize: vertical; }
|
||||
transition: background .1s;
|
||||
}
|
||||
.calc-btn:hover { background: var(--bg); }
|
||||
.calc-btn.op { background: #eef1ff; color: var(--primary); font-weight: 600; }
|
||||
.calc-btn.op:hover { background: #dde3ff; }
|
||||
.calc-btn.op { background: var(--accent-soft); color: var(--primary); font-weight: 600; }
|
||||
.calc-btn.op:hover { background: var(--accent-soft-hover); }
|
||||
.calc-btn.eq { background: var(--primary); color: #fff; }
|
||||
.calc-btn.eq:hover { background: var(--primary-dark); }
|
||||
.calc-btn.span2 { grid-column: span 2; }
|
||||
|
||||
@@ -1,3 +1,39 @@
|
||||
/* ── Theme ────────────────────────────────────── */
|
||||
const THEME_KEY = "theme";
|
||||
|
||||
function getStoredTheme() {
|
||||
return localStorage.getItem(THEME_KEY) || "system";
|
||||
}
|
||||
|
||||
function resolveTheme(mode) {
|
||||
if (mode === "dark") return "dark";
|
||||
if (mode === "light") return "light";
|
||||
return (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) ? "dark" : "light";
|
||||
}
|
||||
|
||||
function applyTheme(mode) {
|
||||
localStorage.setItem(THEME_KEY, mode);
|
||||
document.documentElement.dataset.theme = resolveTheme(mode);
|
||||
document.querySelectorAll(".theme-btn").forEach(btn => {
|
||||
btn.classList.toggle("active", btn.dataset.themeMode === mode);
|
||||
});
|
||||
}
|
||||
|
||||
function initTheme() {
|
||||
const mode = getStoredTheme();
|
||||
applyTheme(mode);
|
||||
document.querySelectorAll(".theme-btn").forEach(btn => {
|
||||
btn.addEventListener("click", () => applyTheme(btn.dataset.themeMode));
|
||||
});
|
||||
if (window.matchMedia) {
|
||||
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
|
||||
if (getStoredTheme() === "system") {
|
||||
document.documentElement.dataset.theme = resolveTheme("system");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Sidebar ──────────────────────────────────── */
|
||||
function toggleCategory(btn) {
|
||||
btn.classList.toggle("open");
|
||||
@@ -30,6 +66,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
}
|
||||
});
|
||||
|
||||
initTheme();
|
||||
initUploadZone();
|
||||
initToolForm();
|
||||
initDependentOptions();
|
||||
|
||||
@@ -4,6 +4,15 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Your Everyday Tools{% endblock %}</title>
|
||||
<script>
|
||||
(function () {
|
||||
var stored = localStorage.getItem('theme') || 'system';
|
||||
var resolved = stored === 'dark' ? 'dark'
|
||||
: stored === 'light' ? 'light'
|
||||
: (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
||||
document.documentElement.dataset.theme = resolved;
|
||||
})();
|
||||
</script>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/icons.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
</head>
|
||||
@@ -37,6 +46,11 @@
|
||||
<header class="top-bar">
|
||||
<button class="menu-btn" onclick="openSidebar()"><i class="bi bi-list"></i></button>
|
||||
<span class="top-title">{% block top_title %}Your Everyday Tools{% endblock %}</span>
|
||||
<div class="theme-switcher" id="theme-switcher" role="group" aria-label="Color theme">
|
||||
<button class="theme-btn" data-theme-mode="system" title="System theme"><i class="bi bi-circle-half"></i></button>
|
||||
<button class="theme-btn" data-theme-mode="light" title="Light theme"><i class="bi bi-sun-fill"></i></button>
|
||||
<button class="theme-btn" data-theme-mode="dark" title="Dark theme"><i class="bi bi-moon-fill"></i></button>
|
||||
</div>
|
||||
</header>
|
||||
<div class="content-area">
|
||||
{% block content %}{% endblock %}
|
||||
|
||||
@@ -67,7 +67,7 @@ function showStrength(pw, poolSize) {
|
||||
let label, color, pct;
|
||||
if (entropy < 40) { label = "Weak"; color = "var(--danger)"; pct = 25; }
|
||||
else if (entropy < 60) { label = "Fair"; color = "var(--warning)"; pct = 50; }
|
||||
else if (entropy < 80) { label = "Strong"; color = "#2ec4b6"; pct = 75; }
|
||||
else if (entropy < 80) { label = "Strong"; color = "var(--success)"; pct = 75; }
|
||||
else { label = "Very Strong"; color = "var(--primary)"; pct = 100; }
|
||||
|
||||
document.getElementById("pw-strength").innerHTML =
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
.match-idx { color: var(--text-light); min-width: 2rem; }
|
||||
.match-val { font-family: Consolas,Monaco,monospace; }
|
||||
.match-pos { color: var(--text-light); font-size: .8rem; }
|
||||
[data-theme="dark"] .regex-hl { background: rgba(244,162,97,.22); }
|
||||
[data-theme="dark"] .regex-hl:nth-of-type(even) { background: rgba(23,162,184,.22); border-bottom-color: #17a2b8; }
|
||||
</style>
|
||||
<script>
|
||||
function testRegex() {
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
.diff-stats { font-size: .85rem; margin-bottom: .5rem; }
|
||||
.diff-stats .add { color: #28a745; font-weight: 600; }
|
||||
.diff-stats .del { color: var(--danger); font-weight: 600; }
|
||||
[data-theme="dark"] .diff-add { background: #0d2e14; }
|
||||
[data-theme="dark"] .diff-del { background: #2e0d0d; }
|
||||
[data-theme="dark"] .diff-stats .add { color: #4ecdc4; }
|
||||
</style>
|
||||
<script>
|
||||
function computeDiff() {
|
||||
|
||||
Reference in New Issue
Block a user