Commit graph

12 commits

Author SHA1 Message Date
semianiakavy 1a55b18744 fix: serve product images from the W4C asset share base 2026-10-05 23:01:11 +00:00
semianiakavy 4ab8249c6a fix: cache the bouquet gallery so the flower field stops re-downloading
The dev server stamped every static response `no-store`, images included.
The field paints 40 bouquets x up to 3 shots in three identical sets, and a
client-side render rebuilds the whole view through `innerHTML` — so every
`<img>` is a new element and, with nothing cacheable, the same ~120 photos
were fetched again on each render. That is what made the slides on
/variant-b look like they kept reloading (and why a hovered cell could fade
in from blank).

- dev-server: per-kind cache policy + weak ETag. `index.html` stays
  `no-store`; `app.js` / `styles.css` (already `?v=`-busted) revalidate and
  answer 304; the committed gallery is kept for a week.
- app.js: keep one decoded image per field URL in `ffImageCache`, warmed in
  small batches when /variant-b renders, so a rebuild of the view reuses the
  bitmap instead of flashing.
- app.js: the copy of each row that is on screen at t=0 loads eagerly (first
  set for left rows, middle set for right rows); the copies drifting in later
  stay lazy.
- index.html: asset buster ?v=22 -> ?v=23.
2026-10-05 19:28:58 +00:00
semianiakavy 0f88522cd2 feat: rebuild info pages from source content in the new design
Scrape the 9 source info pages (R10: URLs 1:1) plus an updated FAQ into
CONTENT_PAGES — the single source of truth for both the seed SQL and the
storefront server — and render them with a structured layout.

- src/db/seed.ts: CONTENT_PAGES now carries the real content in a small
  line-based markup (`##` sections, `###` sub-headings, `- ` lists, `> `
  lead/callout, inline `**bold**` and `[label](href)`).
- scripts/generate-seed-sql.ts: derive the content-page INSERT from
  CONTENT_PAGES instead of a duplicated literal; db/seed/*.sql regenerated.
- public/app.js: map the source routes (/company, /company/b2b,
  /company/politika-konfidentsialnosti, /dostavka, /dostavka/oplata,
  /dostavka/zakaz, /vozvrat, /contacts, /contacts/vakansii) and keep
  /pages/<slug> as aliases; parse + render the markup in pageView with
  breadcrumbs, an overline lead and a contact CTA.
- public/index.html, public/styles.css: footer link columns (Компания) and
  the info-page/CTA styles (section cards, lists, callouts, sticky desktop
  sidebar); menu-panel separator for the info links group.
- Cache-bust the static assets (styles v14, app v15).

Card: #66
2026-10-05 18:40:20 +00:00
semianiakavy 4090aac0c5 feat: real /favicon.ico and an un-stretched brand lockup
Favicon: mirror the source site's /favicon.ico — a 32×32 PNG payload under an
`.ico` name — into public/favicon.ico. scripts/fetch-favicon.ts keeps it in place
(`pnpm fetch:favicon`, or `pnpm fetch:brand` for wordmark + icon) and the dev
server calls it at boot; the file handler sniffs the PNG signature for `.ico` and
serves it as image/png, so the default /favicon.ico request — and the new
<link rel="icon"> — resolve to the brand rose.

Brand lockup: the tagline "Цветы подарки Минск" is now red, un-stretched text
under the wordmark in the header and inside the footer's white plate (it used to
be letter-spaced 8px caps, which read as squeezed). The wordmark itself is sized
on one axis only (height, width:auto, object-fit:contain) — the artwork is tightly
cropped, so a width and a height at once would stretch it. BRAND.tagline /
favicon* record both facts in src/store/constants.ts.
2026-10-05 17:53:49 +00:00
semianiakavy 55b4ebc9a1 feat: use the source wordmark as the store logo
Replace the text brand in the header and footer with the logo the source site
publishes for its footer (637x220 PNG, BRAND.logoSourceUrl):

- src/store/constants.ts: add BRAND (source URL, local path, dimensions).
- scripts/fetch-logo.ts: mirror it into public/images/brand/logo_footer.png
  (idempotent, --force to refresh); `pnpm fetch:logo` runs it standalone.
- scripts/dev-server.ts: ensure the logo at boot, non-fatal on failure.
- public/index.html: <img class="brand__logo"> in the header (the wordmark is
  dark on the light header) and <img class="footer__logo"> in the footer, on a
  white plate because the footer is dark.
- public/styles.css: logo sizing (30px / 40px from 768px) + the footer plate.
2026-10-05 17:39:30 +00:00
semianiakavy 0f7eac406d feat(home): add hero slider, surface catalog slider mode, drop photo-count claims
- Hero: three slides (copy + real bouquet photo + price tag) with arrows,
  dots, counter, autoplay, keyboard nav and touch swipe.
- Catalog: label the view toggle (Сетка/Список/Слайдер) so the
  one-bouquet-per-screen slider view is discoverable.
- Remove the "281 real photos" claim from the meta description, hero perks
  and trust strip; replace with "Фото перед вручением".
- Dev server: send Cache-Control: no-store for static assets and version the
  /app.js + /styles.css links so refreshes always pick up the latest build.
2026-10-05 17:01:06 +00:00
semianiakavy 93b927dfdc feat: implement La Rose storefront design (home, catalog, PDP)
Port the ready OpenPencil design (designs/design.fig) into the runnable
storefront (public/):

- design tokens + components (buttons, inputs, badges, chips, cards,
  skeletons, stepper, variants, pagination, states) from the canvas;
  Playfair Display + Inter, mobile-first at 390/1440.
- shell: topbar, header (nav, search, favourites, cart badge), mobile
  header, bottom nav, footer with real contacts and WhatsApp/Telegram.
- screens: Home (hero, trust, 11 categories, hits, delivery banner,
  info cards), Catalog (breadcrumbs, facets: price/categories/badges,
  sort, 6-per-page pagination, empty state), PDP (gallery + lightbox,
  variants 15/19/25, stepper, sticky buy, delivery block, tabs, specs,
  related).
- cart + single-page checkout + success built from the same tokens
  (not drawn on the canvas yet, flagged as follow-up).
- extend /api/catalog with category counts, variants, occasion, care,
  price range, badge counts and delivery constants; add /api/pages for
  info/FAQ content; export CONTENT_PAGES from the seed.

Money stays integer BYN minor units, formatted via Intl (en-US).
2026-10-05 16:33:55 +00:00
semianiakavy 32bb265252 feat(ui): basic storefront with catalog thumbnails and product gallery 2026-10-05 15:57:51 +00:00
semianiakavy 33ae6aec18 chore(scripts): generate + verify gallery seed artifacts; ci runs tsc/tsx directly (#64) 2026-10-05 15:34:42 +00:00
semianiakavy a8df0b9e1a feat(seed): fetch full product gallery originals from la-rose.by
Add scripts/fetch-images.ts: reads db/seed/catalog.tsv, parses each PDP's
.product_gallery-images-main anchors (href = full-size .900.jpg, order =
data-position + 1), downloads the originals as-is (I3) into
public/images/products/<slug>/<n>.jpg and writes db/seed/images.tsv
(slug, position, source_url, alt). Idempotent and never silent: it prints the
explicit list of products whose gallery failed to parse.

Artifacts: 93/93 products, 281 images, ~39 MiB, 0 failures (docs/PLAN.md §11).
2026-10-05 15:27:01 +00:00
semianiakavy 2cb49e91a3 fix(db): reproducible seed artifact via fixed bcrypt salt for demo accounts 2026-10-04 20:44:35 +00:00
semianiakavy 8c6236c8f1 feat(db): schema, migrations and idempotent seed for the catalog
Implement the data layer from docs/PLAN.md §4 (card #55):

- db/migrations/0001_init.sql: idempotent DDL for the 16 entities (category,
  product, product_category, product_image, product_variant, product_feature,
  cart, cart_item, customer, address, orders, order_item, payment, promo_code,
  content_page, delivery_option) with relations and indexes; explicit index on
  orders.number (product.slug/category.slug are unique-indexed by their keys).
- Currency BYN (R4/Q1): STORE_CURRENCY = 'BYN', money as integer minor units
  (BYN * 100), no float, no interim currency, no FX conversion.
- Idempotent seed: 14 categories (11 visible + 3 hidden visible=false, R13) and
  93 products from docs/CATALOG.md §3 (broken #59 excluded, R14) with prices,
  old prices and badges; cross-listing, images, variants, PDP fields (R9),
  store constants (CATALOG §6), 1 admin + 1 customer and 2 orders.
- scripts/{migrate,seed,verify}.ts + src/db: CLI entry points and an in-process
  Postgres verification harness (satisfies `migrate` + `seed` on a clean clone).
- db/seed/0001_seed.sql: generated single-file SQL for the platform Data Tables
  (`/db-forms`, run_sql) to converge tenant_1 without a Node process.
- Placeholder dev server + storefront currency/constants and money helpers.

Verified on a clean Postgres (PGlite): product = 93; category = 14 with
visible = 11; orders = 2; money integer BYN minor units (0 float rows).
2026-10-04 19:57:52 +00:00