Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 101 additions & 40 deletions src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@
--card: 220 22% 92%;
--card-foreground: 222.2 84% 4.9%;

--border: 266 85% 58%;
--border: 180 50% 35%;
--input: 214.3 31.8% 91.4%;

--primary: 266 85% 58%;
--primary: 175 50% 40%;
--primary-foreground: 210 40% 98%;

--secondary: 231 97% 72%;
--secondary: 180 30% 60%;
--secondary-foreground: 222.2 47.4% 11.2%;

--accent: 210 40% 96.1%;
Expand All @@ -34,95 +34,156 @@
--destructive: 0 72.2% 50.6%;
--destructive-foreground: 210 40% 98%;

--ring: 222.2 84% 4.9%;
--ring: 175 50% 40%;

--radius: 0.5rem;
}

.dark {
--background: 240 21% 15%;
--foreground: 210 40% 98%;
/* Deep warm black - immersive and easy on the eyes */
--background: 220 15% 4%;
--foreground: 220 12% 88%;

--muted: 217.2 32.6% 17.5%;
--muted-foreground: 227 35% 80%;
/* Elevated surfaces with clear hierarchy */
--muted: 220 12% 8%;
--muted-foreground: 220 10% 55%;

--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--popover: 220 15% 6%;
--popover-foreground: 220 12% 88%;

--card: 240 21% 12%;
--card-foreground: 210 40% 98%;
--card: 220 12% 7%;
--card-foreground: 220 12% 88%;

--border: 267 84% 81%;
--input: 217.2 32.6% 17.5%;
/* Teal/cyan accent - modern and calm */
--primary: 175 60% 45%;
--primary-foreground: 220 15% 4%;

--primary: 267 84% 81%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 180 25% 20%;
--secondary-foreground: 220 12% 88%;

--secondary: 232.2 97% 85%;
--secondary-foreground: 210 40% 98%;
--accent: 220 12% 10%;
--accent-foreground: 220 12% 88%;

--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
/* Subtle warm border */
--border: 220 10% 14%;
--input: 220 12% 10%;

--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--destructive: 0 60% 45%;
--destructive-foreground: 220 15% 90%;

--ring: 175 60% 45%;

--ring: 212.7 26.8% 83.9%;
/* Glow color for subtle effects */
--glow: 175 60% 45%;
}

/* Windows 2000 Theme */
.theme-win2000 {
--background: 210 11% 71%; /* Classic W2K gray background: HSL for #D4D0C8 */
--foreground: 0 0% 0%; /* Black text */
--background: 210 11% 71%;
--foreground: 0 0% 0%;

--card: 210 11% 78%; /* Slightly lighter gray for card backgrounds: HSL for #DFDCD5 */
--card: 210 11% 78%;
--card-foreground: 0 0% 0%;

--popover: 0 0% 100%; /* White popovers */
--popover: 0 0% 100%;
--popover-foreground: 0 0% 0%;

--primary: 220 60% 30%; /* Darker, desaturated blue for title bars, buttons: HSL for approx #243C78 */
--primary: 220 60% 30%;
--primary-foreground: 0 0% 100%;

--secondary: 210 10% 85%; /* Lighter gray for some elements: HSL for #D2D2D7 */
--secondary: 210 10% 85%;
--secondary-foreground: 0 0% 0%;

--muted: 210 10% 90%; /* Very light gray: HSL for #E1E1E6 */
--muted-foreground: 0 0% 25%; /* Darker gray text on muted: HSL for #404040 */
--muted: 210 10% 90%;
--muted-foreground: 0 0% 25%;

--accent: 210 15% 65%; /* A slightly different gray for accents: HSL for #989CA6 */
--accent: 210 15% 65%;
--accent-foreground: 0 0% 0%;

--destructive: 0 72.2% 50.6%;
--destructive-foreground: 0 0% 100%;

--border: 0 0% 50%; /* Gray borders: #808080 */
--input: 0 0% 100%; /* White input backgrounds */
--ring: 220 60% 50%; /* Focus ring, a slightly lighter version of primary: HSL for #4C68B9 */
--border: 0 0% 50%;
--input: 0 0% 100%;
--ring: 220 60% 50%;

--radius: 0.125rem; /* Very slight rounding, W2K was mostly sharp */
--radius: 0.125rem;
}

/* Apply base font to html for themes to inherit if not overridden by components */
html.theme-win2000 {
font-family: "Tahoma", "MS Sans Serif", Arial, Inter, sans-serif; /* Prioritize Tahoma/MS Sans Serif */
/* You can also add a W2K cursor here if you have one */
/* cursor: url('/cursors/win2000/arrow.cur'), auto; */
font-family: "Tahoma", "MS Sans Serif", Arial, Inter, sans-serif;
}
}

@layer base {
* {
@apply border-border;
}

html {
scroll-behavior: smooth;
}

body {
@apply bg-background text-foreground;
font-family: "Inter", sans-serif;
font-feature-settings: "cv02", "cv03", "cv04", "cv11";
}

/* Dark mode background - stars handled by StarField component */
.dark body {
position: relative;
overflow-x: hidden;
}
}

@layer components {
/* Subtle glow effect for primary interactive elements */
.glow-sm {
box-shadow: 0 0 10px -3px hsl(var(--glow) / 0.3);
}

.glow-md {
box-shadow: 0 0 20px -5px hsl(var(--glow) / 0.4);
}

/* Hover glow transition */
.hover-glow {
transition: box-shadow 0.2s ease-in-out;
}

.hover-glow:hover {
box-shadow: 0 0 15px -3px hsl(var(--glow) / 0.35);
}

/* Glass card effect - use sparingly */
.glass {
background: hsl(var(--card) / 0.6);
backdrop-filter: blur(8px);
border: 1px solid hsl(var(--border) / 0.5);
}

/* Gradient text for headings - optional flourish */
.gradient-text {
background: linear-gradient(
135deg,
hsl(var(--primary)) 0%,
hsl(180 40% 55%) 100%
);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
}

@layer utilities {
/* Smooth transitions for theme switching */
.theme-transition {
transition: background-color 0.3s ease,
color 0.3s ease,
border-color 0.3s ease,
box-shadow 0.3s ease;
}
}

.font-mono {
Expand Down
134 changes: 134 additions & 0 deletions src/lib/components/StarField.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<script lang="ts">
import { onMount, onDestroy } from 'svelte';

let canvas: HTMLCanvasElement;
let ctx: CanvasRenderingContext2D | null;
let animationId: number;
let mouseX = -1000;
let mouseY = -1000;

interface Star {
x: number;
y: number;
size: number;
brightness: number;
twinkleSpeed: number;
twinkleOffset: number;
layer: number; // 0 = bright, 1 = medium, 2 = dim
}

let stars: Star[] = [];
const connectionRadius = 150;
const starCount = 200;

function initStars() {
stars = [];
const width = window.innerWidth;
const height = window.innerHeight;

for (let i = 0; i < starCount; i++) {
// Distribute stars across layers
const layer = i < starCount * 0.2 ? 0 : i < starCount * 0.5 ? 1 : 2;

stars.push({
x: Math.random() * width,
y: Math.random() * height,
size: layer === 0 ? 1.5 : 1,
brightness: layer === 0 ? 0.9 : layer === 1 ? 0.6 : 0.35,
twinkleSpeed: 0.5 + Math.random() * 1.5,
twinkleOffset: Math.random() * Math.PI * 2,
layer
});
}
}

function getStarColor(layer: number, alpha: number): string {
// Teal-tinted colors matching the theme
if (layer === 0) return `hsla(180, 30%, 80%, ${alpha})`;
if (layer === 1) return `hsla(200, 20%, 60%, ${alpha})`;
return `hsla(220, 15%, 40%, ${alpha})`;
}

function draw(time: number) {
if (!ctx || !canvas) return;

ctx.clearRect(0, 0, canvas.width, canvas.height);

// Draw connection lines first (behind stars)
stars.forEach(star => {
const dx = mouseX - star.x;
const dy = mouseY - star.y;
const distance = Math.sqrt(dx * dx + dy * dy);

if (distance < connectionRadius) {
const opacity = (1 - distance / connectionRadius) * 0.3;
ctx!.beginPath();
ctx!.moveTo(mouseX, mouseY);
ctx!.lineTo(star.x, star.y);
ctx!.strokeStyle = `hsla(175, 60%, 45%, ${opacity})`;
ctx!.lineWidth = 0.7;
ctx!.stroke();
}
});

// Draw stars
stars.forEach(star => {
const twinkle = Math.sin(time * 0.001 * star.twinkleSpeed + star.twinkleOffset);
const alpha = star.brightness * (0.5 + twinkle * 0.5);

ctx!.beginPath();
ctx!.arc(star.x, star.y, star.size, 0, Math.PI * 2);
ctx!.fillStyle = getStarColor(star.layer, alpha);
ctx!.fill();
});

animationId = requestAnimationFrame(draw);
}

function handleMouseMove(e: MouseEvent) {
mouseX = e.clientX;
mouseY = e.clientY;
}

function handleMouseLeave() {
mouseX = -1000;
mouseY = -1000;
}

function handleResize() {
if (!canvas) return;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
initStars();
}

onMount(() => {
ctx = canvas.getContext('2d');
handleResize();

window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseleave', handleMouseLeave);
window.addEventListener('resize', handleResize);

animationId = requestAnimationFrame(draw);
});

onDestroy(() => {
if (animationId) cancelAnimationFrame(animationId);
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mouseleave', handleMouseLeave);
window.removeEventListener('resize', handleResize);
});
</script>

<canvas
bind:this={canvas}
class="fixed inset-0 pointer-events-none z-0"
aria-hidden="true"
></canvas>

<style>
canvas {
background: transparent;
}
</style>
2 changes: 2 additions & 0 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { Card, CardHeader, CardTitle, CardContent } from "$lib/components/ui/card/index.js";
import { flyAndScale } from "$lib/utils.js";
import { Terminal, UserCircle, ServerIcon, FolderGit2, ArrowRight, Gem } from "lucide-svelte";
import StarField from '$lib/components/StarField.svelte';

// Dashboard links remain the same as previous version
const dashboardLinks = [
Expand Down Expand Up @@ -54,6 +55,7 @@
}
</style>

<StarField />
<div class="w-full min-h-[calc(100vh-10rem)] flex flex-col items-center justify-center text-foreground p-4">
<div class="w-full max-w-5xl space-y-10 md:space-y-16" in:flyAndScale={{ y:0, duration:500, start:0.95}}>
<header class="text-center space-y-2">
Expand Down