version-pill-react 1.0.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.d.mts +54 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +296 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +260 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +67 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface Version {
|
|
4
|
+
id: string;
|
|
5
|
+
version: string;
|
|
6
|
+
type: "major" | "minor" | "patch";
|
|
7
|
+
title: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
emoji?: string;
|
|
10
|
+
features?: string[];
|
|
11
|
+
releaseDate: number;
|
|
12
|
+
isActive: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface VersionPillConfig {
|
|
15
|
+
/** Your project slug from Version Pill dashboard */
|
|
16
|
+
projectId: string;
|
|
17
|
+
/** Version Pill API base URL (default: https://versionpill.com) */
|
|
18
|
+
baseUrl?: string;
|
|
19
|
+
}
|
|
20
|
+
interface VersionPillProps extends VersionPillConfig {
|
|
21
|
+
/** Position of the pill */
|
|
22
|
+
position?: "top-left" | "top-right" | "bottom-left" | "bottom-right" | "inline";
|
|
23
|
+
/** Custom class name */
|
|
24
|
+
className?: string;
|
|
25
|
+
/** Theme */
|
|
26
|
+
theme?: "light" | "dark" | "auto";
|
|
27
|
+
/** Show "Powered by Version Pill" branding */
|
|
28
|
+
showBranding?: boolean;
|
|
29
|
+
/** Accent color (hex) */
|
|
30
|
+
accentColor?: string;
|
|
31
|
+
/** Callback when a new version is detected */
|
|
32
|
+
onNewVersion?: (version: Version) => void;
|
|
33
|
+
}
|
|
34
|
+
interface ChangelogProps extends VersionPillConfig {
|
|
35
|
+
/** Max height in pixels */
|
|
36
|
+
maxHeight?: number;
|
|
37
|
+
/** Theme */
|
|
38
|
+
theme?: "light" | "dark" | "auto";
|
|
39
|
+
/** Custom class name */
|
|
40
|
+
className?: string;
|
|
41
|
+
}
|
|
42
|
+
interface RoadmapProps extends VersionPillConfig {
|
|
43
|
+
/** Max height in pixels */
|
|
44
|
+
maxHeight?: number;
|
|
45
|
+
/** Theme */
|
|
46
|
+
theme?: "light" | "dark" | "auto";
|
|
47
|
+
/** Custom class name */
|
|
48
|
+
className?: string;
|
|
49
|
+
}
|
|
50
|
+
declare function VersionPill({ projectId, baseUrl, position, className, theme, showBranding, accentColor, onNewVersion, }: VersionPillProps): react_jsx_runtime.JSX.Element | null;
|
|
51
|
+
declare function Changelog({ projectId, baseUrl, maxHeight, theme, className, }: ChangelogProps): react_jsx_runtime.JSX.Element;
|
|
52
|
+
declare function Roadmap({ projectId, baseUrl, maxHeight, theme, className, }: RoadmapProps): react_jsx_runtime.JSX.Element;
|
|
53
|
+
|
|
54
|
+
export { Changelog, type ChangelogProps, Roadmap, type RoadmapProps, type Version, VersionPill, type VersionPillConfig, type VersionPillProps, VersionPill as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface Version {
|
|
4
|
+
id: string;
|
|
5
|
+
version: string;
|
|
6
|
+
type: "major" | "minor" | "patch";
|
|
7
|
+
title: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
emoji?: string;
|
|
10
|
+
features?: string[];
|
|
11
|
+
releaseDate: number;
|
|
12
|
+
isActive: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface VersionPillConfig {
|
|
15
|
+
/** Your project slug from Version Pill dashboard */
|
|
16
|
+
projectId: string;
|
|
17
|
+
/** Version Pill API base URL (default: https://versionpill.com) */
|
|
18
|
+
baseUrl?: string;
|
|
19
|
+
}
|
|
20
|
+
interface VersionPillProps extends VersionPillConfig {
|
|
21
|
+
/** Position of the pill */
|
|
22
|
+
position?: "top-left" | "top-right" | "bottom-left" | "bottom-right" | "inline";
|
|
23
|
+
/** Custom class name */
|
|
24
|
+
className?: string;
|
|
25
|
+
/** Theme */
|
|
26
|
+
theme?: "light" | "dark" | "auto";
|
|
27
|
+
/** Show "Powered by Version Pill" branding */
|
|
28
|
+
showBranding?: boolean;
|
|
29
|
+
/** Accent color (hex) */
|
|
30
|
+
accentColor?: string;
|
|
31
|
+
/** Callback when a new version is detected */
|
|
32
|
+
onNewVersion?: (version: Version) => void;
|
|
33
|
+
}
|
|
34
|
+
interface ChangelogProps extends VersionPillConfig {
|
|
35
|
+
/** Max height in pixels */
|
|
36
|
+
maxHeight?: number;
|
|
37
|
+
/** Theme */
|
|
38
|
+
theme?: "light" | "dark" | "auto";
|
|
39
|
+
/** Custom class name */
|
|
40
|
+
className?: string;
|
|
41
|
+
}
|
|
42
|
+
interface RoadmapProps extends VersionPillConfig {
|
|
43
|
+
/** Max height in pixels */
|
|
44
|
+
maxHeight?: number;
|
|
45
|
+
/** Theme */
|
|
46
|
+
theme?: "light" | "dark" | "auto";
|
|
47
|
+
/** Custom class name */
|
|
48
|
+
className?: string;
|
|
49
|
+
}
|
|
50
|
+
declare function VersionPill({ projectId, baseUrl, position, className, theme, showBranding, accentColor, onNewVersion, }: VersionPillProps): react_jsx_runtime.JSX.Element | null;
|
|
51
|
+
declare function Changelog({ projectId, baseUrl, maxHeight, theme, className, }: ChangelogProps): react_jsx_runtime.JSX.Element;
|
|
52
|
+
declare function Roadmap({ projectId, baseUrl, maxHeight, theme, className, }: RoadmapProps): react_jsx_runtime.JSX.Element;
|
|
53
|
+
|
|
54
|
+
export { Changelog, type ChangelogProps, Roadmap, type RoadmapProps, type Version, VersionPill, type VersionPillConfig, type VersionPillProps, VersionPill as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/index.tsx
|
|
32
|
+
var index_exports = {};
|
|
33
|
+
__export(index_exports, {
|
|
34
|
+
Changelog: () => Changelog,
|
|
35
|
+
Roadmap: () => Roadmap,
|
|
36
|
+
VersionPill: () => VersionPill,
|
|
37
|
+
default: () => index_default
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(index_exports);
|
|
40
|
+
var import_react = require("react");
|
|
41
|
+
var import_clsx = __toESM(require("clsx"));
|
|
42
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
43
|
+
var DEFAULT_BASE_URL = "https://versionpill.com";
|
|
44
|
+
var styles = {
|
|
45
|
+
pill: `
|
|
46
|
+
inline-flex items-center gap-1.5 px-2.5 py-1
|
|
47
|
+
text-xs font-medium rounded-full cursor-pointer
|
|
48
|
+
transition-all duration-200 select-none
|
|
49
|
+
border shadow-sm hover:shadow-md
|
|
50
|
+
`,
|
|
51
|
+
pillLight: `bg-white text-gray-700 border-gray-200 hover:border-gray-300`,
|
|
52
|
+
pillDark: `bg-gray-900 text-gray-100 border-gray-700 hover:border-gray-600`,
|
|
53
|
+
modal: `fixed inset-0 z-[99999] flex items-center justify-center p-4`,
|
|
54
|
+
backdrop: `absolute inset-0 bg-black/50 backdrop-blur-sm`,
|
|
55
|
+
panel: `relative w-full max-w-md max-h-[80vh] overflow-hidden rounded-xl shadow-2xl`,
|
|
56
|
+
panelLight: `bg-white`,
|
|
57
|
+
panelDark: `bg-gray-900`,
|
|
58
|
+
header: `p-4 border-b flex items-center justify-between`,
|
|
59
|
+
headerLight: `border-gray-100`,
|
|
60
|
+
headerDark: `border-gray-800`,
|
|
61
|
+
content: `p-4 overflow-y-auto max-h-[60vh]`,
|
|
62
|
+
version: `mb-4 last:mb-0`,
|
|
63
|
+
versionHeader: `flex items-center gap-2 mb-2`,
|
|
64
|
+
versionTitle: `font-semibold`,
|
|
65
|
+
versionBadge: `px-1.5 py-0.5 text-[10px] font-medium rounded`,
|
|
66
|
+
versionFeatures: `space-y-1 mt-2`,
|
|
67
|
+
versionFeature: `flex items-start gap-2 text-sm`,
|
|
68
|
+
footer: `p-3 border-t flex items-center justify-between`,
|
|
69
|
+
footerLight: `border-gray-100 bg-gray-50`,
|
|
70
|
+
footerDark: `border-gray-800 bg-gray-950`,
|
|
71
|
+
button: `px-3 py-1.5 text-xs font-medium rounded-lg transition-colors`,
|
|
72
|
+
buttonPrimary: `bg-blue-600 text-white hover:bg-blue-700`,
|
|
73
|
+
buttonSecondary: `text-gray-500 hover:text-gray-700`,
|
|
74
|
+
branding: `text-[10px] opacity-40 flex items-center gap-1`,
|
|
75
|
+
newDot: `w-2 h-2 rounded-full bg-green-500 animate-pulse`,
|
|
76
|
+
iframe: `w-full border-0`
|
|
77
|
+
};
|
|
78
|
+
function useTheme(theme) {
|
|
79
|
+
const [resolved, setResolved] = (0, import_react.useState)("light");
|
|
80
|
+
(0, import_react.useEffect)(() => {
|
|
81
|
+
if (theme === "auto") {
|
|
82
|
+
const isDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
83
|
+
setResolved(isDark ? "dark" : "light");
|
|
84
|
+
const listener = (e) => setResolved(e.matches ? "dark" : "light");
|
|
85
|
+
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
86
|
+
mq.addEventListener("change", listener);
|
|
87
|
+
return () => mq.removeEventListener("change", listener);
|
|
88
|
+
} else {
|
|
89
|
+
setResolved(theme);
|
|
90
|
+
}
|
|
91
|
+
}, [theme]);
|
|
92
|
+
return resolved;
|
|
93
|
+
}
|
|
94
|
+
function VersionPill({
|
|
95
|
+
projectId,
|
|
96
|
+
baseUrl = DEFAULT_BASE_URL,
|
|
97
|
+
position = "inline",
|
|
98
|
+
className,
|
|
99
|
+
theme = "auto",
|
|
100
|
+
showBranding = true,
|
|
101
|
+
accentColor,
|
|
102
|
+
onNewVersion
|
|
103
|
+
}) {
|
|
104
|
+
const [versions, setVersions] = (0, import_react.useState)([]);
|
|
105
|
+
const [loading, setLoading] = (0, import_react.useState)(true);
|
|
106
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
107
|
+
const [isOpen, setIsOpen] = (0, import_react.useState)(false);
|
|
108
|
+
const [hasNewVersion, setHasNewVersion] = (0, import_react.useState)(false);
|
|
109
|
+
const resolvedTheme = useTheme(theme);
|
|
110
|
+
const isLight = resolvedTheme === "light";
|
|
111
|
+
const fetchChangelog = (0, import_react.useCallback)(async () => {
|
|
112
|
+
try {
|
|
113
|
+
const response = await fetch(`${baseUrl}/api/changelog/${projectId}?limit=10`);
|
|
114
|
+
if (!response.ok) throw new Error("Failed to fetch changelog");
|
|
115
|
+
const data = await response.json();
|
|
116
|
+
setVersions(data);
|
|
117
|
+
const storedVersion = localStorage.getItem(`vp_${projectId}_seen`);
|
|
118
|
+
if (data.length > 0 && data[0].version !== storedVersion) {
|
|
119
|
+
setHasNewVersion(true);
|
|
120
|
+
onNewVersion?.(data[0]);
|
|
121
|
+
}
|
|
122
|
+
} catch (err) {
|
|
123
|
+
setError(err.message);
|
|
124
|
+
} finally {
|
|
125
|
+
setLoading(false);
|
|
126
|
+
}
|
|
127
|
+
}, [projectId, baseUrl, onNewVersion]);
|
|
128
|
+
(0, import_react.useEffect)(() => {
|
|
129
|
+
fetchChangelog();
|
|
130
|
+
}, [fetchChangelog]);
|
|
131
|
+
const handleOpen = () => {
|
|
132
|
+
setIsOpen(true);
|
|
133
|
+
if (versions.length > 0) {
|
|
134
|
+
localStorage.setItem(`vp_${projectId}_seen`, versions[0].version);
|
|
135
|
+
setHasNewVersion(false);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const currentVersion = versions[0];
|
|
139
|
+
const positionStyles = {
|
|
140
|
+
"top-left": "fixed top-4 left-4 z-[9999]",
|
|
141
|
+
"top-right": "fixed top-4 right-4 z-[9999]",
|
|
142
|
+
"bottom-left": "fixed bottom-4 left-4 z-[9999]",
|
|
143
|
+
"bottom-right": "fixed bottom-4 right-4 z-[9999]",
|
|
144
|
+
inline: ""
|
|
145
|
+
};
|
|
146
|
+
if (loading) {
|
|
147
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_clsx.default)(positionStyles[position], className), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_clsx.default)(styles.pill, isLight ? styles.pillLight : styles.pillDark), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "opacity-50", children: "..." }) }) });
|
|
148
|
+
}
|
|
149
|
+
if (error || !currentVersion) return null;
|
|
150
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
151
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_clsx.default)(positionStyles[position], className), children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
152
|
+
"button",
|
|
153
|
+
{
|
|
154
|
+
onClick: handleOpen,
|
|
155
|
+
className: (0, import_clsx.default)(styles.pill, isLight ? styles.pillLight : styles.pillDark),
|
|
156
|
+
style: accentColor ? { borderColor: accentColor } : void 0,
|
|
157
|
+
children: [
|
|
158
|
+
hasNewVersion && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: styles.newDot }),
|
|
159
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
160
|
+
"v",
|
|
161
|
+
currentVersion.version
|
|
162
|
+
] }),
|
|
163
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 9l6 6 6-6" }) })
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
) }),
|
|
167
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.modal, children: [
|
|
168
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.backdrop, onClick: () => setIsOpen(false) }),
|
|
169
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_clsx.default)(styles.panel, isLight ? styles.panelLight : styles.panelDark), children: [
|
|
170
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_clsx.default)(styles.header, isLight ? styles.headerLight : styles.headerDark), children: [
|
|
171
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
172
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-lg", children: currentVersion.emoji || "\u2728" }),
|
|
173
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
174
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: (0, import_clsx.default)("font-semibold", isLight ? "text-gray-900" : "text-white"), children: "What's New" }),
|
|
175
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: (0, import_clsx.default)("text-xs", isLight ? "text-gray-500" : "text-gray-400"), children: "Latest updates" })
|
|
176
|
+
] })
|
|
177
|
+
] }),
|
|
178
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
179
|
+
"button",
|
|
180
|
+
{
|
|
181
|
+
onClick: () => setIsOpen(false),
|
|
182
|
+
className: (0, import_clsx.default)("p-1 rounded hover:bg-gray-100", !isLight && "hover:bg-gray-800"),
|
|
183
|
+
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" }) })
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
] }),
|
|
187
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.content, children: versions.slice(0, 5).map((version) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.version, children: [
|
|
188
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.versionHeader, children: [
|
|
189
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-lg", children: version.emoji || "\u{1F4E6}" }),
|
|
190
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: (0, import_clsx.default)(styles.versionTitle, isLight ? "text-gray-900" : "text-white"), children: version.title }),
|
|
191
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
192
|
+
"span",
|
|
193
|
+
{
|
|
194
|
+
className: (0, import_clsx.default)(
|
|
195
|
+
styles.versionBadge,
|
|
196
|
+
version.type === "major" ? "bg-purple-100 text-purple-700" : version.type === "minor" ? "bg-blue-100 text-blue-700" : "bg-gray-100 text-gray-700"
|
|
197
|
+
),
|
|
198
|
+
children: version.type
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
] }),
|
|
202
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_clsx.default)("text-xs mb-2", isLight ? "text-gray-500" : "text-gray-400"), children: [
|
|
203
|
+
"v",
|
|
204
|
+
version.version,
|
|
205
|
+
" \xB7 ",
|
|
206
|
+
new Date(version.releaseDate).toLocaleDateString()
|
|
207
|
+
] }),
|
|
208
|
+
version.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: (0, import_clsx.default)("text-sm mb-2", isLight ? "text-gray-600" : "text-gray-300"), children: version.description }),
|
|
209
|
+
version.features && version.features.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: styles.versionFeatures, children: version.features.map((feature, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: (0, import_clsx.default)(styles.versionFeature, isLight ? "text-gray-600" : "text-gray-300"), children: [
|
|
210
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-green-500 mt-0.5", children: "\u2713" }),
|
|
211
|
+
feature
|
|
212
|
+
] }, i)) })
|
|
213
|
+
] }, version.id)) }),
|
|
214
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_clsx.default)(styles.footer, isLight ? styles.footerLight : styles.footerDark), children: [
|
|
215
|
+
showBranding && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
216
|
+
"a",
|
|
217
|
+
{
|
|
218
|
+
href: "https://versionpill.com",
|
|
219
|
+
target: "_blank",
|
|
220
|
+
rel: "noopener noreferrer",
|
|
221
|
+
className: (0, import_clsx.default)(styles.branding, isLight ? "text-gray-400" : "text-gray-500"),
|
|
222
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Powered by Version Pill" })
|
|
223
|
+
}
|
|
224
|
+
),
|
|
225
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
226
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
227
|
+
"a",
|
|
228
|
+
{
|
|
229
|
+
href: `${baseUrl}/${projectId}/roadmap`,
|
|
230
|
+
target: "_blank",
|
|
231
|
+
rel: "noopener noreferrer",
|
|
232
|
+
className: (0, import_clsx.default)(styles.button, styles.buttonSecondary),
|
|
233
|
+
children: "\u{1F4A1} Roadmap"
|
|
234
|
+
}
|
|
235
|
+
),
|
|
236
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
237
|
+
"a",
|
|
238
|
+
{
|
|
239
|
+
href: `${baseUrl}/${projectId}/changelog`,
|
|
240
|
+
target: "_blank",
|
|
241
|
+
rel: "noopener noreferrer",
|
|
242
|
+
className: (0, import_clsx.default)(styles.button, styles.buttonPrimary),
|
|
243
|
+
style: accentColor ? { backgroundColor: accentColor } : void 0,
|
|
244
|
+
children: "View All"
|
|
245
|
+
}
|
|
246
|
+
)
|
|
247
|
+
] })
|
|
248
|
+
] })
|
|
249
|
+
] })
|
|
250
|
+
] })
|
|
251
|
+
] });
|
|
252
|
+
}
|
|
253
|
+
function Changelog({
|
|
254
|
+
projectId,
|
|
255
|
+
baseUrl = DEFAULT_BASE_URL,
|
|
256
|
+
maxHeight = 600,
|
|
257
|
+
theme = "auto",
|
|
258
|
+
className
|
|
259
|
+
}) {
|
|
260
|
+
const resolvedTheme = useTheme(theme);
|
|
261
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
262
|
+
"iframe",
|
|
263
|
+
{
|
|
264
|
+
src: `${baseUrl}/embed/${projectId}/changelog?theme=${resolvedTheme}`,
|
|
265
|
+
className: (0, import_clsx.default)(styles.iframe, className),
|
|
266
|
+
style: { height: maxHeight },
|
|
267
|
+
title: "Changelog"
|
|
268
|
+
}
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
function Roadmap({
|
|
272
|
+
projectId,
|
|
273
|
+
baseUrl = DEFAULT_BASE_URL,
|
|
274
|
+
maxHeight = 800,
|
|
275
|
+
theme = "auto",
|
|
276
|
+
className
|
|
277
|
+
}) {
|
|
278
|
+
const resolvedTheme = useTheme(theme);
|
|
279
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
280
|
+
"iframe",
|
|
281
|
+
{
|
|
282
|
+
src: `${baseUrl}/embed/${projectId}/roadmap?theme=${resolvedTheme}`,
|
|
283
|
+
className: (0, import_clsx.default)(styles.iframe, className),
|
|
284
|
+
style: { height: maxHeight },
|
|
285
|
+
title: "Roadmap"
|
|
286
|
+
}
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
var index_default = VersionPill;
|
|
290
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
291
|
+
0 && (module.exports = {
|
|
292
|
+
Changelog,
|
|
293
|
+
Roadmap,
|
|
294
|
+
VersionPill
|
|
295
|
+
});
|
|
296
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useState, useEffect, useCallback } from \"react\";\nimport clsx from \"clsx\";\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\nexport interface Version {\n id: string;\n version: string;\n type: \"major\" | \"minor\" | \"patch\";\n title: string;\n description?: string;\n emoji?: string;\n features?: string[];\n releaseDate: number;\n isActive: boolean;\n}\n\nexport interface VersionPillConfig {\n /** Your project slug from Version Pill dashboard */\n projectId: string;\n /** Version Pill API base URL (default: https://versionpill.com) */\n baseUrl?: string;\n}\n\nexport interface VersionPillProps extends VersionPillConfig {\n /** Position of the pill */\n position?: \"top-left\" | \"top-right\" | \"bottom-left\" | \"bottom-right\" | \"inline\";\n /** Custom class name */\n className?: string;\n /** Theme */\n theme?: \"light\" | \"dark\" | \"auto\";\n /** Show \"Powered by Version Pill\" branding */\n showBranding?: boolean;\n /** Accent color (hex) */\n accentColor?: string;\n /** Callback when a new version is detected */\n onNewVersion?: (version: Version) => void;\n}\n\nexport interface ChangelogProps extends VersionPillConfig {\n /** Max height in pixels */\n maxHeight?: number;\n /** Theme */\n theme?: \"light\" | \"dark\" | \"auto\";\n /** Custom class name */\n className?: string;\n}\n\nexport interface RoadmapProps extends VersionPillConfig {\n /** Max height in pixels */\n maxHeight?: number;\n /** Theme */\n theme?: \"light\" | \"dark\" | \"auto\";\n /** Custom class name */\n className?: string;\n}\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\nconst DEFAULT_BASE_URL = \"https://versionpill.com\";\n\n// =============================================================================\n// STYLES\n// =============================================================================\n\nconst styles = {\n pill: `\n inline-flex items-center gap-1.5 px-2.5 py-1\n text-xs font-medium rounded-full cursor-pointer\n transition-all duration-200 select-none\n border shadow-sm hover:shadow-md\n `,\n pillLight: `bg-white text-gray-700 border-gray-200 hover:border-gray-300`,\n pillDark: `bg-gray-900 text-gray-100 border-gray-700 hover:border-gray-600`,\n\n modal: `fixed inset-0 z-[99999] flex items-center justify-center p-4`,\n backdrop: `absolute inset-0 bg-black/50 backdrop-blur-sm`,\n panel: `relative w-full max-w-md max-h-[80vh] overflow-hidden rounded-xl shadow-2xl`,\n panelLight: `bg-white`,\n panelDark: `bg-gray-900`,\n\n header: `p-4 border-b flex items-center justify-between`,\n headerLight: `border-gray-100`,\n headerDark: `border-gray-800`,\n\n content: `p-4 overflow-y-auto max-h-[60vh]`,\n\n version: `mb-4 last:mb-0`,\n versionHeader: `flex items-center gap-2 mb-2`,\n versionTitle: `font-semibold`,\n versionBadge: `px-1.5 py-0.5 text-[10px] font-medium rounded`,\n versionFeatures: `space-y-1 mt-2`,\n versionFeature: `flex items-start gap-2 text-sm`,\n\n footer: `p-3 border-t flex items-center justify-between`,\n footerLight: `border-gray-100 bg-gray-50`,\n footerDark: `border-gray-800 bg-gray-950`,\n\n button: `px-3 py-1.5 text-xs font-medium rounded-lg transition-colors`,\n buttonPrimary: `bg-blue-600 text-white hover:bg-blue-700`,\n buttonSecondary: `text-gray-500 hover:text-gray-700`,\n\n branding: `text-[10px] opacity-40 flex items-center gap-1`,\n newDot: `w-2 h-2 rounded-full bg-green-500 animate-pulse`,\n\n iframe: `w-full border-0`,\n};\n\n// =============================================================================\n// HOOKS\n// =============================================================================\n\nfunction useTheme(theme: \"light\" | \"dark\" | \"auto\"): \"light\" | \"dark\" {\n const [resolved, setResolved] = useState<\"light\" | \"dark\">(\"light\");\n\n useEffect(() => {\n if (theme === \"auto\") {\n const isDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n setResolved(isDark ? \"dark\" : \"light\");\n\n const listener = (e: MediaQueryListEvent) => setResolved(e.matches ? \"dark\" : \"light\");\n const mq = window.matchMedia(\"(prefers-color-scheme: dark)\");\n mq.addEventListener(\"change\", listener);\n return () => mq.removeEventListener(\"change\", listener);\n } else {\n setResolved(theme);\n }\n }, [theme]);\n\n return resolved;\n}\n\n// =============================================================================\n// VERSION PILL COMPONENT\n// =============================================================================\n\nexport function VersionPill({\n projectId,\n baseUrl = DEFAULT_BASE_URL,\n position = \"inline\",\n className,\n theme = \"auto\",\n showBranding = true,\n accentColor,\n onNewVersion,\n}: VersionPillProps) {\n const [versions, setVersions] = useState<Version[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [isOpen, setIsOpen] = useState(false);\n const [hasNewVersion, setHasNewVersion] = useState(false);\n\n const resolvedTheme = useTheme(theme);\n const isLight = resolvedTheme === \"light\";\n\n const fetchChangelog = useCallback(async () => {\n try {\n const response = await fetch(`${baseUrl}/api/changelog/${projectId}?limit=10`);\n if (!response.ok) throw new Error(\"Failed to fetch changelog\");\n\n const data = await response.json();\n setVersions(data);\n\n const storedVersion = localStorage.getItem(`vp_${projectId}_seen`);\n if (data.length > 0 && data[0].version !== storedVersion) {\n setHasNewVersion(true);\n onNewVersion?.(data[0]);\n }\n } catch (err: any) {\n setError(err.message);\n } finally {\n setLoading(false);\n }\n }, [projectId, baseUrl, onNewVersion]);\n\n useEffect(() => {\n fetchChangelog();\n }, [fetchChangelog]);\n\n const handleOpen = () => {\n setIsOpen(true);\n if (versions.length > 0) {\n localStorage.setItem(`vp_${projectId}_seen`, versions[0].version);\n setHasNewVersion(false);\n }\n };\n\n const currentVersion = versions[0];\n\n const positionStyles: Record<string, string> = {\n \"top-left\": \"fixed top-4 left-4 z-[9999]\",\n \"top-right\": \"fixed top-4 right-4 z-[9999]\",\n \"bottom-left\": \"fixed bottom-4 left-4 z-[9999]\",\n \"bottom-right\": \"fixed bottom-4 right-4 z-[9999]\",\n inline: \"\",\n };\n\n if (loading) {\n return (\n <div className={clsx(positionStyles[position], className)}>\n <div className={clsx(styles.pill, isLight ? styles.pillLight : styles.pillDark)}>\n <span className=\"opacity-50\">...</span>\n </div>\n </div>\n );\n }\n\n if (error || !currentVersion) return null;\n\n return (\n <>\n <div className={clsx(positionStyles[position], className)}>\n <button\n onClick={handleOpen}\n className={clsx(styles.pill, isLight ? styles.pillLight : styles.pillDark)}\n style={accentColor ? { borderColor: accentColor } : undefined}\n >\n {hasNewVersion && <span className={styles.newDot} />}\n <span>v{currentVersion.version}</span>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </button>\n </div>\n\n {isOpen && (\n <div className={styles.modal}>\n <div className={styles.backdrop} onClick={() => setIsOpen(false)} />\n <div className={clsx(styles.panel, isLight ? styles.panelLight : styles.panelDark)}>\n <div className={clsx(styles.header, isLight ? styles.headerLight : styles.headerDark)}>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-lg\">{currentVersion.emoji || \"✨\"}</span>\n <div>\n <h2 className={clsx(\"font-semibold\", isLight ? \"text-gray-900\" : \"text-white\")}>What's New</h2>\n <p className={clsx(\"text-xs\", isLight ? \"text-gray-500\" : \"text-gray-400\")}>\n Latest updates\n </p>\n </div>\n </div>\n <button\n onClick={() => setIsOpen(false)}\n className={clsx(\"p-1 rounded hover:bg-gray-100\", !isLight && \"hover:bg-gray-800\")}\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div className={styles.content}>\n {versions.slice(0, 5).map((version) => (\n <div key={version.id} className={styles.version}>\n <div className={styles.versionHeader}>\n <span className=\"text-lg\">{version.emoji || \"📦\"}</span>\n <span className={clsx(styles.versionTitle, isLight ? \"text-gray-900\" : \"text-white\")}>\n {version.title}\n </span>\n <span\n className={clsx(\n styles.versionBadge,\n version.type === \"major\" ? \"bg-purple-100 text-purple-700\" :\n version.type === \"minor\" ? \"bg-blue-100 text-blue-700\" :\n \"bg-gray-100 text-gray-700\"\n )}\n >\n {version.type}\n </span>\n </div>\n <div className={clsx(\"text-xs mb-2\", isLight ? \"text-gray-500\" : \"text-gray-400\")}>\n v{version.version} · {new Date(version.releaseDate).toLocaleDateString()}\n </div>\n {version.description && (\n <p className={clsx(\"text-sm mb-2\", isLight ? \"text-gray-600\" : \"text-gray-300\")}>\n {version.description}\n </p>\n )}\n {version.features && version.features.length > 0 && (\n <ul className={styles.versionFeatures}>\n {version.features.map((feature, i) => (\n <li key={i} className={clsx(styles.versionFeature, isLight ? \"text-gray-600\" : \"text-gray-300\")}>\n <span className=\"text-green-500 mt-0.5\">✓</span>\n {feature}\n </li>\n ))}\n </ul>\n )}\n </div>\n ))}\n </div>\n\n <div className={clsx(styles.footer, isLight ? styles.footerLight : styles.footerDark)}>\n {showBranding && (\n <a\n href=\"https://versionpill.com\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={clsx(styles.branding, isLight ? \"text-gray-400\" : \"text-gray-500\")}\n >\n <span>Powered by Version Pill</span>\n </a>\n )}\n <div className=\"flex items-center gap-2\">\n <a\n href={`${baseUrl}/${projectId}/roadmap`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={clsx(styles.button, styles.buttonSecondary)}\n >\n 💡 Roadmap\n </a>\n <a\n href={`${baseUrl}/${projectId}/changelog`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={clsx(styles.button, styles.buttonPrimary)}\n style={accentColor ? { backgroundColor: accentColor } : undefined}\n >\n View All\n </a>\n </div>\n </div>\n </div>\n </div>\n )}\n </>\n );\n}\n\n// =============================================================================\n// CHANGELOG EMBED COMPONENT\n// =============================================================================\n\nexport function Changelog({\n projectId,\n baseUrl = DEFAULT_BASE_URL,\n maxHeight = 600,\n theme = \"auto\",\n className,\n}: ChangelogProps) {\n const resolvedTheme = useTheme(theme);\n\n return (\n <iframe\n src={`${baseUrl}/embed/${projectId}/changelog?theme=${resolvedTheme}`}\n className={clsx(styles.iframe, className)}\n style={{ height: maxHeight }}\n title=\"Changelog\"\n />\n );\n}\n\n// =============================================================================\n// ROADMAP EMBED COMPONENT\n// =============================================================================\n\nexport function Roadmap({\n projectId,\n baseUrl = DEFAULT_BASE_URL,\n maxHeight = 800,\n theme = \"auto\",\n className,\n}: RoadmapProps) {\n const resolvedTheme = useTheme(theme);\n\n return (\n <iframe\n src={`${baseUrl}/embed/${projectId}/roadmap?theme=${resolvedTheme}`}\n className={clsx(styles.iframe, className)}\n style={{ height: maxHeight }}\n title=\"Roadmap\"\n />\n );\n}\n\n// =============================================================================\n// EXPORTS\n// =============================================================================\n\nexport default VersionPill;\n"],"mappings":"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","names":["clsx"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/index.tsx
|
|
4
|
+
import { useState, useEffect, useCallback } from "react";
|
|
5
|
+
import clsx from "clsx";
|
|
6
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
var DEFAULT_BASE_URL = "https://versionpill.com";
|
|
8
|
+
var styles = {
|
|
9
|
+
pill: `
|
|
10
|
+
inline-flex items-center gap-1.5 px-2.5 py-1
|
|
11
|
+
text-xs font-medium rounded-full cursor-pointer
|
|
12
|
+
transition-all duration-200 select-none
|
|
13
|
+
border shadow-sm hover:shadow-md
|
|
14
|
+
`,
|
|
15
|
+
pillLight: `bg-white text-gray-700 border-gray-200 hover:border-gray-300`,
|
|
16
|
+
pillDark: `bg-gray-900 text-gray-100 border-gray-700 hover:border-gray-600`,
|
|
17
|
+
modal: `fixed inset-0 z-[99999] flex items-center justify-center p-4`,
|
|
18
|
+
backdrop: `absolute inset-0 bg-black/50 backdrop-blur-sm`,
|
|
19
|
+
panel: `relative w-full max-w-md max-h-[80vh] overflow-hidden rounded-xl shadow-2xl`,
|
|
20
|
+
panelLight: `bg-white`,
|
|
21
|
+
panelDark: `bg-gray-900`,
|
|
22
|
+
header: `p-4 border-b flex items-center justify-between`,
|
|
23
|
+
headerLight: `border-gray-100`,
|
|
24
|
+
headerDark: `border-gray-800`,
|
|
25
|
+
content: `p-4 overflow-y-auto max-h-[60vh]`,
|
|
26
|
+
version: `mb-4 last:mb-0`,
|
|
27
|
+
versionHeader: `flex items-center gap-2 mb-2`,
|
|
28
|
+
versionTitle: `font-semibold`,
|
|
29
|
+
versionBadge: `px-1.5 py-0.5 text-[10px] font-medium rounded`,
|
|
30
|
+
versionFeatures: `space-y-1 mt-2`,
|
|
31
|
+
versionFeature: `flex items-start gap-2 text-sm`,
|
|
32
|
+
footer: `p-3 border-t flex items-center justify-between`,
|
|
33
|
+
footerLight: `border-gray-100 bg-gray-50`,
|
|
34
|
+
footerDark: `border-gray-800 bg-gray-950`,
|
|
35
|
+
button: `px-3 py-1.5 text-xs font-medium rounded-lg transition-colors`,
|
|
36
|
+
buttonPrimary: `bg-blue-600 text-white hover:bg-blue-700`,
|
|
37
|
+
buttonSecondary: `text-gray-500 hover:text-gray-700`,
|
|
38
|
+
branding: `text-[10px] opacity-40 flex items-center gap-1`,
|
|
39
|
+
newDot: `w-2 h-2 rounded-full bg-green-500 animate-pulse`,
|
|
40
|
+
iframe: `w-full border-0`
|
|
41
|
+
};
|
|
42
|
+
function useTheme(theme) {
|
|
43
|
+
const [resolved, setResolved] = useState("light");
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (theme === "auto") {
|
|
46
|
+
const isDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
47
|
+
setResolved(isDark ? "dark" : "light");
|
|
48
|
+
const listener = (e) => setResolved(e.matches ? "dark" : "light");
|
|
49
|
+
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
50
|
+
mq.addEventListener("change", listener);
|
|
51
|
+
return () => mq.removeEventListener("change", listener);
|
|
52
|
+
} else {
|
|
53
|
+
setResolved(theme);
|
|
54
|
+
}
|
|
55
|
+
}, [theme]);
|
|
56
|
+
return resolved;
|
|
57
|
+
}
|
|
58
|
+
function VersionPill({
|
|
59
|
+
projectId,
|
|
60
|
+
baseUrl = DEFAULT_BASE_URL,
|
|
61
|
+
position = "inline",
|
|
62
|
+
className,
|
|
63
|
+
theme = "auto",
|
|
64
|
+
showBranding = true,
|
|
65
|
+
accentColor,
|
|
66
|
+
onNewVersion
|
|
67
|
+
}) {
|
|
68
|
+
const [versions, setVersions] = useState([]);
|
|
69
|
+
const [loading, setLoading] = useState(true);
|
|
70
|
+
const [error, setError] = useState(null);
|
|
71
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
72
|
+
const [hasNewVersion, setHasNewVersion] = useState(false);
|
|
73
|
+
const resolvedTheme = useTheme(theme);
|
|
74
|
+
const isLight = resolvedTheme === "light";
|
|
75
|
+
const fetchChangelog = useCallback(async () => {
|
|
76
|
+
try {
|
|
77
|
+
const response = await fetch(`${baseUrl}/api/changelog/${projectId}?limit=10`);
|
|
78
|
+
if (!response.ok) throw new Error("Failed to fetch changelog");
|
|
79
|
+
const data = await response.json();
|
|
80
|
+
setVersions(data);
|
|
81
|
+
const storedVersion = localStorage.getItem(`vp_${projectId}_seen`);
|
|
82
|
+
if (data.length > 0 && data[0].version !== storedVersion) {
|
|
83
|
+
setHasNewVersion(true);
|
|
84
|
+
onNewVersion?.(data[0]);
|
|
85
|
+
}
|
|
86
|
+
} catch (err) {
|
|
87
|
+
setError(err.message);
|
|
88
|
+
} finally {
|
|
89
|
+
setLoading(false);
|
|
90
|
+
}
|
|
91
|
+
}, [projectId, baseUrl, onNewVersion]);
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
fetchChangelog();
|
|
94
|
+
}, [fetchChangelog]);
|
|
95
|
+
const handleOpen = () => {
|
|
96
|
+
setIsOpen(true);
|
|
97
|
+
if (versions.length > 0) {
|
|
98
|
+
localStorage.setItem(`vp_${projectId}_seen`, versions[0].version);
|
|
99
|
+
setHasNewVersion(false);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const currentVersion = versions[0];
|
|
103
|
+
const positionStyles = {
|
|
104
|
+
"top-left": "fixed top-4 left-4 z-[9999]",
|
|
105
|
+
"top-right": "fixed top-4 right-4 z-[9999]",
|
|
106
|
+
"bottom-left": "fixed bottom-4 left-4 z-[9999]",
|
|
107
|
+
"bottom-right": "fixed bottom-4 right-4 z-[9999]",
|
|
108
|
+
inline: ""
|
|
109
|
+
};
|
|
110
|
+
if (loading) {
|
|
111
|
+
return /* @__PURE__ */ jsx("div", { className: clsx(positionStyles[position], className), children: /* @__PURE__ */ jsx("div", { className: clsx(styles.pill, isLight ? styles.pillLight : styles.pillDark), children: /* @__PURE__ */ jsx("span", { className: "opacity-50", children: "..." }) }) });
|
|
112
|
+
}
|
|
113
|
+
if (error || !currentVersion) return null;
|
|
114
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
115
|
+
/* @__PURE__ */ jsx("div", { className: clsx(positionStyles[position], className), children: /* @__PURE__ */ jsxs(
|
|
116
|
+
"button",
|
|
117
|
+
{
|
|
118
|
+
onClick: handleOpen,
|
|
119
|
+
className: clsx(styles.pill, isLight ? styles.pillLight : styles.pillDark),
|
|
120
|
+
style: accentColor ? { borderColor: accentColor } : void 0,
|
|
121
|
+
children: [
|
|
122
|
+
hasNewVersion && /* @__PURE__ */ jsx("span", { className: styles.newDot }),
|
|
123
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
124
|
+
"v",
|
|
125
|
+
currentVersion.version
|
|
126
|
+
] }),
|
|
127
|
+
/* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx("path", { d: "M6 9l6 6 6-6" }) })
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
) }),
|
|
131
|
+
isOpen && /* @__PURE__ */ jsxs("div", { className: styles.modal, children: [
|
|
132
|
+
/* @__PURE__ */ jsx("div", { className: styles.backdrop, onClick: () => setIsOpen(false) }),
|
|
133
|
+
/* @__PURE__ */ jsxs("div", { className: clsx(styles.panel, isLight ? styles.panelLight : styles.panelDark), children: [
|
|
134
|
+
/* @__PURE__ */ jsxs("div", { className: clsx(styles.header, isLight ? styles.headerLight : styles.headerDark), children: [
|
|
135
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
136
|
+
/* @__PURE__ */ jsx("span", { className: "text-lg", children: currentVersion.emoji || "\u2728" }),
|
|
137
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
138
|
+
/* @__PURE__ */ jsx("h2", { className: clsx("font-semibold", isLight ? "text-gray-900" : "text-white"), children: "What's New" }),
|
|
139
|
+
/* @__PURE__ */ jsx("p", { className: clsx("text-xs", isLight ? "text-gray-500" : "text-gray-400"), children: "Latest updates" })
|
|
140
|
+
] })
|
|
141
|
+
] }),
|
|
142
|
+
/* @__PURE__ */ jsx(
|
|
143
|
+
"button",
|
|
144
|
+
{
|
|
145
|
+
onClick: () => setIsOpen(false),
|
|
146
|
+
className: clsx("p-1 rounded hover:bg-gray-100", !isLight && "hover:bg-gray-800"),
|
|
147
|
+
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" }) })
|
|
148
|
+
}
|
|
149
|
+
)
|
|
150
|
+
] }),
|
|
151
|
+
/* @__PURE__ */ jsx("div", { className: styles.content, children: versions.slice(0, 5).map((version) => /* @__PURE__ */ jsxs("div", { className: styles.version, children: [
|
|
152
|
+
/* @__PURE__ */ jsxs("div", { className: styles.versionHeader, children: [
|
|
153
|
+
/* @__PURE__ */ jsx("span", { className: "text-lg", children: version.emoji || "\u{1F4E6}" }),
|
|
154
|
+
/* @__PURE__ */ jsx("span", { className: clsx(styles.versionTitle, isLight ? "text-gray-900" : "text-white"), children: version.title }),
|
|
155
|
+
/* @__PURE__ */ jsx(
|
|
156
|
+
"span",
|
|
157
|
+
{
|
|
158
|
+
className: clsx(
|
|
159
|
+
styles.versionBadge,
|
|
160
|
+
version.type === "major" ? "bg-purple-100 text-purple-700" : version.type === "minor" ? "bg-blue-100 text-blue-700" : "bg-gray-100 text-gray-700"
|
|
161
|
+
),
|
|
162
|
+
children: version.type
|
|
163
|
+
}
|
|
164
|
+
)
|
|
165
|
+
] }),
|
|
166
|
+
/* @__PURE__ */ jsxs("div", { className: clsx("text-xs mb-2", isLight ? "text-gray-500" : "text-gray-400"), children: [
|
|
167
|
+
"v",
|
|
168
|
+
version.version,
|
|
169
|
+
" \xB7 ",
|
|
170
|
+
new Date(version.releaseDate).toLocaleDateString()
|
|
171
|
+
] }),
|
|
172
|
+
version.description && /* @__PURE__ */ jsx("p", { className: clsx("text-sm mb-2", isLight ? "text-gray-600" : "text-gray-300"), children: version.description }),
|
|
173
|
+
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: [
|
|
174
|
+
/* @__PURE__ */ jsx("span", { className: "text-green-500 mt-0.5", children: "\u2713" }),
|
|
175
|
+
feature
|
|
176
|
+
] }, i)) })
|
|
177
|
+
] }, version.id)) }),
|
|
178
|
+
/* @__PURE__ */ jsxs("div", { className: clsx(styles.footer, isLight ? styles.footerLight : styles.footerDark), children: [
|
|
179
|
+
showBranding && /* @__PURE__ */ jsx(
|
|
180
|
+
"a",
|
|
181
|
+
{
|
|
182
|
+
href: "https://versionpill.com",
|
|
183
|
+
target: "_blank",
|
|
184
|
+
rel: "noopener noreferrer",
|
|
185
|
+
className: clsx(styles.branding, isLight ? "text-gray-400" : "text-gray-500"),
|
|
186
|
+
children: /* @__PURE__ */ jsx("span", { children: "Powered by Version Pill" })
|
|
187
|
+
}
|
|
188
|
+
),
|
|
189
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
190
|
+
/* @__PURE__ */ jsx(
|
|
191
|
+
"a",
|
|
192
|
+
{
|
|
193
|
+
href: `${baseUrl}/${projectId}/roadmap`,
|
|
194
|
+
target: "_blank",
|
|
195
|
+
rel: "noopener noreferrer",
|
|
196
|
+
className: clsx(styles.button, styles.buttonSecondary),
|
|
197
|
+
children: "\u{1F4A1} Roadmap"
|
|
198
|
+
}
|
|
199
|
+
),
|
|
200
|
+
/* @__PURE__ */ jsx(
|
|
201
|
+
"a",
|
|
202
|
+
{
|
|
203
|
+
href: `${baseUrl}/${projectId}/changelog`,
|
|
204
|
+
target: "_blank",
|
|
205
|
+
rel: "noopener noreferrer",
|
|
206
|
+
className: clsx(styles.button, styles.buttonPrimary),
|
|
207
|
+
style: accentColor ? { backgroundColor: accentColor } : void 0,
|
|
208
|
+
children: "View All"
|
|
209
|
+
}
|
|
210
|
+
)
|
|
211
|
+
] })
|
|
212
|
+
] })
|
|
213
|
+
] })
|
|
214
|
+
] })
|
|
215
|
+
] });
|
|
216
|
+
}
|
|
217
|
+
function Changelog({
|
|
218
|
+
projectId,
|
|
219
|
+
baseUrl = DEFAULT_BASE_URL,
|
|
220
|
+
maxHeight = 600,
|
|
221
|
+
theme = "auto",
|
|
222
|
+
className
|
|
223
|
+
}) {
|
|
224
|
+
const resolvedTheme = useTheme(theme);
|
|
225
|
+
return /* @__PURE__ */ jsx(
|
|
226
|
+
"iframe",
|
|
227
|
+
{
|
|
228
|
+
src: `${baseUrl}/embed/${projectId}/changelog?theme=${resolvedTheme}`,
|
|
229
|
+
className: clsx(styles.iframe, className),
|
|
230
|
+
style: { height: maxHeight },
|
|
231
|
+
title: "Changelog"
|
|
232
|
+
}
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
function Roadmap({
|
|
236
|
+
projectId,
|
|
237
|
+
baseUrl = DEFAULT_BASE_URL,
|
|
238
|
+
maxHeight = 800,
|
|
239
|
+
theme = "auto",
|
|
240
|
+
className
|
|
241
|
+
}) {
|
|
242
|
+
const resolvedTheme = useTheme(theme);
|
|
243
|
+
return /* @__PURE__ */ jsx(
|
|
244
|
+
"iframe",
|
|
245
|
+
{
|
|
246
|
+
src: `${baseUrl}/embed/${projectId}/roadmap?theme=${resolvedTheme}`,
|
|
247
|
+
className: clsx(styles.iframe, className),
|
|
248
|
+
style: { height: maxHeight },
|
|
249
|
+
title: "Roadmap"
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
var index_default = VersionPill;
|
|
254
|
+
export {
|
|
255
|
+
Changelog,
|
|
256
|
+
Roadmap,
|
|
257
|
+
VersionPill,
|
|
258
|
+
index_default as default
|
|
259
|
+
};
|
|
260
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useState, useEffect, useCallback } from \"react\";\nimport clsx from \"clsx\";\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\nexport interface Version {\n id: string;\n version: string;\n type: \"major\" | \"minor\" | \"patch\";\n title: string;\n description?: string;\n emoji?: string;\n features?: string[];\n releaseDate: number;\n isActive: boolean;\n}\n\nexport interface VersionPillConfig {\n /** Your project slug from Version Pill dashboard */\n projectId: string;\n /** Version Pill API base URL (default: https://versionpill.com) */\n baseUrl?: string;\n}\n\nexport interface VersionPillProps extends VersionPillConfig {\n /** Position of the pill */\n position?: \"top-left\" | \"top-right\" | \"bottom-left\" | \"bottom-right\" | \"inline\";\n /** Custom class name */\n className?: string;\n /** Theme */\n theme?: \"light\" | \"dark\" | \"auto\";\n /** Show \"Powered by Version Pill\" branding */\n showBranding?: boolean;\n /** Accent color (hex) */\n accentColor?: string;\n /** Callback when a new version is detected */\n onNewVersion?: (version: Version) => void;\n}\n\nexport interface ChangelogProps extends VersionPillConfig {\n /** Max height in pixels */\n maxHeight?: number;\n /** Theme */\n theme?: \"light\" | \"dark\" | \"auto\";\n /** Custom class name */\n className?: string;\n}\n\nexport interface RoadmapProps extends VersionPillConfig {\n /** Max height in pixels */\n maxHeight?: number;\n /** Theme */\n theme?: \"light\" | \"dark\" | \"auto\";\n /** Custom class name */\n className?: string;\n}\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\nconst DEFAULT_BASE_URL = \"https://versionpill.com\";\n\n// =============================================================================\n// STYLES\n// =============================================================================\n\nconst styles = {\n pill: `\n inline-flex items-center gap-1.5 px-2.5 py-1\n text-xs font-medium rounded-full cursor-pointer\n transition-all duration-200 select-none\n border shadow-sm hover:shadow-md\n `,\n pillLight: `bg-white text-gray-700 border-gray-200 hover:border-gray-300`,\n pillDark: `bg-gray-900 text-gray-100 border-gray-700 hover:border-gray-600`,\n\n modal: `fixed inset-0 z-[99999] flex items-center justify-center p-4`,\n backdrop: `absolute inset-0 bg-black/50 backdrop-blur-sm`,\n panel: `relative w-full max-w-md max-h-[80vh] overflow-hidden rounded-xl shadow-2xl`,\n panelLight: `bg-white`,\n panelDark: `bg-gray-900`,\n\n header: `p-4 border-b flex items-center justify-between`,\n headerLight: `border-gray-100`,\n headerDark: `border-gray-800`,\n\n content: `p-4 overflow-y-auto max-h-[60vh]`,\n\n version: `mb-4 last:mb-0`,\n versionHeader: `flex items-center gap-2 mb-2`,\n versionTitle: `font-semibold`,\n versionBadge: `px-1.5 py-0.5 text-[10px] font-medium rounded`,\n versionFeatures: `space-y-1 mt-2`,\n versionFeature: `flex items-start gap-2 text-sm`,\n\n footer: `p-3 border-t flex items-center justify-between`,\n footerLight: `border-gray-100 bg-gray-50`,\n footerDark: `border-gray-800 bg-gray-950`,\n\n button: `px-3 py-1.5 text-xs font-medium rounded-lg transition-colors`,\n buttonPrimary: `bg-blue-600 text-white hover:bg-blue-700`,\n buttonSecondary: `text-gray-500 hover:text-gray-700`,\n\n branding: `text-[10px] opacity-40 flex items-center gap-1`,\n newDot: `w-2 h-2 rounded-full bg-green-500 animate-pulse`,\n\n iframe: `w-full border-0`,\n};\n\n// =============================================================================\n// HOOKS\n// =============================================================================\n\nfunction useTheme(theme: \"light\" | \"dark\" | \"auto\"): \"light\" | \"dark\" {\n const [resolved, setResolved] = useState<\"light\" | \"dark\">(\"light\");\n\n useEffect(() => {\n if (theme === \"auto\") {\n const isDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n setResolved(isDark ? \"dark\" : \"light\");\n\n const listener = (e: MediaQueryListEvent) => setResolved(e.matches ? \"dark\" : \"light\");\n const mq = window.matchMedia(\"(prefers-color-scheme: dark)\");\n mq.addEventListener(\"change\", listener);\n return () => mq.removeEventListener(\"change\", listener);\n } else {\n setResolved(theme);\n }\n }, [theme]);\n\n return resolved;\n}\n\n// =============================================================================\n// VERSION PILL COMPONENT\n// =============================================================================\n\nexport function VersionPill({\n projectId,\n baseUrl = DEFAULT_BASE_URL,\n position = \"inline\",\n className,\n theme = \"auto\",\n showBranding = true,\n accentColor,\n onNewVersion,\n}: VersionPillProps) {\n const [versions, setVersions] = useState<Version[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [isOpen, setIsOpen] = useState(false);\n const [hasNewVersion, setHasNewVersion] = useState(false);\n\n const resolvedTheme = useTheme(theme);\n const isLight = resolvedTheme === \"light\";\n\n const fetchChangelog = useCallback(async () => {\n try {\n const response = await fetch(`${baseUrl}/api/changelog/${projectId}?limit=10`);\n if (!response.ok) throw new Error(\"Failed to fetch changelog\");\n\n const data = await response.json();\n setVersions(data);\n\n const storedVersion = localStorage.getItem(`vp_${projectId}_seen`);\n if (data.length > 0 && data[0].version !== storedVersion) {\n setHasNewVersion(true);\n onNewVersion?.(data[0]);\n }\n } catch (err: any) {\n setError(err.message);\n } finally {\n setLoading(false);\n }\n }, [projectId, baseUrl, onNewVersion]);\n\n useEffect(() => {\n fetchChangelog();\n }, [fetchChangelog]);\n\n const handleOpen = () => {\n setIsOpen(true);\n if (versions.length > 0) {\n localStorage.setItem(`vp_${projectId}_seen`, versions[0].version);\n setHasNewVersion(false);\n }\n };\n\n const currentVersion = versions[0];\n\n const positionStyles: Record<string, string> = {\n \"top-left\": \"fixed top-4 left-4 z-[9999]\",\n \"top-right\": \"fixed top-4 right-4 z-[9999]\",\n \"bottom-left\": \"fixed bottom-4 left-4 z-[9999]\",\n \"bottom-right\": \"fixed bottom-4 right-4 z-[9999]\",\n inline: \"\",\n };\n\n if (loading) {\n return (\n <div className={clsx(positionStyles[position], className)}>\n <div className={clsx(styles.pill, isLight ? styles.pillLight : styles.pillDark)}>\n <span className=\"opacity-50\">...</span>\n </div>\n </div>\n );\n }\n\n if (error || !currentVersion) return null;\n\n return (\n <>\n <div className={clsx(positionStyles[position], className)}>\n <button\n onClick={handleOpen}\n className={clsx(styles.pill, isLight ? styles.pillLight : styles.pillDark)}\n style={accentColor ? { borderColor: accentColor } : undefined}\n >\n {hasNewVersion && <span className={styles.newDot} />}\n <span>v{currentVersion.version}</span>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </button>\n </div>\n\n {isOpen && (\n <div className={styles.modal}>\n <div className={styles.backdrop} onClick={() => setIsOpen(false)} />\n <div className={clsx(styles.panel, isLight ? styles.panelLight : styles.panelDark)}>\n <div className={clsx(styles.header, isLight ? styles.headerLight : styles.headerDark)}>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-lg\">{currentVersion.emoji || \"✨\"}</span>\n <div>\n <h2 className={clsx(\"font-semibold\", isLight ? \"text-gray-900\" : \"text-white\")}>What's New</h2>\n <p className={clsx(\"text-xs\", isLight ? \"text-gray-500\" : \"text-gray-400\")}>\n Latest updates\n </p>\n </div>\n </div>\n <button\n onClick={() => setIsOpen(false)}\n className={clsx(\"p-1 rounded hover:bg-gray-100\", !isLight && \"hover:bg-gray-800\")}\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div className={styles.content}>\n {versions.slice(0, 5).map((version) => (\n <div key={version.id} className={styles.version}>\n <div className={styles.versionHeader}>\n <span className=\"text-lg\">{version.emoji || \"📦\"}</span>\n <span className={clsx(styles.versionTitle, isLight ? \"text-gray-900\" : \"text-white\")}>\n {version.title}\n </span>\n <span\n className={clsx(\n styles.versionBadge,\n version.type === \"major\" ? \"bg-purple-100 text-purple-700\" :\n version.type === \"minor\" ? \"bg-blue-100 text-blue-700\" :\n \"bg-gray-100 text-gray-700\"\n )}\n >\n {version.type}\n </span>\n </div>\n <div className={clsx(\"text-xs mb-2\", isLight ? \"text-gray-500\" : \"text-gray-400\")}>\n v{version.version} · {new Date(version.releaseDate).toLocaleDateString()}\n </div>\n {version.description && (\n <p className={clsx(\"text-sm mb-2\", isLight ? \"text-gray-600\" : \"text-gray-300\")}>\n {version.description}\n </p>\n )}\n {version.features && version.features.length > 0 && (\n <ul className={styles.versionFeatures}>\n {version.features.map((feature, i) => (\n <li key={i} className={clsx(styles.versionFeature, isLight ? \"text-gray-600\" : \"text-gray-300\")}>\n <span className=\"text-green-500 mt-0.5\">✓</span>\n {feature}\n </li>\n ))}\n </ul>\n )}\n </div>\n ))}\n </div>\n\n <div className={clsx(styles.footer, isLight ? styles.footerLight : styles.footerDark)}>\n {showBranding && (\n <a\n href=\"https://versionpill.com\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={clsx(styles.branding, isLight ? \"text-gray-400\" : \"text-gray-500\")}\n >\n <span>Powered by Version Pill</span>\n </a>\n )}\n <div className=\"flex items-center gap-2\">\n <a\n href={`${baseUrl}/${projectId}/roadmap`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={clsx(styles.button, styles.buttonSecondary)}\n >\n 💡 Roadmap\n </a>\n <a\n href={`${baseUrl}/${projectId}/changelog`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={clsx(styles.button, styles.buttonPrimary)}\n style={accentColor ? { backgroundColor: accentColor } : undefined}\n >\n View All\n </a>\n </div>\n </div>\n </div>\n </div>\n )}\n </>\n );\n}\n\n// =============================================================================\n// CHANGELOG EMBED COMPONENT\n// =============================================================================\n\nexport function Changelog({\n projectId,\n baseUrl = DEFAULT_BASE_URL,\n maxHeight = 600,\n theme = \"auto\",\n className,\n}: ChangelogProps) {\n const resolvedTheme = useTheme(theme);\n\n return (\n <iframe\n src={`${baseUrl}/embed/${projectId}/changelog?theme=${resolvedTheme}`}\n className={clsx(styles.iframe, className)}\n style={{ height: maxHeight }}\n title=\"Changelog\"\n />\n );\n}\n\n// =============================================================================\n// ROADMAP EMBED COMPONENT\n// =============================================================================\n\nexport function Roadmap({\n projectId,\n baseUrl = DEFAULT_BASE_URL,\n maxHeight = 800,\n theme = \"auto\",\n className,\n}: RoadmapProps) {\n const resolvedTheme = useTheme(theme);\n\n return (\n <iframe\n src={`${baseUrl}/embed/${projectId}/roadmap?theme=${resolvedTheme}`}\n className={clsx(styles.iframe, className)}\n style={{ height: maxHeight }}\n title=\"Roadmap\"\n />\n );\n}\n\n// =============================================================================\n// EXPORTS\n// =============================================================================\n\nexport default VersionPill;\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "version-pill-react",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "React components for Version Pill - embed changelog, roadmap & feedback widgets in your app",
|
|
5
|
+
"author": "Jimmy Harika <jimmy@jimmyharika.com>",
|
|
6
|
+
"homepage": "https://versionpill.com",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/jimmyharika/convex-logbook"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/jimmyharika/convex-logbook/issues"
|
|
13
|
+
},
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"module": "./dist/index.mjs",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.mjs",
|
|
21
|
+
"require": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"sideEffects": false,
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsup",
|
|
30
|
+
"dev": "tsup --watch",
|
|
31
|
+
"typecheck": "tsc --noEmit",
|
|
32
|
+
"prepublishOnly": "bun run build"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": ">=18.0.0",
|
|
36
|
+
"react-dom": ">=18.0.0"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"clsx": "^2.1.1"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/react": "^19.2.7",
|
|
43
|
+
"@types/react-dom": "^19.2.3",
|
|
44
|
+
"react": "^19.2.1",
|
|
45
|
+
"react-dom": "^19.2.1",
|
|
46
|
+
"tsup": "^8.0.0",
|
|
47
|
+
"typescript": "^5.9.3"
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"changelog",
|
|
51
|
+
"version",
|
|
52
|
+
"widget",
|
|
53
|
+
"react",
|
|
54
|
+
"roadmap",
|
|
55
|
+
"feedback",
|
|
56
|
+
"version-pill",
|
|
57
|
+
"versionpill",
|
|
58
|
+
"release-notes",
|
|
59
|
+
"whats-new",
|
|
60
|
+
"product-updates",
|
|
61
|
+
"feature-requests"
|
|
62
|
+
],
|
|
63
|
+
"license": "MIT",
|
|
64
|
+
"publishConfig": {
|
|
65
|
+
"access": "public"
|
|
66
|
+
}
|
|
67
|
+
}
|