Skip to content

Commit 3a7d5ba

Browse files
committed
docs(site): add \"Edit this page\" link and restyle the TOC like docs.docker.com
The right-column aside on every content page now mirrors docs.docker.com (e.g. https://docs.docker.com/get-started/introduction/develop-with-containers/): \u2022 \"Edit this page\" link with a pencil icon at the top, pointing at GitHub's web editor for the source file. The exact URL is resolved at build time via a new <meta name=\"docs-edit-url\"> tag set in default.html using {{ page.path }}. \u2022 \"Table of contents\" heading at text-lg / weight 500 (was a tiny uppercase \"On this page\" eyebrow). \u2022 TOC links bumped to .875rem (\u224814px) and re-colored to the same \"#566581\" (gray-600) light / \"#E7EAEF\" (gray-100) dark that docs.docker.com uses, with hover/active picking up font-weight 500 + a 2px gray-300 left border on the active entry.\n \u2022 The aside is widened from 220 \u2192 260 px so longer headings stop\n being clipped.\n\nbuildTOC() in js/app.js was updated to render the edit link\nunconditionally (even on short pages with no TOC entries) and to\nrender the TOC body whenever the page has \u22652 sub-headings (was 3).\nScroll-spy and smooth-scroll behavior unchanged.
1 parent 937dd3a commit 3a7d5ba

3 files changed

Lines changed: 125 additions & 39 deletions

File tree

docs/_layouts/default.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66
<title>{% if page.title and page.url != '/' %}{{ page.title }} – Docker Agent Docs{% else %}Docker Agent — Run AI agents from YAML, like containers{% endif %}</title>
77
<meta name="description" content="{{ page.description | default: site.description }}">
88

9+
{% comment %}
10+
Source path of the current page on disk, used by the right-column
11+
\"Edit this page\" link in js/app.js. We point at GitHub's web editor
12+
on the configured repo + branch.
13+
{% endcomment %}
14+
<meta name="docs-edit-url" content="https://github.com/docker/docker-agent/edit/main/docs/{{ page.path | replace_first: 'docs/', '' | default: 'index.md' }}">
15+
916
<meta property="og:title" content="{% if page.title and page.url != '/' %}{{ page.title }} – Docker Agent Docs{% else %}Docker Agent — Run AI agents from YAML, like containers{% endif %}">
1017
<meta property="og:description" content="{{ page.description | default: site.description }}">
1118
<meta property="og:type" content="{% if page.url == '/' %}website{% else %}article{% endif %}">

docs/css/style.css

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292

9393
--sidebar-width: 260px;
9494
--header-height: 56px;
95-
--toc-width: 220px;
95+
--toc-width: 260px;
9696

9797
--font-sans: 'Roboto Flex', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
9898
--font-mono: 'Roboto Mono', ui-monospace, 'SF Mono', Menlo, Monaco, Consolas, monospace;
@@ -386,63 +386,116 @@ body {
386386
scroll-margin-top: calc(var(--header-height) + 16px);
387387
}
388388

389-
/* ===== Table of Contents (right sidebar) ===== */
389+
/* ===== Table of Contents (right sidebar) =====
390+
* Layout, font sizes and colors mirror docs.docker.com's right-column
391+
* \"Edit this page\" + \"Table of contents\" pattern. */
390392
.toc-aside {
391393
position: fixed;
392394
top: var(--header-height);
393395
right: 0;
394396
width: var(--toc-width);
395397
height: calc(100vh - var(--header-height));
396-
padding: 32px 16px 32px 0;
398+
padding: 24px 24px 32px 16px;
397399
overflow-y: auto;
398400
scrollbar-width: thin;
399401
scrollbar-color: var(--border) transparent;
402+
font-size: 0.875rem; /* docs.docker.com .prose-sm */
403+
line-height: 1.71;
400404
}
401405

402406
.toc-inner {
403-
border-left: 1px solid var(--border);
404-
padding-left: 16px;
407+
display: flex;
408+
flex-direction: column;
409+
gap: 8px;
405410
}
406411

407-
.toc-title {
408-
font-size: 0.65rem;
409-
font-weight: 700;
410-
text-transform: uppercase;
411-
letter-spacing: 0.1em;
412-
color: var(--text-muted);
413-
margin-bottom: 12px;
412+
/* Edit-this-page action row */
413+
.toc-actions {
414+
display: flex;
415+
flex-direction: column;
416+
gap: 4px;
417+
margin-bottom: 8px;
418+
}
419+
.toc-action {
420+
display: inline-flex;
421+
align-items: center;
422+
gap: 8px;
423+
color: var(--gray-600);
424+
text-decoration: none;
425+
font-weight: 400;
426+
padding: 4px 0;
427+
transition: color 0.12s;
428+
}
429+
[data-theme="dark"] .toc-action,
430+
:root:not([data-theme="light"]) .toc-action {
431+
color: var(--gray-100);
432+
}
433+
.toc-action:hover {
434+
color: var(--text);
435+
text-decoration: none;
436+
}
437+
.toc-action svg {
438+
width: 16px;
439+
height: 16px;
440+
flex-shrink: 0;
441+
opacity: 0.85;
442+
}
443+
444+
.toc-heading {
445+
font-size: 1.05rem; /* docs.docker.com text-lg */
446+
font-weight: 500;
447+
color: var(--text);
448+
margin-top: 8px;
449+
margin-bottom: 4px;
450+
letter-spacing: -0.005em;
414451
}
415452

416453
.toc-nav {
417454
display: flex;
418455
flex-direction: column;
456+
border-left: 1px solid var(--border);
457+
padding-left: 0;
419458
}
420459

421460
.toc-link {
422-
font-size: 0.78rem;
423-
color: var(--text-muted);
424-
text-decoration: none;
425-
padding: 3px 0;
426-
line-height: 1.4;
427-
transition: color 0.12s;
461+
display: block;
462+
padding: 6px 0 6px 12px;
463+
margin-left: -1px; /* sit on top of .toc-nav border */
428464
border-left: 2px solid transparent;
429-
margin-left: -17px;
430-
padding-left: 15px;
465+
color: var(--gray-600);
466+
text-decoration: none;
467+
font-size: 0.875rem;
468+
font-weight: 400;
469+
line-height: 1.5;
470+
transition: color 0.12s, border-color 0.12s, font-weight 0.12s;
471+
text-overflow: ellipsis;
472+
white-space: nowrap;
473+
overflow: hidden;
474+
}
475+
[data-theme="dark"] .toc-link,
476+
:root:not([data-theme="light"]) .toc-link {
477+
color: var(--gray-100);
431478
}
432479
.toc-link:hover {
433480
color: var(--text);
481+
font-weight: 500;
482+
text-decoration: none;
434483
}
435484
.toc-link:focus-visible {
436485
outline: 2px solid var(--accent);
437486
outline-offset: 2px;
438487
}
439488
.toc-link.active {
440-
color: var(--accent);
441-
border-left-color: var(--accent);
489+
color: var(--text);
490+
font-weight: 500;
491+
border-left-color: var(--gray-300);
492+
}
493+
[data-theme="dark"] .toc-link.active,
494+
:root:not([data-theme="light"]) .toc-link.active {
495+
border-left-color: var(--gray-300);
442496
}
443497
.toc-link.toc-h3 {
444-
padding-left: 27px;
445-
font-size: 0.72rem;
498+
padding-left: 28px;
446499
}
447500

448501
@media (min-width: 1280px) {

docs/js/app.js

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,38 +33,64 @@ function toggleTheme() {
3333
}
3434

3535
// ---------- Table of Contents ----------
36+
// The right-column aside on each page contains:
37+
// 1. An \"Edit this page\" link to the source on GitHub (resolved
38+
// from a <meta name=\"docs-edit-url\"> set in the layout).
39+
// 2. A \"Table of contents\" heading + nested links to in-page
40+
// <h2 id> / <h3 id> headings.
41+
// We render the heading + nav unconditionally when there are at least
42+
// 2 headings; the edit link renders even on short pages.
3643
function buildTOC() {
3744
if (!$content) return;
3845

3946
const headings = $content.querySelectorAll('h2[id], h3[id]');
40-
if (headings.length < 3) return;
47+
const editUrl = (document.querySelector('meta[name="docs-edit-url"]') || {}).content || '';
48+
49+
// Don't bother rendering the aside on extremely short pages with no
50+
// navigation value at all.
51+
if (headings.length < 2 && !editUrl) return;
4152

4253
const aside = document.createElement('aside');
4354
aside.className = 'toc-aside';
44-
aside.setAttribute('aria-label', 'Table of contents');
45-
aside.innerHTML = `
46-
<div class="toc-inner">
47-
<div class="toc-title">On this page</div>
55+
aside.setAttribute('aria-label', 'On this page');
56+
57+
const tocBody = headings.length >= 2
58+
? `
59+
<div class="toc-heading">Table of contents</div>
4860
<nav class="toc-nav">
4961
${Array.from(headings).map(h => {
5062
const level = h.tagName === 'H3' ? 'toc-h3' : '';
5163
return `<a class="toc-link ${level}" href="#${h.id}" data-id="${h.id}">${h.textContent}</a>`;
5264
}).join('')}
53-
</nav>
54-
</div>`;
65+
</nav>`
66+
: '';
67+
68+
const editBlock = editUrl
69+
? `
70+
<div class="toc-actions">
71+
<a class="toc-action" href="${editUrl}" target="_blank" rel="noopener">
72+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
73+
<span>Edit this page</span>
74+
</a>
75+
</div>`
76+
: '';
77+
78+
aside.innerHTML = `<div class="toc-inner">${editBlock}${tocBody}</div>`;
5579

5680
const main = document.querySelector('.main');
5781
if (main) main.appendChild(aside);
5882

59-
aside.addEventListener('click', (e) => {
60-
const link = e.target.closest('.toc-link');
61-
if (!link) return;
62-
e.preventDefault();
63-
const target = document.getElementById(link.dataset.id);
64-
if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' });
65-
});
83+
if (headings.length >= 2) {
84+
aside.addEventListener('click', (e) => {
85+
const link = e.target.closest('.toc-link');
86+
if (!link) return;
87+
e.preventDefault();
88+
const target = document.getElementById(link.dataset.id);
89+
if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' });
90+
});
6691

67-
setupScrollSpy(headings, aside);
92+
setupScrollSpy(headings, aside);
93+
}
6894
}
6995

7096
function setupScrollSpy(headings, aside) {

0 commit comments

Comments
 (0)