Skip to content

Timbaines/highline-tales

Repository files navigation

HighlineTales

HighlineTales is a hiking-themed web application built as part of my JavaScript learning journey, inspired by me and my wife's vacation to Glacier National Park. It combines activity guides, blog posts sharing our ‘trailing’ stories, and planning tools centered on Glacier’s iconic Highline Trail.

Vite React React Router Supabase Vitest ESLint

Overview

HighlineTales is a React + Vite application that shares trail information, hiking tips, and personal stories for Glacier National Park. It also includes helpful UI like info cards, visitor analytics (via Supabase), and a clean CSS architecture combining global tokens and CSS Modules. Content is dynamically served via Vercel Serverless Functions from a Vercel Postgres database.

Features

  • Dynamic trail and activity pages fetched from Vercel Postgres
  • Blog with individual post-pages powered by serverless API endpoints
  • Hiking checklist/essentials page
  • Visitor counter backed by Supabase (RPC function increment_page_view)
  • Responsive layout with CSS Modules and global typography/utilities
  • Robust routing with error boundaries

Tech Stack

  • Frontend: React 19, React Router 7 (react-router-dom)
  • Backend/API: Vercel Serverless Functions (Node.js)
  • Database: Vercel Postgres (Powered by Neon)
  • Bundler: Vite 7 with @vitejs/plugin-react, alias @ → src
  • Styles: Global CSS (globals.css, typography.css, prose.css, utilities.css) + CSS Modules
  • Analytics: Supabase JS v2 client for simple analytics/features
  • Testing: Vitest + Testing Library (jsdom environment)
  • Linting: ESLint 9 (react-hooks, react-refresh) configured via eslint.config.js

Architecture at a glance

flowchart TD
  subgraph Client
    A[index.html] --> B(src/main.jsx)
    B --> C(App.jsx)
    C --> F(AppRouter)
  end

  subgraph Frontend Services
    F --> G[HomePage]
    F --> H[ActivityPage]
    F --> K[BlogPage]
    G & H & K --> M[activitiesService]
    G & H & K --> N[blogService]
  end

  subgraph Vercel API
    M --> O[api/activities.js]
    N --> P[api/blogs.js]
  end

  subgraph Database
    O & P --> Q[(Vercel Postgres)]
    S[Supabase] -. analytics .-> F
  end
Loading

Note:

  • activitiesService and blogService fetch data from the /api serverless endpoints.
  • Content is managed in Vercel Postgres; for schema and management.

Project structure

├─ api/                       # Vercel Serverless Functions
├─ docs/                      # Technical documentation (e.g., DATABASE.md)
├─ index.html
├─ vite.config.js
├─ eslint.config.js
├─ jsconfig.json              # @/* → src/* alias for editor/tooling
├─ package.json
├─ package-lock.json
├─ README.md
├─ public/                    # Static assets served as-is
├─ src/
│  ├─ AppRouter.jsx           # Central routes + loaders
│  ├─ services/               # Data fetching logic
│  ├─ components/             # Reusable UI components
│  ├─ pages/                  # Page-level components
│  ├─ data/                   # Static config/fallback data
│  └─ utils/                  # Utility functions & parsers

Tip: Import using the @ alias, e.g., import App from '@/App.jsx'.

Routing map

  • / → HomePage
  • /activities → ActivityPage
  • /activities/:slug → ActivityPost (loader: getActivityBySlug, 404 → ActivityNotFound)
  • /hiking-checklist → EssentialsPage
  • /blog → BlogPage
  • /blog/:slug → BlogPost (loader: getPostBySlug, 404 → BlogPostNotFound)

Getting started

Prerequisites

  • Node.js 18+ (LTS recommended) and npm
  • Optional: Supabase project (for VisitorCounter)

Installation

  • Clone and install

  • Environment variables

    • Create a .env.local file in the repository root by pulling from Vercel (requires Vercel CLI):
      • vercel link
      • vercel env pull .env.local
    • This file will contain your POSTGRES_URL and other database secrets.
    • Also ensure your Supabase variables are set if using analytics:
      • VITE_PUBLIC_SUPABASE_URL=your_supabase_url
      • VITE_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
  • Development server

    • vercel dev (Recommended - runs frontend + API)
    • npm run dev (Frontend only - API calls will fail)
    • Open http://localhost:3000

Available scripts

  • npm run dev → Start Vite dev server (with --host)
  • npm run build → Production build to dist/
  • npm run preview → Serve the production build locally
  • npm run clean → Remove dist/ (safe helper)
  • npm run lint → Lint JS/JSX with ESLint 9 (no warnings allowed)
  • npm test → Run Vitest in CI mode
  • npm run test:watch → Run Vitest in watch mode

Styling approach

  • Global CSS provides design tokens and base typography: globals.css, typography.css
  • prose.css styles rich text for blog posts
  • CSS Modules encapsulate component styles throughout components and pages
  • Utilities: utilities.css offers a small set of global helpers (gap, visibility, etc.). A future enhancement could split utilities into utilities.module.css and surfaces.module.css for better encapsulation.

Data and Supabase

  • The Supabase client lives at src/services/supabase/supabase.js and reads env vars VITE_PUBLIC_SUPABASE_URL and VITE_PUBLIC_SUPABASE_ANON_KEY
  • VisitorCounter uses a Supabase RPC named increment_page_view and basic reads for totals
  • Ensure Row Level Security policies and RPC exist in your Supabase project if you enable this feature

Testing

  • Vitest is configured with jsdom and React Testing Library
  • Setup file: src/test/setupTests.js (adds jest-dom matchers)
  • Run tests: npm test or npm run test:watch

Linting & code quality

  • ESLint 9 with react-hooks and react-refresh plugins
  • Config: eslint.config.js (dist/ ignored; JSX enabled)
  • Run lint: npm run lint

Accessibility & performance

  • Typography and color tokens are centralized for consistency
  • Error boundaries prevent full-app crashes
  • Where possible, provide descriptive alt text; decorative images should use empty alt=""
  • Consider Lighthouse and Axe DevTools checks during development; maintain an internal checklist in issues/PR templates rather than separate docs/ files.

Deployment

  • Production Site: https://www.highlinetales.com

  • Hosting: Deployed on Vercel with continuous deployment from the main branch

  • Domain: Registered with Hostinger with DNS configured to use Vercel nameservers

  • Build Process:

    • Vercel automatically builds the project using npm run build on each push to the main branch
    • The build creates optimized static files in the directory dist/
    • Vercel handles SPA routing configuration automatically, redirecting all routes to index.html
  • Environment Variables:

    • Supabase connection details are configured in the Vercel project settings
    • Environment variables for production are managed through the Vercel dashboard
  • Deployment Options:

    • Manual Deployment: npm run build followed by uploading to Vercel dist/
    • Preview Locally: npm run preview to test the production build before deployment
    • Preview Deployments: Each pull request gets a unique preview URL through Vercel's PR integration

For local development, you can still use npm run dev to start the Vite development server and preview at http://localhost:5173.

License

This project is licensed under the MIT License.

About

HighlineTales is a React + Vite application that shares trail information, hiking tips, and personal stories for Glacier National Park. The site includes helpful UI info cards, visitor analytics (via Supabase), and a clean architecture combining global tokens and CSS modules.

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors