This is a personal portfolio site for Karan Narula, built with React, TypeScript, Vite, and Tailwind CSS. It showcases projects, a profile, and uses a modern component-based architecture. The project is configured for deployment via GitHub Pages.
.
├── src/ # Main source code
│ ├── App.tsx # Main app component (profile, projects grid, mode toggles)
│ ├── main.tsx # React entry point
│ ├── index.css # Tailwind and global styles
│ ├── vite-env.d.ts # Vite/TypeScript env types
│ ├── components/ # UI and typography components
│ │ ├── brutal-hover.tsx # Full-viewport color wash on icon hover
│ │ ├── ui/ # Reusable UI components (Card, Avatar, Button, Tooltip)
│ │ ├── BugMode.tsx # Alternate poster homepage (bug toggle)
│ │ ├── HammerMode.tsx# Alternate hammer-and-nails homepage (nail toggle)
│ │ └── typography/ # Typography components (H1, H2, P, etc.)
│ └── lib/ # Utility functions (cn, icon hover colors)
├── public/ # Static assets (served as root)
│ ├── assets/ # Images and SVGs for profile and projects
│ │ ├── profile.jpg
│ │ ├── hammer-body.png
│ │ └── project-img/ # Project images (gif, png, jpg)
│ └── react.svg # Example SVG
├── dist/ # Build output (after `vite build`)
│ ├── assets/ # Bundled assets and images
│ │ └── project-img/ # Project images (copied from public/assets)
│ └── index.html # Built HTML
├── img/ # Additional SVG icons (not directly referenced in code)
│ └── svg-icons/ # Many social/media SVGs
├── .github/ # GitHub Actions and Dependabot config
│ ├── dependabot.yml # Weekly npm updates, grouped ESLint/Vite bumps
│ └── workflows/
│ ├── ci.yml # PR checks: npm ci, build, lint (job name: test)
│ ├── dependabot-auto-merge.yml # Auto-merge Dependabot patch/minor PRs
│ └── deploy.yml # Deploy to GitHub Pages on push to master
├── package.json # Project metadata, scripts, dependencies
├── postcss.config.js # PostCSS config (`@tailwindcss/postcss`)
├── vite.config.ts # Vite config (React plugin, alias @ to ./src)
├── tsconfig.json # TypeScript config (base, with path aliases)
├── tsconfig.app.json # App-specific TypeScript config
├── tsconfig.node.json # Node-specific TypeScript config
├── components.json # shadcn/ui component config and aliases
├── index.html # HTML entry point for Vite
├── .gitignore # Git ignore rules
├── LICENSE # License file
├── CNAME # Custom domain for GitHub Pages
├── README.md # Project intro (minimal)
└── CURSOR.md # (This file) Project structure/context for Cursor editor
- Path Aliases:
@/maps to./src/(seevite.config.ts,tsconfig.json). - Component Structure: UI components are in
src/components/ui/, typography insrc/components/typography/. - Assets: Images for profile and projects are in
public/assets/and referenced by relative path in code. - Tailwind CSS: v4 CSS-first config in
src/index.css(@import "tailwindcss",@theme, class-baseddarkvariant). PostCSS uses@tailwindcss/postcss. - Deployment: Uses
gh-pagesfor deployment to GitHub Pages, with a custom domain set inCNAME. Auto-deploys from.github/workflows/deploy.ymlon push tomaster. - CI: Pull requests targeting
masterrun.github/workflows/ci.yml(npm ci,npm run build,npm run lint). The job is namedtestand is the required status check for merging. Dependabot patch/minor PRs can auto-merge once that check is green. Major updates foreslintand@eslint/jsare ignored so those packages stay on v9 together. - TypeScript:
tscruns TypeScript 7 via the@typescript/nativealias (npm:typescript). Thetypescriptpackage is aliased to@typescript/typescript6sotypescript-eslintcan keep using the TypeScript 6 compiler API (TypeScript 7.0 does not ship one).tsconfigpath aliases do not usebaseUrl(removed in TypeScript 7). - shadcn/ui: Components are managed/configured via
components.json. - Dark Mode Support: The site supports dark mode, following the user's system preference by default. A toggle button in the top right allows manual switching, and the choice is remembered.
- Brutal hover: Inspired by the May 2017 reference, hovering a project or social icon floods the page with that accent and a giant uppercase label over an opaque wash that hides the hero. Icons also jelly-pop or animate locally. Metadata comes from
brutalHoverProps()insrc/lib/brutal.ts. The email address is not shown on the page.
src/App.tsx: Main React component, renders profile, social icons, and project icons.src/components/brutal-hover.tsx: Viewport-sized hover wash and giant label.src/lib/brutal.ts:brutalHoverProps()for wash metadata and icon accent colors.src/components/BugMode.tsx: Poster layout shown when bug mode is on.src/components/HammerMode.tsx: Hammer-and-nails layout shown when nail mode is on.src/components/ui/card.tsx: Card component (with header, footer, etc.).src/components/ui/avatar.tsx: Avatar component (profile image).src/components/typography/typography.tsx: Typography components (H1, H2, P, etc.).src/lib/utils.ts: Utility for merging class names (cn).src/index.css: Tailwind v4 theme tokens and global styles.vite.config.ts: Vite config, including alias setup.components.json: shadcn/ui config and aliases.- Dark mode toggle: A button in the top right corner lets users switch between dark and light mode. The theme is persisted and respects system settings by default.
- Bug mode toggle: A bug icon in the top-right controls swaps the homepage for a poster layout in
src/components/BugMode.tsx. Display type is Fraunces and labels are IBM Plex Mono (the same pairing as plotmaniac.com). Bug mode is always the dark poster, and the light/dark toggle is hidden while it is on. A white bug perches on the project columns and tumbles between them when hovered or clicked. The choice is stored inlocalStorageunderbugMode. - Nail mode toggle: A nail icon beside the bug control swaps the homepage for the hammer-and-nails layout in
src/components/HammerMode.tsx. The default homepage (brutal hover icons) stays the default view; nail mode is opt-in. The hammer lockup (name, title, and the LinkedIn, GitHub, and Ko-fi marks on the head) stays fixed while hovering. Those three marks are links. Hovering a nail shows a popup label above that nail only; clicking cocks the hammer and swings its face into that nail, then navigates to the project URL. Coming back resets the hammer and the nail. The poster is a fixed light-gray Readymag-style composition, so the light/dark toggle is hidden while it is on. Bug mode and nail mode are mutually exclusive. The choice is stored inlocalStorageundernailMode.
- Run
npm installto install dependencies. - Use
npm run devto start the development server. - Use
npm run buildto build for production (output indist/). - Use
npm run deployto deploy to GitHub Pages.
This file provides a high-level map of the project for navigation, search, and context-aware editing. Update this file if you add major new directories, components, or change conventions.