Skip to content

Commit 6f4112c

Browse files
committed
changes for code items in right side bar styled differently
1 parent 68538e7 commit 6f4112c

3 files changed

Lines changed: 115 additions & 9 deletions

File tree

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import 'package:jaspr/dom.dart';
2+
import 'package:jaspr/jaspr.dart';
3+
import 'package:jaspr_content/jaspr_content.dart';
4+
import 'package:jaspr_router/jaspr_router.dart';
5+
6+
/// A post-processing extension that runs after [TableOfContentsExtension]
7+
/// to preserve `<code>` formatting in TOC entries.
8+
///
9+
/// Headings written with backticks in markdown (e.g. `` ### `types` ``) will
10+
/// render their TOC link text inside a `<code>` element, matching Docusaurus
11+
/// behavior where code-styled headings look visually distinct from regular
12+
/// headings in the table of contents.
13+
class CodeAwareTocPostProcessor implements PageExtension {
14+
static final _headerRegex = RegExp(r'^h(\d)$', caseSensitive: false);
15+
16+
@override
17+
Future<List<Node>> apply(Page page, List<Node> nodes) async {
18+
final codeHeadingIds = <String>{};
19+
_findCodeHeadings(nodes, codeHeadingIds);
20+
21+
if (codeHeadingIds.isNotEmpty) {
22+
final toc = page.data['toc'];
23+
if (toc is TableOfContents) {
24+
page.apply(data: {
25+
'toc': _CodeAwareTableOfContents(toc.entries, codeHeadingIds),
26+
});
27+
}
28+
}
29+
30+
return nodes;
31+
}
32+
33+
void _findCodeHeadings(List<Node> nodes, Set<String> codeIds) {
34+
for (final node in nodes) {
35+
if (node is ElementNode) {
36+
if (_headerRegex.hasMatch(node.tag)) {
37+
final id = node.attributes['id'];
38+
if (id != null && _hasCodeChild(node)) {
39+
codeIds.add(id);
40+
}
41+
}
42+
if (node.children != null) {
43+
_findCodeHeadings(node.children!, codeIds);
44+
}
45+
}
46+
}
47+
}
48+
49+
bool _hasCodeChild(ElementNode node) {
50+
for (final child in node.children ?? const <Node>[]) {
51+
if (child is ElementNode) {
52+
if (child.tag == 'code') return true;
53+
if (_hasCodeChild(child)) return true;
54+
}
55+
}
56+
return false;
57+
}
58+
}
59+
60+
class _CodeAwareTableOfContents extends TableOfContents {
61+
_CodeAwareTableOfContents(super.entries, this._codeEntryIds);
62+
63+
final Set<String> _codeEntryIds;
64+
65+
@override
66+
Component build() {
67+
return ul([..._buildToc(entries)]);
68+
}
69+
70+
Iterable<Component> _buildToc(List<TocEntry> toc, [int indent = 0]) sync* {
71+
for (final entry in toc) {
72+
final isCode = _codeEntryIds.contains(entry.id);
73+
yield li(
74+
styles: Styles(padding: Padding.only(left: (0.75 * indent).em)),
75+
[
76+
Builder(
77+
builder: (context) {
78+
final route = RouteState.of(context);
79+
return a(
80+
href: '${route.path}#${entry.id}',
81+
[
82+
if (isCode)
83+
code([Component.text(entry.text)])
84+
else
85+
Component.text(entry.text),
86+
],
87+
);
88+
},
89+
),
90+
],
91+
);
92+
if (entry.children.isNotEmpty) {
93+
yield* _buildToc(entry.children, indent + 1);
94+
}
95+
}
96+
}
97+
}

site_jaspr/lib/main.server.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import 'package:jaspr_content/theme.dart';
2121

2222
import 'components/breadcrumb.dart';
2323
import 'components/doc_callout.dart';
24+
import 'extensions/code_aware_toc.dart';
2425
import 'components/edit_page_link.dart';
2526
import 'components/homepage_layout.dart';
2627
import 'components/icon_link.dart';
@@ -48,6 +49,7 @@ void main() {
4849
extensions: [
4950
HeadingAnchorsExtension(),
5051
TableOfContentsExtension(),
52+
CodeAwareTocPostProcessor(),
5153
],
5254
components: [
5355
DocCallout(),

site_jaspr/lib/styles/site_styles.dart

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -356,8 +356,8 @@ List<StyleRule> get siteStyles => [
356356
// ───────────────────────────────────────────────────────────────────────
357357
// Sidebar width: match Docusaurus 300px (--doc-sidebar-width)
358358
// Use high specificity to override DocsLayout's .docs .main-container .sidebar-container
359-
css('.docs .main-container .sidebar-container').styles(width: 300.px),
360-
css('.docs .sidebar').styles(width: 300.px),
359+
css('.docs .main-container .sidebar-container').styles(width: 300.px, overflow: Overflow.hidden),
360+
css('.docs .sidebar').styles(width: 300.px, raw: {'overflow-x': 'hidden'}),
361361
// Sidebar border-right: match Docusaurus 1px solid border
362362
css('.docs .sidebar-container').styles(
363363
border: Border.only(
@@ -532,12 +532,13 @@ List<StyleRule> get siteStyles => [
532532
color: Color('#2a48df'),
533533
fontWeight: FontWeight.w500,
534534
),
535-
// TOC sub-items (h3+): rounded pill border (matching Docusaurus nested items)
536-
css('.toc li[style*="0.75"] a').styles(
535+
// TOC code sub-items (backtick headings): rounded pill border
536+
css('.toc a code').styles(
537537
padding: Padding.symmetric(horizontal: 0.5.rem, vertical: 0.125.rem),
538538
border: Border.all(color: Color('#dadde1'), width: 1.px),
539539
radius: BorderRadius.circular(12.px),
540540
fontSize: 11.px,
541+
raw: {'font-family': 'inherit'},
541542
),
542543
// Dark mode TOC
543544
css('[data-theme="dark"] .docs .main-container main > div aside.toc > div').styles(
@@ -554,7 +555,7 @@ List<StyleRule> get siteStyles => [
554555
css('[data-theme="dark"] .toc a.toc-active').styles(
555556
color: Color('#66fbd1'),
556557
),
557-
css('[data-theme="dark"] .toc li[style*="0.75"] a').styles(
558+
css('[data-theme="dark"] .toc a code').styles(
558559
border: Border.all(color: Color('#444950'), width: 1.px),
559560
),
560561
// ───────────────────────────────────────────────────────────────────────
@@ -621,6 +622,14 @@ List<StyleRule> get siteStyles => [
621622
padding: Padding.symmetric(vertical: 0.25.rem),
622623
),
623624
]),
625+
// Mobile TOC code sub-items: pill border (same as sidebar TOC)
626+
css('.mobile-toc .mobile-toc-content a code').styles(
627+
padding: Padding.symmetric(horizontal: 0.5.rem, vertical: 0.125.rem),
628+
border: Border.all(color: Color('#dadde1'), width: 1.px),
629+
radius: BorderRadius.circular(12.px),
630+
fontSize: 11.px,
631+
raw: {'font-family': 'inherit'},
632+
),
624633
// Mobile TOC links: use higher specificity to override .content-container a
625634
css('.mobile-toc .mobile-toc-content a').styles(
626635
color: Color('#1c1e21'),
@@ -645,10 +654,8 @@ List<StyleRule> get siteStyles => [
645654
css('[data-theme="dark"] .mobile-toc .mobile-toc-content a:hover').styles(
646655
color: Color('#66fbd1'),
647656
),
648-
649-
// Dark mode TOC: remove pill borders
650-
css('[data-theme="dark"] .toc li[style] a').styles(
651-
border: Border.none,
657+
css('[data-theme="dark"] .mobile-toc .mobile-toc-content a code').styles(
658+
border: Border.all(color: Color('#444950'), width: 1.px),
652659
),
653660

654661
// ───────────────────────────────────────────────────────────────────────

0 commit comments

Comments
 (0)