Next.js (App Router) site for Yesterday Vintage.
- Next.js (App Router)
- React (JSX)
- SCSS Modules + Global SCSS (tokens + fonts + mixins)
- Fonts: Alte Haas Grotesk (body, local, freeware) and Inclusive Sans
(display, via
next/font/google, OFL)
Pages: Home, About, Events, FAQ. Content for events, FAQ and the social
images comes from the headless CMS at NEXT_PUBLIC_CMS_BASE_URL; every fetch
has a hardcoded fallback so the site still renders if the CMS is down.
npm installnpm run devhttp://localhost:3000IMPORTANT: Use rem for better accessibility and responsive design
All global design tokens live in:
app/_globals/globals.scss(colors + fonts + base styles)app/_globals/mixins.scss(shared SCSS mixins)
Global colors are stored as CSS variables in :root.
Use them in SCSS Modules like this:
.card {
background: var(--eggshell);
color: var(--black);
border: 1px solid var(--canvas);
}
.buttonPrimary {
background: var(--yv-red);
color: var(--white);
}Our shared SCSS mixins live in:
app/_globals/mixins.scss
In any *.module.scss file:
@use "mixins.scss";If you do not hav SASS includePaths set up, use a relative import instead
@use "../../_globals/mixins.scss";@use "mixins.scss";
.wrapper {
padding: 48px 24px;
@include mixins.tablet {
padding: 36px 20px;
}
@include mixins.phone {
padding: 28px 16px;
}
}Call it in your component
import styles from "./home.module.scss";
export default function Home() {
return <main className={styles.wrapper}>Hello</main>;
}Run npm run lint to ensure good code format!
Never commit a Figma SVG export of a photograph. Figma wraps the full
original raster in base64 inside the SVG, and because an SVG is opaque to
next/image it can be neither resized nor served responsively — every visitor
downloads every byte.
The site previously shipped 2736x4096 photos rendered at 280x380 this way. The
About page alone was ~136 MB per visit and the mobile home banner sent 12 MB to
phones. Converting them to sized WebP took public/ from 161 MB to 6 MB.
To add a photo:
- Export as JPEG or PNG at roughly 2x its largest render size
- Convert to WebP (
cwebp -q 82 in.jpg -o out.webp) - Put it in
public/images/, import it, and render withnext/image
- The answer to "What days of the week are you open?" tells people to check the Google Calendar on the Shops page. The calendar is on the Events page, and the shop no longer exists. Please reword.
- Event descriptions render at different weights because some are wrapped in
<strong>in the CMS rich-text editor and others are not. Clearing the bold on the "Day in Downtown" description will make the list consistent.
- The rewards signup form does not send email.
app/api/send-email/route.jsneedsSMTP_HOST,SMTP_PORT,SMTP_USERandSMTP_PASS; onlyNEXT_PUBLIC_CMS_BASE_URLandREVALIDATION_SECRETare configured. The form also ignores the response, so it clears and looks successful either way — seehandleSubmitin the nav bar and the footer.REVALIDATION_SECRETis now unused and can be removed. - The signup form is duplicated verbatim between
_components/nav-bar/page.jsxand_components/footer/page.jsx. Worth extracting before changing either. - The nav logo is a ~99 KB base64 PNG inlined in an SVG
(
_components/nav-bar/page.jsx), shipped in the client bundle on every page.public/images/logo.svgalready exists as a replacement. - Git history still contains the old 136 MB of image blobs, so a fresh clone is large even though the working tree is not. Rewriting history to fix that is destructive and was deliberately left alone.
Every CMS fetch uses cache: "no-store", so published changes appear on the
next page load with no cache to clear and no webhook to configure. The old
/api/send-email/revalidate endpoint was removed along with the shop pages that
used it — if the CMS still has a webhook pointing at that URL, remove it.