docyard 0.6.0 → 0.7.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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -1
  3. data/lib/docyard/build/static_generator.rb +2 -43
  4. data/lib/docyard/builder.rb +14 -4
  5. data/lib/docyard/cli.rb +6 -3
  6. data/lib/docyard/components/aliases.rb +29 -0
  7. data/lib/docyard/components/processors/callout_processor.rb +124 -0
  8. data/lib/docyard/components/processors/code_block_diff_preprocessor.rb +106 -0
  9. data/lib/docyard/components/processors/code_block_focus_preprocessor.rb +79 -0
  10. data/lib/docyard/components/processors/code_block_options_preprocessor.rb +78 -0
  11. data/lib/docyard/components/processors/code_block_processor.rb +175 -0
  12. data/lib/docyard/components/processors/code_snippet_import_preprocessor.rb +127 -0
  13. data/lib/docyard/components/processors/heading_anchor_processor.rb +39 -0
  14. data/lib/docyard/components/processors/icon_processor.rb +53 -0
  15. data/lib/docyard/components/processors/table_of_contents_processor.rb +68 -0
  16. data/lib/docyard/components/processors/table_wrapper_processor.rb +22 -0
  17. data/lib/docyard/components/processors/tabs_processor.rb +48 -0
  18. data/lib/docyard/components/support/code_block/feature_extractor.rb +117 -0
  19. data/lib/docyard/components/support/code_block/icon_detector.rb +44 -0
  20. data/lib/docyard/components/support/code_block/line_parser.rb +84 -0
  21. data/lib/docyard/components/support/code_block/line_wrapper.rb +50 -0
  22. data/lib/docyard/components/support/code_block/patterns.rb +55 -0
  23. data/lib/docyard/components/support/code_detector.rb +61 -0
  24. data/lib/docyard/components/support/tabs/icon_detector.rb +62 -0
  25. data/lib/docyard/components/support/tabs/parser.rb +195 -0
  26. data/lib/docyard/components/support/tabs/range_finder.rb +46 -0
  27. data/lib/docyard/config/branding_resolver.rb +74 -0
  28. data/lib/docyard/{constants.rb → config/constants.rb} +1 -0
  29. data/lib/docyard/config.rb +10 -1
  30. data/lib/docyard/{prev_next_builder.rb → navigation/prev_next_builder.rb} +2 -2
  31. data/lib/docyard/{sidebar → navigation/sidebar}/renderer.rb +3 -14
  32. data/lib/docyard/{sidebar → navigation/sidebar}/tree_builder.rb +9 -2
  33. data/lib/docyard/{sidebar_builder.rb → navigation/sidebar_builder.rb} +3 -15
  34. data/lib/docyard/{icons → rendering/icons}/phosphor.rb +4 -1
  35. data/lib/docyard/{markdown.rb → rendering/markdown.rb} +14 -13
  36. data/lib/docyard/{renderer.rb → rendering/renderer.rb} +20 -17
  37. data/lib/docyard/search/build_indexer.rb +74 -0
  38. data/lib/docyard/search/dev_indexer.rb +110 -0
  39. data/lib/docyard/search/pagefind_support.rb +31 -0
  40. data/lib/docyard/{asset_handler.rb → server/asset_handler.rb} +1 -1
  41. data/lib/docyard/{server.rb → server/dev_server.rb} +32 -9
  42. data/lib/docyard/{preview_server.rb → server/preview_server.rb} +1 -1
  43. data/lib/docyard/{rack_application.rb → server/rack_application.rb} +52 -49
  44. data/lib/docyard/server/resolution_result.rb +29 -0
  45. data/lib/docyard/{router.rb → server/router.rb} +4 -4
  46. data/lib/docyard/templates/assets/css/components/search.css +549 -0
  47. data/lib/docyard/templates/assets/css/layout.css +15 -1
  48. data/lib/docyard/templates/assets/js/components/search.js +685 -0
  49. data/lib/docyard/templates/layouts/default.html.erb +14 -2
  50. data/lib/docyard/templates/partials/_code_block.html.erb +1 -1
  51. data/lib/docyard/templates/partials/_heading_anchor.html.erb +1 -1
  52. data/lib/docyard/templates/partials/_prev_next.html.erb +1 -1
  53. data/lib/docyard/templates/partials/_search_modal.html.erb +45 -0
  54. data/lib/docyard/templates/partials/_search_trigger.html.erb +22 -0
  55. data/lib/docyard/utils/html_helpers.rb +14 -0
  56. data/lib/docyard/utils/path_resolver.rb +2 -1
  57. data/lib/docyard/utils/url_helpers.rb +20 -0
  58. data/lib/docyard/version.rb +1 -1
  59. data/lib/docyard.rb +22 -15
  60. metadata +57 -46
  61. data/lib/docyard/components/callout_processor.rb +0 -121
  62. data/lib/docyard/components/code_block_diff_preprocessor.rb +0 -104
  63. data/lib/docyard/components/code_block_feature_extractor.rb +0 -113
  64. data/lib/docyard/components/code_block_focus_preprocessor.rb +0 -77
  65. data/lib/docyard/components/code_block_icon_detector.rb +0 -40
  66. data/lib/docyard/components/code_block_line_wrapper.rb +0 -46
  67. data/lib/docyard/components/code_block_options_preprocessor.rb +0 -76
  68. data/lib/docyard/components/code_block_patterns.rb +0 -51
  69. data/lib/docyard/components/code_block_processor.rb +0 -176
  70. data/lib/docyard/components/code_detector.rb +0 -59
  71. data/lib/docyard/components/code_line_parser.rb +0 -80
  72. data/lib/docyard/components/code_snippet_import_preprocessor.rb +0 -125
  73. data/lib/docyard/components/heading_anchor_processor.rb +0 -34
  74. data/lib/docyard/components/icon_detector.rb +0 -57
  75. data/lib/docyard/components/icon_processor.rb +0 -51
  76. data/lib/docyard/components/table_of_contents_processor.rb +0 -64
  77. data/lib/docyard/components/table_wrapper_processor.rb +0 -18
  78. data/lib/docyard/components/tabs_parser.rb +0 -191
  79. data/lib/docyard/components/tabs_processor.rb +0 -44
  80. data/lib/docyard/components/tabs_range_finder.rb +0 -42
  81. data/lib/docyard/routing/resolution_result.rb +0 -31
  82. /data/lib/docyard/{sidebar → navigation/sidebar}/config_parser.rb +0 -0
  83. /data/lib/docyard/{sidebar → navigation/sidebar}/file_system_scanner.rb +0 -0
  84. /data/lib/docyard/{sidebar → navigation/sidebar}/item.rb +0 -0
  85. /data/lib/docyard/{sidebar → navigation/sidebar}/title_extractor.rb +0 -0
  86. /data/lib/docyard/{icons → rendering/icons}/LICENSE.phosphor +0 -0
  87. /data/lib/docyard/{icons → rendering/icons}/file_types.rb +0 -0
  88. /data/lib/docyard/{icons.rb → rendering/icons.rb} +0 -0
  89. /data/lib/docyard/{language_mapping.rb → rendering/language_mapping.rb} +0 -0
  90. /data/lib/docyard/{file_watcher.rb → server/file_watcher.rb} +0 -0
  91. /data/lib/docyard/{errors.rb → utils/errors.rb} +0 -0
  92. /data/lib/docyard/{logging.rb → utils/logging.rb} +0 -0
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Docyard
4
+ class ResolutionResult
5
+ attr_reader :file_path, :status
6
+
7
+ def self.found(file_path)
8
+ new(file_path: file_path, status: :found)
9
+ end
10
+
11
+ def self.not_found
12
+ new(file_path: nil, status: :not_found)
13
+ end
14
+
15
+ def initialize(file_path:, status:)
16
+ @file_path = file_path
17
+ @status = status
18
+ freeze
19
+ end
20
+
21
+ def found?
22
+ status == :found
23
+ end
24
+
25
+ def not_found?
26
+ status == :not_found
27
+ end
28
+ end
29
+ end
@@ -12,18 +12,18 @@ module Docyard
12
12
  clean_path = sanitize_path(request_path)
13
13
 
14
14
  file_path = File.join(docs_path, "#{clean_path}#{Constants::MARKDOWN_EXTENSION}")
15
- return Routing::ResolutionResult.found(file_path) if File.file?(file_path)
15
+ return ResolutionResult.found(file_path) if File.file?(file_path)
16
16
 
17
17
  index_path = File.join(docs_path, clean_path, "#{Constants::INDEX_FILE}#{Constants::MARKDOWN_EXTENSION}")
18
- return Routing::ResolutionResult.found(index_path) if File.file?(index_path)
18
+ return ResolutionResult.found(index_path) if File.file?(index_path)
19
19
 
20
- Routing::ResolutionResult.not_found
20
+ ResolutionResult.not_found
21
21
  end
22
22
 
23
23
  private
24
24
 
25
25
  def sanitize_path(request_path)
26
- clean = request_path.delete_prefix("/")
26
+ clean = request_path.delete_prefix("/").delete_suffix("/")
27
27
  clean = Constants::INDEX_FILE if clean.empty?
28
28
  clean.delete_suffix(Constants::MARKDOWN_EXTENSION)
29
29
  end
@@ -0,0 +1,549 @@
1
+ /* Search Trigger Button */
2
+ .search-trigger {
3
+ display: flex;
4
+ align-items: center;
5
+ gap: var(--space-3);
6
+ padding: 8px 14px;
7
+ background-color: var(--color-bg-secondary);
8
+ border: 1px solid var(--color-border);
9
+ border-radius: 12px;
10
+ cursor: pointer;
11
+ color: var(--color-text-tertiary);
12
+ font-size: var(--text-xs);
13
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
14
+ min-width: 280px;
15
+ }
16
+
17
+ .search-trigger:hover {
18
+ border-color: var(--color-border-secondary);
19
+ }
20
+
21
+ .search-trigger:focus-visible {
22
+ outline: 2px solid var(--color-primary);
23
+ outline-offset: 2px;
24
+ }
25
+
26
+ .search-trigger-icon {
27
+ display: flex;
28
+ flex-shrink: 0;
29
+ }
30
+
31
+ .search-trigger-icon svg {
32
+ width: 16px;
33
+ height: 16px;
34
+ opacity: 1;
35
+ }
36
+
37
+ .search-trigger-text {
38
+ flex: 1;
39
+ text-align: left;
40
+ color: var(--color-text-tertiary);
41
+ font-size: var(--text-xs);
42
+ }
43
+
44
+ .search-trigger-shortcut {
45
+ display: flex;
46
+ align-items: center;
47
+ gap: 2px;
48
+ font-family: var(--font-mono);
49
+ font-size: 11px;
50
+ color: var(--color-text-secondary);
51
+ background: none;
52
+ border: none;
53
+ padding: 0;
54
+ }
55
+
56
+ .search-trigger-shortcut-icon {
57
+ display: flex;
58
+ }
59
+
60
+ .search-trigger-shortcut-icon svg {
61
+ width: 14px;
62
+ height: 14px;
63
+ opacity: 1;
64
+ }
65
+
66
+ .search-trigger-shortcut-text {
67
+ opacity: 0.9;
68
+ }
69
+
70
+ /* Hide command icon on non-Mac, show "Ctrl" text instead */
71
+ .search-trigger-shortcut[data-os="windows"] .search-trigger-shortcut-icon {
72
+ display: none;
73
+ }
74
+
75
+ .search-trigger-shortcut[data-os="windows"] .search-trigger-shortcut-text::before {
76
+ content: "Ctrl ";
77
+ }
78
+
79
+ /* Header Actions Container */
80
+ .header-actions {
81
+ display: flex;
82
+ align-items: center;
83
+ gap: var(--space-3);
84
+ }
85
+
86
+ /* Search Modal */
87
+ .search-modal {
88
+ position: fixed;
89
+ inset: 0;
90
+ z-index: 100;
91
+ display: flex;
92
+ align-items: flex-start;
93
+ justify-content: center;
94
+ padding-top: 16px;
95
+ opacity: 0;
96
+ visibility: hidden;
97
+ transition: opacity 0.15s ease, visibility 0.15s ease;
98
+ }
99
+
100
+ .search-modal.is-open {
101
+ opacity: 1;
102
+ visibility: visible;
103
+ }
104
+
105
+ .search-modal[hidden] {
106
+ display: none;
107
+ }
108
+
109
+ .search-modal-backdrop {
110
+ position: fixed;
111
+ inset: 0;
112
+ background-color: rgba(0, 0, 0, 0.15);
113
+ opacity: 0;
114
+ transition: opacity 0.15s ease;
115
+ }
116
+
117
+ .search-modal.is-open .search-modal-backdrop {
118
+ opacity: 1;
119
+ }
120
+
121
+ .dark .search-modal-backdrop {
122
+ background-color: rgba(0, 0, 0, 0.5);
123
+ }
124
+
125
+ .search-modal-container {
126
+ position: relative;
127
+ width: 100%;
128
+ max-width: 640px;
129
+ max-height: calc(100vh - 100px);
130
+ margin: 0 var(--space-4);
131
+ background-color: var(--color-bg);
132
+ border: 1px solid var(--color-border);
133
+ border-radius: 16px;
134
+ box-shadow: 0 25px 80px rgba(0, 0, 0, 0.15);
135
+ display: flex;
136
+ flex-direction: column;
137
+ overflow: hidden;
138
+ transform: scale(0.98) translateY(-8px);
139
+ opacity: 0;
140
+ transition: transform 0.2s ease, opacity 0.15s ease;
141
+ }
142
+
143
+ .search-modal.is-open .search-modal-container {
144
+ transform: scale(1) translateY(0);
145
+ opacity: 1;
146
+ }
147
+
148
+ .dark .search-modal-container {
149
+ box-shadow: 0 16px 70px rgba(0, 0, 0, 0.5);
150
+ }
151
+
152
+ /* Search Modal Header */
153
+ .search-modal-header {
154
+ display: flex;
155
+ align-items: center;
156
+ gap: var(--space-3);
157
+ padding: 16px 20px;
158
+ }
159
+
160
+ .search-modal-icon {
161
+ flex-shrink: 0;
162
+ width: 20px;
163
+ height: 20px;
164
+ color: var(--color-text-tertiary);
165
+ }
166
+
167
+ .search-modal-input {
168
+ flex: 1;
169
+ border: none;
170
+ background: transparent;
171
+ font-size: 16px;
172
+ color: var(--color-text);
173
+ outline: none;
174
+ }
175
+
176
+ .search-modal-input::placeholder {
177
+ color: var(--color-text-tertiary);
178
+ }
179
+
180
+ .search-modal-close {
181
+ display: flex;
182
+ align-items: center;
183
+ padding: 0;
184
+ background: none;
185
+ border: none;
186
+ cursor: pointer;
187
+ }
188
+
189
+ .search-modal-close-text {
190
+ font-family: var(--font-mono);
191
+ font-size: 10px;
192
+ text-transform: uppercase;
193
+ letter-spacing: 0.5px;
194
+ color: var(--color-text-tertiary);
195
+ background-color: var(--color-bg-secondary);
196
+ border: 1px solid var(--color-border);
197
+ border-radius: 4px;
198
+ padding: 3px 6px;
199
+ }
200
+
201
+ .search-modal-close:hover .search-modal-close-text {
202
+ color: var(--color-text-secondary);
203
+ border-color: var(--color-border-secondary);
204
+ }
205
+
206
+ /* Search Modal Body */
207
+ .search-modal-body {
208
+ flex: 1;
209
+ max-height: 400px;
210
+ overflow-y: auto;
211
+ overscroll-behavior: contain;
212
+ padding: var(--space-3);
213
+ border-top: 1px solid var(--color-border);
214
+ }
215
+
216
+ .search-modal-body[hidden] {
217
+ display: none;
218
+ }
219
+
220
+ .search-modal-loading {
221
+ display: flex;
222
+ align-items: center;
223
+ justify-content: center;
224
+ padding: var(--space-6) var(--space-4);
225
+ color: var(--color-text-tertiary);
226
+ font-size: var(--text-sm);
227
+ }
228
+
229
+ .search-modal-loading[hidden] {
230
+ display: none;
231
+ }
232
+
233
+ .search-modal-empty {
234
+ display: flex;
235
+ flex-direction: column;
236
+ align-items: center;
237
+ justify-content: center;
238
+ padding: var(--space-8) var(--space-4);
239
+ text-align: center;
240
+ gap: var(--space-2);
241
+ }
242
+
243
+ .search-modal-empty[hidden] {
244
+ display: none;
245
+ }
246
+
247
+ .search-empty-icon {
248
+ width: 48px;
249
+ height: 48px;
250
+ color: var(--color-border);
251
+ margin-bottom: var(--space-2);
252
+ }
253
+
254
+ .search-empty-title {
255
+ font-size: var(--text-base);
256
+ font-weight: 500;
257
+ color: var(--color-text-secondary);
258
+ }
259
+
260
+ .search-empty-hint {
261
+ font-size: var(--text-sm);
262
+ color: var(--color-text-tertiary);
263
+ }
264
+
265
+ .search-modal-spinner {
266
+ width: 20px;
267
+ height: 20px;
268
+ border: 2px solid var(--color-border);
269
+ border-top-color: var(--color-primary);
270
+ border-radius: 50%;
271
+ animation: search-spin 0.6s linear infinite;
272
+ }
273
+
274
+ @keyframes search-spin {
275
+ to {
276
+ transform: rotate(360deg);
277
+ }
278
+ }
279
+
280
+ /* Search Results */
281
+ .search-modal-results {
282
+ list-style: none;
283
+ padding: 0;
284
+ margin: 0;
285
+ }
286
+
287
+ .search-modal-results[hidden] {
288
+ display: none;
289
+ }
290
+
291
+ /* Result Group (page + its sections) */
292
+ .search-result-group {
293
+ list-style: none;
294
+ }
295
+
296
+ .search-result-group+.search-result-group {
297
+ margin-top: var(--space-1);
298
+ }
299
+
300
+ /* Base result link */
301
+ .search-result {
302
+ display: flex;
303
+ align-items: flex-start;
304
+ gap: var(--space-3);
305
+ padding: 10px 12px;
306
+ border-radius: 8px;
307
+ cursor: pointer;
308
+ text-decoration: none;
309
+ color: var(--color-text);
310
+ transition: background-color 0.1s ease;
311
+ }
312
+
313
+ .search-result:hover,
314
+ .search-result[aria-selected="true"] {
315
+ background-color: var(--color-bg-tertiary, rgba(0, 0, 0, 0.06));
316
+ text-decoration: none;
317
+ }
318
+
319
+ .search-result:hover .search-result-title,
320
+ .search-result[aria-selected="true"] .search-result-title {
321
+ color: var(--color-primary);
322
+ text-decoration: none;
323
+ }
324
+
325
+ .dark .search-result:hover,
326
+ .dark .search-result[aria-selected="true"] {
327
+ background-color: rgba(255, 255, 255, 0.08);
328
+ }
329
+
330
+ .search-result-icon {
331
+ flex-shrink: 0;
332
+ width: 16px;
333
+ height: 16px;
334
+ margin-top: 2px;
335
+ color: var(--color-text-tertiary);
336
+ }
337
+
338
+ .search-result-content {
339
+ display: flex;
340
+ flex-direction: column;
341
+ gap: 2px;
342
+ min-width: 0;
343
+ flex: 1;
344
+ }
345
+
346
+ .search-result-title {
347
+ font-size: var(--text-sm);
348
+ font-weight: 500;
349
+ white-space: nowrap;
350
+ overflow: hidden;
351
+ text-overflow: ellipsis;
352
+ text-decoration: none;
353
+ }
354
+
355
+ .search-result-excerpt {
356
+ font-size: var(--text-xs);
357
+ color: var(--color-text-tertiary);
358
+ white-space: nowrap;
359
+ overflow: hidden;
360
+ text-overflow: ellipsis;
361
+ line-height: 1.4;
362
+ }
363
+
364
+ .search-result-excerpt mark {
365
+ background-color: color-mix(in srgb, var(--color-primary) 15%, transparent);
366
+ color: inherit;
367
+ font-weight: inherit;
368
+ border-radius: 2px;
369
+ padding: 0 1px;
370
+ }
371
+
372
+ /* Title highlight - light background like Stripe */
373
+ .search-title-highlight {
374
+ background-color: color-mix(in srgb, var(--color-primary) 15%, transparent);
375
+ color: inherit;
376
+ font-weight: inherit;
377
+ border-radius: 2px;
378
+ padding: 0 1px;
379
+ }
380
+
381
+ /* Page-level results */
382
+ .search-result-page {
383
+ font-weight: 500;
384
+ }
385
+
386
+ /* Sections list */
387
+ .search-result-sections {
388
+ list-style: none;
389
+ padding: 0;
390
+ margin: 0;
391
+ padding-left: 12px;
392
+ }
393
+
394
+ .search-result-section-item {
395
+ position: relative;
396
+ }
397
+
398
+ /* Section result */
399
+ .search-result-section {
400
+ padding-left: 20px;
401
+ }
402
+
403
+ .search-result-section .search-result-title {
404
+ font-weight: 400;
405
+ color: var(--color-text-secondary);
406
+ }
407
+
408
+ .search-result-section:hover .search-result-title,
409
+ .search-result-section[aria-selected="true"] .search-result-title {
410
+ color: var(--color-primary);
411
+ }
412
+
413
+ /* Tree connector line */
414
+ .search-result-tree-line {
415
+ position: absolute;
416
+ left: 12px;
417
+ top: 0;
418
+ bottom: 50%;
419
+ width: 12px;
420
+ border-left: 1px solid var(--color-border);
421
+ border-bottom: 1px solid var(--color-border);
422
+ border-radius: 0 0 0 4px;
423
+ }
424
+
425
+ .search-result-section-item:last-child .search-result-tree-line {
426
+ bottom: 50%;
427
+ }
428
+
429
+ /* Continuous line for middle items */
430
+ .search-result-section-item:not(:last-child)::before {
431
+ content: '';
432
+ position: absolute;
433
+ left: 12px;
434
+ top: 50%;
435
+ bottom: -50%;
436
+ width: 1px;
437
+ background-color: var(--color-border);
438
+ }
439
+
440
+ /* Load More Link */
441
+ .search-load-more {
442
+ list-style: none;
443
+ padding: var(--space-3) var(--space-3);
444
+ }
445
+
446
+ .search-load-more-btn {
447
+ font-size: 14px;
448
+ font-weight: 500;
449
+ color: var(--color-primary);
450
+ background: none;
451
+ border: none;
452
+ padding: 0;
453
+ cursor: pointer;
454
+ }
455
+
456
+ .search-load-more-btn:hover {
457
+ opacity: 0.8;
458
+ }
459
+
460
+ .search-load-more-btn:focus {
461
+ outline: none;
462
+ }
463
+
464
+ /* Search Modal Footer */
465
+ .search-modal-footer {
466
+ display: flex;
467
+ align-items: center;
468
+ gap: var(--space-4);
469
+ padding: 12px 20px;
470
+ border-top: 1px solid var(--color-border);
471
+ background-color: var(--color-bg-secondary);
472
+ font-size: 11px;
473
+ color: var(--color-text-tertiary);
474
+ }
475
+
476
+ .search-modal-hint {
477
+ display: flex;
478
+ align-items: center;
479
+ gap: 4px;
480
+ }
481
+
482
+ .search-modal-hint kbd {
483
+ display: inline-flex;
484
+ align-items: center;
485
+ justify-content: center;
486
+ min-width: 18px;
487
+ height: 18px;
488
+ padding: 0 4px;
489
+ font-family: var(--font-mono);
490
+ font-size: 10px;
491
+ background-color: var(--color-bg);
492
+ border: 1px solid var(--color-border);
493
+ border-radius: 3px;
494
+ }
495
+
496
+ /* Mobile Responsive */
497
+ @media (max-width: 640px) {
498
+ .search-trigger {
499
+ min-width: auto;
500
+ padding: var(--space-2);
501
+ border-radius: var(--radius-md);
502
+ }
503
+
504
+ .search-trigger-text,
505
+ .search-trigger-shortcut {
506
+ display: none;
507
+ }
508
+
509
+ .search-trigger-icon {
510
+ opacity: 0.7;
511
+ }
512
+
513
+ .search-modal {
514
+ padding-top: 0;
515
+ align-items: stretch;
516
+ }
517
+
518
+ .search-modal-container {
519
+ max-width: 100%;
520
+ max-height: 100%;
521
+ margin: 0;
522
+ border-radius: 0;
523
+ border: none;
524
+ }
525
+
526
+ .search-modal-body {
527
+ max-height: calc(100vh - 160px);
528
+ }
529
+
530
+ .search-modal-footer {
531
+ flex-wrap: wrap;
532
+ gap: var(--space-2);
533
+ }
534
+ }
535
+
536
+ /* Reduced Motion */
537
+ @media (prefers-reduced-motion: reduce) {
538
+ .search-modal-spinner {
539
+ animation: none;
540
+ }
541
+
542
+ .search-modal,
543
+ .search-modal-backdrop,
544
+ .search-modal-container,
545
+ .search-trigger,
546
+ .search-result {
547
+ transition: none;
548
+ }
549
+ }
@@ -26,11 +26,25 @@
26
26
  .header-content {
27
27
  display: flex;
28
28
  align-items: center;
29
- justify-content: space-between;
30
29
  height: 100%;
31
30
  padding: var(--space-5) var(--space-6);
32
31
  }
33
32
 
33
+ .header-logo {
34
+ flex-shrink: 0;
35
+ }
36
+
37
+ .header-center {
38
+ flex: 1;
39
+ display: flex;
40
+ justify-content: center;
41
+ padding: 0 var(--space-6);
42
+ }
43
+
44
+ .header-actions {
45
+ flex-shrink: 0;
46
+ }
47
+
34
48
  .header-left {
35
49
  display: flex;
36
50
  align-items: center;