@bacano/sdk 1.2.6 → 1.2.7

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.
@@ -0,0 +1,113 @@
1
+ # Iconos Bacano en Content y sitios web
2
+
3
+ La biblioteca v6 ofrece **605 iconos**: los 600 dibujos de Bacano y cinco marcas sociales adicionales. Content guarda un ID estable como
4
+ `bacano:carrito` dentro de `contentJson`; nunca guarda SVG, HTML ni una URL
5
+ editable. Los dibujos propios heredan el color del texto. Instagram, Facebook,
6
+ WhatsApp, YouTube y TikTok usan imágenes procedentes de sus paquetes de marca,
7
+ sin recoloración. Sus nuevos IDs son `bacano:instagram`, `bacano:facebook`,
8
+ `bacano:whatsapp`, `bacano:youtube` y `bacano:tiktok`. Los cinco símbolos
9
+ genéricos anteriores mantienen sus IDs y se pueden recolorear. Cada par
10
+ comparte el nombre de la red; en el selector se distinguen por «Color editable»
11
+ y «Marca original». Consulta `provenance` si construyes tu propio selector.
12
+
13
+ ## Elegir el ID desde un agente
14
+
15
+ Con un permiso temporal de Content, consulta las referencias antes de crear un
16
+ tipo o una entrada:
17
+
18
+ ```ts
19
+ const references = await content.getReferences();
20
+ const icon = references.icons.find((item) => item.id === "bacano:carrito");
21
+ if (!icon) throw new Error("El icono no está disponible en Bacano");
22
+ ```
23
+
24
+ `icons` trae `id`, `concept`, `label`, `category`, `keywords` y `provenance`.
25
+ Dos iconos pueden tener el mismo nombre: usa el ID para distinguirlos y
26
+ `provenance` para saber si permiten cambiar el color. No inventes IDs. Define
27
+ un campo `{ key: "icono", label: "Icono",
28
+ type: "icon", sortOrder: 1 }` en un tipo editorial y envía el ID como valor:
29
+
30
+ ```ts
31
+ await content.createEntry({
32
+ contentType: "beneficio",
33
+ key: "entrega_segura",
34
+ name: "Entrega segura",
35
+ locale: "es-CO",
36
+ content: { icono: icon.id, titulo: "Entrega segura" },
37
+ });
38
+ ```
39
+
40
+ Los iconos son válidos en entradas, componentes, filas repetibles y bloques
41
+ adicionales de producto. No son un tipo de ficha técnica. Los ID desconocidos,
42
+ URLs, SVG y HTML se rechazan al guardar.
43
+
44
+ ## Mostrar el icono en una web
45
+
46
+ ```tsx
47
+ import { BacanoIcon } from "@bacano/sdk/react/icon";
48
+
49
+ <BacanoIcon
50
+ id={String(entry.contentJson.icono)}
51
+ apiUrl="https://api.tudominio.com"
52
+ size={28}
53
+ className="text-blue-600"
54
+ decorative
55
+ />
56
+ ```
57
+
58
+ `BacanoIcon` valida el ID. Para dibujos propios usa `mask-image` con
59
+ `currentColor`; para las cinco marcas usa `background-image` y conserva sus
60
+ colores. Solo solicita el archivo de cada icono renderizado: no importa los
61
+ 605 assets al bundle.
62
+ Si el icono comunica información por sí mismo, usa `decorative={false}` y
63
+ proporciona `label`. Para una web sin React:
64
+
65
+ ```ts
66
+ import { resolveBacanoIcon } from "@bacano/sdk/icons";
67
+
68
+ const icon = resolveBacanoIcon(
69
+ entry.contentJson.icono,
70
+ "https://api.tudominio.com",
71
+ );
72
+ // icon?.url es una URL pública de asset solo para IDs conocidos.
73
+ ```
74
+
75
+ Para consultar un ID sin configurar la URL de la API, usa
76
+ `getBacanoIcon(id)`. Devuelve sus metadatos o `null`. Si `resolveBacanoIcon`
77
+ recibe un ID desconocido o una URL base vacía, también devuelve `null`.
78
+ Importa estas funciones desde `@bacano/sdk/icons` y el componente desde
79
+ `@bacano/sdk/react/icon`: así una web que no usa iconos no incluye el catálogo
80
+ en sus entradas generales del SDK.
81
+
82
+ Para los dibujos propios en una web sin React:
83
+
84
+ ```css
85
+ .bacano-icon {
86
+ display: inline-block;
87
+ width: 1.5em;
88
+ height: 1.5em;
89
+ background: currentColor;
90
+ mask: var(--bacano-icon-url) center / contain no-repeat;
91
+ -webkit-mask: var(--bacano-icon-url) center / contain no-repeat;
92
+ }
93
+ ```
94
+
95
+ El sitio coloca `--bacano-icon-url: url("<icon.url>")` en el elemento. Si
96
+ `icon.provenance === "official-brand"`, usa `<img src={icon.url}>` o una imagen
97
+ de fondo con `contain`, sin `mask` ni `currentColor`; dale un nombre accesible
98
+ si el icono no es decorativo. Usa las marcas para enlazar a los perfiles o
99
+ contenidos correspondientes y respeta sus normas de uso.
100
+ También puedes usar `listBacanoIcons()` para construir una lista local de
101
+ opciones; esta función entrega metadatos, no los archivos. Los assets se
102
+ sirven por `/assets/icons/v6/<asset>` con permiso de origen cruzado. Mantén
103
+ el `apiUrl` del SDK apuntando a la API pública de Bacano, no a Hasura.
104
+
105
+ ## Publicación y compatibilidad
106
+
107
+ Primero despliega API/assets y la migración de `content_field_types`; después
108
+ el SDK y el editor. Una web antigua verá el ID en `contentJson` aunque todavía
109
+ no dibuje el icono. Los IDs publicados no se reutilizan ni se retiran. Los diez SVG de
110
+ la aprobación visual inicial siguen en `apps/frontend/public/iconos-muestra`
111
+ solo como revisión; la fuente servida por la API es
112
+ `apps/api/src/assets/icons/v6`. La API conserva las rutas v1, v2, v3 y v4 para webs que
113
+ todavía usan los catálogos anteriores.
@@ -73,8 +73,8 @@ console.log(context.companyId, context.scopes, context.expiresAt);
73
73
  El cliente ofrece:
74
74
 
75
75
  - `getContext()` para confirmar empresa, alcance y vencimiento.
76
- - `getReferences()` para consultar categorías, subcategorías, listas de opciones
77
- y unidades de medida válidas.
76
+ - `getReferences()` para consultar categorías, subcategorías, listas de opciones,
77
+ unidades de medida e iconos Bacano válidos.
78
78
  - `listTypes()` y `getType(idOrKey)`.
79
79
  - `createType(input)` y `updateType(idOrKey, input)`.
80
80
  - `inspectLifecycle(idOrKey, operation)`.
@@ -98,6 +98,12 @@ El cliente ofrece:
98
98
  `reorderProductBlocks(productId, input)` y
99
99
  `retireProductBlock(productId, blockId, expectedUpdatedAt)`.
100
100
 
101
+ Para campos editoriales `type: "icon"`, consulta `getReferences().icons` y
102
+ guarda uno de sus IDs (por ejemplo `bacano:carrito`) en el contenido. No envíes
103
+ SVG ni URL. La validación también cubre componentes y repetibles; las fichas
104
+ técnicas no admiten este tipo. [CONTENT_ICONS.md](CONTENT_ICONS.md) explica
105
+ cómo renderizarlo en la web sin descargar los 605 archivos de icono.
106
+
101
107
  ## Bloques adicionales de un producto
102
108
 
103
109
  Al generar un acceso con `product_content:manage`, indica de 1 a 50 IDs de
package/README.md CHANGED
@@ -38,6 +38,7 @@ import { createContentManagementClient } from "@bacano/sdk/content-management";
38
38
  ```
39
39
 
40
40
  Lee [`CONTENT_TYPE_MANAGEMENT.md`](./CONTENT_TYPE_MANAGEMENT.md) antes de usarlo.
41
+ Para iconos editoriales, consulta [`CONTENT_ICONS.md`](./CONTENT_ICONS.md).
41
42
  La guía contiene el flujo de autorización, contratos de campos, entradas y
42
43
  media, estados, referencias, cambios destructivos y límites de seguridad. Con
43
44
  el scope `content_media:upload`, un agente puede buscar imágenes existentes y
@@ -194,6 +194,14 @@ Referencia oficial: [API Openpay Colombia](https://documents.openpay.co/api/inde
194
194
  El comprador usa los medios habilitados por Openpay dentro de su página
195
195
  alojada; el SDK no pide tarjeta, PSE ni efectivo de forma separada.
196
196
 
197
+ Si el storefront muestra el logotipo de Openpay, hacerlo solo para la opción
198
+ devuelta por `getPaymentOptions()` con `gatewayCode === "OPENPAY"`. Es la marca
199
+ de la pasarela, no otro método seleccionable; puede preceder a los logotipos
200
+ de redes en la misma tarjeta. Mostrar logos de tarjetas, PSE o pago en tienda
201
+ solo cuando su disponibilidad esté confirmada para esa integración y ambiente:
202
+ la lista efectiva de medios pertenece al checkout alojado. El logotipo debe
203
+ tener un nombre accesible y no sustituye la descripción ni el estado del método.
204
+
197
205
  ### Diagnóstico rápido
198
206
 
199
207
  | Síntoma | Acción segura |
@@ -135,6 +135,19 @@ The first visible product image may use eager loading/high priority. Images
135
135
  below the fold and recommendation blocks must remain lazy. Storefronts must not
136
136
  append storage transformation query parameters manually.
137
137
 
138
+ For image carousels, inspect the mobile network trace rather than assuming
139
+ `loading="lazy"` prevents every offscreen request. Some carousel layouts still
140
+ cause all slides to download. Keep the active and nearby slides ready, load
141
+ additional slides as the user navigates, and verify that moving directly to a
142
+ distant thumbnail still displays its image. Recommendations should not download
143
+ every card image before the section is viewed.
144
+
145
+ Test the product page and its cart/gallery interactions in the mobile browsers
146
+ the storefront supports. If older Safari versions are in scope, do not rely on
147
+ unpolyfilled newer array methods such as `toSorted()`; a copied array followed
148
+ by `sort()` is a compatible alternative. A minified browser error alone is not
149
+ enough to identify the failing component: reproduce it and inspect the stack.
150
+
138
151
  ### Banners and full-width heroes
139
152
 
140
153
  Editorial `ContentMedia` images additionally expose:
@@ -261,6 +274,24 @@ If the storefront refreshes public configuration in the browser, it must keep
261
274
  the static bootstrap while the refresh is pending and only replace it when the
262
275
  payload actually changes. Configuration failure must not blank the storefront.
263
276
 
277
+ ## Sitemap and robots delivery
278
+
279
+ Static exports often publish all non-HTML files with the same cache policy.
280
+ Keep long-lived `immutable` caching for fingerprinted assets, **not** for stable
281
+ discovery URLs such as `/sitemap.xml` and `/robots.txt`. Serve those files with
282
+ a short, revalidating TTL and invalidate the CDN on publication so a rebuilt
283
+ catalog can be discovered. This is a hosting rule, not an SDK request.
284
+
285
+ After deployment, check the canonical public URL with a real `GET`: status
286
+ `200`, suitable content type, valid XML, expected URL count and canonical
287
+ hosts. Compare that count with the generated routes and catalog snapshot;
288
+ confirm that `robots.txt` names the sitemap and does not block it. A sitemap
289
+ that opens in a browser can still have a delivery or search-console problem.
290
+ If Search Console reports that it could not fetch the file, compare its last
291
+ attempt with a live URL inspection before changing the XML. Once a delivery
292
+ issue is fixed, submit the sitemap again as described in
293
+ [Google's sitemap troubleshooting guide](https://support.google.com/webmasters/answer/7451001).
294
+
264
295
  Mount third-party authentication only on routes that require it, such as
265
296
  checkout, sign-in and customer account pages. Public catalog and product pages
266
297
  must not download an authentication runtime merely because buyer accounts are
@@ -304,6 +335,10 @@ not verified instead of inferring it from source code.
304
335
  - [ ] `srcset` and `sizes` are present on catalog and product media.
305
336
  - [ ] Live refresh is batched, debounced and failure-safe.
306
337
  - [ ] Recommendations and below-fold media do not block the primary content.
338
+ - [ ] Carousels do not fetch every offscreen image on mobile; supported Safari
339
+ versions can navigate the product gallery after using the cart.
340
+ - [ ] Public sitemap and robots responses are current and are not cached as
341
+ immutable assets.
307
342
  - [ ] Mobile and desktop Lighthouse runs show no material layout shift.
308
343
  - [ ] A production trace confirms no duplicated catalog, shipping or website
309
344
  bootstrap calls during the first navigation.
@@ -3,7 +3,7 @@ export type ContentManagementTypeKind = "entry" | "component";
3
3
  export type ContentManagementTypeStatus = "draft" | "active" | "archived";
4
4
  export type ContentManagementTypeUsage = "website_content" | "product_additional" | "product_specification";
5
5
  export type ContentManagementScope = "content_types:manage" | "content_entries:manage" | "content_media:upload" | "content_entries:publish" | "forms:manage" | "forms:publish" | "product_content:manage";
6
- export type ContentManagementFieldType = "boolean" | "component" | "date" | "link" | "measure" | "media" | "number" | "reference" | "repeater" | "rich_text" | "rich_text_full" | "select" | "slug" | "text" | "textarea";
6
+ export type ContentManagementFieldType = "icon" | "boolean" | "component" | "date" | "link" | "measure" | "media" | "number" | "reference" | "repeater" | "rich_text" | "rich_text_full" | "select" | "slug" | "text" | "textarea";
7
7
  export interface ContentManagementChildFieldInput {
8
8
  id?: string | null;
9
9
  key: string;
@@ -182,6 +182,14 @@ export interface ContentManagementImageUploadResult extends ContentManagementMed
182
182
  reused: boolean;
183
183
  }
184
184
  export interface ContentManagementReferences {
185
+ icons: Array<{
186
+ id: string;
187
+ concept: string;
188
+ label: string;
189
+ category: string;
190
+ keywords: string[];
191
+ provenance: "original-bacano" | "official-brand";
192
+ }>;
185
193
  categories: Array<{
186
194
  code: string;
187
195
  name: string;