version-pill-react 1.1.1 → 1.2.1

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