version-pill-react 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -70,39 +70,17 @@ var SIZE_CONFIG = {
70
70
  md: { height: 26, padding: "0 10px", gap: 5, font: 11, dotSize: 6 },
71
71
  lg: { height: 30, padding: "0 12px", gap: 6, font: 12, dotSize: 7 }
72
72
  };
73
- var styles = {
74
- pill: `
75
- inline-flex items-center gap-1.5 px-2.5 py-1
76
- text-xs font-medium rounded-full cursor-pointer
77
- transition-all duration-200 select-none
78
- border shadow-sm hover:shadow-md
79
- `,
80
- pillLight: `bg-white text-gray-700 border-gray-200 hover:border-gray-300`,
81
- pillDark: `bg-gray-900 text-gray-100 border-gray-700 hover:border-gray-600`,
82
- modal: `fixed inset-0 z-[99999] flex items-center justify-center p-4`,
83
- backdrop: `absolute inset-0 bg-black/50 backdrop-blur-sm`,
84
- panel: `relative w-full max-w-md max-h-[80vh] overflow-hidden rounded-xl shadow-2xl`,
85
- panelLight: `bg-white`,
86
- panelDark: `bg-gray-900`,
87
- header: `p-4 border-b flex items-center justify-between`,
88
- headerLight: `border-gray-100`,
89
- headerDark: `border-gray-800`,
90
- content: `p-4 overflow-y-auto max-h-[60vh]`,
91
- version: `mb-4 last:mb-0`,
92
- versionHeader: `flex items-center gap-2 mb-2`,
93
- versionTitle: `font-semibold`,
94
- versionBadge: `px-1.5 py-0.5 text-[10px] font-medium rounded`,
95
- versionFeatures: `space-y-1 mt-2`,
96
- versionFeature: `flex items-start gap-2 text-sm`,
97
- footer: `p-3 border-t flex items-center justify-between`,
98
- footerLight: `border-gray-100 bg-gray-50`,
99
- footerDark: `border-gray-800 bg-gray-950`,
100
- button: `px-3 py-1.5 text-xs font-medium rounded-lg transition-colors`,
101
- buttonPrimary: `bg-blue-600 text-white hover:bg-blue-700`,
102
- buttonSecondary: `text-gray-500 hover:text-gray-700`,
103
- branding: `text-[10px] opacity-40 flex items-center gap-1`,
104
- newDot: `w-2 h-2 rounded-full bg-green-500 animate-pulse`,
105
- iframe: `w-full border-0`
73
+ var TYPE_COLORS = {
74
+ feature: "#a855f7",
75
+ bug: "#ef4444",
76
+ improvement: "#3b82f6",
77
+ chore: "#71717a"
78
+ };
79
+ var COLUMN_LABELS = {
80
+ backlog: "Backlog",
81
+ todo: "Planned",
82
+ "in-progress": "In Progress",
83
+ done: "Shipped"
106
84
  };
107
85
  function useTheme(theme) {
108
86
  const [resolved, setResolved] = (0, import_react.useState)("light");
@@ -126,7 +104,7 @@ function VersionPill({
126
104
  position = "inline",
127
105
  className,
128
106
  theme = "auto",
129
- style = "dot",
107
+ style = "gradient",
130
108
  size = "md",
131
109
  showBranding = true,
132
110
  accent = "green",
@@ -135,13 +113,14 @@ function VersionPill({
135
113
  }) {
136
114
  const [project, setProject] = (0, import_react.useState)(null);
137
115
  const [versions, setVersions] = (0, import_react.useState)([]);
116
+ const [roadmapTasks, setRoadmapTasks] = (0, import_react.useState)([]);
117
+ const [ideas, setIdeas] = (0, import_react.useState)([]);
138
118
  const [loading, setLoading] = (0, import_react.useState)(true);
139
- const [error, setError] = (0, import_react.useState)(null);
140
119
  const [isOpen, setIsOpen] = (0, import_react.useState)(false);
120
+ const [activeTab, setActiveTab] = (0, import_react.useState)("changelog");
141
121
  const [hasNewVersion, setHasNewVersion] = (0, import_react.useState)(false);
142
122
  const resolvedTheme = useTheme(theme);
143
123
  const isLight = resolvedTheme === "light";
144
- const colors = ACCENT_COLORS[accent][isLight ? "light" : "dark"];
145
124
  const sizeConfig = SIZE_CONFIG[size];
146
125
  const fetchVersion = (0, import_react.useCallback)(async () => {
147
126
  try {
@@ -156,7 +135,7 @@ function VersionPill({
156
135
  }
157
136
  }
158
137
  } catch (err) {
159
- setError(err.message);
138
+ console.error("Failed to fetch version:", err);
160
139
  } finally {
161
140
  setLoading(false);
162
141
  }
@@ -164,7 +143,7 @@ function VersionPill({
164
143
  const fetchChangelog = (0, import_react.useCallback)(async () => {
165
144
  try {
166
145
  const response = await fetch(`${baseUrl}/api/changelog/${projectId}?limit=10`);
167
- if (!response.ok) throw new Error("Failed to fetch changelog");
146
+ if (!response.ok) return;
168
147
  const data = await response.json();
169
148
  setVersions(data.changelog);
170
149
  setProject(data.project);
@@ -179,6 +158,26 @@ function VersionPill({
179
158
  console.error("Failed to fetch changelog:", err);
180
159
  }
181
160
  }, [projectId, baseUrl, onNewVersion]);
161
+ const fetchRoadmap = (0, import_react.useCallback)(async () => {
162
+ try {
163
+ const response = await fetch(`${baseUrl}/api/roadmap/${projectId}`);
164
+ if (!response.ok) return;
165
+ const data = await response.json();
166
+ setRoadmapTasks(data.tasks || []);
167
+ } catch (err) {
168
+ console.error("Failed to fetch roadmap:", err);
169
+ }
170
+ }, [projectId, baseUrl]);
171
+ const fetchIdeas = (0, import_react.useCallback)(async () => {
172
+ try {
173
+ const response = await fetch(`${baseUrl}/api/ideas/${projectId}`);
174
+ if (!response.ok) return;
175
+ const data = await response.json();
176
+ setIdeas(data.ideas || []);
177
+ } catch (err) {
178
+ console.error("Failed to fetch ideas:", err);
179
+ }
180
+ }, [projectId, baseUrl]);
182
181
  (0, import_react.useEffect)(() => {
183
182
  fetchVersion();
184
183
  }, [fetchVersion]);
@@ -189,6 +188,8 @@ function VersionPill({
189
188
  }
190
189
  setIsOpen(true);
191
190
  fetchChangelog();
191
+ fetchRoadmap();
192
+ fetchIdeas();
192
193
  if (project?.currentVersion) {
193
194
  localStorage.setItem(`vp_${projectId}_seen`, project.currentVersion);
194
195
  setHasNewVersion(false);
@@ -216,9 +217,8 @@ function VersionPill({
216
217
  fontFamily: "ui-monospace, monospace",
217
218
  fontWeight: 500,
218
219
  borderRadius: 999,
219
- background: colors.bg,
220
- border: `1px solid ${colors.border}`,
221
- color: colors.text,
220
+ background: "linear-gradient(135deg, #22c55e 0%, #16a34a 100%)",
221
+ color: "#fff",
222
222
  opacity: 0.6
223
223
  },
224
224
  children: [
@@ -229,286 +229,371 @@ function VersionPill({
229
229
  width: sizeConfig.dotSize,
230
230
  height: sizeConfig.dotSize,
231
231
  borderRadius: "50%",
232
- background: colors.dot,
233
- opacity: 0.4
232
+ background: "#fff",
233
+ opacity: 0.6
234
234
  }
235
235
  }
236
236
  ),
237
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { width: 32, height: sizeConfig.font, background: colors.border, borderRadius: 2 } })
237
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { width: 32, height: sizeConfig.font, background: "rgba(255,255,255,0.3)", borderRadius: 2 } })
238
238
  ]
239
239
  }
240
240
  ) });
241
241
  }
242
- if (error || !currentVersion) return null;
242
+ if (!currentVersion) return null;
243
243
  const renderBadge = () => {
244
- const baseButtonStyle = {
245
- display: "inline-flex",
246
- alignItems: "center",
247
- gap: sizeConfig.gap,
248
- height: sizeConfig.height,
249
- padding: sizeConfig.padding,
250
- fontSize: sizeConfig.font,
251
- fontFamily: "ui-monospace, monospace",
252
- fontWeight: 600,
253
- borderRadius: 999,
254
- cursor: "pointer",
255
- border: "none",
256
- transition: "all 150ms ease",
257
- outline: "none"
258
- };
259
- switch (style) {
260
- case "glass":
261
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
262
- "button",
263
- {
264
- onClick: handleOpen,
265
- style: {
266
- ...baseButtonStyle,
267
- background: isLight ? "rgba(255,255,255,0.7)" : "rgba(255,255,255,0.1)",
268
- backdropFilter: "blur(12px)",
269
- WebkitBackdropFilter: "blur(12px)",
270
- border: `1px solid ${isLight ? "rgba(255,255,255,0.8)" : "rgba(255,255,255,0.15)"}`,
271
- boxShadow: "0 4px 12px rgba(0,0,0,0.08), inset 0 1px 0 rgba(255,255,255,0.2)",
272
- color: isLight ? "#374151" : "#f3f4f6"
273
- },
274
- children: [
275
- hasNewVersion && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PulseDot, { color: colors.dot, size: sizeConfig.dotSize }),
276
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
277
- "v",
278
- currentVersion
279
- ] })
280
- ]
281
- }
282
- );
283
- case "gradient":
284
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
285
- "button",
286
- {
287
- onClick: handleOpen,
288
- style: {
289
- ...baseButtonStyle,
290
- background: "linear-gradient(135deg, #22c55e 0%, #16a34a 100%)",
291
- color: "#fff",
292
- boxShadow: "0 4px 12px rgba(34,197,94,0.3)"
293
- },
294
- children: [
295
- hasNewVersion && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PulseDot, { color: "#fff", size: sizeConfig.dotSize }),
296
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
297
- "v",
298
- currentVersion
299
- ] })
300
- ]
301
- }
302
- );
303
- case "pill":
304
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
305
- "button",
306
- {
307
- onClick: handleOpen,
308
- style: {
309
- ...baseButtonStyle,
310
- background: colors.bg,
311
- border: `1px solid ${colors.border}`,
312
- color: colors.text,
313
- boxShadow: `0 0 0 0 ${colors.dot}`
314
- },
315
- onMouseEnter: (e) => {
316
- e.currentTarget.style.boxShadow = `0 0 12px 2px ${colors.dot}40`;
317
- },
318
- onMouseLeave: (e) => {
319
- e.currentTarget.style.boxShadow = `0 0 0 0 ${colors.dot}`;
320
- },
321
- children: [
322
- hasNewVersion && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PulseDot, { color: colors.dot, size: sizeConfig.dotSize }),
323
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
324
- "v",
325
- currentVersion
326
- ] })
327
- ]
328
- }
329
- );
330
- case "minimal":
331
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
332
- "button",
333
- {
334
- onClick: handleOpen,
335
- style: {
336
- ...baseButtonStyle,
337
- background: "transparent",
338
- padding: 0,
339
- height: "auto",
340
- color: colors.text
341
- },
342
- children: [
343
- hasNewVersion && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PulseDot, { color: colors.dot, size: sizeConfig.dotSize }),
344
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
345
- "v",
346
- currentVersion
347
- ] })
348
- ]
349
- }
350
- );
351
- case "dot":
352
- default:
353
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
354
- "button",
355
- {
356
- onClick: handleOpen,
357
- style: {
358
- ...baseButtonStyle,
359
- background: colors.bg,
360
- border: `1px solid ${colors.border}`,
361
- color: colors.text
362
- },
363
- children: [
364
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
365
- "span",
366
- {
367
- style: {
368
- width: sizeConfig.dotSize,
369
- height: sizeConfig.dotSize,
370
- borderRadius: "50%",
371
- background: colors.dot,
372
- flexShrink: 0
373
- }
374
- }
375
- ),
376
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
377
- "v",
378
- currentVersion
379
- ] })
380
- ]
381
- }
382
- );
383
- }
384
- };
385
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
386
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_clsx.default)(positionStyles[position], className), style: { display: "inline-flex" }, children: renderBadge() }),
387
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.modal, children: [
388
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.backdrop, onClick: () => setIsOpen(false) }),
389
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_clsx.default)(styles.panel, isLight ? styles.panelLight : styles.panelDark), children: [
390
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_clsx.default)(styles.header, isLight ? styles.headerLight : styles.headerDark), children: [
391
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10 }, children: [
392
- project?.icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 20 }, children: project.icon }),
393
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
394
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: (0, import_clsx.default)("font-semibold", isLight ? "text-gray-900" : "text-white"), children: project?.name || "What's New" }),
395
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: (0, import_clsx.default)("text-xs", isLight ? "text-gray-500" : "text-gray-400"), children: "Latest updates" })
396
- ] })
397
- ] }),
244
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
245
+ "button",
246
+ {
247
+ onClick: handleOpen,
248
+ style: {
249
+ display: "inline-flex",
250
+ alignItems: "center",
251
+ gap: sizeConfig.gap,
252
+ height: sizeConfig.height,
253
+ padding: sizeConfig.padding,
254
+ fontSize: sizeConfig.font,
255
+ fontFamily: "ui-monospace, monospace",
256
+ fontWeight: 600,
257
+ borderRadius: 999,
258
+ cursor: "pointer",
259
+ border: "none",
260
+ transition: "all 150ms ease",
261
+ outline: "none",
262
+ background: "linear-gradient(135deg, #22c55e 0%, #16a34a 100%)",
263
+ color: "#fff",
264
+ boxShadow: "0 2px 8px rgba(34,197,94,0.3)"
265
+ },
266
+ onMouseEnter: (e) => {
267
+ e.currentTarget.style.boxShadow = "0 4px 12px rgba(34,197,94,0.4)";
268
+ },
269
+ onMouseLeave: (e) => {
270
+ e.currentTarget.style.boxShadow = "0 2px 8px rgba(34,197,94,0.3)";
271
+ },
272
+ children: [
398
273
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
399
- "button",
274
+ "span",
400
275
  {
401
- onClick: () => setIsOpen(false),
402
- className: (0, import_clsx.default)("p-1 rounded hover:bg-gray-100", !isLight && "hover:bg-gray-800"),
403
- style: { background: "transparent", border: "none", cursor: "pointer", color: isLight ? "#374151" : "#9ca3af" },
404
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M18 6L6 18M6 6l12 12" }) })
405
- }
406
- )
407
- ] }),
408
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.content, children: versions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { textAlign: "center", padding: 40, color: isLight ? "#6b7280" : "#9ca3af" }, children: [
409
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 32, marginBottom: 8 }, children: "\u{1F680}" }),
410
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: "No releases yet" })
411
- ] }) : versions.slice(0, 5).map((version, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.version, children: [
412
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.versionHeader, children: [
413
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 16 }, children: version.emoji || "\u{1F4E6}" }),
414
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: (0, import_clsx.default)(styles.versionTitle, isLight ? "text-gray-900" : "text-white"), children: version.title }),
415
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
416
- "span",
417
- {
418
- className: (0, import_clsx.default)(
419
- styles.versionBadge,
420
- version.type === "major" ? "bg-purple-100 text-purple-700" : version.type === "minor" ? "bg-blue-100 text-blue-700" : "bg-gray-100 text-gray-700"
421
- ),
422
- children: version.type
276
+ style: {
277
+ width: sizeConfig.dotSize,
278
+ height: sizeConfig.dotSize,
279
+ borderRadius: "50%",
280
+ background: "#fff",
281
+ boxShadow: "0 0 6px rgba(255,255,255,0.8)",
282
+ flexShrink: 0
423
283
  }
424
- )
425
- ] }),
426
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_clsx.default)("text-xs mb-2", isLight ? "text-gray-500" : "text-gray-400"), children: [
284
+ }
285
+ ),
286
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
427
287
  "v",
428
- version.version,
429
- " \xB7 ",
430
- new Date(version.date).toLocaleDateString()
288
+ currentVersion
431
289
  ] }),
432
- version.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: (0, import_clsx.default)("text-sm mb-2", isLight ? "text-gray-600" : "text-gray-300"), children: version.description }),
433
- version.features && version.features.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: styles.versionFeatures, children: version.features.map((feature, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: (0, import_clsx.default)(styles.versionFeature, isLight ? "text-gray-600" : "text-gray-300"), children: [
434
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "#22c55e", marginTop: 2 }, children: "\u2713" }),
435
- feature
436
- ] }, i)) })
437
- ] }, idx)) }),
438
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_clsx.default)(styles.footer, isLight ? styles.footerLight : styles.footerDark), children: [
439
- showBranding && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
440
- "a",
290
+ hasNewVersion && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
291
+ "span",
441
292
  {
442
- href: "https://versionpill.com",
443
- target: "_blank",
444
- rel: "noopener noreferrer",
445
- className: (0, import_clsx.default)(styles.branding, isLight ? "text-gray-400" : "text-gray-500"),
446
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Powered by Version Pill" })
293
+ style: {
294
+ width: 6,
295
+ height: 6,
296
+ borderRadius: "50%",
297
+ background: "#fbbf24",
298
+ marginLeft: 2
299
+ }
447
300
  }
448
- ),
449
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
450
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
451
- "a",
301
+ )
302
+ ]
303
+ }
304
+ );
305
+ };
306
+ const groupedTasks = roadmapTasks.reduce((acc, task) => {
307
+ const col = task.column || "backlog";
308
+ if (!acc[col]) acc[col] = [];
309
+ acc[col].push(task);
310
+ return acc;
311
+ }, {});
312
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
313
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_clsx.default)(positionStyles[position], className), style: { display: "inline-flex" }, children: renderBadge() }),
314
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
315
+ position: "fixed",
316
+ inset: 0,
317
+ zIndex: 99999,
318
+ display: "flex",
319
+ alignItems: "center",
320
+ justifyContent: "center",
321
+ padding: 16
322
+ }, children: [
323
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
324
+ "div",
325
+ {
326
+ onClick: () => setIsOpen(false),
327
+ style: {
328
+ position: "absolute",
329
+ inset: 0,
330
+ background: "rgba(0,0,0,0.5)",
331
+ backdropFilter: "blur(4px)"
332
+ }
333
+ }
334
+ ),
335
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
336
+ "div",
337
+ {
338
+ style: {
339
+ position: "relative",
340
+ width: "100%",
341
+ maxWidth: 480,
342
+ maxHeight: "80vh",
343
+ overflow: "hidden",
344
+ borderRadius: 16,
345
+ boxShadow: "0 25px 50px -12px rgba(0,0,0,0.25)",
346
+ background: isLight ? "#fff" : "#18181b"
347
+ },
348
+ children: [
349
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
350
+ "div",
452
351
  {
453
- href: `${baseUrl}/${projectId}/roadmap`,
454
- target: "_blank",
455
- rel: "noopener noreferrer",
456
- className: (0, import_clsx.default)(styles.button, styles.buttonSecondary),
457
- children: "\u{1F4A1} Roadmap"
352
+ style: {
353
+ padding: 16,
354
+ borderBottom: `1px solid ${isLight ? "#f4f4f5" : "#27272a"}`,
355
+ display: "flex",
356
+ alignItems: "center",
357
+ justifyContent: "space-between"
358
+ },
359
+ children: [
360
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10 }, children: [
361
+ project?.icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 20 }, children: project.icon }),
362
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
363
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: { fontWeight: 600, color: isLight ? "#18181b" : "#fff", margin: 0 }, children: project?.name || "What's New" }),
364
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: { fontSize: 12, color: isLight ? "#71717a" : "#a1a1aa", margin: 0 }, children: [
365
+ "v",
366
+ currentVersion
367
+ ] })
368
+ ] })
369
+ ] }),
370
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
371
+ "button",
372
+ {
373
+ onClick: () => setIsOpen(false),
374
+ style: {
375
+ padding: 4,
376
+ borderRadius: 6,
377
+ background: "transparent",
378
+ border: "none",
379
+ cursor: "pointer",
380
+ color: isLight ? "#71717a" : "#a1a1aa"
381
+ },
382
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M18 6L6 18M6 6l12 12" }) })
383
+ }
384
+ )
385
+ ]
458
386
  }
459
387
  ),
460
388
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
461
- "a",
389
+ "div",
462
390
  {
463
- href: `${baseUrl}/${projectId}/changelog`,
464
- target: "_blank",
465
- rel: "noopener noreferrer",
466
- className: (0, import_clsx.default)(styles.button, styles.buttonPrimary),
467
- children: "View All"
391
+ style: {
392
+ display: "flex",
393
+ gap: 4,
394
+ padding: "8px 16px",
395
+ borderBottom: `1px solid ${isLight ? "#f4f4f5" : "#27272a"}`
396
+ },
397
+ children: ["changelog", "roadmap", "ideas"].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
398
+ "button",
399
+ {
400
+ onClick: () => setActiveTab(tab),
401
+ style: {
402
+ padding: "6px 12px",
403
+ borderRadius: 6,
404
+ border: "none",
405
+ cursor: "pointer",
406
+ fontSize: 13,
407
+ fontWeight: 500,
408
+ background: activeTab === tab ? isLight ? "#f4f4f5" : "#27272a" : "transparent",
409
+ color: activeTab === tab ? isLight ? "#18181b" : "#fff" : isLight ? "#71717a" : "#a1a1aa"
410
+ },
411
+ children: [
412
+ tab === "changelog" && "\u{1F680} Changelog",
413
+ tab === "roadmap" && "\u{1F5FA}\uFE0F Roadmap",
414
+ tab === "ideas" && "\u{1F4A1} Ideas"
415
+ ]
416
+ },
417
+ tab
418
+ ))
419
+ }
420
+ ),
421
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: 16, overflowY: "auto", maxHeight: "50vh" }, children: [
422
+ activeTab === "changelog" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: versions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { textAlign: "center", padding: 40, color: isLight ? "#71717a" : "#a1a1aa" }, children: [
423
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 32, marginBottom: 8 }, children: "\u{1F680}" }),
424
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: "No releases yet" })
425
+ ] }) : versions.slice(0, 5).map((version, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginBottom: 16, paddingBottom: 16, borderBottom: idx < 4 ? `1px solid ${isLight ? "#f4f4f5" : "#27272a"}` : "none" }, children: [
426
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 4 }, children: [
427
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 16 }, children: version.emoji || "\u{1F4E6}" }),
428
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontWeight: 600, color: isLight ? "#18181b" : "#fff" }, children: version.title }),
429
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
430
+ "span",
431
+ {
432
+ style: {
433
+ padding: "2px 6px",
434
+ fontSize: 10,
435
+ fontWeight: 500,
436
+ borderRadius: 4,
437
+ background: version.type === "major" ? "#f3e8ff" : version.type === "minor" ? "#dbeafe" : "#f4f4f5",
438
+ color: version.type === "major" ? "#7c3aed" : version.type === "minor" ? "#2563eb" : "#52525b"
439
+ },
440
+ children: version.type
441
+ }
442
+ )
443
+ ] }),
444
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: 12, color: isLight ? "#71717a" : "#a1a1aa", marginBottom: 8 }, children: [
445
+ "v",
446
+ version.version,
447
+ " \xB7 ",
448
+ new Date(version.date).toLocaleDateString()
449
+ ] }),
450
+ version.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: 14, color: isLight ? "#52525b" : "#d4d4d8", marginBottom: 8 }, children: version.description }),
451
+ version.features && version.features.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: { margin: 0, paddingLeft: 0, listStyle: "none" }, children: version.features.map((feature, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { style: { display: "flex", alignItems: "flex-start", gap: 8, fontSize: 14, color: isLight ? "#52525b" : "#d4d4d8", marginBottom: 4 }, children: [
452
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "#22c55e", marginTop: 2 }, children: "\u2713" }),
453
+ feature
454
+ ] }, i)) })
455
+ ] }, idx)) }),
456
+ activeTab === "roadmap" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: Object.keys(groupedTasks).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { textAlign: "center", padding: 40, color: isLight ? "#71717a" : "#a1a1aa" }, children: [
457
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 32, marginBottom: 8 }, children: "\u{1F5FA}\uFE0F" }),
458
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: "No public roadmap items" })
459
+ ] }) : ["in-progress", "todo", "backlog", "done"].map((col) => {
460
+ const tasks = groupedTasks[col];
461
+ if (!tasks || tasks.length === 0) return null;
462
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginBottom: 16 }, children: [
463
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { style: { fontSize: 12, fontWeight: 600, color: isLight ? "#71717a" : "#a1a1aa", marginBottom: 8, textTransform: "uppercase" }, children: [
464
+ COLUMN_LABELS[col] || col,
465
+ " (",
466
+ tasks.length,
467
+ ")"
468
+ ] }),
469
+ tasks.map((task) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
470
+ "div",
471
+ {
472
+ style: {
473
+ padding: 12,
474
+ marginBottom: 8,
475
+ borderRadius: 8,
476
+ background: isLight ? "#f4f4f5" : "#27272a"
477
+ },
478
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
479
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
480
+ "span",
481
+ {
482
+ style: {
483
+ width: 8,
484
+ height: 8,
485
+ borderRadius: "50%",
486
+ background: TYPE_COLORS[task.type] || "#71717a"
487
+ }
488
+ }
489
+ ),
490
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 14, color: isLight ? "#18181b" : "#fff" }, children: task.title })
491
+ ] })
492
+ },
493
+ task.id
494
+ ))
495
+ ] }, col);
496
+ }) }),
497
+ activeTab === "ideas" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: ideas.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { textAlign: "center", padding: 40, color: isLight ? "#71717a" : "#a1a1aa" }, children: [
498
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 32, marginBottom: 8 }, children: "\u{1F4A1}" }),
499
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: "No feature requests yet" })
500
+ ] }) : ideas.map((idea) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
501
+ "div",
502
+ {
503
+ style: {
504
+ padding: 12,
505
+ marginBottom: 8,
506
+ borderRadius: 8,
507
+ background: isLight ? "#f4f4f5" : "#27272a",
508
+ display: "flex",
509
+ alignItems: "flex-start",
510
+ gap: 12
511
+ },
512
+ children: [
513
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
514
+ "div",
515
+ {
516
+ style: {
517
+ display: "flex",
518
+ flexDirection: "column",
519
+ alignItems: "center",
520
+ padding: "4px 8px",
521
+ borderRadius: 6,
522
+ background: isLight ? "#fff" : "#18181b",
523
+ minWidth: 40
524
+ },
525
+ children: [
526
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 14, fontWeight: 600, color: isLight ? "#18181b" : "#fff" }, children: idea.votes }),
527
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 10, color: isLight ? "#71717a" : "#a1a1aa" }, children: "votes" })
528
+ ]
529
+ }
530
+ ),
531
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
532
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 14, fontWeight: 500, color: isLight ? "#18181b" : "#fff", marginBottom: 4 }, children: idea.title }),
533
+ idea.description && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: 13, color: isLight ? "#71717a" : "#a1a1aa" }, children: [
534
+ idea.description.slice(0, 100),
535
+ "..."
536
+ ] })
537
+ ] })
538
+ ]
539
+ },
540
+ idea.id
541
+ )) })
542
+ ] }),
543
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
544
+ "div",
545
+ {
546
+ style: {
547
+ padding: 12,
548
+ borderTop: `1px solid ${isLight ? "#f4f4f5" : "#27272a"}`,
549
+ background: isLight ? "#fafafa" : "#0a0a0a",
550
+ display: "flex",
551
+ alignItems: "center",
552
+ justifyContent: "space-between"
553
+ },
554
+ children: [
555
+ showBranding && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
556
+ "a",
557
+ {
558
+ href: "https://versionpill.com",
559
+ target: "_blank",
560
+ rel: "noopener noreferrer",
561
+ style: { fontSize: 10, color: isLight ? "#a1a1aa" : "#52525b", textDecoration: "none" },
562
+ children: "Powered by Version Pill"
563
+ }
564
+ ),
565
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
566
+ "a",
567
+ {
568
+ href: `${baseUrl}/${projectId}/${activeTab === "ideas" ? "feature-requests" : activeTab}`,
569
+ target: "_blank",
570
+ rel: "noopener noreferrer",
571
+ style: {
572
+ padding: "6px 12px",
573
+ fontSize: 12,
574
+ fontWeight: 500,
575
+ borderRadius: 6,
576
+ background: "#22c55e",
577
+ color: "#fff",
578
+ textDecoration: "none"
579
+ },
580
+ children: "View All \u2192"
581
+ }
582
+ )
583
+ ]
468
584
  }
469
585
  )
470
- ] })
471
- ] })
472
- ] })
473
- ] })
474
- ] });
475
- }
476
- function PulseDot({ color, size }) {
477
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { position: "relative", display: "inline-flex", width: size, height: size }, children: [
478
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
479
- "span",
480
- {
481
- style: {
482
- position: "absolute",
483
- inset: 0,
484
- borderRadius: "50%",
485
- background: color,
486
- opacity: 0.75,
487
- animation: "vp-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite"
586
+ ]
488
587
  }
489
- }
490
- ),
491
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
492
- "span",
493
- {
494
- style: {
495
- position: "relative",
496
- display: "inline-flex",
497
- width: size,
498
- height: size,
499
- borderRadius: "50%",
500
- background: color
501
- }
502
- }
503
- ),
504
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `@keyframes vp-ping { 75%, 100% { transform: scale(2); opacity: 0; } }` })
588
+ )
589
+ ] })
505
590
  ] });
506
591
  }
507
592
  function VersionBadge({
508
593
  projectId,
509
594
  baseUrl = DEFAULT_BASE_URL,
510
595
  theme = "auto",
511
- style = "dot",
596
+ style = "gradient",
512
597
  size = "md",
513
598
  accent = "green",
514
599
  className,
@@ -538,9 +623,8 @@ function VersionBadge({
538
623
  fontFamily: "ui-monospace, monospace",
539
624
  fontWeight: 500,
540
625
  borderRadius: 999,
541
- background: colors.bg,
542
- border: `1px solid ${colors.border}`,
543
- color: colors.text,
626
+ background: "linear-gradient(135deg, #22c55e 0%, #16a34a 100%)",
627
+ color: "#fff",
544
628
  opacity: 0.6
545
629
  },
546
630
  children: [
@@ -551,75 +635,43 @@ function VersionBadge({
551
635
  width: sizeConfig.dotSize,
552
636
  height: sizeConfig.dotSize,
553
637
  borderRadius: "50%",
554
- background: colors.dot,
555
- opacity: 0.4
638
+ background: "#fff",
639
+ opacity: 0.6
556
640
  }
557
641
  }
558
642
  ),
559
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { width: 32, height: sizeConfig.font, background: colors.border, borderRadius: 2 } })
643
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { width: 32, height: sizeConfig.font, background: "rgba(255,255,255,0.3)", borderRadius: 2 } })
560
644
  ]
561
645
  }
562
646
  );
563
647
  }
564
648
  if (!version) return null;
565
- const getStyleVariant = () => {
566
- const base = {
567
- display: "inline-flex",
568
- alignItems: "center",
569
- gap: sizeConfig.gap,
570
- fontSize: sizeConfig.font,
571
- fontFamily: "ui-monospace, monospace",
572
- fontWeight: 600,
573
- borderRadius: 999,
574
- textDecoration: "none",
575
- transition: "opacity 150ms ease"
576
- };
577
- if (style === "minimal") {
578
- return { ...base, background: "transparent", border: "none", padding: 0, color: colors.text };
579
- }
580
- if (style === "glass") {
581
- return {
582
- ...base,
583
- height: sizeConfig.height,
584
- padding: sizeConfig.padding,
585
- background: isLight ? "rgba(255,255,255,0.7)" : "rgba(255,255,255,0.1)",
586
- backdropFilter: "blur(12px)",
587
- WebkitBackdropFilter: "blur(12px)",
588
- border: `1px solid ${isLight ? "rgba(255,255,255,0.8)" : "rgba(255,255,255,0.15)"}`,
589
- boxShadow: "0 4px 12px rgba(0,0,0,0.08), inset 0 1px 0 rgba(255,255,255,0.2)",
590
- color: isLight ? "#374151" : "#f3f4f6"
591
- };
592
- }
593
- if (style === "gradient") {
594
- return {
595
- ...base,
596
- height: sizeConfig.height,
597
- padding: sizeConfig.padding,
598
- background: "linear-gradient(135deg, #22c55e 0%, #16a34a 100%)",
599
- border: "none",
600
- color: "#fff",
601
- boxShadow: "0 4px 12px rgba(34,197,94,0.3)"
602
- };
603
- }
604
- return {
605
- ...base,
606
- height: sizeConfig.height,
607
- padding: sizeConfig.padding,
608
- background: colors.bg,
609
- border: `1px solid ${colors.border}`,
610
- color: colors.text
611
- };
649
+ const badgeStyle = {
650
+ display: "inline-flex",
651
+ alignItems: "center",
652
+ gap: sizeConfig.gap,
653
+ height: sizeConfig.height,
654
+ padding: sizeConfig.padding,
655
+ fontSize: sizeConfig.font,
656
+ fontFamily: "ui-monospace, monospace",
657
+ fontWeight: 600,
658
+ borderRadius: 999,
659
+ textDecoration: "none",
660
+ transition: "all 150ms ease",
661
+ background: "linear-gradient(135deg, #22c55e 0%, #16a34a 100%)",
662
+ color: "#fff",
663
+ boxShadow: "0 2px 8px rgba(34,197,94,0.3)"
612
664
  };
613
- const badgeStyle = getStyleVariant();
614
665
  const content = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
615
- style === "dot" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
666
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
616
667
  "span",
617
668
  {
618
669
  style: {
619
670
  width: sizeConfig.dotSize,
620
671
  height: sizeConfig.dotSize,
621
672
  borderRadius: "50%",
622
- background: colors.dot,
673
+ background: "#fff",
674
+ boxShadow: "0 0 6px rgba(255,255,255,0.8)",
623
675
  flexShrink: 0
624
676
  }
625
677
  }
@@ -630,58 +682,10 @@ function VersionBadge({
630
682
  ] })
631
683
  ] });
632
684
  if (href) {
633
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
634
- "a",
635
- {
636
- href,
637
- target: "_blank",
638
- rel: "noopener noreferrer",
639
- className,
640
- style: badgeStyle,
641
- onMouseEnter: (e) => e.currentTarget.style.opacity = "0.8",
642
- onMouseLeave: (e) => e.currentTarget.style.opacity = "1",
643
- children: content
644
- }
645
- );
685
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className, style: badgeStyle, children: content });
646
686
  }
647
687
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className, style: badgeStyle, children: content });
648
688
  }
649
- function Changelog({
650
- projectId,
651
- baseUrl = DEFAULT_BASE_URL,
652
- maxHeight = 600,
653
- theme = "auto",
654
- className
655
- }) {
656
- const resolvedTheme = useTheme(theme);
657
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
658
- "iframe",
659
- {
660
- src: `${baseUrl}/embed/${projectId}/changelog?theme=${resolvedTheme}`,
661
- className: (0, import_clsx.default)(styles.iframe, className),
662
- style: { height: maxHeight },
663
- title: "Changelog"
664
- }
665
- );
666
- }
667
- function Roadmap({
668
- projectId,
669
- baseUrl = DEFAULT_BASE_URL,
670
- maxHeight = 800,
671
- theme = "auto",
672
- className
673
- }) {
674
- const resolvedTheme = useTheme(theme);
675
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
676
- "iframe",
677
- {
678
- src: `${baseUrl}/embed/${projectId}/roadmap?theme=${resolvedTheme}`,
679
- className: (0, import_clsx.default)(styles.iframe, className),
680
- style: { height: maxHeight },
681
- title: "Roadmap"
682
- }
683
- );
684
- }
685
689
  var versionCache = {};
686
690
  function useVersion({
687
691
  projectId,
@@ -725,6 +729,42 @@ function useVersion({
725
729
  }, [refetchInterval, fetchVersion]);
726
730
  return { version, name, slug, loading, error, refetch: fetchVersion };
727
731
  }
732
+ function Changelog({
733
+ projectId,
734
+ baseUrl = DEFAULT_BASE_URL,
735
+ maxHeight = 600,
736
+ theme = "auto",
737
+ className
738
+ }) {
739
+ const resolvedTheme = useTheme(theme);
740
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
741
+ "iframe",
742
+ {
743
+ src: `${baseUrl}/embed/${projectId}/changelog?theme=${resolvedTheme}`,
744
+ className,
745
+ style: { width: "100%", height: maxHeight, border: "none" },
746
+ title: "Changelog"
747
+ }
748
+ );
749
+ }
750
+ function Roadmap({
751
+ projectId,
752
+ baseUrl = DEFAULT_BASE_URL,
753
+ maxHeight = 800,
754
+ theme = "auto",
755
+ className
756
+ }) {
757
+ const resolvedTheme = useTheme(theme);
758
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
759
+ "iframe",
760
+ {
761
+ src: `${baseUrl}/embed/${projectId}/roadmap?theme=${resolvedTheme}`,
762
+ className,
763
+ style: { width: "100%", height: maxHeight, border: "none" },
764
+ title: "Roadmap"
765
+ }
766
+ );
767
+ }
728
768
  var index_default = VersionPill;
729
769
  // Annotate the CommonJS export names for ESM import in node:
730
770
  0 && (module.exports = {