new darkmode, disbales/hidden min games
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
<style>
|
||||
.theme-root {
|
||||
--bg: #1a1a3e;
|
||||
--surface: #12122a;
|
||||
--surface2: #1e1e40;
|
||||
--border: #2e2e5e;
|
||||
--border2: #3a3a6e;
|
||||
--text: #e8e8ff;
|
||||
--muted: #9090c0;
|
||||
--dim: #5050a0;
|
||||
}
|
||||
.theme-root.day {
|
||||
--bg: #f7f6f3;
|
||||
--surface: #ffffff;
|
||||
--surface2: #f0eeea;
|
||||
--border: #e2ddd6;
|
||||
--border2: #ccc7be;
|
||||
--text: #1a1917;
|
||||
--muted: #6b6560;
|
||||
--dim: #b0aa9f;
|
||||
}
|
||||
.scene {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2rem 1rem;
|
||||
gap: 1rem;
|
||||
font-family: var(--font-sans);
|
||||
background: var(--bg);
|
||||
border-radius: var(--border-radius-lg);
|
||||
transition: background 0.4s ease;
|
||||
}
|
||||
.demo-card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--border-radius-lg);
|
||||
padding: 1rem 1.5rem;
|
||||
width: 100%;
|
||||
max-width: 280px;
|
||||
transition: background 0.4s ease, border-color 0.4s ease;
|
||||
}
|
||||
.demo-card p { margin: 0 0 4px; font-size: 14px; color: var(--text); transition: color 0.4s ease; }
|
||||
.demo-card span { font-size: 12px; color: var(--muted); transition: color 0.4s ease; }
|
||||
.demo-tag {
|
||||
display: inline-block;
|
||||
margin-top: 8px;
|
||||
font-size: 11px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 20px;
|
||||
background: var(--surface2);
|
||||
color: var(--dim);
|
||||
border: 1px solid var(--border2);
|
||||
transition: background 0.4s ease, color 0.4s ease, border-color 0.4s ease;
|
||||
}
|
||||
.toggle-wrap {
|
||||
position: relative;
|
||||
width: 50px;
|
||||
height: 25px;
|
||||
cursor: pointer;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.track {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 12.5px;
|
||||
transition: background 0.5s ease;
|
||||
overflow: hidden;
|
||||
}
|
||||
.track.day { background: #87CEEB; }
|
||||
.track.night { background: #1a1a3e; }
|
||||
.stars { position: absolute; inset: 0; opacity: 0; transition: opacity 0.4s ease; }
|
||||
.night .stars { opacity: 1; }
|
||||
.star { position: absolute; background: white; border-radius: 50%; animation: twinkle 2s infinite; }
|
||||
.star:nth-child(1) { width:2px; height:2px; top:4px; left:6px; animation-delay:0s; }
|
||||
.star:nth-child(2) { width:1px; height:1px; top:10px; left:14px; animation-delay:0.4s; }
|
||||
.star:nth-child(3) { width:1px; height:1px; top:5px; left:22px; animation-delay:0.8s; }
|
||||
.star:nth-child(4) { width:2px; height:2px; top:14px; left:10px; animation-delay:1.2s; }
|
||||
.star:nth-child(5) { width:1px; height:1px; top:8px; left:30px; animation-delay:0.2s; }
|
||||
@keyframes twinkle { 0%,100% { opacity:1; } 50% { opacity:0.3; } }
|
||||
.knob {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
border-radius: 50%;
|
||||
transition: left 0.45s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.4s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2;
|
||||
}
|
||||
.knob.night {
|
||||
left: 3px;
|
||||
background: radial-gradient(circle at 35% 35%, #e8e8ff, #c8c8f8);
|
||||
box-shadow: 0 0 0 2px rgba(180,180,255,0.18), 0 0 7px 4px rgba(140,140,255,0.35), 0 0 14px 6px rgba(100,100,220,0.18);
|
||||
}
|
||||
.knob.day {
|
||||
left: 28px;
|
||||
background: radial-gradient(circle at 40% 40%, #fff8c5, #FFD700);
|
||||
box-shadow: 0 0 0 3px rgba(255,220,0,0.25), 0 0 8px 4px rgba(255,200,0,0.45), 0 0 16px 6px rgba(255,160,0,0.2);
|
||||
}
|
||||
.sun-rays { position: absolute; inset: -7px; opacity: 0; transition: opacity 0.3s ease 0.15s; pointer-events: none; }
|
||||
.knob.day .sun-rays { opacity: 1; }
|
||||
.ray { position: absolute; width: 1.5px; height: 4px; background: rgba(255,220,0,0.9); border-radius: 1px; left: 50%; transform-origin: 50% 16px; margin-left: -0.75px; }
|
||||
.moon-crater { position: absolute; border-radius: 50%; background: rgba(140,140,200,0.4); transition: opacity 0.3s ease; }
|
||||
.knob.day .moon-crater { opacity: 0; }
|
||||
.knob.night .moon-crater { opacity: 1; }
|
||||
.label { font-size: 13px; font-weight: 500; user-select: none; color: var(--muted); transition: color 0.4s ease; }
|
||||
.state-label { font-size: 11px; color: var(--muted); letter-spacing: 0.05em; text-transform: uppercase; transition: color 0.4s ease; }
|
||||
.row { display: flex; align-items: center; gap: 12px; }
|
||||
</style>
|
||||
|
||||
<div class="theme-root day" id="themeRoot">
|
||||
<div class="scene">
|
||||
<h2 class="sr-only">Day and night toggle with scoped theme tokens</h2>
|
||||
|
||||
<div class="demo-card">
|
||||
<p>Sample card</p>
|
||||
<span>Tokens update on toggle</span><br>
|
||||
<span class="demo-tag">surface2 · dim · border2</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">Night</span>
|
||||
<div class="toggle-wrap" role="switch" aria-checked="true" tabindex="0" id="toggle" aria-label="Toggle day/night mode">
|
||||
<div class="track day" id="track">
|
||||
<div class="stars">
|
||||
<div class="star"></div><div class="star"></div><div class="star"></div>
|
||||
<div class="star"></div><div class="star"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="knob day" id="knob">
|
||||
<div class="sun-rays" id="rays"></div>
|
||||
<div class="moon-crater" style="width:4px;height:4px;top:3px;left:5px;"></div>
|
||||
<div class="moon-crater" style="width:3px;height:3px;top:9px;left:9px;"></div>
|
||||
<div class="moon-crater" style="width:2px;height:2px;top:4px;left:11px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="label">Day</span>
|
||||
</div>
|
||||
|
||||
<span class="state-label" id="stateLabel">Day mode</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const toggle = document.getElementById('toggle');
|
||||
const track = document.getElementById('track');
|
||||
const knob = document.getElementById('knob');
|
||||
const rays = document.getElementById('rays');
|
||||
const stateLabel = document.getElementById('stateLabel');
|
||||
const themeRoot = document.getElementById('themeRoot');
|
||||
|
||||
let isDay = true;
|
||||
|
||||
for (let i = 0; i < 8; i++) {
|
||||
const r = document.createElement('div');
|
||||
r.className = 'ray';
|
||||
r.style.transform = `rotate(${i * 45}deg)`;
|
||||
rays.appendChild(r);
|
||||
}
|
||||
|
||||
function applyState() {
|
||||
if (isDay) {
|
||||
track.className = 'track day';
|
||||
knob.className = 'knob day';
|
||||
stateLabel.textContent = 'Day mode';
|
||||
toggle.setAttribute('aria-checked', 'true');
|
||||
themeRoot.classList.add('day');
|
||||
} else {
|
||||
track.className = 'track night';
|
||||
knob.className = 'knob night';
|
||||
stateLabel.textContent = 'Night mode';
|
||||
toggle.setAttribute('aria-checked', 'false');
|
||||
themeRoot.classList.remove('day');
|
||||
}
|
||||
}
|
||||
|
||||
toggle.addEventListener('click', () => { isDay = !isDay; applyState(); });
|
||||
toggle.addEventListener('keydown', e => {
|
||||
if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); isDay = !isDay; applyState(); }
|
||||
});
|
||||
</script>
|
||||
+60
-152
@@ -6,9 +6,10 @@
|
||||
<title>Samantha Vero Friis</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@300;400;500&family=IBM+Plex+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap" rel="stylesheet"/>
|
||||
<link rel="stylesheet" href="/static/styles2.css" />
|
||||
<link rel="stylesheet" href="/static/style/styles2.css" />
|
||||
<link rel="stylesheet" href="/static/style/game.css" />
|
||||
</head>
|
||||
<body>
|
||||
<body class="theme-root day " id="themeRoot">
|
||||
|
||||
<nav>
|
||||
<a class="nav-logo" href="#">samantha_vero_friis</a>
|
||||
@@ -20,11 +21,28 @@
|
||||
<a href="/infra">infrastructure</a>
|
||||
<a href="/git">git</a>
|
||||
<a class="cta" href="mailto:me@samantha42.xyz">contact</a>
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="shell">
|
||||
<aside>
|
||||
<div class="row">
|
||||
<div class="toggle-wrap" role="switch" aria-checked="true" tabindex="0" id="toggle" aria-label="Toggle day/night mode">
|
||||
<div class="track day" id="track">
|
||||
<div class="stars">
|
||||
<div class="star"></div><div class="star"></div><div class="star"></div>
|
||||
<div class="star"></div><div class="star"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="knob day" id="knob">
|
||||
<div class="sun-rays" id="rays"></div>
|
||||
<div class="moon-crater" style="width:4px;height:4px;top:3px;left:5px;"></div>
|
||||
<div class="moon-crater" style="width:3px;height:3px;top:9px;left:9px;"></div>
|
||||
<div class="moon-crater" style="width:2px;height:2px;top:4px;left:11px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p class="sidebar-label">navigate</p>
|
||||
<div class="sidebar-links">
|
||||
@@ -52,6 +70,24 @@
|
||||
<p class="sidebar-label">location</p>
|
||||
<div style="font-family:var(--ff-mono);font-size:0.75rem;color:var(--muted);">Denmark<br>Aalborg Øst, 9220</div>
|
||||
</div>
|
||||
<div>
|
||||
<p class="sidebar-label">languages</p>
|
||||
<div class="lang-row">
|
||||
<span class="lang-badge">Danish</span>
|
||||
<span class="lang-badge">English</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="flex: 1;"></div>
|
||||
<!--
|
||||
<div class="sidebar-links">
|
||||
<p class="sidebar-label">mini games</p>
|
||||
<a href="#alice" onclick="unhideGame()"> Follow the rabbit</a>
|
||||
<a href="#tetris" onclick="unhideTetris()" >Alexey Pajitnov</a>
|
||||
</div>
|
||||
-->
|
||||
|
||||
|
||||
</aside>
|
||||
|
||||
<main id="about">
|
||||
@@ -127,14 +163,6 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="section-head"><h2>languages</h2></div>
|
||||
<div class="lang-row">
|
||||
<span class="lang-badge">Danish</span>
|
||||
<span class="lang-badge">English</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="section-head"><h2>interests</h2></div>
|
||||
<div class="interests-row">
|
||||
@@ -188,7 +216,7 @@
|
||||
|
||||
<div class="page-header">
|
||||
<h2 class="page-title" id="interest">interests</h2>
|
||||
<span class="page-sub">Fav lists</span>
|
||||
<span class="page-sub" id="interest-sub">Fav lists</span>
|
||||
</div>
|
||||
<div class="section-head"><h2>Movie/Show Top list</h2></div>
|
||||
<div class="toplist-group">
|
||||
@@ -203,9 +231,9 @@
|
||||
<img src="/static/posters/AcureForWellness.jpg" alt="A Cure of Wellness">
|
||||
<p>A Cure of Wellness</p>
|
||||
</div>
|
||||
<div class="poster-item">
|
||||
<img src="/static/posters/Fightclub.jpg" alt="Fight Club">
|
||||
<p>Fight Club</p>
|
||||
<div class="poster-item posterhover" onclick="matrixClick()">
|
||||
<img src="/static/posters/matrix.jpg" alt="matrix">
|
||||
<p>The Matrix</p>
|
||||
</div>
|
||||
<div class="poster-item posterhover" onclick="draculaClick()">
|
||||
<img src="/static/posters/Dracula.webp" alt="Dracula: A Love Tale">
|
||||
@@ -246,38 +274,28 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-head"><h2>Lunix rice</h2></div>
|
||||
<div class="rice-wrap">
|
||||
<img src="/static/images/rice.png" width="500px">
|
||||
<div>
|
||||
<div style="padding-left: 10%;"><img src="/static/images/rice.png" width="80%" style="align-self: center;"></div>
|
||||
<p class="exp-body">I love my custom Linux setup. I use Hyprland, which automatically arranges app windows on my screen so everything stays organized without dragging things around. I also use Quickshell, which lets me customize menus, shortcuts, and system controls to work exactly how I want.
|
||||
My system is based on Arch Linux or Manjaro Linux, which are versions of Linux that give you more control and customization than a typical computer setup. The result is a clean, fast, and super efficient desktop that’s hard to go back from.</p>
|
||||
My system is based on Arch Linux or Manjaro Linux, which are versions of Linux that give you more control and customization than a typical computer setup. The result is a clean, fast, and super efficient desktop that’s hard to go back from.
|
||||
<a class="outlink" href="https://git.samantha42.xyz/samantha/dotfiles" >Git repo</a>
|
||||
</p>
|
||||
</div>
|
||||
<!--
|
||||
<div class="section-head"><h2>Games</h2></div>
|
||||
<section style="display: none;" id="alice" class="play" >
|
||||
<br>
|
||||
<div class="section-head"><h2>Want to play a game Alice?!</h2></div>
|
||||
<div class="story-text" id="story-text"></div>
|
||||
<div class="choices" id="choices"></div>
|
||||
</section>
|
||||
|
||||
<div class="toplist-group">
|
||||
<script src="/static/scripts/game.js"></script>
|
||||
|
||||
<div class="toplist-body">
|
||||
<div class="game-grid">
|
||||
<div class="poster-item">
|
||||
<img src="/static/posters/Chernobyl.webp" alt="Chernobyl">
|
||||
<p>Chernobyl</p>
|
||||
</div>
|
||||
<div class="poster-item">
|
||||
<section style="display: none;" id="tetris" >
|
||||
<h2>This game is</h2>
|
||||
</section>
|
||||
|
||||
<script src="/static/scripts/tetris.js"></script>
|
||||
|
||||
<p>Balders Gate</p>
|
||||
</div>
|
||||
<div class="poster-item">
|
||||
<p>Factorio</p>
|
||||
</div>
|
||||
<div class="poster-item">
|
||||
<p>Slay the spire 2</p>
|
||||
</div>
|
||||
<div class="game-item">
|
||||
<img src="/static/posters/risetr-banner.png" alt="Rise of the Tomb Raider">
|
||||
<p>Rise of the Tomb Raider</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>-->
|
||||
</div>
|
||||
|
||||
|
||||
@@ -290,116 +308,6 @@ My system is based on Arch Linux or Manjaro Linux, which are versions of Linux t
|
||||
<div class="footer-copy">© 2026 — all rights reserved</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
// just some fun.
|
||||
console.log("%c👀 hi there!", "font-size:20px")
|
||||
|
||||
|
||||
function draculaClick() {
|
||||
const el = document.getElementById('interest');
|
||||
if (!el) return; // el is a DOM node, never a string
|
||||
el.textContent = '🦇 interest 🦇';
|
||||
|
||||
setTimeout(() => {
|
||||
el.textContent = "interest";
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function bladerunnerClick() {
|
||||
if (document.getElementById('rain-canvas')) return; // already running, do nothing
|
||||
|
||||
const el = document.getElementById('interest');
|
||||
el.textContent = 'tears in rain';
|
||||
|
||||
startRain();
|
||||
|
||||
setTimeout(() => {
|
||||
el.textContent = "interest";
|
||||
stopRain();
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
let rainCanvas, rainCtx, rainInterval;
|
||||
|
||||
function startRain() {
|
||||
rainCanvas = document.createElement('canvas');
|
||||
rainCanvas.id = 'rain-canvas';
|
||||
rainCanvas.width = window.innerWidth;
|
||||
rainCanvas.height = window.innerHeight;
|
||||
document.body.appendChild(rainCanvas);
|
||||
rainCtx = rainCanvas.getContext('2d');
|
||||
|
||||
requestAnimationFrame(() => { rainCanvas.style.opacity = '1'; });
|
||||
|
||||
const drops = Array.from({ length: 120 }, () => ({
|
||||
x: Math.random() * rainCanvas.width,
|
||||
y: Math.random() * rainCanvas.height,
|
||||
speed: 8 + Math.random() * 7,
|
||||
length: 12 + Math.random() * 20,
|
||||
opacity: 0.2 + Math.random() * 0.4
|
||||
}));
|
||||
|
||||
rainInterval = setInterval(() => {
|
||||
rainCtx.clearRect(0, 0, rainCanvas.width, rainCanvas.height);
|
||||
drops.forEach(drop => {
|
||||
rainCtx.beginPath();
|
||||
rainCtx.moveTo(drop.x, drop.y);
|
||||
rainCtx.lineTo(drop.x - 2, drop.y + drop.length);
|
||||
rainCtx.strokeStyle = `rgba(174, 214, 241, ${drop.opacity})`;
|
||||
rainCtx.lineWidth = 3;
|
||||
rainCtx.stroke();
|
||||
|
||||
drop.y += drop.speed;
|
||||
if (drop.y > rainCanvas.height) {
|
||||
drop.y = -drop.length;
|
||||
drop.x = Math.random() * rainCanvas.width;
|
||||
}
|
||||
});
|
||||
}, 30);
|
||||
}
|
||||
|
||||
function stopRain() {
|
||||
if (!rainCanvas) return;
|
||||
rainCanvas.style.opacity = '0';
|
||||
setTimeout(() => {
|
||||
clearInterval(rainInterval);
|
||||
rainCanvas.remove();
|
||||
rainCanvas = null;
|
||||
}, 800);
|
||||
}
|
||||
function dragonClick() {
|
||||
const existing = document.getElementById('dragon-grid');
|
||||
if (existing) { existing.remove(); return; }
|
||||
|
||||
const grid = document.createElement('canvas');
|
||||
grid.id = 'dragon-grid';
|
||||
grid.width = window.innerWidth;
|
||||
grid.height = window.innerHeight;
|
||||
grid.style.transition = 'opacity 1s ease';
|
||||
document.body.appendChild(grid);
|
||||
|
||||
const ctx = grid.getContext('2d');
|
||||
const img = new Image();
|
||||
img.src = '/static/images/dragon.png';
|
||||
|
||||
img.onload = () => {
|
||||
const size = 250;
|
||||
const cols = Math.ceil(grid.width / size);
|
||||
const rows = Math.ceil(grid.height / size);
|
||||
|
||||
for (let r = 0; r < rows; r++) {
|
||||
for (let c = 0; c < cols; c++) {
|
||||
ctx.drawImage(img, c * size, r * size, size, size);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
grid.style.opacity = '0';
|
||||
setTimeout(() => grid.remove(), 1000);
|
||||
}, 300);
|
||||
};
|
||||
}
|
||||
|
||||
</script>
|
||||
<script src="/static/about.js" ></script>
|
||||
</body>
|
||||
</html>
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
const toggle = document.getElementById('toggle');
|
||||
const track = document.getElementById('track');
|
||||
const knob = document.getElementById('knob');
|
||||
const rays = document.getElementById('rays');
|
||||
const stateLabel = document.getElementById('state-label');
|
||||
const themeRoot = document.getElementById('themeRoot');
|
||||
|
||||
let isDay = true;
|
||||
|
||||
const RAY_COUNT = 8;
|
||||
for (let i = 0; i < RAY_COUNT; i++) {
|
||||
const r = document.createElement('div');
|
||||
r.className = 'ray';
|
||||
r.style.transform = `rotate(${i * (360/RAY_COUNT)}deg)`;
|
||||
rays.appendChild(r);
|
||||
}
|
||||
|
||||
function applyState() {
|
||||
if (isDay) {
|
||||
track.className = 'track day';
|
||||
knob.className = 'knob day';
|
||||
toggle.setAttribute('aria-checked', 'true');
|
||||
themeRoot.classList.remove('night');
|
||||
} else {
|
||||
track.className = 'track night';
|
||||
knob.className = 'knob night';
|
||||
toggle.setAttribute('aria-checked', 'false');
|
||||
themeRoot.classList.add('night');
|
||||
}
|
||||
}
|
||||
|
||||
toggle.addEventListener('click', () => { isDay = !isDay; applyState(); });
|
||||
toggle.addEventListener('keydown', e => {
|
||||
if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); isDay = !isDay; applyState(); }
|
||||
});
|
||||
|
||||
function copyClass() {
|
||||
navigator.clipboard.writeText(classOut.textContent).catch(() => {});
|
||||
}
|
||||
// just some fun.
|
||||
console.log("%c👀 hi there!", "font-size:20px")
|
||||
|
||||
|
||||
function draculaClick() {
|
||||
const el = document.getElementById('interest');
|
||||
if (!el) return; // el is a DOM node, never a string
|
||||
el.textContent = '🦇 interest 🦇';
|
||||
|
||||
setTimeout(() => {
|
||||
el.textContent = "interest";
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
|
||||
function matrixClick() {
|
||||
const sub = document.getElementById('interest-sub');
|
||||
const col = sub.color
|
||||
sub.textContent = `Do not try and bend the spoon. That's impossible. Instead... only try to realize the truth.`
|
||||
|
||||
sub.style.color = "green"
|
||||
setTimeout(() => {
|
||||
sub.textContent = "Fav lists"
|
||||
sub.style.color = "#6b6560"
|
||||
}, 15000);
|
||||
}
|
||||
|
||||
|
||||
function bladerunnerClick() {
|
||||
if (document.getElementById('rain-canvas')) return; // already running, do nothing
|
||||
|
||||
const el = document.getElementById('interest');
|
||||
el.textContent = 'tears in rain';
|
||||
|
||||
startRain();
|
||||
|
||||
setTimeout(() => {
|
||||
el.textContent = "interest";
|
||||
stopRain();
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
let rainCanvas, rainCtx, rainInterval;
|
||||
|
||||
function startRain() {
|
||||
rainCanvas = document.createElement('canvas');
|
||||
rainCanvas.id = 'rain-canvas';
|
||||
rainCanvas.width = window.innerWidth;
|
||||
rainCanvas.height = window.innerHeight;
|
||||
document.body.appendChild(rainCanvas);
|
||||
rainCtx = rainCanvas.getContext('2d');
|
||||
|
||||
requestAnimationFrame(() => { rainCanvas.style.opacity = '1'; });
|
||||
|
||||
const drops = Array.from({ length: 120 }, () => ({
|
||||
x: Math.random() * rainCanvas.width,
|
||||
y: Math.random() * rainCanvas.height,
|
||||
speed: 8 + Math.random() * 7,
|
||||
length: 12 + Math.random() * 20,
|
||||
opacity: 0.2 + Math.random() * 0.4
|
||||
}));
|
||||
|
||||
rainInterval = setInterval(() => {
|
||||
rainCtx.clearRect(0, 0, rainCanvas.width, rainCanvas.height);
|
||||
drops.forEach(drop => {
|
||||
rainCtx.beginPath();
|
||||
rainCtx.moveTo(drop.x, drop.y);
|
||||
rainCtx.lineTo(drop.x - 2, drop.y + drop.length);
|
||||
rainCtx.strokeStyle = `rgba(174, 214, 241, ${drop.opacity})`;
|
||||
rainCtx.lineWidth = 3;
|
||||
rainCtx.stroke();
|
||||
|
||||
drop.y += drop.speed;
|
||||
if (drop.y > rainCanvas.height) {
|
||||
drop.y = -drop.length;
|
||||
drop.x = Math.random() * rainCanvas.width;
|
||||
}
|
||||
});
|
||||
}, 30);
|
||||
}
|
||||
|
||||
function stopRain() {
|
||||
if (!rainCanvas) return;
|
||||
rainCanvas.style.opacity = '0';
|
||||
setTimeout(() => {
|
||||
clearInterval(rainInterval);
|
||||
rainCanvas.remove();
|
||||
rainCanvas = null;
|
||||
}, 800);
|
||||
}
|
||||
|
||||
function unhideGame() {
|
||||
const alicegameSection = document.getElementById('alice');
|
||||
const gameSection = document.getElementById('tetris');
|
||||
if (alicegameSection.style.display == 'none') {
|
||||
alicegameSection.style.display = 'block';
|
||||
} else {
|
||||
alicegameSection.style.display = 'none';
|
||||
}
|
||||
gameSection.style.display = 'none';
|
||||
|
||||
}
|
||||
|
||||
function unhideTetris() {
|
||||
const alicegameSection = document.getElementById('alice');
|
||||
const gameSection = document.getElementById('tetris');
|
||||
if (gameSection.style.display == 'none') {
|
||||
gameSection.style.display = 'block';
|
||||
} else {
|
||||
gameSection.style.display = 'none';
|
||||
}
|
||||
alicegameSection.style.display = 'none';
|
||||
}
|
||||
function dragonClick() {
|
||||
const existing = document.getElementById('dragon-grid');
|
||||
if (existing) { existing.remove(); return; }
|
||||
|
||||
const grid = document.createElement('canvas');
|
||||
grid.id = 'dragon-grid';
|
||||
grid.width = window.innerWidth;
|
||||
grid.height = window.innerHeight;
|
||||
grid.style.transition = 'opacity 1s ease';
|
||||
document.body.appendChild(grid);
|
||||
|
||||
const ctx = grid.getContext('2d');
|
||||
const img = new Image();
|
||||
img.src = '/static/images/dragon.png';
|
||||
|
||||
img.onload = () => {
|
||||
const size = 250;
|
||||
const cols = Math.ceil(grid.width / size);
|
||||
const rows = Math.ceil(grid.height / size);
|
||||
|
||||
for (let r = 0; r < rows; r++) {
|
||||
for (let c = 0; c < cols; c++) {
|
||||
ctx.drawImage(img, c * size, r * size, size, size);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
grid.style.opacity = '0';
|
||||
setTimeout(() => grid.remove(), 1000);
|
||||
}, 300);
|
||||
};
|
||||
}
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@300;400;500&family=Syne:wght@400;700;800&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="stylesheet" href="/static/styles.css" />
|
||||
<link rel="stylesheet" href="/static/style/styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container--narrow">
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@300;400;500&family=Syne:wght@400;700;800&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="stylesheet" href="/static/styles.css" />
|
||||
<link rel="stylesheet" href="/static/style/styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container--narrow">
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
<title>FP&A Budgeting Engine — Samantha Vero Friis</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@300;400;500&family=Libre+Caslon+Text:wght@400;700;800&family=Syne:wght@400;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/static/styles.css" />
|
||||
<link rel="stylesheet" href="/static/style/styles.css" />
|
||||
<style>
|
||||
/* ── Page-specific layout ── */
|
||||
header { padding: 2.4rem 0 2rem; }
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@300;400;500&family=Syne:wght@400;700;800&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="stylesheet" href="/static/styles.css" />
|
||||
<link rel="stylesheet" href="/static/style/styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container--narrow">
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 9.0 KiB |
+1
-1
@@ -8,7 +8,7 @@
|
||||
href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@300;400;500&family=Syne:wght@400;700;800&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="stylesheet" href="/static/styles.css"/>
|
||||
<link rel="stylesheet" href="/static/style/styles.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 624 KiB |
@@ -0,0 +1,77 @@
|
||||
const nodes = {
|
||||
start: {
|
||||
text: `Voice: Wake up alice! they are coming. you need to find your way out NOW please...
|
||||
You find yourself on a little cute bed, you see out of the window into the fog, you turn to see whom is speaking to only find a door.`,
|
||||
choices: [
|
||||
{ idx: 'A', text: 'You silently walk up to the door.', next: 'door' },
|
||||
{ idx: 'B', text: 'Poke your head out of the window to see what\'s there.', next: 'window' },
|
||||
{ idx: 'C', text: 'In a panic you hide under the bed', next: 'bed' },
|
||||
]
|
||||
},
|
||||
door: {
|
||||
text: `You press your ear against the wood. Silence. Then — footsteps, slow and deliberate, getting closer from the other side.`,
|
||||
choices: [
|
||||
{ idx: 'A', text: 'Open the door.', next: 'door' },
|
||||
{ idx: 'B', text: 'Step back and hide under the bed.', next: 'bed' },
|
||||
{ idx: 'C', text: 'Go to the window now', next: 'highrise' },
|
||||
]
|
||||
},
|
||||
window: {
|
||||
text: `The fog shifts. Below you, shapes move through it — too tall, too still. One of them looks up.`,
|
||||
choices: [
|
||||
{ idx: 'A', text: 'Duck back inside immediately.', next: 'start' },
|
||||
{ idx: 'B', text: 'Keep watching. You need to know what they are.', next: 'highrise' },
|
||||
]
|
||||
},
|
||||
bed: {
|
||||
text: `you feel silent and place your ear against the floor listen to noice below. A deep voice you seem to reconise talk, you cant make it out. You turn your head to use the other ear, you see a old book in the corner.`,
|
||||
choices: [
|
||||
{ idx: 'A', text: 'Pickup the book', next: 'book'},
|
||||
{ idx: 'B', text: 'wait, consentrait to listend closely to the words.', next: 'start' },
|
||||
{ idx: 'C', text: 'go to the window and see ', next: 'window' },
|
||||
{ idx: 'D', text: 'leave to walk to the door', next: 'door' },
|
||||
]
|
||||
},
|
||||
book: {
|
||||
text: `The book is old and dusty as one may expect, but underneath that. A rare bueaty you have never seen before.`,
|
||||
choices: [
|
||||
{ idx: 'A', text: 'go to the window and see ', next: 'window' },
|
||||
{ idx: 'B', text: 'leave to walk to the door', next: 'door' },
|
||||
]
|
||||
},
|
||||
wait: {
|
||||
text: `You hear the man say: "she is mine to keep" unsure of the meaning of this. You quickly find yourself exposed to the room to choice a path. `,
|
||||
choices: [
|
||||
{ idx: 'A', text: 'go to the window and see ', next: 'window' },
|
||||
{ idx: 'B', text: 'leave to walk to the door', next: 'door' },
|
||||
]
|
||||
},
|
||||
highrise: {
|
||||
text: `your eyes get in focus and see stears below, you find yourself on a highrise building. two people a talking on the ground below.`,
|
||||
choices: [
|
||||
{idx: 'A', text: 'walk out to small staers balcany', next: 'window'},
|
||||
{idx: 'B', text: 'Go back to the door', next: 'window'}
|
||||
]
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function goTo(nodeId) {
|
||||
const node = nodes[nodeId];
|
||||
if (!node) return;
|
||||
|
||||
document.getElementById('story-text').innerText = node.text;
|
||||
|
||||
const choicesEl = document.getElementById('choices');
|
||||
choicesEl.innerHTML = '';
|
||||
|
||||
node.choices.forEach(c => {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'choice-btn';
|
||||
btn.innerHTML = `<span class="idx">${c.idx}</span><span>${c.text}</span>`;
|
||||
btn.onclick = () => goTo(c.next);
|
||||
choicesEl.appendChild(btn);
|
||||
});
|
||||
}
|
||||
|
||||
goTo('start');
|
||||
@@ -0,0 +1,57 @@
|
||||
.play {
|
||||
padding: 2rem 0;
|
||||
}
|
||||
|
||||
.play .section-head h2 {
|
||||
font-family: var(--ff-mono);
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--muted);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.play .story-text {
|
||||
font-family: var(--ff-mono);
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.9;
|
||||
color: var(--fg);
|
||||
max-width: 560px;
|
||||
margin-bottom: 2rem;
|
||||
white-space: pre-wrap;
|
||||
border: 1px solid rgb(167, 205, 250);
|
||||
border-radius: 10px;
|
||||
padding: 1rem 1.25rem;
|
||||
}
|
||||
|
||||
.play .choices {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.6rem;
|
||||
max-width: 560px;
|
||||
}
|
||||
|
||||
.play .choices a,
|
||||
.play .choices button {
|
||||
font-family: var(--ff-mono);
|
||||
font-size: 0.8rem;
|
||||
color: var(--muted);
|
||||
background: none;
|
||||
border: none;
|
||||
border-left: 1px solid var(--muted);
|
||||
padding: 0.3rem 0.75rem;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
transition: color 0.15s, border-color 0.15s;
|
||||
}
|
||||
|
||||
.play .choices a:hover,
|
||||
.play .choices button:hover {
|
||||
color: var(--fg);
|
||||
border-color: var(--fg);
|
||||
}
|
||||
.idx {
|
||||
color: blueviolet;
|
||||
padding: 10px;
|
||||
}
|
||||
@@ -1,19 +1,37 @@
|
||||
:root{
|
||||
--bg:#f7f6f3;
|
||||
--surface:#ffffff;
|
||||
--surface2:#f0eeea;
|
||||
--border:#e2ddd6;
|
||||
--border2:#ccc7be;
|
||||
--text:#1a1917;
|
||||
--muted:#6b6560;
|
||||
--dim:#b0aa9f;
|
||||
--accent:#1a56db;
|
||||
.theme-root.night {
|
||||
--bg: #2d2d2d;
|
||||
--surface: #363636;
|
||||
--surface2: #2a2a2a;
|
||||
--border: #555555;
|
||||
--border2: #ccc7be;
|
||||
--text: #ffffff;
|
||||
--muted: #d9d9d9;
|
||||
--dim: #b0aa9f;
|
||||
--navback: rgb(63, 63, 63, 0.95);
|
||||
--accent: #5389ff;
|
||||
--accent2:#1447b8;
|
||||
--green:#0a7c52;
|
||||
--amber:#92620a;
|
||||
--ff-mono:'IBM Plex Mono',monospace;
|
||||
--ff-sans:'IBM Plex Sans',sans-serif;
|
||||
--green:#0eaf74;
|
||||
--amber:#ffd78e;
|
||||
}
|
||||
|
||||
.theme-root {
|
||||
--bg:#f7f6f3;
|
||||
--surface:#ffffff;
|
||||
--surface2:#f0eeea;
|
||||
--border:#e2ddd6;
|
||||
--border2:#ccc7be;
|
||||
--text:#1a1917;
|
||||
--muted:#6b6560;
|
||||
--dim:#b0aa9f;
|
||||
--accent:#1a56db;
|
||||
--accent2:#1447b8;
|
||||
--green:#0a7c52;
|
||||
--amber:#92620a;
|
||||
--navback: rgba(247,246,243,0.95)
|
||||
--ff-mono:'IBM Plex Mono',monospace;
|
||||
--ff-sans:'IBM Plex Sans',sans-serif;
|
||||
}
|
||||
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
html{font-size:15px;scroll-behavior:smooth;}
|
||||
body{
|
||||
@@ -37,7 +55,7 @@ body::before{
|
||||
|
||||
nav{
|
||||
position:sticky;top:0;z-index:100;
|
||||
background:rgba(247,246,243,0.94);
|
||||
background: var(--navback);
|
||||
backdrop-filter:blur(10px);
|
||||
border-bottom:1px solid var(--border);
|
||||
padding:0 clamp(1rem,5vw,3rem);
|
||||
@@ -58,7 +76,7 @@ nav{
|
||||
transition:color 0.15s,background 0.15s;
|
||||
}
|
||||
.nav-links a:hover{color:var(--text);background:var(--surface2);}
|
||||
.nav-links .cta{color:var(--accent);border:1px solid var(--accent2);margin-left:0.4rem;}
|
||||
.nav-links .cta{color:var(--accent);border:1px solid var(--accent);margin-left:0.4rem;}
|
||||
.nav-links .cta:hover{background:var(--accent2);color:#fff;}
|
||||
|
||||
.shell{
|
||||
@@ -72,17 +90,18 @@ nav{
|
||||
|
||||
|
||||
.sidebar-links a.hidden {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.4s linear;
|
||||
}
|
||||
|
||||
.sidebar-links:hover a.hidden {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
aside{
|
||||
border-right:1px solid var(--border);
|
||||
padding:2.5rem 1.5rem;
|
||||
display:flex;flex-direction:column;gap:2.5rem;
|
||||
display:flex;flex-direction:column;gap:1rem;
|
||||
position:sticky;top:52px;height:calc(100vh - 52px);
|
||||
overflow-y:auto;
|
||||
background:var(--surface);
|
||||
@@ -251,8 +270,8 @@ footer{
|
||||
}
|
||||
|
||||
.tag-dropped {
|
||||
background: #F0EBE4;
|
||||
color: #8A5C2E;
|
||||
background: var(--surface2);
|
||||
color: var(--amber);
|
||||
}
|
||||
|
||||
|
||||
@@ -389,20 +408,6 @@ footer{
|
||||
opacity: 0.15;
|
||||
}
|
||||
|
||||
.rice-wrap {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.rice-wrap img {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.rice-wrap .exp-body {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
|
||||
.outlink {font-family:var(--ff-mono);font-size:0.78rem;color:var(--accent);text-decoration:none;}
|
||||
.outlink:hover{text-decoration:underline;}
|
||||
@@ -413,3 +418,161 @@ a{
|
||||
transition:color 0.15s,background 0.15s;
|
||||
display:flex;align-items:center;gap:6px;
|
||||
}
|
||||
|
||||
|
||||
.rabbit-svg path { fill: gray; transition: fill 0.3s ease; }
|
||||
.rabbit-svg:hover path { fill: #7F77DD; }
|
||||
|
||||
|
||||
|
||||
|
||||
.scene {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2rem 1rem;
|
||||
gap: 1rem;
|
||||
font-family: var(--font-sans);
|
||||
}
|
||||
.toggle-wrap {
|
||||
position: relative;
|
||||
width: 50px;
|
||||
height: 25px;
|
||||
cursor: pointer;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.track {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 50px;
|
||||
height: 25px;
|
||||
border-radius: 12.5px;
|
||||
transition: background 0.5s ease;
|
||||
overflow: hidden;
|
||||
}
|
||||
.track.day { background: #87CEEB; }
|
||||
.track.night { background: #1a1a3e; }
|
||||
.stars {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
opacity: 0;
|
||||
transition: opacity 0.4s ease;
|
||||
}
|
||||
.night .stars { opacity: 1; }
|
||||
.star {
|
||||
position: absolute;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
animation: twinkle 2s infinite;
|
||||
}
|
||||
.star:nth-child(1) { width:2px; height:2px; top:4px; left:6px; animation-delay:0s; }
|
||||
.star:nth-child(2) { width:1px; height:1px; top:10px; left:14px; animation-delay:0.4s; }
|
||||
.star:nth-child(3) { width:1px; height:1px; top:5px; left:22px; animation-delay:0.8s; }
|
||||
.star:nth-child(4) { width:2px; height:2px; top:14px; left:10px; animation-delay:1.2s; }
|
||||
.star:nth-child(5) { width:1px; height:1px; top:8px; left:30px; animation-delay:0.2s; }
|
||||
@keyframes twinkle {
|
||||
0%,100% { opacity:1; } 50% { opacity:0.3; }
|
||||
}
|
||||
.knob {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
border-radius: 50%;
|
||||
transition: left 0.45s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.4s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2;
|
||||
}
|
||||
.knob.night {
|
||||
left: 3px;
|
||||
background: radial-gradient(circle at 35% 35%, #e8e8ff, #c8c8f8);
|
||||
box-shadow:
|
||||
0 0 0 2px rgba(180,180,255,0.18),
|
||||
0 0 7px 4px rgba(140,140,255,0.35),
|
||||
0 0 14px 6px rgba(100,100,220,0.18);
|
||||
}
|
||||
.knob.day {
|
||||
left: 28px;
|
||||
background: radial-gradient(circle at 40% 40%, #fff8c5, #FFD700);
|
||||
box-shadow:
|
||||
0 0 0 3px rgba(255,220,0,0.25),
|
||||
0 0 8px 4px rgba(255,200,0,0.45),
|
||||
0 0 16px 6px rgba(255,160,0,0.2);
|
||||
}
|
||||
.sun-rays {
|
||||
position: absolute;
|
||||
inset: -7px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease 0.15s;
|
||||
pointer-events: none;
|
||||
}
|
||||
.knob.day .sun-rays { opacity: 1; }
|
||||
.ray {
|
||||
position: absolute;
|
||||
width: 1.5px;
|
||||
height: 4px;
|
||||
background: rgba(255,220,0,0.9);
|
||||
border-radius: 1px;
|
||||
left: 50%;
|
||||
transform-origin: 50% 16px;
|
||||
margin-left: -0.75px;
|
||||
}
|
||||
.moon-crater {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
background: rgba(140,140,200,0.4);
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
.knob.day .moon-crater { opacity: 0; }
|
||||
.knob.night .moon-crater { opacity: 1; }
|
||||
.label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.03em;
|
||||
transition: color 0.4s ease;
|
||||
user-select: none;
|
||||
}
|
||||
.label.day-label { color: #B8860B; }
|
||||
.label.night-label { color: #9090d0; }
|
||||
.state-label {
|
||||
font-size: 11px;
|
||||
color: var(--color-text-secondary);
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.copy-block {
|
||||
background: var(--color-background-secondary);
|
||||
border: 0.5px solid var(--color-border-tertiary);
|
||||
border-radius: var(--border-radius-lg);
|
||||
padding: 1rem 1.25rem;
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
}
|
||||
.copy-block p { margin: 0 0 8px; font-size: 13px; color: var(--color-text-secondary); }
|
||||
.copy-block code {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 12px;
|
||||
color: var(--color-text-primary);
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.copy-btn {
|
||||
margin-top: 10px;
|
||||
font-size: 12px;
|
||||
padding: 4px 10px;
|
||||
border-radius: var(--border-radius-md);
|
||||
cursor: pointer;
|
||||
border: 0.5px solid var(--color-border-secondary);
|
||||
background: transparent;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
.copy-btn:hover { background: var(--color-background-secondary); }
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user