Tweaks to Binary UI

Signed-off-by: Alexander Lyall <alex@adcm.uk>
This commit is contained in:
2025-12-14 20:00:01 +00:00
parent d4765b3788
commit e6da9c8c98
18 changed files with 304 additions and 1150 deletions

View File

@@ -0,0 +1,7 @@
<footer class="siteFooter">
<div class="siteFooter__inner">
<div>Computer Science Concept Simulators</div>
<div>© 2025 Computing:Box · Created with ❤️ by Mr Lyall</div>
<div>Powered by ADCM Networks</div>
</div>
</footer>

View File

@@ -0,0 +1,13 @@
<header class="siteHeader">
<div class="siteHeader__inner">
<a class="brand" href="/">Computing:Box</a>
<nav class="nav">
<a class="nav__link" href="/binary">Binary</a>
<a class="nav__link" href="/hexadecimal">Hexadecimal</a>
<a class="nav__link" href="/hex-colours">Hex Colours</a>
<a class="nav__link" href="/logic-gates">Logic Gates</a>
<a class="nav__link" href="/about">About</a>
</nav>
</div>
</header>

View File

@@ -1,6 +0,0 @@
<footer class="site-footer">
<div class="site-footer__inner">
<div class="muted">© {new Date().getFullYear()} Computing:Box</div>
<div class="muted">Powered by ADCM Networks</div>
</div>
</footer>

View File

@@ -1,15 +0,0 @@
<header class="site-header">
<div class="site-header__inner">
<a class="brand" href="/">
<span class="brand__name">Computing:Box</span>
</a>
<nav class="nav">
<a href="/about/">About</a>
<a href="/binary/">Binary</a>
<a href="/hexadecimal/">Hexadecimal</a>
<a href="/hex-colours/">Hex Colours</a>
<a href="/logic-gates/">Logic Gates</a>
</nav>
</div>
</header>

View File

@@ -1,9 +1,10 @@
---
import SiteHeader from "../components/SiteHeader.astro";
import SiteFooter from "../components/SiteFooter.astro";
import Header from "../components/Header.astro";
import Footer from "../components/Footer.astro";
const { title = "Computing:Box" } = Astro.props;
---
<!doctype html>
<html lang="en">
<head>
@@ -11,16 +12,18 @@ const { title = "Computing:Box" } = Astro.props;
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>{title}</title>
<!-- Global site styles -->
<link rel="stylesheet" href="/styles/global.css" />
</head>
<body>
<SiteHeader />
<!-- Global site styling -->
<link rel="stylesheet" href="/styles/site.css" />
<main class="site-main">
<!-- Page specific styles can be added by each page -->
<slot name="head" />
</head>
<body>
<Header />
<main class="page">
<slot />
</main>
<SiteFooter />
<Footer />
</body>
</html>

View File

@@ -3,12 +3,11 @@ import BaseLayout from "../layouts/BaseLayout.astro";
---
<BaseLayout title="Binary | Computing:Box">
<!-- Page-specific CSS -->
<link rel="stylesheet" href="/styles/binary.css" />
<main class="wrap">
<section class="topGrid">
<!-- LEFT: readout + buttons + bits -->
<section class="binaryWrap">
<div class="topGrid">
<!-- LEFT -->
<div>
<div class="readout">
<div class="label">Denary</div>
@@ -27,11 +26,11 @@ import BaseLayout from "../layouts/BaseLayout.astro";
<div class="divider"></div>
<!-- Bits render here (JS builds bulbs + switches) -->
<section class="bits" id="bitsGrid" aria-label="Bit switches"></section>
<!-- Bit rows injected by JS -->
<section id="bitsRows" class="bitsRows" aria-label="Bit switches"></section>
</div>
<!-- RIGHT: mode + bit width -->
<!-- RIGHT -->
<aside class="panelCol">
<div class="card">
<div class="cardTitle">Mode</div>
@@ -39,13 +38,12 @@ import BaseLayout from "../layouts/BaseLayout.astro";
<div class="toggleRow">
<div class="toggleLabel" id="lblUnsigned">Unsigned</div>
<!-- SAME SWITCH STYLE as bit switches -->
<label class="switch" aria-label="Toggle mode">
<input id="modeToggle" type="checkbox" />
<span class="slider"></span>
</label>
<div class="toggleLabel" id="lblTwos">Twos complement</div>
<div class="toggleLabel" id="lblTwos">Two's complement</div>
</div>
<div class="hint" id="modeHint">
@@ -61,28 +59,17 @@ import BaseLayout from "../layouts/BaseLayout.astro";
<div class="bitInputWrap">
<div class="bitInputLabel">Bits</div>
<input
id="bitsInput"
class="bitInput"
type="number"
inputmode="numeric"
min="4"
max="64"
step="1"
value="8"
aria-label="Number of bits"
/>
<input id="bitsInput" class="bitInput" type="number" inputmode="numeric" min="4" max="64" step="1" value="8" />
</div>
<button class="miniBtn" id="btnBitsUp" type="button" aria-label="Increase bits">+</button>
</div>
<div class="hint">Minimum 4 bits, maximum 64 bits. Display wraps every 8 bits.</div>
<div class="hint">Minimum 4 bits, maximum 64 bits.</div>
</div>
</aside>
</section>
</main>
</div>
</section>
<!-- Page-specific JS -->
<script type="module" src="/scripts/binary.js"></script>
</BaseLayout>

View File

@@ -1,54 +0,0 @@
let bits = [128,64,32,16,8,4,2,1];
let state = Array(8).fill(0);
const denaryEl = document.getElementById("denaryNumber");
const binaryEl = document.getElementById("binaryNumber");
const bitEls = document.querySelectorAll(".bit");
bitEls.forEach((el, i) => {
el.addEventListener("click", () => {
state[i] = state[i] ? 0 : 1;
el.classList.toggle("on");
update();
});
});
function update() {
const denary = state.reduce((sum, bit, i) => sum + bit * bits[i], 0);
denaryEl.textContent = denary;
binaryEl.textContent = state.join("");
}
function requestBinary() {
const input = prompt("Enter 8-bit binary:");
if (!/^[01]{8}$/.test(input)) return;
state = input.split("").map(Number);
bitEls.forEach((el,i)=>el.classList.toggle("on",state[i]));
update();
}
function requestDenary() {
const input = parseInt(prompt("Enter denary (0255)"),10);
if (isNaN(input) || input < 0 || input > 255) return;
let value = input;
state = bits.map(b => {
if (value >= b) {
value -= b;
return 1;
}
return 0;
});
bitEls.forEach((el,i)=>el.classList.toggle("on",state[i]));
update();
}
function shiftBinary(dir) {
if (dir === "left") state.shift(), state.push(0);
if (dir === "right") state.pop(), state.unshift(0);
bitEls.forEach((el,i)=>el.classList.toggle("on",state[i]));
update();
}
update();

View File

@@ -1,52 +0,0 @@
src/styles/base.css
@import "./md3-tokens.css";
html, body{ height:100%; }
body{
margin:0;
font-family: var(--font-sans);
background: var(--md-surface-2);
color: var(--md-on-surface);
}
a{ color: var(--md-primary); text-decoration: none; }
a:hover{ text-decoration: underline; }
.container{
max-width: 1100px;
margin: 0 auto;
padding: 16px;
}
.card{
background: var(--md-surface);
border: 1px solid var(--md-outline);
border-radius: var(--radius-2);
box-shadow: var(--shadow-1);
padding: 16px;
}
.btn{
display:inline-flex;
gap:8px;
align-items:center;
justify-content:center;
border-radius: 999px;
border: 1px solid var(--md-outline);
background: var(--md-surface);
color: var(--md-on-surface);
padding: 10px 14px;
font-weight: 600;
cursor: pointer;
}
.btn:hover{ filter: brightness(0.98); }
.btn:focus{ outline:none; box-shadow: var(--md-focus); }
.btn-primary{
background: var(--md-primary);
color: var(--md-on-primary);
border-color: transparent;
}
.badge{
display:inline-block;
padding: 2px 10px;
border-radius: 999px;
font-size: 12px;
border: 1px solid var(--md-outline);
background: var(--md-surface-2);
}
code, pre{ font-family: var(--font-mono); }

View File

@@ -1,68 +0,0 @@
.binary-container {
max-width: 1100px;
margin: auto;
padding: 2rem;
color: #e0e0e0;
}
.display {
text-align: center;
}
.label {
font-size: 1.2rem;
opacity: 0.7;
}
.number {
font-size: 3rem;
margin-bottom: 1rem;
color: #00ff66;
}
.controls {
margin-top: 1rem;
}
.controls button {
margin: 0.25rem;
padding: 0.6rem 1rem;
font-size: 1rem;
}
.bits {
display: grid;
grid-template-columns: repeat(8, 1fr);
gap: 1rem;
margin-top: 3rem;
}
.bit {
width: 40px;
height: 80px;
background: #333;
border-radius: 20px;
position: relative;
cursor: pointer;
}
.bit::after {
content: "";
width: 32px;
height: 32px;
background: #555;
border-radius: 50%;
position: absolute;
bottom: 6px;
left: 4px;
transition: all 0.2s ease;
}
.bit.on {
background: #00c853;
}
.bit.on::after {
bottom: 42px;
background: #eaffea;
}

View File

@@ -1,11 +0,0 @@
@font-face {
font-family: "DSEG7";
src: url("/fonts/DSEG7Classic-Regular.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}
.dseg {
font-family: "DSEG7", monospace;
letter-spacing: 0.15em;
}

View File

@@ -1,43 +0,0 @@
src/styles/md3-tokens.css
/* MD3-inspired tokens tuned for education: high readability, clear contrast, calm surfaces */
:root{
/* Typography */
--font-sans: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
--font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
/* Spacing + shape */
--radius-1: 10px;
--radius-2: 16px;
--radius-3: 22px;
--shadow-1: 0 1px 2px rgba(0,0,0,.08), 0 2px 8px rgba(0,0,0,.06);
/* Color roles (keep simple) */
--md-surface: #ffffff;
--md-surface-2: #f6f7fb;
--md-on-surface: #111318;
--md-primary: #2f6fed; /* calm blue */
--md-on-primary: #ffffff;
--md-secondary: #5a5f72; /* muted */
--md-on-secondary: #ffffff;
--md-tertiary: #0f766e; /* teal for "practical" tools */
--md-on-tertiary: #ffffff;
--md-outline: #d7dbe7;
--md-success: #1a7f37;
--md-warning: #b54708;
--md-danger: #b42318;
/* Focus ring for accessibility */
--md-focus: 0 0 0 3px rgba(47,111,237,.28);
}
@media (prefers-color-scheme: dark){
:root{
--md-surface: #0b0e14;
--md-surface-2: #121725;
--md-on-surface: #e8eaf2;
--md-primary: #9bb6ff;
--md-on-primary: #0b0e14;
--md-secondary: #b8bccd;
--md-on-secondary: #0b0e14;
--md-tertiary: #4fd1c5;
--md-on-tertiary: #0b0e14;
--md-outline: #2b3244;
--md-focus: 0 0 0 3px rgba(155,182,255,.25);
}
}