A personal website built with Next.js, featuring a collection of readings, travel map, and quotes with a minimalist design aesthetic. Content is managed through markdown files and a custom CLI tool, emphasizing simplicity, type safety, and accessibility.
- Features
- Tech Stack
- Getting Started
- Content Management
- Development Scripts
- Project Structure
- Development Philosophy
- Accessibility
- State Management
- Testing Strategy
- Git Workflow
- Versioning
- Continuous Integration
- Documentation
- Readings Collection: Showcase books and readings with cover images, organized by year with audiobook indicators and simplified reading/finished status
- Travel Map: Interactive map using Leaflet to display travel locations with custom markers and popups
- Quote Display: Animated typewriter effect for displaying quotes with randomization
- Content Management: Custom CLI tools for adding and managing readings and quotes via markdown files
- Responsive Design: Optimized for all device sizes using Tailwind's responsive utilities
- Dark Mode: Fully implemented dark mode support with theme persistence
- Accessibility: WCAG 2.1 AA compliant with keyboard navigation, semantic HTML, and ARIA attributes
- State Management: Zustand for UI state, native fetch for data loading
- Type Safety: Strict TypeScript throughout with comprehensive type definitions
- Framework: Next.js 15 with App Router
- Language: TypeScript 5.4
- Component Library: Custom React 19 components
- Styling: Tailwind CSS with custom design tokens
- State Management: Zustand v5 (UI state) + native fetch API
- Maps: Leaflet/React-Leaflet v5
- Content Storage: Markdown files with YAML frontmatter
- API Routes: Next.js API Routes serving static content
- CLI Tools: Custom TypeScript CLI for content management
- Logging: Winston for structured JSON logging
- Testing: Jest with React Testing Library
- Accessibility Testing: jest-axe + eslint-plugin-jsx-a11y
- Component Development: Storybook v8 with A11y addon
- Linting: ESLint v9 with Next.js and TypeScript configs
- Formatting: Prettier
- Git Hooks: Husky + lint-staged
- Node.js 20+ and npm 10.9.2+
- Git
- Text editor (for content creation)
-
Clone the repository
git clone https://github.com/phrazzld/vanity.git cd vanity -
Install dependencies
npm install
-
Start the development server
npm run dev
The application will be available at http://localhost:3000.
Content is managed through markdown files and a custom CLI tool. All content is stored in the /content/ directory.
# Add a new quote (opens your $EDITOR for quote and author)
npm run vanity -- quote add
# List recent quotes
npm run vanity -- quote list
npm run vanity -- quote list -n 20 # Show 20 quotesQuotes are saved as /content/quotes/[ID].md with YAML frontmatter:
---
author: 'Author Name'
id: 42
---
The quote text goes here.# Add a new reading (interactive prompts)
npm run vanity -- reading add
# Update a reading (mark finished, add thoughts, delete)
npm run vanity -- reading update
# List recent readings
npm run vanity -- reading list
npm run vanity -- reading list -n 5 # Show 5 readingsReadings support:
- Two-state system: Currently reading or finished (simplified from previous three-state system)
- Audiobook support: Mark readings as audiobooks with 🎧 indicators in the UI
- Cover images: URLs or local files (auto-optimized to WebP at 400x600px)
- Status management: Easy updates via CLI to mark books as finished
- Optional thoughts: Add personal notes via $EDITOR
- File deletion: Remove readings entirely through update command
- Saved as:
/content/readings/[slug].mdwith YAML frontmatter
- Set
EDITORenvironment variable for preferred editor (default:vi) - Example:
export EDITOR=nvim
content/
├── quotes/
│ ├── 0001.md
│ ├── 0002.md
│ └── ...
└── readings/
├── book-title.md
└── ...
public/images/readings/
└── book-title.webp # Optimized cover images
Readings are stored as markdown files with YAML frontmatter:
---
title: 'The Pragmatic Programmer'
author: 'David Thomas and Andrew Hunt'
finished: 2023-06-15T00:00:00.000Z # null for currently reading
audiobook: true # Optional, defaults to false
coverImage: '/images/readings/pragmatic-programmer.webp'
---
Optional thoughts and notes about the book go here.Reading Status:
- Currently Reading:
finished: null - Finished:
finished: 2023-06-15T00:00:00.000Z(ISO date string) - Audiobook:
audiobook: true(shows 🎧 indicator in UI)
- Build Errors: Check for TypeScript errors with
npm run typecheck. - Missing Content: Ensure content directories exist:
/content/quotes/and/content/readings/. - Image Issues: Ensure cover image URLs in markdown content are valid HTTPS URLs from approved CDN domains.
npm run dev- Start development server with Turbopacknpm run dev:log- Start development server with logging to logs/dev.lognpm run logs- View development logsnpm run logs:watch- Watch development logs in real-timenpm run build- Build for production (includes Prisma generation)npm run start- Start production server
npm run test- Run all testsnpm run test:watch- Run tests in watch modenpm run test:coverage- Run tests with coverage reportnpm run test:snapshot- Run snapshot tests onlynpm run test:snapshot:update- Update snapshot tests
npm run lint- Run ESLint on specified filesnpm run lint:fix- Run ESLint and automatically fix issuesnpm run format- Format all files with Prettiernpm run format:check- Check formatting without making changesnpm run typecheck- Run TypeScript type checkingnpm run security:audit- Run npm audit for high and critical vulnerabilitiesnpm run security:scan- Run security scan with allowlist filtering
npm run vanity -- quote add- Add new quote interactivelynpm run vanity -- quote list- List recent quotes (with optional count:-n 20)npm run vanity -- reading add- Add new reading interactively (includes audiobook prompt)npm run vanity -- reading update- Update reading status, add thoughts, or delete readingnpm run vanity -- reading list- List recent readings (with optional count:-n 5)npm run reading-summary- Generate reading summary report
npm run storybook- Start Storybook dev servernpm run build-storybook- Build Storybooknpm run test-storybook- Run Storybook tests
npm run release- Generate new version based on conventional commitsnpm run release:patch- Generate a new patch version (0.0.x)npm run release:minor- Generate a new minor version (0.x.0)npm run release:major- Generate a new major version (x.0.0)npm run release:dry-run- Preview what the next version would look like
/
├── cli/ # Custom CLI tools for content management
├── content/ # Markdown content files
│ ├── quotes/ # Quote markdown files (auto-numbered)
│ └── readings/ # Reading markdown files (slug-based)
├── public/ # Static assets
│ ├── images/ # Project and reading cover images
│ └── ... # Other static files
├── scripts/ # Utility scripts and build tools
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── api/ # API routes (serve static content)
│ │ ├── components/ # React components
│ │ │ ├── keyboard/ # Keyboard navigation components
│ │ │ ├── quotes/ # Quote-related components
│ │ │ └── readings/ # Reading-related components
│ │ ├── contexts/ # React contexts
│ │ ├── hooks/ # Custom React hooks
│ │ └── utils/ # Utility functions
│ ├── lib/ # Core library code
│ │ ├── api/ # API client functions
│ │ └── data.ts # Markdown file parsing
│ ├── store/ # Zustand store definitions
│ └── types/ # TypeScript type definitions
├── docs/ # Documentation files
├── .env.example # No environment variables needed
├── next.config.ts # Next.js configuration
├── tailwind.config.ts # Tailwind CSS configuration
└── tsconfig.json # TypeScript configuration
cli/index.ts- CLI tool entry pointsrc/app/layout.tsx- Root layout with providerssrc/app/page.tsx- Home pagesrc/lib/data.ts- Markdown content parsingsrc/app/api/readings/route.ts- Readings APIsrc/app/api/quotes/route.ts- Quotes APIsrc/store/theme.ts- Theme state managementtailwind.config.ts- Design token configurationcontent/- All content as markdown files
This project follows a set of core principles to ensure maintainable, secure, and high-quality code:
- Simplicity First: Resist unnecessary complexity and over-engineering
- Modularity is Mandatory: Small, focused components with clear responsibilities
- Testability by Design: Code structured for comprehensive testing
- Explicit Intent: Clear, readable code with explicit dependencies
- Secure by Default: Security integrated into the development process
- Automate Everything: Extensive automation for consistency and efficiency
For detailed information, see DEVELOPMENT_PHILOSOPHY.md.
- Strict TypeScript with explicit types and minimal use of
any - Feature-focused organization rather than technical layers
- Functional components with explicit return types
- Detailed JSDoc comments for components and functions
- Consistent naming conventions (PascalCase for components, camelCase for utilities)
This project is committed to WCAG 2.1 AA compliance, ensuring the application is usable by people with various disabilities:
- Semantic HTML structure with appropriate ARIA attributes
- Keyboard navigation support throughout the application (Tab, Shift+Tab, Enter, Space)
- Color contrast ratios that meet WCAG standards in both light and dark themes
- Focus management for modals and interactive elements
- Screen reader compatibility with descriptive alt text and labels
- Accessible hover interactions with keyboard focus equivalence (audiobook indicators)
The project includes comprehensive keyboard navigation utilities:
- Focus trapping for modals and dialogs
- Arrow key navigation within components
- Skip links to bypass navigation elements
- Focus management and restoration
For more details, see KEYBOARD_NAVIGATION.md and ACCESSIBILITY.md.
The project uses a hybrid approach to state management:
- Server State: Native fetch API for loading static markdown data
- UI State: Zustand for simple, lightweight global state management
- Local State: React's useState and useReducer for component-specific state
This approach separates concerns and provides optimal solutions for different types of state. For details, see STATE_MANAGEMENT.md.
The project follows a comprehensive testing approach:
- Unit Tests: For utility functions and isolated logic
- Component Tests: Using React Testing Library with user-centric approach
- Integration Tests: For API routes and data flow
- Accessibility Tests: Using jest-axe for automated accessibility checks
- Snapshot Tests: For UI regression testing
Guidelines:
- Test behavior, not implementation
- Mock external dependencies only (not internal collaborators)
- Focus on user interactions rather than implementation details
- Main branches:
mainormaster - Feature branches:
feature/feature-name - Bug fix branches:
fix/bug-description - Documentation branches:
docs/what-was-documented - Refactoring branches:
refactor/what-was-refactored - Release branches:
release/vX.Y.Z(semantic versioning) - Development branches:
devordevelop - Planning branches:
plan/plan-description
- Pre-commit Hooks: Lint, format, typecheck, and detect sensitive data
- Post-commit Hooks: Generate documentation
- Pre-push Hooks: Run tests and enforce branch naming conventions
This project uses semantic versioning based on Conventional Commits:
- Patch Version (0.0.x): Automatically incremented for
fix:commits - Minor Version (0.x.0): Automatically incremented for
feat:commits - Major Version (x.0.0): Automatically incremented for commits with
BREAKING CHANGE:orfeat!:
The versioning system is managed by standard-version, which:
- Increments the version in package.json based on commit types
- Generates/updates the CHANGELOG.md file
- Creates a git tag for the new version
This project uses GitHub Actions for continuous integration:
- Lint: Ensures code adheres to project standards
- Type Check: Verifies TypeScript type correctness
- Test: Runs the full test suite
- Build: Verifies the project builds successfully
- Storybook: Builds Storybook to ensure component documentation is valid
- Security Scan: Checks for high and critical security vulnerabilities in dependencies with allowlist support
CI runs on each push to main and on pull requests. Check the .github/workflows directory for details.
- DEVELOPMENT_PHILOSOPHY.md - Core development principles
- ACCESSIBILITY.md - Accessibility guidelines and implementation
- STATE_MANAGEMENT.md - State management approach
- DESIGN_TOKENS.md - Design system tokens
- RESPONSIVE_DESIGN.md - Responsive design approach
- KEYBOARD_NAVIGATION.md - Keyboard navigation utilities
- SECURITY_VULNERABILITY_MANAGEMENT.md - Security vulnerability scanning and management
- CI_TESTING_STRATEGY.md - CI pipeline and testing strategy
The project automatically generates technical overviews of code directories.
This project is licensed under the MIT License - see the LICENSE file for details.