veleta-templates 0.0.1 → 0.0.3

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.
Files changed (81) hide show
  1. package/dist/cjs/index-rvPH40G4.js +2 -6
  2. package/dist/cjs/loader.cjs.js +1 -1
  3. package/dist/cjs/veleta-boston-template.cjs.entry.js +148 -0
  4. package/dist/cjs/veleta-templates.cjs.js +1 -1
  5. package/dist/collection/collection-manifest.json +1 -2
  6. package/dist/collection/components/{menu-template-b/menu-template-b.js → boston-template/boston-template.js} +30 -72
  7. package/dist/collection/components/boston-template/boston-template.js.map +1 -0
  8. package/dist/collection/components.js +1 -2
  9. package/dist/collection/components.js.map +1 -1
  10. package/dist/collection/types/interfaces.js.map +1 -1
  11. package/dist/collection/utils/data-helpers.js +0 -8
  12. package/dist/collection/utils/data-helpers.js.map +1 -1
  13. package/dist/components/veleta-boston-template.d.ts +11 -0
  14. package/dist/components/veleta-boston-template.js +171 -0
  15. package/dist/components/veleta-boston-template.js.map +1 -0
  16. package/dist/esm/index-zOTWMTLj.js +2 -6
  17. package/dist/esm/loader.js +1 -1
  18. package/dist/esm/veleta-boston-template.entry.js +146 -0
  19. package/dist/esm/veleta-boston-template.entry.js.map +1 -0
  20. package/dist/esm/veleta-templates.js +1 -1
  21. package/dist/esm-es5/index-zOTWMTLj.js +1 -1
  22. package/dist/esm-es5/loader.js +1 -1
  23. package/dist/esm-es5/veleta-boston-template.entry.js +2 -0
  24. package/dist/esm-es5/veleta-boston-template.entry.js.map +1 -0
  25. package/dist/esm-es5/veleta-templates.js +1 -1
  26. package/dist/types/components/boston-template/boston-template.d.ts +9 -0
  27. package/dist/types/components.d.ts +13 -74
  28. package/dist/types/types/interfaces.d.ts +26 -20
  29. package/dist/types/utils/data-helpers.d.ts +0 -5
  30. package/dist/veleta-templates/p-6b69af1a.system.entry.js +2 -0
  31. package/dist/veleta-templates/p-6b69af1a.system.entry.js.map +1 -0
  32. package/dist/veleta-templates/p-D1BkLoGd.system.js +1 -1
  33. package/dist/{esm/veleta-menu-template-b.entry.js → veleta-templates/p-babbe59a.entry.js} +2 -58
  34. package/dist/veleta-templates/p-babbe59a.entry.js.map +1 -0
  35. package/dist/veleta-templates/veleta-templates.esm.js +1 -1
  36. package/package.json +2 -2
  37. package/dist/cjs/prop-parser-CqlyGycg.js +0 -129
  38. package/dist/cjs/prop-parser-CqlyGycg.js.map +0 -1
  39. package/dist/cjs/veleta-demo-template.cjs.entry.js +0 -39
  40. package/dist/cjs/veleta-menu-template-b.cjs.entry.js +0 -60
  41. package/dist/collection/components/demo-template/demo-template.css +0 -57
  42. package/dist/collection/components/demo-template/demo-template.js +0 -144
  43. package/dist/collection/components/demo-template/demo-template.js.map +0 -1
  44. package/dist/collection/components/menu-template-b/menu-template-b.js.map +0 -1
  45. package/dist/collection/utils/mock-data.js +0 -85
  46. package/dist/collection/utils/mock-data.js.map +0 -1
  47. package/dist/components/p-BtFpp-ge.js +0 -124
  48. package/dist/components/p-BtFpp-ge.js.map +0 -1
  49. package/dist/components/veleta-demo-template.d.ts +0 -11
  50. package/dist/components/veleta-demo-template.js +0 -64
  51. package/dist/components/veleta-demo-template.js.map +0 -1
  52. package/dist/components/veleta-menu-template-b.d.ts +0 -11
  53. package/dist/components/veleta-menu-template-b.js +0 -85
  54. package/dist/components/veleta-menu-template-b.js.map +0 -1
  55. package/dist/esm/prop-parser-D5qpnUIY.js +0 -124
  56. package/dist/esm/prop-parser-D5qpnUIY.js.map +0 -1
  57. package/dist/esm/veleta-demo-template.entry.js +0 -37
  58. package/dist/esm/veleta-demo-template.entry.js.map +0 -1
  59. package/dist/esm/veleta-menu-template-b.entry.js.map +0 -1
  60. package/dist/esm-es5/prop-parser-D5qpnUIY.js +0 -2
  61. package/dist/esm-es5/prop-parser-D5qpnUIY.js.map +0 -1
  62. package/dist/esm-es5/veleta-demo-template.entry.js +0 -2
  63. package/dist/esm-es5/veleta-demo-template.entry.js.map +0 -1
  64. package/dist/esm-es5/veleta-menu-template-b.entry.js +0 -2
  65. package/dist/esm-es5/veleta-menu-template-b.entry.js.map +0 -1
  66. package/dist/types/components/demo-template/demo-template.d.ts +0 -12
  67. package/dist/types/components/menu-template-b/menu-template-b.d.ts +0 -11
  68. package/dist/types/utils/mock-data.d.ts +0 -9
  69. package/dist/veleta-templates/p-1da2f609.entry.js +0 -2
  70. package/dist/veleta-templates/p-1da2f609.entry.js.map +0 -1
  71. package/dist/veleta-templates/p-6f14da26.system.entry.js +0 -2
  72. package/dist/veleta-templates/p-6f14da26.system.entry.js.map +0 -1
  73. package/dist/veleta-templates/p-9e099798.entry.js +0 -2
  74. package/dist/veleta-templates/p-9e099798.entry.js.map +0 -1
  75. package/dist/veleta-templates/p-BtFpp-ge.js +0 -2
  76. package/dist/veleta-templates/p-BtFpp-ge.js.map +0 -1
  77. package/dist/veleta-templates/p-bbAxcnzz.system.js +0 -2
  78. package/dist/veleta-templates/p-bbAxcnzz.system.js.map +0 -1
  79. package/dist/veleta-templates/p-e7ecc57b.system.entry.js +0 -2
  80. package/dist/veleta-templates/p-e7ecc57b.system.entry.js.map +0 -1
  81. /package/dist/collection/components/{menu-template-b/menu-template-b.css → boston-template/boston-template.css} +0 -0
@@ -119,14 +119,10 @@ var loadModule = (cmpMeta, hostRef, hmrVersionId) => {
119
119
  }
120
120
  switch(bundleId) {
121
121
 
122
- case 'veleta-demo-template.cjs':
122
+ case 'veleta-boston-template.cjs':
123
123
  return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(
124
124
  /* webpackMode: "lazy" */
125
- './veleta-demo-template.cjs.entry.js')); }).then(processMod, consoleError);
126
- case 'veleta-menu-template-b.cjs':
127
- return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(
128
- /* webpackMode: "lazy" */
129
- './veleta-menu-template-b.cjs.entry.js')); }).then(processMod, consoleError);
125
+ './veleta-boston-template.cjs.entry.js')); }).then(processMod, consoleError);
130
126
  }
131
127
  }
132
128
  return (function (t) { return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(t)); }); })(
@@ -6,7 +6,7 @@ var appGlobals = require('./app-globals-V2Kpy_OQ.js');
6
6
  const defineCustomElements = async (win, options) => {
7
7
  if (typeof window === 'undefined') return undefined;
8
8
  await appGlobals.globalScripts();
9
- return index.bootstrapLazy([["veleta-demo-template.cjs",[[256,"veleta-demo-template",{"sectionsJson":[1,"sections-json"],"dishesJson":[1,"dishes-json"],"themeJson":[1,"theme-json"],"restaurantName":[1,"restaurant-name"]}]]],["veleta-menu-template-b.cjs",[[256,"veleta-menu-template-b",{"sectionsJson":[1,"sections-json"],"dishesJson":[1,"dishes-json"],"themeJson":[1,"theme-json"],"restaurantName":[1,"restaurant-name"]}]]]], options);
9
+ return index.bootstrapLazy([["veleta-boston-template.cjs",[[256,"veleta-boston-template",{"dataJson":[1,"data-json"],"themeJson":[1,"theme-json"]}]]]], options);
10
10
  };
11
11
 
12
12
  exports.setNonce = index.setNonce;
@@ -0,0 +1,148 @@
1
+ 'use strict';
2
+
3
+ var index = require('./index-rvPH40G4.js');
4
+
5
+ /**
6
+ * Carga fuentes usando webfontloader de forma dinámica.
7
+ * Esta función carga el módulo webfontloader solo cuando es necesario.
8
+ *
9
+ * @param fontConfig Configuración de fuentes para webfontloader
10
+ * @returns Promise que se resuelve cuando las fuentes se cargan
11
+ */
12
+ async function loadFonts(fontConfig) {
13
+ if (!fontConfig || (!fontConfig.google && !fontConfig.custom)) {
14
+ return Promise.resolve();
15
+ }
16
+ try {
17
+ // Importación dinámica de webfontloader
18
+ // webfontloader puede exportar de diferentes formas según el entorno
19
+ const webfontloaderModule = await Promise.resolve().then(function () { return require('./webfontloader-CDgRDOZ3.js'); }).then(function (n) { return n.webfontloader; });
20
+ const WebFont = webfontloaderModule.default || webfontloaderModule;
21
+ if (!WebFont || typeof WebFont.load !== 'function') {
22
+ console.warn('webfontloader no está disponible o no tiene el método load');
23
+ return Promise.resolve();
24
+ }
25
+ return new Promise((resolve) => {
26
+ const config = Object.assign(Object.assign({}, fontConfig), { active: () => {
27
+ if (fontConfig.active) {
28
+ fontConfig.active();
29
+ }
30
+ resolve();
31
+ }, inactive: () => {
32
+ if (fontConfig.inactive) {
33
+ fontConfig.inactive();
34
+ }
35
+ // No rechazamos la promesa, solo resolvemos
36
+ // para que el template pueda renderizarse con fuentes por defecto
37
+ resolve();
38
+ } });
39
+ WebFont.load(config);
40
+ });
41
+ }
42
+ catch (error) {
43
+ console.error('Error loading webfontloader:', error);
44
+ // Resolvemos en lugar de rechazar para que el template pueda renderizarse
45
+ return Promise.resolve();
46
+ }
47
+ }
48
+ /**
49
+ * Aplica la familia de fuente al elemento raíz del componente.
50
+ *
51
+ * @param element Elemento HTML al que aplicar la fuente
52
+ * @param fontFamily Familia de fuente CSS (ej: "Roboto, sans-serif")
53
+ */
54
+ function applyFontFamily(element, fontFamily) {
55
+ if (element) {
56
+ element.style.fontFamily = fontFamily;
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Parsea un prop que puede ser un string JSON o un array/objeto directo.
62
+ * Compatible con Angular/Ionic (objetos directos) y Astro/vanilla JS (strings JSON).
63
+ */
64
+ /**
65
+ * Parsea un prop de tema que puede ser un string JSON o un objeto directo.
66
+ * Compatible con Angular/Ionic (objetos directos) y Astro/vanilla JS (strings JSON).
67
+ */
68
+ function parseTheme(themeJson) {
69
+ try {
70
+ // Si ya es un objeto (Angular/Ionic pasa objetos directamente), devolverlo
71
+ if (typeof themeJson === 'object' && themeJson !== null && !Array.isArray(themeJson)) {
72
+ return themeJson;
73
+ }
74
+ // Si es string, parsearlo (Astro, vanilla JS, etc. pasan strings JSON)
75
+ if (typeof themeJson === 'string') {
76
+ const cleaned = themeJson.trim();
77
+ if (!cleaned || cleaned === '{}') {
78
+ return null;
79
+ }
80
+ const res = JSON.parse(cleaned);
81
+ return res && typeof res === 'object' && !Array.isArray(res)
82
+ ? res
83
+ : null;
84
+ }
85
+ return null;
86
+ }
87
+ catch (_a) {
88
+ return null;
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Formatea un precio como string con símbolo de euro.
94
+ * Si es un número entero, no muestra decimales.
95
+ */
96
+ function formatPrice(price) {
97
+ return (price % 1 === 0 ? price.toString() : price.toFixed(2)) + '€';
98
+ }
99
+
100
+ const bostonTemplateCss = () => `.menu-wrapper{min-height:100vh;width:100%;padding:1.5rem 1rem;font-family:'Merriweather', serif;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;display:block}.menu-wrapper *,.menu-wrapper *::before,.menu-wrapper *::after{-webkit-box-sizing:border-box;box-sizing:border-box}.menu-wrapper h1,.menu-wrapper h2,.menu-wrapper h3,.menu-wrapper h4,.menu-wrapper h5,.menu-wrapper h6,.menu-wrapper p,.menu-wrapper ul,.menu-wrapper ol,.menu-wrapper li,.menu-wrapper header,.menu-wrapper section,.menu-wrapper article,.menu-wrapper aside,.menu-wrapper nav,.menu-wrapper blockquote,.menu-wrapper figure,.menu-wrapper figcaption{margin:0;-webkit-margin-before:0;margin-block-start:0;-webkit-margin-after:0;margin-block-end:0;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:0;margin-inline-end:0}.menu-wrapper ul,.menu-wrapper ol{padding:0}@media (min-width: 640px){.menu-wrapper{padding:2rem 1.5rem}}@media (min-width: 768px){.menu-wrapper{padding:2rem 1rem}}.menu-container{max-width:1280px;margin:0 auto}.menu-header{text-align:center}@media (min-width: 768px){.menu-header{margin-bottom:3rem}}.restaurant-title{font-size:2rem;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;line-height:1.1;margin:0 0 1.5rem 0!important}@media (min-width: 640px){.restaurant-title{font-size:2.5rem;margin:0 0 3rem 0!important}}@media (min-width: 768px){.restaurant-title{font-size:3rem}}@media (min-width: 1024px){.restaurant-title{font-size:3.5rem}}.sections-container{display:grid;grid-template-columns:1fr;gap:3rem}@media (min-width: 768px){.sections-container{grid-template-columns:repeat(2, 1fr);gap:4rem}}.menu-section{display:-ms-flexbox;display:flex;width:100%;position:relative}.section-label-wrapper{position:relative;width:3rem;-ms-flex-negative:0;flex-shrink:0;margin-right:1rem;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end}.section-label-line{position:absolute;right:0;top:0;bottom:0;width:1px;border-right:1px solid}.section-label{font-weight:700;font-size:1.125rem;text-transform:uppercase;letter-spacing:0.15em;-webkit-writing-mode:vertical-rl;-ms-writing-mode:tb-rl;writing-mode:vertical-rl;-webkit-transform:rotate(180deg);transform:rotate(180deg);text-align:right;white-space:nowrap;margin:0 0 0.5rem 0;-webkit-margin-after:0.5rem;margin-block-end:0.5rem;position:absolute;top:0}@media (min-width: 640px){.section-label{font-size:1.2375rem}}@media (min-width: 768px){.section-label{font-size:1.35rem}}@media (min-width: 1024px){.section-label{font-size:1.51875rem}}.section-content{-ms-flex:1;flex:1;padding-top:0.25rem}.section-description{font-size:0.875rem;font-style:italic;margin:0 0 1rem 0!important;-webkit-margin-after:1rem;margin-block-end:1rem;opacity:0.75;color:inherit}@media (min-width: 640px){.section-description{font-size:0.9625rem}}@media (min-width: 768px){.section-description{font-size:1.05rem}}@media (min-width: 1024px){.section-description{font-size:1.18125rem}}.dishes-list{list-style:none;padding:0;margin:0;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;gap:1rem}.dish-item{position:relative}.dish-header{display:-ms-flexbox;display:flex;-ms-flex-align:baseline;align-items:baseline;width:100%;gap:0.5rem}.dish-name{font-size:1rem;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;-ms-flex-negative:0;flex-shrink:0}@media (min-width: 640px){.dish-name{font-size:1.1rem}}@media (min-width: 768px){.dish-name{font-size:1.2rem}}@media (min-width: 1024px){.dish-name{font-size:1.35rem}}.dish-dots{-ms-flex:1;flex:1;opacity:0.25;border-bottom:1px dotted;margin:0 0.55rem;position:relative;top:-5px;border-color:currentColor}.dish-price{font-size:1rem;font-weight:700;-ms-flex-negative:0;flex-shrink:0;text-align:right}@media (min-width: 640px){.dish-price{font-size:1.1rem}}@media (min-width: 768px){.dish-price{font-size:1.2rem}}@media (min-width: 1024px){.dish-price{font-size:1.35rem}}.dish-description{font-size:0.8125rem;margin-top:-0.9rem;line-height:1.4;opacity:0.7;color:inherit}@media (min-width: 640px){.dish-description{font-size:0.9425rem}}`;
101
+
102
+ const BostonTemplate = class {
103
+ constructor(hostRef) {
104
+ index.registerInstance(this, hostRef);
105
+ this.dataJson = '{}';
106
+ this.themeJson = '{}';
107
+ this.fontConfig = {
108
+ google: {
109
+ families: ['Oswald:400,600,700', 'Merriweather:300,400,700'],
110
+ },
111
+ };
112
+ }
113
+ async componentWillLoad() {
114
+ await loadFonts(this.fontConfig);
115
+ applyFontFamily(this.el, 'Merriweather, serif');
116
+ }
117
+ render() {
118
+ let menuData = null;
119
+ try {
120
+ menuData = JSON.parse(this.dataJson);
121
+ }
122
+ catch (e) {
123
+ console.warn('Invalid dataJson provided to veleta-boston-template');
124
+ }
125
+ const theme = parseTheme(this.themeJson);
126
+ const primary = (theme === null || theme === void 0 ? void 0 : theme.primaryColor) || '#1a365d';
127
+ const fontBody = 'Merriweather, serif';
128
+ const fontTitle = 'Oswald, sans-serif';
129
+ if (!menuData) {
130
+ return index.h("div", { class: "menu-wrapper", style: { color: primary } });
131
+ }
132
+ const { sections, business } = menuData;
133
+ // Ordenar secciones por 'order'
134
+ const sortedSections = (sections || []).sort((a, b) => a.order - b.order);
135
+ return (index.h("div", { class: "menu-wrapper", style: { color: primary } }, index.h("div", { class: "menu-container" }, (business === null || business === void 0 ? void 0 : business.name) && (index.h("header", { class: "menu-header" }, index.h("h1", { class: "restaurant-title", style: { fontFamily: fontTitle } }, business.name))), index.h("div", { class: "sections-container" }, sortedSections.map(section => {
136
+ // Ordenar platos por 'order'
137
+ const sectionDishes = (section.dishes || []).sort((a, b) => a.order - b.order);
138
+ if (!sectionDishes.length)
139
+ return null;
140
+ return (index.h("section", { key: section.id, class: "menu-section" }, index.h("div", { class: "section-label-wrapper" }, index.h("div", { class: "section-label-line", style: { borderColor: primary } }), index.h("h2", { class: "section-label", style: { fontFamily: fontTitle, color: primary } }, section.title)), index.h("div", { class: "section-content" }, section.description && (index.h("p", { class: "section-description", style: { fontFamily: fontBody } }, section.description)), index.h("ul", { class: "dishes-list" }, sectionDishes.map(dish => (index.h("li", { key: dish.id, class: "dish-item" }, index.h("div", { class: "dish-header" }, index.h("h3", { class: "dish-name", style: { fontFamily: fontTitle, color: primary } }, dish.name), index.h("div", { class: "dish-dots" }), index.h("span", { class: "dish-price", style: { fontFamily: fontTitle, color: primary } }, formatPrice(dish.price))), dish.description && (index.h("p", { class: "dish-description", style: { fontFamily: fontBody } }, dish.description)))))))));
141
+ })))));
142
+ }
143
+ get el() { return index.getElement(this); }
144
+ };
145
+ BostonTemplate.style = bostonTemplateCss();
146
+
147
+ exports.veleta_boston_template = BostonTemplate;
148
+ //# sourceMappingURL=veleta-boston-template.entry.cjs.js.map
@@ -19,7 +19,7 @@ var patchBrowser = () => {
19
19
 
20
20
  patchBrowser().then(async (options) => {
21
21
  await appGlobals.globalScripts();
22
- return index.bootstrapLazy([["veleta-demo-template.cjs",[[256,"veleta-demo-template",{"sectionsJson":[1,"sections-json"],"dishesJson":[1,"dishes-json"],"themeJson":[1,"theme-json"],"restaurantName":[1,"restaurant-name"]}]]],["veleta-menu-template-b.cjs",[[256,"veleta-menu-template-b",{"sectionsJson":[1,"sections-json"],"dishesJson":[1,"dishes-json"],"themeJson":[1,"theme-json"],"restaurantName":[1,"restaurant-name"]}]]]], options);
22
+ return index.bootstrapLazy([["veleta-boston-template.cjs",[[256,"veleta-boston-template",{"dataJson":[1,"data-json"],"themeJson":[1,"theme-json"]}]]]], options);
23
23
  });
24
24
 
25
25
  exports.setNonce = index.setNonce;
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "entries": [
3
- "components/demo-template/demo-template.js",
4
- "components/menu-template-b/menu-template-b.js"
3
+ "components/boston-template/boston-template.js"
5
4
  ],
6
5
  "compiler": {
7
6
  "name": "@stencil/core",
@@ -1,13 +1,11 @@
1
1
  import { h } from "@stencil/core";
2
2
  import { loadFonts, applyFontFamily } from "../../utils/font-loader";
3
- import { parseList, parseTheme } from "../../utils/prop-parser";
4
- import { getDishesBySection, formatPrice } from "../../utils/data-helpers";
5
- export class MenuTemplateB {
3
+ import { parseTheme } from "../../utils/prop-parser";
4
+ import { formatPrice } from "../../utils/data-helpers";
5
+ export class BostonTemplate {
6
6
  constructor() {
7
- this.sectionsJson = '[]';
8
- this.dishesJson = '[]';
7
+ this.dataJson = '{}';
9
8
  this.themeJson = '{}';
10
- this.restaurantName = '';
11
9
  this.fontConfig = {
12
10
  google: {
13
11
  families: ['Oswald:400,600,700', 'Merriweather:300,400,700'],
@@ -19,71 +17,51 @@ export class MenuTemplateB {
19
17
  applyFontFamily(this.el, 'Merriweather, serif');
20
18
  }
21
19
  render() {
22
- const sections = parseList(this.sectionsJson).sort((a, b) => a.order - b.order);
23
- const dishes = parseList(this.dishesJson);
20
+ let menuData = null;
21
+ try {
22
+ menuData = JSON.parse(this.dataJson);
23
+ }
24
+ catch (e) {
25
+ console.warn('Invalid dataJson provided to veleta-boston-template');
26
+ }
24
27
  const theme = parseTheme(this.themeJson);
25
28
  const primary = (theme === null || theme === void 0 ? void 0 : theme.primaryColor) || '#1a365d';
26
29
  const fontBody = 'Merriweather, serif';
27
30
  const fontTitle = 'Oswald, sans-serif';
28
- return (h("div", { key: '13f686e0069dee50b0b177187cd377f50d6935d2', class: "menu-wrapper", style: { color: primary } }, h("div", { key: 'b3d1b79d94cb4060e429f520122f2780b67e284b', class: "menu-container" }, this.restaurantName && (h("header", { key: '80b7b01796c067c64191ebe02904df58156b1305', class: "menu-header" }, h("h1", { key: 'b75dd9d478241674dc1e7728d238b1d390cfac82', class: "restaurant-title", style: { fontFamily: fontTitle } }, this.restaurantName))), h("div", { key: '96995a7755759113e096c9defb125ee41fda20b6', class: "sections-container" }, sections.map(section => {
29
- const sectionDishes = getDishesBySection(section.id, dishes);
31
+ if (!menuData) {
32
+ return h("div", { class: "menu-wrapper", style: { color: primary } });
33
+ }
34
+ const { sections, business } = menuData;
35
+ // Ordenar secciones por 'order'
36
+ const sortedSections = (sections || []).sort((a, b) => a.order - b.order);
37
+ return (h("div", { class: "menu-wrapper", style: { color: primary } }, h("div", { class: "menu-container" }, (business === null || business === void 0 ? void 0 : business.name) && (h("header", { class: "menu-header" }, h("h1", { class: "restaurant-title", style: { fontFamily: fontTitle } }, business.name))), h("div", { class: "sections-container" }, sortedSections.map(section => {
38
+ // Ordenar platos por 'order'
39
+ const sectionDishes = (section.dishes || []).sort((a, b) => a.order - b.order);
30
40
  if (!sectionDishes.length)
31
41
  return null;
32
42
  return (h("section", { key: section.id, class: "menu-section" }, h("div", { class: "section-label-wrapper" }, h("div", { class: "section-label-line", style: { borderColor: primary } }), h("h2", { class: "section-label", style: { fontFamily: fontTitle, color: primary } }, section.title)), h("div", { class: "section-content" }, section.description && (h("p", { class: "section-description", style: { fontFamily: fontBody } }, section.description)), h("ul", { class: "dishes-list" }, sectionDishes.map(dish => (h("li", { key: dish.id, class: "dish-item" }, h("div", { class: "dish-header" }, h("h3", { class: "dish-name", style: { fontFamily: fontTitle, color: primary } }, dish.name), h("div", { class: "dish-dots" }), h("span", { class: "dish-price", style: { fontFamily: fontTitle, color: primary } }, formatPrice(dish.price))), dish.description && (h("p", { class: "dish-description", style: { fontFamily: fontBody } }, dish.description)))))))));
33
43
  })))));
34
44
  }
35
- static get is() { return "veleta-menu-template-b"; }
45
+ static get is() { return "veleta-boston-template"; }
36
46
  static get originalStyleUrls() {
37
47
  return {
38
- "$": ["menu-template-b.css"]
48
+ "$": ["boston-template.css"]
39
49
  };
40
50
  }
41
51
  static get styleUrls() {
42
52
  return {
43
- "$": ["menu-template-b.css"]
53
+ "$": ["boston-template.css"]
44
54
  };
45
55
  }
46
56
  static get properties() {
47
57
  return {
48
- "sectionsJson": {
58
+ "dataJson": {
49
59
  "type": "string",
50
60
  "mutable": false,
51
61
  "complexType": {
52
- "original": "string | Section[]",
53
- "resolved": "Section[] | string",
54
- "references": {
55
- "Section": {
56
- "location": "import",
57
- "path": "../../types/interfaces",
58
- "id": "src/types/interfaces.ts::Section"
59
- }
60
- }
61
- },
62
- "required": false,
63
- "optional": false,
64
- "docs": {
65
- "tags": [],
66
- "text": ""
67
- },
68
- "getter": false,
69
- "setter": false,
70
- "reflect": false,
71
- "attribute": "sections-json",
72
- "defaultValue": "'[]'"
73
- },
74
- "dishesJson": {
75
- "type": "string",
76
- "mutable": false,
77
- "complexType": {
78
- "original": "string | Dish[]",
79
- "resolved": "Dish[] | string",
80
- "references": {
81
- "Dish": {
82
- "location": "import",
83
- "path": "../../types/interfaces",
84
- "id": "src/types/interfaces.ts::Dish"
85
- }
86
- }
62
+ "original": "string",
63
+ "resolved": "string",
64
+ "references": {}
87
65
  },
88
66
  "required": false,
89
67
  "optional": false,
@@ -94,8 +72,8 @@ export class MenuTemplateB {
94
72
  "getter": false,
95
73
  "setter": false,
96
74
  "reflect": false,
97
- "attribute": "dishes-json",
98
- "defaultValue": "'[]'"
75
+ "attribute": "data-json",
76
+ "defaultValue": "'{}'"
99
77
  },
100
78
  "themeJson": {
101
79
  "type": "string",
@@ -122,29 +100,9 @@ export class MenuTemplateB {
122
100
  "reflect": false,
123
101
  "attribute": "theme-json",
124
102
  "defaultValue": "'{}'"
125
- },
126
- "restaurantName": {
127
- "type": "string",
128
- "mutable": false,
129
- "complexType": {
130
- "original": "string",
131
- "resolved": "string",
132
- "references": {}
133
- },
134
- "required": false,
135
- "optional": false,
136
- "docs": {
137
- "tags": [],
138
- "text": ""
139
- },
140
- "getter": false,
141
- "setter": false,
142
- "reflect": false,
143
- "attribute": "restaurant-name",
144
- "defaultValue": "''"
145
103
  }
146
104
  };
147
105
  }
148
106
  static get elementRef() { return "el"; }
149
107
  }
150
- //# sourceMappingURL=menu-template-b.js.map
108
+ //# sourceMappingURL=boston-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boston-template.js","sourceRoot":"","sources":["../../../src/components/boston-template/boston-template.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component, Prop, h, Element } from '@stencil/core';\nimport { Menu, Theme } from '../../types/interfaces';\nimport { loadFonts, applyFontFamily } from '../../utils/font-loader';\nimport { parseTheme } from '../../utils/prop-parser';\nimport { formatPrice } from '../../utils/data-helpers';\n\n@Component({\n tag: 'veleta-boston-template',\n styleUrl: 'boston-template.css',\n shadow: false,\n})\nexport class BostonTemplate {\n @Element() el: HTMLElement;\n\n @Prop() dataJson: string = '{}';\n @Prop() themeJson: string | Theme = '{}';\n\n private readonly fontConfig = {\n google: {\n families: ['Oswald:400,600,700', 'Merriweather:300,400,700'],\n },\n };\n\n async componentWillLoad() {\n await loadFonts(this.fontConfig);\n applyFontFamily(this.el, 'Merriweather, serif');\n }\n\n render() {\n let menuData: Menu | null = null;\n try {\n menuData = JSON.parse(this.dataJson);\n } catch (e) {\n console.warn('Invalid dataJson provided to veleta-boston-template');\n }\n\n const theme = parseTheme(this.themeJson);\n const primary = theme?.primaryColor || '#1a365d';\n const fontBody = 'Merriweather, serif';\n const fontTitle = 'Oswald, sans-serif';\n\n if (!menuData) {\n return <div class=\"menu-wrapper\" style={{ color: primary }}></div>;\n }\n\n const { sections, business } = menuData;\n // Ordenar secciones por 'order'\n const sortedSections = (sections || []).sort((a, b) => a.order - b.order);\n\n return (\n <div\n class=\"menu-wrapper\"\n style={{ color: primary }}\n >\n <div class=\"menu-container\">\n {business?.name && (\n <header class=\"menu-header\">\n <h1 class=\"restaurant-title\" style={{ fontFamily: fontTitle }}>\n {business.name}\n </h1>\n </header>\n )}\n\n {/* Layout: 1 columna mobile, 2 columnas tablet/desktop */}\n <div class=\"sections-container\">\n {sortedSections.map(section => {\n // Ordenar platos por 'order'\n const sectionDishes = (section.dishes || []).sort((a, b) => a.order - b.order);\n if (!sectionDishes.length) return null;\n\n return (\n <section key={section.id} class=\"menu-section\">\n {/* Título vertical izquierdo */}\n <div class=\"section-label-wrapper\">\n <div class=\"section-label-line\" style={{ borderColor: primary }}></div>\n <h2\n class=\"section-label\"\n style={{ fontFamily: fontTitle, color: primary }}\n >\n {section.title}\n </h2>\n </div>\n\n {/* Contenido de platos */}\n <div class=\"section-content\">\n {section.description && (\n <p class=\"section-description\" style={{ fontFamily: fontBody }}>\n {section.description}\n </p>\n )}\n\n <ul class=\"dishes-list\">\n {sectionDishes.map(dish => (\n <li key={dish.id} class=\"dish-item\">\n <div class=\"dish-header\">\n <h3\n class=\"dish-name\"\n style={{ fontFamily: fontTitle, color: primary }}\n >\n {dish.name}\n </h3>\n <div\n class=\"dish-dots\"\n ></div>\n <span\n class=\"dish-price\"\n style={{ fontFamily: fontTitle, color: primary }}\n >\n {formatPrice(dish.price)}\n </span>\n </div>\n {dish.description && (\n <p class=\"dish-description\" style={{ fontFamily: fontBody }}>\n {dish.description}\n </p>\n )}\n </li>\n ))}\n </ul>\n </div>\n </section>\n );\n })}\n </div>\n </div>\n </div>\n );\n }\n}"]}
@@ -1,3 +1,2 @@
1
- export * from './components/demo-template/demo-template';
2
- export * from './components/menu-template-b/menu-template-b';
1
+ export * from './components/boston-template/boston-template';
3
2
  //# sourceMappingURL=components.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"components.js","sourceRoot":"","sources":["../src/components.ts"],"names":[],"mappings":"AAAA,cAAc,0CAA0C,CAAC;AACzD,cAAc,8CAA8C,CAAC","sourcesContent":["export * from './components/demo-template/demo-template';\nexport * from './components/menu-template-b/menu-template-b';\n\n"]}
1
+ {"version":3,"file":"components.js","sourceRoot":"","sources":["../src/components.ts"],"names":[],"mappings":"AAAA,cAAc,8CAA8C,CAAC","sourcesContent":["export * from './components/boston-template/boston-template';\n\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../../src/types/interfaces.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Representa una sección del menú que agrupa platos.\n */\nexport interface Section {\n id: string; // Identificador único de la sección (requerido)\n title: string; // Título de la sección (requerido)\n description?: string; // Descripción opcional de la sección\n order: number; // Índice de orden para ordenar secciones (requerido)\n}\n\n/**\n * Representa un plato individual del menú que pertenece a una sección.\n */\nexport interface Dish {\n id: string; // Identificador único del plato (requerido)\n name: string; // Nombre del plato (requerido)\n price: number; // Precio del plato en euros (requerido, > 0)\n description?: string; // Descripción opcional del plato\n sectionId: string; // ID de la sección a la que pertenece (requerido)\n order: number; // Índice de orden dentro de la sección (requerido)\n}\n\n/**\n * Representa la configuración de colores del tema para el template.\n */\nexport interface Theme {\n id: string; // Identificador único del tema (requerido)\n name: string; // Nombre del tema (requerido)\n primaryColor: string; // Color primario en formato hexadecimal (requerido, ej: \"#3B82F6\")\n secondaryColor?: string | null; // Color secundario en formato hexadecimal (opcional, ej: \"#60A5FA\")\n backgroundColor?: string | null; // Color de fondo en formato hexadecimal (opcional, ej: \"#FFFFFF\")\n}\n\n/**\n * Propiedades que reciben los componentes Stencil como strings JSON.\n */\nexport interface TemplateProps {\n restaurantName: string; // Nombre del restaurante\n sectionsJson: string; // JSON string del array de secciones\n dishesJson: string; // JSON string del array de platos\n themeJson: string; // JSON string del objeto de tema\n}\n\n"]}
1
+ {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../../src/types/interfaces.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Representa un plato individual del menú.\n */\nexport interface Dish {\n id: string;\n name: string;\n price: number;\n available: boolean;\n order: number;\n description?: string;\n}\n\n/**\n * Representa la configuración de colores del tema para el template.\n */\nexport interface Theme {\n id: string;\n name: string;\n primaryColor: string;\n secondaryColor?: string | null;\n backgroundColor?: string | null;\n}\n\nexport interface MenuInfo {\n id: string;\n businessId: string;\n name: string;\n slug: string;\n active: boolean;\n}\n\nexport interface BusinessInfo {\n name: string;\n description: string;\n instagramUrl: string;\n}\n\nexport interface SectionWithDishes {\n id: string;\n title: string;\n order: number;\n description?: string;\n dishes: Dish[];\n}\n\nexport interface Menu {\n menu: MenuInfo;\n sections: SectionWithDishes[];\n business: BusinessInfo;\n}\n"]}
@@ -1,11 +1,3 @@
1
- /**
2
- * Obtiene los platos de una sección específica, ordenados por order.
3
- */
4
- export function getDishesBySection(sectionId, dishes) {
5
- return dishes
6
- .filter(d => d.sectionId === sectionId)
7
- .sort((a, b) => a.order - b.order);
8
- }
9
1
  /**
10
2
  * Formatea un precio como string con símbolo de euro.
11
3
  * Si es un número entero, no muestra decimales.
@@ -1 +1 @@
1
- {"version":3,"file":"data-helpers.js","sourceRoot":"","sources":["../../src/utils/data-helpers.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAiB,EAAE,MAAc;IAClE,OAAO,MAAM;SACV,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC;SACtC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;AACvE,CAAC","sourcesContent":["import { Dish } from '../types/interfaces';\n\n/**\n * Obtiene los platos de una sección específica, ordenados por order.\n */\nexport function getDishesBySection(sectionId: string, dishes: Dish[]): Dish[] {\n return dishes\n .filter(d => d.sectionId === sectionId)\n .sort((a, b) => a.order - b.order);\n}\n\n/**\n * Formatea un precio como string con símbolo de euro.\n * Si es un número entero, no muestra decimales.\n */\nexport function formatPrice(price: number): string {\n return (price % 1 === 0 ? price.toString() : price.toFixed(2)) + '€';\n}\n\n"]}
1
+ {"version":3,"file":"data-helpers.js","sourceRoot":"","sources":["../../src/utils/data-helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;AACvE,CAAC","sourcesContent":["/**\n * Formatea un precio como string con símbolo de euro.\n * Si es un número entero, no muestra decimales.\n */\nexport function formatPrice(price: number): string {\n return (price % 1 === 0 ? price.toString() : price.toFixed(2)) + '€';\n}\n\n\n"]}
@@ -0,0 +1,11 @@
1
+ import type { Components, JSX } from "../types/components";
2
+
3
+ interface VeletaBostonTemplate extends Components.VeletaBostonTemplate, HTMLElement {}
4
+ export const VeletaBostonTemplate: {
5
+ prototype: VeletaBostonTemplate;
6
+ new (): VeletaBostonTemplate;
7
+ };
8
+ /**
9
+ * Used to define this component and all nested components recursively.
10
+ */
11
+ export const defineCustomElement: () => void;
@@ -0,0 +1,171 @@
1
+ import { t as transformTag, p as proxyCustomElement, H, h } from './index.js';
2
+
3
+ /**
4
+ * Carga fuentes usando webfontloader de forma dinámica.
5
+ * Esta función carga el módulo webfontloader solo cuando es necesario.
6
+ *
7
+ * @param fontConfig Configuración de fuentes para webfontloader
8
+ * @returns Promise que se resuelve cuando las fuentes se cargan
9
+ */
10
+ async function loadFonts(fontConfig) {
11
+ if (!fontConfig || (!fontConfig.google && !fontConfig.custom)) {
12
+ return Promise.resolve();
13
+ }
14
+ try {
15
+ // Importación dinámica de webfontloader
16
+ // webfontloader puede exportar de diferentes formas según el entorno
17
+ const webfontloaderModule = await import('./p-DjUJwx0S.js').then(function (n) { return n.w; });
18
+ const WebFont = webfontloaderModule.default || webfontloaderModule;
19
+ if (!WebFont || typeof WebFont.load !== 'function') {
20
+ console.warn('webfontloader no está disponible o no tiene el método load');
21
+ return Promise.resolve();
22
+ }
23
+ return new Promise((resolve) => {
24
+ const config = Object.assign(Object.assign({}, fontConfig), { active: () => {
25
+ if (fontConfig.active) {
26
+ fontConfig.active();
27
+ }
28
+ resolve();
29
+ }, inactive: () => {
30
+ if (fontConfig.inactive) {
31
+ fontConfig.inactive();
32
+ }
33
+ // No rechazamos la promesa, solo resolvemos
34
+ // para que el template pueda renderizarse con fuentes por defecto
35
+ resolve();
36
+ } });
37
+ WebFont.load(config);
38
+ });
39
+ }
40
+ catch (error) {
41
+ console.error('Error loading webfontloader:', error);
42
+ // Resolvemos en lugar de rechazar para que el template pueda renderizarse
43
+ return Promise.resolve();
44
+ }
45
+ }
46
+ /**
47
+ * Aplica la familia de fuente al elemento raíz del componente.
48
+ *
49
+ * @param element Elemento HTML al que aplicar la fuente
50
+ * @param fontFamily Familia de fuente CSS (ej: "Roboto, sans-serif")
51
+ */
52
+ function applyFontFamily(element, fontFamily) {
53
+ if (element) {
54
+ element.style.fontFamily = fontFamily;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Parsea un prop que puede ser un string JSON o un array/objeto directo.
60
+ * Compatible con Angular/Ionic (objetos directos) y Astro/vanilla JS (strings JSON).
61
+ */
62
+ /**
63
+ * Parsea un prop de tema que puede ser un string JSON o un objeto directo.
64
+ * Compatible con Angular/Ionic (objetos directos) y Astro/vanilla JS (strings JSON).
65
+ */
66
+ function parseTheme(themeJson) {
67
+ try {
68
+ // Si ya es un objeto (Angular/Ionic pasa objetos directamente), devolverlo
69
+ if (typeof themeJson === 'object' && themeJson !== null && !Array.isArray(themeJson)) {
70
+ return themeJson;
71
+ }
72
+ // Si es string, parsearlo (Astro, vanilla JS, etc. pasan strings JSON)
73
+ if (typeof themeJson === 'string') {
74
+ const cleaned = themeJson.trim();
75
+ if (!cleaned || cleaned === '{}') {
76
+ return null;
77
+ }
78
+ const res = JSON.parse(cleaned);
79
+ return res && typeof res === 'object' && !Array.isArray(res)
80
+ ? res
81
+ : null;
82
+ }
83
+ return null;
84
+ }
85
+ catch (_a) {
86
+ return null;
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Formatea un precio como string con símbolo de euro.
92
+ * Si es un número entero, no muestra decimales.
93
+ */
94
+ function formatPrice(price) {
95
+ return (price % 1 === 0 ? price.toString() : price.toFixed(2)) + '€';
96
+ }
97
+
98
+ const bostonTemplateCss = () => `.menu-wrapper{min-height:100vh;width:100%;padding:1.5rem 1rem;font-family:'Merriweather', serif;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;display:block}.menu-wrapper *,.menu-wrapper *::before,.menu-wrapper *::after{-webkit-box-sizing:border-box;box-sizing:border-box}.menu-wrapper h1,.menu-wrapper h2,.menu-wrapper h3,.menu-wrapper h4,.menu-wrapper h5,.menu-wrapper h6,.menu-wrapper p,.menu-wrapper ul,.menu-wrapper ol,.menu-wrapper li,.menu-wrapper header,.menu-wrapper section,.menu-wrapper article,.menu-wrapper aside,.menu-wrapper nav,.menu-wrapper blockquote,.menu-wrapper figure,.menu-wrapper figcaption{margin:0;-webkit-margin-before:0;margin-block-start:0;-webkit-margin-after:0;margin-block-end:0;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:0;margin-inline-end:0}.menu-wrapper ul,.menu-wrapper ol{padding:0}@media (min-width: 640px){.menu-wrapper{padding:2rem 1.5rem}}@media (min-width: 768px){.menu-wrapper{padding:2rem 1rem}}.menu-container{max-width:1280px;margin:0 auto}.menu-header{text-align:center}@media (min-width: 768px){.menu-header{margin-bottom:3rem}}.restaurant-title{font-size:2rem;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;line-height:1.1;margin:0 0 1.5rem 0!important}@media (min-width: 640px){.restaurant-title{font-size:2.5rem;margin:0 0 3rem 0!important}}@media (min-width: 768px){.restaurant-title{font-size:3rem}}@media (min-width: 1024px){.restaurant-title{font-size:3.5rem}}.sections-container{display:grid;grid-template-columns:1fr;gap:3rem}@media (min-width: 768px){.sections-container{grid-template-columns:repeat(2, 1fr);gap:4rem}}.menu-section{display:-ms-flexbox;display:flex;width:100%;position:relative}.section-label-wrapper{position:relative;width:3rem;-ms-flex-negative:0;flex-shrink:0;margin-right:1rem;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end}.section-label-line{position:absolute;right:0;top:0;bottom:0;width:1px;border-right:1px solid}.section-label{font-weight:700;font-size:1.125rem;text-transform:uppercase;letter-spacing:0.15em;-webkit-writing-mode:vertical-rl;-ms-writing-mode:tb-rl;writing-mode:vertical-rl;-webkit-transform:rotate(180deg);transform:rotate(180deg);text-align:right;white-space:nowrap;margin:0 0 0.5rem 0;-webkit-margin-after:0.5rem;margin-block-end:0.5rem;position:absolute;top:0}@media (min-width: 640px){.section-label{font-size:1.2375rem}}@media (min-width: 768px){.section-label{font-size:1.35rem}}@media (min-width: 1024px){.section-label{font-size:1.51875rem}}.section-content{-ms-flex:1;flex:1;padding-top:0.25rem}.section-description{font-size:0.875rem;font-style:italic;margin:0 0 1rem 0!important;-webkit-margin-after:1rem;margin-block-end:1rem;opacity:0.75;color:inherit}@media (min-width: 640px){.section-description{font-size:0.9625rem}}@media (min-width: 768px){.section-description{font-size:1.05rem}}@media (min-width: 1024px){.section-description{font-size:1.18125rem}}.dishes-list{list-style:none;padding:0;margin:0;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;gap:1rem}.dish-item{position:relative}.dish-header{display:-ms-flexbox;display:flex;-ms-flex-align:baseline;align-items:baseline;width:100%;gap:0.5rem}.dish-name{font-size:1rem;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;-ms-flex-negative:0;flex-shrink:0}@media (min-width: 640px){.dish-name{font-size:1.1rem}}@media (min-width: 768px){.dish-name{font-size:1.2rem}}@media (min-width: 1024px){.dish-name{font-size:1.35rem}}.dish-dots{-ms-flex:1;flex:1;opacity:0.25;border-bottom:1px dotted;margin:0 0.55rem;position:relative;top:-5px;border-color:currentColor}.dish-price{font-size:1rem;font-weight:700;-ms-flex-negative:0;flex-shrink:0;text-align:right}@media (min-width: 640px){.dish-price{font-size:1.1rem}}@media (min-width: 768px){.dish-price{font-size:1.2rem}}@media (min-width: 1024px){.dish-price{font-size:1.35rem}}.dish-description{font-size:0.8125rem;margin-top:-0.9rem;line-height:1.4;opacity:0.7;color:inherit}@media (min-width: 640px){.dish-description{font-size:0.9425rem}}`;
99
+
100
+ const BostonTemplate = /*@__PURE__*/ proxyCustomElement(class BostonTemplate extends H {
101
+ constructor(registerHost) {
102
+ super();
103
+ if (registerHost !== false) {
104
+ this.__registerHost();
105
+ }
106
+ this.dataJson = '{}';
107
+ this.themeJson = '{}';
108
+ this.fontConfig = {
109
+ google: {
110
+ families: ['Oswald:400,600,700', 'Merriweather:300,400,700'],
111
+ },
112
+ };
113
+ }
114
+ async componentWillLoad() {
115
+ await loadFonts(this.fontConfig);
116
+ applyFontFamily(this.el, 'Merriweather, serif');
117
+ }
118
+ render() {
119
+ let menuData = null;
120
+ try {
121
+ menuData = JSON.parse(this.dataJson);
122
+ }
123
+ catch (e) {
124
+ console.warn('Invalid dataJson provided to veleta-boston-template');
125
+ }
126
+ const theme = parseTheme(this.themeJson);
127
+ const primary = (theme === null || theme === void 0 ? void 0 : theme.primaryColor) || '#1a365d';
128
+ const fontBody = 'Merriweather, serif';
129
+ const fontTitle = 'Oswald, sans-serif';
130
+ if (!menuData) {
131
+ return h("div", { class: "menu-wrapper", style: { color: primary } });
132
+ }
133
+ const { sections, business } = menuData;
134
+ // Ordenar secciones por 'order'
135
+ const sortedSections = (sections || []).sort((a, b) => a.order - b.order);
136
+ return (h("div", { class: "menu-wrapper", style: { color: primary } }, h("div", { class: "menu-container" }, (business === null || business === void 0 ? void 0 : business.name) && (h("header", { class: "menu-header" }, h("h1", { class: "restaurant-title", style: { fontFamily: fontTitle } }, business.name))), h("div", { class: "sections-container" }, sortedSections.map(section => {
137
+ // Ordenar platos por 'order'
138
+ const sectionDishes = (section.dishes || []).sort((a, b) => a.order - b.order);
139
+ if (!sectionDishes.length)
140
+ return null;
141
+ return (h("section", { key: section.id, class: "menu-section" }, h("div", { class: "section-label-wrapper" }, h("div", { class: "section-label-line", style: { borderColor: primary } }), h("h2", { class: "section-label", style: { fontFamily: fontTitle, color: primary } }, section.title)), h("div", { class: "section-content" }, section.description && (h("p", { class: "section-description", style: { fontFamily: fontBody } }, section.description)), h("ul", { class: "dishes-list" }, sectionDishes.map(dish => (h("li", { key: dish.id, class: "dish-item" }, h("div", { class: "dish-header" }, h("h3", { class: "dish-name", style: { fontFamily: fontTitle, color: primary } }, dish.name), h("div", { class: "dish-dots" }), h("span", { class: "dish-price", style: { fontFamily: fontTitle, color: primary } }, formatPrice(dish.price))), dish.description && (h("p", { class: "dish-description", style: { fontFamily: fontBody } }, dish.description)))))))));
142
+ })))));
143
+ }
144
+ get el() { return this; }
145
+ static get style() { return bostonTemplateCss(); }
146
+ }, [256, "veleta-boston-template", {
147
+ "dataJson": [1, "data-json"],
148
+ "themeJson": [1, "theme-json"]
149
+ }]);
150
+ function defineCustomElement$1() {
151
+ if (typeof customElements === "undefined") {
152
+ return;
153
+ }
154
+ const components = ["veleta-boston-template"];
155
+ components.forEach(tagName => { switch (tagName) {
156
+ case "veleta-boston-template":
157
+ if (!customElements.get(transformTag(tagName))) {
158
+ customElements.define(transformTag(tagName), BostonTemplate);
159
+ }
160
+ break;
161
+ } });
162
+ }
163
+ defineCustomElement$1();
164
+
165
+ const VeletaBostonTemplate = BostonTemplate;
166
+ const defineCustomElement = defineCustomElement$1;
167
+
168
+ export { VeletaBostonTemplate, defineCustomElement };
169
+ //# sourceMappingURL=veleta-boston-template.js.map
170
+
171
+ //# sourceMappingURL=veleta-boston-template.js.map