@happyvertical/smrt-products 0.30.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.
Files changed (147) hide show
  1. package/AGENTS.md +122 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/README.md +115 -0
  5. package/dist/lib/__smrt-register__.d.ts +2 -0
  6. package/dist/lib/__smrt-register__.d.ts.map +1 -0
  7. package/dist/lib/app/main.d.ts +6 -0
  8. package/dist/lib/app/main.d.ts.map +1 -0
  9. package/dist/lib/chunks/ProductAssetCollection-DFPXN43q.js +64 -0
  10. package/dist/lib/chunks/ProductAssetCollection-DFPXN43q.js.map +1 -0
  11. package/dist/lib/chunks/ProductForm-DHeb2L24.js +371 -0
  12. package/dist/lib/chunks/ProductForm-DHeb2L24.js.map +1 -0
  13. package/dist/lib/chunks/Sku-DUKtbYWT.js +511 -0
  14. package/dist/lib/chunks/Sku-DUKtbYWT.js.map +1 -0
  15. package/dist/lib/chunks/SkuCollection-C0tdkEdL.js +160 -0
  16. package/dist/lib/chunks/SkuCollection-C0tdkEdL.js.map +1 -0
  17. package/dist/lib/chunks/__smrt-register__-BIgFaVKn.js +5 -0
  18. package/dist/lib/chunks/__smrt-register__-BIgFaVKn.js.map +1 -0
  19. package/dist/lib/chunks/index-i3-ci1FB.js +6 -0
  20. package/dist/lib/chunks/index-i3-ci1FB.js.map +1 -0
  21. package/dist/lib/chunks/product-store.svelte-Dayd5n3W.js +132 -0
  22. package/dist/lib/chunks/product-store.svelte-Dayd5n3W.js.map +1 -0
  23. package/dist/lib/client.d.ts +9 -0
  24. package/dist/lib/client.d.ts.map +1 -0
  25. package/dist/lib/collections.d.ts +2 -0
  26. package/dist/lib/collections.d.ts.map +1 -0
  27. package/dist/lib/collections.js +12 -0
  28. package/dist/lib/collections.js.map +1 -0
  29. package/dist/lib/components.d.ts +2 -0
  30. package/dist/lib/components.d.ts.map +1 -0
  31. package/dist/lib/components.js +6 -0
  32. package/dist/lib/components.js.map +1 -0
  33. package/dist/lib/generated.d.ts +2 -0
  34. package/dist/lib/generated.d.ts.map +1 -0
  35. package/dist/lib/generated.js +5 -0
  36. package/dist/lib/generated.js.map +1 -0
  37. package/dist/lib/index.d.ts +14 -0
  38. package/dist/lib/index.d.ts.map +1 -0
  39. package/dist/lib/index.js +228 -0
  40. package/dist/lib/index.js.map +1 -0
  41. package/dist/lib/lib/collections/CategoryCollection.d.ts +20 -0
  42. package/dist/lib/lib/collections/CategoryCollection.d.ts.map +1 -0
  43. package/dist/lib/lib/collections/MaterialCollection.d.ts +20 -0
  44. package/dist/lib/lib/collections/MaterialCollection.d.ts.map +1 -0
  45. package/dist/lib/lib/collections/ProductAssetCollection.d.ts +16 -0
  46. package/dist/lib/lib/collections/ProductAssetCollection.d.ts.map +1 -0
  47. package/dist/lib/lib/collections/ProductCollection.d.ts +12 -0
  48. package/dist/lib/lib/collections/ProductCollection.d.ts.map +1 -0
  49. package/dist/lib/lib/collections/ProductVariantCollection.d.ts +10 -0
  50. package/dist/lib/lib/collections/ProductVariantCollection.d.ts.map +1 -0
  51. package/dist/lib/lib/collections/SkuCollection.d.ts +31 -0
  52. package/dist/lib/lib/collections/SkuCollection.d.ts.map +1 -0
  53. package/dist/lib/lib/collections/index.d.ts +7 -0
  54. package/dist/lib/lib/collections/index.d.ts.map +1 -0
  55. package/dist/lib/lib/components/ProductCard.svelte +173 -0
  56. package/dist/lib/lib/components/ProductCard.svelte.d.ts +10 -0
  57. package/dist/lib/lib/components/ProductCard.svelte.d.ts.map +1 -0
  58. package/dist/lib/lib/components/ProductForm.svelte +289 -0
  59. package/dist/lib/lib/components/ProductForm.svelte.d.ts +11 -0
  60. package/dist/lib/lib/components/ProductForm.svelte.d.ts.map +1 -0
  61. package/dist/lib/lib/components/TestComponent.svelte +25 -0
  62. package/dist/lib/lib/components/TestComponent.svelte.d.ts +7 -0
  63. package/dist/lib/lib/components/TestComponent.svelte.d.ts.map +1 -0
  64. package/dist/lib/lib/components/auto-generated/AutoForm.svelte +240 -0
  65. package/dist/lib/lib/components/auto-generated/AutoForm.svelte.d.ts +13 -0
  66. package/dist/lib/lib/components/auto-generated/AutoForm.svelte.d.ts.map +1 -0
  67. package/dist/lib/lib/components/auto-generated/FieldRenderer.svelte +205 -0
  68. package/dist/lib/lib/components/auto-generated/FieldRenderer.svelte.d.ts +14 -0
  69. package/dist/lib/lib/components/auto-generated/FieldRenderer.svelte.d.ts.map +1 -0
  70. package/dist/lib/lib/components/index.d.ts +12 -0
  71. package/dist/lib/lib/components/index.d.ts.map +1 -0
  72. package/dist/lib/lib/components/index.js +11 -0
  73. package/dist/lib/lib/features/CategoryManager.svelte +80 -0
  74. package/dist/lib/lib/features/CategoryManager.svelte.d.ts +7 -0
  75. package/dist/lib/lib/features/CategoryManager.svelte.d.ts.map +1 -0
  76. package/dist/lib/lib/features/ProductCatalog.svelte +299 -0
  77. package/dist/lib/lib/features/ProductCatalog.svelte.d.ts +8 -0
  78. package/dist/lib/lib/features/ProductCatalog.svelte.d.ts.map +1 -0
  79. package/dist/lib/lib/federation-entry.d.ts +11 -0
  80. package/dist/lib/lib/federation-entry.d.ts.map +1 -0
  81. package/dist/lib/lib/generated/index.d.ts +2 -0
  82. package/dist/lib/lib/generated/index.d.ts.map +1 -0
  83. package/dist/lib/lib/i18n.d.ts +79 -0
  84. package/dist/lib/lib/i18n.d.ts.map +1 -0
  85. package/dist/lib/lib/index.d.ts +20 -0
  86. package/dist/lib/lib/index.d.ts.map +1 -0
  87. package/dist/lib/lib/mock-smrt-client.d.ts +40 -0
  88. package/dist/lib/lib/mock-smrt-client.d.ts.map +1 -0
  89. package/dist/lib/lib/mock-smrt-client.js +129 -0
  90. package/dist/lib/lib/mock-smrt-client.js.map +1 -0
  91. package/dist/lib/lib/models/Category.d.ts +38 -0
  92. package/dist/lib/lib/models/Category.d.ts.map +1 -0
  93. package/dist/lib/lib/models/Material.d.ts +22 -0
  94. package/dist/lib/lib/models/Material.d.ts.map +1 -0
  95. package/dist/lib/lib/models/Product.d.ts +57 -0
  96. package/dist/lib/lib/models/Product.d.ts.map +1 -0
  97. package/dist/lib/lib/models/ProductAsset.d.ts +17 -0
  98. package/dist/lib/lib/models/ProductAsset.d.ts.map +1 -0
  99. package/dist/lib/lib/models/ProductVariant.d.ts +51 -0
  100. package/dist/lib/lib/models/ProductVariant.d.ts.map +1 -0
  101. package/dist/lib/lib/models/Sku.d.ts +79 -0
  102. package/dist/lib/lib/models/Sku.d.ts.map +1 -0
  103. package/dist/lib/lib/models/index.d.ts +15 -0
  104. package/dist/lib/lib/models/index.d.ts.map +1 -0
  105. package/dist/lib/lib/models/types.d.ts +41 -0
  106. package/dist/lib/lib/models/types.d.ts.map +1 -0
  107. package/dist/lib/lib/stores/index.d.ts +8 -0
  108. package/dist/lib/lib/stores/index.d.ts.map +1 -0
  109. package/dist/lib/lib/stores/index.js +7 -0
  110. package/dist/lib/lib/stores/product-store.client.svelte.d.ts +45 -0
  111. package/dist/lib/lib/stores/product-store.client.svelte.d.ts.map +1 -0
  112. package/dist/lib/lib/stores/product-store.client.svelte.js +147 -0
  113. package/dist/lib/lib/stores/product-store.svelte.d.ts +29 -0
  114. package/dist/lib/lib/stores/product-store.svelte.d.ts.map +1 -0
  115. package/dist/lib/lib/stores/product-store.svelte.js +144 -0
  116. package/dist/lib/lib/types.d.ts +43 -0
  117. package/dist/lib/lib/types.d.ts.map +1 -0
  118. package/dist/lib/lib/utils/index.d.ts +10 -0
  119. package/dist/lib/lib/utils/index.d.ts.map +1 -0
  120. package/dist/lib/main.d.ts +5 -0
  121. package/dist/lib/main.d.ts.map +1 -0
  122. package/dist/lib/manifest.json +3758 -0
  123. package/dist/lib/mcp.d.ts +14 -0
  124. package/dist/lib/mcp.d.ts.map +1 -0
  125. package/dist/lib/models.d.ts +2 -0
  126. package/dist/lib/models.d.ts.map +1 -0
  127. package/dist/lib/models.js +12 -0
  128. package/dist/lib/models.js.map +1 -0
  129. package/dist/lib/native-api-server.d.ts +7 -0
  130. package/dist/lib/native-api-server.d.ts.map +1 -0
  131. package/dist/lib/server.d.ts +11 -0
  132. package/dist/lib/server.d.ts.map +1 -0
  133. package/dist/lib/simple-api-server.d.ts +7 -0
  134. package/dist/lib/simple-api-server.d.ts.map +1 -0
  135. package/dist/lib/simple-server.d.ts +6 -0
  136. package/dist/lib/simple-server.d.ts.map +1 -0
  137. package/dist/lib/smrt-knowledge.json +1584 -0
  138. package/dist/lib/smrt-products.css +233 -0
  139. package/dist/lib/stores.d.ts +2 -0
  140. package/dist/lib/stores.d.ts.map +1 -0
  141. package/dist/lib/stores.js +6 -0
  142. package/dist/lib/stores.js.map +1 -0
  143. package/dist/lib/utils.d.ts +2 -0
  144. package/dist/lib/utils.d.ts.map +1 -0
  145. package/dist/lib/utils.js +27 -0
  146. package/dist/lib/utils.js.map +1 -0
  147. package/package.json +127 -0
@@ -0,0 +1,205 @@
1
+ <script lang="ts">
2
+ /**
3
+ * Automatic field renderer that maps TypeScript types to UI components
4
+ * This demonstrates the "Define Once, Consume Everywhere" vision
5
+ */
6
+
7
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
8
+ import { M } from '../../i18n.js';
9
+
10
+ const { t } = useI18n();
11
+
12
+ interface Props {
13
+ fieldName: string;
14
+ fieldType: 'string' | 'number' | 'boolean' | 'array' | 'object';
15
+ value: any;
16
+ label?: string;
17
+ placeholder?: string;
18
+ required?: boolean;
19
+ readonly?: boolean;
20
+ onUpdate?: (value: any) => void;
21
+ }
22
+
23
+ const {
24
+ fieldName,
25
+ fieldType,
26
+ value = '',
27
+ label,
28
+ placeholder,
29
+ required = false,
30
+ readonly = false,
31
+ onUpdate,
32
+ }: Props = $props();
33
+
34
+ // Auto-generate label from field name if not provided
35
+ const _displayLabel =
36
+ label ||
37
+ fieldName
38
+ .replace(/([A-Z])/g, ' $1')
39
+ .replace(/^./, (str) => str.toUpperCase());
40
+ const _fieldId = `field-${fieldName}`;
41
+
42
+ function handleUpdate(newValue: any) {
43
+ if (onUpdate && !readonly) {
44
+ onUpdate(newValue);
45
+ }
46
+ }
47
+
48
+ function _handleStringInput(event: Event) {
49
+ const target = event.target as HTMLInputElement;
50
+ handleUpdate(target.value);
51
+ }
52
+
53
+ function _handleNumberInput(event: Event) {
54
+ const target = event.target as HTMLInputElement;
55
+ handleUpdate(Number.parseFloat(target.value) || 0);
56
+ }
57
+
58
+ function _handleBooleanInput(event: Event) {
59
+ const target = event.target as HTMLInputElement;
60
+ handleUpdate(target.checked);
61
+ }
62
+
63
+ function _handleArrayInput(event: Event) {
64
+ const target = event.target as HTMLTextAreaElement;
65
+ try {
66
+ // Simple array handling - comma separated values
67
+ const arrayValue = target.value
68
+ .split(',')
69
+ .map((s) => s.trim())
70
+ .filter((s) => s);
71
+ handleUpdate(arrayValue);
72
+ } catch {
73
+ // Keep current value on parse error
74
+ }
75
+ }
76
+
77
+ function _handleObjectInput(event: Event) {
78
+ const target = event.target as HTMLTextAreaElement;
79
+ try {
80
+ const objectValue = JSON.parse(target.value);
81
+ handleUpdate(objectValue);
82
+ } catch {
83
+ // Keep current value on parse error
84
+ }
85
+ }
86
+ </script>
87
+
88
+ <div class="field-renderer">
89
+ <label for={fieldId} class="field-label">
90
+ {displayLabel}
91
+ {#if required}<span class="required">*</span>{/if}
92
+ </label>
93
+
94
+ {#if fieldType === 'string'}
95
+ <input
96
+ id={fieldId}
97
+ type="text"
98
+ class="field-input"
99
+ {value}
100
+ {placeholder}
101
+ {readonly}
102
+ {required}
103
+ oninput={handleStringInput}
104
+ />
105
+ {:else if fieldType === 'number'}
106
+ <input
107
+ id={fieldId}
108
+ type="number"
109
+ class="field-input"
110
+ value={value || 0}
111
+ {placeholder}
112
+ {readonly}
113
+ {required}
114
+ oninput={handleNumberInput}
115
+ />
116
+ {:else if fieldType === 'boolean'}
117
+ <input
118
+ id={fieldId}
119
+ type="checkbox"
120
+ class="field-checkbox"
121
+ checked={value || false}
122
+ {readonly}
123
+ onchange={handleBooleanInput}
124
+ />
125
+ {:else if fieldType === 'array'}
126
+ <textarea
127
+ id={fieldId}
128
+ class="field-textarea"
129
+ value={Array.isArray(value) ? value.join(', ') : ''}
130
+ placeholder={placeholder || 'Enter comma-separated values'}
131
+ {readonly}
132
+ {required}
133
+ oninput={handleArrayInput}
134
+ />
135
+ <div class="field-hint">{t(M['products.field_renderer.array_hint'])}</div>
136
+ {:else if fieldType === 'object'}
137
+ <textarea
138
+ id={fieldId}
139
+ class="field-textarea"
140
+ value={typeof value === 'object' ? JSON.stringify(value, null, 2) : '{}'}
141
+ placeholder={placeholder || 'Enter JSON object'}
142
+ {readonly}
143
+ {required}
144
+ oninput={handleObjectInput}
145
+ />
146
+ <div class="field-hint">{t(M['products.field_renderer.object_hint'])}</div>
147
+ {/if}
148
+ </div>
149
+
150
+ <style>
151
+ .field-renderer {
152
+ display: flex;
153
+ flex-direction: column;
154
+ gap: 0.5rem;
155
+ margin-bottom: 1rem;
156
+ }
157
+
158
+ .field-label {
159
+ font-weight: var(--smrt-typography-weight-medium, 500);
160
+ color: var(--smrt-color-on-surface, #374151);
161
+ font-size: var(--smrt-typography-label-large-size, 0.875rem);
162
+ }
163
+
164
+ .required {
165
+ color: var(--smrt-color-error, #dc2626);
166
+ }
167
+
168
+ .field-input,
169
+ .field-textarea {
170
+ padding: 0.5rem 0.75rem;
171
+ border: 1px solid var(--smrt-color-outline-variant, #d1d5db);
172
+ border-radius: 0.375rem;
173
+ font-size: var(--smrt-typography-body-medium-size, 0.875rem);
174
+ transition: border-color 0.2s, box-shadow 0.2s;
175
+ }
176
+
177
+ .field-input:focus,
178
+ .field-textarea:focus {
179
+ outline: none;
180
+ border-color: var(--smrt-color-primary, #3b82f6);
181
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--smrt-color-primary, #3b82f6) 10%, transparent);
182
+ }
183
+
184
+ .field-textarea {
185
+ min-height: 4rem;
186
+ resize: vertical;
187
+ }
188
+
189
+ .field-checkbox {
190
+ width: 1rem;
191
+ height: 1rem;
192
+ }
193
+
194
+ .field-hint {
195
+ font-size: var(--smrt-typography-body-small-size, 0.75rem);
196
+ color: var(--smrt-color-on-surface-variant, #6b7280);
197
+ font-style: italic;
198
+ }
199
+
200
+ .field-input:read-only,
201
+ .field-textarea:read-only {
202
+ background-color: var(--smrt-color-surface-container-low, #f9fafb);
203
+ cursor: not-allowed;
204
+ }
205
+ </style>
@@ -0,0 +1,14 @@
1
+ interface Props {
2
+ fieldName: string;
3
+ fieldType: 'string' | 'number' | 'boolean' | 'array' | 'object';
4
+ value: any;
5
+ label?: string;
6
+ placeholder?: string;
7
+ required?: boolean;
8
+ readonly?: boolean;
9
+ onUpdate?: (value: any) => void;
10
+ }
11
+ declare const FieldRenderer: import("svelte").Component<Props, {}, "">;
12
+ type FieldRenderer = ReturnType<typeof FieldRenderer>;
13
+ export default FieldRenderer;
14
+ //# sourceMappingURL=FieldRenderer.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FieldRenderer.svelte.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/auto-generated/FieldRenderer.svelte.ts"],"names":[],"mappings":"AAWA,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;IAChE,KAAK,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;CACjC;AAmGD,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * SMRT Template UI Components
3
+ *
4
+ * Reusable UI components for product management.
5
+ * These components work with SMRT-generated types and can be:
6
+ * - Imported as NPM package components
7
+ * - Consumed via module federation
8
+ * - Used in the standalone application
9
+ */
10
+ export { default as ProductCard } from './ProductCard.svelte';
11
+ export { default as ProductForm } from './ProductForm.svelte';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * SMRT Template UI Components
3
+ *
4
+ * Reusable UI components for product management.
5
+ * These components work with SMRT-generated types and can be:
6
+ * - Imported as NPM package components
7
+ * - Consumed via module federation
8
+ * - Used in the standalone application
9
+ */
10
+ export { default as ProductCard } from './ProductCard.svelte';
11
+ export { default as ProductForm } from './ProductForm.svelte';
@@ -0,0 +1,80 @@
1
+ <script lang="ts">
2
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
3
+ import { M } from '../i18n.js';
4
+ import type { CategoryData } from '../types';
5
+
6
+ const { t } = useI18n();
7
+
8
+ interface Props {
9
+ readonly?: boolean;
10
+ }
11
+
12
+ const { readonly = false }: Props = $props();
13
+
14
+ // Placeholder for category management
15
+ const _categories = $state<CategoryData[]>([]);
16
+ const _loading = $state(false);
17
+ </script>
18
+
19
+ <div class="category-manager">
20
+ <div class="manager-header">
21
+ <h2>{t(M['products.category_manager.title'])}</h2>
22
+ <p>{t(M['products.category_manager.subtitle'])}</p>
23
+ </div>
24
+
25
+ <div class="placeholder-content">
26
+ <p>{t(M['products.category_manager.coming_soon'])}</p>
27
+ <p>{t(M['products.category_manager.will_include'])}</p>
28
+ <ul>
29
+ <li>{t(M['products.category_manager.create_edit'])}</li>
30
+ <li>{t(M['products.category_manager.organize_hierarchy'])}</li>
31
+ <li>{t(M['products.category_manager.manage_permissions'])}</li>
32
+ <li>{t(M['products.category_manager.analytics'])}</li>
33
+ </ul>
34
+ </div>
35
+ </div>
36
+
37
+ <style>
38
+ .category-manager {
39
+ max-width: 800px;
40
+ margin: 0 auto;
41
+ padding: 1rem;
42
+ }
43
+
44
+ .manager-header {
45
+ text-align: center;
46
+ margin-bottom: 2rem;
47
+ }
48
+
49
+ .manager-header h2 {
50
+ margin: 0 0 0.5rem 0;
51
+ color: var(--smrt-color-on-surface, #1f2937);
52
+ font-size: var(--smrt-typography-headline-small-size, 1.5rem);
53
+ font-weight: var(--smrt-typography-weight-semibold, 600);
54
+ }
55
+
56
+ .manager-header p {
57
+ margin: 0;
58
+ color: var(--smrt-color-on-surface-variant, #6b7280);
59
+ }
60
+
61
+ .placeholder-content {
62
+ background: var(--smrt-color-surface-container-low, #f9fafb);
63
+ border: 1px solid var(--smrt-color-outline-variant, #e2e8f0);
64
+ border-radius: var(--smrt-radius-md, 8px);
65
+ padding: 2rem;
66
+ text-align: center;
67
+ }
68
+
69
+ .placeholder-content p {
70
+ margin: 0 0 1rem 0;
71
+ color: var(--smrt-color-on-surface-variant, #6b7280);
72
+ }
73
+
74
+ .placeholder-content ul {
75
+ margin: 1rem 0 0 0;
76
+ text-align: left;
77
+ display: inline-block;
78
+ color: var(--smrt-color-on-surface-variant, #6b7280);
79
+ }
80
+ </style>
@@ -0,0 +1,7 @@
1
+ interface Props {
2
+ readonly?: boolean;
3
+ }
4
+ declare const CategoryManager: import("svelte").Component<Props, {}, "">;
5
+ type CategoryManager = ReturnType<typeof CategoryManager>;
6
+ export default CategoryManager;
7
+ //# sourceMappingURL=CategoryManager.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CategoryManager.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/features/CategoryManager.svelte"],"names":[],"mappings":"AAQA,UAAU,KAAK;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAqCD,QAAA,MAAM,eAAe,2CAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
@@ -0,0 +1,299 @@
1
+ <script lang="ts">
2
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
3
+ import { onMount } from 'svelte';
4
+ import { productStore } from '../stores/product-store.svelte';
5
+ import { M } from '../i18n.js';
6
+ import type { ProductData } from '../types';
7
+
8
+ const { t } = useI18n();
9
+
10
+ interface Props {
11
+ readonly?: boolean;
12
+ showCreateForm?: boolean;
13
+ }
14
+
15
+ const { readonly = false, showCreateForm = false }: Props = $props();
16
+
17
+ const searchQuery = $state('');
18
+ const selectedCategory = $state('');
19
+ let _showForm = $state(false);
20
+ let editingProduct = $state<ProductData | null>(null);
21
+
22
+ // Reactive filtered products
23
+ const _filteredProducts = $derived.by(() => {
24
+ let products = productStore.items;
25
+
26
+ if (searchQuery) {
27
+ products = productStore.searchProducts(searchQuery);
28
+ }
29
+
30
+ if (selectedCategory) {
31
+ products = products.filter((p) => p.category === selectedCategory);
32
+ }
33
+
34
+ return products;
35
+ });
36
+
37
+ onMount(() => {
38
+ productStore.loadProducts();
39
+ });
40
+
41
+ function _handleCreateProduct() {
42
+ editingProduct = null;
43
+ _showForm = true;
44
+ }
45
+
46
+ function _handleEditProduct(product: ProductData) {
47
+ editingProduct = product;
48
+ _showForm = true;
49
+ }
50
+
51
+ async function _handleDeleteProduct(id: string) {
52
+ if (confirm('Are you sure you want to delete this product?')) {
53
+ try {
54
+ await productStore.deleteProduct(id);
55
+ } catch (error) {}
56
+ }
57
+ }
58
+
59
+ async function _handleSubmitProduct(productData: Partial<ProductData>) {
60
+ try {
61
+ if (editingProduct?.id) {
62
+ await productStore.updateProduct(editingProduct.id, productData);
63
+ } else {
64
+ await productStore.createProduct(productData);
65
+ }
66
+ _showForm = false;
67
+ editingProduct = null;
68
+ } catch (error) {}
69
+ }
70
+
71
+ function _handleCancelForm() {
72
+ _showForm = false;
73
+ editingProduct = null;
74
+ }
75
+ </script>
76
+
77
+ <div class="product-catalog">
78
+ <div class="catalog-header">
79
+ <h2>{t(M['products.product_catalog.title'])}</h2>
80
+
81
+ <div class="catalog-stats">
82
+ <span class="stat">
83
+ <strong>{productStore.items.length}</strong> products
84
+ </span>
85
+ <span class="stat">
86
+ <strong>{productStore.inStockCount}</strong> {t(M['products.product_catalog.in_stock'])}
87
+ </span>
88
+ <span class="stat">
89
+ {t(M['products.product_catalog.total_value'])} <strong>${productStore.totalValue.toFixed(2)}</strong>
90
+ </span>
91
+ </div>
92
+ </div>
93
+
94
+ <div class="catalog-controls">
95
+ <div class="search-filters">
96
+ <input
97
+ type="text"
98
+ bind:value={searchQuery}
99
+ placeholder={t(M['products.product_catalog.search_placeholder'])}
100
+ class="search-input"
101
+ />
102
+
103
+ <select bind:value={selectedCategory} class="category-filter">
104
+ <option value="">{t(M['products.product_catalog.all_categories'])}</option>
105
+ {#each productStore.categories as category}
106
+ <option value={category}>{category}</option>
107
+ {/each}
108
+ </select>
109
+ </div>
110
+
111
+ {#if !readonly && (showCreateForm || productStore.items.length === 0)}
112
+ <button
113
+ type="button"
114
+ onclick={handleCreateProduct}
115
+ class="create-btn"
116
+ >
117
+ {t(M['products.product_catalog.add_product'])}
118
+ </button>
119
+ {/if}
120
+ </div>
121
+
122
+ {#if productStore.loading}
123
+ <div class="loading-state">
124
+ <p>{t(M['products.product_catalog.loading'])}</p>
125
+ </div>
126
+ {:else if productStore.error}
127
+ <div class="error-state">
128
+ <p>Error: {productStore.error}</p>
129
+ <button type="button" onclick={() => productStore.loadProducts()}>
130
+ Retry
131
+ </button>
132
+ </div>
133
+ {:else if filteredProducts.length === 0}
134
+ <div class="empty-state">
135
+ {#if productStore.items.length === 0}
136
+ <p>{t(M['products.product_catalog.empty'])}</p>
137
+ {#if !readonly}
138
+ <button type="button" onclick={handleCreateProduct} class="create-btn">
139
+ {t(M['products.product_catalog.create_first'])}
140
+ </button>
141
+ {/if}
142
+ {:else}
143
+ <p>{t(M['products.product_catalog.no_match'])}</p>
144
+ {/if}
145
+ </div>
146
+ {:else}
147
+ <div class="products-grid">
148
+ {#each filteredProducts as product (product.id)}
149
+ <ProductCard
150
+ {product}
151
+ onEdit={readonly ? undefined : handleEditProduct}
152
+ onDelete={readonly ? undefined : handleDeleteProduct}
153
+ />
154
+ {/each}
155
+ </div>
156
+ {/if}
157
+
158
+ {#if showForm && !readonly}
159
+ <div class="form-overlay">
160
+ <div class="form-container">
161
+ <h3>{editingProduct ? 'Edit Product' : 'Create New Product'}</h3>
162
+ <ProductForm
163
+ product={editingProduct}
164
+ onSubmit={handleSubmitProduct}
165
+ onCancel={handleCancelForm}
166
+ loading={productStore.loading}
167
+ />
168
+ </div>
169
+ </div>
170
+ {/if}
171
+ </div>
172
+
173
+ <style>
174
+ .product-catalog {
175
+ max-width: 1200px;
176
+ margin: 0 auto;
177
+ padding: 1rem;
178
+ }
179
+
180
+ .catalog-header {
181
+ display: flex;
182
+ justify-content: space-between;
183
+ align-items: center;
184
+ margin-bottom: 1.5rem;
185
+ padding-bottom: 1rem;
186
+ border-bottom: 2px solid var(--smrt-color-outline-variant, #e2e8f0);
187
+ }
188
+
189
+ .catalog-header h2 {
190
+ margin: 0;
191
+ color: var(--smrt-color-on-surface, #1f2937);
192
+ font-size: var(--smrt-typography-headline-large-size, 1.875rem);
193
+ font-weight: var(--smrt-typography-weight-bold, 700);
194
+ }
195
+
196
+ .catalog-stats {
197
+ display: flex;
198
+ gap: 1.5rem;
199
+ font-size: var(--smrt-typography-label-large-size, 0.875rem);
200
+ color: var(--smrt-color-on-surface-variant, #6b7280);
201
+ }
202
+
203
+ .catalog-controls {
204
+ display: flex;
205
+ justify-content: space-between;
206
+ align-items: center;
207
+ margin-bottom: 1.5rem;
208
+ gap: 1rem;
209
+ }
210
+
211
+ .search-filters {
212
+ display: flex;
213
+ gap: 0.75rem;
214
+ flex: 1;
215
+ }
216
+
217
+ .search-input, .category-filter {
218
+ padding: 0.5rem;
219
+ border: 1px solid var(--smrt-color-outline-variant, #d1d5db);
220
+ border-radius: var(--smrt-radius-sm, 4px);
221
+ font-size: var(--smrt-typography-body-medium-size, 0.875rem);
222
+ }
223
+
224
+ .search-input {
225
+ flex: 1;
226
+ max-width: 300px;
227
+ }
228
+
229
+ .category-filter {
230
+ min-width: 150px;
231
+ }
232
+
233
+ .create-btn {
234
+ background: var(--smrt-color-primary, #3b82f6);
235
+ color: var(--smrt-color-on-primary, white);
236
+ border: none;
237
+ padding: 0.5rem 1rem;
238
+ border-radius: var(--smrt-radius-sm, 4px);
239
+ font-weight: var(--smrt-typography-weight-medium, 500);
240
+ cursor: pointer;
241
+ transition: background-color 0.2s;
242
+ }
243
+
244
+ .create-btn:hover {
245
+ background: var(--smrt-color-primary, #2563eb);
246
+ }
247
+
248
+ .products-grid {
249
+ display: grid;
250
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
251
+ gap: 1.5rem;
252
+ }
253
+
254
+ .loading-state, .error-state, .empty-state {
255
+ text-align: center;
256
+ padding: 3rem 1rem;
257
+ color: var(--smrt-color-on-surface-variant, #6b7280);
258
+ }
259
+
260
+ .error-state button {
261
+ margin-top: 0.5rem;
262
+ background: var(--smrt-color-error, #dc2626);
263
+ color: var(--smrt-color-on-error, white);
264
+ border: none;
265
+ padding: 0.5rem 1rem;
266
+ border-radius: var(--smrt-radius-sm, 4px);
267
+ cursor: pointer;
268
+ }
269
+
270
+ .form-overlay {
271
+ position: fixed;
272
+ top: 0;
273
+ left: 0;
274
+ right: 0;
275
+ bottom: 0;
276
+ background: var(--smrt-color-scrim, rgba(0, 0, 0, 0.5));
277
+ display: flex;
278
+ align-items: center;
279
+ justify-content: center;
280
+ z-index: var(--smrt-z-index-dialog, 1300);
281
+ }
282
+
283
+ .form-container {
284
+ background: white;
285
+ border-radius: var(--smrt-radius-md, 8px);
286
+ max-width: 500px;
287
+ width: 90vw;
288
+ max-height: 90vh;
289
+ overflow-y: auto;
290
+ }
291
+
292
+ .form-container h3 {
293
+ margin: 0 0 1rem 0;
294
+ padding: 1.5rem 1.5rem 0 1.5rem;
295
+ color: var(--smrt-color-on-surface, #1f2937);
296
+ font-size: var(--smrt-typography-title-large-size, 1.25rem);
297
+ font-weight: var(--smrt-typography-weight-semibold, 600);
298
+ }
299
+ </style>
@@ -0,0 +1,8 @@
1
+ interface Props {
2
+ readonly?: boolean;
3
+ showCreateForm?: boolean;
4
+ }
5
+ declare const ProductCatalog: import("svelte").Component<Props, {}, "">;
6
+ type ProductCatalog = ReturnType<typeof ProductCatalog>;
7
+ export default ProductCatalog;
8
+ //# sourceMappingURL=ProductCatalog.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProductCatalog.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/features/ProductCatalog.svelte"],"names":[],"mappings":"AAUA,UAAU,KAAK;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AA0JD,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Federation Entry Point
3
+ *
4
+ * This file provides clean, browser-compatible exports for module federation
5
+ * without any server-side dependencies or SMRT virtual modules.
6
+ */
7
+ export { default as ProductCard } from './components/ProductCard.svelte';
8
+ export { default as ProductForm } from './components/ProductForm.svelte';
9
+ export { default as CategoryManager } from './features/CategoryManager.svelte';
10
+ export type { CategoryData, ProductData } from './types';
11
+ //# sourceMappingURL=federation-entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"federation-entry.d.ts","sourceRoot":"","sources":["../../../src/lib/federation-entry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAG/E,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const autoGeneratedComponents: {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/generated/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,4BAA4B,CAAC;AASpC,eAAO,MAAM,uBAAuB,IAAK,CAAC"}