@astronox/core 0.4.8 → 0.4.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astronox/core",
3
- "version": "0.4.8",
3
+ "version": "0.4.9",
4
4
  "description": "Reusable Astro components, patterns, styles, and infrastructure for AstroNox sites.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -8,22 +8,14 @@ type Props = {
8
8
 
9
9
  const { config }: Props = Astro.props;
10
10
  const clientId = toAdsenseClientId(config.publisherId);
11
- const runtimeConfig = JSON.stringify({
12
- allowedHosts: config.allowedHosts,
13
- clientId,
14
- }).replaceAll('<', '\\u003c');
11
+ const scriptSource = `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${encodeURIComponent(clientId)}`;
15
12
  ---
16
13
 
17
14
  <meta name="google-adsense-account" content={clientId} />
18
- <script
19
- is:inline
20
- type="application/json"
21
- data-astronox-adsense-config
22
- set:html={runtimeConfig}
23
- />
15
+ <script is:inline async crossorigin="anonymous" src={scriptSource}></script>
24
16
 
25
17
  <script>
26
- import { initAdsenseFromDocument } from './runtime';
18
+ import { initAdAnnotationProtection } from './runtime';
27
19
 
28
- initAdsenseFromDocument();
20
+ initAdAnnotationProtection();
29
21
  </script>
@@ -1,45 +1,5 @@
1
- const adsenseScriptSelector =
2
- 'script[src^="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"]';
3
-
4
- type AdsenseRuntimeConfig = {
5
- allowedHosts: readonly string[];
6
- clientId: string;
7
- };
8
-
9
- export function initAdsenseFromDocument(): void {
10
- const config = readRuntimeConfig();
11
- if (!config || !isAllowedHost(config.allowedHosts)) {
12
- return;
13
- }
14
-
1
+ export function initAdAnnotationProtection(): void {
15
2
  protectAdAnnotations();
16
- loadAdsenseScript(config.clientId);
17
- }
18
-
19
- function readRuntimeConfig(): AdsenseRuntimeConfig | undefined {
20
- const element = document.querySelector<HTMLScriptElement>(
21
- 'script[data-astronox-adsense-config]',
22
- );
23
- if (!element?.textContent) return undefined;
24
-
25
- try {
26
- return JSON.parse(element.textContent) as AdsenseRuntimeConfig;
27
- } catch {
28
- return undefined;
29
- }
30
- }
31
-
32
- function isAllowedHost(allowedHosts: readonly string[]): boolean {
33
- const hostname = window.location.hostname.toLowerCase();
34
- if (
35
- hostname === 'localhost' ||
36
- hostname.endsWith('.localhost') ||
37
- hostname === '127.0.0.1' ||
38
- hostname === '::1'
39
- ) {
40
- return false;
41
- }
42
- return allowedHosts.some((host) => host.toLowerCase() === hostname);
43
3
  }
44
4
 
45
5
  function protectAdAnnotations(): void {
@@ -66,13 +26,3 @@ function protectAdAnnotations(): void {
66
26
  }
67
27
  }).observe(document.documentElement, { childList: true, subtree: true });
68
28
  }
69
-
70
- function loadAdsenseScript(clientId: string): void {
71
- if (document.querySelector(adsenseScriptSelector)) return;
72
-
73
- const script = document.createElement('script');
74
- script.async = true;
75
- script.crossOrigin = 'anonymous';
76
- script.src = `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${encodeURIComponent(clientId)}`;
77
- document.head.append(script);
78
- }
@@ -5,7 +5,6 @@ export type DisabledAdsConfig = {
5
5
  export type AdsenseAdsConfig = {
6
6
  enabled: true;
7
7
  provider: 'adsense';
8
- allowedHosts: readonly string[];
9
8
  publisherId: string;
10
9
  };
11
10
 
@@ -20,34 +19,8 @@ export function defineAdsConfig<const TConfig extends AdsConfig>(
20
19
  ): TConfig {
21
20
  if (!config.enabled) return config;
22
21
 
23
- if (config.allowedHosts.length === 0) {
24
- throw new Error('Ad configuration requires at least one allowed hostname');
25
- }
26
- for (const host of config.allowedHosts) {
27
- if (!isValidHostname(host)) {
28
- throw new Error(`Invalid advertising hostname: ${host}`);
29
- }
30
- }
31
22
  if (!/^pub-\d+$/.test(config.publisherId)) {
32
23
  throw new Error('Invalid AdSense publisher id');
33
24
  }
34
25
  return config;
35
26
  }
36
-
37
- function isValidHostname(host: string): boolean {
38
- if (!host || host !== host.trim() || host.includes('/')) return false;
39
- if (
40
- host.toLowerCase() === 'localhost' ||
41
- host.toLowerCase().endsWith('.localhost') ||
42
- host === '127.0.0.1' ||
43
- host === '::1'
44
- ) {
45
- return false;
46
- }
47
-
48
- try {
49
- return new URL(`https://${host}`).hostname === host.toLowerCase();
50
- } catch {
51
- return false;
52
- }
53
- }
@@ -62,30 +62,32 @@ const resolvedTone = tone ?? dataTone;
62
62
  <slot name="head" />
63
63
  </head>
64
64
  <body>
65
- <slot name="skip-link" />
66
- <slot name="header" />
67
- <div class="site-viewport" data-site-viewport>
68
- <main id="content" class="site-main" tabindex="-1">
69
- <div class="site-main__content">
70
- {
71
- breadcrumbs?.length ? (
72
- <Breadcrumbs
73
- {...adAnnotationExclusionAttributes}
74
- items={breadcrumbs}
75
- label={breadcrumbLabel}
76
- tone={breadcrumbTone}
77
- />
78
- ) : null
79
- }
65
+ <div class="site-shell">
66
+ <slot name="skip-link" />
67
+ <slot name="header" />
68
+ <div class="site-viewport" data-site-viewport>
69
+ <main id="content" class="site-main" tabindex="-1">
70
+ <div class="site-main__content">
71
+ {
72
+ breadcrumbs?.length ? (
73
+ <Breadcrumbs
74
+ {...adAnnotationExclusionAttributes}
75
+ items={breadcrumbs}
76
+ label={breadcrumbLabel}
77
+ tone={breadcrumbTone}
78
+ />
79
+ ) : null
80
+ }
80
81
 
81
- <PageSurface {...pageSurfaceAttributes}>
82
- <slot />
83
- <slot name="page-end" />
84
- </PageSurface>
85
- </div>
86
- </main>
87
- <slot name="footer" />
82
+ <PageSurface {...pageSurfaceAttributes}>
83
+ <slot />
84
+ <slot name="page-end" />
85
+ </PageSurface>
86
+ </div>
87
+ </main>
88
+ <slot name="footer" />
89
+ </div>
90
+ {scrollToTopLabel ? <ScrollToTop label={scrollToTopLabel} /> : null}
88
91
  </div>
89
- {scrollToTopLabel ? <ScrollToTop label={scrollToTopLabel} /> : null}
90
92
  </body>
91
93
  </html>
@@ -155,12 +155,12 @@
155
155
  --map-viewport-cell-surface: color-mix(
156
156
  in srgb,
157
157
  var(--map-viewport-cell-seed) 38%,
158
- var(--nox-theme-surface-base)
158
+ var(--nox-mix-light)
159
159
  );
160
160
  --map-viewport-cell-surface-hover: color-mix(
161
161
  in srgb,
162
162
  var(--map-viewport-cell-seed) 52%,
163
- var(--nox-theme-surface-base)
163
+ var(--nox-mix-light)
164
164
  );
165
165
  --map-viewport-cell-background: color-mix(
166
166
  in srgb,
@@ -175,7 +175,7 @@
175
175
  --map-viewport-cell-border: color-mix(
176
176
  in srgb,
177
177
  var(--map-viewport-cell-seed) 74%,
178
- var(--nox-theme-text-base)
178
+ var(--nox-mix-dark)
179
179
  );
180
180
 
181
181
  fill: var(--map-viewport-cell-background);
@@ -53,17 +53,23 @@ html {
53
53
  }
54
54
 
55
55
  body {
56
+ margin: 0;
57
+ overflow: hidden;
58
+ background: var(--nox-page-background);
59
+ }
60
+
61
+ .site-shell {
56
62
  display: grid;
63
+ width: 100vw;
57
64
  height: 100vh;
58
65
  min-height: 100vh;
59
66
  grid-template-rows: auto minmax(0, 1fr);
60
- margin: 0;
61
67
  overflow: hidden;
62
68
  background: var(--nox-page-background);
63
69
  }
64
70
 
65
71
  @supports (height: 100dvh) {
66
- body {
72
+ .site-shell {
67
73
  height: 100dvh;
68
74
  min-height: 100dvh;
69
75
  }
@@ -14,7 +14,7 @@
14
14
  --nox-content-link-font-weight: var(--nox-font-weight-regular);
15
15
  --nox-content-link-emphasis-font-weight: var(--nox-font-weight-medium);
16
16
 
17
- /* Public map seeds. Component states derive their full treatment from these. */
17
+ /* Public map palette. It stays stable across UI color themes. */
18
18
  --nox-source-map-available: #00b86b;
19
19
  --nox-source-map-unavailable: #f43f5e;
20
20
  --nox-source-map-field: #f59e0b;
@@ -48,14 +48,6 @@
48
48
  --nox-source-tone-warning: #f0ad55;
49
49
  --nox-source-tone-danger: #f47777;
50
50
 
51
- --nox-source-map-available: #42d392;
52
- --nox-source-map-unavailable: #fb7185;
53
- --nox-source-map-field: #fbbf24;
54
- --nox-source-map-grass: #84cc16;
55
- --nox-source-map-mountain: #94a3b8;
56
- --nox-source-map-water: #38bdf8;
57
- --nox-source-map-range: #60a5fa;
58
-
59
51
  --nox-theme-page-base: #0f1218;
60
52
  --nox-theme-surface-base: #171b23;
61
53
  --nox-theme-text-base: #f8fafc;