Skip to content

Commit 9030add

Browse files
authored
feat: copy button on hover for all pages (#4)
1 parent 2f7cdb6 commit 9030add

File tree

2 files changed

+51
-17
lines changed

2 files changed

+51
-17
lines changed

app/globals.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ pre {
9494
align-items: center;
9595
justify-content: center;
9696
border-radius: 4px;
97+
opacity: 0;
98+
transition: opacity 0.15s;
99+
}
100+
101+
.codeblock:hover button {
102+
opacity: 1;
97103
}
98104

99105
.codeblock button:hover {

lib/html.ts

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ interface PageConfig {
1313

1414
const github = `<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>`;
1515

16+
const copyIcon = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>`;
17+
18+
const checkIcon = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg>`;
19+
1620
const styles = `
1721
* { margin: 0; padding: 0; box-sizing: border-box; }
1822
body {
@@ -31,7 +35,11 @@ h1 code { color: #e5e5e5; }
3135
section { margin-bottom: 2.5rem; }
3236
.label { font-size: 13px; color: #666; margin-bottom: 0.75rem; }
3337
.label span { color: #888; }
34-
pre { background: #111; padding: 0.75rem; border-radius: 6px; font-size: 11px; line-height: 1.6; overflow: auto; border: 1px solid #222; color: #888; }
38+
.codeblock { position: relative; }
39+
.codeblock pre { background: #111; padding: 0.75rem; border-radius: 6px; font-size: 11px; line-height: 1.6; overflow: auto; border: 1px solid #222; color: #888; margin: 0; }
40+
.codeblock button { position: absolute; top: 0.5rem; right: 0.5rem; background: transparent; border: none; color: #444; cursor: pointer; padding: 0.25rem; display: flex; align-items: center; justify-content: center; border-radius: 4px; opacity: 0; transition: opacity 0.15s; }
41+
.codeblock:hover button { opacity: 1; }
42+
.codeblock button:hover { color: #888; background: #1a1a1a; }
3543
.tools { display: flex; flex-direction: column; gap: 0.5rem; padding-left: 1rem; }
3644
.tool { display: flex; align-items: center; gap: 0.75rem; font-size: 11px; }
3745
.tool code { color: #999; }
@@ -42,6 +50,19 @@ footer a { color: #444; font-size: 11px; text-decoration: none; display: inline-
4250
footer a:hover { color: #666; }
4351
`;
4452

53+
const script = `
54+
function copy(btn) {
55+
const pre = btn.parentElement.querySelector('pre');
56+
navigator.clipboard.writeText(pre.textContent);
57+
btn.innerHTML = '${checkIcon.replace(/'/g, "\\'")}';
58+
setTimeout(() => btn.innerHTML = '${copyIcon.replace(/'/g, "\\'")}', 1500);
59+
}
60+
`;
61+
62+
function codeblock(content: string): string {
63+
return `<div class="codeblock"><pre>${content}</pre><button type="button" onclick="copy(this)" aria-label="copy to clipboard">${copyIcon}</button></div>`;
64+
}
65+
4566
export function mcppage(config: PageConfig): string {
4667
const breadcrumb = config.path.split("/").filter(Boolean);
4768
const breadcrumbHtml = breadcrumb
@@ -67,6 +88,25 @@ export function mcppage(config: PageConfig): string {
6788
const server = config.path.split("/")[1];
6889
const ogUrl = `https://kernelize.dev/og?server=${server}`;
6990

91+
const cursorConfig = `{
92+
"mcpServers": {
93+
"${config.name}": {
94+
"url": "https://kernelize.dev${config.path}"
95+
}
96+
}
97+
}`;
98+
99+
const claudeCommand = `claude mcp add --transport http ${config.name} https://kernelize.dev${config.path}`;
100+
101+
const opencodeConfig = `{
102+
"mcpServers": {
103+
"${config.name}": {
104+
"type": "sse",
105+
"url": "https://kernelize.dev${config.path}"
106+
}
107+
}
108+
}`;
109+
70110
return `<!DOCTYPE html>
71111
<html lang="en">
72112
<head>
@@ -93,30 +133,17 @@ export function mcppage(config: PageConfig): string {
93133
94134
<section>
95135
<p class="label"><span>&gt;</span> cursor?</p>
96-
<pre>{
97-
"mcpServers": {
98-
"${config.name}": {
99-
"url": "https://kernelize.dev${config.path}"
100-
}
101-
}
102-
}</pre>
136+
${codeblock(cursorConfig)}
103137
</section>
104138
105139
<section>
106140
<p class="label"><span>&gt;</span> claude code?</p>
107-
<pre>claude mcp add --transport http ${config.name} https://kernelize.dev${config.path}</pre>
141+
${codeblock(claudeCommand)}
108142
</section>
109143
110144
<section>
111145
<p class="label"><span>&gt;</span> opencode?</p>
112-
<pre>{
113-
"mcpServers": {
114-
"${config.name}": {
115-
"type": "sse",
116-
"url": "https://kernelize.dev${config.path}"
117-
}
118-
}
119-
}</pre>
146+
${codeblock(opencodeConfig)}
120147
</section>
121148
122149
<section>
@@ -147,6 +174,7 @@ export function mcppage(config: PageConfig): string {
147174
</a>
148175
</footer>
149176
</div>
177+
<script>${script}</script>
150178
</body>
151179
</html>`;
152180
}

0 commit comments

Comments
 (0)