Demo project
Notion templates store: TemplateForge
A digital goods catalog, Zustand cart, fully static export.
development · Next.js 15 · TypeScript · Tailwind · Zustand

The task
TemplateForge is a digital goods store: one maker sells 10 Notion templates in four categories, from a $9 habit tracker to a $49 product launch kit. The product is delivered as an email link - no warehouse, no shipping, and no real need for a server. The storefront, product pages and cart should work as static files and cost nothing to host. The buyer’s path is still complete: category filter, a product page with contents and reviews, cart, checkout. A demo project: the company is fictional, the brief is real.
The solution
Dark tech minimalism for an audience that lives in Notion: a near-black background, one violet accent, monospaced prices and labels. A digital product cannot be photographed, so each template is shown through screenshots framed in a browser window - three per product, with a video in the first slot for the bestseller.
- Next.js 15 with static export: 10 product pages are generated from a single data file; the build deploys to any static host, with zero server code.
- The catalog filters on the client, and every category shows a count: All 10, Productivity 3, Finance 2, Business 3, Students 2 - the numbers add up.
- Product page: a gallery, “What’s inside” and “Reviews” tabs, and a related block - own category first, topped up from neighboring categories, always exactly three items.
- The cart is Zustand with persist in localStorage. Digital goods have no quantities: one purchase is one line, and a second click honestly answers “Already in cart” instead of adding a duplicate.
- Checkout asks for a name and an email; the phone is optional. The receipt and the product go to the inbox - extra fields only hurt conversion.
- The cart clears on the thank-you page via a one-time flag, not on submit: a direct visit to /thanks never wipes someone’s cart.
Details that are easy to miss
- Static export hydration done carefully: the cart counter and the phone mask compute after mount, otherwise the prerendered HTML would disagree with localStorage and the browser locale. The console is free of hydration errors - verified in the test report.
- The phone mask follows the browser language: a +7 format for Russian-speaking visitors, +1 for everyone else. The privacy consent is a required checkbox with a clear error message.
- Accessibility: tabs are marked up as tablist/tab/tabpanel, the FAQ uses aria-expanded, the video has a pause button with an aria-label, and autoplay stops under prefers-reduced-motion.
- Demo hygiene: a disclaimer page, a seller labeled as a demo entity, a contact address on the reserved .demo domain, noindex in the metadata and in the X-Robots-Tag header - the demo never competes with real stores in search.
- Interface states beyond the happy path are designed, not skipped: an empty cart with a link back to the catalog, an invalid email, an unchecked consent box - each has its own copy.
The numbers
The finished site has 17 pages: a storefront with a 4-category filter, 10 product pages, a cart, checkout and utility pages. Every template gets 3 screenshots, the bestseller gets a video. There is no server code: the store runs as pure static files and deploys to any free static hosting.
Screenshots




