diff --git a/.Jules/palette.md b/.Jules/palette.md new file mode 100644 index 0000000..0cc8e36 --- /dev/null +++ b/.Jules/palette.md @@ -0,0 +1,7 @@ +## 2024-05-19 - Missing ARIA Labels on Modal Close Buttons +**Learning:** Icon-only close buttons (like the 'X' in ProjectModal and ExperienceModal) were missing ARIA labels, making them inaccessible to screen readers. +**Action:** Always verify that icon-only buttons include descriptive `aria-label` attributes to ensure keyboard and screen reader accessibility. + +## 2024-05-28 - Keyboard Accessibility for Custom Interactive Elements +**Learning:** Custom interactive elements (e.g., clickable `motion.div` cards like ExperienceCard and ProjectCard) lack native keyboard support, which prevents keyboard and screen reader users from triggering actions or seeing a focus state. +**Action:** Always ensure that non-native clickable elements include `role="button"`, `tabIndex={0}`, an `onKeyDown` handler (for "Enter" and "Space" keys), and `focus-visible` styles to ensure full keyboard accessibility. diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..c816c6d --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,11 @@ +{ + "permissions": { + "allow": [ + "Bash(npm run dev:*)", + "Bash(timeout:*)", + "Bash(ping:*)", + "Bash(git stash:*)", + "Bash(git checkout:*)" + ] + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e169df4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,157 @@ +# Created by https://www.toptal.com/developers/gitignore/api/react,node +# Edit at https://www.toptal.com/developers/gitignore?templates=react,node + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +.svelte-kit + +### react ### +.DS_* +**/*.backup.* +**/*.back.* + +node_modules + +*.sublime* + +psd +thumb +sketch + +# End of https://www.toptal.com/developers/gitignore/api/react,node \ No newline at end of file diff --git a/README.md b/README.md index 25ebd29..8659000 100644 --- a/README.md +++ b/README.md @@ -17,4 +17,4 @@ Hi, I’m Dev
šŸ“ Ahmedabad | šŸ–„ļø Backend Engineer | 22

I’m a B [![Ashutosh's github activity graph](https://github-readme-activity-graph.vercel.app/graph?username=dev22603&bg_color=010409&color=ffffff&line=00b344&point=ffffff&area=true&hide_border=true)](https://github.com/ashutosh00710/github-readme-activity-graph) - \ No newline at end of file + diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..de39d30 --- /dev/null +++ b/TODO.md @@ -0,0 +1,449 @@ +# Portfolio Redesign - TODO List + +This document outlines all tasks needed to redesign the portfolio to match the reference design from https://www.chaitanya-bajpai.xyz/ + +--- + +## šŸ“‹ Phase 1: Project Setup & Configuration + +### 1.1 Update Data Structure +- [ ] Create a comprehensive `data.json` or update `portfolio.json` with: + - Personal information (name, role, location, bio, profile image) + - Social media links (Twitter, GitHub, Email, Calendar/Blog) + - Experience data with expandable details (company, role, dates, description, tech stack, key achievements) + - Projects data with categories (personal/client), descriptions, tech stack, links + - Blog posts data (title, excerpt, date, slug/link) + - Skills/tech stack organized by categories + +### 1.2 Update Tailwind Configuration +- [ ] Configure custom color scheme: + - Primary blue accent color (#3B82F6 or similar) + - Dark background colors (#0A0A0A, #1A1A1A, #2A2A2A) + - Text colors (white, gray variations) +- [ ] Add custom spacing if needed for the grid layout +- [ ] Configure custom font families if using specific fonts + +--- + +## šŸ“‹ Phase 2: Layout & Navigation + +### 2.1 Remove/Refactor Navbar +- [ ] Remove the existing keyboard-shortcut based Navbar component +- [ ] Create a new simple header/navigation: + - Name/logo on the left + - Social media icon links on the right (Twitter, Calendar, Email, GitHub) + - Make it fixed or sticky at the top + - Ensure proper spacing and alignment + +### 2.2 Update Layout Component +- [ ] Keep the dot grid background pattern (already implemented) +- [ ] Adjust the grid spacing and dot size to match reference design +- [ ] Ensure proper container max-width (looks like ~1200px centered) +- [ ] Add proper padding/margins for mobile responsiveness + +### 2.3 Create Single-Page Layout +- [ ] Update `App.jsx` to show all sections on one page (remove routing) +- [ ] Or keep routing but make Home page show all sections +- [ ] Implement smooth scroll navigation (optional) + +--- + +## šŸ“‹ Phase 3: Hero Section + +### 3.1 Design Hero Component +- [ ] Create `components/Hero.jsx` or update `pages/Home.jsx` +- [ ] Layout structure: + - Profile image (rounded-full, medium size ~120-150px) + - Name heading (large, bold) + - Subtitle (age/location, role - smaller, gray text) + - Bio paragraph (max-width for readability) +- [ ] Remove the banner image and headshot layout from current Home.jsx +- [ ] Add proper spacing between elements +- [ ] Make it responsive (mobile-first) + +### 3.2 Add Social Media Icons +- [ ] Use lucide-react icons or similar: + - Twitter icon → Twitter link + - Calendar icon → Blog link + - Mail icon → Email link + - GitHub icon → GitHub link +- [ ] Style icons with hover effects (opacity or color change) +- [ ] Position icons horizontally in the hero or header + +--- + +## šŸ“‹ Phase 4: Experience Section + +### 4.1 Create Experience Component +- [ ] Create `components/Experience.jsx` or `components/ExperienceSection.jsx` +- [ ] Design the section: + - Section heading "Experience" (blue accent color, large font) + - Subtitle/description text + - List/timeline of experience items + +### 4.2 Create Experience Card Component +- [ ] Create `components/ExperienceCard.jsx` +- [ ] Design the card: + - Company icon/logo (optional colored background circle) + - Job title (bold, white text) + - Company name and dates (gray text) + - Short description + - Expandable modal/dropdown for details + +### 4.3 Implement Expandable Details +- [ ] Add click/tap interaction to show modal or expanded view +- [ ] Modal/expanded view should show: + - Tech Stack section with pills/tags for each technology + - Key Achievements section as bullet points + - Close button (X icon top-right) +- [ ] Use Framer Motion for smooth animations +- [ ] Ensure modal is accessible (ESC to close, focus trap) + +### 4.4 Style Tech Stack Tags +- [ ] Create reusable `TechTag.jsx` component +- [ ] Style as pills/badges with: + - Dark background + - Light border + - Small padding + - Rounded corners + - Proper spacing between tags + +--- + +## šŸ“‹ Phase 5: Projects Section + +### 5.1 Create Projects Section Component +- [ ] Create `components/ProjectsSection.jsx` +- [ ] Design the section: + - Section heading "Projects" (blue accent color) + - Subtitle/description text + - Tab navigation for "Personal Projects" and "Client Work" + +### 5.2 Implement Tab Navigation +- [ ] Create tab buttons component +- [ ] Implement state management for active tab +- [ ] Add smooth transition between tab content +- [ ] Style active tab with underline or different background +- [ ] Use Framer Motion for tab content transitions + +### 5.3 Create Project Card Component +- [ ] Create `components/ProjectCard.jsx` +- [ ] Design the card: + - Project name (bold, white text) + - Short description + - Tech stack tags (reuse TechTag component) + - Optional status badge (e.g., "Paused") + - External link icon if applicable +- [ ] Add hover effects (subtle scale or border glow) +- [ ] Make cards responsive (grid layout) + +### 5.4 Implement Project Grid +- [ ] Use CSS Grid or Flexbox for card layout +- [ ] 2 columns on desktop, 1 column on mobile +- [ ] Proper gap spacing between cards +- [ ] Ensure consistent card heights (or allow variable) + +--- + +## šŸ“‹ Phase 6: Blogs Section + +### 6.1 Create Blogs Section Component +- [ ] Create `components/BlogsSection.jsx` +- [ ] Design the section: + - Section heading "Blogs" (blue accent color) + - Subtitle/description text + - Grid/list of blog post cards + +### 6.2 Create Blog Card Component +- [ ] Create `components/BlogCard.jsx` +- [ ] Design the card: + - Blog title (bold, white text, clickable) + - Excerpt/description (gray text, 2-3 lines) + - Publication date (small, gray text) + - Hover effect (slight elevation or border highlight) +- [ ] Make entire card clickable/linkable +- [ ] Add smooth transitions + +### 6.3 Implement Blog Grid Layout +- [ ] Use CSS Grid for blog cards +- [ ] 1 column layout (full width cards) +- [ ] Proper spacing between cards +- [ ] Add pagination or "Load More" if many posts (optional) + +### 6.4 Connect to Blog Data +- [ ] Add blog post data to portfolio.json +- [ ] Structure: title, excerpt, date, slug/url, optional cover image +- [ ] Fetch and display dynamically +- [ ] Handle empty state (no blogs yet) + +--- + +## šŸ“‹ Phase 7: Styling & Polish + +### 7.1 Consistent Spacing & Typography +- [ ] Define consistent spacing scale (8px, 16px, 24px, 32px, etc.) +- [ ] Set up typography hierarchy: + - H1: Main name/hero heading (~48-56px) + - H2: Section headings (~32-40px) + - H3: Card titles (~20-24px) + - Body: Descriptions (~16px) + - Small: Dates, metadata (~14px) +- [ ] Ensure consistent line-height and letter-spacing + +### 7.2 Color Consistency +- [ ] Apply consistent color palette throughout: + - Background: Very dark (#0A0A0A - #1A1A1A) + - Cards: Slightly lighter dark (#1A1A1A - #2A2A2A) + - Borders: Subtle gray (#333 - #444) + - Text primary: White/near-white + - Text secondary: Gray (#888 - #999) + - Accent: Blue (#3B82F6 or similar) +- [ ] Add subtle hover states (lighter backgrounds, border glows) + +### 7.3 Card & Component Styling +- [ ] Apply consistent border-radius to all cards (~12-16px) +- [ ] Add subtle borders to cards (#333 1px) +- [ ] Add subtle background to cards (semi-transparent or solid dark) +- [ ] Ensure consistent padding inside cards (24-32px) +- [ ] Add hover effects with smooth transitions + +### 7.4 Animations & Transitions +- [ ] Add scroll-triggered fade-in animations for sections +- [ ] Use Framer Motion for: + - Section entrance animations (fadeIn, slideUp) + - Tab transitions + - Modal/expandable animations + - Hover effects +- [ ] Keep animations subtle and performant + +--- + +## šŸ“‹ Phase 8: Responsive Design āœ… + +### 8.1 Mobile Optimization āœ… +- [x] Test on mobile viewports (320px, 375px, 414px) +- [x] Adjust hero section layout for mobile: + - Stack elements vertically + - Reduce profile image size (w-28 h-28 sm:w-32 sm:h-32 md:w-40 md:h-40) + - Adjust font sizes (text-3xl sm:text-4xl md:text-5xl lg:text-6xl) +- [x] Make navigation mobile-friendly: + - Optimized social icons spacing (gap-2 sm:gap-4) + - Ensured touch targets are 44x44px+ (added p-2 -m-2 to all interactive elements) +- [x] Adjust project/blog grids to single column (grid-cols-1 sm:grid-cols-2) +- [x] Reduce padding/margins for smaller screens (p-4 sm:p-5 md:p-6) + +### 8.2 Tablet Optimization āœ… +- [x] Test on tablet viewports (768px, 1024px) +- [x] Adjust grid layouts (2 columns at 640px sm breakpoint instead of 768px md) +- [x] Ensure proper spacing and readability (responsive gap spacing) + +### 8.3 Desktop Optimization āœ… +- [x] Ensure max-width container is properly centered (max-w-5xl mx-auto) +- [x] Test on large screens (1920px+) +- [x] Ensure content doesn't stretch too wide (max-width constraints in place) +- [x] Optimize whitespace and spacing (responsive padding at all breakpoints) + +--- + +## šŸ“‹ Phase 9: Content & Data + +### 9.1 Populate Experience Data +- [ ] Add all work experiences to data file +- [ ] Include detailed descriptions +- [ ] List tech stacks for each role +- [ ] Document key achievements (3-5 bullet points each) +- [ ] Add company logos or icons (optional) + +### 9.2 Populate Projects Data +- [ ] Add all projects to data file +- [ ] Categorize as Personal or Client Work +- [ ] Write compelling descriptions +- [ ] List tech stacks +- [ ] Add links to live sites/repos +- [ ] Add project status (Active, Paused, Completed) + +### 9.3 Populate Blog Data +- [ ] Add blog posts to data file +- [ ] Write engaging titles and excerpts +- [ ] Add publication dates +- [ ] Add links to blog posts +- [ ] Consider adding cover images (optional) + +### 9.4 Update Personal Info +- [ ] Update name, bio, role +- [ ] Add location information +- [ ] Update profile image +- [ ] Verify all social media links + +--- + +## šŸ“‹ Phase 10: Performance & Optimization + +### 10.1 Image Optimization +- [ ] Optimize profile image (WebP format, proper size) +- [ ] Optimize company logos/icons +- [ ] Lazy load images below the fold +- [ ] Add proper alt text for accessibility + +### 10.2 Code Optimization +- [ ] Remove unused components/code +- [ ] Remove console.logs +- [ ] Optimize re-renders (React.memo, useMemo, useCallback) +- [ ] Code split large components if needed + +### 10.3 Performance Audit +- [ ] Run Lighthouse audit +- [ ] Achieve 90+ performance score +- [ ] Optimize bundle size +- [ ] Test load time on slow connections + +--- + +## šŸ“‹ Phase 11: Accessibility & SEO + +### 11.1 Accessibility +- [ ] Add proper semantic HTML (header, main, section, nav, footer) +- [ ] Ensure proper heading hierarchy (h1 → h2 → h3) +- [ ] Add ARIA labels where needed +- [ ] Ensure keyboard navigation works (tab through all interactive elements) +- [ ] Test with screen reader +- [ ] Ensure color contrast meets WCAG AA standards +- [ ] Add focus visible states for keyboard navigation + +### 11.2 SEO +- [ ] Update page title and meta description +- [ ] Add Open Graph tags for social sharing +- [ ] Add Twitter Card tags +- [ ] Add structured data (JSON-LD) for person/profile +- [ ] Create and add favicon +- [ ] Ensure semantic HTML for better SEO + +--- + +## šŸ“‹ Phase 12: Testing & Deployment + +### 12.1 Cross-Browser Testing +- [ ] Test on Chrome, Firefox, Safari, Edge +- [ ] Test on mobile browsers (Chrome, Safari) +- [ ] Fix any browser-specific issues +- [ ] Ensure animations work across browsers + +### 12.2 Quality Assurance +- [ ] Test all interactive elements (buttons, links, modals, tabs) +- [ ] Verify all links work correctly +- [ ] Test responsive behavior at various breakpoints +- [ ] Check for any console errors or warnings +- [ ] Proofread all content for typos + +### 12.3 Deployment +- [ ] Build production version (`npm run build`) +- [ ] Test production build locally +- [ ] Deploy to hosting platform (Vercel, Netlify, etc.) +- [ ] Verify deployment works correctly +- [ ] Set up custom domain if applicable +- [ ] Test live site on multiple devices + +--- + +## šŸ“‹ Phase 13: Optional Enhancements + +### 13.1 Additional Features +- [ ] Add dark/light mode toggle (currently dark only) +- [ ] Add contact form section +- [ ] Add testimonials section +- [ ] Add skills/tech stack visualization +- [ ] Add resume/CV download button +- [ ] Add "Back to Top" button for long pages + +### 13.2 Animations & Interactions +- [ ] Add cursor trail effect (optional) +- [ ] Add parallax scrolling effects +- [ ] Add loading animation on initial page load +- [ ] Add page transition animations + +### 13.3 Analytics & Tracking +- [ ] Add Google Analytics or similar +- [ ] Track button clicks and interactions +- [ ] Monitor page performance +- [ ] Set up error tracking (Sentry, etc.) + +--- + +## šŸŽÆ Priority Recommendations + +**High Priority (Do First):** +1. Phase 1: Data structure setup +2. Phase 2: Layout and navigation +3. Phase 3: Hero section +4. Phase 4: Experience section +5. Phase 5: Projects section + +**Medium Priority (Do Next):** +6. Phase 6: Blogs section +7. Phase 7: Styling and polish +8. Phase 8: Responsive design +9. Phase 9: Content and data + +**Low Priority (Final touches):** +10. Phase 10: Performance optimization +11. Phase 11: Accessibility and SEO +12. Phase 12: Testing and deployment +13. Phase 13: Optional enhancements + +--- + +## šŸ“ Implementation Notes + +### Component Structure Suggestion: +``` +src/ +ā”œā”€ā”€ components/ +│ ā”œā”€ā”€ Hero.jsx +│ ā”œā”€ā”€ Navigation.jsx (or Header.jsx) +│ ā”œā”€ā”€ ExperienceSection.jsx +│ ā”œā”€ā”€ ExperienceCard.jsx +│ ā”œā”€ā”€ ExperienceModal.jsx +│ ā”œā”€ā”€ ProjectsSection.jsx +│ ā”œā”€ā”€ ProjectCard.jsx +│ ā”œā”€ā”€ BlogsSection.jsx +│ ā”œā”€ā”€ BlogCard.jsx +│ ā”œā”€ā”€ TechTag.jsx +│ ā”œā”€ā”€ SocialLinks.jsx +│ └── Layout.jsx (existing) +ā”œā”€ā”€ data/ +│ └── portfolio.json (or data.json) +ā”œā”€ā”€ pages/ +│ └── Home.jsx (main landing page with all sections) +└── lib/ + └── utils.js (existing) +``` + +### Key Design Principles: +- **Consistency:** Use the same spacing, colors, and typography throughout +- **Hierarchy:** Clear visual hierarchy with headings and sections +- **Whitespace:** Don't overcrowd - let elements breathe +- **Contrast:** Ensure sufficient contrast for readability +- **Responsiveness:** Mobile-first approach, works on all devices +- **Performance:** Keep bundle size small, optimize images +- **Accessibility:** Keyboard navigable, screen reader friendly + +--- + +## āœ… Success Criteria + +The redesign is complete when: +- [ ] All sections match the reference design aesthetically +- [ ] All content is populated and accurate +- [ ] Site is fully responsive on mobile, tablet, and desktop +- [ ] All interactions work smoothly (modals, tabs, links) +- [ ] Performance score is 90+ on Lighthouse +- [ ] Accessibility score is 90+ on Lighthouse +- [ ] Site is deployed and live +- [ ] No console errors or warnings +- [ ] All links and buttons work correctly + +--- + +*Reference Design: https://www.chaitanya-bajpai.xyz/* +*Current Portfolio Data: `/frontend/portfolio.json`* +*Tech Stack: React, Vite, Tailwind CSS, Framer Motion* diff --git a/frontend/.gitignore b/frontend/.gitignore index a547bf3..e169df4 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -1,24 +1,157 @@ +# Created by https://www.toptal.com/developers/gitignore/api/react,node +# Edit at https://www.toptal.com/developers/gitignore?templates=react,node + +### Node ### # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* -pnpm-debug.log* lerna-debug.log* +.pnpm-debug.log* -node_modules +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +.svelte-kit + +### react ### +.DS_* +**/*.backup.* +**/*.back.* + +node_modules + +*.sublime* + +psd +thumb +sketch + +# End of https://www.toptal.com/developers/gitignore/api/react,node \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html index 0c589ec..968afe9 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,9 +2,31 @@ - + - Vite + React + Dev Bachani | Full Stack Engineer + + + + + + + + + + + + + + + + + + + + + +
diff --git a/frontend/jsconfig.json b/frontend/jsconfig.json new file mode 100644 index 0000000..39a3a5e --- /dev/null +++ b/frontend/jsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + // "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + }, + "jsx": "react-jsx" + }, + "include": ["src"] +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1adfcbb..a6b933b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,8 +9,13 @@ "version": "0.0.0", "dependencies": { "@tailwindcss/vite": "^4.1.12", + "clsx": "^2.1.1", + "framer-motion": "^12.23.12", + "lucide-react": "^0.541.0", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-router-dom": "^7.8.1", + "tailwind-merge": "^3.3.1", "tailwindcss": "^4.1.12" }, "devDependencies": { @@ -1688,6 +1693,15 @@ "node": ">=18" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1718,6 +1732,15 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -2097,6 +2120,33 @@ "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true }, + "node_modules/framer-motion": { + "version": "12.23.12", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.12.tgz", + "integrity": "sha512-6e78rdVtnBvlEVgu6eFEAgG9v3wLnYEboM8I5O5EXvfKC8gxGQB8wXJdhkMy10iVcn05jl6CNw7/HTsTCfwcWg==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.23.12", + "motion-utils": "^12.23.6", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2555,6 +2605,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "0.541.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.541.0.tgz", + "integrity": "sha512-s0Vircsu5WaGv2KoJZ5+SoxiAJ3UXV5KqEM3eIFDHaHkcLIFdIWgXtZ412+Gh02UsdS7Was+jvEpBvPCWQISlg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/magic-string": { "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", @@ -2608,6 +2667,21 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/motion-dom": { + "version": "12.23.12", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.12.tgz", + "integrity": "sha512-RcR4fvMCTESQBD/uKQe49D5RUeDOokkGRmz4ceaJKDBgHYtZtntC/s2vLvY38gqGaytinij/yi3hMcWVcEF5Kw==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.23.6" + } + }, + "node_modules/motion-utils": { + "version": "12.23.6", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz", + "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -2809,6 +2883,44 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.8.1.tgz", + "integrity": "sha512-5cy/M8DHcG51/KUIka1nfZ2QeylS4PJRs6TT8I4PF5axVsI5JUxp0hC0NZ/AEEj8Vw7xsEoD7L/6FY+zoYaOGA==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.8.1.tgz", + "integrity": "sha512-NkgBCF3sVgCiAWIlSt89GR2PLaksMpoo3HDCorpRfnCEfdtRPLiuTf+CNXvqZMI5SJLZCLpVCvcZrTdtGW64xQ==", + "license": "MIT", + "dependencies": { + "react-router": "7.8.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2870,6 +2982,12 @@ "semver": "bin/semver.js" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2923,6 +3041,16 @@ "node": ">=8" } }, + "node_modules/tailwind-merge": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz", + "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/tailwindcss": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.12.tgz", @@ -2975,6 +3103,12 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 38b0db8..b87b930 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,8 +11,13 @@ }, "dependencies": { "@tailwindcss/vite": "^4.1.12", + "clsx": "^2.1.1", + "framer-motion": "^12.23.12", + "lucide-react": "^0.541.0", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-router-dom": "^7.8.1", + "tailwind-merge": "^3.3.1", "tailwindcss": "^4.1.12" }, "devDependencies": { diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml new file mode 100644 index 0000000..4d1dc5a --- /dev/null +++ b/frontend/pnpm-lock.yaml @@ -0,0 +1,2265 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@tailwindcss/vite': + specifier: ^4.1.12 + version: 4.3.0(vite@7.3.3(jiti@2.7.0)(lightningcss@1.32.0)) + clsx: + specifier: ^2.1.1 + version: 2.1.1 + framer-motion: + specifier: ^12.23.12 + version: 12.40.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + lucide-react: + specifier: ^0.541.0 + version: 0.541.0(react@19.2.6) + react: + specifier: ^19.1.1 + version: 19.2.6 + react-dom: + specifier: ^19.1.1 + version: 19.2.6(react@19.2.6) + react-router-dom: + specifier: ^7.8.1 + version: 7.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + tailwind-merge: + specifier: ^3.3.1 + version: 3.6.0 + tailwindcss: + specifier: ^4.1.12 + version: 4.3.0 + devDependencies: + '@eslint/js': + specifier: ^9.33.0 + version: 9.39.4 + '@types/react': + specifier: ^19.1.10 + version: 19.2.15 + '@types/react-dom': + specifier: ^19.1.7 + version: 19.2.3(@types/react@19.2.15) + '@vitejs/plugin-react': + specifier: ^5.0.0 + version: 5.2.0(vite@7.3.3(jiti@2.7.0)(lightningcss@1.32.0)) + eslint: + specifier: ^9.33.0 + version: 9.39.4(jiti@2.7.0) + eslint-plugin-react-hooks: + specifier: ^5.2.0 + version: 5.2.0(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-react-refresh: + specifier: ^0.4.20 + version: 0.4.26(eslint@9.39.4(jiti@2.7.0)) + globals: + specifier: ^16.3.0 + version: 16.5.0 + vite: + specifier: ^7.1.2 + version: 7.3.3(jiti@2.7.0)(lightningcss@1.32.0) + +packages: + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.29.7': + resolution: {integrity: sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.29.7': + resolution: {integrity: sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.4': + resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@rolldown/pluginutils@1.0.0-rc.3': + resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} + + '@rollup/rollup-android-arm-eabi@4.60.4': + resolution: {integrity: sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.60.4': + resolution: {integrity: sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.60.4': + resolution: {integrity: sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.60.4': + resolution: {integrity: sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.60.4': + resolution: {integrity: sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.60.4': + resolution: {integrity: sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.60.4': + resolution: {integrity: sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.60.4': + resolution: {integrity: sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.60.4': + resolution: {integrity: sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.60.4': + resolution: {integrity: sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.60.4': + resolution: {integrity: sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.60.4': + resolution: {integrity: sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.60.4': + resolution: {integrity: sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.60.4': + resolution: {integrity: sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.60.4': + resolution: {integrity: sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.60.4': + resolution: {integrity: sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.60.4': + resolution: {integrity: sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.60.4': + resolution: {integrity: sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.60.4': + resolution: {integrity: sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.60.4': + resolution: {integrity: sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.60.4': + resolution: {integrity: sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.60.4': + resolution: {integrity: sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.60.4': + resolution: {integrity: sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.60.4': + resolution: {integrity: sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.60.4': + resolution: {integrity: sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==} + cpu: [x64] + os: [win32] + + '@tailwindcss/node@4.3.0': + resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} + + '@tailwindcss/oxide-android-arm64@4.3.0': + resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.0': + resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.0': + resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.0': + resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.0': + resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==} + engines: {node: '>= 20'} + + '@tailwindcss/vite@4.3.0': + resolution: {integrity: sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 || ^8 + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.15': + resolution: {integrity: sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==} + + '@vitejs/plugin-react@5.2.0': + resolution: {integrity: sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + baseline-browser-mapping@2.10.32: + resolution: {integrity: sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==} + engines: {node: '>=6.0.0'} + hasBin: true + + brace-expansion@1.1.15: + resolution: {integrity: sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==} + + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001793: + resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + electron-to-chromium@1.5.363: + resolution: {integrity: sha512-VjUKPyWzGnT1fujlkEGC/BvN70Hh70KXtAqcmniXviYlJC/ivcT+BWGPyxWVbJZLfvtKR6dqg1L7T7pgAMBtWA==} + + enhanced-resolve@5.22.1: + resolution: {integrity: sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==} + engines: {node: '>=10.13.0'} + + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-plugin-react-hooks@5.2.0: + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react-refresh@0.4.26: + resolution: {integrity: sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==} + peerDependencies: + eslint: '>=8.40' + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.39.4: + resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + + framer-motion@12.40.0: + resolution: {integrity: sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@16.5.0: + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} + engines: {node: '>=18'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@0.541.0: + resolution: {integrity: sha512-s0Vircsu5WaGv2KoJZ5+SoxiAJ3UXV5KqEM3eIFDHaHkcLIFdIWgXtZ412+Gh02UsdS7Was+jvEpBvPCWQISlg==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + motion-dom@12.40.0: + resolution: {integrity: sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg==} + + motion-utils@12.39.0: + resolution: {integrity: sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-releases@2.0.46: + resolution: {integrity: sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==} + engines: {node: '>=18'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + react-dom@19.2.6: + resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} + peerDependencies: + react: ^19.2.6 + + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} + engines: {node: '>=0.10.0'} + + react-router-dom@7.16.0: + resolution: {integrity: sha512-kMUAbimWB5FVbF4Bce4bJsiKJWLIUHq/mEG8+CFDnCSgltptBiG5nguducmsJeGKytlCvQud9Qhzpn49iduTlA==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.16.0: + resolution: {integrity: sha512-wArC8lVyJb3+jM9OpDyW6hLCizACWkvQR/sSGqSs+o5uEXEtGlqdZ4v8hENR3Jad6i+LRkK93q/+bQAcvl6V1A==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + + react@19.2.6: + resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + rollup@4.60.4: + resolution: {integrity: sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + tailwind-merge@3.6.0: + resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} + + tailwindcss@4.3.0: + resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + vite@7.3.3: + resolution: {integrity: sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.7': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.29.7': {} + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/plugin-transform-react-jsx-self@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-react-jsx-source@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/traverse@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': + dependencies: + eslint: 9.39.4(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.2': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.5': + dependencies: + ajv: 6.15.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.4': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@rolldown/pluginutils@1.0.0-rc.3': {} + + '@rollup/rollup-android-arm-eabi@4.60.4': + optional: true + + '@rollup/rollup-android-arm64@4.60.4': + optional: true + + '@rollup/rollup-darwin-arm64@4.60.4': + optional: true + + '@rollup/rollup-darwin-x64@4.60.4': + optional: true + + '@rollup/rollup-freebsd-arm64@4.60.4': + optional: true + + '@rollup/rollup-freebsd-x64@4.60.4': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.60.4': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.60.4': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-x64-musl@4.60.4': + optional: true + + '@rollup/rollup-openbsd-x64@4.60.4': + optional: true + + '@rollup/rollup-openharmony-arm64@4.60.4': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.60.4': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.60.4': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.60.4': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.60.4': + optional: true + + '@tailwindcss/node@4.3.0': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.22.1 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.0 + + '@tailwindcss/oxide-android-arm64@4.3.0': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.0': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.0': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + optional: true + + '@tailwindcss/oxide@4.3.0': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-x64': 4.3.0 + '@tailwindcss/oxide-freebsd-x64': 4.3.0 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.0 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.0 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-x64-musl': 4.3.0 + '@tailwindcss/oxide-wasm32-wasi': 4.3.0 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 + + '@tailwindcss/vite@4.3.0(vite@7.3.3(jiti@2.7.0)(lightningcss@1.32.0))': + dependencies: + '@tailwindcss/node': 4.3.0 + '@tailwindcss/oxide': 4.3.0 + tailwindcss: 4.3.0 + vite: 7.3.3(jiti@2.7.0)(lightningcss@1.32.0) + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.29.7 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.29.7 + + '@types/estree@1.0.8': {} + + '@types/estree@1.0.9': {} + + '@types/json-schema@7.0.15': {} + + '@types/react-dom@19.2.3(@types/react@19.2.15)': + dependencies: + '@types/react': 19.2.15 + + '@types/react@19.2.15': + dependencies: + csstype: 3.2.3 + + '@vitejs/plugin-react@5.2.0(vite@7.3.3(jiti@2.7.0)(lightningcss@1.32.0))': + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.7) + '@rolldown/pluginutils': 1.0.0-rc.3 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: 7.3.3(jiti@2.7.0)(lightningcss@1.32.0) + transitivePeerDependencies: + - supports-color + + acorn-jsx@5.3.2(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + + acorn@8.16.0: {} + + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + balanced-match@1.0.2: {} + + baseline-browser-mapping@2.10.32: {} + + brace-expansion@1.1.15: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.32 + caniuse-lite: 1.0.30001793 + electron-to-chromium: 1.5.363 + node-releases: 2.0.46 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001793: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + cookie@1.1.1: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.3: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + detect-libc@2.1.2: {} + + electron-to-chromium@1.5.363: {} + + enhanced-resolve@5.22.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-plugin-react-hooks@5.2.0(eslint@9.39.4(jiti@2.7.0)): + dependencies: + eslint: 9.39.4(jiti@2.7.0) + + eslint-plugin-react-refresh@0.4.26(eslint@9.39.4(jiti@2.7.0)): + dependencies: + eslint: 9.39.4(jiti@2.7.0) + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.39.4(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.2 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.5 + '@eslint/js': 9.39.4 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 + ajv: 6.15.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + fast-deep-equal@3.1.3: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.4.2 + keyv: 4.5.4 + + flatted@3.4.2: {} + + framer-motion@12.40.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + dependencies: + motion-dom: 12.40.0 + motion-utils: 12.39.0 + tslib: 2.8.1 + optionalDependencies: + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + + fsevents@2.3.3: + optional: true + + gensync@1.0.0-beta.2: {} + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globals@16.5.0: {} + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + ignore@5.3.2: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + isexe@2.0.0: {} + + jiti@2.7.0: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@0.541.0(react@19.2.6): + dependencies: + react: 19.2.6 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.15 + + motion-dom@12.40.0: + dependencies: + motion-utils: 12.39.0 + + motion-utils@12.39.0: {} + + ms@2.1.3: {} + + nanoid@3.3.12: {} + + natural-compare@1.4.0: {} + + node-releases@2.0.46: {} + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + picocolors@1.1.1: {} + + picomatch@4.0.4: {} + + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + punycode@2.3.1: {} + + react-dom@19.2.6(react@19.2.6): + dependencies: + react: 19.2.6 + scheduler: 0.27.0 + + react-refresh@0.18.0: {} + + react-router-dom@7.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + dependencies: + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react-router: 7.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + + react-router@7.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + dependencies: + cookie: 1.1.1 + react: 19.2.6 + set-cookie-parser: 2.7.2 + optionalDependencies: + react-dom: 19.2.6(react@19.2.6) + + react@19.2.6: {} + + resolve-from@4.0.0: {} + + rollup@4.60.4: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.60.4 + '@rollup/rollup-android-arm64': 4.60.4 + '@rollup/rollup-darwin-arm64': 4.60.4 + '@rollup/rollup-darwin-x64': 4.60.4 + '@rollup/rollup-freebsd-arm64': 4.60.4 + '@rollup/rollup-freebsd-x64': 4.60.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.4 + '@rollup/rollup-linux-arm-musleabihf': 4.60.4 + '@rollup/rollup-linux-arm64-gnu': 4.60.4 + '@rollup/rollup-linux-arm64-musl': 4.60.4 + '@rollup/rollup-linux-loong64-gnu': 4.60.4 + '@rollup/rollup-linux-loong64-musl': 4.60.4 + '@rollup/rollup-linux-ppc64-gnu': 4.60.4 + '@rollup/rollup-linux-ppc64-musl': 4.60.4 + '@rollup/rollup-linux-riscv64-gnu': 4.60.4 + '@rollup/rollup-linux-riscv64-musl': 4.60.4 + '@rollup/rollup-linux-s390x-gnu': 4.60.4 + '@rollup/rollup-linux-x64-gnu': 4.60.4 + '@rollup/rollup-linux-x64-musl': 4.60.4 + '@rollup/rollup-openbsd-x64': 4.60.4 + '@rollup/rollup-openharmony-arm64': 4.60.4 + '@rollup/rollup-win32-arm64-msvc': 4.60.4 + '@rollup/rollup-win32-ia32-msvc': 4.60.4 + '@rollup/rollup-win32-x64-gnu': 4.60.4 + '@rollup/rollup-win32-x64-msvc': 4.60.4 + fsevents: 2.3.3 + + scheduler@0.27.0: {} + + semver@6.3.1: {} + + set-cookie-parser@2.7.2: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + source-map-js@1.2.1: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + tailwind-merge@3.6.0: {} + + tailwindcss@4.3.0: {} + + tapable@2.3.3: {} + + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + vite@7.3.3(jiti@2.7.0)(lightningcss@1.32.0): + dependencies: + esbuild: 0.27.7 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + postcss: 8.5.15 + rollup: 4.60.4 + tinyglobby: 0.2.16 + optionalDependencies: + fsevents: 2.3.3 + jiti: 2.7.0 + lightningcss: 1.32.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + yallist@3.1.1: {} + + yocto-queue@0.1.0: {} diff --git a/frontend/portfolio.json b/frontend/portfolio.json new file mode 100644 index 0000000..39497b4 --- /dev/null +++ b/frontend/portfolio.json @@ -0,0 +1,323 @@ +{ + "personalInfo": { + "name": "Dev Bachani", + "role": "Full Stack Engineer", + "location": "Ahmedabad, Gujarat, India", + "bio": "A computer science graduate with a background in building production applications, leveraging my skills to architect and develop backend solutions at scale in the field of agentic AI.", + "profileImage": "/headshot.jpg", + "email": "devbachani08@gmail.com", + "socialLinks": { + "twitter": "https://twitter.com/dev_by_dev_", + "github": "https://github.com/dev22603", + "linkedin": "https://linkedin.com/in/devbachani", + "blog": "#blogs", + "calendar": "https://calendly.com/devbachani08" + } + }, + "experience": [ + { + "id": "hyperlab", + "company": "Hyperlab Sportech Pvt Ltd", + "role": "Software Engineer", + "startDate": "September 2025", + "endDate": "Present", + "status": "Current", + "location": "Remote", + "shortDescription": "Developing detection algorithms and UI flows for exercise tracking system.", + "icon": "HL", + "logo": "/hyperlab_logo.svg", + "techStack": ["Lua", "Algorithm Design", "State Machines", "Peak Detection"], + "keyAchievements": [ + "Developed detection algorithms for 35+ exercises using state machines, peak detection and movement thresholds", + "Built complete UI flows and integrated all exercises into a unified Lua system", + "Led most of the development, creating new exercises and improving existing ones for accuracy and consistency" + ] + }, + { + "id": "zymr", + "company": "Zymr, Inc.", + "role": "Software Engineer", + "startDate": "July 2025", + "endDate": "September 2025", + "status": "Completed", + "location": "Remote", + "shortDescription": "Building Agentic AI systems and contributing to cutting-edge AI development projects.", + "icon": "ZM", + "logo": "/zymr_logo.jpeg", + "techStack": ["Python", "FastAPI", "LangChain", "React", "TypeScript", "Docker"], + "keyAchievements": [ + "Contributor to a project focused on developing Agentic AI systems", + "Working on scalable backend solutions for AI-powered applications", + "Implementing advanced AI workflows and integrations" + ] + }, + { + "id": "medkart", + "company": "Medkart Pharmacy Pvt Ltd", + "role": "Flutter Developer Intern", + "startDate": "January 2025", + "endDate": "June 2025", + "status": "Completed", + "location": "Ahmedabad, India", + "shortDescription": "Revamped core app features and improved user engagement for 50,000+ users.", + "icon": "MK", + "logo": "/medkart_logo.jpeg", + "techStack": ["Flutter", "Dart", "Firebase", "REST APIs"], + "keyAchievements": [ + "Revamped 9 core app screens in 12 weeks, increasing engagement rates for 50,000+ users", + "Improved product discovery and boosted conversion rates via comprehensive sorting/filtering system", + "Reduced customer support response time by 30% by developing Contact Us module with form validation", + "Decreased bounce rates by 28% with responsive loading skeletons on 12+ pages", + "Achieved 75% workflow efficiency improvement by collapsing a 4-step task to 1 tap using Flutter intents" + ] + } + ], + "projects": { + "personal": [ + { + "id": "mathex", + "name": "Mathex-Editor", + "description": "A React component library for building math equation editors with automatic keyboard routing to focused input fields. Features 13 function categories including Trig, Calculus, Statistics, Probability, and Geometry with subscript/superscript mode. Packaged as a tree-shakeable npm library with full TypeScript support.", + "status": "Completed", + "techStack": ["React", "TypeScript", "MathQuill", "KaTeX", "Vite"], + "links": { + "github": "https://github.com/Dev22603/MathEx", + "live": null, + "npm": "https://www.npmjs.com/package/mathex-editor", + "kaggle": null + } + }, + { + "id": "dsa-tracker", + "name": "DSA Progress Tracker", + "description": "A progress tracking tool for the A2Z DSA sheet, allowing users to mark question status, add notes, and access multiple reference links including LeetCode, GeeksforGeeks, Code360, and Hackerrank for comprehensive practice and study.", + "status": "Paused", + "techStack": ["React", "Node.js", "MongoDB", "Express.js"], + "links": { + "github": "https://github.com/Dev22603/DSA-Progress-Tracker", + "live": null, + "npm": null, + "kaggle": null + } + }, + { + "id": "audio-classification", + "name": "Audio Language Classification using Deep Learning", + "description": "Built a BiLSTM model in TensorFlow for spoken language classification, achieving 75.46% test accuracy, with MFCC feature extraction from 40,000+ audio samples.", + "status": "Completed", + "techStack": ["Python", "TensorFlow", "Keras", "NumPy"], + "links": { + "github": null, + "live": null, + "npm": null, + "kaggle": "https://www.kaggle.com/code/devbachani/audio-language-classification-using-blstms" + } + }, + { + "id": "ecommerce-personal", + "name": "E-Commerce Platform", + "description": "Designed and built a role-based e-commerce platform (Admin, Customer) using Node.js, Express.js, React.js, Tailwind CSS, PostgreSQL. Secured with JWT, RBAC; developed REST APIs.", + "status": "Completed", + "techStack": ["Node.js", "Express.js", "React", "Tailwind CSS", "PostgreSQL"], + "links": { + "github": "https://github.com/Dev22603/ecommerce", + "live": null, + "npm": null, + "kaggle": null + } + }, + { + "id": "crisplogs-py", + "name": "crisplogs (Python)", + "description": "A PyPI package that replaces Python's verbose logging setup with a single setup_logging() call. Features ANSI-colored output per log level, 4 box styles (default, short-fixed, short-dynamic, long-boxed), structured extras rendered as inline/json/pretty, dual console+file logging with automatic ANSI stripping, named loggers with inherited config, and a configurable LogFormatter for custom handlers. Zero runtime dependencies, supports Python 3.8–3.13.", + "status": "Completed", + "techStack": ["Python", "PyPI"], + "links": { + "github": "https://github.com/dev22603/crisplogs", + "live": null, + "npm": null, + "pypi": "https://pypi.org/project/crisplogs/", + "kaggle": null + } + }, + { + "id": "crisplogs-js", + "name": "crisplogs (Node.js)", + "description": "An npm package that brings Python-style structured logging to Node.js backends with a single setupLogging() call. Features ANSI-colored output per log level, 4 box styles (default, short-fixed, short-dynamic, long-boxed), structured extras rendered as inline/json/pretty, async file logging via WriteStream with automatic ANSI stripping, named loggers, pluggable custom handlers, and full TypeScript types. Zero runtime dependencies, ships ESM + CJS builds.", + "status": "Completed", + "techStack": ["TypeScript", "Node.js", "npm"], + "links": { + "github": "https://github.com/dev22603/crisplogs-js", + "live": null, + "npm": "https://www.npmjs.com/package/crisplogs", + "kaggle": null + } + }, + { + "id": "eduscraper", + "name": "EduScraper", + "description": "Used Beautiful Soup to extract Aptitude MCQs from IndiaBix and stored them in a JSON file. Built a React app to display/download MCQ PDFs.", + "status": "Completed", + "techStack": ["Python", "Beautiful Soup", "React", "JavaScript"], + "links": { + "github": "https://github.com/Dev22603/EduScraper", + "live": null, + "npm": null, + "kaggle": null + } + }, + { + "id": "dex-fastapi-personal", + "name": "Decentralized Exchange", + "description": "Full-stack decentralized exchange project with FastAPI backend and React frontend. Key features include order management, trade execution, modern UI, and SuperTokens authentication.", + "status": "Completed", + "techStack": ["FastAPI", "React", "Python", "SuperTokens", "TypeScript"], + "links": { + "github": "https://github.com/Dev22603/Decentralized-Exchange-FastAPI", + "live": null, + "npm": null, + "kaggle": null + } + } + ], + "client": [ + { + "id": "ecommerce", + "name": "E-Commerce Platform", + "description": "Designed and built a role-based e-commerce platform (Admin, Customer) using Node.js, Express.js, React.js, Tailwind CSS, PostgreSQL. Secured with JWT, RBAC; developed REST APIs.", + "status": "Completed", + "techStack": ["Node.js", "Express.js", "React", "Tailwind CSS", "PostgreSQL"], + "links": { + "github": "https://github.com/Dev22603/ecommerce", + "live": null, + "npm": null, + "kaggle": null + } + }, + { + "id": "dex-fastapi", + "name": "Decentralized Exchange", + "description": "Full-stack decentralized exchange project with FastAPI backend and React frontend. Key features include order management, trade execution, modern UI, and SuperTokens authentication.", + "status": "Completed", + "techStack": ["FastAPI", "React", "Python", "SuperTokens", "TypeScript"], + "links": { + "github": "https://github.com/Dev22603/Decentralized-Exchange-FastAPI", + "live": null, + "npm": null, + "kaggle": null + } + } + ] + }, + "blogs": [ + { + "id": "python-logging", + "title": "Python Logging: Colored and Boxed Loggers for Readable Outputs", + "excerpt": "A comprehensive guide to creating visually appealing and readable Python loggers with colored and boxed formatting for better debugging and monitoring.", + "date": "2025-09-23", + "slug": "https://medium.com/@devcodes2206/python-logging-colored-and-boxed-loggers-for-readable-outputs-4e57102a3ec5", + "tags": ["Python", "Logging", "Development"] + }, + { + "id": "nodejs-backend", + "title": "Modern Node.js Backend: Build It Like a Pro", + "excerpt": "Build a professional-grade REST API with Node.js, Express, and MongoDB using clean architecture patterns. From JWT authentication to Zod validation, learn the exact structure and conventions that make backends maintainable, secure, and production-ready.", + "date": "2025-12-09", + "slug": "https://medium.com/@devcodes2206/modern-node-js-backend-build-it-like-a-pro-6c5cdcab918f", + "tags": ["NodeJS", "Backend", "Good Coding Practices"] + } + ], + "skills": { + "backend": [ + "Node.js", + "Express.js", + "FastAPI", + "MongoDB", + "PostgreSQL", + "SuperTokens", + "Keycloak IAM", + "REST APIs" + ], + "frontend": [ + "React", + "Flutter", + "Tailwind CSS", + "HTML", + "CSS" + ], + "languages": [ + "C", + "C++", + "Python", + "JavaScript", + "TypeScript", + "Java", + "Dart", + "Lua" + ], + "mlDl": [ + "TensorFlow", + "PyTorch", + "NumPy", + "Pandas", + "Scikit-learn" + ], + "tools": [ + "Git", + "GitHub", + "Docker", + "Postman", + "VSCode", + "Cursor", + "Windsurf", + "LangFlow", + "Flowise" + ] + }, + "education": [ + { + "institution": "Institute of Technology, Nirma University, Ahmedabad", + "degree": "B.Tech in Computer Science and Engineering", + "startYear": 2021, + "endYear": 2025 + } + ], + "programmingProfiles": { + "codeforces": { + "handle": "Dev_Bachani", + "link": "https://codeforces.com/profile/Dev_Bachani", + "maxRating": 1018, + "problemsSolved": 500 + }, + "leetcode": { + "handle": "Dev22603", + "link": "https://leetcode.com/Dev22603/", + "maxRating": 1538, + "problemsSolved": 300 + }, + "hackerrank": { + "handle": "Dev22603", + "link": "https://www.hackerrank.com/profile/Dev22603", + "stars": { + "problemSolving": 5, + "python": 5 + } + }, + "codechef": { + "handle": "Dev22603", + "link": "https://www.codechef.com/users/dev22603", + "stars": 2, + "maxRating": 1476 + } + }, + "certificates": [ + { + "title": "JavaScript (Intermediate) Certificate", + "link": "https://www.hackerrank.com/certificates/692ea16532b2" + }, + { + "title": "Python Language Course", + "link": "https://olympus1.mygreatlearning.com/course_certificate/BCEFFFJL" + } + ] +} diff --git a/frontend/public/banner.jpg b/frontend/public/banner.jpg new file mode 100644 index 0000000..15c3c41 Binary files /dev/null and b/frontend/public/banner.jpg differ diff --git a/frontend/public/favicon.png b/frontend/public/favicon.png new file mode 100644 index 0000000..7d5cd1e Binary files /dev/null and b/frontend/public/favicon.png differ diff --git a/frontend/public/headshot.jpg b/frontend/public/headshot.jpg new file mode 100644 index 0000000..f186b20 Binary files /dev/null and b/frontend/public/headshot.jpg differ diff --git a/frontend/public/hyperlab_logo.svg b/frontend/public/hyperlab_logo.svg new file mode 100644 index 0000000..5249335 --- /dev/null +++ b/frontend/public/hyperlab_logo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/public/medkart_logo.jpeg b/frontend/public/medkart_logo.jpeg new file mode 100644 index 0000000..ecd6235 Binary files /dev/null and b/frontend/public/medkart_logo.jpeg differ diff --git a/frontend/public/preview.png b/frontend/public/preview.png new file mode 100644 index 0000000..4adaf9d Binary files /dev/null and b/frontend/public/preview.png differ diff --git a/frontend/public/vite.svg b/frontend/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/frontend/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/public/zymr_logo.jpeg b/frontend/public/zymr_logo.jpeg new file mode 100644 index 0000000..17d7833 Binary files /dev/null and b/frontend/public/zymr_logo.jpeg differ diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 616911f..19887a6 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,9 +1,27 @@ -function App() { +import React from "react"; +import { Routes, Route, Navigate, BrowserRouter } from "react-router-dom"; +import Home from "@/pages/Home"; +import { Layout } from "@/components/Layout"; +import Header from "@/components/Header"; +import Footer from "@/components/Footer"; +import ScrollToTop from "@/components/ScrollToTop"; + +export default function App() { return ( - <> -

Dev

- + +
+
+
+ + + } /> + } /> + + +
+
+
); } - -export default App; diff --git a/frontend/src/assets/react.svg b/frontend/src/assets/react.svg deleted file mode 100644 index 6c87de9..0000000 --- a/frontend/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/components/BlogCard.jsx b/frontend/src/components/BlogCard.jsx new file mode 100644 index 0000000..4480443 --- /dev/null +++ b/frontend/src/components/BlogCard.jsx @@ -0,0 +1,81 @@ +import React from "react"; +import { motion } from "framer-motion"; +import { ArrowUpRight, Calendar } from "lucide-react"; +import TechTag from "./TechTag"; +import { cn } from "@/lib/utils"; + +export default function BlogCard({ blog, index }) { + const formattedDate = new Date(blog.date).toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }); + + return ( + + {/* Hover gradient overlay */} +
+
+
+ + {/* Article number */} +
+ {String(index + 1).padStart(2, '0')} +
+ +
+ {/* Date */} +
+ + +
+ + {/* Title */} +
+

+ {blog.title} +

+
+ + {/* Excerpt */} +

+ {blog.excerpt} +

+ + {/* Tags */} + {blog.tags && blog.tags.length > 0 && ( +
+ {blog.tags.map((tag, idx) => ( + + ))} +
+ )} + + {/* Read more link */} +
+ Read article + +
+
+ + ); +} diff --git a/frontend/src/components/BlogsSection.jsx b/frontend/src/components/BlogsSection.jsx new file mode 100644 index 0000000..eedad74 --- /dev/null +++ b/frontend/src/components/BlogsSection.jsx @@ -0,0 +1,48 @@ +import React from "react"; +import { motion } from "framer-motion"; +import BlogCard from "./BlogCard"; +import portfolioData from "../../portfolio.json"; + +export default function BlogsSection() { + const blogs = portfolioData.blogs; + + return ( +
+ {/* Section Header */} +
+ + Blogs + +
+ + {/* Blogs Grid */} + {blogs && blogs.length > 0 ? ( +
+ {blogs.map((blog, index) => ( + + + + ))} +
+ ) : ( +
+

+ No blog posts yet. Check back soon! +

+
+ )} +
+ ); +} diff --git a/frontend/src/components/ExperienceCard.jsx b/frontend/src/components/ExperienceCard.jsx new file mode 100644 index 0000000..709ecb3 --- /dev/null +++ b/frontend/src/components/ExperienceCard.jsx @@ -0,0 +1,119 @@ +import React from "react"; +import { motion } from "framer-motion"; +import { MapPin, ChevronRight } from "lucide-react"; +import TechTag from "./TechTag"; +import { cn } from "@/lib/utils"; + +export default function ExperienceCard({ experience, onClick }) { + const handleKeyDown = (e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + onClick?.(); + } + }; + + return ( + + {/* Current status indicator bar */} + {experience.status === "Current" && ( +
+ )} + +
+
+ {/* Logo/Icon */} +
+ {experience.logo ? ( + {`${experience.company} + ) : ( + + {experience.icon} + + )} +
+ + {/* Content */} +
+ {/* Header row */} +
+
+

+ {experience.role} +

+

+ {experience.company} +

+
+ + {/* Status badge */} + {experience.status === "Current" && ( + + Current + + )} +
+ + {/* Meta info */} +
+ + {experience.startDate} - {experience.endDate} + + + + {experience.location} + +
+ + {/* Description */} +

+ {experience.shortDescription} +

+ + {/* Tech stack preview */} +
+ {experience.techStack.slice(0, 4).map((tech, index) => ( + + ))} + {experience.techStack.length > 4 && ( + + +{experience.techStack.length - 4} + + )} +
+
+ + {/* Arrow indicator */} + +
+
+ + ); +} diff --git a/frontend/src/components/ExperienceModal.jsx b/frontend/src/components/ExperienceModal.jsx new file mode 100644 index 0000000..214c857 --- /dev/null +++ b/frontend/src/components/ExperienceModal.jsx @@ -0,0 +1,163 @@ +import React, { useEffect } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { X, MapPin, Calendar, CheckCircle2 } from "lucide-react"; +import TechTag from "./TechTag"; + +export default function ExperienceModal({ experience, isOpen, onClose }) { + // Handle ESC key + useEffect(() => { + const handleEsc = (e) => { + if (e.key === "Escape") onClose(); + }; + + if (isOpen) { + document.addEventListener("keydown", handleEsc); + document.body.style.overflow = "hidden"; + } + + return () => { + document.removeEventListener("keydown", handleEsc); + document.body.style.overflow = "unset"; + }; + }, [isOpen, onClose]); + + if (!experience) return null; + + return ( + + {isOpen && ( +
+ {/* Backdrop */} + + + {/* Modal */} + + {/* Header accent */} +
+ + {/* Close button */} + + + {/* Content */} +
+ {/* Header */} +
+ {/* Logo/Icon */} +
+ {experience.logo ? ( + {`${experience.company} + ) : ( + + {experience.icon} + + )} +
+ +
+
+
+

+ {experience.role} +

+

+ {experience.company} +

+
+ + {experience.status === "Current" && ( + + Current + + )} +
+
+
+ + {/* Meta info */} +
+ + + {experience.startDate} - {experience.endDate} + + + + {experience.location} + +
+ + {/* Description */} +
+

+ Overview +

+

+ {experience.shortDescription} +

+
+ + {/* Key Achievements */} + {experience.keyAchievements && experience.keyAchievements.length > 0 && ( +
+

+ Key Achievements +

+
    + {experience.keyAchievements.map((achievement, index) => ( + + + + {achievement} + + + ))} +
+
+ )} + + {/* Tech Stack */} +
+

+ Technologies Used +

+
+ {experience.techStack.map((tech, index) => ( + + ))} +
+
+
+ +
+ )} + + ); +} diff --git a/frontend/src/components/ExperienceSection.jsx b/frontend/src/components/ExperienceSection.jsx new file mode 100644 index 0000000..1645474 --- /dev/null +++ b/frontend/src/components/ExperienceSection.jsx @@ -0,0 +1,87 @@ +import React, { useState } from "react"; +import { motion } from "framer-motion"; +import ExperienceCard from "./ExperienceCard"; +import ExperienceModal from "./ExperienceModal"; +import portfolioData from "../../portfolio.json"; + +export default function ExperienceSection() { + const [selectedExperience, setSelectedExperience] = useState(null); + const [isModalOpen, setIsModalOpen] = useState(false); + + const experiences = portfolioData.experience; + + const handleCardClick = (experience) => { + setSelectedExperience(experience); + setIsModalOpen(true); + }; + + const handleCloseModal = () => { + setIsModalOpen(false); + setTimeout(() => setSelectedExperience(null), 200); + }; + + return ( +
+ {/* Section Header */} +
+ + Experience + +
+ + {/* Experience Timeline */} +
+ {/* Vertical timeline line */} +
+ + {/* Experience Cards */} +
+ {experiences.map((experience, index) => ( + + {/* Timeline dot */} +
+
+
+ + {/* Date label - Desktop */} +
+ + {experience.startDate.split(' ')[0].slice(0, 3)} '{experience.startDate.split(' ')[1]?.slice(2) || ''} + +
+ + handleCardClick(experience)} + /> + + ))} +
+
+ + {/* Experience Modal */} + +
+ ); +} diff --git a/frontend/src/components/Footer.jsx b/frontend/src/components/Footer.jsx new file mode 100644 index 0000000..110c6af --- /dev/null +++ b/frontend/src/components/Footer.jsx @@ -0,0 +1,104 @@ +import React from "react"; +import { motion } from "framer-motion"; +import { Twitter, Github, Mail, Linkedin, ArrowUp } from "lucide-react"; +import portfolioData from "../../portfolio.json"; + +export default function Footer() { + const { name, email, socialLinks } = portfolioData.personalInfo; + const currentYear = new Date().getFullYear(); + + const socialIcons = [ + { name: "GitHub", icon: Github, href: socialLinks.github }, + { name: "LinkedIn", icon: Linkedin, href: socialLinks.linkedin }, + { name: "Twitter", icon: Twitter, href: socialLinks.twitter }, + { name: "Email", icon: Mail, href: `mailto:${email}` }, + ]; + + const scrollToTop = () => { + window.scrollTo({ top: 0, behavior: "smooth" }); + }; + + return ( +
+ {/* Top accent line */} +
+ +
+
+ {/* Brand Column */} +
+
+ [ + + {name.split(' ')[0]} + . + + ] +
+

+ Full Stack Engineer building production-grade applications + with a focus on backend architecture and AI systems. +

+
+ + {/* Quick Links */} +
+

+ Quick Links +

+ +
+ + {/* Connect */} +
+

+ Connect +

+
+ {socialIcons.map((social) => { + const Icon = social.icon; + return ( + + + + ); + })} +
+
+
+ + {/* Bottom bar */} +
+

+ © {currentYear} {name}. Crafted with precision. +

+ + +
+
+
+ ); +} diff --git a/frontend/src/components/Header.jsx b/frontend/src/components/Header.jsx new file mode 100644 index 0000000..4966724 --- /dev/null +++ b/frontend/src/components/Header.jsx @@ -0,0 +1,122 @@ +import { useEffect, useState } from "react"; +import { Menu, X } from "lucide-react"; +import { cn } from "@/lib/utils"; +import portfolioData from "../../portfolio.json"; + +export default function Header({ className }) { + const { name } = portfolioData.personalInfo; + const [mobileMenuOpen, setMobileMenuOpen] = useState(false); + + const navLinks = [ + { name: "Experience", shortcut: "e", sectionId: "experience" }, + { name: "Projects", shortcut: "p", sectionId: "projects" }, + { name: "Blogs", shortcut: "b", sectionId: "blogs" }, + ]; + + const scrollToSection = (sectionId) => { + const section = document.getElementById(sectionId); + if (section) { + section.scrollIntoView({ behavior: "smooth", block: "start" }); + } + setMobileMenuOpen(false); + }; + + // Keyboard shortcuts + useEffect(() => { + const handleKeyDown = (e) => { + // Don't trigger if user is typing in an input + if (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA") return; + + const link = navLinks.find((l) => l.shortcut === e.key.toLowerCase()); + if (link) { + e.preventDefault(); + scrollToSection(link.sectionId); + } + }; + + document.addEventListener("keydown", handleKeyDown); + return () => document.removeEventListener("keydown", handleKeyDown); + }, []); + + return ( +
+ {/* Accent line at top */} +
+ +
+ {/* Name/Logo with decorative brackets */} +
+ [ + + {name.split(' ')[0]} + . + + ] +
+ + {/* Center Navigation - hidden on mobile */} + + + {/* Mobile menu button */} + + + {/* Empty div for flex spacing - hidden on mobile */} +
+
+ + {/* Mobile Navigation Menu */} + {mobileMenuOpen && ( +
+ +
+ )} +
+ ); +} diff --git a/frontend/src/components/Hero.jsx b/frontend/src/components/Hero.jsx new file mode 100644 index 0000000..f0266db --- /dev/null +++ b/frontend/src/components/Hero.jsx @@ -0,0 +1,175 @@ +import React from "react"; +import { motion } from "framer-motion"; +import { Twitter, Github, Mail, Linkedin, FileText, MapPin, ArrowRight } from "lucide-react"; +import portfolioData from "../../portfolio.json"; + +export default function Hero() { + const { name, role, location, bio, profileImage, email, socialLinks } = + portfolioData.personalInfo; + + const socialIcons = [ + { name: "GitHub", icon: Github, href: socialLinks.github }, + { name: "LinkedIn", icon: Linkedin, href: socialLinks.linkedin }, + { name: "Twitter", icon: Twitter, href: socialLinks.twitter }, + { name: "Email", icon: Mail, href: `mailto:${email}` }, + ]; + + return ( +
+
+ {/* Left side - Text content */} +
+ {/* Eyebrow text */} + +
+ + {role} + + + + {/* Name */} + + Hello, I'm + + {name.split(' ')[0]} + + + + + {/* Location */} + + + + {location} + + + + {/* Bio */} + + {bio} + + + {/* CTA Button */} + + {/* Primary CTA */} + + + View Resume + + {/* Shine effect */} + + + + + {/* Social Links */} + + {socialIcons.map((social, index) => { + const Icon = social.icon; + return ( + + + + ); + })} + +
+ + {/* Right side - Profile Image */} +
+ + {/* Decorative frame */} +
+
+ + {/* Image container */} +
+ {`${name} + {/* Overlay gradient */} +
+
+ + {/* Corner accents */} +
+
+
+
+ + {/* Floating status badge */} + + + + Available for work + + + +
+
+
+ ); +} diff --git a/frontend/src/components/Layout.jsx b/frontend/src/components/Layout.jsx new file mode 100644 index 0000000..2885e86 --- /dev/null +++ b/frontend/src/components/Layout.jsx @@ -0,0 +1,58 @@ +import { cn } from "@/lib/utils"; + +export function Layout({ + children, + className, + dotSize = 1, + dotSpacing = 20, +}) { + const backgroundColor = "var(--color-background-primary)"; + const dotColorLight = "var(--color-dot-light)"; + const dotColorDark = "var(--color-dot-dark)"; + + return ( +
+ {/* Fixed dot pattern background */} +
+ {/* Light dot pattern */} +
+ + {/* Dark dot pattern overlay */} +
+ + {/* Gradient fade overlay - creates depth */} +
+
+ + {/* Noise texture overlay */} +
+ + {/* Main content container */} +
+
+ {children} +
+
+
+ ); +} diff --git a/frontend/src/components/ProjectCard.jsx b/frontend/src/components/ProjectCard.jsx new file mode 100644 index 0000000..d70787f --- /dev/null +++ b/frontend/src/components/ProjectCard.jsx @@ -0,0 +1,205 @@ +import React from "react"; +import { motion } from "framer-motion"; +import { ExternalLink, Github, ArrowUpRight } from "lucide-react"; +import TechTag from "./TechTag"; +import { cn } from "@/lib/utils"; + +export default function ProjectCard({ project, useModal = false, onModalClick, featured = false }) { + const hasGithubLink = project.links?.github; + const hasLiveLink = project.links?.live; + const hasNpmLink = project.links?.npm; + const hasKaggleLink = project.links?.kaggle; + const hasPypiLink = project.links?.pypi; + + const handleCardClick = () => { + if (useModal && onModalClick) { + onModalClick(); + } else if (hasGithubLink) { + window.open(project.links.github, "_blank", "noopener,noreferrer"); + } + }; + + const handleKeyDown = (e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + handleCardClick(); + } + }; + + const statusColors = { + Paused: { bg: "bg-yellow-500/10", text: "text-yellow-400", border: "border-yellow-500/30" }, + Completed: { bg: "bg-[var(--color-primary-dim)]", text: "text-[var(--color-primary)]", border: "border-[var(--color-primary)]/30" }, + Active: { bg: "bg-blue-500/10", text: "text-blue-400", border: "border-blue-500/30" }, + }; + + const status = statusColors[project.status] || statusColors.Active; + + return ( + + {/* Hover gradient overlay */} +
+
+
+ + {/* Featured image placeholder for featured card */} + {featured && ( +
+
+
+ 01 +
+ {/* Corner accents */} +
+
+
+ )} + + {/* Content */} +
+ {/* Header */} +
+
+ {/* Status Badge */} + {project.status && ( + + {project.status} + + )} + + {/* Project Name */} +

+ {project.name} +

+
+ + {/* Arrow indicator */} + +
+ + {/* Description */} +

+ {project.description} +

+ + {/* Tech Stack */} +
+ {project.techStack.slice(0, featured ? 6 : 4).map((tech, index) => ( + + ))} + {project.techStack.length > (featured ? 6 : 4) && ( + + +{project.techStack.length - (featured ? 6 : 4)} + + )} +
+ + {/* Links */} + {(hasGithubLink || hasLiveLink || hasNpmLink || hasKaggleLink || hasPypiLink) && ( +
+ {hasGithubLink && ( + e.stopPropagation()} + > + + Source + + )} + {hasNpmLink && ( + e.stopPropagation()} + > + + + + npm + + )} + {hasKaggleLink && ( + e.stopPropagation()} + > + + + + Kaggle + + )} + {hasPypiLink && ( + e.stopPropagation()} + > + + + + + PyPI + + )} + {hasLiveLink && ( + e.stopPropagation()} + > + + Live + + )} +
+ )} +
+ + ); +} diff --git a/frontend/src/components/ProjectModal.jsx b/frontend/src/components/ProjectModal.jsx new file mode 100644 index 0000000..cc53484 --- /dev/null +++ b/frontend/src/components/ProjectModal.jsx @@ -0,0 +1,189 @@ +import React, { useEffect } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { X, ExternalLink, Github } from "lucide-react"; +import TechTag from "./TechTag"; + +export default function ProjectModal({ project, isOpen, onClose }) { + useEffect(() => { + const handleEsc = (e) => { + if (e.key === "Escape") onClose(); + }; + + if (isOpen) { + document.addEventListener("keydown", handleEsc); + document.body.style.overflow = "hidden"; + } + + return () => { + document.removeEventListener("keydown", handleEsc); + document.body.style.overflow = "unset"; + }; + }, [isOpen, onClose]); + + if (!project) return null; + + const hasGithubLink = project.links?.github; + const hasLiveLink = project.links?.live; + const hasNpmLink = project.links?.npm; + const hasKaggleLink = project.links?.kaggle; + const hasPypiLink = project.links?.pypi; + + const statusColors = { + Paused: { bg: "bg-yellow-500/10", text: "text-yellow-400", border: "border-yellow-500/30" }, + Completed: { bg: "bg-[var(--color-primary-dim)]", text: "text-[var(--color-primary)]", border: "border-[var(--color-primary)]/30" }, + Active: { bg: "bg-blue-500/10", text: "text-blue-400", border: "border-blue-500/30" }, + }; + + const status = statusColors[project.status] || statusColors.Active; + + return ( + + {isOpen && ( +
+ {/* Backdrop */} + + + {/* Modal */} + + {/* Header accent */} +
+ + {/* Close button */} + + + {/* Content */} +
+ {/* Header */} +
+ {/* Status Badge */} + {project.status && ( + + {project.status} + + )} + +

+ {project.name} +

+
+ + {/* Description */} +
+

+ About +

+

+ {project.description} +

+
+ + {/* Tech Stack */} +
+

+ Technologies +

+
+ {project.techStack.map((tech, index) => ( + + ))} +
+
+ + {/* Links */} + {(hasGithubLink || hasLiveLink || hasNpmLink || hasKaggleLink || hasPypiLink) && ( +
+

+ Links +

+
+ {hasGithubLink && ( + + + View Source + + )} + {hasNpmLink && ( + + + + + npm Package + + )} + {hasKaggleLink && ( + + + + + View on Kaggle + + )} + {hasPypiLink && ( + + + + + + PyPI Package + + )} + {hasLiveLink && ( + + + Live Demo + + )} +
+
+ )} +
+ +
+ )} + + ); +} diff --git a/frontend/src/components/ProjectsSection.jsx b/frontend/src/components/ProjectsSection.jsx new file mode 100644 index 0000000..77c304a --- /dev/null +++ b/frontend/src/components/ProjectsSection.jsx @@ -0,0 +1,108 @@ +import React, { useState } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import TabNavigation from "./TabNavigation"; +import ProjectCard from "./ProjectCard"; +import ProjectModal from "./ProjectModal"; +import portfolioData from "../../portfolio.json"; + +export default function ProjectsSection() { + const [activeTab, setActiveTab] = useState("personal"); + const [selectedProject, setSelectedProject] = useState(null); + const [isModalOpen, setIsModalOpen] = useState(false); + + const SHOW_CLIENT_WORK_TAB = false; + const USE_MODAL_ON_CLICK = true; + + const tabs = SHOW_CLIENT_WORK_TAB + ? [ + { id: "personal", label: "Personal Projects" }, + { id: "client", label: "Client Work" }, + ] + : [{ id: "personal", label: "Personal Projects" }]; + + const displayedProjects = + activeTab === "personal" + ? portfolioData.projects.personal + : portfolioData.projects.client; + + const handleProjectClick = (project) => { + setSelectedProject(project); + setIsModalOpen(true); + }; + + const handleCloseModal = () => { + setIsModalOpen(false); + setTimeout(() => setSelectedProject(null), 200); + }; + + return ( +
+ {/* Section Header */} +
+ + Projects + +
+ + {/* Tab Navigation */} + {SHOW_CLIENT_WORK_TAB && ( + + )} + + {/* Projects Grid - Masonry-like layout */} + + + {displayedProjects.map((project, index) => ( + + handleProjectClick(project)} + featured={index === 0} + /> + + ))} + + + + {/* Empty State */} + {displayedProjects.length === 0 && ( +
+

+ No projects in this category yet. +

+
+ )} + + {/* Project Modal */} + +
+ ); +} diff --git a/frontend/src/components/ScrollToTop.jsx b/frontend/src/components/ScrollToTop.jsx new file mode 100644 index 0000000..aa33b09 --- /dev/null +++ b/frontend/src/components/ScrollToTop.jsx @@ -0,0 +1,49 @@ +import React, { useState, useEffect } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { ArrowUp } from "lucide-react"; + +export default function ScrollToTop() { + const [isVisible, setIsVisible] = useState(false); + + useEffect(() => { + const scrollContainer = document.querySelector('.overflow-y-auto'); + + const toggleVisibility = () => { + if (scrollContainer && scrollContainer.scrollTop > 400) { + setIsVisible(true); + } else { + setIsVisible(false); + } + }; + + if (scrollContainer) { + scrollContainer.addEventListener("scroll", toggleVisibility); + return () => scrollContainer.removeEventListener("scroll", toggleVisibility); + } + }, []); + + const scrollToTop = () => { + const scrollContainer = document.querySelector('.overflow-y-auto'); + if (scrollContainer) { + scrollContainer.scrollTo({ top: 0, behavior: "smooth" }); + } + }; + + return ( + + {isVisible && ( + + + + )} + + ); +} diff --git a/frontend/src/components/SkillsSection.jsx b/frontend/src/components/SkillsSection.jsx new file mode 100644 index 0000000..c291466 --- /dev/null +++ b/frontend/src/components/SkillsSection.jsx @@ -0,0 +1,208 @@ +import React, { useState } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { Code2, Server, Layout, Wrench, Brain } from "lucide-react"; +import portfolioData from "../../portfolio.json"; + +const categoryConfig = { + backend: { + label: "Backend", + icon: Server, + color: "#00d4aa", + description: "Server-side technologies & databases" + }, + frontend: { + label: "Frontend", + icon: Layout, + color: "#ff6b35", + description: "Client-side frameworks & styling" + }, + languages: { + label: "Languages", + icon: Code2, + color: "#9b5de5", + description: "Programming languages" + }, + mlDl: { + label: "ML / DL", + icon: Brain, + color: "#f15bb5", + description: "Machine learning & deep learning" + }, + tools: { + label: "Tools", + icon: Wrench, + color: "#00bbf9", + description: "Development & productivity tools" + } +}; + +export default function SkillsSection() { + const [activeCategory, setActiveCategory] = useState("backend"); + const skills = portfolioData.skills; + + const categories = Object.keys(skills).filter(key => categoryConfig[key]); + + return ( +
+ {/* Section Header */} +
+ + Skills + +
+ + {/* Category Navigation */} + + {categories.map((categoryKey) => { + const config = categoryConfig[categoryKey]; + const Icon = config.icon; + const isActive = activeCategory === categoryKey; + + return ( + + ); + })} + + + {/* Skills Display */} +
+ {/* Background decorative grid */} +
+ +
+ {/* Category description */} + + + {(() => { + const config = categoryConfig[activeCategory]; + const Icon = config.icon; + return ( + <> +
+ +
+
+

+ {config.label} +

+

+ {config.description} +

+
+ + ); + })()} +
+
+ + {/* Skills Grid */} + + + {skills[activeCategory]?.map((skill, index) => { + const config = categoryConfig[activeCategory]; + return ( + +
+ {/* Hover gradient */} +
+ + {/* Skill name */} + + {skill} + + + {/* Bottom accent line */} +
+
+ + ); + })} + + + + {/* Decorative corner elements */} +
+
+
+
+
+
+ +
+ ); +} diff --git a/frontend/src/components/TabNavigation.jsx b/frontend/src/components/TabNavigation.jsx new file mode 100644 index 0000000..720d42c --- /dev/null +++ b/frontend/src/components/TabNavigation.jsx @@ -0,0 +1,31 @@ +import React from "react"; +import { motion } from "framer-motion"; +import { cn } from "@/lib/utils"; + +export default function TabNavigation({ tabs, activeTab, onTabChange }) { + return ( +
+ {tabs.map((tab) => ( + + ))} +
+ ); +} diff --git a/frontend/src/components/TechTag.jsx b/frontend/src/components/TechTag.jsx new file mode 100644 index 0000000..29af209 --- /dev/null +++ b/frontend/src/components/TechTag.jsx @@ -0,0 +1,30 @@ +import React from "react"; +import { cn } from "@/lib/utils"; + +export default function TechTag({ technology, className, size = "md" }) { + const sizeClasses = { + sm: "px-2 py-0.5 text-xs", + md: "px-3 py-1 text-sm", + lg: "px-4 py-1.5 text-base", + }; + + return ( + + {technology} + + ); +} diff --git a/frontend/src/index.css b/frontend/src/index.css index 444f889..f71d547 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1,13 +1,65 @@ +/* Google Fonts */ +@import url('https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500;600&family=Sora:wght@300;400;500;600;700&display=swap'); + @import "tailwindcss"; +@theme { + /* Architectural Blueprint Color Palette */ + --color-primary: #00d4aa; + --color-primary-hover: #00f5c4; + --color-primary-dim: #00d4aa33; + --color-primary-glow: #00d4aa66; + + /* Secondary accent */ + --color-accent: #ff6b35; + --color-accent-dim: #ff6b3533; + + /* Deep Dark Backgrounds */ + --color-background-primary: #050a0e; + --color-background-secondary: #0a1218; + --color-background-tertiary: #111a22; + --color-background-card: #0d151c; + + /* Text Colors */ + --color-text-primary: #e8f4f0; + --color-text-secondary: #8aa8a0; + --color-text-tertiary: #5a7872; + --color-text-muted: #3d5550; + + /* Border Colors */ + --color-border-primary: #1a2830; + --color-border-secondary: #253540; + --color-border-glow: #00d4aa40; + + /* Grid Pattern */ + --color-grid-line: #152028; + --color-grid-accent: #1a3040; + + /* Dot Pattern */ + --color-dot-light: #5a7872; + --color-dot-dark: #253540; + + /* Custom Spacing */ + --spacing-section: 8rem; + --spacing-card: 2rem; +} + +html, body, #root { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + overflow: hidden; +} + :root { - font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; + font-family: 'Sora', system-ui, sans-serif; + line-height: 1.6; font-weight: 400; - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; + color-scheme: dark; + color: var(--color-text-primary); + background-color: var(--color-background-primary); font-synthesis: none; text-rendering: optimizeLegibility; @@ -15,56 +67,229 @@ -moz-osx-font-smoothing: grayscale; } +* { + box-sizing: border-box; +} + +/* Selection styling */ +::selection { + background: var(--color-primary-dim); + color: var(--color-text-primary); +} + a { font-weight: 500; - color: #646cff; - text-decoration: inherit; + color: var(--color-primary); + text-decoration: none; + transition: color 0.3s ease, text-shadow 0.3s ease; } + a:hover { - color: #535bf2; + color: var(--color-primary-hover); + text-shadow: 0 0 20px var(--color-primary-glow); } body { margin: 0; - display: flex; - place-items: center; min-width: 320px; min-height: 100vh; } -h1 { - font-size: 3.2em; +/* Typography - Instrument Serif for display, Sora for body, JetBrains Mono for code */ +h1, h2, h3, h4, h5, h6 { + font-family: 'Instrument Serif', Georgia, serif; + color: var(--color-text-primary); + font-weight: 400; line-height: 1.1; + letter-spacing: -0.02em; } -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; +h1 { + font-size: clamp(2.5rem, 8vw, 5rem); + line-height: 1; } -button:hover { - border-color: #646cff; + +h2 { + font-size: clamp(2rem, 5vw, 3rem); } -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; + +h3 { + font-size: 1.5rem; } -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; +p { + color: var(--color-text-secondary); + line-height: 1.8; +} + +/* Monospace for technical elements */ +.font-mono { + font-family: 'JetBrains Mono', monospace; +} + +/* Smooth scrolling */ +html { + scroll-behavior: smooth; +} + +/* Custom scrollbar */ +::-webkit-scrollbar { + width: 6px; +} + +::-webkit-scrollbar-track { + background: var(--color-background-primary); +} + +::-webkit-scrollbar-thumb { + background: var(--color-border-secondary); + border-radius: 3px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--color-primary-dim); +} + +/* Glow effects */ +.glow-primary { + box-shadow: 0 0 30px var(--color-primary-dim), 0 0 60px var(--color-primary-dim); +} + +.glow-text { + text-shadow: 0 0 30px var(--color-primary-glow); +} + +/* Border glow animation */ +@keyframes border-glow { + 0%, 100% { border-color: var(--color-border-primary); } + 50% { border-color: var(--color-border-glow); } +} + +.animate-border-glow { + animation: border-glow 3s ease-in-out infinite; +} + +/* Diagonal line decorations */ +.diagonal-line { + position: absolute; + height: 1px; + background: linear-gradient(90deg, transparent, var(--color-primary-dim), transparent); + transform-origin: left center; +} + +/* Card hover effect */ +.card-hover { + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); +} + +.card-hover:hover { + transform: translateY(-4px); + box-shadow: + 0 20px 40px -20px var(--color-primary-dim), + 0 0 0 1px var(--color-border-glow); +} + +/* Skill orbit animation */ +@keyframes orbit { + from { transform: rotate(0deg) translateX(var(--orbit-radius)) rotate(0deg); } + to { transform: rotate(360deg) translateX(var(--orbit-radius)) rotate(-360deg); } +} + +@keyframes pulse-glow { + 0%, 100% { opacity: 0.5; transform: scale(1); } + 50% { opacity: 1; transform: scale(1.1); } +} + +.animate-orbit { + animation: orbit var(--orbit-duration, 20s) linear infinite; +} + +.animate-pulse-glow { + animation: pulse-glow 2s ease-in-out infinite; +} + +/* Staggered fade in */ +@keyframes fade-in-up { + from { + opacity: 0; + transform: translateY(30px); } - button { - background-color: #f9f9f9; + to { + opacity: 1; + transform: translateY(0); } } + +.animate-fade-in-up { + animation: fade-in-up 0.6s ease-out forwards; +} + +/* Corner decorations */ +.corner-decoration::before, +.corner-decoration::after { + content: ''; + position: absolute; + width: 20px; + height: 20px; + border: 1px solid var(--color-primary-dim); +} + +.corner-decoration::before { + top: -1px; + left: -1px; + border-right: none; + border-bottom: none; +} + +.corner-decoration::after { + bottom: -1px; + right: -1px; + border-left: none; + border-top: none; +} + +/* Grid background pattern */ +.grid-pattern { + background-image: + linear-gradient(var(--color-grid-line) 1px, transparent 1px), + linear-gradient(90deg, var(--color-grid-line) 1px, transparent 1px); + background-size: 40px 40px; +} + +/* Criss-cross pattern */ +.crisscross-pattern { + background-image: + linear-gradient(45deg, var(--color-grid-line) 1px, transparent 1px), + linear-gradient(-45deg, var(--color-grid-line) 1px, transparent 1px); + background-size: 30px 30px; +} + +/* Tech stack badge glow on hover */ +.tech-badge { + transition: all 0.3s ease; +} + +.tech-badge:hover { + background: var(--color-primary-dim); + border-color: var(--color-primary); + color: var(--color-primary); + box-shadow: 0 0 15px var(--color-primary-dim); +} + +/* Section divider */ +.section-divider { + height: 1px; + background: linear-gradient(90deg, transparent, var(--color-border-secondary) 20%, var(--color-primary-dim) 50%, var(--color-border-secondary) 80%, transparent); +} + +/* Noise texture overlay */ +.noise-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + opacity: 0.03; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 400 400' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E"); +} diff --git a/frontend/src/lib/utils.js b/frontend/src/lib/utils.js new file mode 100644 index 0000000..f735956 --- /dev/null +++ b/frontend/src/lib/utils.js @@ -0,0 +1,6 @@ +import { clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs) { + return twMerge(clsx(inputs)); +} diff --git a/frontend/src/pages/Contact.jsx b/frontend/src/pages/Contact.jsx new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/pages/Experience.jsx b/frontend/src/pages/Experience.jsx new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/pages/GuestBook.jsx b/frontend/src/pages/GuestBook.jsx new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/pages/Home.jsx b/frontend/src/pages/Home.jsx new file mode 100644 index 0000000..7dffb3d --- /dev/null +++ b/frontend/src/pages/Home.jsx @@ -0,0 +1,35 @@ +import React from "react"; +import Hero from "@/components/Hero"; +import SkillsSection from "@/components/SkillsSection"; +import ExperienceSection from "@/components/ExperienceSection"; +import ProjectsSection from "@/components/ProjectsSection"; +import BlogsSection from "@/components/BlogsSection"; + +const Home = () => { + return ( +
+ {/* Hero Section */} + + + {/* Skills Section - NEW */} +
+ +
+ + {/* Experience Section */} +
+ +
+ + {/* Projects Section */} +
+ +
+ + {/* Blogs Section */} + +
+ ); +}; + +export default Home; diff --git a/frontend/src/pages/Projects.jsx b/frontend/src/pages/Projects.jsx new file mode 100644 index 0000000..e69de29 diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 410f91e..166094f 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -1,12 +1,33 @@ import { defineConfig } from "vite"; import tailwindcss from "@tailwindcss/vite"; import react from "@vitejs/plugin-react"; +import path from "path"; // https://vite.dev/config/ export default defineConfig({ - plugins: [react(), tailwindcss()], - server: { - host: "127.0.0.1", - port: 5173 // optional, defaults to 5173 anyway - } + plugins: [react(), tailwindcss()], + resolve: { + alias: [ + { + find: '@', + replacement: path.resolve(__dirname, 'src') + }, + { + find: '@components', + replacement: path.resolve(__dirname, 'src/components') + }, + { + find: '@lib', + replacement: path.resolve(__dirname, 'src/lib') + }, + { + find: '@pages', + replacement: path.resolve(__dirname, 'src/pages') + } + ] + }, + server: { + host: "127.0.0.1", + port: 5173, // optional, defaults to 5173 anyway + }, }); \ No newline at end of file diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 0000000..3c2e634 --- /dev/null +++ b/netlify.toml @@ -0,0 +1,22 @@ +[build] + base = "frontend" + command = "npm run build" + publish = "dist" + +[[redirects]] + from = "/*" + to = "/index.html" + status = 200 + +[[headers]] + for = "/*" + [headers.values] + X-Frame-Options = "DENY" + X-XSS-Protection = "1; mode=block" + X-Content-Type-Options = "nosniff" + Referrer-Policy = "strict-origin-when-cross-origin" + +[[headers]] + for = "/assets/*" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable"