From 0192c5193361b69672f1551981948fb42fc446b1 Mon Sep 17 00:00:00 2001 From: Borys Levytskyi Date: Thu, 27 Nov 2025 22:25:01 -0500 Subject: [PATCH] Graphite theme. Theme consolidation --- .../test-instruction.instructions.md | 0 src/css/index.css | 235 ++++++++++ src/css/theme-bladerunner.css | 140 ++++++ src/css/theme-dark.css | 27 ++ src/css/theme-graphite.css | 42 ++ src/css/theme-light.css | 31 ++ src/css/theme-midnight.css | 28 ++ src/css/theme.css | 110 +++++ src/index.css | 443 ------------------ src/index.tsx | 4 +- src/shell/AppState.ts | 15 +- src/shell/components/HelpResultView.css | 4 +- src/shell/components/HelpResultView.tsx | 3 +- src/shell/components/WhatsNewResultView.tsx | 8 + src/shell/module.tsx | 2 + 15 files changed, 640 insertions(+), 452 deletions(-) create mode 100644 .github/instructions/test-instruction.instructions.md create mode 100644 src/css/index.css create mode 100644 src/css/theme-bladerunner.css create mode 100644 src/css/theme-dark.css create mode 100644 src/css/theme-graphite.css create mode 100644 src/css/theme-light.css create mode 100644 src/css/theme-midnight.css create mode 100644 src/css/theme.css delete mode 100644 src/index.css diff --git a/.github/instructions/test-instruction.instructions.md b/.github/instructions/test-instruction.instructions.md new file mode 100644 index 0000000..e69de29 diff --git a/src/css/index.css b/src/css/index.css new file mode 100644 index 0000000..3043c87 --- /dev/null +++ b/src/css/index.css @@ -0,0 +1,235 @@ +body { padding:0; margin:0; height: 100%; overflow: hidden; } +html { height: 100% } + +/* Theme bundles */ +@import './theme-light.css'; +@import './theme-dark.css'; +@import './theme-midnight.css'; +@import './theme-bladerunner.css'; +@import './theme-graphite.css'; +@import './theme.css'; + +.app-root { + font-family: var(--font-family, Verdana); + font-size: 0.8em; + margin: 0; + padding: 0px 30px; + height: 100%; + overflow: auto; + position: relative; +} + +/* Centered vs stretched layout */ +.app-root.layout-centered { } + +/* Constrain and center top-level sections while keeping full-width theme background */ +.app-root.layout-centered > * { + max-width: clamp(70rem, 92vw, 100rem); + margin-left: auto; + margin-right: auto; +} + +/* Theme-specific overrides are moved into their theme-*.css files */ + +.app-root.layout-stretched { + max-width: none; + margin: 0; +} + +/* Theme-scoped code styling to avoid cross-theme overrides */ +.light code, .dark code, .midnight code, .bladerunner code, .graphite code { font-size: 1.2em; font-weight: bold; } + +h1 { font-family: Impact, Verdana; + text-transform: uppercase; + font-weight: lighter; +} +.icon { margin-right: 5px; vertical-align: middle; } +.header-cmd { color: #c5c5c5 } + +.mono { font-family: monospace; font-size: 1.3em } + +.button { + padding: 10px; + border: solid 1px white; + border-radius: 5px; + text-decoration: none; + display: inline-block; +} + +.button { padding: 5px;} +.button svg { margin: 0; margin-right: 5px; } +.button-large { padding: 10px; } + +.expressionInput { + padding: 3px; + outline: none; + border: none; + border-bottom: solid 1px rgba(255, 255, 255, 0.5); + z-index: 100; + padding-left: 15px; + padding-bottom: 5px; + width: 600px; + background: rgba(0, 0, 0, 0); +} + +.hidden { display: none;} + +.result { margin: 10px 10px 30px; } +.result .input { margin-bottom: 10px; } +.result .content { padding-left: 10px} +.result .cur { margin-right: 5px; } + +.input-string { margin-right: 10px;} +.hashLink { text-decoration: none; margin-left: 8px; visibility: hidden; margin-right: 0; padding: 0; text-decoration: none; } +a.hashLink { font-size: 1.1em;} +.hashLink .icon { margin: 0;} +.hashLink:hover { text-decoration: underline; background: none; } +.result:hover .hashLink { visibility: visible } + +.expression { font-size: 1.7em; font-family: monospace } +.expression button { font-family: monospace; font-size: 0.9em;} +.expression .label { font-weight: bold; padding-right: 5px; text-align: right; } +.expression .bin { letter-spacing: 3px; } +.expression .info { font-size: 0.9em; color: teal; } +.expression .byte { margin: 0 3px; } +.expression-result td { border-top: dotted 1px gray; } +.expression .prefix { font-weight: normal; display: none; font-size: 0.9em } +.expression .other { font-size: 0.9em} +.expression .sign { text-align: right; padding-right: 5px;} + +.flipable { cursor: pointer; opacity: 1 } +.flipable { cursor: pointer; opacity: 1 } +.flipable:hover { opacity: 0.8 } + +.hex .prefix { display: inline; } + +.indicator { padding: 0px 5px; background: transparent; border: none; cursor: pointer; vertical-align: middle; color:rgba(0, 0, 0, 0.25) } + +.expanded { display: block;} +.collapsed { display: none;} + +.error { color: maroon; } + +.soft { opacity: 0.7 } + +.small-text { font-size: 0.8em;} + +#view { padding: 10px} + +.cur { color: var(--cur-color, lightgray); } + + +button { border: none; } +button.link-button {text-decoration: underline;} + +.settings-button { + margin-left: -20px; +} + +/* When Settings is active (no .soft), remove any button border/outline */ +.settings-button button, +.settings-button .command-link { + border: none; + outline: none; + box-shadow: none; +} + +.undo button { + opacity: 0.4; + padding: 0; + margin-left: 5px; +} + +.solid-border { border: solid 1px rgba(255, 255, 255, 0.8); border-radius: 5px;} +.solid-border-soft { border: solid 1px rgba(255, 255, 255, 0.5); border-radius: 5px;} + + +.zero { opacity: 0.5} +.dim-extra-bits .extra-bit { opacity: 0.1;} + +/* Light theme moved to theme-light.css */ + +/* Dark theme moved to theme-dark.css */ + +/* Midnight theme moved to theme-midnight.css */ + +/* Blade Runner theme moved to theme-bladerunner.css */ + +.bladerunner .bladerunner-easter-egg {display: none;} + +.bladerunner-easter-egg { + position: absolute; + right: 1em; + bottom: 1em; + opacity: 0.3; +} + +.bladerunner-easter-egg:hover { + opacity: 1; +} + + +button { + border: none; + background: none; + cursor: pointer; +} + + + +button:focus {outline:0;} + +/* Remove blue focus ring from the Blade Runner easter egg button */ +.bladerunner-easter-egg button:focus, +.bladerunner-easter-egg button:focus-visible { + outline: none !important; + box-shadow: none !important; +} + +/* Anchor the Blade Runner easter egg to bottom-right regardless of scrolling */ +.bladerunner-easter-egg { + position: fixed; + right: 20px; + bottom: 20px; + z-index: 1000; +} + +/* Top Links Shrink */ +@media (max-width: 800px) { + .top-links .link-text { display: none } + .debug-indicators { display: none;} + .app-root {padding: 10px; } +} + +.social-container{ position:fixed; bottom:20px; right:20px } + +/* Remove margin space on body. Inline top links with header */ +@media (max-width: 700px) { + /*.expressionInput { width: 450px; } */ +} + +/* Further shrink */ +@media (max-width: 500px) { + .expressionInput { width: 400px; } + .top-links a { display: inline-block; padding: 5px 10px} +} + +@media (max-width: 450px) { + + .expressionInput { width: 350px; } +} + + +#output { + padding: 30px 30px; +} + +.input-p { + display:inline; + z-index: 101; + position: absolute; + margin-right: -10px; + margin-top: 3px; + opacity: 0.5; +} + diff --git a/src/css/theme-bladerunner.css b/src/css/theme-bladerunner.css new file mode 100644 index 0000000..7518796 --- /dev/null +++ b/src/css/theme-bladerunner.css @@ -0,0 +1,140 @@ +/* Blade Runner theme tokens */ +.app-root.bladerunner { + --bg-color: #0b0f14; + --text-color: #e6f0ff; + --solid-bg-color: #0b0f14; + --font-family: Verdana, sans-serif; + --header-cmd-color: #ff7fb0a8; /* lights-on override remains below */ + --anchor-color: #00d1f2; + --button-color: #00eaff; + --indicator-color: #0e6e7e; + --on-color: white; + --prefix-color: #00d1f2; + --other-color: #6c8497; + --hashlink-color: #52687b; + --hashlink-hover-color: #5fc2e9; + --top-links-li-hover-bg: transparent; + --error-color: #d83e8f; + --btn-color: #00eaff; + --btn-hover-bg: #11222c; + --btn-disabled-color: #0e6e7e; + --accent1-color: #e3a600; + --accent-background: #131a22; + --button-border-color: #00eaff; + --solid-border-color: #1f3b4a; + --help-code-color: #e3a600; + --input-border-color: #1f3b4a; + --input-text-color: white; + --expression-color: #e6f0ff; + --button-hover-bg: var(--top-links-li-hover-bg); + --cur-color: #6c8497; + --panel-bg-color: #0e161d; + --label-color: #7ac9d6; + --command-link-color: #5fc2e9; + --top-links-color: #dce7f5; + --top-links-hover-color: hsl(45, 100%, 50%); + --soft-color: #aebed0; + --zero-color: #b9cfe2; + --placeholder-color: #7e95a7; + --settings-button-color: #b9cfe2; + --lights-on-header-color: #ff7fb0; + --settings-accent-color: #ffbf69; +} + +/* Blade Runner header effects */ +.bladerunner .header-cmd { color: var(--header-cmd-color) !important; } +.bladerunner .lights-on .header-cmd { color: var(--lights-on-header-color) !important; } +.bladerunner .header.lights-on { text-shadow: 0 0 4px rgba(255, 127, 176, 0.35), 0 0 9px rgba(255, 127, 176, 0.22); } +.bladerunner .header h1 { text-transform: uppercase; color: #66d9e8a8; cursor: pointer; position: relative; z-index: 1; font-weight: bold; user-select: none;} +.bladerunner .header h1.lights-on { color: #66d9e8; text-shadow: 0 0 4px rgba(102, 217, 232, 0.35), 0 0 9px rgba(102, 217, 232, 0.22); } +.bladerunner .header h1.lights-on::after { + content: ""; + animation: flicker 1s forwards; + position: absolute; + left: 0; + top: 50%; + transform: translate(-30%, -50%); + width: 20%; + height: 120%; + pointer-events: none; + z-index: 0; + background: + radial-gradient(ellipse at center, + rgba(102, 217, 232, 0.70) 0%, + rgba(102, 217, 232, 0.45) 22%, + rgba(0, 0, 0, 0) 60%), + radial-gradient(ellipse at center, + rgba(255, 127, 176, 0.55) 0%, + rgba(255, 127, 176, 0.35) 35%, + rgba(0, 0, 0, 0) 72%); + filter: blur(35px); +} + +@keyframes flicker { + 20%, 24%, 55% { opacity: 0; } + 40% { opacity: 1; } + 80% { opacity: 1; } + 100% { opacity: 1; } +} + +/* Blade Runner-specific component tweaks */ +.bladerunner .accent1 button:hover { text-shadow: 0 0 2px #e3a600 } +.bladerunner .command-link:hover, +.bladerunner .command-link:focus { text-shadow: 0 0 2px rgba(69, 243, 255, 0.949); } +.bladerunner button.hashLink:hover, .bladerunner .undo button:hover, .bladerunner a.hashLink:hover { + --text-shadow: 0 0 2px currentColor; + text-shadow: 0 0 2px rgb(229, 33, 0.5); + color: var(--hashlink-hover-color); +} +.bladerunner .undo button:hover { opacity: 1; } + +/* Blade Runner: subtle glow for SVG icons inside hash links on hover/focus */ +.bladerunner .hashLink:hover .icon, +.bladerunner .hashLink:focus .icon, +.bladerunner .hashLink:hover svg, +.bladerunner .undo:hover svg, +.bladerunner .hashLink:focus svg { + filter: drop-shadow(0 0 2px currentColor); +} + +/* Blade Runner: neon hover glow for top-links controls */ +.bladerunner .top-links a, .bladerunner .top-links a:visited { color: var(--top-links-color); } +.bladerunner .top-links button { color: var(--top-links-color); } +.bladerunner .top-links a:hover, +.bladerunner .top-links a:focus, +.bladerunner .top-links button:hover, +.bladerunner .top-links button:focus { + text-shadow: 0 0 2px rgb(229, 33, 0.5); + color: var(--top-links-hover-color); +} + +/* Optional: prototype radial glow kept commented +.bladerunner .top-links li {position: relative;} +.bladerunner .top-links button:hover::after, .bladerunner .top-links a:hover::after { + content: ""; + position: absolute; + right: 50%; + top: 50%; + transform: translate(50%, -50%); + white-space: nowrap; + width: 200%; + height: 120%; + pointer-events: none; + z-index: 0; + background: radial-gradient(ellipse at center, rgba(227, 166, 0, 0.85) 0%, rgba(227, 166, 0, 0.55) 22%, rgba(0, 0, 0, 0) 60%); + filter: blur(20px); +} +*/ + +/* Blade Runner: add matching glow to SVG icons inside top-links on hover/focus */ +.bladerunner .top-links a:hover .icon, +.bladerunner .top-links a:focus .icon, +.bladerunner .top-links button:hover .icon, +.bladerunner .top-links button:focus .icon, +.bladerunner .top-links a:hover svg, +.bladerunner .top-links a:focus svg, +.bladerunner .top-links button:hover svg, +.bladerunner .top-links button:focus svg { + color: amber !important; + filter: drop-shadow(0 0 2px rgba(255, 127, 176, 0.5)); +} diff --git a/src/css/theme-dark.css b/src/css/theme-dark.css new file mode 100644 index 0000000..17e5453 --- /dev/null +++ b/src/css/theme-dark.css @@ -0,0 +1,27 @@ +/* Dark theme tokens */ +.app-root.dark { + --bg-color: #121212; + --text-color: white; + --solid-bg-color: #121212; + --font-family: Verdana, sans-serif; + --header-cmd-color: #c5c5c5; /* default fallback used for header-cmd unless overridden */ + --anchor-color: white; + --button-color: white; + --indicator-color: #555; + --on-color: white; + --prefix-color: #999; + --other-color: #777; + --hashlink-color: #555; + --hashlink-hover-color: #999; + --top-links-li-hover-bg: #333; + --error-color: #d83e8f; + --btn-color: white; + --btn-hover-bg: #333; + --btn-disabled-color: #999; + --accent1-color: mediumseagreen; + --help-code-color: mediumseagreen; + --input-border-color: rgba(255, 255, 255, 0.5); + --input-text-color: white; + --expression-color: white; + --button-hover-bg: rgba(255, 255, 255, 0.2); +} diff --git a/src/css/theme-graphite.css b/src/css/theme-graphite.css new file mode 100644 index 0000000..88d064b --- /dev/null +++ b/src/css/theme-graphite.css @@ -0,0 +1,42 @@ +/* Graphite theme tokens */ +.app-root.graphite { + --bg-color: #151617; + --solid-bg-color: #151617; + --text-color: #ececec; + --font-family: Verdana, sans-serif; + --header-cmd-color: #5f9ea0; + --anchor-color: #5f9ea0; + --button-color: #5f9ea0; + --indicator-color: #9aa0a3; + --on-color: #ececec; + --prefix-color: #5f9ea0; + --other-color: #7a8286; + --hashlink-color: #9aa0a3; + --hashlink-hover-color: #b4c6c9; + --top-links-li-hover-bg: #191c1d; + --error-color: #d83e8f; + --btn-color: #ececec; + --btn-hover-bg: #1f2324; + --btn-disabled-color: #9aa0a3; + --accent1-color: #5f9ea0; + --accent-background: #191c1d; + --button-border-color: #313639; + --solid-border-color: #313639; + --help-code-color: #b4c6c9; + --input-border-color: #313639; + --input-text-color: #ececec; + --expression-color: #ececec; + --button-hover-bg: #1f2324; + --cur-color: #5f9ea0; + --panel-bg-color: #1f2324; + --label-color: #b4c6c9; + --command-link-color: #5f9ea0; + --top-links-color: #ececec; + --top-links-hover-color: #5f9ea0; + --soft-color: #9aa0a3; + --zero-color: #b4c6c9; + --placeholder-color: #9aa0a3; + --settings-button-color: #b4c6c9; + --settings-accent-color: #5f9ea0; + --lights-on-header-color: #b4c6c9; +} diff --git a/src/css/theme-light.css b/src/css/theme-light.css new file mode 100644 index 0000000..0847c55 --- /dev/null +++ b/src/css/theme-light.css @@ -0,0 +1,31 @@ +/* Light theme tokens */ +.app-root.light { + --bg-color: #fafafa; + --text-color: #121212; + --solid-bg-color: var(--bg-color); + --font-family: Verdana, sans-serif; + --header-cmd-color: #919191; + --anchor-color: #222; + --button-color: #222; + --indicator-color: #ddd; + --on-color: #121212; + --prefix-color: #888; + --other-color: #bbb; + --hashlink-color: #aaa; + --hashlink-hover-color: #888; + --top-links-li-hover-bg: #ddd; + --error-color: #d83e8f; + --btn-color: black; + --btn-hover-bg: #ddd; + --btn-disabled-color: #888; + --accent1-color: green; + --accent-background: transparent; + --button-border-color: gray; + --solid-border-color: gray; + --help-code-color: green; + --input-border-color: rgba(0, 0, 0, 0.5); + --input-text-color: inherit; + --expression-color: var(--text-color); + --button-hover-bg: rgba(255, 255, 255, 0.2); + --cur-color: lightgray; +} diff --git a/src/css/theme-midnight.css b/src/css/theme-midnight.css new file mode 100644 index 0000000..efb0975 --- /dev/null +++ b/src/css/theme-midnight.css @@ -0,0 +1,28 @@ +/* Midnight theme tokens */ +.app-root.midnight { + --bg-color: #2c3e50; + --text-color: white; + --solid-bg-color: #2c3e50; + --font-family: Verdana, sans-serif; + --header-cmd-color: #7ea3b5; + --anchor-color: white; + --button-color: white; + --indicator-color: #85a0ad; + --on-color: white; + --prefix-color: #85a0ad; + --other-color: #9FBAC7; + --hashlink-color: #85a0ad; + --hashlink-hover-color: #9FBAC7; + --top-links-li-hover-bg: #132537; + --error-color: #d83e8f; + --btn-color: white; + --btn-hover-bg: #132537; + --btn-disabled-color: #85a0ad; + --accent1-color: mediumseagreen; + --accent-background: #3b5268; + --help-code-color: mediumseagreen; + --input-border-color: rgba(255, 255, 255, 0.5); + --input-text-color: white; + --expression-color: white; + --button-hover-bg: rgba(255, 255, 255, 0.2); +} diff --git a/src/css/theme.css b/src/css/theme.css new file mode 100644 index 0000000..14e86d4 --- /dev/null +++ b/src/css/theme.css @@ -0,0 +1,110 @@ +/* Shared theme surface rules driven by CSS variables */ +.app-root { + background: var(--bg-color); + color: var(--text-color); +} + +.app-root .solid-background { + background: var(--solid-bg-color); +} + +.app-root .header-cmd { + color: var(--header-cmd-color); +} + +.app-root .lights-on .header-cmd, +.app-root .header-cmd.lights-on { + color: var(--lights-on-header-color, var(--header-cmd-color)); +} + +.app-root a, +.app-root a:visited, +.app-root button { + color: var(--anchor-color); +} + +.app-root .indicator { color: var(--indicator-color); } +.app-root .on { color: var(--on-color); } +.app-root .prefix { color: var(--prefix-color); } +.app-root .other { color: var(--other-color); } +.app-root .expression { color: var(--expression-color); } +.app-root .accent-background { background-color: var(--accent-background, transparent); } + +.app-root .hashLink, +.app-root .hashLink:visited { + color: var(--hashlink-color); +} + +.app-root .hashLink:hover { + color: var(--hashlink-hover-color); +} + +.app-root ul.top-links li:hover { + background: var(--top-links-li-hover-bg); + border-radius: 10px; +} + +.app-root .error { color: var(--error-color); } + +.app-root button.btn { color: var(--btn-color); } +.app-root button.btn:hover { background: var(--btn-hover-bg); } +.app-root button.btn:disabled { + color: var(--btn-disabled-color); + background-color: inherit; +} + +.app-root .accent1 { color: var(--accent1-color); } +.app-root .accent1-border { border-color: var(--accent1-color); } + +.app-root .expressionInput { + border-bottom: solid 1px var(--input-border-color); + color: var(--input-text-color); +} + +.app-root .button { + border: solid 1px var(--button-border-color, var(--solid-border-color, currentColor)); +} + +.app-root .button:hover { + background: var(--button-hover-bg); +} + +.app-root .solid-border { + border: solid 1px var(--solid-border-color, var(--button-border-color, currentColor)); + background-color: var(--panel-bg-color, transparent); +} + +.app-root .help code, +.app-root .help code a { + color: var(--help-code-color); +} + +.app-root .cur { color: var(--cur-color, inherit); } +.app-root .soft { color: var(--soft-color, inherit); } +.app-root .label { color: var(--label-color, inherit); } +.app-root .zero { color: var(--zero-color, inherit); } + +.app-root .command-link { + color: var(--command-link-color, var(--anchor-color)); +} + +.app-root .expressionInput::placeholder { + color: var(--placeholder-color, inherit); +} + +.app-root .top-links a, +.app-root .top-links a:visited, +.app-root .top-links button { + color: var(--top-links-color, var(--anchor-color)); +} + +.app-root .top-links a:hover, +.app-root .top-links a:focus, +.app-root .top-links button:hover, +.app-root .top-links button:focus { + color: var(--top-links-hover-color, var(--anchor-color)); +} + +.app-root #settings button { + color: var(--settings-accent-color, inherit); +} diff --git a/src/index.css b/src/index.css deleted file mode 100644 index e6b88b9..0000000 --- a/src/index.css +++ /dev/null @@ -1,443 +0,0 @@ -body { padding:0; margin:0; height: 100%; overflow: hidden; } -html { height: 100% } - -.app-root { - font-family: Verdana; - font-size: 0.8em; - margin: 0; - padding: 0px 30px; - height: 100%; - overflow: auto; - position: relative; -} - -/* Centered vs stretched layout */ -.app-root.layout-centered { } - -/* Constrain and center top-level sections while keeping full-width theme background */ -.app-root.layout-centered > * { - max-width: clamp(70rem, 92vw, 100rem); - margin-left: auto; - margin-right: auto; -} - -/* Blade Runner theme overrides for Settings pane (centralized here per AGENTS.md) */ -.app-root.bladerunner #settings button { color: #ffbf69 } - -.app-root.layout-stretched { - max-width: none; - margin: 0; -} - -/* Theme-scoped code styling to avoid cross-theme overrides */ -.light code, .dark code, .midnight code, .bladerunner code { font-size: 1.2em; font-weight: bold; } - -h1 { font-family: Impact, Verdana; - text-transform: uppercase; - font-weight: lighter; -} -.icon { margin-right: 5px; vertical-align: middle; } -.header-cmd { color: #c5c5c5 } - -.mono { font-family: monospace; font-size: 1.3em } - -.button { - padding: 10px; - border: solid 1px white; - border-radius: 5px; - text-decoration: none; - display: inline-block; -} - -.button { padding: 5px;} -.button svg { margin: 0; margin-right: 5px; } -.button-large { padding: 10px; } - -.expressionInput { - padding: 3px; - outline: none; - border: none; - border-bottom: solid 1px rgba(255, 255, 255, 0.5); - z-index: 100; - padding-left: 15px; - padding-bottom: 5px; - width: 600px; - background: rgba(0, 0, 0, 0); -} - -.hidden { display: none;} - -.result { margin: 10px 10px 30px; } -.result .input { margin-bottom: 10px; } -.result .content { padding-left: 10px} -.result .cur { margin-right: 5px; } - -.input-string { margin-right: 10px;} -.hashLink { text-decoration: none; margin-left: 8px; visibility: hidden; margin-right: 0; padding: 0; text-decoration: none; } -a.hashLink { font-size: 1.1em;} -.hashLink .icon { margin: 0;} -.hashLink:hover { text-decoration: underline; background: none; } -.result:hover .hashLink { visibility: visible } - -.expression { font-size: 1.7em; font-family: monospace } -.expression button { font-family: monospace; font-size: 0.9em;} -.expression .label { font-weight: bold; padding-right: 5px; text-align: right; } -.expression .bin { letter-spacing: 3px; } -.expression .info { font-size: 0.9em; color: teal; } -.expression .byte { margin: 0 3px; } -.expression-result td { border-top: dotted 1px gray; } -.expression .prefix { font-weight: normal; display: none; font-size: 0.9em } -.expression .other { font-size: 0.9em} -.expression .sign { text-align: right; padding-right: 5px;} - -.flipable { cursor: pointer; opacity: 1 } -.flipable { cursor: pointer; opacity: 1 } -.flipable:hover { opacity: 0.8 } - -.hex .prefix { display: inline; } - -.indicator { padding: 0px 5px; background: transparent; border: none; cursor: pointer; vertical-align: middle; color:rgba(0, 0, 0, 0.25) } - -.expanded { display: block;} -.collapsed { display: none;} - -.error { color: maroon; } - -.soft { opacity: 0.7 } - -.small-text { font-size: 0.8em;} - -#view { padding: 10px} - -.cur { color: lightgray; } - - -button { border: none; } -button.link-button {text-decoration: underline;} - -.settings-button { - margin-left: -20px; -} - -/* When Settings is active (no .soft), remove any button border/outline */ -.settings-button button, -.settings-button .command-link { - border: none; - outline: none; - box-shadow: none; -} - -.undo button { - opacity: 0.4; - padding: 0; - margin-left: 5px; -} - -.solid-border { border: solid 1px rgba(255, 255, 255, 0.8); border-radius: 5px;} -.solid-border-soft { border: solid 1px rgba(255, 255, 255, 0.5); border-radius: 5px;} - - -.zero { opacity: 0.5} -.dim-extra-bits .extra-bit { opacity: 0.1;} - -/* Light */ -.light { background: #fafafa; } -.light .solid-background {background: #fafafa;} -.light .header-cmd { color: #919191 } -.light a, .light a:visited, .light button { color: #222; } -.light .indicator { color: #ddd; } -.light .on { color: #121212; } -.light .prefix { color: #888} -.light .other { color: #bbb } -.light .hashLink, .light .hashLink:visited { color: #aaa; } -.light .hashLink:hover { color: #888 } -.light ul.top-links li:hover { background: #ddd } -.light .error { color: #d83e8f } -.light button.btn { color: black} -.light button.btn:hover { background: #ddd} -.light button.btn:disabled { color: #888; background-color: inherit; } -.light .accent1 { color:green} -.light .expressionInput { border-bottom: solid 1px rgba(0, 0, 0, 0.5);} -.light .button { border: solid 1px gray; } -.light .button:hover { background: rgba(0, 0, 0, 0.2);} -.light .solid-border { border: solid 1px gray;} -.light .accent1-border { border-color:green} -.light .help code, .light .help code a { color:green} -.light .button:hover { background: rgba(255, 255, 255, 0.2);} - -/* Dark */ -.dark { background: #121212; color: white;} -.dark .solid-background {background: #121212;} -.dark .expression { color: white;} -.dark .expressionInput { color: white; } -.dark a, .dark a:visited, .dark button { color: white; } -.dark .indicator { color: #555; } -.dark .on { color: white; } -.dark .prefix { color: #999} -.dark .other { color: #777;} -.dark .hashLink, .dark .hashLink:visited { color: #555 } -.dark .hashLink:hover { color: #999 } -.dark ul.top-links li:hover { background: #333 } -.dark .error { color: #d83e8f} -.dark button.btn { color: white} -.dark button.btn:hover { background: #333} -.dark button.btn:disabled { color: #999; background-color: inherit; } -.dark .accent1 { color:mediumseagreen} -.dark .accent1-border { border-color:mediumseagreen} -.dark .help code, .dark .help code a { color:mediumseagreen} -.dark .button:hover { background: rgba(255, 255, 255, 0.2);} - -/* - Midnight Theme -*/ -.midnight { background: #2c3e50; color: white } -.midnight .solid-background {background: #2c3e50;} -.midnight .header-cmd { color: #7ea3b5 !important } -.midnight .expression { color: white;} -.midnight .expressionInput { color: white;} -.midnight a, .dark a:visited, .midnight button { color: white; } -.midnight .indicator { color: #85a0ad; } -.midnight .on { color: white; } -.midnight .prefix { color: #85a0ad} -.midnight .other { color: #9FBAC7;} -.midnight .accent-background { background-color: #3b5268;} -.midnight .hashLink, .midnight .hashLink:visited { color: #85a0ad } -.midnight .hashLink:hover { color: #9FBAC7 } -.midnight ul.top-links li:hover { background: #132537 } -.midnight .error { color:#d83e8f} -.midnight .changelog .item-new .date { font-weight: bold } -.midnight button.btn { color: white} -.midnight button.btn:hover { background: #132537} -.midnight button.btn:disabled { color: #85a0ad; background-color: inherit; } -.midnight .accent1 { color:mediumseagreen} -.midnight .accent1-border { border-color:mediumseagreen} -.midnight .help code, .midnight .help code a { color:mediumseagreen} -.midnight .button:hover { background: rgba(255, 255, 255, 0.2);} - -/* - Blade Runner Theme -*/ -.bladerunner { background: #0b0f14; color: white } -.bladerunner .solid-background { background: #0b0f14; } -.bladerunner .header-cmd { color: #ff7fb0a8 !important; } -.bladerunner .lights-on .header-cmd { color: #ff7fb0 !important; } -.bladerunner .header.lights-on { text-shadow: 0 0 4px rgba(255, 127, 176, 0.35), 0 0 9px rgba(255, 127, 176, 0.22); } -.bladerunner .header h1 { text-transform: uppercase; color: #66d9e8a8; cursor: pointer; position: relative; z-index: 1; font-weight: bold; user-select: none;} - -.bladerunner .header h1.lights-on { color: #66d9e8; text-shadow: 0 0 4px rgba(102, 217, 232, 0.35), 0 0 9px rgba(102, 217, 232, 0.22); } -.bladerunner .header h1.lights-on::after { - /* Neon-style halo: layered cyan + magenta radial glows */ - content: ""; - animation: flicker 1s forwards; - position: absolute; - left: 0; - top: 50%; - transform: translate(-30%, -50%); - width: 20%; - height: 120%; - pointer-events: none; - z-index: 0; - background: - radial-gradient(ellipse at center, - rgba(102, 217, 232, 0.70) 0%, - rgba(102, 217, 232, 0.45) 22%, - rgba(0, 0, 0, 0) 60%), - radial-gradient(ellipse at center, - rgba(255, 127, 176, 0.55) 0%, - rgba(255, 127, 176, 0.35) 35%, - rgba(0, 0, 0, 0) 72%); - filter: blur(35px); -} - -@keyframes flicker { - 20%, 24%, 55% { - opacity: 0; - } - 40% { - opacity: 1; - } - 80% { - opacity: 1; - } - 100% { - opacity: 1; - } -} -.bladerunner {color: #e6f0ff;} -.bladerunner .expression { color: white; } -.bladerunner .expressionInput { color: white; } -.bladerunner a, .bladerunner a:visited { color: #00d1f2; } -.bladerunner button { color: #00eaff; } -.bladerunner .indicator { color: #0e6e7e; } -.bladerunner .on { color: white; } -.bladerunner .prefix { color: #00d1f2 } -.bladerunner .other { color: #6c8497} -.bladerunner .label { color: #7ac9d6 } -.bladerunner .accent-background { background-color: #131a22; } -.bladerunner .hashLink:hover { color: #33e1ff } -.bladerunner .error { color:#d83e8f } -.bladerunner .changelog .item-new .date { font-weight: bold } -.bladerunner button.btn { color: #00eaff } -.bladerunner button.btn:hover { background: #11222c } -.bladerunner button.btn:disabled { color: #0e6e7e; background-color: inherit; } -.bladerunner .accent1 { color: #e3a600 } -.bladerunner .accent1 button:hover { text-shadow: 0 0 2px #e3a600 } -.bladerunner .accent1-border { border-color: #e3a600 } -.bladerunner .button { border-color: #00eaff } -.bladerunner code { color: #e3a600 } -.bladerunner code a, .bladerunner code a:visited { color: #e3a600 } -.bladerunner .command-link { color: #5fc2e9 } -.bladerunner .command-link:hover, -.bladerunner .command-link:focus { text-shadow: 0 0 2px rgba(69, 243, 255, 0.949); } - -.bladerunner .soft { color: #aebed0 } -.bladerunner .solid-border { background-color: #0e161d; border-color: #1f3b4a;} -.bladerunner .expressionInput {border-color: #1f3b4a;} -.bladerunner .expressionInput::placeholder {color: #7e95a7;} -.bladerunner .zero {color: #b9cfe2; } -.bladerunner .expression {color: #e6f0ff;} -.bladerunner .settings-button button {color: #b9cfe2;} -.bladerunner button.hashLink, .bladerunner a.hashLink, .bladerunner a.hashLink:visited { color: #52687b; } -.bladerunner button.hashLink:hover, .bladerunner .undo button:hover, .bladerunner a.hashLink:hover { - /* subtle glow derived from current hover color */ - --text-shadow: 0 0 2px currentColor; - text-shadow:0 0 2px rgb(229, 33, 0.5); - color: #5fc2e9; -} -.bladerunner .undo button:hover { opacity: 1; } -.bladerunner .cur { color: #6c8497; } - -/* Blade Runner: subtle glow for SVG icons inside hash links on hover/focus */ -.bladerunner .hashLink:hover .icon, -.bladerunner .hashLink:focus .icon, -.bladerunner .hashLink:hover svg, -.bladerunner .undo:hover svg, -.bladerunner .hashLink:focus svg { - filter: drop-shadow(0 0 2px currentColor); -} -/* Blade Runner: neon hover glow for top-links controls */ -.bladerunner .top-links a, .bladerunner .top-links a:visited { color: #dce7f5 } -.bladerunner .top-links button { color: #dce7f5 } - -.bladerunner .top-links a:hover, -.bladerunner .top-links a:focus, -.bladerunner .top-links button:hover, -.bladerunner .top-links button:focus { - /* very dim magenta glow */ - text-shadow:0 0 2px rgb(229, 33, 0.5); - color: hsl(45, 100%, 50%); -} - - -/* -.bladerunner .top-links li {position: relative;} -.bladerunner .top-links button:hover::after, .bladerunner .top-links a:hover::after { - content: ""; - position: absolute; - right: 50%; - top: 50%; - transform: translate(50%, -50%); - white-space: nowrap; - width: 200%; - height: 120%; - pointer-events: none; - z-index: 0; - background: - radial-gradient(ellipse at center, - rgba(227, 166, 0, 0.85) 0%, - rgba(227, 166, 0, 0.55) 22%, - rgba(0, 0, 0, 0) 60%); - filter: blur(20px); -}*/ - -/* Blade Runner: add matching glow to SVG icons inside top-links on hover/focus */ -.bladerunner .top-links a:hover .icon, -.bladerunner .top-links a:focus .icon, -.bladerunner .top-links button:hover .icon, -.bladerunner .top-links button:focus .icon, -.bladerunner .top-links a:hover svg, -.bladerunner .top-links a:focus svg, -.bladerunner .top-links button:hover svg, -.bladerunner .top-links button:focus svg { - color: amber !important; - filter: drop-shadow(0 0 2px rgba(255, 127, 176, 0.5)); -} - -.bladerunner .bladerunner-easter-egg {display: none;} - -.bladerunner-easter-egg { - position: absolute; - right: 1em; - bottom: 1em; - opacity: 0.3; -} - -.bladerunner-easter-egg:hover { - opacity: 1; -} - - -button { - border: none; - background: none; - cursor: pointer; -} - - - -button:focus {outline:0;} - -/* Remove blue focus ring from the Blade Runner easter egg button */ -.bladerunner-easter-egg button:focus, -.bladerunner-easter-egg button:focus-visible { - outline: none !important; - box-shadow: none !important; -} - -/* Anchor the Blade Runner easter egg to bottom-right regardless of scrolling */ -.bladerunner-easter-egg { - position: fixed; - right: 20px; - bottom: 20px; - z-index: 1000; -} - -/* Top Links Shrink */ -@media (max-width: 800px) { - .top-links .link-text { display: none } - .debug-indicators { display: none;} - .app-root {padding: 10px; } -} - -.social-container{ position:fixed; bottom:20px; right:20px } - -/* Remove margin space on body. Inline top links with header */ -@media (max-width: 700px) { - /*.expressionInput { width: 450px; } */ -} - -/* Further shrink */ -@media (max-width: 500px) { - .expressionInput { width: 400px; } - .top-links a { display: inline-block; padding: 5px 10px} -} - -@media (max-width: 450px) { - - .expressionInput { width: 350px; } -} - - -#output { - padding: 30px 30px; -} - -.input-p { - display:inline; - z-index: 101; - position: absolute; - margin-right: -10px; - margin-top: 3px; - opacity: 0.5; -} - diff --git a/src/index.tsx b/src/index.tsx index 177dfd5..40a9595 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,7 +3,7 @@ import ReactDOM from 'react-dom/client'; import cmd, { CommandInput } from './shell/cmd'; import AppRoot from './shell/components/AppRoot'; import log from 'loglevel'; -import './index.css'; +import './css/index.css'; import networkingAppModule from './networking/module'; import expressionAppModule from './expression/module'; import shellModule from './shell/module'; @@ -52,4 +52,4 @@ root.render( // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -//eportWebVitals(); \ No newline at end of file +//eportWebVitals(); diff --git a/src/shell/AppState.ts b/src/shell/AppState.ts index e89a375..edf01dd 100644 --- a/src/shell/AppState.ts +++ b/src/shell/AppState.ts @@ -1,6 +1,6 @@ import log from 'loglevel'; -export const APP_VERSION = 10; +export const APP_VERSION = 11; export type PersistedAppData = { emphasizeBytes: boolean; @@ -49,7 +49,7 @@ export default class AppState { this.env = env; - this.uiTheme = persistData.uiTheme; + this.uiTheme = normalizeTheme(persistData.uiTheme); this.emphasizeBytes = !!persistData.emphasizeBytes; this.persistedVersion = persistData.version || 0.1; this.wasOldVersion = persistData.version !== null && persistData.version !== undefined && this.version > this.persistedVersion; @@ -97,10 +97,12 @@ export default class AppState { setUiTheme(theme: string) { - if(this.uiTheme === theme) + const normalized = normalizeTheme(theme); + + if(this.uiTheme === normalized) return; - this.uiTheme = theme; + this.uiTheme = normalized; this.triggerChanged('uiTheme'); } @@ -166,3 +168,8 @@ export default class AppState { function generateKey(): number { return Math.ceil(Math.random() * 10000000) ^ Date.now(); // Because why the hell not... } + +function normalizeTheme(theme: string): string { + if (theme === 'iron') return 'graphite'; + return theme; +} diff --git a/src/shell/components/HelpResultView.css b/src/shell/components/HelpResultView.css index 3236577..79bf578 100644 --- a/src/shell/components/HelpResultView.css +++ b/src/shell/components/HelpResultView.css @@ -1,6 +1,6 @@ .help ul { list-style-type: none; margin: 0; margin-left: 10px; margin-top: 0.2em; padding: 0; } .help li { padding: 1px; margin-bottom: 5px;} -.light .help code, .light .help code a { color:green} +/* Theme-specific styling moved to src/index.css via CSS variables */ .help p { margin-top: 0.5em } .help .section {padding: 1em;} .help .panel-container {overflow: hidden;} @@ -12,4 +12,4 @@ .left-panel, .right-panel { width: 45%; } -} \ No newline at end of file +} diff --git a/src/shell/components/HelpResultView.tsx b/src/shell/components/HelpResultView.tsx index 81fbd41..f4d580c 100644 --- a/src/shell/components/HelpResultView.tsx +++ b/src/shell/components/HelpResultView.tsx @@ -31,7 +31,8 @@ function HelpResultView() {
diff --git a/src/shell/components/WhatsNewResultView.tsx b/src/shell/components/WhatsNewResultView.tsx index 90526f8..cf811cc 100644 --- a/src/shell/components/WhatsNewResultView.tsx +++ b/src/shell/components/WhatsNewResultView.tsx @@ -7,6 +7,14 @@ function WhatsNewResultView() { return

Changelog

+

+ Nov 28th, 2025
+

+
    +
  • Introduced a new theme inspired by industrial gradients.
  • +
+
+

Nov 8th, 2025

diff --git a/src/shell/module.tsx b/src/shell/module.tsx index fcfdbd4..56514b8 100644 --- a/src/shell/module.tsx +++ b/src/shell/module.tsx @@ -24,6 +24,8 @@ const shellModule = { cmd.command("dark", () => appState.setUiTheme('dark')); cmd.command("light", () => appState.setUiTheme('light')); cmd.command("midnight", () => appState.setUiTheme('midnight')); + cmd.command("graphite", () => appState.setUiTheme('graphite')); + cmd.command("iron", () => appState.setUiTheme('graphite')); // legacy alias cmd.command("settings", () => appState.toggleShowSettings()); cmd.command("bladerunner", () => appState.setUiTheme('bladerunner')); cmd.command("bladerunner-easter", (c: CommandInput) => {