Skip to content

Commit 637ebfe

Browse files
authored
Merge pull request #60 from nucliweb/feat/external-snippets
Extract snippets to external JS files
2 parents 88ff5c8 + bde35ba commit 637ebfe

94 files changed

Lines changed: 11786 additions & 11286 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

components/Snippet.jsx

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { useState, useMemo } from "react";
2+
import hljs from "highlight.js/lib/core";
3+
import javascript from "highlight.js/lib/languages/javascript";
4+
5+
hljs.registerLanguage("javascript", javascript);
6+
7+
export function Snippet({ code }) {
8+
const [copied, setCopied] = useState(false);
9+
const [hovered, setHovered] = useState(false);
10+
11+
const highlighted = useMemo(() => hljs.highlight(code, { language: "javascript" }).value, [code]);
12+
13+
async function handleCopy() {
14+
try {
15+
await navigator.clipboard.writeText(code);
16+
} catch {
17+
const el = document.createElement("textarea");
18+
el.value = code;
19+
el.style.cssText = "position:fixed;top:0;left:0;opacity:0";
20+
document.body.appendChild(el);
21+
el.select();
22+
document.execCommand("copy");
23+
document.body.removeChild(el);
24+
}
25+
setCopied(true);
26+
setTimeout(() => setCopied(false), 2000);
27+
}
28+
29+
return (
30+
<div
31+
className="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"
32+
onMouseEnter={() => setHovered(true)}
33+
onMouseLeave={() => setHovered(false)}
34+
>
35+
<pre
36+
data-language="js"
37+
data-theme="default"
38+
className="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[13px] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40"
39+
>
40+
<code
41+
data-language="js"
42+
data-theme="default"
43+
className="hljs nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border dark:nx-border-white/10 dark:nx-bg-white/10 nx-py-4 nx-px-4"
44+
dangerouslySetInnerHTML={{ __html: highlighted }}
45+
/>
46+
</pre>
47+
<div
48+
className="nx-transition nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"
49+
style={{ opacity: hovered || copied ? 1 : 0 }}
50+
>
51+
<button
52+
onClick={handleCopy}
53+
aria-label="Copy code"
54+
className="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-gray-100/5 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50"
55+
>
56+
{copied ? (
57+
<svg
58+
width="16"
59+
height="16"
60+
viewBox="0 0 24 24"
61+
fill="none"
62+
stroke="currentColor"
63+
strokeWidth="2"
64+
>
65+
<polyline points="20 6 9 17 4 12" />
66+
</svg>
67+
) : (
68+
<svg
69+
width="16"
70+
height="16"
71+
viewBox="0 0 24 24"
72+
fill="none"
73+
stroke="currentColor"
74+
strokeWidth="2"
75+
>
76+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
77+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
78+
</svg>
79+
)}
80+
</button>
81+
</div>
82+
</div>
83+
);
84+
}

next.config.js

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,36 @@
1-
const withNextra = require("nextra")({
2-
theme: "nextra-theme-docs",
3-
themeConfig: "./theme.config.jsx",
4-
});
1+
const path = require('path')
2+
const withNextra = require('nextra')({
3+
theme: 'nextra-theme-docs',
4+
themeConfig: './theme.config.jsx'
5+
})
56

67
module.exports = withNextra({
8+
webpack(config) {
9+
const snippetsDir = path.join(__dirname, 'snippets')
10+
11+
// Exclude snippets from pre-loaders (React Fast Refresh, etc.)
12+
for (const rule of config.module.rules) {
13+
if (rule.enforce === 'pre') {
14+
rule.exclude = [].concat(rule.exclude || [], snippetsDir)
15+
}
16+
}
17+
18+
// Inject into oneOf so our rule takes precedence over the SWC loader
19+
const rawRule = {
20+
test: /\.js$/,
21+
include: snippetsDir,
22+
resourceQuery: /raw/,
23+
type: 'asset/source',
24+
}
25+
const oneOfRule = config.module.rules.find(r => Array.isArray(r.oneOf))
26+
if (oneOfRule) {
27+
oneOfRule.oneOf.unshift(rawRule)
28+
} else {
29+
config.module.rules.unshift(rawRule)
30+
}
31+
32+
return config
33+
},
734
async redirects() {
835
return [
936
{

pages/CoreWebVitals/CLS.mdx

Lines changed: 4 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import snippet from '../../snippets/CoreWebVitals/CLS.js?raw'
2+
import { Snippet } from '../../components/Snippet'
3+
14
# Cumulative Layout Shift (CLS)
25

36
### Overview
@@ -20,64 +23,7 @@ Unexpected layout shifts are frustrating and can cause users to click the wrong
2023
2124
### Snippet
2225

23-
```js copy
24-
// CLS Quick Check
25-
// https://webperf-snippets.nucliweb.net
26-
27-
(() => {
28-
let cls = 0;
29-
30-
const valueToRating = (score) =>
31-
score <= 0.1 ? "good" : score <= 0.25 ? "needs-improvement" : "poor";
32-
33-
const RATING = {
34-
good: { icon: "🟢", color: "#0CCE6A" },
35-
"needs-improvement": { icon: "🟡", color: "#FFA400" },
36-
poor: { icon: "🔴", color: "#FF4E42" },
37-
};
38-
39-
const logCLS = () => {
40-
const rating = valueToRating(cls);
41-
const { icon, color } = RATING[rating];
42-
console.log(
43-
`%cCLS: ${icon} ${cls.toFixed(4)} (${rating})`,
44-
`color: ${color}; font-weight: bold; font-size: 14px;`
45-
);
46-
};
47-
48-
const observer = new PerformanceObserver((list) => {
49-
for (const entry of list.getEntries()) {
50-
if (!entry.hadRecentInput) {
51-
cls += entry.value;
52-
}
53-
}
54-
logCLS();
55-
});
56-
57-
observer.observe({ type: "layout-shift", buffered: true });
58-
59-
// Update on visibility change (final CLS)
60-
document.addEventListener("visibilitychange", () => {
61-
if (document.visibilityState === "hidden") {
62-
observer.takeRecords();
63-
console.log("%c📊 Final CLS (on page hide):", "font-weight: bold;");
64-
logCLS();
65-
}
66-
});
67-
68-
// Expose function for manual check
69-
window.getCLS = () => {
70-
logCLS();
71-
return cls;
72-
};
73-
74-
console.log(
75-
" Call %cgetCLS()%c anytime to check current value.",
76-
"font-family: monospace; background: #f3f4f6; padding: 2px 4px;",
77-
""
78-
);
79-
})();
80-
```
26+
<Snippet code={snippet} />
8127

8228
### Understanding CLS
8329

0 commit comments

Comments
 (0)