@thorprovider/blocks 0.1.3 → 2.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/CHANGELOG.md +155 -0
- package/README.md +228 -68
- package/docs/standards/data-contracts.md +13 -2
- package/package.json +26 -10
- package/scripts/fix-esm-extensions.mjs +40 -0
- package/src/blocks/application/login-forms/login-page.test.tsx +190 -0
- package/src/blocks/application/login-forms/login-page.tsx +240 -0
- package/src/blocks/application/password-recovery/forgot-password-page-1.tsx +6 -8
- package/src/blocks/application/signup-forms/signup-page-1.tsx +127 -129
- package/src/blocks/application/verification/verify-1.tsx +2 -2
- package/src/blocks/application/viewport-ownership.test.tsx +41 -0
- package/src/blocks/e-commerce/category-filters/category-listing-filter-fields.tsx +218 -0
- package/src/blocks/e-commerce/category-filters/{category-filter-2.test.tsx → category-listing.test.tsx} +287 -199
- package/src/blocks/e-commerce/category-filters/category-listing.tsx +934 -0
- package/src/blocks/e-commerce/checkout-forms/checkout-contact-step.tsx +149 -0
- package/src/blocks/e-commerce/checkout-forms/{checkout-form-1-country-field.tsx → checkout-country-field.tsx} +10 -8
- package/src/blocks/e-commerce/checkout-forms/checkout-order-summary.tsx +230 -0
- package/src/blocks/e-commerce/checkout-forms/checkout-payment-step.tsx +100 -0
- package/src/blocks/e-commerce/checkout-forms/checkout-progress.tsx +62 -0
- package/src/blocks/e-commerce/checkout-forms/checkout-review-step.tsx +59 -0
- package/src/blocks/e-commerce/checkout-forms/{checkout-form-1-shipping-step.tsx → checkout-shipping-step.tsx} +65 -41
- package/src/blocks/e-commerce/checkout-forms/checkout.test.tsx +478 -0
- package/src/blocks/e-commerce/checkout-forms/checkout.tsx +550 -0
- package/src/blocks/e-commerce/navigation/storefront-navbar-account-menu.test.tsx +56 -0
- package/src/blocks/{marketing/navbars/navbar-4-account-menu.tsx → e-commerce/navigation/storefront-navbar-account-menu.tsx} +3 -3
- package/src/blocks/{marketing/navbars/navbar-4-cart-sheet.test.tsx → e-commerce/navigation/storefront-navbar-cart-sheet.test.tsx} +22 -22
- package/src/blocks/{marketing/navbars/navbar-4-cart-sheet.tsx → e-commerce/navigation/storefront-navbar-cart-sheet.tsx} +3 -3
- package/src/blocks/{marketing/navbars/navbar-4-mobile-nav.tsx → e-commerce/navigation/storefront-navbar-mobile-nav.tsx} +4 -12
- package/src/blocks/{marketing/navbars/navbar-4-search-bar.tsx → e-commerce/navigation/storefront-navbar-search-bar.tsx} +3 -3
- package/src/blocks/{marketing/navbars/navbar-4.test.tsx → e-commerce/navigation/storefront-navbar.test.tsx} +67 -36
- package/src/blocks/{marketing/navbars/navbar-4.tsx → e-commerce/navigation/storefront-navbar.tsx} +43 -25
- package/src/blocks/e-commerce/product-categories/category-card-grid.test.tsx +122 -0
- package/src/blocks/e-commerce/product-categories/category-card.test.tsx +68 -0
- package/src/blocks/e-commerce/product-categories/category-card.tsx +172 -0
- package/src/blocks/e-commerce/product-categories/category-grid.test.tsx +67 -0
- package/src/blocks/e-commerce/product-categories/category-shared.tsx +109 -0
- package/src/blocks/e-commerce/product-categories/product-category-grid.tsx +170 -0
- package/src/blocks/e-commerce/product-categories/product-category.test.tsx +266 -0
- package/src/blocks/e-commerce/product-categories/product-category.tsx +462 -0
- package/src/blocks/e-commerce/product-list/product-card.test.tsx +263 -0
- package/src/blocks/e-commerce/product-list/product-card.tsx +447 -0
- package/src/blocks/e-commerce/product-list/product-grid.test.tsx +162 -0
- package/src/blocks/e-commerce/product-list/product-grid.tsx +114 -0
- package/src/blocks/e-commerce/product-overview/product-overview-gallery.tsx +71 -0
- package/src/blocks/e-commerce/product-overview/{product-overview-5-lightbox-tab.tsx → product-overview-lightbox-tab.tsx} +35 -23
- package/src/blocks/e-commerce/product-overview/{product-overview-5-reviews-tab.tsx → product-overview-reviews-tab.tsx} +40 -17
- package/src/blocks/e-commerce/product-overview/{product-overview-5-tabs.tsx → product-overview-tabs.tsx} +8 -7
- package/src/blocks/e-commerce/product-overview/product-overview.test.tsx +283 -0
- package/src/blocks/e-commerce/product-overview/product-overview.tsx +1186 -0
- package/src/blocks/e-commerce/reviews/review-rating-2.tsx +5 -6
- package/src/blocks/e-commerce/shopping-carts/shopping-cart.test.tsx +399 -0
- package/src/blocks/e-commerce/shopping-carts/{shopping-cart-4.tsx → shopping-cart.tsx} +119 -85
- package/src/blocks/e-commerce/storefront-hero/storefront-hero.test.tsx +412 -0
- package/src/blocks/e-commerce/storefront-hero/storefront-hero.tsx +1283 -0
- package/src/blocks/marketing/features/feature.test.tsx +153 -0
- package/src/blocks/marketing/features/feature.tsx +195 -0
- package/src/blocks/marketing/footers/footer-section-accessibility.test.tsx +118 -0
- package/src/blocks/marketing/footers/footer-section-actions.test.tsx +131 -0
- package/src/blocks/marketing/footers/footer-section-data.test.tsx +127 -0
- package/src/blocks/marketing/footers/footer-section-native-links.test.tsx +100 -0
- package/src/blocks/marketing/footers/footer-section-public-api.test.tsx +11 -0
- package/src/blocks/marketing/footers/footer-section.test.tsx +46 -0
- package/src/blocks/marketing/footers/footer-section.tsx +532 -0
- package/src/blocks/marketing/navbars/navbar-public-api.test.tsx +57 -0
- package/src/blocks/marketing/navbars/navbar.mega.test.tsx +149 -0
- package/src/blocks/marketing/navbars/navbar.test.tsx +155 -0
- package/src/blocks/marketing/navbars/navbar.tsx +735 -0
- package/src/blocks/marketing/testimonials/testimonial-section.test.tsx +171 -0
- package/src/blocks/marketing/testimonials/testimonial-section.tsx +237 -0
- package/src/index.ts +156 -128
- package/src/lib/contracts-curated.test.ts +47 -29
- package/src/lib/contracts.test.ts +198 -2
- package/src/lib/contracts.ts +410 -16
- package/src/ui/button-group.tsx +1 -1
- package/src/ui/carousel.tsx +1 -1
- package/src/ui/dialog.tsx +1 -1
- package/src/ui/field.tsx +2 -2
- package/src/ui/input-group.tsx +3 -3
- package/src/ui/pagination.tsx +1 -1
- package/src/ui/sidebar.tsx +7 -7
- package/src/ui/toggle-group.tsx +1 -1
- package/tsconfig.build.json +12 -0
- package/tsup.config.ts +11 -7
- package/.turbo/turbo-build.log +0 -24
- package/.turbo/turbo-test.log +0 -47
- package/.turbo/turbo-type-check.log +0 -0
- package/dist/.tsbuildinfo +0 -1
- package/dist/contracts.d.mts +0 -1732
- package/dist/contracts.d.ts +0 -1732
- package/dist/contracts.js +0 -423
- package/dist/contracts.js.map +0 -1
- package/dist/contracts.mjs +0 -365
- package/dist/contracts.mjs.map +0 -1
- package/dist/index.d.mts +0 -3068
- package/dist/index.d.ts +0 -3068
- package/dist/index.js +0 -17834
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -17740
- package/dist/index.mjs.map +0 -1
- package/src/blocks/application/login-forms/login-page-1.tsx +0 -246
- package/src/blocks/application/login-forms/login-page-2.tsx +0 -207
- package/src/blocks/e-commerce/category-filters/category-filter-1.tsx +0 -260
- package/src/blocks/e-commerce/category-filters/category-filter-2-filter-panel.tsx +0 -222
- package/src/blocks/e-commerce/category-filters/category-filter-2.tsx +0 -921
- package/src/blocks/e-commerce/category-filters/category-filter-4-chip-rail.tsx +0 -57
- package/src/blocks/e-commerce/category-filters/category-filter-4-drawer.tsx +0 -124
- package/src/blocks/e-commerce/category-filters/category-filter-4-fields.tsx +0 -170
- package/src/blocks/e-commerce/category-filters/category-filter-4-sidebar.tsx +0 -52
- package/src/blocks/e-commerce/category-filters/category-filter-4-sort-sheet.tsx +0 -57
- package/src/blocks/e-commerce/category-filters/category-filter-4-state.ts +0 -68
- package/src/blocks/e-commerce/category-filters/category-filter-4.tsx +0 -298
- package/src/blocks/e-commerce/checkout-forms/card-formatting.test.ts +0 -47
- package/src/blocks/e-commerce/checkout-forms/card-formatting.ts +0 -9
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1-contact-step.tsx +0 -96
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1-order-summary.tsx +0 -252
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1-payment-step.tsx +0 -188
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1-progress.tsx +0 -36
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1.test.tsx +0 -216
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1.tsx +0 -338
- package/src/blocks/e-commerce/checkout-forms/checkout-form-2-order-summary.tsx +0 -130
- package/src/blocks/e-commerce/checkout-forms/checkout-form-2-payment-card.tsx +0 -175
- package/src/blocks/e-commerce/checkout-forms/checkout-form-2-shipping-card.tsx +0 -190
- package/src/blocks/e-commerce/checkout-forms/checkout-form-2.tsx +0 -312
- package/src/blocks/e-commerce/checkout-forms/checkout-form-3-information-step.tsx +0 -91
- package/src/blocks/e-commerce/checkout-forms/checkout-form-3-order-summary.tsx +0 -110
- package/src/blocks/e-commerce/checkout-forms/checkout-form-3-payment-step.tsx +0 -137
- package/src/blocks/e-commerce/checkout-forms/checkout-form-3-progress.tsx +0 -68
- package/src/blocks/e-commerce/checkout-forms/checkout-form-3-review-step.tsx +0 -79
- package/src/blocks/e-commerce/checkout-forms/checkout-form-3-shipping-step.tsx +0 -172
- package/src/blocks/e-commerce/checkout-forms/checkout-form-3.tsx +0 -392
- package/src/blocks/e-commerce/product-categories/avatar-group.tsx +0 -86
- package/src/blocks/e-commerce/product-categories/product-category-1.tsx +0 -126
- package/src/blocks/e-commerce/product-categories/product-category-2.test.tsx +0 -51
- package/src/blocks/e-commerce/product-categories/product-category-2.tsx +0 -120
- package/src/blocks/e-commerce/product-categories/product-category-4.tsx +0 -129
- package/src/blocks/e-commerce/product-categories/product-category-5.tsx +0 -218
- package/src/blocks/e-commerce/product-list/product-card-1.test.tsx +0 -88
- package/src/blocks/e-commerce/product-list/product-card-1.tsx +0 -192
- package/src/blocks/e-commerce/product-list/product-card-2.tsx +0 -71
- package/src/blocks/e-commerce/product-list/product-card-3-reaction-toggle.tsx +0 -166
- package/src/blocks/e-commerce/product-list/product-card-3.tsx +0 -215
- package/src/blocks/e-commerce/product-list/product-card-5-checkbox-check.tsx +0 -98
- package/src/blocks/e-commerce/product-list/product-card-5-reaction-toggle.tsx +0 -171
- package/src/blocks/e-commerce/product-list/product-card-5.tsx +0 -367
- package/src/blocks/e-commerce/product-overview/product-overview-1.test.tsx +0 -182
- package/src/blocks/e-commerce/product-overview/product-overview-1.tsx +0 -370
- package/src/blocks/e-commerce/product-overview/product-overview-2.tsx +0 -272
- package/src/blocks/e-commerce/product-overview/product-overview-5-gallery.tsx +0 -59
- package/src/blocks/e-commerce/product-overview/product-overview-5.tsx +0 -274
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-1-spinning-counter.tsx +0 -142
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-1.tsx +0 -291
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-2-item-row.tsx +0 -110
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-2-recommendations.tsx +0 -51
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-2-spinning-counter.tsx +0 -146
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-2.tsx +0 -295
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-3-spinning-counter.tsx +0 -142
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-3.tsx +0 -342
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-4-spinning-counter.tsx +0 -146
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-4.test.tsx +0 -229
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.test.tsx +0 -72
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.tsx +0 -263
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-2.tsx +0 -283
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-5.tsx +0 -318
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-6.tsx +0 -205
- package/src/blocks/marketing/features/feature-1.tsx +0 -97
- package/src/blocks/marketing/features/feature-2.tsx +0 -82
- package/src/blocks/marketing/footers/footer-section-1.test.tsx +0 -117
- package/src/blocks/marketing/footers/footer-section-1.tsx +0 -178
- package/src/blocks/marketing/footers/footer-section-3.tsx +0 -192
- package/src/blocks/marketing/footers/footer-section-4.tsx +0 -355
- package/src/blocks/marketing/navbars/navbar-1.tsx +0 -267
- package/src/blocks/marketing/navbars/navbar-2.tsx +0 -351
- package/src/blocks/marketing/navbars/navbar-3.tsx +0 -303
- package/src/blocks/marketing/navbars/navbar-4-account-menu.test.tsx +0 -38
- package/src/blocks/marketing/navbars/navbar-4-like-button.tsx +0 -177
- package/src/blocks/marketing/navbars/navbar-4-product-grid.tsx +0 -219
- package/src/blocks/marketing/testimonials/testimonial-1.tsx +0 -141
- package/src/blocks/marketing/testimonials/testimonial-2.tsx +0 -108
|
@@ -81,150 +81,148 @@ export function SignUpPage1({
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
return (
|
|
84
|
-
<
|
|
85
|
-
<
|
|
86
|
-
<
|
|
87
|
-
<div className='
|
|
88
|
-
<div className='
|
|
89
|
-
<div className='
|
|
90
|
-
<
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
</svg>
|
|
117
|
-
</div>
|
|
84
|
+
<div className='flex w-full max-w-lg flex-col items-center'>
|
|
85
|
+
<Card className='relative w-full max-w-lg p-8 shadow-2xl ring-0'>
|
|
86
|
+
<div className='mb-8 flex flex-col items-center'>
|
|
87
|
+
<div className='my-4 flex justify-center'>
|
|
88
|
+
<div className='bg-secondary relative size-14 rounded-full border'>
|
|
89
|
+
<div className='flex h-full items-center justify-center'>
|
|
90
|
+
<svg width='32' height='32' viewBox='0 0 32 32' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
|
91
|
+
<path
|
|
92
|
+
d='M26 24.75C26.4142 24.75 26.75 24.4142 26.75 24C26.75 23.5858 26.4142 23.25 26 23.25V24.75ZM26 23.25H11V24.75H26V23.25ZM8.75 21V15H7.25V21H8.75ZM11 23.25C9.75736 23.25 8.75 22.2426 8.75 21H7.25C7.25 23.0711 8.92893 24.75 11 24.75V23.25Z'
|
|
93
|
+
fill='currentColor'
|
|
94
|
+
/>
|
|
95
|
+
<path
|
|
96
|
+
d='M1.5 3.25C1.08579 3.25 0.75 3.58579 0.75 4C0.75 4.41421 1.08579 4.75 1.5 4.75V3.25ZM1.5 4.75H6V3.25H1.5V4.75ZM7.25 6V21H8.75V6H7.25ZM6 4.75C6.69036 4.75 7.25 5.30964 7.25 6H8.75C8.75 4.48122 7.51878 3.25 6 3.25V4.75Z'
|
|
97
|
+
fill='currentColor'
|
|
98
|
+
/>
|
|
99
|
+
<path
|
|
100
|
+
d='M22 21.75C22.4142 21.75 22.75 21.4142 22.75 21C22.75 20.5858 22.4142 20.25 22 20.25V21.75ZM22 20.25H11V21.75H22V20.25ZM8.75 18V12H7.25V18H8.75ZM11 20.25C9.75736 20.25 8.75 19.2426 8.75 18H7.25C7.25 20.0711 8.92893 21.75 11 21.75V20.25Z'
|
|
101
|
+
fill='currentColor'
|
|
102
|
+
/>
|
|
103
|
+
<path
|
|
104
|
+
d='M27.2057 19.754C27.0654 20.1438 26.6357 20.346 26.246 20.2057C25.8562 20.0654 25.654 19.6357 25.7943 19.246L27.2057 19.754ZM30.0361 9.67744L29.3305 9.4234L29.3305 9.4234L30.0361 9.67744ZM25.7943 19.246L29.3305 9.4234L30.7418 9.93148L27.2057 19.754L25.7943 19.246ZM28.1543 7.75L8 7.75V6.25L28.1543 6.25V7.75ZM29.3305 9.4234C29.6237 8.60882 29.0201 7.75 28.1543 7.75V6.25C30.059 6.25 31.3869 8.13941 30.7418 9.93148L29.3305 9.4234Z'
|
|
105
|
+
fill='currentColor'
|
|
106
|
+
/>
|
|
107
|
+
<path
|
|
108
|
+
d='M13.5 21.75C13.0858 21.75 12.75 21.4142 12.75 21C12.75 20.5858 13.0858 20.25 13.5 20.25V21.75ZM26.7111 19.009L27.4174 19.2613L27.4174 19.2613L26.7111 19.009ZM13.5 20.25H23.8858V21.75H13.5V20.25ZM26.0048 18.7568L27.7937 13.7477L29.2063 14.2523L27.4174 19.2613L26.0048 18.7568ZM23.8858 20.25C24.8367 20.25 25.6849 19.6522 26.0048 18.7568L27.4174 19.2613C26.8843 20.7537 25.4706 21.75 23.8858 21.75V20.25Z'
|
|
109
|
+
fill='currentColor'
|
|
110
|
+
/>
|
|
111
|
+
<path d='M21.1694 10.5806L14.5651 17.1849' stroke='currentColor' />
|
|
112
|
+
<path d='M22.1694 14.5806L18.5632 18.1868' stroke='currentColor' />
|
|
113
|
+
<circle cx='13.1' cy='26.1' r='1.7' stroke='currentColor' />
|
|
114
|
+
<circle cx='22.1' cy='26.1' r='1.7' stroke='currentColor' />
|
|
115
|
+
</svg>
|
|
118
116
|
</div>
|
|
119
117
|
</div>
|
|
120
|
-
{logoText && <div className='text-base font-semibold tracking-tight'>{logoText}</div>}
|
|
121
|
-
<h1 className='mb-2 mt-4 text-center text-2xl font-bold tracking-tight'>{createAccountTitleLabel}</h1>
|
|
122
|
-
<p className='text-muted-foreground text-center text-sm'>{createAccountDescriptionLabel}</p>
|
|
123
118
|
</div>
|
|
119
|
+
{logoText && <div className='text-base font-semibold tracking-tight'>{logoText}</div>}
|
|
120
|
+
<h1 className='mb-2 mt-4 text-center text-2xl font-bold tracking-tight'>{createAccountTitleLabel}</h1>
|
|
121
|
+
<p className='text-muted-foreground text-center text-sm'>{createAccountDescriptionLabel}</p>
|
|
122
|
+
</div>
|
|
124
123
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
124
|
+
<form className='flex flex-col gap-6' onSubmit={handleSubmit}>
|
|
125
|
+
<div className='relative'>
|
|
126
|
+
<Input
|
|
127
|
+
id='fullname'
|
|
128
|
+
name='fullName'
|
|
129
|
+
type='text'
|
|
130
|
+
placeholder={fullNamePlaceholder}
|
|
131
|
+
aria-label={fullNameLabel}
|
|
132
|
+
className='bg-transparent h-9 ps-10 text-sm'
|
|
133
|
+
autoComplete='name'
|
|
134
|
+
required
|
|
135
|
+
/>
|
|
136
|
+
<User className='text-muted-foreground absolute start-3 top-1/2 size-5 -translate-y-1/2' />
|
|
137
|
+
</div>
|
|
139
138
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
139
|
+
<div className='relative'>
|
|
140
|
+
<Input
|
|
141
|
+
id='email'
|
|
142
|
+
name='email'
|
|
143
|
+
type='email'
|
|
144
|
+
placeholder={emailPlaceholder}
|
|
145
|
+
aria-label={emailLabel}
|
|
146
|
+
className='bg-transparent h-9 ps-10 text-sm'
|
|
147
|
+
autoComplete='email'
|
|
148
|
+
required
|
|
149
|
+
/>
|
|
150
|
+
<Mail className='text-muted-foreground absolute start-3 top-1/2 size-5 -translate-y-1/2' />
|
|
151
|
+
</div>
|
|
153
152
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
153
|
+
<div className='relative'>
|
|
154
|
+
<Input
|
|
155
|
+
id='password'
|
|
156
|
+
name='password'
|
|
157
|
+
type='password'
|
|
158
|
+
placeholder={passwordPlaceholder}
|
|
159
|
+
aria-label={passwordLabel}
|
|
160
|
+
className='bg-transparent h-9 ps-10 text-sm'
|
|
161
|
+
autoComplete='new-password'
|
|
162
|
+
required
|
|
163
|
+
/>
|
|
164
|
+
<Lock className='text-muted-foreground absolute start-3 top-1/2 size-5 -translate-y-1/2' />
|
|
165
|
+
</div>
|
|
167
166
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
167
|
+
<Button className='h-9 w-full cursor-pointer px-4 py-2' type='submit'>
|
|
168
|
+
{createAccountLabel}
|
|
169
|
+
</Button>
|
|
171
170
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
</div>
|
|
178
|
-
<div className='relative flex justify-center text-xs uppercase'>
|
|
179
|
-
<span className='bg-card text-muted-foreground px-2'>{orSignUpWithLabel}</span>
|
|
180
|
-
</div>
|
|
171
|
+
{socialButtons.length > 0 && (
|
|
172
|
+
<>
|
|
173
|
+
<div className='relative my-6 text-center'>
|
|
174
|
+
<div className='absolute inset-0 flex items-center'>
|
|
175
|
+
<div className='w-full border-t' />
|
|
181
176
|
</div>
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
{socialButtons.map(button => (
|
|
185
|
-
<Button key={button.name} variant='outline' className='h-9 w-full cursor-pointer px-4 py-2'>
|
|
186
|
-
<button.icon />
|
|
187
|
-
<span className='sr-only'>{socialAriaLabel.replace('{name}', button.name)}</span>
|
|
188
|
-
</Button>
|
|
189
|
-
))}
|
|
177
|
+
<div className='relative flex justify-center text-xs uppercase'>
|
|
178
|
+
<span className='bg-card text-muted-foreground px-2'>{orSignUpWithLabel}</span>
|
|
190
179
|
</div>
|
|
191
|
-
|
|
192
|
-
)}
|
|
193
|
-
</form>
|
|
180
|
+
</div>
|
|
194
181
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
</
|
|
182
|
+
<div className='grid grid-cols-3 gap-3'>
|
|
183
|
+
{socialButtons.map(button => (
|
|
184
|
+
<Button key={button.name} variant='outline' className='h-9 w-full cursor-pointer px-4 py-2'>
|
|
185
|
+
<button.icon />
|
|
186
|
+
<span className='sr-only'>{socialAriaLabel.replace('{name}', button.name)}</span>
|
|
187
|
+
</Button>
|
|
188
|
+
))}
|
|
189
|
+
</div>
|
|
190
|
+
</>
|
|
191
|
+
)}
|
|
192
|
+
</form>
|
|
206
193
|
|
|
207
|
-
<p className='
|
|
208
|
-
{
|
|
209
|
-
{
|
|
210
|
-
<
|
|
211
|
-
{
|
|
212
|
-
</
|
|
213
|
-
) : (
|
|
214
|
-
<span className='hover:text-primary underline underline-offset-4'>{termsLinkLabel}</span>
|
|
215
|
-
)}{' '}
|
|
216
|
-
{termsAndLabel}{' '}
|
|
217
|
-
{privacyHref ? (
|
|
218
|
-
<a href={privacyHref} className='hover:text-primary underline underline-offset-4'>
|
|
219
|
-
{privacyLinkLabel}
|
|
220
|
-
</a>
|
|
194
|
+
<p className='mt-6 flex justify-center gap-1 text-center text-sm'>
|
|
195
|
+
<span>{alreadyHaveAccountLabel}</span>
|
|
196
|
+
{onSignIn ? (
|
|
197
|
+
<button type='button' onClick={onSignIn} className='underline underline-offset-4'>
|
|
198
|
+
{signInLabel}
|
|
199
|
+
</button>
|
|
221
200
|
) : (
|
|
222
|
-
<span className='
|
|
201
|
+
<span className='underline underline-offset-4'>{signInLabel}</span>
|
|
223
202
|
)}
|
|
224
|
-
.
|
|
225
203
|
</p>
|
|
226
|
-
</
|
|
227
|
-
|
|
204
|
+
</Card>
|
|
205
|
+
|
|
206
|
+
<p className='text-muted-foreground relative z-10 mt-8 max-w-lg px-8 text-center text-xs text-balance'>
|
|
207
|
+
{termsLabel}{' '}
|
|
208
|
+
{termsHref ? (
|
|
209
|
+
<a href={termsHref} className='hover:text-primary underline underline-offset-4'>
|
|
210
|
+
{termsLinkLabel}
|
|
211
|
+
</a>
|
|
212
|
+
) : (
|
|
213
|
+
<span className='hover:text-primary underline underline-offset-4'>{termsLinkLabel}</span>
|
|
214
|
+
)}{' '}
|
|
215
|
+
{termsAndLabel}{' '}
|
|
216
|
+
{privacyHref ? (
|
|
217
|
+
<a href={privacyHref} className='hover:text-primary underline underline-offset-4'>
|
|
218
|
+
{privacyLinkLabel}
|
|
219
|
+
</a>
|
|
220
|
+
) : (
|
|
221
|
+
<span className='hover:text-primary underline underline-offset-4'>{privacyLinkLabel}</span>
|
|
222
|
+
)}
|
|
223
|
+
.
|
|
224
|
+
</p>
|
|
225
|
+
</div>
|
|
228
226
|
)
|
|
229
227
|
}
|
|
230
228
|
|
|
@@ -162,7 +162,7 @@ export function Verify1({
|
|
|
162
162
|
|
|
163
163
|
if (verified) {
|
|
164
164
|
return (
|
|
165
|
-
<div className='
|
|
165
|
+
<div className='relative w-full max-w-md'>
|
|
166
166
|
{/* Fired once, over the whole field rather than the card, so the paper has somewhere
|
|
167
167
|
to fall. The success is stated in the heading below; this only decorates it. */}
|
|
168
168
|
<Confetti fire origin={{ x: 0.5, y: 0.5 }} />
|
|
@@ -187,7 +187,7 @@ export function Verify1({
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
return (
|
|
190
|
-
<div className='
|
|
190
|
+
<div className='w-full max-w-md'>
|
|
191
191
|
<Card className='w-full max-w-md gap-6 py-8 shadow-lg'>
|
|
192
192
|
<CardHeader className='gap-2 px-8 text-center'>
|
|
193
193
|
<span
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
//
|
|
3
|
+
// Invariant: an auth composition renders into the host page and never owns it.
|
|
4
|
+
// A page (route shell, or a template the host owns) supplies the canvas: height,
|
|
5
|
+
// backdrop, centring. Keeping this assertion next to the blocks means a new auth
|
|
6
|
+
// surface cannot quietly reintroduce a second viewport owner.
|
|
7
|
+
import { beforeAll, describe, expect, it } from 'vitest';
|
|
8
|
+
import { render, screen } from '@testing-library/react';
|
|
9
|
+
import { LoginPage } from './login-forms/login-page';
|
|
10
|
+
import { SignUpPage1 } from './signup-forms/signup-page-1';
|
|
11
|
+
import { ForgotPasswordPage1 } from './password-recovery/forgot-password-page-1';
|
|
12
|
+
import { Verify1 } from './verification/verify-1';
|
|
13
|
+
|
|
14
|
+
beforeAll(() => {
|
|
15
|
+
Object.assign(SVGElement.prototype, { getTotalLength: () => 15 });
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const PAGE_SHELL = /min-h-dvh|min-h-screen|h-dvh|h-screen|bg-linear-to-br/;
|
|
19
|
+
|
|
20
|
+
const surfaces = [
|
|
21
|
+
['LoginPage (card)', () => <LoginPage presentation="card" />],
|
|
22
|
+
['LoginPage (social)', () => <LoginPage presentation="social" />],
|
|
23
|
+
['SignUpPage1', () => <SignUpPage1 />],
|
|
24
|
+
['ForgotPasswordPage1', () => <ForgotPasswordPage1 />],
|
|
25
|
+
['Verify1', () => <Verify1 />],
|
|
26
|
+
] as const;
|
|
27
|
+
|
|
28
|
+
describe.each(surfaces)('%s', (_name, renderBlock) => {
|
|
29
|
+
it('does not declare a page landmark', () => {
|
|
30
|
+
render(renderBlock());
|
|
31
|
+
expect(screen.queryByRole('main')).toBeNull();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('renders into a neutral content-sized root', () => {
|
|
35
|
+
const { container } = render(renderBlock());
|
|
36
|
+
const root = container.firstElementChild;
|
|
37
|
+
expect(root?.tagName).toBe('DIV');
|
|
38
|
+
expect(root?.className).not.toMatch(PAGE_SHELL);
|
|
39
|
+
expect(container.innerHTML).not.toMatch(PAGE_SHELL);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useId } from 'react'
|
|
4
|
+
|
|
5
|
+
import { Button } from '../../../ui/button'
|
|
6
|
+
import { CardTitle } from '../../../ui/card'
|
|
7
|
+
import { Input } from '../../../ui/input'
|
|
8
|
+
import { CheckboxCheck } from '../checkout-forms/checkbox-check'
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
CategoryListingFacetGroup,
|
|
12
|
+
CategoryListingOption,
|
|
13
|
+
CategoryListingPriceRange,
|
|
14
|
+
} from './category-listing'
|
|
15
|
+
|
|
16
|
+
export interface CategoryListingFilterFieldsProps {
|
|
17
|
+
selectedText?: string
|
|
18
|
+
clearAllLabel?: string
|
|
19
|
+
priceRangeTitle?: string
|
|
20
|
+
priceRange: [number, number]
|
|
21
|
+
/**
|
|
22
|
+
* Real provider range only. When absent the price section is not rendered —
|
|
23
|
+
* the block never fabricates a `0..1000` range.
|
|
24
|
+
*/
|
|
25
|
+
priceRangeConfig?: CategoryListingPriceRange
|
|
26
|
+
minLabel?: string
|
|
27
|
+
maxLabel?: string
|
|
28
|
+
onPriceChange: (range: [number, number]) => void
|
|
29
|
+
categoriesTitle?: string
|
|
30
|
+
categories: CategoryListingOption[]
|
|
31
|
+
selectedCategories: string[]
|
|
32
|
+
onCategoryChange: (category: string, checked: boolean) => void
|
|
33
|
+
collectionsTitle?: string
|
|
34
|
+
collections: CategoryListingOption[]
|
|
35
|
+
selectedCollections: string[]
|
|
36
|
+
onCollectionChange: (collection: string, checked: boolean) => void
|
|
37
|
+
/**
|
|
38
|
+
* Generic provider-backed facet groups. A group renders only when it carries
|
|
39
|
+
* at least one option; the block never invents groups, options or counts.
|
|
40
|
+
*/
|
|
41
|
+
facets?: CategoryListingFacetGroup[]
|
|
42
|
+
selectedFacets: Record<string, string[]>
|
|
43
|
+
onFacetChange: (group: CategoryListingFacetGroup, value: string, checked: boolean) => void
|
|
44
|
+
onClearAll: () => void
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Render a count only when it is a real, non-negative, finite number. */
|
|
48
|
+
function readableCount(count: number | undefined): number | undefined {
|
|
49
|
+
return typeof count === 'number' && Number.isFinite(count) && count >= 0 ? count : undefined
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The control set shared by both presentations. The presentation only decides
|
|
54
|
+
* where these fields live (persistent sidebar, mobile sheet, or drawer); the
|
|
55
|
+
* fields, their semantics and the emitted values are identical.
|
|
56
|
+
*/
|
|
57
|
+
export function CategoryListingFilterFields({
|
|
58
|
+
selectedText = 'Filtros',
|
|
59
|
+
clearAllLabel = 'Restablecer',
|
|
60
|
+
priceRangeTitle = 'Rango de precio',
|
|
61
|
+
priceRange,
|
|
62
|
+
priceRangeConfig,
|
|
63
|
+
minLabel = 'Mínimo',
|
|
64
|
+
maxLabel = 'Máximo',
|
|
65
|
+
onPriceChange,
|
|
66
|
+
categoriesTitle = 'Categoría',
|
|
67
|
+
categories,
|
|
68
|
+
selectedCategories,
|
|
69
|
+
onCategoryChange,
|
|
70
|
+
collectionsTitle = 'Colección',
|
|
71
|
+
collections,
|
|
72
|
+
selectedCollections,
|
|
73
|
+
onCollectionChange,
|
|
74
|
+
facets = [],
|
|
75
|
+
selectedFacets,
|
|
76
|
+
onFacetChange,
|
|
77
|
+
onClearAll,
|
|
78
|
+
}: CategoryListingFilterFieldsProps) {
|
|
79
|
+
const priceInputId = useId()
|
|
80
|
+
const categoryInputId = useId()
|
|
81
|
+
const collectionInputId = useId()
|
|
82
|
+
const facetInputId = useId()
|
|
83
|
+
const visibleFacets = facets.filter(group => group.options.length > 0)
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<>
|
|
87
|
+
<div className='flex flex-col gap-6'>
|
|
88
|
+
<div className='mb-3 flex items-center justify-between'>
|
|
89
|
+
<h2 className='font-semibold'>{selectedText}</h2>
|
|
90
|
+
<Button variant='ghost' size='sm' className='h-8 cursor-pointer px-2 text-xs' onClick={onClearAll}>
|
|
91
|
+
{clearAllLabel}
|
|
92
|
+
</Button>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
{priceRangeConfig ? (
|
|
97
|
+
<div className='mt-4 flex flex-col gap-4'>
|
|
98
|
+
<CardTitle className='font-semibold'>{priceRangeTitle}</CardTitle>
|
|
99
|
+
<div className='flex items-center gap-3'>
|
|
100
|
+
<div className='flex flex-1 flex-col gap-1'>
|
|
101
|
+
<label htmlFor={`${priceInputId}-min`}>{minLabel}</label>
|
|
102
|
+
<Input
|
|
103
|
+
id={`${priceInputId}-min`}
|
|
104
|
+
type='number'
|
|
105
|
+
value={priceRange[0]}
|
|
106
|
+
onChange={event => {
|
|
107
|
+
const value = parseInt(event.target.value)
|
|
108
|
+
if (!Number.isNaN(value) && value >= priceRangeConfig.min && value <= priceRange[1]) {
|
|
109
|
+
onPriceChange([value, priceRange[1]])
|
|
110
|
+
}
|
|
111
|
+
}}
|
|
112
|
+
min={priceRangeConfig.min}
|
|
113
|
+
max={priceRange[1]}
|
|
114
|
+
step={priceRangeConfig.step}
|
|
115
|
+
className='h-9'
|
|
116
|
+
/>
|
|
117
|
+
</div>
|
|
118
|
+
<div className='mt-5 flex-none'>-</div>
|
|
119
|
+
<div className='flex flex-1 flex-col gap-1'>
|
|
120
|
+
<label htmlFor={`${priceInputId}-max`}>{maxLabel}</label>
|
|
121
|
+
<Input
|
|
122
|
+
id={`${priceInputId}-max`}
|
|
123
|
+
type='number'
|
|
124
|
+
value={priceRange[1]}
|
|
125
|
+
onChange={event => {
|
|
126
|
+
const value = parseInt(event.target.value)
|
|
127
|
+
if (!Number.isNaN(value) && value >= priceRange[0] && value <= priceRangeConfig.max) {
|
|
128
|
+
onPriceChange([priceRange[0], value])
|
|
129
|
+
}
|
|
130
|
+
}}
|
|
131
|
+
min={priceRange[0]}
|
|
132
|
+
max={priceRangeConfig.max}
|
|
133
|
+
step={priceRangeConfig.step}
|
|
134
|
+
className='h-9'
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
) : null}
|
|
140
|
+
|
|
141
|
+
{categories.length > 0 ? (
|
|
142
|
+
<div className='mt-4 flex flex-col gap-4'>
|
|
143
|
+
<CardTitle className='font-semibold'>{categoriesTitle}</CardTitle>
|
|
144
|
+
<div className='flex flex-col gap-2'>
|
|
145
|
+
{categories.map(category => (
|
|
146
|
+
<div key={category.id} className='flex items-center gap-2'>
|
|
147
|
+
<CheckboxCheck
|
|
148
|
+
id={`${categoryInputId}-${category.id}`}
|
|
149
|
+
checked={selectedCategories.includes(category.id)}
|
|
150
|
+
onCheckedChange={checked => onCategoryChange(category.id, checked as boolean)}
|
|
151
|
+
/>
|
|
152
|
+
<label htmlFor={`${categoryInputId}-${category.id}`} className='text-sm'>
|
|
153
|
+
{category.label}
|
|
154
|
+
</label>
|
|
155
|
+
</div>
|
|
156
|
+
))}
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
) : null}
|
|
160
|
+
|
|
161
|
+
{collections.length > 0 ? (
|
|
162
|
+
<div className='mt-4 flex flex-col gap-4'>
|
|
163
|
+
<CardTitle className='font-semibold'>{collectionsTitle}</CardTitle>
|
|
164
|
+
<div className='flex flex-col gap-2'>
|
|
165
|
+
{collections.map(collection => (
|
|
166
|
+
<div key={collection.id} className='flex items-center gap-2'>
|
|
167
|
+
<CheckboxCheck
|
|
168
|
+
id={`${collectionInputId}-${collection.id}`}
|
|
169
|
+
checked={selectedCollections.includes(collection.id)}
|
|
170
|
+
onCheckedChange={checked => onCollectionChange(collection.id, checked as boolean)}
|
|
171
|
+
/>
|
|
172
|
+
<label htmlFor={`${collectionInputId}-${collection.id}`} className='text-sm'>
|
|
173
|
+
{collection.label}
|
|
174
|
+
</label>
|
|
175
|
+
</div>
|
|
176
|
+
))}
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
) : null}
|
|
180
|
+
|
|
181
|
+
{visibleFacets.map(group => {
|
|
182
|
+
const selected = selectedFacets[group.id] ?? []
|
|
183
|
+
return (
|
|
184
|
+
<div key={group.id} className='mt-4 flex flex-col gap-4' data-slot='facet-group' data-facet-id={group.id}>
|
|
185
|
+
<CardTitle className='font-semibold'>{group.label}</CardTitle>
|
|
186
|
+
<div className='flex flex-col gap-2'>
|
|
187
|
+
{group.options.map(option => {
|
|
188
|
+
const count = readableCount(option.count)
|
|
189
|
+
return (
|
|
190
|
+
<div key={option.value} className='flex items-center gap-2'>
|
|
191
|
+
<CheckboxCheck
|
|
192
|
+
id={`${facetInputId}-${group.id}-${option.value}`}
|
|
193
|
+
checked={selected.includes(option.value)}
|
|
194
|
+
onCheckedChange={checked => onFacetChange(group, option.value, checked as boolean)}
|
|
195
|
+
/>
|
|
196
|
+
<label
|
|
197
|
+
htmlFor={`${facetInputId}-${group.id}-${option.value}`}
|
|
198
|
+
className='flex flex-1 items-center justify-between gap-2 text-sm'
|
|
199
|
+
>
|
|
200
|
+
<span>{option.label}</span>
|
|
201
|
+
{count === undefined ? null : (
|
|
202
|
+
<span data-slot='facet-count' className='text-muted-foreground text-xs'>
|
|
203
|
+
{count}
|
|
204
|
+
</span>
|
|
205
|
+
)}
|
|
206
|
+
</label>
|
|
207
|
+
</div>
|
|
208
|
+
)
|
|
209
|
+
})}
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
)
|
|
213
|
+
})}
|
|
214
|
+
</>
|
|
215
|
+
)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export default CategoryListingFilterFields
|