mirror of
https://github.com/System-End/My-website.git
synced 2026-04-19 19:45:10 +00:00
.
This commit is contained in:
parent
428822a894
commit
c677cdacd4
21 changed files with 666 additions and 297 deletions
7
.npmrc
Normal file
7
.npmrc
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
legacy-peer-deps=true
|
||||
strict-peer-dependencies=false
|
||||
auto-install-peers=true
|
||||
resolution-mode=highest
|
||||
prefer-dedupe=true
|
||||
package-lock=true
|
||||
save-exact=true
|
||||
31
package.json
31
package.json
|
|
@ -14,8 +14,11 @@
|
|||
"lru-cache": "^10.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
"@types/react": "^18.2.48",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@types/node": "^16.18.70",
|
||||
"@cloudflare/workers-types": "^4.20240208.0",
|
||||
"typescript": "^4.9.5",
|
||||
"wrangler": "^3.28.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
@ -23,26 +26,20 @@
|
|||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"deploy": "powershell ./deploy-master.ps1"
|
||||
"deploy": "powershell ./deploy-master.ps1",
|
||||
"clean": "rm -rf node_modules package-lock.json build dist .cache"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"overrides": {
|
||||
"inflight": "npm:lru-cache@^10.1.0"
|
||||
}
|
||||
"browserslist": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all",
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>My Project Website</title>
|
||||
<title>EndofTimee</title>
|
||||
<link rel="stylesheet" href="pages/style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
<nav>
|
||||
<ul>
|
||||
<li><a href="/public/pages/about-us.html">About Us</a><li>
|
||||
<li><a href="/public/pages/system.html">Our system></a></li>
|
||||
<li><a href="../index.html">Home</a></li>
|
||||
<li><a href="/pages/APCSP.html">APCSP Project</a></li>
|
||||
<li><a href="/pages/github-repos.html">GitHub Projects</a></li>
|
||||
<li><a href="/public/pages/APCSP.html">APCSP Project</a></li>
|
||||
<li><a href="/public/pages/github-repos.html">GitHub Projects</a></li>
|
||||
</ul>
|
||||
<input type="color" id="theme-color-picker" title="Choose your color">
|
||||
</nav>
|
||||
|
|
|
|||
|
|
@ -1,165 +1,106 @@
|
|||
/* General reset */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* public/pages/style.css */
|
||||
:root {
|
||||
--background-color-light: #f9f9f9;
|
||||
--text-color-light: #333;
|
||||
--background-color-dark: #1e1e1e;
|
||||
--text-color-dark: #e0e0e0;
|
||||
--primary-color: #4a90e2;
|
||||
--accent-color: #ff5722;
|
||||
}
|
||||
|
||||
[data-theme="light"] {
|
||||
--background-color: var(--background-color-light);
|
||||
--text-color: var(--text-color-light);
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--background-color: var(--background-color-dark);
|
||||
--text-color: var(--text-color-dark);
|
||||
--background-primary: #1a0b2e;
|
||||
--background-secondary: #2f1c54;
|
||||
--accent-primary: #9d4edd;
|
||||
--accent-neon: #b249f8;
|
||||
--text-glow: #e0aaff;
|
||||
--text-primary: #ffffff;
|
||||
--dark-accent: #240046;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--background-color);
|
||||
color: var(--text-color);
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, var(--background-primary), var(--background-secondary));
|
||||
color: var(--text-primary);
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
}
|
||||
|
||||
/* Navbar styling */
|
||||
/* Neon text effect */
|
||||
.neon-text {
|
||||
color: var(--text-primary);
|
||||
text-shadow: 0 0 5px var(--text-glow),
|
||||
0 0 10px var(--text-glow),
|
||||
0 0 20px var(--accent-neon);
|
||||
}
|
||||
|
||||
/* Interactive elements */
|
||||
a, button {
|
||||
color: var(--text-primary);
|
||||
text-decoration: none;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
a:hover, button:hover {
|
||||
color: var(--accent-neon);
|
||||
text-shadow: 0 0 5px var(--text-glow);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* Card styling */
|
||||
.card {
|
||||
background: rgba(47, 28, 84, 0.3);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(157, 78, 221, 0.2);
|
||||
border-radius: 12px;
|
||||
padding: 1.5rem;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
border-color: var(--accent-neon);
|
||||
box-shadow: 0 0 20px rgba(178, 73, 248, 0.2);
|
||||
}
|
||||
|
||||
/* Navigation styling */
|
||||
nav {
|
||||
background-color: var(--primary-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
background: rgba(36, 0, 70, 0.8);
|
||||
backdrop-filter: blur(10px);
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
display: flex;
|
||||
gap: 2rem;
|
||||
justify-content: center;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
nav ul li a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
nav a {
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
/* Theme toggle button */
|
||||
.theme-toggle {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 1.5em;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
margin-left: auto;
|
||||
nav a:hover {
|
||||
color: var(--accent-neon);
|
||||
text-shadow: 0 0 10px var(--text-glow);
|
||||
}
|
||||
|
||||
/* Header styling */
|
||||
.header {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
/* Content sections */
|
||||
.content-section {
|
||||
padding: 2rem;
|
||||
margin: 2rem 0;
|
||||
background: rgba(26, 11, 46, 0.5);
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
/* Animated gradient background */
|
||||
@keyframes gradientAnimation {
|
||||
0% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
100% { background-position: 0% 50%; }
|
||||
}
|
||||
|
||||
.apcsp-blurb {
|
||||
margin-top: 10px;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Main content styling */
|
||||
.main-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-grow: 1;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.project-demo {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.project-demo iframe {
|
||||
border: none;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* Light/Dark Mode Toggle */
|
||||
[data-theme="dark"] body {
|
||||
background-color: var(--background-color-dark);
|
||||
color: var(--text-color-dark);
|
||||
}
|
||||
|
||||
[data-theme="light"] body {
|
||||
background-color: var(--background-color-light);
|
||||
color: var(--text-color-light);
|
||||
}
|
||||
|
||||
/* responsive design */
|
||||
@media (max-width: 768px) {
|
||||
nav ul {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.main-content { padding: 10px; }
|
||||
}
|
||||
|
||||
/* Loading animation */
|
||||
#loading {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
#loading .spinner {
|
||||
border: 8px solid #f3f3f3;
|
||||
border-top: 8px solid var(--primary-color);
|
||||
border-radius: 50%;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
#spotify-list {
|
||||
position:fixed;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 200px;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
padding: 10px;
|
||||
box-sizing: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
.animated-bg {
|
||||
background: linear-gradient(135deg,
|
||||
var(--background-primary),
|
||||
var(--background-secondary),
|
||||
var(--dark-accent));
|
||||
background-size: 200% 200%;
|
||||
animation: gradientAnimation 15s ease infinite;
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
|
||||
@keyframes rollingCode {
|
||||
0% { transform: translateY(0); opacity: 1; }
|
||||
100% { transform: translateY(100vh); opacity: 0; }
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: black;
|
||||
color: limegreen;
|
||||
font-family: monospace;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.code-line {
|
||||
position: absolute;
|
||||
top: -10%;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
animation: rollingCode 5s linear infinite;
|
||||
}
|
||||
165
src/App.css
165
src/App.css
|
|
@ -1,41 +1,158 @@
|
|||
.App {
|
||||
text-align: center;
|
||||
/* src/App.css */
|
||||
:root {
|
||||
--background-primary: #1a0b2e;
|
||||
--background-secondary: #2f1c54;
|
||||
--accent-primary: #9d4edd;
|
||||
--accent-neon: #b249f8;
|
||||
--text-glow: #e0aaff;
|
||||
--text-primary: #ffffff;
|
||||
--dark-accent: #240046;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
/* Custom Scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--background-primary);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--accent-primary);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--accent-neon);
|
||||
box-shadow: 0 0 10px var(--text-glow);
|
||||
}
|
||||
|
||||
/* Particle Effects */
|
||||
.particle-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
background-image: url('/logo.png');
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
.particle {
|
||||
position: absolute;
|
||||
width: 3px;
|
||||
height: 3px;
|
||||
background: var(--text-glow);
|
||||
border-radius: 50%;
|
||||
animation: particleFloat linear infinite;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@keyframes particleFloat {
|
||||
0% {
|
||||
transform: translateY(100vh) scale(0);
|
||||
opacity: 0;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-20vh) scale(1);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.App-header {
|
||||
background-color: #282c34;
|
||||
/* Main Layout */
|
||||
.app-container {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: linear-gradient(135deg, var(--background-primary), var(--background-secondary));
|
||||
color: var(--text-primary);
|
||||
font-family: 'Inter', sans-serif;
|
||||
position: relative;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* Header Styles */
|
||||
.header {
|
||||
text-align: center;
|
||||
padding: 4rem 2rem;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 3.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1.2rem;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* Content Sections */
|
||||
.content-section {
|
||||
max-width: 1200px;
|
||||
margin: 2rem auto;
|
||||
padding: 2rem;
|
||||
background: rgba(26, 11, 46, 0.5);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 16px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* Interests Grid */
|
||||
.interests-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 2rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.interest-card {
|
||||
background: rgba(47, 28, 84, 0.3);
|
||||
padding: 1.5rem;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(157, 78, 221, 0.2);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.interest-card:hover {
|
||||
transform: translateY(-5px);
|
||||
border-color: var(--accent-neon);
|
||||
box-shadow: 0 0 20px rgba(178, 73, 248, 0.2);
|
||||
}
|
||||
|
||||
/* Twitch Button */
|
||||
.twitch-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
gap: 0.5rem;
|
||||
background: #9146ff;
|
||||
color: white;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
color: #61dafb;
|
||||
.twitch-button:hover {
|
||||
background: #7c2bff;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 0 15px rgba(145, 70, 255, 0.5);
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.header h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
|
||||
.content-section {
|
||||
padding: 1rem;
|
||||
margin: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.interests-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
136
src/App.js
136
src/App.js
|
|
@ -1,42 +1,112 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import './styles/rolling-effects.css'; // Fixed import path
|
||||
import './App.css';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import './styles/App.css';
|
||||
import SpotifyList from './components/SpotifyList';
|
||||
import LoadingAnimation from './components/LoadingAnimation';
|
||||
import GithubRepos from './components/GithubRepos';
|
||||
import { Music, Code, Twitch, Github, Cpu, Shield } from 'lucide-react';
|
||||
|
||||
const App = () => {
|
||||
useEffect(() => {
|
||||
// Generate rolling code lines
|
||||
const container = document.querySelector('.rolling-code-container');
|
||||
if (container) {
|
||||
for (let i = 0; i < 30; i++) {
|
||||
const line = document.createElement('div');
|
||||
line.className = 'code-line';
|
||||
line.style.animationDelay = `${Math.random() * 5}s`;
|
||||
line.textContent = Math.random().toString(36).substr(2, 80);
|
||||
container.appendChild(line);
|
||||
}
|
||||
}
|
||||
const [age, setAge] = useState(0);
|
||||
|
||||
// Generate particles
|
||||
const particleContainer = document.querySelector('.particle-container');
|
||||
if (particleContainer) {
|
||||
for (let i = 0; i < 50; i++) {
|
||||
const particle = document.createElement('div');
|
||||
particle.className = 'particle';
|
||||
particle.style.left = `${Math.random() * 100}vw`;
|
||||
particle.style.animationDelay = `${Math.random() * 10}s`;
|
||||
particleContainer.appendChild(particle);
|
||||
useEffect(() => {
|
||||
// Age calculation
|
||||
const calculateAge = () => {
|
||||
const birthDate = new Date('2009-05-15');
|
||||
const today = new Date();
|
||||
let age = today.getFullYear() - birthDate.getFullYear();
|
||||
const monthDiff = today.getMonth() - birthDate.getMonth();
|
||||
|
||||
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
|
||||
age--;
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
return age;
|
||||
};
|
||||
setAge(calculateAge());
|
||||
|
||||
// Particle effect setup
|
||||
const createParticles = () => {
|
||||
const particleContainer = document.querySelector('.particle-container');
|
||||
if (particleContainer) {
|
||||
for (let i = 0; i < 50; i++) {
|
||||
const particle = document.createElement('div');
|
||||
particle.className = 'particle';
|
||||
particle.style.left = `${Math.random() * 100}vw`;
|
||||
particle.style.animationDuration = `${Math.random() * 3 + 2}s`;
|
||||
particle.style.animationDelay = `${Math.random() * 2}s`;
|
||||
particleContainer.appendChild(particle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
createParticles();
|
||||
}, []);
|
||||
|
||||
const interests = [
|
||||
{ icon: <Code size={24} />, title: 'Programming', description: 'Full-stack development & coding projects' },
|
||||
{ icon: <Cpu size={24} />, title: 'Robotics', description: 'Building & programming robots' },
|
||||
{ icon: <Shield size={24} />, title: 'Cybersecurity', description: 'Network security & ethical hacking' },
|
||||
{ icon: <Music size={24} />, title: 'Music', description: 'Music production & listening' },
|
||||
{ icon: <Twitch size={24} />, title: 'Streaming', description: 'FiveM & variety gaming on Twitch' },
|
||||
{ icon: <Github size={24} />, title: 'Open Source', description: 'Contributing to GitHub projects' }
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="app-container">
|
||||
<div className="animated-lighting"></div>
|
||||
<div className="rolling-code-container"></div>
|
||||
<div className="particle-container"></div>
|
||||
<div className="content">
|
||||
<h1>Welcome to My Website</h1>
|
||||
<p>Enhanced Background with Lighting Effects</p>
|
||||
<div className="app-container animated-bg">
|
||||
<div className="particle-container" />
|
||||
|
||||
{/* Header Section */}
|
||||
<header className="header neon-text">
|
||||
<h1>EndofTimee</h1>
|
||||
<p className="subtitle">Programmer • Streamer • Foxgirl 🦊</p>
|
||||
</header>
|
||||
|
||||
{/* About Section */}
|
||||
<section className="content-section about-section">
|
||||
<h2 className="neon-text">About Me</h2>
|
||||
<div className="about-content">
|
||||
<p>Hey there! I'm a {age}-year-old transfem programmer and content creator.
|
||||
When I'm not coding or building robots, you can find me streaming on
|
||||
<a href="https://twitch.tv/EndofTimee" target="_blank" rel="noopener noreferrer"
|
||||
className="twitch-link">Twitch</a>!</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Interests Grid */}
|
||||
<section className="content-section interests-section">
|
||||
<h2 className="neon-text">What I Do</h2>
|
||||
<div className="interests-grid">
|
||||
{interests.map((interest, index) => (
|
||||
<div key={index} className="interest-card">
|
||||
<div className="interest-icon">{interest.icon}</div>
|
||||
<h3>{interest.title}</h3>
|
||||
<p>{interest.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Streaming Section */}
|
||||
<section className="content-section stream-section">
|
||||
<h2 className="neon-text">Streaming</h2>
|
||||
<div className="stream-content">
|
||||
<p>Join me on Twitch for FiveM roleplay and various other games!
|
||||
I love interacting with chat and building a positive community.</p>
|
||||
<a href="https://twitch.tv/EndofTimee" target="_blank"
|
||||
rel="noopener noreferrer" className="twitch-button">
|
||||
<Twitch className="icon" />
|
||||
Watch Live
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* GitHub Section */}
|
||||
<div className="github-section">
|
||||
<GithubRepos />
|
||||
</div>
|
||||
|
||||
{/* Music Section */}
|
||||
<div className="music-section">
|
||||
<SpotifyList />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
46
src/components/ErrorBoundary.js
Normal file
46
src/components/ErrorBoundary.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import React from 'react';
|
||||
|
||||
class ErrorBoundary extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { hasError: false, error: null };
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error) {
|
||||
return { hasError: true, error };
|
||||
}
|
||||
|
||||
componentDidCatch(error, errorInfo) {
|
||||
console.error('Error caught by boundary:', error, errorInfo);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return (
|
||||
<div className="error-container">
|
||||
<div className="fox-error">
|
||||
<div className="fox-face sad">
|
||||
<div className="fox-ears">
|
||||
<div className="ear left"></div>
|
||||
<div className="ear right"></div>
|
||||
</div>
|
||||
<div className="fox-eyes">
|
||||
<div className="eye left"></div>
|
||||
<div className="eye right"></div>
|
||||
</div>
|
||||
<div className="fox-nose"></div>
|
||||
</div>
|
||||
<p>Oops! Something went wrong</p>
|
||||
<button onClick={() => window.location.reload()}>
|
||||
Try Again
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
export default ErrorBoundary;
|
||||
14
src/components/FoxCar.js
Normal file
14
src/components/FoxCar.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import React from 'react';
|
||||
import '../styles/FoxCard.css';
|
||||
|
||||
const FoxCard = ({ children, className = '' }) => {
|
||||
return (
|
||||
<div className={`fox-card ${className}`}>
|
||||
<div className="fox-ear fox-ear-left" />
|
||||
<div className="fox-ear fox-ear-right" />
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FoxCard;
|
||||
14
src/components/FoxCard.js
Normal file
14
src/components/FoxCard.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import React from 'react';
|
||||
import '../styles/FoxCard.css';
|
||||
|
||||
const FoxCard = ({ children, className = '' }) => {
|
||||
return (
|
||||
<div className={`fox-card ${className}`}>
|
||||
<div className="fox-ear fox-ear-left" />
|
||||
<div className="fox-ear fox-ear-right" />
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FoxCard;
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import GithubRepos from './GithubRepos';
|
||||
|
||||
test('renders GithubRepos component', () => {
|
||||
render(<GithubRepos />);
|
||||
const linkElement = screen.getByText(/Github Repositories/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
||||
59
src/components/SpotifyVisualizer.js
Normal file
59
src/components/SpotifyVisualizer.js
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import React, { useEffect, useRef } from 'react';
|
||||
import '../styles/SpotifyVisualizer.css';
|
||||
|
||||
const SpotifyVisualizer = ({ isPlaying }) => {
|
||||
const canvasRef = useRef(null);
|
||||
const animationRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
const ctx = canvas.getContext('2d');
|
||||
const bars = 50;
|
||||
const barWidth = canvas.width / bars;
|
||||
|
||||
const animate = () => {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
for (let i = 0; i < bars; i++) {
|
||||
const height = isPlaying ?
|
||||
Math.random() * canvas.height * 0.8 :
|
||||
canvas.height * 0.1;
|
||||
|
||||
const gradient = ctx.createLinearGradient(0, canvas.height, 0, canvas.height - height);
|
||||
gradient.addColorStop(0, '#9d4edd');
|
||||
gradient.addColorStop(1, '#b249f8');
|
||||
|
||||
ctx.fillStyle = gradient;
|
||||
ctx.fillRect(
|
||||
i * barWidth,
|
||||
canvas.height - height,
|
||||
barWidth - 2,
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
animationRef.current = requestAnimationFrame(animate);
|
||||
};
|
||||
|
||||
animate();
|
||||
|
||||
return () => {
|
||||
if (animationRef.current) {
|
||||
cancelAnimationFrame(animationRef.current);
|
||||
}
|
||||
};
|
||||
}, [isPlaying]);
|
||||
|
||||
return (
|
||||
<div className="visualizer-container">
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
width={300}
|
||||
height={60}
|
||||
className="music-visualizer"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SpotifyVisualizer;
|
||||
35
src/styles/FoxCard.css
Normal file
35
src/styles/FoxCard.css
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
.fox-card {
|
||||
position: relative;
|
||||
background: var(--gradient-card);
|
||||
border-radius: 16px;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid rgba(157, 78, 221, 0.2);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.fox-ear {
|
||||
position: absolute;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background: var(--fox-pink);
|
||||
opacity: 0.1;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.fox-ear-left {
|
||||
top: -15px;
|
||||
left: -15px;
|
||||
transform: rotate(45deg);
|
||||
border-radius: 0 0 0 15px;
|
||||
}
|
||||
|
||||
.fox-ear-right {
|
||||
top: -15px;
|
||||
right: -15px;
|
||||
transform: rotate(-45deg);
|
||||
border-radius: 0 0 15px 0;
|
||||
}
|
||||
|
||||
.fox-card:hover .fox-ear {
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
|
@ -1,62 +1,57 @@
|
|||
/* src/styles/LoadingAnimation.css */
|
||||
.loading-container {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
background: linear-gradient(135deg, rgba(26, 11, 46, 0.9), rgba(47, 28, 84, 0.9));
|
||||
backdrop-filter: blur(10px);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.loading-background {
|
||||
.loading-spinner {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border: 4px solid rgba(157, 78, 221, 0.1);
|
||||
border-left: 4px solid #9d4edd;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.loading-spinner::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
opacity: 0.2;
|
||||
z-index: -1;
|
||||
border-radius: 50%;
|
||||
border: 4px solid transparent;
|
||||
border-left: 4px solid #b249f8;
|
||||
animation: spin 0.5s linear infinite reverse;
|
||||
}
|
||||
|
||||
.code-char {
|
||||
color: #00ff00;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-size: 14px;
|
||||
animation: scroll 10s linear infinite;
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.code-char:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
.loading-text {
|
||||
position: absolute;
|
||||
margin-top: 100px;
|
||||
color: #ffffff;
|
||||
font-size: 1.2rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
animation: glow 1.5s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes scroll {
|
||||
0% { transform: translateY(100%); }
|
||||
100% { transform: translateY(-100%); }
|
||||
}
|
||||
|
||||
.loading-blocks {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.block {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: var(--primary-color);
|
||||
animation: block-loading 1s infinite;
|
||||
}
|
||||
|
||||
.block:nth-child(1) { animation-delay: 0s; }
|
||||
.block:nth-child(2) { animation-delay: 0.2s; }
|
||||
.block:nth-child(3) { animation-delay: 0.4s; }
|
||||
.block:nth-child(4) { animation-delay: 0.6s; }
|
||||
.block:nth-child(5) { animation-delay: 0.8s; }
|
||||
|
||||
@keyframes block-loading {
|
||||
0%, 100% { transform: scale(1); }
|
||||
50% { transform: scale(1.5); }
|
||||
@keyframes glow {
|
||||
from {
|
||||
text-shadow: 0 0 5px #e0aaff, 0 0 10px #e0aaff, 0 0 15px #b249f8;
|
||||
}
|
||||
to {
|
||||
text-shadow: 0 0 10px #e0aaff, 0 0 20px #e0aaff, 0 0 30px #b249f8;
|
||||
}
|
||||
}
|
||||
49
src/styles/LoadingFox.css
Normal file
49
src/styles/LoadingFox.css
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
.loading-fox-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.fox-loader {
|
||||
position: relative;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.fox-face {
|
||||
position: relative;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background: var(--fox-orange);
|
||||
border-radius: 50%;
|
||||
animation: bounce 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.fox-ears {
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.ear {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: var(--fox-orange);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.ear.left {
|
||||
transform: rotate(-30deg);
|
||||
}
|
||||
|
||||
.ear.right {
|
||||
transform: rotate(30deg);
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-10px); }
|
||||
}
|
||||
15
src/styles/cursor.css
Normal file
15
src/styles/cursor.css
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/* Base cursor */
|
||||
* {
|
||||
cursor: url("cursor/default.svg") 16 16, auto;
|
||||
}
|
||||
|
||||
/* Clickable elements cursor */
|
||||
a, button, [role="button"], input[type="submit"],
|
||||
input[type="button"], select {
|
||||
cursor: url("cursor/paw.svg") 16 16, pointer;
|
||||
}
|
||||
|
||||
/* Loading cursor */
|
||||
.loading {
|
||||
cursor: url("cursor/tail-loading.svg") 16 16, progress;
|
||||
}
|
||||
3
src/styles/cursor/default.svg
Normal file
3
src/styles/cursor/default.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16 8C16 8 18 12 22 14C26 16 28 16 28 16C28 16 26 20 22 22C18 24 16 24 16 24C16 24 14 20 10 18C6 16 4 16 4 16C4 16 6 12 10 10C14 8 16 8 16 8Z" fill="#9d4edd" stroke="#ffc6e5" stroke-width="1.5"/>
|
||||
</svg>
|
||||
4
src/styles/cursor/paw.svg
Normal file
4
src/styles/cursor/paw.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 8C12 10.2091 10.2091 12 8 12C5.79086 12 4 10.2091 4 8C4 5.79086 5.79086 4 8 4C10.2091 4 12 5.79086 12 8Z" fill="#9d4edd"/>
|
||||
<path d="M28 8C28 10.2091 26.2091 12 24 12C21.7909 12 20 10.2091 20 8C20 5.79086 21.7909 4 24 4C26.2091 4 28 5.79086 28 8Z" fill="#9d4edd"/>
|
||||
</svg>
|
||||
22
src/styles/theme.css
Normal file
22
src/styles/theme.css
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* Base theme colors */
|
||||
:root {
|
||||
/* Main colors */
|
||||
--background-primary: #1a0b2e;
|
||||
--background-secondary: #2f1c54;
|
||||
--accent-primary: #9d4edd;
|
||||
--accent-neon: #b249f8;
|
||||
--text-glow: #e0aaff;
|
||||
--text-primary: #ffffff;
|
||||
--dark-accent: #240046;
|
||||
|
||||
/* Fox theme accents */
|
||||
--fox-pink: #ffc6e5;
|
||||
--fox-pink-glow: #ffadd6;
|
||||
--fox-orange: #ff9466;
|
||||
--fox-white: #fff5f9;
|
||||
|
||||
/* Gradients */
|
||||
--gradient-primary: linear-gradient(135deg, var(--background-primary) 0%, var(--background-secondary) 100%);
|
||||
--gradient-card: linear-gradient(135deg, rgba(47, 28, 84, 0.3) 0%, rgba(157, 78, 221, 0.1) 100%);
|
||||
--gradient-hover: linear-gradient(135deg, rgba(157, 78, 221, 0.2) 0%, rgba(178, 73, 248, 0.1) 100%);
|
||||
}
|
||||
|
|
@ -4,15 +4,26 @@ compatibility_date = "2024-01-30"
|
|||
|
||||
[build]
|
||||
command = "npm run build"
|
||||
watch_dir = "build"
|
||||
cwd = "."
|
||||
watch_dir = "src"
|
||||
|
||||
[site]
|
||||
bucket = "./build"
|
||||
|
||||
# Environment-specific configurations
|
||||
[env.production]
|
||||
name = "personal-site"
|
||||
vars = { ENVIRONMENT = "production" }
|
||||
routes = ["personal-site.pages.dev/*"]
|
||||
|
||||
[env.development]
|
||||
name = "personal-site-dev"
|
||||
vars = { ENVIRONMENT = "development" }
|
||||
vars = { ENVIRONMENT = "development" }
|
||||
|
||||
[[rules]]
|
||||
type = "CompiledWasm"
|
||||
globs = ["**/*.wasm"]
|
||||
|
||||
[[rules]]
|
||||
type = "Text"
|
||||
globs = ["**/*.html", "**/*.css", "**/*.js", "**/*.json"]
|
||||
Loading…
Add table
Reference in a new issue