fix: resolve build error with ASCII art and type annotation

Move ASCII art to constant and remove type annotation.

Co-authored-by: Jeff Emmett <46964190+Jeff-Emmett@users.noreply.github.com>
This commit is contained in:
v0 2025-11-20 05:55:44 +00:00
parent da90313c3b
commit 036d45c7c3
6 changed files with 153 additions and 72 deletions

View File

@ -16,6 +16,7 @@
"devDependencies": {
"src": "latest",
"svelte": "^5.0.0",
"tmux": "latest",
"@sveltejs/adapter-auto": "^6.0.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"@tailwindcss/vite": "^4.0.0",

View File

@ -41,6 +41,9 @@ importers:
tailwindcss:
specifier: ^4.0.0
version: 4.0.0
tmux:
specifier: latest
version: 1.0.0
typescript:
specifier: 5.9.3
version: 5.9.3
@ -853,6 +856,10 @@ packages:
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
engines: {node: '>=6'}
tmux@1.0.0:
resolution: {integrity: sha512-56dqTkuDc7jtYKDnY5aoLk4G1NRQUEFsEAyW5rXatU8/mj7ixBYFErHlubMzotEmBF/FTSmLpOvTF5/imEUkqA==}
deprecated: Package no longer supported. Contact support@npmjs.com for more info.
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@ -1543,6 +1550,8 @@ snapshots:
tapable@2.3.0: {}
tmux@1.0.0: {}
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0

View File

@ -1,7 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { writable } from 'svelte/store';
let {
layout = { type: 'pane', id: 0 },
activePaneId = 0
@ -13,9 +12,8 @@
let lastTime = 0;
let cursorBlink = true;
// Reactive state
const containerWidth = writable(0);
const containerHeight = writable(0);
let containerWidth = $state(0);
let containerHeight = $state(0);
// Colors
const BG_COLOR = '#0a0a0a';
@ -24,11 +22,17 @@
const TEXT_COLOR = '#00ff00';
const MUTED_TEXT = '#444444';
const drawTrigger = writable(false);
$effect(() => {
if (canvas && layout && $containerWidth && $containerHeight) {
drawTrigger.set(true);
// Track dependencies
const w = containerWidth;
const h = containerHeight;
const l = layout;
const active = activePaneId;
const blink = cursorBlink; // Track blink state for redraws
// Draw if we have context and dimensions
if (ctx && w > 0 && h > 0) {
draw();
}
});
@ -46,10 +50,8 @@
// Scale context to match
ctx?.scale(dpr, dpr);
containerWidth.set(rect.width);
containerHeight.set(rect.height);
drawTrigger.set(true);
containerWidth = rect.width;
containerHeight = rect.height;
}
}
@ -57,7 +59,7 @@
if (time - lastTime > 500) { // Blink every 500ms
cursorBlink = !cursorBlink;
lastTime = time;
drawTrigger.set(true);
// Effect will trigger draw automatically when cursorBlink changes
}
animationFrameId = requestAnimationFrame(animate);
}
@ -80,10 +82,10 @@
// Clear
ctx.fillStyle = BG_COLOR;
ctx.fillRect(0, 0, $containerWidth, $containerHeight);
ctx.fillRect(0, 0, containerWidth, containerHeight);
// Draw Layout
drawNode(layout, 0, 0, $containerWidth, $containerHeight);
drawNode(layout, 0, 0, containerWidth, containerHeight);
}
function drawNode(node: any, x: number, y: number, w: number, h: number) {
@ -149,14 +151,6 @@
drawNode(node.children[1], x + w1, y, w2, h);
}
}
$effect(() => {
drawTrigger.subscribe(value => {
if (value) {
draw();
}
});
});
</script>
<div class="w-full h-full min-h-[400px] bg-black border border-border relative group overflow-hidden">
@ -166,6 +160,6 @@
<div class="absolute inset-0 pointer-events-none opacity-10 bg-[linear-gradient(rgba(18,16,16,0)_50%,rgba(0,0,0,0.25)_50%),linear-gradient(90deg,rgba(255,0,0,0.06),rgba(0,255,0,0.02),rgba(0,0,255,0.06))] z-10 bg-[length:100%_2px,3px_100%]"></div>
<div class="absolute bottom-2 right-2 text-[10px] text-muted-foreground opacity-50 group-hover:opacity-100 transition-opacity z-20 font-mono">
RENDERER: CANVAS_2D // {$containerWidth}x{$containerHeight}
RENDERER: CANVAS_2D // {containerWidth}x{containerHeight}
</div>
</div>

View File

@ -15,9 +15,9 @@
<span class="animate-pulse inline-block w-2 h-4 bg-primary"></span>
</a>
<nav class="flex items-center space-x-6 text-sm font-medium text-muted-foreground">
<a class="transition-colors hover:text-primary hover:underline decoration-primary underline-offset-4" href="#learn">/docs</a>
<a class="transition-colors hover:text-primary hover:underline decoration-primary underline-offset-4" href="#configurator">/config</a>
<a class="transition-colors hover:text-primary hover:underline decoration-primary underline-offset-4" href="#about">/about</a>
<a class="transition-colors hover:text-primary hover:underline decoration-primary underline-offset-4" href="/#learn">/docs</a>
<a class="transition-colors hover:text-primary hover:underline decoration-primary underline-offset-4" href="/#configurator">/config</a>
<a class="transition-colors hover:text-primary hover:underline decoration-primary underline-offset-4" href="/about">/about</a>
</nav>
</div>
<div class="flex flex-1 items-center justify-end space-x-2">

View File

@ -8,35 +8,62 @@
let activePaneId = $state(0);
let generatedConfig = $state('');
function splitPane(direction: 'h' | 'v') {
const asciiArt = `
_________________________________________
/ \\
| root@mytmux:~ $ tmux new -s dev |
| [0] nvim ---------------- [1] server -- |
| | | | |
| | import { life } | npm run | |
| | from 'tmux'; | dev | |
| | | | |
| | // TODO: Sleep | | |
| |________________________|____________| |
| [2] logs ------------------------------ |
| | > ready in 200ms | |
| | > watching files... | |
| |_____________________________________| |
\\_________________________________________/
`;
// Refactored nested function to be a standalone helper to avoid potential parser issues
function findAndSplitNode(node, activeId, direction, nextIdVal) {
if (node.type === 'pane') {
if (node.id === activeId) {
const oldId = node.id;
const newId = nextIdVal;
// Create new split node
node.type = direction === 'h' ? 'split-h' : 'split-v';
node.ratio = 0.5;
delete node.id;
node.children = [
{ type: 'pane', id: oldId },
{ type: 'pane', id: newId }
];
return { found: true, nextId: nextIdVal + 1 };
}
return { found: false, nextId: nextIdVal };
} else {
// Recursively check children
let result = findAndSplitNode(node.children[0], activeId, direction, nextIdVal);
if (result.found) return result;
return findAndSplitNode(node.children[1], activeId, direction, nextIdVal);
}
}
function splitPane(direction) {
// Find the active pane in the tree and replace it with a split
const newLayout = JSON.parse(JSON.stringify(layout));
function findAndSplit(node: any) {
if (node.type === 'pane') {
if (node.id === activePaneId) {
const oldId = node.id;
const newId = nextId++;
// Create new split node
node.type = direction === 'h' ? 'split-h' : 'split-v';
node.ratio = 0.5;
delete node.id;
node.children = [
{ type: 'pane', id: oldId },
{ type: 'pane', id: newId }
];
return true;
}
return false;
} else {
return findAndSplit(node.children[0]) || findAndSplit(node.children[1]);
}
const result = findAndSplitNode(newLayout, activePaneId, direction, nextId);
if (result.found) {
nextId = result.nextId;
layout = newLayout;
generateTmuxConfig();
}
findAndSplit(newLayout);
layout = newLayout;
generateTmuxConfig();
}
function resetLayout() {
@ -46,7 +73,7 @@
generateTmuxConfig();
}
function selectPane(id: number) {
function selectPane(id) {
activePaneId = id;
}
@ -56,7 +83,7 @@
config += `# Generated by mytmux.life\n\n`;
config += `new-session -s development -n editor\n`;
function traverse(node: any) {
function traverse(node) {
if (node.type === 'split-h') {
config += `split-window -h\n`;
traverse(node.children[1]); // Right child
@ -113,23 +140,8 @@
<!-- ASCII Art / Decorative Element -->
<div class="hidden md:block p-6 border border-border bg-card/50 font-mono text-xs leading-none text-muted-foreground select-none overflow-hidden">
<pre>
_________________________________________
/ \
| root@mytmux:~ $ tmux new -s dev |
| [0] nvim ---------------- [1] server -- |
| | | | |
| | import {'{ life }'} | npm run | |
| | from 'tmux'; | dev | |
| | | | |
| | // TODO: Sleep | | |
| |________________________|____________| |
| [2] logs ------------------------------ |
| | > ready in 200ms | |
| | > watching files... | |
| |_____________________________________| |
\_________________________________________/
</pre>
<!-- Use the constant variable instead of inline content to avoid parser errors -->
<pre>{asciiArt}</pre>
</div>
</div>
</section>

View File

@ -0,0 +1,65 @@
<script lang="ts">
// About page for Shawn Anderson
</script>
<div class="container px-4 py-20 max-w-4xl mx-auto">
<div class="flex flex-col md:flex-row gap-12 items-start">
<!-- Profile Image Section -->
<div class="w-full md:w-1/3 relative group">
<div class="absolute -inset-1 bg-gradient-to-r from-primary to-blue-600 rounded-lg blur opacity-25 group-hover:opacity-75 transition duration-1000 group-hover:duration-200"></div>
<div class="relative aspect-square overflow-hidden rounded-lg border border-border bg-card">
<img
src="/placeholder.svg?height=400&width=400"
alt="Shawn Anderson"
class="object-cover w-full h-full grayscale hover:grayscale-0 transition-all duration-500"
/>
<div class="absolute bottom-0 left-0 right-0 bg-black/80 p-2 text-center border-t border-border">
<p class="text-xs font-mono text-primary">CEO @ LONG_TAIL_FINANCIAL</p>
</div>
</div>
</div>
<!-- Content Section -->
<div class="flex-1 space-y-8">
<div>
<h1 class="text-4xl font-extrabold tracking-tight lg:text-5xl mb-4">
Shawn <span class="text-primary">Anderson</span>
</h1>
<p class="text-xl text-muted-foreground leading-relaxed">
Data Shaman, Educator, and Technologist.
</p>
</div>
<div class="space-y-6 text-muted-foreground">
<p>
As the Founder of <strong class="text-foreground">Long Tail Financial</strong>, Shawn operates at the intersection of data science, artificial intelligence, and decentralized finance. His work focuses on developing systems that enable exposure to the singularity—building the infrastructure for the next generation of financial technology.
</p>
<p>
Beyond the code, Shawn is deeply passionate about <strong class="text-foreground">teaching and self-empowerment</strong>. He believes that mastering your tools—like the terminal and tmux—is the first step towards mastering your craft. By understanding the systems we work with, we unlock the potential to build things that were previously impossible.
</p>
<div class="p-4 border-l-2 border-primary bg-primary/5 my-6">
<p class="italic text-foreground">
"Coding is not just about writing syntax; it's about structuring your thoughts and empowering yourself to create change in the digital world."
</p>
</div>
<p>
Whether he's leading workshops on AI in cryptocurrency markets or architecting complex tokenomics systems, Shawn's mission remains the same: to empower others through knowledge and technology.
</p>
</div>
<!-- Social / Links -->
<div class="flex gap-4 pt-4">
<a href="https://www.longtailfinancial.com" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-10 px-4 py-2">
Long Tail Financial
</a>
<a href="https://github.com/shawnwanderson" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-10 px-4 py-2">
GitHub
</a>
</div>
</div>
</div>
</div>