Fully static Persian e-commerce front end with no backend or database; all data is handled client-side
TakMarket-public — Vite Ecommerce Template
By lavaoverjava
A fully static Persian electronics store template built with Vite + React, including product browsing, filtering, cart, and wishlist, with all data handled client-side and no backend.
Explore the design
Compare the page layouts and mobile experience. Open any screenshot for a closer look.
Actual screenshot captured by the server browser.
All pages & views 3
Screenshots show visual appearance; interactive behavior may differ.
What stands out
A quick read of the recorded project description.
Includes 33 products and 8 categories, with full-text search, multi-criteria filtering, sorting, and pagination
Cart and wishlist persist via localStorage and remain after refresh
Right-to-left layout using CSS logical properties and Persian number formatting, with self-hosted Vazirmatn font
Generates separate HTML files for 44 indexable routes at build time, each with its own metadata and JSON-LD
Includes a demo support chat window using keyword-matched preset replies and clearly stating that no one is online
Template Details
TakMarket-public is a front-end template for a Persian (right-to-left layout) electronics store, built with Vite and React and published as a purely static site. It includes 33 products and 8 categories, and supports full-text search, brand/price/stock/discount/rating filters, sorting, and pagination, all performed in the browser against static JSON data without calling any API. The cart and wishlist are persisted in localStorage via Zustand's persist middleware and remain after page refresh.
At build time, the template generates separate HTML files for 44 indexable routes, each with its own title, description, canonical tag, social tags, and JSON-LD structured data, along with a sitemap.xml and social share cards. Because there is no backend, the login, registration, order, and subscription forms have complete interfaces and validation, but on submission they only display a notice stating that the current build has no backend and do not fake a success state. The admin panel has been completely removed.
The template uses TypeScript strict mode, Tailwind CSS, and Zod form validation, and includes accessibility support (skip links, focus management, reduced motion preference, etc.). The demo support chat window uses keyword-matched preset replies and clearly states that no one is online.
Is it right for your project?
Use Cases
- As a reference project for learning the structure of a Vite + React static e-commerce front end
- For demonstrating how to implement product browsing, filtering, and cart functionality without a backend
- As a starting template for a Persian or right-to-left e-commerce interface
- For testing static site deployment and prerendering on GitHub Pages
Suitable For
- Developers who want to study pure front-end e-commerce implementations
- Front-end developers who need a Persian RTL e-commerce interface template
- Individuals or teams planning to host a static demo store on GitHub Pages
Getting started & customization
Use these recorded setup notes alongside the repository instructions for your chosen version.
- 1
Run npm install to install dependencies, then npm run dev to start the development server (default port 3000)
- 2
Run npm run build to generate the static site into the dist/ directory; npm start previews the build locally
- 3
To add or edit products, modify src/data/products.json and place WebP images in public/, then run npm run build:images to generate thumbnails
- 4
summaries.json and sitemap.xml are generated automatically by scripts and should not be edited manually
- 5
Login, registration, order, and subscription features have no backend support in this static build; submissions only display a notice
License & source material
Usage conditions & limitations
Free to use · keep license noticeThis entry covers the free version under the MIT license in the public repository; the free scope is the code of that version and does not mean external services or third-party assets are free.
Must comply with when using
- You may use, modify, commercialize, and distribute the code of this version for free.
- When distributing copies or substantial portions of the code, retain the original author's copyright notice and the full MIT license notice.
- The code is provided as is; warranties and limitations of liability are governed by the original license and applicable law.
Additional costs & items to verify
- The phone, email, and address in the template are placeholders and must be replaced before use for a real store.
- The login and registration pages only have interfaces and validation; the static build has no backend, so submissions only display a notice and do not actually log in.
- The checkout order form cannot actually submit an order; the static build has no backend, so submissions only display a notice.
- The subscription form has no backend support; submissions only display a notice and do not actually subscribe.
- The admin panel has been completely removed; the template does not include any admin functionality.
- On GitHub Pages, real HTTP security response headers cannot be set; if protection against clickjacking, etc. is needed, use a hosting service that supports custom headers.
- This project is a derivative work of another open-source template; the MIT license requires retaining the original author Aleksandar Kuzmanović's copyright notice.
- Demo images, fonts, icons, and other third-party assets must be checked against their respective licenses; they cannot be judged solely by the code's MIT license.
- External services such as domain, hosting, database, payment, or AI may incur additional charges.
View Original Text Basis
Permission is hereby granted, free of charge
Original License Text
The phone, email and address are deliberate placeholders — replace them before using this for a real shop.
Original README
Login and register (`/login`, `/register`)
Original README
Placing an order (`/checkout`)
Original README
Newsletter signup
Original README
The admin dashboard was dropped entirely
Original README
Real HTTP security headers (`X-Frame-Options`, or `frame-ancestors` against clickjacking) can't be set on GitHub Pages
Original README
https://github.com/lavaoverjava/TakMarket-public/blob/main/LICENSEhttps://github.com/lavaoverjava/TakMarket-public/blob/main/README.mdThis started life as a fork of an open-source storefront template by Aleksandar Kuzmanović; that copyright line stays in `LICENSE`
Original README
Compiled by DeepSeek based on repository license and README ·2026-10-01. Results only cover the materials read; dependencies, images, fonts, and subsequent term changes are subject to their respective original texts.
Project checks & description sources
Template Information
- Source platforms
- GitHub
- Documentation and maintenance reference score
- More documented · 85 / 100
- Technologies
- Vite · React
- Website type
- E-commerce
How this score is calculated
Our heuristic uses license records (up to 30), a demo link (12), a preview (10), stars (15), recorded maintenance (15), description completeness (8), feature records (5) and classification data (5). It is not a code, security or performance test, or a Google score. A link does not establish tested functionality.
What to verify for this project
- Repository update recorded
- 2026-08-14
- Screenshot last checked
- 2026-10-01
A demo link is listed. Check it with your own content and viewport sizes; its presence does not confirm that forms, authentication or payments work.
The catalog identifies Vite as the primary stack. Check the actual dependency manifest and lockfile for versions and hosting requirements. These notes use recorded metadata, not a code audit or a deployment test.
Use a selection guide →How this description was prepared
AI-assisted description based on catalog records and repository material. Repository authors are not automatically the reviewers of this description.
Automatically checked against source and license rules; no manual editorial review.
Inspect the recorded source material
SHA-256: 11d17de444e0c7f47dcbe75597dddc88d22044654ef5792ac1dbfe35cbbd7595
2026-10-01T01:31:00.669Z
Source file / repository<div align="center">
<img src="public/apple-touch-icon.png" alt="TakMarket" width="120" height="120">
# 🛒 تکمارکت — TakMarket
**A fully static, right-to-left Persian electronics storefront, built with Vite + React and served from GitHub Pages.**
33 products · 8 categories · client-side search, filters and cart · no backend, no database, no tracking.
[**🛍️ Open the store**](https://lavaoverjava.github.io/TakMarket-public/) · [🐛 Report a bug](https://github.com/lavaoverjava/TakMarket-public/issues)
</div>
---
## 📑 Contents
- [✨ Features](#-features)
- [⚠️ What "no backend" means here](#️-what-no-backend-means-here)
- [🛠️ Tech stack](#️-tech-stack)
- [🚀 Installation and usage](#-installation-and-usage)
- [📂 Code structure](#-code-structure)
- [🖼️ Adding or editing products](#️-adding-or-editing-products)
- [⚡ Performance notes](#-performance-notes)
- [🛡️ Security notes](#️-security-notes)
- [🎨 Customization](#-customization)
- [📄 License](#-license)
---
## ✨ Features
**🔎 A real catalogue, searched in the browser.** 33 products across 8
categories, with full-text search, brand/price/stock/discount/rating filters,
sorting and pagination — all running on static JSON, no API call anywhere.
Every one of those choices lives in the query string, so a filtered view is a
URL you can bookmark, share, refresh, or step back out of.
**🧭 Right-to-left by design.** Persian throughout, laid out with CSS logical
properties (`start`/`end`, not `left`/`right`), Persian digit formatting for
every price and count, and the self-hosted **Vazirmatn** typeface.
**🛒 A cart and wishlist that survive a refresh.** Both live in `localStorage`
via Zustand's `persist`, and both treat what they read back as untrusted input
— corrupt or hand-edited entries are dropped or clamped rather than rendered.
**📱 Responsive from 320px up.** Mobile-first layout, a slide-in menu, a
scrollable category rail, and no horizontal overflow at any breakpoint.
**💬 Demo support chat.** A floating widget with a typing indicator and
keyword-matched canned replies. It says up front that nobody is on the other
end — see `src/lib/chatReplies.ts`.
**♿ Accessible.** Skip-to-content link, one `<h1>` per page, labelled form
fields and icon buttons, visible `:focus-visible` rings, drawers that really
trap focus instead of only claiming `aria-modal`, and a
`prefers-reduced-motion` block that turns the animations off.
**🔒 Hardened by default.** A restrictive `Content-Security-Policy` meta tag
ships in `<head>` — and the published build drops `'unsafe-inline'` from
`script-src` entirely. Forms are validated with Zod, and no component anywhere
uses `dangerouslySetInnerHTML`.
**🔗 Every URL is a real page.** All 44 indexable routes are written out as
their own HTML file at build time, each with its own title, description,
canonical tag, social tags and JSON-LD (`Product`, `BreadcrumbList`,
`Organization`), plus a matching `sitemap.xml` and a 1200×630 social card
drawn from the site's own logo and typeface.
---
## ⚠️ What "no backend" means here
GitHub Pages serves static files only — no Node process, no database. The
original project had an Express + MySQL backend; this build does not, and it
never pretends otherwise.
### Works completely ✅
| Area | Notes |
| --- | --- |
| Browsing and search | Runs on static JSON, in the browser |
| Filtering and sorting | Brand, max price, in-stock, discounted, rating |
| Pagination | Fully client-side |
| Product detail pages | Image gallery, spec table, related products |
| Cart | Saved in the visitor's `localStorage` |
| Wishlist | Saved in the visitor's `localStorage` |
### Deliberately doesn't ❌
These forms have complete UIs and real validation, but on submit they show a
plain notice that this build has no backend, instead of faking success:
- Login and register (`/login`, `/register`)
- Placing an order (`/checkout`)
- Newsletter signup
The admin dashboard was dropped entirely — without a server there is nothing
for it to administer. **No visitor data is ever sent anywhere.**
---
## 🛠️ Tech stack
- **Vite 8** — bundler and dev server.
- **React 18** + **React Router 7** for client-side routing.
- **TypeScript**, strict mode.
- **Tailwind CSS 3** with custom design tokens (`tailwind.config.ts`).
- **Zustand** for cart and wishlist state, persisted to `localStorage`.
- **Zod** for form validation.
- **Vazirmatn** via `@fontsource-variable/vazirmatn` — self-hosted, so no
request ever leaves for Google's servers.
- **sharp**, **opentype.js** and **resvg** in build scripts only, for
thumbnails, the favicon and the social card.
### Why Vite and not Next.js?
Earlier versions of this project were built with Next.js (App Router). Since
the site has no backend and is published statically to GitHub Pages, the
server-side half of Next.js — SSR, API routes, runtime image optimisation —
was never being used. Vite produces the same final artifact with a simpler
config and a much faster build.
**What that gave up, and how it's paid back:** Next.js pre-rendered every page
at build time, so each product had its own HTML file. A plain Vite SPA has
one `index.html` and lets React Router sort out the rest — which means every
URL but the home page was served through the 404 fallback, answering with an
HTTP 404 and the site-wide title. [`scripts/prerender.mjs`](scripts/prerender.mjs)
puts that back: after the bundle is built it writes a real
`dist/<route>/index.html` for all 44 indexable URLs, each carrying its own
head. The body is still filled in by React — this is metadata prerendering,
not server rendering — but the pages now return 200 with their own titles,
which is what indexing and link previews depend on.
---
## 🚀 Installation and usage
```bash
npm install
npm run dev
```
Then open <http://localhost:3000>.
### Building
```bash
npm run build
```
The static site lands in `dist/`. To preview exactly what will be published:
```bash
npm start
```
### Scripts
| Command | What it does |
| --- | --- |
| `npm run dev` | Regenerates assets, then starts Vite on port 3000 |
| `npm run build` | Regenerates assets, typechecks, builds into `dist/`, prerenders every route |
| `npm start` | Serves the built `dist/` locally |
| `npm run lint` | ESLint, including the a11y rules |
| `npm run typecheck` | `tsc --noEmit` |
| `npm run build:images` | Rebuilds the 400px `*-thumb.webp` product thumbnails |
| `npm run build:data` | Rebuilds `src/data/summaries.json` from `products.json` |
| `npm run build:sitemap` | Rebuilds `public/sitemap.xml` |
| `npm run build:favicon` | Redraws `favicon.svg`, `favicon.ico`, `apple-touch-icon.png` |
| `npm run build:og` | Redraws `public/og-image.png`, the 1200×630 social card |
| `npm run build:hero` | Recomposes `public/hero.webp` from the featured product photos |
> The image, data and sitemap steps run automatically before `dev` and
> `build`. `summaries.json` and `sitemap.xml` are generated — don't hand-edit
> them. The favicon, social card and hero are design assets: they are
> committed, and only rebuilt when you change the brand or the products they
> feature.
---
## 📂 Code structure
```
index.html Vite entry point; site-wide <head> tags live here
vite.config.ts Base path, aliases, and the Pages output files
scripts/
build-thumbnails.mjs 400px WebP thumbnails for catalogue images
build-summaries.mjs Generates the light product records
build-sitemap.mjs Generates public/sitemap.xml
prerender.mjs Writes one HTML file per indexable route
build-favicon.mjs Draws the icons from the font's own "ت" glyph
build-og-image.mjs Draws the 1200×630 social card
build-hero.mjs Composes the home page's hero image
lib/routes.mjs The indexable routes + their metadata and JSON-LD
lib/woff.mjs Unpacks a WOFF to a TTF the drawing tools can read
src/
main.tsx Root render + BrowserRouter
App.tsx Layout shell and route table
routes/ One component per page
components/
Link.tsx Router link with a next/link-shaped API
PageMeta.tsx Per-route title, description, canonical, og:url
ErrorBoundary.tsx App-wide error boundary
layout/ home/ product/ shop/ cart/ checkout/ auth/ ui/
hooks/
useRouter.ts Small navigation helper
useHydrated.ts True once localStorage state has loaded
store/ Zustand cart and wishlist stores
data/
products.json Full catalogue
summaries.json Generated light records for cards
categories.json Categories
lib/
products.ts Reads over the full record (product page only)
summaries.ts Filter, sort and search over light records
format.ts Persian number, price and date formatting
validation.ts Zod schemas
email.ts The email rule, dependency-free (see below)
chatReplies.ts Canned support-chat replies
site.ts Site name, URL, repo, and the demo notice
```
### Why two data files?
| File | Contents | Used by |
| --- | --- | --- |
| `products.json` | Full records, including descriptions and spec tables | `lib/products.ts` only (product detail page) |
| `summaries.json` | Just the fields a product card needs | Everything else — listings, filters, search, cart |
Descriptions and spec tables are roughly **70%** of the catalogue's bytes and
never appear in a listing. If a component used on a listing imported
`lib/products.ts`, all of that would land in that route's bundle — so those
components always use `lib/summaries.ts`.
---
## 🖼️ Adding or editing products
1. Add the record to [`src/data/products.json`](src/data/products.json).
2. Drop the images into `public/` as **WebP**.
3. Run `npm run build:images` to generate the 400px thumbnails.
`summaries.json` and `sitemap.xml` regenerate on the next `dev` or `build`.
---
## ⚡ Performance notes
- **Route-level code splitting.** Every route except the home page is behind
`React.lazy`, so a visitor who never leaves the landing page never downloads
the checkout schemas or the product gallery. The home page is eager on
purpose — splitting it would only add a request that every first visit needs.
- **Zod is not in the first download.** It used to be, because the footer's
newsletter box imported the shared schemas and the footer is on every page —
14 KB gzipped to validate one text field. That form now uses
`src/lib/email.ts`, which `validation.ts` also builds its email schema on, so
the rule stays in one place and Zod loads only with the forms that need it.
- **Two sizes per image.** Cards render at roughly 180–280 CSS px, so
`build-thumbnails.mjs` emits a 400px WebP next to each full-size image; the
large file is only fetched on a product page.
- **A hero built at the size it renders.** `hero.webp` is composed at
1160×870, exactly twice its layout box, so it is sharp on a 2× screen and
never upscaled or cropped on a 1× one.
- **Lazy images below the fold.** Everything except the hero is
`loading="lazy"`, and every image sits in a fixed-aspect-ratio box, so
loading one never shifts the layout.
- **Self-hosted fonts, subset by script.** The Arabic and Latin subsets load
separately, so a page with no Latin text doesn't pay for Latin glyphs.
A cold load of the home page is about **165 KB** over 22 requests: one ~89 KB
gzipped JS bundle, 8 KB of CSS, the two font subsets, and the hero image.
---
## 🛡️ Security notes
The published output is entirely static, so the whole server-side class of
vulnerabilities — SQL injection, auth bypass, file upload — cannot exist here;
there is no server-side code to attack. What is in place:
- **Content-Security-Policy** as a `<meta>` tag, with `object-src 'none'`,
`base-uri 'self'`, `form-action 'none'`, `worker-src 'none'` and
`frame-src 'none'`. The published build goes further than the source: the
file in the repo allows inline script because Vite's dev server injects its
HMR client that way, and `cspForProduction()` in `vite.config.ts` strips
`'unsafe-inline'` out of `script-src` when it writes `dist/index.html` —
the production bundle has no inline script to allow.
- **No `dangerouslySetInnerHTML` anywhere** — every string goes through
React's escaping.
- **`localStorage` is treated as untrusted.** It is fully user-writable, so
every persisted cart and wishlist line is re-validated on load: negative
prices and quantities, non-numeric values, duplicate ids and image paths
that are not really paths (`javascript:`, `//another-host/x.png`, `..`) are
dropped or clamped.
- **The query string is treated the same way.** The shop reads its filters,
sort and page number out of the URL, so every one of them is validated
against the real brands, sort keys and ratings before it is used.
- **Zod validation on every form**, with `rel="noopener noreferrer"` on every
external link.
- **No secrets in the repository** — the project has no secret to keep.
- **`npm audit` reports 0 vulnerabilities.**
### Known limitation
Real HTTP security headers (`X-Frame-Options`, or `frame-ancestors` against
clickjacking) can't be set on GitHub Pages: the service doesn't allow custom
response headers, and browsers ignore `frame-ancestors` when it arrives via
`<meta>`. Hosting that supports headers — Netlify, Vercel, Cloudflare Pages —
is the fix if those matter.
> Client-side validation is not a security boundary. Here it exists purely to
> give the visitor honest feedback, because there is no server that could be
> tricked into trusting the input.
---
## 🎨 Customization
**Colours, spacing and shadows** are design tokens in
[`tailwind.config.ts`](tailwind.config.ts). The brand ramp drives the header,
buttons, links and the generated icons:
```ts
brand: {
50: "#eef4ff",
600: "#1d45f5", // primary actions, logo badge, favicon
700: "#1633e1", // hover state
// ...
}
```
After changing `brand-600`, rerun `npm run build:favicon`,
`npm run build:og` and `npm run build:hero` so the icons, the social card and
the hero all match.
**Store name, tagline, URL and contact details** live in
[`src/lib/site.ts`](src/lib/site.ts). The phone, email and address are
deliberate placeholders — replace them before using this for a real shop.
`site.url` is read by the app, the sitemap and the prerenderer alike.
Publishing under a different path or domain takes two edits: `PROJECT_BASE`
in [`vite.config.ts`](vite.config.ts) (or `VITE_BASE_PATH` at build time) for
the URL prefix, and `site.url` above for the canonical/OG/sitemap URLs. A
custom domain served from the root wants the base set to `/`.
---
## 📄 License
Released under the [MIT License](LICENSE). This started life as a fork of an
open-source storefront template by Aleksandar Kuzmanović; that copyright line
stays in `LICENSE` alongside the one for this rewrite.
Explore similar templates
Compare previews and descriptions within the same stack and category.

free.website.templates
A free open-source web template collection maintained by Vontext, built on Vite, React, TypeScript, and TailwindCSS. It currently offers 8 independent landing page templates covering SaaS, AI, blogs, design tools, and more, each installable and runnable separately.
Vite · Admin dashboard

alexkpotstore
A React and Vite e-commerce front-end learning project that presents 3D prints, Notion templates, VS Code themes, and wallpapers in a responsive homepage grid, with React Router layout routes, SCSS theming, and Firebase Google sign-in plus Firestore user documents.
Vite · E-commerce

templatevibecode
A free, MIT-licensed collection of four independent React website templates under apps/: a SaaS landing page, a beauty storefront, a fashion editorial page, and an interior design company profile.
Vite · E-commerce

webspatial-shop
WebSpatial Shop is a Vite and React e-commerce storefront starter that shows a product catalog with responsive browsing, category filtering, product cards, and detail routes.
Vite · E-commerce

Next.js Commerce
Vercel's officially maintained Next.js App Router ecommerce starter with deep Shopify integration, offering a complete product catalog, cart, and checkout flow. Core logic is modular for swapping backends, and community provider versions exist for BigCommerce, Medusa, and Saleor.
Next.js · E-commerce

astro-ecommerce
Astro Ecommerce is a Creative Tim e-commerce Astro starter template under the MIT license, with 70+ coded elements, 30+ blocks, and landing, product, and shopping cart example pages.
Astro · E-commerce
