@hagicode/hagilight-docusaurus 0.10.0 → 0.10.1-dev.123.1.28afdf0

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.
@@ -1,2 +1,9 @@
1
+ /**
2
+ * Centers the fixed card in the main content column instead of the viewport: it
3
+ * starts after the doc sidebar and ends before the desktop table of contents.
4
+ * Infima's layout cannot be expressed in CSS alone (collapsible sidebar, container
5
+ * max-width, TOC column), so the two insets are measured and handed to promoto.css.
6
+ */
7
+ export declare function syncPromotoInsets(doc: Document, banner: HTMLElement): void;
1
8
  export declare function mountPromotoBanner(doc: Document, locale: string): void;
2
9
  export declare function onRouteDidUpdate(): void;
@@ -3,6 +3,67 @@ import { PROMOTO_SHELL_MARKUP } from './promoto-markup.js';
3
3
  const ELEMENT_NAME = 'hagilight-promoto-banner';
4
4
  const DEFAULT_LOCALE = 'en-US';
5
5
  const mounts = new WeakMap();
6
+ /** Infima switches to the single-column mobile layout below this width. */
7
+ const DESKTOP_MIN_WIDTH = 997;
8
+ const INSET_START = '--hagilight-promoto-inset-start';
9
+ const INSET_END = '--hagilight-promoto-inset-end';
10
+ let stopWatchingLayout;
11
+ function widest(elements) {
12
+ return elements
13
+ .map((element) => element.getBoundingClientRect())
14
+ .filter((rect) => rect.width > 0)
15
+ .sort((a, b) => b.width - a.width)[0];
16
+ }
17
+ /**
18
+ * Centers the fixed card in the main content column instead of the viewport: it
19
+ * starts after the doc sidebar and ends before the desktop table of contents.
20
+ * Infima's layout cannot be expressed in CSS alone (collapsible sidebar, container
21
+ * max-width, TOC column), so the two insets are measured and handed to promoto.css.
22
+ */
23
+ export function syncPromotoInsets(doc, banner) {
24
+ const viewport = doc.documentElement.clientWidth;
25
+ let start = 0;
26
+ let end = 0;
27
+ if (viewport >= DESKTOP_MIN_WIDTH) {
28
+ const main = doc.querySelector('main');
29
+ const columns = main ? Array.from(main.querySelectorAll(':scope > * > .row > .col, :scope > .row > .col')) : [];
30
+ const content = widest(columns) ?? main?.getBoundingClientRect();
31
+ if (content && content.width > 0) {
32
+ const sidebar = doc.querySelector('.theme-doc-sidebar-container')?.getBoundingClientRect();
33
+ start = Math.max(content.left, sidebar && sidebar.width > 0 ? sidebar.right : 0);
34
+ end = Math.max(0, viewport - content.right);
35
+ }
36
+ }
37
+ banner.style.setProperty(INSET_START, `${Math.max(0, Math.round(start))}px`);
38
+ banner.style.setProperty(INSET_END, `${Math.max(0, Math.round(end))}px`);
39
+ }
40
+ function watchPromotoLayout(doc, banner) {
41
+ stopWatchingLayout?.();
42
+ stopWatchingLayout = undefined;
43
+ const win = doc.defaultView;
44
+ if (!win || !banner.style || typeof win.ResizeObserver !== 'function')
45
+ return;
46
+ let frame = 0;
47
+ const schedule = () => {
48
+ if (frame)
49
+ return;
50
+ frame = win.requestAnimationFrame(() => {
51
+ frame = 0;
52
+ syncPromotoInsets(doc, banner);
53
+ });
54
+ };
55
+ const observer = new win.ResizeObserver(schedule);
56
+ const main = doc.querySelector('main');
57
+ if (main)
58
+ observer.observe(main);
59
+ observer.observe(doc.documentElement);
60
+ syncPromotoInsets(doc, banner);
61
+ stopWatchingLayout = () => {
62
+ observer.disconnect();
63
+ if (frame)
64
+ win.cancelAnimationFrame(frame);
65
+ };
66
+ }
6
67
  function readSiteId(doc) {
7
68
  const content = doc.querySelector('meta[name="hagilight-site-id"]')?.getAttribute('content')?.trim();
8
69
  return content || undefined;
@@ -10,8 +71,11 @@ function readSiteId(doc) {
10
71
  export function mountPromotoBanner(doc, locale) {
11
72
  const footer = doc.querySelector('footer');
12
73
  const previous = mounts.get(doc);
13
- if (previous?.banner.isConnected && previous.footer === footer && previous.locale === locale)
74
+ if (previous?.banner.isConnected && previous.footer === footer && previous.locale === locale) {
75
+ // The page layout may have been swapped under the same footer (docs to blog), so re-measure it.
76
+ watchPromotoLayout(doc, previous.banner);
14
77
  return;
78
+ }
15
79
  doc.querySelectorAll(ELEMENT_NAME).forEach((existing) => existing.remove());
16
80
  const banner = doc.createElement(ELEMENT_NAME);
17
81
  banner.className = 'hagilight-promoto';
@@ -23,6 +87,7 @@ export function mountPromotoBanner(doc, locale) {
23
87
  banner.innerHTML = PROMOTO_SHELL_MARKUP;
24
88
  doc.body.append(banner);
25
89
  mounts.set(doc, { banner, footer, locale });
90
+ watchPromotoLayout(doc, banner);
26
91
  }
27
92
  export function onRouteDidUpdate() {
28
93
  definePromotoBannerElement();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hagicode/hagilight-docusaurus",
3
- "version": "0.10.0",
3
+ "version": "0.10.1-dev.123.1.28afdf0",
4
4
  "type": "module",
5
5
  "description": "Docusaurus plugin for HagiCode site features: footer, analytics, promote card, locales, SEO, sitemap, robots.txt, and RSS",
6
6
  "repository": {
@@ -38,7 +38,7 @@
38
38
  ],
39
39
  "dependencies": {
40
40
  "@docusaurus/types": "^3.9.2",
41
- "@hagicode/hagilight-core": "0.10.0"
41
+ "@hagicode/hagilight-core": "0.10.1-dev.123.1.28afdf0"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "@docusaurus/core": "^3.9.2",
package/promoto.css CHANGED
@@ -24,9 +24,11 @@
24
24
  .hagilight-promoto__shell {
25
25
  position: fixed;
26
26
  z-index: 40;
27
- inset-inline: 0;
27
+ /* Centered in the content area: a theme narrows it by setting these two insets on :root. */
28
+ inset-inline-start: var(--hagilight-promoto-inset-start, 0px);
29
+ inset-inline-end: var(--hagilight-promoto-inset-end, 0px);
28
30
  bottom: max(1rem, env(safe-area-inset-bottom));
29
- width: min(42rem, calc(100vw - 1rem - 2 * max(env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px))));
31
+ width: min(42rem, calc(100% - var(--hagilight-promoto-inset-start, 0px) - var(--hagilight-promoto-inset-end, 0px) - 1rem - 2 * max(env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px))));
30
32
  margin-inline: auto;
31
33
  overflow: hidden;
32
34
  border: 1px solid color-mix(in srgb, var(--ifm-color-primary) 24%, var(--ifm-color-emphasis-300));