@real1ty-obsidian-plugins/utils 2.32.0 → 2.33.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.
|
@@ -47,6 +47,10 @@ export interface WhatsNewModalConfig {
|
|
|
47
47
|
* Example: "https://docs.example.com" or "https://docs.example.com/"
|
|
48
48
|
*/
|
|
49
49
|
documentation: string;
|
|
50
|
+
/**
|
|
51
|
+
* URL to GitHub repository.
|
|
52
|
+
*/
|
|
53
|
+
github: string;
|
|
50
54
|
/**
|
|
51
55
|
* URL to tools page showcasing all plugins and productivity tools.
|
|
52
56
|
* Defaults to DEFAULT_WHATS_NEW_LINKS.TOOLS if not provided.
|
|
@@ -72,10 +76,8 @@ export interface WhatsNewModalConfig {
|
|
|
72
76
|
* - `.{prefix}-whats-new-modal` - Applied to the main content element
|
|
73
77
|
* - `.{prefix}-whats-new-modal .modal` - Modal dialog styling (max-width, width)
|
|
74
78
|
*
|
|
75
|
-
* ###
|
|
76
|
-
* -
|
|
77
|
-
* - Contains h2 (title) and subtitle paragraph
|
|
78
|
-
* - `.{prefix}-whats-new-header h2` - Main title styling
|
|
79
|
+
* ### Title and Subtitle
|
|
80
|
+
* - Modal title is set via `setTitle()` - Obsidian handles the styling and X close button
|
|
79
81
|
* - `.{prefix}-whats-new-subtitle` - Subtitle text ("Changes since vX.X.X")
|
|
80
82
|
*
|
|
81
83
|
* ### Support Section
|
|
@@ -101,11 +103,9 @@ export interface WhatsNewModalConfig {
|
|
|
101
103
|
*
|
|
102
104
|
* ### Sticky Footer
|
|
103
105
|
* - `.{prefix}-whats-new-sticky-footer` - Footer container (should be sticky)
|
|
104
|
-
*
|
|
105
|
-
* - `.{prefix}-whats-new-separator` - Separator with custom class
|
|
106
|
+
* - Has border-top to separate from content
|
|
106
107
|
* - `.{prefix}-whats-new-buttons` - Button container
|
|
107
108
|
* - `.{prefix}-whats-new-buttons button` - Individual buttons
|
|
108
|
-
* - `.{prefix}-mod-cta` - Primary/CTA button state (applied to Close button)
|
|
109
109
|
*
|
|
110
110
|
* ## Example CSS Implementation
|
|
111
111
|
*
|
|
@@ -116,25 +116,45 @@ export interface WhatsNewModalConfig {
|
|
|
116
116
|
* width: 90%;
|
|
117
117
|
* }
|
|
118
118
|
*
|
|
119
|
-
* //
|
|
120
|
-
* .my-plugin-whats-new-
|
|
121
|
-
*
|
|
119
|
+
* // Plugin Name Link (in title)
|
|
120
|
+
* .my-plugin-whats-new-plugin-name {
|
|
121
|
+
* color: var(--link-color);
|
|
122
|
+
* text-decoration: none;
|
|
123
|
+
* transition: all 0.2s ease;
|
|
124
|
+
* position: relative;
|
|
125
|
+
* font-weight: 600;
|
|
122
126
|
* }
|
|
123
127
|
*
|
|
124
|
-
* .my-plugin-whats-new-
|
|
125
|
-
*
|
|
126
|
-
*
|
|
128
|
+
* .my-plugin-whats-new-plugin-name:hover {
|
|
129
|
+
* color: var(--link-color-hover);
|
|
130
|
+
* text-decoration: none;
|
|
127
131
|
* }
|
|
128
132
|
*
|
|
133
|
+
* .my-plugin-whats-new-plugin-name::after {
|
|
134
|
+
* content: '';
|
|
135
|
+
* position: absolute;
|
|
136
|
+
* bottom: -2px;
|
|
137
|
+
* left: 0;
|
|
138
|
+
* width: 0;
|
|
139
|
+
* height: 2px;
|
|
140
|
+
* background-color: var(--interactive-accent);
|
|
141
|
+
* transition: width 0.3s ease;
|
|
142
|
+
* }
|
|
143
|
+
*
|
|
144
|
+
* .my-plugin-whats-new-plugin-name:hover::after {
|
|
145
|
+
* width: 100%;
|
|
146
|
+
* }
|
|
147
|
+
*
|
|
148
|
+
* // Subtitle
|
|
129
149
|
* .my-plugin-whats-new-subtitle {
|
|
130
150
|
* color: var(--text-muted);
|
|
131
151
|
* font-size: 0.9rem;
|
|
132
|
-
* margin: 0;
|
|
152
|
+
* margin: 0 0 1rem 0;
|
|
133
153
|
* }
|
|
134
154
|
*
|
|
135
155
|
* // Support Section (with donation, tools, and YouTube links)
|
|
136
156
|
* .my-plugin-whats-new-support {
|
|
137
|
-
* margin:
|
|
157
|
+
* margin: 0 0 1rem 0;
|
|
138
158
|
* padding: 1rem;
|
|
139
159
|
* background-color: var(--background-secondary);
|
|
140
160
|
* border-radius: 8px;
|
|
@@ -154,17 +174,35 @@ export interface WhatsNewModalConfig {
|
|
|
154
174
|
* .my-plugin-whats-new-support a {
|
|
155
175
|
* color: var(--link-color);
|
|
156
176
|
* text-decoration: none;
|
|
177
|
+
* transition: all 0.2s ease;
|
|
178
|
+
* position: relative;
|
|
157
179
|
* }
|
|
158
180
|
*
|
|
159
181
|
* .my-plugin-whats-new-support a:hover {
|
|
160
|
-
*
|
|
182
|
+
* color: var(--link-color-hover);
|
|
183
|
+
* text-decoration: none;
|
|
184
|
+
* }
|
|
185
|
+
*
|
|
186
|
+
* .my-plugin-whats-new-support a::after {
|
|
187
|
+
* content: '';
|
|
188
|
+
* position: absolute;
|
|
189
|
+
* bottom: -2px;
|
|
190
|
+
* left: 0;
|
|
191
|
+
* width: 0;
|
|
192
|
+
* height: 2px;
|
|
193
|
+
* background-color: var(--interactive-accent);
|
|
194
|
+
* transition: width 0.3s ease;
|
|
195
|
+
* }
|
|
196
|
+
*
|
|
197
|
+
* .my-plugin-whats-new-support a:hover::after {
|
|
198
|
+
* width: 100%;
|
|
161
199
|
* }
|
|
162
200
|
*
|
|
163
201
|
* // Changelog Content (Scrollable Area)
|
|
164
202
|
* .my-plugin-whats-new-content {
|
|
165
|
-
* max-height:
|
|
203
|
+
* max-height: 400px;
|
|
166
204
|
* overflow-y: auto;
|
|
167
|
-
* margin-bottom:
|
|
205
|
+
* margin-bottom: 1rem;
|
|
168
206
|
* padding-right: 0.5rem;
|
|
169
207
|
* border-radius: 8px;
|
|
170
208
|
* }
|
|
@@ -227,50 +265,44 @@ export interface WhatsNewModalConfig {
|
|
|
227
265
|
* position: sticky;
|
|
228
266
|
* bottom: 0;
|
|
229
267
|
* background: var(--background-primary);
|
|
230
|
-
* padding-top:
|
|
231
|
-
* margin-top:
|
|
268
|
+
* padding-top: 0.75rem;
|
|
269
|
+
* margin-top: 0;
|
|
232
270
|
* z-index: 10;
|
|
233
271
|
* border-top: 1px solid var(--background-modifier-border);
|
|
234
272
|
* }
|
|
235
273
|
*
|
|
236
|
-
* .my-plugin-whats-new-modal hr,
|
|
237
|
-
* .my-plugin-whats-new-separator {
|
|
238
|
-
* margin: 0 0 1rem 0;
|
|
239
|
-
* border: none;
|
|
240
|
-
* border-top: 1px solid var(--background-modifier-border);
|
|
241
|
-
* }
|
|
242
|
-
*
|
|
243
274
|
* .my-plugin-whats-new-buttons {
|
|
244
275
|
* display: flex;
|
|
245
276
|
* gap: 0.5rem;
|
|
246
|
-
* justify-content:
|
|
277
|
+
* justify-content: space-between;
|
|
247
278
|
* flex-wrap: wrap;
|
|
248
|
-
* margin-top: 1rem;
|
|
249
279
|
* padding-bottom: 0.5rem;
|
|
280
|
+
* width: 100%;
|
|
250
281
|
* }
|
|
251
282
|
*
|
|
252
283
|
* .my-plugin-whats-new-buttons button {
|
|
284
|
+
* flex: 1;
|
|
285
|
+
* min-width: 0;
|
|
253
286
|
* padding: 0.5rem 1rem;
|
|
254
287
|
* border-radius: 4px;
|
|
255
288
|
* cursor: pointer;
|
|
256
289
|
* border: 1px solid var(--background-modifier-border);
|
|
257
290
|
* background: var(--interactive-normal);
|
|
258
291
|
* color: var(--text-normal);
|
|
259
|
-
* transition:
|
|
292
|
+
* transition: all 0.2s ease;
|
|
293
|
+
* text-align: center;
|
|
260
294
|
* }
|
|
261
295
|
*
|
|
262
296
|
* .my-plugin-whats-new-buttons button:hover {
|
|
263
297
|
* background: var(--interactive-hover);
|
|
264
|
-
* }
|
|
265
|
-
*
|
|
266
|
-
* .my-plugin-whats-new-buttons button.my-plugin-mod-cta {
|
|
267
|
-
* background: var(--interactive-accent);
|
|
268
|
-
* color: var(--text-on-accent);
|
|
269
298
|
* border-color: var(--interactive-accent);
|
|
299
|
+
* transform: translateY(-1px);
|
|
300
|
+
* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
270
301
|
* }
|
|
271
302
|
*
|
|
272
|
-
* .my-plugin-whats-new-buttons button
|
|
273
|
-
*
|
|
303
|
+
* .my-plugin-whats-new-buttons button:active {
|
|
304
|
+
* transform: translateY(0);
|
|
305
|
+
* box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
|
274
306
|
* }
|
|
275
307
|
* ```
|
|
276
308
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whats-new-modal.d.ts","sourceRoot":"","sources":["../../src/components/whats-new-modal.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"whats-new-modal.d.ts","sourceRoot":"","sources":["../../src/components/whats-new-modal.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAoB,KAAK,EAAE,MAAM,UAAU,CAAC;AAEnD;;;GAGG;AACH,eAAO,MAAM,uBAAuB;IACnC;;OAEG;;IAGH;;;OAGG;;CAEM,CAAC;AAEX,MAAM,WAAW,mBAAmB;IACnC;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,gBAAgB,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,KAAK,EAAE;QACN;;WAEG;QACH,OAAO,EAAE,MAAM,CAAC;QAEhB;;WAEG;QACH,SAAS,EAAE,MAAM,CAAC;QAElB;;;WAGG;QACH,aAAa,EAAE,MAAM,CAAC;QAEtB;;WAEG;QACH,MAAM,EAAE,MAAM,CAAC;QAEf;;;WAGG;QACH,KAAK,CAAC,EAAE,MAAM,CAAC;QAEf;;;WAGG;QACH,OAAO,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiQG;AACH,qBAAa,aAAc,SAAQ,KAAK;IAGtC,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,SAAS;gBAJjB,GAAG,EAAE,GAAG,EACA,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,mBAAmB,EAC3B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM;IAK1B;;OAEG;IACH,OAAO,CAAC,GAAG;IAIX;;OAEG;IACH,OAAO,CAAC,MAAM;IAId;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAmC5B,MAAM;IAoJZ,OAAO;CAGP"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __awaiter } from "tslib";
|
|
2
|
+
import { formatChangelogSections, getChangelogSince } from "@real1ty-obsidian-plugins/utils";
|
|
2
3
|
import { MarkdownRenderer, Modal } from "obsidian";
|
|
3
|
-
import { formatChangelogSections, getChangelogSince } from "../string/changelog-parser";
|
|
4
4
|
/**
|
|
5
5
|
* Default URLs for the What's New modal.
|
|
6
6
|
* These can be overridden in the config.
|
|
@@ -29,10 +29,8 @@ export const DEFAULT_WHATS_NEW_LINKS = {
|
|
|
29
29
|
* - `.{prefix}-whats-new-modal` - Applied to the main content element
|
|
30
30
|
* - `.{prefix}-whats-new-modal .modal` - Modal dialog styling (max-width, width)
|
|
31
31
|
*
|
|
32
|
-
* ###
|
|
33
|
-
* -
|
|
34
|
-
* - Contains h2 (title) and subtitle paragraph
|
|
35
|
-
* - `.{prefix}-whats-new-header h2` - Main title styling
|
|
32
|
+
* ### Title and Subtitle
|
|
33
|
+
* - Modal title is set via `setTitle()` - Obsidian handles the styling and X close button
|
|
36
34
|
* - `.{prefix}-whats-new-subtitle` - Subtitle text ("Changes since vX.X.X")
|
|
37
35
|
*
|
|
38
36
|
* ### Support Section
|
|
@@ -58,11 +56,9 @@ export const DEFAULT_WHATS_NEW_LINKS = {
|
|
|
58
56
|
*
|
|
59
57
|
* ### Sticky Footer
|
|
60
58
|
* - `.{prefix}-whats-new-sticky-footer` - Footer container (should be sticky)
|
|
61
|
-
*
|
|
62
|
-
* - `.{prefix}-whats-new-separator` - Separator with custom class
|
|
59
|
+
* - Has border-top to separate from content
|
|
63
60
|
* - `.{prefix}-whats-new-buttons` - Button container
|
|
64
61
|
* - `.{prefix}-whats-new-buttons button` - Individual buttons
|
|
65
|
-
* - `.{prefix}-mod-cta` - Primary/CTA button state (applied to Close button)
|
|
66
62
|
*
|
|
67
63
|
* ## Example CSS Implementation
|
|
68
64
|
*
|
|
@@ -73,25 +69,45 @@ export const DEFAULT_WHATS_NEW_LINKS = {
|
|
|
73
69
|
* width: 90%;
|
|
74
70
|
* }
|
|
75
71
|
*
|
|
76
|
-
* //
|
|
77
|
-
* .my-plugin-whats-new-
|
|
78
|
-
*
|
|
72
|
+
* // Plugin Name Link (in title)
|
|
73
|
+
* .my-plugin-whats-new-plugin-name {
|
|
74
|
+
* color: var(--link-color);
|
|
75
|
+
* text-decoration: none;
|
|
76
|
+
* transition: all 0.2s ease;
|
|
77
|
+
* position: relative;
|
|
78
|
+
* font-weight: 600;
|
|
79
79
|
* }
|
|
80
80
|
*
|
|
81
|
-
* .my-plugin-whats-new-
|
|
82
|
-
*
|
|
83
|
-
*
|
|
81
|
+
* .my-plugin-whats-new-plugin-name:hover {
|
|
82
|
+
* color: var(--link-color-hover);
|
|
83
|
+
* text-decoration: none;
|
|
84
|
+
* }
|
|
85
|
+
*
|
|
86
|
+
* .my-plugin-whats-new-plugin-name::after {
|
|
87
|
+
* content: '';
|
|
88
|
+
* position: absolute;
|
|
89
|
+
* bottom: -2px;
|
|
90
|
+
* left: 0;
|
|
91
|
+
* width: 0;
|
|
92
|
+
* height: 2px;
|
|
93
|
+
* background-color: var(--interactive-accent);
|
|
94
|
+
* transition: width 0.3s ease;
|
|
95
|
+
* }
|
|
96
|
+
*
|
|
97
|
+
* .my-plugin-whats-new-plugin-name:hover::after {
|
|
98
|
+
* width: 100%;
|
|
84
99
|
* }
|
|
85
100
|
*
|
|
101
|
+
* // Subtitle
|
|
86
102
|
* .my-plugin-whats-new-subtitle {
|
|
87
103
|
* color: var(--text-muted);
|
|
88
104
|
* font-size: 0.9rem;
|
|
89
|
-
* margin: 0;
|
|
105
|
+
* margin: 0 0 1rem 0;
|
|
90
106
|
* }
|
|
91
107
|
*
|
|
92
108
|
* // Support Section (with donation, tools, and YouTube links)
|
|
93
109
|
* .my-plugin-whats-new-support {
|
|
94
|
-
* margin:
|
|
110
|
+
* margin: 0 0 1rem 0;
|
|
95
111
|
* padding: 1rem;
|
|
96
112
|
* background-color: var(--background-secondary);
|
|
97
113
|
* border-radius: 8px;
|
|
@@ -111,17 +127,35 @@ export const DEFAULT_WHATS_NEW_LINKS = {
|
|
|
111
127
|
* .my-plugin-whats-new-support a {
|
|
112
128
|
* color: var(--link-color);
|
|
113
129
|
* text-decoration: none;
|
|
130
|
+
* transition: all 0.2s ease;
|
|
131
|
+
* position: relative;
|
|
114
132
|
* }
|
|
115
133
|
*
|
|
116
134
|
* .my-plugin-whats-new-support a:hover {
|
|
117
|
-
*
|
|
135
|
+
* color: var(--link-color-hover);
|
|
136
|
+
* text-decoration: none;
|
|
137
|
+
* }
|
|
138
|
+
*
|
|
139
|
+
* .my-plugin-whats-new-support a::after {
|
|
140
|
+
* content: '';
|
|
141
|
+
* position: absolute;
|
|
142
|
+
* bottom: -2px;
|
|
143
|
+
* left: 0;
|
|
144
|
+
* width: 0;
|
|
145
|
+
* height: 2px;
|
|
146
|
+
* background-color: var(--interactive-accent);
|
|
147
|
+
* transition: width 0.3s ease;
|
|
148
|
+
* }
|
|
149
|
+
*
|
|
150
|
+
* .my-plugin-whats-new-support a:hover::after {
|
|
151
|
+
* width: 100%;
|
|
118
152
|
* }
|
|
119
153
|
*
|
|
120
154
|
* // Changelog Content (Scrollable Area)
|
|
121
155
|
* .my-plugin-whats-new-content {
|
|
122
|
-
* max-height:
|
|
156
|
+
* max-height: 400px;
|
|
123
157
|
* overflow-y: auto;
|
|
124
|
-
* margin-bottom:
|
|
158
|
+
* margin-bottom: 1rem;
|
|
125
159
|
* padding-right: 0.5rem;
|
|
126
160
|
* border-radius: 8px;
|
|
127
161
|
* }
|
|
@@ -184,50 +218,44 @@ export const DEFAULT_WHATS_NEW_LINKS = {
|
|
|
184
218
|
* position: sticky;
|
|
185
219
|
* bottom: 0;
|
|
186
220
|
* background: var(--background-primary);
|
|
187
|
-
* padding-top:
|
|
188
|
-
* margin-top:
|
|
221
|
+
* padding-top: 0.75rem;
|
|
222
|
+
* margin-top: 0;
|
|
189
223
|
* z-index: 10;
|
|
190
224
|
* border-top: 1px solid var(--background-modifier-border);
|
|
191
225
|
* }
|
|
192
226
|
*
|
|
193
|
-
* .my-plugin-whats-new-modal hr,
|
|
194
|
-
* .my-plugin-whats-new-separator {
|
|
195
|
-
* margin: 0 0 1rem 0;
|
|
196
|
-
* border: none;
|
|
197
|
-
* border-top: 1px solid var(--background-modifier-border);
|
|
198
|
-
* }
|
|
199
|
-
*
|
|
200
227
|
* .my-plugin-whats-new-buttons {
|
|
201
228
|
* display: flex;
|
|
202
229
|
* gap: 0.5rem;
|
|
203
|
-
* justify-content:
|
|
230
|
+
* justify-content: space-between;
|
|
204
231
|
* flex-wrap: wrap;
|
|
205
|
-
* margin-top: 1rem;
|
|
206
232
|
* padding-bottom: 0.5rem;
|
|
233
|
+
* width: 100%;
|
|
207
234
|
* }
|
|
208
235
|
*
|
|
209
236
|
* .my-plugin-whats-new-buttons button {
|
|
237
|
+
* flex: 1;
|
|
238
|
+
* min-width: 0;
|
|
210
239
|
* padding: 0.5rem 1rem;
|
|
211
240
|
* border-radius: 4px;
|
|
212
241
|
* cursor: pointer;
|
|
213
242
|
* border: 1px solid var(--background-modifier-border);
|
|
214
243
|
* background: var(--interactive-normal);
|
|
215
244
|
* color: var(--text-normal);
|
|
216
|
-
* transition:
|
|
245
|
+
* transition: all 0.2s ease;
|
|
246
|
+
* text-align: center;
|
|
217
247
|
* }
|
|
218
248
|
*
|
|
219
249
|
* .my-plugin-whats-new-buttons button:hover {
|
|
220
250
|
* background: var(--interactive-hover);
|
|
221
|
-
* }
|
|
222
|
-
*
|
|
223
|
-
* .my-plugin-whats-new-buttons button.my-plugin-mod-cta {
|
|
224
|
-
* background: var(--interactive-accent);
|
|
225
|
-
* color: var(--text-on-accent);
|
|
226
251
|
* border-color: var(--interactive-accent);
|
|
252
|
+
* transform: translateY(-1px);
|
|
253
|
+
* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
227
254
|
* }
|
|
228
255
|
*
|
|
229
|
-
* .my-plugin-whats-new-buttons button
|
|
230
|
-
*
|
|
256
|
+
* .my-plugin-whats-new-buttons button:active {
|
|
257
|
+
* transform: translateY(0);
|
|
258
|
+
* box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
|
231
259
|
* }
|
|
232
260
|
* ```
|
|
233
261
|
*
|
|
@@ -307,12 +335,23 @@ export class WhatsNewModal extends Modal {
|
|
|
307
335
|
const { contentEl } = this;
|
|
308
336
|
contentEl.empty();
|
|
309
337
|
this.addCls(contentEl, "whats-new-modal");
|
|
310
|
-
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
338
|
+
this.setTitle("");
|
|
339
|
+
const titleEl = this.titleEl;
|
|
340
|
+
titleEl.empty();
|
|
341
|
+
const pluginNameLink = titleEl.createEl("a", {
|
|
342
|
+
text: this.config.pluginName,
|
|
343
|
+
cls: this.cls("whats-new-plugin-name"),
|
|
344
|
+
href: "#",
|
|
314
345
|
});
|
|
315
|
-
|
|
346
|
+
pluginNameLink.addEventListener("click", (e) => {
|
|
347
|
+
e.preventDefault();
|
|
348
|
+
window.open(this.config.links.github, "_blank");
|
|
349
|
+
});
|
|
350
|
+
titleEl.createSpan({
|
|
351
|
+
text: ` updated to v${this.toVersion}`,
|
|
352
|
+
});
|
|
353
|
+
// Subtitle
|
|
354
|
+
contentEl.createEl("p", {
|
|
316
355
|
text: `Changes since v${this.fromVersion}`,
|
|
317
356
|
cls: this.cls("whats-new-subtitle"),
|
|
318
357
|
});
|
|
@@ -320,38 +359,29 @@ export class WhatsNewModal extends Modal {
|
|
|
320
359
|
const supportSection = contentEl.createDiv({
|
|
321
360
|
cls: this.cls("whats-new-support"),
|
|
322
361
|
});
|
|
323
|
-
supportSection.createEl("h3", { text: "Support
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
362
|
+
supportSection.createEl("h3", { text: "Support the development of this plugin" });
|
|
363
|
+
const introText = supportSection.createEl("p");
|
|
364
|
+
introText.setText("If this plugin saves you time or improves how you work in Obsidian, consider supporting its development. Your support helps fund ongoing maintenance, new features, and long-term stability.");
|
|
365
|
+
const supportLinkText = supportSection.createEl("p");
|
|
366
|
+
supportLinkText.createSpan({ text: "👉 " });
|
|
367
|
+
supportLinkText.createEl("a", {
|
|
368
|
+
text: "Support my work",
|
|
329
369
|
href: this.config.links.support,
|
|
330
370
|
});
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
const toolsText = supportSection.createEl("p");
|
|
336
|
-
toolsText.createSpan({ text: "Check out my " });
|
|
337
|
-
toolsText.createEl("a", {
|
|
338
|
-
text: "other plugins and productivity tools",
|
|
371
|
+
const exploreText = supportSection.createEl("p");
|
|
372
|
+
exploreText.createSpan({ text: "You can also explore my " });
|
|
373
|
+
exploreText.createEl("a", {
|
|
374
|
+
text: "other Obsidian plugins and productivity tools",
|
|
339
375
|
href: (_a = this.config.links.tools) !== null && _a !== void 0 ? _a : DEFAULT_WHATS_NEW_LINKS.TOOLS,
|
|
340
376
|
});
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
});
|
|
344
|
-
// YouTube channel
|
|
345
|
-
const youtubeText = supportSection.createEl("p");
|
|
346
|
-
youtubeText.createSpan({ text: "Subscribe to my " });
|
|
347
|
-
youtubeText.createEl("a", {
|
|
377
|
+
exploreText.createSpan({ text: ", or follow my " });
|
|
378
|
+
exploreText.createEl("a", {
|
|
348
379
|
text: "YouTube channel",
|
|
349
380
|
href: (_b = this.config.links.youtube) !== null && _b !== void 0 ? _b : DEFAULT_WHATS_NEW_LINKS.YOUTUBE,
|
|
350
381
|
});
|
|
351
|
-
|
|
352
|
-
text: " for
|
|
382
|
+
exploreText.createSpan({
|
|
383
|
+
text: " for in-depth tutorials and workflow ideas.",
|
|
353
384
|
});
|
|
354
|
-
contentEl.createEl("hr");
|
|
355
385
|
// Changelog content
|
|
356
386
|
const changelogSections = getChangelogSince(this.config.changelogContent, this.fromVersion, this.toVersion);
|
|
357
387
|
if (changelogSections.length === 0) {
|
|
@@ -373,14 +403,17 @@ export class WhatsNewModal extends Modal {
|
|
|
373
403
|
const stickyFooter = contentEl.createDiv({
|
|
374
404
|
cls: this.cls("whats-new-sticky-footer"),
|
|
375
405
|
});
|
|
376
|
-
// Separator line
|
|
377
|
-
stickyFooter.createEl("hr", {
|
|
378
|
-
cls: this.cls("whats-new-separator"),
|
|
379
|
-
});
|
|
380
406
|
// Action buttons
|
|
381
407
|
const buttonContainer = stickyFooter.createDiv({
|
|
382
408
|
cls: this.cls("whats-new-buttons"),
|
|
383
409
|
});
|
|
410
|
+
// GitHub button
|
|
411
|
+
const githubBtn = buttonContainer.createEl("button", {
|
|
412
|
+
text: "GitHub",
|
|
413
|
+
});
|
|
414
|
+
githubBtn.addEventListener("click", () => {
|
|
415
|
+
window.open(this.config.links.github, "_blank");
|
|
416
|
+
});
|
|
384
417
|
// Full changelog button
|
|
385
418
|
const changelogBtn = buttonContainer.createEl("button", {
|
|
386
419
|
text: "Changelog",
|
|
@@ -411,12 +444,6 @@ export class WhatsNewModal extends Modal {
|
|
|
411
444
|
var _a;
|
|
412
445
|
window.open((_a = this.config.links.youtube) !== null && _a !== void 0 ? _a : DEFAULT_WHATS_NEW_LINKS.YOUTUBE, "_blank");
|
|
413
446
|
});
|
|
414
|
-
// Close button (always present)
|
|
415
|
-
const closeBtn = buttonContainer.createEl("button", {
|
|
416
|
-
text: "Close",
|
|
417
|
-
cls: this.cls("mod-cta"),
|
|
418
|
-
});
|
|
419
|
-
closeBtn.addEventListener("click", () => this.close());
|
|
420
447
|
});
|
|
421
448
|
}
|
|
422
449
|
onClose() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whats-new-modal.js","sourceRoot":"","sources":["../../src/components/whats-new-modal.ts"],"names":[],"mappings":"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","sourcesContent":["import type { App, Plugin } from \"obsidian\";\nimport { MarkdownRenderer, Modal } from \"obsidian\";\nimport { formatChangelogSections, getChangelogSince } from \"../string/changelog-parser\";\n\n/**\n * Default URLs for the What's New modal.\n * These can be overridden in the config.\n */\nexport const DEFAULT_WHATS_NEW_LINKS = {\n\t/**\n\t * Default tools page showcasing all plugins and productivity software.\n\t */\n\tTOOLS: \"https://matejvavroproductivity.com/tools/\",\n\n\t/**\n\t * Default YouTube channel with Obsidian tutorials and productivity tips.\n\t * Includes subscription confirmation parameter.\n\t */\n\tYOUTUBE: \"https://www.youtube.com/@MatejVavroProductivity?sub_confirmation=1\",\n} as const;\n\nexport interface WhatsNewModalConfig {\n\t/**\n\t * The CSS class prefix/suffix to use for styling.\n\t * Example: \"custom-calendar\" will generate classes like \"custom-calendar-whats-new-modal\"\n\t */\n\tcssPrefix: string;\n\n\t/**\n\t * Display name of the plugin.\n\t * Example: \"Custom Calendar\"\n\t */\n\tpluginName: string;\n\n\t/**\n\t * Raw changelog markdown content to parse.\n\t */\n\tchangelogContent: string;\n\n\t/**\n\t * Links to external resources.\n\t */\n\tlinks: {\n\t\t/**\n\t\t * URL to support/donate page.\n\t\t */\n\t\tsupport: string;\n\n\t\t/**\n\t\t * URL to full changelog page.\n\t\t */\n\t\tchangelog: string;\n\n\t\t/**\n\t\t * Base URL for documentation (used to resolve relative links in changelog).\n\t\t * Example: \"https://docs.example.com\" or \"https://docs.example.com/\"\n\t\t */\n\t\tdocumentation: string;\n\n\t\t/**\n\t\t * URL to tools page showcasing all plugins and productivity tools.\n\t\t * Defaults to DEFAULT_WHATS_NEW_LINKS.TOOLS if not provided.\n\t\t */\n\t\ttools?: string;\n\n\t\t/**\n\t\t * URL to YouTube channel with tutorials and productivity tips.\n\t\t * Defaults to DEFAULT_WHATS_NEW_LINKS.YOUTUBE if not provided.\n\t\t */\n\t\tyoutube?: string;\n\t};\n}\n\n/**\n * Generic \"What's New\" modal that displays changelog entries between versions.\n * Supports custom CSS prefixes, plugin names, and configurable links.\n *\n * ## CSS Classes\n *\n * This modal uses the following CSS classes (with your custom prefix).\n * Replace `{prefix}` with your `cssPrefix` value (e.g., \"my-plugin\").\n *\n * ### Main Container\n * - `.{prefix}-whats-new-modal` - Applied to the main content element\n * - `.{prefix}-whats-new-modal .modal` - Modal dialog styling (max-width, width)\n *\n * ### Header Section\n * - `.{prefix}-whats-new-header` - Container for the header section\n * - Contains h2 (title) and subtitle paragraph\n * - `.{prefix}-whats-new-header h2` - Main title styling\n * - `.{prefix}-whats-new-subtitle` - Subtitle text (\"Changes since vX.X.X\")\n *\n * ### Support Section\n * - `.{prefix}-whats-new-support` - Support section container\n * - Contains donation, tools, and YouTube links\n * - Should have background, padding, border-radius\n * - `.{prefix}-whats-new-support h3` - Support section heading\n * - `.{prefix}-whats-new-support p` - Support section paragraph text (one per row)\n * - `.{prefix}-whats-new-support a` - Links in support section (consistent styling)\n * - `.{prefix}-whats-new-support a:hover` - Link hover state\n *\n * ### Changelog Content\n * - `.{prefix}-whats-new-content` - Changelog content container\n * - Should have max-height, overflow-y: auto for scrolling\n * - `.{prefix}-whats-new-content h2` - Version headings in changelog\n * - `.{prefix}-whats-new-content h3` - Section headings in changelog\n * - `.{prefix}-whats-new-content ul` - Changelog lists\n * - `.{prefix}-whats-new-content li` - Changelog list items\n * - `.{prefix}-whats-new-content code` - Inline code in changelog\n * - `.{prefix}-whats-new-content pre` - Code blocks in changelog\n * - `.{prefix}-whats-new-content a.external-link` - External links (auto-added)\n * - `.{prefix}-whats-new-empty` - Empty state message\n *\n * ### Sticky Footer\n * - `.{prefix}-whats-new-sticky-footer` - Footer container (should be sticky)\n * - `.{prefix}-whats-new-modal hr` - Separator line in footer\n * - `.{prefix}-whats-new-separator` - Separator with custom class\n * - `.{prefix}-whats-new-buttons` - Button container\n * - `.{prefix}-whats-new-buttons button` - Individual buttons\n * - `.{prefix}-mod-cta` - Primary/CTA button state (applied to Close button)\n *\n * ## Example CSS Implementation\n *\n * ```css\n * // Main Container\n * .my-plugin-whats-new-modal .modal {\n * max-width: 800px;\n * width: 90%;\n * }\n *\n * // Header\n * .my-plugin-whats-new-header {\n * margin-bottom: 1.5rem;\n * }\n *\n * .my-plugin-whats-new-header h2 {\n * margin-bottom: 0.5rem;\n * color: var(--text-normal);\n * }\n *\n * .my-plugin-whats-new-subtitle {\n * color: var(--text-muted);\n * font-size: 0.9rem;\n * margin: 0;\n * }\n *\n * // Support Section (with donation, tools, and YouTube links)\n * .my-plugin-whats-new-support {\n * margin: 1.5rem 0;\n * padding: 1rem;\n * background-color: var(--background-secondary);\n * border-radius: 8px;\n * }\n *\n * .my-plugin-whats-new-support h3 {\n * margin-top: 0;\n * margin-bottom: 0.5rem;\n * font-size: 1rem;\n * }\n *\n * .my-plugin-whats-new-support p {\n * margin: 0.5rem 0;\n * color: var(--text-normal);\n * }\n *\n * .my-plugin-whats-new-support a {\n * color: var(--link-color);\n * text-decoration: none;\n * }\n *\n * .my-plugin-whats-new-support a:hover {\n * text-decoration: underline;\n * }\n *\n * // Changelog Content (Scrollable Area)\n * .my-plugin-whats-new-content {\n * max-height: 500px;\n * overflow-y: auto;\n * margin-bottom: 1.5rem;\n * padding-right: 0.5rem;\n * border-radius: 8px;\n * }\n *\n * .my-plugin-whats-new-content h2 {\n * font-size: 1.3rem;\n * margin-top: 1.5rem;\n * margin-bottom: 0.5rem;\n * color: var(--text-accent);\n * }\n *\n * .my-plugin-whats-new-content h3 {\n * font-size: 1.1rem;\n * margin-top: 1rem;\n * margin-bottom: 0.5rem;\n * }\n *\n * .my-plugin-whats-new-content ul {\n * padding-left: 1.5rem;\n * }\n *\n * .my-plugin-whats-new-content li {\n * margin-bottom: 0.5rem;\n * line-height: 1.6;\n * }\n *\n * .my-plugin-whats-new-content code {\n * background: var(--code-background);\n * padding: 0.2em 0.4em;\n * border-radius: 3px;\n * font-size: 0.9em;\n * }\n *\n * .my-plugin-whats-new-content pre {\n * background: var(--code-background);\n * padding: 1rem;\n * border-radius: 6px;\n * overflow-x: auto;\n * }\n *\n * .my-plugin-whats-new-content a.external-link {\n * color: var(--link-external-color);\n * }\n *\n * .my-plugin-whats-new-content a.external-link::after {\n * content: \"↗\";\n * margin-left: 0.2em;\n * font-size: 0.8em;\n * }\n *\n * .my-plugin-whats-new-empty {\n * text-align: center;\n * color: var(--text-muted);\n * padding: 2rem;\n * font-style: italic;\n * }\n *\n * // Sticky Footer\n * .my-plugin-whats-new-sticky-footer {\n * position: sticky;\n * bottom: 0;\n * background: var(--background-primary);\n * padding-top: 1rem;\n * margin-top: 1rem;\n * z-index: 10;\n * border-top: 1px solid var(--background-modifier-border);\n * }\n *\n * .my-plugin-whats-new-modal hr,\n * .my-plugin-whats-new-separator {\n * margin: 0 0 1rem 0;\n * border: none;\n * border-top: 1px solid var(--background-modifier-border);\n * }\n *\n * .my-plugin-whats-new-buttons {\n * display: flex;\n * gap: 0.5rem;\n * justify-content: flex-end;\n * flex-wrap: wrap;\n * margin-top: 1rem;\n * padding-bottom: 0.5rem;\n * }\n *\n * .my-plugin-whats-new-buttons button {\n * padding: 0.5rem 1rem;\n * border-radius: 4px;\n * cursor: pointer;\n * border: 1px solid var(--background-modifier-border);\n * background: var(--interactive-normal);\n * color: var(--text-normal);\n * transition: background-color 0.2s;\n * }\n *\n * .my-plugin-whats-new-buttons button:hover {\n * background: var(--interactive-hover);\n * }\n *\n * .my-plugin-whats-new-buttons button.my-plugin-mod-cta {\n * background: var(--interactive-accent);\n * color: var(--text-on-accent);\n * border-color: var(--interactive-accent);\n * }\n *\n * .my-plugin-whats-new-buttons button.my-plugin-mod-cta:hover {\n * background: var(--interactive-accent-hover);\n * }\n * ```\n *\n * @example\n * ```typescript\n * const modal = new WhatsNewModal(app, plugin, {\n * cssPrefix: \"my-plugin\",\n * pluginName: \"My Plugin\",\n * changelogContent: rawChangelog,\n * links: {\n * support: \"https://...\",\n * changelog: \"https://...\",\n * documentation: \"https://...\"\n * }\n * }, \"1.0.0\", \"2.0.0\");\n * modal.open();\n * ```\n */\nexport class WhatsNewModal extends Modal {\n\tconstructor(\n\t\tapp: App,\n\t\tprivate plugin: Plugin,\n\t\tprivate config: WhatsNewModalConfig,\n\t\tprivate fromVersion: string,\n\t\tprivate toVersion: string\n\t) {\n\t\tsuper(app);\n\t}\n\n\t/**\n\t * Helper to create CSS class names with the configured prefix.\n\t */\n\tprivate cls(suffix: string): string {\n\t\treturn `${this.config.cssPrefix}-${suffix}`;\n\t}\n\n\t/**\n\t * Helper to add CSS class to an element.\n\t */\n\tprivate addCls(el: HTMLElement, suffix: string): void {\n\t\tel.classList.add(this.cls(suffix));\n\t}\n\n\t/**\n\t * Makes external links in rendered markdown clickable by adding click handlers.\n\t * Handles both absolute URLs (http/https) and relative URLs (starting with /).\n\t * Relative URLs are resolved against the documentation base URL.\n\t */\n\tprivate makeExternalLinksClickable(container: HTMLElement): void {\n\t\tconst links = container.querySelectorAll<HTMLAnchorElement>(\"a[href]\");\n\n\t\t// Convert NodeList to Array for iteration\n\t\tArray.from(links).forEach((link) => {\n\t\t\tconst href = link.getAttribute(\"href\");\n\t\t\tif (!href) return;\n\n\t\t\tlet finalUrl: string | null = null;\n\n\t\t\t// Handle absolute HTTP(S) links\n\t\t\tif (href.startsWith(\"http://\") || href.startsWith(\"https://\")) {\n\t\t\t\tfinalUrl = href;\n\t\t\t}\n\t\t\t// Handle relative links (starting with /)\n\t\t\telse if (href.startsWith(\"/\")) {\n\t\t\t\t// Get base documentation URL and ensure proper slash handling\n\t\t\t\tconst baseUrl = this.config.links.documentation;\n\t\t\t\tconst normalizedBase = baseUrl.endsWith(\"/\") ? baseUrl.slice(0, -1) : baseUrl;\n\t\t\t\tfinalUrl = `${normalizedBase}${href}`;\n\t\t\t}\n\n\t\t\t// Add click handler for external links\n\t\t\tif (finalUrl) {\n\t\t\t\tlink.addEventListener(\"click\", (event: MouseEvent) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\twindow.open(finalUrl, \"_blank\");\n\t\t\t\t});\n\n\t\t\t\t// Add visual indicator that it's an external link\n\t\t\t\tlink.classList.add(\"external-link\");\n\t\t\t}\n\t\t});\n\t}\n\n\tasync onOpen() {\n\t\tconst { contentEl } = this;\n\t\tcontentEl.empty();\n\n\t\tthis.addCls(contentEl, \"whats-new-modal\");\n\n\t\t// Header section\n\t\tconst header = contentEl.createDiv({ cls: this.cls(\"whats-new-header\") });\n\t\theader.createEl(\"h2\", {\n\t\t\ttext: `${this.config.pluginName} updated to v${this.toVersion}`,\n\t\t});\n\n\t\theader.createEl(\"p\", {\n\t\t\ttext: `Changes since v${this.fromVersion}`,\n\t\t\tcls: this.cls(\"whats-new-subtitle\"),\n\t\t});\n\n\t\t// Support section\n\t\tconst supportSection = contentEl.createDiv({\n\t\t\tcls: this.cls(\"whats-new-support\"),\n\t\t});\n\n\t\tsupportSection.createEl(\"h3\", { text: \"Support My Work\" });\n\n\t\t// Support/donate\n\t\tconst supportText = supportSection.createEl(\"p\");\n\t\tsupportText.createSpan({ text: \"If you enjoy using this plugin, please consider \" });\n\t\tsupportText.createEl(\"a\", {\n\t\t\ttext: \"supporting my work\",\n\t\t\thref: this.config.links.support,\n\t\t});\n\t\tsupportText.createSpan({\n\t\t\ttext: \". Your support helps keep this plugin maintained and improved!\",\n\t\t});\n\n\t\t// Other tools\n\t\tconst toolsText = supportSection.createEl(\"p\");\n\t\ttoolsText.createSpan({ text: \"Check out my \" });\n\t\ttoolsText.createEl(\"a\", {\n\t\t\ttext: \"other plugins and productivity tools\",\n\t\t\thref: this.config.links.tools ?? DEFAULT_WHATS_NEW_LINKS.TOOLS,\n\t\t});\n\t\ttoolsText.createSpan({\n\t\t\ttext: \" to enhance your workflow even further.\",\n\t\t});\n\n\t\t// YouTube channel\n\t\tconst youtubeText = supportSection.createEl(\"p\");\n\t\tyoutubeText.createSpan({ text: \"Subscribe to my \" });\n\t\tyoutubeText.createEl(\"a\", {\n\t\t\ttext: \"YouTube channel\",\n\t\t\thref: this.config.links.youtube ?? DEFAULT_WHATS_NEW_LINKS.YOUTUBE,\n\t\t});\n\t\tyoutubeText.createSpan({\n\t\t\ttext: \" for Obsidian tutorials and productivity tips!\",\n\t\t});\n\n\t\tcontentEl.createEl(\"hr\");\n\n\t\t// Changelog content\n\t\tconst changelogSections = getChangelogSince(\n\t\t\tthis.config.changelogContent,\n\t\t\tthis.fromVersion,\n\t\t\tthis.toVersion\n\t\t);\n\n\t\tif (changelogSections.length === 0) {\n\t\t\tcontentEl.createEl(\"p\", {\n\t\t\t\ttext: \"No significant changes found in this update.\",\n\t\t\t\tcls: this.cls(\"whats-new-empty\"),\n\t\t\t});\n\t\t} else {\n\t\t\tconst changelogContainer = contentEl.createDiv({\n\t\t\t\tcls: this.cls(\"whats-new-content\"),\n\t\t\t});\n\n\t\t\tconst markdownContent = formatChangelogSections(changelogSections);\n\n\t\t\tawait MarkdownRenderer.render(\n\t\t\t\tthis.app,\n\t\t\t\tmarkdownContent,\n\t\t\t\tchangelogContainer,\n\t\t\t\t\"/\",\n\t\t\t\tthis.plugin\n\t\t\t);\n\n\t\t\t// Make external links clickable\n\t\t\tthis.makeExternalLinksClickable(changelogContainer);\n\t\t}\n\n\t\t// Sticky footer section (hr + buttons)\n\t\tconst stickyFooter = contentEl.createDiv({\n\t\t\tcls: this.cls(\"whats-new-sticky-footer\"),\n\t\t});\n\n\t\t// Separator line\n\t\tstickyFooter.createEl(\"hr\", {\n\t\t\tcls: this.cls(\"whats-new-separator\"),\n\t\t});\n\n\t\t// Action buttons\n\t\tconst buttonContainer = stickyFooter.createDiv({\n\t\t\tcls: this.cls(\"whats-new-buttons\"),\n\t\t});\n\n\t\t// Full changelog button\n\t\tconst changelogBtn = buttonContainer.createEl(\"button\", {\n\t\t\ttext: \"Changelog\",\n\t\t});\n\t\tchangelogBtn.addEventListener(\"click\", () => {\n\t\t\twindow.open(this.config.links.changelog, \"_blank\");\n\t\t});\n\n\t\t// Documentation button\n\t\tconst docsBtn = buttonContainer.createEl(\"button\", {\n\t\t\ttext: \"Documentation\",\n\t\t});\n\t\tdocsBtn.addEventListener(\"click\", () => {\n\t\t\twindow.open(this.config.links.documentation, \"_blank\");\n\t\t});\n\n\t\t// Tools button\n\t\tconst toolsBtn = buttonContainer.createEl(\"button\", {\n\t\t\ttext: \"Other Plugins\",\n\t\t});\n\t\ttoolsBtn.addEventListener(\"click\", () => {\n\t\t\twindow.open(this.config.links.tools ?? DEFAULT_WHATS_NEW_LINKS.TOOLS, \"_blank\");\n\t\t});\n\n\t\t// YouTube button\n\t\tconst youtubeBtn = buttonContainer.createEl(\"button\", {\n\t\t\ttext: \"YouTube\",\n\t\t});\n\t\tyoutubeBtn.addEventListener(\"click\", () => {\n\t\t\twindow.open(this.config.links.youtube ?? DEFAULT_WHATS_NEW_LINKS.YOUTUBE, \"_blank\");\n\t\t});\n\n\t\t// Close button (always present)\n\t\tconst closeBtn = buttonContainer.createEl(\"button\", {\n\t\t\ttext: \"Close\",\n\t\t\tcls: this.cls(\"mod-cta\"),\n\t\t});\n\t\tcloseBtn.addEventListener(\"click\", () => this.close());\n\t}\n\n\tonClose() {\n\t\tthis.contentEl.empty();\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"whats-new-modal.js","sourceRoot":"","sources":["../../src/components/whats-new-modal.ts"],"names":[],"mappings":"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","sourcesContent":["import { formatChangelogSections, getChangelogSince } from \"@real1ty-obsidian-plugins/utils\";\nimport type { App, Plugin } from \"obsidian\";\nimport { MarkdownRenderer, Modal } from \"obsidian\";\n\n/**\n * Default URLs for the What's New modal.\n * These can be overridden in the config.\n */\nexport const DEFAULT_WHATS_NEW_LINKS = {\n\t/**\n\t * Default tools page showcasing all plugins and productivity software.\n\t */\n\tTOOLS: \"https://matejvavroproductivity.com/tools/\",\n\n\t/**\n\t * Default YouTube channel with Obsidian tutorials and productivity tips.\n\t * Includes subscription confirmation parameter.\n\t */\n\tYOUTUBE: \"https://www.youtube.com/@MatejVavroProductivity?sub_confirmation=1\",\n} as const;\n\nexport interface WhatsNewModalConfig {\n\t/**\n\t * The CSS class prefix/suffix to use for styling.\n\t * Example: \"custom-calendar\" will generate classes like \"custom-calendar-whats-new-modal\"\n\t */\n\tcssPrefix: string;\n\n\t/**\n\t * Display name of the plugin.\n\t * Example: \"Custom Calendar\"\n\t */\n\tpluginName: string;\n\n\t/**\n\t * Raw changelog markdown content to parse.\n\t */\n\tchangelogContent: string;\n\n\t/**\n\t * Links to external resources.\n\t */\n\tlinks: {\n\t\t/**\n\t\t * URL to support/donate page.\n\t\t */\n\t\tsupport: string;\n\n\t\t/**\n\t\t * URL to full changelog page.\n\t\t */\n\t\tchangelog: string;\n\n\t\t/**\n\t\t * Base URL for documentation (used to resolve relative links in changelog).\n\t\t * Example: \"https://docs.example.com\" or \"https://docs.example.com/\"\n\t\t */\n\t\tdocumentation: string;\n\n\t\t/**\n\t\t * URL to GitHub repository.\n\t\t */\n\t\tgithub: string;\n\n\t\t/**\n\t\t * URL to tools page showcasing all plugins and productivity tools.\n\t\t * Defaults to DEFAULT_WHATS_NEW_LINKS.TOOLS if not provided.\n\t\t */\n\t\ttools?: string;\n\n\t\t/**\n\t\t * URL to YouTube channel with tutorials and productivity tips.\n\t\t * Defaults to DEFAULT_WHATS_NEW_LINKS.YOUTUBE if not provided.\n\t\t */\n\t\tyoutube?: string;\n\t};\n}\n\n/**\n * Generic \"What's New\" modal that displays changelog entries between versions.\n * Supports custom CSS prefixes, plugin names, and configurable links.\n *\n * ## CSS Classes\n *\n * This modal uses the following CSS classes (with your custom prefix).\n * Replace `{prefix}` with your `cssPrefix` value (e.g., \"my-plugin\").\n *\n * ### Main Container\n * - `.{prefix}-whats-new-modal` - Applied to the main content element\n * - `.{prefix}-whats-new-modal .modal` - Modal dialog styling (max-width, width)\n *\n * ### Title and Subtitle\n * - Modal title is set via `setTitle()` - Obsidian handles the styling and X close button\n * - `.{prefix}-whats-new-subtitle` - Subtitle text (\"Changes since vX.X.X\")\n *\n * ### Support Section\n * - `.{prefix}-whats-new-support` - Support section container\n * - Contains donation, tools, and YouTube links\n * - Should have background, padding, border-radius\n * - `.{prefix}-whats-new-support h3` - Support section heading\n * - `.{prefix}-whats-new-support p` - Support section paragraph text (one per row)\n * - `.{prefix}-whats-new-support a` - Links in support section (consistent styling)\n * - `.{prefix}-whats-new-support a:hover` - Link hover state\n *\n * ### Changelog Content\n * - `.{prefix}-whats-new-content` - Changelog content container\n * - Should have max-height, overflow-y: auto for scrolling\n * - `.{prefix}-whats-new-content h2` - Version headings in changelog\n * - `.{prefix}-whats-new-content h3` - Section headings in changelog\n * - `.{prefix}-whats-new-content ul` - Changelog lists\n * - `.{prefix}-whats-new-content li` - Changelog list items\n * - `.{prefix}-whats-new-content code` - Inline code in changelog\n * - `.{prefix}-whats-new-content pre` - Code blocks in changelog\n * - `.{prefix}-whats-new-content a.external-link` - External links (auto-added)\n * - `.{prefix}-whats-new-empty` - Empty state message\n *\n * ### Sticky Footer\n * - `.{prefix}-whats-new-sticky-footer` - Footer container (should be sticky)\n * - Has border-top to separate from content\n * - `.{prefix}-whats-new-buttons` - Button container\n * - `.{prefix}-whats-new-buttons button` - Individual buttons\n *\n * ## Example CSS Implementation\n *\n * ```css\n * // Main Container\n * .my-plugin-whats-new-modal .modal {\n * max-width: 800px;\n * width: 90%;\n * }\n *\n * // Plugin Name Link (in title)\n * .my-plugin-whats-new-plugin-name {\n * color: var(--link-color);\n * text-decoration: none;\n * transition: all 0.2s ease;\n * position: relative;\n * font-weight: 600;\n * }\n *\n * .my-plugin-whats-new-plugin-name:hover {\n * color: var(--link-color-hover);\n * text-decoration: none;\n * }\n *\n * .my-plugin-whats-new-plugin-name::after {\n * content: '';\n * position: absolute;\n * bottom: -2px;\n * left: 0;\n * width: 0;\n * height: 2px;\n * background-color: var(--interactive-accent);\n * transition: width 0.3s ease;\n * }\n *\n * .my-plugin-whats-new-plugin-name:hover::after {\n * width: 100%;\n * }\n *\n * // Subtitle\n * .my-plugin-whats-new-subtitle {\n * color: var(--text-muted);\n * font-size: 0.9rem;\n * margin: 0 0 1rem 0;\n * }\n *\n * // Support Section (with donation, tools, and YouTube links)\n * .my-plugin-whats-new-support {\n * margin: 0 0 1rem 0;\n * padding: 1rem;\n * background-color: var(--background-secondary);\n * border-radius: 8px;\n * }\n *\n * .my-plugin-whats-new-support h3 {\n * margin-top: 0;\n * margin-bottom: 0.5rem;\n * font-size: 1rem;\n * }\n *\n * .my-plugin-whats-new-support p {\n * margin: 0.5rem 0;\n * color: var(--text-normal);\n * }\n *\n * .my-plugin-whats-new-support a {\n * color: var(--link-color);\n * text-decoration: none;\n * transition: all 0.2s ease;\n * position: relative;\n * }\n *\n * .my-plugin-whats-new-support a:hover {\n * color: var(--link-color-hover);\n * text-decoration: none;\n * }\n *\n * .my-plugin-whats-new-support a::after {\n * content: '';\n * position: absolute;\n * bottom: -2px;\n * left: 0;\n * width: 0;\n * height: 2px;\n * background-color: var(--interactive-accent);\n * transition: width 0.3s ease;\n * }\n *\n * .my-plugin-whats-new-support a:hover::after {\n * width: 100%;\n * }\n *\n * // Changelog Content (Scrollable Area)\n * .my-plugin-whats-new-content {\n * max-height: 400px;\n * overflow-y: auto;\n * margin-bottom: 1rem;\n * padding-right: 0.5rem;\n * border-radius: 8px;\n * }\n *\n * .my-plugin-whats-new-content h2 {\n * font-size: 1.3rem;\n * margin-top: 1.5rem;\n * margin-bottom: 0.5rem;\n * color: var(--text-accent);\n * }\n *\n * .my-plugin-whats-new-content h3 {\n * font-size: 1.1rem;\n * margin-top: 1rem;\n * margin-bottom: 0.5rem;\n * }\n *\n * .my-plugin-whats-new-content ul {\n * padding-left: 1.5rem;\n * }\n *\n * .my-plugin-whats-new-content li {\n * margin-bottom: 0.5rem;\n * line-height: 1.6;\n * }\n *\n * .my-plugin-whats-new-content code {\n * background: var(--code-background);\n * padding: 0.2em 0.4em;\n * border-radius: 3px;\n * font-size: 0.9em;\n * }\n *\n * .my-plugin-whats-new-content pre {\n * background: var(--code-background);\n * padding: 1rem;\n * border-radius: 6px;\n * overflow-x: auto;\n * }\n *\n * .my-plugin-whats-new-content a.external-link {\n * color: var(--link-external-color);\n * }\n *\n * .my-plugin-whats-new-content a.external-link::after {\n * content: \"↗\";\n * margin-left: 0.2em;\n * font-size: 0.8em;\n * }\n *\n * .my-plugin-whats-new-empty {\n * text-align: center;\n * color: var(--text-muted);\n * padding: 2rem;\n * font-style: italic;\n * }\n *\n * // Sticky Footer\n * .my-plugin-whats-new-sticky-footer {\n * position: sticky;\n * bottom: 0;\n * background: var(--background-primary);\n * padding-top: 0.75rem;\n * margin-top: 0;\n * z-index: 10;\n * border-top: 1px solid var(--background-modifier-border);\n * }\n *\n * .my-plugin-whats-new-buttons {\n * display: flex;\n * gap: 0.5rem;\n * justify-content: space-between;\n * flex-wrap: wrap;\n * padding-bottom: 0.5rem;\n * width: 100%;\n * }\n *\n * .my-plugin-whats-new-buttons button {\n * flex: 1;\n * min-width: 0;\n * padding: 0.5rem 1rem;\n * border-radius: 4px;\n * cursor: pointer;\n * border: 1px solid var(--background-modifier-border);\n * background: var(--interactive-normal);\n * color: var(--text-normal);\n * transition: all 0.2s ease;\n * text-align: center;\n * }\n *\n * .my-plugin-whats-new-buttons button:hover {\n * background: var(--interactive-hover);\n * border-color: var(--interactive-accent);\n * transform: translateY(-1px);\n * box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n * }\n *\n * .my-plugin-whats-new-buttons button:active {\n * transform: translateY(0);\n * box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);\n * }\n * ```\n *\n * @example\n * ```typescript\n * const modal = new WhatsNewModal(app, plugin, {\n * cssPrefix: \"my-plugin\",\n * pluginName: \"My Plugin\",\n * changelogContent: rawChangelog,\n * links: {\n * support: \"https://...\",\n * changelog: \"https://...\",\n * documentation: \"https://...\"\n * }\n * }, \"1.0.0\", \"2.0.0\");\n * modal.open();\n * ```\n */\nexport class WhatsNewModal extends Modal {\n\tconstructor(\n\t\tapp: App,\n\t\tprivate plugin: Plugin,\n\t\tprivate config: WhatsNewModalConfig,\n\t\tprivate fromVersion: string,\n\t\tprivate toVersion: string\n\t) {\n\t\tsuper(app);\n\t}\n\n\t/**\n\t * Helper to create CSS class names with the configured prefix.\n\t */\n\tprivate cls(suffix: string): string {\n\t\treturn `${this.config.cssPrefix}-${suffix}`;\n\t}\n\n\t/**\n\t * Helper to add CSS class to an element.\n\t */\n\tprivate addCls(el: HTMLElement, suffix: string): void {\n\t\tel.classList.add(this.cls(suffix));\n\t}\n\n\t/**\n\t * Makes external links in rendered markdown clickable by adding click handlers.\n\t * Handles both absolute URLs (http/https) and relative URLs (starting with /).\n\t * Relative URLs are resolved against the documentation base URL.\n\t */\n\tprivate makeExternalLinksClickable(container: HTMLElement): void {\n\t\tconst links = container.querySelectorAll<HTMLAnchorElement>(\"a[href]\");\n\n\t\t// Convert NodeList to Array for iteration\n\t\tArray.from(links).forEach((link) => {\n\t\t\tconst href = link.getAttribute(\"href\");\n\t\t\tif (!href) return;\n\n\t\t\tlet finalUrl: string | null = null;\n\n\t\t\t// Handle absolute HTTP(S) links\n\t\t\tif (href.startsWith(\"http://\") || href.startsWith(\"https://\")) {\n\t\t\t\tfinalUrl = href;\n\t\t\t}\n\t\t\t// Handle relative links (starting with /)\n\t\t\telse if (href.startsWith(\"/\")) {\n\t\t\t\t// Get base documentation URL and ensure proper slash handling\n\t\t\t\tconst baseUrl = this.config.links.documentation;\n\t\t\t\tconst normalizedBase = baseUrl.endsWith(\"/\") ? baseUrl.slice(0, -1) : baseUrl;\n\t\t\t\tfinalUrl = `${normalizedBase}${href}`;\n\t\t\t}\n\n\t\t\t// Add click handler for external links\n\t\t\tif (finalUrl) {\n\t\t\t\tlink.addEventListener(\"click\", (event: MouseEvent) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\twindow.open(finalUrl, \"_blank\");\n\t\t\t\t});\n\n\t\t\t\t// Add visual indicator that it's an external link\n\t\t\t\tlink.classList.add(\"external-link\");\n\t\t\t}\n\t\t});\n\t}\n\n\tasync onOpen() {\n\t\tconst { contentEl } = this;\n\t\tcontentEl.empty();\n\n\t\tthis.addCls(contentEl, \"whats-new-modal\");\n\n\t\tthis.setTitle(\"\");\n\n\t\tconst titleEl = this.titleEl;\n\t\ttitleEl.empty();\n\n\t\tconst pluginNameLink = titleEl.createEl(\"a\", {\n\t\t\ttext: this.config.pluginName,\n\t\t\tcls: this.cls(\"whats-new-plugin-name\"),\n\t\t\thref: \"#\",\n\t\t});\n\n\t\tpluginNameLink.addEventListener(\"click\", (e) => {\n\t\t\te.preventDefault();\n\t\t\twindow.open(this.config.links.github, \"_blank\");\n\t\t});\n\n\t\ttitleEl.createSpan({\n\t\t\ttext: ` updated to v${this.toVersion}`,\n\t\t});\n\n\t\t// Subtitle\n\t\tcontentEl.createEl(\"p\", {\n\t\t\ttext: `Changes since v${this.fromVersion}`,\n\t\t\tcls: this.cls(\"whats-new-subtitle\"),\n\t\t});\n\n\t\t// Support section\n\t\tconst supportSection = contentEl.createDiv({\n\t\t\tcls: this.cls(\"whats-new-support\"),\n\t\t});\n\n\t\tsupportSection.createEl(\"h3\", { text: \"Support the development of this plugin\" });\n\n\t\tconst introText = supportSection.createEl(\"p\");\n\t\tintroText.setText(\n\t\t\t\"If this plugin saves you time or improves how you work in Obsidian, consider supporting its development. Your support helps fund ongoing maintenance, new features, and long-term stability.\"\n\t\t);\n\n\t\tconst supportLinkText = supportSection.createEl(\"p\");\n\t\tsupportLinkText.createSpan({ text: \"👉 \" });\n\t\tsupportLinkText.createEl(\"a\", {\n\t\t\ttext: \"Support my work\",\n\t\t\thref: this.config.links.support,\n\t\t});\n\n\t\tconst exploreText = supportSection.createEl(\"p\");\n\t\texploreText.createSpan({ text: \"You can also explore my \" });\n\t\texploreText.createEl(\"a\", {\n\t\t\ttext: \"other Obsidian plugins and productivity tools\",\n\t\t\thref: this.config.links.tools ?? DEFAULT_WHATS_NEW_LINKS.TOOLS,\n\t\t});\n\t\texploreText.createSpan({ text: \", or follow my \" });\n\t\texploreText.createEl(\"a\", {\n\t\t\ttext: \"YouTube channel\",\n\t\t\thref: this.config.links.youtube ?? DEFAULT_WHATS_NEW_LINKS.YOUTUBE,\n\t\t});\n\t\texploreText.createSpan({\n\t\t\ttext: \" for in-depth tutorials and workflow ideas.\",\n\t\t});\n\n\t\t// Changelog content\n\t\tconst changelogSections = getChangelogSince(\n\t\t\tthis.config.changelogContent,\n\t\t\tthis.fromVersion,\n\t\t\tthis.toVersion\n\t\t);\n\n\t\tif (changelogSections.length === 0) {\n\t\t\tcontentEl.createEl(\"p\", {\n\t\t\t\ttext: \"No significant changes found in this update.\",\n\t\t\t\tcls: this.cls(\"whats-new-empty\"),\n\t\t\t});\n\t\t} else {\n\t\t\tconst changelogContainer = contentEl.createDiv({\n\t\t\t\tcls: this.cls(\"whats-new-content\"),\n\t\t\t});\n\n\t\t\tconst markdownContent = formatChangelogSections(changelogSections);\n\n\t\t\tawait MarkdownRenderer.render(\n\t\t\t\tthis.app,\n\t\t\t\tmarkdownContent,\n\t\t\t\tchangelogContainer,\n\t\t\t\t\"/\",\n\t\t\t\tthis.plugin\n\t\t\t);\n\n\t\t\t// Make external links clickable\n\t\t\tthis.makeExternalLinksClickable(changelogContainer);\n\t\t}\n\n\t\t// Sticky footer section (hr + buttons)\n\t\tconst stickyFooter = contentEl.createDiv({\n\t\t\tcls: this.cls(\"whats-new-sticky-footer\"),\n\t\t});\n\n\t\t// Action buttons\n\t\tconst buttonContainer = stickyFooter.createDiv({\n\t\t\tcls: this.cls(\"whats-new-buttons\"),\n\t\t});\n\n\t\t// GitHub button\n\t\tconst githubBtn = buttonContainer.createEl(\"button\", {\n\t\t\ttext: \"GitHub\",\n\t\t});\n\t\tgithubBtn.addEventListener(\"click\", () => {\n\t\t\twindow.open(this.config.links.github, \"_blank\");\n\t\t});\n\n\t\t// Full changelog button\n\t\tconst changelogBtn = buttonContainer.createEl(\"button\", {\n\t\t\ttext: \"Changelog\",\n\t\t});\n\t\tchangelogBtn.addEventListener(\"click\", () => {\n\t\t\twindow.open(this.config.links.changelog, \"_blank\");\n\t\t});\n\n\t\t// Documentation button\n\t\tconst docsBtn = buttonContainer.createEl(\"button\", {\n\t\t\ttext: \"Documentation\",\n\t\t});\n\t\tdocsBtn.addEventListener(\"click\", () => {\n\t\t\twindow.open(this.config.links.documentation, \"_blank\");\n\t\t});\n\n\t\t// Tools button\n\t\tconst toolsBtn = buttonContainer.createEl(\"button\", {\n\t\t\ttext: \"Other Plugins\",\n\t\t});\n\t\ttoolsBtn.addEventListener(\"click\", () => {\n\t\t\twindow.open(this.config.links.tools ?? DEFAULT_WHATS_NEW_LINKS.TOOLS, \"_blank\");\n\t\t});\n\n\t\t// YouTube button\n\t\tconst youtubeBtn = buttonContainer.createEl(\"button\", {\n\t\t\ttext: \"YouTube\",\n\t\t});\n\t\tyoutubeBtn.addEventListener(\"click\", () => {\n\t\t\twindow.open(this.config.links.youtube ?? DEFAULT_WHATS_NEW_LINKS.YOUTUBE, \"_blank\");\n\t\t});\n\t}\n\n\tonClose() {\n\t\tthis.contentEl.empty();\n\t}\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { App, Plugin } from "obsidian";
|
|
2
2
|
import { MarkdownRenderer, Modal } from "obsidian";
|
|
3
|
-
import { formatChangelogSections, getChangelogSince } from "../string/changelog-parser";
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Default URLs for the What's New modal.
|
|
@@ -57,6 +56,11 @@ export interface WhatsNewModalConfig {
|
|
|
57
56
|
*/
|
|
58
57
|
documentation: string;
|
|
59
58
|
|
|
59
|
+
/**
|
|
60
|
+
* URL to GitHub repository.
|
|
61
|
+
*/
|
|
62
|
+
github: string;
|
|
63
|
+
|
|
60
64
|
/**
|
|
61
65
|
* URL to tools page showcasing all plugins and productivity tools.
|
|
62
66
|
* Defaults to DEFAULT_WHATS_NEW_LINKS.TOOLS if not provided.
|
|
@@ -84,10 +88,8 @@ export interface WhatsNewModalConfig {
|
|
|
84
88
|
* - `.{prefix}-whats-new-modal` - Applied to the main content element
|
|
85
89
|
* - `.{prefix}-whats-new-modal .modal` - Modal dialog styling (max-width, width)
|
|
86
90
|
*
|
|
87
|
-
* ###
|
|
88
|
-
* -
|
|
89
|
-
* - Contains h2 (title) and subtitle paragraph
|
|
90
|
-
* - `.{prefix}-whats-new-header h2` - Main title styling
|
|
91
|
+
* ### Title and Subtitle
|
|
92
|
+
* - Modal title is set via `setTitle()` - Obsidian handles the styling and X close button
|
|
91
93
|
* - `.{prefix}-whats-new-subtitle` - Subtitle text ("Changes since vX.X.X")
|
|
92
94
|
*
|
|
93
95
|
* ### Support Section
|
|
@@ -113,11 +115,9 @@ export interface WhatsNewModalConfig {
|
|
|
113
115
|
*
|
|
114
116
|
* ### Sticky Footer
|
|
115
117
|
* - `.{prefix}-whats-new-sticky-footer` - Footer container (should be sticky)
|
|
116
|
-
*
|
|
117
|
-
* - `.{prefix}-whats-new-separator` - Separator with custom class
|
|
118
|
+
* - Has border-top to separate from content
|
|
118
119
|
* - `.{prefix}-whats-new-buttons` - Button container
|
|
119
120
|
* - `.{prefix}-whats-new-buttons button` - Individual buttons
|
|
120
|
-
* - `.{prefix}-mod-cta` - Primary/CTA button state (applied to Close button)
|
|
121
121
|
*
|
|
122
122
|
* ## Example CSS Implementation
|
|
123
123
|
*
|
|
@@ -128,25 +128,45 @@ export interface WhatsNewModalConfig {
|
|
|
128
128
|
* width: 90%;
|
|
129
129
|
* }
|
|
130
130
|
*
|
|
131
|
-
* //
|
|
132
|
-
* .my-plugin-whats-new-
|
|
133
|
-
*
|
|
131
|
+
* // Plugin Name Link (in title)
|
|
132
|
+
* .my-plugin-whats-new-plugin-name {
|
|
133
|
+
* color: var(--link-color);
|
|
134
|
+
* text-decoration: none;
|
|
135
|
+
* transition: all 0.2s ease;
|
|
136
|
+
* position: relative;
|
|
137
|
+
* font-weight: 600;
|
|
134
138
|
* }
|
|
135
139
|
*
|
|
136
|
-
* .my-plugin-whats-new-
|
|
137
|
-
*
|
|
138
|
-
*
|
|
140
|
+
* .my-plugin-whats-new-plugin-name:hover {
|
|
141
|
+
* color: var(--link-color-hover);
|
|
142
|
+
* text-decoration: none;
|
|
143
|
+
* }
|
|
144
|
+
*
|
|
145
|
+
* .my-plugin-whats-new-plugin-name::after {
|
|
146
|
+
* content: '';
|
|
147
|
+
* position: absolute;
|
|
148
|
+
* bottom: -2px;
|
|
149
|
+
* left: 0;
|
|
150
|
+
* width: 0;
|
|
151
|
+
* height: 2px;
|
|
152
|
+
* background-color: var(--interactive-accent);
|
|
153
|
+
* transition: width 0.3s ease;
|
|
154
|
+
* }
|
|
155
|
+
*
|
|
156
|
+
* .my-plugin-whats-new-plugin-name:hover::after {
|
|
157
|
+
* width: 100%;
|
|
139
158
|
* }
|
|
140
159
|
*
|
|
160
|
+
* // Subtitle
|
|
141
161
|
* .my-plugin-whats-new-subtitle {
|
|
142
162
|
* color: var(--text-muted);
|
|
143
163
|
* font-size: 0.9rem;
|
|
144
|
-
* margin: 0;
|
|
164
|
+
* margin: 0 0 1rem 0;
|
|
145
165
|
* }
|
|
146
166
|
*
|
|
147
167
|
* // Support Section (with donation, tools, and YouTube links)
|
|
148
168
|
* .my-plugin-whats-new-support {
|
|
149
|
-
* margin:
|
|
169
|
+
* margin: 0 0 1rem 0;
|
|
150
170
|
* padding: 1rem;
|
|
151
171
|
* background-color: var(--background-secondary);
|
|
152
172
|
* border-radius: 8px;
|
|
@@ -166,17 +186,35 @@ export interface WhatsNewModalConfig {
|
|
|
166
186
|
* .my-plugin-whats-new-support a {
|
|
167
187
|
* color: var(--link-color);
|
|
168
188
|
* text-decoration: none;
|
|
189
|
+
* transition: all 0.2s ease;
|
|
190
|
+
* position: relative;
|
|
169
191
|
* }
|
|
170
192
|
*
|
|
171
193
|
* .my-plugin-whats-new-support a:hover {
|
|
172
|
-
*
|
|
194
|
+
* color: var(--link-color-hover);
|
|
195
|
+
* text-decoration: none;
|
|
196
|
+
* }
|
|
197
|
+
*
|
|
198
|
+
* .my-plugin-whats-new-support a::after {
|
|
199
|
+
* content: '';
|
|
200
|
+
* position: absolute;
|
|
201
|
+
* bottom: -2px;
|
|
202
|
+
* left: 0;
|
|
203
|
+
* width: 0;
|
|
204
|
+
* height: 2px;
|
|
205
|
+
* background-color: var(--interactive-accent);
|
|
206
|
+
* transition: width 0.3s ease;
|
|
207
|
+
* }
|
|
208
|
+
*
|
|
209
|
+
* .my-plugin-whats-new-support a:hover::after {
|
|
210
|
+
* width: 100%;
|
|
173
211
|
* }
|
|
174
212
|
*
|
|
175
213
|
* // Changelog Content (Scrollable Area)
|
|
176
214
|
* .my-plugin-whats-new-content {
|
|
177
|
-
* max-height:
|
|
215
|
+
* max-height: 400px;
|
|
178
216
|
* overflow-y: auto;
|
|
179
|
-
* margin-bottom:
|
|
217
|
+
* margin-bottom: 1rem;
|
|
180
218
|
* padding-right: 0.5rem;
|
|
181
219
|
* border-radius: 8px;
|
|
182
220
|
* }
|
|
@@ -239,50 +277,44 @@ export interface WhatsNewModalConfig {
|
|
|
239
277
|
* position: sticky;
|
|
240
278
|
* bottom: 0;
|
|
241
279
|
* background: var(--background-primary);
|
|
242
|
-
* padding-top:
|
|
243
|
-
* margin-top:
|
|
280
|
+
* padding-top: 0.75rem;
|
|
281
|
+
* margin-top: 0;
|
|
244
282
|
* z-index: 10;
|
|
245
283
|
* border-top: 1px solid var(--background-modifier-border);
|
|
246
284
|
* }
|
|
247
285
|
*
|
|
248
|
-
* .my-plugin-whats-new-modal hr,
|
|
249
|
-
* .my-plugin-whats-new-separator {
|
|
250
|
-
* margin: 0 0 1rem 0;
|
|
251
|
-
* border: none;
|
|
252
|
-
* border-top: 1px solid var(--background-modifier-border);
|
|
253
|
-
* }
|
|
254
|
-
*
|
|
255
286
|
* .my-plugin-whats-new-buttons {
|
|
256
287
|
* display: flex;
|
|
257
288
|
* gap: 0.5rem;
|
|
258
|
-
* justify-content:
|
|
289
|
+
* justify-content: space-between;
|
|
259
290
|
* flex-wrap: wrap;
|
|
260
|
-
* margin-top: 1rem;
|
|
261
291
|
* padding-bottom: 0.5rem;
|
|
292
|
+
* width: 100%;
|
|
262
293
|
* }
|
|
263
294
|
*
|
|
264
295
|
* .my-plugin-whats-new-buttons button {
|
|
296
|
+
* flex: 1;
|
|
297
|
+
* min-width: 0;
|
|
265
298
|
* padding: 0.5rem 1rem;
|
|
266
299
|
* border-radius: 4px;
|
|
267
300
|
* cursor: pointer;
|
|
268
301
|
* border: 1px solid var(--background-modifier-border);
|
|
269
302
|
* background: var(--interactive-normal);
|
|
270
303
|
* color: var(--text-normal);
|
|
271
|
-
* transition:
|
|
304
|
+
* transition: all 0.2s ease;
|
|
305
|
+
* text-align: center;
|
|
272
306
|
* }
|
|
273
307
|
*
|
|
274
308
|
* .my-plugin-whats-new-buttons button:hover {
|
|
275
309
|
* background: var(--interactive-hover);
|
|
276
|
-
* }
|
|
277
|
-
*
|
|
278
|
-
* .my-plugin-whats-new-buttons button.my-plugin-mod-cta {
|
|
279
|
-
* background: var(--interactive-accent);
|
|
280
|
-
* color: var(--text-on-accent);
|
|
281
310
|
* border-color: var(--interactive-accent);
|
|
311
|
+
* transform: translateY(-1px);
|
|
312
|
+
* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
282
313
|
* }
|
|
283
314
|
*
|
|
284
|
-
* .my-plugin-whats-new-buttons button
|
|
285
|
-
*
|
|
315
|
+
* .my-plugin-whats-new-buttons button:active {
|
|
316
|
+
* transform: translateY(0);
|
|
317
|
+
* box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
|
286
318
|
* }
|
|
287
319
|
* ```
|
|
288
320
|
*
|
|
@@ -372,13 +404,28 @@ export class WhatsNewModal extends Modal {
|
|
|
372
404
|
|
|
373
405
|
this.addCls(contentEl, "whats-new-modal");
|
|
374
406
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
407
|
+
this.setTitle("");
|
|
408
|
+
|
|
409
|
+
const titleEl = this.titleEl;
|
|
410
|
+
titleEl.empty();
|
|
411
|
+
|
|
412
|
+
const pluginNameLink = titleEl.createEl("a", {
|
|
413
|
+
text: this.config.pluginName,
|
|
414
|
+
cls: this.cls("whats-new-plugin-name"),
|
|
415
|
+
href: "#",
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
pluginNameLink.addEventListener("click", (e) => {
|
|
419
|
+
e.preventDefault();
|
|
420
|
+
window.open(this.config.links.github, "_blank");
|
|
379
421
|
});
|
|
380
422
|
|
|
381
|
-
|
|
423
|
+
titleEl.createSpan({
|
|
424
|
+
text: ` updated to v${this.toVersion}`,
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// Subtitle
|
|
428
|
+
contentEl.createEl("p", {
|
|
382
429
|
text: `Changes since v${this.fromVersion}`,
|
|
383
430
|
cls: this.cls("whats-new-subtitle"),
|
|
384
431
|
});
|
|
@@ -388,43 +435,35 @@ export class WhatsNewModal extends Modal {
|
|
|
388
435
|
cls: this.cls("whats-new-support"),
|
|
389
436
|
});
|
|
390
437
|
|
|
391
|
-
supportSection.createEl("h3", { text: "Support
|
|
438
|
+
supportSection.createEl("h3", { text: "Support the development of this plugin" });
|
|
439
|
+
|
|
440
|
+
const introText = supportSection.createEl("p");
|
|
441
|
+
introText.setText(
|
|
442
|
+
"If this plugin saves you time or improves how you work in Obsidian, consider supporting its development. Your support helps fund ongoing maintenance, new features, and long-term stability."
|
|
443
|
+
);
|
|
392
444
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
text: "supporting my work",
|
|
445
|
+
const supportLinkText = supportSection.createEl("p");
|
|
446
|
+
supportLinkText.createSpan({ text: "👉 " });
|
|
447
|
+
supportLinkText.createEl("a", {
|
|
448
|
+
text: "Support my work",
|
|
398
449
|
href: this.config.links.support,
|
|
399
450
|
});
|
|
400
|
-
supportText.createSpan({
|
|
401
|
-
text: ". Your support helps keep this plugin maintained and improved!",
|
|
402
|
-
});
|
|
403
451
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
text: "other plugins and productivity tools",
|
|
452
|
+
const exploreText = supportSection.createEl("p");
|
|
453
|
+
exploreText.createSpan({ text: "You can also explore my " });
|
|
454
|
+
exploreText.createEl("a", {
|
|
455
|
+
text: "other Obsidian plugins and productivity tools",
|
|
409
456
|
href: this.config.links.tools ?? DEFAULT_WHATS_NEW_LINKS.TOOLS,
|
|
410
457
|
});
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
// YouTube channel
|
|
416
|
-
const youtubeText = supportSection.createEl("p");
|
|
417
|
-
youtubeText.createSpan({ text: "Subscribe to my " });
|
|
418
|
-
youtubeText.createEl("a", {
|
|
458
|
+
exploreText.createSpan({ text: ", or follow my " });
|
|
459
|
+
exploreText.createEl("a", {
|
|
419
460
|
text: "YouTube channel",
|
|
420
461
|
href: this.config.links.youtube ?? DEFAULT_WHATS_NEW_LINKS.YOUTUBE,
|
|
421
462
|
});
|
|
422
|
-
|
|
423
|
-
text: " for
|
|
463
|
+
exploreText.createSpan({
|
|
464
|
+
text: " for in-depth tutorials and workflow ideas.",
|
|
424
465
|
});
|
|
425
466
|
|
|
426
|
-
contentEl.createEl("hr");
|
|
427
|
-
|
|
428
467
|
// Changelog content
|
|
429
468
|
const changelogSections = getChangelogSince(
|
|
430
469
|
this.config.changelogContent,
|
|
@@ -461,16 +500,19 @@ export class WhatsNewModal extends Modal {
|
|
|
461
500
|
cls: this.cls("whats-new-sticky-footer"),
|
|
462
501
|
});
|
|
463
502
|
|
|
464
|
-
// Separator line
|
|
465
|
-
stickyFooter.createEl("hr", {
|
|
466
|
-
cls: this.cls("whats-new-separator"),
|
|
467
|
-
});
|
|
468
|
-
|
|
469
503
|
// Action buttons
|
|
470
504
|
const buttonContainer = stickyFooter.createDiv({
|
|
471
505
|
cls: this.cls("whats-new-buttons"),
|
|
472
506
|
});
|
|
473
507
|
|
|
508
|
+
// GitHub button
|
|
509
|
+
const githubBtn = buttonContainer.createEl("button", {
|
|
510
|
+
text: "GitHub",
|
|
511
|
+
});
|
|
512
|
+
githubBtn.addEventListener("click", () => {
|
|
513
|
+
window.open(this.config.links.github, "_blank");
|
|
514
|
+
});
|
|
515
|
+
|
|
474
516
|
// Full changelog button
|
|
475
517
|
const changelogBtn = buttonContainer.createEl("button", {
|
|
476
518
|
text: "Changelog",
|
|
@@ -502,13 +544,6 @@ export class WhatsNewModal extends Modal {
|
|
|
502
544
|
youtubeBtn.addEventListener("click", () => {
|
|
503
545
|
window.open(this.config.links.youtube ?? DEFAULT_WHATS_NEW_LINKS.YOUTUBE, "_blank");
|
|
504
546
|
});
|
|
505
|
-
|
|
506
|
-
// Close button (always present)
|
|
507
|
-
const closeBtn = buttonContainer.createEl("button", {
|
|
508
|
-
text: "Close",
|
|
509
|
-
cls: this.cls("mod-cta"),
|
|
510
|
-
});
|
|
511
|
-
closeBtn.addEventListener("click", () => this.close());
|
|
512
547
|
}
|
|
513
548
|
|
|
514
549
|
onClose() {
|