@customviews-js/customviews 1.4.1-beta.0 → 1.4.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/custom-views.core.cjs.js +277 -185
- package/dist/custom-views.core.cjs.js.map +1 -1
- package/dist/custom-views.core.esm.js +277 -185
- package/dist/custom-views.core.esm.js.map +1 -1
- package/dist/custom-views.esm.js +277 -185
- package/dist/custom-views.esm.js.map +1 -1
- package/dist/custom-views.js +277 -185
- package/dist/custom-views.js.map +1 -1
- package/dist/custom-views.min.js +2 -2
- package/dist/custom-views.min.js.map +1 -1
- package/dist/types/core/core.d.ts +4 -0
- package/dist/types/core/core.d.ts.map +1 -1
- package/dist/types/core/widget.d.ts +11 -12
- package/dist/types/core/widget.d.ts.map +1 -1
- package/dist/types/styles/widget-styles.d.ts +1 -1
- package/dist/types/styles/widget-styles.d.ts.map +1 -1
- package/dist/types/types/types.d.ts +0 -2
- package/dist/types/types/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/custom-views.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @customviews-js/customviews v1.4.1-beta.
|
|
2
|
+
* @customviews-js/customviews v1.4.1-beta.1
|
|
3
3
|
* (c) 2025 Chan Ger Teck
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -710,7 +710,7 @@
|
|
|
710
710
|
});
|
|
711
711
|
}
|
|
712
712
|
// Add tooltip for UX feedback (use native title attribute)
|
|
713
|
-
navLink.setAttribute('title',
|
|
713
|
+
navLink.setAttribute('title', "Double-click a tab to 'pin' it in all similar tab groups.");
|
|
714
714
|
listItem.appendChild(navLink);
|
|
715
715
|
navContainer.appendChild(listItem);
|
|
716
716
|
});
|
|
@@ -2738,6 +2738,12 @@ ${TAB_STYLES}
|
|
|
2738
2738
|
this.componentRegistry.tabGroups.delete(tabGroup);
|
|
2739
2739
|
});
|
|
2740
2740
|
}
|
|
2741
|
+
/**
|
|
2742
|
+
* Check if there are any active components in the registry
|
|
2743
|
+
*/
|
|
2744
|
+
hasActiveComponents() {
|
|
2745
|
+
return this.componentRegistry.toggles.size > 0 || this.componentRegistry.tabGroups.size > 0;
|
|
2746
|
+
}
|
|
2741
2747
|
getConfig() {
|
|
2742
2748
|
return this.config;
|
|
2743
2749
|
}
|
|
@@ -4196,97 +4202,7 @@ ${TAB_STYLES}
|
|
|
4196
4202
|
}
|
|
4197
4203
|
|
|
4198
4204
|
/* Dark theme custom state styles */
|
|
4199
|
-
/* Welcome modal styles */
|
|
4200
|
-
.cv-welcome-modal {
|
|
4201
|
-
max-width: 32rem;
|
|
4202
|
-
width: 90vw;
|
|
4203
|
-
background: white;
|
|
4204
|
-
border-radius: 0.75rem;
|
|
4205
|
-
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
4206
|
-
animation: slideIn 0.2s ease;
|
|
4207
|
-
display: flex;
|
|
4208
|
-
flex-direction: column;
|
|
4209
|
-
}
|
|
4210
|
-
|
|
4211
|
-
.cv-modal-main {
|
|
4212
|
-
padding: 1rem;
|
|
4213
|
-
flex: 1;
|
|
4214
|
-
display: flex;
|
|
4215
|
-
flex-direction: column;
|
|
4216
|
-
gap: 1rem;
|
|
4217
|
-
overflow-y: auto;
|
|
4218
|
-
max-height: calc(80vh - 8rem);
|
|
4219
|
-
}
|
|
4220
|
-
|
|
4221
|
-
.cv-welcome-message {
|
|
4222
|
-
font-size: 0.875rem;
|
|
4223
|
-
color: rgba(0, 0, 0, 0.8);
|
|
4224
|
-
margin: 0;
|
|
4225
|
-
line-height: 1.4;
|
|
4226
|
-
text-align: center;
|
|
4227
|
-
}
|
|
4228
|
-
|
|
4229
|
-
.cv-welcome-message a {
|
|
4230
|
-
color: #3e84f4;
|
|
4231
|
-
text-align: justify;
|
|
4232
|
-
text-decoration: none;
|
|
4233
|
-
}
|
|
4234
|
-
|
|
4235
|
-
.cv-welcome-message a:hover {
|
|
4236
|
-
text-decoration: underline;
|
|
4237
|
-
}
|
|
4238
|
-
|
|
4239
|
-
.cv-welcome-widget-preview {
|
|
4240
|
-
display: flex;
|
|
4241
|
-
align-items: center;
|
|
4242
|
-
justify-content: center;
|
|
4243
|
-
gap: 1rem;
|
|
4244
|
-
padding: 1rem;
|
|
4245
|
-
background: #f8f9fa;
|
|
4246
|
-
border-radius: 0.5rem;
|
|
4247
|
-
margin: 1rem 0;
|
|
4248
|
-
}
|
|
4249
4205
|
|
|
4250
|
-
.cv-welcome-widget-icon {
|
|
4251
|
-
width: 2rem;
|
|
4252
|
-
height: 2rem;
|
|
4253
|
-
background: rgba(62, 132, 244, 0.1);
|
|
4254
|
-
border-radius: 9999px;
|
|
4255
|
-
display: flex;
|
|
4256
|
-
align-items: center;
|
|
4257
|
-
justify-content: center;
|
|
4258
|
-
animation: cv-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
4259
|
-
color: #3e84f4;
|
|
4260
|
-
}
|
|
4261
|
-
|
|
4262
|
-
.cv-welcome-widget-label {
|
|
4263
|
-
font-size: 0.875rem;
|
|
4264
|
-
font-weight: 500;
|
|
4265
|
-
color: rgba(0, 0, 0, 0.8);
|
|
4266
|
-
margin: 0;
|
|
4267
|
-
}
|
|
4268
|
-
|
|
4269
|
-
.cv-welcome-got-it {
|
|
4270
|
-
width: 100%;
|
|
4271
|
-
background: #3e84f4;
|
|
4272
|
-
color: white;
|
|
4273
|
-
font-weight: 600;
|
|
4274
|
-
padding: 0.75rem 1rem;
|
|
4275
|
-
border-radius: 0.5rem;
|
|
4276
|
-
border: none;
|
|
4277
|
-
cursor: pointer;
|
|
4278
|
-
font-size: 0.875rem;
|
|
4279
|
-
transition: background-color 0.2s ease;
|
|
4280
|
-
outline: none;
|
|
4281
|
-
}
|
|
4282
|
-
|
|
4283
|
-
.cv-welcome-got-it:hover {
|
|
4284
|
-
background: rgba(62, 132, 244, 0.9);
|
|
4285
|
-
}
|
|
4286
|
-
|
|
4287
|
-
.cv-welcome-got-it:focus {
|
|
4288
|
-
box-shadow: 0 0 0 2px rgba(62, 132, 244, 0.5);
|
|
4289
|
-
}
|
|
4290
4206
|
|
|
4291
4207
|
/* Animations */
|
|
4292
4208
|
@keyframes cv-pulse {
|
|
@@ -4298,26 +4214,7 @@ ${TAB_STYLES}
|
|
|
4298
4214
|
}
|
|
4299
4215
|
}
|
|
4300
4216
|
|
|
4301
|
-
/* Dark theme welcome modal styles */
|
|
4302
|
-
.cv-widget-theme-dark .cv-welcome-modal {
|
|
4303
|
-
background: #101722;
|
|
4304
|
-
}
|
|
4305
4217
|
|
|
4306
|
-
.cv-widget-theme-dark .cv-welcome-message {
|
|
4307
|
-
color: rgba(255, 255, 255, 0.8);
|
|
4308
|
-
}
|
|
4309
|
-
|
|
4310
|
-
.cv-widget-theme-dark .cv-welcome-message a {
|
|
4311
|
-
color: #60a5fa;
|
|
4312
|
-
}
|
|
4313
|
-
|
|
4314
|
-
.cv-widget-theme-dark .cv-welcome-widget-preview {
|
|
4315
|
-
background: rgba(255, 255, 255, 0.1);
|
|
4316
|
-
}
|
|
4317
|
-
|
|
4318
|
-
.cv-widget-theme-dark .cv-welcome-widget-label {
|
|
4319
|
-
color: #e2e8f0;
|
|
4320
|
-
}
|
|
4321
4218
|
|
|
4322
4219
|
/* Dark theme logo box */
|
|
4323
4220
|
.cv-widget-theme-dark .cv-tabgroup-logo-box {
|
|
@@ -4492,6 +4389,176 @@ ${TAB_STYLES}
|
|
|
4492
4389
|
.cv-widget-theme-dark .cv-share-action-btn.primary:hover {
|
|
4493
4390
|
background: #2b74e6;
|
|
4494
4391
|
}
|
|
4392
|
+
|
|
4393
|
+
/* Intro Callout styles */
|
|
4394
|
+
.cv-widget-callout {
|
|
4395
|
+
position: fixed;
|
|
4396
|
+
background: white;
|
|
4397
|
+
border-radius: 8px;
|
|
4398
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
|
4399
|
+
padding: 12px 16px;
|
|
4400
|
+
width: 260px;
|
|
4401
|
+
z-index: 9999;
|
|
4402
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
4403
|
+
animation: cvFadeIn 0.3s ease-out;
|
|
4404
|
+
pointer-events: auto;
|
|
4405
|
+
display: flex;
|
|
4406
|
+
flex-direction: column;
|
|
4407
|
+
gap: 8px;
|
|
4408
|
+
}
|
|
4409
|
+
|
|
4410
|
+
.cv-widget-callout-text {
|
|
4411
|
+
font-size: 0.9rem;
|
|
4412
|
+
color: #333;
|
|
4413
|
+
margin: 0;
|
|
4414
|
+
line-height: 1.4;
|
|
4415
|
+
}
|
|
4416
|
+
|
|
4417
|
+
.cv-widget-callout-close {
|
|
4418
|
+
position: absolute;
|
|
4419
|
+
top: 6px;
|
|
4420
|
+
right: 6px;
|
|
4421
|
+
width: 18px;
|
|
4422
|
+
height: 18px;
|
|
4423
|
+
border: none;
|
|
4424
|
+
background: rgba(0,0,0,0.05);
|
|
4425
|
+
color: #666;
|
|
4426
|
+
cursor: pointer;
|
|
4427
|
+
display: flex;
|
|
4428
|
+
align-items: center;
|
|
4429
|
+
justify-content: center;
|
|
4430
|
+
border-radius: 50%;
|
|
4431
|
+
font-size: 14px;
|
|
4432
|
+
line-height: 1;
|
|
4433
|
+
padding: 0;
|
|
4434
|
+
transition: all 0.2s ease;
|
|
4435
|
+
}
|
|
4436
|
+
|
|
4437
|
+
.cv-widget-callout-close:hover {
|
|
4438
|
+
background: #f0f0f0;
|
|
4439
|
+
color: #333;
|
|
4440
|
+
}
|
|
4441
|
+
|
|
4442
|
+
/* Callout positioning and arrow */
|
|
4443
|
+
.cv-widget-callout::after {
|
|
4444
|
+
content: '';
|
|
4445
|
+
position: absolute;
|
|
4446
|
+
width: 10px;
|
|
4447
|
+
height: 10px;
|
|
4448
|
+
background: white;
|
|
4449
|
+
transform: rotate(45deg);
|
|
4450
|
+
box-shadow: 1px 1px 1px rgba(0,0,0,0.05); /* subtle shadow for arrow */
|
|
4451
|
+
}
|
|
4452
|
+
|
|
4453
|
+
/* Top-Right Widget -> Callout to the left */
|
|
4454
|
+
.cv-widget-callout.cv-pos-top-right {
|
|
4455
|
+
top: 20px;
|
|
4456
|
+
right: 64px;
|
|
4457
|
+
}
|
|
4458
|
+
.cv-widget-callout.cv-pos-top-right::after {
|
|
4459
|
+
top: 13px;
|
|
4460
|
+
right: -5px;
|
|
4461
|
+
box-shadow: 1px -1px 1px rgba(0,0,0,0.05);
|
|
4462
|
+
transform: rotate(45deg);
|
|
4463
|
+
}
|
|
4464
|
+
|
|
4465
|
+
/* Bottom-Right Widget -> Callout to the left */
|
|
4466
|
+
.cv-widget-callout.cv-pos-bottom-right {
|
|
4467
|
+
bottom: 20px;
|
|
4468
|
+
right: 64px;
|
|
4469
|
+
}
|
|
4470
|
+
.cv-widget-callout.cv-pos-bottom-right::after {
|
|
4471
|
+
bottom: 13px;
|
|
4472
|
+
right: -5px;
|
|
4473
|
+
}
|
|
4474
|
+
|
|
4475
|
+
/* Top-Left Widget -> Callout to the right */
|
|
4476
|
+
.cv-widget-callout.cv-pos-top-left {
|
|
4477
|
+
top: 20px;
|
|
4478
|
+
left: 64px;
|
|
4479
|
+
}
|
|
4480
|
+
.cv-widget-callout.cv-pos-top-left::after {
|
|
4481
|
+
top: 13px;
|
|
4482
|
+
left: -5px;
|
|
4483
|
+
}
|
|
4484
|
+
|
|
4485
|
+
/* Bottom-Left Widget -> Callout to the right */
|
|
4486
|
+
.cv-widget-callout.cv-pos-bottom-left {
|
|
4487
|
+
bottom: 20px;
|
|
4488
|
+
left: 64px;
|
|
4489
|
+
}
|
|
4490
|
+
.cv-widget-callout.cv-pos-bottom-left::after {
|
|
4491
|
+
bottom: 13px;
|
|
4492
|
+
left: -5px;
|
|
4493
|
+
}
|
|
4494
|
+
|
|
4495
|
+
/* Middle-Right Widget -> Callout to the left */
|
|
4496
|
+
.cv-widget-callout.cv-pos-middle-right {
|
|
4497
|
+
top: 50%;
|
|
4498
|
+
right: 64px;
|
|
4499
|
+
transform: translateY(-50%);
|
|
4500
|
+
}
|
|
4501
|
+
.cv-widget-callout.cv-pos-middle-right::after {
|
|
4502
|
+
top: 50%;
|
|
4503
|
+
right: -5px;
|
|
4504
|
+
transform: translateY(-50%) rotate(45deg);
|
|
4505
|
+
}
|
|
4506
|
+
|
|
4507
|
+
/* Middle-Left Widget -> Callout to the right */
|
|
4508
|
+
.cv-widget-callout.cv-pos-middle-left {
|
|
4509
|
+
top: 50%;
|
|
4510
|
+
left: 64px;
|
|
4511
|
+
transform: translateY(-50%);
|
|
4512
|
+
}
|
|
4513
|
+
.cv-widget-callout.cv-pos-middle-left::after {
|
|
4514
|
+
top: 50%;
|
|
4515
|
+
left: -5px;
|
|
4516
|
+
transform: translateY(-50%) rotate(45deg);
|
|
4517
|
+
}
|
|
4518
|
+
|
|
4519
|
+
/* Pulse animation utility */
|
|
4520
|
+
.cv-widget-icon.cv-pulse {
|
|
4521
|
+
animation: cv-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
4522
|
+
box-shadow: 0 0 0 0 rgba(62, 132, 244, 0.7);
|
|
4523
|
+
}
|
|
4524
|
+
|
|
4525
|
+
@keyframes cv-pulse {
|
|
4526
|
+
0% {
|
|
4527
|
+
transform: scale(1);
|
|
4528
|
+
box-shadow: 0 0 0 0 rgba(62, 132, 244, 0.7);
|
|
4529
|
+
}
|
|
4530
|
+
70% {
|
|
4531
|
+
transform: scale(1.05);
|
|
4532
|
+
box-shadow: 0 0 0 10px rgba(62, 132, 244, 0);
|
|
4533
|
+
}
|
|
4534
|
+
100% {
|
|
4535
|
+
transform: scale(1);
|
|
4536
|
+
box-shadow: 0 0 0 0 rgba(62, 132, 244, 0);
|
|
4537
|
+
}
|
|
4538
|
+
}
|
|
4539
|
+
|
|
4540
|
+
/* Dark Theme */
|
|
4541
|
+
.cv-widget-theme-dark .cv-widget-callout {
|
|
4542
|
+
background: #1f2937; /* Tailwind gray-800 mostly */
|
|
4543
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
|
|
4544
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
4545
|
+
}
|
|
4546
|
+
.cv-widget-theme-dark .cv-widget-callout::after {
|
|
4547
|
+
background: #1f2937;
|
|
4548
|
+
border-top: 1px solid rgba(255,255,255,0.1);
|
|
4549
|
+
border-right: 1px solid rgba(255,255,255,0.1);
|
|
4550
|
+
}
|
|
4551
|
+
.cv-widget-theme-dark .cv-widget-callout-text {
|
|
4552
|
+
color: #e5e7eb;
|
|
4553
|
+
}
|
|
4554
|
+
.cv-widget-theme-dark .cv-widget-callout-close {
|
|
4555
|
+
background: rgba(255,255,255,0.1);
|
|
4556
|
+
color: #9ca3af;
|
|
4557
|
+
}
|
|
4558
|
+
.cv-widget-theme-dark .cv-widget-callout-close:hover {
|
|
4559
|
+
background: rgba(255,255,255,0.2);
|
|
4560
|
+
color: #fff;
|
|
4561
|
+
}
|
|
4495
4562
|
`;
|
|
4496
4563
|
/**
|
|
4497
4564
|
* Inject widget styles into the document head
|
|
@@ -4510,6 +4577,7 @@ ${TAB_STYLES}
|
|
|
4510
4577
|
core;
|
|
4511
4578
|
container;
|
|
4512
4579
|
widgetIcon = null;
|
|
4580
|
+
introCallout = null;
|
|
4513
4581
|
options;
|
|
4514
4582
|
_hasVisibleConfig = false;
|
|
4515
4583
|
pageToggleIds = new Set();
|
|
@@ -4530,8 +4598,7 @@ ${TAB_STYLES}
|
|
|
4530
4598
|
title: options.title || 'Customize View',
|
|
4531
4599
|
description: options.description || '',
|
|
4532
4600
|
showWelcome: options.showWelcome ?? false,
|
|
4533
|
-
|
|
4534
|
-
welcomeMessage: options.welcomeMessage || 'This site is powered by Custom Views. Use the widget on the side (⚙) to customize your experience. Your preferences will be saved and can be shared via URL.<br><br>Learn more at <a href="https://github.com/customviews-js/customviews" target="_blank">customviews GitHub</a>.',
|
|
4601
|
+
welcomeMessage: options.welcomeMessage || 'Customize your reading experience (theme, toggles, tabs) here.',
|
|
4535
4602
|
showTabGroups: options.showTabGroups ?? true
|
|
4536
4603
|
};
|
|
4537
4604
|
// Determine if there are any configurations to show
|
|
@@ -4573,9 +4640,9 @@ ${TAB_STYLES}
|
|
|
4573
4640
|
this.attachEventListeners();
|
|
4574
4641
|
// Always append to body since it's a floating icon
|
|
4575
4642
|
document.body.appendChild(this.widgetIcon);
|
|
4576
|
-
// Show
|
|
4643
|
+
// Show intro callout on first visit if enabled
|
|
4577
4644
|
if (this.options.showWelcome) {
|
|
4578
|
-
this.
|
|
4645
|
+
this.showIntroCalloutIfFirstVisit();
|
|
4579
4646
|
}
|
|
4580
4647
|
return this.widgetIcon;
|
|
4581
4648
|
}
|
|
@@ -4605,6 +4672,11 @@ ${TAB_STYLES}
|
|
|
4605
4672
|
this.stateModal.remove();
|
|
4606
4673
|
this.stateModal = null;
|
|
4607
4674
|
}
|
|
4675
|
+
// Clean up callout
|
|
4676
|
+
if (this.introCallout) {
|
|
4677
|
+
this.introCallout.remove();
|
|
4678
|
+
this.introCallout = null;
|
|
4679
|
+
}
|
|
4608
4680
|
}
|
|
4609
4681
|
attachEventListeners() {
|
|
4610
4682
|
if (!this.widgetIcon)
|
|
@@ -4620,10 +4692,48 @@ ${TAB_STYLES}
|
|
|
4620
4692
|
this.stateModal.classList.add('cv-hidden');
|
|
4621
4693
|
}
|
|
4622
4694
|
}
|
|
4695
|
+
/**
|
|
4696
|
+
* Dismiss the intro callout
|
|
4697
|
+
*/
|
|
4698
|
+
dismissIntroCallout() {
|
|
4699
|
+
if (!this.introCallout)
|
|
4700
|
+
return;
|
|
4701
|
+
const callout = this.introCallout;
|
|
4702
|
+
// Clear reference immediately from class to prevent re-use
|
|
4703
|
+
this.introCallout = null;
|
|
4704
|
+
callout.remove();
|
|
4705
|
+
// Stop pulsing the widget icon
|
|
4706
|
+
if (this.widgetIcon) {
|
|
4707
|
+
this.widgetIcon.classList.remove('cv-pulse');
|
|
4708
|
+
}
|
|
4709
|
+
// Mark as shown in localStorage
|
|
4710
|
+
try {
|
|
4711
|
+
localStorage.setItem('cv-intro-shown', 'true');
|
|
4712
|
+
}
|
|
4713
|
+
catch (e) {
|
|
4714
|
+
// Ignore localStorage errors
|
|
4715
|
+
}
|
|
4716
|
+
}
|
|
4623
4717
|
/**
|
|
4624
4718
|
* Open the custom state creator
|
|
4625
4719
|
*/
|
|
4626
4720
|
openStateModal() {
|
|
4721
|
+
// Dismiss intro callout if valid
|
|
4722
|
+
if (this.introCallout) {
|
|
4723
|
+
this.dismissIntroCallout();
|
|
4724
|
+
}
|
|
4725
|
+
else {
|
|
4726
|
+
// Even if no callout is shown (e.g. page had no content), opening the widget
|
|
4727
|
+
// should count as "seen", preventing future callouts.
|
|
4728
|
+
try {
|
|
4729
|
+
if (!localStorage.getItem('cv-intro-shown')) {
|
|
4730
|
+
localStorage.setItem('cv-intro-shown', 'true');
|
|
4731
|
+
}
|
|
4732
|
+
}
|
|
4733
|
+
catch (e) {
|
|
4734
|
+
// Ignore localStorage errors
|
|
4735
|
+
}
|
|
4736
|
+
}
|
|
4627
4737
|
if (!this.stateModal) {
|
|
4628
4738
|
this._createStateModal();
|
|
4629
4739
|
}
|
|
@@ -5081,88 +5191,70 @@ ${TAB_STYLES}
|
|
|
5081
5191
|
}
|
|
5082
5192
|
}
|
|
5083
5193
|
/**
|
|
5084
|
-
* Check if this is the first visit and show
|
|
5194
|
+
* Check if this is the first visit and show intro callout
|
|
5085
5195
|
*/
|
|
5086
|
-
|
|
5196
|
+
showIntroCalloutIfFirstVisit() {
|
|
5087
5197
|
if (!this._hasVisibleConfig)
|
|
5088
5198
|
return;
|
|
5089
|
-
|
|
5090
|
-
//
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5199
|
+
// Strict check: Only show callout if there is actual content on the page to customize.
|
|
5200
|
+
// We check the core registry for any active toggles or tab groups.
|
|
5201
|
+
if (!this.core.hasActiveComponents()) {
|
|
5202
|
+
return;
|
|
5203
|
+
}
|
|
5204
|
+
const STORAGE_KEY = 'cv-intro-shown';
|
|
5205
|
+
// Check if intro has been shown before
|
|
5206
|
+
let hasSeenIntro = null;
|
|
5207
|
+
try {
|
|
5208
|
+
hasSeenIntro = localStorage.getItem(STORAGE_KEY);
|
|
5209
|
+
}
|
|
5210
|
+
catch (e) {
|
|
5211
|
+
// Ignore localStorage errors (e.g. private mode)
|
|
5212
|
+
}
|
|
5213
|
+
if (!hasSeenIntro) {
|
|
5214
|
+
// Show callout after a short delay
|
|
5094
5215
|
setTimeout(() => {
|
|
5095
|
-
this.
|
|
5096
|
-
},
|
|
5097
|
-
// Mark as shown
|
|
5098
|
-
localStorage.setItem(STORAGE_KEY, 'true');
|
|
5216
|
+
this.createCallout();
|
|
5217
|
+
}, 1000);
|
|
5099
5218
|
}
|
|
5100
5219
|
}
|
|
5101
5220
|
/**
|
|
5102
|
-
* Create and show the
|
|
5221
|
+
* Create and show the intro callout
|
|
5103
5222
|
*/
|
|
5104
|
-
|
|
5105
|
-
//
|
|
5106
|
-
if (this.
|
|
5223
|
+
createCallout() {
|
|
5224
|
+
// Avoid duplicates
|
|
5225
|
+
if (this.introCallout || document.querySelector('.cv-widget-callout'))
|
|
5107
5226
|
return;
|
|
5108
|
-
|
|
5109
|
-
|
|
5227
|
+
this.introCallout = document.createElement('div');
|
|
5228
|
+
const callout = this.introCallout;
|
|
5229
|
+
callout.className = `cv-widget-callout cv-pos-${this.options.position}`;
|
|
5110
5230
|
if (this.options.theme === 'dark') {
|
|
5111
|
-
|
|
5231
|
+
callout.classList.add('cv-widget-theme-dark');
|
|
5232
|
+
}
|
|
5233
|
+
// Close button
|
|
5234
|
+
const closeBtn = document.createElement('button');
|
|
5235
|
+
closeBtn.className = 'cv-widget-callout-close';
|
|
5236
|
+
closeBtn.innerHTML = '×';
|
|
5237
|
+
closeBtn.setAttribute('aria-label', 'Dismiss intro');
|
|
5238
|
+
closeBtn.addEventListener('click', (e) => {
|
|
5239
|
+
e.stopPropagation();
|
|
5240
|
+
this.dismissIntroCallout();
|
|
5241
|
+
});
|
|
5242
|
+
// Message
|
|
5243
|
+
const msg = document.createElement('p');
|
|
5244
|
+
msg.className = 'cv-widget-callout-text';
|
|
5245
|
+
msg.textContent = this.options.welcomeMessage;
|
|
5246
|
+
callout.appendChild(closeBtn);
|
|
5247
|
+
callout.appendChild(msg);
|
|
5248
|
+
document.body.appendChild(callout);
|
|
5249
|
+
// Add pulse to widget icon to draw attention
|
|
5250
|
+
if (this.widgetIcon) {
|
|
5251
|
+
this.widgetIcon.classList.add('cv-pulse');
|
|
5112
5252
|
}
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
<div class="cv-modal-icon">
|
|
5118
|
-
${getGearIcon()}
|
|
5119
|
-
</div>
|
|
5120
|
-
<h1 class="cv-modal-title">${this.options.welcomeTitle}</h1>
|
|
5121
|
-
</div>
|
|
5122
|
-
</header>
|
|
5123
|
-
<div class="cv-modal-main">
|
|
5124
|
-
<p class="cv-welcome-message">${this.options.welcomeMessage}</p>
|
|
5125
|
-
|
|
5126
|
-
<div class="cv-welcome-widget-preview">
|
|
5127
|
-
<div class="cv-welcome-widget-icon">
|
|
5128
|
-
${getGearIcon()}
|
|
5129
|
-
</div>
|
|
5130
|
-
<p class="cv-welcome-widget-label">Look for this widget</p>
|
|
5131
|
-
</div>
|
|
5132
|
-
|
|
5133
|
-
<button class="cv-welcome-got-it">Got it!</button>
|
|
5134
|
-
</div>
|
|
5135
|
-
</div>
|
|
5136
|
-
`;
|
|
5137
|
-
document.body.appendChild(welcomeModal);
|
|
5138
|
-
this.attachWelcomeModalEventListeners(welcomeModal);
|
|
5139
|
-
}
|
|
5140
|
-
/**
|
|
5141
|
-
* Attach event listeners for welcome modal
|
|
5142
|
-
*/
|
|
5143
|
-
attachWelcomeModalEventListeners(welcomeModal) {
|
|
5144
|
-
const closeModal = () => {
|
|
5145
|
-
welcomeModal.remove();
|
|
5146
|
-
document.removeEventListener('keydown', handleEscape);
|
|
5147
|
-
};
|
|
5148
|
-
// Got it button
|
|
5149
|
-
const gotItBtn = welcomeModal.querySelector('.cv-welcome-got-it');
|
|
5150
|
-
if (gotItBtn) {
|
|
5151
|
-
gotItBtn.addEventListener('click', closeModal);
|
|
5152
|
-
}
|
|
5153
|
-
// Overlay click to close
|
|
5154
|
-
welcomeModal.addEventListener('click', (e) => {
|
|
5155
|
-
if (e.target === welcomeModal) {
|
|
5156
|
-
closeModal();
|
|
5157
|
-
}
|
|
5253
|
+
// Auto-dismiss and open widget on click anywhere on callout
|
|
5254
|
+
callout.addEventListener('click', () => {
|
|
5255
|
+
this.dismissIntroCallout();
|
|
5256
|
+
this.openStateModal();
|
|
5158
5257
|
});
|
|
5159
|
-
// Escape key to close
|
|
5160
|
-
const handleEscape = (e) => {
|
|
5161
|
-
if (e.key === 'Escape') {
|
|
5162
|
-
closeModal();
|
|
5163
|
-
}
|
|
5164
|
-
};
|
|
5165
|
-
document.addEventListener('keydown', handleEscape);
|
|
5166
5258
|
}
|
|
5167
5259
|
}
|
|
5168
5260
|
|