Skip to content

Commit b11731a

Browse files
committed
Improve documentation layout
1 parent 0e131ab commit b11731a

File tree

8 files changed

+308
-58
lines changed

8 files changed

+308
-58
lines changed

docs/_data/manifest.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"docs.css": "/styles.0007.css",
3-
"docs.js": "/scripts.0002.js"
2+
"docs.css": "/styles.css",
3+
"docs.js": "/scripts.js"
44
}

docs/_layouts/default.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<link rel="preconnect" href="https://fonts.googleapis.com">
2323
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
2424
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@300;400;500&family=Onest:wght@300;400;500;600;700;900&display=swap" rel="stylesheet">
25-
<link href="{{ site.baseurl }}{{ site.data.manifest['docs.css'] }}" rel="stylesheet">
25+
<link href="{{ site.baseurl }}{{ site.data.manifest['docs.css'] }}?v={{ site.time | date:'%s' }}" rel="stylesheet">
2626
</head>
2727
<body class="bg-white text-dark font-onest antialiased relative">
2828
<div class="relative z-10">
@@ -34,7 +34,7 @@
3434
</a>
3535
</div>
3636
</header>
37-
<main class="relative flex justify-center mx-auto max-w-8xl sm:px-2 lg:px-8 xl:px-12">
37+
<main class="relative flex justify-center mx-auto max-w-8xl sm:px-2 lg:px-8 xl:px-12 gap-8">
3838
<label for="navigation" class="fixed top-5 right-5 z-50 flex items-center justify-center w-12 h-12 mb-4 ml-4 bg-white border rounded-full shadow-lg cursor-pointer text-slate-600 border-slate-300 lg:hidden transition duration-200 ease-in-out active:scale-95">
3939
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
4040
<path stroke-linecap="round" stroke-linejoin="round" d="M4 8h16M4 16h16" />
@@ -154,6 +154,6 @@ <h3 class="font-semibold tracking-tight text-slate-900">Older versions</h3>
154154
</div>
155155
</footer>
156156
</div>
157-
<script src="{{ site.baseurl }}{{ site.data.manifest['docs.js'] }}"></script>
157+
<script src="{{ site.baseurl }}{{ site.data.manifest['docs.js'] }}?v={{ site.time | date:'%s' }}"></script>
158158
</body>
159159
</html>

docs/_layouts/homepage.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<link rel="preconnect" href="https://fonts.googleapis.com">
1515
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
1616
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@300;400;500&family=Onest:wght@300;400;500;600;700;900&display=swap" rel="stylesheet">
17-
<link href="{{ site.baseurl }}{{ site.data.manifest['docs.css'] }}" rel="stylesheet">
17+
<link href="{{ site.baseurl }}{{ site.data.manifest['docs.css'] }}?v={{ site.time | date:'%s' }}" rel="stylesheet">
1818
</head>
1919
<body class="bg-white text-dark font-onest antialiased relative">
2020
<div class="relative z-10">

docs/_layouts/redirect.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<title>{{ page.title }} - {{ site.data.project.title }}</title>
1515
<meta http-equiv="refresh" content="0; url={{ page.redirect.to }}">
1616
<title>{{ site.data.project.tagline }} - {{ site.data.project.title }}</title>
17-
<link rel="stylesheet"href="{{ site.baseurl }}{{ site.data.manifest['docs.css'] }}">
17+
<link rel="stylesheet"href="{{ site.baseurl }}{{ site.data.manifest['docs.css'] }}?v={{ site.time | date:'%s' }}">
1818
<link rel="canonical" href="{{ site.baseurl }}{{ page.redirect.to }}">
1919
</head>
2020
<body>

docs/input.css

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,3 +571,32 @@ img {
571571
display: none !important;
572572
}
573573
}
574+
575+
576+
#onthispage {
577+
@apply sticky top-[4.5rem] h-[calc(100vh-4.5rem)] w-72 overflow-y-auto pr-8 text-sm xl:pr-16 self-start hidden lg:block shrink-0;
578+
}
579+
580+
#onthispage nav h3 {
581+
@apply font-semibold tracking-tight text-slate-900;
582+
}
583+
584+
#onthispage ul {
585+
@apply pl-3 mt-3 space-y-2;
586+
}
587+
588+
#onthispage a {
589+
@apply block border-l-2 border-transparent pl-2 no-underline;
590+
}
591+
592+
#onthispage a:hover {
593+
@apply underline;
594+
}
595+
596+
#onthispage .active {
597+
@apply text-csv-dark border-l-csv-dark;
598+
}
599+
600+
html {
601+
scroll-behavior: smooth;
602+
}

docs/scripts.0002.js

Lines changed: 0 additions & 51 deletions
This file was deleted.

docs/scripts.js

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
(() => {
2+
const root = document.querySelector('article.content');
3+
if (!root) return;
4+
5+
const isHeading = el => el && el.nodeType === 1 && /^H[1-6]$/.test(el.tagName);
6+
const headers = root.querySelectorAll('h2, h3, h4, h5, h6');
7+
const ids = new Set();
8+
headers.forEach(h => {
9+
let id = h.id || h.textContent.trim().toLowerCase().replace(/\W+/g, '-');
10+
let base = id;
11+
let i = 2;
12+
while (ids.has(id)) id = `${base}-${i++}`;
13+
ids.add(id);
14+
h.id = id;
15+
});
16+
17+
for (const h of Array.from(headers)) {
18+
// Idempotence : si ce titre est déjà le 1er enfant d'un .section-wrapper, on ne fait rien
19+
if (h.parentElement?.classList.contains('section-wrapper') &&
20+
h.parentElement.firstElementChild === h) {
21+
continue;
22+
}
23+
24+
const wrapper = document.createElement('div');
25+
wrapper.className = 'section-wrapper';
26+
// (optionnel) pour debug :
27+
wrapper.dataset.heading = h.tagName.toLowerCase();
28+
if (h.id) wrapper.dataset.anchor = h.id;
29+
30+
// Insérer le wrapper juste avant le titre
31+
h.parentNode.insertBefore(wrapper, h);
32+
33+
// Déplacer le titre dans le wrapper
34+
wrapper.appendChild(h);
35+
36+
// Puis déplacer tout ce qui suit IMMÉDIATEMENT jusqu'au prochain heading (quel que soit le niveau)
37+
// -> ainsi on n'englobe jamais les sous-titres
38+
let node = wrapper.nextSibling; // ancien "nextSibling" du h2, devenu celui du wrapper
39+
while (node) {
40+
const next = node.nextSibling; // mémoriser avant déplacement/arrêt
41+
42+
// Si on tombe sur un titre (h1..h6), on s'arrête (le prochain wrapper le prendra en charge)
43+
if (node.nodeType === 1 && isHeading(node)) break;
44+
45+
// Sinon, c'est du contenu d'intro : on le rapatrie dans ce wrapper
46+
wrapper.appendChild(node);
47+
48+
node = next;
49+
}
50+
}
51+
})();
52+
53+
(() => {
54+
let contentHeaders= document.querySelectorAll("main h2[id]");
55+
if (!document.querySelector('html').classList.contains('homepage') && contentHeaders) {
56+
const sections = document.querySelector('article.content').querySelectorAll('h2, h3, h4, h5, h6');
57+
const headings = [...sections];
58+
if (headings.length > 0) {
59+
// on page aside generation
60+
const aside = document.createElement('aside');
61+
aside.setAttribute('id', 'onthispage');
62+
const tocParent = document.createElement('nav');
63+
const tocParentTitle = document.createElement('h3');
64+
tocParentTitle.textContent = 'On This Page';
65+
const toc = document.createElement('ul');
66+
let currentLevel = 1;
67+
let currentList = toc;
68+
headings.forEach(h => {
69+
const level = parseInt(h.tagName.slice(1), 10);
70+
71+
// Going deeper
72+
while (level > currentLevel) {
73+
const newList = document.createElement('ul');
74+
75+
// If there is no lastElementChild, create a dummy parent <li>
76+
if (!currentList.lastElementChild) {
77+
const placeholder = document.createElement('li');
78+
currentList.appendChild(placeholder);
79+
}
80+
81+
currentList.lastElementChild.appendChild(newList);
82+
currentList = newList;
83+
currentLevel++;
84+
}
85+
86+
// Going shallower
87+
while (level < currentLevel) {
88+
currentList = currentList.parentElement.closest('ul');
89+
currentLevel--;
90+
}
91+
92+
// Add list item for current heading
93+
const li = document.createElement('li');
94+
const a = document.createElement('a');
95+
96+
if (!h.id) {
97+
h.id = h.textContent.trim().toLowerCase().replace(/\s+/g, '-');
98+
}
99+
100+
a.href = `#${h.id}`;
101+
a.textContent = h.textContent;
102+
li.appendChild(a);
103+
currentList.appendChild(li);
104+
});
105+
106+
tocParent.append(tocParentTitle, toc);
107+
aside.append(tocParent);
108+
document.querySelector('main').append(aside);
109+
}
110+
111+
const uri = new URL(location.href);
112+
// adding a pointer for headers
113+
contentHeaders.forEach((header) => {
114+
uri.hash = header.id;
115+
let link = document.createElement("a");
116+
link.classList.add("header-permalink");
117+
link.title = "Permalink";
118+
link.href = uri.toString();
119+
link.innerHTML = "&#182;";
120+
header.appendChild(link);
121+
});
122+
123+
const menuLinks = document.querySelectorAll('#onthispage a');
124+
const observer = new IntersectionObserver(entries => {
125+
entries.forEach(entry => {
126+
const id = entry.target.getAttribute("data-anchor");
127+
const link = document.querySelector(`#onthispage a[href="#${id}"]`);
128+
129+
if (entry.isIntersecting) {
130+
menuLinks.forEach(a => a.classList.remove("active"));
131+
link.classList.add("active");
132+
}
133+
});
134+
}, {
135+
root: null,
136+
rootMargin: "0px 0px -100% 0px",
137+
threshold: 0
138+
});
139+
140+
sections.forEach(section => observer.observe(section.parentElement));
141+
}
142+
143+
// generate code snippet copy/paste
144+
let codeSnippet = document.querySelectorAll('.content .language-php.highlighter-rouge');
145+
codeSnippet.forEach((snippet) => {
146+
let notification = document.createElement("div");
147+
notification.classList.add('copy-snippet-notification', 'hidden', 'rounded', 'p-2');
148+
snippet.appendChild(notification);
149+
150+
let link = document.createElement("span");
151+
link.classList.add("copy-snippet");
152+
link.innerHTML = "copy 📋";
153+
link.addEventListener('click', function (e) {
154+
let snippetParent = e.target.parentNode;
155+
let notification = snippetParent.querySelector('.copy-snippet-notification');
156+
let content = snippetParent.querySelector('pre').textContent;
157+
try {
158+
navigator.clipboard.writeText(content);
159+
notification.innerHTML = 'Copied!';
160+
notification.classList.add('bg-black');
161+
notification.classList.remove('hidden');
162+
setTimeout(() => {
163+
notification.classList.add('hidden');
164+
notification.classList.remove('bg-black');
165+
}, 500);
166+
} catch (err) {
167+
notification.innerHTML = 'Copy failed!';
168+
notification.classList.add('bg-red-800');
169+
notification.classList.remove('hidden');
170+
setTimeout(() => {
171+
notification.classList.add('hidden');
172+
notification.classList.remove('bg-red-800');
173+
}, 500);
174+
}
175+
}, false);
176+
snippet.appendChild(link);
177+
});
178+
179+
//package menu dropdown
180+
const dropDownList = document.getElementById('packageDropdownList');
181+
const dropDownButton = document.getElementById('packageDropdown');
182+
183+
dropDownButton.addEventListener('click', () => {
184+
dropDownList.classList.toggle('hidden');
185+
});
186+
187+
document.addEventListener('click', (event) => {
188+
if (!dropDownButton.contains(event.target) && !dropDownList.contains(event.target)) {
189+
dropDownList.classList.add('hidden');
190+
}
191+
});
192+
})();

0 commit comments

Comments
 (0)