feat(ui): serve the public offer at /offer/ with a landing footer link
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 19s
CI / ui (pull_request) Successful in 1m9s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m41s

The offer is the legal document a purchase accepts, needed before real-money
intake goes live. Convert the source PDF to an editable ui/legal/offer_ru.md and
render it to a standalone static dist/offer/index.html at build (a vite
emit-offer plugin using marked); the landing container serves it at /offer/,
with a bare /offer redirecting in. Add a small centered "Публичная оферта"
footer link on the landing (ru/en) and a CI probe asserting /offer/ serves the
page rather than silently falling through to the landing shell.
This commit is contained in:
Ilia Denisov
2026-07-09 16:03:50 +02:00
parent a118c63411
commit 625fc3135a
14 changed files with 355 additions and 6 deletions
+18
View File
@@ -3,6 +3,7 @@ import { resolve } from 'node:path';
import { defineConfig, type Plugin } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import { VitePWA } from 'vite-plugin-pwa';
import { renderOfferHtml } from './src/lib/offer';
/**
* injectBootVersion stamps the app version into index.html's boot-capability guard, replacing its
@@ -38,6 +39,22 @@ function emitPolyfills(): Plugin {
};
}
/**
* emitOffer renders the public offer markdown (legal/offer_ru.md) to a standalone
* static page and emits it as dist/offer/index.html, which the landing container
* serves at /offer/ (deploy/landing/Caddyfile). The markdown is the owner-editable
* source of truth, so the page is regenerated from it on every build.
*/
function emitOffer(): Plugin {
return {
name: 'emit-offer',
generateBundle() {
const md = readFileSync(resolve(import.meta.dirname, 'legal/offer_ru.md'), 'utf8');
this.emitFile({ type: 'asset', fileName: 'offer/index.html', source: renderOfferHtml(md) });
},
};
}
// The edge Connect service is scrabble.edge.v1.Gateway; the gateway serves it over
// h2c on :8081 by default. In dev we proxy the RPC path so the browser (which can
// not speak h2c directly) talks to the dev server on the same origin. In `mock`
@@ -60,6 +77,7 @@ export default defineConfig(({ mode }) => ({
plugins: [
svelte(),
emitPolyfills(),
emitOffer(),
injectBootVersion(),
// App-shell precache for the offline mode: a custom (injectManifest) service worker precaches
// index.html + the hashed assets so the installed web PWA cold-launches with no network. It