Skip to content

Commit a799520

Browse files
committed
Add more Walkthrough sections, index subsection redesign
1 parent 31c92f6 commit a799520

5 files changed

Lines changed: 280 additions & 19 deletions

File tree

_config.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -440,10 +440,11 @@ bun create ${pkg}
440440
`;
441441
}, { type: "filter" });
442442

443-
site.helper("i", (page) => {
444-
const content = site.pages.find((v) => v.src.path === page)?.data.content;
443+
site.helper("i", (path) => {
444+
const page = site.pages.find((v) => v.src.path === path);
445+
const content = page?.data.content;
445446
if (typeof content !== "string") {
446-
return "no for " + page;
447+
return "no for " + path;
447448
}
448449
const links = new Array<[string, string]>();
449450
for (let line of content.split("\n")) {
@@ -452,10 +453,20 @@ site.helper("i", (page) => {
452453
}
453454
line = line.slice(3).trim();
454455
const title = line;
455-
const link = page + "#" + toAnchor(line);
456+
const link = path + "#" + toAnchor(line);
456457
links.push([title, link]);
457458
}
458-
return "\n" + links.map((v) => ` - [${v[0]}](${v[1]})`).join("\n");
459+
if (!links.length) {
460+
return "";
461+
}
462+
const title = page.data.title ?? path;
463+
const items = links.map(([heading, link], index) => ` <li style="--subsection-delay: ${index * 28}ms"><a href="${escapeHtml(link)}">${escapeHtml(heading)}</a></li>`).join("\n");
464+
return `
465+
<div class="index-subsections">
466+
<ul aria-label="Sections in ${escapeHtml(title)}">
467+
${items}
468+
</ul>
469+
</div>`;
459470
}, { type: "filter" });
460471

461472
site.helper("walkthrough", (track: string) => {
@@ -473,13 +484,13 @@ site.helper("walkthrough", (track: string) => {
473484
const headings = getH2Links(page);
474485
const audiences = getWalkthroughData(page)?.sections ?? {};
475486
const sections = headings.length
476-
? `\n <ul aria-label="Sections in ${escapeHtml(title)}">\n${
477-
headings.map(([heading, link, id]) => {
487+
? `\n <div class="index-subsections">\n <ul aria-label="Sections in ${escapeHtml(title)}">\n${
488+
headings.map(([heading, link, id], index) => {
478489
const audience = audiences[id];
479490
const badge = audience ? `<span class="inline-flex w-fit items-center" style="font-size:12px;white-space:nowrap;word-break:keep-all;"><span class="w-fit bg-dbt select-none text-fgt" style="padding:2px 8px;border-radius:12px;">${audience.toUpperCase()}-ONLY</span></span>` : "";
480-
return ` <li><a href="${escapeHtml(link)}">${escapeHtml(heading)}</a>${badge}</li>`;
491+
return ` <li style="--subsection-delay: ${index * 28}ms"><a href="${escapeHtml(link)}">${escapeHtml(heading)}</a>${badge}</li>`;
481492
}).join("\n")
482-
}\n </ul>`
493+
}\n </ul>\n </div>`
483494
: "";
484495
return ` <li><a href="${escapeHtml(page.src.path)}">${escapeHtml(title)}</a>${sections}\n </li>`;
485496
});

src/_includes/style/walkthrough.scss

Lines changed: 131 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,142 @@ ol.walkthrough-list {
2323
font-weight: 400;
2424
font-variant-numeric: tabular-nums;
2525
}
26+
}
2627

27-
+ li {
28-
margin-top: 0.6rem;
29-
}
28+
> li > .index-subsections > ul > li > .inline-flex {
29+
margin-left: 0.4rem;
30+
}
31+
}
32+
33+
.index-subsections > ul {
34+
display: grid;
35+
gap: 0.15rem;
36+
margin: 0 !important;
37+
padding: 0 0 0 1.2rem !important;
38+
color: var(--fgt);
39+
40+
> li:first-child {
41+
margin-top: 0.2rem;
3042
}
3143

32-
> li > ul {
44+
> li:last-child {
45+
margin-bottom: 0.35rem;
46+
}
47+
}
48+
49+
.index-subsection-toggle {
50+
display: inline-grid;
51+
width: 1.2rem;
52+
height: 1.75rem;
53+
place-items: center;
54+
border-radius: 0.4rem;
55+
color: var(--kr);
56+
cursor: pointer;
57+
line-height: 1;
58+
opacity: 0.55;
59+
transition: opacity 180ms ease, background-color 180ms ease;
60+
vertical-align: middle;
61+
62+
&:hover {
63+
background-color: var(--dbt);
64+
opacity: 0.9;
65+
}
66+
67+
&[aria-hidden="true"] {
68+
pointer-events: none;
69+
}
70+
71+
> svg {
72+
display: block;
73+
width: 0.72rem;
74+
height: 0.72rem;
75+
overflow: visible;
76+
fill: none;
77+
stroke: currentColor;
78+
stroke-linecap: round;
79+
stroke-linejoin: round;
80+
stroke-width: 1.75;
81+
transform-box: fill-box;
82+
transform-origin: center;
83+
transition: transform 420ms cubic-bezier(0.34, 1.56, 0.64, 1);
84+
}
85+
}
86+
87+
.index-subsections-enhanced {
88+
.index-subsections {
3389
display: grid;
34-
gap: 0.15rem;
35-
margin: 0.2rem 0 0.35rem !important;
36-
padding-left: 1.2rem !important;
37-
color: var(--fgt);
90+
grid-template-rows: 0fr;
91+
opacity: 0;
92+
transform: translateY(-0.35rem) scale(0.985);
93+
transform-origin: top left;
94+
transition:
95+
grid-template-rows 480ms cubic-bezier(0.16, 1, 0.3, 1),
96+
opacity 160ms ease,
97+
transform 380ms cubic-bezier(0.16, 1, 0.3, 1);
98+
99+
> ul {
100+
min-height: 0;
101+
overflow: hidden;
102+
103+
> li {
104+
opacity: 0;
105+
transform: translate3d(-0.55rem, -0.15rem, 0);
106+
transition:
107+
opacity 180ms ease,
108+
transform 360ms cubic-bezier(0.16, 1, 0.3, 1);
109+
}
110+
}
38111
}
39112

40-
> li > ul > li > .inline-flex {
41-
margin-left: 0.4rem;
113+
.index-item-collapsible.is-open {
114+
> .index-subsections {
115+
grid-template-rows: 1fr;
116+
opacity: 1;
117+
transform: none;
118+
119+
> ul > li {
120+
opacity: 1;
121+
transform: none;
122+
transition-delay: calc(55ms + var(--subsection-delay, 0ms));
123+
}
124+
}
125+
126+
.index-subsection-toggle {
127+
opacity: 0.9;
128+
129+
> svg {
130+
transform: rotate(180deg);
131+
}
132+
}
133+
}
134+
}
135+
136+
@media (hover: hover) and (pointer: fine) {
137+
.index-subsections-enhanced .index-item-collapsible:is(:hover, :focus-within) {
138+
> .index-subsections {
139+
grid-template-rows: 1fr;
140+
opacity: 1;
141+
transform: none;
142+
143+
> ul > li {
144+
opacity: 1;
145+
transform: none;
146+
transition-delay: calc(55ms + var(--subsection-delay, 0ms));
147+
}
148+
}
149+
150+
.index-subsection-toggle {
151+
opacity: 0.9;
152+
153+
> svg {
154+
transform: rotate(180deg);
155+
}
156+
}
157+
}
158+
}
159+
160+
@media (prefers-reduced-motion: reduce) {
161+
.index-subsections > ul > li {
162+
transition-delay: 0ms !important;
42163
}
43164
}

src/chat-recommendations.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
title: Chat Recommendations
3+
parent: /#walkthrough
4+
walkthrough:
5+
track: user
6+
order: 15
7+
---
8+
9+
User clients can get recommended channels and find similar channels or bots.
10+
11+
## Getting Recommended Channels
12+
13+
Use {{ "getRecommendedChannels" |> m }} to get recommended channels as {{ "ChatPChannel" |> t }} objects.
14+
15+
```ts
16+
const channels = await client.getRecommendedChannels();
17+
18+
for (const channel of channels) {
19+
console.log(channel.id, channel.title);
20+
}
21+
```
22+
23+
## Getting Similar Channels
24+
25+
Use {{ "getSimilarChannels" |> m }} with a channel's identifier.
26+
27+
```ts
28+
const channels = await client.getSimilarChannels(channelId);
29+
```
30+
31+
## Getting Similar Bots
32+
33+
Use {{ "getSimilarBots" |> m }} with a bot's identifier.
34+
35+
```ts
36+
const bots = await client.getSimilarBots(botId);
37+
```

src/saved-messages.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
title: Saved Messages
3+
parent: /#walkthrough
4+
walkthrough:
5+
track: user
6+
order: 16
7+
---
8+
9+
User clients can list chats with saved messages and get the messages saved from each chat.
10+
11+
## Listing Saved Chats
12+
13+
Use {{ "getSavedChats" |> m }} to get a {{ "SavedChats" |> t }} object.
14+
15+
```ts
16+
const { chats } = await client.getSavedChats();
17+
18+
for (const { chat } of chats) {
19+
console.log(chat.id, chat.type);
20+
}
21+
```
22+
23+
## Getting Saved Messages
24+
25+
Use {{ "getSavedMessages" |> m }} with a chat's identifier.
26+
27+
```ts
28+
const messages = await client.getSavedMessages(chatId);
29+
```

src/static/script.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,68 @@ document.querySelectorAll(".code-group-button").forEach((button) => {
2121
});
2222
});
2323

24+
function initIndexSubsections() {
25+
const panels = Array.from(document.querySelectorAll(".index-subsections"));
26+
const content = panels[0]?.closest(".content");
27+
if (!panels.length || !content) return;
28+
29+
const hoverQuery = globalThis.matchMedia("(hover: hover) and (pointer: fine)");
30+
const entries = panels.map((panel, index) => {
31+
const item = panel.parentElement;
32+
const list = panel.querySelector(":scope > ul");
33+
const link = item?.querySelector(":scope > a, :scope > p > a");
34+
if (!item || !list || !link) return null;
35+
36+
const title = list.getAttribute("aria-label")?.replace(/^Sections in /, "") || link.textContent.trim();
37+
const button = document.createElement("button");
38+
const panelId = `index-subsections-${index + 1}`;
39+
40+
panel.id = panelId;
41+
item.classList.add("index-item-collapsible");
42+
button.type = "button";
43+
button.className = "index-subsection-toggle";
44+
button.setAttribute("aria-controls", panelId);
45+
button.innerHTML = '<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M3 5.5l5 5 5-5" /></svg>';
46+
link.after(button);
47+
48+
const entry = { button, item, panel, title };
49+
button.addEventListener("click", () => {
50+
if (!hoverQuery.matches) setOpen(entry, !item.classList.contains("is-open"));
51+
});
52+
return entry;
53+
}).filter(Boolean);
54+
55+
function setOpen(entry, open) {
56+
entry.item.classList.toggle("is-open", open);
57+
entry.panel.inert = !open;
58+
entry.panel.setAttribute("aria-hidden", String(!open));
59+
entry.button.setAttribute("aria-expanded", String(open));
60+
entry.button.setAttribute("aria-label", `${open ? "Hide" : "Show"} sections in ${entry.title}`);
61+
}
62+
63+
function syncInputMode() {
64+
for (const entry of entries) {
65+
entry.item.classList.remove("is-open");
66+
if (hoverQuery.matches) {
67+
entry.panel.inert = false;
68+
entry.panel.removeAttribute("aria-hidden");
69+
entry.button.tabIndex = -1;
70+
entry.button.setAttribute("aria-hidden", "true");
71+
entry.button.removeAttribute("aria-expanded");
72+
entry.button.removeAttribute("aria-label");
73+
} else {
74+
entry.button.tabIndex = 0;
75+
entry.button.removeAttribute("aria-hidden");
76+
setOpen(entry, false);
77+
}
78+
}
79+
}
80+
81+
syncInputMode();
82+
content.classList.add("index-subsections-enhanced");
83+
hoverQuery.addEventListener("change", syncInputMode);
84+
}
85+
2486
function initToc() {
2587
const toc = document.querySelector(".toc");
2688
const viewport = toc?.querySelector(".toc-list-wrap");
@@ -376,4 +438,5 @@ function initToc() {
376438
if (!activateHashEntry()) updateActive();
377439
}
378440

441+
initIndexSubsections();
379442
initToc();

0 commit comments

Comments
 (0)