summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGab Virebent <gabriel1@virebent.art>2026-07-02 03:58:31 +0200
committerGab Virebent <gabriel1@virebent.art>2026-07-02 03:58:31 +0200
commit52eb46afad75d76c707ed11bbddddbcf5e121deb (patch)
tree728a5590c028e16a8a824274b7657b235439fea2
parent4da18fe598f243c777d330ba9d50f1ecd4382b05 (diff)
downloadnymdrop-52eb46afad75d76c707ed11bbddddbcf5e121deb.tar.gz
nymdrop-52eb46afad75d76c707ed11bbddddbcf5e121deb.tar.xz
nymdrop-52eb46afad75d76c707ed11bbddddbcf5e121deb.zip
Add light/dark theme toggle, fix dark theme text contrast
Theme state persists via localStorage, applied pre-paint by theme-init.js to avoid flash. All JS moved to external files (app.js, theme-init.js) to keep script-src 'self' CSP intact, no inline scripts. Dark theme footer/notice/tagline colors were too close to the background (footer nearly matched the card border color) and hard to read; brightened to readable grays while leaving the light theme and submit button untouched.
-rw-r--r--static/app.js30
-rw-r--r--static/index.html10
-rw-r--r--static/style.css153
-rw-r--r--static/theme-init.js5
4 files changed, 161 insertions, 37 deletions
diff --git a/static/app.js b/static/app.js
new file mode 100644
index 0000000..1168281
--- /dev/null
+++ b/static/app.js
@@ -0,0 +1,30 @@
+document.getElementById('file').addEventListener('change', function() {
+ const name = this.files.length ? this.files[0].name : '';
+ document.getElementById('filename').textContent = name;
+});
+
+(function() {
+ var toggleBtn = document.getElementById('theme-toggle');
+
+ function isLight() {
+ return document.documentElement.getAttribute('data-theme') === 'light';
+ }
+
+ function updateIcon() {
+ // Shows the icon for the theme you'd switch TO.
+ toggleBtn.textContent = isLight() ? '\u{1F319}' : '☀️';
+ }
+
+ toggleBtn.addEventListener('click', function() {
+ if (isLight()) {
+ document.documentElement.removeAttribute('data-theme');
+ localStorage.setItem('nymdrop-theme', 'dark');
+ } else {
+ document.documentElement.setAttribute('data-theme', 'light');
+ localStorage.setItem('nymdrop-theme', 'light');
+ }
+ updateIcon();
+ });
+
+ updateIcon();
+})();
diff --git a/static/index.html b/static/index.html
index c957a01..33e5868 100644
--- a/static/index.html
+++ b/static/index.html
@@ -6,10 +6,13 @@
<meta name="referrer" content="no-referrer">
<title>NymDrop — Secure Submission</title>
<link rel="stylesheet" href="/style.css">
+ <script src="/theme-init.js"></script>
</head>
<body>
<div class="card">
+ <button id="theme-toggle" class="theme-toggle" type="button" aria-label="Toggle light/dark theme"></button>
+
<div class="logo">
<div class="logo-icon">⬡</div>
<h1>NYMDROP</h1>
@@ -51,11 +54,6 @@
</div>
<div class="footer">NYMDROP &nbsp;·&nbsp; ZERO KNOWLEDGE &nbsp;·&nbsp; ZERO LOGS</div>
<script src="/crypto.js"></script>
-<script>
- document.getElementById('file').addEventListener('change', function() {
- const name = this.files.length ? this.files[0].name : '';
- document.getElementById('filename').textContent = name;
- });
-</script>
+<script src="/app.js"></script>
</body>
</html>
diff --git a/static/style.css b/static/style.css
index 3b077d7..d463876 100644
--- a/static/style.css
+++ b/static/style.css
@@ -1,8 +1,74 @@
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
+:root {
+ --bg: #0d1117;
+ --card-bg: #161b22;
+ --card-border: #21262d;
+ --card-shadow: rgba(0,255,160,0.04);
+ --text: #c9d1d9;
+ --heading: #e6edf3;
+ --tagline: #8b949e;
+ --label: #8b949e;
+ --field-bg: #0d1117;
+ --field-border: #30363d;
+ --accent-green: #00ffa0;
+ --accent-blue: #0080ff;
+ --accent-blue-text: #58a6ff;
+ --badge-green-bg: rgba(0,255,160,0.08);
+ --badge-green-border: rgba(0,255,160,0.2);
+ --badge-blue-bg: rgba(0,128,255,0.08);
+ --badge-blue-border: rgba(0,128,255,0.2);
+ --badge-gray-bg: rgba(255,255,255,0.04);
+ --badge-gray-text: #8b949e;
+ --badge-gray-border: #30363d;
+ --file-label-bg: #21262d;
+ --status-error: #f85149;
+ --divider: #21262d;
+ --notice: #8b949e;
+ --notice-span: #c9d1d9;
+ --footer: #7d8590;
+ --btn-text: #0d1117;
+ --toggle-bg: #21262d;
+ --toggle-border: #30363d;
+ --toggle-color: #8b949e;
+}
+
+html[data-theme="light"] {
+ --bg: #f6f8fa;
+ --card-bg: #ffffff;
+ --card-border: #d0d7de;
+ --card-shadow: rgba(0,0,0,0.06);
+ --text: #24292f;
+ --heading: #1b1f24;
+ --tagline: #6e7781;
+ --label: #57606a;
+ --field-bg: #f6f8fa;
+ --field-border: #d0d7de;
+ --accent-green: #067d4f;
+ --accent-blue: #0969da;
+ --accent-blue-text: #0969da;
+ --badge-green-bg: rgba(6,125,79,0.08);
+ --badge-green-border: rgba(6,125,79,0.25);
+ --badge-blue-bg: rgba(9,105,218,0.08);
+ --badge-blue-border: rgba(9,105,218,0.25);
+ --badge-gray-bg: rgba(0,0,0,0.04);
+ --badge-gray-text: #57606a;
+ --badge-gray-border: #d0d7de;
+ --file-label-bg: #eaeef2;
+ --status-error: #cf222e;
+ --divider: #d0d7de;
+ --notice: #8c959f;
+ --notice-span: #57606a;
+ --footer: #afb8c1;
+ --btn-text: #ffffff;
+ --toggle-bg: #eaeef2;
+ --toggle-border: #d0d7de;
+ --toggle-color: #57606a;
+}
+
body {
- background: #0d1117;
- color: #c9d1d9;
+ background: var(--bg);
+ color: var(--text);
font-family: 'Courier New', Courier, monospace;
min-height: 100vh;
display: flex;
@@ -10,48 +76,73 @@ body {
align-items: center;
justify-content: center;
padding: 2rem 1rem;
+ transition: background-color 0.15s, color 0.15s;
}
.card {
- background: #161b22;
- border: 1px solid #21262d;
+ position: relative;
+ background: var(--card-bg);
+ border: 1px solid var(--card-border);
border-radius: 8px;
padding: 2.5rem 2rem;
width: 100%;
max-width: 580px;
- box-shadow: 0 0 40px rgba(0,255,160,0.04);
+ box-shadow: 0 0 40px var(--card-shadow);
+ transition: background-color 0.15s, border-color 0.15s;
}
+.theme-toggle {
+ position: absolute;
+ top: 1rem;
+ right: 1rem;
+ width: 32px;
+ height: 32px;
+ background: var(--toggle-bg);
+ border: 1px solid var(--toggle-border);
+ border-radius: 6px;
+ color: var(--toggle-color);
+ font-size: 0.95rem;
+ line-height: 1;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: border-color 0.2s, color 0.2s;
+}
+
+.theme-toggle:hover { border-color: var(--accent-blue-text); color: var(--accent-blue-text); }
+
.logo {
display: flex;
align-items: center;
gap: 0.7rem;
margin-bottom: 0.5rem;
+ padding-right: 2.5rem;
}
.logo-icon {
width: 32px;
height: 32px;
- background: linear-gradient(135deg, #00ffa0, #0080ff);
+ background: linear-gradient(135deg, var(--accent-green), var(--accent-blue));
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1rem;
- color: #0d1117;
+ color: var(--bg);
font-weight: bold;
}
h1 {
font-size: 1.4rem;
font-weight: bold;
- color: #e6edf3;
+ color: var(--heading);
letter-spacing: 0.15em;
}
.tagline {
font-size: 0.72rem;
- color: #484f58;
+ color: var(--tagline);
margin-bottom: 2rem;
letter-spacing: 0.03em;
}
@@ -71,14 +162,14 @@ h1 {
font-weight: bold;
}
-.badge-green { background: rgba(0,255,160,0.08); color: #00ffa0; border: 1px solid rgba(0,255,160,0.2); }
-.badge-blue { background: rgba(0,128,255,0.08); color: #58a6ff; border: 1px solid rgba(0,128,255,0.2); }
-.badge-gray { background: rgba(255,255,255,0.04); color: #8b949e; border: 1px solid #30363d; }
+.badge-green { background: var(--badge-green-bg); color: var(--accent-green); border: 1px solid var(--badge-green-border); }
+.badge-blue { background: var(--badge-blue-bg); color: var(--accent-blue-text); border: 1px solid var(--badge-blue-border); }
+.badge-gray { background: var(--badge-gray-bg); color: var(--badge-gray-text); border: 1px solid var(--badge-gray-border); }
label {
display: block;
font-size: 0.72rem;
- color: #8b949e;
+ color: var(--label);
margin-bottom: 0.4rem;
text-transform: uppercase;
letter-spacing: 0.08em;
@@ -87,52 +178,52 @@ label {
textarea {
width: 100%;
height: 160px;
- background: #0d1117;
- border: 1px solid #30363d;
+ background: var(--field-bg);
+ border: 1px solid var(--field-border);
border-radius: 6px;
- color: #c9d1d9;
+ color: var(--text);
font-family: 'Courier New', Courier, monospace;
font-size: 0.88rem;
padding: 0.9rem;
resize: vertical;
margin-bottom: 1.4rem;
- transition: border-color 0.2s;
+ transition: border-color 0.2s, background-color 0.15s, color 0.15s;
outline: none;
}
-textarea:focus { border-color: #00ffa0; box-shadow: 0 0 0 2px rgba(0,255,160,0.08); }
+textarea:focus { border-color: var(--accent-green); box-shadow: 0 0 0 2px var(--badge-green-bg); }
.file-section { margin-bottom: 1.8rem; }
.file-label {
display: inline-block;
- background: #21262d;
- border: 1px solid #30363d;
+ background: var(--file-label-bg);
+ border: 1px solid var(--field-border);
border-radius: 6px;
- color: #8b949e;
+ color: var(--label);
font-size: 0.78rem;
padding: 0.5rem 1rem;
cursor: pointer;
transition: border-color 0.2s, color 0.2s;
}
-.file-label:hover { border-color: #58a6ff; color: #58a6ff; }
+.file-label:hover { border-color: var(--accent-blue-text); color: var(--accent-blue-text); }
#file { display: none; }
#filename {
font-size: 0.72rem;
- color: #58a6ff;
+ color: var(--accent-blue-text);
margin-left: 0.6rem;
vertical-align: middle;
}
.submit-btn {
width: 100%;
- background: linear-gradient(135deg, #00ffa0 0%, #0080ff 100%);
+ background: linear-gradient(135deg, var(--accent-green) 0%, var(--accent-blue) 100%);
border: none;
border-radius: 6px;
- color: #0d1117;
+ color: var(--btn-text);
font-family: 'Courier New', Courier, monospace;
font-size: 0.9rem;
font-weight: bold;
@@ -151,29 +242,29 @@ textarea:focus { border-color: #00ffa0; box-shadow: 0 0 0 2px rgba(0,255,160,0.0
font-size: 0.78rem;
min-height: 1.2rem;
text-align: center;
- color: #00ffa0;
+ color: var(--accent-green);
}
-#status.error { color: #f85149; }
+#status.error { color: var(--status-error); }
.divider {
border: none;
- border-top: 1px solid #21262d;
+ border-top: 1px solid var(--divider);
margin: 2rem 0 1.2rem;
}
.notice {
font-size: 0.68rem;
- color: #3d444d;
+ color: var(--notice);
line-height: 1.7;
}
-.notice span { color: #484f58; }
+.notice span { color: var(--notice-span); }
.footer {
margin-top: 1.5rem;
font-size: 0.62rem;
- color: #21262d;
+ color: var(--footer);
text-align: center;
letter-spacing: 0.05em;
}
diff --git a/static/theme-init.js b/static/theme-init.js
new file mode 100644
index 0000000..95b9a95
--- /dev/null
+++ b/static/theme-init.js
@@ -0,0 +1,5 @@
+(function() {
+ if (localStorage.getItem('nymdrop-theme') === 'light') {
+ document.documentElement.setAttribute('data-theme', 'light');
+ }
+})();