nitrostack 1.0.54 → 1.0.56

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 (220) hide show
  1. package/dist/cli/commands/init.d.ts.map +1 -1
  2. package/dist/cli/commands/init.js +14 -9
  3. package/dist/cli/commands/init.js.map +1 -1
  4. package/dist/widgets/hooks/index.d.ts +7 -0
  5. package/dist/widgets/hooks/index.d.ts.map +1 -0
  6. package/dist/widgets/hooks/index.js +7 -0
  7. package/dist/widgets/hooks/index.js.map +1 -0
  8. package/dist/widgets/hooks/use-display-mode.d.ts +11 -0
  9. package/dist/widgets/hooks/use-display-mode.d.ts.map +1 -0
  10. package/dist/widgets/hooks/use-display-mode.js +13 -0
  11. package/dist/widgets/hooks/use-display-mode.js.map +1 -0
  12. package/dist/widgets/hooks/use-max-height.d.ts +10 -0
  13. package/dist/widgets/hooks/use-max-height.d.ts.map +1 -0
  14. package/dist/widgets/hooks/use-max-height.js +13 -0
  15. package/dist/widgets/hooks/use-max-height.js.map +1 -0
  16. package/dist/widgets/hooks/use-openai-global.d.ts +12 -0
  17. package/dist/widgets/hooks/use-openai-global.d.ts.map +1 -0
  18. package/dist/widgets/hooks/use-openai-global.js +32 -0
  19. package/dist/widgets/hooks/use-openai-global.js.map +1 -0
  20. package/dist/widgets/hooks/use-theme.d.ts +10 -0
  21. package/dist/widgets/hooks/use-theme.d.ts.map +1 -0
  22. package/dist/widgets/hooks/use-theme.js +12 -0
  23. package/dist/widgets/hooks/use-theme.js.map +1 -0
  24. package/dist/widgets/hooks/use-widget-state.d.ts +18 -0
  25. package/dist/widgets/hooks/use-widget-state.d.ts.map +1 -0
  26. package/dist/widgets/hooks/use-widget-state.js +27 -0
  27. package/dist/widgets/hooks/use-widget-state.js.map +1 -0
  28. package/dist/widgets/hooks/useWidgetSDK.d.ts +47 -0
  29. package/dist/widgets/hooks/useWidgetSDK.d.ts.map +1 -0
  30. package/dist/widgets/hooks/useWidgetSDK.js +67 -0
  31. package/dist/widgets/hooks/useWidgetSDK.js.map +1 -0
  32. package/dist/widgets/index.d.ts +7 -1
  33. package/dist/widgets/index.d.ts.map +1 -1
  34. package/dist/widgets/index.js +11 -1
  35. package/dist/widgets/index.js.map +1 -1
  36. package/dist/widgets/runtime/WidgetLayout.d.ts +32 -0
  37. package/dist/widgets/runtime/WidgetLayout.d.ts.map +1 -0
  38. package/dist/widgets/runtime/WidgetLayout.js +143 -0
  39. package/dist/widgets/runtime/WidgetLayout.js.map +1 -0
  40. package/dist/widgets/runtime/widget-polyfill.d.ts +1 -0
  41. package/dist/widgets/runtime/widget-polyfill.d.ts.map +1 -0
  42. package/dist/widgets/runtime/widget-polyfill.js +28 -0
  43. package/dist/widgets/runtime/widget-polyfill.js.map +1 -0
  44. package/dist/widgets/sdk.d.ts +109 -0
  45. package/dist/widgets/sdk.d.ts.map +1 -0
  46. package/dist/widgets/sdk.js +221 -0
  47. package/dist/widgets/sdk.js.map +1 -0
  48. package/dist/widgets/types.d.ts +89 -0
  49. package/dist/widgets/types.d.ts.map +1 -0
  50. package/dist/widgets/types.js +8 -0
  51. package/dist/widgets/types.js.map +1 -0
  52. package/dist/widgets/utils/media-queries.d.ts +34 -0
  53. package/dist/widgets/utils/media-queries.d.ts.map +1 -0
  54. package/dist/widgets/utils/media-queries.js +42 -0
  55. package/dist/widgets/utils/media-queries.js.map +1 -0
  56. package/package.json +2 -2
  57. package/src/studio/app/chat/page.tsx +274 -137
  58. package/src/studio/app/globals.css +140 -64
  59. package/src/studio/branding.md +807 -0
  60. package/src/studio/components/WidgetRenderer.tsx +222 -16
  61. package/src/studio/lib/llm-service.ts +39 -39
  62. package/templates/typescript-oauth/.env.example +27 -0
  63. package/templates/typescript-oauth/README.md +226 -306
  64. package/templates/typescript-oauth/package-lock.json +4253 -0
  65. package/templates/typescript-oauth/package.json +10 -5
  66. package/templates/typescript-oauth/src/app.module.ts +39 -36
  67. package/templates/typescript-oauth/src/guards/oauth.guard.ts +0 -1
  68. package/templates/typescript-oauth/src/index.ts +22 -30
  69. package/templates/typescript-oauth/src/modules/flights/booking.tools.ts +323 -0
  70. package/templates/typescript-oauth/src/modules/flights/flights.module.ts +14 -0
  71. package/templates/typescript-oauth/src/modules/flights/flights.prompts.ts +231 -0
  72. package/templates/typescript-oauth/src/modules/flights/flights.resources.ts +215 -0
  73. package/templates/typescript-oauth/src/modules/flights/flights.tools.ts +457 -0
  74. package/templates/typescript-oauth/src/services/duffel.service.ts +285 -0
  75. package/templates/typescript-oauth/src/widgets/app/airport-search/page.tsx +270 -0
  76. package/templates/typescript-oauth/src/widgets/app/flight-details/page.tsx +261 -0
  77. package/templates/typescript-oauth/src/widgets/app/flight-search-results/page.tsx +378 -0
  78. package/templates/typescript-oauth/src/widgets/app/globals.css +167 -0
  79. package/templates/typescript-oauth/src/widgets/app/layout.tsx +6 -2
  80. package/templates/typescript-oauth/src/widgets/app/order-cancellation/page.tsx +207 -0
  81. package/templates/typescript-oauth/src/widgets/app/order-summary/page.tsx +245 -0
  82. package/templates/typescript-oauth/src/widgets/app/payment-confirmation/page.tsx +152 -0
  83. package/templates/typescript-oauth/src/widgets/app/seat-selection/page.tsx +486 -0
  84. package/templates/typescript-oauth/src/widgets/next-env.d.ts +5 -0
  85. package/templates/typescript-oauth/src/widgets/package-lock.json +155 -126
  86. package/templates/typescript-oauth/src/widgets/widget-manifest.json +374 -27
  87. package/templates/typescript-pizzaz/IMPLEMENTATION.md +98 -0
  88. package/templates/typescript-pizzaz/README.md +233 -0
  89. package/templates/typescript-pizzaz/package.json +31 -0
  90. package/templates/typescript-pizzaz/src/app.module.ts +28 -0
  91. package/templates/typescript-pizzaz/src/index.ts +30 -0
  92. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.data.ts +106 -0
  93. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.module.ts +11 -0
  94. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.service.ts +60 -0
  95. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.tools.ts +197 -0
  96. package/templates/typescript-pizzaz/src/widgets/app/layout.tsx +18 -0
  97. package/templates/typescript-pizzaz/src/widgets/app/pizza-list/page.tsx +272 -0
  98. package/templates/typescript-pizzaz/src/widgets/app/pizza-map/page.tsx +216 -0
  99. package/templates/typescript-pizzaz/src/widgets/app/pizza-shop/page.tsx +374 -0
  100. package/templates/typescript-pizzaz/src/widgets/components/CompactShopCard.tsx +144 -0
  101. package/templates/typescript-pizzaz/src/widgets/components/PizzaCard.tsx +191 -0
  102. package/templates/typescript-pizzaz/src/widgets/package.json +30 -0
  103. package/templates/typescript-pizzaz/src/widgets/widget-manifest.json +253 -0
  104. package/templates/typescript-pizzaz/tsconfig.json +30 -0
  105. package/templates/typescript-starter/src/modules/calculator/calculator.resources.ts +0 -1
  106. package/templates/typescript-starter/src/widgets/app/calculator-result/page.tsx +102 -56
  107. package/templates/typescript-starter/src/widgets/app/layout.tsx +6 -2
  108. package/templates/typescript-auth/AI_AGENT_CLI_REFERENCE.md +0 -702
  109. package/templates/typescript-auth/AI_AGENT_SDK_REFERENCE.md +0 -1260
  110. package/templates/typescript-auth/README.md +0 -402
  111. package/templates/typescript-auth/package.json +0 -36
  112. package/templates/typescript-auth/src/app.module.ts +0 -103
  113. package/templates/typescript-auth/src/db/database.ts +0 -160
  114. package/templates/typescript-auth/src/db/seed.ts +0 -374
  115. package/templates/typescript-auth/src/db/setup.ts +0 -87
  116. package/templates/typescript-auth/src/events/analytics.service.ts +0 -52
  117. package/templates/typescript-auth/src/events/notification.service.ts +0 -40
  118. package/templates/typescript-auth/src/filters/global-exception.filter.ts +0 -28
  119. package/templates/typescript-auth/src/guards/README.md +0 -75
  120. package/templates/typescript-auth/src/guards/jwt.guard.ts +0 -105
  121. package/templates/typescript-auth/src/health/database.health.ts +0 -41
  122. package/templates/typescript-auth/src/index.ts +0 -29
  123. package/templates/typescript-auth/src/interceptors/transform.interceptor.ts +0 -24
  124. package/templates/typescript-auth/src/middleware/logging.middleware.ts +0 -42
  125. package/templates/typescript-auth/src/modules/addresses/addresses.module.ts +0 -16
  126. package/templates/typescript-auth/src/modules/addresses/addresses.prompts.ts +0 -114
  127. package/templates/typescript-auth/src/modules/addresses/addresses.resources.ts +0 -40
  128. package/templates/typescript-auth/src/modules/addresses/addresses.tools.ts +0 -284
  129. package/templates/typescript-auth/src/modules/auth/auth.module.ts +0 -16
  130. package/templates/typescript-auth/src/modules/auth/auth.prompts.ts +0 -147
  131. package/templates/typescript-auth/src/modules/auth/auth.resources.ts +0 -84
  132. package/templates/typescript-auth/src/modules/auth/auth.tools.ts +0 -139
  133. package/templates/typescript-auth/src/modules/cart/cart.module.ts +0 -16
  134. package/templates/typescript-auth/src/modules/cart/cart.prompts.ts +0 -95
  135. package/templates/typescript-auth/src/modules/cart/cart.resources.ts +0 -44
  136. package/templates/typescript-auth/src/modules/cart/cart.tools.ts +0 -277
  137. package/templates/typescript-auth/src/modules/orders/orders.module.ts +0 -16
  138. package/templates/typescript-auth/src/modules/orders/orders.prompts.ts +0 -88
  139. package/templates/typescript-auth/src/modules/orders/orders.resources.ts +0 -48
  140. package/templates/typescript-auth/src/modules/orders/orders.tools.ts +0 -303
  141. package/templates/typescript-auth/src/modules/products/products.module.ts +0 -16
  142. package/templates/typescript-auth/src/modules/products/products.prompts.ts +0 -146
  143. package/templates/typescript-auth/src/modules/products/products.resources.ts +0 -98
  144. package/templates/typescript-auth/src/modules/products/products.tools.ts +0 -266
  145. package/templates/typescript-auth/src/pipes/validation.pipe.ts +0 -42
  146. package/templates/typescript-auth/src/services/database.service.ts +0 -90
  147. package/templates/typescript-auth/src/widgets/app/add-to-cart/page.tsx +0 -122
  148. package/templates/typescript-auth/src/widgets/app/address-added/page.tsx +0 -116
  149. package/templates/typescript-auth/src/widgets/app/address-deleted/page.tsx +0 -105
  150. package/templates/typescript-auth/src/widgets/app/address-list/page.tsx +0 -139
  151. package/templates/typescript-auth/src/widgets/app/address-updated/page.tsx +0 -153
  152. package/templates/typescript-auth/src/widgets/app/cart-cleared/page.tsx +0 -86
  153. package/templates/typescript-auth/src/widgets/app/cart-updated/page.tsx +0 -116
  154. package/templates/typescript-auth/src/widgets/app/categories/page.tsx +0 -134
  155. package/templates/typescript-auth/src/widgets/app/layout.tsx +0 -21
  156. package/templates/typescript-auth/src/widgets/app/login-result/page.tsx +0 -129
  157. package/templates/typescript-auth/src/widgets/app/order-confirmation/page.tsx +0 -231
  158. package/templates/typescript-auth/src/widgets/app/order-details/page.tsx +0 -225
  159. package/templates/typescript-auth/src/widgets/app/order-history/page.tsx +0 -218
  160. package/templates/typescript-auth/src/widgets/app/product-card/page.tsx +0 -121
  161. package/templates/typescript-auth/src/widgets/app/products-grid/page.tsx +0 -198
  162. package/templates/typescript-auth/src/widgets/app/shopping-cart/page.tsx +0 -187
  163. package/templates/typescript-auth/src/widgets/app/whoami/page.tsx +0 -165
  164. package/templates/typescript-auth/src/widgets/next.config.js +0 -38
  165. package/templates/typescript-auth/src/widgets/package.json +0 -18
  166. package/templates/typescript-auth/src/widgets/styles/ecommerce.ts +0 -169
  167. package/templates/typescript-auth/src/widgets/tsconfig.json +0 -28
  168. package/templates/typescript-auth/src/widgets/types/tool-data.ts +0 -141
  169. package/templates/typescript-auth/src/widgets/widget-manifest.json +0 -464
  170. package/templates/typescript-auth/tsconfig.json +0 -27
  171. package/templates/typescript-auth-api-key/AI_AGENT_CLI_REFERENCE.md +0 -701
  172. package/templates/typescript-auth-api-key/AI_AGENT_SDK_REFERENCE.md +0 -1260
  173. package/templates/typescript-auth-api-key/README.md +0 -485
  174. package/templates/typescript-auth-api-key/package.json +0 -21
  175. package/templates/typescript-auth-api-key/src/app.module.ts +0 -38
  176. package/templates/typescript-auth-api-key/src/guards/apikey.guard.ts +0 -47
  177. package/templates/typescript-auth-api-key/src/guards/multi-auth.guard.ts +0 -157
  178. package/templates/typescript-auth-api-key/src/index.ts +0 -47
  179. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.module.ts +0 -12
  180. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.prompts.ts +0 -73
  181. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.resources.ts +0 -60
  182. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.tools.ts +0 -71
  183. package/templates/typescript-auth-api-key/src/modules/demo/demo.module.ts +0 -18
  184. package/templates/typescript-auth-api-key/src/modules/demo/demo.tools.ts +0 -155
  185. package/templates/typescript-auth-api-key/src/modules/demo/multi-auth.tools.ts +0 -123
  186. package/templates/typescript-auth-api-key/src/widgets/app/calculator-operations/page.tsx +0 -133
  187. package/templates/typescript-auth-api-key/src/widgets/app/calculator-result/page.tsx +0 -134
  188. package/templates/typescript-auth-api-key/src/widgets/app/layout.tsx +0 -14
  189. package/templates/typescript-auth-api-key/src/widgets/package.json +0 -24
  190. package/templates/typescript-auth-api-key/src/widgets/widget-manifest.json +0 -48
  191. package/templates/typescript-auth-api-key/tsconfig.json +0 -23
  192. package/templates/typescript-oauth/OAUTH_SETUP.md +0 -592
  193. package/templates/typescript-oauth/src/modules/demo/demo.module.ts +0 -16
  194. package/templates/typescript-oauth/src/modules/demo/demo.tools.ts +0 -190
  195. package/templates/typescript-oauth/src/widgets/app/calculator-operations/page.tsx +0 -133
  196. package/templates/typescript-oauth/src/widgets/app/calculator-result/page.tsx +0 -134
  197. package/templates/typescript-oauth/src/widgets/out/404.html +0 -1
  198. package/templates/typescript-oauth/src/widgets/out/_next/static/WU9THacVqL52RZbrZOLS1/_buildManifest.js +0 -1
  199. package/templates/typescript-oauth/src/widgets/out/_next/static/WU9THacVqL52RZbrZOLS1/_ssgManifest.js +0 -1
  200. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/117-eb57c7ef86f964a4.js +0 -2
  201. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/_not-found/page-dcb83ba3e4d0aafd.js +0 -1
  202. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/calculator-operations/page-b8913a740073ea8a.js +0 -1
  203. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/calculator-result/page-ddaaab2fce95dea2.js +0 -1
  204. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/layout-cbd3ebdc4ecc5247.js +0 -1
  205. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/fd9d1056-749e5812300142af.js +0 -1
  206. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/framework-f66176bb897dc684.js +0 -1
  207. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/main-76df43fcef3db344.js +0 -1
  208. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/main-app-f9c40224d04023c5.js +0 -1
  209. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/pages/_app-72b849fbd24ac258.js +0 -1
  210. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/pages/_error-7ba65e1336b92748.js +0 -1
  211. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
  212. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/webpack-100b9e646d9c912e.js +0 -1
  213. package/templates/typescript-oauth/src/widgets/out/calculator-operations.html +0 -1
  214. package/templates/typescript-oauth/src/widgets/out/calculator-operations.txt +0 -7
  215. package/templates/typescript-oauth/src/widgets/out/calculator-result.html +0 -1
  216. package/templates/typescript-oauth/src/widgets/out/calculator-result.txt +0 -7
  217. package/templates/typescript-starter/src/widgets/app/calculator-operations/page.tsx +0 -133
  218. /package/templates/{typescript-auth-api-key → typescript-oauth}/src/health/system.health.ts +0 -0
  219. /package/templates/{typescript-auth-api-key → typescript-pizzaz}/src/widgets/next.config.js +0 -0
  220. /package/templates/{typescript-auth-api-key → typescript-pizzaz}/src/widgets/tsconfig.json +0 -0
@@ -0,0 +1,374 @@
1
+ 'use client';
2
+
3
+ import { useTheme, useMaxHeight, useWidgetSDK } from 'nitrostack/widgets';
4
+
5
+ // Disable static generation - this is a dynamic widget
6
+ export const dynamic = 'force-dynamic';
7
+ import { Star, MapPin, Phone, Globe, Clock, Heart, Share2, Navigation } from 'lucide-react';
8
+
9
+ interface PizzaShop {
10
+ id: string;
11
+ name: string;
12
+ description: string;
13
+ address: string;
14
+ coords: [number, number];
15
+ rating: number;
16
+ reviews: number;
17
+ priceLevel: 1 | 2 | 3;
18
+ cuisine: string[];
19
+ hours: { open: string; close: string };
20
+ phone: string;
21
+ website?: string;
22
+ image: string;
23
+ specialties: string[];
24
+ openNow: boolean;
25
+ }
26
+
27
+ interface WidgetData {
28
+ shop: PizzaShop;
29
+ relatedShops: PizzaShop[];
30
+ }
31
+
32
+ export default function PizzaShopWidget() {
33
+ const theme = useTheme();
34
+ const maxHeight = useMaxHeight();
35
+ const isDark = theme === 'dark';
36
+ const { isReady, getToolOutput, openExternal } = useWidgetSDK();
37
+
38
+ // Access tool output
39
+ const data = getToolOutput<WidgetData>();
40
+
41
+ if (!data) {
42
+ return (
43
+ <div style={{
44
+ padding: '40px',
45
+ textAlign: 'center',
46
+ color: isDark ? '#fff' : '#000',
47
+ }}>
48
+ Loading shop details... {isReady ? '(SDK ready but no data)' : '(waiting for SDK)'}
49
+ </div>
50
+ );
51
+ }
52
+
53
+ const { shop, relatedShops } = data;
54
+ const priceSymbol = '$'.repeat(shop.priceLevel);
55
+
56
+ const openMaps = () => {
57
+ const url = `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(shop.address)}`;
58
+ openExternal(url);
59
+ };
60
+
61
+ const callPhone = () => {
62
+ openExternal(`tel:${shop.phone}`);
63
+ };
64
+
65
+ const visitWebsite = () => {
66
+ if (shop.website) {
67
+ openExternal(shop.website);
68
+ }
69
+ };
70
+
71
+ return (
72
+ <div style={{
73
+ background: isDark ? '#0a0a0a' : '#f9fafb',
74
+ minHeight: '100vh',
75
+ maxHeight: maxHeight || '100vh',
76
+ overflow: 'auto',
77
+ }}>
78
+ {/* Hero Image */}
79
+ <div style={{ position: 'relative', height: '300px', overflow: 'hidden' }}>
80
+ <img
81
+ src={shop.image}
82
+ alt={shop.name}
83
+ style={{
84
+ width: '100%',
85
+ height: '100%',
86
+ objectFit: 'cover',
87
+ }}
88
+ />
89
+ <div style={{
90
+ position: 'absolute',
91
+ inset: 0,
92
+ background: 'linear-gradient(to top, rgba(0,0,0,0.7), transparent)',
93
+ }} />
94
+
95
+ {/* Shop Name Overlay */}
96
+ <div style={{
97
+ position: 'absolute',
98
+ bottom: '24px',
99
+ left: '24px',
100
+ right: '24px',
101
+ }}>
102
+ <h1 style={{
103
+ margin: '0 0 8px 0',
104
+ fontSize: '32px',
105
+ fontWeight: '700',
106
+ color: '#fff',
107
+ textShadow: '0 2px 4px rgba(0,0,0,0.5)',
108
+ }}>
109
+ {shop.name}
110
+ </h1>
111
+ <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
112
+ <div style={{ display: 'flex', alignItems: 'center', gap: '6px' }}>
113
+ <Star size={20} fill="#fbbf24" stroke="#fbbf24" />
114
+ <span style={{ fontSize: '18px', fontWeight: '600', color: '#fff' }}>
115
+ {shop.rating}
116
+ </span>
117
+ <span style={{ fontSize: '14px', color: '#ccc' }}>
118
+ ({shop.reviews} reviews)
119
+ </span>
120
+ </div>
121
+ <span style={{ fontSize: '16px', color: '#fff' }}>{priceSymbol}</span>
122
+ {shop.openNow && (
123
+ <span style={{
124
+ background: '#10b981',
125
+ color: 'white',
126
+ padding: '4px 12px',
127
+ borderRadius: '12px',
128
+ fontSize: '14px',
129
+ fontWeight: '600',
130
+ }}>
131
+ Open Now
132
+ </span>
133
+ )}
134
+ </div>
135
+ </div>
136
+ </div>
137
+
138
+ {/* Content */}
139
+ <div style={{ padding: '24px' }}>
140
+ {/* Description */}
141
+ <p style={{
142
+ margin: '0 0 24px 0',
143
+ fontSize: '16px',
144
+ lineHeight: '1.6',
145
+ color: isDark ? '#ccc' : '#666',
146
+ }}>
147
+ {shop.description}
148
+ </p>
149
+
150
+ {/* Cuisine Tags */}
151
+ <div style={{ marginBottom: '24px' }}>
152
+ <h3 style={{
153
+ margin: '0 0 12px 0',
154
+ fontSize: '14px',
155
+ fontWeight: '600',
156
+ color: isDark ? '#999' : '#666',
157
+ textTransform: 'uppercase',
158
+ letterSpacing: '0.5px',
159
+ }}>
160
+ Cuisine
161
+ </h3>
162
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
163
+ {shop.cuisine.map(c => (
164
+ <span
165
+ key={c}
166
+ style={{
167
+ background: isDark ? '#1a1a1a' : '#f3f4f6',
168
+ color: isDark ? '#fff' : '#111',
169
+ padding: '8px 16px',
170
+ borderRadius: '20px',
171
+ fontSize: '14px',
172
+ fontWeight: '500',
173
+ border: `1px solid ${isDark ? '#333' : '#e5e7eb'}`,
174
+ }}
175
+ >
176
+ {c}
177
+ </span>
178
+ ))}
179
+ </div>
180
+ </div>
181
+
182
+ {/* Specialties */}
183
+ <div style={{ marginBottom: '24px' }}>
184
+ <h3 style={{
185
+ margin: '0 0 12px 0',
186
+ fontSize: '14px',
187
+ fontWeight: '600',
188
+ color: isDark ? '#999' : '#666',
189
+ textTransform: 'uppercase',
190
+ letterSpacing: '0.5px',
191
+ }}>
192
+ Specialties
193
+ </h3>
194
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
195
+ {shop.specialties.map(s => (
196
+ <span
197
+ key={s}
198
+ style={{
199
+ background: isDark ? '#1a1a1a' : '#fef3c7',
200
+ color: isDark ? '#fbbf24' : '#92400e',
201
+ padding: '8px 16px',
202
+ borderRadius: '20px',
203
+ fontSize: '14px',
204
+ fontWeight: '500',
205
+ border: `1px solid ${isDark ? '#333' : '#fbbf24'}`,
206
+ }}
207
+ >
208
+ 🍕 {s}
209
+ </span>
210
+ ))}
211
+ </div>
212
+ </div>
213
+
214
+ {/* Contact Info */}
215
+ <div style={{
216
+ background: isDark ? '#1a1a1a' : '#fff',
217
+ border: `1px solid ${isDark ? '#333' : '#e5e7eb'}`,
218
+ borderRadius: '12px',
219
+ padding: '20px',
220
+ marginBottom: '24px',
221
+ }}>
222
+ <h3 style={{
223
+ margin: '0 0 16px 0',
224
+ fontSize: '18px',
225
+ fontWeight: '600',
226
+ color: isDark ? '#fff' : '#111',
227
+ }}>
228
+ Contact & Hours
229
+ </h3>
230
+
231
+ {/* Address */}
232
+ <div style={{ display: 'flex', alignItems: 'start', gap: '12px', marginBottom: '12px' }}>
233
+ <MapPin size={20} style={{ color: isDark ? '#999' : '#666', marginTop: '2px', flexShrink: 0 }} />
234
+ <div style={{ flex: 1 }}>
235
+ <p style={{ margin: '0 0 8px 0', fontSize: '14px', color: isDark ? '#ccc' : '#666' }}>
236
+ {shop.address}
237
+ </p>
238
+ <button
239
+ onClick={openMaps}
240
+ style={{
241
+ padding: '6px 12px',
242
+ background: isDark ? '#333' : '#f3f4f6',
243
+ border: 'none',
244
+ borderRadius: '6px',
245
+ fontSize: '13px',
246
+ color: isDark ? '#fff' : '#111',
247
+ cursor: 'pointer',
248
+ display: 'flex',
249
+ alignItems: 'center',
250
+ gap: '6px',
251
+ }}
252
+ >
253
+ <Navigation size={14} />
254
+ Get Directions
255
+ </button>
256
+ </div>
257
+ </div>
258
+
259
+ {/* Phone */}
260
+ <div style={{ display: 'flex', alignItems: 'center', gap: '12px', marginBottom: '12px' }}>
261
+ <Phone size={20} style={{ color: isDark ? '#999' : '#666' }} />
262
+ <button
263
+ onClick={callPhone}
264
+ style={{
265
+ background: 'none',
266
+ border: 'none',
267
+ fontSize: '14px',
268
+ color: isDark ? '#60a5fa' : '#2563eb',
269
+ cursor: 'pointer',
270
+ textDecoration: 'underline',
271
+ }}
272
+ >
273
+ {shop.phone}
274
+ </button>
275
+ </div>
276
+
277
+ {/* Website */}
278
+ {shop.website && (
279
+ <div style={{ display: 'flex', alignItems: 'center', gap: '12px', marginBottom: '12px' }}>
280
+ <Globe size={20} style={{ color: isDark ? '#999' : '#666' }} />
281
+ <button
282
+ onClick={visitWebsite}
283
+ style={{
284
+ background: 'none',
285
+ border: 'none',
286
+ fontSize: '14px',
287
+ color: isDark ? '#60a5fa' : '#2563eb',
288
+ cursor: 'pointer',
289
+ textDecoration: 'underline',
290
+ }}
291
+ >
292
+ Visit Website
293
+ </button>
294
+ </div>
295
+ )}
296
+
297
+ {/* Hours */}
298
+ <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
299
+ <Clock size={20} style={{ color: isDark ? '#999' : '#666' }} />
300
+ <span style={{ fontSize: '14px', color: isDark ? '#ccc' : '#666' }}>
301
+ {shop.hours.open} - {shop.hours.close}
302
+ </span>
303
+ </div>
304
+ </div>
305
+
306
+ {/* Related Shops */}
307
+ {relatedShops.length > 0 && (
308
+ <div>
309
+ <h3 style={{
310
+ margin: '0 0 16px 0',
311
+ fontSize: '18px',
312
+ fontWeight: '600',
313
+ color: isDark ? '#fff' : '#111',
314
+ }}>
315
+ You Might Also Like
316
+ </h3>
317
+ <div style={{ display: 'grid', gap: '12px' }}>
318
+ {relatedShops.map(related => (
319
+ <div
320
+ key={related.id}
321
+ style={{
322
+ background: isDark ? '#1a1a1a' : '#fff',
323
+ border: `1px solid ${isDark ? '#333' : '#e5e7eb'}`,
324
+ borderRadius: '12px',
325
+ padding: '16px',
326
+ display: 'flex',
327
+ gap: '16px',
328
+ }}
329
+ >
330
+ <img
331
+ src={related.image}
332
+ alt={related.name}
333
+ style={{
334
+ width: '80px',
335
+ height: '80px',
336
+ borderRadius: '8px',
337
+ objectFit: 'cover',
338
+ }}
339
+ />
340
+ <div style={{ flex: 1 }}>
341
+ <h4 style={{
342
+ margin: '0 0 4px 0',
343
+ fontSize: '16px',
344
+ fontWeight: '600',
345
+ color: isDark ? '#fff' : '#111',
346
+ }}>
347
+ {related.name}
348
+ </h4>
349
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '4px' }}>
350
+ <Star size={14} fill="#fbbf24" stroke="#fbbf24" />
351
+ <span style={{ fontSize: '14px', color: isDark ? '#ccc' : '#666' }}>
352
+ {related.rating}
353
+ </span>
354
+ </div>
355
+ <p style={{
356
+ margin: 0,
357
+ fontSize: '13px',
358
+ color: isDark ? '#999' : '#666',
359
+ overflow: 'hidden',
360
+ textOverflow: 'ellipsis',
361
+ whiteSpace: 'nowrap',
362
+ }}>
363
+ {related.description}
364
+ </p>
365
+ </div>
366
+ </div>
367
+ ))}
368
+ </div>
369
+ </div>
370
+ )}
371
+ </div>
372
+ </div>
373
+ );
374
+ }
@@ -0,0 +1,144 @@
1
+ 'use client';
2
+
3
+ interface PizzaShop {
4
+ id: string;
5
+ name: string;
6
+ description: string;
7
+ address: string;
8
+ coords: [number, number];
9
+ rating: number;
10
+ reviews: number;
11
+ priceLevel: 1 | 2 | 3;
12
+ cuisine: string[];
13
+ hours: { open: string; close: string };
14
+ phone: string;
15
+ website?: string;
16
+ image: string;
17
+ specialties: string[];
18
+ openNow: boolean;
19
+ }
20
+
21
+ interface CompactShopCardProps {
22
+ shop: PizzaShop;
23
+ isSelected: boolean;
24
+ onClick: () => void;
25
+ isDark?: boolean;
26
+ }
27
+
28
+ export function CompactShopCard({ shop, isSelected, onClick, isDark = true }: CompactShopCardProps) {
29
+ const priceSymbol = '$'.repeat(shop.priceLevel);
30
+
31
+ return (
32
+ <div
33
+ onClick={onClick}
34
+ style={{
35
+ display: 'flex',
36
+ gap: '12px',
37
+ padding: '12px',
38
+ background: isSelected
39
+ ? 'rgba(255, 255, 255, 0.95)'
40
+ : 'rgba(255, 255, 255, 0.9)',
41
+ backdropFilter: 'blur(10px)',
42
+ borderRadius: '12px',
43
+ cursor: 'pointer',
44
+ transition: 'all 0.2s',
45
+ border: isSelected ? '2px solid #3b82f6' : '2px solid transparent',
46
+ boxShadow: isSelected
47
+ ? '0 4px 12px rgba(59, 130, 246, 0.3)'
48
+ : '0 2px 8px rgba(0, 0, 0, 0.1)',
49
+ minWidth: '280px',
50
+ maxWidth: '280px',
51
+ }}
52
+ onMouseEnter={(e) => {
53
+ if (!isSelected) {
54
+ e.currentTarget.style.transform = 'translateY(-2px)';
55
+ e.currentTarget.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.15)';
56
+ }
57
+ }}
58
+ onMouseLeave={(e) => {
59
+ if (!isSelected) {
60
+ e.currentTarget.style.transform = 'translateY(0)';
61
+ e.currentTarget.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.1)';
62
+ }
63
+ }}
64
+ >
65
+ {/* Image */}
66
+ <img
67
+ src={shop.image}
68
+ alt={shop.name}
69
+ style={{
70
+ width: '80px',
71
+ height: '80px',
72
+ borderRadius: '8px',
73
+ objectFit: 'cover',
74
+ flexShrink: 0,
75
+ }}
76
+ />
77
+
78
+ {/* Info */}
79
+ <div style={{
80
+ flex: 1,
81
+ display: 'flex',
82
+ flexDirection: 'column',
83
+ justifyContent: 'space-between',
84
+ minWidth: 0,
85
+ }}>
86
+ {/* Name */}
87
+ <h4 style={{
88
+ margin: 0,
89
+ fontSize: '14px',
90
+ fontWeight: '600',
91
+ color: '#111',
92
+ overflow: 'hidden',
93
+ textOverflow: 'ellipsis',
94
+ whiteSpace: 'nowrap',
95
+ }}>
96
+ {shop.name}
97
+ </h4>
98
+
99
+ {/* Description */}
100
+ <p style={{
101
+ margin: '4px 0',
102
+ fontSize: '12px',
103
+ color: '#666',
104
+ overflow: 'hidden',
105
+ textOverflow: 'ellipsis',
106
+ whiteSpace: 'nowrap',
107
+ }}>
108
+ {shop.description}
109
+ </p>
110
+
111
+ {/* Rating & Price */}
112
+ <div style={{
113
+ display: 'flex',
114
+ alignItems: 'center',
115
+ gap: '8px',
116
+ fontSize: '12px',
117
+ }}>
118
+ <div style={{
119
+ display: 'flex',
120
+ alignItems: 'center',
121
+ gap: '4px',
122
+ }}>
123
+ <span style={{ color: '#fbbf24' }}>⭐</span>
124
+ <span style={{ fontWeight: '600', color: '#111' }}>{shop.rating}</span>
125
+ </div>
126
+ <span style={{ color: '#999' }}>•</span>
127
+ <span style={{ color: '#666' }}>{priceSymbol}</span>
128
+ {shop.openNow && (
129
+ <>
130
+ <span style={{ color: '#999' }}>•</span>
131
+ <span style={{
132
+ color: '#10b981',
133
+ fontWeight: '600',
134
+ fontSize: '11px',
135
+ }}>
136
+ Open Now
137
+ </span>
138
+ </>
139
+ )}
140
+ </div>
141
+ </div>
142
+ </div>
143
+ );
144
+ }