@osimart/create-storefront 0.0.0-stage → 1.0.0
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.
- package/README.md +80 -2
- package/THEME_DEV_API.md +80 -0
- package/app/app.vue +154 -0
- package/app/assets/css/osi-controls.css +824 -0
- package/app/components/SectionRenderer.vue +46 -0
- package/app/components/builder/BuilderOverlay.vue +582 -0
- package/app/components/checkout/ExtraFees.vue +329 -0
- package/app/components/checkout/PaymentHandoff.vue +388 -0
- package/app/components/common/Banner.vue +35 -0
- package/app/components/common/ConfirmDeleteModal.vue +117 -0
- package/app/components/common/DropdownSelect.vue +432 -0
- package/app/components/common/Loader.vue +32 -0
- package/app/components/common/OsiField.vue +218 -0
- package/app/components/common/PhoneNumInput.vue +434 -0
- package/app/composables/UseBodyScrollLock.js +122 -0
- package/app/composables/UseThemeGroup.js +575 -0
- package/app/composables/useAddToCart.js +87 -0
- package/app/composables/useAnalytics.js +15 -0
- package/app/composables/useAnnouncements.js +29 -0
- package/app/composables/useApiErrorToast.js +104 -0
- package/app/composables/useAuth.js +99 -0
- package/app/composables/useBanners.js +25 -0
- package/app/composables/useBuilderPreview.js +320 -0
- package/app/composables/useButtonStyle.js +107 -0
- package/app/composables/useCarousel.js +160 -0
- package/app/composables/useCart.js +109 -0
- package/app/composables/useCheckout.js +76 -0
- package/app/composables/useClassificationItems.js +269 -0
- package/app/composables/useClassificationPage.js +545 -0
- package/app/composables/useClassificationUrl.js +63 -0
- package/app/composables/useColorScheme.js +44 -0
- package/app/composables/useContactForm.js +53 -0
- package/app/composables/useContentTree.js +770 -0
- package/app/composables/useDragScroll.js +73 -0
- package/app/composables/useFooterSocials.js +107 -0
- package/app/composables/useInputStyle.js +45 -0
- package/app/composables/useLayoutShell.js +114 -0
- package/app/composables/useLazyVideo.js +36 -0
- package/app/composables/useMediaTypes.js +66 -0
- package/app/composables/useMediaUrl.js +71 -0
- package/app/composables/useMenu.js +100 -0
- package/app/composables/useNavStyle.js +219 -0
- package/app/composables/usePlaceholders.js +294 -0
- package/app/composables/usePolicies.js +26 -0
- package/app/composables/useProductCardMedia.js +135 -0
- package/app/composables/useProductCardStyle.js +132 -0
- package/app/composables/useProductDetail.js +982 -0
- package/app/composables/useProductGallery.js +166 -0
- package/app/composables/useProductItems.js +270 -0
- package/app/composables/useProductUrl.js +60 -0
- package/app/composables/useProductVariants.js +210 -0
- package/app/composables/useQuickShop.js +115 -0
- package/app/composables/useRelatedProducts.js +186 -0
- package/app/composables/useRenderContext.js +45 -0
- package/app/composables/useScopedCss.js +106 -0
- package/app/composables/useSearch.js +35 -0
- package/app/composables/useSectionData.js +462 -0
- package/app/composables/useSectionShell.js +113 -0
- package/app/composables/useSidebar.js +69 -0
- package/app/composables/useStoreData.js +57 -0
- package/app/composables/useStoreInit.js +52 -0
- package/app/composables/useStorefront.js +239 -0
- package/app/composables/useT.js +21 -0
- package/app/composables/useTextStyles.js +84 -0
- package/app/composables/useThemeControls.js +34 -0
- package/app/composables/useThemeSeo.js +91 -0
- package/app/composables/useThemeTokens.js +171 -0
- package/app/composables/useWishlist.js +66 -0
- package/app/logic/components/AnnouncementBar.js +118 -0
- package/app/logic/components/CardGrid.js +125 -0
- package/app/logic/components/CardList.js +98 -0
- package/app/logic/components/CartDrawer.js +273 -0
- package/app/logic/components/CartItem.js +31 -0
- package/app/logic/components/ClassificationBento.js +6 -0
- package/app/logic/components/ClassificationCard.js +6 -0
- package/app/logic/components/ClassificationCarousel.js +115 -0
- package/app/logic/components/ClassificationEditorial.js +41 -0
- package/app/logic/components/ClassificationFeatured.js +57 -0
- package/app/logic/components/ClassificationGrid.js +6 -0
- package/app/logic/components/ClassificationNav.js +61 -0
- package/app/logic/components/ClassificationPart.js +72 -0
- package/app/logic/components/FooterBlock.js +91 -0
- package/app/logic/components/FooterSocials.js +60 -0
- package/app/logic/components/HeaderDropdownList.js +29 -0
- package/app/logic/components/HeaderIcon.js +68 -0
- package/app/logic/components/HeaderLogo.js +39 -0
- package/app/logic/components/HeaderNav.js +268 -0
- package/app/logic/components/MobileMenu.js +280 -0
- package/app/logic/components/ProductBuyButtons.js +66 -0
- package/app/logic/components/ProductCard.js +160 -0
- package/app/logic/components/ProductFilters.js +37 -0
- package/app/logic/components/ProductGallery.js +19 -0
- package/app/logic/components/ProductInfoBlock.js +411 -0
- package/app/logic/components/ProductLightbox.js +12 -0
- package/app/logic/components/ProductQuantity.js +31 -0
- package/app/logic/components/ProductVariantPicker.js +125 -0
- package/app/logic/components/QuickBuy.js +194 -0
- package/app/logic/components/SearchOverlay.js +41 -0
- package/app/logic/components/SidebarMenuItem.js +39 -0
- package/app/logic/components/SiteFooter.js +476 -0
- package/app/logic/components/SiteHeader.js +266 -0
- package/app/logic/components/WhatsAppButton.js +75 -0
- package/app/logic/layouts/default.js +66 -0
- package/app/logic/sections/AnnouncementBarSection.js +6 -0
- package/app/logic/sections/BlockCarousel.js +103 -0
- package/app/logic/sections/ClassificationListSection.js +40 -0
- package/app/logic/sections/ContactFormSection.js +294 -0
- package/app/logic/sections/ContactInfoSection.js +419 -0
- package/app/logic/sections/ContentNode.js +189 -0
- package/app/logic/sections/CountdownSection.js +254 -0
- package/app/logic/sections/CustomHtmlSection.js +51 -0
- package/app/logic/sections/DividerSection.js +31 -0
- package/app/logic/sections/FaqSection.js +53 -0
- package/app/logic/sections/FeatureListSection.js +6 -0
- package/app/logic/sections/FeaturedProductSection.js +40 -0
- package/app/logic/sections/FooterSection.js +16 -0
- package/app/logic/sections/FooterUtilitiesSection.js +24 -0
- package/app/logic/sections/GallerySection.js +232 -0
- package/app/logic/sections/HeaderSection.js +24 -0
- package/app/logic/sections/HeroSection.js +24 -0
- package/app/logic/sections/LogoListSection.js +6 -0
- package/app/logic/sections/MainClassificationSection.js +473 -0
- package/app/logic/sections/MainProductSection.js +211 -0
- package/app/logic/sections/MainSearchSection.js +6 -0
- package/app/logic/sections/MapSection.js +92 -0
- package/app/logic/sections/MediaContentSection.js +38 -0
- package/app/logic/sections/MediaWithTextSection.js +238 -0
- package/app/logic/sections/NewsletterSection.js +126 -0
- package/app/logic/sections/ProductHighlightSection.js +201 -0
- package/app/logic/sections/ProductListSection.js +45 -0
- package/app/logic/sections/ProductRecommendationsSection.js +113 -0
- package/app/logic/sections/RichTextSection.js +6 -0
- package/app/logic/sections/ScrollingTextSection.js +69 -0
- package/app/logic/sections/SearchHeaderSection.js +22 -0
- package/app/logic/sections/SlideshowSection.js +118 -0
- package/app/logic/sections/SpacerSection.js +37 -0
- package/app/logic/sections/SplitShowcaseSection.js +6 -0
- package/app/logic/sections/TestimonialListSection.js +6 -0
- package/app/logic/sections/VideoSection.js +235 -0
- package/app/pages/[category]/[product].vue +196 -0
- package/app/pages/__builder-preview.vue +38 -0
- package/app/pages/categories/[slug].vue +208 -0
- package/app/pages/checkout.vue +1972 -0
- package/app/pages/forgot-password.vue +115 -0
- package/app/pages/index.vue +64 -0
- package/app/pages/login.vue +585 -0
- package/app/pages/order-detail.vue +442 -0
- package/app/pages/pages/[handle].vue +58 -0
- package/app/pages/privacy-policy.vue +46 -0
- package/app/pages/resetpassword.vue +138 -0
- package/app/pages/resetverificationcode.vue +163 -0
- package/app/pages/result.vue +203 -0
- package/app/pages/return-policy.vue +50 -0
- package/app/pages/search.vue +100 -0
- package/app/pages/shipping-policy.vue +46 -0
- package/app/pages/user-profile/components/AddAddressModal.vue +452 -0
- package/app/pages/user-profile/components/Whishlist.vue +137 -0
- package/app/pages/user-profile/components/left-bar.vue +233 -0
- package/app/pages/user-profile/components/orders.vue +162 -0
- package/app/pages/user-profile/components/profile-details.vue +566 -0
- package/app/pages/user-profile/components/settings.vue +194 -0
- package/app/pages/user-profile/index.vue +252 -0
- package/app/pages/verificationcode.vue +188 -0
- package/app/plugins/analytics.client.js +99 -0
- package/app/plugins/geo.ts +24 -0
- package/app/plugins/reveal.client.js +53 -0
- package/app/plugins/toast.js +10 -0
- package/app/plugins/vue-query.ts +5 -0
- package/app/services/ApiServices.js +74 -0
- package/app/services/AuthBus.js +162 -0
- package/app/services/Authentication/AuthenticationService.js +133 -0
- package/app/services/Authentication/TokenService.js +62 -0
- package/app/services/CartServices.js +91 -0
- package/app/services/CartToken.js +26 -0
- package/app/services/CategoryServices.js +54 -0
- package/app/services/CheckoutServices.js +113 -0
- package/app/services/HomeServices.js +133 -0
- package/app/services/NewsletterServices.js +29 -0
- package/app/services/PaymentServices.js +71 -0
- package/app/services/PoliciesServices.js +16 -0
- package/app/services/ProductServices.js +79 -0
- package/app/services/SearchServices.js +18 -0
- package/app/services/UserServices.js +105 -0
- package/app/services/UtilsServices.js +46 -0
- package/app/services/WishlistServices.js +51 -0
- package/app/services/storefront.service.js +57 -0
- package/app/stores/userStore.js +13 -0
- package/app/theme/categoryTree.js +68 -0
- package/app/theme/controls.js +88 -0
- package/app/theme/registry.js +56 -0
- package/app/utils/analytics.js +864 -0
- package/app/utils/device.js +50 -0
- package/app/utils/eventBus.js +24 -0
- package/app/utils/icon-presets.js +24 -0
- package/app/utils/productOffers.js +118 -0
- package/app/utils/requestCache.js +36 -0
- package/app/utils/scrollToError.js +59 -0
- package/app/utils/toPlainError.js +30 -0
- package/bin/osimart-theme.mjs +259 -0
- package/nuxt/osi-sections.ts +56 -0
- package/nuxt.config.ts +60 -0
- package/package.json +43 -3
- package/public/css/input.css +29 -0
- package/public/css/output.css +2716 -0
- package/public/favicon-32x32.png +0 -0
- package/public/robots.txt +2 -0
package/README.md
CHANGED
|
@@ -1,3 +1,81 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @osimart/osimart-storefront
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The Osimart storefront **platform**, published as a private Nuxt layer. It has no look of
|
|
4
|
+
its own. Every theme repo extends it:
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
// osimart-theme-base/nuxt.config.ts, store-offsiders/nuxt.config.ts, …
|
|
8
|
+
export default defineNuxtConfig({ extends: ["@osimart/create-storefront"] });
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
| | Shopify | Osimart |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| Platform (hidden, updates everyone) | Shopify's servers | this package |
|
|
14
|
+
| Theme (Dawn) | sections, snippets, layout, assets | `osimart-theme-base` repo |
|
|
15
|
+
| Theme JSON | `templates/*.json`, `sections/*-group.json`, `config/settings_data.json` | `theme/` in the theme repo, `osimart-theme pull/push` |
|
|
16
|
+
| A store's custom theme | copy of Dawn | a repo created from `osimart-theme-base` |
|
|
17
|
+
|
|
18
|
+
## What's here
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
app/
|
|
22
|
+
├── logic/ the script of every theme file — the theme only imports it
|
|
23
|
+
│ ├── sections/ HeroSection.js, MainProductSection.js, … (#logic/sections/…)
|
|
24
|
+
│ ├── components/ ProductCard.js, SiteHeader.js, … (#logic/components/…)
|
|
25
|
+
│ └── layouts/default.js
|
|
26
|
+
├── composables/ services/ utils/ stores/ plugins/
|
|
27
|
+
├── pages/ routes: index, [category]/[product], categories/[slug], search,
|
|
28
|
+
│ pages/[handle] (each = "render this path's template");
|
|
29
|
+
│ checkout, login, user-profile, order-detail… (platform pages)
|
|
30
|
+
├── components/ platform UI: SectionRenderer, builder/, checkout/,
|
|
31
|
+
│ common/ (OsiField, PhoneNumInput, DropdownSelect, Banner…)
|
|
32
|
+
├── theme/ registry.js (section map), controls.js, categoryTree.js
|
|
33
|
+
└── app.vue
|
|
34
|
+
bin/osimart-theme.mjs CLI: themes / pull / push / publish
|
|
35
|
+
nuxt/osi-sections.ts builds the section map from the theme's app/sections
|
|
36
|
+
THEME_DEV_API.md the backend endpoints the CLI calls
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
A theme section looks like this — markup and CSS in the theme, logic from here:
|
|
40
|
+
|
|
41
|
+
```vue
|
|
42
|
+
<script setup>
|
|
43
|
+
import useLogic from "#logic/sections/HeroSection";
|
|
44
|
+
|
|
45
|
+
const props = defineProps({ section: Object, index: Number });
|
|
46
|
+
const { asBanner } = useLogic({ props });
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<template><MediaWithTextSection :section="asBanner" :index="index" /></template>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`useLogic` returns everything the original `<script setup>` declared, so the template can use
|
|
53
|
+
any of it. Changing the logic changes every theme after its next build; the theme's markup
|
|
54
|
+
and CSS are untouched.
|
|
55
|
+
|
|
56
|
+
## Rules for code in this package
|
|
57
|
+
|
|
58
|
+
- Never import with `~/` — inside a layer it means the theme. Use `#osi/…` (this `app/`),
|
|
59
|
+
`#logic/…`, or `#components` (which picks the theme's component when it has one).
|
|
60
|
+
- `useLogic` return keys are the theme's API. Adding a key is a minor release; renaming or
|
|
61
|
+
removing one breaks themes, so it's a major.
|
|
62
|
+
- A logic file with a top-level `await` wraps it in `withAsyncContext` (already done for
|
|
63
|
+
`AnnouncementBar.js`) so composables after it still have the component instance.
|
|
64
|
+
|
|
65
|
+
## Releasing
|
|
66
|
+
|
|
67
|
+
1. Bump `version` (semver): patch/minor for fixes and additions, **major** if a `useLogic`
|
|
68
|
+
key, a component's props or a route changes.
|
|
69
|
+
2. `git tag v1.4.0 && git push --tags` → `release.yml` publishes to GitHub Packages and sends
|
|
70
|
+
`storefront-release` to every repo in `STORE_REPOS`; each one updates and redeploys.
|
|
71
|
+
|
|
72
|
+
Repo setup once: secret `STORES_DISPATCH_TOKEN` (fine-grained PAT, contents read/write on the
|
|
73
|
+
theme repos), variable `STORE_REPOS` (`ositcom/osimart-theme-base ositcom/store-offsiders`).
|
|
74
|
+
Package settings: *Manage Actions access* → every theme repo; *Manage access* → each outside
|
|
75
|
+
developer (read).
|
|
76
|
+
|
|
77
|
+
## Working on the platform and a theme together
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
cd osimart-theme-base && npm link ../osimart-storefront && npm run dev
|
|
81
|
+
```
|
package/THEME_DEV_API.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Theme dev API (backend contract for `osimart-theme`)
|
|
2
|
+
|
|
3
|
+
All under `theme-dev/` on the store's API host. The host picks the store, as for every
|
|
4
|
+
storefront call.
|
|
5
|
+
|
|
6
|
+
**Auth:** `Authorization: ThemeToken <token>`. The `ThemeAccessToken` belongs to one store
|
|
7
|
+
(hashed, revocable, created in the dashboard). Anything else gets `401`.
|
|
8
|
+
|
|
9
|
+
`<theme>` is either a theme id, `live` (the published theme) or `draft`.
|
|
10
|
+
|
|
11
|
+
## Existing (from the theme access work)
|
|
12
|
+
|
|
13
|
+
| Method | Path | Used by |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| GET | `theme-dev/schemas/` | `pull` → `.osimart/schemas.json` |
|
|
16
|
+
| POST | `theme-dev/sections/sync/` | `push`: the theme's `*Section.schema.json` → `StoreSection` (`managed_by=CODE`) |
|
|
17
|
+
|
|
18
|
+
`sections/sync/` body: `{ sections: [{ type, name, group?, allowed_templates, schema: { settings, blocks, max_blocks? } }], prune, dry_run }`.
|
|
19
|
+
Response: `{ created, updated, unchanged, deleted, kept_in_use }` (lists of types).
|
|
20
|
+
|
|
21
|
+
## New
|
|
22
|
+
|
|
23
|
+
### `GET theme-dev/themes/`
|
|
24
|
+
```json
|
|
25
|
+
[{ "id": "uuid", "name": "Base", "role": "LIVE", "updated_at": "…" },
|
|
26
|
+
{ "id": "uuid", "name": "Base (draft)", "role": "DRAFT", "updated_at": "…" }]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### `GET theme-dev/theme/?theme=<theme>`
|
|
30
|
+
The theme's JSON exactly as stored, so a push of the same data is a no-op.
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"theme": { "id": "uuid", "name": "Base", "role": "LIVE", "version": "2026-10-12T13:40:11.120Z" },
|
|
34
|
+
"settings": { "PRIMARY_COLOR": "#20336b" },
|
|
35
|
+
"groups": {
|
|
36
|
+
"header": { "sections": [ { "key": "…", "type": "HEADER", "settings": {}, "blocks": [], "disabled": false } ] },
|
|
37
|
+
"footer": { "sections": [ … ] }
|
|
38
|
+
},
|
|
39
|
+
"templates": [
|
|
40
|
+
{ "type": "INDEX", "suffix": "", "data": { "sections": [ … ] } },
|
|
41
|
+
{ "type": "PRODUCT", "suffix": "alternate", "data": { "sections": [ … ] } },
|
|
42
|
+
{ "type": "PAGE", "suffix": "contact", "data": { "sections": [ … ] } }
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
- `version` is any value that changes on every save of the theme, its templates or its groups
|
|
47
|
+
(`updated_at` of the newest row works).
|
|
48
|
+
- `data` holds what the template stores (section order, settings, blocks); media stay as the
|
|
49
|
+
ids the dashboard saves, not resolved URLs.
|
|
50
|
+
|
|
51
|
+
### `PUT theme-dev/theme/`
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"theme": "draft",
|
|
55
|
+
"base_version": "2026-10-12T13:40:11.120Z",
|
|
56
|
+
"dry_run": false,
|
|
57
|
+
"settings": { … },
|
|
58
|
+
"groups": { "header": { … }, "footer": { … } },
|
|
59
|
+
"templates": [ { "type": "PRODUCT", "suffix": "alternate", "data": { … } } ]
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
- `theme: "draft"`: use the store's draft. If there is none, copy the live theme into a new
|
|
63
|
+
draft first (the same as a theme update, so the live theme stays as the rollback).
|
|
64
|
+
- `base_version` not null and different from the theme's current `version` → `409`
|
|
65
|
+
(the merchant changed it in the dashboard after the pull). `null` = overwrite.
|
|
66
|
+
- Any key left out (`settings`, `groups`, a template) is left as it is. Templates are
|
|
67
|
+
created or replaced by `(type, suffix)` and never deleted here.
|
|
68
|
+
- Validate everything the dashboard validates (`get_section_schemas(store)`: section types,
|
|
69
|
+
setting ids, block types, `visible_if`) and answer `400` with field errors. On `dry_run`,
|
|
70
|
+
validate and report only.
|
|
71
|
+
- Response:
|
|
72
|
+
```json
|
|
73
|
+
{ "theme": { "id": "uuid", "name": "…", "role": "DRAFT", "version": "…" },
|
|
74
|
+
"created": ["PRODUCT.alternate"], "updated": ["INDEX"], "unchanged": ["PRODUCT"],
|
|
75
|
+
"preview_url": "https://store.com/?preview_theme=<id>" }
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### `POST theme-dev/themes/<id>/publish/`
|
|
79
|
+
Makes that theme live (the previous live one becomes unpublished). Returns the theme
|
|
80
|
+
(`{ id, name, role }`).
|
package/app/app.vue
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
// Global on purpose: every button and field in the storefront reads it.
|
|
3
|
+
import "#osi/assets/css/osi-controls.css";
|
|
4
|
+
import { parseIds } from "#osi/utils/analytics";
|
|
5
|
+
|
|
6
|
+
const { load, dir, store, error } = useStorefront();
|
|
7
|
+
const { tokens, rootClasses, fontLinks } = useThemeTokens();
|
|
8
|
+
const { start: startBuilderPreview, stop: stopBuilderPreview } = useBuilderPreview();
|
|
9
|
+
|
|
10
|
+
const { error: fetchError } = await useAsyncData("storefront", () => load());
|
|
11
|
+
const shown = computed(() => error.value ?? fetchError.value ?? null);
|
|
12
|
+
|
|
13
|
+
const isDev = import.meta.dev;
|
|
14
|
+
|
|
15
|
+
onMounted(() => {
|
|
16
|
+
if (!import.meta.client) return;
|
|
17
|
+
let isFramed = false;
|
|
18
|
+
try {
|
|
19
|
+
isFramed = window.parent !== window || window.self !== window.top;
|
|
20
|
+
} catch {
|
|
21
|
+
isFramed = true;
|
|
22
|
+
}
|
|
23
|
+
const route = useRoute();
|
|
24
|
+
if (
|
|
25
|
+
isFramed ||
|
|
26
|
+
route?.path?.includes("__builder-preview") ||
|
|
27
|
+
route?.query?.osi_preview !== undefined ||
|
|
28
|
+
route?.query?.preview !== undefined
|
|
29
|
+
) {
|
|
30
|
+
startBuilderPreview();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
onBeforeUnmount(() => {
|
|
35
|
+
stopBuilderPreview();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Favicon, title format, default description / share image, custom CSS.
|
|
39
|
+
useThemeSeo();
|
|
40
|
+
|
|
41
|
+
useHead({
|
|
42
|
+
htmlAttrs: computed(() => ({ dir: dir.value })),
|
|
43
|
+
noscript: computed(() =>
|
|
44
|
+
parseIds(store.value?.meta_pixel_id, "pixel").map((id) => ({
|
|
45
|
+
tagPosition: "bodyOpen",
|
|
46
|
+
innerHTML: `<img height="1" width="1" style="display:none" alt="" src="https://www.facebook.com/tr?id=${id}&ev=PageView&noscript=1" />`,
|
|
47
|
+
})),
|
|
48
|
+
),
|
|
49
|
+
bodyAttrs: computed(() => ({
|
|
50
|
+
style: tokens.value,
|
|
51
|
+
class: rootClasses.value.filter((c) => /^osi-(btns|inputs|labels)/.test(c)),
|
|
52
|
+
})),
|
|
53
|
+
// A getter, not a snapshot: a font picked in the editor (or a theme that
|
|
54
|
+
// loads later) must add its stylesheet.
|
|
55
|
+
link: computed(() => [
|
|
56
|
+
...fontLinks.value,
|
|
57
|
+
{
|
|
58
|
+
rel: "stylesheet",
|
|
59
|
+
href: "/css/output.css",
|
|
60
|
+
},
|
|
61
|
+
]),
|
|
62
|
+
})
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<template>
|
|
66
|
+
<div v-if="shown" class="osi-fatal">
|
|
67
|
+
<p>This store isn't available right now.</p>
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
<pre v-if="isDev" class="osi-fatal-detail">{{ shown.status ? `HTTP ${shown.status} — ` : "" }}{{ shown.message }}<template v-if="shown.data">
|
|
71
|
+
{{ shown.data }}</template></pre>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div v-else class="osi-root" :class="rootClasses" :style="tokens" :dir="dir">
|
|
75
|
+
<NuxtLoadingIndicator
|
|
76
|
+
color="var(--osi-primary-color)"
|
|
77
|
+
error-color="#dc2626"
|
|
78
|
+
:height="3"
|
|
79
|
+
/>
|
|
80
|
+
<NuxtLayout>
|
|
81
|
+
<NuxtPage />
|
|
82
|
+
</NuxtLayout>
|
|
83
|
+
<div id="osi-teleport-root" />
|
|
84
|
+
</div>
|
|
85
|
+
</template>
|
|
86
|
+
|
|
87
|
+
<style>
|
|
88
|
+
body {
|
|
89
|
+
font-family: var(--osi-font-body);
|
|
90
|
+
font-size: var(--osi-body-size);
|
|
91
|
+
color: var(--osi-text, #121212);
|
|
92
|
+
background: var(--osi-bg, #ffffff);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.osi-root {
|
|
96
|
+
font-family: var(--osi-font-body);
|
|
97
|
+
font-size: var(--osi-body-size);
|
|
98
|
+
color: var(--osi-text, #121212);
|
|
99
|
+
background: var(--osi-bg, #ffffff);
|
|
100
|
+
}
|
|
101
|
+
/* Section padding: useSectionShell writes desktop and phone values as
|
|
102
|
+
variables; these pick the one that applies. */
|
|
103
|
+
.osi-section {
|
|
104
|
+
--osi-sec-pt-now: var(--osi-sec-pt);
|
|
105
|
+
--osi-sec-pb-now: var(--osi-sec-pb);
|
|
106
|
+
--osi-sec-pl-now: var(--osi-sec-pl);
|
|
107
|
+
--osi-sec-pr-now: var(--osi-sec-pr);
|
|
108
|
+
}
|
|
109
|
+
@media (max-width: 749px) {
|
|
110
|
+
.osi-section {
|
|
111
|
+
--osi-sec-pt-now: var(--osi-sec-pt-m, var(--osi-sec-pt));
|
|
112
|
+
--osi-sec-pb-now: var(--osi-sec-pb-m, var(--osi-sec-pb));
|
|
113
|
+
--osi-sec-pl-now: var(--osi-sec-pl-m, var(--osi-sec-pl));
|
|
114
|
+
--osi-sec-pr-now: var(--osi-sec-pr-m, var(--osi-sec-pr));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
.osi-root h1,
|
|
118
|
+
.osi-root h2,
|
|
119
|
+
.osi-root h3,
|
|
120
|
+
.osi-root h4,
|
|
121
|
+
.osi-root h5,
|
|
122
|
+
.osi-root h6 {
|
|
123
|
+
font-family: var(--osi-font-heading);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* The old utility classes (login, account, checkout, cart… ) carry fixed
|
|
127
|
+
families from output.css; point them at the theme's fonts. `body` in front
|
|
128
|
+
beats the single-class utility and still reaches teleported drawers,
|
|
129
|
+
which sit outside .osi-root. */
|
|
130
|
+
body .font-body,
|
|
131
|
+
body .font-poppins,
|
|
132
|
+
body .font-thoren {
|
|
133
|
+
font-family: var(--osi-font-body);
|
|
134
|
+
}
|
|
135
|
+
body .font-heading {
|
|
136
|
+
font-family: var(--osi-font-heading);
|
|
137
|
+
}
|
|
138
|
+
.osi-fatal {
|
|
139
|
+
padding: 4rem 1rem;
|
|
140
|
+
text-align: center;
|
|
141
|
+
font-family: system-ui, sans-serif;
|
|
142
|
+
}
|
|
143
|
+
.osi-fatal-detail {
|
|
144
|
+
display: inline-block;
|
|
145
|
+
margin-top: 1rem;
|
|
146
|
+
padding: 0.75rem 1rem;
|
|
147
|
+
text-align: start;
|
|
148
|
+
background: #fef2f2;
|
|
149
|
+
color: #991b1b;
|
|
150
|
+
border-radius: 6px;
|
|
151
|
+
font-size: 12px;
|
|
152
|
+
white-space: pre-wrap;
|
|
153
|
+
}
|
|
154
|
+
</style>
|