@zenky/storefront-vue 0.10.0 → 0.10.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/README.md +66 -6
  3. package/dist/cart/index.d.ts +31 -2
  4. package/dist/cart/index.js +6 -9
  5. package/dist/catalog/index.d.ts +1 -11
  6. package/dist/catalog/index.js +2 -2
  7. package/dist/chunk-2CI4RW7V.js +21 -0
  8. package/dist/chunk-2CI4RW7V.js.map +1 -0
  9. package/dist/{chunk-GW2QNTAD.js → chunk-4IFPVEO7.js} +3 -113
  10. package/dist/chunk-4IFPVEO7.js.map +1 -0
  11. package/dist/{chunk-EYRCAUUP.js → chunk-E3G7NGCH.js} +2 -2
  12. package/dist/chunk-E3G7NGCH.js.map +1 -0
  13. package/dist/{chunk-IGDDWGS4.js → chunk-IVG4FQE5.js} +21 -13
  14. package/dist/chunk-IVG4FQE5.js.map +1 -0
  15. package/dist/{chunk-PJ2LEKW6.js → chunk-MZ66ARDL.js} +18 -3
  16. package/dist/chunk-MZ66ARDL.js.map +1 -0
  17. package/dist/{chunk-2OD7CLKD.js → chunk-NG7RUIWW.js} +3 -13
  18. package/dist/chunk-NG7RUIWW.js.map +1 -0
  19. package/dist/{chunk-VL3T36VM.js → chunk-NIQFYJRP.js} +53 -9
  20. package/dist/chunk-NIQFYJRP.js.map +1 -0
  21. package/dist/{chunk-AL5W5JSD.js → chunk-OTSAR32A.js} +6 -3
  22. package/dist/chunk-OTSAR32A.js.map +1 -0
  23. package/dist/{chunk-BIGTKVC6.js → chunk-SS7B2NLF.js} +3 -3
  24. package/dist/{chunk-BIGTKVC6.js.map → chunk-SS7B2NLF.js.map} +1 -1
  25. package/dist/{chunk-PWHIDGKW.js → chunk-TB5TBJ4U.js} +53 -6
  26. package/dist/chunk-TB5TBJ4U.js.map +1 -0
  27. package/dist/{chunk-4MJKN7PL.js → chunk-YREGCQSB.js} +4 -6
  28. package/dist/chunk-YREGCQSB.js.map +1 -0
  29. package/dist/{chunk-OQLU7FSR.js → chunk-YS5DXYYV.js} +228 -51
  30. package/dist/chunk-YS5DXYYV.js.map +1 -0
  31. package/dist/index.d.ts +6 -8
  32. package/dist/index.js +14 -16
  33. package/dist/order/index.d.ts +2 -0
  34. package/dist/order/index.js +2 -5
  35. package/dist/order/index.js.map +1 -1
  36. package/dist/pagination/index.js.map +1 -1
  37. package/dist/ports/index.d.ts +12 -1
  38. package/dist/ports/index.js +1 -1
  39. package/dist/products/index.js +3 -4
  40. package/dist/promotions/index.js +3 -5
  41. package/dist/seo/index.d.ts +5 -11
  42. package/dist/seo/index.js +17 -27
  43. package/dist/seo/index.js.map +1 -1
  44. package/dist/snippets/index.d.ts +21 -15
  45. package/dist/snippets/index.js +1 -1
  46. package/dist/stores/index.d.ts +1 -1
  47. package/dist/stores/index.js +3 -5
  48. package/dist/theme/index.d.ts +1 -11
  49. package/dist/theme/index.js +1 -1
  50. package/dist/utils/index.d.ts +28 -5
  51. package/dist/utils/index.js +1 -1
  52. package/dist/website-settings/index.d.ts +1 -1
  53. package/docs/consumer-setup.md +279 -0
  54. package/docs/ports.md +148 -0
  55. package/docs/releasing.md +53 -0
  56. package/package.json +27 -8
  57. package/dist/chunk-2OD7CLKD.js.map +0 -1
  58. package/dist/chunk-4MJKN7PL.js.map +0 -1
  59. package/dist/chunk-AL5W5JSD.js.map +0 -1
  60. package/dist/chunk-BWUKMWHL.js +0 -45
  61. package/dist/chunk-BWUKMWHL.js.map +0 -1
  62. package/dist/chunk-DKWDKVXQ.js +0 -91
  63. package/dist/chunk-DKWDKVXQ.js.map +0 -1
  64. package/dist/chunk-EYRCAUUP.js.map +0 -1
  65. package/dist/chunk-GW2QNTAD.js.map +0 -1
  66. package/dist/chunk-IGDDWGS4.js.map +0 -1
  67. package/dist/chunk-OQLU7FSR.js.map +0 -1
  68. package/dist/chunk-PJ2LEKW6.js.map +0 -1
  69. package/dist/chunk-PWHIDGKW.js.map +0 -1
  70. package/dist/chunk-V3VVDQIR.js +0 -27
  71. package/dist/chunk-V3VVDQIR.js.map +0 -1
  72. package/dist/chunk-VL3T36VM.js.map +0 -1
  73. package/dist/layout/index.d.ts +0 -54
  74. package/dist/layout/index.js +0 -102
  75. package/dist/layout/index.js.map +0 -1
  76. package/dist/schedule-Dd3zwHEb.d.ts +0 -27
  77. package/dist/snippets-BC5bkSjm.d.ts +0 -23
package/CHANGELOG.md ADDED
@@ -0,0 +1,105 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and releases follow
5
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## 0.10.4 - 2026-07-29
8
+
9
+ > **Breaking.** This release changes the runtime port contract and removes public
10
+ > exports. The version stays in the `0.10.x` range because the package has no stable
11
+ > release yet and has a single, already-migrated consumer. Read the migration notes
12
+ > below before upgrading.
13
+
14
+ ### Migration
15
+
16
+ 1. **Provide the `messages` port.** `StorefrontRuntime` now requires a
17
+ `MessageFormatter`. `createStorefront()` and `provideStorefront()` throw on start
18
+ when any required port is missing, instead of failing later inside a `catch` block.
19
+ Tests and headless consumers can pass `KEY_MESSAGE_FORMATTER`, which returns the key
20
+ itself.
21
+
22
+ ```ts
23
+ import { KEY_MESSAGE_FORMATTER } from '@zenky/storefront-vue/ports'
24
+
25
+ app.use(createStorefront({ ...runtime, messages: KEY_MESSAGE_FORMATTER }))
26
+ ```
27
+
28
+ 2. **Move removed symbols into your app.** Gone from their subpath *and* from the root
29
+ entry: `catalogRoutes` (`./catalog`), `THEME_PRESETS` / `DARK_THEME_PRESETS` /
30
+ `ThemePreset` (`./theme`), `buildSnippetHead` / `SnippetHead` (`./snippets`). Gone
31
+ from their subpath only: `withSeoMetaPriority` (`./seo`) and the entire `./layout`
32
+ subpath (`useHeaderData`, `useFooterData`) — neither was re-exported from the root.
33
+
34
+ 3. **Pass `formatDayLabel` if you rely on localized day tabs.** Without it,
35
+ `generateFreeTimeGroups` labels days as `DD.MM`. This affects only free-slot mode —
36
+ in interval mode the day names come from the API.
37
+
38
+ ### Added
39
+
40
+ - `check:boundaries` gate that fails the build when Nuxt, Unhead, route policy, or
41
+ tenant presets reappear in `src/`.
42
+ - Pull-request quality checks restored in CI.
43
+
44
+ ### Removed
45
+
46
+ - The `./layout` subpath (`useHeaderData`, `useFooterData`, and the `HeaderData`,
47
+ `HeaderDataOptions`, `FooterData`, `FooterDataOptions`, `FormattedPhone`, `LegalLink`
48
+ types) — header and footer composition reads consumer config and belongs to the
49
+ consumer.
50
+ - `catalogRoutes` — catalog route policy is owned by the consumer.
51
+ - `withSeoMetaPriority` — `tagPriority` is Unhead-specific.
52
+ - `THEME_PRESETS`, `DARK_THEME_PRESETS`, `ThemePreset` — tenant branding.
53
+ - `buildSnippetHead`, `SnippetHead` — the head payload shape is framework-specific.
54
+
55
+ ### Changed
56
+
57
+ - Storefront runtime now requires a consumer-owned message formatter. Cart notification
58
+ copy is emitted as stable message keys instead of Russian literals. Error text
59
+ forwarded from the API is passed through untouched and stays in the language the
60
+ backend sent. Formatting helpers — weight units, schedule status, contact labels,
61
+ address parsing, pluralization — remain Russian-only and are tracked as known debt.
62
+ - Delivery slot labels are consumer-configurable and default to locale-neutral dates.
63
+ - SEO builders now return framework-neutral meta records without Unhead-specific fields.
64
+ - `@zenky/storefront-api` peer range moved to `^1.0.1`.
65
+
66
+ ## 0.10.3 - 2026-07-24
67
+
68
+ ### Added
69
+
70
+ - Pull-request CI for formatting, linting, types, coverage, tests, package exports,
71
+ Node/runtime compatibility, bundle budgets, and secret scanning.
72
+ - Dependabot updates for npm dependencies and GitHub Actions.
73
+ - Public security, contribution, conduct, runtime-port, and release documentation.
74
+ - Coverage ratchet and regression tests for checkout state and credential-safe logging.
75
+ - Cart composables for evaluating product restrictions, confirming blocking
76
+ restrictions, and reading variants that remain visible after optimistic updates.
77
+
78
+ ### Changed
79
+
80
+ - GitHub Actions are pinned to immutable commits with minimum workflow permissions.
81
+ - QR-code encoding now uses Web Platform APIs and works without Node `Buffer` or browser
82
+ globals, improving Node SSR and edge-runtime compatibility.
83
+ - npm package metadata now includes its homepage, issue tracker, and supported engines.
84
+
85
+ ### Fixed
86
+
87
+ - Empty post-checkout orders no longer trigger a minimum-order-price violation.
88
+
89
+ ### Security
90
+
91
+ - Cart and checkout errors now pass through recursive redaction before being logged.
92
+ - Direct cart logging no longer emits complete order, credentials, request, or API error
93
+ objects.
94
+
95
+ ## 0.10.0 - 2026-07-21
96
+
97
+ ### Added
98
+
99
+ - GitHub release workflow for npm OIDC trusted publishing.
100
+
101
+ ### Changed
102
+
103
+ - Package renamed to `@zenky/storefront-vue`.
104
+ - Storefront runtime state and cart flows were isolated across Vue applications and SSR
105
+ requests.
package/README.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  Headless storefront engine for Zenky — Vue 3 + Pinia, no framework lock-in.
4
4
 
5
+ [![CI](https://github.com/zenky/storefront-vue/actions/workflows/ci.yml/badge.svg)](https://github.com/zenky/storefront-vue/actions/workflows/ci.yml)
6
+ [![npm](https://img.shields.io/npm/v/@zenky/storefront-vue.svg)](https://www.npmjs.com/package/@zenky/storefront-vue)
7
+
5
8
  One engine behind many storefronts. The cart, order building, checkout, catalog resolution, delivery slots, SEO/JSON-LD, theme, and store/profile state all live here as framework-agnostic composables and Pinia stores. The consumer — a Nuxt site, a QR-code menu, a new template — brings the framework glue (cookies, config, toasts, HTTP transport, `useHead`) and draws its own UI on top.
6
9
 
7
10
  The design is Ports & Adapters: the core declares small ports for everything it needs from the outside world, the consumer provides adapters once, and every composable reads them through `useRuntime()`. The core never imports `useCookie`, `useRoute`, `useHead`, `$fetch`, or anything Nuxt-specific.
@@ -18,7 +21,7 @@ Peer dependencies (the consumer already has these):
18
21
  {
19
22
  "vue": "^3.5.0",
20
23
  "pinia": "^3.0.0",
21
- "@zenky/storefront-api": ">=0.0.64",
24
+ "@zenky/storefront-api": "^1.0.1",
22
25
  "@zenky/integrations-sdk": ">=0.1.3"
23
26
  }
24
27
  ```
@@ -45,6 +48,9 @@ app.use(
45
48
  warning: (m) => toast.warning(m),
46
49
  message: (title, opts) => toast(title, opts),
47
50
  },
51
+ messages: { // consumer-owned localization
52
+ format: (key, params) => i18n.t(key, params),
53
+ },
48
54
  activity: { // busy indicators for long operations
49
55
  begin: (kind) => busy.begin(kind),
50
56
  end: (kind) => busy.end(kind),
@@ -69,7 +75,7 @@ cart.totalPrice.value
69
75
 
70
76
  ## Runtime Ports
71
77
 
72
- `createStorefront(runtime)` takes one object. Five ports are required; the rest are optional — omit an optional port and the feature that needs it is simply skipped.
78
+ `createStorefront(runtime)` takes one object. Six ports are required; the rest are optional — omit an optional port and the feature that needs it is simply skipped.
73
79
 
74
80
  | Port | Required | What the consumer provides |
75
81
  | --- | --- | --- |
@@ -77,6 +83,7 @@ cart.totalPrice.value
77
83
  | `config` | yes | `{ baseUrl, baseAuthUrl, salesChannelId? }`. |
78
84
  | `storage` | yes | Key/value persistence — cookies, `localStorage`, memory. |
79
85
  | `notifier` | yes | Toasts: `error` / `success` / `warning` / `message`. |
86
+ | `messages` | yes | Maps stable domain message keys to localized consumer copy. |
80
87
  | `activity` | yes | `begin(kind)` / `end(kind)` for busy state. |
81
88
  | `events` | no | Lazy `{ get() }` provider for `ZenkyIntegrationsSDK`; resolve on every event. |
82
89
  | `realtime` | no | Lazy `{ get() }` provider for the WebSocket adapter (`subscribe` / `unsubscribe` / `isReady`). |
@@ -90,28 +97,61 @@ Types for every port live in the `ports` subpath, alongside no-op defaults and a
90
97
  import {
91
98
  type StorefrontRuntime,
92
99
  type StorageAdapter,
100
+ KEY_MESSAGE_FORMATTER,
93
101
  NOOP_NOTIFIER,
94
102
  NOOP_ACTIVITY_REPORTER,
95
103
  createMemoryStorage,
96
104
  } from '@zenky/storefront-vue/ports'
97
105
  ```
98
106
 
107
+ The full public contract, adapter examples, SSR lifecycle, and security boundary are in
108
+ [Runtime Ports](docs/ports.md). For a step-by-step consumer integration and upgrade
109
+ checklist, see [Consumer Setup](docs/consumer-setup.md).
110
+
99
111
  ## Subpath Imports
100
112
 
101
113
  Each public domain is its own entry point, so bundlers only pull in what you import.
102
114
 
103
115
  ```ts
104
116
  import { minorToMajor } from '@zenky/storefront-vue/money'
105
- import { buildCssVariableMap, THEME_PRESETS } from '@zenky/storefront-vue/theme'
117
+ import { buildCssVariableMap } from '@zenky/storefront-vue/theme'
106
118
  import { getRemoteCatalog, findCategoryByShortId } from '@zenky/storefront-vue/catalog'
107
119
  import { useStorefrontCart, useCheckoutSubmit } from '@zenky/storefront-vue/cart'
108
120
  import { generateFreeTimeGroups } from '@zenky/storefront-vue/order'
109
121
  import { buildProductSchema, buildOgTags } from '@zenky/storefront-vue/seo'
110
- import { useHeaderData, useFooterData } from '@zenky/storefront-vue/layout'
111
122
  import { usePaginatedList } from '@zenky/storefront-vue/pagination'
112
123
  ```
113
124
 
114
- Available subpaths: `ports`, `money`, `utils`, `theme`, `stores`, `products`, `catalog`, `cart`, `order`, `promotions`, `seo`, `layout`, `pagination`, `snippets`, `website-settings`.
125
+ Available subpaths: `ports`, `money`, `utils`, `theme`, `stores`, `products`, `catalog`, `cart`, `order`, `promotions`, `seo`, `pagination`, `snippets`, `website-settings`.
126
+
127
+ Routing, tenant theme presets, localized copy, header/footer composition, and conversion to
128
+ framework-specific head records belong to the consumer. Core SEO builders return plain
129
+ records; a Nuxt adapter may add Unhead-specific fields such as `tagPriority`.
130
+
131
+ ## Runtime Compatibility
132
+
133
+ - ESM-only, targeting ES2022.
134
+ - Vue 3.5+ and Pinia 3.
135
+ - Node.js 20.19+ for SSR and package tooling; Node.js 22 is recommended for production and development.
136
+ - Modern browsers and edge runtimes with standard Web Platform APIs.
137
+
138
+ CI imports every public entry in Node SSR and scans the emitted ESM for CommonJS, Node
139
+ built-ins, `Buffer`, and `process`. Browser-only behavior is guarded; for example,
140
+ online-payment retry accepts an explicit `currentUrl` when no `window` is available.
141
+
142
+ For SSR, create a new Vue app, Pinia instance, storefront runtime, and storage adapter per
143
+ request. Never share `createMemoryStorage()` between users.
144
+
145
+ ## Package Size
146
+
147
+ Every domain has a tree-shakeable subpath. CI measures the transitive gzip graph for the
148
+ root, cart, and utils entries plus all emitted JavaScript. The budgets are regression
149
+ ceilings, not size targets; increasing one requires review and a release-note explanation.
150
+
151
+ ```bash
152
+ npm run build
153
+ npm run check:size
154
+ ```
115
155
 
116
156
  ## Pinia Stores
117
157
 
@@ -138,9 +178,16 @@ majorToMinor(650, 'RUB') // 65000 — user input back into the store
138
178
  ```bash
139
179
  npm run dev # tsup --watch
140
180
  npm run build # ESM + .d.ts to dist/
181
+ npm run lint # Biome lint
182
+ npm run format # Biome format --write
141
183
  npm run typecheck # tsc --noEmit
142
184
  npm test # vitest
185
+ npm run test:coverage # vitest + V8 coverage report
186
+ npm run check # format + lint + types + tests + build + exports
143
187
  npm run check:exports # publint + are-the-types-wrong (esm-only profile)
188
+ npm run check:boundaries # reject Nuxt/Unhead and consumer policy in src/
189
+ npm run check:runtime # import all entries in SSR + reject Node-only output
190
+ npm run check:size # enforce gzip bundle budgets
144
191
  ```
145
192
 
146
193
  ### Local linking with yalc
@@ -165,7 +212,20 @@ npm run build && npx yalc push
165
212
  - `test` / `test:watch` — run the Vitest suite.
166
213
  - `typecheck` — type-only compile.
167
214
  - `check:exports` — validate the exports map and published types.
168
- - `prepublishOnly` — typecheck → test → build → check:exports.
215
+ - `check:boundaries` — reject Nuxt/Unhead APIs, routes, and tenant presets in core source.
216
+ - `check:runtime` — verify Node SSR imports and browser/edge-safe ESM output.
217
+ - `check:size` — enforce root/domain/all-output gzip budgets.
218
+ - `check:ci` — quality gate with the V8 coverage ratchet.
219
+ - `prepublishOnly` — run the release quality gate.
220
+
221
+ ## Contributing and Releases
222
+
223
+ Read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request. User-visible changes
224
+ belong in [CHANGELOG.md](CHANGELOG.md); maintainer steps are documented in the
225
+ [release process](docs/releasing.md).
226
+
227
+ Security vulnerabilities must be reported privately according to
228
+ [SECURITY.md](SECURITY.md), never through a public issue.
169
229
 
170
230
  ## License
171
231
 
@@ -1,4 +1,4 @@
1
- import { ProductModifiersRequest, OrderProductVariant, PaymentMethod, OrderPaymentMethodRequest, OrderAuthenticationMethod, OrderCredentials, Order, OrderCheckoutTotal, OrderSettings, OrderPaymentMethod, OrderDeliveryMethod, InclusionRequest, ZenkyStorefront, SetOrderCustomerRequest, SetOrderDeliveryRequest, OrderPromocode, OrderCheckoutResult, RecaptchaAction } from '@zenky/storefront-api';
1
+ import { ProductModifiersRequest, OrderProductVariant, PaymentMethod, OrderPaymentMethodRequest, OrderAuthenticationMethod, OrderCredentials, Order, OrderCheckoutTotal, OrderSettings, OrderPaymentMethod, OrderDeliveryMethod, InclusionRequest, ZenkyStorefront, SetOrderCustomerRequest, SetOrderDeliveryRequest, OrderPromocode, OrderCheckoutResult, RecaptchaAction, EvaluatedRestriction, Media, Product } from '@zenky/storefront-api';
2
2
  import { ComputedRef, MaybeRefOrGetter, Ref } from 'vue';
3
3
  import { ActivityReporter, Notifier, Result } from '../ports/index.js';
4
4
  import '@zenky/integrations-sdk';
@@ -556,4 +556,33 @@ interface StorefrontCart {
556
556
  }
557
557
  declare function useStorefrontCart(): StorefrontCart;
558
558
 
559
- export { type AttachedCustomerCache, type BonusesReconciliation, type BonusesReconciliationDeps, CASH_DENOMINATIONS_MAJOR, type CachedCustomerView, type CartCredentials, type CartDependencies, type CartErrorScope, type CartInitialization, type CartItemRequest, type CartLineKeyParams, type CartMutationComposable, type CartOperations, type CartQuantities, type CartRecalculation, type CartRecalculationDeps, type CartStockWatcher, type CashChangePresetsOptions, type CheckoutFlowFlags, type CheckoutSubmitComposable, type CustomerAttachComposable, DEFAULT_ROUND_STEPS_MAJOR, type MainPaymentRequestParams, type MutationKind, type MutationOptions, ORDER_EVENTS, ORDER_WITH, type OrderBonusesComposable, type OrderBonusesDeps, type OrderCredentialsLike, type OrderDelivery, type OrderDeliveryDeps, type OrderPromocodeComposable, type OrderPromocodeDeps, type OrderSettingsComposable, type OrderTotal, type PaymentSelection, type PaymentSelectionComposable, type RecaptchaPayloadProvider, type RetryOptions, type StorefrontCart, buildCartLineKey, buildCashChangePresets, buildMainPaymentRequest, getCartErrorCode, getCartErrorHttpCode, getCartErrorMessage, getCashDenominationsMinor, getDefaultRoundStepsMinor, getValidationErrors, logCartError, normalizeAddress, useBonusesReconciliation, useCartAddressSync, useCartCredentials, useCartCustomerAttachment, useCartDeliveryAttachment, useCartInitialization, useCartMutation, useCartOperations, useCartQuantities, useCartRecalculation, useCartStockWatcher, useCheckoutFlow, useCheckoutSubmit, useCustomerAttach, useOnlinePaymentRetry, useOrderBonuses, useOrderChannel, useOrderDelivery, useOrderPromocode, useOrderSettings, useOrderTotal, usePaymentSelection, useStorefrontCart, variantLineKey };
559
+ /** Данные товара для показа в модалке гейта (как строка корзины). */
560
+ interface RestrictionGateProduct {
561
+ name: string;
562
+ image: Media | null;
563
+ }
564
+ interface RestrictionGate {
565
+ isOpen: Ref<boolean>;
566
+ blocking: Ref<EvaluatedRestriction[]>;
567
+ product: Ref<RestrictionGateProduct | null>;
568
+ confirmBlocking: (items: EvaluatedRestriction[], gateProduct: RestrictionGateProduct) => Promise<boolean>;
569
+ confirm: () => void;
570
+ cancel: () => void;
571
+ }
572
+ declare function useRestrictionGate(): RestrictionGate;
573
+
574
+ type RestrictedProduct = Pick<Product, 'id' | 'restrictions' | 'name' | 'images'>;
575
+ interface RestrictedAddToCart {
576
+ checkRestrictionsAllowed: (product: RestrictedProduct, alreadyInCart: boolean) => Promise<boolean>;
577
+ addWithRestrictionCheck: (product: RestrictedProduct, request: CartItemRequest, alreadyInCart: boolean) => Promise<void>;
578
+ }
579
+ declare function useRestrictedAddToCart(): RestrictedAddToCart;
580
+
581
+ /**
582
+ * Позиции корзины, видимые покупателю: серверное количество с учётом оптимистичной дельты.
583
+ * Единый источник для списка, футера и подсветки — иначе блокировка чекаута, поиск
584
+ * блокирующей позиции и реальный рендер списка могут разъехаться.
585
+ */
586
+ declare function useVisibleCartVariants(): ComputedRef<OrderProductVariant[]>;
587
+
588
+ export { type AttachedCustomerCache, type BonusesReconciliation, type BonusesReconciliationDeps, CASH_DENOMINATIONS_MAJOR, type CachedCustomerView, type CartCredentials, type CartDependencies, type CartErrorScope, type CartInitialization, type CartItemRequest, type CartLineKeyParams, type CartMutationComposable, type CartOperations, type CartQuantities, type CartRecalculation, type CartRecalculationDeps, type CartStockWatcher, type CashChangePresetsOptions, type CheckoutFlowFlags, type CheckoutSubmitComposable, type CustomerAttachComposable, DEFAULT_ROUND_STEPS_MAJOR, type MainPaymentRequestParams, type MutationKind, type MutationOptions, ORDER_EVENTS, ORDER_WITH, type OrderBonusesComposable, type OrderBonusesDeps, type OrderCredentialsLike, type OrderDelivery, type OrderDeliveryDeps, type OrderPromocodeComposable, type OrderPromocodeDeps, type OrderSettingsComposable, type OrderTotal, type PaymentSelection, type PaymentSelectionComposable, type RecaptchaPayloadProvider, type RestrictedAddToCart, type RestrictionGate, type RestrictionGateProduct, type RetryOptions, type StorefrontCart, buildCartLineKey, buildCashChangePresets, buildMainPaymentRequest, getCartErrorCode, getCartErrorHttpCode, getCartErrorMessage, getCashDenominationsMinor, getDefaultRoundStepsMinor, getValidationErrors, logCartError, normalizeAddress, useBonusesReconciliation, useCartAddressSync, useCartCredentials, useCartCustomerAttachment, useCartDeliveryAttachment, useCartInitialization, useCartMutation, useCartOperations, useCartQuantities, useCartRecalculation, useCartStockWatcher, useCheckoutFlow, useCheckoutSubmit, useCustomerAttach, useOnlinePaymentRetry, useOrderBonuses, useOrderChannel, useOrderDelivery, useOrderPromocode, useOrderSettings, useOrderTotal, usePaymentSelection, useRestrictedAddToCart, useRestrictionGate, useStorefrontCart, useVisibleCartVariants, variantLineKey };
@@ -1,13 +1,10 @@
1
- export { CASH_DENOMINATIONS_MAJOR, DEFAULT_ROUND_STEPS_MAJOR, ORDER_EVENTS, ORDER_WITH, buildCartLineKey, buildCashChangePresets, buildMainPaymentRequest, getCartErrorCode, getCartErrorHttpCode, getCartErrorMessage, getCashDenominationsMinor, getDefaultRoundStepsMinor, getValidationErrors, logCartError, normalizeAddress, useBonusesReconciliation, useCartAddressSync, useCartCustomerAttachment, useCartDeliveryAttachment, useCartInitialization, useCartMutation, useCartOperations, useCartQuantities, useCartRecalculation, useCartStockWatcher, useCheckoutFlow, useCheckoutSubmit, useCustomerAttach, useOnlinePaymentRetry, useOrderBonuses, useOrderChannel, useOrderDelivery, useOrderPromocode, useOrderSettings, useOrderTotal, usePaymentSelection, useStorefrontCart, variantLineKey } from '../chunk-OQLU7FSR.js';
2
- export { useCartCredentials } from '../chunk-4MJKN7PL.js';
3
- import '../chunk-5QCUH3FF.js';
1
+ export { CASH_DENOMINATIONS_MAJOR, DEFAULT_ROUND_STEPS_MAJOR, ORDER_EVENTS, ORDER_WITH, buildCartLineKey, buildCashChangePresets, buildMainPaymentRequest, getCartErrorCode, getCartErrorHttpCode, getCartErrorMessage, getCashDenominationsMinor, getDefaultRoundStepsMinor, getValidationErrors, logCartError, normalizeAddress, useBonusesReconciliation, useCartAddressSync, useCartCustomerAttachment, useCartDeliveryAttachment, useCartInitialization, useCartMutation, useCartOperations, useCartQuantities, useCartRecalculation, useCartStockWatcher, useCheckoutFlow, useCheckoutSubmit, useCustomerAttach, useOnlinePaymentRetry, useOrderBonuses, useOrderChannel, useOrderDelivery, useOrderPromocode, useOrderSettings, useOrderTotal, usePaymentSelection, useRestrictedAddToCart, useRestrictionGate, useStorefrontCart, useVisibleCartVariants, variantLineKey } from '../chunk-YS5DXYYV.js';
2
+ export { useCartCredentials } from '../chunk-YREGCQSB.js';
4
3
  import '../chunk-Z3IW4ODZ.js';
5
- import '../chunk-BWUKMWHL.js';
6
- import '../chunk-PWHIDGKW.js';
7
- import '../chunk-EYRCAUUP.js';
8
- import '../chunk-VL3T36VM.js';
9
- import '../chunk-V3VVDQIR.js';
4
+ import '../chunk-NIQFYJRP.js';
5
+ import '../chunk-E3G7NGCH.js';
10
6
  import '../chunk-RO25KNM5.js';
11
- import '../chunk-AL5W5JSD.js';
7
+ import '../chunk-5QCUH3FF.js';
8
+ import '../chunk-TB5TBJ4U.js';
12
9
  //# sourceMappingURL=index.js.map
13
10
  //# sourceMappingURL=index.js.map
@@ -60,14 +60,4 @@ declare function useCollections(sdk: ZenkyStorefront): {
60
60
  loadCollections: (storeId: string, request?: CollectionsListRequest) => Promise<ProductsCollection[]>;
61
61
  };
62
62
 
63
- /** URL-хелперы каталога — единая точка правды для путей категорий/коллекций. */
64
- declare const catalogRoutes: {
65
- /** Корневая страница каталога: список категорий + коллекций */
66
- readonly index: () => string;
67
- /** Страница конкретной категории */
68
- readonly category: (shortId: string, slug: string | null) => string;
69
- /** Страница конкретной коллекции */
70
- readonly collection: (id: string) => string;
71
- };
72
-
73
- export { type GroupedProducts, type SubcategoryGroup, catalogRoutes, collectDescendantIds, findCategoryById, findCategoryByShortId, findRootAncestor, getCategoryPath, getCity, getRemoteCatalog, getStock, groupProductsBySubcategory, useCollections };
63
+ export { type GroupedProducts, type SubcategoryGroup, collectDescendantIds, findCategoryById, findCategoryByShortId, findRootAncestor, getCategoryPath, getCity, getRemoteCatalog, getStock, groupProductsBySubcategory, useCollections };
@@ -1,4 +1,4 @@
1
- export { catalogRoutes, collectDescendantIds, findCategoryById, findCategoryByShortId, findRootAncestor, getCategoryPath, groupProductsBySubcategory, useCollections } from '../chunk-2OD7CLKD.js';
2
- export { getCity, getRemoteCatalog, getStock } from '../chunk-EYRCAUUP.js';
1
+ export { collectDescendantIds, findCategoryById, findCategoryByShortId, findRootAncestor, getCategoryPath, groupProductsBySubcategory, useCollections } from '../chunk-NG7RUIWW.js';
2
+ export { getCity, getRemoteCatalog, getStock } from '../chunk-E3G7NGCH.js';
3
3
  //# sourceMappingURL=index.js.map
4
4
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,21 @@
1
+ // src/snippets/snippets.ts
2
+ function normalizeSnippets(groups) {
3
+ if (!Array.isArray(groups)) return [];
4
+ return groups.flatMap(
5
+ (group, groupIndex) => (group.snippets ?? []).filter((item) => !!item.content?.trim()).map((item, itemIndex) => {
6
+ const snippet = {
7
+ id: `${group.region}-${groupIndex}-${itemIndex}`,
8
+ position: group.region,
9
+ language: item.language,
10
+ code: item.content,
11
+ enabled: item.enabled ?? true
12
+ };
13
+ if (item.name !== void 0) snippet.name = item.name;
14
+ return snippet;
15
+ })
16
+ );
17
+ }
18
+
19
+ export { normalizeSnippets };
20
+ //# sourceMappingURL=chunk-2CI4RW7V.js.map
21
+ //# sourceMappingURL=chunk-2CI4RW7V.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/snippets/snippets.ts"],"names":[],"mappings":";AAwBO,SAAS,kBAAkB,MAAA,EAAsD;AACpF,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,SAAU,EAAC;AAEpC,EAAA,OAAO,MAAA,CAAO,OAAA;AAAA,IAAQ,CAAC,OAAO,UAAA,KAAA,CACzB,KAAA,CAAM,YAAY,EAAC,EACf,OAAO,CAAC,IAAA,KAAS,CAAC,CAAC,IAAA,CAAK,SAAS,IAAA,EAAM,EACvC,GAAA,CAAI,CAAC,MAAM,SAAA,KAAuB;AAC/B,MAAA,MAAM,OAAA,GAAmB;AAAA,QACrB,IAAI,CAAA,EAAG,KAAA,CAAM,MAAM,CAAA,CAAA,EAAI,UAAU,IAAI,SAAS,CAAA,CAAA;AAAA,QAC9C,UAAU,KAAA,CAAM,MAAA;AAAA,QAChB,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,MAAM,IAAA,CAAK,OAAA;AAAA,QACX,OAAA,EAAS,KAAK,OAAA,IAAW;AAAA,OAC7B;AAEA,MAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,EAAW,OAAA,CAAQ,OAAO,IAAA,CAAK,IAAA;AACjD,MAAA,OAAO,OAAA;AAAA,IACX,CAAC;AAAA,GACT;AACJ","file":"chunk-2CI4RW7V.js","sourcesContent":["export type SnippetPosition = 'head_start' | 'head_end' | 'body_start' | 'body_end'\nexport type SnippetLanguage = 'html' | 'css' | 'javascript'\n\nexport interface Snippet {\n id: string\n name?: string\n position: SnippetPosition\n language: SnippetLanguage\n code: string\n enabled: boolean\n}\n\nexport interface RawSnippetItem {\n language: SnippetLanguage\n content: string\n enabled?: boolean\n name?: string\n}\n\nexport interface SnippetGroup {\n region: SnippetPosition\n snippets: RawSnippetItem[]\n}\n\nexport function normalizeSnippets(groups: SnippetGroup[] | null | undefined): Snippet[] {\n if (!Array.isArray(groups)) return []\n\n return groups.flatMap((group, groupIndex) =>\n (group.snippets ?? [])\n .filter((item) => !!item.content?.trim())\n .map((item, itemIndex): Snippet => {\n const snippet: Snippet = {\n id: `${group.region}-${groupIndex}-${itemIndex}`,\n position: group.region,\n language: item.language,\n code: item.content,\n enabled: item.enabled ?? true,\n }\n // exactOptionalPropertyTypes: name задаём только если оно есть\n if (item.name !== undefined) snippet.name = item.name\n return snippet\n })\n )\n}\n"]}
@@ -212,116 +212,6 @@ function useTheme(colorConfig, fontConfig) {
212
212
  };
213
213
  }
214
214
 
215
- // src/theme/presets.ts
216
- var THEME_PRESETS = [
217
- {
218
- id: "yarollov",
219
- label: "Yarollov",
220
- description: "\u0424\u0438\u0440\u043C\u0435\u043D\u043D\u044B\u0439 \u0431\u0440\u0435\u043D\u0434 \u2014 \u043C\u0430\u043B\u0438\u043D\u043E\u0432\u044B\u0439 primary, \u0442\u0451\u043C\u043D\u043E-\u0441\u0438\u043D\u0438\u0439 accent",
221
- colors: {
222
- primary: "#D81C4B",
223
- secondary: "#8272C1",
224
- accent: "#1E1B4B",
225
- background: "#FFFFFF",
226
- text: "#1A1A1A"
227
- }
228
- },
229
- {
230
- id: "orange",
231
- label: "Orange",
232
- description: "\u0422\u0451\u043F\u043B\u044B\u0439 \u043E\u0440\u0430\u043D\u0436\u0435\u0432\u044B\u0439 \u0441 \u0441\u0438\u043D\u0438\u043C \u0430\u043A\u0446\u0435\u043D\u0442\u043E\u043C",
233
- colors: {
234
- primary: "#FE5000",
235
- secondary: "#64748B",
236
- accent: "#007AFF",
237
- background: "#FFFFFF",
238
- text: "#1A1A1A"
239
- }
240
- },
241
- {
242
- id: "sushi03",
243
- label: "Sushi03",
244
- description: "\u0422\u0451\u043C\u043D\u043E-\u0441\u0438\u043D\u0438\u0439 primary + \u0433\u043E\u0440\u0447\u0438\u0447\u043D\u044B\u0439 accent",
245
- colors: {
246
- primary: "#002F8C",
247
- secondary: "#8B9DC3",
248
- accent: "#FFDE69",
249
- background: "#FFFFFF",
250
- text: "#1A1A1A",
251
- success: "#00A980",
252
- danger: "#E61717"
253
- }
254
- },
255
- {
256
- id: "olive",
257
- label: "Olive Whisper",
258
- description: "\u041A\u0438\u0441\u043B\u043E\u0442\u043D\u043E-\u0437\u0435\u043B\u0451\u043D\u044B\u0439 \u043D\u0430 \u0442\u0451\u043C\u043D\u043E\u043C \u0444\u043E\u043D\u0435",
259
- colors: {
260
- primary: "#C0F53D",
261
- secondary: "#0A0D04",
262
- accent: "#C0F53D",
263
- background: "#1A2209",
264
- text: "#FAFFF3",
265
- headerBg: "#1A2209",
266
- footerBg: "#0A0D04",
267
- footerText: "#FAFFF3",
268
- footerTextMuted: "#6B7A4A"
269
- }
270
- }
271
- ];
272
- var DARK_THEME_PRESETS = [
273
- {
274
- id: "yarollov-dark",
275
- label: "Yarollov Dark",
276
- description: "\u0424\u0438\u0440\u043C\u0435\u043D\u043D\u044B\u0439 \u0431\u0440\u0435\u043D\u0434 (\u0442\u0451\u043C\u043D\u0430\u044F)",
277
- colors: {
278
- primary: "#F472B6",
279
- secondary: "#A78BFA",
280
- accent: "#818CF8",
281
- background: "#121212",
282
- text: "#E5E5E5",
283
- headerBg: "#1A1A1A",
284
- footerBg: "#0F0F0F",
285
- footerText: "#A3A3A3",
286
- footerTextMuted: "#525252"
287
- }
288
- },
289
- {
290
- id: "orange-dark",
291
- label: "Orange Dark",
292
- description: "\u0422\u0451\u043F\u043B\u044B\u0439 \u043E\u0440\u0430\u043D\u0436\u0435\u0432\u044B\u0439 (\u0442\u0451\u043C\u043D\u0430\u044F)",
293
- colors: {
294
- primary: "#FE5000",
295
- secondary: "#64748B",
296
- accent: "#60A5FA",
297
- background: "#121212",
298
- text: "#E5E5E5",
299
- headerBg: "#1A1A1A",
300
- footerBg: "#0F0F0F",
301
- footerText: "#A3A3A3",
302
- footerTextMuted: "#525252"
303
- }
304
- },
305
- {
306
- id: "sushi03-dark",
307
- label: "Sushi03 Dark",
308
- description: "\u0422\u0451\u043C\u043D\u043E-\u0441\u0438\u043D\u0438\u0439 (\u0442\u0451\u043C\u043D\u0430\u044F)",
309
- colors: {
310
- primary: "#4D8DE8",
311
- secondary: "#5A6D8A",
312
- accent: "#FFDE69",
313
- background: "#0F1419",
314
- text: "#E5E5E5",
315
- success: "#34D399",
316
- danger: "#F87171",
317
- headerBg: "#161C24",
318
- footerBg: "#0A0F14",
319
- footerText: "#94A3B8",
320
- footerTextMuted: "#475569"
321
- }
322
- }
323
- ];
324
-
325
- export { DARK_THEME_PRESETS, THEME_PRESETS, buildCssVariableMap, generatePrimaryShades, generateShades, useTheme };
326
- //# sourceMappingURL=chunk-GW2QNTAD.js.map
327
- //# sourceMappingURL=chunk-GW2QNTAD.js.map
215
+ export { buildCssVariableMap, generatePrimaryShades, generateShades, useTheme };
216
+ //# sourceMappingURL=chunk-4IFPVEO7.js.map
217
+ //# sourceMappingURL=chunk-4IFPVEO7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/theme/colors.ts","../src/theme/useTheme.ts"],"names":["p","q"],"mappings":"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","file":"chunk-4IFPVEO7.js","sourcesContent":["// Генерация цветовой шкалы и CSS-переменных из базовых цветов бренда.\n// Чистая математика в HSL/RGB — ноль зависимостей, ноль Nuxt. Портируется как есть.\n\nexport interface ThemeColorConfig {\n primary: string\n secondary: string\n accent: string\n background: string\n text: string\n success?: string\n danger?: string\n warning?: string\n info?: string\n /** Цвет текста поверх primary-фона. Если не задан — рассчитывается автоматически. */\n onPrimary?: string\n headerBg?: string\n footerBg?: string\n footerText?: string\n footerTextMuted?: string\n}\n\ninterface HslColor {\n h: number\n s: number\n l: number\n}\n\nfunction hexToHsl(hex: string): HslColor {\n const clean = hex.replace('#', '')\n const r = parseInt(clean.substring(0, 2), 16) / 255\n const g = parseInt(clean.substring(2, 4), 16) / 255\n const b = parseInt(clean.substring(4, 6), 16) / 255\n\n const max = Math.max(r, g, b)\n const min = Math.min(r, g, b)\n const l = (max + min) / 2\n\n if (max === min) {\n return { h: 0, s: 0, l }\n }\n\n const d = max - min\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min)\n\n let h = 0\n\n if (max === r) {\n h = ((g - b) / d + (g < b ? 6 : 0)) / 6\n } else if (max === g) {\n h = ((b - r) / d + 2) / 6\n } else {\n h = ((r - g) / d + 4) / 6\n }\n\n return { h, s, l }\n}\n\nfunction hslToHex(hsl: HslColor): string {\n const { h, s, l } = hsl\n\n if (s === 0) {\n const v = Math.round(l * 255)\n return `#${v.toString(16).padStart(2, '0').repeat(3)}`\n }\n\n const hue2rgb = (p: number, q: number, t: number): number => {\n let tt = t\n\n if (tt < 0) tt += 1\n if (tt > 1) tt -= 1\n if (tt < 1 / 6) return p + (q - p) * 6 * tt\n if (tt < 1 / 2) return q\n if (tt < 2 / 3) return p + (q - p) * (2 / 3 - tt) * 6\n\n return p\n }\n\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s\n const p = 2 * l - q\n\n const r = Math.round(hue2rgb(p, q, h + 1 / 3) * 255)\n const g = Math.round(hue2rgb(p, q, h) * 255)\n const b = Math.round(hue2rgb(p, q, h - 1 / 3) * 255)\n\n return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`\n}\n\n// ---------------------------------------------------------------------------\n// Color utilities\n// ---------------------------------------------------------------------------\n\n/**\n * Mix two hex colors in HSL space.\n * amount: 0 = pure hex1, 100 = pure hex2.\n */\nfunction mixColors(hex1: string, hex2: string, amount: number): string {\n const c1 = hexToHsl(hex1)\n const c2 = hexToHsl(hex2)\n const t = amount / 100\n\n // Handle achromatic mixing: if one color has no saturation,\n // inherit hue from the other\n let h: number\n if (c1.s === 0 && c2.s === 0) {\n h = 0\n } else if (c1.s === 0) {\n h = c2.h\n } else if (c2.s === 0) {\n h = c1.h\n } else {\n // Shortest path around the hue circle\n let dh = c2.h - c1.h\n if (dh > 0.5) dh -= 1\n if (dh < -0.5) dh += 1\n h = c1.h + dh * t\n if (h < 0) h += 1\n if (h > 1) h -= 1\n }\n\n return hslToHex({\n h,\n s: c1.s + (c2.s - c1.s) * t,\n l: c1.l + (c2.l - c1.l) * t,\n })\n}\n\n/**\n * Mix two hex colors in linear RGB space — matches CSS `linear-gradient` overlay behavior.\n * amount: 0 = pure hex1, 100 = pure hex2.\n */\nfunction mixColorsRgb(hex1: string, hex2: string, amount: number): string {\n const c1 = hex1.replace('#', '')\n const c2 = hex2.replace('#', '')\n const t = amount / 100\n\n const r1 = parseInt(c1.substring(0, 2), 16)\n const g1 = parseInt(c1.substring(2, 4), 16)\n const b1 = parseInt(c1.substring(4, 6), 16)\n const r2 = parseInt(c2.substring(0, 2), 16)\n const g2 = parseInt(c2.substring(2, 4), 16)\n const b2 = parseInt(c2.substring(4, 6), 16)\n\n const r = Math.round(r1 + (r2 - r1) * t)\n const g = Math.round(g1 + (g2 - g1) * t)\n const b = Math.round(b1 + (b2 - b1) * t)\n\n return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`\n}\n\n/**\n * Adjust lightness of a hex color by a relative percentage.\n * delta: -0.05 = 5% darker, +0.05 = 5% lighter.\n */\nfunction adjustLightness(hex: string, delta: number): string {\n const hsl = hexToHsl(hex)\n return hslToHex({\n h: hsl.h,\n s: hsl.s,\n l: Math.min(1, Math.max(0, hsl.l + delta)),\n })\n}\n\n/**\n * Returns a contrasting text color (white or dark) for a given background hex.\n * Uses relative luminance formula (WCAG).\n */\nfunction getContrastColor(hex: string): string {\n const clean = hex.replace('#', '')\n const r = parseInt(clean.substring(0, 2), 16) / 255\n const g = parseInt(clean.substring(2, 4), 16) / 255\n const b = parseInt(clean.substring(4, 6), 16) / 255\n\n // sRGB to linear\n const toLinear = (c: number): number =>\n c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4\n const luminance = 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b)\n\n return luminance > 0.4 ? '#1a1a1a' : '#ffffff'\n}\n\n// ---------------------------------------------------------------------------\n// Primary shades\n// ---------------------------------------------------------------------------\n\nexport interface PrimaryShades {\n lightest: string\n lighter: string\n light: string\n base: string\n dark: string\n darker: string\n darkest: string\n tint: string\n tintHover: string\n tintPressed: string\n ink: string\n}\n\n/** Универсальный генератор 11-ступенчатой шкалы от одного hex. */\nexport function generateShades(\n hex: string,\n bg: string = '#ffffff',\n text: string = '#000000'\n): PrimaryShades {\n return generatePrimaryShades(hex, bg, text)\n}\n\nexport function generatePrimaryShades(\n hex: string,\n bg: string = '#ffffff',\n text: string = '#000000'\n): PrimaryShades {\n const hsl = hexToHsl(hex)\n\n const clamp = (v: number): number => Math.min(1, Math.max(0, v))\n\n // For very dark colors (l < 0.15), dark shades go UP (lighten)\n // because you can't darken black — multiplying 0 by anything stays 0\n const isVeryDark = hsl.l < 0.15\n const dark = isVeryDark ? clamp(hsl.l + 0.12) : clamp(hsl.l * 0.85)\n const darker = isVeryDark ? clamp(hsl.l + 0.08) : clamp(hsl.l * 0.65)\n const darkest = isVeryDark ? clamp(hsl.l + 0.05) : clamp(hsl.l * 0.45)\n\n return {\n lightest: hslToHex({ h: hsl.h, s: hsl.s * 0.3, l: clamp(0.92) }),\n lighter: hslToHex({ h: hsl.h, s: hsl.s * 0.5, l: clamp(0.8) }),\n light: hslToHex({ h: hsl.h, s: hsl.s * 0.7, l: clamp(hsl.l + (1 - hsl.l) * 0.4) }),\n base: hex,\n dark: hslToHex({ h: hsl.h, s: hsl.s, l: dark }),\n darker: hslToHex({ h: hsl.h, s: hsl.s, l: darker }),\n darkest: hslToHex({ h: hsl.h, s: hsl.s, l: darkest }),\n tint: mixColorsRgb(bg, hex, 14),\n tintHover: mixColorsRgb(mixColorsRgb(bg, hex, 14), bg, 34),\n tintPressed: mixColorsRgb(bg, hex, 5),\n ink: mixColorsRgb(text, hex, 44),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Build complete CSS variable map from core colors\n// ---------------------------------------------------------------------------\n\nexport function buildCssVariableMap(config: ThemeColorConfig): Record<string, string> {\n const bg = config.background\n const text = config.text\n const shades = generatePrimaryShades(config.primary, bg, text)\n const secondaryShades = generateShades(config.secondary, bg, text)\n\n const vars: Record<string, string> = {\n // Primary palette\n '--zenky-primary-lightest': shades.lightest,\n '--zenky-primary-lighter': shades.lighter,\n '--zenky-primary-light': shades.light,\n '--zenky-primary': shades.base,\n '--zenky-primary-dark': shades.dark,\n '--zenky-primary-darker': shades.darker,\n '--zenky-primary-darkest': shades.darkest,\n '--zenky-primary-tint': shades.tint,\n '--zenky-primary-tint-hover': shades.tintHover,\n '--zenky-primary-tint-pressed': shades.tintPressed,\n '--zenky-primary-ink': shades.ink,\n\n // Secondary palette\n '--zenky-secondary-lightest': secondaryShades.lightest,\n '--zenky-secondary-lighter': secondaryShades.lighter,\n '--zenky-secondary-light': secondaryShades.light,\n '--zenky-secondary': secondaryShades.base,\n '--zenky-secondary-dark': secondaryShades.dark,\n '--zenky-secondary-darker': secondaryShades.darker,\n '--zenky-secondary-darkest': secondaryShades.darkest,\n\n // Auto-contrast for secondary\n '--zenky-on-secondary': getContrastColor(config.secondary),\n\n // Accent\n '--zenky-accent': config.accent,\n '--zenky-accent-tint': mixColorsRgb(bg, config.accent, 14),\n '--zenky-accent-tint-hover': mixColorsRgb(mixColorsRgb(bg, config.accent, 14), bg, 34),\n '--zenky-accent-tint-pressed': mixColorsRgb(bg, config.accent, 5),\n '--zenky-accent-ink': mixColorsRgb(text, config.accent, 44),\n '--zenky-bg': bg,\n '--zenky-text': text,\n\n // Цвет текста поверх primary: ручная настройка или авто-контраст\n '--zenky-on-primary': config.onPrimary || getContrastColor(config.primary),\n '--zenky-on-accent': getContrastColor(config.accent),\n\n // Derived text shades\n '--zenky-text-muted': mixColors(bg, text, 50),\n '--zenky-text-light': mixColors(bg, text, 35),\n\n // Derived borders\n '--zenky-border-light': mixColors(bg, text, 6),\n '--zenky-border': mixColors(bg, text, 12),\n '--zenky-border-strong': mixColors(bg, text, 35),\n\n // Derived surfaces\n '--zenky-surface-secondary': mixColors(bg, text, 5),\n '--zenky-surface-secondary-hover': mixColors(bg, text, 10),\n '--zenky-surface-active': mixColors(bg, config.primary, 8),\n '--zenky-surface-dark':\n getContrastColor(bg) === '#ffffff'\n ? adjustLightness(bg, 0.08)\n : adjustLightness(text, -0.1),\n '--zenky-control-active': mixColors(bg, text, 80),\n '--zenky-surface-elevated': adjustLightness(bg, 0.06),\n\n // Status (defaults if not provided)\n '--zenky-success': config.success ?? '#22c55e',\n '--zenky-danger': config.danger ?? '#ef4444',\n '--zenky-warning': config.warning ?? '#f59e0b',\n '--zenky-info': config.info ?? '#3b82f6',\n\n // Component semantic (auto-derived with optional overrides)\n '--zenky-header-bg': config.headerBg ?? adjustLightness(bg, -0.02),\n '--zenky-nav-bg': config.headerBg ?? adjustLightness(bg, -0.02),\n '--zenky-footer-bg': config.footerBg ?? adjustLightness(bg, -0.03),\n '--zenky-footer-text': config.footerText ?? mixColors(bg, text, 70),\n '--zenky-footer-text-muted': config.footerTextMuted ?? mixColors(bg, text, 40),\n }\n\n return vars\n}\n","import { computed, type ComputedRef } from 'vue'\n\nimport { buildCssVariableMap, type ThemeColorConfig } from './colors'\n\nexport interface FontConfig {\n family: string\n url: string\n}\n\nexport interface ThemeData {\n cssVariables: ComputedRef<Record<string, string>>\n fontFamily: ComputedRef<string | null>\n fontUrl: ComputedRef<string | null>\n}\n\n/** CSS-переменные темы + шрифт из цвето-/шрифто-конфига (инъекция в head — на стороне app). */\nexport function useTheme(colorConfig: ThemeColorConfig, fontConfig: FontConfig): ThemeData {\n const cssVariables = computed<Record<string, string>>(() => {\n const vars = buildCssVariableMap(colorConfig)\n\n if (fontConfig.family) {\n const stack = `'${fontConfig.family}', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif`\n vars['--zenky-font-sans'] = stack\n }\n\n return vars\n })\n\n const fontFamily = computed<string | null>(() => fontConfig.family || null)\n const fontUrl = computed<string | null>(() => fontConfig.url || null)\n\n return {\n cssVariables,\n fontFamily,\n fontUrl,\n }\n}\n"]}
@@ -41,5 +41,5 @@ function getRemoteCatalog(store, city, stock) {
41
41
  }
42
42
 
43
43
  export { getCity, getRemoteCatalog, getStock };
44
- //# sourceMappingURL=chunk-EYRCAUUP.js.map
45
- //# sourceMappingURL=chunk-EYRCAUUP.js.map
44
+ //# sourceMappingURL=chunk-E3G7NGCH.js.map
45
+ //# sourceMappingURL=chunk-E3G7NGCH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/catalog/catalogResolver.ts"],"names":[],"mappings":";AAEO,SAAS,OAAA,CAAQ,OAAc,MAAA,EAAqC;AACvE,EAAA,IAAI,CAAC,KAAA,CAAM,MAAA,CAAO,MAAA,EAAQ,OAAO,IAAA;AAEjC,EAAA,MAAM,WAAA,GAAc,KAAA,CAAM,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,CAAA,IAAK,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,IAAK,IAAA;AAEjF,EAAA,IAAI,CAAC,QAAQ,OAAO,WAAA;AAEpB,EAAA,OAAO,KAAA,CAAM,OAAO,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,EAAA,KAAO,MAAM,CAAA,IAAK,WAAA;AACxD;AAEO,SAAS,QAAA,CAAS,MAAY,OAAA,EAAuC;AACxE,EAAA,IAAI,CAAC,IAAA,CAAK,MAAA,EAAQ,MAAA,EAAQ,OAAO,IAAA;AAEjC,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,IAAK,IAAA;AAEvC,EAAA,IAAI,CAAC,SAAS,OAAO,YAAA;AAErB,EAAA,OAAO,IAAA,CAAK,OAAO,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,EAAA,KAAO,OAAO,CAAA,IAAK,YAAA;AACxD;AAEO,SAAS,gBAAA,CACZ,KAAA,EACA,IAAA,EACA,KAAA,EACoB;AACpB,EAAA,IAAI,CAAC,KAAA,CAAM,QAAA,CAAS,MAAA,EAAQ;AACxB,IAAA,OAAA,CAAQ,KAAK,4CAAA,EAA8C;AAAA,MACvD,SAAS,KAAA,CAAM,EAAA;AAAA,MACf,QAAQ,IAAA,CAAK,EAAA;AAAA,MACb,OAAA,EAAS,OAAO,EAAA,IAAM;AAAA,KACzB,CAAA;AACD,IAAA,OAAO,IAAA;AAAA,EACX;AAGA,EAAA,IAAI,KAAA,EAAO;AACP,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,KAAY,IAAA,CAAK,EAAA,IAAM,CAAA,CAAE,QAAA,KAAa,MAAM,EAAE,CAAA;AACzF,IAAA,IAAI,OAAO,OAAO,KAAA;AAAA,EACtB;AAEA,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,KAAY,IAAA,CAAK,EAAA,IAAM,CAAA,CAAE,QAAA,KAAa,IAAI,CAAA;AACxF,EAAA,IAAI,UAAU,OAAO,QAAA;AAErB,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,KAAY,IAAA,IAAQ,CAAA,CAAE,QAAA,KAAa,IAAI,CAAA;AACnF,EAAA,IAAI,QAAQ,OAAO,MAAA;AAEnB,EAAA,OAAA,CAAQ,KAAK,gEAAA,EAAkE;AAAA,IAC3E,SAAS,KAAA,CAAM,EAAA;AAAA,IACf,QAAQ,IAAA,CAAK,EAAA;AAAA,IACb,OAAA,EAAS,OAAO,EAAA,IAAM,IAAA;AAAA,IACtB,iBAAA,EAAmB,KAAA,CAAM,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,MAC1C,SAAS,CAAA,CAAE,OAAA;AAAA,MACX,UAAU,CAAA,CAAE;AAAA,KAChB,CAAE;AAAA,GACL,CAAA;AAED,EAAA,OAAO,IAAA;AACX","file":"chunk-E3G7NGCH.js","sourcesContent":["import type { City, RemoteCatalog, Stock, Store } from '@zenky/storefront-api'\n\nexport function getCity(store: Store, cityId?: string | null): City | null {\n if (!store.cities.length) return null\n\n const defaultCity = store.cities.find((c) => c.is_default) ?? store.cities[0] ?? null\n\n if (!cityId) return defaultCity\n\n return store.cities.find((c) => c.id === cityId) ?? defaultCity\n}\n\nexport function getStock(city: City, stockId?: string | null): Stock | null {\n if (!city.stocks?.length) return null\n\n const defaultStock = city.stocks[0] ?? null\n\n if (!stockId) return defaultStock\n\n return city.stocks.find((s) => s.id === stockId) ?? defaultStock\n}\n\nexport function getRemoteCatalog(\n store: Store,\n city: City,\n stock: Stock | null\n): RemoteCatalog | null {\n if (!store.catalogs.length) {\n console.warn('[catalog-resolver] store.catalogs is empty', {\n storeId: store.id,\n cityId: city.id,\n stockId: stock?.id ?? null,\n })\n return null\n }\n\n // Приоритет: точное совпадение city+stock → city-only → глобальный.\n if (stock) {\n const exact = store.catalogs.find((c) => c.city_id === city.id && c.stock_id === stock.id)\n if (exact) return exact\n }\n\n const cityOnly = store.catalogs.find((c) => c.city_id === city.id && c.stock_id === null)\n if (cityOnly) return cityOnly\n\n const global = store.catalogs.find((c) => c.city_id === null && c.stock_id === null)\n if (global) return global\n\n console.warn('[catalog-resolver] no catalog matched (exact/city-only/global)', {\n storeId: store.id,\n cityId: city.id,\n stockId: stock?.id ?? null,\n availableCatalogs: store.catalogs.map((c) => ({\n city_id: c.city_id,\n stock_id: c.stock_id,\n })),\n })\n\n return null\n}\n"]}