diff --git a/src/lib/assets/css/terminal-tui.css b/src/lib/assets/css/terminal-tui.css
index e632d69..2ba5f65 100644
--- a/src/lib/assets/css/terminal-tui.css
+++ b/src/lib/assets/css/terminal-tui.css
@@ -7,10 +7,10 @@
position: relative;
display: flex;
flex-direction: column;
- width: 95%;
+ width: 100%;
margin: 0 auto;
- height: calc(100vh - var(--navbar-height) - 80px);
- max-height: calc(100vh - var(--navbar-height) - 80px);
+ height: calc(100vh - var(--navbar-height) - 65px);
+ max-height: calc(100vh - var(--navbar-height) - 65px);
animation: tuiFadeIn 0.4s ease-out;
}
diff --git a/src/lib/assets/css/tui-body.css b/src/lib/assets/css/tui-body.css
index 4ad4e24..d0cdce9 100644
--- a/src/lib/assets/css/tui-body.css
+++ b/src/lib/assets/css/tui-body.css
@@ -12,11 +12,23 @@
.tui-inline-group {
display: flex;
flex-wrap: wrap;
+ align-items: flex-start;
gap: 0.5rem;
margin-bottom: 0.2rem;
animation: lineSlideIn 0.15s ease-out;
}
+/* When inline group contains an image, allow text to wrap beside it */
+.tui-inline-group:has(.inline-image) {
+ flex-wrap: nowrap;
+ align-items: flex-start;
+}
+
+.tui-inline-group:has(.inline-image) .inline-content {
+ flex: 1;
+ min-width: 0;
+}
+
.inline-content {
display: inline;
white-space: pre-wrap;
@@ -179,6 +191,14 @@
padding: 0.5rem 0;
}
+/* Inline images */
+.tui-image.inline-image {
+ display: inline-flex;
+ padding: 0;
+ vertical-align: middle;
+ flex-shrink: 0;
+}
+
.tui-image img {
border-radius: 6px;
border: 1px solid var(--terminal-border);
diff --git a/src/lib/components/Background3D.svelte b/src/lib/components/Background3D.svelte
index 30dce5c..ad4ff49 100644
--- a/src/lib/components/Background3D.svelte
+++ b/src/lib/components/Background3D.svelte
@@ -3,10 +3,11 @@
import { T } from '@threlte/core';
import ParticleField from './ParticleField.svelte';
import { themeColors, mode } from '$lib/stores/theme';
- import * as THREE from 'three';
import '$lib/assets/css/background-3d.css';
- let bgColor = $derived($mode === 'dark' ? $themeColors.background : $themeColors.background);
+ // Reactive theme colors
+ const bgColor = $derived($themeColors.background);
+ const primaryColor = $derived($themeColors.primary);
@@ -26,7 +27,7 @@
diff --git a/src/lib/components/ParticleField.svelte b/src/lib/components/ParticleField.svelte
index 059f7a1..8cafb86 100644
--- a/src/lib/components/ParticleField.svelte
+++ b/src/lib/components/ParticleField.svelte
@@ -17,6 +17,14 @@
let velocities: Float32Array;
let time = 0;
+ // Reactive theme values - use accent or a darker color for light mode visibility
+ const currentMode = $derived($mode);
+ const particleColor = $derived(
+ currentMode === 'dark'
+ ? $themeColors.primary
+ : $themeColors.accent || $themeColors.primary
+ );
+
// Create particles
function createParticles() {
positions = new Float32Array(particleCount * 3);
@@ -40,10 +48,11 @@
particlesMaterial = new THREE.PointsMaterial({
size: 0.05,
+ color: new THREE.Color(particleColor),
sizeAttenuation: true,
transparent: true,
- opacity: 0.6,
- blending: THREE.AdditiveBlending,
+ opacity: currentMode === 'dark' ? 0.6 : 0.8,
+ blending: currentMode === 'dark' ? THREE.AdditiveBlending : THREE.NormalBlending,
depthWrite: false
});
@@ -54,12 +63,13 @@
createParticles();
});
- // Update particle color based on theme
+ // Update particle color and opacity based on theme
$effect(() => {
if (particlesMaterial) {
- const color = new THREE.Color($themeColors.primary);
- particlesMaterial.color = color;
- particlesMaterial.opacity = $mode === 'dark' ? 0.6 : 0.4;
+ particlesMaterial.color.set(particleColor);
+ particlesMaterial.opacity = currentMode === 'dark' ? 0.6 : 0.8;
+ particlesMaterial.blending = currentMode === 'dark' ? THREE.AdditiveBlending : THREE.NormalBlending;
+ particlesMaterial.needsUpdate = true;
}
});
diff --git a/src/lib/components/tui/TuiBody.svelte b/src/lib/components/tui/TuiBody.svelte
index 37728d7..ac71631 100644
--- a/src/lib/components/tui/TuiBody.svelte
+++ b/src/lib/components/tui/TuiBody.svelte
@@ -70,6 +70,7 @@
{@const line = displayed.parsed.line}
{@const idx = group.indices[j]}
{@const visibleSegments = getSegmentsUpToChar(displayed.parsed.segments, displayed.charIndex)}
+ {@const showImage = displayed.showImage}
{#if line.type === 'button'}
{:else if line.type === 'link'}
@@ -84,7 +85,14 @@
{:else if line.type === 'toggle'}
- {:else}
+ {:else if line.type === 'image' && showImage}
+
+

+ {#if line.content}
+
{line.content}
+ {/if}
+
+ {:else if line.type !== 'image'}
{getLinePrefix(line.type)}{#each visibleSegments as segment}{#if segment.icon}{:else if getSegmentStyle(segment)}{segment.text}{:else}{segment.text}{/if}{/each}
diff --git a/src/lib/keybinds.ts b/src/lib/keybinds.ts
index afd7b94..1d1471e 100644
--- a/src/lib/keybinds.ts
+++ b/src/lib/keybinds.ts
@@ -18,7 +18,7 @@ export function registerKeybinds(opts: KeybindsOptions) {
// alt/option + t: toggle mode (hold+digit to pick theme)
// keydown: start hold
- hotkeys('alt+t', (e) => {
+ hotkeys('alt+b', (e) => {
if (e.repeat) return;
tHeld = true;
tDigitUsed = false;
@@ -26,7 +26,7 @@ export function registerKeybinds(opts: KeybindsOptions) {
});
// macOS alias: option
- hotkeys('option+t', (e) => {
+ hotkeys('option+b', (e) => {
if (e.repeat) return;
tHeld = true;
tDigitUsed = false;
@@ -34,7 +34,7 @@ export function registerKeybinds(opts: KeybindsOptions) {
});
// keyup: toggle if no digit used
- hotkeys('alt+t', { keyup: true }, (e) => {
+ hotkeys('alt+b', { keyup: true }, (e) => {
if (!tDigitUsed && tHeld) {
const now = Date.now();
if (now - lastToggleAt > 400) {
@@ -47,7 +47,7 @@ export function registerKeybinds(opts: KeybindsOptions) {
e.preventDefault();
});
- hotkeys('option+t', { keyup: true }, (e) => {
+ hotkeys('option+b', { keyup: true }, (e) => {
if (!tDigitUsed && tHeld) {
const now = Date.now();
if (now - lastToggleAt > 400) {
@@ -99,8 +99,8 @@ export function registerKeybinds(opts: KeybindsOptions) {
export function unregisterKeybinds() {
// Unbind all key patterns we registered
- hotkeys.unbind('alt+t');
- hotkeys.unbind('option+t');
+ hotkeys.unbind('alt+b');
+ hotkeys.unbind('option+b');
const tThemeKeys = Array.from({ length: 9 }, (_, i) => `alt+t+${i + 1}`).join(',');
const tThemeKeysOption = Array.from({ length: 9 }, (_, i) => `option+t+${i + 1}`).join(',');
hotkeys.unbind(`${tThemeKeys},${tThemeKeysOption}`);
diff --git a/src/lib/pages/home.ts b/src/lib/pages/home.ts
index cff889b..e887964 100644
--- a/src/lib/pages/home.ts
+++ b/src/lib/pages/home.ts
@@ -15,7 +15,7 @@ export const lines: TerminalLine[] = [
{ type: 'blank', content: '' },
{ type: 'header', content: `Welcome to ${user.displayname}'s Portfolio` },
{ type: 'blank', content: '' },
- // { type: 'image', content: '', image: user.avatar, imageAlt: user.name, imageWidth: 120, inline: false },
+ { type: 'image', content: '', image: user.avatar, imageAlt: user.name, imageWidth: 120, inline: true },
{ type: 'output', content: `(&muted)${user.bio}(&)`, inline: true },
{ type: 'blank', content: '' },
@@ -34,9 +34,9 @@ export const lines: TerminalLine[] = [
{ type: 'blank', content: '' },
{ type: 'divider', content: 'Website Keybinds' },
{ type: 'blank', content: '' },
- { type: 'output', content: '(&orange)Toggle Light/Dark Mode(&) (&text, bold)(Alt/Option+T)(&)' , inline: true },
+ { type: 'output', content: '(&orange)Toggle Light/Dark Mode(&) (&text, bold)(Alt/Option+B)(&)' , inline: true },
{ type: 'output', content: '(&muted)•(&)' , inline: true },
- { type: 'output', content: '(&orange)Select Theme(&) (&text, bold)Use Alt/Option+T + [#](&)' , inline: true },
+ { type: 'output', content: '(&orange)Select Theme(&) (&text, bold)(Alt/Option+T + [#])(&)' , inline: true },
{ type: 'output', content: '(&muted)•(&)' , inline: true },
{ type: 'output', content: '(&orange)Skip typing animation(&) (&text, bold)(Y)(&)' , inline: true },
{ type: 'output', content: '(&muted)•(&)' , inline: true },
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index 0fe8d31..507d5ee 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -73,10 +73,10 @@
color: {$themeColors.text};
"
>
-
+
{@render children()}