@netlify/spark-ui 0.0.46-alpha.4 → 0.0.47-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/dist/analytics/analytics.d.ts +1 -1
- package/dist/assets/ChatApp.css +1 -0
- package/dist/chunks/compat.module.BjTzMHXJ.js +296 -0
- package/dist/chunks/hooks.module.DeYLzLnU.js +177 -0
- package/dist/chunks/{useTimeout.DOkYFG64.js → useTimeout.DYuvQwFN.js} +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/preact/ChatApp/ChatApp.d.ts +2 -0
- package/dist/components/preact/ChatApp/ChatApp.js +5346 -0
- package/dist/components/preact/Modal/Modal.js +1 -1
- package/dist/components/preact/SearchModal/components/SearchInput.js +2 -2
- package/dist/components/preact/SearchModal/components/SearchLink/SearchLink.js +1 -1
- package/dist/components/preact/SearchModal/components/SearchModal/SearchModal.js +1 -1
- package/dist/components/preact/SearchModal/components/SearchToggle/SearchToggle.js +1 -1
- package/dist/components/preact/SearchModal/components/SearchWindow.js +1 -1
- package/dist/components/preact/SearchModal/hooks/useKeyboardNav.js +1 -1
- package/dist/components/preact/SearchModal/hooks/useSearch.js +2 -2
- package/dist/components/preact/SearchModal/hooks/useSearchHotkeys.js +1 -1
- package/dist/components/preact/SearchModal/hooks/useSearchLogger.d.ts +4 -4
- package/dist/components/preact/SearchModal/hooks/useSearchLogger.js +18 -18
- package/dist/components/preact/SearchModal/hooks/useSearchParams.js +1 -1
- package/dist/components/preact/SearchModal/hooks/useSearchToggles.js +1 -1
- package/dist/components/preact/SearchModal/types/search.types.d.ts +6 -0
- package/dist/components/preact/index.d.ts +1 -0
- package/dist/components/preact/index.js +7 -5
- package/package.json +4 -1
- package/packages/analytics/GoogleAnalytics.astro +16 -9
- package/packages/analytics/GoogleTagManager.astro +9 -7
- package/packages/analytics/GoogleTagManagerNoscript.astro +12 -9
- package/packages/analytics/analytics.ts +2 -2
- package/packages/components/CodeBlock.astro +208 -0
- package/packages/components/index.ts +1 -0
- package/packages/components/preact/ChatApp/ChatApp.css +142 -0
- package/packages/components/preact/ChatApp/ChatApp.tsx +237 -0
- package/packages/components/preact/SearchModal/hooks/useSearchLogger.ts +15 -18
- package/packages/components/preact/SearchModal/types/search.types.tsx +7 -0
- package/packages/components/preact/index.ts +1 -0
- package/packages/global.d.ts +5 -0
- package/packages/styles/code-block.css +249 -0
- package/dist/chunks/compat.module.DT16W4Wr.js +0 -175
- package/dist/chunks/hooks.module.CNV9mxng.js +0 -138
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { u as l } from "../../../chunks/jsxRuntime.module.Bzuv3cXw.js";
|
|
2
|
-
import { D as d } from "../../../chunks/compat.module.
|
|
2
|
+
import { D as d } from "../../../chunks/compat.module.BjTzMHXJ.js";
|
|
3
3
|
const u = d(function({ children: o, className: r, ...a }, t) {
|
|
4
4
|
return /* @__PURE__ */ l("dialog", { ref: t, className: r, role: "dialog", "aria-modal": "true", ...a, children: o });
|
|
5
5
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { u as e } from "../../../../chunks/jsxRuntime.module.Bzuv3cXw.js";
|
|
2
|
-
import { d as u, y as h } from "../../../../chunks/hooks.module.
|
|
3
|
-
import { u as o } from "../../../../chunks/useTimeout.
|
|
2
|
+
import { d as u, y as h } from "../../../../chunks/hooks.module.DeYLzLnU.js";
|
|
3
|
+
import { u as o } from "../../../../chunks/useTimeout.DYuvQwFN.js";
|
|
4
4
|
import d from "../../Icon/index.js";
|
|
5
5
|
const I = (a) => {
|
|
6
6
|
const [r, t] = u(""), { reset: c, run: i } = o((l) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { u as a } from "../../../../../chunks/jsxRuntime.module.Bzuv3cXw.js";
|
|
2
|
-
import "../../../../../chunks/hooks.module.
|
|
2
|
+
import "../../../../../chunks/hooks.module.DeYLzLnU.js";
|
|
3
3
|
import { useSearchLogger as h } from "../../hooks/useSearchLogger.js";
|
|
4
4
|
import c from "../../../Icon/index.js";
|
|
5
5
|
import '../../../../../assets/SearchLink.css';const k = ({ icon: n, label: s, url: r, excerpt: l, resource: e }) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { u as e } from "../../../../../chunks/jsxRuntime.module.Bzuv3cXw.js";
|
|
2
|
-
import { A as v, y as u, d as S } from "../../../../../chunks/hooks.module.
|
|
2
|
+
import { A as v, y as u, d as S } from "../../../../../chunks/hooks.module.DeYLzLnU.js";
|
|
3
3
|
import L from "../../../Modal/Modal.js";
|
|
4
4
|
import d from "../../../KeyboardKey/KeyboardKey.js";
|
|
5
5
|
import k from "../SearchWindow.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { u as e } from "../../../../../chunks/jsxRuntime.module.Bzuv3cXw.js";
|
|
2
|
-
import { D as t } from "../../../../../chunks/compat.module.
|
|
2
|
+
import { D as t } from "../../../../../chunks/compat.module.BjTzMHXJ.js";
|
|
3
3
|
import o from "../../../Icon/index.js";
|
|
4
4
|
import '../../../../../assets/SearchToggle.css';const s = t(function(r, a) {
|
|
5
5
|
return /* @__PURE__ */ e("button", { id: r.id, ref: a, class: "n-search-toggle", disabled: !0, "data-ntl-search-toggle": !0, children: [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { u as e } from "../../../../chunks/jsxRuntime.module.Bzuv3cXw.js";
|
|
2
|
-
import { T as o } from "../../../../chunks/hooks.module.
|
|
2
|
+
import { T as o } from "../../../../chunks/hooks.module.DeYLzLnU.js";
|
|
3
3
|
import t from "./SearchHeading/SearchHeading.js";
|
|
4
4
|
import a from "./SearchLink/SearchLink.js";
|
|
5
5
|
const h = ({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { d as g, A as w } from "../../../../chunks/hooks.module.
|
|
2
|
-
import { u as S } from "../../../../chunks/useTimeout.
|
|
1
|
+
import { d as g, A as w } from "../../../../chunks/hooks.module.DeYLzLnU.js";
|
|
2
|
+
import { u as S } from "../../../../chunks/useTimeout.DYuvQwFN.js";
|
|
3
3
|
function x() {
|
|
4
4
|
const [l, r] = g({
|
|
5
5
|
searchTerm: "",
|
|
@@ -3,9 +3,9 @@ import { SearchState } from '../types/search.types';
|
|
|
3
3
|
* Custom hook that logs search-related events for analytics.
|
|
4
4
|
*
|
|
5
5
|
* This hook tracks the following search events:
|
|
6
|
-
* - `
|
|
7
|
-
* - `
|
|
8
|
-
* - `
|
|
6
|
+
* - `search:new_query`: Logs when the search query changes.
|
|
7
|
+
* - `search:no_results`: Logs when no results are found for a search.
|
|
8
|
+
* - `search:result_selected`: Logs when a search result is clicked.
|
|
9
9
|
*
|
|
10
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
11
|
*
|
|
@@ -15,7 +15,7 @@ import { SearchState } from '../types/search.types';
|
|
|
15
15
|
* @param {boolean} [debug=false] - Flag to enable debug mode. If true, additional debug information will be sent with the event payloads.
|
|
16
16
|
*
|
|
17
17
|
* @returns {Object} - An object with the following function:
|
|
18
|
-
* - `handleClick`: A callback function that should be attached to search result click events. It tracks `
|
|
18
|
+
* - `handleClick`: A callback function that should be attached to search result click events. It tracks `search:result_selected` events with the clicked result's title and URL.
|
|
19
19
|
*
|
|
20
20
|
* @example
|
|
21
21
|
* const { handleClick } = useSearchLogger(searchState);
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
class
|
|
1
|
+
import { A as y, y as h, q as k } from "../../../../chunks/hooks.module.DeYLzLnU.js";
|
|
2
|
+
class s {
|
|
3
3
|
/**
|
|
4
4
|
* Pushes an event payload into the dataLayer.
|
|
5
|
-
* @param eventName e.g. 'www:
|
|
5
|
+
* @param eventName e.g. 'www:search_new_query'
|
|
6
6
|
* @param payload additional key/value data
|
|
7
7
|
*/
|
|
8
|
-
track(
|
|
9
|
-
typeof gtag == "function" ? gtag("event",
|
|
8
|
+
track(n, i = {}) {
|
|
9
|
+
typeof gtag == "function" ? gtag("event", n, { ...i }) : console.error(`gtag is not defined. Event [${n}] failed.`);
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
-
function
|
|
13
|
-
const
|
|
14
|
-
return
|
|
12
|
+
function p(r, n) {
|
|
13
|
+
const l = y(new s()).current, e = (c) => c.debug_mode = !0;
|
|
14
|
+
return h(() => {
|
|
15
15
|
if (!(r != null && r.searchTerm)) return;
|
|
16
16
|
const c = { query: r == null ? void 0 : r.searchTerm };
|
|
17
|
-
|
|
18
|
-
}, [r == null ? void 0 : r.searchTerm]),
|
|
17
|
+
n && e(c), l.track("search:new_query", c);
|
|
18
|
+
}, [r == null ? void 0 : r.searchTerm]), h(() => {
|
|
19
19
|
if (!(r != null && r.results)) return;
|
|
20
20
|
const c = { query: r == null ? void 0 : r.searchTerm };
|
|
21
|
-
|
|
21
|
+
n && e(c), r != null && r.searchTerm && r.results.length === 0 && l.track("search:no_results", c);
|
|
22
22
|
}, [r == null ? void 0 : r.results]), {
|
|
23
23
|
handleClick: k((c) => {
|
|
24
|
-
var
|
|
25
|
-
const
|
|
26
|
-
if (!
|
|
27
|
-
const
|
|
28
|
-
resultTitle:
|
|
24
|
+
var f;
|
|
25
|
+
const o = c.target.closest("a");
|
|
26
|
+
if (!o) return;
|
|
27
|
+
const g = (f = o.querySelector(".n-search-link-label")) == null ? void 0 : f.innerHTML, d = o.getAttribute("href") || void 0, u = {
|
|
28
|
+
resultTitle: g,
|
|
29
29
|
resultUrl: d
|
|
30
30
|
};
|
|
31
|
-
|
|
31
|
+
n && e(u), l.track("search:result_selected", u);
|
|
32
32
|
}, [])
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
export {
|
|
36
|
-
|
|
36
|
+
p as useSearchLogger
|
|
37
37
|
};
|
|
@@ -4,5 +4,6 @@ export { default as Icon } from './Icon';
|
|
|
4
4
|
export { default as SearchLink } from './SearchModal/components/SearchLink/SearchLink';
|
|
5
5
|
export { default as SearchHeading } from './SearchModal/components/SearchHeading/SearchHeading';
|
|
6
6
|
export { default as SearchToggle } from './SearchModal/components/SearchToggle/SearchToggle';
|
|
7
|
+
export { default as ChatApp } from './ChatApp/ChatApp';
|
|
7
8
|
export { SearchModal } from './SearchModal';
|
|
8
9
|
export { type IconName } from './Icon';
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { default as t } from "./KeyboardKey/KeyboardKey.js";
|
|
2
2
|
import { default as d } from "./Modal/Modal.js";
|
|
3
|
-
import { default as
|
|
3
|
+
import { default as l } from "./Icon/index.js";
|
|
4
4
|
import { default as s } from "./SearchModal/components/SearchLink/SearchLink.js";
|
|
5
5
|
import { default as x } from "./SearchModal/components/SearchHeading/SearchHeading.js";
|
|
6
6
|
import { default as h } from "./SearchModal/components/SearchToggle/SearchToggle.js";
|
|
7
|
+
import { default as S } from "./ChatApp/ChatApp.js";
|
|
7
8
|
import "preact";
|
|
8
|
-
import "../../chunks/hooks.module.
|
|
9
|
-
import { default as
|
|
9
|
+
import "../../chunks/hooks.module.DeYLzLnU.js";
|
|
10
|
+
import { default as n } from "./SearchModal/components/SearchModal/SearchModal.js";
|
|
10
11
|
export {
|
|
11
|
-
|
|
12
|
+
S as ChatApp,
|
|
13
|
+
l as Icon,
|
|
12
14
|
t as KeyboardKey,
|
|
13
15
|
d as Modal,
|
|
14
16
|
x as SearchHeading,
|
|
15
17
|
s as SearchLink,
|
|
16
|
-
|
|
18
|
+
n as SearchModal,
|
|
17
19
|
h as SearchToggle
|
|
18
20
|
};
|
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.
|
|
4
|
+
"version": "0.0.47-alpha",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/components/preact/index.js",
|
|
7
7
|
"types": "dist/components/preact/index.d.ts",
|
|
@@ -32,8 +32,11 @@
|
|
|
32
32
|
"./analytics": "./packages/analytics/index.ts"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
+
"@kapaai/react-sdk": "^0.0.5",
|
|
35
36
|
"@preact/preset-vite": "^2.10.1",
|
|
37
|
+
"@shikijs/transformers": "^3.3.0",
|
|
36
38
|
"glob": "^11.0.1",
|
|
39
|
+
"marked": "^15.0.11",
|
|
37
40
|
"preact": "^10.26.4",
|
|
38
41
|
"vite": "^6.2.5",
|
|
39
42
|
"vite-plugin-dts": "^4.5.3",
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
2
|
+
interface Props {
|
|
3
|
+
gaId: string;
|
|
4
|
+
}
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
const { gaId } = Astro.props as Props;
|
|
5
7
|
---
|
|
6
8
|
<!-- Google tag (gtag.js) -->
|
|
7
|
-
<script async src=`https://www.googletagmanager.com/gtag/js?id=${gaId}`></script>
|
|
8
|
-
<script define:vars={{id: gaId}}>
|
|
9
|
-
window.dataLayer = window.dataLayer || [];
|
|
10
|
-
function gtag(){dataLayer.push(arguments);}
|
|
11
|
-
gtag('js', new Date());
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
{gaId &&
|
|
11
|
+
<>
|
|
12
|
+
<script async src={`https://www.googletagmanager.com/gtag/js?id=${gaId}`}></script>
|
|
13
|
+
<script define:vars={{id: gaId}}>
|
|
14
|
+
window.dataLayer = window.dataLayer || [];
|
|
15
|
+
function gtag(){dataLayer.push(arguments);}
|
|
16
|
+
gtag('js', new Date());
|
|
17
|
+
|
|
18
|
+
gtag('config', id);
|
|
19
|
+
</script>
|
|
20
|
+
</>
|
|
21
|
+
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
2
|
+
interface Props {
|
|
3
|
+
gtmId: string;
|
|
4
|
+
gaId: string;
|
|
5
|
+
}
|
|
3
6
|
|
|
4
|
-
|
|
5
|
-
if (!gaId) console.error ('[GoogleTagManager] no GA id provided')
|
|
7
|
+
const { gtmId, gaId } = Astro.props as Props;
|
|
6
8
|
---
|
|
7
9
|
<!-- Google Tag Manager -->
|
|
8
|
-
<script define:vars={{id: gtmId}}>
|
|
10
|
+
{gtmId && <script define:vars={{id: gtmId}}>
|
|
9
11
|
(function (w, d, s, l, i) {
|
|
10
12
|
w[l] = w[l] || [];
|
|
11
13
|
w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
|
|
@@ -16,14 +18,14 @@ if (!gaId) console.error ('[GoogleTagManager] no GA id provided')
|
|
|
16
18
|
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
|
|
17
19
|
f.parentNode.insertBefore(j, f);
|
|
18
20
|
})(window, document, 'script', 'dataLayer', id);
|
|
19
|
-
</script>
|
|
21
|
+
</script>}
|
|
20
22
|
<!-- End Google Tag Manager -->
|
|
21
23
|
|
|
22
24
|
<!-- Google Analytics (gtag.js) -->
|
|
23
|
-
<script define:vars={{id: gaId}}>
|
|
25
|
+
{gaId && <script define:vars={{id: gaId}}>
|
|
24
26
|
function gtag(){dataLayer.push(arguments);}
|
|
25
27
|
gtag('js', new Date());
|
|
26
28
|
|
|
27
29
|
gtag('config', id);
|
|
28
|
-
</script>
|
|
30
|
+
</script>}
|
|
29
31
|
<!-- End Google Analytics (gtag.js) -->
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
{
|
|
2
|
+
Astro.props.gtmId && (
|
|
3
|
+
<noscript>
|
|
4
|
+
<iframe
|
|
5
|
+
src={`https://www.googletagmanager.com/ns.html?id=${Astro.props.gtmId}`}
|
|
6
|
+
height="0"
|
|
7
|
+
width="0"
|
|
8
|
+
style="display:none;visibility:hidden"
|
|
9
|
+
></iframe>
|
|
10
|
+
</noscript>
|
|
11
|
+
)
|
|
12
|
+
}
|
|
@@ -2,7 +2,7 @@ export default class Analytics {
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Pushes an event payload into the dataLayer.
|
|
5
|
-
* @param eventName e.g. 'www:
|
|
5
|
+
* @param eventName e.g. 'www:search_new_query'
|
|
6
6
|
* @param payload additional key/value data
|
|
7
7
|
*/
|
|
8
8
|
track(eventName: string, payload: Record<string, any> = {}): void {
|
|
@@ -10,7 +10,7 @@ export default class Analytics {
|
|
|
10
10
|
if (typeof gtag === 'function') {
|
|
11
11
|
gtag('event', eventName, { ...payload });
|
|
12
12
|
} else {
|
|
13
|
-
console.error(`gtag is not defined.
|
|
13
|
+
console.error(`gtag is not defined. Event [${eventName}] failed.`);
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { Code } from 'astro:components';
|
|
3
|
+
import '../styles/code-block.css';
|
|
4
|
+
import poimandresTheme from '../../themes/poimandres.json';
|
|
5
|
+
import {
|
|
6
|
+
transformerMetaHighlight,
|
|
7
|
+
transformerNotationDiff,
|
|
8
|
+
transformerNotationFocus,
|
|
9
|
+
} from '@shikijs/transformers';
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
code: string;
|
|
13
|
+
lang?: string;
|
|
14
|
+
highlight?: string;
|
|
15
|
+
del?: string;
|
|
16
|
+
ins?: string;
|
|
17
|
+
frame?: 'code' | 'terminal' | 'none';
|
|
18
|
+
theme?: string;
|
|
19
|
+
wrap?: boolean;
|
|
20
|
+
title?: string;
|
|
21
|
+
class?: string;
|
|
22
|
+
showLineNumbers?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
code,
|
|
27
|
+
lang = '',
|
|
28
|
+
highlight = '',
|
|
29
|
+
del = '',
|
|
30
|
+
ins = '',
|
|
31
|
+
frame = 'none',
|
|
32
|
+
theme = 'poimandres',
|
|
33
|
+
wrap = false,
|
|
34
|
+
title = '',
|
|
35
|
+
class: className,
|
|
36
|
+
showLineNumbers = false,
|
|
37
|
+
...rest
|
|
38
|
+
} = Astro.props;
|
|
39
|
+
|
|
40
|
+
// Process highlighting ranges (e.g. {2-3,6})
|
|
41
|
+
const highlightRanges = highlight
|
|
42
|
+
? highlight
|
|
43
|
+
.replace(/[{}]/g, '')
|
|
44
|
+
.split(',')
|
|
45
|
+
.map((range: string) => {
|
|
46
|
+
if (range.includes('-')) {
|
|
47
|
+
const [start, end] = range.split('-').map(Number);
|
|
48
|
+
return Array.from({ length: end - start + 1 }, (_, i) => start + i);
|
|
49
|
+
}
|
|
50
|
+
return [Number(range)];
|
|
51
|
+
})
|
|
52
|
+
.flat()
|
|
53
|
+
: [];
|
|
54
|
+
|
|
55
|
+
// Process deleted lines
|
|
56
|
+
const delRanges = del
|
|
57
|
+
? del
|
|
58
|
+
.split(',')
|
|
59
|
+
.map((range: string) => {
|
|
60
|
+
if (range.includes('-')) {
|
|
61
|
+
const [start, end] = range.split('-').map(Number);
|
|
62
|
+
return Array.from({ length: end - start + 1 }, (_, i) => start + i);
|
|
63
|
+
}
|
|
64
|
+
return [Number(range)];
|
|
65
|
+
})
|
|
66
|
+
.flat()
|
|
67
|
+
: [];
|
|
68
|
+
|
|
69
|
+
// Process inserted lines
|
|
70
|
+
const insRanges = ins
|
|
71
|
+
? ins
|
|
72
|
+
.split(',')
|
|
73
|
+
.map((range: string) => {
|
|
74
|
+
if (range.includes('-')) {
|
|
75
|
+
const [start, end] = range.split('-').map(Number);
|
|
76
|
+
return Array.from({ length: end - start + 1 }, (_, i) => start + i);
|
|
77
|
+
}
|
|
78
|
+
return [Number(range)];
|
|
79
|
+
})
|
|
80
|
+
.flat()
|
|
81
|
+
: [];
|
|
82
|
+
|
|
83
|
+
// Apply highlighting, deletions, and insertions using Shiki's transformers
|
|
84
|
+
const codeWithMeta = code
|
|
85
|
+
.split('\n')
|
|
86
|
+
.map((line: string, i: number) => {
|
|
87
|
+
const lineNumber = i + 1;
|
|
88
|
+
const meta = [];
|
|
89
|
+
|
|
90
|
+
if (highlightRanges.includes(lineNumber)) {
|
|
91
|
+
meta.push('focus');
|
|
92
|
+
}
|
|
93
|
+
if (delRanges.includes(lineNumber)) {
|
|
94
|
+
meta.push('--');
|
|
95
|
+
}
|
|
96
|
+
if (insRanges.includes(lineNumber)) {
|
|
97
|
+
meta.push('++');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return meta.length > 0 ? `${line} // [!code ${meta.join(' ')}]` : line;
|
|
101
|
+
})
|
|
102
|
+
.join('\n');
|
|
103
|
+
|
|
104
|
+
// Determine which theme to use
|
|
105
|
+
const selectedTheme = theme === 'poimandres' ? poimandresTheme : theme;
|
|
106
|
+
|
|
107
|
+
// Determine if we should show line numbers
|
|
108
|
+
const showNumbers = showLineNumbers && code.split('\n').length > 1;
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
<div
|
|
112
|
+
class:list={[
|
|
113
|
+
'code-block',
|
|
114
|
+
frame === 'terminal' && 'terminal-frame',
|
|
115
|
+
frame === 'code' && 'code-frame',
|
|
116
|
+
frame === 'none' && 'no-frame',
|
|
117
|
+
showNumbers && 'with-line-numbers',
|
|
118
|
+
className,
|
|
119
|
+
]}
|
|
120
|
+
{...rest}
|
|
121
|
+
>
|
|
122
|
+
{
|
|
123
|
+
(title || lang) && frame !== 'none' && frame !== 'terminal' && (
|
|
124
|
+
<div class="code-block-title">
|
|
125
|
+
{lang && <span class="code-language">{lang}</span>}
|
|
126
|
+
{title && <span class="code-title">{title}</span>}
|
|
127
|
+
</div>
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
<div class="code-block-content">
|
|
131
|
+
<Code
|
|
132
|
+
code={codeWithMeta}
|
|
133
|
+
lang={lang}
|
|
134
|
+
theme={selectedTheme}
|
|
135
|
+
wrap={wrap}
|
|
136
|
+
transformers={[
|
|
137
|
+
transformerMetaHighlight(),
|
|
138
|
+
transformerNotationDiff(),
|
|
139
|
+
transformerNotationFocus(),
|
|
140
|
+
]}
|
|
141
|
+
/>
|
|
142
|
+
<button class="copy-button" aria-label="Copy code to clipboard" data-tooltip="Copy">
|
|
143
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="copy-icon">
|
|
144
|
+
<path
|
|
145
|
+
d="M18 3c0-1.657-1.343-3-3-3v0h-12c-1.657 0-3 1.343-3 3v0 12c0 1.657 1.343 3 3 3v0h12c1.657 0 3-1.343 3-3v0zM15 1.5c0.828 0 1.5 0.672 1.5 1.5v0 12c0 0.828-0.672 1.5-1.5 1.5v0h-12c-0.828 0-1.5-0.672-1.5-1.5v0-12c0-0.828 0.672-1.5 1.5-1.5v0zM21 7.5c0.828 0 1.5 0.672 1.5 1.5v0 12c0 0.828-0.672 1.5-1.5 1.5v0h-12c-0.828 0-1.5-0.672-1.5-1.5v0-1.5h-1.5v1.5c0 1.657 1.343 3 3 3v0h12c1.657 0 3-1.343 3-3v0-12c0-1.657-1.343-3-3-3v0h-1.5v1.5z"
|
|
146
|
+
></path>
|
|
147
|
+
</svg>
|
|
148
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="check-icon">
|
|
149
|
+
<path
|
|
150
|
+
d="M22.942 6.582l-13.778 13.778c-0.156 0.156-0.371 0.253-0.609 0.253s-0.453-0.097-0.609-0.253v0l-6.028-6.028c-0.156-0.156-0.252-0.371-0.252-0.609 0-0.476 0.386-0.862 0.862-0.862 0.238 0 0.453 0.096 0.609 0.252v0l5.418 5.42 13.168-13.169c0.156-0.156 0.371-0.252 0.609-0.252 0.476 0 0.862 0.386 0.862 0.862 0 0.238-0.096 0.453-0.252 0.609v0z"
|
|
151
|
+
></path>
|
|
152
|
+
</svg>
|
|
153
|
+
</button>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
<script>
|
|
158
|
+
document.addEventListener('astro:page-load', () => {
|
|
159
|
+
setupCopyBtn();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Also initialize immediately in case the page is not using transitions
|
|
163
|
+
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
|
164
|
+
setupCopyBtn();
|
|
165
|
+
} else {
|
|
166
|
+
document.addEventListener('DOMContentLoaded', setupCopyBtn);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function setupCopyBtn() {
|
|
170
|
+
const copyButtons = document.querySelectorAll(
|
|
171
|
+
'.code-block .copy-button'
|
|
172
|
+
) as NodeListOf<HTMLButtonElement>;
|
|
173
|
+
copyButtons.forEach(button => {
|
|
174
|
+
button.addEventListener('click', async () => {
|
|
175
|
+
const codeBlock = button.closest('.code-block');
|
|
176
|
+
if (!codeBlock) return;
|
|
177
|
+
|
|
178
|
+
const pre = codeBlock.querySelector('pre');
|
|
179
|
+
if (!pre) return;
|
|
180
|
+
|
|
181
|
+
// Get the text content, remove the Shiki annotations if present
|
|
182
|
+
const rawText = pre.textContent || '';
|
|
183
|
+
const code = rawText.replace(/\/\/\s*\[!.*?\]/g, '').trim();
|
|
184
|
+
|
|
185
|
+
// Copy to clipboard
|
|
186
|
+
try {
|
|
187
|
+
await navigator.clipboard.writeText(code);
|
|
188
|
+
button.classList.add('copied');
|
|
189
|
+
button.setAttribute('data-tooltip', 'Copied!');
|
|
190
|
+
setTimeout(() => {
|
|
191
|
+
button.classList.remove('copied');
|
|
192
|
+
button.setAttribute('data-tooltip', 'Copy');
|
|
193
|
+
button.blur();
|
|
194
|
+
}, 2000);
|
|
195
|
+
} catch (error) {
|
|
196
|
+
console.error('Failed to copy code: ', error);
|
|
197
|
+
button.classList.add('error');
|
|
198
|
+
button.setAttribute('data-tooltip', 'Failed to copy!');
|
|
199
|
+
setTimeout(() => {
|
|
200
|
+
button.classList.remove('error');
|
|
201
|
+
button.setAttribute('data-tooltip', 'Copy');
|
|
202
|
+
button.blur();
|
|
203
|
+
}, 2000);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
</script>
|
|
@@ -6,6 +6,7 @@ export { default as SearchLink } from './preact/SearchModal/components/SearchLin
|
|
|
6
6
|
export { default as SearchHeading } from './preact/SearchModal/components/SearchHeading/SearchHeading';
|
|
7
7
|
export { default as SearchToggle } from './preact/SearchModal/components/SearchToggle/SearchToggle';
|
|
8
8
|
export { default as SearchModal } from './preact/SearchModal/components/SearchModal/SearchModal';
|
|
9
|
+
export { default as ChatApp } from './preact/ChatApp/ChatApp';
|
|
9
10
|
export { type IconName } from './preact/Icon';
|
|
10
11
|
|
|
11
12
|
// Astro components
|