Optimized images and linting

This commit is contained in:
2026-03-11 20:47:07 +01:00 Verified
parent 252790cfc2
commit 1cd07b9dd5
8 changed files with 65 additions and 32 deletions
+1 -2
View File
@@ -19,7 +19,6 @@ export default function MatrixRain({ color = '#84c0a0', fps = 15 }: MatrixRainPr
const ctx = canvas.getContext('2d');
if (!ctx) return;
let intervalId: NodeJS.Timeout;
const fontSize = 16;
let columns = 0;
let drops: number[] = [];
@@ -60,7 +59,7 @@ export default function MatrixRain({ color = '#84c0a0', fps = 15 }: MatrixRainPr
}
};
intervalId = setInterval(draw, 1000 / fps);
const intervalId = setInterval(draw, 1000 / fps);
const handleResize = () => {
if (window.innerWidth !== lastWidth.current) {
+8 -1
View File
@@ -4,6 +4,7 @@
import Link from 'next/link';
import { useState } from 'react';
import Image from 'next/image';
export default function Navbar() {
const [isExpanded, setIsExpanded] = useState(false);
@@ -17,7 +18,13 @@ export default function Navbar() {
<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" />
<Image
src="/assets/logos/logo.svg"
alt="Wiking"
width={32}
height={32}
className="w-8 h-8 filter dark:invert-0 invert"
/>
</div>
<span className="hidden md:block ml-4 text-sm tracking-widest text-[#84c0a0] font-mono group-hover:text-white transition-colors">
SODERBERG TECH
+4 -1
View File
@@ -1,15 +1,18 @@
// app/contact/page.tsx
import { FaInstagram, FaLinkedin, FaDiscord, FaEnvelope, FaMapMarkerAlt } from 'react-icons/fa';
import Image from 'next/image';
export default function ContactPage() {
return (
<main className="flex flex-col flex-1 relative bg-[#0d1117] overflow-hidden">
{/* 1. Immersive Mountain Background */}
<img
<Image
src="/assets/images/snowy_mountain_peaks.jpg"
alt="Snowy Mountains"
fill
priority
className="absolute inset-0 w-full h-full object-cover z-0"
/>
{/* Dark blur overlay so the text and cards remain perfectly readable */}
+9 -2
View File
@@ -2,10 +2,17 @@
import Navbar from './components/Navbar';
import './globals.css';
import Link from 'next/link';
export const metadata = {
title: 'Soderberg Tech',
description: 'William Söderberg, Technical high school engineer from Höganäs, Sweden',
icons: {
icon: '/assets/logos/logo.svg',
shortcut: '/assets/logos/logo.svg',
apple: '/assets/logos/logo.svg',
},
};
export default function RootLayout({
@@ -24,9 +31,9 @@ export default function RootLayout({
<footer className="w-full relative z-50 mt-auto border-t border-white/5">
<div className="bg-[#0d1117] flex justify-center items-center h-10">
<a className="text-[#a0aab6] no-underline flex font-medium items-center hover:text-white transition-colors text-sm tracking-widest uppercase" href="/">
<Link className="text-[#a0aab6] no-underline flex font-medium items-center hover:text-white transition-colors text-sm tracking-widest uppercase" href="/">
© William Söderberg {new Date().getFullYear()}
</a>
</Link>
</div>
</footer>
</body>
+15 -13
View File
@@ -2,11 +2,10 @@
'use client';
import React from 'react';
import Link from 'next/link';
import MatrixRain from '@/app/components/MatrixRain';
import { FaInstagram, FaLinkedin, FaDiscord, FaEnvelope, FaCamera, FaVolleyballBall, FaTree, FaCode } from 'react-icons/fa';
import { FaCamera, FaCode, FaTree, FaVolleyballBall } from 'react-icons/fa';
import { TbCube3dSphere } from 'react-icons/tb';
import Image from 'next/image';
export default function Home() {
@@ -35,7 +34,7 @@ export default function Home() {
<div className="relative z-10 flex flex-col items-center px-4">
<div className="bg-[#84c0a0] rounded-full h-45 w-45 md:h-55 md:w-55 flex justify-center items-center shadow-[0_0_50px_rgba(132,192,160,0.3)] animate-[zoomIn_1000ms_ease-out]">
<img src="/assets/logos/logo.svg" alt="Logo" className="h-[60%]" />
<Image src="/assets/logos/logo.svg" alt="Logo" width={130} height={130} className="w-[60%] h-[60%]" />
</div>
<h2 className="text-[#84c0a0] font-mono font-bold tracking-[0.3em] uppercase mt-12 text-sm md:text-xl text-center">
@@ -69,9 +68,11 @@ export default function Home() {
{/* Left Column: Profile with "Scanning" Effect */}
<div className="lg:w-2/5 relative group border-b lg:border-b-0 lg:border-r border-white/10">
<img
<Image
src="/assets/images/profile_picture.jpg"
alt="William Söderberg"
width={800}
height={1000}
className="w-full h-full object-cover"
/>
<div className="absolute inset-0 bg-linear-to-t from-[#0d1117] via-transparent to-transparent opacity-60"></div>
@@ -88,7 +89,7 @@ export default function Home() {
<h2 className="text-white text-3xl font-bold uppercase tracking-widest">DATA CARD</h2>
</div>
<p className="text-gray-300 text-lg leading-relaxed font-light">
My name is William Söderberg and I'm {calculateAge("2002-07-17")} years old. I have a degree in technical high school engineering specialized in design and industrial manufacturing, with heavy influence from IT and coding. I love problem solving and finding new ways to solve the most complicated problems.
My name is William Söderberg and I&apos;m {calculateAge("2002-07-17")} years old. I have a degree in technical high school engineering specialized in design and industrial manufacturing, with heavy influence from IT and coding. I love problem solving and finding new ways to solve the most complicated problems.
</p>
<div className="mt-10 grid grid-cols-2 gap-6 border-t border-white/10 pt-10">
<div>
@@ -108,7 +109,7 @@ export default function Home() {
{/* 3. WHAT DO I DO SECTION */}
<section className="relative py-24 px-6 overflow-hidden">
{/* Subtle Background Image Integration */}
<img src="/assets/images/leaves.jpg" alt="Leaves" className="absolute inset-0 w-full h-full object-cover z-0" />
<Image src="/assets/images/leaves.jpg" alt="Leaves" fill className="object-cover z-0" />
<div className="absolute inset-0 bg-[#0d1117]/50 z-0"></div>
<div className="relative z-10 max-w-6xl mx-auto">
@@ -147,7 +148,7 @@ export default function Home() {
{/* My Photos (Ynni Image) */}
<div className="relative w-full lg:w-1/2">
<img src="/assets/images/ynni.jpg" alt="My Photos" className="w-full rounded-4xl shadow-2xl object-cover lg:h-160" />
<Image src="/assets/images/ynni.jpg" alt="My Photos" width={800} height={800} className="w-full rounded-4xl shadow-2xl object-cover lg:h-125" />
<div className="absolute top-[10%] -left-4 lg:-left-12 bg-white/10 backdrop-blur-xl border border-white/20 py-6 px-10 shadow-2xl rounded-2xl">
<h2 className="text-[30px] lg:text-[40px] text-white font-black whitespace-nowrap uppercase tracking-wider">My Photos</h2>
</div>
@@ -155,7 +156,7 @@ export default function Home() {
{/* Night Sky Collection */}
<div className="flex flex-col items-start w-full lg:w-1/2 lg:pt-8">
<img src="/assets/images/night_sky.jpg" alt="Night Sky" className="w-full max-w-125 rounded-3xl shadow-xl border border-white/10" />
<Image src="/assets/images/night_sky.jpg" alt="Night Sky" width={600} height={400} className="w-full max-w-125 rounded-3xl shadow-xl border border-gray-200 dark:border-white/10" />
<h3 className="text-white text-[26px] mt-8 font-bold uppercase tracking-wide">My Photography collection</h3>
<div className="w-12 h-1 border-t-2 border-[#84c0a0] my-4"></div>
<p className="text-gray-400 text-[18px] font-light leading-relaxed">
@@ -169,7 +170,7 @@ export default function Home() {
{/* Singapore Full Width wrapper */}
<div className="w-full mt-32 relative h-125 md:h-175 rounded-[40px] overflow-hidden shadow-2xl border border-white/10 group">
<img src="/assets/images/singapore.jpg" alt="Singapore" className="absolute inset-0 w-full h-full object-cover transition-transform duration-2000 group-hover:scale-105" />
<Image src="/assets/images/singapore.jpg" alt="Singapore" fill className="object-cover transition-transform duration-1000 group-hover:scale-105" />
<div className="absolute inset-0 bg-linear-to-t from-[#0d1117]/90 via-[#0d1117]/20 to-transparent"></div>
<div className="relative z-10 w-full h-full p-8 md:p-16 flex items-end md:items-start">
@@ -190,10 +191,11 @@ export default function Home() {
{/* 5. CONTACT CALL-TO-ACTION (Compact Banner) */}
<section className="relative py-16 px-6 overflow-hidden border-t border-white/5">
{/* Immersive Mountain Background */}
<img
<Image
src="/assets/images/snowy_mountain_peaks.jpg"
alt="Snowy Mountains"
className="absolute inset-0 w-full h-full object-cover z-0"
fill
className="object-cover z-0"
/>
{/* Dark overlay */}
@@ -204,7 +206,7 @@ export default function Home() {
<div className="text-center md:text-left">
<h2 className="text-white text-3xl md:text-4xl font-black uppercase tracking-tighter mb-2">
Let's Connect
Let&apos;s Connect
</h2>
<p className="text-[#84c0a0] font-mono uppercase text-xs md:text-sm tracking-widest font-bold">
Transmission & Socials
+12 -11
View File
@@ -2,6 +2,7 @@
import MatrixRain from '@/app/components/MatrixRain';
import { FaCodeBranch, FaGithub, FaGitlab, FaGlobe, FaStar } from 'react-icons/fa';
import Image from 'next/image';
interface GithubProfile {
html_url: string;
@@ -38,7 +39,7 @@ async function getProfile(): Promise<GithubProfile | null> {
const res = await fetch('https://api.github.com/users/WilliamSoderberg', { next: { revalidate: 60 } });
if (!res.ok) return null;
return res.json();
} catch (e) {
} catch {
return null;
}
}
@@ -48,7 +49,7 @@ async function getGithubRepos(): Promise<GithubRepo[]> {
const res = await fetch('https://api.github.com/users/WilliamSoderberg/repos?sort=updated', { next: { revalidate: 60 } });
if (!res.ok) return [];
return res.json();
} catch (e) {
} catch {
return [];
}
}
@@ -73,7 +74,7 @@ async function getGitlabRepos(): Promise<GitlabRepo[]> {
const topLanguage = Object.keys(languages).sort((a, b) => languages[b] - languages[a])[0];
return { ...repo, language: topLanguage };
}
} catch (e) {
} catch {
console.error(`Failed to fetch language for GitLab repo: ${repo.id}`);
}
return repo;
@@ -81,7 +82,7 @@ async function getGitlabRepos(): Promise<GitlabRepo[]> {
);
return projectsWithLanguages;
} catch (e) {
} catch {
console.error("GitLab fetch failed, returning empty array");
return [];
}
@@ -122,7 +123,7 @@ export default async function CodePage() {
</a>
<div className="w-full">
<div className="relative h-37.5 w-37.5 mx-auto mb-5">
<img src={profile.avatar_url} alt="Avatar" className="h-full w-full rounded-full object-cover border-4 border-[#84c0a0] shadow-[0_0_15px_rgba(132,192,160,0.5)]" />
<Image src={profile.avatar_url} alt="Avatar" width={150} height={150} className="h-full w-full rounded-full object-cover border-4 border-[#58806a] dark:border-[#84c0a0] shadow-[0_0_15px_rgba(88,128,106,0.3)] dark:shadow-[0_0_15px_rgba(132,192,160,0.5)]" />
</div>
<h1 className="mb-1">
<a className="text-white text-[26px] font-bold tracking-wide no-underline hover:text-[#84c0a0] transition-colors" href={profile.html_url} target="_blank" rel="noopener noreferrer">
@@ -257,16 +258,16 @@ export default async function CodePage() {
{/* Changed from Flex to Grid for perfect centering! */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-12 max-w-5xl mx-auto justify-items-center items-center py-6">
<a className="no-underline text-white text-[22px] flex flex-col items-center hover:scale-105 transition-transform group" href="https://soderberg.tech">
<img src="/assets/logos/logo.svg" alt="Soderberg Tech" className="w-22.5 h-16.25 object-contain mb-5 drop-shadow-md group-hover:drop-shadow-[0_0_10px_rgba(255,255,255,0.5)] transition-all" />
<a className="no-underline text-gray-900 dark:text-white text-[22px] flex flex-col items-center hover:scale-105 transition-transform group" href="https://soderberg.tech">
<Image src="/assets/logos/logo.svg" alt="Soderberg Tech" width={90} height={65} className="w-22.5 h-16.25 object-contain mb-5 drop-shadow-md group-hover:drop-shadow-[0_0_10px_rgba(0,0,0,0.2)] dark:group-hover:drop-shadow-[0_0_10px_rgba(255,255,255,0.5)] transition-all dark:invert-0 filter invert" />
<span className="font-bold tracking-wide text-center">Soderberg Tech</span>
</a>
<a className="no-underline text-white text-[22px] flex flex-col items-center hover:scale-105 transition-transform group" href="https://lirkab.se">
<img src="/assets/logos/lirkab.svg" alt="Lirkab" className="w-22.5 h-16.25 object-contain mb-5 drop-shadow-md group-hover:drop-shadow-[0_0_10px_rgba(255,255,255,0.5)] transition-all" />
<a className="no-underline text-gray-900 dark:text-white text-[22px] flex flex-col items-center hover:scale-105 transition-transform group" href="https://lirkab.se">
<Image src="/assets/logos/lirkab.svg" alt="Lirkab" width={90} height={65} className="w-22.5 h-16.25 object-contain mb-5 drop-shadow-md group-hover:drop-shadow-[0_0_10px_rgba(0,0,0,0.2)] dark:group-hover:drop-shadow-[0_0_10px_rgba(255,255,255,0.5)] transition-all dark:invert-0 filter invert" />
<span className="font-bold tracking-wide text-center">Lirkab</span>
</a>
<a className="no-underline text-white text-[22px] flex flex-col items-center hover:scale-105 transition-transform group" href="https://lerbergetsvolleyboll.se">
<img src="/assets/logos/lvs.svg" alt="Lerbergets Volleyboll" className="w-22.5 h-16.25 object-contain mb-5 drop-shadow-md group-hover:drop-shadow-[0_0_10px_rgba(255,255,255,0.5)] transition-all" />
<a className="no-underline text-gray-900 dark:text-white text-[22px] flex flex-col items-center hover:scale-105 transition-transform group" href="https://lerbergetsvolleyboll.se">
<Image src="/assets/logos/lvs.svg" alt="Lerbergets Volleyboll" width={90} height={65} className="w-22.5 h-16.25 object-contain mb-5 drop-shadow-md group-hover:drop-shadow-[0_0_10px_rgba(0,0,0,0.2)] dark:group-hover:drop-shadow-[0_0_10px_rgba(255,255,255,0.5)] transition-all dark:invert-0 filter invert" />
<span className="font-bold tracking-wide text-center">Lerbergets Volleyboll</span>
</a>
</div>
+8 -1
View File
@@ -7,6 +7,7 @@ import { Canvas, useThree } from '@react-three/fiber';
import { Suspense, useEffect, useState, useTransition } from 'react';
import { TbCube3dSphere } from 'react-icons/tb';
import * as THREE from 'three';
import Image from 'next/image';
const models = [
{ name: 'Wallet', src: 'Wallet' },
@@ -122,7 +123,13 @@ export default function DesignPage() {
/>
<a href={`/models/${activeModel}.usdz`} rel="ar" className="absolute top-4 right-4 bg-black/50 backdrop-blur-md text-white text-sm px-4 py-2 rounded-full border border-white/10 hover:bg-white/20 transition-colors md:hidden z-10 flex items-center gap-2">
<img src={`/models/${activeModel}.png`} alt="AR Preview" className="w-5 h-5 rounded-full object-cover" />
<Image
src={`/models/${activeModel}.png`}
alt="AR Preview"
width={20}
height={20}
className="w-5 h-5 rounded-full object-cover"
/>
View in AR
</a>
</div>
+8 -1
View File
@@ -4,7 +4,14 @@ import type { NextConfig } from "next";
const nextConfig: NextConfig = {
images: {
qualities: [75, 80, 85, 90, 95, 100], // Add 90 here!
qualities: [75, 80, 85, 90, 95, 100],
remotePatterns: [
{
protocol: 'https',
hostname: 'avatars.githubusercontent.com',
pathname: '/**',
},
],
},
};