-
-
{project} {repo}
+
+
+
+
+
+
+
{project} {repo}
+
+
+
{descriptionTitle} {description}
+
+
+
+
+
+
+
-
-
{descriptionTitle} {description}
-
-
-
-
-
-
-
-
-
-
- { images.map( ({key, url, hover, h, w }, index) => {
- hover = ( hover === 'left' ) ? hoverLeft : hoverRight
- return (
-
-
-
+
+
+ { images.map( ({key, url, hover, h, w }, index) => {
+ hover = ( hover === 'left' ) ? hoverLeft : hoverRight
+ return (
+
+
+
+
-
- )}
- ) }
-
-
-
+ )}
+ ) }
+
+
+
+
)
}
@@ -136,4 +139,3 @@ const hoverRight = {
x: 20
}
}
-
diff --git a/components/layout/footer.jsx b/components/layout/footer.jsx
index e3ab895e6..ed669fcaf 100644
--- a/components/layout/footer.jsx
+++ b/components/layout/footer.jsx
@@ -71,7 +71,7 @@ export default function Footer() {
-
*/}
diff --git a/components/redesign/Card.jsx b/components/redesign/Card.jsx
new file mode 100644
index 000000000..337bf3887
--- /dev/null
+++ b/components/redesign/Card.jsx
@@ -0,0 +1,44 @@
+import { motion } from 'framer-motion';
+import styles from './Card.module.scss';
+
+const cardVariants = {
+ hidden: {
+ opacity: 0,
+ y: 30
+ },
+ visible: {
+ opacity: 1,
+ y: 0,
+ transition: {
+ duration: 0.6,
+ ease: [0.25, 0.46, 0.45, 0.94],
+ },
+ },
+};
+
+export default function Card({
+ id,
+ title,
+ children,
+ className = '',
+ delay = 0
+}) {
+ return (
+
+ {title && (
+ {title}
+ )}
+
+ {children}
+
+
+ );
+}
diff --git a/components/redesign/Card.module.scss b/components/redesign/Card.module.scss
new file mode 100644
index 000000000..52a37c1ee
--- /dev/null
+++ b/components/redesign/Card.module.scss
@@ -0,0 +1,57 @@
+.card {
+ background: var(--bg-card);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius-lg);
+ padding: var(--space-8);
+ margin-bottom: var(--space-6);
+ transition: border-color var(--transition-base);
+
+ &:hover {
+ border-color: var(--border-hover);
+ }
+
+ @media (max-width: 640px) {
+ padding: var(--space-6);
+ margin-bottom: var(--space-4);
+ }
+}
+
+.title {
+ font-size: var(--text-2xl);
+ font-weight: 400;
+ margin-bottom: var(--space-6);
+ padding-bottom: var(--space-4);
+ border-bottom: 1px solid var(--border-color);
+ font-family: var(--font-sans);
+
+ @media (max-width: 640px) {
+ font-size: var(--text-xl);
+ margin-bottom: var(--space-4);
+ padding-bottom: var(--space-3);
+ }
+}
+
+.content {
+ p {
+ color: var(--text-secondary);
+ line-height: 1.7;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
+
+ a {
+ color: var(--accent);
+ text-decoration: none;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+
+ strong {
+ color: var(--text-primary);
+ font-weight: 600;
+ }
+}
diff --git a/components/redesign/DotMatrix.jsx b/components/redesign/DotMatrix.jsx
new file mode 100644
index 000000000..356002189
--- /dev/null
+++ b/components/redesign/DotMatrix.jsx
@@ -0,0 +1,299 @@
+import { useState, useEffect, useCallback, useMemo } from 'react';
+import { motion, AnimatePresence } from 'framer-motion';
+import styles from './DotMatrix.module.scss';
+
+// Grid configuration
+const GRID_SIZE = 15;
+const DOT_COUNT = GRID_SIZE * GRID_SIZE;
+
+// Icon definitions - each icon is a set of dot indices that should be "active"
+// Grid is 15x15 (0-224), calculated as row * 15 + col
+const generateIconDots = (pattern) => {
+ const dots = new Set();
+ pattern.forEach(([row, col]) => {
+ if (row >= 0 && row < GRID_SIZE && col >= 0 && col < GRID_SIZE) {
+ dots.add(row * GRID_SIZE + col);
+ }
+ });
+ return dots;
+};
+
+// Rocket League car icon - stylized car silhouette
+const rocketLeagueCar = generateIconDots([
+ // Car body
+ [7, 3], [7, 4], [7, 5], [7, 6], [7, 7], [7, 8], [7, 9], [7, 10], [7, 11],
+ [8, 2], [8, 3], [8, 4], [8, 5], [8, 6], [8, 7], [8, 8], [8, 9], [8, 10], [8, 11], [8, 12],
+ [9, 2], [9, 3], [9, 4], [9, 5], [9, 6], [9, 7], [9, 8], [9, 9], [9, 10], [9, 11], [9, 12],
+ // Cabin/top
+ [6, 5], [6, 6], [6, 7], [6, 8], [6, 9],
+ [5, 6], [5, 7], [5, 8],
+ // Wheels
+ [10, 3], [10, 4], [11, 3], [11, 4],
+ [10, 10], [10, 11], [11, 10], [11, 11],
+ // Boost flames
+ [8, 13], [9, 13], [8, 14], [7, 13],
+]);
+
+// Neural network / AI brain icon
+const neuralNetwork = generateIconDots([
+ // Input layer (left)
+ [3, 2], [5, 2], [7, 2], [9, 2], [11, 2],
+ // Hidden layer 1
+ [4, 5], [6, 5], [8, 5], [10, 5],
+ // Hidden layer 2
+ [5, 8], [7, 8], [9, 8],
+ // Output layer
+ [6, 11], [8, 11],
+ // Connections (dots along the paths)
+ [3, 3], [4, 4], [5, 3], [6, 4], [7, 3], [8, 4], [9, 3], [10, 4], [11, 3],
+ [4, 6], [5, 7], [6, 6], [7, 7], [8, 6], [9, 7], [10, 6],
+ [5, 9], [6, 10], [7, 9], [8, 10], [9, 9],
+ // Brain outline hint
+ [2, 6], [2, 7], [2, 8], [12, 6], [12, 7], [12, 8],
+]);
+
+// Microphone / Music note for a cappella
+const microphone = generateIconDots([
+ // Mic head (circle)
+ [3, 6], [3, 7], [3, 8],
+ [4, 5], [4, 9],
+ [5, 5], [5, 9],
+ [6, 5], [6, 9],
+ [7, 6], [7, 7], [7, 8],
+ // Mic body
+ [8, 7], [9, 7], [10, 7],
+ // Stand base
+ [11, 5], [11, 6], [11, 7], [11, 8], [11, 9],
+ [12, 4], [12, 5], [12, 6], [12, 7], [12, 8], [12, 9], [12, 10],
+ // Sound waves
+ [4, 3], [5, 2], [6, 3],
+ [4, 11], [5, 12], [6, 11],
+ [3, 4], [3, 10],
+]);
+
+// Globe / Travel / Wanderlust icon
+const wanderlust = generateIconDots([
+ // Globe circle
+ [2, 7],
+ [3, 5], [3, 6], [3, 7], [3, 8], [3, 9],
+ [4, 4], [4, 10],
+ [5, 3], [5, 11],
+ [6, 3], [6, 11],
+ [7, 3], [7, 11],
+ [8, 3], [8, 11],
+ [9, 3], [9, 11],
+ [10, 4], [10, 10],
+ [11, 5], [11, 6], [11, 7], [11, 8], [11, 9],
+ [12, 7],
+ // Longitude line
+ [4, 7], [5, 7], [6, 7], [7, 7], [8, 7], [9, 7], [10, 7],
+ // Latitude lines
+ [5, 5], [5, 6], [5, 8], [5, 9],
+ [7, 4], [7, 5], [7, 6], [7, 8], [7, 9], [7, 10],
+ [9, 5], [9, 6], [9, 8], [9, 9],
+ // Plane
+ [4, 12], [5, 13], [6, 12], [5, 11], [5, 12],
+]);
+
+// Lightbulb / Innovation icon
+const lightbulb = generateIconDots([
+ // Bulb top
+ [2, 7],
+ [3, 5], [3, 6], [3, 7], [3, 8], [3, 9],
+ [4, 4], [4, 10],
+ [5, 3], [5, 11],
+ [6, 3], [6, 11],
+ [7, 4], [7, 10],
+ [8, 5], [8, 9],
+ // Neck
+ [9, 6], [9, 7], [9, 8],
+ // Base
+ [10, 5], [10, 6], [10, 7], [10, 8], [10, 9],
+ [11, 6], [11, 7], [11, 8],
+ [12, 6], [12, 7], [12, 8],
+ // Filament/rays
+ [4, 6], [4, 7], [4, 8],
+ [5, 7],
+ // Rays emanating
+ [1, 7],
+ [2, 4], [2, 10],
+ [4, 2], [4, 12],
+]);
+
+// Rocket icon for entrepreneurship
+const rocket = generateIconDots([
+ // Nose cone
+ [2, 7],
+ [3, 6], [3, 7], [3, 8],
+ // Body
+ [4, 5], [4, 6], [4, 7], [4, 8], [4, 9],
+ [5, 5], [5, 6], [5, 7], [5, 8], [5, 9],
+ [6, 5], [6, 6], [6, 7], [6, 8], [6, 9],
+ [7, 5], [7, 6], [7, 7], [7, 8], [7, 9],
+ [8, 5], [8, 6], [8, 7], [8, 8], [8, 9],
+ // Fins
+ [7, 3], [8, 3], [9, 4],
+ [7, 11], [8, 11], [9, 10],
+ // Engine
+ [9, 6], [9, 7], [9, 8],
+ // Flames
+ [10, 7],
+ [11, 6], [11, 7], [11, 8],
+ [12, 5], [12, 7], [12, 9],
+ [13, 6], [13, 8],
+]);
+
+// Code brackets icon - for developer
+const codeBrackets = generateIconDots([
+ // Left bracket <
+ [4, 4], [5, 3], [6, 2], [7, 2], [8, 2], [9, 3], [10, 4],
+ // Slash /
+ [5, 8], [6, 7], [7, 7], [8, 7], [9, 6],
+ // Right bracket >
+ [4, 10], [5, 11], [6, 12], [7, 12], [8, 12], [9, 11], [10, 10],
+ // Dots for decoration
+ [3, 6], [3, 7], [3, 8],
+ [11, 6], [11, 7], [11, 8],
+]);
+
+// Heart icon - for passion/creativity
+const heart = generateIconDots([
+ // Top curves
+ [4, 4], [4, 5], [4, 9], [4, 10],
+ [3, 3], [3, 4], [3, 5], [3, 6], [3, 8], [3, 9], [3, 10], [3, 11],
+ [4, 2], [4, 3], [4, 6], [4, 8], [4, 11], [4, 12],
+ [5, 2], [5, 3], [5, 4], [5, 5], [5, 6], [5, 7], [5, 8], [5, 9], [5, 10], [5, 11], [5, 12],
+ // Middle
+ [6, 3], [6, 4], [6, 5], [6, 6], [6, 7], [6, 8], [6, 9], [6, 10], [6, 11],
+ [7, 4], [7, 5], [7, 6], [7, 7], [7, 8], [7, 9], [7, 10],
+ [8, 5], [8, 6], [8, 7], [8, 8], [8, 9],
+ // Bottom point
+ [9, 6], [9, 7], [9, 8],
+ [10, 7],
+]);
+
+// All icons with labels
+const ICONS = [
+ { id: 'rocket-league', name: 'Gaming', dots: rocketLeagueCar, color: '#3B82F6' },
+ { id: 'neural-network', name: 'AI/ML', dots: neuralNetwork, color: '#8B5CF6' },
+ { id: 'microphone', name: 'Music', dots: microphone, color: '#EC4899' },
+ { id: 'wanderlust', name: 'Travel', dots: wanderlust, color: '#10B981' },
+ { id: 'lightbulb', name: 'Ideas', dots: lightbulb, color: '#F59E0B' },
+ { id: 'rocket', name: 'Building', dots: rocket, color: '#EF4444' },
+ { id: 'code', name: 'Code', dots: codeBrackets, color: '#06B6D4' },
+ { id: 'heart', name: 'Passion', dots: heart, color: '#F43F5E' },
+];
+
+// Duration each icon is shown (ms)
+const ICON_DURATION = 3000;
+// Transition duration for dots
+const DOT_TRANSITION = 0.6;
+
+export default function DotMatrix({ className = '' }) {
+ const [currentIconIndex, setCurrentIconIndex] = useState(0);
+ const [isAnimating, setIsAnimating] = useState(false);
+
+ // Cycle through icons
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setIsAnimating(true);
+ setTimeout(() => {
+ setCurrentIconIndex((prev) => (prev + 1) % ICONS.length);
+ setIsAnimating(false);
+ }, 300);
+ }, ICON_DURATION);
+
+ return () => clearInterval(interval);
+ }, []);
+
+ const currentIcon = ICONS[currentIconIndex];
+
+ // Generate dots array
+ const dots = useMemo(() => {
+ return Array.from({ length: DOT_COUNT }, (_, i) => ({
+ id: i,
+ row: Math.floor(i / GRID_SIZE),
+ col: i % GRID_SIZE,
+ }));
+ }, []);
+
+ return (
+
+
+
+ {dots.map((dot) => {
+ const isActive = currentIcon.dots.has(dot.id);
+ const delay = (dot.row + dot.col) * 0.02;
+
+ return (
+
+
+
+ );
+ })}
+
+
+
+ {/* Icon label */}
+
+
+
+ {currentIcon.name}
+
+
+
+
+ {/* Progress indicator */}
+
+ {ICONS.map((icon, index) => (
+ setCurrentIconIndex(index)}
+ aria-label={`Show ${icon.name} icon`}
+ style={{
+ backgroundColor: index === currentIconIndex ? icon.color : undefined,
+ }}
+ />
+ ))}
+
+
+ );
+}
diff --git a/components/redesign/DotMatrix.module.scss b/components/redesign/DotMatrix.module.scss
new file mode 100644
index 000000000..53fa19c27
--- /dev/null
+++ b/components/redesign/DotMatrix.module.scss
@@ -0,0 +1,94 @@
+// Dot Matrix Animation Component Styles
+
+.container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--space-6);
+}
+
+.matrixWrapper {
+ position: relative;
+ width: 100%;
+ max-width: 280px;
+ aspect-ratio: 1;
+
+ @media (max-width: 640px) {
+ max-width: 220px;
+ }
+}
+
+.dotGrid {
+ display: grid;
+ gap: 4px;
+ width: 100%;
+ height: 100%;
+ padding: var(--space-2);
+
+ @media (max-width: 640px) {
+ gap: 3px;
+ }
+}
+
+.dotWrapper {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ aspect-ratio: 1;
+}
+
+.dot {
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ background-color: var(--dot-inactive);
+ will-change: transform, opacity, background-color;
+}
+
+.iconLabel {
+ height: 28px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.labelText {
+ font-family: var(--font-mono);
+ font-size: var(--text-sm);
+ font-weight: 600;
+ letter-spacing: 0.1em;
+ text-transform: uppercase;
+}
+
+.progressContainer {
+ display: flex;
+ gap: var(--space-2);
+ padding: var(--space-2);
+}
+
+.progressDot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ border: none;
+ background-color: var(--border-color);
+ cursor: pointer;
+ transition: all var(--transition-base);
+ padding: 0;
+
+ &:hover {
+ background-color: var(--text-muted);
+ transform: scale(1.2);
+ }
+
+ &.active {
+ transform: scale(1.3);
+ }
+
+ &:focus-visible {
+ outline: 2px solid var(--accent);
+ outline-offset: 2px;
+ }
+}
+
+// Note: --dot-inactive variable is defined in variables-new.css
diff --git a/components/redesign/Header.jsx b/components/redesign/Header.jsx
new file mode 100644
index 000000000..045b0f3a7
--- /dev/null
+++ b/components/redesign/Header.jsx
@@ -0,0 +1,129 @@
+import { motion } from 'framer-motion';
+import { FaGithub, FaLinkedin, FaTwitter, FaEnvelope, FaArrowDown } from 'react-icons/fa';
+import DotMatrix from './DotMatrix';
+import styles from './Header.module.scss';
+
+const socialLinks = [
+ {
+ icon: FaGithub,
+ href: 'https://github.com/RiptideStar',
+ label: 'GitHub',
+ },
+ {
+ icon: FaLinkedin,
+ href: 'https://www.linkedin.com/in/zhangkyle/',
+ label: 'LinkedIn',
+ },
+ {
+ icon: FaTwitter,
+ href: 'https://twitter.com/',
+ label: 'Twitter',
+ },
+];
+
+const containerVariants = {
+ hidden: { opacity: 0 },
+ visible: {
+ opacity: 1,
+ transition: {
+ staggerChildren: 0.15,
+ delayChildren: 0.2,
+ },
+ },
+};
+
+const itemVariants = {
+ hidden: { opacity: 0, y: 20 },
+ visible: {
+ opacity: 1,
+ y: 0,
+ transition: {
+ duration: 0.6,
+ ease: [0.25, 0.46, 0.45, 0.94],
+ },
+ },
+};
+
+export default function Header({
+ name = "Kyle Zhang",
+ tagline = "Builder. Researcher. Creator.",
+ description = "M&T graduate from UPenn, passionate about building products at the intersection of gaming, AI, and human impact.",
+ email = "kyle@example.com"
+}) {
+ const scrollToContent = () => {
+ const content = document.getElementById('about-section');
+ if (content) {
+ content.scrollIntoView({ behavior: 'smooth' });
+ }
+ };
+
+ return (
+
+ );
+}
diff --git a/components/redesign/Header.module.scss b/components/redesign/Header.module.scss
new file mode 100644
index 000000000..d1c8901d9
--- /dev/null
+++ b/components/redesign/Header.module.scss
@@ -0,0 +1,192 @@
+// Header Styles - Minimalist Hero with Dot Matrix
+
+.header {
+ min-height: 100vh;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: var(--space-8) var(--space-6);
+ position: relative;
+
+ @media (max-width: 640px) {
+ min-height: calc(100vh - 60px);
+ padding: var(--space-6) var(--space-4);
+ }
+}
+
+.heroContent {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+ max-width: 600px;
+ gap: var(--space-8);
+
+ @media (max-width: 640px) {
+ gap: var(--space-6);
+ }
+}
+
+.dotMatrixWrapper {
+ margin-bottom: var(--space-4);
+}
+
+.introSection {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-3);
+}
+
+.name {
+ font-size: var(--text-5xl);
+ font-weight: 600;
+ letter-spacing: -0.03em;
+ color: var(--text-primary);
+ line-height: 1.1;
+
+ @media (max-width: 640px) {
+ font-size: var(--text-4xl);
+ }
+}
+
+.tagline {
+ font-family: var(--font-mono);
+ font-size: var(--text-lg);
+ color: var(--text-muted);
+ letter-spacing: 0.02em;
+ margin: 0;
+
+ @media (max-width: 640px) {
+ font-size: var(--text-base);
+ }
+}
+
+.description {
+ font-size: var(--text-lg);
+ color: var(--text-secondary);
+ line-height: 1.7;
+ max-width: 480px;
+ margin: 0;
+
+ @media (max-width: 640px) {
+ font-size: var(--text-base);
+ }
+}
+
+.socialRow {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--space-4);
+}
+
+.emailLink {
+ display: inline-flex;
+ align-items: center;
+ gap: var(--space-2);
+ padding: var(--space-3) var(--space-5);
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius-full);
+ color: var(--text-secondary);
+ font-size: var(--text-sm);
+ transition: all var(--transition-base);
+ text-decoration: none;
+
+ &:hover {
+ border-color: var(--border-hover);
+ color: var(--text-primary);
+ background: var(--bg-tertiary);
+ }
+
+ svg {
+ width: 16px;
+ height: 16px;
+ color: var(--text-muted);
+ }
+}
+
+.socialLinks {
+ display: flex;
+ gap: var(--space-3);
+}
+
+.socialIcon {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 44px;
+ height: 44px;
+ border-radius: 50%;
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ color: var(--text-secondary);
+ transition: all var(--transition-base);
+
+ &:hover {
+ border-color: var(--text-primary);
+ color: var(--text-primary);
+ background: var(--bg-tertiary);
+ }
+
+ svg {
+ width: 20px;
+ height: 20px;
+ }
+}
+
+.scrollIndicator {
+ position: absolute;
+ bottom: var(--space-8);
+ left: 50%;
+ transform: translateX(-50%);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ color: var(--text-muted);
+ cursor: pointer;
+ transition: all var(--transition-base);
+ animation: bounce 2s infinite;
+
+ &:hover {
+ color: var(--text-primary);
+ }
+
+ svg {
+ width: 16px;
+ height: 16px;
+ }
+
+ @media (max-width: 640px) {
+ bottom: var(--space-6);
+ }
+}
+
+@keyframes bounce {
+ 0%, 20%, 50%, 80%, 100% {
+ transform: translateX(-50%) translateY(0);
+ }
+ 40% {
+ transform: translateX(-50%) translateY(-8px);
+ }
+ 60% {
+ transform: translateX(-50%) translateY(-4px);
+ }
+}
+
+// Dark mode adjustments
+:global([data-theme='dark']) {
+ .emailLink,
+ .socialIcon {
+ background: var(--bg-tertiary);
+ border-color: var(--border-color);
+
+ &:hover {
+ background: var(--bg-card);
+ border-color: var(--border-hover);
+ }
+ }
+}
diff --git a/components/redesign/Layout.jsx b/components/redesign/Layout.jsx
new file mode 100644
index 000000000..d2d1e2923
--- /dev/null
+++ b/components/redesign/Layout.jsx
@@ -0,0 +1,29 @@
+import { motion, AnimatePresence } from 'framer-motion';
+import ThemeToggle from './ThemeToggle';
+import styles from './Layout.module.scss';
+
+export default function Layout({ children }) {
+ return (
+
+
+
+
+ {children}
+
+
+
+
+ );
+}
diff --git a/components/redesign/Layout.module.scss b/components/redesign/Layout.module.scss
new file mode 100644
index 000000000..1598ea4c3
--- /dev/null
+++ b/components/redesign/Layout.module.scss
@@ -0,0 +1,47 @@
+// Layout Styles - Minimalist Portfolio
+
+.layout {
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ background: var(--bg-primary);
+}
+
+.main {
+ flex: 1;
+}
+
+.container {
+ width: 100%;
+ max-width: var(--max-width);
+ margin: 0 auto;
+ padding: 0 var(--space-6);
+
+ @media (max-width: 640px) {
+ padding: 0 var(--space-4);
+ }
+}
+
+.footer {
+ padding: var(--space-16) var(--space-6);
+ border-top: 1px solid var(--border-color);
+
+ .container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--space-2);
+ }
+
+ p {
+ color: var(--text-muted);
+ font-size: var(--text-sm);
+ text-align: center;
+ margin: 0;
+ }
+
+ .copyright {
+ font-size: var(--text-xs);
+ color: var(--text-faint);
+ }
+}
diff --git a/components/redesign/ThemeToggle.jsx b/components/redesign/ThemeToggle.jsx
new file mode 100644
index 000000000..3ded77639
--- /dev/null
+++ b/components/redesign/ThemeToggle.jsx
@@ -0,0 +1,64 @@
+import { useState, useEffect } from 'react';
+import { motion } from 'framer-motion';
+import { FaSun, FaMoon } from 'react-icons/fa';
+import styles from './ThemeToggle.module.scss';
+
+export default function ThemeToggle() {
+ const [theme, setTheme] = useState('light');
+ const [mounted, setMounted] = useState(false);
+
+ useEffect(() => {
+ setMounted(true);
+ // Check localStorage or system preference
+ const savedTheme = localStorage.getItem('theme');
+ const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
+
+ if (savedTheme) {
+ setTheme(savedTheme);
+ document.documentElement.setAttribute('data-theme', savedTheme);
+ } else if (systemPrefersDark) {
+ setTheme('dark');
+ document.documentElement.setAttribute('data-theme', 'dark');
+ }
+ }, []);
+
+ const toggleTheme = () => {
+ const newTheme = theme === 'light' ? 'dark' : 'light';
+ setTheme(newTheme);
+ document.documentElement.setAttribute('data-theme', newTheme);
+ localStorage.setItem('theme', newTheme);
+ };
+
+ // Prevent hydration mismatch
+ if (!mounted) {
+ return (
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+ {theme === 'light' ? : }
+
+
+
+ );
+}
diff --git a/components/redesign/ThemeToggle.module.scss b/components/redesign/ThemeToggle.module.scss
new file mode 100644
index 000000000..8b796786c
--- /dev/null
+++ b/components/redesign/ThemeToggle.module.scss
@@ -0,0 +1,58 @@
+// Theme Toggle - Minimalist style
+
+.toggleWrapper {
+ position: fixed;
+ top: var(--space-6);
+ right: var(--space-6);
+ z-index: 1000;
+
+ @media (max-width: 640px) {
+ top: var(--space-4);
+ right: var(--space-4);
+ }
+}
+
+.toggle {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 44px;
+ height: 44px;
+ border: 1px solid var(--border-color);
+ border-radius: 50%;
+ background: var(--bg-secondary);
+ color: var(--text-muted);
+ cursor: pointer;
+ transition: all var(--transition-base);
+ backdrop-filter: blur(8px);
+
+ &:hover {
+ border-color: var(--border-hover);
+ color: var(--text-primary);
+ background: var(--bg-tertiary);
+ }
+
+ span {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ svg {
+ width: 18px;
+ height: 18px;
+ }
+}
+
+// Dark mode adjustments
+:global([data-theme='dark']) {
+ .toggle {
+ background: var(--bg-tertiary);
+ border-color: var(--border-color);
+
+ &:hover {
+ background: var(--bg-card);
+ border-color: var(--border-hover);
+ }
+ }
+}
diff --git a/components/redesign/sections/About.jsx b/components/redesign/sections/About.jsx
new file mode 100644
index 000000000..832c1f50f
--- /dev/null
+++ b/components/redesign/sections/About.jsx
@@ -0,0 +1,73 @@
+import { motion } from 'framer-motion';
+import { useInView } from 'react-intersection-observer';
+import styles from './Sections.module.scss';
+
+const containerVariants = {
+ hidden: { opacity: 0 },
+ visible: {
+ opacity: 1,
+ transition: {
+ staggerChildren: 0.1,
+ },
+ },
+};
+
+const itemVariants = {
+ hidden: { opacity: 0, y: 20 },
+ visible: {
+ opacity: 1,
+ y: 0,
+ transition: { duration: 0.5, ease: 'easeOut' },
+ },
+};
+
+export default function About({ data }) {
+ const [ref, inView] = useInView({
+ triggerOnce: true,
+ threshold: 0.1,
+ });
+
+ const { intro, highlights = [] } = data || {};
+
+ return (
+
+
+
+ 01
+ About
+
+
+
+ {intro}
+
+ {highlights.length > 0 && (
+
+ {highlights.map((highlight, index) => (
+
+ {highlight.link ? (
+ <>
+ {highlight.text}
+
+ {highlight.link.text}
+
+ {highlight.suffix}
+ >
+ ) : (
+ highlight.text
+ )}
+
+ ))}
+
+ )}
+
+
+
+ );
+}
diff --git a/components/redesign/sections/Contact.jsx b/components/redesign/sections/Contact.jsx
new file mode 100644
index 000000000..601fb826f
--- /dev/null
+++ b/components/redesign/sections/Contact.jsx
@@ -0,0 +1,103 @@
+import { motion } from 'framer-motion';
+import { useInView } from 'react-intersection-observer';
+import { FaEnvelope, FaLinkedin, FaGithub, FaTwitter } from 'react-icons/fa';
+import styles from './Sections.module.scss';
+
+const containerVariants = {
+ hidden: { opacity: 0 },
+ visible: {
+ opacity: 1,
+ transition: {
+ staggerChildren: 0.1,
+ },
+ },
+};
+
+const itemVariants = {
+ hidden: { opacity: 0, y: 20 },
+ visible: {
+ opacity: 1,
+ y: 0,
+ transition: { duration: 0.5, ease: 'easeOut' },
+ },
+};
+
+const socialLinks = [
+ {
+ icon: FaEnvelope,
+ href: 'mailto:kyle@example.com',
+ label: 'Email',
+ text: 'kyle@example.com',
+ },
+ {
+ icon: FaLinkedin,
+ href: 'https://www.linkedin.com/in/zhangkyle/',
+ label: 'LinkedIn',
+ text: 'linkedin.com/in/zhangkyle',
+ },
+ {
+ icon: FaGithub,
+ href: 'https://github.com/RiptideStar',
+ label: 'GitHub',
+ text: 'github.com/RiptideStar',
+ },
+ {
+ icon: FaTwitter,
+ href: 'https://twitter.com/',
+ label: 'Twitter',
+ text: '@kylezhang',
+ },
+];
+
+export default function Contact({ data }) {
+ const [ref, inView] = useInView({
+ triggerOnce: true,
+ threshold: 0.1,
+ });
+
+ const { message } = data || {};
+
+ return (
+
+
+
+ 03
+ Get in Touch
+
+
+
+
+ {message || "I'm always excited to connect with fellow builders, researchers, and anyone passionate about technology. Whether you have a project idea, want to collaborate, or just want to chat—reach out!"}
+
+
+
+
+ {socialLinks.map((link) => (
+
+
+
+ {link.label}
+ {link.text}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/components/redesign/sections/Experience.jsx b/components/redesign/sections/Experience.jsx
new file mode 100644
index 000000000..1d047fb0c
--- /dev/null
+++ b/components/redesign/sections/Experience.jsx
@@ -0,0 +1,88 @@
+import { motion } from 'framer-motion';
+import Card from '../Card';
+import styles from './Sections.module.scss';
+
+const listVariants = {
+ hidden: { opacity: 0 },
+ visible: {
+ opacity: 1,
+ transition: {
+ staggerChildren: 0.1,
+ },
+ },
+};
+
+const itemVariants = {
+ hidden: { opacity: 0, x: -10 },
+ visible: {
+ opacity: 1,
+ x: 0,
+ transition: { duration: 0.4 },
+ },
+};
+
+export default function Experience({ data }) {
+ const { intro, education = [], internships = [] } = data;
+
+ return (
+
+ {intro}
+
+ {education.length > 0 && (
+ <>
+ Education
+
+ {education.map((item, index) => (
+
+ {item.link ? (
+
+ {item.name}
+
+ ) : (
+ {item.name}
+ )}
+ {item.description && (
+ — {item.description}
+ )}
+
+ ))}
+
+ >
+ )}
+
+ {internships.length > 0 && (
+ <>
+ Internships
+
+ {internships.map((item, index) => (
+
+ {item.link ? (
+
+ {item.name}
+
+ ) : (
+ {item.name}
+ )}
+ {item.description && (
+ , {item.description}
+ )}
+
+ ))}
+
+ >
+ )}
+
+ );
+}
diff --git a/components/redesign/sections/Present.jsx b/components/redesign/sections/Present.jsx
new file mode 100644
index 000000000..132917a43
--- /dev/null
+++ b/components/redesign/sections/Present.jsx
@@ -0,0 +1,62 @@
+import { motion } from 'framer-motion';
+import Card from '../Card';
+import styles from './Sections.module.scss';
+
+const listVariants = {
+ hidden: { opacity: 0 },
+ visible: {
+ opacity: 1,
+ transition: {
+ staggerChildren: 0.1,
+ },
+ },
+};
+
+const itemVariants = {
+ hidden: { opacity: 0, x: -10 },
+ visible: {
+ opacity: 1,
+ x: 0,
+ transition: { duration: 0.4 },
+ },
+};
+
+export default function Present({ data }) {
+ const { intro, updates = [] } = data;
+
+ return (
+
+
+ {intro}
+
+
+ {updates.length > 0 && (
+ <>
+ Updates
+
+ {updates.map((update, index) => (
+
+ {update.date}
+
+ {update.text}
+ {update.link && (
+
+ {update.link.text}
+
+ )}
+ {update.suffix}
+
+
+ ))}
+
+ >
+ )}
+
+ );
+}
diff --git a/components/redesign/sections/Projects.jsx b/components/redesign/sections/Projects.jsx
new file mode 100644
index 000000000..2fe194c75
--- /dev/null
+++ b/components/redesign/sections/Projects.jsx
@@ -0,0 +1,101 @@
+import { motion } from 'framer-motion';
+import { FaExternalLinkAlt, FaGithub } from 'react-icons/fa';
+import Card from '../Card';
+import styles from './Sections.module.scss';
+
+const projectVariants = {
+ hidden: { opacity: 0 },
+ visible: {
+ opacity: 1,
+ transition: {
+ staggerChildren: 0.15,
+ },
+ },
+};
+
+const itemVariants = {
+ hidden: { opacity: 0, y: 20 },
+ visible: {
+ opacity: 1,
+ y: 0,
+ transition: { duration: 0.5 },
+ },
+};
+
+export default function Projects({ data }) {
+ const projects = data || [];
+
+ return (
+
+
+ {projects.map((project, index) => (
+
+
+
+ {project.url ? (
+
+ {project.project}
+
+ ) : (
+ project.project
+ )}
+
+
+ {project.url && (
+
+
+
+ )}
+ {project.repo && project.repo !== 'Private' && (
+
+
+
+ )}
+
+
+
+
+ {project.descriptionTitle} {project.description}
+
+
+ {project.stack && project.stack.length > 0 && (
+
+ {project.stack.slice(0, 6).map((tech, i) => (
+
+ {tech.name}
+
+ ))}
+ {project.stack.length > 6 && (
+ +{project.stack.length - 6}
+ )}
+
+ )}
+
+ ))}
+
+
+ );
+}
diff --git a/components/redesign/sections/Sections.module.scss b/components/redesign/sections/Sections.module.scss
new file mode 100644
index 000000000..cb444488a
--- /dev/null
+++ b/components/redesign/sections/Sections.module.scss
@@ -0,0 +1,481 @@
+// Section Styles - Minimalist Portfolio
+
+// Base section styles
+.section {
+ padding: var(--space-24) var(--space-6);
+ border-top: 1px solid var(--border-color);
+
+ @media (max-width: 640px) {
+ padding: var(--space-16) var(--space-4);
+ }
+}
+
+.container {
+ max-width: var(--max-width);
+ margin: 0 auto;
+}
+
+// Section header with number
+.sectionHeader {
+ display: flex;
+ align-items: center;
+ gap: var(--space-4);
+ margin-bottom: var(--space-10);
+
+ @media (max-width: 640px) {
+ margin-bottom: var(--space-8);
+ }
+}
+
+.sectionNumber {
+ font-family: var(--font-mono);
+ font-size: var(--text-sm);
+ color: var(--text-muted);
+ font-weight: 500;
+}
+
+.sectionTitle {
+ font-size: var(--text-2xl);
+ font-weight: 600;
+ color: var(--text-primary);
+ margin: 0;
+}
+
+// Content area
+.content {
+ max-width: var(--max-width-narrow);
+}
+
+// Introduction text
+.intro {
+ font-size: var(--text-lg);
+ color: var(--text-secondary);
+ line-height: 1.8;
+ margin-bottom: var(--space-6);
+
+ @media (max-width: 640px) {
+ font-size: var(--text-base);
+ }
+}
+
+// Highlight list
+.highlightList {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-4);
+
+ li {
+ display: flex;
+ align-items: flex-start;
+ gap: var(--space-3);
+ color: var(--text-secondary);
+ line-height: 1.6;
+
+ &::before {
+ content: "→";
+ color: var(--text-muted);
+ flex-shrink: 0;
+ margin-top: 2px;
+ }
+
+ a {
+ color: var(--link-color);
+ font-weight: 500;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+ }
+}
+
+// Project list
+.projectList {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-10);
+}
+
+.projectItem {
+ padding-bottom: var(--space-10);
+ border-bottom: 1px solid var(--border-color);
+
+ &:last-child {
+ border-bottom: none;
+ padding-bottom: 0;
+ }
+}
+
+.projectMeta {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: var(--space-3);
+}
+
+.projectType {
+ font-family: var(--font-mono);
+ font-size: var(--text-xs);
+ text-transform: uppercase;
+ letter-spacing: 0.1em;
+ color: var(--text-muted);
+}
+
+.projectLinks {
+ display: flex;
+ gap: var(--space-3);
+
+ a {
+ color: var(--text-muted);
+ transition: color var(--transition-fast);
+
+ &:hover {
+ color: var(--text-primary);
+ }
+
+ svg {
+ width: 16px;
+ height: 16px;
+ }
+ }
+}
+
+.projectName {
+ font-size: var(--text-xl);
+ font-weight: 600;
+ margin-bottom: var(--space-3);
+
+ a {
+ color: var(--text-primary);
+ text-decoration: none;
+ transition: color var(--transition-fast);
+
+ &:hover {
+ color: var(--link-color);
+ }
+ }
+}
+
+.projectDescription {
+ color: var(--text-secondary);
+ line-height: 1.7;
+ margin-bottom: var(--space-4);
+
+ strong {
+ color: var(--text-primary);
+ font-weight: 500;
+ }
+}
+
+.techStack {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--space-2);
+}
+
+.techTag {
+ font-family: var(--font-mono);
+ font-size: var(--text-xs);
+ padding: var(--space-1) var(--space-3);
+ background: var(--bg-tertiary);
+ border-radius: var(--radius-sm);
+ color: var(--text-muted);
+}
+
+.techMore {
+ font-family: var(--font-mono);
+ font-size: var(--text-xs);
+ color: var(--text-faint);
+}
+
+// Contact section
+.contactIntro {
+ font-size: var(--text-lg);
+ color: var(--text-secondary);
+ line-height: 1.8;
+ margin-bottom: var(--space-8);
+ max-width: var(--max-width-narrow);
+
+ @media (max-width: 640px) {
+ font-size: var(--text-base);
+ }
+}
+
+.contactGrid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: var(--space-4);
+
+ @media (max-width: 640px) {
+ grid-template-columns: 1fr;
+ }
+}
+
+.contactCard {
+ display: flex;
+ align-items: center;
+ gap: var(--space-4);
+ padding: var(--space-5);
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius-lg);
+ text-decoration: none;
+ transition: all var(--transition-base);
+
+ &:hover {
+ border-color: var(--border-hover);
+ background: var(--bg-tertiary);
+ }
+}
+
+.contactIcon {
+ width: 24px;
+ height: 24px;
+ color: var(--text-muted);
+ flex-shrink: 0;
+}
+
+.contactInfo {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-1);
+ min-width: 0;
+}
+
+.contactLabel {
+ font-size: var(--text-xs);
+ text-transform: uppercase;
+ letter-spacing: 0.1em;
+ color: var(--text-muted);
+}
+
+.contactText {
+ font-size: var(--text-sm);
+ color: var(--text-primary);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+// Existing legacy styles (keeping for backwards compatibility)
+.mainText {
+ color: var(--text-secondary);
+ line-height: 1.7;
+ margin-bottom: var(--space-4);
+
+ a {
+ color: var(--link-color);
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+}
+
+.subheading {
+ font-size: var(--text-lg);
+ font-weight: 600;
+ color: var(--text-primary);
+ margin-top: var(--space-6);
+ margin-bottom: var(--space-3);
+}
+
+.updateList {
+ list-style: disc;
+ padding-left: var(--space-6);
+
+ li {
+ margin-bottom: var(--space-2);
+ color: var(--text-secondary);
+ line-height: 1.6;
+
+ &::marker {
+ color: var(--text-muted);
+ }
+ }
+}
+
+.updateDate {
+ color: var(--text-muted);
+ font-weight: 500;
+
+ &::after {
+ content: ": ";
+ }
+}
+
+.updateText {
+ a {
+ color: var(--link-color);
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+}
+
+.itemList {
+ list-style: disc;
+ padding-left: var(--space-6);
+
+ li {
+ margin-bottom: var(--space-3);
+ color: var(--text-secondary);
+ line-height: 1.6;
+
+ &::marker {
+ color: var(--text-muted);
+ }
+
+ a {
+ color: var(--link-color);
+ font-weight: 600;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+
+ strong {
+ color: var(--text-primary);
+ }
+ }
+}
+
+.itemDescription {
+ color: var(--text-secondary);
+}
+
+.projectGrid {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-6);
+}
+
+.projectCard {
+ padding: var(--space-5);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius-md);
+ background: var(--bg-secondary);
+ transition: all var(--transition-base);
+
+ &:hover {
+ border-color: var(--border-hover);
+ box-shadow: var(--shadow-sm);
+ }
+}
+
+.projectHeader {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ margin-bottom: var(--space-3);
+}
+
+.projectTitle {
+ font-size: var(--text-lg);
+ font-weight: 600;
+ margin: 0;
+
+ a {
+ color: var(--text-primary);
+ text-decoration: none;
+
+ &:hover {
+ color: var(--link-color);
+ }
+ }
+}
+
+.projectLink {
+ color: var(--text-muted);
+ transition: color var(--transition-fast);
+
+ &:hover {
+ color: var(--link-color);
+ }
+
+ svg {
+ width: 16px;
+ height: 16px;
+ }
+}
+
+.skillsContainer {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-6);
+}
+
+.skillCategory {
+ &:not(:last-child) {
+ padding-bottom: var(--space-6);
+ border-bottom: 1px solid var(--border-color);
+ }
+}
+
+.skillCategoryTitle {
+ font-size: var(--text-base);
+ font-weight: 600;
+ color: var(--text-primary);
+ margin-bottom: var(--space-3);
+}
+
+.skillTags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--space-2);
+}
+
+.skillTag {
+ font-size: var(--text-sm);
+ padding: var(--space-2) var(--space-4);
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius-md);
+ color: var(--text-secondary);
+ transition: all var(--transition-fast);
+
+ &:hover {
+ border-color: var(--border-hover);
+ color: var(--text-primary);
+ }
+}
+
+.contactLinks {
+ display: flex;
+ gap: var(--space-4);
+ margin-top: var(--space-4);
+ flex-wrap: wrap;
+}
+
+.contactLink {
+ color: var(--link-color);
+ font-weight: 500;
+
+ &:hover {
+ text-decoration: underline;
+ }
+}
+
+// Dark mode
+:global([data-theme='dark']) {
+ .contactCard {
+ background: var(--bg-tertiary);
+
+ &:hover {
+ background: var(--bg-card);
+ }
+ }
+
+ .techTag {
+ background: var(--bg-card);
+ }
+}
diff --git a/components/redesign/sections/Skills.jsx b/components/redesign/sections/Skills.jsx
new file mode 100644
index 000000000..46a1e52db
--- /dev/null
+++ b/components/redesign/sections/Skills.jsx
@@ -0,0 +1,55 @@
+import { motion } from 'framer-motion';
+import Card from '../Card';
+import styles from './Sections.module.scss';
+
+const skillVariants = {
+ hidden: { opacity: 0 },
+ visible: {
+ opacity: 1,
+ transition: {
+ staggerChildren: 0.05,
+ },
+ },
+};
+
+const tagVariants = {
+ hidden: { opacity: 0, scale: 0.8 },
+ visible: {
+ opacity: 1,
+ scale: 1,
+ transition: { duration: 0.3 },
+ },
+};
+
+export default function Skills({ data }) {
+ const categories = data || [];
+
+ return (
+
+
+ {categories.map((category, index) => (
+
+
{category.title}
+
+ {category.skills.map((skill, i) => (
+
+ {skill}
+
+ ))}
+
+
+ ))}
+
+
+ );
+}
diff --git a/components/redesign/sections/Work.jsx b/components/redesign/sections/Work.jsx
new file mode 100644
index 000000000..ea1615fa7
--- /dev/null
+++ b/components/redesign/sections/Work.jsx
@@ -0,0 +1,117 @@
+import { motion } from 'framer-motion';
+import { useInView } from 'react-intersection-observer';
+import { FaExternalLinkAlt, FaGithub } from 'react-icons/fa';
+import styles from './Sections.module.scss';
+
+const containerVariants = {
+ hidden: { opacity: 0 },
+ visible: {
+ opacity: 1,
+ transition: {
+ staggerChildren: 0.15,
+ },
+ },
+};
+
+const itemVariants = {
+ hidden: { opacity: 0, y: 20 },
+ visible: {
+ opacity: 1,
+ y: 0,
+ transition: { duration: 0.5, ease: 'easeOut' },
+ },
+};
+
+export default function Work({ data }) {
+ const [ref, inView] = useInView({
+ triggerOnce: true,
+ threshold: 0.1,
+ });
+
+ const projects = data || [];
+
+ return (
+
+
+
+ 02
+ Work
+
+
+
+ {projects.map((project, index) => (
+
+
+
+ {project.type || 'Project'}
+
+
+ {project.url && (
+
+
+
+ )}
+ {project.repo && project.repo !== 'Private' && (
+
+
+
+ )}
+
+
+
+
+ {project.url ? (
+
+ {project.project}
+
+ ) : (
+ project.project
+ )}
+
+
+
+ {project.descriptionTitle} {project.description}
+
+
+ {project.stack && project.stack.length > 0 && (
+
+ {project.stack.slice(0, 5).map((tech, i) => (
+
+ {tech.name}
+
+ ))}
+ {project.stack.length > 5 && (
+
+ +{project.stack.length - 5}
+
+ )}
+
+ )}
+
+ ))}
+
+
+
+ );
+}
diff --git a/components/sections/index/about.jsx b/components/sections/index/about.jsx
deleted file mode 100644
index aa507db8e..000000000
--- a/components/sections/index/about.jsx
+++ /dev/null
@@ -1,73 +0,0 @@
-// Core packages
-import Image from 'next/image'
-
-// Section structure
-import Section from '../../structure/section';
-import Container from '../../structure/container';
-
-// Section general blocks
-import SectionTitle from '../../blocks/section.title.block'
-import SectionGridBg from '../../blocks/section.grid.block'
-
-// Section specific blocks
-import BadgesBlock from '../../blocks/about.badges.block'
-import CopyBlock from '../../blocks/about.copy.block'
-
-// Section scss
-import about from '../../../styles/sections/index/about.module.scss';
-
-/**
- * Section: About
- * An overview of yourself.
- * Highlight your top level attributes and disciplines.
- *
- * @returns {jsx}
- */
-export default function About() {
- return (
-
-
-
-
-
-
- {/*
*/}
-
-
-
-
-
-
-
-
- )
-}
-
-const methods = [
- { key: 'planet-moon', name: 'User Research', type: 'fad' },
- { key: 'qrcode', name: 'Digital Strategy', type: 'fad' },
- { key: 'window', name: 'Design Systems', type: 'fad' },
- { key: 'cubes', name: 'Product Strategy', type: 'far' },
- { key: 'layer-plus', name: 'Brand Strategy', type: 'fad' },
- { key: 'solar-system', name: 'Operations', type: 'fad' },
-]
\ No newline at end of file
diff --git a/components/sections/index/career.jsx b/components/sections/index/career.jsx
deleted file mode 100644
index f9d8fe06e..000000000
--- a/components/sections/index/career.jsx
+++ /dev/null
@@ -1,191 +0,0 @@
-// Core packages
-import Image from 'next/image'
-
-import Badges from '../../utils/badge.list.util'
-
-// Section structure
-import Section from '../../structure/section';
-import Container from '../../structure/container';
-
-// Section general blocks
-import SectionTitle from '../../blocks/section.title.block'
-import SectionGridBg from '../../blocks/section.grid.block'
-
-// Career scss
-import career from '../../../styles/sections/index/career.module.scss'
-
-/**
- * Section: Career
- *
- * @returns {jsx}
- */
-export default function Career() {
- return (
-
-
-
-
-
-
-
- My Supply Co.
- Permanent Full-time
- Apr 2019 - Present · 3 yrs 10 mos
- Vancouver, British Columbia, Canada
-
-
- My Supply Co. helps Canadians manage mental and physical health with naturally occurring nootropic and adaptogenic products. They carry products with complex attributes, aiming to solve a large variety of personal care needs — this requires an extremely customized and evolving approach to how the store is built and functions.
-
-
-
-
-
-
-
-
-
-
- I am responsible for the ideation, planning, and development of new consumer goods—and customer and employee facing microservice software. During these projects I work with key stakeholders within our company and supplychain to ensure and meet quality goals across multiple domains.
-
-
-
-
-
-
-
-
-
- As the lead full stack developer I am responsible for all software development, CI/CD, and QA. This is for the front end, APIs, and the back end. Additionally I was tasked with identifying and analyzing weak points in the customer journey and employee workflows. Each project had to be estimated and prioritized based on its workload and immediate impact to efficiency or revenue. Some of these projects have been so successful internally that we have planned refactoring for commercialization.
-
-
- Some key projects complete during this time 👇
-
-
-
- Product attribute and settings automated testing
- Eradicated critical data input errors
-
-
- Inventory management reporting and automation
- Decreased purchasing labour by ~80%
-
-
- Sales management plugin with AJAX shopping cart integration
- Increased AOV by 8.3%
-
-
- Bespoke ID verification software and WooCommerce integration
- Decreased Credit Card fraud by 98%
-
-
-
-
-
-
-
-
-
-
-
- I was brought on to help fill multiple creative rolls in a small start-up environment. Working with the marketing team to create the brand and logos — designing and developing a new front end for the website — and improving the users experience and store KPIs through design and merchandising optimizations.
-
-
- Some key projects completed during this time 👇
-
-
-
- Full functionality interactive shopping cart to replace cart page
- Increased conversions by 0.7%
-
- Complex multi-state animated menus represented in an elegant UI
- Strong brand confidence booster with state of the art menu
-
-
- Design and development of the site and merchandising strategy optimized for market
- 7.1% overall conversion rate
-
-
-
-
-
-
-
-
-
-
-
- Another Creative Ltd.
- Contract Part-time
- Jun 2016 - Present · 6 yrs 8 mos
- Vancouver, British Columbia, Canada
-
-
- Another Creative is a full stack agency that helps deliver exceptional digital experiences to small and medium businesses. Branding, Marketing, and Web/Software Development.
-
-
-
-
-
-
-
-
- West Coast Electronics
- Permanent Full-time
- Jan 2006 - Nov 2011 · 5 yrs 11 mos
- Vancouver, British Columbia, Canada
-
-
I was the Electronics Wizard 🧙♂️
-
West Coast Electronics was a repair shop that fixed computers, consoles, and cell phones.
-
-
-
-
-
-
- )
-}
-
-const fullStack = [
- { key: 'javascript', name: 'JavaScript', type: 'devicon' },
- { key: 'nodejs', name: 'NodeJS', type: 'devicon' },
- { key: 'react', name: 'React', type: 'devicon' },
- { key: 'nextjs', name: 'NextJS', type: 'devicon' },
- { key: 'php', name: 'PHP', type: 'devicon' },
- { key: 'wordpress', name: 'WordPress', type: 'devicon' },
- { key: 'woocommerce', name: 'WooCommerce', type: 'devicon' },
- { key: 'html5', name: 'HTML5', type: 'devicon' },
- { key: 'css3', name: 'CSS3', type: 'devicon' },
- { key: 'sass', name: 'SASS', type: 'devicon' },
- { key: 'git', name: 'Git', type: 'devicon' },
- { key: 'mysql', name: 'MySQL', type: 'devicon' },
- { key: 'mongodb', name: 'MongoDB', type: 'devicon' },
-]
-
-const stack = [
- { key: 'javascript', name: 'JavaScript', type: 'devicon' },
- { key: 'nodejs', name: 'NodeJS', type: 'devicon' },
- { key: 'react', name: 'React', type: 'devicon' },
- { key: 'nextjs', name: 'NextJS', type: 'devicon' },
- { key: 'php', name: 'PHP', type: 'devicon' },
- { key: 'wordpress', name: 'WordPress', type: 'devicon' },
- { key: 'woocommerce', name: 'WooCommerce', type: 'devicon' },
- { key: 'html5', name: 'HTML5', type: 'devicon' },
- { key: 'css3', name: 'CSS3', type: 'devicon' },
- { key: 'sass', name: 'SASS', type: 'devicon' },
- { key: 'git', name: 'Git', type: 'devicon' },
- { key: 'mysql', name: 'MySQL', type: 'devicon' },
- { key: 'mongodb', name: 'MongoDB', type: 'devicon' },
-]
\ No newline at end of file
diff --git a/components/sections/index/hero.jsx b/components/sections/index/hero.jsx
deleted file mode 100644
index ff05c3440..000000000
--- a/components/sections/index/hero.jsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import { useState } from 'react';
-import { TypeAnimation } from 'react-type-animation';
-
-import Section from '../../structure/section';
-import Container from '../../structure/container';
-
-import space from '../../utils/spacing.util';
-
-import Icon from '../../utils/icon.util'
-
-import HeroBg from '../../blocks/hero.bg/bg-color-1';
-
-import hero from '../../../styles/sections/index/hero.module.scss';
-import button from '../../../styles/blocks/button.module.scss';
-
-import content from '../../../content/index/hero.json'
-
-
-/**
- * TO DO LIST
- *
- * - Create a typog.modules.scss
- * Load this module onto every component, and use predefined typography classes to keep typography consistent
- *
- * - space.modules.scss
- * Load this module onto every component, and use predefined spacial classes to keep geometry consistent
- */
-
-export default function Hero() {
-
- const [typingStatus, setTypingStatus] = useState('Initializing');
-
- return (
-
-
- { setTypingStatus('typing') },
- content.intro.start,
- () => { setTypingStatus('typed') },
- content.intro.deleteDelay,
- () => { setTypingStatus('deleting') },
- content.intro.end,
- () => { setTypingStatus('deleted') },
- content.intro.restartDelay,
- ]}
- speed={content.intro.speed}
- deletionSpeed={content.intro.deletionSpeed}
- wrapper={content.intro.wrapper}
- repeat={Infinity}
- />
-
-
- {content.header.name}
-
-
- {content.header.usp}
-
-
-
-
- { content.paragraph }
-
-
-
- window.location = 'mailto:hello@andrewnelson.net' } >
- {content.buttons.primary.title}
-
- window.open("https://www.linkedin.com/in/--andrewnelson/", "_blank") } >
- {content.buttons.secondary.title}
-
-
-
-
-
- )
-}
\ No newline at end of file
diff --git a/components/sections/index/looking.jsx b/components/sections/index/looking.jsx
deleted file mode 100644
index 443881aa4..000000000
--- a/components/sections/index/looking.jsx
+++ /dev/null
@@ -1,37 +0,0 @@
-// Section structure
-import Section from '../../structure/section';
-import Container from '../../structure/container';
-
-// Specing util
-import Spacing from '../../utils/spacing.util';
-
-// Section general blocks
-import SectionGridBg from '../../blocks/section.grid.block'
-import SectionTitle from '../../blocks/section.title.block'
-
-// Section scss
-import looking from '../../../styles/sections/index/looking.module.scss';
-import section from '../../../styles/blocks/section.title.module.scss'
-
-/**
- * Section: Looking
- * Declare your employment intentions 🚀
- *
- * @returns {jsx}
- */
-export default function Looking() {
- return (
-
-
- I'm currently looking for employment.
- Senior : {
- Front End Engineer ,
- User Experience Designer
- }
- I am particularily interested in product facing postions where I can help make an organization wide impact.
- {/* Senior User Experience Designer */}
- {/* with a focus on Product Design.
*/}
-
-
- )
-}
\ No newline at end of file
diff --git a/components/sections/index/technical.jsx b/components/sections/index/technical.jsx
deleted file mode 100644
index 5b3fc85b0..000000000
--- a/components/sections/index/technical.jsx
+++ /dev/null
@@ -1,103 +0,0 @@
-// Core packages
-import Image from 'next/image'
-
-// Section structure
-import Section from '../../structure/section';
-import Container from '../../structure/container';
-
-// Section general blocks
-import SectionTitle from '../../blocks/section.title.block'
-import SectionGridBg from '../../blocks/section.grid.block'
-
-// Section specific blocks
-import BadgesBlock from '../../blocks/about.badges.block'
-import CopyBlock from '../../blocks/about.copy.block'
-
-// Section scss
-import about from '../../../styles/sections/index/about.module.scss'
-
-/**
- * Section: Technical
- * Highlight your technical skills with a short blurb about you,
- * Then display the programs you are proficient with and the technologies you use if applicable.
- *
- * @returns {jsx}
- */
-export default function Technical() {
- return (
-
- )
-}
-
-const software = [
- { key: 'photoshop', name: 'Photoshop', type: 'devicon' },
- { key: 'illustrator', name: 'Illustrator', type: 'devicon' },
- { key: 'figma', name: 'Figma', type: 'devicon' },
- { key: 'vscode', name: 'VSCode', type: 'devicon' },
- { key: 'mailbox', name: 'Postman', type: 'fas' },
- { key: 'computer-mouse',name: 'Click Up', type: 'fas' },
- { key: 'list-music', name: 'Ableton', type: 'fas' },
- { key: 'aftereffects', name: 'After Effects', type: 'devicon' },
- { key: 'premierepro', name: 'Premiere Pro', type: 'devicon' },
-]
-
-const tech = [
- { key: 'javascript', name: 'JavaScript', type: 'devicon' },
- { key: 'nodejs', name: 'NodeJS', type: 'devicon' },
- { key: 'react', name: 'React', type: 'devicon' },
- { key: 'nextjs', name: 'NextJS', type: 'devicon' },
- { key: 'jquery', name: 'jQuery', type: 'devicon' },
- { key: 'php', name: 'PHP', type: 'devicon' },
- { key: 'wordpress', name: 'WordPress', type: 'devicon' },
- { key: 'woocommerce', name: 'WooCommerce', type: 'devicon' },
- { key: "google", name: "GA4/GTM", type: "devicon" },
- { key: 'html5', name: 'HTML5', type: 'devicon' },
- { key: 'css3', name: 'CSS3', type: 'devicon' },
- { key: 'sass', name: 'SASS', type: 'devicon' },
- { key: 'git', name: 'Git', type: 'devicon' },
- { key: 'mysql', name: 'MySQL', type: 'devicon' },
- { key: 'mongodb', name: 'MongoDB', type: 'devicon' },
-]
\ No newline at end of file
diff --git a/components/sections/projects/featured.jsx b/components/sections/projects/featured.jsx
index 10f0c018b..d159153d8 100644
--- a/components/sections/projects/featured.jsx
+++ b/components/sections/projects/featured.jsx
@@ -18,8 +18,8 @@ export default function FeaturedProjects() {
{
content.map( (data, index) => {
return (
diff --git a/content/_settings.json b/content/_settings.json
index 7567f7853..7f8ee89b0 100644
--- a/content/_settings.json
+++ b/content/_settings.json
@@ -1,9 +1,9 @@
{
- "name": "Andrew Nelson",
+ "name": "Kyle Zhang",
"logo": "",
"username": {
- "github": "atlamors",
+ "github": "RiptideStar",
"medium": "@--andrewnelson"
},
diff --git a/content/footer.json b/content/footer.json
index f72f02857..4ae90eace 100644
--- a/content/footer.json
+++ b/content/footer.json
@@ -1,50 +1,27 @@
{
"acknowledgments": [
{
- "person": "Jihad Hassan - Marketing Director",
- "link": "",
+ "person": "Gad Allon - Professor, Director of M&T",
+ "link": "https://oid.wharton.upenn.edu/profile/gadallon/",
"note": "Thank you for all the advice and feedback."
- },
- {
- "person": "Colorpong - Artist",
- "link": "ttps://www.youworkforthem.com/designer/536/colorpong?aff=1115",
- "note": "Checkout their amazing vector illustrations."
- },
- {
- "person": "Brittany Chiang - Software Engineer",
- "link": "https://brittanychiang.com/",
- "note": "A major inspiration to create an open source theme."
- },
- {
- "person": "Vercel - Platform",
- "link": "https://vercel.com/docs",
- "note": "Host your own Next.js project for free!"
}
],
"links": [
{
- "person": "YWFT Creative Marketplace",
- "link": "https://www.youworkforthem.com/?aff=1115",
- "note": "Best in class creative assets."
+ "person": "Jerome Fisher Program in Management & Technology",
+ "link": "https://fisher.wharton.upenn.edu/",
+ "note": "Dual degree program offering BSE/BAS from Penn Engineering and BS in Economics from Wharton."
}
],
"social": [
{
- "url": "https://medium.com/@--andrewnelson",
- "icon": "medium"
- },
- {
- "url": "https://dev.to/andrewnelson",
- "icon": "dev"
- },
- {
- "url": "https://www.linkedin.com/in/--andrewnelson/",
+ "url": "https://www.linkedin.com/in/zhangkyle/",
"icon": "linkedin"
},
{
- "url": "https://github.com/atlamors",
+ "url": "https://github.com/RiptideStar",
"icon": "github"
}
]
diff --git a/content/index/hero.json b/content/index/hero.json
index d11d50feb..39a8222b2 100644
--- a/content/index/hero.json
+++ b/content/index/hero.json
@@ -1,6 +1,6 @@
{
"intro": {
- "start": "const Andrew = ( name, passion ) =>",
+ "start": "founder, designer, engineer",
"end": "Hello, my name is",
"speed": 60,
"deletionSpeed": 80,
@@ -11,11 +11,11 @@
},
"header": {
- "name": "Andrew Nelson.",
+ "name": "Kyle Zhang.",
"usp": "I design and build meaningful experiences."
},
- "paragraph": "I am a digital polymath — a constantly evolving digital creator driven by a passion for lifelong learning and the desire to leave a lasting impact.",
+ "paragraph": "Entrepreneurial UPenn M&T graduate, dabbling into everything from full stack to AI, for the gaming and healthcare industries.",
"buttons": {
"primary": {
@@ -25,7 +25,7 @@
},
"secondary": {
"title": "LinkedIn",
- "url": "",
+ "url": "https://www.linkedin.com/in/zhangkyle/",
"leaveSite": "true"
}
}
diff --git a/content/navbar.json b/content/navbar.json
index d1e27782d..726142c91 100644
--- a/content/navbar.json
+++ b/content/navbar.json
@@ -1,18 +1,7 @@
[
{
- "url": "/",
- "title": "About Me"
- },
- {
- "url": "/case-studies",
- "title": "Case Studies"
- },
- {
- "url": "/articles",
- "title": "Articles"
- },
- {
- "url": "/projects",
- "title": "Projects"
+ "url": "/links",
+ "title": "Links",
+ "id": "links"
}
]
\ No newline at end of file
diff --git a/content/projects/featured.json b/content/projects/featured.json
index 34e0a010e..357d29c86 100644
--- a/content/projects/featured.json
+++ b/content/projects/featured.json
@@ -1,53 +1,60 @@
[
- {
- "project": "My Supply Co.",
- "url": "https://mysupplyco.com",
- "repo": "Private",
- "descriptionTitle": "D2C & B2B ecommerce site and blog",
- "description": "with elegant solutions for a complex codebase and customer journey.",
- "imageOptions": [
- ],
- "images": [
- { "key": "mock-stack", "hover": "right", "h": "1200", "w": "556", "url": "/img/msc-mock_stack/03.png" },
- { "key": "mock-stack", "hover": "right", "h": "1200", "w": "556", "url": "/img/msc-mock_stack/02.png" },
- { "key": "mock-stack", "hover": "left", "h": "1200", "w": "556", "url": "/img/msc-mock_stack/01.png" }
- ],
- "stack": [
- { "key": "php", "name": "PHP", "type": "devicon" },
- { "key": "mysql", "name": "mySQL", "type": "devicon" },
- { "key": "javascript", "name": "JavaScript", "type": "devicon" },
- { "key": "jquery", "name": "jQuery", "type": "devicon" },
- { "key": "woocommerce", "name": "WooCommerce", "type": "devicon" },
- { "key": "wordpress", "name": "Wordpress", "type": "devicon" },
- { "key": "html5", "name": "HTML5", "type": "devicon" },
- { "key": "css3", "name": "CSS3", "type": "devicon" },
- { "key": "sass", "name": "SCSS", "type": "devicon" },
- { "key": "git", "name": "Git(Hub)", "type": "devicon" },
- { "key": "google", "name": "GA4/GTM/EEC", "type": "devicon" }
- ]
- },
- {
- "project": "andrewnelson.net",
- "url": "https://github.com/atlamors/portfolio",
- "repo": "Public",
- "descriptionTitle": "An open source portfolio",
- "description": "built on Next.js and React. A fast and agile MERN stack single page application.",
- "imageOptions": [
- { "key": "size", "value": "large" }
- ],
- "images": [
- { "key": "portfolio", "hover": "left", "h": "797", "w": "556", "url": "/img/portfolio-mock_single.png" }
- ],
- "stack": [
- { "key": "nextjs", "name": "Next.js", "type": "devicon" },
- { "key": "react", "name": "React", "type": "devicon" },
- { "key": "nodejs", "name": "Node.js", "type": "devicon" },
- { "key": "mongodb", "name": "MongoDB", "type": "devicon" },
- { "key": "javascript", "name": "JavaScript", "type": "devicon" },
- { "key": "html5", "name": "HTML5", "type": "devicon" },
- { "key": "css3", "name": "CSS3", "type": "devicon" },
- { "key": "sass", "name": "SCSS", "type": "devicon" },
- { "key": "git", "name": "Git(Hub)", "type": "devicon" }
- ]
- }
-]
\ No newline at end of file
+ {
+ "project": "LineupsValorant",
+ "type": "Gaming Platform",
+ "url": "https://lineupsvalorant.com",
+ "repo": "Private",
+ "descriptionTitle": "Platform for millions of Valorant players",
+ "description": "to discover and share the best agent lineups. Built with a focus on speed, accessibility, and community engagement.",
+ "stack": [
+ { "key": "mysql", "name": "MySQL", "type": "devicon" },
+ { "key": "javascript", "name": "JavaScript", "type": "devicon" },
+ { "key": "python", "name": "Python", "type": "devicon" },
+ { "key": "flask", "name": "Flask", "type": "devicon" },
+ { "key": "google", "name": "Analytics", "type": "devicon" }
+ ]
+ },
+ {
+ "project": "Robin",
+ "type": "AI Healthcare",
+ "url": "https://robin-ai.vercel.app",
+ "repo": "Private",
+ "descriptionTitle": "LLM-powered fraud detection",
+ "description": "for US government Medicaid and Medicare programs. Combines GPT-4, vector embeddings, and custom ML pipelines to identify suspicious patterns.",
+ "stack": [
+ { "key": "nextjs", "name": "Next.js", "type": "devicon" },
+ { "key": "python", "name": "Python", "type": "devicon" },
+ { "key": "openai", "name": "GPT-4", "type": "custom" },
+ { "key": "pinecone", "name": "Pinecone", "type": "custom" },
+ { "key": "fastapi", "name": "FastAPI", "type": "devicon" }
+ ]
+ },
+ {
+ "project": "NCut Visualization",
+ "type": "Research",
+ "url": null,
+ "repo": "Private",
+ "descriptionTitle": "Computer vision research",
+ "description": "on normalized cut algorithms and spectral clustering for image segmentation. Developed visualization tools to understand and improve segmentation quality.",
+ "stack": [
+ { "key": "python", "name": "Python", "type": "devicon" },
+ { "key": "pytorch", "name": "PyTorch", "type": "devicon" },
+ { "key": "numpy", "name": "NumPy", "type": "devicon" },
+ { "key": "matplotlib", "name": "Visualization", "type": "custom" }
+ ]
+ },
+ {
+ "project": "Forte",
+ "type": "Music Tech",
+ "url": null,
+ "repo": "Private",
+ "descriptionTitle": "A cappella practice companion",
+ "description": "helping vocal groups rehearse more effectively. Features pitch tracking, harmony analysis, and section-specific practice modes.",
+ "stack": [
+ { "key": "react", "name": "React", "type": "devicon" },
+ { "key": "nodejs", "name": "Node.js", "type": "devicon" },
+ { "key": "tensorflow", "name": "TensorFlow", "type": "custom" },
+ { "key": "webAudio", "name": "Web Audio", "type": "custom" }
+ ]
+ }
+]
diff --git a/content/redesign/portfolio.json b/content/redesign/portfolio.json
new file mode 100644
index 000000000..07a34ecf4
--- /dev/null
+++ b/content/redesign/portfolio.json
@@ -0,0 +1,49 @@
+{
+ "header": {
+ "name": "Kyle Zhang",
+ "tagline": "Builder. Researcher. Creator.",
+ "description": "M&T graduate from UPenn, passionate about building products at the intersection of gaming, AI, and human impact.",
+ "email": "kyle@example.com",
+ "social": {
+ "github": "https://github.com/RiptideStar",
+ "linkedin": "https://www.linkedin.com/in/zhangkyle/",
+ "twitter": "https://twitter.com/"
+ }
+ },
+
+ "about": {
+ "intro": "I'm an entrepreneurial UPenn M&T graduate who loves turning ideas into impactful products. My journey spans from building gaming tools used by millions to developing AI-powered healthcare solutions. I believe in creating technology that genuinely helps people.",
+ "highlights": [
+ {
+ "text": "Currently building AI solutions for fraud detection in ",
+ "link": {
+ "text": "government healthcare programs",
+ "url": "https://robin-ai.vercel.app"
+ },
+ "suffix": ""
+ },
+ {
+ "text": "Created ",
+ "link": {
+ "text": "LineupsValorant",
+ "url": "https://lineupsvalorant.com"
+ },
+ "suffix": ", serving millions of players worldwide"
+ },
+ {
+ "text": "Researched computer vision and ML at UPenn, contributing to NCut visualization and segmentation work",
+ "link": null,
+ "suffix": ""
+ },
+ {
+ "text": "Passionate about a cappella, exploring new cities, and finding the best local food spots",
+ "link": null,
+ "suffix": ""
+ }
+ ]
+ },
+
+ "contact": {
+ "message": "I'm always excited to connect with fellow builders, researchers, and anyone passionate about technology. Whether you have a project idea, want to collaborate, or just want to chat about gaming, AI, or food—reach out!"
+ }
+}
diff --git a/node_modules/@fortawesome/.DS_Store b/node_modules/@fortawesome/.DS_Store
new file mode 100644
index 000000000..e8be070b0
Binary files /dev/null and b/node_modules/@fortawesome/.DS_Store differ
diff --git a/package-lock.json b/package-lock.json
index 636c0ca70..086ac88dc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,5 +1,5 @@
{
- "name": "public_html",
+ "name": "portfolio",
"lockfileVersion": 3,
"requires": true,
"packages": {
@@ -24,11 +24,14 @@
"devicon": "^2.15.1",
"framer-motion": "^8.5.0",
"next": "^12.3",
+ "nodemailer": "^7.0.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-icons": "^5.3.0",
"react-intersection-observer": "^9.4.1",
"react-markdown": "^8.0.4",
"react-type-animation": "^2.1.2",
+ "resend": "^4.6.0",
"swr": "^2.0.0",
"the-new-css-reset": "^1.8.2",
"uuid": "^9.0.0"
@@ -2024,12 +2027,41 @@
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==",
"dev": true
},
+ "node_modules/@react-email/render": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@react-email/render/-/render-1.1.2.tgz",
+ "integrity": "sha512-RnRehYN3v9gVlNMehHPHhyp2RQo7+pSkHDtXPvg3s0GbzM9SQMW4Qrf8GRNvtpLC4gsI+Wt0VatNRUFqjvevbw==",
+ "dependencies": {
+ "html-to-text": "^9.0.5",
+ "prettier": "^3.5.3",
+ "react-promise-suspense": "^0.3.4"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
"node_modules/@rushstack/eslint-patch": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz",
"integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==",
"dev": true
},
+ "node_modules/@selderee/plugin-htmlparser2": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
+ "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==",
+ "dependencies": {
+ "domhandler": "^5.0.3",
+ "selderee": "^0.11.0"
+ },
+ "funding": {
+ "url": "https://ko-fi.com/killymxi"
+ }
+ },
"node_modules/@sinclair/typebox": {
"version": "0.25.21",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.21.tgz",
@@ -3623,10 +3655,9 @@
"dev": true
},
"node_modules/deepmerge": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz",
- "integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==",
- "dev": true,
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
"engines": {
"node": ">=0.10.0"
}
@@ -3746,6 +3777,30 @@
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true
},
+ "node_modules/dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ]
+ },
"node_modules/domexception": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
@@ -3758,6 +3813,33 @@
"node": ">=12"
}
},
+ "node_modules/domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "dependencies": {
+ "domelementtype": "^2.3.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+ "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
+ "dependencies": {
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
"node_modules/electron-to-chromium": {
"version": "1.4.295",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.295.tgz",
@@ -3799,7 +3881,6 @@
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
"integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
- "dev": true,
"engines": {
"node": ">=0.12"
},
@@ -5336,6 +5417,21 @@
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
+ "node_modules/html-to-text": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz",
+ "integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==",
+ "dependencies": {
+ "@selderee/plugin-htmlparser2": "^0.11.0",
+ "deepmerge": "^4.3.1",
+ "dom-serializer": "^2.0.0",
+ "htmlparser2": "^8.0.2",
+ "selderee": "^0.11.0"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/html-void-elements": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz",
@@ -5345,6 +5441,24 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/htmlparser2": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
+ "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1",
+ "entities": "^4.4.0"
+ }
+ },
"node_modules/http-proxy-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
@@ -8080,6 +8194,14 @@
"language-subtag-registry": "~0.3.2"
}
},
+ "node_modules/leac": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz",
+ "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==",
+ "funding": {
+ "url": "https://ko-fi.com/killymxi"
+ }
+ },
"node_modules/leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -9147,6 +9269,14 @@
"integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==",
"dev": true
},
+ "node_modules/nodemailer": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.5.tgz",
+ "integrity": "sha512-nsrh2lO3j4GkLLXoeEksAMgAOqxOv6QumNRVQTJwKH4nuiww6iC2y7GyANs9kRAxCexg3+lTWM3PZ91iLlVjfg==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -9465,6 +9595,18 @@
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
},
+ "node_modules/parseley": {
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz",
+ "integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==",
+ "dependencies": {
+ "leac": "^0.6.0",
+ "peberminta": "^0.9.0"
+ },
+ "funding": {
+ "url": "https://ko-fi.com/killymxi"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -9505,6 +9647,14 @@
"node": ">=8"
}
},
+ "node_modules/peberminta": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz",
+ "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==",
+ "funding": {
+ "url": "https://ko-fi.com/killymxi"
+ }
+ },
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@@ -9627,6 +9777,20 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/prettier": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
+ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
"node_modules/pretty-format": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
@@ -9764,6 +9928,14 @@
"react": "^18.2.0"
}
},
+ "node_modules/react-icons": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz",
+ "integrity": "sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/react-intersection-observer": {
"version": "9.4.1",
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.4.1.tgz",
@@ -9812,6 +9984,19 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
+ "node_modules/react-promise-suspense": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/react-promise-suspense/-/react-promise-suspense-0.3.4.tgz",
+ "integrity": "sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==",
+ "dependencies": {
+ "fast-deep-equal": "^2.0.1"
+ }
+ },
+ "node_modules/react-promise-suspense/node_modules/fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w=="
+ },
"node_modules/react-type-animation": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/react-type-animation/-/react-type-animation-2.1.2.tgz",
@@ -10071,6 +10256,17 @@
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"dev": true
},
+ "node_modules/resend": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/resend/-/resend-4.6.0.tgz",
+ "integrity": "sha512-D5T2I82FvEUYFlrHzaDvVtr5ADHdhuoLaXgLFGABKyNtQgPWIuz0Vp2L2Evx779qjK37aF4kcw1yXJDHhA2JnQ==",
+ "dependencies": {
+ "@react-email/render": "1.1.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/resolve": {
"version": "1.22.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
@@ -10241,6 +10437,17 @@
"loose-envify": "^1.1.0"
}
},
+ "node_modules/selderee": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz",
+ "integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==",
+ "dependencies": {
+ "parseley": "^0.12.0"
+ },
+ "funding": {
+ "url": "https://ko-fi.com/killymxi"
+ }
+ },
"node_modules/semver": {
"version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
diff --git a/package.json b/package.json
index 2f66a0b1c..395db20aa 100644
--- a/package.json
+++ b/package.json
@@ -26,11 +26,14 @@
"devicon": "^2.15.1",
"framer-motion": "^8.5.0",
"next": "^12.3",
+ "nodemailer": "^7.0.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-icons": "^5.3.0",
"react-intersection-observer": "^9.4.1",
"react-markdown": "^8.0.4",
"react-type-animation": "^2.1.2",
+ "resend": "^4.6.0",
"swr": "^2.0.0",
"the-new-css-reset": "^1.8.2",
"uuid": "^9.0.0"
diff --git a/pages/_app.jsx b/pages/_app.jsx
index c8fe40583..15274d9aa 100644
--- a/pages/_app.jsx
+++ b/pages/_app.jsx
@@ -2,12 +2,6 @@
import { Analytics } from '@vercel/analytics/react';
import { LazyMotion, domAnimation } from "framer-motion"
-// Utils
-import SetGridGap from '../components/utils/set.grid.util'
-
-// Structure
-import Layout from '../components/layout/layout'
-
// CSS reset (https://github.com/elad2412/the-new-css-reset.git)
import "../node_modules/the-new-css-reset/css/reset.css"
@@ -15,15 +9,13 @@ import "../node_modules/the-new-css-reset/css/reset.css"
import "@fontsource/fira-code/400.css"
import "@fontsource/fira-code/600.css"
import "@fontsource/inter/400.css"
+import "@fontsource/inter/600.css"
import "@fontsource/inter/700.css"
import "@fontsource/inter/800.css"
-// Devicon import (https://github.com/devicons/devicon)
-import '../node_modules/devicon/devicon.min.css'
-
-// Global css
-import '../styles/css/variables.css'
-import '../styles/css/global.css'
+// New redesign styles
+import '../styles/css/variables-new.css'
+import '../styles/css/global-new.css'
/**
* _app.jsx
@@ -34,14 +26,9 @@ import '../styles/css/global.css'
*/
export default function MyApp({ Component, pageProps }) {
return (
- <>
-
-
-
-
-
+
+
- >
)
-}
\ No newline at end of file
+}
diff --git a/pages/api/contact.js b/pages/api/contact.js
new file mode 100644
index 000000000..544170699
--- /dev/null
+++ b/pages/api/contact.js
@@ -0,0 +1,27 @@
+import { Resend } from 'resend';
+
+export default async function handler(req, res) {
+ if (req.method !== 'POST') {
+ return res.status(405).json({ error: 'Method not allowed' });
+ }
+
+ const { name, email, message } = req.body;
+ if (!name || !email || !message) {
+ return res.status(400).json({ error: 'Missing required fields' });
+ }
+
+ try {
+ const resend = new Resend(process.env.RESEND_API_KEY);
+ const result = await resend.emails.send({
+ from: 'onboarding@resend.dev',
+ to: 'kyle100@wharton.upenn.edu', // <-- replace with your Resend account email if different
+ subject: `${name} sent a message from Kyle's portfolio website`,
+ text: `Name: ${name}\nEmail: ${email}\nMessage: ${message}`,
+ });
+ console.log('Resend API result:', result);
+ return res.status(200).json({ success: true, result });
+ } catch (err) {
+ console.error('Resend API error:', err);
+ return res.status(500).json({ error: 'Failed to send email', details: err.message });
+ }
+}
\ No newline at end of file
diff --git a/pages/index.jsx b/pages/index.jsx
index 335ec6ebe..5ea0eda20 100644
--- a/pages/index.jsx
+++ b/pages/index.jsx
@@ -1,26 +1,48 @@
-import Hero from '../components/sections/index/hero'
-import Looking from '../components/sections/index/looking'
-import About from '../components/sections/index/about'
-import Technical from '../components/sections/index/technical'
-import Career from '../components/sections/index/career'
-import FeaturedProjects from '../components/sections/projects/featured'
-
-import Color from '../components/utils/page.colors.util'
-
-import colors from '../content/index/_colors.json'
-
-//
-export default function HomePage() {
-
- return (
- <>
-
-
- {/* */}
-
-
-
- {/* */}
- >
- );
-}
\ No newline at end of file
+import Head from 'next/head';
+import Layout from '../components/redesign/Layout';
+import Header from '../components/redesign/Header';
+import About from '../components/redesign/sections/About';
+import Work from '../components/redesign/sections/Work';
+import Contact from '../components/redesign/sections/Contact';
+
+import portfolioData from '../content/redesign/portfolio.json';
+import projectsData from '../content/projects/featured.json';
+
+export default function HomePage() {
+ return (
+ <>
+
+ Kyle Zhang | Builder & Creator
+
+
+
+
+ {/* Open Graph */}
+
+
+
+
+
+ {/* Twitter */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/pages/links/index.jsx b/pages/links/index.jsx
new file mode 100644
index 000000000..e7f1f37e1
--- /dev/null
+++ b/pages/links/index.jsx
@@ -0,0 +1,7 @@
+import ComingSoon from '../../components/sections/comingsoon';
+
+export default function LinksPage() {
+ return (
+
+ );
+}
diff --git a/public/.DS_Store b/public/.DS_Store
new file mode 100644
index 000000000..44e86253c
Binary files /dev/null and b/public/.DS_Store differ
diff --git a/public/Profile_Exported.mov b/public/Profile_Exported.mov
new file mode 100644
index 000000000..d8de89bc4
Binary files /dev/null and b/public/Profile_Exported.mov differ
diff --git a/public/Profile_Exported_KyleText.mov b/public/Profile_Exported_KyleText.mov
new file mode 100644
index 000000000..2f69fb9ff
Binary files /dev/null and b/public/Profile_Exported_KyleText.mov differ
diff --git a/public/favicon/android-chrome-192x192.png b/public/favicon/android-chrome-192x192.png
index 98735c6e0..893883bee 100644
Binary files a/public/favicon/android-chrome-192x192.png and b/public/favicon/android-chrome-192x192.png differ
diff --git a/public/favicon/android-chrome-384x384.png b/public/favicon/android-chrome-384x384.png
deleted file mode 100644
index 779207b6f..000000000
Binary files a/public/favicon/android-chrome-384x384.png and /dev/null differ
diff --git a/public/favicon/android-chrome-512x512.png b/public/favicon/android-chrome-512x512.png
new file mode 100644
index 000000000..427827b01
Binary files /dev/null and b/public/favicon/android-chrome-512x512.png differ
diff --git a/public/favicon/apple-touch-icon.png b/public/favicon/apple-touch-icon.png
index fa65be871..bcb682e03 100644
Binary files a/public/favicon/apple-touch-icon.png and b/public/favicon/apple-touch-icon.png differ
diff --git a/public/favicon/browserconfig.xml b/public/favicon/browserconfig.xml
deleted file mode 100644
index 70cb989d3..000000000
--- a/public/favicon/browserconfig.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
- #da532c
-
-
-
diff --git a/public/favicon/favicon-16x16.png b/public/favicon/favicon-16x16.png
index 7fadcd019..1f4759358 100644
Binary files a/public/favicon/favicon-16x16.png and b/public/favicon/favicon-16x16.png differ
diff --git a/public/favicon/favicon-32x32.png b/public/favicon/favicon-32x32.png
index 76949cd69..697973972 100644
Binary files a/public/favicon/favicon-32x32.png and b/public/favicon/favicon-32x32.png differ
diff --git a/public/favicon/favicon.ico b/public/favicon/favicon.ico
index 0543754a9..8664b8e89 100644
Binary files a/public/favicon/favicon.ico and b/public/favicon/favicon.ico differ
diff --git a/public/favicon/mstile-150x150.png b/public/favicon/mstile-150x150.png
deleted file mode 100644
index c9034c7a7..000000000
Binary files a/public/favicon/mstile-150x150.png and /dev/null differ
diff --git a/public/favicon/safari-pinned-tab.svg b/public/favicon/safari-pinned-tab.svg
deleted file mode 100644
index 933efbb64..000000000
--- a/public/favicon/safari-pinned-tab.svg
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-Created by potrace 1.14, written by Peter Selinger 2001-2017
-
-
-
-
-
diff --git a/public/favicon/site.webmanifest b/public/favicon/site.webmanifest
index 4bae9f961..901bd0c6f 100644
--- a/public/favicon/site.webmanifest
+++ b/public/favicon/site.webmanifest
@@ -3,17 +3,17 @@
"short_name": "",
"icons": [
{
- "src": "/favicon/android-chrome-192x192.png",
+ "src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
- "src": "/favicon/android-chrome-384x384.png",
- "sizes": "384x384",
+ "src": "/android-chrome-512x512.png",
+ "sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
-}
+}
\ No newline at end of file
diff --git a/public/headshot.jpeg b/public/headshot.jpeg
new file mode 100644
index 000000000..1b2ab2209
Binary files /dev/null and b/public/headshot.jpeg differ
diff --git a/public/img/.DS_Store b/public/img/.DS_Store
new file mode 100644
index 000000000..fda075ee1
Binary files /dev/null and b/public/img/.DS_Store differ
diff --git a/public/img/Robin.png b/public/img/Robin.png
new file mode 100644
index 000000000..5357494d6
Binary files /dev/null and b/public/img/Robin.png differ
diff --git a/public/img/msc-mock_stack/left-phone-LineupsValorant-2.png b/public/img/msc-mock_stack/left-phone-LineupsValorant-2.png
new file mode 100644
index 000000000..b0e10db9f
Binary files /dev/null and b/public/img/msc-mock_stack/left-phone-LineupsValorant-2.png differ
diff --git a/public/img/msc-mock_stack/left2-phone-LineupsValorant.png b/public/img/msc-mock_stack/left2-phone-LineupsValorant.png
new file mode 100644
index 000000000..844bb6dfd
Binary files /dev/null and b/public/img/msc-mock_stack/left2-phone-LineupsValorant.png differ
diff --git a/public/img/msc-mock_stack/mac-LineupsValorant.png b/public/img/msc-mock_stack/mac-LineupsValorant.png
new file mode 100644
index 000000000..1cdd414fe
Binary files /dev/null and b/public/img/msc-mock_stack/mac-LineupsValorant.png differ
diff --git a/public/img/msc-mock_stack/mac2-LineupsValorant.png b/public/img/msc-mock_stack/mac2-LineupsValorant.png
new file mode 100644
index 000000000..0ab8fb445
Binary files /dev/null and b/public/img/msc-mock_stack/mac2-LineupsValorant.png differ
diff --git a/styles/css/global-new.css b/styles/css/global-new.css
new file mode 100644
index 000000000..56a65cfb2
--- /dev/null
+++ b/styles/css/global-new.css
@@ -0,0 +1,164 @@
+/* Global Styles - Minimalist Portfolio */
+
+* {
+ box-sizing: border-box;
+}
+
+::selection {
+ background: var(--text-primary);
+ color: var(--bg-primary);
+}
+
+html {
+ font-size: 16px;
+ scroll-behavior: smooth;
+}
+
+body {
+ font-family: var(--font-sans);
+ background: var(--bg-primary);
+ color: var(--text-primary);
+ line-height: 1.7;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+#__next {
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+}
+
+/* Typography */
+h1, h2, h3, h4, h5, h6 {
+ font-weight: 600;
+ line-height: 1.3;
+ color: var(--text-primary);
+ margin: 0;
+}
+
+h1 {
+ font-size: var(--text-4xl);
+ font-weight: 500;
+ letter-spacing: -0.02em;
+}
+
+h2 {
+ font-size: var(--text-2xl);
+ font-weight: 600;
+ letter-spacing: -0.01em;
+}
+
+h3 {
+ font-size: var(--text-xl);
+ font-weight: 600;
+}
+
+p {
+ color: var(--text-secondary);
+ margin: 0;
+}
+
+/* Links */
+a {
+ color: var(--link-color);
+ text-decoration: none;
+ transition: color var(--transition-fast);
+}
+
+a:hover {
+ color: var(--link-hover);
+}
+
+/* Lists */
+ul, ol {
+ padding-left: var(--space-6);
+ margin: 0;
+}
+
+ul li, ol li {
+ color: var(--text-secondary);
+ margin-bottom: var(--space-2);
+}
+
+ul li::marker, ol li::marker {
+ color: var(--text-muted);
+}
+
+/* Buttons */
+button {
+ cursor: pointer;
+ font-family: inherit;
+ border: none;
+ background: none;
+}
+
+/* Images */
+img {
+ max-width: 100%;
+ height: auto;
+}
+
+/* Focus styles for accessibility */
+:focus-visible {
+ outline: 2px solid var(--link-color);
+ outline-offset: 2px;
+}
+
+/* Utility classes */
+.mono {
+ font-family: var(--font-mono);
+}
+
+.text-muted {
+ color: var(--text-muted);
+}
+
+.text-secondary {
+ color: var(--text-secondary);
+}
+
+/* Smooth page transitions */
+.page-transition-enter {
+ opacity: 0;
+ transform: translateY(10px);
+}
+
+.page-transition-enter-active {
+ opacity: 1;
+ transform: translateY(0);
+ transition: opacity 300ms ease, transform 300ms ease;
+}
+
+.page-transition-exit {
+ opacity: 1;
+}
+
+.page-transition-exit-active {
+ opacity: 0;
+ transition: opacity 200ms ease;
+}
+
+/* Scrollbar styling */
+::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+
+::-webkit-scrollbar-track {
+ background: var(--bg-secondary);
+}
+
+::-webkit-scrollbar-thumb {
+ background: var(--border-color);
+ border-radius: var(--radius-full);
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: var(--border-hover);
+}
+
+/* Main content area */
+main {
+ flex: 1;
+}
diff --git a/styles/css/global.css b/styles/css/global.css
deleted file mode 100644
index d3296a0b9..000000000
--- a/styles/css/global.css
+++ /dev/null
@@ -1 +0,0 @@
-::-moz-selection{color:var(--background);background:var(--secondary)}::selection{color:var(--background);background:var(--secondary)}html{font-size:16px;font-family:var(--font-sans);color:var(--primary-dim);background:var(--background);text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased}#__next{width:100%;overflow-x:hidden}img{border-radius:.5rem;filter:brightness(var(--brightness-low))}img:hover{filter:brightness(var(--brightness-high))}button.button{cursor:pointer;font-family:var(--font-accent);font-size:1rem;font-weight:700;padding:.75rem 2.5rem;border-radius:99rem;border:none;margin-right:1rem;transition:all,cubic-bezier(0.4, 0, 0.2, 1),750ms}button.button:hover{transition:all,cubic-bezier(0.4, 0, 0.2, 1),750ms}h1{font-size:var(--font-xl);font-family:var(--font-sans);font-weight:600;letter-spacing:-0.1rem}h2{color:var(--primary);font-size:var(--font-xl);font-family:var(--font-sans);font-weight:700;letter-spacing:-0.05rem}h3{font-size:var(--font-m);font-family:var(--font-sans);color:var(--primary);font-weight:600;letter-spacing:-0.01rem}h4{font-size:var(--font-xs);font-family:var(--font-sans);font-weight:600;text-transform:uppercase;letter-spacing:.1rem}h5{font-size:var(--font-m);font-family:var(--font-sans);color:var(--primary);font-weight:600;letter-spacing:-0.01rem}p{font-size:var(--font-r);font-family:var(--font-sans);line-height:1.6;letter-spacing:-0.02rem}p.subtitle{font-family:var(--font-accent);font-size:var(--font-r-s);font-weight:600;letter-spacing:0}a{font-weight:600;color:var(--primary)}a:hover{color:var(--primary-bright)}a:hover [data-prefix=far][data-icon=arrow-up-right-from-square]{color:var(--primary)}a:hover h3{color:var(--primary-bright)}a [data-prefix=far][data-icon=arrow-up-right-from-square]{height:.75rem;vertical-align:-1.5px;color:var(--primary-dim)}a svg{margin-left:.25rem}.noEvents{pointer-events:none}.list{list-style:disc;margin-left:1.5rem}.list li::marker{content:normal}.leaveSite:after{content:"↗";position:relative;font-size:inherit;line-height:0;vertical-align:-1px;margin-left:.5rem;text-decoration:none;text-rendering:optimizeLegibility;white-space:nowrap;font-feature-settings:"liga";-webkit-font-smoothing:antialiased}.borderBottom{border-bottom:1px solid var(--primary-dark)}#gradient-canvas{position:absolute;z-index:-1;opacity:100%;left:0;top:0;width:100%;height:100%;transform:rotate(180deg);aspect-ratio:auto;--gradient-color-1: var( --mesh-color-1 );--gradient-color-2: var( --mesh-color-2 );--gradient-color-3: var( --mesh-color-3 );--gradient-color-4: var( --mesh-color-4 )}.highlight{--looking-bg-1: var(--neon-1-1);--looking-bg-2: var(--neon-1-2);width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;background:var(--bar-gradient);--bar-gradient: linear-gradient( 90deg, var(--looking-bg-1) 0%, var(--looking-bg-2) 100% );-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:rgba(0,0,0,0)}/*# sourceMappingURL=global.css.map */
\ No newline at end of file
diff --git a/styles/css/global.css.map b/styles/css/global.css.map
deleted file mode 100644
index d79f07c20..000000000
--- a/styles/css/global.css.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["global.css","../scss/global.scss","../scss/_mixins.scss"],"names":[],"mappings":"AAAA,iBCGA,uBACC,CAAA,2BACA,CDLD,YCGA,uBACC,CAAA,2BACA,CAAA,KAGD,cACC,CAAA,4BACA,CAAA,wBAEA,CAAA,4BACA,CAAA,iCAEA,CAAA,kCACG,CAAA,QAGJ,UACC,CAAA,iBACG,CAAA,IAGJ,mBACC,CAAA,wCAEA,CAAA,UAEA,yCACC,CAAA,cAIF,cACC,CAAA,8BACA,CAAA,cACA,CAAA,eACA,CAAA,qBACA,CAAA,mBACA,CAAA,WACA,CAAA,iBACA,CAAA,iDCpBA,CAAA,oBDuBA,iDCvBA,CAAA,GD4BD,wBACC,CAAA,4BACA,CAAA,eACA,CAAA,sBACA,CAAA,GAGD,oBACC,CAAA,wBACA,CAAA,4BACA,CAAA,eACA,CAAA,uBACG,CAAA,GAGJ,uBACC,CAAA,4BACA,CAAA,oBACA,CAAA,eACA,CAAA,uBACA,CAAA,GAGD,wBACC,CAAA,4BACA,CAAA,eACA,CAAA,wBACA,CAAA,oBACA,CAAA,GAGD,uBACC,CAAA,4BACA,CAAA,oBACA,CAAA,eACA,CAAA,uBACA,CAAA,EAGD,uBACC,CAAA,4BACA,CAAA,eACA,CAAA,uBACA,CAAA,WAEA,8BACC,CAAA,yBACA,CAAA,eACA,CAAA,gBACA,CAAA,EAIF,eACC,CAAA,oBACA,CAAA,QAEA,2BACC,CAAA,gEAEA,oBACC,CAAA,WAGD,2BACC,CAAA,0DAMF,aACC,CAAA,qBACA,CAAA,wBACA,CAAA,MAGD,kBACC,CAAA,UAIF,mBACC,CAAA,MAGD,eACC,CAAA,kBACA,CAAA,iBAEC,cACC,CAAA,iBAMF,WACC,CAAA,iBACA,CAAA,iBACA,CAAA,aACA,CAAA,mBACA,CAAA,iBACA,CAAA,oBACA,CAAA,iCACA,CAAA,kBACA,CAAA,4BACA,CAAA,kCACA,CAAA,cAIF,2CACC,CAAA,iBAGD,iBACC,CAAA,UACG,CAAA,YACH,CAAA,MACG,CAAA,KACA,CAAA,UACA,CAAA,WACA,CAAA,wBACA,CAAA,iBACA,CAAA,yCACA,CAAA,yCACH,CAAA,yCACA,CAAA,yCACA,CAAA,WAGD,+BACC,CAAA,+BACA,CAAA,yBAEA,CAFA,sBAEA,CAFA,iBAEA,CAAA,8BACA,CAAA,0FACA,CAAA,4BAOA,CAAA,oBACA,CAAA,qCACA","file":"global.css"}
\ No newline at end of file
diff --git a/styles/css/variables-new.css b/styles/css/variables-new.css
new file mode 100644
index 000000000..6992f4956
--- /dev/null
+++ b/styles/css/variables-new.css
@@ -0,0 +1,129 @@
+/* Portfolio Design System - Minimalist & Clean */
+
+/* Fonts - Clean, modern typography */
+:root {
+ --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", sans-serif;
+ --font-mono: "Fira Code", "SF Mono", "Monaco", "Inconsolata", monospace;
+ --font-serif: "Georgia", "Times New Roman", serif;
+
+ /* Font sizes - refined scale */
+ --text-xs: 0.75rem;
+ --text-sm: 0.875rem;
+ --text-base: 1rem;
+ --text-lg: 1.125rem;
+ --text-xl: 1.25rem;
+ --text-2xl: 1.5rem;
+ --text-3xl: 2rem;
+ --text-4xl: 2.75rem;
+ --text-5xl: 3.5rem;
+
+ /* Spacing scale */
+ --space-1: 0.25rem;
+ --space-2: 0.5rem;
+ --space-3: 0.75rem;
+ --space-4: 1rem;
+ --space-5: 1.25rem;
+ --space-6: 1.5rem;
+ --space-8: 2rem;
+ --space-10: 2.5rem;
+ --space-12: 3rem;
+ --space-16: 4rem;
+ --space-20: 5rem;
+ --space-24: 6rem;
+ --space-32: 8rem;
+
+ /* Layout */
+ --max-width: 800px;
+ --max-width-narrow: 640px;
+ --mobile: 640px;
+
+ /* Border radius */
+ --radius-sm: 4px;
+ --radius-md: 8px;
+ --radius-lg: 12px;
+ --radius-xl: 16px;
+ --radius-full: 9999px;
+
+ /* Transitions */
+ --transition-fast: 150ms ease;
+ --transition-base: 200ms ease;
+ --transition-slow: 300ms ease;
+ --transition-slower: 500ms ease;
+
+ /* Dot matrix colors */
+ --dot-inactive: #e5e7eb;
+}
+
+/* Light theme (default) */
+:root,
+:root[data-theme='light'] {
+ --bg-primary: #fafafa;
+ --bg-secondary: #ffffff;
+ --bg-tertiary: #f5f5f5;
+ --bg-card: #ffffff;
+
+ --border-color: #e5e5e5;
+ --border-hover: #d4d4d4;
+ --border-strong: #a3a3a3;
+
+ --text-primary: #0a0a0a;
+ --text-secondary: #404040;
+ --text-muted: #737373;
+ --text-faint: #a3a3a3;
+
+ --accent: #0a0a0a;
+ --accent-hover: #262626;
+ --accent-muted: #525252;
+
+ --link-color: #2563eb;
+ --link-hover: #1d4ed8;
+
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.07);
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.08);
+
+ --dot-inactive: #d1d5db;
+
+ color-scheme: light;
+}
+
+/* Dark theme */
+:root[data-theme='dark'] {
+ --bg-primary: #0a0a0a;
+ --bg-secondary: #141414;
+ --bg-tertiary: #1a1a1a;
+ --bg-card: #141414;
+
+ --border-color: #262626;
+ --border-hover: #404040;
+ --border-strong: #525252;
+
+ --text-primary: #fafafa;
+ --text-secondary: #a3a3a3;
+ --text-muted: #737373;
+ --text-faint: #525252;
+
+ --accent: #fafafa;
+ --accent-hover: #e5e5e5;
+ --accent-muted: #a3a3a3;
+
+ --link-color: #60a5fa;
+ --link-hover: #93c5fd;
+
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.2);
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4);
+
+ --dot-inactive: #374151;
+
+ color-scheme: dark;
+}
+
+/* Responsive font sizes */
+@media (max-width: 640px) {
+ :root {
+ --text-3xl: 1.75rem;
+ --text-4xl: 2.25rem;
+ --text-5xl: 2.75rem;
+ }
+}
diff --git a/styles/css/variables.css b/styles/css/variables.css
deleted file mode 100644
index 60165df8b..000000000
--- a/styles/css/variables.css
+++ /dev/null
@@ -1 +0,0 @@
-:root{--font-sans: "Inter",-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue",sans-serif;--font-accent: "Fira Code", monospace}:root{--mobile: 768px;--reading-width: 1000px}:root{--font-xx: 0.60rem;--font-xs: 0.75rem;--font-s: 0.875rem;--font-r-s: 1.00rem;--font-r: 1.00rem;--font-m: 1.125rem;--font-l: 2.00rem;--font-xl-l: 3.75rem;--font-xl: 3.75rem;--size-4-: 0.25rem;--size-3-: 0.35rem;--size-2-: 0.50rem;--size-1x: 1.00rem;--size-2x: 2.00rem;--size-3x: 3.00rem;--size-4x: 4.00rem;--size-5x: 5.00rem;--size-6x: 7.00rem;--size-7x: 10.00rem}@media screen and (max-width: 767px){:root{--font-xx: 0.60rem;--font-xs: 0.75rem;--font-s: 0.875rem;--font-r-s: 0.875rem;--font-r: 0.95rem;--font-m: 1.00rem;--font-l: 2.00rem;--font-xl-l: 2.00rem;--font-xl: 2.75rem;--size-4-: 0.25rem;--size-3-: 0.35rem;--size-2-: 0.50rem;--size-1x: 1.00rem;--size-2x: 1.50rem;--size-3x: 2.00rem;--size-4x: 3.00rem;--size-5x: 4.00rem;--size-6x: 5.50rem;--size-7x: 7.00rem}}:root[data-theme=dark]{--primary-bright: #ffffff;--primary: #bfbfbf;--primary-dim: #888889;--primary-dim2: #262627;--primary-dark: #141415;--secondary: #7feaff;--secondary-bright: #5f8cff;--background: #060708;--background-dim: #08090a;--background-dim2: #0e0f11;--neon-1-1: #a7d575;--neon-1-2: #52abc4;--neon-2-1: #37eaf7;--neon-2-2: #c624ee;--icon-bright: #ffffff;--brightness-low: 100%;--brightness-high: 100%;--mesh-color-1: #060708;--mesh-color-2: #030408;--mesh-color-3: #05070a;--mesh-color-4: #0c1019;color-scheme:dark}:root[data-theme=light],:root[data-theme=undefined]{--primary-bright: #000000;--primary: #2e2e2e;--primary-dim: #3a3a3a;--primary-dim2: #585858;--primary-dark: #dfdfdf;--secondary: #002aff;--secondary-bright: #4800ff;--background: #ededed;--background-dim: #fbfbfb;--background-dim2: #fefefe;--neon-1-1: #424bff;--neon-1-2: #2493ee;--neon-2-1: #37eaf7;--neon-2-2: #c624ee;--icon-bright: var(--neon-1-1);--mesh-color-1: #96c4f3;--mesh-color-2: #96a8f2;--mesh-color-3: #bad0ef;--mesh-color-4: #c8ceda}:root[data-theme=unicorn]{--primary-bright: #000000;--primary: #2e2e2e;--primary-dim: #464646;--primary-dim2: #585858;--primary-dark: #dfdfdf;--secondary: #ff00bb;--secondary-bright: #feff00;--background: #ffffff;--background-dim: #fbfbfb;--background-dim2: #fefefe;--neon-1-1: #37eaf7;--neon-1-2: #c624ee;--neon-2-1: #eaf737;--neon-2-2: #2493ee;--icon-bright: var(--neon-1-1);--mesh-color-1: #96c4f3;--mesh-color-2: #f296cc;--mesh-color-3: #efe2ba;--mesh-color-4: #c8d7da}/*# sourceMappingURL=variables.css.map */
\ No newline at end of file
diff --git a/styles/css/variables.css.map b/styles/css/variables.css.map
deleted file mode 100644
index 82a5c1ddb..000000000
--- a/styles/css/variables.css.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["../scss/variables.scss","../scss/_mixins.scss"],"names":[],"mappings":"AAGA,MACC,4JAAA,CACA,qCAAA,CAID,MACC,eAAA,CACA,uBAAA,CAID,MAEC,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,mBAAA,CACA,iBAAA,CACA,kBAAA,CACA,iBAAA,CACA,oBAAA,CACA,kBAAA,CAGA,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,mBAAA,CC3BE,qCDgCF,MAEC,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,oBAAA,CACA,iBAAA,CACA,iBAAA,CACA,iBAAA,CACA,oBAAA,CACA,kBAAA,CAGA,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,kBAAA,CACA,kBAAA,CAAA,CAKF,uBACC,yBAAA,CACA,kBAAA,CACA,sBAAA,CACA,uBAAA,CACA,uBAAA,CAEA,oBAAA,CACA,2BAAA,CAEA,qBAAA,CACA,yBAAA,CACA,0BAAA,CAEA,mBAAA,CACA,mBAAA,CACA,mBAAA,CACA,mBAAA,CAEA,sBAAA,CAEA,sBAAA,CACA,uBAAA,CAEA,uBAAA,CACG,uBAAA,CACA,uBAAA,CACA,uBAAA,CAEH,iBAAA,CAID,oDAEC,yBAAA,CACA,kBAAA,CACA,sBAAA,CACA,uBAAA,CACA,uBAAA,CAEA,oBAAA,CACA,2BAAA,CAEA,qBAAA,CACA,yBAAA,CACA,0BAAA,CAEA,mBAAA,CACA,mBAAA,CACA,mBAAA,CACA,mBAAA,CAEA,8BAAA,CAEA,uBAAA,CACG,uBAAA,CACA,uBAAA,CACA,uBAAA,CAIJ,0BACC,yBAAA,CACA,kBAAA,CACA,sBAAA,CACA,uBAAA,CACA,uBAAA,CAEA,oBAAA,CACA,2BAAA,CAEA,qBAAA,CACA,yBAAA,CACA,0BAAA,CAEA,mBAAA,CACA,mBAAA,CACA,mBAAA,CACA,mBAAA,CAEA,8BAAA,CAEA,uBAAA,CACG,uBAAA,CACA,uBAAA,CACA,uBAAA","file":"variables.css"}
\ No newline at end of file
diff --git a/styles/scss/global.scss b/styles/scss/global.scss
deleted file mode 100644
index 9c5122ebf..000000000
--- a/styles/scss/global.scss
+++ /dev/null
@@ -1,199 +0,0 @@
-@import '_variables';
-@import '_mixins';
-
-::selection {
- color: var(--background);
- background: var(--secondary);
-}
-
-html {
- font-size: 16px;
- font-family: var(--font-sans);
-
- color: var(--primary-dim);
- background: var(--background);
-
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
-}
-
-#__next {
- width: 100%;
- overflow-x: hidden;
-}
-
-img {
- border-radius: .5rem;
- //width: 100%;
- filter: brightness( var(--brightness-low) );
-
- &:hover {
- filter: brightness( var(--brightness-high) );
- }
-}
-
-button.button {
- cursor: pointer;
- font-family: var(--font-accent);
- font-size: 1rem;
- font-weight: 700;
- padding: .75rem 2.5rem;
- border-radius: 99rem;
- border: none;
- margin-right: 1rem;
-
- @include transition(750ms);
- &:hover {
- @include transition(750ms);
- }
-}
-
-h1 {
- font-size: var(--font-xl);
- font-family: var(--font-sans);
- font-weight: 600;
- letter-spacing: -.1rem;
-}
-
-h2 {
- color: var(--primary);
- font-size: var(--font-xl);
- font-family: var(--font-sans);
- font-weight: 700;
- letter-spacing: -.05rem;
-}
-
-h3 {
- font-size: var(--font-m);
- font-family: var(--font-sans);
- color: var(--primary);
- font-weight: 600;
- letter-spacing: -.01rem;
-}
-
-h4 {
- font-size: var(--font-xs);
- font-family: var(--font-sans);
- font-weight: 600;
- text-transform: uppercase;
- letter-spacing: .1rem;
-}
-
-h5 {
- font-size: var(--font-m);
- font-family: var(--font-sans);
- color: var(--primary);
- font-weight: 600;
- letter-spacing: -.01rem;
-}
-
-p {
- font-size: var(--font-r);
- font-family: var(--font-sans);
- line-height: 1.6;
- letter-spacing: -.02rem;
-
- &.subtitle {
- font-family: var(--font-accent);
- font-size: var(--font-r-s);
- font-weight: 600;
- letter-spacing: 0;
- }
-}
-
-a {
- font-weight: 600;
- color: var(--primary);
-
- &:hover {
- color: var(--primary-bright);
-
- [data-prefix="far"][data-icon="arrow-up-right-from-square"] {
- color: var(--primary);
- }
-
- h3 {
- color: var(--primary-bright);
- }
- }
-
-
-
- [data-prefix="far"][data-icon="arrow-up-right-from-square"] {
- height: .75rem;
- vertical-align: -1.5px;
- color: var(--primary-dim);
- }
-
- svg {
- margin-left: .25rem;
- }
-}
-
-.noEvents {
- pointer-events: none;
-}
-
-.list {
- list-style: disc;
- margin-left: 1.5rem;
- li {
- &::marker {
- content: normal;
- }
- }
-}
-
-.leaveSite {
- &:after {
- content: "↗";
- position: relative;
- font-size: inherit;
- line-height: 0;
- vertical-align: -1px;
- margin-left: .5rem;
- text-decoration: none;
- text-rendering: optimizeLegibility;
- white-space: nowrap;
- font-feature-settings: "liga";
- -webkit-font-smoothing: antialiased;
- }
-}
-
-.borderBottom {
- border-bottom: 1px solid var(--primary-dark);
-}
-
-#gradient-canvas {
- position: absolute;
- z-index: -1;
- opacity: 100%;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- transform: rotate(180deg);
- aspect-ratio: auto;
- --gradient-color-1: var( --mesh-color-1 );
- --gradient-color-2: var( --mesh-color-2 );
- --gradient-color-3: var( --mesh-color-3 );
- --gradient-color-4: var( --mesh-color-4 );
-}
-
-.highlight {
- --looking-bg-1: var(--neon-1-1);
- --looking-bg-2: var(--neon-1-2);
-
- width: fit-content;
- background: var(--bar-gradient);
- --bar-gradient:
- linear-gradient(
- 90deg,
- var(--looking-bg-1) 0%,
- var(--looking-bg-2) 100%
- );
-
- -webkit-background-clip: text;
- background-clip: text;
- -webkit-text-fill-color: transparent;
-}
\ No newline at end of file
diff --git a/styles/scss/variables.scss b/styles/scss/variables.scss
deleted file mode 100644
index aa27ddf22..000000000
--- a/styles/scss/variables.scss
+++ /dev/null
@@ -1,159 +0,0 @@
-@import "../scss/mixins";
-
-// Fonts
-:root {
- --font-sans: "Inter",-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue",sans-serif;
- --font-accent: "Fira Code", monospace;
-}
-
-// Breakpoints and containers
-:root {
- --mobile: 768px;
- --reading-width: 1000px;
-}
-
-// Spatial sizing
-:root {
- // Fonts sizes
- --font-xx: 0.60rem;
- --font-xs: 0.75rem;
- --font-s: 0.875rem;
- --font-r-s: 1.00rem;
- --font-r: 1.00rem;
- --font-m: 1.125rem;
- --font-l: 2.00rem;
- --font-xl-l: 3.75rem;
- --font-xl: 3.75rem;
-
- // Marging/padding sizes
- --size-4-: 0.25rem;
- --size-3-: 0.35rem;
- --size-2-: 0.50rem;
- --size-1x: 1.00rem;
- --size-2x: 2.00rem;
- --size-3x: 3.00rem;
- --size-4x: 4.00rem;
- --size-5x: 5.00rem;
- --size-6x: 7.00rem;
- --size-7x: 10.00rem;
-}
-
-// Spatial sizing
-@include media($max: $mobile) {
- :root {
- // Fonts sizes
- --font-xx: 0.60rem;
- --font-xs: 0.75rem;
- --font-s: 0.875rem;
- --font-r-s: 0.875rem;
- --font-r: 0.95rem;
- --font-m: 1.00rem;
- --font-l: 2.00rem;
- --font-xl-l: 2.00rem;
- --font-xl: 2.75rem;
-
- // Marging/padding sizes
- --size-4-: 0.25rem;
- --size-3-: 0.35rem;
- --size-2-: 0.50rem;
- --size-1x: 1.00rem;
- --size-2x: 1.50rem;
- --size-3x: 2.00rem;
- --size-4x: 3.00rem;
- --size-5x: 4.00rem;
- --size-6x: 5.50rem;
- --size-7x: 7.00rem;
- }
-}
-
-// Dark mode theme
-:root[data-theme='dark'] {
- --primary-bright: #ffffff;
- --primary: #bfbfbf;
- --primary-dim: #888889;
- --primary-dim2: #262627;
- --primary-dark: #141415;
-
- --secondary: #7feaff;
- --secondary-bright: #5f8cff;
-
- --background: #060708;
- --background-dim: #08090a;
- --background-dim2: #0e0f11;
-
- --neon-1-1: #a7d575;
- --neon-1-2: #52abc4;
- --neon-2-1: #37eaf7;
- --neon-2-2: #c624ee;
-
- --icon-bright: #ffffff;
-
- --brightness-low: 100%;
- --brightness-high: 100%;
-
- --mesh-color-1: #060708;
- --mesh-color-2: #030408;
- --mesh-color-3: #05070a;
- --mesh-color-4: #0c1019;
-
- color-scheme: dark;
-}
-
-// Light mode theme
-:root[data-theme='light'],
-:root[data-theme='undefined'] {
- --primary-bright: #000000;
- --primary: #2e2e2e;
- --primary-dim: #3a3a3a;
- --primary-dim2: #585858;
- --primary-dark: #dfdfdf;
-
- --secondary: #002aff;
- --secondary-bright: #4800ff;
-
- --background: #ededed;
- --background-dim: #fbfbfb;
- --background-dim2: #fefefe;
-
- --neon-1-1: #424bff;
- --neon-1-2: #2493ee;
- --neon-2-1: #37eaf7;
- --neon-2-2: #c624ee;
-
- --icon-bright: var(--neon-1-1);
-
- --mesh-color-1: #96c4f3;
- --mesh-color-2: #96a8f2;
- --mesh-color-3: #bad0ef;
- --mesh-color-4: #c8ceda;
-}
-
-// Unicorn mode theme
-:root[data-theme='unicorn'] {
- --primary-bright: #000000;
- --primary: #2e2e2e;
- --primary-dim: #464646;
- --primary-dim2: #585858;
- --primary-dark: #dfdfdf;
-
- --secondary: #ff00bb;
- --secondary-bright: #feff00;
-
- --background: #ffffff;
- --background-dim: #fbfbfb;
- --background-dim2: #fefefe;
-
- --neon-1-1: #37eaf7;
- --neon-1-2: #c624ee;
- --neon-2-1: #eaf737;
- --neon-2-2: #2493ee;
-
- --icon-bright: var(--neon-1-1);
-
- --mesh-color-1: #96c4f3;
- --mesh-color-2: #f296cc;
- --mesh-color-3: #efe2ba;
- --mesh-color-4: #c8d7da;
-}
-
-
diff --git a/styles/sections/index/about.module.scss b/styles/sections/index/about.module.scss
deleted file mode 100644
index e6e8bdab9..000000000
--- a/styles/sections/index/about.module.scss
+++ /dev/null
@@ -1,157 +0,0 @@
-@import '../../scss/mixins';
-
-// Section
-.section {
-
- .content {
- $padding: 2rem;
- position: relative;
- display: flex;
- flex-direction: row;
- gap: 1rem;
-
- > div {
- padding: 0;
- }
-
- h3 {
- position: relative;
- color: var(--primary);
-
- // &:before {
- // content: '';
- // position: absolute;
- // left: calc( $padding * -1 );
- // width: 18px;
- // aspect-ratio: 1/1;
- // background-color: var(--primary-bright);
- // border-radius: 99rem;
- // border: 3px solid var(--background);
- // top: 50%;
- // transform: translate(-50%, -50%);
- // }
-
- // &:after {
- // content: '';
- // position: absolute;
- // left: calc( $padding * -1 );
- // width: 9px;
- // aspect-ratio: 1/1;
- // background-color: var(--background);
- // border-radius: 99rem;
- // top: 50%;
- // transform: translate(-50%, -50%);
- // }
- }
-
- .container {
- display: flex;
- flex-direction: column;
- gap: var(--size-1x);
- border: 1px solid var(--primary-dark);
- border-radius: 2rem;
- background: var(--background-dim2);
- box-shadow: 0 0 30px var(--background);
- overflow: hidden;
-
- padding: var(--padding);
- --padding: 2rem;
- --padding-left: var(--padding);
- --padding-top: var(--padding);
- --padding-right: var(--padding);
- --padding-bottom: var(--padding);
-
- &:not(:last-of-type) {
- margin-bottom: var(--size-1x);
- }
- }
-
- .copy {
- flex-basis: calc(60% + 1px);
- flex-grow: 1;
- flex-shrink: 1;
- }
-
- .icon {
- padding: 0.5rem;
- display: flex;
- align-items: center;
- background: var(--primary-dark);
- width: fit-content;
- border-radius: 0.5rem;
- aspect-ratio: 1;
-
- svg {
- height: 1.6rem;
- color: var(--primary);
-
- path {
- fill: url(#fa-gradient) #fff;
- }
- }
-
-
- }
-
- // Columns
- .image {
- flex-basis: 50%;
- flex-grow: 1;
- flex-shrink: 1;
- position: relative;
-
- img {
- height: 100%;
- width: auto;
- aspect-ratio: 3/4;
- object-fit: cover;
- border-radius: 2rem;
- }
-
- &.technicalSvg {
- > span {
- position: relative !important;
- overflow: visible !important;
- height: 100% !important;
- z-index: -1;
- }
- img {
- overflow: visible;
- filter: brightness(100%);
- }
- }
- }
- }
-}
-
-@include media($max: $mobile) {
- .section {
- .content {
- flex-direction: column;
-
- > div {
- flex-basis: 100% !important;
- }
-
- .container {
- padding: 2rem 1.25rem;
- }
-
- .image {
- padding: 1rem;
- &.technicalSvg {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- height: 140%;
- z-index: -1;
- }
- }
-
- .copy {
- padding: 0;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/styles/sections/index/career.module.scss b/styles/sections/index/career.module.scss
deleted file mode 100644
index 427c09fe1..000000000
--- a/styles/sections/index/career.module.scss
+++ /dev/null
@@ -1,154 +0,0 @@
-// Career component
-@import '../../scss/mixins';
-
-.section {
-
- .area {
- display: flex;
- flex-direction: column;
- gap: 1rem;
-
- h3 {
- margin-top: - .25rem;
- margin-bottom: .35rem;
- }
-
- h4 {
- font-size: .9rem;
- margin-bottom: .25rem;
- text-transform: none;
- letter-spacing: 0;
- }
-
- h5 {
- font-size: .9rem;
- margin-bottom: .25rem;
- opacity: .5;
- }
- }
-
- .company {
- position: relative;
- display: flex;
- flex-direction: row;
- gap: 1rem;
- }
-
- .company,
- .position {
- border: 1px solid var(--primary-dark);
- border-radius: 1rem;
- overflow: hidden;
-
- padding: var(--padding);
- --padding: 2rem;
- --padding-left: var(--padding);
- --padding-top: var(--padding);
- --padding-right: var(--padding);
- --padding-bottom: var(--padding);
-
- background: var(--background-dim2);
- }
-
- .companyContent {
- display: flex;
- flex-direction: column;
- gap: 1rem;
- max-width: calc( var(--grid-32) * 20 );
- }
-
- .companyPositions {
- display: flex;
- flex-direction: column;
- gap: 1rem;
- }
-
- .position {
- margin-left: calc( var(--grid-32) * 2 );
- background: var(--background-dim);
- max-width: 100%;
-
- &.first {
- .content {
- padding-bottom: 0;
- }
- }
-
- .positionContent {
- position: relative;
- display: flex;
- flex-direction: column;
- gap: 2rem;
-
- .list {
- display: flex;
- flex-direction: column;
- gap: .75rem;
-
- .subList {
- position: relative;
- margin-left: 2rem;
- margin-top: .5rem;
- display: block;
- color: var(--primary);
-
- .bullet {
- position: absolute;
- margin-left: -1.5rem;
- &:before {
- content: "⇒";
- }
- }
- }
-
- }
- }
- }
-
- .technicalSvg {
- position: absolute;
- top: 0;
- bottom: 0;
- right: 0;
-
- img {
- transform: rotate(90deg);
- }
- }
-}
-
-@include media($max: $mobile) {
- .section {
- .area {
- .company,
- .position {
- padding: 2rem 1rem;
- }
- .position {
- padding-bottom: 1rem;
- --padding-top: 1rem;
- }
- .companyContent {
- max-width: 100%;
- }
- .positionContent {
- gap: 1rem;
- max-width: 100%;
- }
- p {
- font-size: .8rem;
- }
- ul.list {
- li {
- font-size: .8rem;
- }
- }
-
- ul:not(.list) {
- li {
- font-size: .6rem;
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/styles/sections/index/hero.module.scss b/styles/sections/index/hero.module.scss
deleted file mode 100644
index af0956756..000000000
--- a/styles/sections/index/hero.module.scss
+++ /dev/null
@@ -1,173 +0,0 @@
-@import '../../scss/_mixins';
-
-//global.module.scss
-.section {
- border-bottom: 1px solid var(--primary-dark);
-
- max-height: 1440px;
- height: 100vh;
- justify-content: center;
-
- > .container {
- height: fit-content;
- }
-
- .preHeader {
- color: var(--secondary);
- font-family: var(--font-accent);
- font-size: 1.2rem;
- font-weight: 400;
- margin: 1rem 0;
- }
-
- .header {
- color: var(--primary-bright);
- font-family: var(--font-sans);
- font-size: 5rem;
- margin: 0;
- }
-
- .primaryDim {
- color: var(--primary-dim);
- }
-
- .primaryBright {
- color: var(--primary);
- }
-
- .tempBright {
- font-size: .875rem;
- width: 60%;
- }
-
- .gitBadges {
- position: relative;
- display: flex;
- gap: .5rem;
- flex-wrap: wrap;
- height: 1rem;
- img {
- height: 16px;
- width: fit-content;
- border-radius: .25rem;
- }
- }
-
- @include media($max: $mobile) {
- .preHeader {
- font-size: 1rem;
- }
- .header {
- font-size: 2.9rem;
- }
- .tempBright {
- width: 100%;
- padding-right: 1rem;
- }
- button {
- font-size: .875rem;
- padding: 0.75rem 2rem;
- }
- }
-}
-
-// Backgrounds
-.colorfulV1 {
- --hero-gradient-bg-1: var(--neon-1-1);
- --hero-gradient-bg-2: var(--neon-1-2);
- --hero-gradient-bg-3: var(--neon-2-1);
- --hero-gradient-bg-4: var(--neon-2-2);
-
- position: absolute;
- pointer-events: none;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
-
- .svg_background {
- position: absolute;
- z-index: -1;
- width: 200vw;
- aspect-ratio: 1/1;
- bottom: 50%;
- right: 50%;
- opacity: 15%;
- transform: translate(48.5%, 50%);
- max-inline-size: unset;
- max-block-size: unset;
- }
-
- .radialContainer {
- position: absolute;
- width: 100%;
- height: 100%;
-
- .radialGradient {
- position: absolute;
- right: -30%;
- width: 100%;
- left: unset;
- aspect-ratio: 1/1;
- height: unset;
- bottom: -60%;
- filter: blur(100px);
- transform: translateZ(0);
- opacity: 20%;
- background: var(--bar-gradient);
- --bar-gradient: radial-gradient(
- circle,
- var(--hero-gradient-bg-1) 0%,
- var(--hero-gradient-bg-2) 24%,
- var(--hero-gradient-bg-3) 44%,
- var(--hero-gradient-bg-4) 57%,
- transparent 70%
- );
- }
- }
-
- .barContainer {
- position: absolute;
- left: 0;
- bottom: 0;
- width: 100%;
- height: 100px;
- }
-
- .barGradient {
- --bar-opacity:0.15;
- --bar-blend-mode:screen;
- --bar-gradient: linear-gradient(
- 90deg,
- var(--hero-gradient-bg-1) 0%,
- var(--hero-gradient-bg-2) 26.88%,
- var(--hero-gradient-bg-3) 48.46%,
- var(--hero-gradient-bg-4) 74.51%
- );
-
- opacity: var(--bar-opacity);
- background-blend-mode: var(--bar-blend-mode);
- background: var(--bar-gradient);
-
- position: absolute;
- pointer-events: none;
- -webkit-user-select: none;
- user-select: none;
- z-index: 0;
- width: 100%;
- bottom: 0;
- height: 100%;
- filter: blur(100px);
- transform: translateZ(0);
- }
-
- @include media($max: $mobile) {
- .radialContainer {
- .radialGradient {
- right: -180%;
- width: 300%;
- bottom: -55%;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/styles/sections/index/looking.module.scss b/styles/sections/index/looking.module.scss
deleted file mode 100644
index d1e43671c..000000000
--- a/styles/sections/index/looking.module.scss
+++ /dev/null
@@ -1,84 +0,0 @@
-// Section
-.section {
- background-color: var(--background-dim);
-
- h2 {
- font-size: var(--font-xl-l);
- }
-
- h4 {
- font-family: var(--font-accent);
- text-transform: none;
- font-size: var(--font-r-s);
- letter-spacing: .01rem;
- }
-
- .container {
- text-align: left;
- max-width: 700px;
- }
-
- .copy {
- width: fit-content;
- display: flex;
- flex-direction: column;
- }
-
- .jsonSub {
- line-height: .9;
- margin: 0.25rem 0;
- margin-left: 2rem;
- }
-
- .preHeader {
- font-family: var(--font-subheader);
- font-weight: 400;
- letter-spacing: -.05rem;
- font-size: 2rem;
- }
- .header {
- color: var(--secondary);
- }
- .subHeader {
- font-family: var(--font-subheader);
- color: var(--primary-bright);
- font-weight: 400;
- letter-spacing: -.05rem;
- text-align: right;
- font-size: 2rem;
- }
-
- .highlight {
- --looking-bg-1: var(--neon-1-1);
- --looking-bg-2: var(--neon-1-2);
-
- background: var(--bar-gradient);
- --bar-gradient:
- linear-gradient(
- 90deg,
- var(--looking-bg-1) -45%,
- var(--looking-bg-2) 125%
- );
-
- -webkit-background-clip: text;
- background-clip: text;
- -webkit-text-fill-color: transparent;
- }
-
- .highlight2 {
- --looking-bg-1: var(--neon-2-1);
- --looking-bg-2: var(--neon-2-2);
-
- background: var(--bar-gradient);
- --bar-gradient:
- linear-gradient(
- 90deg,
- var(--looking-bg-1) -45%,
- var(--looking-bg-2) 125%
- );
-
- -webkit-background-clip: text;
- background-clip: text;
- -webkit-text-fill-color: transparent;
- }
-}
\ No newline at end of file