@64mb/freelens-power 1.2.1 → 1.2.2

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.
@@ -14,6 +14,7 @@ var reloadChannel = "freelens-power:dashboard-views:reload";
14
14
  var clearChannel = "freelens-power:dashboard-views:clear";
15
15
  var dashboardPath = "/extension/freelens-power/dashboard";
16
16
  var websiteStyles = "* { scrollbar-width: none !important; } *::-webkit-scrollbar { display: none !important; width: 0 !important; height: 0 !important; }";
17
+ var expandedWebsiteStyles = "* { scrollbar-width: auto !important; } *::-webkit-scrollbar { display: revert !important; width: revert !important; height: revert !important; }";
17
18
  function rendererUrl(value, dashboardOnly = false) {
18
19
  try {
19
20
  const url = new URL(value);
@@ -48,19 +49,58 @@ function rectangle(value) {
48
49
  height: rect.height
49
50
  };
50
51
  }
51
- async function waitForReadiness(contents, network, selector, current) {
52
+ function createDashboardSkeleton() {
53
+ const view = new electron.View();
54
+ view.setBackgroundColor(electron.nativeTheme.shouldUseDarkColors ? "#202124" : "#ffffff");
55
+ const bars = Array.from({ length: 4 }, () => {
56
+ const bar = new electron.View();
57
+ bar.setBackgroundColor(electron.nativeTheme.shouldUseDarkColors ? "#393b40" : "#e8e9eb");
58
+ bar.setBorderRadius(6);
59
+ view.addChildView(bar);
60
+ return bar;
61
+ });
62
+ return {
63
+ view,
64
+ layout: (width, height) => {
65
+ view.setBounds({
66
+ x: 0,
67
+ y: 0,
68
+ width,
69
+ height
70
+ });
71
+ bars.forEach((bar, index) => {
72
+ bar.setBounds({
73
+ x: 20,
74
+ y: index === 0 ? 20 : 60 + (index - 1) * 24,
75
+ width: Math.max(1, Math.round((width - 40) * (index === 0 ? .45 : 1))),
76
+ height: index === 0 ? 20 : index === 3 ? Math.max(30, height - 128) : 12
77
+ });
78
+ });
79
+ }
80
+ };
81
+ }
82
+ async function applyWebsiteStyles(card) {
83
+ const contents = card.view.webContents;
84
+ const generation = (card.websiteStylesGeneration ?? 0) + 1;
85
+ card.websiteStylesGeneration = generation;
86
+ const previous = card.websiteStylesKey;
87
+ card.websiteStylesKey = void 0;
88
+ if (contents.isDestroyed()) return;
89
+ if (previous) await contents.removeInsertedCSS(previous).catch(() => {});
90
+ if (card.websiteStylesGeneration !== generation || contents.isDestroyed()) return;
91
+ const key = await contents.insertCSS(card.scrollbars ? expandedWebsiteStyles : websiteStyles, { cssOrigin: "user" }).catch(() => void 0);
92
+ if (!key) return;
93
+ if (card.websiteStylesGeneration === generation && !contents.isDestroyed()) card.websiteStylesKey = key;
94
+ else if (!contents.isDestroyed()) await contents.removeInsertedCSS(key).catch(() => {});
95
+ }
96
+ async function waitForReadiness(contents, _network, selector, current) {
52
97
  let deadline;
53
98
  try {
54
99
  await Promise.race([(async () => {
55
100
  if (!current()) return;
56
- await network.ready();
101
+ await contents.mainFrame.executeJavaScript(require_dashboard_selector.dashboardSelectorScript(selector())).catch(() => {});
57
102
  if (!current()) return;
58
- await contents.executeJavaScriptInIsolatedWorld(1004, [{ code: require_dashboard_selector.dashboardSelectorScript(selector()) }]).catch(() => {});
59
- do {
60
- await network.wait();
61
- if (!current()) return;
62
- await contents.executeJavaScriptInIsolatedWorld(1004, [{ code: require_dashboard_readiness.dashboardReadinessScript(selector()) }]);
63
- } while (current() && !network.quiet());
103
+ await contents.mainFrame.executeJavaScript(require_dashboard_readiness.dashboardReadinessScript(selector()));
64
104
  })().catch(() => new Promise((resolve) => setTimeout(resolve, 200))), new Promise((resolve) => {
65
105
  deadline = setTimeout(resolve, 8500);
66
106
  })]);
@@ -68,6 +108,21 @@ async function waitForReadiness(contents, network, selector, current) {
68
108
  clearTimeout(deadline);
69
109
  }
70
110
  }
111
+ async function prepareDashboardPage(contents) {
112
+ if (contents.isDestroyed()) return;
113
+ let deadline;
114
+ try {
115
+ await Promise.race([contents.mainFrame.executeJavaScript("document.dispatchEvent(new Event(\"freelens-power:dashboard:preparing\"))").catch(() => {}), new Promise((resolve) => {
116
+ deadline = setTimeout(resolve, 250);
117
+ })]);
118
+ } finally {
119
+ clearTimeout(deadline);
120
+ }
121
+ }
122
+ function releaseDashboardPage(contents) {
123
+ if (contents.isDestroyed()) return Promise.resolve();
124
+ return contents.mainFrame.executeJavaScript("document.dispatchEvent(new Event(\"freelens-power:dashboard:prepared\"))").catch(() => {});
125
+ }
71
126
  function startDashboardViews() {
72
127
  const websiteSession = electron.session.fromPartition("persist:freelens-power-websites");
73
128
  websiteSession.setPermissionRequestHandler((_contents, _permission, callback) => callback(false));
@@ -78,9 +133,11 @@ function startDashboardViews() {
78
133
  const card = owner.cards.get(id);
79
134
  if (!card) return;
80
135
  owner.cards.delete(id);
136
+ card.nativeNavigation?.fail();
81
137
  card.stopPreparation?.();
138
+ card.websiteStylesGeneration = (card.websiteStylesGeneration ?? 0) + 1;
82
139
  card.faviconRequest?.abort();
83
- clearInterval(card.refreshTimer);
140
+ clearTimeout(card.refreshTimer);
84
141
  card.floatingPreparation?.stop();
85
142
  card.floating?.destroy();
86
143
  card.floating = void 0;
@@ -129,10 +186,12 @@ function startDashboardViews() {
129
186
  });
130
187
  }
131
188
  };
132
- const reload = (card, configuredUrl, initial = false) => {
189
+ const reload = (card, configuredUrl, initial = false, navigation) => {
133
190
  const current = card.view.webContents.getURL();
134
191
  const target = !initial && card.url === configuredUrl && webUrl(current) ? current : configuredUrl;
192
+ const prepareExisting = !initial && !navigation && !card.loading && !card.failed && webUrl(current);
135
193
  card.faviconRequest?.abort();
194
+ if (!navigation) card.nativeNavigation?.fail();
136
195
  card.url = configuredUrl;
137
196
  card.failed = false;
138
197
  card.loading = true;
@@ -142,23 +201,27 @@ function startDashboardViews() {
142
201
  if (backgroundThrottling) contents.setBackgroundThrottling(false);
143
202
  const network = require_dashboard_network.observeDashboardNetwork(card.view.webContents);
144
203
  let stopped = false;
204
+ let documentReady;
145
205
  const stopPreparation = () => {
146
206
  if (stopped) return;
147
207
  stopped = true;
148
208
  network.dispose();
149
209
  contents.removeListener("destroyed", stopPreparation);
210
+ if (documentReady) contents.removeListener("dom-ready", documentReady);
150
211
  if (!contents.isDestroyed() && backgroundThrottling && !contents.getBackgroundThrottling()) contents.setBackgroundThrottling(backgroundThrottling);
151
212
  if (card.stopPreparation === stopPreparation) card.stopPreparation = void 0;
152
213
  };
153
214
  card.stopPreparation = stopPreparation;
154
215
  contents.once("destroyed", stopPreparation);
155
216
  const generation = ++card.generation;
156
- card.container.setVisible(false);
217
+ card.skeleton.view.setVisible(true);
218
+ card.container.setVisible(card.visible && !card.floating);
157
219
  publishLoading(card);
158
220
  const settled = (failed) => {
159
221
  if (card.generation !== generation || card.view.webContents.isDestroyed()) return;
160
222
  card.failed = failed;
161
223
  card.loading = false;
224
+ card.skeleton.view.setVisible(false);
162
225
  for (const [sender, owner] of owners) {
163
226
  if (![...owner.cards.values()].includes(card)) continue;
164
227
  card.container.setVisible(card.visible && !card.floating && !failed && dashboardUrl(sender.getURL()));
@@ -167,19 +230,33 @@ function startDashboardViews() {
167
230
  };
168
231
  const load = () => {
169
232
  if (card.generation !== generation || card.view.webContents.isDestroyed() || ![...owners.values()].some((owner) => [...owner.cards.values()].includes(card))) return Promise.resolve();
170
- return card.view.webContents.loadURL(target);
233
+ if (navigation) return navigation;
234
+ const navigate = () => {
235
+ if (card.generation !== generation || contents.isDestroyed()) return Promise.resolve();
236
+ card.requestedNavigation = true;
237
+ return contents.loadURL(target).finally(() => {
238
+ if (card.generation === generation) card.requestedNavigation = false;
239
+ });
240
+ };
241
+ return prepareExisting ? prepareDashboardPage(contents).then(navigate) : navigate();
171
242
  };
172
- card.pending = load().then(async () => {
243
+ const ready = new Promise((resolve) => {
244
+ documentReady = resolve;
245
+ contents.once("dom-ready", documentReady);
246
+ });
247
+ card.pending = Promise.race([load(), ready]).then(async () => {
173
248
  let preparing = true;
174
249
  const current = () => preparing && card.generation === generation && !card.view.webContents.isDestroyed() && [...owners.values()].some((owner) => [...owner.cards.values()].includes(card));
175
250
  try {
176
251
  await waitForReadiness(contents, network, () => card.selector, current);
252
+ if (current()) await releaseDashboardPage(contents);
177
253
  } finally {
178
254
  preparing = false;
179
255
  stopPreparation();
180
256
  }
181
257
  settled(false);
182
258
  }, () => {
259
+ if (card.generation === generation) releaseDashboardPage(contents);
183
260
  stopPreparation();
184
261
  settled(true);
185
262
  });
@@ -187,7 +264,7 @@ function startDashboardViews() {
187
264
  };
188
265
  const applySelector = (card) => {
189
266
  if (card.view.webContents.isDestroyed()) return Promise.resolve();
190
- return card.view.webContents.executeJavaScriptInIsolatedWorld(1004, [{ code: require_dashboard_selector.dashboardSelectorScript(card.selector) }]).catch(() => {});
267
+ return card.view.webContents.mainFrame.executeJavaScript(require_dashboard_selector.dashboardSelectorScript(card.selector)).catch(() => {});
191
268
  };
192
269
  const refreshTimers = () => {
193
270
  const configured = configuredCards();
@@ -207,28 +284,55 @@ function startDashboardViews() {
207
284
  card.floatingPreparation?.selectorChanged();
208
285
  }
209
286
  if (card.floating && !card.floating.isDestroyed()) card.floating.setTitle(setting.title);
287
+ if (card.floatingStyles) {
288
+ const scrollbars = setting.size === "l" || setting.size === "xl";
289
+ if (card.floatingStyles.scrollbars !== scrollbars) {
290
+ card.floatingStyles.scrollbars = scrollbars;
291
+ applyWebsiteStyles(card.floatingStyles);
292
+ }
293
+ }
210
294
  const interval = setting.refreshEvery10Seconds ? 1e4 : setting.autoRefresh ? 6e5 : void 0;
211
295
  if (card.refreshInterval === interval) continue;
212
- clearInterval(card.refreshTimer);
296
+ clearTimeout(card.refreshTimer);
213
297
  card.refreshTimer = void 0;
214
298
  card.refreshInterval = interval;
299
+ const refreshGeneration = (card.refreshGeneration ?? 0) + 1;
300
+ card.refreshGeneration = refreshGeneration;
215
301
  if (!interval) continue;
216
- card.refreshTimer = setInterval(() => {
217
- const latest = configuredCards().find((item) => item.id === id);
218
- if (owners.get(sender) !== owner || owner.cards.get(id) !== card || !latest || latest.url !== card.url || (latest.refreshEvery10Seconds ? 1e4 : latest.autoRefresh ? 6e5 : void 0) !== interval || card.view.webContents.isDestroyed() || card.loading || card.view.webContents.isLoading()) return;
219
- if (latest.refreshEvery10Seconds) {
220
- if (card.floating) {
221
- if (card.floating.isDestroyed() || card.floating.webContents.isLoading() || card.floatingPreparation?.isPreparing()) return;
222
- Promise.all([reload(card, latest.url), card.floatingPreparation?.refresh()]);
223
- } else if (card.visible && dashboardUrl(sender.getURL())) reload(card, latest.url);
224
- } else if (!card.floating && !dashboardUrl(sender.getURL())) reload(card, latest.url);
225
- }, interval);
302
+ const schedule = () => {
303
+ if (owners.get(sender) !== owner || owner.cards.get(id) !== card || card.refreshGeneration !== refreshGeneration) return;
304
+ if (card.loading && card.pending) {
305
+ card.pending.then(schedule);
306
+ return;
307
+ }
308
+ card.refreshTimer = setTimeout(tick, interval);
309
+ };
310
+ const tick = async () => {
311
+ try {
312
+ const latest = configuredCards().find((item) => item.id === id);
313
+ if (owners.get(sender) !== owner || owner.cards.get(id) !== card || !latest || latest.url !== card.url || (latest.refreshEvery10Seconds ? 1e4 : latest.autoRefresh ? 6e5 : void 0) !== interval || card.view.webContents.isDestroyed()) return;
314
+ if (card.loading) {
315
+ await card.pending;
316
+ return;
317
+ }
318
+ if (latest.refreshEvery10Seconds) {
319
+ if (card.floating) {
320
+ if (card.floating.isDestroyed() || card.floatingPreparation?.isPreparing()) return;
321
+ await Promise.all([reload(card, latest.url), card.floatingPreparation?.refresh()]);
322
+ } else if (card.visible && dashboardUrl(sender.getURL())) await reload(card, latest.url);
323
+ } else if (!card.floating && !dashboardUrl(sender.getURL())) await reload(card, latest.url);
324
+ } finally {
325
+ schedule();
326
+ }
327
+ };
328
+ schedule();
226
329
  }
227
330
  };
228
- const stopSettingsReaction = require__global_external_mobx.reaction(() => JSON.stringify(configuredCards().map(({ id, title, url, autoRefresh, refreshEvery10Seconds, selector }) => ({
331
+ const stopSettingsReaction = require__global_external_mobx.reaction(() => JSON.stringify(configuredCards().map(({ id, title, url, size, autoRefresh, refreshEvery10Seconds, selector }) => ({
229
332
  id,
230
333
  title,
231
334
  url,
335
+ size,
232
336
  autoRefresh,
233
337
  refreshEvery10Seconds,
234
338
  selector
@@ -299,12 +403,10 @@ function startDashboardViews() {
299
403
  contextIsolation: true,
300
404
  sandbox: true,
301
405
  webSecurity: true,
302
- partition: "persist:freelens-power-websites"
406
+ partition: "persist:freelens-power-websites",
407
+ preload: (0, node_path.join)(__dirname, "dashboard-preload.js")
303
408
  } });
304
409
  view.setBackgroundColor("#00000000");
305
- view.webContents.on("did-finish-load", () => {
306
- if (!view.webContents.isDestroyed()) view.webContents.insertCSS(websiteStyles, { cssOrigin: "user" }).catch(() => {});
307
- });
308
410
  view.webContents.setWindowOpenHandler(({ url }) => {
309
411
  if (webUrl(url)) electron.shell.openExternal(url).catch(() => {});
310
412
  return { action: "deny" };
@@ -318,9 +420,12 @@ function startDashboardViews() {
318
420
  if (!webUrl(event.url)) event.preventDefault();
319
421
  });
320
422
  container.addChildView(view);
423
+ const skeleton = createDashboardSkeleton();
424
+ container.addChildView(skeleton.view);
321
425
  window.contentView.addChildView(container);
322
426
  card = {
323
427
  container,
428
+ skeleton,
324
429
  view,
325
430
  url: "",
326
431
  failed: false,
@@ -335,7 +440,38 @@ function startDashboardViews() {
335
440
  event.sender.send("freelens-power:dashboard-escape");
336
441
  });
337
442
  created.selector = configured.selector;
338
- view.webContents.on("did-finish-load", () => applySelector(created));
443
+ view.webContents.on("did-start-navigation", (_event, _url, inPlace, mainFrame) => {
444
+ if (!mainFrame) return;
445
+ if (created.requestedNavigation) {
446
+ created.requestedNavigation = false;
447
+ return;
448
+ }
449
+ created.nativeNavigation?.fail();
450
+ const navigation = new Promise((resolve, reject) => {
451
+ created.nativeNavigation = {
452
+ finish: () => {
453
+ created.nativeNavigation = void 0;
454
+ resolve();
455
+ },
456
+ fail: () => {
457
+ created.nativeNavigation = void 0;
458
+ reject(/* @__PURE__ */ new Error("dashboard navigation failed"));
459
+ }
460
+ };
461
+ });
462
+ if (inPlace) view.webContents.mainFrame.executeJavaScript("document.dispatchEvent(new Event(\"freelens-power:dashboard:preparing\"))").catch(() => {});
463
+ reload(created, created.url, false, navigation);
464
+ if (inPlace) created.nativeNavigation?.finish();
465
+ });
466
+ view.webContents.on("did-finish-load", () => {
467
+ applyWebsiteStyles(created);
468
+ applySelector(created);
469
+ created.nativeNavigation?.finish();
470
+ });
471
+ view.webContents.on("did-fail-load", (_event, code, _description, _url, mainFrame) => {
472
+ if (!mainFrame || code === -3 && view.webContents.isLoading()) return;
473
+ created.nativeNavigation?.fail();
474
+ });
339
475
  view.webContents.on("page-favicon-updated", (_event, favicons) => {
340
476
  const favicon = favicons.find((value) => {
341
477
  if (!webUrl(value)) return false;
@@ -417,8 +553,12 @@ function startDashboardViews() {
417
553
  })().catch(() => {}).finally(() => clearTimeout(timeout));
418
554
  });
419
555
  }
556
+ if (card.scrollbars !== (item.scrollbars === true)) {
557
+ card.scrollbars = item.scrollbars === true;
558
+ applyWebsiteStyles(card);
559
+ }
420
560
  card.visible = true;
421
- card.container.setVisible(!card.loading && !card.failed && card.url === configured.url);
561
+ card.container.setVisible(!card.failed && (card.loading || card.url === configured.url));
422
562
  const zoom = event.sender.getZoomFactor();
423
563
  card.container.setBorderRadius(Math.round(12 * zoom));
424
564
  card.view.setBorderRadius(Math.round(12 * zoom));
@@ -429,6 +569,7 @@ function startDashboardViews() {
429
569
  height: Math.round(rect.height * zoom)
430
570
  });
431
571
  card.container.setBounds(scale(clip));
572
+ card.skeleton.layout(Math.round(clip.width * zoom), Math.round(clip.height * zoom));
432
573
  card.view.setBounds(scale({
433
574
  x: bounds.x - clip.x,
434
575
  y: bounds.y - clip.y,
@@ -489,7 +630,8 @@ function startDashboardViews() {
489
630
  contextIsolation: true,
490
631
  sandbox: true,
491
632
  webSecurity: true,
492
- partition: "persist:freelens-power-websites"
633
+ partition: "persist:freelens-power-websites",
634
+ preload: (0, node_path.join)(__dirname, "dashboard-preload.js")
493
635
  }
494
636
  });
495
637
  floating.setMenu(null);
@@ -498,6 +640,11 @@ function startDashboardViews() {
498
640
  card.floating = floating;
499
641
  card.container.setVisible(false);
500
642
  const contents = floating.webContents;
643
+ const floatingStyles = {
644
+ view: { webContents: contents },
645
+ scrollbars: configured.size === "l" || configured.size === "xl"
646
+ };
647
+ card.floatingStyles = floatingStyles;
501
648
  contents.setWindowOpenHandler(({ url }) => {
502
649
  if (webUrl(url)) electron.shell.openExternal(url).catch(() => {});
503
650
  return { action: "deny" };
@@ -512,31 +659,11 @@ function startDashboardViews() {
512
659
  });
513
660
  contents.on("page-title-updated", (event) => event.preventDefault());
514
661
  contents.on("will-prevent-unload", (event) => event.preventDefault());
515
- const skeleton = new electron.View();
516
- skeleton.setBackgroundColor(electron.nativeTheme.shouldUseDarkColors ? "#202124" : "#ffffff");
517
- const bars = Array.from({ length: 4 }, () => {
518
- const bar = new electron.View();
519
- bar.setBackgroundColor(electron.nativeTheme.shouldUseDarkColors ? "#393b40" : "#e8e9eb");
520
- bar.setBorderRadius(6);
521
- skeleton.addChildView(bar);
522
- return bar;
523
- });
662
+ const loadingSkeleton = createDashboardSkeleton();
663
+ const skeleton = loadingSkeleton.view;
524
664
  const layoutSkeleton = () => {
525
665
  const { width, height } = floating.getContentBounds();
526
- skeleton.setBounds({
527
- x: 0,
528
- y: 0,
529
- width,
530
- height
531
- });
532
- bars.forEach((bar, index) => {
533
- bar.setBounds({
534
- x: 20,
535
- y: index === 0 ? 20 : 60 + (index - 1) * 24,
536
- width: Math.max(1, Math.round((width - 40) * (index === 0 ? .45 : 1))),
537
- height: index === 0 ? 20 : index === 3 ? Math.max(30, height - 128) : 12
538
- });
539
- });
666
+ loadingSkeleton.layout(width, height);
540
667
  };
541
668
  floating.contentView.addChildView(skeleton);
542
669
  floating.on("resize", layoutSkeleton);
@@ -568,6 +695,8 @@ function startDashboardViews() {
568
695
  finishing ??= (async () => {
569
696
  await waitForReadiness(contents, network, () => card.selector, current);
570
697
  if (!current()) return false;
698
+ await releaseDashboardPage(contents);
699
+ if (!current()) return false;
571
700
  skeleton.setVisible(false);
572
701
  stop();
573
702
  return false;
@@ -579,6 +708,7 @@ function startDashboardViews() {
579
708
  finish,
580
709
  fail: () => {
581
710
  if (current()) {
711
+ releaseDashboardPage(contents);
582
712
  skeleton.setVisible(false);
583
713
  stop();
584
714
  }
@@ -588,17 +718,26 @@ function startDashboardViews() {
588
718
  const refresh = () => {
589
719
  const preparation = begin();
590
720
  const current = contents.getURL();
591
- return contents.loadURL(webUrl(current) ? current : configured.url).then(() => finishLoad?.() ?? false, () => {
721
+ let documentReady;
722
+ const ready = new Promise((resolve) => {
723
+ documentReady = () => {
724
+ (finishLoad?.() ?? Promise.resolve(false)).then(resolve);
725
+ };
726
+ contents.once("dom-ready", documentReady);
727
+ });
728
+ const loading = prepareDashboardPage(contents).then(() => contents.loadURL(webUrl(current) ? current : configured.url)).then(() => finishLoad?.() ?? false, () => {
592
729
  preparation.fail();
593
730
  return !contents.isDestroyed();
594
731
  });
732
+ return Promise.race([loading, ready]).finally(() => {
733
+ contents.removeListener("dom-ready", documentReady);
734
+ });
595
735
  };
596
736
  card.floatingPreparation = {
597
737
  refresh,
598
738
  isPreparing: () => floatingPreparing,
599
739
  selectorChanged: () => {
600
- const preparation = begin();
601
- if (!contents.isLoading()) preparation.finish();
740
+ begin().finish();
602
741
  },
603
742
  stop: () => {
604
743
  ++generation;
@@ -610,14 +749,18 @@ function startDashboardViews() {
610
749
  const preparation = begin();
611
750
  if (inPlace) preparation.finish();
612
751
  });
752
+ contents.on("dom-ready", () => {
753
+ applyWebsiteStyles(floatingStyles);
754
+ if (!contents.isDestroyed()) finishLoad?.();
755
+ });
613
756
  contents.on("did-finish-load", () => {
614
- if (contents.isDestroyed()) return;
615
- contents.insertCSS(websiteStyles, { cssOrigin: "user" }).catch(() => {});
616
- finishLoad?.();
757
+ applyWebsiteStyles(floatingStyles);
758
+ if (!contents.isDestroyed()) finishLoad?.();
617
759
  });
618
760
  contents.on("did-fail-load", (_event, code, _description, _url, mainFrame) => {
619
761
  if (!mainFrame || code === -3) return;
620
762
  stopPreparation();
763
+ releaseDashboardPage(contents);
621
764
  skeleton.setVisible(false);
622
765
  });
623
766
  contents.once("destroyed", () => {
@@ -628,6 +771,8 @@ function startDashboardViews() {
628
771
  if (card.floating !== floating) return;
629
772
  card.floatingPreparation?.stop();
630
773
  card.floatingPreparation = void 0;
774
+ floatingStyles.websiteStylesGeneration = (floatingStyles.websiteStylesGeneration ?? 0) + 1;
775
+ card.floatingStyles = void 0;
631
776
  card.floating = void 0;
632
777
  if (owner.cards.get(id) === card) publishPinned(event.sender, owner);
633
778
  });