@netlify/spark-ui 0.0.44 → 0.0.46-alpha

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/README.md CHANGED
@@ -34,3 +34,9 @@ Tokens are converted into CSS variables using the [terrazzo](https://terrazzo.ap
34
34
  ### Rebuild CSS token variables
35
35
 
36
36
  When any files in this tokens directory are updated and merged into the `main` branch, the [build-tokens-css](https://github.com/netlify/netlify-bits/blob/main/.github/workflows/build-tokens-css.yml) GitHub Action is executed. This runs the `build:tokens` script, recreating the [tokens.css](https://github.com/netlify/netlify-bits/blob/main/packages/styles/tokens.css) file with updated CSS variables.
37
+
38
+ The tokens file can also be rebuilt manually with the following command:
39
+
40
+ ```bash
41
+ npm run build:tokens
42
+ ```
@@ -0,0 +1,8 @@
1
+ export default class Analytics {
2
+ /**
3
+ * Pushes an event payload into the dataLayer.
4
+ * @param eventName e.g. 'www:search_query_changed'
5
+ * @param payload additional key/value data
6
+ */
7
+ track(eventName: string, payload?: Record<string, any>): void;
8
+ }
@@ -0,0 +1,4 @@
1
+ import { default as GoogleTagManager } from './GoogleTagManager.astro';
2
+ import { default as GoogleAnalytics } from './GoogleAnalytics.astro';
3
+ import { default as Analytics } from './analytics';
4
+ export { Analytics, GoogleAnalytics, GoogleTagManager };
@@ -5,5 +5,7 @@ export { default as SearchLink } from './preact/SearchModal/components/SearchLin
5
5
  export { default as SearchHeading } from './preact/SearchModal/components/SearchHeading/SearchHeading';
6
6
  export { default as SearchToggle } from './preact/SearchModal/components/SearchToggle/SearchToggle';
7
7
  export { default as SearchModal } from './preact/SearchModal/components/SearchModal/SearchModal';
8
- export { default as Tabs } from './Tabs.astro';
9
8
  export { type IconName } from './preact/Icon';
9
+ export { default as Button } from './Button.astro';
10
+ export { default as DeployToNetlifyButton } from './DeployToNetlifyButton.astro';
11
+ export { default as Tabs } from './Tabs.astro';
@@ -1,17 +1,26 @@
1
1
  import { SearchState } from '../types/search.types';
2
2
  /**
3
- * Hook that logs search-related events to your analytics Logger.
3
+ * Custom hook that logs search-related events for analytics.
4
4
  *
5
- * It will:
6
- * - Push a `searchQueryChanged` event whenever the search term changes.
7
- * - Push a `searchNoResults` event whenever a non-empty query returns zero results.
8
- * - Provide a click handler (`handleClick`) to log `searchResultClick` events.
5
+ * This hook tracks the following search events:
6
+ * - `spark_search:query_changed`: Logs when the search query changes.
7
+ * - `spark_search:no_results`: Logs when no results are found for a search.
8
+ * - `spark_search:result_clicked`: Logs when a search result is clicked.
9
9
  *
10
- * @param {SearchState} state - The current search state, containing:
11
- * - `searchTerm` (string): the text the user has searched for.
12
- * - `results` (Array<any>): the array of result objects returned.
13
- * @returns {{ handleClick: (e: Event) => void }}
14
- * An object with a `handleClick` function that you can attach to result links to log clicks.
10
+ * It uses an instance of `Analytics` to track these events. The hook listens to changes in the `searchTerm` and `results` properties from the provided `SearchState`.
11
+ *
12
+ * @param {SearchState} [state] - The search state, which includes the current search term and the results of the search.
13
+ * - `state.searchTerm`: The current search query string.
14
+ * - `state.results`: The search results array. If it's empty, the hook will log a no-results event.
15
+ *
16
+ * @returns {Object} - An object with the following function:
17
+ * - `handleClick`: A callback function that should be attached to search result click events. It tracks `spark_search:result_clicked` events with the clicked result's title and URL.
18
+ *
19
+ * @example
20
+ * const { handleClick } = useSearchLogger(searchState);
21
+ *
22
+ * // In your component, attach handleClick to the search result links
23
+ * <a href="result-url" onClick={handleClick}>Search Result</a>
15
24
  */
16
25
  export declare function useSearchLogger(state?: SearchState): {
17
26
  handleClick: (e: Event) => void;
@@ -1,43 +1,33 @@
1
- var a = Object.defineProperty;
2
- var d = (r, e, c) => e in r ? a(r, e, { enumerable: !0, configurable: !0, writable: !0, value: c }) : r[e] = c;
3
- var h = (r, e, c) => d(r, typeof e != "symbol" ? e + "" : e, c);
4
- import { A as L, y as l, q as s } from "../../../../chunks/hooks.module.CNV9mxng.js";
1
+ import { A as k, y as u, q as f } from "../../../../chunks/hooks.module.CNV9mxng.js";
5
2
  class g {
6
- /**
7
- * @param dl Optional injected dataLayer array. Defaults to window.dataLayer.
8
- */
9
- constructor(e) {
10
- h(this, "dataLayer");
11
- this.dataLayer = Array.isArray(e) ? e : window.dataLayer, Array.isArray(this.dataLayer) || (window.dataLayer = [], this.dataLayer = window.dataLayer);
12
- }
13
3
  /**
14
4
  * Pushes an event payload into the dataLayer.
15
- * @param eventName e.g. 'searchResultClick'
5
+ * @param eventName e.g. 'www:search_query_changed'
16
6
  * @param payload additional key/value data
17
7
  */
18
- push(e, c = {}) {
19
- this.dataLayer.push({ event: e, ...c });
8
+ track(n, c = {}) {
9
+ gtag("event", n, c);
20
10
  }
21
11
  }
22
- function m(r) {
23
- const e = L(new g());
24
- return l(() => {
25
- r != null && r.searchTerm && e.current.push("searchQueryChanged", { query: r == null ? void 0 : r.searchTerm });
26
- }, [r == null ? void 0 : r.searchTerm]), l(() => {
27
- r != null && r.results && r != null && r.searchTerm && r.results.length === 0 && e.current.push("searchNoResults", { query: r == null ? void 0 : r.searchTerm });
12
+ function T(r) {
13
+ const c = k(new g()).current;
14
+ return u(() => {
15
+ r != null && r.searchTerm && c.track("spark_search:query_changed", { query: r == null ? void 0 : r.searchTerm });
16
+ }, [r == null ? void 0 : r.searchTerm]), u(() => {
17
+ r != null && r.results && r != null && r.searchTerm && r.results.length === 0 && c.track("spark_search:no_results", { query: r == null ? void 0 : r.searchTerm });
28
18
  }, [r == null ? void 0 : r.results]), {
29
- handleClick: s((i) => {
30
- var u;
31
- const n = i.target.closest("a");
32
- if (!n) return;
33
- const o = (u = n.querySelector(".n-search-link-label")) == null ? void 0 : u.innerHTML, y = n.getAttribute("href");
34
- e.current.push("searchResultClick", {
35
- searchResultTitle: o,
36
- searchResultURL: y
19
+ handleClick: f((h) => {
20
+ var e;
21
+ const l = h.target.closest("a");
22
+ if (!l) return;
23
+ const i = (e = l.querySelector(".n-search-link-label")) == null ? void 0 : e.innerHTML, o = l.getAttribute("href");
24
+ c.track("spark_search:result_clicked", {
25
+ resultTitle: i,
26
+ resultUrl: o
37
27
  });
38
28
  }, [])
39
29
  };
40
30
  }
41
31
  export {
42
- m as useSearchLogger
32
+ T as useSearchLogger
43
33
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@netlify/spark-ui",
3
3
  "description": "Assets, design tokens, components, and utilities",
4
- "version": "0.0.44",
4
+ "version": "0.0.46-alpha",
5
5
  "type": "module",
6
6
  "main": "dist/components/preact/index.js",
7
7
  "types": "dist/components/preact/index.d.ts",
@@ -28,7 +28,8 @@
28
28
  "./logos/*.svg": "./packages/assets/logos/*.svg",
29
29
  "./styles/*.css": "./packages/styles/*.css",
30
30
  "./components": "./packages/components/index.ts",
31
- "./utils": "./packages/utils/index.ts"
31
+ "./utils": "./packages/utils/index.ts",
32
+ "./analytics": "./packages/analytics/index.ts"
32
33
  },
33
34
  "dependencies": {
34
35
  "@preact/preset-vite": "^2.10.1",
@@ -42,6 +43,7 @@
42
43
  "devDependencies": {
43
44
  "@terrazzo/cli": "^0.6.3",
44
45
  "@terrazzo/plugin-css": "^0.6.0",
46
+ "@types/gtag.js": "^0.0.20",
45
47
  "tslib": "^2.8.1",
46
48
  "typescript": "^5.8.2"
47
49
  },
@@ -0,0 +1,9 @@
1
+ <!-- Google tag (gtag.js) -->
2
+ <script async src="https://www.googletagmanager.com/gtag/js?id=G-X2FMMZSSS9"></script>
3
+ <script>
4
+ window.dataLayer = window.dataLayer || [];
5
+ function gtag(){dataLayer.push(arguments);}
6
+ gtag('js', new Date());
7
+
8
+ gtag('config', 'G-X2FMMZSSS9');
9
+ </script>
@@ -0,0 +1,14 @@
1
+ <!-- Google Tag Manager -->
2
+ <script>
3
+ (function (w, d, s, l, i) {
4
+ w[l] = w[l] || [];
5
+ w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
6
+ var f = d.getElementsByTagName(s)[0],
7
+ j = d.createElement(s),
8
+ dl = l != 'dataLayer' ? '&l=' + l : '';
9
+ j.async = true;
10
+ j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
11
+ f.parentNode.insertBefore(j, f);
12
+ })(window, document, 'script', 'dataLayer', 'GTM-T7WNFLD');
13
+ </script>
14
+ <!-- End Google Tag Manager -->
@@ -0,0 +1,10 @@
1
+ export default class Analytics {
2
+ /**
3
+ * Pushes an event payload into the dataLayer.
4
+ * @param eventName e.g. 'www:search_query_changed'
5
+ * @param payload additional key/value data
6
+ */
7
+ track(eventName: string, payload: Record<string, any> = {}): void {
8
+ gtag('event', eventName, payload);
9
+ }
10
+ }
@@ -0,0 +1,5 @@
1
+ import GoogleTagManager from "./GoogleTagManager.astro";
2
+ import GoogleAnalytics from "./GoogleAnalytics.astro";
3
+ import Analytics from "./analytics"
4
+
5
+ export { Analytics, GoogleAnalytics, GoogleTagManager }
@@ -0,0 +1,22 @@
1
+ ---
2
+ import '../styles/buttons.css';
3
+
4
+ interface Props {
5
+ variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
6
+ href?: string;
7
+ }
8
+
9
+ const {
10
+ class: className,
11
+ variant = 'primary',
12
+ href,
13
+ target = !href?.includes(Astro.url.origin) ? '_blank' : undefined,
14
+ ...rest
15
+ } = Astro.props;
16
+
17
+ const Element = href ? 'a' : 'button';
18
+ ---
19
+
20
+ <Element class:list={['button', className]} data-button-variant={variant} {href} {target} {...rest}>
21
+ <slot />
22
+ </Element>
@@ -0,0 +1,36 @@
1
+ ---
2
+ interface Props {
3
+ repo: string;
4
+ branch?: string;
5
+ path?: string;
6
+ utm?: string;
7
+ }
8
+ const { repo, branch, path, utm } = Astro.props;
9
+
10
+ const url = new URL('https://app.netlify.com/start/deploy');
11
+
12
+ url.search = new URLSearchParams({
13
+ repository: repo,
14
+ ...(branch ? { branch } : { branch: 'main' }),
15
+ ...(path ? { create_from_path: path } : {}),
16
+ ...(utm ? { utm } : {}),
17
+ }).toString();
18
+ ---
19
+
20
+ <a href={url.toString()} rel="nofollow">
21
+ <img
22
+ src="https://www.netlify.com/img/deploy/button.svg"
23
+ alt="Deploy to Netlify"
24
+ width="179"
25
+ height="32"
26
+ />
27
+ </a>
28
+
29
+ <style>
30
+ a {
31
+ display: inline-grid;
32
+ text-decoration: none;
33
+ border-radius: 0.35em;
34
+ outline-offset: 2px;
35
+ }
36
+ </style>
@@ -1,4 +1,6 @@
1
1
  ---
2
+ import '../styles/tabs.css';
3
+
2
4
  interface Props {
3
5
  id?: string;
4
6
  class?: string;
@@ -0,0 +1,112 @@
1
+ ---
2
+ interface Props {
3
+ id?: string;
4
+ class?: string;
5
+ gap?: string;
6
+ pauseOnHover?: boolean;
7
+ reverse?: boolean;
8
+ scrollY?: boolean;
9
+ speed?: string;
10
+ }
11
+
12
+ const {
13
+ id,
14
+ class: className,
15
+ gap,
16
+ pauseOnHover,
17
+ reverse,
18
+ scrollY,
19
+ speed = 30,
20
+ ...rest
21
+ } = Astro.props;
22
+
23
+ const css = {
24
+ 'n-ticker-animation': scrollY ? 'scroll-y' : 'scroll-x',
25
+ 'n-ticker-direction': scrollY ? 'column' : 'row',
26
+ 'n-ticker-duration': speed + 's',
27
+ 'n-ticker-gap': gap || undefined,
28
+ 'n-ticker-hover-play-state': pauseOnHover ? 'paused' : 'running',
29
+ 'n-ticker-mask-direction': scrollY ? 'to bottom' : 'to right',
30
+ };
31
+ ---
32
+
33
+ <div id={id} class:list={['ticker', reverse && 'ticker-reverse', className]} {...rest}>
34
+ {
35
+ Array.from({ length: 2 }, (_, index) => (
36
+ <div class="ticker-content" aria-hidden={index !== 0 ? 'true' : undefined}>
37
+ <slot />
38
+ </div>
39
+ ))
40
+ }
41
+ </div>
42
+
43
+ <style define:vars={css}>
44
+ .ticker {
45
+ --_gap: var(--n-ticker-gap, 1rem);
46
+ display: flex;
47
+ flex-direction: var(--n-ticker-direction, row);
48
+ overflow: hidden;
49
+ user-select: none;
50
+ gap: var(--_gap);
51
+
52
+ /** Fade out along edges */
53
+ mask-image: linear-gradient(
54
+ var(--n-ticker-mask-direction, to right),
55
+ rgba(0, 0, 0, 0) 0%,
56
+ rgba(0, 0, 0, 1) 15%,
57
+ rgba(0, 0, 0, 1) 85%,
58
+ rgba(0, 0, 0, 0) 100%
59
+ );
60
+ }
61
+
62
+ .ticker-content {
63
+ flex-shrink: 0;
64
+ display: flex;
65
+ flex-direction: var(--n-ticker-direction, row);
66
+ justify-content: space-around;
67
+ min-width: 100%;
68
+ gap: var(--_gap);
69
+ }
70
+
71
+ /** Animation */
72
+ .ticker-content {
73
+ animation-name: var(--n-ticker-animation, scroll-x);
74
+ animation-duration: var(--n-ticker-duration, 30s);
75
+ animation-play-state: var(--n-ticker-play-state, running);
76
+ animation-timing-function: linear;
77
+ animation-iteration-count: infinite;
78
+ }
79
+
80
+ .ticker:hover .ticker-content {
81
+ animation-play-state: var(--n-ticker-hover-play-state, running);
82
+ }
83
+
84
+ .ticker-reverse .ticker-content {
85
+ animation-direction: reverse;
86
+ }
87
+
88
+ @keyframes scroll-x {
89
+ from {
90
+ transform: translateX(0);
91
+ }
92
+ to {
93
+ transform: translateX(calc(-100% - var(--_gap)));
94
+ }
95
+ }
96
+
97
+ @keyframes scroll-y {
98
+ from {
99
+ transform: translateY(0);
100
+ }
101
+ to {
102
+ transform: translateY(calc(-100% - var(--_gap)));
103
+ }
104
+ }
105
+
106
+ /* Pause animation when reduced-motion is set */
107
+ @media (prefers-reduced-motion: reduce) {
108
+ .ticker-content {
109
+ animation-play-state: paused !important;
110
+ }
111
+ }
112
+ </style>
@@ -1,3 +1,4 @@
1
+ // Preact components
1
2
  export { default as KeyboardKey } from './preact/KeyboardKey/KeyboardKey';
2
3
  export { default as Modal } from './preact/Modal/Modal';
3
4
  export { default as Icon } from './preact/Icon';
@@ -5,6 +6,9 @@ export { default as SearchLink } from './preact/SearchModal/components/SearchLin
5
6
  export { default as SearchHeading } from './preact/SearchModal/components/SearchHeading/SearchHeading';
6
7
  export { default as SearchToggle } from './preact/SearchModal/components/SearchToggle/SearchToggle';
7
8
  export { default as SearchModal } from './preact/SearchModal/components/SearchModal/SearchModal';
8
- export { default as Tabs } from './Tabs.astro';
9
-
10
9
  export { type IconName } from './preact/Icon';
10
+
11
+ // Astro components
12
+ export { default as Button } from './Button.astro';
13
+ export { default as DeployToNetlifyButton } from './DeployToNetlifyButton.astro';
14
+ export { default as Tabs } from './Tabs.astro';
@@ -1,30 +1,39 @@
1
1
  import type { SearchState } from '../types/search.types';
2
2
  import { useEffect, useRef, useCallback } from 'preact/hooks';
3
- import { Logger } from '../../../../analytics/logger';
3
+ import Analytics from '../../../../analytics/analytics';
4
4
 
5
5
  /**
6
- * Hook that logs search-related events to your analytics Logger.
6
+ * Custom hook that logs search-related events for analytics.
7
7
  *
8
- * It will:
9
- * - Push a `searchQueryChanged` event whenever the search term changes.
10
- * - Push a `searchNoResults` event whenever a non-empty query returns zero results.
11
- * - Provide a click handler (`handleClick`) to log `searchResultClick` events.
8
+ * This hook tracks the following search events:
9
+ * - `spark_search:query_changed`: Logs when the search query changes.
10
+ * - `spark_search:no_results`: Logs when no results are found for a search.
11
+ * - `spark_search:result_clicked`: Logs when a search result is clicked.
12
12
  *
13
- * @param {SearchState} state - The current search state, containing:
14
- * - `searchTerm` (string): the text the user has searched for.
15
- * - `results` (Array<any>): the array of result objects returned.
16
- * @returns {{ handleClick: (e: Event) => void }}
17
- * An object with a `handleClick` function that you can attach to result links to log clicks.
13
+ * It uses an instance of `Analytics` to track these events. The hook listens to changes in the `searchTerm` and `results` properties from the provided `SearchState`.
14
+ *
15
+ * @param {SearchState} [state] - The search state, which includes the current search term and the results of the search.
16
+ * - `state.searchTerm`: The current search query string.
17
+ * - `state.results`: The search results array. If it's empty, the hook will log a no-results event.
18
+ *
19
+ * @returns {Object} - An object with the following function:
20
+ * - `handleClick`: A callback function that should be attached to search result click events. It tracks `spark_search:result_clicked` events with the clicked result's title and URL.
21
+ *
22
+ * @example
23
+ * const { handleClick } = useSearchLogger(searchState);
24
+ *
25
+ * // In your component, attach handleClick to the search result links
26
+ * <a href="result-url" onClick={handleClick}>Search Result</a>
18
27
  */
19
28
 
20
-
21
29
  export function useSearchLogger(state?: SearchState) {
22
- const loggerRef = useRef<Logger>(new Logger());
30
+ const ref = useRef<Analytics>(new Analytics());
31
+ const analytics = ref.current;
23
32
 
24
33
  // Log search query
25
34
  useEffect(() => {
26
35
  if (!state?.searchTerm) return
27
- loggerRef.current.push('searchQueryChanged', { query: state?.searchTerm });
36
+ analytics.track('spark_search:query_changed', { query: state?.searchTerm });
28
37
  }, [state?.searchTerm]);
29
38
 
30
39
  // Log zero‑hit searches
@@ -32,7 +41,7 @@ export function useSearchLogger(state?: SearchState) {
32
41
  if (!state?.results) return
33
42
 
34
43
  if (state?.searchTerm && state.results.length === 0) {
35
- loggerRef.current.push('searchNoResults', { query: state?.searchTerm });
44
+ analytics.track('spark_search:no_results', { query: state?.searchTerm });
36
45
  }
37
46
  }, [state?.results]);
38
47
 
@@ -44,9 +53,9 @@ export function useSearchLogger(state?: SearchState) {
44
53
  const label = anchor.querySelector('.n-search-link-label')?.innerHTML
45
54
  const url = anchor.getAttribute('href')
46
55
 
47
- loggerRef.current.push('searchResultClick', {
48
- searchResultTitle: label,
49
- searchResultURL: url,
56
+ analytics.track('spark_search:result_clicked', {
57
+ resultTitle: label,
58
+ resultUrl: url,
50
59
  });
51
60
  }, []);
52
61
 
@@ -2,4 +2,3 @@
2
2
  @import 'utils.css';
3
3
  @import 'fonts.css';
4
4
  @import 'layout.css';
5
- @import 'buttons.css';
@@ -1,11 +1,12 @@
1
1
  button,
2
2
  .button {
3
3
  appearance: none;
4
+ position: relative;
4
5
  cursor: pointer;
5
6
  display: inline-flex;
6
7
  align-items: center;
7
8
  gap: var(--space-xs);
8
- padding: var(--space-s) var(--space-m);
9
+ padding: var(--space-xs) var(--space-m);
9
10
  font-size: var(--font-size-0);
10
11
  font-family: var(--font-body);
11
12
  font-weight: var(--font-semibold);
@@ -21,6 +22,7 @@ button,
21
22
  flex: none;
22
23
  height: var(--button-icon-size, 1.2cap);
23
24
  width: auto;
25
+ fill: currentColor;
24
26
  }
25
27
 
26
28
  /* Button states */
@@ -46,13 +48,13 @@ button,
46
48
  border-color: var(--color-brand-alt);
47
49
  }
48
50
 
49
- &[data-button-variant='text'] {
51
+ &[data-button-variant='ghost'] {
50
52
  color: currentColor;
51
53
  background-color: transparent;
52
54
  border-color: transparent;
53
55
  }
54
56
 
55
- &[data-button-variant='ghost'] {
57
+ &[data-button-variant='outline'] {
56
58
  color: currentColor;
57
59
  background-color: transparent;
58
60
  border-color: currentColor;
@@ -1,10 +1,10 @@
1
- .tabs [role='tablist'] {
1
+ [role='tablist'] {
2
2
  display: flex;
3
3
  isolation: isolate;
4
4
  border: var(--_border);
5
5
  }
6
6
 
7
- .tabs [role='tab'] {
7
+ [role='tab'] {
8
8
  position: relative;
9
9
  border-color: transparent;
10
10
 
@@ -14,12 +14,12 @@
14
14
  }
15
15
  }
16
16
 
17
- .tabs [role='tab'][aria-selected='true'] {
17
+ [role='tab'][aria-selected='true'] {
18
18
  /* Bring selected tab to layer above others to avoid clipping outline styles */
19
19
  z-index: 1;
20
20
  }
21
21
 
22
- .tabs [role='tabpanel'] {
22
+ [role='tabpanel'] {
23
23
  border: var(--_border);
24
24
  border-block-start: unset;
25
25
  padding: var(--_padding);
@@ -18,6 +18,7 @@
18
18
  --color-bg-3: var(--neutral-200);
19
19
  --color-border: var(--neutral-200);
20
20
  --color-brand: var(--blue-700);
21
+ --color-brand-alt: var(--teal-200);
21
22
  --color-disabled-bg: var(--neutral-200);
22
23
  --color-disabled-border: var(--neutral-400);
23
24
  --color-disabled-text: var(--neutral-400);
@@ -32,6 +33,7 @@
32
33
  --color-text-2: var(--neutral-600);
33
34
  --color-text-3: var(--neutral-400);
34
35
  --color-text-accent: var(--teal-000);
36
+ --color-text-inverse: var(--neutral-100);
35
37
  --color-warning-bg: var(--gold-100);
36
38
  --color-warning-border: var(--gold-300);
37
39
  --color-warning-text: var(--gold-800);
@@ -149,6 +151,7 @@
149
151
  --color-bg-3: var(--neutral-200);
150
152
  --color-border: var(--neutral-200);
151
153
  --color-brand: var(--blue-700);
154
+ --color-brand-alt: var(--teal-200);
152
155
  --color-disabled-bg: var(--neutral-200);
153
156
  --color-disabled-border: var(--neutral-400);
154
157
  --color-disabled-text: var(--neutral-400);
@@ -163,6 +166,7 @@
163
166
  --color-text-2: var(--neutral-600);
164
167
  --color-text-3: var(--neutral-400);
165
168
  --color-text-accent: var(--teal-000);
169
+ --color-text-inverse: var(--neutral-100);
166
170
  --color-warning-bg: var(--gold-100);
167
171
  --color-warning-border: var(--gold-300);
168
172
  --color-warning-text: var(--gold-800);
@@ -184,6 +188,7 @@
184
188
  --color-bg-3: var(--neutral-200);
185
189
  --color-border: var(--neutral-200);
186
190
  --color-brand: var(--blue-700);
191
+ --color-brand-alt: var(--teal-200);
187
192
  --color-disabled-bg: var(--neutral-200);
188
193
  --color-disabled-border: var(--neutral-400);
189
194
  --color-disabled-text: var(--neutral-400);
@@ -198,6 +203,7 @@
198
203
  --color-text-2: var(--neutral-600);
199
204
  --color-text-3: var(--neutral-400);
200
205
  --color-text-accent: var(--teal-000);
206
+ --color-text-inverse: var(--neutral-100);
201
207
  --color-warning-bg: var(--gold-100);
202
208
  --color-warning-border: var(--gold-300);
203
209
  --color-warning-text: var(--gold-800);
@@ -219,6 +225,7 @@
219
225
  --color-bg-3: var(--neutral-600);
220
226
  --color-border: var(--neutral-200);
221
227
  --color-brand: var(--teal-200);
228
+ --color-brand-alt: var(--blue-700);
222
229
  --color-disabled-bg: var(--neutral-600);
223
230
  --color-disabled-border: var(--neutral-400);
224
231
  --color-disabled-text: var(--neutral-400);
@@ -233,6 +240,7 @@
233
240
  --color-text-2: var(--neutral-300);
234
241
  --color-text-3: var(--neutral-500);
235
242
  --color-text-accent: var(--teal-600);
243
+ --color-text-inverse: var(--teal-800);
236
244
  --color-warning-bg: var(--gold-200);
237
245
  --color-warning-border: var(--gold-400);
238
246
  --color-warning-text: var(--gold-900);
@@ -254,6 +262,7 @@
254
262
  --color-bg-3: var(--neutral-600);
255
263
  --color-border: var(--neutral-200);
256
264
  --color-brand: var(--teal-200);
265
+ --color-brand-alt: var(--blue-700);
257
266
  --color-disabled-bg: var(--neutral-600);
258
267
  --color-disabled-border: var(--neutral-400);
259
268
  --color-disabled-text: var(--neutral-400);
@@ -268,6 +277,7 @@
268
277
  --color-text-2: var(--neutral-300);
269
278
  --color-text-3: var(--neutral-500);
270
279
  --color-text-accent: var(--teal-600);
280
+ --color-text-inverse: var(--teal-800);
271
281
  --color-warning-bg: var(--gold-200);
272
282
  --color-warning-border: var(--gold-400);
273
283
  --color-warning-text: var(--gold-900);
@@ -1,13 +0,0 @@
1
- export declare class Logger {
2
- private dataLayer;
3
- /**
4
- * @param dl Optional injected dataLayer array. Defaults to window.dataLayer.
5
- */
6
- constructor(dl?: any[]);
7
- /**
8
- * Pushes an event payload into the dataLayer.
9
- * @param eventName e.g. 'searchResultClick'
10
- * @param payload additional key/value data
11
- */
12
- push(eventName: string, payload?: Record<string, any>): void;
13
- }
@@ -1,26 +0,0 @@
1
- export class Logger {
2
- private dataLayer: any[];
3
-
4
- /**
5
- * @param dl Optional injected dataLayer array. Defaults to window.dataLayer.
6
- */
7
- constructor(dl?: any[]) {
8
- // Use injected or global dataLayer
9
- this.dataLayer = Array.isArray(dl) ? dl : (window as any).dataLayer;
10
-
11
- // If for some reason it's not an array, initialize it
12
- if (!Array.isArray(this.dataLayer)) {
13
- (window as any).dataLayer = [];
14
- this.dataLayer = (window as any).dataLayer;
15
- }
16
- }
17
-
18
- /**
19
- * Pushes an event payload into the dataLayer.
20
- * @param eventName e.g. 'searchResultClick'
21
- * @param payload additional key/value data
22
- */
23
- push(eventName: string, payload: Record<string, any> = {}): void {
24
- this.dataLayer.push({ event: eventName, ...payload });
25
- }
26
- }