rdoc 7.2.0 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +3 -4
  3. data/LICENSE.rdoc +4 -0
  4. data/README.md +43 -2
  5. data/doc/markup_reference/markdown.md +104 -3
  6. data/lib/rdoc/code_object/alias.rb +2 -8
  7. data/lib/rdoc/code_object/any_method.rb +11 -6
  8. data/lib/rdoc/code_object/attr.rb +11 -6
  9. data/lib/rdoc/code_object/class_module.rb +62 -32
  10. data/lib/rdoc/code_object/constant.rb +29 -3
  11. data/lib/rdoc/code_object/context/section.rb +4 -35
  12. data/lib/rdoc/code_object/context.rb +39 -34
  13. data/lib/rdoc/code_object/method_attr.rb +9 -15
  14. data/lib/rdoc/code_object/mixin.rb +2 -2
  15. data/lib/rdoc/code_object/top_level.rb +9 -3
  16. data/lib/rdoc/code_object.rb +2 -4
  17. data/lib/rdoc/comment.rb +0 -65
  18. data/lib/rdoc/cross_reference.rb +7 -27
  19. data/lib/rdoc/encoding.rb +3 -3
  20. data/lib/rdoc/generator/aliki.rb +17 -0
  21. data/lib/rdoc/generator/darkfish.rb +12 -6
  22. data/lib/rdoc/generator/json_index.rb +2 -2
  23. data/lib/rdoc/generator/markup.rb +56 -31
  24. data/lib/rdoc/generator/template/aliki/DESIGN.md +536 -0
  25. data/lib/rdoc/generator/template/aliki/_aside_toc.rhtml +1 -1
  26. data/lib/rdoc/generator/template/aliki/_head.rhtml +1 -1
  27. data/lib/rdoc/generator/template/aliki/_sidebar_extends.rhtml +8 -6
  28. data/lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml +8 -6
  29. data/lib/rdoc/generator/template/aliki/_sidebar_installed.rhtml +1 -1
  30. data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +2 -2
  31. data/lib/rdoc/generator/template/aliki/_sidebar_sections.rhtml +1 -1
  32. data/lib/rdoc/generator/template/aliki/_sidebar_toggle.rhtml +1 -1
  33. data/lib/rdoc/generator/template/aliki/class.rhtml +56 -46
  34. data/lib/rdoc/generator/template/aliki/css/rdoc.css +337 -111
  35. data/lib/rdoc/generator/template/aliki/index.rhtml +1 -1
  36. data/lib/rdoc/generator/template/aliki/js/aliki.js +20 -18
  37. data/lib/rdoc/generator/template/aliki/page.rhtml +1 -1
  38. data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +1 -1
  39. data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +2 -2
  40. data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +8 -6
  41. data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +8 -6
  42. data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +1 -1
  43. data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +1 -1
  44. data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +1 -1
  45. data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +5 -5
  46. data/lib/rdoc/generator/template/darkfish/class.rhtml +18 -21
  47. data/lib/rdoc/generator/template/darkfish/css/rdoc.css +0 -1
  48. data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +3 -3
  49. data/lib/rdoc/i18n/text.rb +3 -3
  50. data/lib/rdoc/markdown.kpeg +15 -10
  51. data/lib/rdoc/markdown.rb +289 -104
  52. data/lib/rdoc/markup/document.rb +2 -2
  53. data/lib/rdoc/markup/formatter.rb +24 -34
  54. data/lib/rdoc/markup/heading.rb +1 -4
  55. data/lib/rdoc/markup/indented_paragraph.rb +1 -1
  56. data/lib/rdoc/markup/list.rb +2 -2
  57. data/lib/rdoc/markup/list_item.rb +2 -2
  58. data/lib/rdoc/markup/pre_process.rb +0 -25
  59. data/lib/rdoc/markup/to_ansi.rb +1 -1
  60. data/lib/rdoc/markup/to_bs.rb +1 -1
  61. data/lib/rdoc/markup/to_html.rb +131 -53
  62. data/lib/rdoc/markup/to_html_crossref.rb +97 -71
  63. data/lib/rdoc/markup/to_html_snippet.rb +5 -5
  64. data/lib/rdoc/markup/to_joined_paragraph.rb +0 -5
  65. data/lib/rdoc/markup/to_label.rb +2 -2
  66. data/lib/rdoc/markup/to_markdown.rb +1 -1
  67. data/lib/rdoc/markup/to_rdoc.rb +2 -2
  68. data/lib/rdoc/markup/to_table_of_contents.rb +1 -1
  69. data/lib/rdoc/markup/to_tt_only.rb +0 -7
  70. data/lib/rdoc/markup/verbatim.rb +1 -1
  71. data/lib/rdoc/options.rb +36 -51
  72. data/lib/rdoc/parser/c.rb +7 -6
  73. data/lib/rdoc/parser/rbs.rb +275 -0
  74. data/lib/rdoc/parser/ruby.rb +954 -2066
  75. data/lib/rdoc/parser/ruby_colorizer.rb +253 -0
  76. data/lib/rdoc/parser.rb +3 -2
  77. data/lib/rdoc/rbs_helper.rb +186 -0
  78. data/lib/rdoc/rdoc.rb +196 -24
  79. data/lib/rdoc/ri/driver.rb +8 -2
  80. data/lib/rdoc/ri/paths.rb +1 -1
  81. data/lib/rdoc/{servlet.rb → ri/servlet.rb} +5 -5
  82. data/lib/rdoc/ri.rb +4 -3
  83. data/lib/rdoc/rubygems_hook.rb +11 -11
  84. data/lib/rdoc/server.rb +460 -0
  85. data/lib/rdoc/stats.rb +147 -124
  86. data/lib/rdoc/store.rb +212 -4
  87. data/lib/rdoc/task.rb +16 -15
  88. data/lib/rdoc/text.rb +1 -118
  89. data/lib/rdoc/token_stream.rb +11 -33
  90. data/lib/rdoc/version.rb +1 -1
  91. data/lib/rdoc.rb +35 -7
  92. data/lib/rubygems_plugin.rb +2 -11
  93. data/rdoc-logo.svg +43 -0
  94. data/rdoc.gemspec +6 -4
  95. metadata +35 -18
  96. data/lib/rdoc/code_object/anon_class.rb +0 -10
  97. data/lib/rdoc/code_object/ghost_method.rb +0 -6
  98. data/lib/rdoc/code_object/meta_method.rb +0 -6
  99. data/lib/rdoc/parser/prism_ruby.rb +0 -1112
  100. data/lib/rdoc/parser/ripper_state_lex.rb +0 -302
  101. data/lib/rdoc/parser/ruby_tools.rb +0 -163
@@ -0,0 +1,536 @@
1
+ # DESIGN.md
2
+
3
+ Single source of truth for the **Aliki** theme's visual language. The generated
4
+ HTML documentation — served from `localhost` (`rdoc --server`),
5
+ [docs.ruby-lang.org](https://docs.ruby-lang.org), and static GitHub Pages —
6
+ implements what's specified here. The implementation lives in one stylesheet,
7
+ [`css/rdoc.css`](css/rdoc.css). When a value here drifts from that file, **the
8
+ stylesheet is wrong** and should be brought back in line.
9
+
10
+ This document follows the
11
+ [Stitch DESIGN.md format](https://github.com/VoltAgent/awesome-design-md) —
12
+ nine sections covering theme, color, type, components, layout, elevation,
13
+ guardrails, responsive behavior, and an agent quick reference.
14
+
15
+ > Scope: this is the **visual** contract only. It does not cover the generator
16
+ > pipeline, templates, or JS architecture.
17
+
18
+ ---
19
+
20
+ ## 1. Visual Theme & Atmosphere
21
+
22
+ **Personality.** Modern, light, content-first. Aliki is a quiet reading surface
23
+ for Ruby API docs — the documentation is the product, and the chrome recedes.
24
+ It should feel like a well-made developer-docs site, not a framework's default
25
+ output.
26
+
27
+ **Context of use.** Developers read reference docs while coding — scanning for a
28
+ method, a signature, a constant. The job is to find the thing and read it
29
+ comfortably. Reading measure and code legibility matter more than decoration.
30
+
31
+ **Mood.** Calm and neutral with a single decisive accent. Warm "stone" grays
32
+ carry the text hierarchy; one red accent carries identity and wayfinding
33
+ (headings, links-on-hover, active TOC, signature cards). Dark mode is a
34
+ first-class, hand-tuned surface — not an inverted afterthought.
35
+
36
+ **Density.** Comfortable, not cramped. A capped 800 px reading measure, generous
37
+ `--space-12` page padding, and a token-driven spacing rhythm. Every element
38
+ earns its space; there is no decorative chrome.
39
+
40
+ **Anti-references.** What Aliki must **not** look or feel like:
41
+
42
+ - **Not Darkfish** — the predecessor theme it deliberately departs from.
43
+ - **Not corporate** — no heavy, dense doc-portal styling.
44
+ - **Not cluttered** — sidebars and chrome stay quiet; content leads.
45
+
46
+ **References (inferred from the implementation, not externally specified).** The
47
+ system-font stack, GitHub-style heading anchors, and a flat token system place
48
+ Aliki in the family of modern, lightweight developer-doc themes. Treat positive
49
+ references as open — the brand is currently defined by its principles and
50
+ anti-references, not a named lookalike.
51
+
52
+ **Surface contexts.**
53
+
54
+ | Surface | Theme | Atmosphere |
55
+ |----------------------------|----------------------------------------|-------------------------------------------------------------------|
56
+ | Generated docs (static) | Light default · Dark via `data-theme` | The primary reading surface; must work offline / from static hosts |
57
+ | Live server (`--server`) | Same light/dark | Servlet pages (root, 404) use lighter chrome — no header/TOC/footer |
58
+
59
+ Aliki ships a **single brand palette** (red) with explicit **light and dark**
60
+ variants — not a multi-theme system.
61
+
62
+ ## 2. Color Palette & Roles
63
+
64
+ All color is defined as CSS custom properties in
65
+ [`css/rdoc.css`](css/rdoc.css): light tokens in `:root`, dark tokens in a
66
+ `[data-theme="dark"]` override block that re-declares **only** what differs.
67
+ Components reference semantic tokens, never raw hex.
68
+
69
+ ### Semantic roles
70
+
71
+ | Role | Token (`--color-…`) | Meaning |
72
+ |--------------------|----------------------------|--------------------------------------------------|
73
+ | Brand accent | `accent-primary` | Identity + wayfinding (headings, active TOC, sig border) |
74
+ | Accent hover | `accent-hover` | Hover/darker accent |
75
+ | Accent subtle | `accent-subtle` | Tinted accent fills (buttons, focus ring) |
76
+ | Primary text | `text-primary` | Body copy, method names |
77
+ | Secondary text | `text-secondary` | Meta, secondary labels, branch |
78
+ | Tertiary text | `text-tertiary` | Placeholders, snippets, signatures, footer-bottom |
79
+ | Page background | `background-primary` | Main surface |
80
+ | Raised/​sunk bg | `background-secondary` / `-tertiary` | Footer, modal close, hover fills |
81
+ | Borders | `border-subtle` / `-default` / `-emphasis` | Hairlines from quiet → strong |
82
+ | Link | `link-default` / `link-hover` | Body links (default = text color; hover = accent) |
83
+ | Code surface | `code-bg` / `code-border` | `<pre>` / inline `code` |
84
+ | Signature card | `sig-bg` / `sig-border` | Method/attribute header card |
85
+ | Page title kind | `title-kind-border` | Border for the class/module kind badge |
86
+ | Nav | `nav-bg` / `nav-text` | Left sidebar surface + text |
87
+ | Table | `th-background` / `td-background` | Header row + zebra rows |
88
+
89
+ ### Brand palette — red ramp (identity, **fixed**)
90
+
91
+ | Step | Hex | | Step | Hex |
92
+ |------|-----------|-|------|-----------|
93
+ | 50 | `#fdeae9` | | 500 | `#eb544f` |
94
+ | 100 | `#fadad3` | | 600 | `#e62923` ← light accent |
95
+ | 200 | `#f8bfbd` | | 700 | `#b8211c` |
96
+ | 300 | `#f5a9a7` | | 800 | `#8a1915` |
97
+ | 400 | `#f07f7b` | | 900 | `#5c100e` |
98
+
99
+ Light accent = `primary-600` (`#e62923`); dark accent = `primary-500`
100
+ (`#eb544f`). **The hue is a fixed brand identity — do not retune it without
101
+ approval** (see §7).
102
+
103
+ ### Neutral palette — warm "stone" ramp
104
+
105
+ `50 #fafaf9 · 100 #f5f5f4 · 200 #e7e5e4 · 300 #d6d3d1 · 400 #a8a29e · 500 #78716c · 600 #57534e · 700 #44403c · 800 #292524 · 900 #1c1917`
106
+
107
+ ### Semantic tokens — resolved values
108
+
109
+ | Role | Light | Dark |
110
+ |-----------------------|---------------------------|---------------------------|
111
+ | `text-primary` | `#1c1917` (neutral-900) | `#fafaf9` (neutral-50) |
112
+ | `text-secondary` | `#57534e` (neutral-600) | `#e7e5e4` (neutral-200) |
113
+ | `text-tertiary` | `#78716c` (neutral-500) | `#a8a29e` (neutral-400) |
114
+ | `background-primary` | `#ffffff` | `#1c1917` (neutral-900) |
115
+ | `background-secondary`| `#fafaf9` (neutral-50) | `#292524` (neutral-800) |
116
+ | `background-tertiary` | `#f5f5f4` (neutral-100) | `#44403c` (neutral-700) |
117
+ | `border-subtle` | `#e7e5e4` (neutral-200) | `#44403c` (neutral-700) |
118
+ | `border-default` | `#d6d3d1` (neutral-300) | `#57534e` (neutral-600) |
119
+ | `border-emphasis` | `#a8a29e` (neutral-400) | `#d6d3d1` (neutral-300) |
120
+ | `link-default` | `#1c1917` | `#fafaf9` |
121
+ | `link-hover` | `#e62923` (primary-600) | `#eb544f` (primary-500) |
122
+ | `accent-primary` | `#e62923` (primary-600) | `#eb544f` (primary-500) |
123
+ | `accent-hover` | `#b8211c` (primary-700) | `#f07f7b` (primary-400) |
124
+ | `accent-subtle` | `#fdeae9` (primary-50) | `rgb(235 84 79 / 10%)` |
125
+ | `title-kind-border` | `#f8bfbd` (primary-200) | `rgb(235 84 79 / 35%)` |
126
+ | `code-bg` | `#f6f8fa` | `#292524` (neutral-800) |
127
+ | `code-border` | `#d6d3d1` | `#44403c` (neutral-700) |
128
+ | `sig-bg` | `#f5f5f4` (neutral-100) | `#211f1e` (hand-picked) |
129
+ | `sig-border` | `#d6d3d1` (neutral-300) | `#44403c` (neutral-700) |
130
+ | `nav-bg` / `nav-text` | `#ffffff` / `#44403c` | `#1c1917` / `#fafaf9` |
131
+
132
+ ### Syntax-highlight palette (`--code-*`)
133
+
134
+ One palette shared across **Ruby, C, and Shell** highlighting. Brighter in dark
135
+ mode so tokens stay legible on the dark code surface.
136
+
137
+ | Token | Light | Dark |
138
+ |---------|-----------|-----------|
139
+ | blue | `#1d4ed8` | `#93c5fd` |
140
+ | green | `#047857` | `#34d399` |
141
+ | orange | `#d97706` | `#fbbf24` |
142
+ | purple | `#7e22ce` | `#c084fc` |
143
+ | red | `#dc2626` | `#f87171` |
144
+ | cyan | `#0891b2` | `#22d3ee` |
145
+ | gray | `#78716c` | `#a8a29e` |
146
+
147
+ ### Search-type badge colors
148
+
149
+ | Type | Light bg / text | Dark bg / text |
150
+ |----------|-----------------------|-----------------------|
151
+ | class | `#e6f0ff` / `#0050a0` | `#1e3a5f` / `#93c5fd` |
152
+ | module | `#e6ffe6` / `#006600` | `#14532d` / `#86efac` |
153
+ | constant | `#fff0e6` / `#995200` | `#451a03` / `#fcd34d` |
154
+ | method | `#f0e6ff` / `#5200a0` | `#3b0764` / `#d8b4fe` |
155
+
156
+ ### Theme-agnostic tokens (not overridden in dark)
157
+
158
+ | Token | Value | Use |
159
+ |------------------------|--------------------------|----------------------------------|
160
+ | `overlay` | `rgb(0 0 0 / 50%)` | Modal / mobile-nav backdrop |
161
+ | `emphasis-bg` | `rgb(255 111 97 / 10%)` | `strong` / `em` highlight |
162
+ | `emphasis-decoration` | `rgb(52 48 64 / 25%)` | `em` dotted underline |
163
+ | `search-highlight-bg` | `rgb(224 108 117 / 10%)` | Matched-term highlight |
164
+ | `success-bg` | `rgb(34 197 94 / 10%)` | Copy-button "copied" state |
165
+
166
+ ### Success palette
167
+ `green-400 #4ade80 · green-500 #22c55e · green-600 #16a34a` — copy-button feedback only.
168
+
169
+ ## 3. Typography Rules
170
+
171
+ ### Font stacks
172
+
173
+ | Family | Stack |
174
+ |--------|------------------------------------------------------------------------------------------------|
175
+ | Sans (base + headings) | `-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif` |
176
+ | Mono | `ui-monospace, 'SFMono-Regular', 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace` |
177
+
178
+ System fonts only — **no web fonts are shipped** (keeps output lightweight; see
179
+ §7). Headings reuse the base sans; mono is used for code, method headings, and
180
+ type signatures.
181
+
182
+ ### Type scale
183
+
184
+ | Token | rem | px | Token | rem | px |
185
+ |---------|----------|----|---------|----------|----|
186
+ | `xs` | 0.75 | 12 | `2xl` | 1.5 | 24 |
187
+ | `sm` | 0.875 | 14 | `3xl` | 1.875 | 30 |
188
+ | `base` | 1 | 16 | `4xl` | 2.25 | 36 |
189
+ | `lg` | 1.125 | 18 | `5xl` | 3 | 48 |
190
+ | `xl` | 1.25 | 20 | | | |
191
+
192
+ Weights: `normal 400 · medium 500 · semibold 600 · bold 700`.
193
+ Line heights: `tight 1.25 · normal 1.5 · relaxed 1.625` (body is relaxed).
194
+
195
+ ### Heading ladder (`main`)
196
+
197
+ | Element | Size | Weight | Notes |
198
+ |---------|------------|-----------|-----------------------------------------|
199
+ | `h1.page-title` | kind badge: `sm` / name: `3xl` (30) | semibold / bold | Type kind renders as an accent badge above the class/module name; long names may wrap |
200
+ | `h1` | `3xl` (30) | bold | tight line-height |
201
+ | `h2` | `2xl` (24) | semibold | `margin-top: space-8`; section headers add a 1 px top rule + `space-3` padding |
202
+ | `h3` | `xl` (20) | semibold | `margin-top: space-8`; section headers add a 1 px top rule + `space-3` padding |
203
+ | `h4` | `lg` (18) | medium | |
204
+ | `h5`/`h6` | `base` (16) | medium | |
205
+
206
+ All headings render in `accent-primary` and carry
207
+ `scroll-margin-top: calc(header-height + 2rem)` so anchored links clear the
208
+ sticky header.
209
+
210
+ ### Color × text pairing
211
+
212
+ - Body links default to **text color**, not accent — only hover reveals accent
213
+ (`link-hover`). Keeps prose calm.
214
+ - Status/role meaning in search badges is carried by **both** a tinted
215
+ background and a text color, never color alone.
216
+ - `strong` and `em` share the accent color + `emphasis-bg` tint; `em` adds a
217
+ dotted underline so emphasis survives in monochrome.
218
+
219
+ ## 4. Component Stylings
220
+
221
+ Spacing/radius tokens referenced below resolve in §5/§6.
222
+
223
+ ### Header bar (`header.top-navbar`)
224
+
225
+ | Property | Value |
226
+ |------------|-------------------------------------------------------------|
227
+ | Layout | Sticky top, `z-fixed` (300), `height: 64px`; desktop grid mirrors the page shell so search aligns to the main content rail |
228
+ | Background | `background-primary` + `border-bottom` hairline + `shadow-sm` |
229
+ | Padding | Desktop columns are unpadded; brand/toggle use `space-6` side offsets, search rail uses main content `space-8` inset (mobile header: `space-4`) |
230
+ | Brand | `xl` (20) semibold; hover → accent |
231
+ | Search | content-rail aligned desktop field, `width: 400px` within the main rail (see Search below) |
232
+
233
+ ### Theme toggle (`.theme-toggle`)
234
+
235
+ | Property | Value |
236
+ |----------|------------------------------------------------------------------|
237
+ | Box | `2.5rem` square · `radius-md` · 1px `border-default` |
238
+ | Hover | `background-secondary`, accent border + text, `scale(1.05)` |
239
+ | Active | `scale(0.95)` |
240
+ | Focus | accent border + `0 0 0 3px accent-subtle` ring |
241
+ | Icon | rotates `15deg` + `scale(1.1)` on hover, `--ease-out-smooth` |
242
+
243
+ ### Left navigation (`#sidebar-navigation` + `.nav-section`)
244
+
245
+ | Property | Value |
246
+ |-----------------|--------------------------------------------------------------|
247
+ | Surface | `nav-bg`, `border-right` hairline, sticky under header, full-height scroll; rules are scoped to `#sidebar-navigation` so the right TOC can use its own `<nav>` semantics |
248
+ | Scrollbar | 6 px, `border-default` thumb (custom, thin) |
249
+ | Section heading | `lg` semibold in **accent**, `border-bottom` |
250
+ | Section padding | `margin-top: space-6`, `padding: 0 space-6` |
251
+ | Link hover | `padding-left: space-1` nudge + `link-hover` color + underline |
252
+ | Collapsible | `<details>` with `::details-content` `block-size` 200 ms ease + `interpolate-size: allow-keywords` |
253
+ | Section icon | `1.25rem`, accent color · chevron `1rem`, tertiary, rotates `90deg` open |
254
+ | Nested list | `border-left` subtle hairline, `margin-left: 9px` (aligns to icon center) |
255
+
256
+ ### Signature card (`.method-header` / `.method-heading`)
257
+
258
+ The defining content component — a method or attribute presented as a card.
259
+
260
+ | Property | Value |
261
+ |-----------------|--------------------------------------------------------------|
262
+ | Card | `sig-bg` background · 1px `sig-border` full border · `radius-md` |
263
+ | Layout | two-column grid, `minmax(0, 1fr) auto`, `gap: space-4`; narrows to one column on `≤480px` |
264
+ | Padding | `space-4` desktop, `space-2` on `≤480px` |
265
+ | Heading group | `.method-heading-group`, `min-width: 0`; contains method heading(s) and optional method type signature |
266
+ | Heading | flex column, **mono**, `lg`, semibold; name `overflow-wrap: anywhere` |
267
+ | Type signature (method) | `pre.method-type-signature` — transparent, dotted top rule via `::before`, `sm` mono, `text-tertiary`, tight, `pre-wrap` |
268
+ | Type signature (attribute) | inline after `[RW]` badge, `sm` mono, `text-secondary` |
269
+ | Source toggle (`.method-controls summary`) | static grid action inside the card header; inline-flex with `{}` `.method-source-icon`, accent text on `accent-subtle`, `radius-sm`, `sm` medium; hover `primary-100` bg + `primary-300` border + `translateY(-1px)`; active `scale(0.96)` |
270
+ | Source reveal | `.method-source-code` animates `max-height`+`opacity`+`translateY`, `--duration-medium`/`-fast` + `--ease-out-smooth`; revealed `<pre>` uses the standard code border |
271
+ | `:target` | method-detail gets a neutral left-rail indent treatment |
272
+
273
+ ### Code (`pre`, `code`) + copy button
274
+
275
+ | Property | Value |
276
+ |---------------|----------------------------------------------------------------|
277
+ | `pre` | mono, `code-bg`, 1px `code-border`, `radius-md`, `space-4` pad, `sm`, `x-scroll` |
278
+ | inline `code` | `code-bg`, 1px `border-subtle`, `0.125rem 0.375rem` pad, `radius-sm`, `0.9em` |
279
+ | Copy button | absolute top/right `space-2`, `2rem` square, `radius-sm`, opacity `0.6` |
280
+ | Copy hover | opacity `1`, `background-tertiary`, `translateY(-1px)`, `shadow-md` |
281
+ | Copy active | `scale(0.92)` |
282
+ | Copied | `success-bg` + green-500 border + green-600 check (green-400 in dark) |
283
+
284
+ ### Tables
285
+
286
+ `th`/`td` padding `0.2em 0.4em`, 1px `border-default`; `th` uses
287
+ `th-background`; even rows use `td-background`. On `≤480px` tables scroll
288
+ horizontally.
289
+
290
+ ### Search
291
+
292
+ | Element | Value |
293
+ |----------------------------------|-------------------------------------------------------------|
294
+ | Desktop field (`#search-field`) | full-width border-box, `space-2 space-4` pad, 1px border, `radius-md`, `base`; focus → accent border + `0 0 0 3px accent-subtle` |
295
+ | Desktop dropdown (`#search-results-desktop`) | absolute inside the search form, full-width border-box to match the field, `max-height: 60vh`, `radius-lg`, `shadow-lg`, `z-popover` (500) |
296
+ | Mobile modal (`.search-modal-content`) | centered card, `max-width: 600px`, `max-height: 80vh`, `radius-lg`, `shadow-xl` |
297
+ | Modal result item | `space-3 space-4` pad, `radius-md`, hover `background-secondary` |
298
+ | Servlet field | pill `border-radius: 1.25rem`, leading 🔍 (`\1F50D`) glyph |
299
+ | Result lines | `.search-match` `base` · `.search-namespace` `sm` secondary · `.search-snippet` `sm` tertiary |
300
+ | Type badge (`.search-type-*`) | inline-block, `space-0 space-2` pad, `xs`, weight 500, `radius-sm`, colors per §2 |
301
+ | Matched term (`li em`) | `search-highlight-bg`, `font-style: normal` |
302
+
303
+ ### Right TOC (`#table-of-contents`)
304
+
305
+ | Property | Value |
306
+ |---------------|----------------------------------------------------------------|
307
+ | Layout | sticky under header, `padding: space-8 space-6`, `border-left` hairline; its internal `.toc-nav` owns its scroll area and does not inherit left-navigation chrome |
308
+ | Heading | `lg` semibold, `text-primary` |
309
+ | Indent | `.toc-h2` `margin-left: space-4`, `.toc-h3` `space-8`; nested `ul` border-left + `space-4` pad |
310
+ | Link | block, `text-secondary`; hover `link-hover` + underline; focus-visible accent outline |
311
+ | **Active (scroll-spy)** | `accent-primary` + `font-weight: medium` |
312
+ | Visibility | hidden `≤1279px` |
313
+
314
+ ### Footer (`footer.site-footer`) + breadcrumb
315
+
316
+ Footer: `background-secondary`, `border-top`, `padding: space-12 space-6`;
317
+ columns via `repeat(auto-fit, minmax(200px, 1fr))`, gap `space-8`; column `h3`
318
+ is `sm` semibold with `letter-spacing: 0.05em`; `.footer-bottom` is centered
319
+ `xs` `text-tertiary` credit. Breadcrumb (`ol.breadcrumb`) is a wrapping flex row
320
+ at `125%` font-size; long namespace parts may wrap on narrow screens.
321
+
322
+ ## 5. Layout Principles
323
+
324
+ ### Spacing scale (`--space-*`)
325
+
326
+ ```
327
+ 1 · 2 · 3 · 4 · 5 · 6 · 8 · 12 · 16 (4 · 8 · 12 · 16 · 20 · 24 · 32 · 48 · 64 px)
328
+ ```
329
+
330
+ Non-linear above `6` — there is no `7`/`9`/`10`/`11`. Anything outside this list
331
+ is suspect; reach for the nearest token.
332
+
333
+ ### Page grid (`body`)
334
+
335
+ | Mode | Grid |
336
+ |--------------------|----------------------------------------------------------------|
337
+ | Default (2-col) | areas `header / "nav main" / "nav footer"`; columns `300px 1fr` |
338
+ | `.has-toc` (3-col) | adds a TOC column `minmax(240px, 18%)` |
339
+ | `≤1023px` | collapses to `flex` column; nav becomes an off-canvas drawer |
340
+
341
+ Key layout tokens: `sidebar-width 300px · content-max-width 800px ·
342
+ header-height 64px · search-width 400px · toc-width minmax(240px, 18%)`.
343
+
344
+ ### Reading measure & density
345
+
346
+ `main` is capped at **800 px** and centered, with `space-12 space-8` (48 / 32 px)
347
+ padding, `min-width: 0` inside the page grid, and `relaxed` (1.625) line-height
348
+ — a comfortable column for prose and signatures. The left nav and right TOC are
349
+ sticky and independently scrollable, so the reading column never jumps.
350
+
351
+ ### Alignment
352
+
353
+ - Content + nav + TOC: leading-aligned.
354
+ - Method source toggle: static trailing action inside the signature card grid.
355
+ - Centered text is reserved for empty states and the footer credit.
356
+
357
+ ## 6. Depth & Elevation
358
+
359
+ Hierarchy comes from **hairline borders, surface tinting, and a restrained
360
+ shadow set** — used together. (Unlike some flat systems, Aliki *does* use
361
+ shadows, but only for genuinely floating surfaces.)
362
+
363
+ ### Radius scale
364
+
365
+ | Radius | Usage |
366
+ |-------------------|----------------------------------------------------------|
367
+ | `sm` (4 px) | inline code, badges, copy button, source-toggle, chips |
368
+ | `md` (6 px) | `pre`, header controls, theme toggle, search field, modal (small screens) |
369
+ | `lg` (8 px) | search dropdown, search modal content |
370
+ | `1.25rem` (20 px) | servlet search field (pill) |
371
+
372
+ ### Shadow scale
373
+
374
+ | Token | Light (`rgb(0 0 0 / 10%)`) | Dark (40% opacity) | Used by |
375
+ |-------|--------------------------------------------|--------------------|------------------------|
376
+ | `sm` | `0 1px 3px`, `0 1px 2px -1px` | same geometry | header bar |
377
+ | `md` | `0 2px 8px` | same | copy-button hover |
378
+ | `lg` | `0 10px 15px -3px`, `0 4px 6px -4px` | same | nav drawer, search dropdown |
379
+ | `xl` | `0 20px 25px -5px`, `0 8px 10px -6px` | same | search modal |
380
+
381
+ ### Borders & focus
382
+
383
+ - Three hairline weights: `border-subtle` → `border-default` → `border-emphasis`.
384
+ The 1 px hairline is the primary divider everywhere (nav, header, cards, table).
385
+ - **Focus ring:** `box-shadow: 0 0 0 3px accent-subtle` on interactive controls
386
+ (theme toggle, search field, copy button) paired with an accent border.
387
+
388
+ ### Motion
389
+
390
+ | Token | Value | Where |
391
+ |-------------------|-----------------------------|----------------------------------------|
392
+ | `transition-fast` | `150ms ease-in-out` | color/background hovers |
393
+ | `transition-base` | `200ms ease-in-out` | links, chevron rotation |
394
+ | `transition-slow` | `350ms ease-in-out` | — |
395
+ | `ease-out-smooth` | `cubic-bezier(0.4, 0, 0.2, 1)` | theme-toggle icon, source reveal |
396
+ | `duration-fast/​base/​medium` | `250 / 300 / 350ms` | source-code reveal, theme icon |
397
+
398
+ Z-index ladder: `fixed 300 · modal 400 · popover 500`.
399
+
400
+ ## 7. Do's and Don'ts
401
+
402
+ ### Load-bearing guardrails
403
+
404
+ 1. **The red is fixed identity.** Reskin via other tokens freely, but **do not
405
+ change the `--color-primary-*` hue without approval** — it cascades across
406
+ headings, links, active TOC, signature borders, and badges.
407
+ 2. **Never break static / offline viewing.** Output must render with no server
408
+ on GitHub Pages and `file://`. Don't introduce anything that needs a backend
409
+ or a same-origin `fetch()`.
410
+ 3. **Accessibility bar = WCAG 2.1 AA + honor `prefers-reduced-motion`.** Treat
411
+ gaps as bugs. ⚠️ **`prefers-reduced-motion` is not yet implemented** (nav
412
+ collapse, TOC scroll, source-reveal, and `::details-content` all animate
413
+ unconditionally) — adding a reduced-motion block is the top open item (§8).
414
+ 4. **Edit light *and* dark together.** Any new color/semantic token must be
415
+ declared in both `:root` and `[data-theme="dark"]`.
416
+ 5. **Change tokens, not literals.** Components must reference `--*` tokens.
417
+
418
+ ### Do / Don't
419
+
420
+ | Don't | Do |
421
+ |-----------------------------------------------------|-----------------------------------------------------------|
422
+ | Retune the brand red | Reskin via neutrals / semantic tokens; keep the red hue |
423
+ | Hard-code hex in a component rule | Reference a semantic token (`accent-primary`, `text-…`) |
424
+ | Add a color in `:root` only | Add it to the `[data-theme="dark"]` block too |
425
+ | Use `prefers-color-scheme` for dark | Key off the `[data-theme="dark"]` attribute (JS-set) |
426
+ | Add a syntax token class without CSS | Add `.{ruby,c,sh}-*` rule **and** the emitter together |
427
+ | Ship a web font or image sprite | Stay on the system font stack; inline SVG only |
428
+ | Invent a 6th syntax color | Map onto the existing `--code-*` seven |
429
+ | Animate with no reduced-motion guard | Wrap non-essential motion in `prefers-reduced-motion` |
430
+ | Convey meaning by color alone | Pair color with text/weight (badges, emphasis) |
431
+ | Add decorative shadows | Use the `sm/md/lg/xl` set only for truly floating surfaces |
432
+
433
+ ## 8. Responsive Behavior
434
+
435
+ The generated docs are fluid; the layout adapts at five breakpoints.
436
+
437
+ | Breakpoint | Behavior |
438
+ |-----------------------|--------------------------------------------------------------------------------------------|
439
+ | `1024–1279px` | Right **TOC hidden**; `.has-toc` grid drops to 2 columns while the footer stays in the content column |
440
+ | `≤1023px` | Right **TOC hidden**; body → flex column; **left nav becomes an off-canvas drawer** (`300px`, `shadow-lg`) with an `overlay` backdrop + hamburger (`#sidebar-navigation-toggle`); desktop search swaps to a mobile **search modal**; header padding/gap tighten to `space-4` |
441
+ | `768–1023px` (tablet) | Header `0 space-6`; main `space-8 space-6`, full-width |
442
+ | `≤480px` | Nav `width: 85%` (max `320px`); main padding `space-4`; tables scroll; method heading → `base`; signature card padding tightens |
443
+ | `≤420px` | Search modal padding tightens |
444
+ | `(hover: none)` | Copy button rests at opacity `0.7` |
445
+
446
+ ### Color scheme
447
+
448
+ Dark mode is the **`[data-theme="dark"]` attribute** on the document root, set by
449
+ `theme-toggle.js` and persisted in `localStorage` (`rdoc-theme`). It is **not**
450
+ driven by `prefers-color-scheme`. Light is the default.
451
+
452
+ ### Reduced motion ⚠️ (target, not yet implemented)
453
+
454
+ The standard: under `prefers-reduced-motion: reduce`, all non-essential
455
+ transitions/animations should collapse to instant — the nav-section
456
+ `::details-content` block-size tween, the method-source-code reveal, the
457
+ theme-toggle icon spin, chevron rotations, and any smooth-scroll. This guard
458
+ does not exist yet and should be added to satisfy the AA + reduced-motion bar.
459
+
460
+ ## 9. Agent Prompt Guide
461
+
462
+ A cheat-sheet for prompting AI tools (or new contributors) to produce
463
+ Aliki-consistent UI.
464
+
465
+ ### One-line palette identifier
466
+
467
+ | Mode | accent | bg | fg | accent-hover |
468
+ |-------|-----------|-----------|-----------|--------------|
469
+ | Light | `#e62923` | `#ffffff` | `#1c1917` | `#b8211c` |
470
+ | Dark | `#eb544f` | `#1c1917` | `#fafaf9` | `#f07f7b` |
471
+
472
+ Neutral ramp (warm stone): `#fafaf9 #f5f5f4 #e7e5e4 #d6d3d1 #a8a29e #78716c #57534e #44403c #292524 #1c1917`.
473
+
474
+ ### Syntax colors (light → dark)
475
+
476
+ ```
477
+ blue #1d4ed8 → #93c5fd purple #7e22ce → #c084fc
478
+ green #047857 → #34d399 red #dc2626 → #f87171
479
+ orange #d97706 → #fbbf24 cyan #0891b2 → #22d3ee
480
+ gray #78716c → #a8a29e
481
+ ```
482
+
483
+ ### Font stacks
484
+
485
+ ```
486
+ Sans/Headings: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, … sans-serif
487
+ Mono: ui-monospace, 'SFMono-Regular', 'SF Mono', Menlo, Consolas, … monospace
488
+ (no web fonts — system stacks only)
489
+ ```
490
+
491
+ ### Ladders
492
+
493
+ ```
494
+ Type: 12 · 14 · 16 · 18 · 20 · 24 · 30 · 36 · 48 (xs…5xl)
495
+ Spacing: 4 · 8 · 12 · 16 · 20 · 24 · 32 · 48 · 64 (space-1…16)
496
+ Radius: 4 · 6 · 8 (+ 20px servlet pill)
497
+ Layout: sidebar 300 · content 800 · header 64 · search 400 · toc minmax(240, 18%)
498
+ ```
499
+
500
+ ### Ready-to-use prompt fragments
501
+
502
+ > "Use the Aliki theme: red accent `#e62923` (light) / `#eb544f` (dark), warm
503
+ > stone neutrals, page bg `#fff` / `#1c1917`, text `#1c1917` / `#fafaf9`. Body
504
+ > links are text-colored and only turn red on hover. Dark mode keys off a
505
+ > `[data-theme="dark"]` attribute, not `prefers-color-scheme`."
506
+
507
+ > "Layout: 2-column (300 px nav + 800 px content), optional 3rd TOC column
508
+ > `minmax(240px, 18%)`; 64 px sticky header. Spacing scale
509
+ > 4/8/12/16/20/24/32/48/64; radii 4/6/8. Hairline 1 px borders + a restrained
510
+ > sm/md/lg/xl shadow set for floating surfaces only."
511
+
512
+ > "Type: system sans for everything, mono for code + method headings + RBS
513
+ > signatures. Heading ladder h1 30 / h2 24 / h3 20, all in the red accent.
514
+ > Class/module page titles render the kind as a small accent badge above the
515
+ > red `3xl` object name.
516
+ > Comfortable density, 1.625 body line-height. No web fonts, no image sprites."
517
+
518
+ > "Don't retune the red hue, don't hard-code hex (use `--color-*` tokens), don't
519
+ > add a token to `:root` without the dark block, and wrap any new animation in a
520
+ > `prefers-reduced-motion` guard."
521
+
522
+ ### Where to look in `css/rdoc.css`
523
+
524
+ | Asking about… | Read this |
525
+ |----------------------|-----------------------------------------------------------------|
526
+ | Tokens (light) | `:root` — §1 banner "Design System" |
527
+ | Tokens (dark) | `[data-theme="dark"]` block |
528
+ | Layout grid | §2 "Global Styles & Layout" |
529
+ | Code / copy button | §5 "Code and Pre" |
530
+ | Header / theme toggle| §6 "Header (Top Navbar)" |
531
+ | Left nav (`#sidebar-navigation`) | §7 "Navigation (Left Sidebar)" |
532
+ | Signature cards, syntax classes | §8 "Main Content" (syntax classes ~`.ruby/.c/.sh-*`) |
533
+ | Search (modal + dropdown + badges) | §9 "Search Modal" + the `.search-results` block |
534
+ | TOC scroll-spy | §10 "Right Sidebar - Table of Contents" |
535
+ | Footer | §11 "Footer" |
536
+ | Theme attribute / persistence | `js/theme-toggle.js` (`data-theme`, `localStorage`) |
@@ -1,4 +1,4 @@
1
- <aside class="table-of-contents" role="complementary" aria-label="Table of Contents">
1
+ <aside id="table-of-contents" class="table-of-contents" role="complementary" aria-label="Table of Contents">
2
2
  <div class="toc-sticky">
3
3
  <h3 class="toc-heading">On This Page</h3>
4
4
  <nav class="toc-nav" id="toc-nav" aria-label="Page sections">
@@ -28,7 +28,7 @@
28
28
  <%- elsif @title %>
29
29
  <meta name="keywords" content="ruby,documentation,<%= h @title %>">
30
30
  <%- if @options.main_page and
31
- main_page = @files.find { |f| f.full_name == @options.main_page } then %>
31
+ main_page = @files.find { |f| f.full_name == @options.main_page } %>
32
32
  <meta
33
33
  name="description"
34
34
  content="<%= h "#{@title}: #{excerpt(main_page.comment)}" %>"
@@ -1,4 +1,4 @@
1
- <%- unless klass.extends.empty? then %>
1
+ <%- unless klass.extends.empty? %>
2
2
  <div id="extends-section" class="nav-section">
3
3
  <details class="nav-section-collapsible" open>
4
4
  <summary class="nav-section-header">
@@ -13,11 +13,13 @@
13
13
 
14
14
  <ul class="nav-list">
15
15
  <%- klass.extends.each do |ext| %>
16
- <%- unless String === ext.module then %>
17
- <li><a class="extend" href="<%= klass.aref_to ext.module.path %>"><%= ext.module.full_name %></a></li>
18
- <%- else %>
19
- <li><span class="extend"><%= ext.name %></span></li>
20
- <%- end %>
16
+ <li>
17
+ <%- unless String === ext.module %>
18
+ <a class="extend" href="<%= klass.aref_to ext.module.path %>"><%= ext.module.full_name %></a>
19
+ <%- else %>
20
+ <span class="extend"><%= ext.name %></span>
21
+ <%- end %>
22
+ </li>
21
23
  <%- end %>
22
24
  </ul>
23
25
  </details>
@@ -1,4 +1,4 @@
1
- <%- unless klass.includes.empty? then %>
1
+ <%- unless klass.includes.empty? %>
2
2
  <div id="includes-section" class="nav-section">
3
3
  <details class="nav-section-collapsible" open>
4
4
  <summary class="nav-section-header">
@@ -13,11 +13,13 @@
13
13
 
14
14
  <ul class="nav-list">
15
15
  <%- klass.includes.each do |inc| %>
16
- <%- unless String === inc.module then %>
17
- <li><a class="include" href="<%= klass.aref_to inc.module.path %>"><%= inc.module.full_name %></a></li>
18
- <%- else %>
19
- <li><span class="include"><%= inc.name %></span></li>
20
- <%- end %>
16
+ <li>
17
+ <%- unless String === inc.module %>
18
+ <a class="include" href="<%= klass.aref_to inc.module.path %>"><%= inc.module.full_name %></a>
19
+ <%- else %>
20
+ <span class="include"><%= inc.name %></span>
21
+ <%- end %>
22
+ </li>
21
23
  <%- end %>
22
24
  </ul>
23
25
  </details>
@@ -5,7 +5,7 @@
5
5
  <%- installed.each do |name, href, exists, type, _| %>
6
6
  <%- next if type == :extra %>
7
7
  <li class="folder">
8
- <%- if exists then %>
8
+ <%- if exists %>
9
9
  <a href="<%= href %>"><%= h name %></a>
10
10
  <%- else %>
11
11
  <%= h name %>
@@ -1,10 +1,10 @@
1
- <%- simple_files = @files.select { |f| f.text? } %>
1
+ <%- simple_files = @files.select { |f| f.text? && f.full_name != @options.main_page } %>
2
2
 
3
3
  <%- if defined?(current) && current.respond_to?(:page_name) %>
4
4
  <%- dir = current.full_name[%r{\A[^/]+(?=/)}] || current.page_name %>
5
5
  <%- end %>
6
6
 
7
- <%- unless simple_files.empty? then %>
7
+ <%- unless simple_files.empty? %>
8
8
  <div id="fileindex-section" class="nav-section">
9
9
  <details class="nav-section-collapsible" <%= 'open' unless @inside_class_file %>>
10
10
  <summary class="nav-section-header">
@@ -1,4 +1,4 @@
1
- <%- unless klass.sections.length == 1 then %>
1
+ <%- unless klass.sections.length == 1 %>
2
2
  <div id="sections-section" class="nav-section">
3
3
  <details class="nav-section-collapsible" open>
4
4
  <summary class="nav-section-header">
@@ -1,3 +1,3 @@
1
- <div id="navigation-toggle" role="button" tabindex="0" aria-label="Toggle sidebar" aria-expanded="true" aria-controls="navigation">
1
+ <div id="sidebar-navigation-toggle" role="button" tabindex="0" aria-label="Toggle sidebar" aria-expanded="false" aria-controls="sidebar-navigation">
2
2
  <span aria-hidden="true">&#9776;</span>
3
3
  </div>