@asksable/site-connector 0.4.2 → 0.6.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 +4 -4
- package/dist/analytics.d.ts.map +1 -1
- package/dist/analytics.js +1 -0
- package/dist/analytics.js.map +1 -1
- package/dist/bones/registry.js +1 -1
- package/dist/booking-widget.d.ts +4 -4
- package/dist/booking-widget.js +21 -21
- package/dist/styles.css +84 -66
- package/dist/translations.d.ts +2 -2
- package/dist/translations.js +2 -2
- package/dist/types.d.ts +25 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -152,7 +152,7 @@ function App() {
|
|
|
152
152
|
}
|
|
153
153
|
```
|
|
154
154
|
|
|
155
|
-
The widget responds instantly to language changes
|
|
155
|
+
The widget responds instantly to language changes. Your toggle component flips both the host site's text and the widget by sharing the same `language` state.
|
|
156
156
|
|
|
157
157
|
### Override individual strings (rare)
|
|
158
158
|
|
|
@@ -181,8 +181,8 @@ Form labels, button text, mobile step labels, helper text, success/cancelled sta
|
|
|
181
181
|
|
|
182
182
|
### What the widget does NOT translate
|
|
183
183
|
|
|
184
|
-
- **Service names, descriptions, category names
|
|
185
|
-
- **Customer-typed input
|
|
184
|
+
- **Service names, descriptions, category names**: these come from the Sable workspace. The widget reads `nameEn` / `nameEs` (or any `${field}En` / `${field}Es`) fields when available, falling back to the base field. If the workspace only entered one locale, that text renders regardless of UI language. (Future workstream: dashboard support for entering both locales.)
|
|
185
|
+
- **Customer-typed input**: names, notes, etc.
|
|
186
186
|
|
|
187
187
|
### Detecting locale in custom components
|
|
188
188
|
|
|
@@ -199,7 +199,7 @@ function MyComponent() {
|
|
|
199
199
|
|
|
200
200
|
### For template builders
|
|
201
201
|
|
|
202
|
-
Every Sable website template should include the `language` prop wiring as part of the boilerplate. If the template supports a toggle, the toggle component must flip both the host site's text and the widget by sharing the same language state. **Never let the widget and host site drift to different locales
|
|
202
|
+
Every Sable website template should include the `language` prop wiring as part of the boilerplate. If the template supports a toggle, the toggle component must flip both the host site's text and the widget by sharing the same language state. **Never let the widget and host site drift to different locales**. Pass a single reactive `language` value into `SableSiteConfig` and the widget stays in sync automatically.
|
|
203
203
|
|
|
204
204
|
## Public API Contract
|
|
205
205
|
|
package/dist/analytics.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA0B,UAAU,EAAE,MAAM,YAAY,CAAA;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AAS7E,KAAK,oBAAoB,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;
|
|
1
|
+
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA0B,UAAU,EAAE,MAAM,YAAY,CAAA;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AAS7E,KAAK,oBAAoB,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AA0GD,wBAAsB,4BAA4B,CAAC,EACjD,MAAM,EACN,WAAW,EACX,OAAO,GACR,EAAE;IACD,MAAM,EAAE,wBAAwB,GAAG,SAAS,CAAA;IAC5C,WAAW,EAAE,iBAAiB,GAAG,IAAI,CAAA;IACrC,OAAO,EAAE,oBAAoB,CAAA;CAC9B,oBA6DA;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,oBAAoB,QAKrE;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,UAAU,GAAG,SAAS,EAClC,OAAO,EAAE,oBAAoB,QAO9B"}
|
package/dist/analytics.js
CHANGED
|
@@ -78,6 +78,7 @@ function recordSableSitePageviewRollup(context, properties) {
|
|
|
78
78
|
const url = `${normalizeApiUrl(context.apiUrl)}/public/analytics/pageview`;
|
|
79
79
|
const body = JSON.stringify({
|
|
80
80
|
siteSlug: context.siteSlug,
|
|
81
|
+
visitorId: 'cookieless',
|
|
81
82
|
path: properties.sable_pathname,
|
|
82
83
|
source: properties.sable_source,
|
|
83
84
|
device: properties.sable_device_type,
|
package/dist/analytics.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analytics.js","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"analytics.js","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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"}
|
package/dist/bones/registry.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
// Auto-generated by `npx boneyard-js build`
|
|
2
|
+
// Auto-generated by `npx boneyard-js build` - do not edit
|
|
3
3
|
import { registerBones } from 'boneyard-js';
|
|
4
4
|
import { configureBoneyard } from 'boneyard-js/react';
|
|
5
5
|
import _booking_widget from './booking-widget.bones.json';
|
package/dist/booking-widget.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export type BookingRescheduleContext = {
|
|
|
13
13
|
* giving up. */
|
|
14
14
|
formerStartTime: number;
|
|
15
15
|
formerEndTime: number;
|
|
16
|
-
/** Locked service for the reschedule
|
|
16
|
+
/** Locked service for the reschedule - cannot be changed without
|
|
17
17
|
* cancelling and re-booking. */
|
|
18
18
|
serviceId: string;
|
|
19
19
|
/** Optional staff lock. When set, the staff picker is pre-filled
|
|
@@ -39,7 +39,7 @@ type BookingWidgetProps = {
|
|
|
39
39
|
* from `rescheduleContext`, swaps the CTA copy, and routes the
|
|
40
40
|
* submit through `onRescheduleSubmit` instead of the public-create
|
|
41
41
|
* mutation. Adding this as an opt-in prop keeps the npm package
|
|
42
|
-
* fully backward compatible
|
|
42
|
+
* fully backward compatible - every existing consumer that omits
|
|
43
43
|
* `mode` continues to behave exactly as before.
|
|
44
44
|
*/
|
|
45
45
|
mode?: 'create' | 'reschedule';
|
|
@@ -65,13 +65,13 @@ type BookingWidgetProps = {
|
|
|
65
65
|
* Dev-only: forces the widget into a terminal state without
|
|
66
66
|
* calling any backend mutation. Used by the dev preview page to
|
|
67
67
|
* iterate on success/cancel visuals without spinning through the
|
|
68
|
-
* form each time. Strip from prod surfaces
|
|
68
|
+
* form each time. Strip from prod surfaces - these never call any
|
|
69
69
|
* backend.
|
|
70
70
|
*
|
|
71
71
|
* - `'success'`: renders the "You're All Set!" view (or the
|
|
72
72
|
* reschedule variant when `mode === 'reschedule'`).
|
|
73
73
|
* - `'cancelled'`: renders the "Booking cancelled" view (preview
|
|
74
|
-
* only
|
|
74
|
+
* only - the customer-side cancel mutation isn't built yet).
|
|
75
75
|
*
|
|
76
76
|
* The legacy `__devForceSuccess` boolean is still accepted for
|
|
77
77
|
* back-compat with surfaces that use the old prop.
|
package/dist/booking-widget.js
CHANGED
|
@@ -82,7 +82,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
|
|
|
82
82
|
// Pre-fill contact fields from the original booking when
|
|
83
83
|
// rescheduling. Editable, since a user might want to fix typos at
|
|
84
84
|
// the same time, but the reschedule flow doesn't actually overwrite
|
|
85
|
-
// them
|
|
85
|
+
// them - the host's mutation only patches the time fields.
|
|
86
86
|
const [customerName, setCustomerName] = useState(() => rescheduleContext?.customerName ?? '');
|
|
87
87
|
const [customerEmail, setCustomerEmail] = useState(() => rescheduleContext?.customerEmail ?? '');
|
|
88
88
|
const [customerPhone, setCustomerPhone] = useState(() => rescheduleContext?.customerPhone ?? '');
|
|
@@ -177,7 +177,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
|
|
|
177
177
|
throw new Error(`Calculated service "${missingIntake.name}" is missing intakeForm.sections. Shipping services must provide an intakeForm instead of falling back to the generic contact form.`);
|
|
178
178
|
}
|
|
179
179
|
setSetup(result);
|
|
180
|
-
// Don't auto-select a service in create mode
|
|
180
|
+
// Don't auto-select a service in create mode - let the user
|
|
181
181
|
// actively pick one. Reschedule mode pre-seeds via the
|
|
182
182
|
// useState initializer above so this preserves that.
|
|
183
183
|
setError(null);
|
|
@@ -213,7 +213,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
|
|
|
213
213
|
const isCustomerEmailValid = trimmedCustomerEmail.length > 0 && isValidEmailAddress(trimmedCustomerEmail);
|
|
214
214
|
const showCustomerEmailError = trimmedCustomerEmail.length > 0 && !isCustomerEmailValid;
|
|
215
215
|
// In reschedule mode we pre-select the original service but keep
|
|
216
|
-
// the full list visible
|
|
216
|
+
// the full list visible - the admin may legitimately need to
|
|
217
217
|
// switch service when rescheduling (e.g. customer asked for a
|
|
218
218
|
// shorter visit alongside the time change).
|
|
219
219
|
const visibleServices = useMemo(() => {
|
|
@@ -266,7 +266,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
|
|
|
266
266
|
// Original service / staff display names (looked up against the
|
|
267
267
|
// loaded setup), used in the reschedule summary's "Former …" rows.
|
|
268
268
|
// These render only when the user changes the corresponding field
|
|
269
|
-
// away from the original
|
|
269
|
+
// away from the original - picking only a new time leaves them
|
|
270
270
|
// hidden, so the summary stays clean for the common case.
|
|
271
271
|
const formerService = useMemo(() => {
|
|
272
272
|
if (!isReschedule || !rescheduleContext || !setup)
|
|
@@ -293,7 +293,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
|
|
|
293
293
|
return setup.staff.filter((staffMember) => selectedService.assignedStaffIds.includes(staffMember._id));
|
|
294
294
|
}, [selectedService, setup]);
|
|
295
295
|
useEffect(() => {
|
|
296
|
-
// Wait for availableStaff to populate before clearing
|
|
296
|
+
// Wait for availableStaff to populate before clearing - otherwise
|
|
297
297
|
// a pre-seeded staffMemberId (e.g. from rescheduleContext) gets
|
|
298
298
|
// wiped on the first render before the staff list arrives.
|
|
299
299
|
if (availableStaff.length === 0)
|
|
@@ -318,8 +318,8 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
|
|
|
318
318
|
// `availableStaffIds`, and we filter client-side per selected
|
|
319
319
|
// provider. That means switching providers in the dropdown is
|
|
320
320
|
// instant (no refetch) and we always know which staff are
|
|
321
|
-
// available on a given date
|
|
322
|
-
// selected
|
|
321
|
+
// available on a given date - even when a single provider is
|
|
322
|
+
// selected - so we can disable unavailable rows in the dropdown.
|
|
323
323
|
const requestKey = getAvailabilityCacheKey(siteSlug, selectedServiceId, calendarMonth);
|
|
324
324
|
const cachedAvailability = availabilityCacheRef.current.get(requestKey);
|
|
325
325
|
if (cachedAvailability) {
|
|
@@ -549,7 +549,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
|
|
|
549
549
|
});
|
|
550
550
|
}, refreshAt);
|
|
551
551
|
return () => window.clearTimeout(handle);
|
|
552
|
-
// handleHoldExpired is stable enough
|
|
552
|
+
// handleHoldExpired is stable enough - it only reads setters
|
|
553
553
|
}, [client, holdExpiresAt, holdId, sessionToken, siteSlug]);
|
|
554
554
|
// Fires the moment the displayed countdown hits zero. The refresh
|
|
555
555
|
// effect above usually preempts this by extending the hold ~30s
|
|
@@ -632,7 +632,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
|
|
|
632
632
|
// Mobile 4-step gates. canAdvanceStepN = "the user can move PAST
|
|
633
633
|
// step N to step N+1". Step 1 (service) requires a pick. Step 2
|
|
634
634
|
// combines calendar + provider + time slots; user must pick date +
|
|
635
|
-
// slot to advance. Step 3 is the details form
|
|
635
|
+
// slot to advance. Step 3 is the details form - needs contact name,
|
|
636
636
|
// valid email, and any required intake fields filled. Step 4 is
|
|
637
637
|
// the review screen (submit, not advance).
|
|
638
638
|
const canAdvanceStep1 = Boolean(selectedService);
|
|
@@ -650,10 +650,10 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
|
|
|
650
650
|
// Re-mount the slots wrapper whenever the inputs that affect the
|
|
651
651
|
// slot list change so the CSS enter animation fires (.bw-slots-fade
|
|
652
652
|
// + per-slot stagger). React diffs keys per parent, so reusing the
|
|
653
|
-
// same key on both the mobile and desktop render sites is fine
|
|
653
|
+
// same key on both the mobile and desktop render sites is fine -
|
|
654
654
|
// each parent independently remounts its child.
|
|
655
655
|
// Provider row is the visible-list replacement for the old
|
|
656
|
-
// dropdown
|
|
656
|
+
// dropdown - same data, same handlers, but always-rendered so the
|
|
657
657
|
// user sees every option at a glance (Any + each staff). Active
|
|
658
658
|
// selection is the filled state; unavailable staff (no slots on
|
|
659
659
|
// the selected date) render disabled with an inline "Unavailable"
|
|
@@ -736,7 +736,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
|
|
|
736
736
|
const intakeFields = renderIntakeFields(idPrefix);
|
|
737
737
|
const contactFields = renderContactFields(idSuffix);
|
|
738
738
|
// Contact first, intake after. Customers expect "tell us who you
|
|
739
|
-
// are" before "tell us about your shipment"
|
|
739
|
+
// are" before "tell us about your shipment" - name and email are
|
|
740
740
|
// identity, intake fields are service-specific details.
|
|
741
741
|
return (_jsxs(_Fragment, { children: [contactFields, intakeFields] }));
|
|
742
742
|
}
|
|
@@ -858,7 +858,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
|
|
|
858
858
|
function handleConfirmAttempt() {
|
|
859
859
|
// The disabled state is purely visual (aria-disabled + class). Real
|
|
860
860
|
// submittability gates here so we can surface validation help only
|
|
861
|
-
// after the user actually tries to confirm
|
|
861
|
+
// after the user actually tries to confirm - never on a fresh form.
|
|
862
862
|
if (!canSubmit || isQuoteLoading || isSubmitting) {
|
|
863
863
|
setSubmitAttempted(true);
|
|
864
864
|
return;
|
|
@@ -995,7 +995,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
|
|
|
995
995
|
}
|
|
996
996
|
if (forcedState === 'cancelled') {
|
|
997
997
|
return (_jsx("section", { className: "bw", children: _jsxs("div", { className: "bw-done", children: [_jsx("div", { className: "bw-done-icon bw-done-icon--muted", children: _jsx(XIcon, {}) }), _jsx("h3", { className: "bw-done-title", children: t('cancelledTitle') }), _jsx("p", { className: "bw-done-text", children: t('cancelledBody') }), _jsx("button", { type: "button", className: "bw-btn-primary", onClick: () => {
|
|
998
|
-
/* dev preview only
|
|
998
|
+
/* dev preview only - host wires the real handler */
|
|
999
999
|
}, children: t('cancelledCta') })] }) }));
|
|
1000
1000
|
}
|
|
1001
1001
|
if (success || forcedState === 'success') {
|
|
@@ -1249,7 +1249,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
|
|
|
1249
1249
|
? t('btnContinueToPayment')
|
|
1250
1250
|
: t('btnConfirmBooking') }), !isSubmitting ? _jsx(ArrowRightIcon, {}) : null] }))] }) })] }, bookingFlowKey) }));
|
|
1251
1251
|
}
|
|
1252
|
-
/* Payment panel
|
|
1252
|
+
/* Payment panel - design proposal for the pay-before-booking flow.
|
|
1253
1253
|
* Renders inside the desktop details form (and mobile step-4 form
|
|
1254
1254
|
* once wired) when the selected service has paymentMode === 'full'
|
|
1255
1255
|
* or 'deposit'. Visuals only today: real implementation will mount
|
|
@@ -1264,7 +1264,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
|
|
|
1264
1264
|
* 1. Move/replace this PaymentPanel into the left summary pane
|
|
1265
1265
|
* (.bw-details-summary) so the Stripe Element sits where the
|
|
1266
1266
|
* customer reads what they're paying for. The right form pane
|
|
1267
|
-
* stays as-is
|
|
1267
|
+
* stays as-is - name/email/phone/notes only.
|
|
1268
1268
|
* 2. Backend gap: getPublicBookingSetup currently strips the
|
|
1269
1269
|
* payment fields. Surface paymentMode, depositCents,
|
|
1270
1270
|
* requiresPayment, and the workspace's Stripe Connect account
|
|
@@ -1276,7 +1276,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
|
|
|
1276
1276
|
* to the bookingHoldId so the amount can't be tampered with).
|
|
1277
1277
|
* 4. Gate createPublicAppointment behind paymentIntent.status
|
|
1278
1278
|
* === 'succeeded'. On failure: keep the hold for one retry.
|
|
1279
|
-
* 5. Confirm CTA copy already branches on forcedState
|
|
1279
|
+
* 5. Confirm CTA copy already branches on forcedState - wire the
|
|
1280
1280
|
* same branch on the real `service.requiresPayment` field.
|
|
1281
1281
|
* 6. Visual reference: this PaymentPanel + the dev preview pills
|
|
1282
1282
|
* ('Pay full' / 'Pay deposit') in dev/booking-widget-preview
|
|
@@ -1505,12 +1505,12 @@ function IntakeSelect({ id, value, onChange, options, placeholder, required, })
|
|
|
1505
1505
|
* Decide which side to open the menu on. If the space below the
|
|
1506
1506
|
* trigger isn't enough to fit the menu, and there's more space
|
|
1507
1507
|
* above, flip the menu above the trigger. Runs at every open
|
|
1508
|
-
* (desktop AND mobile)
|
|
1508
|
+
* (desktop AND mobile) - handles both the desktop near-footer
|
|
1509
1509
|
* case and the mobile near-bottom-of-widget case.
|
|
1510
1510
|
*
|
|
1511
1511
|
* The menu's CSS max-height is `min(280px, 60svh)`. We compute
|
|
1512
1512
|
* the same effective max here so the flip decision tracks the
|
|
1513
|
-
* real available space
|
|
1513
|
+
* real available space - important on short phones where 60svh
|
|
1514
1514
|
* is much smaller than 280px.
|
|
1515
1515
|
*/
|
|
1516
1516
|
function computePlacement() {
|
|
@@ -1770,7 +1770,7 @@ function readString(value) {
|
|
|
1770
1770
|
// SSR/no-bones space holder and Suspense fallback for host sites.
|
|
1771
1771
|
function AvailabilitySkeleton() {
|
|
1772
1772
|
// Reuses .bw-time-slots so the skeleton inherits the same layout
|
|
1773
|
-
// overrides as the real slots
|
|
1773
|
+
// overrides as the real slots - vertical 1-col on desktop (via the
|
|
1774
1774
|
// .bw-slots-desktop scope), 4-col grid on mobile (default). Pill
|
|
1775
1775
|
// dimensions match the rendered .bw-slot.
|
|
1776
1776
|
return (_jsx("div", { className: "bw-time-slots bw-time-slots--skeleton", children: Array.from({ length: 8 }).map((_, index) => (_jsx("div", { className: "bw-skel bw-skel--slot" }, index))) }));
|
|
@@ -1867,7 +1867,7 @@ function formatDateKey(date) {
|
|
|
1867
1867
|
function formatMonthLabel(date, locale = 'en-US') {
|
|
1868
1868
|
// Use a simple "Month YYYY" shape across locales. Default Spanish
|
|
1869
1869
|
// formatting yields "mayo de 2026" (lowercased, with "de"), which
|
|
1870
|
-
// we don't want
|
|
1870
|
+
// we don't want - strip both for a tighter calendar header.
|
|
1871
1871
|
const month = new Intl.DateTimeFormat(locale, { month: 'long' }).format(date);
|
|
1872
1872
|
const capitalizedMonth = month.charAt(0).toUpperCase() + month.slice(1);
|
|
1873
1873
|
return `${capitalizedMonth} ${date.getFullYear()}`;
|
package/dist/styles.css
CHANGED
|
@@ -18,8 +18,10 @@
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
.bw {
|
|
21
|
-
/* Theme tokens
|
|
22
|
-
--bw-font:
|
|
21
|
+
/* Theme tokens - overridable per host site (color + font). */
|
|
22
|
+
--bw-font:
|
|
23
|
+
'Inter', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
|
24
|
+
'Segoe UI', sans-serif;
|
|
23
25
|
--bw-bg: #ffffff;
|
|
24
26
|
--bw-text: #1a1a1a;
|
|
25
27
|
--bw-text-secondary: #6b6b6b;
|
|
@@ -34,19 +36,22 @@
|
|
|
34
36
|
--bw-hover: #f8f8f8;
|
|
35
37
|
--bw-error-bg: #fef2f2;
|
|
36
38
|
--bw-error-text: #b91c1c;
|
|
37
|
-
/* Structural tokens
|
|
39
|
+
/* Structural tokens - Sable design rhythm; tenants generally
|
|
38
40
|
don't override these. Mirrors the radius scale documented in
|
|
39
|
-
productdesign.md (cards 12/16,
|
|
41
|
+
productdesign.md (cards 12/16, fields 8, buttons 28). */
|
|
40
42
|
--bw-radius-xs: 4px;
|
|
41
43
|
--bw-radius-sm: 8px;
|
|
42
44
|
--bw-radius-md: 12px;
|
|
43
45
|
--bw-radius: 12px;
|
|
44
46
|
--bw-radius-lg: 16px;
|
|
45
47
|
--bw-radius-xl: 22px;
|
|
48
|
+
--bw-radius-field: 8px;
|
|
46
49
|
--bw-radius-pill: 9999px;
|
|
47
|
-
--bw-shadow:
|
|
50
|
+
--bw-shadow:
|
|
51
|
+
0 1px 2px rgba(15, 15, 15, 0.04), 0 8px 24px -12px rgba(15, 15, 15, 0.08);
|
|
48
52
|
--bw-shadow-badge: 0 1px 4px rgba(15, 15, 15, 0.12);
|
|
49
|
-
--bw-shadow-lift:
|
|
53
|
+
--bw-shadow-lift:
|
|
54
|
+
0 1px 2px rgba(15, 15, 15, 0.06), 0 12px 32px -16px rgba(15, 15, 15, 0.12);
|
|
50
55
|
--bw-ease: cubic-bezier(0.16, 1, 0.3, 1);
|
|
51
56
|
--bw-duration: 220ms;
|
|
52
57
|
position: relative;
|
|
@@ -56,7 +61,7 @@
|
|
|
56
61
|
background: var(--bw-bg);
|
|
57
62
|
color: var(--bw-text);
|
|
58
63
|
font-family: var(--bw-font);
|
|
59
|
-
font-feature-settings:
|
|
64
|
+
font-feature-settings: 'ss01', 'cv11';
|
|
60
65
|
-webkit-font-smoothing: antialiased;
|
|
61
66
|
-moz-osx-font-smoothing: grayscale;
|
|
62
67
|
text-wrap: pretty;
|
|
@@ -91,7 +96,12 @@
|
|
|
91
96
|
|
|
92
97
|
.bw-skel {
|
|
93
98
|
border-radius: var(--bw-radius);
|
|
94
|
-
background: linear-gradient(
|
|
99
|
+
background: linear-gradient(
|
|
100
|
+
90deg,
|
|
101
|
+
var(--bw-border-light) 25%,
|
|
102
|
+
var(--bw-border) 50%,
|
|
103
|
+
var(--bw-border-light) 75%
|
|
104
|
+
);
|
|
95
105
|
background-size: 200% 100%;
|
|
96
106
|
animation: bw-shimmer 1.5s ease infinite;
|
|
97
107
|
}
|
|
@@ -111,7 +121,12 @@
|
|
|
111
121
|
|
|
112
122
|
.bw-placeholder-shape {
|
|
113
123
|
border-radius: var(--bw-radius);
|
|
114
|
-
background: linear-gradient(
|
|
124
|
+
background: linear-gradient(
|
|
125
|
+
90deg,
|
|
126
|
+
var(--bw-border-light) 25%,
|
|
127
|
+
var(--bw-border) 50%,
|
|
128
|
+
var(--bw-border-light) 75%
|
|
129
|
+
);
|
|
115
130
|
background-size: 200% 100%;
|
|
116
131
|
animation: bw-shimmer 1.5s ease infinite;
|
|
117
132
|
}
|
|
@@ -365,7 +380,7 @@
|
|
|
365
380
|
|
|
366
381
|
/* Review variant runs full-bleed inside its col: no card chrome (no
|
|
367
382
|
border, no rounded background), generous type. Sized for arm's-
|
|
368
|
-
length reading on phone
|
|
383
|
+
length reading on phone - body 15px floor, total 17px, with a
|
|
369
384
|
thin hairline separating each group. */
|
|
370
385
|
.bw-summary--review {
|
|
371
386
|
width: 100%;
|
|
@@ -461,7 +476,7 @@
|
|
|
461
476
|
background: var(--bw-border);
|
|
462
477
|
}
|
|
463
478
|
|
|
464
|
-
/* Service groups
|
|
479
|
+
/* Service groups - categories. We use generous vertical rhythm
|
|
465
480
|
(28px gap) and a small caption-style heading instead of a hard
|
|
466
481
|
divider line, so the category break reads through whitespace +
|
|
467
482
|
typographic shift, not via a blend-in 1px border. */
|
|
@@ -506,7 +521,8 @@
|
|
|
506
521
|
background: transparent;
|
|
507
522
|
cursor: pointer;
|
|
508
523
|
text-align: left;
|
|
509
|
-
transition:
|
|
524
|
+
transition:
|
|
525
|
+
border-color var(--bw-duration) var(--bw-ease),
|
|
510
526
|
box-shadow var(--bw-duration) var(--bw-ease),
|
|
511
527
|
background var(--bw-duration) var(--bw-ease);
|
|
512
528
|
}
|
|
@@ -683,7 +699,7 @@
|
|
|
683
699
|
/* When the picker is in expanded mode (full list visible), let it
|
|
684
700
|
stretch to fill the column so the scroll list extends down to the
|
|
685
701
|
bottom of the left column instead of capping at an arbitrary
|
|
686
|
-
height. Detected via :has()
|
|
702
|
+
height. Detected via :has() - the .bw-svc-scroll only renders in
|
|
687
703
|
expanded mode; in collapsed mode the picker contains only the
|
|
688
704
|
selected card, which sizes to its content (so the provider section
|
|
689
705
|
below sits flush, not pushed to the bottom). */
|
|
@@ -708,7 +724,7 @@
|
|
|
708
724
|
overflow-y: auto;
|
|
709
725
|
/* Soft fade at the top + bottom so the scroll edge looks
|
|
710
726
|
intentional instead of cutting service rows in half. Matches
|
|
711
|
-
the editorial "warm paper, not cold glass" feel
|
|
727
|
+
the editorial "warm paper, not cold glass" feel - depth from
|
|
712
728
|
softness, not a hard line. */
|
|
713
729
|
-webkit-mask-image: linear-gradient(
|
|
714
730
|
to bottom,
|
|
@@ -750,7 +766,7 @@
|
|
|
750
766
|
padding-block: 12px 24px;
|
|
751
767
|
}
|
|
752
768
|
|
|
753
|
-
/* Service row
|
|
769
|
+
/* Service row - refactored to fix the narrow-width hierarchy issues:
|
|
754
770
|
- Top-aligned items so price reads with the first line of the name
|
|
755
771
|
- Name allowed to wrap with text-wrap: pretty (no orphans)
|
|
756
772
|
- Description line-clamps to 2 lines instead of single-line ellipsis
|
|
@@ -767,7 +783,8 @@
|
|
|
767
783
|
background: transparent;
|
|
768
784
|
cursor: pointer;
|
|
769
785
|
text-align: left;
|
|
770
|
-
transition:
|
|
786
|
+
transition:
|
|
787
|
+
background var(--bw-duration) var(--bw-ease),
|
|
771
788
|
box-shadow var(--bw-duration) var(--bw-ease),
|
|
772
789
|
transform var(--bw-duration) var(--bw-ease);
|
|
773
790
|
}
|
|
@@ -798,7 +815,8 @@
|
|
|
798
815
|
border: 1.5px solid var(--bw-border);
|
|
799
816
|
border-radius: var(--bw-radius-xs);
|
|
800
817
|
color: transparent;
|
|
801
|
-
transition:
|
|
818
|
+
transition:
|
|
819
|
+
border-color var(--bw-duration) var(--bw-ease),
|
|
802
820
|
background var(--bw-duration) var(--bw-ease),
|
|
803
821
|
color var(--bw-duration) var(--bw-ease);
|
|
804
822
|
}
|
|
@@ -823,7 +841,7 @@
|
|
|
823
841
|
/* Service thumbnail (Fresha/Square pattern). Replaces the checkbox
|
|
824
842
|
slot when a service has an image. Selected state shows a small
|
|
825
843
|
primary-colored badge in the bottom-right corner with the same
|
|
826
|
-
check icon
|
|
844
|
+
check icon - keeps the affordance consistent with image-less
|
|
827
845
|
rows. Concentric radius (md = 12px) matches surrounding chrome. */
|
|
828
846
|
.bw-svc-image {
|
|
829
847
|
position: relative;
|
|
@@ -953,7 +971,7 @@
|
|
|
953
971
|
|
|
954
972
|
/* Price: same scale as name so the first-line baseline locks them
|
|
955
973
|
together optically. Regular weight (not 600) so price doesn't
|
|
956
|
-
compete for attention with the name
|
|
974
|
+
compete for attention with the name - name leads, price reads
|
|
957
975
|
as a quiet endcap. */
|
|
958
976
|
.bw-svc-price {
|
|
959
977
|
flex-shrink: 0;
|
|
@@ -1050,10 +1068,10 @@
|
|
|
1050
1068
|
}
|
|
1051
1069
|
}
|
|
1052
1070
|
|
|
1053
|
-
/* Provider list
|
|
1071
|
+
/* Provider list - replaces the old dropdown so every option is
|
|
1054
1072
|
visible at a glance. Two layouts share the same DOM:
|
|
1055
1073
|
Desktop (>=1025px): vertical stack of horizontal rows
|
|
1056
|
-
(avatar | name + desc)
|
|
1074
|
+
(avatar | name + desc) - reads like the old dropdown list.
|
|
1057
1075
|
Mobile (<=1024px): horizontal scrolling strip of square-ish
|
|
1058
1076
|
cards (avatar above name) so the row fits on a phone column.
|
|
1059
1077
|
Selection, hover, and disabled-state chrome is shared between
|
|
@@ -1179,7 +1197,7 @@
|
|
|
1179
1197
|
color: var(--bw-text-muted);
|
|
1180
1198
|
}
|
|
1181
1199
|
|
|
1182
|
-
/* Mobile uses the same vertical list as desktop
|
|
1200
|
+
/* Mobile uses the same vertical list as desktop - no horizontal
|
|
1183
1201
|
scrolling chip strip. The single layout keeps the visual language
|
|
1184
1202
|
identical across breakpoints; if the list exceeds the card's
|
|
1185
1203
|
built-in 320px max-height, it scrolls vertically inside the
|
|
@@ -1219,7 +1237,7 @@
|
|
|
1219
1237
|
margin-bottom: 0;
|
|
1220
1238
|
}
|
|
1221
1239
|
|
|
1222
|
-
/* The provider section uses .bw-mobile-card chrome
|
|
1240
|
+
/* The provider section uses .bw-mobile-card chrome - kill the
|
|
1223
1241
|
desktop bw-provider-section animation so it doesn't replay
|
|
1224
1242
|
when the section enters the mobile flow. */
|
|
1225
1243
|
.bw-mobile-card.bw-provider-section--mobile {
|
|
@@ -1227,7 +1245,7 @@
|
|
|
1227
1245
|
}
|
|
1228
1246
|
}
|
|
1229
1247
|
|
|
1230
|
-
/* Service picker
|
|
1248
|
+
/* Service picker - collapsed selected state. Once a service is
|
|
1231
1249
|
picked, the long list collapses to a read-only card showing just
|
|
1232
1250
|
the selected service plus a "Change" link. Below this card the
|
|
1233
1251
|
provider section reveals (per the service-first flow). The card
|
|
@@ -1284,7 +1302,7 @@
|
|
|
1284
1302
|
line items + total + charge breakdown (mirrors the reference
|
|
1285
1303
|
pattern but in Sable's tone), then a card-details slot for the
|
|
1286
1304
|
eventual Stripe PaymentElement, then a small "secured by Stripe"
|
|
1287
|
-
reassurance line. Stub fields are placeholders only
|
|
1305
|
+
reassurance line. Stub fields are placeholders only - real impl
|
|
1288
1306
|
replaces .bw-pay-card-slot's children with <PaymentElement />. */
|
|
1289
1307
|
.bw-pay {
|
|
1290
1308
|
display: flex;
|
|
@@ -1550,7 +1568,8 @@
|
|
|
1550
1568
|
cursor: default;
|
|
1551
1569
|
font-size: 13px;
|
|
1552
1570
|
font-variant-numeric: tabular-nums;
|
|
1553
|
-
transition:
|
|
1571
|
+
transition:
|
|
1572
|
+
background var(--bw-duration) var(--bw-ease),
|
|
1554
1573
|
color var(--bw-duration) var(--bw-ease);
|
|
1555
1574
|
}
|
|
1556
1575
|
|
|
@@ -1576,7 +1595,7 @@
|
|
|
1576
1595
|
font-weight: 600;
|
|
1577
1596
|
}
|
|
1578
1597
|
|
|
1579
|
-
/* Dot under today's number
|
|
1598
|
+
/* Dot under today's number - subtle reference indicator. Hidden when
|
|
1580
1599
|
the day is the active selection (the filled background already
|
|
1581
1600
|
communicates focus). */
|
|
1582
1601
|
.bw-cal-day.is-today::after {
|
|
@@ -1669,7 +1688,8 @@
|
|
|
1669
1688
|
font-size: 13px;
|
|
1670
1689
|
font-variant-numeric: tabular-nums;
|
|
1671
1690
|
color: var(--bw-text);
|
|
1672
|
-
transition:
|
|
1691
|
+
transition:
|
|
1692
|
+
border-color var(--bw-duration) var(--bw-ease),
|
|
1673
1693
|
background var(--bw-duration) var(--bw-ease),
|
|
1674
1694
|
color var(--bw-duration) var(--bw-ease),
|
|
1675
1695
|
transform var(--bw-duration) var(--bw-ease);
|
|
@@ -1736,12 +1756,13 @@
|
|
|
1736
1756
|
width: 100%;
|
|
1737
1757
|
padding: 11px 16px;
|
|
1738
1758
|
border: 1px solid var(--bw-border);
|
|
1739
|
-
border-radius: var(--bw-radius-
|
|
1759
|
+
border-radius: var(--bw-radius-field);
|
|
1740
1760
|
background: transparent;
|
|
1741
1761
|
color: var(--bw-text);
|
|
1742
1762
|
font-size: 13px;
|
|
1743
1763
|
font-family: inherit;
|
|
1744
|
-
transition:
|
|
1764
|
+
transition:
|
|
1765
|
+
border-color var(--bw-duration) var(--bw-ease),
|
|
1745
1766
|
box-shadow var(--bw-duration) var(--bw-ease);
|
|
1746
1767
|
}
|
|
1747
1768
|
|
|
@@ -1765,7 +1786,8 @@
|
|
|
1765
1786
|
.bw-field.is-invalid textarea,
|
|
1766
1787
|
.bw-field.is-invalid select {
|
|
1767
1788
|
border-color: var(--bw-error-text);
|
|
1768
|
-
box-shadow: 0 0 0 3px
|
|
1789
|
+
box-shadow: 0 0 0 3px
|
|
1790
|
+
color-mix(in srgb, var(--bw-error-text) 12%, transparent);
|
|
1769
1791
|
}
|
|
1770
1792
|
|
|
1771
1793
|
.bw-field-error {
|
|
@@ -1781,7 +1803,7 @@
|
|
|
1781
1803
|
}
|
|
1782
1804
|
|
|
1783
1805
|
/* ===========================================================================
|
|
1784
|
-
Custom IntakeSelect
|
|
1806
|
+
Custom IntakeSelect - replaces the native <select>. Trigger matches
|
|
1785
1807
|
the .bw-field input chrome (border, radius, padding, font). Menu sits
|
|
1786
1808
|
absolutely below, scrolls if taller than max-height, animates in.
|
|
1787
1809
|
=========================================================================== */
|
|
@@ -1798,7 +1820,7 @@
|
|
|
1798
1820
|
width: 100%;
|
|
1799
1821
|
padding: 11px 14px 11px 16px;
|
|
1800
1822
|
border: 1px solid var(--bw-border);
|
|
1801
|
-
border-radius: var(--bw-radius-
|
|
1823
|
+
border-radius: var(--bw-radius-field);
|
|
1802
1824
|
background: transparent;
|
|
1803
1825
|
color: var(--bw-text);
|
|
1804
1826
|
font-size: 13px;
|
|
@@ -1861,8 +1883,8 @@
|
|
|
1861
1883
|
/* Sits above the widget's own footer (z-index up to 102 on mobile)
|
|
1862
1884
|
and any nearby chrome so flip-up + flip-down both render cleanly. */
|
|
1863
1885
|
z-index: 110;
|
|
1864
|
-
/* Cap menu height to whichever is smaller
|
|
1865
|
-
or 60% of the viewport
|
|
1886
|
+
/* Cap menu height to whichever is smaller - the 280px design max
|
|
1887
|
+
or 60% of the viewport - so on short phones the dropdown never
|
|
1866
1888
|
dominates the screen and always leaves the trigger visible. */
|
|
1867
1889
|
max-height: min(280px, 60svh);
|
|
1868
1890
|
overflow-y: auto;
|
|
@@ -1995,7 +2017,8 @@
|
|
|
1995
2017
|
}
|
|
1996
2018
|
|
|
1997
2019
|
.bw-submit-help {
|
|
1998
|
-
border: 1px solid
|
|
2020
|
+
border: 1px solid
|
|
2021
|
+
color-mix(in srgb, var(--bw-error-text) 24%, var(--bw-border));
|
|
1999
2022
|
border-radius: 10px;
|
|
2000
2023
|
background: color-mix(in srgb, var(--bw-error-text) 8%, var(--bw-bg));
|
|
2001
2024
|
color: var(--bw-text);
|
|
@@ -2168,7 +2191,8 @@
|
|
|
2168
2191
|
background: var(--bw-primary);
|
|
2169
2192
|
color: var(--bw-primary-text);
|
|
2170
2193
|
cursor: pointer;
|
|
2171
|
-
transition:
|
|
2194
|
+
transition:
|
|
2195
|
+
opacity var(--bw-duration) var(--bw-ease),
|
|
2172
2196
|
transform var(--bw-duration) var(--bw-ease),
|
|
2173
2197
|
box-shadow var(--bw-duration) var(--bw-ease);
|
|
2174
2198
|
}
|
|
@@ -2282,7 +2306,7 @@
|
|
|
2282
2306
|
}
|
|
2283
2307
|
|
|
2284
2308
|
/* Cancelled-state disc: neutral background instead of the celebratory
|
|
2285
|
-
primary fill. Tone is informational, not affirmative
|
|
2309
|
+
primary fill. Tone is informational, not affirmative - we don't
|
|
2286
2310
|
want to "celebrate" a cancellation with a brand-color check badge. */
|
|
2287
2311
|
.bw-done-icon--muted {
|
|
2288
2312
|
background: var(--bw-border-light);
|
|
@@ -2290,7 +2314,7 @@
|
|
|
2290
2314
|
}
|
|
2291
2315
|
|
|
2292
2316
|
/* Override the shared 16px sizing for icons rendered inside chrome
|
|
2293
|
-
(.bw-done-icon, .bw-staff-avatar, etc.)
|
|
2317
|
+
(.bw-done-icon, .bw-staff-avatar, etc.) - the success view's check
|
|
2294
2318
|
reads small inside the 56px disc, so bump the glyph to 24px so it
|
|
2295
2319
|
anchors the moment cleanly. */
|
|
2296
2320
|
.bw-done-icon svg {
|
|
@@ -2339,7 +2363,7 @@
|
|
|
2339
2363
|
/* Lock header/footer in the column so they never shrink under
|
|
2340
2364
|
content pressure. Flex children default to flex-shrink: 1, which
|
|
2341
2365
|
would let a tall body squeeze the title/buttons. Force them to
|
|
2342
|
-
size to their content and stay put
|
|
2366
|
+
size to their content and stay put - the body in between is the
|
|
2343
2367
|
only thing that scrolls. */
|
|
2344
2368
|
.bw-mobile-header,
|
|
2345
2369
|
.bw-header,
|
|
@@ -2360,12 +2384,7 @@
|
|
|
2360
2384
|
#000 24px,
|
|
2361
2385
|
#000 100%
|
|
2362
2386
|
);
|
|
2363
|
-
mask-image: linear-gradient(
|
|
2364
|
-
to bottom,
|
|
2365
|
-
transparent 0,
|
|
2366
|
-
#000 24px,
|
|
2367
|
-
#000 100%
|
|
2368
|
-
);
|
|
2387
|
+
mask-image: linear-gradient(to bottom, transparent 0, #000 24px, #000 100%);
|
|
2369
2388
|
}
|
|
2370
2389
|
|
|
2371
2390
|
.bw-placeholder {
|
|
@@ -2520,33 +2539,33 @@
|
|
|
2520
2539
|
Provider lives inside bw-cal-card on mobile so the visual
|
|
2521
2540
|
order reads date → provider → time. The desktop dropdown in
|
|
2522
2541
|
bw-step-1 is hidden on mobile (we use chips here instead). */
|
|
2523
|
-
.bw-body[data-mobile-step=
|
|
2524
|
-
.bw-body[data-mobile-step=
|
|
2525
|
-
.bw-body[data-mobile-step=
|
|
2526
|
-
.bw-body[data-mobile-step=
|
|
2542
|
+
.bw-body[data-mobile-step='1'] .bw-col--left,
|
|
2543
|
+
.bw-body[data-mobile-step='2'] .bw-col--center,
|
|
2544
|
+
.bw-body[data-mobile-step='3'] .bw-col--right,
|
|
2545
|
+
.bw-body[data-mobile-step='4'] .bw-col--review {
|
|
2527
2546
|
display: flex;
|
|
2528
2547
|
padding-top: 16px;
|
|
2529
2548
|
padding-bottom: 24px;
|
|
2530
2549
|
}
|
|
2531
2550
|
|
|
2532
|
-
.bw-body[data-mobile-step=
|
|
2551
|
+
.bw-body[data-mobile-step='3'] .bw-right-inner {
|
|
2533
2552
|
padding-bottom: 20px;
|
|
2534
2553
|
}
|
|
2535
2554
|
|
|
2536
2555
|
/* Step 1: hide the desktop service-picker (inside bw-step-1) and
|
|
2537
2556
|
hide the entire bw-step-1 wrapper. Show bw-step-2 (full-width
|
|
2538
2557
|
services list). */
|
|
2539
|
-
.bw-body[data-mobile-step=
|
|
2558
|
+
.bw-body[data-mobile-step='1'] .bw-step-1 {
|
|
2540
2559
|
display: none;
|
|
2541
2560
|
}
|
|
2542
2561
|
|
|
2543
|
-
.bw-body[data-mobile-step=
|
|
2562
|
+
.bw-body[data-mobile-step='1'] .bw-step-2 {
|
|
2544
2563
|
display: flex;
|
|
2545
2564
|
flex-direction: column;
|
|
2546
2565
|
}
|
|
2547
2566
|
|
|
2548
|
-
.bw-body[data-mobile-step=
|
|
2549
|
-
.bw-body[data-mobile-step=
|
|
2567
|
+
.bw-body[data-mobile-step='1'] .bw-step-2-heading,
|
|
2568
|
+
.bw-body[data-mobile-step='1'] .bw-step-2-divider {
|
|
2550
2569
|
display: none;
|
|
2551
2570
|
}
|
|
2552
2571
|
|
|
@@ -2657,8 +2676,7 @@
|
|
|
2657
2676
|
Host site MUST include `viewport-fit=cover` in its viewport
|
|
2658
2677
|
meta for env(safe-area-inset-*) to be non-zero on iOS. */
|
|
2659
2678
|
margin-top: 16px;
|
|
2660
|
-
padding: 16px 24px
|
|
2661
|
-
max(24px, calc(env(safe-area-inset-bottom) + 16px));
|
|
2679
|
+
padding: 16px 24px max(24px, calc(env(safe-area-inset-bottom) + 16px));
|
|
2662
2680
|
border-top: 1px solid var(--bw-border-light);
|
|
2663
2681
|
}
|
|
2664
2682
|
|
|
@@ -2736,7 +2754,7 @@
|
|
|
2736
2754
|
gap: 6px;
|
|
2737
2755
|
}
|
|
2738
2756
|
|
|
2739
|
-
.bw-body[data-mobile-step=
|
|
2757
|
+
.bw-body[data-mobile-step='3'] .bw-right-inner {
|
|
2740
2758
|
padding-bottom: 16px;
|
|
2741
2759
|
}
|
|
2742
2760
|
|
|
@@ -2806,7 +2824,7 @@
|
|
|
2806
2824
|
}
|
|
2807
2825
|
|
|
2808
2826
|
.bw-slot {
|
|
2809
|
-
/* Time pills are a primary tap target
|
|
2827
|
+
/* Time pills are a primary tap target - bump from 13px
|
|
2810
2828
|
(footnote-tier) to 15px (subheadline). 3-col mobile grid
|
|
2811
2829
|
still fits "10:30 a. m." comfortably at 15px. */
|
|
2812
2830
|
font-size: 15px;
|
|
@@ -2821,7 +2839,7 @@
|
|
|
2821
2839
|
|
|
2822
2840
|
/* ===========================================================================
|
|
2823
2841
|
Desktop-only right-pane swap (slots → details) and sizing fixes.
|
|
2824
|
-
Mobile is intentionally untouched here
|
|
2842
|
+
Mobile is intentionally untouched here - the pane wrappers exist in the
|
|
2825
2843
|
DOM on mobile but receive no styling, so they collapse into transparent
|
|
2826
2844
|
block containers and the form / cal-card / step-1 keep their original
|
|
2827
2845
|
mobile flex behavior from commit 6ca438f.
|
|
@@ -2884,7 +2902,7 @@
|
|
|
2884
2902
|
}
|
|
2885
2903
|
|
|
2886
2904
|
/* Desktop body grid: cols sit at the top of their cell instead of
|
|
2887
|
-
stretching to the row's max content height
|
|
2905
|
+
stretching to the row's max content height - the visual empty
|
|
2888
2906
|
space below the cal-card and right-pane goes away. */
|
|
2889
2907
|
.bw-body {
|
|
2890
2908
|
align-items: start;
|
|
@@ -2921,7 +2939,7 @@
|
|
|
2921
2939
|
}
|
|
2922
2940
|
|
|
2923
2941
|
/* --bw-cal-h is set on the .bw root via ResizeObserver in the
|
|
2924
|
-
widget
|
|
2942
|
+
widget - it tracks the live height of the .bw-cal-card in the
|
|
2925
2943
|
middle column. Use it to cap the services list (left) and the
|
|
2926
2944
|
slots list (right) so all three columns share the same visual
|
|
2927
2945
|
height. Both internal scrollers fade their top + bottom edges
|
|
@@ -3147,7 +3165,7 @@
|
|
|
3147
3165
|
max-width: 1440px;
|
|
3148
3166
|
width: 100%;
|
|
3149
3167
|
margin: 0 auto;
|
|
3150
|
-
/* Default hidden state
|
|
3168
|
+
/* Default hidden state - overlaid on top of body. */
|
|
3151
3169
|
opacity: 0;
|
|
3152
3170
|
transform: scale(0.99);
|
|
3153
3171
|
pointer-events: none;
|
|
@@ -3179,7 +3197,7 @@
|
|
|
3179
3197
|
intake fields). `align-self: start` keeps the grid cell from
|
|
3180
3198
|
stretching to row height, which would block sticky behavior.
|
|
3181
3199
|
Host sites can override --bw-sticky-summary-top to clear a
|
|
3182
|
-
fixed top nav
|
|
3200
|
+
fixed top nav - encomiendas' nav is 72px so a host override
|
|
3183
3201
|
to ~96px makes sense; the default 24px works for hosts with
|
|
3184
3202
|
no fixed nav. */
|
|
3185
3203
|
position: sticky;
|
|
@@ -3284,7 +3302,7 @@
|
|
|
3284
3302
|
}
|
|
3285
3303
|
|
|
3286
3304
|
/* Back link sits at the top of the summary pane, in the eyebrow
|
|
3287
|
-
position
|
|
3305
|
+
position - replacing the previous static "Reschedule" / "Booking"
|
|
3288
3306
|
label as the first thing the user reads on the left. The static
|
|
3289
3307
|
eyebrow still renders just below as the section label for the
|
|
3290
3308
|
summary stack. */
|
|
@@ -3339,7 +3357,7 @@
|
|
|
3339
3357
|
width: 100%;
|
|
3340
3358
|
min-height: 40px;
|
|
3341
3359
|
border: 1px solid var(--bw-border);
|
|
3342
|
-
border-radius:
|
|
3360
|
+
border-radius: var(--bw-radius-field);
|
|
3343
3361
|
background: var(--bw-bg);
|
|
3344
3362
|
color: var(--bw-text);
|
|
3345
3363
|
padding: 0 12px;
|
package/dist/translations.d.ts
CHANGED
|
@@ -255,13 +255,13 @@ export declare function createTranslator(locale: Locale, overrides?: Translation
|
|
|
255
255
|
* Picks the best matching field from an object with locale-suffixed variants.
|
|
256
256
|
*
|
|
257
257
|
* The base field (`name`, `title`, `description`) is the CANONICAL SOURCE
|
|
258
|
-
*
|
|
258
|
+
* - operator's own input, in whatever language they wrote it. Locale-
|
|
259
259
|
* suffixed siblings (`nameEs`, `nameEn`, ...) are auto-translations
|
|
260
260
|
* derived from the base.
|
|
261
261
|
*
|
|
262
262
|
* Lookup order:
|
|
263
263
|
* 1. Locale-suffixed field for the requested locale (`nameEs` for 'es').
|
|
264
|
-
* 2. Base field (`name`)
|
|
264
|
+
* 2. Base field (`name`) - the operator's source text.
|
|
265
265
|
*
|
|
266
266
|
* We do NOT fall back through an "English first" default, because the
|
|
267
267
|
* base field already IS the source of truth and may itself be Spanish
|
package/dist/translations.js
CHANGED
|
@@ -302,13 +302,13 @@ export function createTranslator(locale, overrides) {
|
|
|
302
302
|
* Picks the best matching field from an object with locale-suffixed variants.
|
|
303
303
|
*
|
|
304
304
|
* The base field (`name`, `title`, `description`) is the CANONICAL SOURCE
|
|
305
|
-
*
|
|
305
|
+
* - operator's own input, in whatever language they wrote it. Locale-
|
|
306
306
|
* suffixed siblings (`nameEs`, `nameEn`, ...) are auto-translations
|
|
307
307
|
* derived from the base.
|
|
308
308
|
*
|
|
309
309
|
* Lookup order:
|
|
310
310
|
* 1. Locale-suffixed field for the requested locale (`nameEs` for 'es').
|
|
311
|
-
* 2. Base field (`name`)
|
|
311
|
+
* 2. Base field (`name`) - the operator's source text.
|
|
312
312
|
*
|
|
313
313
|
* We do NOT fall back through an "English first" default, because the
|
|
314
314
|
* base field already IS the source of truth and may itself be Spanish
|
package/dist/types.d.ts
CHANGED
|
@@ -75,6 +75,29 @@ export type PublicContactInput = {
|
|
|
75
75
|
phone?: string;
|
|
76
76
|
message: string;
|
|
77
77
|
page?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Optional structured intake from a quote form. All optional and purely
|
|
80
|
+
* additive — the minimal contact form still sends just name/email/message.
|
|
81
|
+
* On the Sable side these flow into the `requests` row created for the lead,
|
|
82
|
+
* so it surfaces as an actionable inbox card the owner can reply to.
|
|
83
|
+
*/
|
|
84
|
+
kind?: 'quote' | 'general';
|
|
85
|
+
/** Requested services, e.g. ['Carpet cleaning', 'Tile & grout']. */
|
|
86
|
+
services?: Array<string>;
|
|
87
|
+
/** Free-text timeline, e.g. 'As soon as possible'. */
|
|
88
|
+
urgency?: string;
|
|
89
|
+
/** Free-text property type, e.g. 'Home' / 'Business'. */
|
|
90
|
+
propertyType?: string;
|
|
91
|
+
/**
|
|
92
|
+
* Downscaled photos, base64-encoded (image/jpeg, no data-URI prefix) — the
|
|
93
|
+
* same shape a quote form produces on-device. Keep them small (the connector
|
|
94
|
+
* forwards them verbatim in the JSON POST); Sable stores each to file storage
|
|
95
|
+
* and attaches it to the lead's request, so they show up in the inbox.
|
|
96
|
+
*/
|
|
97
|
+
photos?: Array<{
|
|
98
|
+
filename: string;
|
|
99
|
+
data: string;
|
|
100
|
+
}>;
|
|
78
101
|
};
|
|
79
102
|
export type PublicBookingSetup = {
|
|
80
103
|
site: {
|
|
@@ -105,7 +128,7 @@ export type PublicBookingSetup = {
|
|
|
105
128
|
* filed under a category. */
|
|
106
129
|
categoryId?: string;
|
|
107
130
|
/** Optional service thumbnail (Fresha/Square pattern). Resolved
|
|
108
|
-
* on the server to a plain URL
|
|
131
|
+
* on the server to a plain URL - the widget renders it as a
|
|
109
132
|
* rounded square on the left of the row, replacing the checkbox
|
|
110
133
|
* slot. `null` when the service has no image, in which case the
|
|
111
134
|
* widget falls back to the checkbox affordance. */
|
|
@@ -130,7 +153,7 @@ export type PublicBookingSetup = {
|
|
|
130
153
|
/** All categories that contain at least one active service.
|
|
131
154
|
* Sorted by `sortOrder` so widgets can render groups in the same
|
|
132
155
|
* order the host configured. Empty when no categories exist on
|
|
133
|
-
* the workspace yet
|
|
156
|
+
* the workspace yet - widgets must fall back to a flat list in
|
|
134
157
|
* that case. */
|
|
135
158
|
categories: Array<{
|
|
136
159
|
_id: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAErE,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,SAAS,CAAC,EAAE,wBAAwB,CAAA;IACpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;CAC5C,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE;QACJ,GAAG,EAAE,MAAM,CAAA;QACX,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;QACZ,YAAY,EAAE,MAAM,CAAA;QACpB,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;IACD,OAAO,EAAE;QACP,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;QAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;QAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;QAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;QACtB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;QAC/B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;QACxB,WAAW,EAAE;YACX,SAAS,CAAC,EAAE,MAAM,CAAA;YAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;YACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;YACjB,wBAAwB,CAAC,EAAE,MAAM,CAAA;YACjC,MAAM,CAAC,EAAE,MAAM,CAAA;YACf,OAAO,CAAC,EAAE,MAAM,CAAA;SACjB,GAAG,IAAI,CAAA;QACR,aAAa,EAAE,KAAK,CAAC;YACnB,GAAG,EAAE,MAAM,CAAA;YACX,MAAM,EAAE,OAAO,CAAA;YACf,QAAQ,CAAC,EAAE,MAAM,CAAA;YACjB,SAAS,CAAC,EAAE,MAAM,CAAA;SACnB,CAAC,CAAA;QACF,cAAc,EAAE,OAAO,CAAA;QACvB,eAAe,EAAE;YACf,oBAAoB,EAAE,OAAO,CAAA;YAC7B,2BAA2B,EAAE,MAAM,CAAA;YACnC,4BAA4B,EAAE,MAAM,CAAA;YACpC,mBAAmB,EAAE,OAAO,CAAA;YAC5B,qBAAqB,EAAE,OAAO,CAAA;YAC9B,sBAAsB,CAAC,EAAE,MAAM,CAAA;SAChC,GAAG,IAAI,CAAA;KACT,CAAA;IACD,SAAS,CAAC,EAAE,wBAAwB,CAAA;CACrC,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|