@mohasinac/appkit 4.55.0-next.0 → 4.56.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/dist/.build-stamp.json +4 -4
- package/dist/_internal/server/features/checkout/actions.d.ts +22 -0
- package/dist/_internal/server/features/checkout/actions.js +100 -5
- package/dist/_internal/server/features/shipping/reconcile.d.ts +28 -0
- package/dist/_internal/server/features/shipping/reconcile.js +93 -0
- package/dist/_internal/shared/config/schema.d.ts +6 -0
- package/dist/_internal/shared/features/checkout/config.d.ts +1 -1
- package/dist/_internal/shared/features/checkout/config.js +1 -1
- package/dist/_internal/shared/features/site-settings/fees.d.ts +1 -1
- package/dist/_internal/shared/features/site-settings/fees.js +1 -1
- package/dist/_internal/shared/fees/calculator.d.ts +35 -3
- package/dist/_internal/shared/fees/calculator.js +34 -4
- package/dist/_internal/shared/listing-types/route-gating.d.ts +56 -0
- package/dist/_internal/shared/listing-types/route-gating.js +114 -0
- package/dist/_internal/shared/shipping/quote.d.ts +153 -0
- package/dist/_internal/shared/shipping/quote.js +124 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.js +8 -0
- package/dist/errors/error-codes.d.ts +15 -0
- package/dist/errors/error-codes.js +15 -0
- package/dist/errors/index.d.ts +1 -1
- package/dist/errors/index.js +1 -1
- package/dist/features/account/components/UserBidsView.js +4 -2
- package/dist/features/admin/components/AdminSiteSettingsView.js +18 -2
- package/dist/features/admin/schemas/firestore.d.ts +37 -2
- package/dist/features/admin/schemas/firestore.js +12 -1
- package/dist/features/auctions/components/AuctionDetailPageView.js +2 -1
- package/dist/features/auth/schemas/firestore.d.ts +15 -0
- package/dist/features/cart/components/CartPriceBreakdown.js +1 -1
- package/dist/features/checkout/schemas/firestore.d.ts +12 -1
- package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +2 -1
- package/dist/features/homepage/components/HeroCarousel.js +4 -2
- package/dist/features/homepage/components/MarketplaceHomepageView.js +16 -1
- package/dist/features/homepage/components/WelcomeSection.d.ts +16 -3
- package/dist/features/homepage/components/WelcomeSection.js +3 -3
- package/dist/features/homepage/lib/section-renderer.d.ts +9 -0
- package/dist/features/homepage/lib/section-renderer.js +22 -5
- package/dist/features/homepage/lib/slide-gating.d.ts +52 -0
- package/dist/features/homepage/lib/slide-gating.js +98 -0
- package/dist/features/layout/NavbarLayout.js +139 -32
- package/dist/features/live/components/LiveItemDetailPageView.js +2 -1
- package/dist/features/media/MediaAvatar.js +1 -1
- package/dist/features/media/MediaImage.d.ts +18 -1
- package/dist/features/media/MediaImage.js +1 -1
- package/dist/features/media/messages/en.json +67 -67
- package/dist/features/orders/schemas/firestore.d.ts +39 -1
- package/dist/features/points/repository/points.repository.d.ts +81 -0
- package/dist/features/points/repository/points.repository.js +155 -0
- package/dist/features/points/schemas/firestore.d.ts +102 -0
- package/dist/features/points/schemas/firestore.js +99 -0
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +2 -1
- package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -1
- package/dist/features/products/components/ProductDetailPageView.js +5 -26
- package/dist/features/products/components/ProductOwnerQuickActions.d.ts +11 -0
- package/dist/features/products/components/ProductOwnerQuickActions.js +120 -0
- package/dist/features/products/components/ProductsIndexListing.js +35 -5
- package/dist/features/products/components/ProductsIndexPageView.js +40 -7
- package/dist/features/seller/actions/seller-actions.d.ts +17 -0
- package/dist/features/seller/actions/seller-actions.js +33 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +8 -0
- package/dist/providers/shipping-shiprocket/index.d.ts +13 -4
- package/dist/providers/shipping-shiprocket/index.js +34 -10
- package/dist/security/csp.d.ts +1 -16
- package/dist/security/csp.js +3 -5
- package/dist/seed/carousel-slides-seed-data.js +48 -7
- package/dist/seed/faq-seed-data.js +1 -1
- package/dist/seed/site-settings-seed-data.js +1 -1
- package/dist/seo/json-ld.d.ts +8 -1
- package/dist/seo/json-ld.js +39 -2
- package/dist/styles.css +419 -542
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/index.d.ts +1 -3
- package/dist/tokens/themes/index.js +1 -11
- package/dist/tokens/tokens.css +0 -155
- package/dist/ui/components/GatedPrice.style.css +43 -43
- package/dist/ui/components/ImageMosaic.d.ts +17 -1
- package/dist/ui/components/ImageMosaic.js +28 -5
- package/dist/ui/components/ImageMosaic.style.css +37 -5
- package/dist/ui/components/QuickCreateModal.style.css +78 -78
- package/dist/ui/forms/FormShell.style.css +260 -260
- package/package.json +1 -1
- package/dist/tokens/themes/technical-dark.d.ts +0 -30
- package/dist/tokens/themes/technical-dark.js +0 -103
- package/dist/tokens/themes/technical-light.d.ts +0 -22
- package/dist/tokens/themes/technical-light.js +0 -89
|
@@ -2,10 +2,8 @@ import { DEFAULT_DARK_THEME } from "./default-dark";
|
|
|
2
2
|
import { DEFAULT_LIGHT_THEME } from "./default-light";
|
|
3
3
|
import { COBALT_NIGHT_THEME } from "./cobalt-night";
|
|
4
4
|
import { SUNSET_THEME } from "./sunset";
|
|
5
|
-
import { TECHNICAL_DARK_THEME } from "./technical-dark";
|
|
6
|
-
import { TECHNICAL_LIGHT_THEME } from "./technical-light";
|
|
7
5
|
import type { ThemeMode, ThemeRecord } from "./types";
|
|
8
|
-
export { DEFAULT_LIGHT_THEME, DEFAULT_DARK_THEME, COBALT_NIGHT_THEME, SUNSET_THEME
|
|
6
|
+
export { DEFAULT_LIGHT_THEME, DEFAULT_DARK_THEME, COBALT_NIGHT_THEME, SUNSET_THEME };
|
|
9
7
|
export { REQUIRED_GRADIENT_KEYS, REQUIRED_THEME_TOKENS } from "./required";
|
|
10
8
|
export type { RequiredThemeToken } from "./required";
|
|
11
9
|
export type { GradientKey, ThemeMode, ThemeRecord } from "./types";
|
|
@@ -2,9 +2,7 @@ import { DEFAULT_DARK_THEME } from "./default-dark.js";
|
|
|
2
2
|
import { DEFAULT_LIGHT_THEME } from "./default-light.js";
|
|
3
3
|
import { COBALT_NIGHT_THEME } from "./cobalt-night.js";
|
|
4
4
|
import { SUNSET_THEME } from "./sunset.js";
|
|
5
|
-
|
|
6
|
-
import { TECHNICAL_LIGHT_THEME } from "./technical-light.js";
|
|
7
|
-
export { DEFAULT_LIGHT_THEME, DEFAULT_DARK_THEME, COBALT_NIGHT_THEME, SUNSET_THEME, TECHNICAL_DARK_THEME, TECHNICAL_LIGHT_THEME, };
|
|
5
|
+
export { DEFAULT_LIGHT_THEME, DEFAULT_DARK_THEME, COBALT_NIGHT_THEME, SUNSET_THEME };
|
|
8
6
|
export { REQUIRED_GRADIENT_KEYS, REQUIRED_THEME_TOKENS } from "./required.js";
|
|
9
7
|
/** Built-in themes that ship with appkit; admin cannot delete these. */
|
|
10
8
|
export const BUILT_IN_THEMES = [
|
|
@@ -19,14 +17,6 @@ export const BUILT_IN_THEMES = [
|
|
|
19
17
|
export const THEME_TEMPLATES = [
|
|
20
18
|
COBALT_NIGHT_THEME,
|
|
21
19
|
SUNSET_THEME,
|
|
22
|
-
/*
|
|
23
|
-
* Technical Dark / Light — a developer-tool identity: graphite surfaces,
|
|
24
|
-
* hairline borders, a mono-forward type stack and syntax-palette accents
|
|
25
|
-
* reused semantically (difficulty badges, submission verdicts, status chips).
|
|
26
|
-
* Shipped as a matched PAIR so switching mode does not change identity.
|
|
27
|
-
*/
|
|
28
|
-
TECHNICAL_DARK_THEME,
|
|
29
|
-
TECHNICAL_LIGHT_THEME,
|
|
30
20
|
];
|
|
31
21
|
/**
|
|
32
22
|
* Find the default built-in theme for a given mode.
|
package/dist/tokens/tokens.css
CHANGED
|
@@ -632,161 +632,6 @@
|
|
|
632
632
|
--appkit-shadow-glow-pink: 0 0 0 1px rgba(244,63,94,0.18), 0 4px 20px -4px rgba(244,63,94,0.30);
|
|
633
633
|
}
|
|
634
634
|
|
|
635
|
-
/* --- Theme — Technical Dark ([data-theme="technical-dark"]) --------------- */
|
|
636
|
-
/* Developer-tool identity: graphite surfaces, hairline borders, a mono-forward
|
|
637
|
-
type stack, and accents from a syntax palette (keyword violet, string green,
|
|
638
|
-
number amber, error red) reused semantically for difficulty badges,
|
|
639
|
-
submission verdicts and status chips.
|
|
640
|
-
|
|
641
|
-
Mirrors src/tokens/themes/technical-dark.ts — values must stay identical or
|
|
642
|
-
the first paint disagrees with the hydrated theme.
|
|
643
|
-
|
|
644
|
-
Contrast on --appkit-color-bg (#0b0d10), measured: text 15.82:1,
|
|
645
|
-
muted 7.72:1, faint 4.68:1, primary 6.53:1, lowest status 7.01:1. */
|
|
646
|
-
[data-theme="technical-dark"] {
|
|
647
|
-
--appkit-color-primary: #7c8cff;
|
|
648
|
-
--appkit-color-primary-50: #eef0ff;
|
|
649
|
-
--appkit-color-primary-100: #e0e4ff;
|
|
650
|
-
--appkit-color-primary-200: #c7cdff;
|
|
651
|
-
--appkit-color-primary-300: #a5aeff;
|
|
652
|
-
--appkit-color-primary-400: #8e99ff;
|
|
653
|
-
--appkit-color-primary-500: #7c8cff;
|
|
654
|
-
--appkit-color-primary-600: #5a68e8;
|
|
655
|
-
--appkit-color-primary-700: #4650c4;
|
|
656
|
-
--appkit-color-primary-800: #373f9c;
|
|
657
|
-
--appkit-color-primary-900: #2b317a;
|
|
658
|
-
--appkit-color-primary-950: #171a45;
|
|
659
|
-
|
|
660
|
-
--appkit-color-secondary: #56d39a;
|
|
661
|
-
--appkit-color-secondary-50: #ecfdf5;
|
|
662
|
-
--appkit-color-secondary-100: #d1fae5;
|
|
663
|
-
--appkit-color-secondary-200: #a7f3d0;
|
|
664
|
-
--appkit-color-secondary-300: #7ee7b8;
|
|
665
|
-
--appkit-color-secondary-400: #56d39a;
|
|
666
|
-
--appkit-color-secondary-500: #34b87d;
|
|
667
|
-
--appkit-color-secondary-600: #1f9664;
|
|
668
|
-
--appkit-color-secondary-700: #187752;
|
|
669
|
-
--appkit-color-secondary-800: #155e42;
|
|
670
|
-
--appkit-color-secondary-900: #124b36;
|
|
671
|
-
--appkit-color-secondary-950: #062a1d;
|
|
672
|
-
|
|
673
|
-
--appkit-color-bg: #0b0d10;
|
|
674
|
-
--appkit-color-surface: #13161b;
|
|
675
|
-
--appkit-color-surface-elevated: rgba(19, 22, 27, 0.92);
|
|
676
|
-
--appkit-color-surface-input: rgba(27, 31, 38, 0.7);
|
|
677
|
-
|
|
678
|
-
--appkit-color-surface-hover: rgba(148, 163, 184, 0.1);
|
|
679
|
-
--appkit-color-surface-raised: rgba(27, 31, 38, 0.8);
|
|
680
|
-
--appkit-color-primary-surface: rgba(124, 140, 255, 0.16);
|
|
681
|
-
|
|
682
|
-
--appkit-color-border: #242a33;
|
|
683
|
-
--appkit-color-border-subtle: rgba(36, 42, 51, 0.6);
|
|
684
|
-
|
|
685
|
-
--appkit-color-text: #e4e8ee;
|
|
686
|
-
--appkit-color-text-muted: #9aa4b2;
|
|
687
|
-
--appkit-color-text-faint: #747d8c;
|
|
688
|
-
/* Dark ink on the violet fill: 6.53:1, where white measures 2.98:1 and
|
|
689
|
-
fails. Declared here AND in the TS record or first paint disagrees. */
|
|
690
|
-
--appkit-color-text-on-primary: #0b0d10;
|
|
691
|
-
|
|
692
|
-
--appkit-color-success: #4ade80;
|
|
693
|
-
--appkit-color-success-surface: rgba(22, 101, 68, 0.22);
|
|
694
|
-
--appkit-color-warning: #f2b544;
|
|
695
|
-
--appkit-color-warning-surface: rgba(120, 78, 10, 0.22);
|
|
696
|
-
--appkit-color-error: #ff6b6b;
|
|
697
|
-
--appkit-color-error-surface: rgba(140, 30, 30, 0.22);
|
|
698
|
-
--appkit-color-info: #58b4ff;
|
|
699
|
-
--appkit-color-info-surface: rgba(12, 74, 110, 0.22);
|
|
700
|
-
|
|
701
|
-
/* Amber, deliberately not a status or brand hue — a focus ring that doubles
|
|
702
|
-
as an error colour is unreadable on an invalid field. */
|
|
703
|
-
--appkit-color-focus-ring: #ffb86b;
|
|
704
|
-
--appkit-shadow-glow: 0 0 0 1px rgba(124,140,255,0.14), 0 4px 16px -6px rgba(124,140,255,0.2);
|
|
705
|
-
--appkit-shadow-glow-pink: 0 0 0 1px rgba(86,211,154,0.14), 0 4px 18px -6px rgba(86,211,154,0.22);
|
|
706
|
-
|
|
707
|
-
/* Mono-forward: display/sans are monospace for headings, labels, IDs and
|
|
708
|
-
tables; editorial carries the reading face for long lesson prose. */
|
|
709
|
-
--appkit-font-display: var(--font-mono), "JetBrains Mono", "IBM Plex Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
|
|
710
|
-
--appkit-font-sans: var(--font-mono), "JetBrains Mono", "IBM Plex Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
|
|
711
|
-
--appkit-font-editorial: var(--font-body), ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
712
|
-
--appkit-font-mono: var(--font-mono), "JetBrains Mono", "IBM Plex Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
/* --- Theme — Technical Light ([data-theme="technical-light"]) ------------- */
|
|
716
|
-
/* The matched light counterpart. Every accent is RE-DARKENED rather than
|
|
717
|
-
reused: the dark preset's #7c8cff measures 2.88:1 on this ground and fails
|
|
718
|
-
AA, and its #ffb86b focus ring measures 1.65:1 — an invisible focus ring is
|
|
719
|
-
a keyboard trap.
|
|
720
|
-
|
|
721
|
-
Mirrors src/tokens/themes/technical-light.ts.
|
|
722
|
-
|
|
723
|
-
Contrast on --appkit-color-bg (#fbfbfa), measured: text 17.15:1,
|
|
724
|
-
muted 5.84:1, faint 4.67:1, primary 5.38:1, lowest status 4.80:1. */
|
|
725
|
-
[data-theme="technical-light"] {
|
|
726
|
-
--appkit-color-primary: #4b5bd6;
|
|
727
|
-
--appkit-color-primary-50: #eef0ff;
|
|
728
|
-
--appkit-color-primary-100: #e0e4ff;
|
|
729
|
-
--appkit-color-primary-200: #c7cdff;
|
|
730
|
-
--appkit-color-primary-300: #a5aeff;
|
|
731
|
-
--appkit-color-primary-400: #7c8cff;
|
|
732
|
-
--appkit-color-primary-500: #5a68e8;
|
|
733
|
-
--appkit-color-primary-600: #4b5bd6;
|
|
734
|
-
--appkit-color-primary-700: #3b45ad;
|
|
735
|
-
--appkit-color-primary-800: #2f3789;
|
|
736
|
-
--appkit-color-primary-900: #262c6d;
|
|
737
|
-
--appkit-color-primary-950: #151840;
|
|
738
|
-
|
|
739
|
-
--appkit-color-secondary: #0f8f5f;
|
|
740
|
-
--appkit-color-secondary-50: #ecfdf5;
|
|
741
|
-
--appkit-color-secondary-100: #d1fae5;
|
|
742
|
-
--appkit-color-secondary-200: #a7f3d0;
|
|
743
|
-
--appkit-color-secondary-300: #6ee7b7;
|
|
744
|
-
--appkit-color-secondary-400: #34b87d;
|
|
745
|
-
--appkit-color-secondary-500: #0f8f5f;
|
|
746
|
-
--appkit-color-secondary-600: #0c744d;
|
|
747
|
-
--appkit-color-secondary-700: #0a5c3d;
|
|
748
|
-
--appkit-color-secondary-800: #084830;
|
|
749
|
-
--appkit-color-secondary-900: #063a27;
|
|
750
|
-
--appkit-color-secondary-950: #032016;
|
|
751
|
-
|
|
752
|
-
--appkit-color-bg: #fbfbfa;
|
|
753
|
-
--appkit-color-surface: #ffffff;
|
|
754
|
-
--appkit-color-surface-elevated: rgba(255, 255, 255, 0.96);
|
|
755
|
-
--appkit-color-surface-input: rgba(244, 244, 242, 0.8);
|
|
756
|
-
|
|
757
|
-
--appkit-color-surface-hover: rgba(22, 24, 29, 0.05);
|
|
758
|
-
--appkit-color-surface-raised: rgba(244, 244, 242, 0.9);
|
|
759
|
-
--appkit-color-primary-surface: rgba(75, 91, 214, 0.1);
|
|
760
|
-
|
|
761
|
-
--appkit-color-border: #e2e2df;
|
|
762
|
-
--appkit-color-border-subtle: rgba(226, 226, 223, 0.7);
|
|
763
|
-
|
|
764
|
-
--appkit-color-text: #16181d;
|
|
765
|
-
--appkit-color-text-muted: #5c6370;
|
|
766
|
-
/* #767d89 measured 4.00:1 — AA for large text only. Darkened to clear AA
|
|
767
|
-
at body size. */
|
|
768
|
-
--appkit-color-text-faint: #6b7280;
|
|
769
|
-
--appkit-color-text-on-primary: #ffffff;
|
|
770
|
-
|
|
771
|
-
--appkit-color-success: #13804f;
|
|
772
|
-
--appkit-color-success-surface: rgba(19, 128, 79, 0.1);
|
|
773
|
-
--appkit-color-warning: #9a6400;
|
|
774
|
-
--appkit-color-warning-surface: rgba(154, 100, 0, 0.1);
|
|
775
|
-
--appkit-color-error: #c62828;
|
|
776
|
-
--appkit-color-error-surface: rgba(198, 40, 40, 0.1);
|
|
777
|
-
--appkit-color-info: #0a69b5;
|
|
778
|
-
--appkit-color-info-surface: rgba(10, 105, 181, 0.1);
|
|
779
|
-
|
|
780
|
-
--appkit-color-focus-ring: #b45a00;
|
|
781
|
-
--appkit-shadow-glow: 0 0 0 1px rgba(75,91,214,0.14), 0 4px 16px -6px rgba(75,91,214,0.18);
|
|
782
|
-
--appkit-shadow-glow-pink: 0 0 0 1px rgba(15,143,95,0.14), 0 4px 18px -6px rgba(15,143,95,0.2);
|
|
783
|
-
|
|
784
|
-
--appkit-font-display: var(--font-mono), "JetBrains Mono", "IBM Plex Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
|
|
785
|
-
--appkit-font-sans: var(--font-mono), "JetBrains Mono", "IBM Plex Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
|
|
786
|
-
--appkit-font-editorial: var(--font-body), ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
787
|
-
--appkit-font-mono: var(--font-mono), "JetBrains Mono", "IBM Plex Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
|
|
788
|
-
}
|
|
789
|
-
|
|
790
635
|
/* --- Typography ----------------------------------------------------------- */
|
|
791
636
|
:root {
|
|
792
637
|
--appkit-font-sans: var(--font-body), ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sign-in gate for money amounts on public listing surfaces.
|
|
3
|
-
*
|
|
4
|
-
* The pending state must occupy the SAME vertical space as a rendered price, or
|
|
5
|
-
* every card in a grid reflows once the session resolves. It is deliberately a
|
|
6
|
-
* silent placeholder rather than a shimmer: the wait is short, and an animated
|
|
7
|
-
* skeleton on 24 cards reads as a page that failed to load.
|
|
8
|
-
*/
|
|
9
|
-
.appkit-gated-price__pending {
|
|
10
|
-
display: inline-block;
|
|
11
|
-
min-width: 5rem;
|
|
12
|
-
height: 1.25rem;
|
|
13
|
-
border-radius: 0.25rem;
|
|
14
|
-
/* 🛑 `--appkit-color-surface-muted` is NOT a token — 15 uses, 0 definitions,
|
|
15
|
-
and `audit-undefined-css-vars` ratchets it down. An undefined custom
|
|
16
|
-
property with no fallback makes the whole declaration invalid, so this
|
|
17
|
-
placeholder had no background at all and the grid still reflowed on
|
|
18
|
-
resolve, which is the one job it has. */
|
|
19
|
-
background: var(--appkit-color-surface-input);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.appkit-gated-price__prompt {
|
|
23
|
-
display: inline-flex;
|
|
24
|
-
align-items: center;
|
|
25
|
-
/*
|
|
26
|
-
* The eye is a 2rem IconButton while `__pending` above is a 1.25rem price
|
|
27
|
-
* line, so a GUEST's row grows by 0.75rem once the session resolves. That is
|
|
28
|
-
* deliberate and is the lesser of the two: the alternative is making
|
|
29
|
-
* `__pending` 2rem, which shifts the row for SIGNED-IN users — the ones who
|
|
30
|
-
* end up looking at real content. The guest shift happens once per load and
|
|
31
|
-
* applies to every card identically, so the grid moves as one rather than
|
|
32
|
-
* going ragged.
|
|
33
|
-
*/
|
|
34
|
-
line-height: 1.25rem;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/*
|
|
38
|
-
* 🛑 The eye itself has NO rules here, on purpose. It is an `<IconButton
|
|
39
|
-
* size="sm" variant="outline">`, so its box, ink, hover and focus ring all
|
|
40
|
-
* come from the design system — a second, private set of button styles for
|
|
41
|
-
* one control is exactly how a UI ends up with two kinds of icon button that
|
|
42
|
-
* drift apart. This wrapper only has to keep the row's height stable.
|
|
43
|
-
*/
|
|
1
|
+
/**
|
|
2
|
+
* Sign-in gate for money amounts on public listing surfaces.
|
|
3
|
+
*
|
|
4
|
+
* The pending state must occupy the SAME vertical space as a rendered price, or
|
|
5
|
+
* every card in a grid reflows once the session resolves. It is deliberately a
|
|
6
|
+
* silent placeholder rather than a shimmer: the wait is short, and an animated
|
|
7
|
+
* skeleton on 24 cards reads as a page that failed to load.
|
|
8
|
+
*/
|
|
9
|
+
.appkit-gated-price__pending {
|
|
10
|
+
display: inline-block;
|
|
11
|
+
min-width: 5rem;
|
|
12
|
+
height: 1.25rem;
|
|
13
|
+
border-radius: 0.25rem;
|
|
14
|
+
/* 🛑 `--appkit-color-surface-muted` is NOT a token — 15 uses, 0 definitions,
|
|
15
|
+
and `audit-undefined-css-vars` ratchets it down. An undefined custom
|
|
16
|
+
property with no fallback makes the whole declaration invalid, so this
|
|
17
|
+
placeholder had no background at all and the grid still reflowed on
|
|
18
|
+
resolve, which is the one job it has. */
|
|
19
|
+
background: var(--appkit-color-surface-input);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.appkit-gated-price__prompt {
|
|
23
|
+
display: inline-flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
/*
|
|
26
|
+
* The eye is a 2rem IconButton while `__pending` above is a 1.25rem price
|
|
27
|
+
* line, so a GUEST's row grows by 0.75rem once the session resolves. That is
|
|
28
|
+
* deliberate and is the lesser of the two: the alternative is making
|
|
29
|
+
* `__pending` 2rem, which shifts the row for SIGNED-IN users — the ones who
|
|
30
|
+
* end up looking at real content. The guest shift happens once per load and
|
|
31
|
+
* applies to every card identically, so the grid moves as one rather than
|
|
32
|
+
* going ragged.
|
|
33
|
+
*/
|
|
34
|
+
line-height: 1.25rem;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/*
|
|
38
|
+
* 🛑 The eye itself has NO rules here, on purpose. It is an `<IconButton
|
|
39
|
+
* size="sm" variant="outline">`, so its box, ink, hover and focus ring all
|
|
40
|
+
* come from the design system — a second, private set of button styles for
|
|
41
|
+
* one control is exactly how a UI ends up with two kinds of icon button that
|
|
42
|
+
* drift apart. This wrapper only has to keep the row's height stable.
|
|
43
|
+
*/
|
|
@@ -13,6 +13,22 @@ export interface ImageMosaicProps {
|
|
|
13
13
|
alt: string;
|
|
14
14
|
/** Height preset. Defaults to `"band"`, the original behaviour. */
|
|
15
15
|
size?: ImageMosaicSize;
|
|
16
|
+
/**
|
|
17
|
+
* Replaces the large cell's image with arbitrary content — the homepage
|
|
18
|
+
* hero's brand panel is the only caller.
|
|
19
|
+
*
|
|
20
|
+
* 🛑 It changes what `images` MEANS, which is the whole reason it is a
|
|
21
|
+
* separate prop rather than a `images[0]`-shaped special case: without a
|
|
22
|
+
* slot the first image takes the large cell, with one EVERY image goes to
|
|
23
|
+
* the small column. A caller that passes both a slot and three images gets
|
|
24
|
+
* three small tiles, not two.
|
|
25
|
+
*
|
|
26
|
+
* `MOSAIC_MIN` is also not applied in this mode. The minimum exists because
|
|
27
|
+
* fewer than three images is not an arrangement — but a slot is content in
|
|
28
|
+
* its own right, so one image beside it is still a composition, and zero
|
|
29
|
+
* images collapses to the slot alone at full width.
|
|
30
|
+
*/
|
|
31
|
+
leadSlot?: React.ReactNode;
|
|
16
32
|
className?: string;
|
|
17
33
|
}
|
|
18
34
|
/**
|
|
@@ -47,4 +63,4 @@ export interface ImageMosaicProps {
|
|
|
47
63
|
* breaks SSR/hydration agreement and makes the page feel unstable — and it is
|
|
48
64
|
* the shape Root Cause #25 is about on the seed side.
|
|
49
65
|
*/
|
|
50
|
-
export declare function ImageMosaic({ images, alt, size, className }: ImageMosaicProps): React.JSX.Element | null;
|
|
66
|
+
export declare function ImageMosaic({ images, alt, size, leadSlot, className }: ImageMosaicProps): React.JSX.Element | null;
|
|
@@ -37,11 +37,34 @@ export const MOSAIC_MIN = 3;
|
|
|
37
37
|
* breaks SSR/hydration agreement and makes the page feel unstable — and it is
|
|
38
38
|
* the shape Root Cause #25 is about on the seed side.
|
|
39
39
|
*/
|
|
40
|
-
export function ImageMosaic({ images, alt, size = "band", className }) {
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
export function ImageMosaic({ images, alt, size = "band", leadSlot, className }) {
|
|
41
|
+
// With a slot the large cell is already spoken for, so the whole budget
|
|
42
|
+
// belongs to the small column — one fewer tile than the image-led shape.
|
|
43
|
+
const tiles = images.filter(Boolean).slice(0, leadSlot ? MOSAIC_MAX - 1 : MOSAIC_MAX);
|
|
44
|
+
if (!leadSlot && tiles.length < MOSAIC_MIN)
|
|
43
45
|
return null;
|
|
44
|
-
const [lead, ...rest] = tiles;
|
|
46
|
+
const [lead, ...rest] = leadSlot ? [undefined, ...tiles] : tiles;
|
|
45
47
|
const sizeClass = size === "hero" ? "appkit-image-mosaic--hero" : "";
|
|
46
|
-
|
|
48
|
+
// Nothing to put in the small column — the 1fr track would otherwise render
|
|
49
|
+
// as an empty gutter beside the slot, which reads as a failed image load
|
|
50
|
+
// rather than as a deliberate panel.
|
|
51
|
+
const soloClass = leadSlot && rest.length === 0 ? "appkit-image-mosaic--solo" : "";
|
|
52
|
+
/*
|
|
53
|
+
* 🛑 WHERE `role="img"` GOES DEPENDS ON THE SLOT, and getting this wrong is
|
|
54
|
+
* silent.
|
|
55
|
+
*
|
|
56
|
+
* `role="img"` collapses its entire subtree into ONE node named by
|
|
57
|
+
* `aria-label` — that is exactly right for a group of decorative thumbnails
|
|
58
|
+
* (point 1 in the header: one alt describing the subject, not five
|
|
59
|
+
* filenames). Leave it on the grid in `leadSlot` mode and it also swallows
|
|
60
|
+
* the slot, so the hero's logo and its "Let It Rip India" caption would
|
|
61
|
+
* reach a screen reader as "…collection highlights" and nothing else — real
|
|
62
|
+
* content erased by a label meant for the pictures beside it.
|
|
63
|
+
*
|
|
64
|
+
* So in slot mode the role moves down to the image group, where it belongs,
|
|
65
|
+
* and the slot stays ordinary DOM. The no-slot path is byte-identical to
|
|
66
|
+
* what it always was.
|
|
67
|
+
*/
|
|
68
|
+
const imageGroupA11y = { role: "img", "aria-label": alt };
|
|
69
|
+
return (_jsxs(Div, { className: `appkit-image-mosaic ${sizeClass} ${soloClass} ${className ?? ""}`, ...(leadSlot ? {} : imageGroupA11y), children: [_jsx(Div, { className: "appkit-image-mosaic__lead", children: leadSlot ?? _jsx(MediaImage, { src: lead, alt: "", size: "card" }) }), rest.length > 0 && (_jsx(Div, { className: "appkit-image-mosaic__rest", ...(leadSlot ? imageGroupA11y : {}), children: rest.map((src, i) => (_jsx(Div, { className: "appkit-image-mosaic__tile", children: _jsx(MediaImage, { src: src, alt: "", size: "thumbnail" }) }, `${src}-${i}`))) }))] }));
|
|
47
70
|
}
|
|
@@ -7,10 +7,19 @@
|
|
|
7
7
|
* around as a visitor moves through the tree. A fixed height per breakpoint is
|
|
8
8
|
* the one shape that keeps the hero stable.
|
|
9
9
|
*
|
|
10
|
-
* 🛑 `overflow: hidden` on the grid and
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* 🛑 `overflow: hidden` on the grid, and the images are CONTAINED rather than
|
|
11
|
+
* cropped. This block used to say the opposite — "cropping is the only option
|
|
12
|
+
* that does not distort the subject" — and `object-fit: cover` was declared
|
|
13
|
+
* here. Both are gone: `MediaImage` now defaults to `contain` app-wide, which
|
|
14
|
+
* it applies as a Tailwind utility, and both Tailwind configs set
|
|
15
|
+
* `important: true` — so a plain `object-fit: cover` declaration here could
|
|
16
|
+
* never have won anyway. It would have been a rule that reads as the
|
|
17
|
+
* governing decision while changing nothing (Root Cause #106).
|
|
18
|
+
*
|
|
19
|
+
* The trade is real and is the one that was asked for: a 4:3 publisher shot in
|
|
20
|
+
* a square tile now letterboxes against `--appkit-color-surface` instead of
|
|
21
|
+
* having its edges cut off. Most of this catalogue's imagery is product-on-
|
|
22
|
+
* white, where a crop removes the product and `contain` does not.
|
|
14
23
|
*/
|
|
15
24
|
.appkit-image-mosaic {
|
|
16
25
|
display: grid;
|
|
@@ -49,6 +58,16 @@
|
|
|
49
58
|
}
|
|
50
59
|
}
|
|
51
60
|
|
|
61
|
+
/*
|
|
62
|
+
* `--solo` — a `leadSlot` with no images beside it.
|
|
63
|
+
*
|
|
64
|
+
* One column, not `2fr 1fr`. The small track has nothing to hold, and an empty
|
|
65
|
+
* 1fr gutter beside a brand panel reads as four images that failed to load.
|
|
66
|
+
*/
|
|
67
|
+
.appkit-image-mosaic--solo {
|
|
68
|
+
grid-template-columns: 1fr;
|
|
69
|
+
}
|
|
70
|
+
|
|
52
71
|
.appkit-image-mosaic__lead,
|
|
53
72
|
.appkit-image-mosaic__tile {
|
|
54
73
|
position: relative;
|
|
@@ -61,7 +80,20 @@
|
|
|
61
80
|
.appkit-image-mosaic__tile img {
|
|
62
81
|
width: 100%;
|
|
63
82
|
height: 100%;
|
|
64
|
-
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/*
|
|
86
|
+
* Breathing room INSIDE the tile, so a contained image stops short of the
|
|
87
|
+
* rounded corners instead of touching them. On `cover` this was unnecessary —
|
|
88
|
+
* the crop ran to the edge by definition — which is why it arrives with the
|
|
89
|
+
* fit change rather than before it.
|
|
90
|
+
*/
|
|
91
|
+
.appkit-image-mosaic__lead img {
|
|
92
|
+
padding: var(--appkit-space-3);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.appkit-image-mosaic__tile img {
|
|
96
|
+
padding: var(--appkit-space-2);
|
|
65
97
|
}
|
|
66
98
|
|
|
67
99
|
.appkit-image-mosaic__rest {
|
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
.appkit-quick-create-modal {
|
|
2
|
-
position: fixed;
|
|
3
|
-
inset: 0;
|
|
4
|
-
z-index: var(--appkit-z-modal, 1000);
|
|
5
|
-
display: flex;
|
|
6
|
-
align-items: stretch;
|
|
7
|
-
justify-content: center;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.appkit-quick-create-modal__backdrop {
|
|
11
|
-
position: absolute;
|
|
12
|
-
inset: 0;
|
|
13
|
-
background: rgb(0 0 0 / 0.45);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.appkit-quick-create-modal__panel {
|
|
17
|
-
position: relative;
|
|
18
|
-
display: flex;
|
|
19
|
-
flex-direction: column;
|
|
20
|
-
background: var(--appkit-color-surface, #ffffff);
|
|
21
|
-
color: var(--appkit-color-foreground, inherit);
|
|
22
|
-
width: 100%;
|
|
23
|
-
max-width: 560px;
|
|
24
|
-
margin: auto;
|
|
25
|
-
max-height: 92vh;
|
|
26
|
-
border-radius: 0.75rem;
|
|
27
|
-
box-shadow: var(--appkit-shadow-lg, 0 20px 40px rgb(0 0 0 / 0.25));
|
|
28
|
-
outline: none;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.appkit-quick-create-modal__header {
|
|
32
|
-
display: flex;
|
|
33
|
-
align-items: center;
|
|
34
|
-
justify-content: space-between;
|
|
35
|
-
padding: 1rem 1.25rem;
|
|
36
|
-
border-bottom: 1px solid var(--appkit-color-border, rgb(0 0 0 / 0.1));
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.appkit-quick-create-modal__title {
|
|
40
|
-
margin: 0;
|
|
41
|
-
font-size: 1.125rem;
|
|
42
|
-
font-weight: 600;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.appkit-quick-create-modal__body {
|
|
46
|
-
flex: 1 1 auto;
|
|
47
|
-
overflow-y: auto;
|
|
48
|
-
padding: 1.25rem;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/* Chrome only — layout comes from ActionRow. Re-adding `display: flex` or
|
|
52
|
-
`justify-content` here would fight the row this class now decorates. */
|
|
53
|
-
.appkit-quick-create-modal__footer {
|
|
54
|
-
padding: 1rem 1.25rem;
|
|
55
|
-
border-top: 1px solid var(--appkit-color-border, rgb(0 0 0 / 0.1));
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.appkit-quick-create-modal__full-link {
|
|
59
|
-
font-size: 0.875rem;
|
|
60
|
-
color: var(--appkit-color-primary, #6366f1);
|
|
61
|
-
text-decoration: underline;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
@media (max-width: 640px) {
|
|
65
|
-
.appkit-quick-create-modal {
|
|
66
|
-
align-items: flex-end;
|
|
67
|
-
}
|
|
68
|
-
.appkit-quick-create-modal__panel {
|
|
69
|
-
max-width: 100%;
|
|
70
|
-
margin: 0;
|
|
71
|
-
border-radius: 0.75rem 0.75rem 0 0;
|
|
72
|
-
max-height: 92vh;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
[data-theme="default-dark"] .appkit-quick-create-modal__panel {
|
|
77
|
-
background: var(--appkit-color-surface-dark, #1e293b);
|
|
78
|
-
}
|
|
1
|
+
.appkit-quick-create-modal {
|
|
2
|
+
position: fixed;
|
|
3
|
+
inset: 0;
|
|
4
|
+
z-index: var(--appkit-z-modal, 1000);
|
|
5
|
+
display: flex;
|
|
6
|
+
align-items: stretch;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.appkit-quick-create-modal__backdrop {
|
|
11
|
+
position: absolute;
|
|
12
|
+
inset: 0;
|
|
13
|
+
background: rgb(0 0 0 / 0.45);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.appkit-quick-create-modal__panel {
|
|
17
|
+
position: relative;
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
background: var(--appkit-color-surface, #ffffff);
|
|
21
|
+
color: var(--appkit-color-foreground, inherit);
|
|
22
|
+
width: 100%;
|
|
23
|
+
max-width: 560px;
|
|
24
|
+
margin: auto;
|
|
25
|
+
max-height: 92vh;
|
|
26
|
+
border-radius: 0.75rem;
|
|
27
|
+
box-shadow: var(--appkit-shadow-lg, 0 20px 40px rgb(0 0 0 / 0.25));
|
|
28
|
+
outline: none;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.appkit-quick-create-modal__header {
|
|
32
|
+
display: flex;
|
|
33
|
+
align-items: center;
|
|
34
|
+
justify-content: space-between;
|
|
35
|
+
padding: 1rem 1.25rem;
|
|
36
|
+
border-bottom: 1px solid var(--appkit-color-border, rgb(0 0 0 / 0.1));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.appkit-quick-create-modal__title {
|
|
40
|
+
margin: 0;
|
|
41
|
+
font-size: 1.125rem;
|
|
42
|
+
font-weight: 600;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.appkit-quick-create-modal__body {
|
|
46
|
+
flex: 1 1 auto;
|
|
47
|
+
overflow-y: auto;
|
|
48
|
+
padding: 1.25rem;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* Chrome only — layout comes from ActionRow. Re-adding `display: flex` or
|
|
52
|
+
`justify-content` here would fight the row this class now decorates. */
|
|
53
|
+
.appkit-quick-create-modal__footer {
|
|
54
|
+
padding: 1rem 1.25rem;
|
|
55
|
+
border-top: 1px solid var(--appkit-color-border, rgb(0 0 0 / 0.1));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.appkit-quick-create-modal__full-link {
|
|
59
|
+
font-size: 0.875rem;
|
|
60
|
+
color: var(--appkit-color-primary, #6366f1);
|
|
61
|
+
text-decoration: underline;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@media (max-width: 640px) {
|
|
65
|
+
.appkit-quick-create-modal {
|
|
66
|
+
align-items: flex-end;
|
|
67
|
+
}
|
|
68
|
+
.appkit-quick-create-modal__panel {
|
|
69
|
+
max-width: 100%;
|
|
70
|
+
margin: 0;
|
|
71
|
+
border-radius: 0.75rem 0.75rem 0 0;
|
|
72
|
+
max-height: 92vh;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
[data-theme="default-dark"] .appkit-quick-create-modal__panel {
|
|
77
|
+
background: var(--appkit-color-surface-dark, #1e293b);
|
|
78
|
+
}
|