docyard 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -1
- data/LICENSE.vscode-icons +42 -0
- data/README.md +46 -5
- data/lib/docyard/asset_handler.rb +33 -0
- data/lib/docyard/components/base_processor.rb +24 -0
- data/lib/docyard/components/callout_processor.rb +121 -0
- data/lib/docyard/components/code_block_processor.rb +55 -0
- data/lib/docyard/components/code_detector.rb +59 -0
- data/lib/docyard/components/icon_detector.rb +57 -0
- data/lib/docyard/components/icon_processor.rb +51 -0
- data/lib/docyard/components/registry.rb +34 -0
- data/lib/docyard/components/tabs_parser.rb +60 -0
- data/lib/docyard/components/tabs_processor.rb +44 -0
- data/lib/docyard/config/validator.rb +171 -0
- data/lib/docyard/config.rb +133 -0
- data/lib/docyard/constants.rb +5 -0
- data/lib/docyard/icons/LICENSE.phosphor +21 -0
- data/lib/docyard/icons/file_types.rb +92 -0
- data/lib/docyard/icons/phosphor.rb +63 -0
- data/lib/docyard/icons.rb +40 -0
- data/lib/docyard/initializer.rb +20 -2
- data/lib/docyard/language_mapping.rb +52 -0
- data/lib/docyard/markdown.rb +14 -3
- data/lib/docyard/rack_application.rb +76 -7
- data/lib/docyard/renderer.rb +40 -7
- data/lib/docyard/server.rb +5 -2
- data/lib/docyard/sidebar_builder.rb +10 -2
- data/lib/docyard/templates/assets/css/code.css +150 -2
- data/lib/docyard/templates/assets/css/components/callout.css +169 -0
- data/lib/docyard/templates/assets/css/components/code-block.css +196 -0
- data/lib/docyard/templates/assets/css/components/icon.css +16 -0
- data/lib/docyard/templates/assets/css/components/logo.css +44 -0
- data/lib/docyard/templates/assets/css/{components.css → components/navigation.css} +47 -47
- data/lib/docyard/templates/assets/css/components/tabs.css +298 -0
- data/lib/docyard/templates/assets/css/components/theme-toggle.css +61 -0
- data/lib/docyard/templates/assets/css/layout.css +14 -4
- data/lib/docyard/templates/assets/css/markdown.css +9 -8
- data/lib/docyard/templates/assets/css/reset.css +4 -0
- data/lib/docyard/templates/assets/css/variables.css +94 -3
- data/lib/docyard/templates/assets/favicon.svg +16 -0
- data/lib/docyard/templates/assets/js/components/code-block.js +162 -0
- data/lib/docyard/templates/assets/js/components/tabs.js +338 -0
- data/lib/docyard/templates/assets/js/theme.js +16 -0
- data/lib/docyard/templates/assets/logo-dark.svg +4 -0
- data/lib/docyard/templates/assets/logo.svg +12 -0
- data/lib/docyard/templates/config/docyard.yml.erb +20 -0
- data/lib/docyard/templates/layouts/default.html.erb +31 -3
- data/lib/docyard/templates/markdown/components/callouts.md.erb +204 -0
- data/lib/docyard/templates/markdown/components/icons.md.erb +125 -0
- data/lib/docyard/templates/markdown/components/tabs.md.erb +686 -0
- data/lib/docyard/templates/markdown/configuration.md.erb +202 -0
- data/lib/docyard/templates/partials/_callout.html.erb +11 -0
- data/lib/docyard/templates/partials/_code_block.html.erb +6 -0
- data/lib/docyard/templates/partials/_icon.html.erb +1 -0
- data/lib/docyard/templates/partials/_icon_file_extension.html.erb +1 -0
- data/lib/docyard/templates/partials/_tabs.html.erb +40 -0
- data/lib/docyard/templates/partials/_theme_toggle.html.erb +13 -0
- data/lib/docyard/version.rb +1 -1
- metadata +41 -2
|
@@ -0,0 +1,686 @@
|
|
|
1
|
+
# Code Tabs
|
|
2
|
+
|
|
3
|
+
Docyard supports interactive code tabs to display multiple code examples or package manager installation commands in a space-efficient way. Users can switch between tabs, and their preference is automatically saved.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
### Package Manager Installation
|
|
8
|
+
|
|
9
|
+
The most common use case is showing installation commands for different package managers:
|
|
10
|
+
|
|
11
|
+
:::tabs
|
|
12
|
+
== npm
|
|
13
|
+
```bash
|
|
14
|
+
npm install docyard
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
== yarn
|
|
18
|
+
```bash
|
|
19
|
+
yarn add docyard
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
== pnpm
|
|
23
|
+
```bash
|
|
24
|
+
pnpm add docyard
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
== bun
|
|
28
|
+
```bash
|
|
29
|
+
bun add docyard
|
|
30
|
+
```
|
|
31
|
+
:::
|
|
32
|
+
|
|
33
|
+
## Tab Icons
|
|
34
|
+
|
|
35
|
+
Tabs automatically display icons to make them more visually distinctive and easier to scan. Icons can be specified manually or detected automatically from code blocks.
|
|
36
|
+
|
|
37
|
+
### Auto-Detected Icons
|
|
38
|
+
|
|
39
|
+
When your tab contains a code block, Docyard automatically detects the programming language and displays the appropriate icon:
|
|
40
|
+
|
|
41
|
+
:::tabs
|
|
42
|
+
== JavaScript
|
|
43
|
+
```javascript
|
|
44
|
+
const greeting = "Hello, World!";
|
|
45
|
+
console.log(greeting);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
== Python
|
|
49
|
+
```python
|
|
50
|
+
greeting = "Hello, World!"
|
|
51
|
+
print(greeting)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
== Ruby
|
|
55
|
+
```ruby
|
|
56
|
+
greeting = "Hello, World!"
|
|
57
|
+
puts greeting
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
== Go
|
|
61
|
+
```go
|
|
62
|
+
package main
|
|
63
|
+
import "fmt"
|
|
64
|
+
|
|
65
|
+
func main() {
|
|
66
|
+
fmt.Println("Hello, World!")
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
:::
|
|
70
|
+
|
|
71
|
+
The following languages are automatically detected and display their brand icons:
|
|
72
|
+
|
|
73
|
+
| Language | Aliases | Icon Source |
|
|
74
|
+
|----------|---------|-------------|
|
|
75
|
+
| JavaScript | `js` | Simple Icons |
|
|
76
|
+
| TypeScript | `ts` | Simple Icons |
|
|
77
|
+
| Python | `py` | Simple Icons |
|
|
78
|
+
| Ruby | `rb` | Simple Icons |
|
|
79
|
+
| Go | `golang` | Simple Icons |
|
|
80
|
+
| Rust | `rs` | Simple Icons |
|
|
81
|
+
| PHP | - | Simple Icons |
|
|
82
|
+
| HTML | `html5`, `htm` | Simple Icons |
|
|
83
|
+
| CSS | - | Simple Icons |
|
|
84
|
+
| C | - | Simple Icons |
|
|
85
|
+
| C++ | `cpp`, `cxx`, `c++` | Simple Icons |
|
|
86
|
+
| SQL | - | PostgreSQL icon |
|
|
87
|
+
| Bash | `sh`, `shell` | Simple Icons |
|
|
88
|
+
| Swift | - | Simple Icons |
|
|
89
|
+
| Kotlin | `kt` | Simple Icons |
|
|
90
|
+
| Elixir | `ex` | Simple Icons |
|
|
91
|
+
| Dart | - | Simple Icons |
|
|
92
|
+
| Scala | - | Simple Icons |
|
|
93
|
+
|
|
94
|
+
### Manual Icons
|
|
95
|
+
|
|
96
|
+
You can specify a custom icon using the `:icon-name:` syntax at the start of your tab name:
|
|
97
|
+
|
|
98
|
+
:::tabs
|
|
99
|
+
== :package: npm
|
|
100
|
+
```bash
|
|
101
|
+
npm install docyard
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
== :cube: yarn
|
|
105
|
+
```bash
|
|
106
|
+
yarn add docyard
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
== :rocket: Quick Start
|
|
110
|
+
Get started in seconds with our CLI tool.
|
|
111
|
+
|
|
112
|
+
== :gear: Configuration
|
|
113
|
+
Customize Docyard to fit your needs.
|
|
114
|
+
:::
|
|
115
|
+
|
|
116
|
+
Manual icons use the [Phosphor Icons](https://phosphoricons.com) library, giving you access to hundreds of beautiful icons.
|
|
117
|
+
|
|
118
|
+
### Icon Fallback
|
|
119
|
+
|
|
120
|
+
If a tab doesn't have a manual icon specified and doesn't contain a recognized code block, it will display a generic code icon from Phosphor Icons.
|
|
121
|
+
|
|
122
|
+
:::tabs
|
|
123
|
+
== Overview
|
|
124
|
+
This tab shows markdown content without a code block, so it gets the default code icon.
|
|
125
|
+
|
|
126
|
+
== JavaScript
|
|
127
|
+
```javascript
|
|
128
|
+
// This tab auto-detects the JavaScript icon
|
|
129
|
+
console.log("Hello!");
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
== :star: Featured
|
|
133
|
+
Manual icon takes precedence over auto-detection.
|
|
134
|
+
:::
|
|
135
|
+
|
|
136
|
+
## Programming Language Examples
|
|
137
|
+
|
|
138
|
+
Show the same functionality in different programming languages:
|
|
139
|
+
|
|
140
|
+
:::tabs
|
|
141
|
+
== JavaScript
|
|
142
|
+
```javascript
|
|
143
|
+
function greet(name) {
|
|
144
|
+
return `Hello, ${name}!`;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
console.log(greet('World'));
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
== TypeScript
|
|
151
|
+
```typescript
|
|
152
|
+
function greet(name: string): string {
|
|
153
|
+
return `Hello, ${name}!`;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
console.log(greet('World'));
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
== Ruby
|
|
160
|
+
```ruby
|
|
161
|
+
def greet(name)
|
|
162
|
+
"Hello, #{name}!"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
puts greet('World')
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
== Python
|
|
169
|
+
```python
|
|
170
|
+
def greet(name):
|
|
171
|
+
return f"Hello, {name}!"
|
|
172
|
+
|
|
173
|
+
print(greet('World'))
|
|
174
|
+
```
|
|
175
|
+
:::
|
|
176
|
+
|
|
177
|
+
## Framework-Specific Examples
|
|
178
|
+
|
|
179
|
+
Compare syntax across different frameworks:
|
|
180
|
+
|
|
181
|
+
:::tabs
|
|
182
|
+
== React
|
|
183
|
+
```jsx
|
|
184
|
+
import { useState } from 'react';
|
|
185
|
+
|
|
186
|
+
export default function Counter() {
|
|
187
|
+
const [count, setCount] = useState(0);
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<button onClick={() => setCount(count + 1)}>
|
|
191
|
+
Count: {count}
|
|
192
|
+
</button>
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
== Vue
|
|
198
|
+
```vue
|
|
199
|
+
<template>
|
|
200
|
+
<button @click="count++">
|
|
201
|
+
Count: {{ count }}
|
|
202
|
+
</button>
|
|
203
|
+
</template>
|
|
204
|
+
|
|
205
|
+
<script setup>
|
|
206
|
+
import { ref } from 'vue';
|
|
207
|
+
|
|
208
|
+
const count = ref(0);
|
|
209
|
+
</script>
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
== Svelte
|
|
213
|
+
```svelte
|
|
214
|
+
<script>
|
|
215
|
+
let count = 0;
|
|
216
|
+
</script>
|
|
217
|
+
|
|
218
|
+
<button on:click={() => count++}>
|
|
219
|
+
Count: {count}
|
|
220
|
+
</button>
|
|
221
|
+
```
|
|
222
|
+
:::
|
|
223
|
+
|
|
224
|
+
## Configuration Files
|
|
225
|
+
|
|
226
|
+
Show different configuration formats:
|
|
227
|
+
|
|
228
|
+
:::tabs
|
|
229
|
+
== JSON
|
|
230
|
+
```json
|
|
231
|
+
{
|
|
232
|
+
"name": "docyard",
|
|
233
|
+
"version": "1.0.0",
|
|
234
|
+
"main": "index.js",
|
|
235
|
+
"scripts": {
|
|
236
|
+
"start": "node index.js",
|
|
237
|
+
"test": "jest"
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
== YAML
|
|
243
|
+
```yaml
|
|
244
|
+
name: docyard
|
|
245
|
+
version: 1.0.0
|
|
246
|
+
main: index.js
|
|
247
|
+
scripts:
|
|
248
|
+
start: node index.js
|
|
249
|
+
test: jest
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
== TOML
|
|
253
|
+
```toml
|
|
254
|
+
name = "docyard"
|
|
255
|
+
version = "1.0.0"
|
|
256
|
+
main = "index.js"
|
|
257
|
+
|
|
258
|
+
[scripts]
|
|
259
|
+
start = "node index.js"
|
|
260
|
+
test = "jest"
|
|
261
|
+
```
|
|
262
|
+
:::
|
|
263
|
+
|
|
264
|
+
## Rich Markdown Content
|
|
265
|
+
|
|
266
|
+
Tabs support all markdown features, not just code blocks:
|
|
267
|
+
|
|
268
|
+
:::tabs
|
|
269
|
+
== Overview
|
|
270
|
+
# Getting Started
|
|
271
|
+
|
|
272
|
+
Welcome to Docyard! This tab contains **rich markdown** content.
|
|
273
|
+
|
|
274
|
+
- Easy to use
|
|
275
|
+
- Fully customizable
|
|
276
|
+
- Dark mode support
|
|
277
|
+
|
|
278
|
+
Learn more in the [documentation](https://github.com).
|
|
279
|
+
|
|
280
|
+
== Installation
|
|
281
|
+
Install Docyard using your preferred package manager:
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
gem install docyard
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Then initialize a new project:
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
docyard init my-docs
|
|
291
|
+
cd my-docs
|
|
292
|
+
docyard serve
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
== Configuration
|
|
296
|
+
You can customize Docyard by creating a `docyard.yml` file:
|
|
297
|
+
|
|
298
|
+
```yaml
|
|
299
|
+
title: My Documentation
|
|
300
|
+
theme: default
|
|
301
|
+
sidebar:
|
|
302
|
+
- Home
|
|
303
|
+
- Getting Started
|
|
304
|
+
- API Reference
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
See the configuration guide for all available options.
|
|
308
|
+
:::
|
|
309
|
+
|
|
310
|
+
## Multiple Tab Groups
|
|
311
|
+
|
|
312
|
+
You can use multiple tab groups in the same document:
|
|
313
|
+
|
|
314
|
+
### Client Installation
|
|
315
|
+
|
|
316
|
+
:::tabs
|
|
317
|
+
== npm
|
|
318
|
+
```bash
|
|
319
|
+
npm install @docyard/client
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
== yarn
|
|
323
|
+
```bash
|
|
324
|
+
yarn add @docyard/client
|
|
325
|
+
```
|
|
326
|
+
:::
|
|
327
|
+
|
|
328
|
+
### Server Installation
|
|
329
|
+
|
|
330
|
+
:::tabs
|
|
331
|
+
== npm
|
|
332
|
+
```bash
|
|
333
|
+
npm install @docyard/server
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
== yarn
|
|
337
|
+
```bash
|
|
338
|
+
yarn add @docyard/server
|
|
339
|
+
```
|
|
340
|
+
:::
|
|
341
|
+
|
|
342
|
+
## API Comparison
|
|
343
|
+
|
|
344
|
+
Compare different API approaches:
|
|
345
|
+
|
|
346
|
+
:::tabs
|
|
347
|
+
== REST API
|
|
348
|
+
```javascript
|
|
349
|
+
// Fetch user data
|
|
350
|
+
fetch('/api/users/123')
|
|
351
|
+
.then(response => response.json())
|
|
352
|
+
.then(user => console.log(user));
|
|
353
|
+
|
|
354
|
+
// Create new user
|
|
355
|
+
fetch('/api/users', {
|
|
356
|
+
method: 'POST',
|
|
357
|
+
headers: { 'Content-Type': 'application/json' },
|
|
358
|
+
body: JSON.stringify({ name: 'John Doe' })
|
|
359
|
+
});
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
== GraphQL
|
|
363
|
+
```graphql
|
|
364
|
+
# Fetch user data
|
|
365
|
+
query GetUser {
|
|
366
|
+
user(id: "123") {
|
|
367
|
+
id
|
|
368
|
+
name
|
|
369
|
+
email
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
# Create new user
|
|
374
|
+
mutation CreateUser {
|
|
375
|
+
createUser(input: { name: "John Doe" }) {
|
|
376
|
+
id
|
|
377
|
+
name
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
== gRPC
|
|
383
|
+
```protobuf
|
|
384
|
+
// user.proto
|
|
385
|
+
service UserService {
|
|
386
|
+
rpc GetUser (GetUserRequest) returns (User);
|
|
387
|
+
rpc CreateUser (CreateUserRequest) returns (User);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
message User {
|
|
391
|
+
string id = 1;
|
|
392
|
+
string name = 2;
|
|
393
|
+
string email = 3;
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
:::
|
|
397
|
+
|
|
398
|
+
## Environment-Specific Code
|
|
399
|
+
|
|
400
|
+
Show different code for different environments:
|
|
401
|
+
|
|
402
|
+
:::tabs
|
|
403
|
+
== Development
|
|
404
|
+
```javascript
|
|
405
|
+
const config = {
|
|
406
|
+
apiUrl: 'http://localhost:3000',
|
|
407
|
+
debug: true,
|
|
408
|
+
logLevel: 'verbose',
|
|
409
|
+
cache: false
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
// Development-specific logging
|
|
413
|
+
console.log('Running in development mode');
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
== Production
|
|
417
|
+
```javascript
|
|
418
|
+
const config = {
|
|
419
|
+
apiUrl: 'https://api.production.com',
|
|
420
|
+
debug: false,
|
|
421
|
+
logLevel: 'error',
|
|
422
|
+
cache: true
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
// Production optimizations enabled
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
== Testing
|
|
429
|
+
```javascript
|
|
430
|
+
const config = {
|
|
431
|
+
apiUrl: 'http://localhost:3001',
|
|
432
|
+
debug: true,
|
|
433
|
+
logLevel: 'info',
|
|
434
|
+
cache: false,
|
|
435
|
+
mockData: true
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
// Test environment with mocks
|
|
439
|
+
```
|
|
440
|
+
:::
|
|
441
|
+
|
|
442
|
+
## Platform-Specific Instructions
|
|
443
|
+
|
|
444
|
+
Provide instructions for different operating systems:
|
|
445
|
+
|
|
446
|
+
:::tabs
|
|
447
|
+
== macOS
|
|
448
|
+
Install the required dependencies:
|
|
449
|
+
|
|
450
|
+
```bash
|
|
451
|
+
brew install ruby
|
|
452
|
+
brew install node
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Then install Docyard:
|
|
456
|
+
|
|
457
|
+
```bash
|
|
458
|
+
gem install docyard
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
== Linux
|
|
462
|
+
Install the required dependencies:
|
|
463
|
+
|
|
464
|
+
```bash
|
|
465
|
+
sudo apt-get update
|
|
466
|
+
sudo apt-get install ruby-full nodejs npm
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
Then install Docyard:
|
|
470
|
+
|
|
471
|
+
```bash
|
|
472
|
+
sudo gem install docyard
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
== Windows
|
|
476
|
+
Download and install:
|
|
477
|
+
- [Ruby for Windows](https://rubyinstaller.org/)
|
|
478
|
+
- [Node.js for Windows](https://nodejs.org/)
|
|
479
|
+
|
|
480
|
+
Then open PowerShell and run:
|
|
481
|
+
|
|
482
|
+
```powershell
|
|
483
|
+
gem install docyard
|
|
484
|
+
```
|
|
485
|
+
:::
|
|
486
|
+
|
|
487
|
+
## Database Queries
|
|
488
|
+
|
|
489
|
+
Compare query syntax across different databases:
|
|
490
|
+
|
|
491
|
+
:::tabs
|
|
492
|
+
== PostgreSQL
|
|
493
|
+
```sql
|
|
494
|
+
SELECT u.name, COUNT(p.id) as post_count
|
|
495
|
+
FROM users u
|
|
496
|
+
LEFT JOIN posts p ON u.id = p.user_id
|
|
497
|
+
WHERE u.created_at > '2024-01-01'
|
|
498
|
+
GROUP BY u.id, u.name
|
|
499
|
+
ORDER BY post_count DESC
|
|
500
|
+
LIMIT 10;
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
== MySQL
|
|
504
|
+
```sql
|
|
505
|
+
SELECT u.name, COUNT(p.id) as post_count
|
|
506
|
+
FROM users u
|
|
507
|
+
LEFT JOIN posts p ON u.id = p.user_id
|
|
508
|
+
WHERE u.created_at > '2024-01-01'
|
|
509
|
+
GROUP BY u.id, u.name
|
|
510
|
+
ORDER BY post_count DESC
|
|
511
|
+
LIMIT 10;
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
== MongoDB
|
|
515
|
+
```javascript
|
|
516
|
+
db.users.aggregate([
|
|
517
|
+
{
|
|
518
|
+
$match: {
|
|
519
|
+
created_at: { $gt: new Date('2024-01-01') }
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
$lookup: {
|
|
524
|
+
from: 'posts',
|
|
525
|
+
localField: '_id',
|
|
526
|
+
foreignField: 'user_id',
|
|
527
|
+
as: 'posts'
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
$project: {
|
|
532
|
+
name: 1,
|
|
533
|
+
post_count: { $size: '$posts' }
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
{ $sort: { post_count: -1 } },
|
|
537
|
+
{ $limit: 10 }
|
|
538
|
+
]);
|
|
539
|
+
```
|
|
540
|
+
:::
|
|
541
|
+
|
|
542
|
+
## Testing Frameworks
|
|
543
|
+
|
|
544
|
+
Show examples for different testing frameworks:
|
|
545
|
+
|
|
546
|
+
:::tabs
|
|
547
|
+
== Jest
|
|
548
|
+
```javascript
|
|
549
|
+
describe('Calculator', () => {
|
|
550
|
+
test('adds two numbers', () => {
|
|
551
|
+
expect(add(2, 3)).toBe(5);
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
test('subtracts two numbers', () => {
|
|
555
|
+
expect(subtract(5, 3)).toBe(2);
|
|
556
|
+
});
|
|
557
|
+
});
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
== RSpec
|
|
561
|
+
```ruby
|
|
562
|
+
RSpec.describe Calculator do
|
|
563
|
+
describe '#add' do
|
|
564
|
+
it 'adds two numbers' do
|
|
565
|
+
expect(calculator.add(2, 3)).to eq(5)
|
|
566
|
+
end
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
describe '#subtract' do
|
|
570
|
+
it 'subtracts two numbers' do
|
|
571
|
+
expect(calculator.subtract(5, 3)).to eq(2)
|
|
572
|
+
end
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
== pytest
|
|
578
|
+
```python
|
|
579
|
+
def test_add():
|
|
580
|
+
assert add(2, 3) == 5
|
|
581
|
+
|
|
582
|
+
def test_subtract():
|
|
583
|
+
assert subtract(5, 3) == 2
|
|
584
|
+
```
|
|
585
|
+
:::
|
|
586
|
+
|
|
587
|
+
## Advanced Features
|
|
588
|
+
|
|
589
|
+
### Keyboard Navigation
|
|
590
|
+
|
|
591
|
+
Tabs are fully keyboard accessible:
|
|
592
|
+
|
|
593
|
+
- **Tab**: Focus on the tab list
|
|
594
|
+
- **Arrow Left/Right**: Navigate between tabs
|
|
595
|
+
- **Home**: Jump to first tab
|
|
596
|
+
- **End**: Jump to last tab
|
|
597
|
+
- **Enter/Space**: Activate focused tab
|
|
598
|
+
- **Tab** (again): Move to tab panel content
|
|
599
|
+
|
|
600
|
+
### Persistent Preferences
|
|
601
|
+
|
|
602
|
+
The tabs component automatically remembers your package manager preference using localStorage. If you select "pnpm" in one tab group, all package manager tab groups will default to "pnpm" on subsequent page loads.
|
|
603
|
+
|
|
604
|
+
### Accessibility
|
|
605
|
+
|
|
606
|
+
All tabs include proper ARIA attributes for screen readers:
|
|
607
|
+
|
|
608
|
+
- `role="tablist"` for the tab container
|
|
609
|
+
- `role="tab"` for each tab button
|
|
610
|
+
- `role="tabpanel"` for each content panel
|
|
611
|
+
- `aria-selected` to indicate active tab
|
|
612
|
+
- `aria-controls` linking tabs to panels
|
|
613
|
+
- `aria-labelledby` linking panels to tabs
|
|
614
|
+
- `aria-hidden` to hide inactive panels
|
|
615
|
+
|
|
616
|
+
### Dark Mode
|
|
617
|
+
|
|
618
|
+
Tabs automatically adapt to dark mode with:
|
|
619
|
+
|
|
620
|
+
- Enhanced contrast for readability
|
|
621
|
+
- Subtle visual indicators
|
|
622
|
+
- Smooth animations (respects `prefers-reduced-motion`)
|
|
623
|
+
|
|
624
|
+
## Best Practices
|
|
625
|
+
|
|
626
|
+
::: tip When to Use Tabs
|
|
627
|
+
Use tabs when you need to show:
|
|
628
|
+
- **Alternative implementations** of the same functionality
|
|
629
|
+
- **Different package managers** or installation methods
|
|
630
|
+
- **Multiple programming languages** for the same example
|
|
631
|
+
- **Platform-specific instructions** (OS, frameworks, etc.)
|
|
632
|
+
- **Environment-specific configurations** (dev, prod, test)
|
|
633
|
+
:::
|
|
634
|
+
|
|
635
|
+
::: warning When Not to Use Tabs
|
|
636
|
+
Avoid using tabs for:
|
|
637
|
+
- **Sequential content** that should be read in order (use numbered steps instead)
|
|
638
|
+
- **Unrelated content** (use separate sections instead)
|
|
639
|
+
- **Single option** (just show the code directly)
|
|
640
|
+
- **Too many tabs** (>6 tabs becomes hard to navigate)
|
|
641
|
+
:::
|
|
642
|
+
|
|
643
|
+
## Syntax Reference
|
|
644
|
+
|
|
645
|
+
Basic syntax:
|
|
646
|
+
|
|
647
|
+
```markdown
|
|
648
|
+
:::tabs
|
|
649
|
+
== Tab Name 1
|
|
650
|
+
Content for tab 1
|
|
651
|
+
|
|
652
|
+
== Tab Name 2
|
|
653
|
+
Content for tab 2
|
|
654
|
+
|
|
655
|
+
== Tab Name 3
|
|
656
|
+
Content for tab 3
|
|
657
|
+
:::
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
### Tab Names
|
|
661
|
+
|
|
662
|
+
Tab names support:
|
|
663
|
+
- Letters, numbers, and spaces
|
|
664
|
+
- Special characters (e.g., "Node.js", "C++", "C#")
|
|
665
|
+
- Unicode characters
|
|
666
|
+
|
|
667
|
+
### Content
|
|
668
|
+
|
|
669
|
+
Each tab can contain:
|
|
670
|
+
- **Code blocks** with syntax highlighting
|
|
671
|
+
- **Markdown formatting** (bold, italic, links)
|
|
672
|
+
- **Lists** (ordered and unordered)
|
|
673
|
+
- **Headings** and paragraphs
|
|
674
|
+
- **Tables** and blockquotes
|
|
675
|
+
- **Images** and other media
|
|
676
|
+
- **Nested markdown** of any complexity
|
|
677
|
+
|
|
678
|
+
## Examples in Action
|
|
679
|
+
|
|
680
|
+
::: note
|
|
681
|
+
Throughout the Docyard documentation, you'll see tabs used to provide multiple implementation options, making it easy for users to find exactly what they need for their specific setup.
|
|
682
|
+
:::
|
|
683
|
+
|
|
684
|
+
::: tip Try It Yourself
|
|
685
|
+
Create your own tabs in your documentation to improve the user experience when showing multiple code examples or alternatives!
|
|
686
|
+
:::
|