Skip to content

Commit 88f5029

Browse files
Merge branch 'main' into worktree-fix-copy-icon-hover
2 parents 60f7603 + a46b069 commit 88f5029

File tree

13 files changed

+437
-108
lines changed

13 files changed

+437
-108
lines changed

_components/CopyPage.tsx

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
export default function CopyPage({ file }: { file: string | undefined }) {
2+
if (!file || file.includes("[")) return null;
3+
4+
const markdownUrl = `https://docs.deno.com${file}`;
5+
const claudeUrl = `https://claude.ai/new?q=${
6+
encodeURIComponent(
7+
`Read this page from the Deno docs: ${markdownUrl} and answer questions about the content.`,
8+
)
9+
}`;
10+
11+
return (
12+
<div class="copy-page-split inline-flex shrink-0 rounded-full border-2 border-foreground-primary dark:border-background-tertiary">
13+
{/* Primary: directly copies the URL */}
14+
<button
15+
type="button"
16+
class="copy-page-main-btn flex items-center gap-2 px-4 py-2 text-sm font-semibold text-foreground-primary bg-transparent hover:bg-header-highlight dark:hover:text-background-primary rounded-l-full transition-colors cursor-pointer select-none"
17+
>
18+
<svg
19+
xmlns="http://www.w3.org/2000/svg"
20+
aria-hidden="true"
21+
fill="currentColor"
22+
width="12"
23+
height="12"
24+
viewBox="0 0 16 16"
25+
>
26+
<path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z" />
27+
<path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z" />
28+
</svg>
29+
<span class="copy-page-main-label">Copy page</span>
30+
</button>
31+
32+
{/* Visual divider between the two halves */}
33+
<span
34+
class="self-stretch w-0.5 bg-foreground-primary dark:bg-background-tertiary shrink-0"
35+
aria-hidden="true"
36+
>
37+
</span>
38+
39+
{/* Chevron: opens the popover panel */}
40+
<button
41+
type="button"
42+
class="copy-page-toggle-btn flex items-center px-3 py-2 text-foreground-primary bg-transparent hover:bg-header-highlight dark:hover:text-background-primary rounded-r-full transition-colors cursor-pointer select-none"
43+
popovertarget="copy-page-menu"
44+
aria-label="More copy options"
45+
aria-haspopup="menu"
46+
>
47+
<svg
48+
class="copy-page-chevron transition-transform duration-200"
49+
xmlns="http://www.w3.org/2000/svg"
50+
aria-hidden="true"
51+
fill="currentColor"
52+
width="12"
53+
height="12"
54+
viewBox="0 0 16 16"
55+
>
56+
<path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z" />
57+
</svg>
58+
</button>
59+
60+
{/* Popover panel — lives in top layer, positioned via JS */}
61+
<div id="copy-page-menu" popover="auto" class="copy-page-panel">
62+
<a
63+
href={file}
64+
target="_blank"
65+
class="no-underline flex items-start gap-3 px-4 py-3 hover:bg-background-secondary dark:hover:bg-gray-800 transition-colors"
66+
>
67+
<svg
68+
xmlns="http://www.w3.org/2000/svg"
69+
aria-hidden="true"
70+
fill="currentColor"
71+
width="16"
72+
height="16"
73+
viewBox="0 0 16 16"
74+
class="mt-0.5 shrink-0"
75+
>
76+
<path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z" />
77+
</svg>
78+
<span>
79+
<span class="block text-sm font-medium">View Page as Markdown</span>
80+
<span class="block text-xs text-foreground-secondary mt-0.5">
81+
Open the Markdown file in a new tab
82+
</span>
83+
</span>
84+
</a>
85+
<a
86+
href={claudeUrl}
87+
target="_blank"
88+
class="no-underline flex items-start gap-3 px-4 py-3 border-t border-foreground-tertiary hover:bg-background-secondary dark:hover:bg-gray-800 transition-colors"
89+
>
90+
<svg
91+
xmlns="http://www.w3.org/2000/svg"
92+
aria-hidden="true"
93+
fill="currentColor"
94+
width="16"
95+
height="16"
96+
viewBox="0 0 24 24"
97+
class="mt-0.5 shrink-0"
98+
>
99+
<path d="M12 0C12 0 10.5 10.5 0 12C10.5 12 12 24 12 24C12 24 13.5 13.5 24 12C13.5 12 12 0 12 0Z" />
100+
</svg>
101+
<span>
102+
<span class="block text-sm font-medium">Open in Claude</span>
103+
<span class="block text-xs text-foreground-secondary mt-0.5">
104+
Ask Claude about this page
105+
</span>
106+
</span>
107+
</a>
108+
</div>
109+
</div>
110+
);
111+
}

_components/TableOfContents.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default function TableOfContents({ data, toc, hasSubNav }: {
1212

1313
return (
1414
<ul
15-
className={`toc-list hidden sticky p-4 pr-0 h-screen-minus-header overflow-y-auto border-l border-l-foreground-tertiary lg:block lg:w-full ${topClasses}`}
15+
className={`toc-list hidden sticky ${topClasses} h-screen-minus-header overflow-y-auto border-l border-l-foreground-tertiary p-4 pr-0 lg:flex lg:flex-col lg:w-full`}
1616
id="toc"
1717
>
1818
{toc.map((item: TableOfContentsItem_) => (

_config.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,24 @@ site.addEventListener("afterBuild", async () => {
190190
/* NOTE: we used to get gfm.css from the jsr.io CDN, but now we simply have a local copy. This is because it needs to be placed on a CSS layer, which isn't possible with an imported file. */
191191
// Deno.writeTextFileSync(site.dest("gfm.css"), GFM_CSS);
192192

193+
// Copy lint rule markdown source files to _site so they're served at /lint/rules/*.md.
194+
// These files are excluded from Lume's processing pipeline (site.ignore) because
195+
// lint_rule.page.tsx handles page generation, but we still want the raw .md accessible.
196+
try {
197+
await Deno.mkdir(site.dest("lint/rules"), { recursive: true });
198+
for await (const entry of Deno.readDir("lint/rules")) {
199+
if (entry.isFile && entry.name.endsWith(".md")) {
200+
await Deno.copyFile(
201+
`lint/rules/${entry.name}`,
202+
site.dest(`lint/rules/${entry.name}`),
203+
);
204+
}
205+
}
206+
log.info("Copied lint rule markdown files to _site/lint/rules/");
207+
} catch (error) {
208+
log.error("Error copying lint rule markdown files: " + error);
209+
}
210+
193211
// Generate LLMs documentation files directly to _site directory
194212
if (Deno.env.get("BUILD_TYPE") == "FULL") {
195213
try {

_includes/doc.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,17 @@ export default function Doc(data: Lume.Data, helpers: Lume.Helpers) {
6969
class="markdown-body mt-6 sm:mt-6"
7070
>
7171
{!(isReference && !isApiLandingPage) && (
72-
<h1
73-
dangerouslySetInnerHTML={{
74-
__html: helpers.md(data.title!, true),
75-
}}
76-
>
77-
</h1>
72+
<header class="flex items-start justify-between gap-4">
73+
<h1
74+
dangerouslySetInnerHTML={{
75+
__html: helpers.md(data.title!, true),
76+
}}
77+
>
78+
</h1>
79+
{file && !file.includes("[") && file.endsWith(".md") && (
80+
<data.comp.CopyPage file={file} />
81+
)}
82+
</header>
7883
)}
7984
{data.available_since && (
8085
<div class="bg-gray-200 rounded-md text-sm py-3 px-4 mb-4 font-semibold">

_includes/layout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export default function Layout(data: Lume.Data) {
7777
<script type="module" defer src="/js/copy.js"></script>
7878
<script type="module" defer src="/js/tabs.js"></script>
7979
<script type="module" defer src="/js/feedback.js"></script>
80+
<script type="module" defer src="/js/copy-page.js"></script>
8081
<script type="module" defer src="/js/search.js"></script>
8182
<script
8283
async

js/copy-page.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Primary "Copy page" button — directly copies URL
2+
document.querySelectorAll<HTMLButtonElement>(".copy-page-main-btn").forEach(
3+
(btn) => {
4+
btn.addEventListener("click", () => {
5+
navigator?.clipboard?.writeText(window.location.href).then(() => {
6+
const label = btn.querySelector<HTMLElement>(".copy-page-main-label");
7+
if (label) {
8+
const original = label.textContent;
9+
label.textContent = "Copied!";
10+
setTimeout(() => {
11+
label.textContent = original;
12+
}, 2000);
13+
}
14+
}).catch(() => {
15+
const label = btn.querySelector<HTMLElement>(".copy-page-main-label");
16+
if (label) {
17+
const original = label.textContent;
18+
label.textContent = "Copy failed";
19+
setTimeout(() => {
20+
label.textContent = original;
21+
}, 2000);
22+
}
23+
});
24+
});
25+
},
26+
);
27+
28+
// Popover panel — position below the chevron button + rotate chevron
29+
const panel = document.getElementById("copy-page-menu") as HTMLElement | null;
30+
const toggleBtn = document.querySelector<HTMLButtonElement>(
31+
".copy-page-toggle-btn",
32+
);
33+
34+
panel?.addEventListener("toggle", (event) => {
35+
const e = event as ToggleEvent;
36+
const chevron = toggleBtn?.querySelector<SVGElement>(".copy-page-chevron");
37+
38+
if (e.newState === "open" && toggleBtn) {
39+
const rect = toggleBtn.getBoundingClientRect();
40+
panel.style.top = `${rect.bottom + 4}px`;
41+
panel.style.right = `${window.innerWidth - rect.right}px`;
42+
}
43+
if (chevron) {
44+
chevron.style.transform = e.newState === "open" ? "rotate(180deg)" : "";
45+
}
46+
});

replacements.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"CLI_VERSION": "2.7.1"
2+
"CLI_VERSION": "2.7.4"
33
}

runtime/fundamentals/modules.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,45 @@ When using a `package.json` file, dev dependencies can be added to the separate
563563
}
564564
```
565565

566+
### JSR packages in package.json
567+
568+
You can depend on JSR packages directly from `package.json` using the `jsr:`
569+
scheme, without needing a separate `deno.json`:
570+
571+
```json title="package.json"
572+
{
573+
"dependencies": {
574+
"@std/path": "jsr:^1.0.9"
575+
}
576+
}
577+
```
578+
579+
This works with `deno install` and brings JSR packages to any project that uses
580+
`package.json` for dependency management.
581+
582+
### Dependency overrides
583+
584+
The `overrides` field in `package.json` lets you control transitive dependency
585+
versions throughout your dependency tree. This is useful for applying security
586+
patches, fixing version compatibility issues, or replacing packages:
587+
588+
```json title="package.json"
589+
{
590+
"dependencies": {
591+
"express": "^4.18.0"
592+
},
593+
"overrides": {
594+
"cookie": "0.7.0",
595+
"express": {
596+
"qs": "6.13.0"
597+
}
598+
}
599+
}
600+
```
601+
602+
In this example, `cookie` is pinned globally to `0.7.0`, while `qs` is
603+
overridden only when required by `express`.
604+
566605
### Why does Deno not have a `devImports` field?
567606

568607
To understand why Deno does not separate out dev dependencies in the package

runtime/getting_started/installation.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ oldUrl:
99

1010
Deno works on macOS, Linux, and Windows. Deno is a single binary executable. It
1111
has no external dependencies. On macOS, both M1 (arm64) and Intel (x64)
12-
executables are provided. On Linux and Windows, only x64 is supported.
12+
executables are provided. On Windows, both ARM64 and x64 are supported. On
13+
Linux, only x64 is supported.
1314

1415
## Download and install
1516

0 commit comments

Comments
 (0)