changelogdev-widget 0.1.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/LICENSE +21 -0
- package/README.md +173 -0
- package/dist/index.cjs +417 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +65 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.iife.js +417 -0
- package/dist/index.iife.js.map +1 -0
- package/dist/index.js +417 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Changelog.dev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# @changelogdev/widget
|
|
2
|
+
|
|
3
|
+
An embeddable changelog widget for any website. Show your users what's new with a single line of code.
|
|
4
|
+
|
|
5
|
+
Zero dependencies. Framework-agnostic. Built as a Web Component with Shadow DOM for complete style isolation.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
### Script Tag (simplest)
|
|
10
|
+
|
|
11
|
+
Drop this into any HTML page:
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<script src="https://unpkg.com/@changelogdev/widget"></script>
|
|
15
|
+
<changelog-widget project-id="your-project-id"></changelog-widget>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
That's it. A floating bell icon appears in the bottom-right corner. Click it to see your changelog.
|
|
19
|
+
|
|
20
|
+
### npm
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install @changelogdev/widget
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Option A: Declarative (HTML element)**
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import '@changelogdev/widget'
|
|
30
|
+
|
|
31
|
+
// In your HTML or JSX:
|
|
32
|
+
<changelog-widget project-id="your-project-id" theme="dark" />
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Option B: Programmatic**
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { init } from '@changelogdev/widget'
|
|
39
|
+
|
|
40
|
+
init({
|
|
41
|
+
projectId: 'your-project-id',
|
|
42
|
+
position: 'bottom-right',
|
|
43
|
+
theme: 'dark',
|
|
44
|
+
accentColor: '#6366f1',
|
|
45
|
+
})
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### React / Next.js
|
|
49
|
+
|
|
50
|
+
The widget works out of the box with React. Import once and use the custom element:
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import '@changelogdev/widget'
|
|
54
|
+
|
|
55
|
+
export default function App() {
|
|
56
|
+
return (
|
|
57
|
+
<div>
|
|
58
|
+
<h1>My App</h1>
|
|
59
|
+
<changelog-widget
|
|
60
|
+
project-id="your-project-id"
|
|
61
|
+
theme="auto"
|
|
62
|
+
accent-color="#6366f1"
|
|
63
|
+
/>
|
|
64
|
+
</div>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
For TypeScript, add this declaration to avoid JSX type errors:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
// global.d.ts
|
|
73
|
+
declare namespace JSX {
|
|
74
|
+
interface IntrinsicElements {
|
|
75
|
+
'changelog-widget': React.DetailedHTMLProps<
|
|
76
|
+
React.HTMLAttributes<HTMLElement> & {
|
|
77
|
+
'project-id'?: string
|
|
78
|
+
'api-url'?: string
|
|
79
|
+
position?: 'bottom-right' | 'bottom-left'
|
|
80
|
+
theme?: 'light' | 'dark' | 'auto'
|
|
81
|
+
'accent-color'?: string
|
|
82
|
+
},
|
|
83
|
+
HTMLElement
|
|
84
|
+
>
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Vue
|
|
90
|
+
|
|
91
|
+
```vue
|
|
92
|
+
<template>
|
|
93
|
+
<changelog-widget project-id="your-project-id" theme="dark" />
|
|
94
|
+
</template>
|
|
95
|
+
|
|
96
|
+
<script setup>
|
|
97
|
+
import '@changelogdev/widget'
|
|
98
|
+
</script>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Configuration
|
|
102
|
+
|
|
103
|
+
All configuration is done through HTML attributes or the `init()` options object.
|
|
104
|
+
|
|
105
|
+
| Attribute | Option | Default | Description |
|
|
106
|
+
| --------------- | -------------- | ---------------------------------------------- | ---------------------------------- |
|
|
107
|
+
| `project-id` | `projectId` | (required) | Your project ID from Changelog.dev |
|
|
108
|
+
| `api-url` | `apiUrl` | `https://www.changelogdev.com/api/widget` | API endpoint for fetching entries |
|
|
109
|
+
| `position` | `position` | `bottom-right` | Widget position on screen |
|
|
110
|
+
| `theme` | `theme` | `auto` | `light`, `dark`, or `auto` |
|
|
111
|
+
| `accent-color` | `accentColor` | `#6366f1` | Primary color for the trigger button |
|
|
112
|
+
|
|
113
|
+
## Features
|
|
114
|
+
|
|
115
|
+
- **Zero dependencies** -- no React, no Vue, no nothing. Pure Web Components.
|
|
116
|
+
- **Shadow DOM isolation** -- styles never leak in or out. Works on any page.
|
|
117
|
+
- **Unread badge** -- tracks which entries the user has seen via localStorage.
|
|
118
|
+
- **Responsive** -- works on mobile, adapts to small screens.
|
|
119
|
+
- **Theme support** -- light, dark, or auto (follows system preference).
|
|
120
|
+
- **Keyboard accessible** -- Escape to close, focusable trigger button.
|
|
121
|
+
- **Mock data fallback** -- works offline or without an API for demos.
|
|
122
|
+
- **Tiny footprint** -- under 8KB gzipped.
|
|
123
|
+
|
|
124
|
+
## API Response Format
|
|
125
|
+
|
|
126
|
+
The widget expects your API to return JSON in one of these shapes:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
[
|
|
130
|
+
{
|
|
131
|
+
"id": "entry-1",
|
|
132
|
+
"title": "New Feature: Dark Mode",
|
|
133
|
+
"description": "You can now switch between light and dark themes.",
|
|
134
|
+
"type": "feature",
|
|
135
|
+
"date": "2026-03-01",
|
|
136
|
+
"url": "https://example.com/blog/dark-mode"
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Or wrapped:
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"entries": [...]
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Entry fields:**
|
|
150
|
+
|
|
151
|
+
| Field | Type | Required | Values |
|
|
152
|
+
| ------------- | -------- | -------- | ------------------------------------------------- |
|
|
153
|
+
| `id` | `string` | Yes | Unique identifier |
|
|
154
|
+
| `title` | `string` | Yes | Entry title |
|
|
155
|
+
| `description` | `string` | Yes | Entry description (plain text) |
|
|
156
|
+
| `type` | `string` | Yes | `feature`, `improvement`, `fix`, `announcement` |
|
|
157
|
+
| `date` | `string` | Yes | ISO date string (`YYYY-MM-DD`) |
|
|
158
|
+
| `url` | `string` | No | Link to full entry |
|
|
159
|
+
|
|
160
|
+
## Development
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
npm install
|
|
164
|
+
npm run build # Build ESM + CJS + IIFE
|
|
165
|
+
npm run dev # Watch mode
|
|
166
|
+
npm run typecheck
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
MIT -- see [LICENSE](./LICENSE).
|
|
172
|
+
|
|
173
|
+
Built by [Changelog.dev](https://www.changelogdev.com).
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
"use strict";var l=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var b=(r,o)=>{for(var e in o)l(r,e,{get:o[e],enumerable:!0})},f=(r,o,e,t)=>{if(o&&typeof o=="object"||typeof o=="function")for(let i of u(o))!m.call(r,i)&&i!==e&&l(r,i,{get:()=>o[i],enumerable:!(t=w(o,i))||t.enumerable});return r};var v=r=>f(l({},"__esModule",{value:!0}),r);var L={};b(L,{ChangelogWidget:()=>a,init:()=>C});module.exports=v(L);var x=[{id:"mock-1",title:"AI-Powered Release Summaries",description:"Changelog entries are now automatically summarized using AI. Connect your GitHub repo and we generate human-readable release notes from your commits and PRs.",type:"feature",date:"2026-03-05",url:"https://www.changelogdev.com/blog/ai-summaries"},{id:"mock-2",title:"Embeddable Widget",description:"You can now embed a changelog widget directly on your site. One script tag, zero dependencies. Your users see what's new without leaving your app.",type:"feature",date:"2026-03-01",url:"https://www.changelogdev.com/blog/widget-launch"},{id:"mock-3",title:"Faster Dashboard Loading",description:"Dashboard load times reduced by 60% through query optimization and edge caching. The changelog list now renders in under 200ms.",type:"improvement",date:"2026-02-25"},{id:"mock-4",title:"Markdown Rendering Fix",description:"Fixed an issue where inline code blocks in changelog descriptions were not rendering correctly in the email digest.",type:"fix",date:"2026-02-20"},{id:"mock-5",title:"Webhook Notifications",description:"Send changelog updates to Slack, Discord, or any webhook endpoint. Configure per-project notification rules from the dashboard.",type:"feature",date:"2026-02-15",url:"https://www.changelogdev.com/blog/webhooks"},{id:"mock-6",title:"Public Changelog Pages",description:"Every project now gets a public changelog page at changelog.dev/your-project. Share it with your users or link to it from your docs.",type:"announcement",date:"2026-02-10",url:"https://www.changelogdev.com/blog/public-pages"}];async function d(r,o){try{let e=`${r}?projectId=${encodeURIComponent(o)}`,t=await fetch(e,{headers:{Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(!t.ok)throw new Error(`HTTP ${t.status}`);let i=await t.json();if(Array.isArray(i))return i;if(i?.entries&&Array.isArray(i.entries))return i.entries;throw new Error("Unexpected response shape")}catch{return x}}function g(r){return`
|
|
2
|
+
:host {
|
|
3
|
+
--clw-accent: ${r};
|
|
4
|
+
--clw-accent-hover: color-mix(in srgb, ${r} 85%, white);
|
|
5
|
+
--clw-radius: 12px;
|
|
6
|
+
--clw-radius-sm: 8px;
|
|
7
|
+
--clw-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
8
|
+
--clw-transition: 0.2s ease;
|
|
9
|
+
|
|
10
|
+
position: fixed;
|
|
11
|
+
z-index: 2147483647;
|
|
12
|
+
font-family: var(--clw-font);
|
|
13
|
+
font-size: 14px;
|
|
14
|
+
line-height: 1.5;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
:host([position="bottom-right"]) {
|
|
18
|
+
bottom: 20px;
|
|
19
|
+
right: 20px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
:host([position="bottom-left"]) {
|
|
23
|
+
bottom: 20px;
|
|
24
|
+
left: 20px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* ---- Theme variables ---- */
|
|
28
|
+
:host([data-theme="dark"]) {
|
|
29
|
+
--clw-bg: #111113;
|
|
30
|
+
--clw-bg-elevated: #1a1a1f;
|
|
31
|
+
--clw-bg-hover: #222228;
|
|
32
|
+
--clw-border: #2a2a32;
|
|
33
|
+
--clw-text: #ededef;
|
|
34
|
+
--clw-text-secondary: #9393a0;
|
|
35
|
+
--clw-text-muted: #65656d;
|
|
36
|
+
--clw-shadow: 0 16px 48px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.06);
|
|
37
|
+
--clw-btn-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
:host([data-theme="light"]) {
|
|
41
|
+
--clw-bg: #ffffff;
|
|
42
|
+
--clw-bg-elevated: #f8f8fa;
|
|
43
|
+
--clw-bg-hover: #f0f0f3;
|
|
44
|
+
--clw-border: #e4e4e8;
|
|
45
|
+
--clw-text: #111113;
|
|
46
|
+
--clw-text-secondary: #65656d;
|
|
47
|
+
--clw-text-muted: #9393a0;
|
|
48
|
+
--clw-shadow: 0 16px 48px rgba(0, 0, 0, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.06);
|
|
49
|
+
--clw-btn-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
*, *::before, *::after {
|
|
53
|
+
box-sizing: border-box;
|
|
54
|
+
margin: 0;
|
|
55
|
+
padding: 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* ---- Trigger button ---- */
|
|
59
|
+
.clw-trigger {
|
|
60
|
+
width: 48px;
|
|
61
|
+
height: 48px;
|
|
62
|
+
border-radius: 50%;
|
|
63
|
+
border: none;
|
|
64
|
+
background: var(--clw-accent);
|
|
65
|
+
color: #fff;
|
|
66
|
+
cursor: pointer;
|
|
67
|
+
display: flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
justify-content: center;
|
|
70
|
+
box-shadow: var(--clw-btn-shadow);
|
|
71
|
+
transition: transform var(--clw-transition), box-shadow var(--clw-transition);
|
|
72
|
+
position: relative;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.clw-trigger:hover {
|
|
76
|
+
transform: scale(1.08);
|
|
77
|
+
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.3);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.clw-trigger:active {
|
|
81
|
+
transform: scale(0.96);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.clw-trigger svg {
|
|
85
|
+
width: 22px;
|
|
86
|
+
height: 22px;
|
|
87
|
+
fill: currentColor;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* ---- Badge ---- */
|
|
91
|
+
.clw-badge {
|
|
92
|
+
position: absolute;
|
|
93
|
+
top: -4px;
|
|
94
|
+
right: -4px;
|
|
95
|
+
min-width: 20px;
|
|
96
|
+
height: 20px;
|
|
97
|
+
padding: 0 6px;
|
|
98
|
+
border-radius: 10px;
|
|
99
|
+
background: #ef4444;
|
|
100
|
+
color: #fff;
|
|
101
|
+
font-size: 11px;
|
|
102
|
+
font-weight: 700;
|
|
103
|
+
display: flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
justify-content: center;
|
|
106
|
+
pointer-events: none;
|
|
107
|
+
line-height: 1;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.clw-badge:empty,
|
|
111
|
+
.clw-badge[data-count="0"] {
|
|
112
|
+
display: none;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* ---- Panel ---- */
|
|
116
|
+
.clw-panel {
|
|
117
|
+
position: fixed;
|
|
118
|
+
bottom: 80px;
|
|
119
|
+
width: 380px;
|
|
120
|
+
max-height: min(520px, calc(100vh - 120px));
|
|
121
|
+
background: var(--clw-bg);
|
|
122
|
+
border-radius: var(--clw-radius);
|
|
123
|
+
box-shadow: var(--clw-shadow);
|
|
124
|
+
display: flex;
|
|
125
|
+
flex-direction: column;
|
|
126
|
+
overflow: hidden;
|
|
127
|
+
opacity: 0;
|
|
128
|
+
transform: translateY(12px) scale(0.96);
|
|
129
|
+
pointer-events: none;
|
|
130
|
+
transition: opacity var(--clw-transition), transform var(--clw-transition);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
:host([position="bottom-right"]) .clw-panel {
|
|
134
|
+
right: 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
:host([position="bottom-left"]) .clw-panel {
|
|
138
|
+
left: 0;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.clw-panel.open {
|
|
142
|
+
opacity: 1;
|
|
143
|
+
transform: translateY(0) scale(1);
|
|
144
|
+
pointer-events: auto;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* ---- Panel header ---- */
|
|
148
|
+
.clw-header {
|
|
149
|
+
padding: 16px 20px;
|
|
150
|
+
border-bottom: 1px solid var(--clw-border);
|
|
151
|
+
display: flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
justify-content: space-between;
|
|
154
|
+
flex-shrink: 0;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.clw-header-title {
|
|
158
|
+
font-size: 15px;
|
|
159
|
+
font-weight: 600;
|
|
160
|
+
color: var(--clw-text);
|
|
161
|
+
letter-spacing: -0.01em;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.clw-close {
|
|
165
|
+
width: 28px;
|
|
166
|
+
height: 28px;
|
|
167
|
+
border-radius: 6px;
|
|
168
|
+
border: none;
|
|
169
|
+
background: transparent;
|
|
170
|
+
color: var(--clw-text-muted);
|
|
171
|
+
cursor: pointer;
|
|
172
|
+
display: flex;
|
|
173
|
+
align-items: center;
|
|
174
|
+
justify-content: center;
|
|
175
|
+
transition: background var(--clw-transition), color var(--clw-transition);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.clw-close:hover {
|
|
179
|
+
background: var(--clw-bg-hover);
|
|
180
|
+
color: var(--clw-text);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.clw-close svg {
|
|
184
|
+
width: 16px;
|
|
185
|
+
height: 16px;
|
|
186
|
+
stroke: currentColor;
|
|
187
|
+
fill: none;
|
|
188
|
+
stroke-width: 2;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/* ---- Entries list ---- */
|
|
192
|
+
.clw-entries {
|
|
193
|
+
overflow-y: auto;
|
|
194
|
+
flex: 1;
|
|
195
|
+
padding: 8px 0;
|
|
196
|
+
overscroll-behavior: contain;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.clw-entries::-webkit-scrollbar {
|
|
200
|
+
width: 6px;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.clw-entries::-webkit-scrollbar-track {
|
|
204
|
+
background: transparent;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.clw-entries::-webkit-scrollbar-thumb {
|
|
208
|
+
background: var(--clw-border);
|
|
209
|
+
border-radius: 3px;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* ---- Single entry ---- */
|
|
213
|
+
.clw-entry {
|
|
214
|
+
padding: 14px 20px;
|
|
215
|
+
border-bottom: 1px solid var(--clw-border);
|
|
216
|
+
transition: background var(--clw-transition);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.clw-entry:last-child {
|
|
220
|
+
border-bottom: none;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.clw-entry:hover {
|
|
224
|
+
background: var(--clw-bg-hover);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.clw-entry-meta {
|
|
228
|
+
display: flex;
|
|
229
|
+
align-items: center;
|
|
230
|
+
gap: 8px;
|
|
231
|
+
margin-bottom: 6px;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.clw-type-badge {
|
|
235
|
+
font-size: 11px;
|
|
236
|
+
font-weight: 600;
|
|
237
|
+
padding: 2px 8px;
|
|
238
|
+
border-radius: 4px;
|
|
239
|
+
text-transform: uppercase;
|
|
240
|
+
letter-spacing: 0.04em;
|
|
241
|
+
line-height: 1.4;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.clw-type-feature {
|
|
245
|
+
background: rgba(59, 130, 246, 0.15);
|
|
246
|
+
color: #60a5fa;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.clw-type-improvement {
|
|
250
|
+
background: rgba(168, 85, 247, 0.15);
|
|
251
|
+
color: #c084fc;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.clw-type-fix {
|
|
255
|
+
background: rgba(34, 197, 94, 0.15);
|
|
256
|
+
color: #4ade80;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.clw-type-announcement {
|
|
260
|
+
background: rgba(251, 191, 36, 0.15);
|
|
261
|
+
color: #fbbf24;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/* Light theme badge overrides */
|
|
265
|
+
:host([data-theme="light"]) .clw-type-feature {
|
|
266
|
+
background: rgba(59, 130, 246, 0.1);
|
|
267
|
+
color: #2563eb;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
:host([data-theme="light"]) .clw-type-improvement {
|
|
271
|
+
background: rgba(168, 85, 247, 0.1);
|
|
272
|
+
color: #7c3aed;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
:host([data-theme="light"]) .clw-type-fix {
|
|
276
|
+
background: rgba(34, 197, 94, 0.1);
|
|
277
|
+
color: #16a34a;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
:host([data-theme="light"]) .clw-type-announcement {
|
|
281
|
+
background: rgba(251, 191, 36, 0.1);
|
|
282
|
+
color: #d97706;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.clw-entry-date {
|
|
286
|
+
font-size: 12px;
|
|
287
|
+
color: var(--clw-text-muted);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.clw-entry-title {
|
|
291
|
+
font-size: 14px;
|
|
292
|
+
font-weight: 600;
|
|
293
|
+
color: var(--clw-text);
|
|
294
|
+
margin-bottom: 4px;
|
|
295
|
+
line-height: 1.4;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.clw-entry-title a {
|
|
299
|
+
color: inherit;
|
|
300
|
+
text-decoration: none;
|
|
301
|
+
transition: color var(--clw-transition);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.clw-entry-title a:hover {
|
|
305
|
+
color: var(--clw-accent);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.clw-entry-desc {
|
|
309
|
+
font-size: 13px;
|
|
310
|
+
color: var(--clw-text-secondary);
|
|
311
|
+
line-height: 1.55;
|
|
312
|
+
display: -webkit-box;
|
|
313
|
+
-webkit-line-clamp: 3;
|
|
314
|
+
-webkit-box-orient: vertical;
|
|
315
|
+
overflow: hidden;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/* ---- Footer ---- */
|
|
319
|
+
.clw-footer {
|
|
320
|
+
padding: 10px 20px;
|
|
321
|
+
border-top: 1px solid var(--clw-border);
|
|
322
|
+
text-align: center;
|
|
323
|
+
flex-shrink: 0;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.clw-footer a {
|
|
327
|
+
font-size: 11px;
|
|
328
|
+
color: var(--clw-text-muted);
|
|
329
|
+
text-decoration: none;
|
|
330
|
+
transition: color var(--clw-transition);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.clw-footer a:hover {
|
|
334
|
+
color: var(--clw-text-secondary);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/* ---- Loading / Empty ---- */
|
|
338
|
+
.clw-loading,
|
|
339
|
+
.clw-empty {
|
|
340
|
+
padding: 40px 20px;
|
|
341
|
+
text-align: center;
|
|
342
|
+
color: var(--clw-text-muted);
|
|
343
|
+
font-size: 13px;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.clw-spinner {
|
|
347
|
+
width: 24px;
|
|
348
|
+
height: 24px;
|
|
349
|
+
border: 2px solid var(--clw-border);
|
|
350
|
+
border-top-color: var(--clw-accent);
|
|
351
|
+
border-radius: 50%;
|
|
352
|
+
animation: clw-spin 0.7s linear infinite;
|
|
353
|
+
margin: 0 auto 12px;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
@keyframes clw-spin {
|
|
357
|
+
to { transform: rotate(360deg); }
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/* ---- Mobile ---- */
|
|
361
|
+
@media (max-width: 440px) {
|
|
362
|
+
.clw-panel {
|
|
363
|
+
width: calc(100vw - 24px);
|
|
364
|
+
bottom: 76px;
|
|
365
|
+
max-height: calc(100vh - 100px);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
:host([position="bottom-right"]) .clw-panel {
|
|
369
|
+
right: -8px;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
:host([position="bottom-left"]) .clw-panel {
|
|
373
|
+
left: -8px;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
`}var p={feature:"New",improvement:"Improved",fix:"Fixed",announcement:"Announcement"};var y="clw_last_seen_",k='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 2C10.343 2 9 3.343 9 5v.26C6.667 6.34 5 8.66 5 11.4V16l-2 2v1h18v-1l-2-2v-4.6c0-2.74-1.667-5.06-4-6.14V5c0-1.657-1.343-3-3-3zm0 20c1.105 0 2-.895 2-2h-4c0 1.105.895 2 2 2z"/></svg>',E='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',a=class extends HTMLElement{constructor(){super();this.entries=[];this.isOpen=!1;this.isLoading=!1;this.shadow=this.attachShadow({mode:"open"})}static get observedAttributes(){return["project-id","api-url","position","theme","accent-color"]}get projectId(){return this.getAttribute("project-id")||""}get apiUrl(){return this.getAttribute("api-url")||"https://www.changelogdev.com/api/widget"}get position(){return this.getAttribute("position")==="bottom-left"?"bottom-left":"bottom-right"}get theme(){let e=this.getAttribute("theme");return e==="light"||e==="dark"?e:"auto"}get accentColor(){return this.getAttribute("accent-color")||"#6366f1"}connectedCallback(){this.hasAttribute("position")||this.setAttribute("position","bottom-right"),this.resolveTheme(),this.render(),this.loadEntries(),this.theme==="auto"&&window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>this.resolveTheme())}attributeChangedCallback(e,t,i){t!==i&&(e==="theme"&&this.resolveTheme(),e==="accent-color"&&this.render(),(e==="project-id"||e==="api-url")&&this.loadEntries())}resolveTheme(){let e="dark";this.theme==="auto"?e=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":e=this.theme,this.setAttribute("data-theme",e)}async loadEntries(){this.projectId&&(this.isLoading=!0,this.updatePanel(),this.entries=await d(this.apiUrl,this.projectId),this.isLoading=!1,this.updatePanel(),this.updateBadge())}get storageKey(){return`${y}${this.projectId}`}getLastSeenDate(){try{return localStorage.getItem(this.storageKey)}catch{return null}}markAsSeen(){if(this.entries.length!==0)try{localStorage.setItem(this.storageKey,this.entries[0].date)}catch{}}getUnreadCount(){let e=this.getLastSeenDate();return e?this.entries.filter(t=>t.date>e).length:this.entries.length}render(){let e=document.createElement("style");e.textContent=g(this.accentColor);let t=document.createElement("div");t.innerHTML=`
|
|
377
|
+
<button class="clw-trigger" aria-label="View changelog">
|
|
378
|
+
${k}
|
|
379
|
+
<span class="clw-badge" data-count="0"></span>
|
|
380
|
+
</button>
|
|
381
|
+
<div class="clw-panel" role="dialog" aria-label="Changelog">
|
|
382
|
+
<div class="clw-header">
|
|
383
|
+
<span class="clw-header-title">What's New</span>
|
|
384
|
+
<button class="clw-close" aria-label="Close changelog">
|
|
385
|
+
${E}
|
|
386
|
+
</button>
|
|
387
|
+
</div>
|
|
388
|
+
<div class="clw-entries">
|
|
389
|
+
<div class="clw-loading">
|
|
390
|
+
<div class="clw-spinner"></div>
|
|
391
|
+
Loading...
|
|
392
|
+
</div>
|
|
393
|
+
</div>
|
|
394
|
+
<div class="clw-footer">
|
|
395
|
+
<a href="https://www.changelogdev.com?ref=widget" target="_blank" rel="noopener noreferrer">
|
|
396
|
+
Powered by Changelog.dev
|
|
397
|
+
</a>
|
|
398
|
+
</div>
|
|
399
|
+
</div>
|
|
400
|
+
`,this.shadow.innerHTML="",this.shadow.appendChild(e),this.shadow.appendChild(t),this.shadow.querySelector(".clw-trigger").addEventListener("click",()=>this.toggle()),this.shadow.querySelector(".clw-close").addEventListener("click",()=>this.close()),document.addEventListener("click",n=>{this.isOpen&&!this.contains(n.target)&&this.close()}),document.addEventListener("keydown",n=>{n.key==="Escape"&&this.isOpen&&this.close()})}toggle(){this.isOpen?this.close():this.open()}open(){this.isOpen=!0,this.shadow.querySelector(".clw-panel")?.classList.add("open"),this.markAsSeen(),this.updateBadge()}close(){this.isOpen=!1,this.shadow.querySelector(".clw-panel")?.classList.remove("open")}updateBadge(){let e=this.shadow.querySelector(".clw-badge");if(!e)return;let t=this.getUnreadCount();e.textContent=t>0?t>9?"9+":String(t):"",e.setAttribute("data-count",String(t))}updatePanel(){let e=this.shadow.querySelector(".clw-entries");if(e){if(this.isLoading){e.innerHTML=`
|
|
401
|
+
<div class="clw-loading">
|
|
402
|
+
<div class="clw-spinner"></div>
|
|
403
|
+
Loading...
|
|
404
|
+
</div>
|
|
405
|
+
`;return}if(this.entries.length===0){e.innerHTML=`
|
|
406
|
+
<div class="clw-empty">No changelog entries yet.</div>
|
|
407
|
+
`;return}e.innerHTML=this.entries.map(t=>this.renderEntry(t)).join("")}}renderEntry(e){let t=p[e.type]||e.type,i=this.formatDate(e.date),s=e.url?`<a href="${this.escapeHtml(e.url)}" target="_blank" rel="noopener noreferrer">${this.escapeHtml(e.title)}</a>`:this.escapeHtml(e.title);return`
|
|
408
|
+
<div class="clw-entry">
|
|
409
|
+
<div class="clw-entry-meta">
|
|
410
|
+
<span class="clw-type-badge clw-type-${e.type}">${t}</span>
|
|
411
|
+
<span class="clw-entry-date">${i}</span>
|
|
412
|
+
</div>
|
|
413
|
+
<div class="clw-entry-title">${s}</div>
|
|
414
|
+
<div class="clw-entry-desc">${this.escapeHtml(e.description)}</div>
|
|
415
|
+
</div>
|
|
416
|
+
`}formatDate(e){try{let t=new Date(e+"T00:00:00"),i=new Date,s=i.getTime()-t.getTime(),n=Math.floor(s/(1e3*60*60*24));if(n===0)return"Today";if(n===1)return"Yesterday";if(n<7)return`${n} days ago`;if(n<30){let c=Math.floor(n/7);return`${c} ${c===1?"week":"weeks"} ago`}return t.toLocaleDateString("en-US",{month:"short",day:"numeric",year:t.getFullYear()!==i.getFullYear()?"numeric":void 0})}catch{return e}}escapeHtml(e){let t=document.createElement("div");return t.textContent=e,t.innerHTML}};function h(){typeof window<"u"&&!customElements.get("changelog-widget")&&customElements.define("changelog-widget",a)}function C(r){h();let o=document.createElement("changelog-widget");return o.setAttribute("project-id",r.projectId),r.apiUrl&&o.setAttribute("api-url",r.apiUrl),r.position&&o.setAttribute("position",r.position),r.theme&&o.setAttribute("theme",r.theme),r.accentColor&&o.setAttribute("accent-color",r.accentColor),document.body.appendChild(o),o}h();0&&(module.exports={ChangelogWidget,init});
|
|
417
|
+
//# sourceMappingURL=index.cjs.map
|