seahaven-site/README.md
Adam Moussa 5ee640074c
Migrate to thin Eleventy build + a11y/SEO/perf/CI hardening (#20)
* chore(build): add Eleventy scaffold

Thin Eleventy build (v3.1.6, pinned) — passthrough-copies assets/,
robots.txt, sitemap.xml; outputs flat HTML to _site/. _data/site.json
holds site-wide constants; _data/images.json maps image keys to
src+width+height for the {% image %} shortcode (CLS fix). Output stays
flat HTML served from the same S3 bucket + CloudFront.

* refactor(templates): base layout, partials, shared JS, CSS extraction

- _includes/base.njk + nav/mobile-menu/footer partials reproduce the
  shared chrome once (was hand-duplicated across 13 pages). Adds a
  skip-link and <main> landmark (WCAG 2.4.1), aria-expanded/role=dialog
  hooks on the menu, and a {% year %} shortcode replacing document.write.
- assets/js/nav.js: extracted sticky-nav + accessible mobile-menu dialog
  (focus trap, Escape, focus return) + rAF-throttled hero parallax.
- assets/js/form.js: Basin AJAX submit with an accessible status region.
- assets/css/*.css: per-page inline <style> extracted into page CSS files
  (home/about/services/careers/jobs/contact/social/legal/404); skip-link
  + :focus-visible added to main.css.
- index.njk: homepage converted as the reference page.

* fix(css): make hero-bg url root-relative after extraction

Inline CSS used a document-relative url('assets/...') that resolves
correctly from / but breaks once moved into /assets/css/home.css.
Rewrite to /assets/images/.

* refactor(pages): convert 12 pages to Eleventy templates

Convert about, services, careers (listing + 3 jobs), contact, social-
accountability, privacy-policy, terms-of-service, eula, and 404 from
standalone HTML to .njk against base.njk. Each page now carries only
front-matter (title/description/SEO) + its <main> content; shared head/
nav/footer/scripts come from the layout. JobPosting + LocalBusiness
JSON-LD preserved. Images use the {% image %} shortcode (width/height).
Contact gets an accessible #form-status region. form.js generalized to
wire BOTH the contact form and the .apply-form job application forms
(was contact-only), preserving each submit button's own label.

* fix(a11y): footer contrast to WCAG AA + scope services .form-group

Raise footer text colors (footer-bottom/col/brand/social/contact) and
darken --text-muted so muted text clears 4.5:1 on the dark footer and
warm-gray surfaces. Scope services' flex .form-group override to
.contact-form .form-group so it can't leak to the global rule.

* perf(seo): og-cover image, webp logos, hero preload

Add a real 1200x630 og-cover.jpg (was a 153x49 favicon) wired site-wide
via base.njk og:image/twitter:image. Convert nav/footer logos to webp
(nav 58KB->22KB); PNGs kept as passthrough so old URLs still resolve.
Preload the LCP hero image on the homepage (fetchpriority=high). All
<img> carry width/height via the image shortcode (CLS).

* ci(deploy): build-then-sync, cache headers, safe concurrency

Rename main.yml -> deploy.yaml (org convention). Build with Eleventy
(npm ci && npm run build) and sync _site/ instead of the repo root, so
only built output ships (no source/templates/node_modules). Split
Cache-Control (1-day assets, no-cache HTML) and keep /* invalidation
since filenames are not yet fingerprinted. concurrency cancel-in-progress
false so a deploy is never cut mid sync. ci.yaml validates _site/ via
ci-static build mode.

* docs: README for the Eleventy build and structure

* fix(security): wire services form, guard build, harden deploy

Fable build-review findings:
- BLOCK: services puts .contact-form on the <form> itself (contact uses a
  wrapper div), so form.js selector '.contact-form form' never matched it
  — the services lead form submitted natively with an empty reCAPTCHA
  token. Selector now also matches form.contact-form.
- Guard the build before the --delete S3 sync: require index/contact/404
  and >=40 files, so a silently-empty build can never wipe the live bucket.
- npm ci --ignore-scripts on deploy (build verified to pass) to shrink the
  supply-chain window on the OIDC-credentialed runner.
- Escape quotes in the image shortcode alt text.
2026-06-12 17:02:06 -04:00

67 lines
No EOL
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Main Website for Sea Haven Industries
![HTML](https://img.shields.io/badge/HTML-E34F26?logo=html5&logoColor=white)
![Eleventy](https://img.shields.io/badge/Eleventy-000?logo=eleventy&logoColor=white)
![JavaScript](https://img.shields.io/badge/JavaScript-F7DF1E?logo=javascript&logoColor=black)
![Deploy](https://github.com/Sea-Haven-Industries/seahaven-site/actions/workflows/deploy.yaml/badge.svg)
A clean static website for Sea Haven Industries — authored as [Eleventy](https://www.11ty.dev/) templates that build to flat HTML, served from an AWS S3 bucket via CloudFront.
## Stack
- **Eleventy (11ty)** — thin static build: one base layout + partials, no client framework. Output is plain HTML/CSS/vanilla JS.
- **Design system** — CSS custom properties (DM Serif Display + Inter, `--rose: #cc3366`)
- **Forms** — Basin (AJAX submission, reCAPTCHA v3, honeypot spam protection)
- **Hosting** — S3 + CloudFront, deployed via GitHub Actions OIDC (`npm run build` → sync `_site/`)
## Develop
```bash
npm ci # install (Eleventy, pinned)
npm run serve # local dev server with live reload
npm run build # build to _site/
```
## Structure
| Path | Purpose |
|------|---------|
| `*.njk`, `*/index.njk` | page templates (front-matter + `<main>` content) |
| `_includes/base.njk` | document layout (head, nav, footer, skip-link, `<main>`) |
| `_includes/{nav,mobile-menu,footer}.njk` | shared chrome partials |
| `_data/site.json` | site-wide constants (nav, contact, social) |
| `_data/images.json` | image dimensions for the `{% image %}` shortcode (CLS) |
| `assets/css/` | `main.css` (shared) + per-page CSS |
| `assets/js/` | `nav.js` (chrome), `form.js` (Basin forms) |
| `.eleventy.js` | build config + shortcodes |
| `_site/` | build output (gitignored; what deploys) |
## Pages
| Page | Path |
|------|------|
| Homepage | `/` |
| About | `/about/` |
| Services | `/services/` |
| Careers | `/careers/` |
| Contact | `/contact/` |
| Social Accountability | `/social-accountability/` |
| Privacy Policy | `/privacy-policy/` |
| Terms of Service | `/terms-of-service/` |
| Job: Dispatcher | `/careers/dispatcher/` |
| Job: Scheduling Coordinator | `/careers/scheduling-coordinator/` |
| Job: Traveling Maintenance/Electrical Assistant | `/careers/traveling-maintenance-assistant/` |
## Changelog
* 12-JUN-2026: Migrated to a thin Eleventy build — shared chrome (head/nav/footer/JS) deduplicated into one base layout + partials (was hand-copied across 13 pages). Added skip-link + `<main>` landmark, accessible mobile-menu dialog, `:focus-visible`, WCAG AA footer contrast, 1200×630 `og-cover` social image, hero LCP preload, WebP logos, image `width`/`height` (CLS), and pre-deploy CI validation (htmlhint/JSON-LD/sitemap/links). Deploy now builds and syncs `_site/` with split Cache-Control.
* 14-JUL-2025: Initial pull from WordPress site, changed permalinks for proper navigation
* 17-JUL-2025: Add GitHub Actions workflow for S3 sync on push, using AWS OIDC
* 04-APR-2026: Major cleanup — stripped unused JS (~805KB), consolidated CSS, removed ~1,150 dead plugin files
* 04-APR-2026: Added meta descriptions, OG/Twitter Card tags, alt text, robots directives, sitemap, and robots.txt
* 04-APR-2026: Updated contact info sitewide, fixed broken links, removed WordPress API/generator meta tags
* 04-APR-2026: Wired contact form to Basin (AJAX), replaced dead metform endpoint
* 04-APR-2026: Converted all images to WebP, removed metform CSS, stripped WP version strings
* 07-APR-2026: Full site redesign — rewrote all 9 pages as clean static HTML, removed all WordPress/Elementor markup
* 07-APR-2026: New Figma-based homepage design with updated stats, logos, and layout
* 07-APR-2026: Connected all forms to Basin with AJAX submission, reCAPTCHA v3, and honeypot spam protection
* 07-APR-2026: Moved all images to `/assets/images/` with clean filenames, restored original blue wave favicon
* 07-APR-2026: Deleted all remaining WP assets (~8MB): plugins, themes, uploads, wp-includes
* 30-APR-2026: Restructured /career/ and /jobs/ into unified /careers/ directory, updated all sitewide links
* 30-APR-2026: Added traveling maintenance/electrical assistant job page, updated dispatcher and assistant postings to match Indeed listings
* 30-APR-2026: Replace hardcoded copyright year in footer with dynamic script across all pages