Skip to content

Repository files navigation

Uncharted Travels β€” Pakistan Heritage & Land Travel

Pakistan's definitive heritage travel guide. Explore 5,000 years of history across five regions β€” Punjab, Sindh, KPK, Balochistan, and Gilgit-Baltistan.

Live demo:Deployment


πŸ“‹ Overview

Uncharted Travels is a static multi-page website built with plain HTML, CSS, and vanilla JavaScript β€” no framework, no build step, no npm install. It's a heritage travel guide and booking portal for curated cultural and historical tours across Pakistan, covering UNESCO World Heritage Sites, ancient civilisations, Mughal architecture, Buddhist monasteries, Sufi shrines, and curated land routes.

8 pages, 9 stylesheets, one shared JS file, zero dependencies beyond two CDN links (Google Fonts, Font Awesome).


πŸ—‚οΈ Project Structure

Uncharted-Travels-main/
β”‚
β”œβ”€β”€ index.html                  # Home β€” hero, regions, featured sites, timeline, testimonials
β”œβ”€β”€ about.html                  # Company story, team, milestones, mission
β”œβ”€β”€ destinations.html           # Full destination listing by province (30+ locations)
β”œβ”€β”€ historical-sites.html       # Deep-dive into major archaeological sites + UNESCO table
β”œβ”€β”€ cultural-insights.html      # Culture, festivals, Gandhara art, Sufism, food, language
β”œβ”€β”€ travel-guide.html           # Visas, safety, transport, budget, packing, itineraries
β”œβ”€β”€ contact.html                # Multi-step booking form, FAQ, emergency contact
β”œβ”€β”€ 404.html                    # Custom not-found page, matches site design system
β”‚
β”œβ”€β”€ css/
β”‚   β”œβ”€β”€ shared.css              # Design tokens, reset, nav, footer, utilities, a11y
β”‚   β”œβ”€β”€ index.css                 about.css                 contact.css
β”‚   β”œβ”€β”€ destinations.css          historical-sites.css       cultural-insights.css
β”‚   β”œβ”€β”€ travel-guide.css        # ...one file per page for its unique sections
β”‚   └── 404.css                 # 404 page layout
β”‚
β”œβ”€β”€ js/
β”‚   └── main.js                 # Nav, hamburger, scroll reveal, forms, FAQ, sliders
β”‚
β”œβ”€β”€ htmlpictures/                # ~75 image assets (photos, icons, OG previews)
β”‚
β”œβ”€β”€ manifest.json                # PWA manifest β€” name, icons, theme colour
β”œβ”€β”€ robots.txt                   # Crawler rules + sitemap pointer
β”œβ”€β”€ sitemap.xml                  # Search-engine sitemap (needs your real domain β€” see below)
β”œβ”€β”€ .hintrc                      # webhint/Edge Tools linter config
β”œβ”€β”€ LICENSE                      # MIT
└── README.md

No build tools, no frameworks, no npm. Drop the folder on any static host and it works exactly as-is.


🎨 Design System

Colour Tokens

Token Hex Usage
--void #07070D Page background
--stone #12121A Card backgrounds
--deep #1C1C28 Section backgrounds
--slate #252535 Elevated surfaces
--copper #BF7A35 Primary accent, CTAs
--gold #D4A843 Highlight, numbers, active states
--rust #A03820 Emergency/alert sections
--parchment #EBD9B8 Body text
--cream #F7F0E0 Headings
--sand #C8B08A Secondary text
--mist #9696AF Subdued text (WCAG AA compliant)
--white #FAFAF5 High-contrast text
--nav-h 68px Fixed nav height β€” used in calc() throughout for hero padding, scroll offsets, mobile menu positioning

Typography

  • Cormorant Garamond β€” all headings, serif display type
  • Outfit β€” body text, UI labels, nav

External Dependencies

That's the entire dependency list. No build tools, no frameworks, no npm.


β™Ώ Accessibility (WCAG 2.1 AA)

Built to meet WCAG 2.1 Level AA across all pages.

Contrast ratios (key pairs)

Element Background Ratio Status
--mist text --void 6.96:1 βœ… AA
--mist text --stone 6.46:1 βœ… AA
--mist text --deep 5.84:1 βœ… AA
--sand text --void 9.60:1 βœ… AA
--copper --void 5.79:1 βœ… AA
--cream headings --void 17.69:1 βœ… AA
Newsletter placeholder Input background 7.19:1 βœ… AA
Emergency subtext Dark red bg 8.50:1 βœ… AA

Structural accessibility

  • Skip-to-content link on every page, visible on focus
  • Single <h1> per page, no skipped heading levels
  • <nav>, <main>, <footer> landmarks throughout β€” every page's <main> correctly wraps its full content, including the hero
  • Hamburger menu: full aria-expanded / aria-controls / aria-label state management, toggled in JS
  • All decorative icons aria-hidden="true"; all functional icons have accessible labels
  • Every #anchor target (region tabs, deep-dive sections, table-of-contents links) has scroll-margin-top set, so the fixed nav never covers content you jump to
  • @media (prefers-reduced-motion: reduce) disables scroll-reveal animation, the homepage ticker, and other transitions for users who've asked their OS for reduced motion

βš™οΈ JavaScript Features (js/main.js)

Feature Description
Hamburger menu Toggles .open on .nav-links, swaps bars ↔ times icon, closes on outside click. Switches on below 1100px (not 768px) β€” the full desktop nav genuinely needs that much width for the logo, 7 links, and CTA button to fit without overlapping
Nav scroll darkening On the homepage only, nav starts transparent over the hero and darkens after 60px of scroll
Scroll reveal IntersectionObserver adds .visible to .reveal elements as they enter the viewport, staggered slightly per element
Scroll-to-top button Appears after 400px of scroll, smooth-scrolls to top on click
FAQ accordion Single-open accordion on the Contact page
Tour type selector Click-to-select cards on the Contact page's tour picker
Booking form Live progress indicator as fields fill in; validates with reportValidity() before showing success (so an empty form can't submit); attempts a real fetch() POST to its configured endpoint, falling back to a demo success state if that endpoint isn't set up yet β€” see Making the Forms Real
Newsletter form Same validate-then-submit-with-fallback pattern as the booking form
Region tabs / filter buttons Simple active-state toggles on Destinations and Historical Sites
Group size slider Live numeric display synced to the range input on the booking form

Note on "active" nav state: which link shows as current-page is set directly in each page's HTML (class="active" on the matching <a>), not detected automatically via window.location.pathname. If you add more pages, remember to set this by hand.


πŸ” SEO & Social Sharing

Every page has:

  • Unique <title> and meta description (within recommended length ranges)
  • <link rel="canonical">
  • <meta name="robots" content="index, follow"> (404.html correctly uses noindex, follow instead)
  • Full Open Graph + Twitter Card tags, each pointing at a real, page-specific preview image already in htmlpictures/
  • manifest.json linked, with a full icon set (16px, 32px, 180px apple-touch, 192px, 512px) generated from the actual logo β€” not stretched up from the small favicon
  • theme-color set to the site's copper accent, so mobile browser chrome matches the brand

Before this does anything for real search engines:

  1. Open sitemap.xml and replace every https://REPLACE-WITH-YOUR-DOMAIN.com with your real deployed domain β€” the sitemap spec requires absolute URLs, so it's inert until you do this
  2. robots.txt already points at sitemap.xml correctly and needs no changes

πŸš€ Performance

  • Every image below the fold uses loading="lazy" decoding="async" (13 images across the site); the logo, which is above the fold on every page, correctly stays eager
  • htmlpictures/ was audited and re-compressed this pass: 30MB β†’ 12MB. The worst single offender was a 9.4MB, 5248Γ—2944px DSLR photo used as a small ~400px card background β€” resized and re-encoded down to 178KB with no visible quality loss. Several page-preview screenshots were converted from lossless PNG to high-quality JPEG for the same reason (OG images get recompressed by social platforms anyway, so there's no benefit to serving them lossless)
  • will-change: transform on the homepage's continuously-animating ticker, so it runs on the compositor thread instead of repainting every frame
  • Two Google Fonts preconnect hints (fonts.googleapis.com and fonts.gstatic.com, the second with crossorigin) β€” the font files themselves are served from the second domain, and skipping that preconnect is a common miss that costs a full extra DNS+TLS round trip
  • Font Awesome is loaded with an SRI integrity hash and crossorigin="anonymous"

Still open, if you want to push further: the three remaining .webp images over 500KB (Altit-Fort, Carved-stupas, Swat-Valley) are already in an efficient format at reasonable dimensions for their use as hero/card backgrounds β€” further gains there would be marginal. htmlpictures/homepage-desktop.png (1.3MB) isn't referenced anywhere in the codebase; it's safe to delete if you don't need it for something outside the site itself.


πŸ“¬ Making the Forms Real

Both the booking form (contact.html) and the newsletter form (index.html) are fully wired to submit β€” they're just pointed at a placeholder endpoint right now:

<form id="bookingForm" action="https://formspree.io/f/YOUR_FORM_ID" method="POST" novalidate>

The JS in main.js already does a real fetch() POST to whatever's in that action attribute, and only falls back to the demo success message if that request fails β€” which right now, it always will, since YOUR_FORM_ID isn't real.

To make it actually send emails, no other code changes needed:

  1. Create a free account at formspree.io
  2. Create a new form, copy the endpoint it gives you (https://formspree.io/f/xxxxxxxx)
  3. Replace https://formspree.io/f/YOUR_FORM_ID in both contact.html and index.html with that real URL
  4. Done β€” submissions will land in your Formspree inbox (and forward to your email) immediately

Any other form backend that accepts a standard multipart/form-data POST and returns a 2xx status works exactly the same way β€” Netlify Forms, Getform, EmailJS with a small adapter, or your own serverless function.


🌐 Browser Support

Tested against current Chrome, Firefox, Safari, and Edge. Uses:

  • CSS custom properties, clamp(), CSS Grid, backdrop-filter (with -webkit- prefix for Safari)
  • IntersectionObserver for scroll reveal
  • fetch() for form submission

No transpilation or polyfills β€” all of the above have been baseline browser features since 2020 or earlier.


🧹 Code Quality

  • Zero inline style= attributes anywhere in the project. The one place that used to need them β€” six safety-rating bars on the Travel Guide page, each with a different fill percentage β€” now use plain utility classes (.pct-55 through .pct-88) defined in travel-guide.css instead.
  • .hintrc configures webhint (the linter behind the "Microsoft Edge Tools" VS Code extension) with a real target browser list and two intentional exceptions: theme-color and min-height: auto are both progressive enhancements that fail gracefully in browsers that don't support them, so they're excluded rather than removed. Everything else webhint flags is worth a look if you see it.

πŸ–₯️ Getting Started

Option A β€” Direct download

  1. Click the green Code button on GitHub β†’ Download ZIP
  2. Extract it
  3. Double-click index.html to open it in your browser
  4. Navigate using the top nav bar β€” every page works from file:// with no server needed, since all asset paths are relative

Option B β€” Clone with Git

git clone https://github.com/ahmedabbas52233-a11y/Uncharted-Travels.git
cd Uncharted-Travels

Then open index.html directly, or serve it locally:

# Python (built in on most systems)
python3 -m http.server 8000

# Node
npx serve .

# VS Code β€” install the "Live Server" extension,
# right-click index.html β†’ "Open with Live Server"

🚒 Deployment

This is a static site β€” any static host works with zero configuration.

Netlify (fastest):

  1. Go to app.netlify.com/drop
  2. Drag the whole project folder onto the page
  3. Live in about 30 seconds, with a real URL

GitHub Pages:

  1. Repo Settings β†’ Pages β†’ Source: main branch, / (root)
  2. Save β€” live at https://ahmedabbas52233-a11y.github.io/Uncharted-Travels/ a minute or two later

Vercel: npx vercel from the project folder, follow the prompts.

After deploying anywhere, come back and:

  • Update the og:url and <link rel="canonical"> values in all 8 HTML files to your real domain
  • Replace the placeholder domain in sitemap.xml
  • Swap in a real Formspree endpoint (see above) if you want the forms to actually work

πŸ—ΊοΈ Pages at a Glance

Page Purpose
index.html Landing page β€” hero, five-region overview, featured sites, historical timeline, testimonials, newsletter signup
about.html Company story, team (with real photos), milestones, values, awards
destinations.html Full destination grid sorted by province β€” 30+ locations across 5 regions
historical-sites.html In-depth coverage of Taxila, Lahore Fort, Takht-i-Bahi, Mohenjo-daro, plus a full UNESCO sites reference table
cultural-insights.html Gandhara art, Mughal architecture, Sufism, Kalash culture, regional festivals, cuisine, languages
travel-guide.html Visa info, safety by region, transport options, budget tiers, packing lists, sample itineraries
contact.html Multi-step booking inquiry form, FAQ accordion, emergency contact, office hours
404.html Custom not-found page matching the site's design system

πŸ“„ License

MIT β€” see LICENSE.


πŸ‘€ Author

Ahmad Abbas Hussain GitHub Β· LinkedIn

About

A fully responsive, 7-page static travel platform exploring Pakistan's UNESCO heritage, regional destinations, living cultures, and travel logistics. Renovated from a Taxila-specialized portal into a comprehensive Pakistan tourism experience. Built with pure HTML5, CSS3, and vanilla JavaScript, zero frameworks.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages