diff --git a/README.md b/README.md index a256540..dd4e692 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,10 @@ The workflow checks: - [ ] Admin dashboard - [-] Add SEO - [ ] Add blog +- [ ] Secret audio page - [ ] Deepgram API for speech to text +- [-] responsive +- [ ] loading screen ## License diff --git a/app/about/page.tsx b/app/about/page.tsx index 55fe157..e119fe7 100644 --- a/app/about/page.tsx +++ b/app/about/page.tsx @@ -12,60 +12,96 @@ export default function AboutPage() {

About Me

-
-
- -

Professional Journey

-

- With a unique blend of software development and industrial automation expertise, I bring a diverse perspective to technical challenges. My journey began in industrial automation, where I developed a strong foundation in electrical systems and controls. -

-

- Today, I'm focused on software development, combining my hardware knowledge with modern programming practices to create innovative solutions. -

-
+
+ +

Introduction

+

+ I am a mechatronic technologist and software developer, where I work on industrial manufacturing equipment, + software, and web development. Before my obsession with technology, I was primarily focused on music + production. During COVID-19, I distributed my first album on streaming services such as Apple Music and + Spotify. +

+

+ In my spare time, I enjoy investing in learning new things, building web apps, and further expand my + ideas. I am particularly interested in complex projects with artificial intelligence, virtual reality, industrial + manufacturing, data centers, and blockchain technology. If you think I can be helpful to you or your cause and + would like to meet, please feel free to get in touch. +

+
- -

Technical Philosophy

-

- I believe in creating software that isn't just functional, but also maintainable and scalable. My approach combines practical industrial experience with modern development practices. -

-

- I'm particularly interested in the intersection of software and hardware, exploring ways to bridge these domains to create more efficient and reliable systems. -

-
-
+ +

Executive Summary

+

+ With over 11 years of experience troubleshooting complex electromechanical systems and developing software + solutions, I believe I have the skills and background to excel in this position. As outlined on my attached resume, + I have extensive hands-on experience maintaining and repairing industrial equipment and machinery. From + pneumatic and hydraulic systems to PLCs and HMIs, I have worked with a wide variety of components and + understand how to keep production lines running smoothly. I also have experience with programming + languages C Python and JavaScript and have worked on projects involving robotics, computer vision, and + embedded systems. In addition to my technical expertise, I am an analytical and solutions-oriented + professional. Whether troubleshooting sudden breakdown or planning major upgrades, I can systematically + evaluate problems, weigh alternatives, and implement effective solutions. +

+
-
- -

Core Skills

-
-
-

Software Development

-
- Python - JavaScript - React - Node.js -
+ +

Objective

+

+ To obtain an Industrial Mechanic role that leverages my 11+ years of experience troubleshooting complex + industrial equipment and developing robust software solutions for manufacturing systems, instrumentation, and + robotics. I offer my expertise in preventative maintenance, manufacturing processes, and programming + languages to improve production efficiency, uptime, quality, and innovation. +

+

+ My goal is to utilize my skill set in automation technologies to reduce downtime and drive process + improvements through systemic analysis and effective implementations. +

+
+ + +

Core Skills

+
+
+

Software Development

+
+ Python + JavaScript + React + Node.js + C
-
-

Industrial Automation

-
- PLC Programming - HMI Design - Control Systems -
+
+
+

Industrial Automation

+
+ PLCs + HMIs + Robotics + Computer Vision + Embedded Systems
- - - -

Continuous Learning

-

- I'm constantly exploring new technologies and methodologies, believing that the best solutions come from a combination of proven practices and innovative approaches. -

-
-
+
+

Technologies

+
+ AI + Virtual Reality + Blockchain + Data Centers + Manufacturing +
+
+
+

Mechanical Systems

+
+ Pneumatics + Hydraulics + Preventative Maintenance + Troubleshooting +
+
+
+
) diff --git a/app/audio-recorder/page.tsx b/app/audio-recorder/page.tsx new file mode 100644 index 0000000..a19e5dd --- /dev/null +++ b/app/audio-recorder/page.tsx @@ -0,0 +1,83 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { Card } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; +import dynamic from 'next/dynamic'; + +// Dynamically import react-confetti to avoid SSR issues +const Confetti = dynamic(() => import('react-confetti'), { + ssr: false +}); + +export default function AudioRecorderPage() { + const [showConfetti, setShowConfetti] = useState(true); + const [showDialog, setShowDialog] = useState(true); + const [windowSize, setWindowSize] = useState({ + width: typeof window !== 'undefined' ? window.innerWidth : 0, + height: typeof window !== 'undefined' ? window.innerHeight : 0 + }); + + useEffect(() => { + const handleResize = () => { + setWindowSize({ + width: window.innerWidth, + height: window.innerHeight + }); + }; + + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); + + useEffect(() => { + // Hide confetti after 5 seconds + const timer = setTimeout(() => { + setShowConfetti(false); + }, 5000); + + return () => clearTimeout(timer); + }, []); + + return ( +
+ {showConfetti && ( + + )} + + + + + + 🎉 Congratulations! 🎉 + + +
+

+ You've discovered the secret audio recorder page! +

+ +
+
+
+ + +
+

Audio Recorder

+

+ This is a hidden page where you can record and play audio. +

+ {/* Audio recorder component will go here */} +
+
+
+ ); +} diff --git a/app/blog/hello-world/page.tsx b/app/blog/hello-world/page.tsx new file mode 100644 index 0000000..24f22b1 --- /dev/null +++ b/app/blog/hello-world/page.tsx @@ -0,0 +1,47 @@ +import Link from 'next/link' + +export default function HelloWorldPost() { + return ( +
+
+
+ + Back + +
+ +
+

Hello World

+

+ You've seen so many videos and blogs mention 'Hello World', but do you really know what it means? +

+ +
+ Written by John Doe + • + Sep 20, 2024 +
+ +

What is "Hello World"?

+

+ "Hello World" is essentially a way to confirm that everything is working as expected. When + you write and run this program, it outputs the phrase "Hello, World!" to the screen, showing + that your environment is set up correctly. Every programming language has its own + syntax for doing this, and it's the perfect way to get comfortable with the basics. +

+ +

A Simple Example in Python:

+
print("Hello, World!")
+ +

+ That's it! Running this code will output the text to the console, and boom—you've just + written your first Python program. +

+
+
+
+ ) +} diff --git a/app/blog/page.tsx b/app/blog/page.tsx new file mode 100644 index 0000000..28bba88 --- /dev/null +++ b/app/blog/page.tsx @@ -0,0 +1,27 @@ +import Link from 'next/link' + +export default function BlogPage() { + return ( +
+
+

Blog

+ +
+
+ +

Hello World

+

+ You've seen so many videos and blogs mention 'Hello World', but do you really know what it means? +

+
+ Written by John Doe + • + Sep 20, 2024 +
+ +
+
+
+
+ ) +} diff --git a/app/globals.css b/app/globals.css index 4d5daf2..907799a 100644 --- a/app/globals.css +++ b/app/globals.css @@ -90,3 +90,28 @@ body { background-color: black; } } + +/* Blog styles */ +.prose { + @apply text-foreground; +} + +.prose h1 { + @apply text-4xl font-bold mb-4 mt-0; +} + +.prose h2 { + @apply text-2xl font-bold mt-8 mb-4; +} + +.prose p { + @apply mb-4 leading-relaxed; +} + +.prose pre { + @apply bg-card p-4 rounded-lg my-4; +} + +.prose code { + @apply text-sm font-mono; +} diff --git a/app/layout.tsx b/app/layout.tsx index 56ea2d3..e110d11 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -4,6 +4,7 @@ import "./globals.css"; import { ThemeProvider } from "@/components/theme-provider"; import Navbar from "@/components/navbar"; import { personSchema, projectsSchema } from './schema'; +import { LoadingScreen } from "@/components/loading-screen"; const geistSans = localFont({ src: "./fonts/GeistVF.woff", @@ -89,8 +90,10 @@ export default function RootLayout({ attribute="class" defaultTheme="dark" enableSystem={true} + disableTransitionOnChange >
+
{children} diff --git a/app/resume/page.tsx b/app/resume/page.tsx index 5ccfbce..cf2e4e2 100644 --- a/app/resume/page.tsx +++ b/app/resume/page.tsx @@ -4,6 +4,7 @@ import { Button } from "@/components/ui/button" import { Card } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" import { Download, Mail, Github, Linkedin } from "lucide-react" +import { CodeIcon, GlobeIcon, Settings2Icon, BotIcon, WrenchIcon } from "@/components/icons" export default function ResumePage() { return ( @@ -20,7 +21,7 @@ export default function ResumePage() {
@@ -97,50 +124,123 @@ export default function ResumePage() { {/* Sidebar - Right Column */}
- {/* Skills Section */} + {/* Technical Skills Section */}
-

Skills

- -
-
-

Programming

-
- JavaScript - TypeScript - Python - React - Node.js +
+

Technical Skills

+ + +

+
+ + Programming & Development
+

+
+ Python + JavaScript + Java + C + C# + HTML + CSS + React + Node.js + Next.js
-
-

Technical

-
- PLC Programming - Electrical - Mechanical - AutoCAD + + + +

+
+ + Database & Cloud Technologies
+

+
+ SQL + MongoDB + PostgreSQL + Google Cloud + Azure + Docker + Git + Version Control + CI/CD
-
-

Tools

-
- Git - Docker - AWS - Linux + + + +

+
+ + Industrial Automation
+

+
+ PLC Programming + HMI Integration + SCADA Systems + Electrical Systems + Mechanical Systems + Pneumatics + Hydraulics + Industrial IoT
-
- + + + +

+
+ + Professional Skills +
+

+
+ Project Management + Preventative Maintenance + Quality Assurance + Technical Documentation + Problem Solving + Team Leadership + Cross-functional Collaboration + Process Optimization +
+
+ + +

+
+ + AI & Machine Learning +
+

+
+ Large Language Models + Computer Vision + Natural Language Processing + TensorFlow + PyTorch + Neural Networks +
+
+
{/* Education Section */}

Education

-

The University of Texas at El Paso

-

B.S. in Electrical Engineering

-

2015-2018

+
+
+

Computer Programming & Computer Science

+

El Paso Community College

+
+
+

Electrical Engineering

+

University of Texas at El Paso

+
+
@@ -149,9 +249,8 @@ export default function ResumePage() {

Certifications

    -
  • AWS Certified Cloud Practitioner
  • -
  • CompTIA A+
  • -
  • OSHA 30-Hour Safety
  • +
  • NFPA 70E: Electrical Safety
  • +
  • OSHA 10: Construction Safety
diff --git a/app/skills/page.tsx b/app/skills/page.tsx index 93f8b21..c43f714 100644 --- a/app/skills/page.tsx +++ b/app/skills/page.tsx @@ -1,8 +1,9 @@ +"use client"; + import { PageLayout } from "@/components/page-layout"; import { Card } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { FaCode, FaCogs, FaServer, FaTools, FaBrain } from "react-icons/fa"; -import { SkillsScene } from "@/components/three/SkillsScene" interface SkillCategory { title: string; @@ -86,17 +87,7 @@ export default function SkillsPage() {
{/* 3D Skills Visualization */} -
-

Skills Integration

-

- Explore how my expertise in software development, mechatronics, and audio engineering intersect - and complement each other. Click and drag to rotate the visualization. -

-
- -
-
- + {/* Original Skills Content */}

Technical Skills

diff --git a/components/audio/AudioEffectsProcessor.tsx b/components/audio/AudioEffectsProcessor.tsx index 904c7ab..5b40ed7 100644 --- a/components/audio/AudioEffectsProcessor.tsx +++ b/components/audio/AudioEffectsProcessor.tsx @@ -56,7 +56,7 @@ export function AudioEffectsProcessor({ } // Create convolution reverb buffer - const createReverbBuffer = async () => { + const createReverbBuffer = useCallback(async () => { if (!audioContext) return null const length = audioContext.sampleRate * 2 // 2 seconds @@ -70,8 +70,43 @@ export function AudioEffectsProcessor({ } return impulseBuffer + }, [audioContext]) + + // Create distortion curve + const createDistortionCurve = (amount: number) => { + const samples = 44100 + const curve = new Float32Array(samples) + const deg = Math.PI / 180 + + for (let i = 0; i < samples; ++i) { + const x = (i * 2) / samples - 1 + curve[i] = ((3 + amount) * x * 20 * deg) / (Math.PI + amount * Math.abs(x)) + } + + return curve } + // Connect all effects in the chain + const connectEffectsChain = useCallback(() => { + if (!audioContext || !sourceNode || effects.length === 0) return + + let previousNode: AudioNode = sourceNode + + effects.forEach((effect) => { + if (!effect.bypass) { + previousNode.connect(effect.node) + previousNode = effect.node + } + }) + + // Connect the last effect to the destination + if (onProcessedNode) { + onProcessedNode(previousNode) + } else { + previousNode.connect(audioContext.destination) + } + }, [audioContext, sourceNode, effects, onProcessedNode]) + // Initialize effects chain const initializeEffects = useCallback(async () => { if (!audioContext || !sourceNode) return @@ -136,42 +171,7 @@ export function AudioEffectsProcessor({ // Connect the effects chain connectEffectsChain() - }, [audioContext, sourceNode]) - - // Create distortion curve - const createDistortionCurve = (amount: number) => { - const samples = 44100 - const curve = new Float32Array(samples) - const deg = Math.PI / 180 - - for (let i = 0; i < samples; ++i) { - const x = (i * 2) / samples - 1 - curve[i] = ((3 + amount) * x * 20 * deg) / (Math.PI + amount * Math.abs(x)) - } - - return curve - } - - // Connect all effects in the chain - const connectEffectsChain = () => { - if (!audioContext || !sourceNode || effects.length === 0) return - - let previousNode: AudioNode = sourceNode - - effects.forEach((effect) => { - if (!effect.bypass) { - previousNode.connect(effect.node) - previousNode = effect.node - } - }) - - // Connect the last effect to the destination - if (onProcessedNode) { - onProcessedNode(previousNode) - } else { - previousNode.connect(audioContext.destination) - } - } + }, [audioContext, sourceNode, createReverbBuffer, connectEffectsChain]) // Update effect parameters const updateEffect = (effectType: string, paramName: string, value: number) => { diff --git a/components/icons.tsx b/components/icons.tsx index 177a3ef..cfd4f22 100644 --- a/components/icons.tsx +++ b/components/icons.tsx @@ -12,3 +12,114 @@ export function IconUser({ className }: { className?: string }) { ); } + +export function CodeIcon({ className }: { className?: string }) { + return ( + + + + + ); +} + +export function GlobeIcon({ className }: { className?: string }) { + return ( + + + + + + ); +} + +export function Settings2Icon({ className }: { className?: string }) { + return ( + + + + + + + ); +} + +export function ChipIcon({ className }: { className?: string }) { + return ( + + + + + + + + + + + + + ); +} + +export function MonitorIcon({ className }: { className?: string }) { + return ( + + + + + + ); +} + +export function NetworkIcon({ className }: { className?: string }) { + return ( + + + + + + + + + + ); +} + +export function BotIcon({ className }: { className?: string }) { + return ( + + + + + + + + ); +} + +export function GaugeIcon({ className }: { className?: string }) { + return ( + + + + + ); +} + +export function LayoutDashboardIcon({ className }: { className?: string }) { + return ( + + + + + + + ); +} + +export function WrenchIcon({ className }: { className?: string }) { + return ( + + + + ); +} diff --git a/components/loading-screen.tsx b/components/loading-screen.tsx new file mode 100644 index 0000000..e71471d --- /dev/null +++ b/components/loading-screen.tsx @@ -0,0 +1,130 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; + +export function LoadingScreen() { + const [isLoading, setIsLoading] = useState(true); + const [dimensions, setDimensions] = useState({ + width: typeof window !== 'undefined' ? window.innerWidth : 0, + height: typeof window !== 'undefined' ? window.innerHeight : 0, + }); + + useEffect(() => { + const handleResize = () => { + setDimensions({ + width: window.innerWidth, + height: window.innerHeight, + }); + }; + + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); + + useEffect(() => { + // Hide loading screen after 2.5 seconds + const timer = setTimeout(() => { + setIsLoading(false); + }, 2500); + + return () => clearTimeout(timer); + }, []); + + const letterVariants = { + hidden: { y: 20, opacity: 0 }, + visible: (i: number) => ({ + y: 0, + opacity: 1, + transition: { + delay: i * 0.1, + duration: 0.5, + ease: [0.6, -0.05, 0.01, 0.99], + }, + }), + exit: { + y: -20, + opacity: 0, + transition: { + duration: 0.5, + ease: [0.6, -0.05, 0.01, 0.99], + }, + }, + }; + + // Split name into first and last name for better mobile layout + const firstName = "Christopher".split(""); + const lastName = "Celaya".split(""); + + return ( + + {isLoading && ( + +
+
+ {/* First Name */} +
+ {firstName.map((letter, i) => ( + + {letter} + + ))} +
+ + {/* Space between names */} + + {" "} + + + {/* Last Name */} +
+ {lastName.map((letter, i) => ( + + {letter} + + ))} +
+
+ + {/* Underline */} + +
+
+ )} +
+ ); +} diff --git a/components/nav-dropdown.tsx b/components/nav-dropdown.tsx index d74e263..b16a083 100644 --- a/components/nav-dropdown.tsx +++ b/components/nav-dropdown.tsx @@ -1,7 +1,8 @@ 'use client'; import * as React from 'react'; -import { Github, Linkedin, Twitter, FileText } from 'lucide-react'; +import Link from 'next/link'; +import { Github, Linkedin, Twitter, FileText, BookOpen } from 'lucide-react'; import { DropdownMenu, DropdownMenuContent, @@ -11,10 +12,36 @@ import { export function NavDropdown() { const menuItems = [ - { icon: , label: 'GitHub', href: 'https://github.com/christophercelaya' }, - { icon: , label: 'LinkedIn', href: 'https://linkedin.com/in/christophercelaya' }, - { icon: , label: 'Twitter', href: 'https://twitter.com/christophercelaya' }, - { icon: , label: 'Resume', href: '/resume.pdf' }, + { + icon: , + label: 'Blog', + href: '/blog', + internal: true + }, + { + icon: , + label: 'GitHub', + href: 'https://github.com/christophercelaya', + internal: false + }, + { + icon: , + label: 'LinkedIn', + href: 'https://linkedin.com/in/christophercelaya', + internal: false + }, + { + icon: , + label: 'Twitter', + href: 'https://twitter.com/christophercelaya', + internal: false + }, + { + icon: , + label: 'Resume', + href: '/resume.pdf', + internal: true + }, ]; return ( @@ -34,15 +61,25 @@ export function NavDropdown() { {menuItems.map((item) => ( - - {item.icon} - {item.label} - + {item.internal ? ( + + {item.icon} + {item.label} + + ) : ( + + {item.icon} + {item.label} + + )} ))} diff --git a/components/navbar.tsx b/components/navbar.tsx index 5a67ca3..81437df 100644 --- a/components/navbar.tsx +++ b/components/navbar.tsx @@ -14,6 +14,11 @@ const Navbar = () => { label: "About", active: pathname === "/about", }, + { + href: "/blog", + label: "Blog", + active: pathname === "/blog", + }, { href: "/projects", label: "Projects", @@ -39,11 +44,7 @@ const Navbar = () => { label: "Resume", active: pathname === "/resume", }, - { - href: "/audio", - label: "Audio", - active: pathname === "/audio", - }, + // Audio recorder page is hidden ] return ( diff --git a/components/ui/progress.tsx b/components/ui/progress.tsx new file mode 100644 index 0000000..5c87ea4 --- /dev/null +++ b/components/ui/progress.tsx @@ -0,0 +1,28 @@ +"use client" + +import * as React from "react" +import * as ProgressPrimitive from "@radix-ui/react-progress" + +import { cn } from "@/lib/utils" + +const Progress = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, value, ...props }, ref) => ( + + + +)) +Progress.displayName = ProgressPrimitive.Root.displayName + +export { Progress } diff --git a/package-lock.json b/package-lock.json index aa406aa..a97efc6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-popover": "^1.1.2", + "@radix-ui/react-progress": "^1.1.0", "@radix-ui/react-scroll-area": "^1.2.1", "@radix-ui/react-select": "^2.1.2", "@radix-ui/react-slider": "^1.2.1", @@ -30,6 +31,7 @@ "next-sitemap": "^4.2.3", "next-themes": "^0.4.3", "react": "^18", + "react-confetti": "^6.1.0", "react-dom": "^18", "react-icons": "^5.3.0", "react-markdown": "^9.0.1", @@ -1507,6 +1509,45 @@ } } }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.0.tgz", + "integrity": "sha512-aSzvnYpP725CROcxAOEBVZZSIQVQdHgBr2QQFKySsaD14u8dNT0batuXI+AAGDdAHfXH8rbnHmjYFqVJ21KkRg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-roving-focus": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz", @@ -7797,6 +7838,21 @@ "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-confetti": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.1.0.tgz", + "integrity": "sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==", + "license": "MIT", + "dependencies": { + "tween-functions": "^1.2.0" + }, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.1 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -9203,6 +9259,12 @@ } } }, + "node_modules/tween-functions": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz", + "integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==", + "license": "BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index b27142e..74edcd7 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-popover": "^1.1.2", + "@radix-ui/react-progress": "^1.1.0", "@radix-ui/react-scroll-area": "^1.2.1", "@radix-ui/react-select": "^2.1.2", "@radix-ui/react-slider": "^1.2.1", @@ -35,6 +36,7 @@ "next-sitemap": "^4.2.3", "next-themes": "^0.4.3", "react": "^18", + "react-confetti": "^6.1.0", "react-dom": "^18", "react-icons": "^5.3.0", "react-markdown": "^9.0.1", diff --git a/public/sitemap.xml b/public/sitemap.xml index 362a629..87360b9 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -1,14 +1,17 @@ -https://chriscelaya.com/about2024-11-30T07:27:41.852Zweekly0.8 -https://chriscelaya.com/experience2024-11-30T07:27:41.854Zweekly0.8 -https://chriscelaya.com/profile2024-11-30T07:27:41.854Zweekly0.7 -https://chriscelaya.com/projects2024-11-30T07:27:41.854Zweekly0.9 -https://chriscelaya.com/resume2024-11-30T07:27:41.854Zweekly0.7 -https://chriscelaya.com/dashboard2024-11-30T07:27:41.854Zweekly0.7 -https://chriscelaya.com/gallery2024-11-30T07:27:41.854Zweekly0.7 -https://chriscelaya.com2024-11-30T07:27:41.854Zweekly1 -https://chriscelaya.com/case-studies2024-11-30T07:27:41.854Zweekly0.9 -https://chriscelaya.com/skills2024-11-30T07:27:41.854Zweekly0.7 -https://chriscelaya.com/audio2024-11-30T07:27:41.854Zweekly0.7 +https://chriscelaya.com/about2024-11-30T08:24:01.264Zweekly0.8 +https://chriscelaya.com/blog2024-11-30T08:24:01.265Zweekly0.7 +https://chriscelaya.com/dashboard2024-11-30T08:24:01.265Zweekly0.7 +https://chriscelaya.com/gallery2024-11-30T08:24:01.265Zweekly0.7 +https://chriscelaya.com/profile2024-11-30T08:24:01.265Zweekly0.7 +https://chriscelaya.com/resume2024-11-30T08:24:01.265Zweekly0.7 +https://chriscelaya.com/case-studies2024-11-30T08:24:01.265Zweekly0.9 +https://chriscelaya.com/experience2024-11-30T08:24:01.265Zweekly0.8 +https://chriscelaya.com/projects2024-11-30T08:24:01.265Zweekly0.9 +https://chriscelaya.com/skills2024-11-30T08:24:01.265Zweekly0.7 +https://chriscelaya.com2024-11-30T08:24:01.265Zweekly1 +https://chriscelaya.com/blog/hello-world2024-11-30T08:24:01.265Zweekly0.7 +https://chriscelaya.com/audio2024-11-30T08:24:01.265Zweekly0.7 +https://chriscelaya.com/audio-recorder2024-11-30T08:24:01.265Zweekly0.7 \ No newline at end of file