Fix stack overlap, staggered folder tabs with click-to-jump.
Shared scroll driver for all variants; wider folders; tab rail; trace and rack aligned. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+13
-11
@@ -6,26 +6,28 @@
|
||||
<title>Levkin — Stack Rack</title>
|
||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="../shared/stack-vars.css" />
|
||||
<link rel="stylesheet" href="./rack.css" />
|
||||
</head>
|
||||
<body>
|
||||
<nav class="nav"><a href="/">← options</a><a href="/stack-trace/">trace</a><span id="depth">U0</span></nav>
|
||||
|
||||
<nav class="nav"><a href="/">← options</a><a href="/stack-trace/">trace</a><a href="/stack-folder/">folder</a><span id="depth">U0</span></nav>
|
||||
<div class="rack-frame">
|
||||
<div class="rack-label">LEV-RACK-01</div>
|
||||
<main class="mount">
|
||||
<div class="scroll-section" data-layer="0"><article class="unit u0"><header class="unit-head"><span class="led on"></span><span class="uid">U0</span><span class="svc">foundation</span></header><div class="unit-body"><strong>Levkin</strong><p>Software dev · CA · 15+ yrs · new work open</p></div></article></div>
|
||||
<div class="scroll-section" data-layer="1"><article class="unit u1"><header class="unit-head"><span class="led on"></span><span class="uid">U1</span><span class="svc">application</span></header><div class="unit-body"><strong>custom_software</strong><p>TS · Python · .NET</p></div></article></div>
|
||||
<div class="scroll-section" data-layer="2"><article class="unit u2"><header class="unit-head"><span class="led on"></span><span class="uid">U2</span><span class="svc">automation</span><a href="https://auto.levkin.ca">auto↗</a></header><div class="unit-body"><strong>pipeline_cluster</strong><p>n8n · CI/CD · LLM hooks</p></div></article></div>
|
||||
<div class="scroll-section" data-layer="3"><article class="unit u3"><header class="unit-head"><span class="led on"></span><span class="uid">U3</span><span class="svc">enterprise</span><a href="https://caseware.levkin.ca">caseware↗</a></header><div class="unit-body"><strong>caseware_module</strong><p>MNP · JazzIt · 8h→2m</p></div></article></div>
|
||||
<div class="scroll-section" data-layer="4"><article class="unit u4"><header class="unit-head"><span class="led blink"></span><span class="uid">U4</span><span class="svc">quality</span><a href="https://iliadobkin.com">iliadobkin↗</a></header><div class="unit-body"><strong>sdet_suite</strong><p>traces · Playwright · CI</p></div></article></div>
|
||||
<div class="scroll-section" data-layer="5"><article class="unit u5"><header class="unit-head"><span class="led"></span><span class="uid">U5</span><span class="svc">ops</span><a href="https://jobs.levkin.ca">jobs↗</a></header><div class="unit-body"><strong>job_ops</strong><p>auth · internal</p></div></article></div>
|
||||
<div class="scroll-section scroll-section--final" data-layer="6"><article class="unit u6"><header class="unit-head"><span class="led on"></span><span class="uid">U6</span><span class="svc">interface</span></header><div class="unit-body"><strong>engage()</strong><p><a href="https://cal.levkin.ca/ilia/consult">book_consult</a> · <a href="mailto:hello@levkine.ca">mail</a></p></div></article></div>
|
||||
<div class="scroll-section" data-layer="0"><article class="unit u0"><header class="unit-head"><button type="button" class="jump" data-goto="0"><span class="led on"></span><span class="uid">U0</span><span class="svc">foundation</span></button></header><div class="unit-body"><strong>Levkin</strong><p>Software dev · CA · 15+ yrs</p></div></article></div>
|
||||
<div class="scroll-section" data-layer="1"><article class="unit u1"><header class="unit-head"><button type="button" class="jump" data-goto="1"><span class="led on"></span><span class="uid">U1</span><span class="svc">application</span></button></header><div class="unit-body"><strong>custom_software</strong><p>TS · Python · .NET</p></div></article></div>
|
||||
<div class="scroll-section" data-layer="2"><article class="unit u2"><header class="unit-head"><button type="button" class="jump" data-goto="2"><span class="led on"></span><span class="uid">U2</span><span class="svc">automation</span></button><a class="ext" href="https://auto.levkin.ca">auto↗</a></header><div class="unit-body"><strong>pipeline</strong><p>n8n · CI/CD</p></div></article></div>
|
||||
<div class="scroll-section" data-layer="3"><article class="unit u3"><header class="unit-head"><button type="button" class="jump" data-goto="3"><span class="led on"></span><span class="uid">U3</span><span class="svc">enterprise</span></button><a class="ext" href="https://caseware.levkin.ca">case↗</a></header><div class="unit-body"><strong>caseware</strong><p>MNP · JazzIt</p></div></article></div>
|
||||
<div class="scroll-section" data-layer="4"><article class="unit u4"><header class="unit-head"><button type="button" class="jump" data-goto="4"><span class="led blink"></span><span class="uid">U4</span><span class="svc">quality</span></button><a class="ext" href="https://iliadobkin.com">sdet↗</a></header><div class="unit-body"><strong>sdet_suite</strong><p>iliadobkin.com</p></div></article></div>
|
||||
<div class="scroll-section" data-layer="5"><article class="unit u5"><header class="unit-head"><button type="button" class="jump" data-goto="5"><span class="led"></span><span class="uid">U5</span><span class="svc">ops</span></button><a class="ext" href="https://jobs.levkin.ca">jobs↗</a></header><div class="unit-body"><strong>job_ops</strong><p>auth</p></div></article></div>
|
||||
<div class="scroll-section scroll-section--final" data-layer="6"><article class="unit u6"><header class="unit-head"><button type="button" class="jump" data-goto="6"><span class="led on"></span><span class="uid">U6</span><span class="svc">interface</span></button></header><div class="unit-body"><strong>engage()</strong><p><a href="https://cal.levkin.ca/ilia/consult">book</a> · <a href="mailto:hello@levkine.ca">mail</a></p></div></article></div>
|
||||
<div class="stop"></div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<footer class="foot"><span>// rack EOT</span><a href="https://git.levkin.ca">git.levkin.ca</a></footer>
|
||||
<script src="./rack.js" type="module"></script>
|
||||
<script type="module">
|
||||
import { initStackScroll } from '../shared/stack-scroll.js';
|
||||
initStackScroll({ depthPrefix: 'U' });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+41
-71
@@ -1,17 +1,9 @@
|
||||
:root {
|
||||
--nav: 2.5rem;
|
||||
--stick: 0.5rem;
|
||||
--step: 1.7rem;
|
||||
--scroll-tick: 26vh;
|
||||
--overlap: 22vh;
|
||||
--rack: #12141a;
|
||||
--mono: 'IBM Plex Mono', monospace;
|
||||
}
|
||||
@import '../shared/stack-vars.css';
|
||||
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
body {
|
||||
font-family: var(--mono);
|
||||
font-family: 'IBM Plex Mono', ui-monospace, monospace;
|
||||
background: #08090c;
|
||||
color: #9ca3af;
|
||||
font-size: 0.75rem;
|
||||
@@ -28,101 +20,79 @@ body {
|
||||
#depth { margin-left: auto; color: #4ade80; font-weight: 600; }
|
||||
|
||||
.rack-frame {
|
||||
max-width: 540px;
|
||||
width: min(600px, 100%);
|
||||
margin: 0 auto;
|
||||
padding: calc(var(--nav) + 0.75rem) 0.75rem 0;
|
||||
padding: calc(var(--stack-nav) + 0.5rem) 0.5rem 0;
|
||||
border-left: 4px solid #2a3040;
|
||||
border-right: 4px solid #2a3040;
|
||||
background: linear-gradient(90deg, #0c0e14 0%, var(--rack) 8%, var(--rack) 92%, #0c0e14 100%);
|
||||
background: linear-gradient(90deg, #0c0e14 0%, #12141a 8%, #12141a 92%, #0c0e14 100%);
|
||||
min-height: 100vh;
|
||||
box-shadow: inset 0 0 40px rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
.rack-label {
|
||||
font-size: 0.55rem;
|
||||
letter-spacing: 0.2em;
|
||||
color: #3a4458;
|
||||
padding: 0 0.5rem 0.75rem;
|
||||
border-bottom: 1px dashed #2a3040;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.55rem; letter-spacing: 0.2em; color: #3a4458;
|
||||
padding: 0 0.5rem 0.65rem; border-bottom: 1px dashed #2a3040;
|
||||
}
|
||||
|
||||
.mount { padding: 0 0.35rem; }
|
||||
.mount { padding: 0 0.25rem; }
|
||||
|
||||
.scroll-section { height: var(--scroll-tick); position: relative; }
|
||||
.scroll-section--final { height: 16vh; min-height: 160px; }
|
||||
.stop { height: 1px; margin-bottom: 2rem; }
|
||||
.scroll-section { height: var(--stack-tick); position: relative; }
|
||||
.scroll-section--final { height: 12vh; min-height: 200px; }
|
||||
.stop { height: 1px; margin-bottom: 4rem; }
|
||||
|
||||
.unit {
|
||||
position: sticky;
|
||||
margin-bottom: calc(-1 * var(--overlap));
|
||||
margin-bottom: calc(-1 * var(--stack-overlap));
|
||||
border: 1px solid #2a3448;
|
||||
background: #161a22;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 0 #0a0c10, inset 0 1px 0 rgba(255,255,255,0.04);
|
||||
box-shadow: 0 6px 0 #0a0c10, 0 12px 24px rgba(0,0,0,0.4);
|
||||
min-height: 160px;
|
||||
}
|
||||
|
||||
.unit-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.35rem 0.65rem;
|
||||
display: flex; align-items: center; gap: 0.5rem;
|
||||
padding: 0.4rem 0.65rem;
|
||||
background: #1a2030;
|
||||
border-bottom: 1px solid #2a3448;
|
||||
font-size: 0.62rem;
|
||||
position: relative;
|
||||
z-index: 20;
|
||||
position: sticky;
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
.led {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: #3a4458;
|
||||
flex-shrink: 0;
|
||||
.unit-head button.jump {
|
||||
background: none; border: none; font: inherit; color: inherit;
|
||||
cursor: pointer; display: flex; align-items: center; gap: 0.5rem; flex: 1;
|
||||
text-align: left; padding: 0;
|
||||
}
|
||||
|
||||
.unit-head button.jump:hover .uid { color: #4ade80; }
|
||||
|
||||
.led { width: 6px; height: 6px; border-radius: 50%; background: #3a4458; flex-shrink: 0; }
|
||||
.led.on { background: #4ade80; box-shadow: 0 0 6px #4ade80; }
|
||||
.led.blink { background: #fbbf24; animation: blink 1.2s ease infinite; }
|
||||
@keyframes blink { 50% { opacity: 0.35; } }
|
||||
|
||||
@keyframes blink {
|
||||
50% { opacity: 0.35; }
|
||||
}
|
||||
|
||||
.uid { color: #6b7280; font-weight: 600; min-width: 1.5rem; }
|
||||
.uid { color: #6b7280; font-weight: 600; min-width: 1.4rem; }
|
||||
.svc { color: #9ca3af; text-transform: uppercase; letter-spacing: 0.08em; flex: 1; }
|
||||
.unit-head a {
|
||||
color: #60a5fa;
|
||||
text-decoration: none;
|
||||
font-size: 0.58rem;
|
||||
}
|
||||
.unit-head a.ext { color: #60a5fa; text-decoration: none; font-size: 0.58rem; }
|
||||
|
||||
.unit-body {
|
||||
padding: 0.55rem 0.65rem 0.65rem;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.unit-body strong { color: #e5e7eb; font-weight: 500; display: block; margin-bottom: 0.15rem; }
|
||||
.unit-body p { color: #6b7280; font-size: 0.68rem; }
|
||||
.unit-body { padding: 0.6rem 0.7rem 0.75rem; min-height: 120px; }
|
||||
.unit-body strong { color: #e5e7eb; display: block; margin-bottom: 0.2rem; }
|
||||
.unit-body p { color: #6b7280; font-size: 0.7rem; }
|
||||
.unit-body a { color: #60a5fa; text-decoration: none; }
|
||||
.unit-body a:hover { text-decoration: underline; }
|
||||
|
||||
.u0 { top: calc(var(--nav) + var(--stick)); z-index: 1; }
|
||||
.u1 { top: calc(var(--nav) + var(--stick) + var(--step)); z-index: 2; }
|
||||
.u2 { top: calc(var(--nav) + var(--stick) + var(--step) * 2); z-index: 3; }
|
||||
.u3 { top: calc(var(--nav) + var(--stick) + var(--step) * 3); z-index: 4; }
|
||||
.u4 { top: calc(var(--nav) + var(--stick) + var(--step) * 4); z-index: 5; }
|
||||
.u5 { top: calc(var(--nav) + var(--stick) + var(--step) * 5); z-index: 6; }
|
||||
.u6 {
|
||||
top: calc(var(--nav) + var(--stick) + var(--step) * 6);
|
||||
z-index: 7;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.u0 { top: calc(var(--stack-nav) + var(--stack-stick)); z-index: 1; }
|
||||
.u1 { top: calc(var(--stack-nav) + var(--stack-stick) + var(--stack-step)); z-index: 2; }
|
||||
.u2 { top: calc(var(--stack-nav) + var(--stack-stick) + var(--stack-step) * 2); z-index: 3; }
|
||||
.u3 { top: calc(var(--stack-nav) + var(--stack-stick) + var(--stack-step) * 3); z-index: 4; }
|
||||
.u4 { top: calc(var(--stack-nav) + var(--stack-stick) + var(--stack-step) * 4); z-index: 5; }
|
||||
.u5 { top: calc(var(--stack-nav) + var(--stack-stick) + var(--stack-step) * 5); z-index: 6; }
|
||||
.u6 { top: calc(var(--stack-nav) + var(--stack-stick) + var(--stack-step) * 6); z-index: 7; margin-bottom: 0; }
|
||||
|
||||
.foot {
|
||||
display: flex; justify-content: space-between; max-width: 540px; margin: 0 auto;
|
||||
padding: 1rem 1.25rem 2rem; font-size: 0.58rem; color: #3a4458;
|
||||
display: flex; justify-content: space-between;
|
||||
width: min(600px, 100%); margin: 0 auto;
|
||||
padding: 1rem 1.25rem 2.5rem; font-size: 0.58rem; color: #3a4458;
|
||||
}
|
||||
.foot a { color: #3a4458; text-decoration: none; }
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
const sections = document.querySelectorAll('.scroll-section');
|
||||
const depthEl = document.getElementById('depth');
|
||||
const mid = () => window.innerHeight * 0.42;
|
||||
|
||||
function tick() {
|
||||
let a = 0;
|
||||
sections.forEach((s) => {
|
||||
const r = s.getBoundingClientRect();
|
||||
if (r.top <= mid() && r.bottom > mid()) a = +s.dataset.layer;
|
||||
});
|
||||
depthEl.textContent = `U${a}`;
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', tick, { passive: true });
|
||||
tick();
|
||||
Reference in New Issue
Block a user