Source map
What lives in each directory of the Beauty Affairs AU theme, and what depends on what.
Source map
Repository root
| Path | Contents | Generated? |
|---|---|---|
layout/ | Six layouts. See Layouts and templates | No |
templates/ | 51 JSON templates, 59 Liquid templates, plus customers/ | JSON templates are written by the theme editor |
sections/ | Around 197 theme editor sections and section groups | No |
snippets/ | Around 280 Liquid fragments, including app-provided ones | vite-tag.liquid is generated |
blocks/ | 19 theme blocks | No |
config/ | settings_schema.json, settings_data.json, markets.json | settings_data.json and markets.json are written by Shopify |
locales/ | 11 translation files, en.default.json is the source | No |
assets/ | Compiled bundles plus older hand-written assets | Partly |
src/ | TypeScript, TSX and source CSS | No |
scripts/ | Node scripts for onboarding, deploys and the tunnel | No |
Inside src
src/
├── @types/ Ambient types and third-party SDK shapes
├── assets/ theme_in.css, the Tailwind entry
├── components/ Shared logic, imported by entrypoints
├── entrypoints/ One bundle per file
└── lib/ Small cross-cutting helpersOnly files under src/entrypoints/ become bundles. Everything else is imported.
src/@types
| File | Contents |
|---|---|
global.ts | The window.theme and window.Shopify shapes, and every global the theme sets |
shopify.ts | Shopify storefront object types: Product, Variant, Cart |
calendar.ts | Sesami SDK shape, calendar config, Klaviyo and Zapier payloads |
klaviyo.ts | Klaviyo globals |
vite-virtual.d.ts | Vite virtual module declarations |
global.ts is the most useful file in the repository for understanding what Liquid hands to JavaScript. Every
window.theme.* key that a Liquid file sets is declared there.
src/lib
| File | Contents |
|---|---|
logger.ts | The conditional console logger and namespace system |
cart-source.ts | The _source line item property convention |
utils.ts | createEnum |
src/components
One directory per feature. These hold logic that entrypoints import.
| Directory | Feature |
|---|---|
medispa-calendar/ | The React booking calendar, 12 components plus Jotai atoms |
popup-logic/ | Popup manager, timer, adapters and sniffers, popup definitions |
purchase-gift-manager/ | Multi-buy gift promotion logic |
cart-reward-banner/ | Homepage reward tier banner |
homepage-prominence-banner/ | Homepage gifts banner |
pack-options/ | Product pack size selection |
swatch-filters/ | Colour swatch filtering |
clickable-slideshow/ | Slideshow with clickable regions |
counter/ | Countdown and counting behaviour |
utils/ | defer and deferJS polling helpers, MediSpa landing page helpers |
In utils/defer.ts, defer(fn, selector) polls every 50 milliseconds until an element exists, and
deferJS(fn, validator) polls until a predicate is true. Both are exposed on window. The theme uses them to wait for
app scripts whose load order it cannot control.
src/entrypoints
Around 60 top-level entrypoints plus two subsystem directories.
| Path | Subsystem |
|---|---|
mini-cart/ | Cart drawer. internals/ for logic, elements/ for custom elements, components/ for features |
homepage-redesign/components/ | One entrypoint pair per homepage section |
medispa-*.ts | MediSpa landing page behaviours, one per section |
theme.css, styles.css, custom.css, theme.styles.css | Global stylesheets loaded by the layouts |
utils.ts | debounce, cn, and the money formatting helpers |
main.ts | Nothing but the Vite modulepreload polyfill |
Most entrypoints come in pairs. sections/hero-banner.liquid renders both
homepage-redesign/components/hero-banner.css and hero-banner.ts, so the styles load only where the section does.
The full mapping from Liquid file to entrypoint is in Entrypoint map.
How Liquid passes data to TypeScript
A feature uses one of four channels. Find the channel and you know where to look.
| Channel | How it works | Used by |
|---|---|---|
Global on window.theme | A Liquid snippet writes it and an entrypoint reads it. src/@types/global.ts declares keys | Booking calendar, reward banner |
| Data attribute | The custom element that owns the element reads it | Mini-cart section settings, for example data-open-on-add |
Custom event on window | Any script can dispatch it without importing anything | Mini-cart command events |
| Inline JSON script tag | Code queries it from the DOM | MediSpa treatment lists, one script[data-medispa-products-fragment] per Services Overview section |
Path aliases
tsconfig.json maps @/* and ~/* to ./src/*. Both work. @/ is more common in this codebase.
import { createLogger } from '@/lib/logger';snippets/vite-tag.liquid also rewrites ~/ and @/ prefixes to ../ when resolving an entrypoint path, so
render 'vite-tag' with '@/entrypoints/foo.ts' resolves the same as the bare path.
Key dependencies
| Package | Used by |
|---|---|
react, react-dom | Only the MediSpa booking calendar |
jotai | Only the booking calendar's shared state |
swiper | Carousels across the homepage and MediSpa pages |
date-fns | Date handling in the calendar |
clsx | The cn helper in src/entrypoints/utils.ts |
react-spinners | Calendar loading state |
Only the booking calendar uses React. Adding a second React island would double the bundle on pages that need it, so prefer a custom element unless the feature needs React.
jQuery is declared in tsconfig.json types and referenced from older assets, but it is not an npm dependency of src/.
The MediSpa landing pages were deliberately built without it.