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.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",
424
352
  {
425
- href: `${baseUrl}/${projectId}/changelog`,
426
- target: "_blank",
427
- rel: "noopener noreferrer",
428
- className: clsx(styles.button, styles.buttonPrimary),
429
- children: "View All"
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",
507
+ {
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"
548
+ ]
450
549
  }
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
463
- }
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 = "gradient",
474
559
  size = "md",
475
560
  accent = "green",
476
561
  className,
@@ -500,9 +585,8 @@ function VersionBadge({
500
585
  fontFamily: "ui-monospace, monospace",
501
586
  fontWeight: 500,
502
587
  borderRadius: 999,
503
- background: colors.bg,
504
- border: `1px solid ${colors.border}`,
505
- color: colors.text,
588
+ background: "linear-gradient(135deg, #22c55e 0%, #16a34a 100%)",
589
+ color: "#fff",
506
590
  opacity: 0.6
507
591
  },
508
592
  children: [
@@ -513,75 +597,43 @@ function VersionBadge({
513
597
  width: sizeConfig.dotSize,
514
598
  height: sizeConfig.dotSize,
515
599
  borderRadius: "50%",
516
- background: colors.dot,
517
- opacity: 0.4
600
+ background: "#fff",
601
+ opacity: 0.6
518
602
  }
519
603
  }
520
604
  ),
521
- /* @__PURE__ */ jsx("span", { style: { width: 32, height: sizeConfig.font, background: colors.border, borderRadius: 2 } })
605
+ /* @__PURE__ */ jsx("span", { style: { width: 32, height: sizeConfig.font, background: "rgba(255,255,255,0.3)", borderRadius: 2 } })
522
606
  ]
523
607
  }
524
608
  );
525
609
  }
526
610
  if (!version) return null;
527
- const getStyleVariant = () => {
528
- const base = {
529
- display: "inline-flex",
530
- alignItems: "center",
531
- gap: sizeConfig.gap,
532
- fontSize: sizeConfig.font,
533
- fontFamily: "ui-monospace, monospace",
534
- fontWeight: 600,
535
- borderRadius: 999,
536
- textDecoration: "none",
537
- transition: "opacity 150ms ease"
538
- };
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
- };
565
- }
566
- 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
573
- };
611
+ const badgeStyle = {
612
+ display: "inline-flex",
613
+ alignItems: "center",
614
+ gap: sizeConfig.gap,
615
+ height: sizeConfig.height,
616
+ padding: sizeConfig.padding,
617
+ fontSize: sizeConfig.font,
618
+ fontFamily: "ui-monospace, monospace",
619
+ fontWeight: 600,
620
+ borderRadius: 999,
621
+ textDecoration: "none",
622
+ transition: "all 150ms ease",
623
+ background: "linear-gradient(135deg, #22c55e 0%, #16a34a 100%)",
624
+ color: "#fff",
625
+ boxShadow: "0 2px 8px rgba(34,197,94,0.3)"
574
626
  };
575
- const badgeStyle = getStyleVariant();
576
627
  const content = /* @__PURE__ */ jsxs(Fragment, { children: [
577
- style === "dot" && /* @__PURE__ */ jsx(
628
+ /* @__PURE__ */ jsx(
578
629
  "span",
579
630
  {
580
631
  style: {
581
632
  width: sizeConfig.dotSize,
582
633
  height: sizeConfig.dotSize,
583
634
  borderRadius: "50%",
584
- background: colors.dot,
635
+ background: "#fff",
636
+ boxShadow: "0 0 6px rgba(255,255,255,0.8)",
585
637
  flexShrink: 0
586
638
  }
587
639
  }
@@ -592,58 +644,10 @@ function VersionBadge({
592
644
  ] })
593
645
  ] });
594
646
  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
- );
647
+ return /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noopener noreferrer", className, style: badgeStyle, children: content });
608
648
  }
609
649
  return /* @__PURE__ */ jsx("span", { className, style: badgeStyle, children: content });
610
650
  }
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
651
  var versionCache = {};
648
652
  function useVersion({
649
653
  projectId,
@@ -687,6 +691,42 @@ function useVersion({
687
691
  }, [refetchInterval, fetchVersion]);
688
692
  return { version, name, slug, loading, error, refetch: fetchVersion };
689
693
  }
694
+ function Changelog({
695
+ projectId,
696
+ baseUrl = DEFAULT_BASE_URL,
697
+ maxHeight = 600,
698
+ theme = "auto",
699
+ className
700
+ }) {
701
+ const resolvedTheme = useTheme(theme);
702
+ return /* @__PURE__ */ jsx(
703
+ "iframe",
704
+ {
705
+ src: `${baseUrl}/embed/${projectId}/changelog?theme=${resolvedTheme}`,
706
+ className,
707
+ style: { width: "100%", height: maxHeight, border: "none" },
708
+ title: "Changelog"
709
+ }
710
+ );
711
+ }
712
+ function Roadmap({
713
+ projectId,
714
+ baseUrl = DEFAULT_BASE_URL,
715
+ maxHeight = 800,
716
+ theme = "auto",
717
+ className
718
+ }) {
719
+ const resolvedTheme = useTheme(theme);
720
+ return /* @__PURE__ */ jsx(
721
+ "iframe",
722
+ {
723
+ src: `${baseUrl}/embed/${projectId}/roadmap?theme=${resolvedTheme}`,
724
+ className,
725
+ style: { width: "100%", height: maxHeight, border: "none" },
726
+ title: "Roadmap"
727
+ }
728
+ );
729
+ }
690
730
  var index_default = VersionPill;
691
731
  export {
692
732
  Changelog,