PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.5
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.5
4.9.5 4.9.4 4.9.3 4.9.2 4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 All 203 releases
betterdocs / react-src / scss / code-snippet.scss

code-snippet.scss in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.9.5, at react-src/scss/code-snippet.scss

876 lines 20.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* BetterDocs Code Snippet Frontend Styles */
2
3 .betterdocs-code-snippet-wrapper {
4 position: relative;
5 margin: 1.5rem 0;
6 border-radius: 8px;
7 // Visible so the language dropdown menu isn't clipped. Corners are rounded
8 // on the header (top) + content (bottom) instead of on the wrapper.
9 overflow: visible;
10 font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'Courier New', monospace;
11 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
12 transition: box-shadow 0.3s ease;
13
14 &:hover {
15 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
16 }
17
18 .betterdocs-code-snippet-header,
19 .betterdocs-file-preview-header {
20 border-top-left-radius: 8px;
21 border-top-right-radius: 8px;
22 }
23
24 .betterdocs-code-snippet-content {
25 border-bottom-left-radius: 8px;
26 border-bottom-right-radius: 8px;
27 overflow: hidden;
28
29 // No header → the content rounds all four corners.
30 &:first-child {
31 border-top-left-radius: 8px;
32 border-top-right-radius: 8px;
33 }
34 }
35
36 /* Light */
37 &.theme-light {
38 background-color: #ffffff;
39 border: 1px solid #e1e5e9;
40
41 .betterdocs-code-snippet-header,
42 .betterdocs-file-preview-header {
43 background-color: #f6f8fa;
44 border-bottom: 1px solid #e1e5e9;
45 }
46
47 .betterdocs-code-snippet-language {
48 color: #586069;
49 }
50
51 .betterdocs-file-name .file-name-text {
52 color: #24292e;
53 }
54
55 .betterdocs-traffic-lights .traffic-light {
56 &.traffic-light-red {
57 background-color: #ff5f57;
58 border: 1px solid rgba(0, 0, 0, 0.1);
59 }
60
61 &.traffic-light-yellow {
62 background-color: #ffbd2e;
63 border: 1px solid rgba(0, 0, 0, 0.1);
64 }
65
66 &.traffic-light-green {
67 background-color: #28ca42;
68 border: 1px solid rgba(0, 0, 0, 0.1);
69 }
70 }
71
72 .betterdocs-code-snippet-code {
73 background-color: #ffffff;
74 color: #24292e;
75 }
76
77 .betterdocs-code-snippet-line-numbers {
78 background-color: #f6f8fa;
79 color: #586069;
80 border-right: 1px solid #e1e5e9;
81 }
82
83 .betterdocs-code-snippet-copy-button {
84 background: transparent;
85 color: #6c757d;
86 border: none;
87 border-radius: 6px;
88 padding: 8px;
89 width: 32px;
90 height: 32px;
91 display: flex;
92 align-items: center;
93 justify-content: center;
94 cursor: pointer;
95 transition: all 0.2s ease;
96
97 svg {
98 width: 16px;
99 height: 16px;
100 }
101
102 &:hover {
103 background: rgba(31, 35, 40, 0.08);
104 color: #24292f;
105 }
106
107 &:active {
108 background: rgba(31, 35, 40, 0.14);
109 }
110 }
111 }
112
113 /* Dark Theme */
114 &.theme-dark {
115 background-color: #0d1117;
116 border: 1px solid #30363d;
117
118 .betterdocs-code-snippet-header,
119 .betterdocs-file-preview-header {
120 background-color: #161b22;
121 border-bottom: 1px solid #30363d;
122 }
123
124 .betterdocs-code-snippet-language {
125 color: #8b949e;
126 }
127
128 .betterdocs-file-name .file-name-text {
129 color: #e6edf3;
130 }
131
132 .betterdocs-traffic-lights .traffic-light {
133 &.traffic-light-red {
134 background-color: #ff6058;
135 border: 1px solid rgba(255, 255, 255, 0.1);
136 }
137
138 &.traffic-light-yellow {
139 background-color: #ffbd2e;
140 border: 1px solid rgba(255, 255, 255, 0.1);
141 }
142
143 &.traffic-light-green {
144 background-color: #28ca42;
145 border: 1px solid rgba(255, 255, 255, 0.1);
146 }
147 }
148
149 .betterdocs-code-snippet-code {
150 background-color: #0d1117;
151 color: #e6edf3;
152 }
153
154 .betterdocs-code-snippet-line-numbers {
155 background-color: #161b22;
156 color: #656d76;
157 border-right: 1px solid #30363d;
158 }
159
160 .betterdocs-code-snippet-copy-button {
161 background: transparent;
162 color: #a0aec0;
163 border: none;
164 border-radius: 6px;
165 padding: 8px;
166 width: 32px;
167 height: 32px;
168 display: flex;
169 align-items: center;
170 justify-content: center;
171 cursor: pointer;
172 transition: all 0.2s ease;
173
174 svg {
175 width: 16px;
176 height: 16px;
177 }
178
179 &:hover {
180 background: rgba(230, 237, 243, 0.1);
181 color: #e6edf3;
182 }
183
184 &:active {
185 background: rgba(230, 237, 243, 0.16);
186 color: #cbd5e0;
187 }
188
189 &:focus {
190 outline: none;
191 }
192 }
193 }
194 }
195
196 /* File Preview Header Styles */
197 .betterdocs-file-preview-header {
198 display: flex;
199 justify-content: space-between;
200 align-items: center;
201 padding: 0.75rem 1rem;
202 font-size: 0.875rem;
203 font-weight: 500;
204 min-height: 3rem;
205
206 .betterdocs-file-preview-left {
207 display: flex;
208 align-items: center;
209 gap: 0.75rem;
210 flex: 1;
211 }
212
213 .betterdocs-file-preview-right {
214 display: flex;
215 align-items: center;
216 gap: 0.5rem;
217 }
218 }
219
220 /* Multi-language dropdown (Mintlify-style language switcher) */
221 .betterdocs-code-lang-dropdown {
222 position: relative;
223
224 .betterdocs-code-lang-toggle {
225 display: flex;
226 align-items: center;
227 gap: 6px;
228 padding: 4px 6px;
229 background: transparent;
230 border: none;
231 border-radius: 6px;
232 cursor: pointer;
233 font-size: 12px;
234 font-weight: 600;
235 color: #57606a;
236 line-height: 1.4;
237 font-family: inherit;
238 text-transform: none;
239 transition: color 0.2s ease;
240
241 &:hover {
242 color: #24292f;
243 }
244
245 // Icon + label spacing (matches the menu options).
246 .betterdocs-code-lang-current {
247 display: inline-flex;
248 align-items: center;
249 gap: 6px;
250 }
251
252 .betterdocs-code-lang-caret {
253 transition: transform 0.2s ease;
254 }
255 }
256
257 &.is-open .betterdocs-code-lang-toggle .betterdocs-code-lang-caret {
258 transform: rotate(180deg);
259 }
260
261 // Menu + options mirror the shared betterdocs-dropdown (react-select)
262 // `__menu` / `__option`: rounded-pill options, neutral hover, green active
263 // with a checkmark tick.
264 .betterdocs-code-lang-menu {
265 position: absolute;
266 top: calc(100% + 6px);
267 right: 0;
268 z-index: 20;
269 min-width: 180px;
270 margin: 0;
271 padding: 8px;
272 list-style: none;
273 background: #ffffff;
274 border-radius: 8px;
275 overflow: hidden;
276 box-shadow: 0px 4px 16px rgba(16, 24, 40, 0.12);
277 display: none;
278 flex-direction: column;
279 gap: 4px;
280
281 .betterdocs-code-lang-option {
282 display: flex;
283 align-items: center;
284 gap: 8px;
285 padding: 6px 12px;
286 border-radius: 6px;
287 cursor: pointer;
288 font-size: 13px;
289 color: #344054;
290 background: transparent;
291 text-transform: none;
292
293 // --is-focused
294 &:hover {
295 background: #f9fafb;
296 }
297
298 // --is-selected: neutral bg + brand-green text + tick
299 &.is-active {
300 background: #f9fafb;
301 color: #00b884;
302
303 &::after {
304 margin-left: auto;
305 content: "\2713";
306 font-size: 13px;
307 line-height: 1;
308 }
309 }
310 }
311 }
312
313 &.is-open .betterdocs-code-lang-menu {
314 display: flex;
315 }
316 }
317
318 /* Dark theme for the language dropdown */
319 .betterdocs-code-snippet-wrapper.theme-dark {
320 .betterdocs-code-lang-toggle {
321 color: #8b949e;
322
323 &:hover {
324 color: #e6edf3;
325 }
326 }
327
328 .betterdocs-code-lang-menu {
329 background: #161b22;
330 box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.4);
331
332 .betterdocs-code-lang-option {
333 color: #e6edf3;
334
335 &:hover {
336 background: rgba(255, 255, 255, 0.06);
337 }
338
339 &.is-active {
340 background: rgba(255, 255, 255, 0.06);
341 color: #00b884;
342 }
343 }
344 }
345 }
346
347 /* Traffic Lights */
348 .betterdocs-traffic-lights {
349 display: flex;
350 align-items: center;
351 gap: 0.5rem;
352
353 .traffic-light {
354 width: 12px;
355 height: 12px;
356 border-radius: 50%;
357 display: block;
358
359 &.traffic-light-red {
360 background-color: #ff5f57;
361 }
362
363 &.traffic-light-yellow {
364 background-color: #ffbd2e;
365 }
366
367 &.traffic-light-green {
368 background-color: #28ca42;
369 }
370 }
371 }
372
373 /* File Info */
374 .betterdocs-file-info {
375 display: flex;
376 align-items: center;
377 gap: 0.5rem;
378 flex: 1;
379 min-width: 0; /* Allow text truncation */
380 }
381
382 .betterdocs-file-icon {
383 display: flex;
384 align-items: center;
385 justify-content: center;
386 width: 20px;
387 height: 20px;
388 flex-shrink: 0;
389
390 img {
391 width: 100%;
392 height: 100%;
393 object-fit: contain;
394 border-radius: 2px;
395 }
396
397 .betterdocs-file-icon-emoji {
398 font-size: 16px;
399 line-height: 1;
400 display: block;
401 }
402 }
403
404 .betterdocs-file-name {
405 flex: 1;
406 min-width: 0;
407
408 .file-name-text {
409 font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'Courier New', monospace;
410 font-size: 0.875rem;
411 font-weight: 500;
412 white-space: nowrap;
413 overflow: hidden;
414 text-overflow: ellipsis;
415 display: block;
416 }
417 }
418
419 /* Legacy header styles for backward compatibility */
420 .betterdocs-code-snippet-header:not(.betterdocs-file-preview-header) {
421 display: flex;
422 justify-content: space-between;
423 align-items: center;
424 padding: 0.75rem 1rem;
425 font-size: 0.875rem;
426 font-weight: 500;
427 min-height: 3rem;
428 }
429
430 .betterdocs-code-snippet-language {
431 font-family: inherit;
432 text-transform: uppercase;
433 letter-spacing: 0.05em;
434 font-weight: 600;
435 font-size: 0.8125rem;
436 }
437
438 .betterdocs-code-snippet-copy-button {
439 display: inline-flex;
440 align-items: center;
441 gap: 0.5rem;
442 padding: 0.5rem 0.875rem;
443 border: none;
444 border-radius: 6px;
445 font-size: 0.875rem;
446 font-weight: 500;
447 cursor: pointer;
448 transition: all 0.2s ease;
449 text-decoration: none;
450 white-space: nowrap;
451
452 &:focus {
453 outline: none;
454 }
455
456 svg {
457 width: 16px;
458 height: 16px;
459 flex-shrink: 0;
460 }
461 }
462
463 /* All buttons inside a code block stay flat — reset the theme's default
464 <button> box-shadow (and any of our own) in every state. One rule for every
465 code-snippet button: the copy button, the language-dropdown toggle, and the
466 Code Snippet Tab status tabs. */
467 .betterdocs-code-snippet-wrapper .betterdocs-code-snippet-copy-button,
468 .betterdocs-code-snippet-wrapper .betterdocs-code-lang-toggle,
469 .betterdocs-code-snippet-wrapper .betterdocs-code-snippet-tab-item {
470 box-shadow: none;
471
472 &:hover,
473 &:focus,
474 &:focus-visible,
475 &:active {
476 box-shadow: none;
477 }
478 }
479
480 .betterdocs-code-snippet-content {
481 position: relative;
482 overflow: hidden;
483 }
484
485 /* Each language is its own panel; only the active one shows. The flex row
486 (line numbers + code) lives on the panel. */
487 .betterdocs-code-snippet-panel {
488 display: none;
489 position: relative;
490
491 &.is-active {
492 display: flex;
493 }
494 }
495
496 .betterdocs-code-snippet-line-numbers {
497 display: flex;
498 flex-direction: column;
499 padding: 1rem 0.75rem;
500 font-size: 0.8125rem;
501 line-height: 1.5;
502 text-align: right;
503 user-select: none;
504 min-width: 3rem;
505 flex-shrink: 0;
506
507 .line-number {
508 height: 1.5em;
509 display: flex;
510 align-items: center;
511 justify-content: flex-end;
512 font-variant-numeric: tabular-nums;
513 }
514 }
515
516 .betterdocs-code-snippet-code {
517 flex: 1;
518 margin: 0;
519 padding: 1rem;
520 font-family: inherit;
521 font-size: 0.875rem;
522 line-height: 1.5;
523 white-space: pre;
524 overflow-x: auto;
525 background: transparent;
526 border: none;
527 min-height: 3rem;
528
529 code {
530 font-family: inherit;
531 font-size: inherit;
532 line-height: inherit;
533 background: transparent;
534 padding: 0;
535 border: none;
536 display: block;
537 white-space: pre;
538 }
539
540 /* Custom scrollbar for webkit browsers */
541 &::-webkit-scrollbar {
542 height: 8px;
543 }
544
545 &::-webkit-scrollbar-track {
546 background: rgba(0, 0, 0, 0.1);
547 border-radius: 4px;
548 }
549
550 &::-webkit-scrollbar-thumb {
551 background: rgba(0, 0, 0, 0.3);
552 border-radius: 4px;
553
554 &:hover {
555 background: rgba(0, 0, 0, 0.5);
556 }
557 }
558 }
559
560 /* ---------------------------------------------------------------------------
561 Copy button + tooltip
562
563 The button ships both icons and CSS cross-fades between them on `.is-copied`,
564 so the script never rewrites the SVG (rewriting it used to bake the tick in
565 permanently when you clicked twice quickly). The tooltip is anchored to the
566 container with plain absolute positioning — the wrapper and header are
567 `overflow: visible`, so it can sit above the button with no JS layout pass.
568 -------------------------------------------------------------------------- */
569 .betterdocs-code-snippet-copy-container {
570 position: relative;
571 display: inline-flex;
572 }
573
574 .betterdocs-code-snippet-wrapper .betterdocs-code-snippet-copy-button {
575 position: relative;
576 flex-shrink: 0;
577
578 .betterdocs-code-snippet-copy-icon,
579 .betterdocs-code-snippet-copied-icon {
580 display: flex;
581 align-items: center;
582 justify-content: center;
583 transition: opacity 0.18s ease, transform 0.18s ease;
584 }
585
586 /* Stack the tick on top of the copy glyph so the button never resizes. */
587 .betterdocs-code-snippet-copied-icon {
588 position: absolute;
589 inset: 0;
590 opacity: 0;
591 transform: scale(0.5);
592 }
593
594 &.is-copied {
595 .betterdocs-code-snippet-copy-icon {
596 opacity: 0;
597 transform: scale(0.5);
598 }
599
600 // No accent colour — the tick inherits the button's `currentColor` so it
601 // reads exactly like the copy glyph it replaces.
602 .betterdocs-code-snippet-copied-icon {
603 opacity: 1;
604 transform: scale(1);
605 }
606 }
607
608 &:focus-visible {
609 outline: 2px solid #0969da;
610 outline-offset: 2px;
611 }
612 }
613
614 .betterdocs-code-snippet-tooltip {
615 position: absolute;
616 bottom: calc(100% + 9px);
617 left: 50%;
618 padding: 5px 9px;
619 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
620 font-size: 12px;
621 font-weight: 500;
622 line-height: 1.35;
623 white-space: nowrap;
624 border-radius: 6px;
625 pointer-events: none;
626 z-index: 20;
627 opacity: 0;
628 visibility: hidden;
629 transform: translateX(-50%) translateY(3px);
630 transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
631
632 /* Arrow */
633 &::after {
634 content: '';
635 position: absolute;
636 top: 100%;
637 left: 50%;
638 margin-left: -5px;
639 border: 5px solid transparent;
640 border-top-color: inherit;
641 }
642
643 &.show {
644 opacity: 1;
645 visibility: visible;
646 transform: translateX(-50%) translateY(0);
647 }
648 }
649
650 /* Light theme — dark bubble on a light snippet. `border-top-color` feeds the
651 arrow through `inherit`; the bubble itself has no visible border.
652 "Copied!" deliberately reuses the idle palette — the label carries the
653 confirmation, so no colour change is needed. Only failure gets an accent. */
654 .betterdocs-code-snippet-wrapper.theme-light .betterdocs-code-snippet-tooltip {
655 background-color: #24292f;
656 border-top-color: #24292f;
657 color: #ffffff;
658 box-shadow: 0 4px 12px rgba(31, 35, 40, 0.28);
659
660 &.is-error {
661 background-color: #cf222e;
662 border-top-color: #cf222e;
663 }
664 }
665
666 /* Dark theme — light bubble on a dark snippet. */
667 .betterdocs-code-snippet-wrapper.theme-dark .betterdocs-code-snippet-tooltip {
668 background-color: #e6edf3;
669 border-top-color: #e6edf3;
670 color: #0d1117;
671 box-shadow: 0 4px 12px rgba(1, 4, 9, 0.6);
672
673 &.is-error {
674 background-color: #f85149;
675 border-top-color: #f85149;
676 color: #2d0709;
677 }
678 }
679
680 /* Responsive Design */
681 @media (max-width: 768px) {
682 .betterdocs-code-snippet-wrapper {
683 margin: 1rem 0;
684 border-radius: 6px;
685 }
686
687 .betterdocs-code-snippet-header,
688 .betterdocs-file-preview-header {
689 padding: 0.625rem 0.75rem;
690 font-size: 0.8125rem;
691 min-height: auto;
692 }
693
694 .betterdocs-file-preview-header {
695 .betterdocs-file-preview-left {
696 gap: 0.5rem;
697 }
698
699 .betterdocs-traffic-lights {
700 gap: 0.375rem;
701
702 .traffic-light {
703 width: 10px;
704 height: 10px;
705 }
706 }
707
708 .betterdocs-file-name .file-name-text {
709 font-size: 0.8125rem;
710 }
711 }
712
713 /* Legacy header responsive styles */
714 .betterdocs-code-snippet-header:not(.betterdocs-file-preview-header) {
715 flex-direction: column;
716 gap: 0.5rem;
717 align-items: flex-start;
718 }
719
720 .betterdocs-code-snippet-copy-button {
721 padding: 0.375rem 0.625rem;
722 font-size: 0.8125rem;
723 align-self: flex-end;
724
725 svg {
726 width: 14px;
727 height: 14px;
728 }
729 }
730
731 .betterdocs-code-snippet-line-numbers {
732 padding: 0.75rem 0.5rem;
733 font-size: 0.75rem;
734 min-width: 2.5rem;
735 }
736
737 .betterdocs-code-snippet-code {
738 padding: 0.75rem;
739 font-size: 0.8125rem;
740 }
741 }
742
743 @media (max-width: 480px) {
744 .betterdocs-code-snippet-wrapper {
745 margin: 0.75rem 0;
746 border-radius: 4px;
747 }
748
749 .betterdocs-code-snippet-header,
750 .betterdocs-file-preview-header {
751 padding: 0.5rem;
752 }
753
754 .betterdocs-file-preview-header {
755 .betterdocs-file-preview-left {
756 gap: 0.375rem;
757 }
758
759 .betterdocs-traffic-lights {
760 gap: 0.25rem;
761
762 .traffic-light {
763 width: 8px;
764 height: 8px;
765 }
766 }
767
768 .betterdocs-file-icon {
769 width: 16px;
770 height: 16px;
771
772 .betterdocs-file-icon-emoji {
773 font-size: 12px;
774 }
775 }
776
777 .betterdocs-file-name .file-name-text {
778 font-size: 0.75rem;
779 }
780 }
781
782 .betterdocs-code-snippet-copy-button {
783 padding: 0.25rem 0.5rem;
784 font-size: 0.75rem;
785 gap: 0.25rem;
786
787 svg {
788 width: 12px;
789 height: 12px;
790 }
791 }
792
793 .betterdocs-code-snippet-line-numbers {
794 padding: 0.5rem 0.375rem;
795 font-size: 0.6875rem;
796 min-width: 2rem;
797 }
798
799 .betterdocs-code-snippet-code {
800 padding: 0.5rem;
801 font-size: 0.75rem;
802 }
803 }
804
805 /* High contrast mode support */
806 @media (prefers-contrast: high) {
807 .betterdocs-code-snippet-wrapper {
808 border-width: 2px;
809
810 &.theme-light {
811 border-color: #000000;
812
813 .betterdocs-code-snippet-header {
814 border-bottom-color: #000000;
815 }
816
817 .betterdocs-code-snippet-line-numbers {
818 border-right-color: #000000;
819 }
820 }
821
822 &.theme-dark {
823 border-color: #ffffff;
824
825 .betterdocs-code-snippet-header {
826 border-bottom-color: #ffffff;
827 }
828
829 .betterdocs-code-snippet-line-numbers {
830 border-right-color: #ffffff;
831 }
832 }
833 }
834 }
835
836 /* Reduced motion support */
837 @media (prefers-reduced-motion: reduce) {
838 .betterdocs-code-snippet-wrapper,
839 .betterdocs-code-snippet-copy-button,
840 .betterdocs-code-snippet-tooltip {
841 transition: none;
842 }
843 }
844
845 /* Print styles */
846 @media print {
847 .betterdocs-code-snippet-wrapper {
848 box-shadow: none;
849 border: 1px solid #000000;
850 break-inside: avoid;
851 }
852
853 .betterdocs-code-snippet-header {
854 background-color: #f5f5f5 !important;
855 border-bottom: 1px solid #000000;
856 }
857
858 .betterdocs-code-snippet-copy-button {
859 display: none;
860 }
861
862 .betterdocs-code-snippet-code {
863 background-color: #ffffff !important;
864 color: #000000 !important;
865 overflow: visible;
866 white-space: pre-wrap;
867 word-wrap: break-word;
868 }
869
870 .betterdocs-code-snippet-line-numbers {
871 background-color: #f5f5f5 !important;
872 color: #666666 !important;
873 border-right: 1px solid #000000;
874 }
875 }
876