@reblu/site-contracts 1.11.0 → 1.13.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 +12 -0
- package/README.md +25 -0
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @reblu/site-contracts
|
|
2
2
|
|
|
3
|
+
## 1.13.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
|
+
## 1.12.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- fd17765: Site-level SEO (REB-651). `Config` gains optional `seoTitle`, `seoDescription` and `canonicalUrl`, all `string | null`. `seoTitle` and `seoDescription` are the site's own search title and description (the home page), apart from `siteName` and `siteDescription`; `null` means never set, so fall back to `siteName` and `siteDescription`. A set `seoTitle` is used as-is and never gets the template suffix. `canonicalUrl` is the site's https origin (no trailing slash), to use as Next's `metadataBase`. Purely additive.
|
|
14
|
+
|
|
3
15
|
## 1.11.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -132,6 +132,16 @@ may exist in both `tratamientos` and `especialidades`. Consequences for a SITE:
|
|
|
132
132
|
legacy slug-only reference **only when that slug is unique** — otherwise
|
|
133
133
|
`resolved` is `null`. Build the embed's href from `resolved.category`.
|
|
134
134
|
|
|
135
|
+
### Featured pages per category (REB-869)
|
|
136
|
+
|
|
137
|
+
`PagesListQuery` is the query of `GET /api/site/pages`. With `category` set,
|
|
138
|
+
`featured: true` returns that category's featured pages (max 3) in the order
|
|
139
|
+
the tenant chose in nexus, instead of the normal listing. Unpublished,
|
|
140
|
+
deleted or moved pages are skipped; nothing featured → empty `data` (the API
|
|
141
|
+
never falls back). For a teaser that falls back to the category's first pages,
|
|
142
|
+
use `@reblu/site-client`'s `pages.featured(category)` with
|
|
143
|
+
`@reblu/site-blocks`' `PageCardGrid`.
|
|
144
|
+
|
|
135
145
|
### Shop — product trust items (REB-858)
|
|
136
146
|
|
|
137
147
|
`ShopConfig.productTrustItems` is the store-wide list of short trust messages
|
|
@@ -169,6 +179,21 @@ another `"… · Brand"` template. For list/index routes, or an older API withou
|
|
|
169
179
|
`@reblu/site-next/seo`. Both fields are optional in the types so the minor stays
|
|
170
180
|
additive; `seoTitle`/`metaTitle` are unchanged.
|
|
171
181
|
|
|
182
|
+
### Site SEO title, description and canonical URL (REB-651)
|
|
183
|
+
|
|
184
|
+
`Config` carries the site's own search fields, apart from the identity fields
|
|
185
|
+
`siteName`/`siteDescription` (which stay short for breadcrumbs and chrome):
|
|
186
|
+
|
|
187
|
+
- `seoTitle` — the home page title. When set it is used **as-is**, never
|
|
188
|
+
suffixed by `seoTitleTemplate`. `null` → use `siteName`.
|
|
189
|
+
- `seoDescription` — the home page description. `null` → `siteDescription`.
|
|
190
|
+
- `canonicalUrl` — the site origin, `https://…` with no trailing slash, or
|
|
191
|
+
`null`. Use it as Next's `metadataBase` so relative Open Graph paths resolve.
|
|
192
|
+
|
|
193
|
+
They are served raw (`null` = never set). `buildMetadata({ config, home: true })`
|
|
194
|
+
from `@reblu/site-next/seo` applies the fallbacks for you. All three are
|
|
195
|
+
optional in the types so the minor stays additive.
|
|
196
|
+
|
|
172
197
|
## How the types stay correct
|
|
173
198
|
|
|
174
199
|
The types are re-derived from the response schemas that live in the Reblu API
|
package/dist/index.d.cts
CHANGED
|
@@ -45,7 +45,7 @@ export type BlogSlug = { slug: string; updatedAt: string;}
|
|
|
45
45
|
|
|
46
46
|
export type BlogTag = { id: string; name: string; slug: string; color: string;}
|
|
47
47
|
|
|
48
|
-
export type Config = { siteName: string; siteDescription: string | null; language: string | null; contactEmail: string | null; keywords: string[]; businessType: string | null; isSetupComplete: boolean; logoLightExpandedUrl: string | null; logoDarkExpandedUrl: string | null; logoLightSmallUrl: string | null; logoDarkSmallUrl: string | null; ogImageUrl: string | null; owner: { name: string | null; email: string | null; jobTitle: string | null; }; business: { name: string | null; }; address: { street: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; telephone: string | null; lat: number | null; lng: number | null; } | null; fiscal: { taxId: string | null; taxIdKind: "NIF" | "CIF" | null; legalName: string | null; registry: { name: string; number: string; } | null; } | null; social: { linkedin: string | null; twitter: string | null; facebook: string | null; instagram: string | null; youtube: string | null; } | null; metadata: unknown; openingHours: { ranges: { days: ("MON" | "TUE" | "WED" | "THU" | "FRI" | "SAT" | "SUN")[]; opens: string; closes: string; }[]; note?: string | undefined; } | null; contactFormMode: "NOT_CONFIGURED" | "DISABLED" | "DB_ONLY" | "WEBHOOK" | "RESEND"; features: Record<string, unknown>; seoTitleTemplate?: string | undefined;}
|
|
48
|
+
export type Config = { siteName: string; siteDescription: string | null; language: string | null; contactEmail: string | null; keywords: string[]; businessType: string | null; isSetupComplete: boolean; logoLightExpandedUrl: string | null; logoDarkExpandedUrl: string | null; logoLightSmallUrl: string | null; logoDarkSmallUrl: string | null; ogImageUrl: string | null; owner: { name: string | null; email: string | null; jobTitle: string | null; }; business: { name: string | null; }; address: { street: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; telephone: string | null; lat: number | null; lng: number | null; } | null; fiscal: { taxId: string | null; taxIdKind: "NIF" | "CIF" | null; legalName: string | null; registry: { name: string; number: string; } | null; } | null; social: { linkedin: string | null; twitter: string | null; facebook: string | null; instagram: string | null; youtube: string | null; } | null; metadata: unknown; openingHours: { ranges: { days: ("MON" | "TUE" | "WED" | "THU" | "FRI" | "SAT" | "SUN")[]; opens: string; closes: string; }[]; note?: string | undefined; } | null; contactFormMode: "NOT_CONFIGURED" | "DISABLED" | "DB_ONLY" | "WEBHOOK" | "RESEND"; features: Record<string, unknown>; seoTitleTemplate?: string | undefined; seoTitle?: string | null | undefined; seoDescription?: string | null | undefined; canonicalUrl?: string | null | undefined;}
|
|
49
49
|
|
|
50
50
|
export type ConfigAddress = { street: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; telephone: string | null; lat: number | null; lng: number | null;}
|
|
51
51
|
|
|
@@ -111,6 +111,8 @@ export type PageSlug = { slug: string; type: "SERVICE" | "CUSTOM"; upda
|
|
|
111
111
|
|
|
112
112
|
export type PageType = "custom" | "service" | "treatments" | "specialties" | "team" | "generic"
|
|
113
113
|
|
|
114
|
+
export type PagesListQuery = { type?: ("custom" | "service" | "treatments" | "specialties" | "team" | "generic")[] | undefined; category?: string | undefined; page?: unknown; pageSize?: unknown; sort?: "order" | "-publishedAt" | undefined; featured?: boolean | undefined;}
|
|
115
|
+
|
|
114
116
|
export type PagesListSort = "order" | "-publishedAt"
|
|
115
117
|
|
|
116
118
|
export type PaginationMeta = { total?: number | undefined; page?: number | undefined; limit?: number | undefined; pages?: number | undefined;}
|
package/dist/index.d.ts
CHANGED
|
@@ -45,7 +45,7 @@ export type BlogSlug = { slug: string; updatedAt: string;}
|
|
|
45
45
|
|
|
46
46
|
export type BlogTag = { id: string; name: string; slug: string; color: string;}
|
|
47
47
|
|
|
48
|
-
export type Config = { siteName: string; siteDescription: string | null; language: string | null; contactEmail: string | null; keywords: string[]; businessType: string | null; isSetupComplete: boolean; logoLightExpandedUrl: string | null; logoDarkExpandedUrl: string | null; logoLightSmallUrl: string | null; logoDarkSmallUrl: string | null; ogImageUrl: string | null; owner: { name: string | null; email: string | null; jobTitle: string | null; }; business: { name: string | null; }; address: { street: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; telephone: string | null; lat: number | null; lng: number | null; } | null; fiscal: { taxId: string | null; taxIdKind: "NIF" | "CIF" | null; legalName: string | null; registry: { name: string; number: string; } | null; } | null; social: { linkedin: string | null; twitter: string | null; facebook: string | null; instagram: string | null; youtube: string | null; } | null; metadata: unknown; openingHours: { ranges: { days: ("MON" | "TUE" | "WED" | "THU" | "FRI" | "SAT" | "SUN")[]; opens: string; closes: string; }[]; note?: string | undefined; } | null; contactFormMode: "NOT_CONFIGURED" | "DISABLED" | "DB_ONLY" | "WEBHOOK" | "RESEND"; features: Record<string, unknown>; seoTitleTemplate?: string | undefined;}
|
|
48
|
+
export type Config = { siteName: string; siteDescription: string | null; language: string | null; contactEmail: string | null; keywords: string[]; businessType: string | null; isSetupComplete: boolean; logoLightExpandedUrl: string | null; logoDarkExpandedUrl: string | null; logoLightSmallUrl: string | null; logoDarkSmallUrl: string | null; ogImageUrl: string | null; owner: { name: string | null; email: string | null; jobTitle: string | null; }; business: { name: string | null; }; address: { street: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; telephone: string | null; lat: number | null; lng: number | null; } | null; fiscal: { taxId: string | null; taxIdKind: "NIF" | "CIF" | null; legalName: string | null; registry: { name: string; number: string; } | null; } | null; social: { linkedin: string | null; twitter: string | null; facebook: string | null; instagram: string | null; youtube: string | null; } | null; metadata: unknown; openingHours: { ranges: { days: ("MON" | "TUE" | "WED" | "THU" | "FRI" | "SAT" | "SUN")[]; opens: string; closes: string; }[]; note?: string | undefined; } | null; contactFormMode: "NOT_CONFIGURED" | "DISABLED" | "DB_ONLY" | "WEBHOOK" | "RESEND"; features: Record<string, unknown>; seoTitleTemplate?: string | undefined; seoTitle?: string | null | undefined; seoDescription?: string | null | undefined; canonicalUrl?: string | null | undefined;}
|
|
49
49
|
|
|
50
50
|
export type ConfigAddress = { street: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; telephone: string | null; lat: number | null; lng: number | null;}
|
|
51
51
|
|
|
@@ -111,6 +111,8 @@ export type PageSlug = { slug: string; type: "SERVICE" | "CUSTOM"; upda
|
|
|
111
111
|
|
|
112
112
|
export type PageType = "custom" | "service" | "treatments" | "specialties" | "team" | "generic"
|
|
113
113
|
|
|
114
|
+
export type PagesListQuery = { type?: ("custom" | "service" | "treatments" | "specialties" | "team" | "generic")[] | undefined; category?: string | undefined; page?: unknown; pageSize?: unknown; sort?: "order" | "-publishedAt" | undefined; featured?: boolean | undefined;}
|
|
115
|
+
|
|
114
116
|
export type PagesListSort = "order" | "-publishedAt"
|
|
115
117
|
|
|
116
118
|
export type PaginationMeta = { total?: number | undefined; page?: number | undefined; limit?: number | undefined; pages?: number | undefined;}
|
package/package.json
CHANGED