version-pill-react 1.2.7 → 1.5.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
@@ -40,6 +40,7 @@ __export(index_exports, {
40
40
  });
41
41
  module.exports = __toCommonJS(index_exports);
42
42
  var import_react = require("react");
43
+ var import_react_dom = require("react-dom");
43
44
  var import_clsx = __toESM(require("clsx"));
44
45
  var import_jsx_runtime = require("react/jsx-runtime");
45
46
  var DEFAULT_BASE_URL = "https://www.versionpill.com";
@@ -76,12 +77,37 @@ var TYPE_COLORS = {
76
77
  improvement: "#3b82f6",
77
78
  chore: "#71717a"
78
79
  };
79
- var COLUMN_LABELS = {
80
- backlog: "Backlog",
81
- todo: "Planned",
82
- "in-progress": "In Progress",
83
- done: "Shipped"
80
+ var TYPE_EMOJIS = {
81
+ feature: "\u2728",
82
+ bug: "\u{1F41B}",
83
+ improvement: "\u{1F4C8}",
84
+ chore: "\u{1F527}",
85
+ idea: "\u{1F4A1}"
84
86
  };
87
+ var PRIORITY_COLORS = {
88
+ urgent: "#ef4444",
89
+ high: "#f97316",
90
+ medium: "#3b82f6",
91
+ low: "#9ca3af"
92
+ };
93
+ var STATUS_CONFIG = {
94
+ new: { color: "#3b82f6", label: "New" },
95
+ "under review": { color: "#f59e0b", label: "Under Review" },
96
+ planned: { color: "#8b5cf6", label: "Planned" },
97
+ "in progress": { color: "#3b82f6", label: "In Progress" },
98
+ shipped: { color: "#22c55e", label: "Shipped" },
99
+ declined: { color: "#ef4444", label: "Declined" }
100
+ };
101
+ var FADE_IN_KEYFRAMES = `
102
+ @keyframes vpFadeIn {
103
+ from { opacity: 0; }
104
+ to { opacity: 1; }
105
+ }
106
+ @keyframes vpSlideUp {
107
+ from { opacity: 0; transform: translateY(8px); }
108
+ to { opacity: 1; transform: translateY(0); }
109
+ }
110
+ `;
85
111
  function useTheme(theme) {
86
112
  const [resolved, setResolved] = (0, import_react.useState)("light");
87
113
  (0, import_react.useEffect)(() => {
@@ -114,11 +140,24 @@ function VersionPill({
114
140
  const [project, setProject] = (0, import_react.useState)(null);
115
141
  const [versions, setVersions] = (0, import_react.useState)([]);
116
142
  const [roadmapTasks, setRoadmapTasks] = (0, import_react.useState)([]);
143
+ const [roadmapColumns, setRoadmapColumns] = (0, import_react.useState)([]);
144
+ const [roadmapItems, setRoadmapItems] = (0, import_react.useState)([]);
117
145
  const [ideas, setIdeas] = (0, import_react.useState)([]);
118
146
  const [loading, setLoading] = (0, import_react.useState)(true);
119
147
  const [isOpen, setIsOpen] = (0, import_react.useState)(false);
120
148
  const [activeTab, setActiveTab] = (0, import_react.useState)("changelog");
121
149
  const [hasNewVersion, setHasNewVersion] = (0, import_react.useState)(false);
150
+ const [showIdeaForm, setShowIdeaForm] = (0, import_react.useState)(false);
151
+ const [ideaTitle, setIdeaTitle] = (0, import_react.useState)("");
152
+ const [ideaDescription, setIdeaDescription] = (0, import_react.useState)("");
153
+ const [ideaAuthorName, setIdeaAuthorName] = (0, import_react.useState)("");
154
+ const [ideaAuthorEmail, setIdeaAuthorEmail] = (0, import_react.useState)("");
155
+ const [submittingIdea, setSubmittingIdea] = (0, import_react.useState)(false);
156
+ const [ideaSubmitMessage, setIdeaSubmitMessage] = (0, import_react.useState)(null);
157
+ const [roadmapView, setRoadmapView] = (0, import_react.useState)("board");
158
+ const [isMobile, setIsMobile] = (0, import_react.useState)(false);
159
+ const [votedIdeas, setVotedIdeas] = (0, import_react.useState)(/* @__PURE__ */ new Set());
160
+ const [collapsedColumns, setCollapsedColumns] = (0, import_react.useState)(/* @__PURE__ */ new Set());
122
161
  const resolvedTheme = useTheme(theme);
123
162
  const isLight = resolvedTheme === "light";
124
163
  const sizeConfig = SIZE_CONFIG[size];
@@ -164,7 +203,45 @@ function VersionPill({
164
203
  const response = await fetch(`${baseUrl}/api/roadmap/${projectId}`);
165
204
  if (!response.ok) return;
166
205
  const data = await response.json();
167
- setRoadmapTasks(data.tasks || []);
206
+ if (data.columns && data.items) {
207
+ setRoadmapColumns(data.columns);
208
+ setRoadmapItems(data.items);
209
+ return;
210
+ }
211
+ let tasks = [];
212
+ if (Array.isArray(data.tasks)) {
213
+ tasks = data.tasks;
214
+ } else if (data.tasks && typeof data.tasks === "object") {
215
+ const grouped = data.tasks;
216
+ const mapTask = (t, defaultColumn) => ({
217
+ id: t.id || t._id,
218
+ title: t.title,
219
+ description: t.description,
220
+ type: t.type || "feature",
221
+ priority: t.priority || "medium",
222
+ column: t.columnId || defaultColumn,
223
+ columnId: t.columnId,
224
+ columnName: t.columnName
225
+ });
226
+ const inProgress = (grouped.inProgress || []).map((t) => mapTask(t, "in-progress"));
227
+ const planned = (grouped.planned || []).map((t) => mapTask(t, "todo"));
228
+ tasks = [...inProgress, ...planned];
229
+ }
230
+ setRoadmapColumns([
231
+ { id: "planned", name: "Planned" },
232
+ { id: "in_progress", name: "In Progress" },
233
+ { id: "completed", name: "Completed" }
234
+ ]);
235
+ setRoadmapItems(tasks.map((t) => ({
236
+ id: t.id,
237
+ title: t.title,
238
+ description: t.description,
239
+ type: t.type,
240
+ priority: t.priority,
241
+ itemType: "task",
242
+ columnId: t.column === "in-progress" ? "in_progress" : t.column === "done" || t.column === "shipped" ? "completed" : "planned"
243
+ })));
244
+ setRoadmapTasks(tasks);
168
245
  } catch {
169
246
  }
170
247
  }, [projectId, baseUrl]);
@@ -177,9 +254,93 @@ function VersionPill({
177
254
  } catch {
178
255
  }
179
256
  }, [projectId, baseUrl]);
257
+ const submitIdea = (0, import_react.useCallback)(async () => {
258
+ if (!ideaTitle.trim()) return;
259
+ setSubmittingIdea(true);
260
+ setIdeaSubmitMessage(null);
261
+ try {
262
+ const response = await fetch(`${baseUrl}/api/ideas/${projectId}`, {
263
+ method: "POST",
264
+ headers: { "Content-Type": "application/json" },
265
+ body: JSON.stringify({
266
+ title: ideaTitle.trim(),
267
+ description: ideaDescription.trim() || void 0,
268
+ authorName: ideaAuthorName.trim() || void 0,
269
+ authorEmail: ideaAuthorEmail.trim() || void 0
270
+ })
271
+ });
272
+ if (!response.ok) {
273
+ const error = await response.json().catch(() => ({ error: "Failed to submit" }));
274
+ throw new Error(error.error || "Failed to submit idea");
275
+ }
276
+ setIdeaSubmitMessage({ type: "success", text: "Thanks! Your idea has been submitted." });
277
+ setIdeaTitle("");
278
+ setIdeaDescription("");
279
+ setShowIdeaForm(false);
280
+ fetchIdeas();
281
+ } catch (err) {
282
+ setIdeaSubmitMessage({ type: "error", text: err.message || "Failed to submit idea" });
283
+ } finally {
284
+ setSubmittingIdea(false);
285
+ }
286
+ }, [baseUrl, projectId, ideaTitle, ideaDescription, ideaAuthorName, ideaAuthorEmail, fetchIdeas]);
287
+ const voteIdea = (0, import_react.useCallback)(async (ideaId) => {
288
+ if (votedIdeas.has(ideaId)) return;
289
+ setIdeas((prev) => prev.map((i) => i.id === ideaId ? { ...i, votes: i.votes + 1 } : i));
290
+ setVotedIdeas((prev) => new Set(prev).add(ideaId));
291
+ try {
292
+ await fetch(`${baseUrl}/api/ideas/${projectId}/vote`, {
293
+ method: "POST",
294
+ headers: { "Content-Type": "application/json" },
295
+ body: JSON.stringify({ ideaId })
296
+ });
297
+ } catch {
298
+ setIdeas((prev) => prev.map((i) => i.id === ideaId ? { ...i, votes: i.votes - 1 } : i));
299
+ setVotedIdeas((prev) => {
300
+ const s = new Set(prev);
301
+ s.delete(ideaId);
302
+ return s;
303
+ });
304
+ }
305
+ }, [baseUrl, projectId, votedIdeas]);
180
306
  (0, import_react.useEffect)(() => {
181
307
  fetchVersion();
182
308
  }, [fetchVersion]);
309
+ (0, import_react.useEffect)(() => {
310
+ if (isOpen) {
311
+ const prev = document.body.style.overflow;
312
+ document.body.style.overflow = "hidden";
313
+ return () => {
314
+ document.body.style.overflow = prev;
315
+ };
316
+ }
317
+ }, [isOpen]);
318
+ (0, import_react.useEffect)(() => {
319
+ if (!isOpen) return;
320
+ const handleKey = (e) => {
321
+ if (e.key === "Escape") setIsOpen(false);
322
+ };
323
+ document.addEventListener("keydown", handleKey);
324
+ return () => document.removeEventListener("keydown", handleKey);
325
+ }, [isOpen]);
326
+ (0, import_react.useEffect)(() => {
327
+ const check = () => setIsMobile(window.innerWidth < 640);
328
+ check();
329
+ window.addEventListener("resize", check);
330
+ return () => window.removeEventListener("resize", check);
331
+ }, []);
332
+ (0, import_react.useEffect)(() => {
333
+ if (!isOpen) return;
334
+ const id = "vp-modal-keyframes";
335
+ if (document.getElementById(id)) return;
336
+ const style2 = document.createElement("style");
337
+ style2.id = id;
338
+ style2.textContent = FADE_IN_KEYFRAMES;
339
+ document.head.appendChild(style2);
340
+ return () => {
341
+ document.getElementById(id)?.remove();
342
+ };
343
+ }, [isOpen]);
183
344
  const handleOpen = () => {
184
345
  if (onClick) {
185
346
  onClick();
@@ -296,298 +457,842 @@ function VersionPill({
296
457
  );
297
458
  };
298
459
  const versionsArray = Array.isArray(versions) ? versions : [];
299
- const tasksArray = Array.isArray(roadmapTasks) ? roadmapTasks : [];
300
460
  const ideasArray = Array.isArray(ideas) ? ideas : [];
301
- const groupedTasks = tasksArray.reduce((acc, task) => {
302
- const col = task.column || "backlog";
303
- if (!acc[col]) acc[col] = [];
304
- acc[col].push(task);
305
- return acc;
306
- }, {});
307
461
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
308
462
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_clsx.default)(positionStyles[position], className), style: { display: "inline-flex" }, children: renderBadge() }),
309
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
310
- position: "fixed",
311
- top: 0,
312
- left: 0,
313
- right: 0,
314
- bottom: 0,
315
- width: "100vw",
316
- height: "100vh",
317
- zIndex: 2147483647,
318
- display: "flex",
319
- flexDirection: "column",
320
- boxSizing: "border-box",
321
- background: isLight ? "#fff" : "#0a0a0a"
322
- }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
323
- "div",
324
- {
325
- style: {
326
- display: "flex",
327
- flexDirection: "column",
328
- width: "100%",
329
- height: "100%",
330
- borderRadius: 12,
331
- overflow: "hidden"
332
- },
333
- children: [
334
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
335
- "div",
336
- {
337
- style: {
338
- flexShrink: 0,
339
- padding: "16px 20px",
340
- borderBottom: `1px solid ${isLight ? "#e5e5e5" : "#1f1f1f"}`,
341
- display: "flex",
342
- alignItems: "center",
343
- justifyContent: "space-between"
344
- },
345
- children: [
346
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
347
- project?.icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 24 }, children: project.icon }),
348
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
349
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: { fontWeight: 600, fontSize: 18, color: isLight ? "#18181b" : "#fff", margin: 0 }, children: project?.name || "What's New" }),
350
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: { fontSize: 13, color: isLight ? "#71717a" : "#a1a1aa", margin: 0 }, children: [
351
- "v",
352
- currentVersion
353
- ] })
354
- ] })
355
- ] }),
356
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
357
- "button",
358
- {
359
- onClick: () => setIsOpen(false),
360
- style: {
361
- width: 36,
362
- height: 36,
363
- display: "flex",
364
- alignItems: "center",
365
- justifyContent: "center",
366
- borderRadius: 8,
367
- background: isLight ? "#f5f5f5" : "#1f1f1f",
368
- border: "none",
369
- cursor: "pointer",
370
- color: isLight ? "#71717a" : "#a1a1aa",
371
- transition: "background 150ms"
372
- },
373
- onMouseEnter: (e) => e.currentTarget.style.background = isLight ? "#e5e5e5" : "#2a2a2a",
374
- onMouseLeave: (e) => e.currentTarget.style.background = isLight ? "#f5f5f5" : "#1f1f1f",
375
- 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" }) })
376
- }
377
- )
378
- ]
463
+ isOpen && (0, import_react_dom.createPortal)(
464
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
465
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
466
+ "div",
467
+ {
468
+ onClick: () => setIsOpen(false),
469
+ style: {
470
+ position: "fixed",
471
+ top: 0,
472
+ left: 0,
473
+ right: 0,
474
+ bottom: 0,
475
+ zIndex: 2147483646,
476
+ background: "rgba(0,0,0,0.5)",
477
+ animation: "vpFadeIn 200ms ease-out"
379
478
  }
380
- ),
381
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
382
- "div",
383
- {
384
- style: {
385
- flexShrink: 0,
386
- display: "flex",
387
- gap: 4,
388
- padding: "12px 20px",
389
- borderBottom: `1px solid ${isLight ? "#e5e5e5" : "#1f1f1f"}`
390
- },
391
- children: ["changelog", "roadmap", "ideas"].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
392
- "button",
479
+ }
480
+ ),
481
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
482
+ "div",
483
+ {
484
+ onClick: (e) => e.stopPropagation(),
485
+ style: {
486
+ position: "fixed",
487
+ top: isMobile ? 0 : 20,
488
+ left: isMobile ? 0 : 20,
489
+ right: isMobile ? 0 : 20,
490
+ bottom: isMobile ? 0 : 20,
491
+ zIndex: 2147483647,
492
+ display: "flex",
493
+ flexDirection: "column",
494
+ boxSizing: "border-box",
495
+ background: isLight ? "#fff" : "#0a0a0a",
496
+ borderRadius: isMobile ? 0 : 16,
497
+ overflow: "hidden",
498
+ boxShadow: "0 25px 50px -12px rgba(0,0,0,0.25)",
499
+ animation: "vpSlideUp 250ms ease-out"
500
+ },
501
+ children: [
502
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
503
+ "div",
393
504
  {
394
- onClick: () => setActiveTab(tab),
395
505
  style: {
396
- padding: "10px 16px",
397
- borderRadius: 8,
398
- border: "none",
399
- cursor: "pointer",
400
- fontSize: 14,
401
- fontWeight: 500,
402
- background: activeTab === tab ? isLight ? "#18181b" : "#fff" : "transparent",
403
- color: activeTab === tab ? isLight ? "#fff" : "#18181b" : isLight ? "#71717a" : "#71717a",
404
- transition: "all 150ms"
506
+ flexShrink: 0,
507
+ padding: isMobile ? "12px 16px" : "16px 20px",
508
+ borderBottom: `1px solid ${isLight ? "#e5e5e5" : "#1f1f1f"}`,
509
+ display: "flex",
510
+ alignItems: "center",
511
+ justifyContent: "space-between"
405
512
  },
406
513
  children: [
407
- tab === "changelog" && "\u{1F680} Changelog",
408
- tab === "roadmap" && "\u{1F5FA}\uFE0F Roadmap",
409
- tab === "ideas" && "\u{1F4A1} Ideas"
514
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: isMobile ? 8 : 12 }, children: [
515
+ project?.icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: isMobile ? 20 : 24 }, children: project.icon }),
516
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
517
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: { fontWeight: 600, fontSize: isMobile ? 16 : 18, color: isLight ? "#18181b" : "#fff", margin: 0 }, children: project?.name || "What's New" }),
518
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: { fontSize: 12, color: isLight ? "#71717a" : "#a1a1aa", margin: 0 }, children: [
519
+ "v",
520
+ currentVersion
521
+ ] })
522
+ ] })
523
+ ] }),
524
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
525
+ "button",
526
+ {
527
+ onClick: () => setIsOpen(false),
528
+ style: {
529
+ width: 36,
530
+ height: 36,
531
+ display: "flex",
532
+ alignItems: "center",
533
+ justifyContent: "center",
534
+ borderRadius: 8,
535
+ background: isLight ? "#f5f5f5" : "#1f1f1f",
536
+ border: "none",
537
+ cursor: "pointer",
538
+ color: isLight ? "#71717a" : "#a1a1aa",
539
+ transition: "background 150ms"
540
+ },
541
+ onMouseEnter: (e) => e.currentTarget.style.background = isLight ? "#e5e5e5" : "#2a2a2a",
542
+ onMouseLeave: (e) => e.currentTarget.style.background = isLight ? "#f5f5f5" : "#1f1f1f",
543
+ 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" }) })
544
+ }
545
+ )
410
546
  ]
411
- },
412
- tab
413
- ))
414
- }
415
- ),
416
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { flex: 1, overflowY: "auto", padding: "20px 24px", minHeight: 0 }, children: [
417
- activeTab === "changelog" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { maxWidth: 640 }, children: versionsArray.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { textAlign: "center", padding: 60, color: isLight ? "#71717a" : "#a1a1aa" }, children: [
418
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 48, marginBottom: 12 }, children: "\u{1F680}" }),
419
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 16 }, children: "No releases yet" })
420
- ] }) : versionsArray.slice(0, 10).map((version, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginBottom: 24, paddingBottom: 24, borderBottom: idx < versionsArray.length - 1 && idx < 9 ? `1px solid ${isLight ? "#f0f0f0" : "#1f1f1f"}` : "none" }, children: [
421
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 6 }, children: [
422
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 20 }, children: version.emoji || "\u{1F4E6}" }),
423
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontWeight: 600, fontSize: 18, color: isLight ? "#18181b" : "#fff" }, children: version.title }),
424
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
425
- "span",
426
- {
427
- style: {
428
- padding: "3px 8px",
429
- fontSize: 11,
430
- fontWeight: 500,
431
- borderRadius: 4,
432
- background: version.type === "major" ? "#f3e8ff" : version.type === "minor" ? "#dbeafe" : isLight ? "#f4f4f5" : "#1f1f1f",
433
- color: version.type === "major" ? "#7c3aed" : version.type === "minor" ? "#2563eb" : isLight ? "#52525b" : "#a1a1aa"
434
- },
435
- children: version.type
436
- }
437
- )
438
- ] }),
439
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: 13, color: isLight ? "#71717a" : "#71717a", marginBottom: 10 }, children: [
440
- "v",
441
- version.version,
442
- " \xB7 ",
443
- new Date(version.date).toLocaleDateString()
444
- ] }),
445
- version.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: 15, color: isLight ? "#52525b" : "#a1a1aa", margin: "0 0 12px 0", lineHeight: 1.6 }, children: version.description }),
446
- 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: 10, fontSize: 14, color: isLight ? "#52525b" : "#a1a1aa", marginBottom: 6, lineHeight: 1.5 }, children: [
447
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "#22c55e", fontSize: 14, marginTop: 2 }, children: "\u2713" }),
448
- feature
449
- ] }, i)) })
450
- ] }, idx)) }),
451
- activeTab === "roadmap" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { maxWidth: 640 }, children: Object.keys(groupedTasks).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { textAlign: "center", padding: 60, color: isLight ? "#71717a" : "#a1a1aa" }, children: [
452
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 48, marginBottom: 12 }, children: "\u{1F5FA}\uFE0F" }),
453
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 16 }, children: "No public roadmap items" })
454
- ] }) : ["in-progress", "todo", "backlog"].map((col) => {
455
- const tasks = groupedTasks[col];
456
- if (!tasks || tasks.length === 0) return null;
457
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginBottom: 24 }, children: [
458
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { style: { fontSize: 12, fontWeight: 600, color: isLight ? "#a1a1aa" : "#71717a", marginBottom: 12, textTransform: "uppercase", letterSpacing: "0.5px" }, children: [
459
- COLUMN_LABELS[col] || col,
460
- " (",
461
- tasks.length,
462
- ")"
463
- ] }),
464
- tasks.map((task) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
465
- "div",
466
- {
467
- style: {
468
- padding: "12px 16px",
469
- marginBottom: 8,
470
- borderRadius: 8,
471
- background: isLight ? "#f5f5f5" : "#151515",
472
- border: `1px solid ${isLight ? "#e5e5e5" : "#1f1f1f"}`
547
+ }
548
+ ),
549
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
550
+ "div",
551
+ {
552
+ style: {
553
+ flexShrink: 0,
554
+ display: "flex",
555
+ justifyContent: "center",
556
+ gap: 2,
557
+ padding: isMobile ? "8px 12px" : "10px 20px",
558
+ borderBottom: `1px solid ${isLight ? "#e5e5e5" : "#1f1f1f"}`,
559
+ overflowX: "auto"
560
+ },
561
+ children: ["changelog", "roadmap", "ideas"].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
562
+ "button",
563
+ {
564
+ onClick: () => setActiveTab(tab),
565
+ style: {
566
+ padding: isMobile ? "8px 16px" : "8px 20px",
567
+ borderRadius: 999,
568
+ border: "none",
569
+ cursor: "pointer",
570
+ fontSize: isMobile ? 13 : 14,
571
+ fontWeight: 500,
572
+ whiteSpace: "nowrap",
573
+ background: activeTab === tab ? isLight ? "#18181b" : "#fff" : "transparent",
574
+ color: activeTab === tab ? isLight ? "#fff" : "#18181b" : isLight ? "#71717a" : "#71717a",
575
+ transition: "all 150ms"
576
+ },
577
+ onMouseEnter: (e) => {
578
+ if (activeTab !== tab) {
579
+ e.currentTarget.style.background = isLight ? "#f4f4f5" : "#1f1f1f";
580
+ }
581
+ },
582
+ onMouseLeave: (e) => {
583
+ if (activeTab !== tab) {
584
+ e.currentTarget.style.background = "transparent";
585
+ }
586
+ },
587
+ children: [
588
+ tab === "changelog" && "\u{1F680} Changelog",
589
+ tab === "roadmap" && "\u{1F5FA}\uFE0F Roadmap",
590
+ tab === "ideas" && "\u{1F4A1} Ideas"
591
+ ]
473
592
  },
474
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10 }, children: [
475
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
476
- "span",
593
+ tab
594
+ ))
595
+ }
596
+ ),
597
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { flex: 1, overflow: activeTab === "roadmap" ? "hidden" : "auto", padding: isMobile ? "16px" : "20px 24px", minHeight: 0, display: "flex", flexDirection: "column", alignItems: "center" }, children: [
598
+ activeTab === "changelog" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { maxWidth: 640, width: "100%", overflowY: "auto", flex: 1 }, children: versionsArray.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { textAlign: "center", padding: 60, color: isLight ? "#71717a" : "#a1a1aa" }, children: [
599
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 48, marginBottom: 12 }, children: "\u{1F680}" }),
600
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 16 }, children: "No releases yet" })
601
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
602
+ versionsArray.slice(0, 10).map((version, idx) => {
603
+ const isLatest = idx === 0;
604
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
605
+ marginBottom: 24,
606
+ paddingBottom: 24,
607
+ paddingLeft: isLatest ? 16 : 0,
608
+ borderLeft: isLatest ? `3px solid #22c55e` : "none",
609
+ borderBottom: idx < versionsArray.length - 1 && idx < 9 ? `1px solid ${isLight ? "#f0f0f0" : "#1f1f1f"}` : "none"
610
+ }, children: [
611
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 6, flexWrap: "wrap" }, children: [
612
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: isLatest ? 22 : 20 }, children: version.emoji || "\u{1F4E6}" }),
613
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontWeight: 600, fontSize: isLatest ? 20 : 18, color: isLight ? "#18181b" : "#fff" }, children: version.title }),
614
+ isLatest && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
615
+ padding: "2px 8px",
616
+ fontSize: 10,
617
+ fontWeight: 600,
618
+ borderRadius: 999,
619
+ background: isLight ? "#dcfce7" : "rgba(34,197,94,0.15)",
620
+ color: "#22c55e",
621
+ textTransform: "uppercase",
622
+ letterSpacing: "0.5px"
623
+ }, children: "Latest" }),
624
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
625
+ "span",
626
+ {
627
+ style: {
628
+ padding: "3px 10px",
629
+ fontSize: 11,
630
+ fontWeight: 500,
631
+ borderRadius: 999,
632
+ background: version.type === "major" ? isLight ? "#f3e8ff" : "rgba(147,51,234,0.15)" : version.type === "minor" ? isLight ? "#dbeafe" : "rgba(59,130,246,0.15)" : isLight ? "#f4f4f5" : "#1f1f1f",
633
+ color: version.type === "major" ? "#7c3aed" : version.type === "minor" ? "#2563eb" : isLight ? "#52525b" : "#a1a1aa"
634
+ },
635
+ children: version.type
636
+ }
637
+ )
638
+ ] }),
639
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: 13, color: isLight ? "#71717a" : "#71717a", marginBottom: 10 }, children: [
640
+ "v",
641
+ version.version,
642
+ " \xB7 ",
643
+ new Date(version.date).toLocaleDateString()
644
+ ] }),
645
+ version.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: 15, color: isLight ? "#52525b" : "#a1a1aa", margin: "0 0 12px 0", lineHeight: 1.6 }, children: version.description }),
646
+ 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: 10, fontSize: 14, color: isLight ? "#52525b" : "#a1a1aa", marginBottom: 6, lineHeight: 1.5 }, children: [
647
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "#22c55e", fontSize: 14, marginTop: 2 }, children: "\u2713" }),
648
+ feature
649
+ ] }, i)) }),
650
+ version.tasks && version.tasks.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginTop: 10, paddingTop: 10, borderTop: `1px solid ${isLight ? "#f0f0f0" : "#1f1f1f"}` }, children: version.tasks.map((task, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, fontSize: 13, color: isLight ? "#71717a" : "#a1a1aa", marginBottom: 4 }, children: [
651
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
652
+ width: 6,
653
+ height: 6,
654
+ borderRadius: "50%",
655
+ background: TYPE_COLORS[task.type] || "#71717a",
656
+ flexShrink: 0
657
+ } }),
658
+ task.title
659
+ ] }, i)) })
660
+ ] }, idx);
661
+ }),
662
+ versionsArray.length > 10 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
663
+ "a",
664
+ {
665
+ href: `${baseUrl}/${projectId}/changelog`,
666
+ target: "_blank",
667
+ rel: "noopener noreferrer",
668
+ style: {
669
+ display: "block",
670
+ textAlign: "center",
671
+ padding: 12,
672
+ fontSize: 14,
673
+ color: "#22c55e",
674
+ textDecoration: "none"
675
+ },
676
+ children: "View all releases \u2192"
677
+ }
678
+ )
679
+ ] }) }),
680
+ activeTab === "roadmap" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", flexDirection: "column", flex: 1, minHeight: 0, width: "100%" }, children: roadmapItems.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { textAlign: "center", padding: 60, color: isLight ? "#71717a" : "#a1a1aa" }, children: [
681
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 48, marginBottom: 12 }, children: "\u{1F5FA}\uFE0F" }),
682
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 16 }, children: "No public roadmap items" })
683
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
684
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 4, marginBottom: 12, flexShrink: 0 }, children: [
685
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
686
+ "button",
687
+ {
688
+ onClick: () => setRoadmapView("board"),
689
+ style: {
690
+ padding: "6px 10px",
691
+ borderRadius: 6,
692
+ border: `1px solid ${roadmapView === "board" ? isLight ? "#18181b" : "#fff" : isLight ? "#e5e5e5" : "#2a2a2a"}`,
693
+ background: roadmapView === "board" ? isLight ? "#18181b" : "#fff" : "transparent",
694
+ color: roadmapView === "board" ? isLight ? "#fff" : "#18181b" : isLight ? "#71717a" : "#a1a1aa",
695
+ cursor: "pointer",
696
+ fontSize: 12,
697
+ fontWeight: 500,
698
+ display: "flex",
699
+ alignItems: "center",
700
+ gap: 4
701
+ },
702
+ children: [
703
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
704
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "3", y: "3", width: "7", height: "7" }),
705
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "14", y: "3", width: "7", height: "7" }),
706
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "3", y: "14", width: "7", height: "7" }),
707
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "14", y: "14", width: "7", height: "7" })
708
+ ] }),
709
+ "Board"
710
+ ]
711
+ }
712
+ ),
713
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
714
+ "button",
715
+ {
716
+ onClick: () => setRoadmapView("list"),
717
+ style: {
718
+ padding: "6px 10px",
719
+ borderRadius: 6,
720
+ border: `1px solid ${roadmapView === "list" ? isLight ? "#18181b" : "#fff" : isLight ? "#e5e5e5" : "#2a2a2a"}`,
721
+ background: roadmapView === "list" ? isLight ? "#18181b" : "#fff" : "transparent",
722
+ color: roadmapView === "list" ? isLight ? "#fff" : "#18181b" : isLight ? "#71717a" : "#a1a1aa",
723
+ cursor: "pointer",
724
+ fontSize: 12,
725
+ fontWeight: 500,
726
+ display: "flex",
727
+ alignItems: "center",
728
+ gap: 4
729
+ },
730
+ children: [
731
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
732
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "8", y1: "6", x2: "21", y2: "6" }),
733
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "8", y1: "12", x2: "21", y2: "12" }),
734
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "8", y1: "18", x2: "21", y2: "18" }),
735
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "3", y1: "6", x2: "3.01", y2: "6" }),
736
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "3", y1: "12", x2: "3.01", y2: "12" }),
737
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "3", y1: "18", x2: "3.01", y2: "18" })
738
+ ] }),
739
+ "List"
740
+ ]
741
+ }
742
+ )
743
+ ] }),
744
+ roadmapView === "board" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
745
+ display: "flex",
746
+ gap: 12,
747
+ flex: 1,
748
+ minHeight: 0,
749
+ overflow: "hidden",
750
+ flexDirection: isMobile ? "column" : "row",
751
+ overflowY: isMobile ? "auto" : "hidden"
752
+ }, children: roadmapColumns.map((col) => {
753
+ const colItems = roadmapItems.filter((item) => item.columnId === col.id);
754
+ const isCollapsed = isMobile && collapsedColumns.has(col.id);
755
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
756
+ flex: isMobile ? "none" : 1,
757
+ minWidth: 0,
758
+ display: "flex",
759
+ flexDirection: "column",
760
+ minHeight: isMobile ? "auto" : 0
761
+ }, children: [
762
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
763
+ "button",
477
764
  {
765
+ onClick: () => isMobile && setCollapsedColumns((prev) => {
766
+ const s = new Set(prev);
767
+ s.has(col.id) ? s.delete(col.id) : s.add(col.id);
768
+ return s;
769
+ }),
478
770
  style: {
479
- width: 8,
480
- height: 8,
481
- borderRadius: "50%",
482
- background: TYPE_COLORS[task.type] || "#71717a",
483
- flexShrink: 0
484
- }
771
+ display: "flex",
772
+ alignItems: "center",
773
+ gap: 6,
774
+ fontSize: 12,
775
+ fontWeight: 600,
776
+ color: isLight ? "#a1a1aa" : "#71717a",
777
+ marginBottom: 8,
778
+ textTransform: "uppercase",
779
+ letterSpacing: "0.5px",
780
+ flexShrink: 0,
781
+ background: "none",
782
+ border: "none",
783
+ cursor: isMobile ? "pointer" : "default",
784
+ padding: 0,
785
+ width: "100%",
786
+ textAlign: "left"
787
+ },
788
+ children: [
789
+ isMobile && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", style: { transform: isCollapsed ? "rotate(-90deg)" : "rotate(0)", transition: "transform 150ms" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 9l6 6 6-6" }) }),
790
+ col.name,
791
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
792
+ padding: "1px 6px",
793
+ fontSize: 11,
794
+ fontWeight: 500,
795
+ borderRadius: 999,
796
+ background: isLight ? "#f4f4f5" : "#1f1f1f",
797
+ color: isLight ? "#71717a" : "#a1a1aa"
798
+ }, children: colItems.length })
799
+ ]
485
800
  }
486
801
  ),
487
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 14, color: isLight ? "#18181b" : "#fff" }, children: task.title })
488
- ] })
489
- },
490
- task.id
491
- ))
492
- ] }, col);
493
- }) }),
494
- activeTab === "ideas" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { maxWidth: 640 }, children: ideasArray.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { textAlign: "center", padding: 60, color: isLight ? "#71717a" : "#a1a1aa" }, children: [
495
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 48, marginBottom: 12 }, children: "\u{1F4A1}" }),
496
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 16 }, children: "No feature requests yet" })
497
- ] }) : ideasArray.map((idea) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
498
- "div",
499
- {
500
- style: {
501
- padding: 16,
502
- marginBottom: 12,
503
- borderRadius: 8,
504
- background: isLight ? "#f5f5f5" : "#151515",
505
- border: `1px solid ${isLight ? "#e5e5e5" : "#1f1f1f"}`,
506
- display: "flex",
507
- alignItems: "flex-start",
508
- gap: 16
509
- },
510
- children: [
511
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
512
- "div",
802
+ !isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
803
+ display: "flex",
804
+ flexDirection: "column",
805
+ gap: 8,
806
+ flex: isMobile ? "none" : 1,
807
+ overflowY: isMobile ? "visible" : "auto",
808
+ minHeight: 0,
809
+ paddingRight: isMobile ? 0 : 2,
810
+ paddingBottom: isMobile ? 12 : 0
811
+ }, children: [
812
+ colItems.map((item) => {
813
+ const priorityColor = PRIORITY_COLORS[item.priority || ""] || "transparent";
814
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
815
+ "div",
816
+ {
817
+ style: {
818
+ padding: "12px 14px",
819
+ borderRadius: 8,
820
+ background: isLight ? "#f9fafb" : "#151515",
821
+ border: `1px solid ${isLight ? "#e5e5e5" : "#1f1f1f"}`,
822
+ borderLeft: `3px solid ${priorityColor}`,
823
+ transition: "border-color 150ms"
824
+ },
825
+ onMouseEnter: (e) => e.currentTarget.style.borderColor = isLight ? "#d4d4d8" : "#3f3f46",
826
+ onMouseLeave: (e) => e.currentTarget.style.borderColor = isLight ? "#e5e5e5" : "#1f1f1f",
827
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "flex-start", gap: 8 }, children: [
828
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
829
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6, marginBottom: 4 }, children: [
830
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 13 }, children: TYPE_EMOJIS[item.type || ""] || "\u{1F4CB}" }),
831
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 13, fontWeight: 500, color: isLight ? "#18181b" : "#fff" }, children: item.title })
832
+ ] }),
833
+ item.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: {
834
+ fontSize: 12,
835
+ color: isLight ? "#71717a" : "#a1a1aa",
836
+ margin: "0 0 0 0",
837
+ lineHeight: 1.4,
838
+ overflow: "hidden",
839
+ display: "-webkit-box",
840
+ WebkitLineClamp: 2,
841
+ WebkitBoxOrient: "vertical"
842
+ }, children: item.description })
843
+ ] }),
844
+ item.itemType === "idea" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: {
845
+ fontSize: 11,
846
+ fontWeight: 600,
847
+ color: isLight ? "#ea580c" : "#fb923c",
848
+ background: isLight ? "rgba(249,115,22,0.1)" : "rgba(249,115,22,0.15)",
849
+ padding: "2px 6px",
850
+ borderRadius: 4,
851
+ flexShrink: 0
852
+ }, children: [
853
+ item.votes ?? 0,
854
+ "\u2191"
855
+ ] })
856
+ ] })
857
+ },
858
+ item.id
859
+ );
860
+ }),
861
+ colItems.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
862
+ padding: 20,
863
+ textAlign: "center",
864
+ fontSize: 13,
865
+ color: isLight ? "#a1a1aa" : "#525252",
866
+ borderRadius: 8,
867
+ border: `1px dashed ${isLight ? "#e5e5e5" : "#1f1f1f"}`
868
+ }, children: "No items" })
869
+ ] })
870
+ ] }, col.id);
871
+ }) }),
872
+ roadmapView === "list" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { flex: 1, overflowY: "auto", minHeight: 0 }, children: roadmapColumns.map((col) => {
873
+ const colItems = roadmapItems.filter((item) => item.columnId === col.id);
874
+ if (colItems.length === 0) return null;
875
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginBottom: 20 }, children: [
876
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { style: {
877
+ fontSize: 12,
878
+ fontWeight: 600,
879
+ color: isLight ? "#a1a1aa" : "#71717a",
880
+ marginBottom: 8,
881
+ textTransform: "uppercase",
882
+ letterSpacing: "0.5px",
883
+ display: "flex",
884
+ alignItems: "center",
885
+ gap: 6
886
+ }, children: [
887
+ col.name,
888
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
889
+ padding: "1px 6px",
890
+ fontSize: 11,
891
+ fontWeight: 500,
892
+ borderRadius: 999,
893
+ background: isLight ? "#f4f4f5" : "#1f1f1f",
894
+ color: isLight ? "#71717a" : "#a1a1aa"
895
+ }, children: colItems.length })
896
+ ] }),
897
+ colItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
898
+ "div",
899
+ {
900
+ style: {
901
+ display: "flex",
902
+ alignItems: "center",
903
+ gap: 10,
904
+ padding: "10px 12px",
905
+ borderRadius: 6,
906
+ marginBottom: 4,
907
+ background: isLight ? "#f9fafb" : "#151515",
908
+ border: `1px solid ${isLight ? "#f0f0f0" : "#1a1a1a"}`
909
+ },
910
+ children: [
911
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 13, flexShrink: 0 }, children: TYPE_EMOJIS[item.type || ""] || "\u{1F4CB}" }),
912
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 13, fontWeight: 500, color: isLight ? "#18181b" : "#fff", flex: 1, minWidth: 0 }, children: item.title }),
913
+ item.priority && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
914
+ padding: "2px 8px",
915
+ fontSize: 10,
916
+ fontWeight: 500,
917
+ borderRadius: 999,
918
+ background: isLight ? "#f4f4f5" : "#1f1f1f",
919
+ color: PRIORITY_COLORS[item.priority] || (isLight ? "#71717a" : "#a1a1aa"),
920
+ flexShrink: 0
921
+ }, children: item.priority })
922
+ ]
923
+ },
924
+ item.id
925
+ ))
926
+ ] }, col.id);
927
+ }) })
928
+ ] }) }),
929
+ activeTab === "ideas" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { maxWidth: 640, width: "100%", overflowY: "auto", flex: 1 }, children: [
930
+ !showIdeaForm ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
931
+ "button",
513
932
  {
933
+ onClick: () => setShowIdeaForm(true),
514
934
  style: {
515
935
  display: "flex",
516
- flexDirection: "column",
517
936
  alignItems: "center",
518
- padding: "8px 12px",
519
- borderRadius: 6,
520
- background: isLight ? "#fff" : "#0a0a0a",
521
- minWidth: 50
937
+ justifyContent: "center",
938
+ gap: 8,
939
+ width: "100%",
940
+ padding: "12px 16px",
941
+ marginBottom: 20,
942
+ borderRadius: 999,
943
+ border: `1px dashed ${isLight ? "#d4d4d8" : "#3f3f46"}`,
944
+ background: "transparent",
945
+ color: isLight ? "#71717a" : "#a1a1aa",
946
+ fontSize: 14,
947
+ fontWeight: 500,
948
+ cursor: "pointer",
949
+ transition: "all 150ms"
950
+ },
951
+ onMouseEnter: (e) => {
952
+ e.currentTarget.style.borderColor = isLight ? "#a1a1aa" : "#71717a";
953
+ e.currentTarget.style.color = isLight ? "#52525b" : "#d4d4d8";
954
+ },
955
+ onMouseLeave: (e) => {
956
+ e.currentTarget.style.borderColor = isLight ? "#d4d4d8" : "#3f3f46";
957
+ e.currentTarget.style.color = isLight ? "#71717a" : "#a1a1aa";
522
958
  },
523
959
  children: [
524
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 18, fontWeight: 600, color: isLight ? "#18181b" : "#fff" }, children: idea.votes }),
525
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 11, color: isLight ? "#71717a" : "#71717a" }, children: "votes" })
960
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 18 }, children: "\u{1F4A1}" }),
961
+ "Suggest a feature"
962
+ ]
963
+ }
964
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
965
+ "div",
966
+ {
967
+ style: {
968
+ padding: 16,
969
+ marginBottom: 20,
970
+ borderRadius: 12,
971
+ background: isLight ? "#f5f5f5" : "#151515",
972
+ border: `1px solid ${isLight ? "#e5e5e5" : "#1f1f1f"}`
973
+ },
974
+ children: [
975
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 12 }, children: [
976
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontWeight: 600, color: isLight ? "#18181b" : "#fff" }, children: "Suggest a Feature" }),
977
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
978
+ "button",
979
+ {
980
+ onClick: () => {
981
+ setShowIdeaForm(false);
982
+ setIdeaSubmitMessage(null);
983
+ },
984
+ style: {
985
+ background: "transparent",
986
+ border: "none",
987
+ color: isLight ? "#71717a" : "#a1a1aa",
988
+ cursor: "pointer",
989
+ fontSize: 18
990
+ },
991
+ children: "\xD7"
992
+ }
993
+ )
994
+ ] }),
995
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
996
+ "input",
997
+ {
998
+ type: "text",
999
+ value: ideaTitle,
1000
+ onChange: (e) => setIdeaTitle(e.target.value),
1001
+ placeholder: "Feature title *",
1002
+ style: {
1003
+ width: "100%",
1004
+ padding: "10px 12px",
1005
+ marginBottom: 8,
1006
+ borderRadius: 6,
1007
+ border: `1px solid ${isLight ? "#e5e5e5" : "#2a2a2a"}`,
1008
+ background: isLight ? "#fff" : "#0a0a0a",
1009
+ color: isLight ? "#18181b" : "#fff",
1010
+ fontSize: 14,
1011
+ outline: "none",
1012
+ boxSizing: "border-box"
1013
+ }
1014
+ }
1015
+ ),
1016
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1017
+ "textarea",
1018
+ {
1019
+ value: ideaDescription,
1020
+ onChange: (e) => setIdeaDescription(e.target.value),
1021
+ placeholder: "Describe your idea...",
1022
+ rows: 3,
1023
+ style: {
1024
+ width: "100%",
1025
+ padding: "10px 12px",
1026
+ marginBottom: 8,
1027
+ borderRadius: 6,
1028
+ border: `1px solid ${isLight ? "#e5e5e5" : "#2a2a2a"}`,
1029
+ background: isLight ? "#fff" : "#0a0a0a",
1030
+ color: isLight ? "#18181b" : "#fff",
1031
+ fontSize: 14,
1032
+ outline: "none",
1033
+ resize: "none",
1034
+ boxSizing: "border-box"
1035
+ }
1036
+ }
1037
+ ),
1038
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "grid", gridTemplateColumns: isMobile ? "1fr" : "1fr 1fr", gap: 8, marginBottom: 12 }, children: [
1039
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1040
+ "input",
1041
+ {
1042
+ type: "text",
1043
+ value: ideaAuthorName,
1044
+ onChange: (e) => setIdeaAuthorName(e.target.value),
1045
+ placeholder: "Name (optional)",
1046
+ style: {
1047
+ width: "100%",
1048
+ padding: "8px 12px",
1049
+ borderRadius: 6,
1050
+ border: `1px solid ${isLight ? "#e5e5e5" : "#2a2a2a"}`,
1051
+ background: isLight ? "#fff" : "#0a0a0a",
1052
+ color: isLight ? "#18181b" : "#fff",
1053
+ fontSize: 13,
1054
+ outline: "none",
1055
+ boxSizing: "border-box"
1056
+ }
1057
+ }
1058
+ ),
1059
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1060
+ "input",
1061
+ {
1062
+ type: "email",
1063
+ value: ideaAuthorEmail,
1064
+ onChange: (e) => setIdeaAuthorEmail(e.target.value),
1065
+ placeholder: "Email *",
1066
+ style: {
1067
+ width: "100%",
1068
+ padding: "8px 12px",
1069
+ borderRadius: 6,
1070
+ border: `1px solid ${isLight ? "#e5e5e5" : "#2a2a2a"}`,
1071
+ background: isLight ? "#fff" : "#0a0a0a",
1072
+ color: isLight ? "#18181b" : "#fff",
1073
+ fontSize: 13,
1074
+ outline: "none",
1075
+ boxSizing: "border-box"
1076
+ }
1077
+ }
1078
+ )
1079
+ ] }),
1080
+ ideaSubmitMessage && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
1081
+ padding: "8px 12px",
1082
+ marginBottom: 12,
1083
+ borderRadius: 6,
1084
+ background: ideaSubmitMessage.type === "success" ? isLight ? "#dcfce7" : "#14532d" : isLight ? "#fee2e2" : "#450a0a",
1085
+ color: ideaSubmitMessage.type === "success" ? isLight ? "#166534" : "#86efac" : isLight ? "#dc2626" : "#fca5a5",
1086
+ fontSize: 13
1087
+ }, children: ideaSubmitMessage.text }),
1088
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1089
+ "button",
1090
+ {
1091
+ onClick: submitIdea,
1092
+ disabled: submittingIdea || !ideaTitle.trim() || !ideaAuthorEmail.trim(),
1093
+ style: {
1094
+ width: "100%",
1095
+ padding: "10px 16px",
1096
+ borderRadius: 999,
1097
+ border: "none",
1098
+ background: "#22c55e",
1099
+ color: "#fff",
1100
+ fontSize: 14,
1101
+ fontWeight: 500,
1102
+ cursor: submittingIdea || !ideaTitle.trim() || !ideaAuthorEmail.trim() ? "not-allowed" : "pointer",
1103
+ opacity: submittingIdea || !ideaTitle.trim() || !ideaAuthorEmail.trim() ? 0.6 : 1,
1104
+ transition: "opacity 150ms"
1105
+ },
1106
+ children: submittingIdea ? "Submitting..." : "Submit Idea"
1107
+ }
1108
+ )
526
1109
  ]
527
1110
  }
528
1111
  ),
529
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
530
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 16, fontWeight: 500, color: isLight ? "#18181b" : "#fff", marginBottom: 4 }, children: idea.title }),
531
- idea.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 14, color: isLight ? "#71717a" : "#71717a", lineHeight: 1.5 }, children: idea.description })
532
- ] })
533
- ]
534
- },
535
- idea.id
536
- )) })
537
- ] }),
538
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
539
- "div",
540
- {
541
- style: {
542
- flexShrink: 0,
543
- padding: "16px 24px",
544
- borderTop: `1px solid ${isLight ? "#e5e5e5" : "#1f1f1f"}`,
545
- display: "flex",
546
- alignItems: "center",
547
- justifyContent: "space-between"
548
- },
549
- children: [
550
- showBranding && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
551
- "a",
552
- {
553
- href: "https://versionpill.com",
554
- target: "_blank",
555
- rel: "noopener noreferrer",
556
- style: { fontSize: 12, color: isLight ? "#a1a1aa" : "#525252", textDecoration: "none" },
557
- children: "Powered by Version Pill"
558
- }
559
- ),
560
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
561
- "a",
562
- {
563
- href: `${baseUrl}/${projectId}/${activeTab === "ideas" ? "feature-requests" : activeTab}`,
564
- target: "_blank",
565
- rel: "noopener noreferrer",
566
- style: {
567
- padding: "10px 20px",
568
- fontSize: 14,
569
- fontWeight: 500,
570
- borderRadius: 8,
571
- background: "#22c55e",
572
- color: "#fff",
573
- textDecoration: "none",
574
- transition: "background 150ms"
575
- },
576
- onMouseEnter: (e) => e.currentTarget.style.background = "#16a34a",
577
- onMouseLeave: (e) => e.currentTarget.style.background = "#22c55e",
578
- children: [
579
- "View Full ",
580
- activeTab === "changelog" ? "Changelog" : activeTab === "roadmap" ? "Roadmap" : "Ideas",
581
- " \u2192"
582
- ]
583
- }
584
- )
585
- ]
586
- }
587
- )
588
- ]
589
- }
590
- ) })
1112
+ ideasArray.length === 0 && !showIdeaForm ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { textAlign: "center", padding: 60, color: isLight ? "#71717a" : "#a1a1aa" }, children: [
1113
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", style: { marginBottom: 12, opacity: 0.5 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" }) }),
1114
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 16, fontWeight: 500, marginBottom: 8 }, children: "No feature requests yet" }),
1115
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1116
+ "button",
1117
+ {
1118
+ onClick: () => setShowIdeaForm(true),
1119
+ style: {
1120
+ padding: "8px 20px",
1121
+ borderRadius: 999,
1122
+ border: "none",
1123
+ background: "#22c55e",
1124
+ color: "#fff",
1125
+ fontSize: 14,
1126
+ fontWeight: 500,
1127
+ cursor: "pointer"
1128
+ },
1129
+ children: "Suggest a feature"
1130
+ }
1131
+ )
1132
+ ] }) : (() => {
1133
+ const statusOrder = ["under review", "planned", "in progress", "new", "shipped"];
1134
+ const grouped = {};
1135
+ ideasArray.forEach((idea) => {
1136
+ const status = (idea.status || "new").toLowerCase();
1137
+ if (!grouped[status]) grouped[status] = [];
1138
+ grouped[status].push(idea);
1139
+ });
1140
+ return statusOrder.map((status) => {
1141
+ const items = grouped[status];
1142
+ if (!items || items.length === 0) return null;
1143
+ const cfg = STATUS_CONFIG[status] || { color: "#71717a", label: status };
1144
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginBottom: 20 }, children: [
1145
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 10 }, children: [
1146
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
1147
+ width: 8,
1148
+ height: 8,
1149
+ borderRadius: "50%",
1150
+ background: cfg.color,
1151
+ flexShrink: 0
1152
+ } }),
1153
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 13, fontWeight: 600, color: isLight ? "#52525b" : "#a1a1aa", textTransform: "uppercase", letterSpacing: "0.5px" }, children: cfg.label }),
1154
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
1155
+ padding: "1px 6px",
1156
+ fontSize: 11,
1157
+ fontWeight: 500,
1158
+ borderRadius: 999,
1159
+ background: isLight ? "#f4f4f5" : "#1f1f1f",
1160
+ color: isLight ? "#71717a" : "#a1a1aa"
1161
+ }, children: items.length })
1162
+ ] }),
1163
+ items.map((idea) => {
1164
+ const hasVoted = votedIdeas.has(idea.id) || idea.hasVoted;
1165
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1166
+ "div",
1167
+ {
1168
+ style: {
1169
+ padding: isMobile ? 12 : 16,
1170
+ marginBottom: 8,
1171
+ borderRadius: 10,
1172
+ background: isLight ? "#f9fafb" : "#151515",
1173
+ border: `1px solid ${isLight ? "#e5e5e5" : "#1f1f1f"}`,
1174
+ display: "flex",
1175
+ alignItems: "flex-start",
1176
+ gap: isMobile ? 10 : 16
1177
+ },
1178
+ children: [
1179
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1180
+ "button",
1181
+ {
1182
+ onClick: () => voteIdea(idea.id),
1183
+ disabled: hasVoted,
1184
+ style: {
1185
+ display: "flex",
1186
+ flexDirection: "column",
1187
+ alignItems: "center",
1188
+ padding: "8px 12px",
1189
+ borderRadius: 8,
1190
+ background: hasVoted ? isLight ? "#dcfce7" : "rgba(34,197,94,0.15)" : isLight ? "#fff" : "#0a0a0a",
1191
+ border: `1px solid ${hasVoted ? "#22c55e" : isLight ? "#e5e5e5" : "#2a2a2a"}`,
1192
+ minWidth: 48,
1193
+ cursor: hasVoted ? "default" : "pointer",
1194
+ transition: "all 150ms"
1195
+ },
1196
+ onMouseEnter: (e) => {
1197
+ if (!hasVoted) {
1198
+ e.currentTarget.style.borderColor = "#22c55e";
1199
+ e.currentTarget.style.background = isLight ? "#f0fdf4" : "rgba(34,197,94,0.1)";
1200
+ }
1201
+ },
1202
+ onMouseLeave: (e) => {
1203
+ if (!hasVoted) {
1204
+ e.currentTarget.style.borderColor = isLight ? "#e5e5e5" : "#2a2a2a";
1205
+ e.currentTarget.style.background = isLight ? "#fff" : "#0a0a0a";
1206
+ }
1207
+ },
1208
+ children: [
1209
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: hasVoted ? "#22c55e" : "none", stroke: hasVoted ? "#22c55e" : isLight ? "#71717a" : "#a1a1aa", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M18 15l-6-6-6 6" }) }),
1210
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 16, fontWeight: 600, color: hasVoted ? "#22c55e" : isLight ? "#18181b" : "#fff" }, children: idea.votes })
1211
+ ]
1212
+ }
1213
+ ),
1214
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
1215
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 4, flexWrap: "wrap" }, children: [
1216
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 15, fontWeight: 500, color: isLight ? "#18181b" : "#fff" }, children: idea.title }),
1217
+ idea.status && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
1218
+ padding: "2px 8px",
1219
+ fontSize: 10,
1220
+ fontWeight: 500,
1221
+ borderRadius: 999,
1222
+ background: isLight ? `${cfg.color}15` : `${cfg.color}20`,
1223
+ color: cfg.color,
1224
+ textTransform: "uppercase",
1225
+ letterSpacing: "0.3px"
1226
+ }, children: cfg.label })
1227
+ ] }),
1228
+ idea.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 14, color: isLight ? "#71717a" : "#a1a1aa", lineHeight: 1.5 }, children: idea.description })
1229
+ ] })
1230
+ ]
1231
+ },
1232
+ idea.id
1233
+ );
1234
+ })
1235
+ ] }, status);
1236
+ });
1237
+ })()
1238
+ ] })
1239
+ ] }),
1240
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1241
+ "div",
1242
+ {
1243
+ style: {
1244
+ flexShrink: 0,
1245
+ padding: "16px 24px",
1246
+ borderTop: `1px solid ${isLight ? "#e5e5e5" : "#1f1f1f"}`,
1247
+ display: "flex",
1248
+ alignItems: "center",
1249
+ justifyContent: "space-between"
1250
+ },
1251
+ children: [
1252
+ showBranding && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1253
+ "a",
1254
+ {
1255
+ href: "https://versionpill.com",
1256
+ target: "_blank",
1257
+ rel: "noopener noreferrer",
1258
+ style: { fontSize: 12, color: isLight ? "#a1a1aa" : "#525252", textDecoration: "none" },
1259
+ children: "Powered by Version Pill"
1260
+ }
1261
+ ),
1262
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1263
+ "a",
1264
+ {
1265
+ href: `${baseUrl}/${projectId}/${activeTab === "ideas" ? "feature-requests" : activeTab}`,
1266
+ target: "_blank",
1267
+ rel: "noopener noreferrer",
1268
+ style: {
1269
+ padding: "10px 20px",
1270
+ fontSize: 14,
1271
+ fontWeight: 500,
1272
+ borderRadius: 8,
1273
+ background: "#22c55e",
1274
+ color: "#fff",
1275
+ textDecoration: "none",
1276
+ transition: "background 150ms"
1277
+ },
1278
+ onMouseEnter: (e) => e.currentTarget.style.background = "#16a34a",
1279
+ onMouseLeave: (e) => e.currentTarget.style.background = "#22c55e",
1280
+ children: [
1281
+ "View Full ",
1282
+ activeTab === "changelog" ? "Changelog" : activeTab === "roadmap" ? "Roadmap" : "Ideas",
1283
+ " \u2192"
1284
+ ]
1285
+ }
1286
+ )
1287
+ ]
1288
+ }
1289
+ )
1290
+ ]
1291
+ }
1292
+ )
1293
+ ] }),
1294
+ document.body
1295
+ )
591
1296
  ] });
592
1297
  }
593
1298
  function VersionBadge({