@reblu/site-blocks 0.10.0 → 0.12.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 CHANGED
@@ -1,5 +1,22 @@
1
1
  # @reblu/site-blocks
2
2
 
3
+ ## 0.12.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 7a00471: Featured pages per page category (REB-869). `@reblu/site-contracts` adds `PagesListQuery`, the query of `GET /api/site/pages`, including the new `featured` flag. `@reblu/site-client`: `pages.list({ category, featured: true })` returns that category's featured pages (max 3) in the tenant's order, skipping unpublished, deleted or moved pages, and an empty list when nothing is featured; the new `pages.featured(category, { limit?, fallback?, cache? })` helper returns the featured pages, or the category's first `limit` pages in normal order when none are featured, so a landing teaser is never empty. `limit` must be an integer >= 1: above 3 it is clamped to 3; 0, negative, fractional or NaN throw a `RangeError` before any request. Against an API that predates `featured`, the flag is ignored and `pages.featured()` silently degrades to the category's first `limit` pages. `@reblu/site-blocks` adds `PageCardGrid`, the page-card grid `ParentPage` already rendered for its child pages, as a drop-in (`pages`, `pageHref`, `heading`); cards are keyed by category + slug, an empty `heading` renders no `<h2>`. `ParentPage` now renders through it with unchanged markup (including the empty `<h2>` for `childPagesLabel=''`).
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [7a00471]
12
+ - @reblu/site-contracts@1.13.0
13
+
14
+ ## 0.11.0
15
+
16
+ ### Minor Changes
17
+
18
+ - c147a33: Add `ProductTrustItems` (REB-862): a plug-and-play Server Component that renders the store-wide trust messages from `ShopConfig.productTrustItems` (REB-858). Renders nothing when there is no data, skips items with an unknown icon or empty text, and never invents default claims. Ships `DEFAULT_TRUST_ICONS` (Lucide icons, bundled — no `lucide-react` needed in the SITE) with a per-icon `icons` override.
19
+
3
20
  ## 0.10.0
4
21
 
5
22
  ### Minor Changes
package/README.md CHANGED
@@ -19,6 +19,7 @@ a different-looking site for every tenant, with zero forks.
19
19
  | `ShopFilters` | `.` | Plug-and-play shop filter chrome over `GET /api/site/shop/facets`. RSC-safe. See "Shop filters" below. |
20
20
  | `CartLineList`, `CartSummary`, `AddedToCartToast`, `CheckoutLoginPrompt`, `CheckoutForm`, `OrderConfirmation` | `.` | Cart & checkout organisms. RSC-safe by construction. See "Cart & checkout" below. |
21
21
  | `PageBlocks`, `FaqAccordion` | `.` | Registry-block renderer (`PageDetail.blocks`) and native `<details>` FAQ. Server Components. See "Page blocks" below. |
22
+ | `ProductTrustItems`, `DEFAULT_TRUST_ICONS` | `.` | Store-wide trust messages from `ShopConfig.productTrustItems`. Server Component. See "Product trust items" below. |
22
23
  | `buildFaqPageJsonLd`, `collectFaqItems` | `./seo` | schema.org `FAQPage` structured data. Directive-free (also on `.`). See "Page blocks" below. |
23
24
  | `useCollection` | `./client` | Headless filterable/sortable/paginated collection hook (facets, category, tag, search). Serves both page and blog indexes. |
24
25
  | `Collection` | `./client` | Token-driven presentational grid over `useCollection`. |
@@ -380,6 +381,71 @@ Every title/description is overridable via `labels` (see
380
381
  "`useShopOrderStatus` — the order-confirmation flow" for the full wiring
381
382
  recipe.
382
383
 
384
+ ## Product trust items
385
+
386
+ `ProductTrustItems` renders the store-wide trust messages (shipping, returns,
387
+ secure payment…) the owner configures in nexus and the API serves as
388
+ `ShopConfig.productTrustItems` (REB-858). It is a Server Component — no
389
+ `'use client'`, no hooks — so it works in a Server Component page and inside a
390
+ Client Component alike. Drop it under the add-to-cart button:
391
+
392
+ ```tsx
393
+ import { createRebluClient } from '@reblu/site-client'
394
+ import { ProductTrustItems } from '@reblu/site-blocks'
395
+
396
+ const client = createRebluClient({
397
+ baseUrl: 'https://api.reblu.app',
398
+ apiKey: process.env.REBLU_API_KEY!,
399
+ })
400
+
401
+ export default async function ProductPage() {
402
+ const shopConfig = await client.shop.config()
403
+ return (
404
+ <>
405
+ {/* …product, price, add-to-cart… */}
406
+ <ProductTrustItems items={shopConfig.productTrustItems} className='border-t pt-4' />
407
+ </>
408
+ )
409
+ }
410
+ ```
411
+
412
+ ### Semantics — the API is the only source of claims
413
+
414
+ - **No data, no block.** `null`, `undefined` or `[]` render nothing. The
415
+ component never invents default items.
416
+ - **Unknown icons are skipped**, with no fallback icon. The contract is
417
+ forward-compatible (`icon: ShopProductTrustIcon | (string & {})`), so a newer
418
+ API may send an icon this version does not know; that item is dropped.
419
+ - **Empty text is skipped** (whitespace-only included). If no item survives,
420
+ nothing is rendered — never an empty `<ul>`.
421
+ - **Unknown item keys are ignored.**
422
+ - Order is the configured order.
423
+
424
+ ### Markup and styling
425
+
426
+ A semantic `<ul>` (or `<ol>` via `as='ol'`) of `<li>` rows; each icon is
427
+ `aria-hidden` because the text carries the meaning. Colours come from theme
428
+ tokens only (`text-muted-foreground`, `text-foreground/60`). `className` styles
429
+ the list, `itemClassName` each row.
430
+
431
+ ### Overriding icons
432
+
433
+ `DEFAULT_TRUST_ICONS` maps every `ShopProductTrustIcon` to a Lucide icon
434
+ (`shipping`→Truck, `returns`→RotateCcw, `secure-payment`→ShieldCheck,
435
+ `support`→Headset, `gift`→Gift, `pickup`→Store, `warranty`→BadgeCheck,
436
+ `quality`→Award). They are bundled into this package, so the SITE needs no
437
+ `lucide-react` of its own. Pass `icons` to replace any of them — the override is
438
+ merged over the defaults and receives `className` and `aria-hidden`:
439
+
440
+ ```tsx
441
+ import { Truck } from 'my-icon-set'
442
+
443
+ <ProductTrustItems items={shopConfig.productTrustItems} icons={{ shipping: Truck }} />
444
+ ```
445
+
446
+ `icons` cannot add a new icon key: an item whose `icon` this version does not
447
+ know is still skipped.
448
+
383
449
  ## `ParentPage` (formerly `Specialty`)
384
450
 
385
451
  `ParentPage` renders a page that groups other pages: the hero and content
@@ -417,6 +483,30 @@ counterpart are both passed, the new one wins. The default grid heading stays
417
483
  `"Treatments"` and the root keeps `data-slot="specialty"` until that major, so
418
484
  the rename changes no markup — pass `childPagesLabel` to set your own heading.
419
485
 
486
+ ## `PageCardGrid` — featured pages teaser (REB-869)
487
+
488
+ The linked page-card grid `ParentPage` uses for its child pages, as a
489
+ standalone drop-in over any `PageListItem[]`, rendered in the order given (and
490
+ nothing at all for an empty list). Its natural feed is
491
+ `client.pages.featured(category)` from `@reblu/site-client`: the up-to-3 pages
492
+ the tenant featured on that category in nexus («Destacadas en la portada»), in
493
+ the tenant's order — or the category's first pages when none are featured yet.
494
+
495
+ ```tsx
496
+ import { PageCardGrid } from '@reblu/site-blocks'
497
+
498
+ export async function ServicesTeaser() {
499
+ const pages = await client.pages.featured('servicios')
500
+ return (
501
+ <PageCardGrid
502
+ pages={pages}
503
+ heading='Servicios'
504
+ pageHref={(page) => `/${page.category?.slug}/${page.slug}`} // default: `/${slug}`
505
+ />
506
+ )
507
+ }
508
+ ```
509
+
420
510
  ## Page blocks
421
511
 
422
512
  `PageBlocks` renders a page's registry blocks (`PageDetail.blocks` from