Main pages

This commit is contained in:
2026-03-10 23:45:14 +01:00 Unverified
parent 2b4897ad65
commit b6a78abae8
17 changed files with 2244 additions and 116 deletions
+68
View File
@@ -0,0 +1,68 @@
// app/components/BlurredCode.tsx
'use client';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';
const pythonCode = `import quantum_entanglement
import neural_net_vibes
from cosmos import dark_matter
class HotdogAnalyzer(quantum_entanglement.Observer):
def __init__(self, mustard_ratio=0.8):
self.mustard_ratio = mustard_ratio
self.is_sandwich = None
self.__secret_sauce = "01101000 01101101 01101101"
async def _calculate_bun_topology(self, bread_manifold):
"""Uses string theory to determine if a bun is contiguous."""
try:
dimensions = await dark_matter.measure(bread_manifold)
if dimensions > 3:
raise Exception("Bun exists in the 4th dimension.")
return dimensions * self.mustard_ratio
except OverflowError:
return "Just eat it already"
@neural_net_vibes.optimize(epochs=42069)
def check_is_sandwich(self, hotdog):
if hotdog.is_taco():
self.is_sandwich = False
return self.is_sandwich
# Initiate brute-force topological check
for atom in hotdog.get_atoms():
if atom.vibe_check() == "sus":
hotdog.add_ketchup(override=True)
self.is_sandwich = True if hotdog.entropy < 9000 else False
return "Maybe?"
if __name__ == "__main__":
analyzer = HotdogAnalyzer(mustard_ratio=1.1)
analyzer.check_is_sandwich(target="glizzy")`;
export default function BlurredCode() {
return (
<div className="absolute inset-0 overflow-hidden bg-[#0d1117] z-0 pointer-events-none flex justify-center">
<div className="relative w-full h-full text-left p-8 opacity-40 blur-[2px] group-hover:blur-none group-hover:opacity-100 transition-all duration-700 animate-[scrollUp_40s_linear_infinite]">
<SyntaxHighlighter
language="python"
style={vscDarkPlus}
customStyle={{ background: 'transparent', margin: 0, padding: 0, fontSize: '14px' }}
>
{pythonCode + '\n\n\n' + pythonCode + '\n\n\n' + pythonCode}
</SyntaxHighlighter>
</div>
<style dangerouslySetInnerHTML={{
__html: `
@keyframes scrollUp {
0% { transform: translateY(0); }
100% { transform: translateY(-33.33%); }
}
`}} />
</div>
);
}
+89
View File
@@ -0,0 +1,89 @@
// app/components/MatrixRain.tsx
'use client';
import { useEffect, useRef } from 'react';
interface MatrixRainProps {
color?: string;
fps?: number;
}
export default function MatrixRain({ color = '#84c0a0', fps = 15 }: MatrixRainProps) {
const canvasRef = useRef<HTMLCanvasElement>(null);
const lastWidth = useRef<number>(0);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
if (!ctx) return;
let intervalId: NodeJS.Timeout;
const fontSize = 16;
let columns = 0;
let drops: number[] = [];
const setCanvasSize = () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight + 120;
ctx.fillStyle = '#0d1117';
ctx.fillRect(0, 0, canvas.width, canvas.height);
};
const initDrops = () => {
columns = Math.floor(canvas.width / fontSize);
drops = [];
for (let x = 0; x < columns; x++) {
drops[x] = Math.random() * -100;
}
};
lastWidth.current = window.innerWidth;
setCanvasSize();
initDrops();
const draw = () => {
ctx.fillStyle = 'rgba(13, 17, 23, 0.2)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.font = `bold ${fontSize}px monospace`;
for (let i = 0; i < drops.length; i++) {
const text = Math.random() > 0.5 ? '0' : '1';
ctx.fillStyle = color;
ctx.fillText(text, i * fontSize, drops[i] * fontSize);
if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {
drops[i] = 0;
}
drops[i]++;
}
};
intervalId = setInterval(draw, 1000 / fps);
const handleResize = () => {
if (window.innerWidth !== lastWidth.current) {
lastWidth.current = window.innerWidth;
setCanvasSize();
initDrops();
}
};
window.addEventListener('resize', handleResize);
return () => {
clearInterval(intervalId);
window.removeEventListener('resize', handleResize);
};
}, [color, fps]);
return (
<div className="fixed inset-0 pointer-events-none w-screen h-[110vh] bg-[#0d1117]" style={{ zIndex: -1 }}>
<canvas
ref={canvasRef}
className="absolute inset-0 w-full h-full opacity-[0.15] blur-[0.5px]"
/>
</div>
);
}
+68
View File
@@ -0,0 +1,68 @@
// app/components/Navbar.tsx
'use client';
import Link from 'next/link';
import { useState } from 'react';
export default function Navbar() {
const [isExpanded, setIsExpanded] = useState(false);
const toggleMenu = () => setIsExpanded(!isExpanded);
const closeMenu = () => setIsExpanded(false);
return (
<header className="fixed h-25 bg-[#0d1117]/80 backdrop-blur-md border-b border-white/10 left-0 right-0 z-100 transition-all duration-300">
<nav className="flex justify-between h-full items-center max-w-400 px-8 mx-auto">
<Link href="/" className="group text-white no-underline flex uppercase font-extrabold items-center tracking-[1px] transition-transform hover:scale-105" onClick={closeMenu}>
<div className="w-12 h-12 flex justify-center items-center rounded-full bg-[#84c0a0]/10 border border-[#84c0a0]/30 shadow-[0_0_15px_rgba(132,192,160,0.2)] group-hover:bg-[#84c0a0]/20 transition-all duration-300">
<img src="/assets/logos/logo.svg" alt="Wiking" className="w-8 h-8" />
</div>
<span className="hidden md:block ml-4 text-sm tracking-widest text-[#84c0a0] font-mono group-hover:text-white transition-colors">
SODERBERG TECH
</span>
</Link>
<button
type="button"
className="cursor-pointer border-none bg-transparent w-10 h-10 flex items-center justify-center flex-col md:hidden relative group"
aria-expanded={isExpanded}
onClick={toggleMenu}
>
<span className={`block h-0.5 bg-white transition-all duration-300 ease-in-out group-hover:bg-[#84c0a0] ${isExpanded ? 'absolute m-0 w-7 rotate-45' : 'w-6 m-0.75'}`}></span>
<span className={`block h-0.5 bg-white transition-all duration-300 ease-in-out group-hover:bg-[#84c0a0] ${isExpanded ? 'opacity-0 w-0' : 'w-6 m-0.75'}`}></span>
<span className={`block h-0.5 bg-white transition-all duration-300 ease-in-out group-hover:bg-[#84c0a0] ${isExpanded ? 'absolute m-0 w-7 -rotate-45' : 'w-6 m-0.75'}`}></span>
</button>
<div
className={`fixed top-25 bottom-0 left-0 right-0 transition-all duration-300 md:static md:block md:opacity-100 md:visible md:h-full ${isExpanded ? 'bg-[#0d1117]/60 backdrop-blur-sm opacity-100 visible' : 'opacity-0 invisible'}`}
onClick={closeMenu}
>
<ul
className={`list-none absolute flex flex-col items-center left-0 right-0 m-4 rounded-3xl bg-[#131920]/70 backdrop-blur-2xl md:backdrop-blur-none border border-white/10 shadow-2xl md:m-0 md:p-0 md:border-none md:shadow-none md:static md:flex-row md:w-full md:h-full md:bg-transparent md:justify-end gap-2 md:gap-8 transition-all duration-300 ${isExpanded ? 'p-8 translate-y-0 opacity-100' : '-translate-y-4 opacity-0 md:translate-y-0 md:opacity-100'}`}
onClick={(e) => e.stopPropagation()}
>
{[
{ name: 'Home', path: '/' },
{ name: 'Gallery', path: '/gallery' },
{ name: 'Projects', path: '/projects' },
{ name: 'Contact', path: '/contact' },
].map((link) => (
<li key={link.name} className="w-full md:w-auto">
<Link
className="relative flex justify-center items-center text-gray-300 uppercase font-bold tracking-[2px] text-sm px-4 py-3 rounded-xl hover:text-white hover:bg-white/5 transition-all duration-300 group overflow-hidden"
href={link.path}
onClick={closeMenu}
>
<span className="relative z-10">{link.name}</span>
<span className="absolute bottom-0 left-1/2 w-0 h-0.5 bg-[#84c0a0] transition-all duration-300 group-hover:w-1/2 group-hover:-translate-x-1/2 shadow-[0_0_10px_rgba(132,192,160,0.8)]"></span>
</Link>
</li>
))}
</ul>
</div>
</nav>
</header>
);
}
+64
View File
@@ -0,0 +1,64 @@
// app/components/PhotoGallery.tsx
'use client';
import { Gallery, Item } from 'react-photoswipe-gallery';
import 'photoswipe/dist/photoswipe.css';
import Image from 'next/image';
interface GalleryImage {
src: string;
width: number;
height: number;
name: string;
}
export default function PhotoGallery({ images }: { images: GalleryImage[] }) {
return (
<div className="bg-[#0a0d11] flex justify-center w-full min-h-screen border-t border-white/5">
<Gallery>
<div className="grid grid-cols-2 lg:grid-cols-4 2xl:grid-cols-6 grid-flow-dense w-full">
{images.map((img, index) => {
const isHorizontal = img.width > img.height;
return (
<div
key={index}
className={`relative bg-[#0d1117] overflow-hidden group cursor-pointer border-[0.5px] border-white/5 ${isHorizontal ? 'col-span-2' : 'col-span-1'}`}
>
<Item
original={img.src}
thumbnail={img.src}
width={img.width}
height={img.height}
alt={`Gallery image ${img.name}`}
>
{({ ref, open }) => (
<div
ref={ref as React.RefCallback<HTMLDivElement>}
onClick={open}
className="w-full h-full relative block min-h-75"
>
<div className="absolute inset-0 border-8 border-[#0d1117]/50 transition-all duration-300 z-10 pointer-events-none"></div>
<div className="absolute inset-4 border-2 border-white/10 transition-all duration-500 z-10 pointer-events-none group-hover:scale-95 group-hover:border-[#84c0a0]/60 [clip-path:polygon(0_calc(100%-1rem),0_100%,1rem_100%,1rem_0,0_0,0_1rem,100%_1rem,100%_0,calc(100%-1rem)_0,calc(100%-1rem)_100%,100%_100%,100%_calc(100%-1rem))]"></div>
<Image
src={img.src}
alt={`Photo of ${img.name.replace('.jpg', '')}`}
width={isHorizontal ? 1200 : 800}
height={isHorizontal ? 800 : 800}
quality={90}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
className="w-full h-full object-cover block opacity-80 transition-all duration-700 group-hover:scale-110 group-hover:opacity-100"
/>
</div>
)}
</Item>
</div>
);
})}
</div>
</Gallery>
</div>
);
}