]> BookStack Code Mirror - bookstack/blob - resources/sass/_editor.scss
Tests: Updated comment test to account for new editor usage
[bookstack] / resources / sass / _editor.scss
1 @use "mixins";
2 @use "vars";
3
4 // Common variables
5 :root {
6   --editor-color-primary: #206ea7;
7 }
8
9 // Main UI elements
10 .editor-container {
11   @include mixins.lightDark(background-color, #FFF, #222);
12   position: relative;
13   &.fullscreen {
14     z-index: 500;
15   }
16 }
17
18 .editor-toolbar-main {
19   display: flex;
20   flex-wrap: wrap;
21   justify-content: center;
22   border-top: 1px solid #DDD;
23   border-bottom: 1px solid #DDD;
24   @include mixins.lightDark(border-color, #DDD, #000);
25 }
26
27 @include mixins.smaller-than(vars.$bp-xl) {
28   .editor-toolbar-main {
29     overflow-x: scroll;
30     flex-wrap: nowrap;
31     justify-content: start;
32   }
33 }
34
35 body.editor-is-fullscreen {
36   overflow: hidden;
37   .edit-area {
38     z-index: 20;
39   }
40 }
41 .editor-content-area {
42   min-height: 100%;
43   padding-block: 1rem;
44   &:focus {
45     outline: 0;
46   }
47 }
48 .editor-content-wrap {
49   position: relative;
50   overflow-y: scroll;
51   padding-inline: vars.$s;
52   flex: 1;
53 }
54
55 // Variation specific styles
56 .comment-editor-container,
57 .basic-editor-container {
58   border-left: 1px solid #DDD;
59   border-right: 1px solid #DDD;
60   border-bottom: 1px solid #DDD;
61   border-radius: 3px;
62   @include mixins.lightDark(border-color, #DDD, #000);
63
64   .editor-toolbar-main {
65     border-radius: 3px 3px 0 0;
66     justify-content: end;
67   }
68 }
69
70 .basic-editor-container .editor-content-area {
71   padding-bottom: 0;
72 }
73
74 // Buttons
75 .editor-button {
76   font-size: 12px;
77   padding: 4px;
78   color: #444;
79   @include mixins.lightDark(color, #444, #999);
80   border-radius: 4px;
81   display: flex;
82   align-items: center;
83   justify-content: center;
84   margin: 2px;
85 }
86 .editor-button:hover {
87   background-color: #EEE;
88   @include mixins.lightDark(background-color, #EEE, #333);
89   cursor: pointer;
90   color: #000;
91 }
92 .editor-button[disabled] {
93   pointer-events: none;
94   cursor: not-allowed;
95   opacity: .6;
96 }
97 .editor-button-active, .editor-button-active:hover {
98   @include mixins.lightDark(background-color, #ceebff, #444);
99   color: #000;
100 }
101 .editor-button-long {
102   display: flex !important;
103   flex-direction: row;
104   align-items: center;
105   justify-content: start;
106   gap: .5rem;
107 }
108 .editor-button-text {
109   font-weight: 400;
110   @include mixins.lightDark(color, #000, #AAA);
111   font-size: 14px;
112   flex: 1;
113   padding-inline-end: 4px;
114 }
115 .editor-button-format-preview {
116   padding: 4px 6px;
117   display: block;
118 }
119 .editor-button-long .editor-button-icon {
120   width: 24px;
121   height: 24px;
122 }
123 .editor-button-icon svg {
124   width: 24px;
125   height: 24px;
126   color: inherit;
127   fill: currentColor;
128   display: block;
129 }
130 .editor-menu-button-icon {
131   width: 24px;
132   height: 24px;
133   svg {
134     fill: #888;
135   }
136 }
137 .editor-container[dir="rtl"] .editor-menu-button-icon {
138   rotate: 180deg;
139 }
140 .editor-button-with-menu-container {
141   display: flex;
142   flex-direction: row;
143   gap: 0;
144   align-items: stretch;
145   border-radius: 4px;
146   .editor-dropdown-menu-container {
147     display: flex;
148   }
149   .editor-dropdown-menu-container > .editor-dropdown-menu {
150     top: 100%;
151   }
152   .editor-dropdown-menu-container > .editor-button {
153     padding-inline: 4px;
154     margin-inline-start: -3px;
155     svg {
156       width: 12px;
157       height: 12px;
158     }
159   }
160   &:hover {
161     outline: 1px solid;
162     @include mixins.lightDark(outline-color, #DDD, #111);
163     outline-offset: -3px;
164   }
165 }
166
167 // Containers
168 .editor-dropdown-menu-container {
169     position: relative;
170 }
171 .editor-dropdown-menu {
172   position: absolute;
173   border: 1px solid;
174   @include mixins.lightDark(background-color, #FFF, #292929);
175   @include mixins.lightDark(border-color, #FFF, #333);
176   @include mixins.lightDark(box-shadow, 0 0 6px 0 rgba(0, 0, 0, 0.15), 0 1px 4px 0 rgba(0, 0, 0, 0.4));
177   z-index: 99;
178   display: flex;
179   flex-direction: row;
180   border-radius: 3px;
181 }
182 .editor-dropdown-menu-vertical {
183   display: flex;
184   flex-direction: column;
185   align-items: stretch;
186   min-width: 160px;
187 }
188 .editor-dropdown-menu-vertical .editor-button {
189   border-bottom: 0;
190   text-align: start;
191   display: block;
192   width: 100%;
193 }
194 .editor-dropdown-menu-vertical > .editor-dropdown-menu-container .editor-dropdown-menu {
195   inset-inline-start: 100%;
196   top: 0;
197 }
198
199 .editor-separator {
200   display: block;
201   height: 1px;
202   opacity: .8;
203   @include mixins.lightDark(background-color, #DDD, #000);
204 }
205
206 .editor-format-menu-toggle {
207   width: 130px;
208   height: 32px;
209   font-size: 13px;
210   overflow: hidden;
211   padding-inline: 12px;
212   justify-content: start;
213   background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="%23666" d="M7.41 8L12 12.58 16.59 8 18 9.41l-6 6-6-6z"/></svg>');
214   background-repeat: no-repeat;
215   background-position: 98% 50%;
216   background-size: 28px;
217 }
218 .editor-container[dir="rtl"] .editor-format-menu-toggle {
219   background-position: 2% 50%;
220 }
221 .editor-format-menu .editor-dropdown-menu {
222   min-width: 300px;
223   .editor-dropdown-menu {
224     min-width: 220px;
225   }
226   .editor-button-icon {
227     display: none;
228   }
229 }
230 .editor-format-menu .editor-dropdown-menu .editor-dropdown-menu-container > .editor-button {
231   padding: 8px 10px;
232 }
233
234 .editor-overflow-container {
235   display: flex;
236   border-inline: 1px solid #DDD;
237   padding-inline: 4px;
238   @include mixins.lightDark(border-color, #DDD, #000);
239   &:first-child {
240     border-inline-start: none;
241   }
242   &:last-child {
243     border-inline-end: none;
244   }
245   + .editor-overflow-container {
246     border-inline-start: none;
247   }
248 }
249
250 .editor-context-toolbar {
251   position: fixed;
252   border: 1px solid #DDD;
253   @include mixins.lightDark(background-color, #FFF, #222);
254   @include mixins.lightDark(border-color, #DDD, #333);
255   @include mixins.lightDark(box-shadow, 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 1px 4px 0 rgba(0, 0, 0, 0.4));
256   padding: .2rem;
257   border-radius: 4px;
258   display: flex;
259   flex-direction: row;
260   &:before {
261     content: '';
262     z-index: -1;
263     display: block;
264     width: 8px;
265     height: 8px;
266     position: absolute;
267     @include mixins.lightDark(background-color, #FFF, #222);
268     border-top: 1px solid #DDD;
269     border-left: 1px solid #DDD;
270     @include mixins.lightDark(border-color, #DDD, #333);
271     transform: rotate(45deg);
272     left: 50%;
273     margin-left: -4px;
274     top: -5px;
275   }
276   &.is-above:before {
277     top: calc(100% - 5px);
278     transform: rotate(225deg);
279   }
280 }
281
282 // Modals
283 .editor-modal-wrapper {
284   position: fixed;
285   display: flex;
286   align-items: center;
287   justify-content: center;
288   z-index: 999;
289   background-color: rgba(0, 0, 0, 0.5);
290   width: 100%;
291   height: 100%;
292 }
293 .editor-modal {
294   @include mixins.lightDark(background-color, #FFF, #222);
295   border-radius: 4px;
296   overflow: hidden;
297   box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.3);
298   margin: vars.$xs;
299   max-height: 100%;
300   overflow-y: auto;
301 }
302 .editor-modal-header {
303   display: flex;
304   justify-content: space-between;
305   align-items: stretch;
306   background-color: var(--color-primary);
307   color: #FFF;
308 }
309 .editor-modal-title {
310   padding: 8px vars.$m;
311 }
312 .editor-modal-close {
313   color: #FFF;
314   padding: 8px vars.$m;
315   align-items: center;
316   justify-content: center;
317   cursor: pointer;
318   &:hover {
319   background-color: rgba(255, 255, 255, 0.1);
320   }
321   svg {
322     width: 1rem;
323     height: 1rem;
324     fill: currentColor;
325     display: block;
326   }
327 }
328 .editor-modal-body {
329   padding: vars.$m;
330 }
331
332 // Specific UI elements
333 .editor-color-select-row {
334   display: flex;
335 }
336 .editor-color-select-option {
337   width: 28px;
338   height: 28px;
339   cursor: pointer;
340   display: flex;
341   align-items: center;
342   justify-content: center;
343 }
344 .editor-color-select-option:hover {
345   border-radius: 3px;
346   box-sizing: border-box;
347   z-index: 3;
348   box-shadow: 0 0 4px 1px rgba(0, 0, 0, 0.25);
349 }
350 .editor-color-select-option[data-color=""] svg {
351   width: 20px;
352   height: 20px;
353   fill: #888;
354 }
355 .editor-table-creator-row {
356   display: flex;
357 }
358 .editor-table-creator-cell {
359   border: 1px solid;
360   @include mixins.lightDark(border-color, #DDD, #000);
361   width: 15px;
362   height: 15px;
363   cursor: pointer;
364   &.active {
365     background-color: var(--editor-color-primary);
366   }
367 }
368 .editor-table-creator-display {
369   text-align: center;
370   padding: 0.2em;
371 }
372 .editor-external-content {
373   min-width: 500px;
374   min-height: 500px;
375   h4:first-child {
376     margin-top: 0;
377   }
378 }
379
380 // In-editor elements
381 .editor-image-wrap {
382   position: relative;
383   display: inline-flex;
384 }
385 .editor-node-resizer {
386   position: absolute;
387   left: 0;
388   right: auto;
389   display: inline-block;
390   outline: 2px dashed var(--editor-color-primary);
391   direction: ltr;
392   pointer-events: none;
393 }
394 .editor-node-resizer-handle {
395   pointer-events: auto;
396   position: absolute;
397   display: block;
398   width: 10px;
399   height: 10px;
400   border: 2px solid var(--editor-color-primary);
401   z-index: 3;
402   @include mixins.lightDark(background-color, #FFF, #000);
403   user-select: none;
404   &.nw {
405     inset-inline-start: -5px;
406     inset-block-start: -5px;
407     cursor: nw-resize;
408   }
409   &.ne {
410     inset-inline-end: -5px;
411     inset-block-start: -5px;
412     cursor: ne-resize;
413   }
414   &.se {
415     inset-inline-end: -5px;
416     inset-block-end: -5px;
417     cursor: se-resize;
418   }
419   &.sw {
420     inset-inline-start: -5px;
421     inset-block-end: -5px;
422     cursor: sw-resize;
423   }
424 }
425 .editor-node-resizer-ghost {
426   opacity: 0.5;
427   display: none;
428   position: absolute;
429   left: 0;
430   top: 0;
431   width: 100%;
432   height: 100%;
433   z-index: 2;
434   pointer-events: none;
435   background-color: var(--editor-color-primary);
436 }
437 .editor-node-resizer.active .editor-node-resizer-ghost {
438   display: block;
439 }
440
441 .editor-table-marker {
442   position: fixed;
443   background-color: var(--editor-color-primary);
444   z-index: 3;
445   user-select: none;
446   opacity: 0;
447   &:hover, &.active {
448     opacity: 0.4;
449   }
450 }
451 .editor-table-marker-column {
452   width: 4px;
453   cursor: col-resize;
454 }
455 .editor-table-marker-row {
456   height: 4px;
457   cursor: row-resize;
458 }
459
460 .editor-code-block-wrap {
461   user-select: none;
462   > * {
463     pointer-events: none;
464   }
465   &.selected .cm-editor {
466     border: 1px dashed var(--editor-color-primary);
467   }
468 }
469 .editor-diagram.selected {
470   outline: 2px dashed var(--editor-color-primary);
471 }
472
473 .editor-media-wrap {
474   display: inline-block;
475   cursor: not-allowed;
476   iframe, video {
477     pointer-events: none;
478   }
479   &.align-left {
480     float: left;
481   }
482   &.align-right {
483     float: right;
484   }
485   &.align-center {
486     display: block;
487     margin-inline: auto;
488   }
489 }
490
491 /**
492  * Fake task list checkboxes
493  */
494 .editor-content-area .task-list-item {
495   margin-left: 0;
496   position: relative;
497 }
498 .editor-content-area .task-list-item > input[type="checkbox"] {
499   display: none;
500 }
501 .editor-content-area .task-list-item:before {
502   content: '';
503   display: inline-block;
504   border: 2px solid #CCC;
505   width: 12px;
506   height: 12px;
507   border-radius: 2px;
508   margin-right: 8px;
509   vertical-align: text-top;
510   cursor: pointer;
511   position: absolute;
512   left: -24px;
513   top: 4px;
514 }
515 .editor-content-area .task-list-item[checked]:before {
516   background-color: #CCC;
517   background-image: url('data:image/svg+xml;utf8,<svg fill="%23FFFFFF" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m8.4856 20.274-6.736-6.736 2.9287-2.7823 3.8073 3.8073 10.836-10.836 2.9287 2.9287z" stroke-width="1.4644"/></svg>');
518   background-position: 50% 50%;
519   background-size: 100% 100%;
520 }
521
522 /**
523  * Form elements
524  */
525 $inputWidth: 260px;
526
527 .editor-form-field-wrapper {
528   margin-bottom: .5rem;
529 }
530 .editor-form-field-input {
531   display: block;
532   width: $inputWidth;
533   min-width: 100px;
534   max-width: 100%;
535   border: 1px solid;
536   @include mixins.lightDark(border-color, #DDD, #000);
537   padding: .5rem;
538   border-radius: 4px;
539   @include mixins.lightDark(color, #444, #BBB);
540 }
541
542 @include mixins.smaller-than(vars.$bp-xs) {
543   .editor-form-field-input {
544     min-width: 160px;
545   }
546 }
547
548 textarea.editor-form-field-input {
549   font-family: var(--font-code);
550   width: 350px;
551   height: 250px;
552   font-size: 12px;
553 }
554 .editor-form-field-label {
555   color: #444;
556   font-weight: 700;
557   font-size: 12px;
558 }
559 .editor-form-actions {
560   display: flex;
561   justify-content: end;
562   gap: vars.$s;
563   margin-top: vars.$m;
564 }
565 .editor-form-actions > button {
566   display: block;
567   font-size: 0.85rem;
568   line-height: 1.4em;
569   padding: vars.$xs*1.3 vars.$m;
570   font-weight: 400;
571   border-radius: 4px;
572   cursor: pointer;
573   box-shadow: none;
574   &:focus {
575     outline: 1px dotted currentColor;
576     outline-offset: -(vars.$xs);
577     box-shadow: none;
578     filter: brightness(90%);
579   }
580 }
581 .editor-form-action-primary {
582   background-color: var(--color-primary);
583   color: #FFF;
584   border: 1px solid var(--color-primary);
585   &:hover {
586     @include mixins.lightDark(box-shadow, vars.$bs-light, vars.$bs-dark);
587     filter: brightness(110%);
588   }
589 }
590 .editor-form-action-secondary {
591   border: 1px solid;
592   @include mixins.lightDark(border-color, #CCC, #666);
593   @include mixins.lightDark(color, #666, #AAA);
594   &:hover, &:focus, &:active {
595     @include mixins.lightDark(color, #444, #BBB);
596     border: 1px solid #CCC;
597     box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.1);
598     background-color: #F2F2F2;
599     @include mixins.lightDark(background-color, #f8f8f8, #444);
600     filter: none;
601   }
602   &:active {
603     border-color: #BBB;
604     background-color: #DDD;
605     color: #666;
606     box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.1);
607   }
608 }
609 .editor-form-tab-container {
610   display: flex;
611   flex-direction: row;
612   gap: 2rem;
613 }
614 .editor-form-tab-controls {
615   display: flex;
616   flex-direction: column;
617   align-items: stretch;
618   gap: .25rem;
619 }
620
621 @include mixins.smaller-than(vars.$bp-m) {
622   .editor-form-tab-container {
623     flex-direction: column;
624     gap: .5rem;
625   }
626   .editor-form-tab-controls {
627     flex-direction: row;
628   }
629 }
630
631 .editor-form-tab-control {
632   font-weight: bold;
633   font-size: 14px;
634   @include mixins.lightDark(color, #444, #666);
635   border-bottom: 2px solid transparent;
636   position: relative;
637   cursor: pointer;
638   padding: .25rem .5rem;
639   text-align: start;
640   &[aria-selected="true"] {
641     border-color: var(--editor-color-primary);
642     color: var(--editor-color-primary) !important;
643   }
644   &[aria-selected="true"]:after, &:hover:after {
645     background-color: var(--editor-color-primary);
646     opacity: .15;
647     content: '';
648     display: block;
649     position: absolute;
650     left: 0;
651     top: 0;
652     width: 100%;
653     height: 100%;
654   }
655 }
656 .editor-form-tab-contents {
657   width: $inputWidth;
658   max-width: 100%;
659 }
660 .editor-action-input-container {
661   display: flex;
662   flex-direction: row;
663   align-items: end;
664   justify-content: space-between;
665   gap: .1rem;
666   .editor-button {
667     margin-bottom: 12px;
668   }
669   input {
670     width: $inputWidth - 40px;
671   }
672 }
673 .editor-color-field-container {
674   position: relative;
675   input {
676     padding-left: 36px;
677   }
678   .editor-dropdown-menu-container {
679     position: absolute;
680     bottom: 0;
681   }
682 }
683
684 // Editor theme styles
685 .editor-theme-bold {
686   font-weight: bold;
687 }
688 .editor-theme-italic {
689   font-style: italic;
690 }
691 .editor-theme-strikethrough {
692   text-decoration-line: line-through;
693 }
694 .editor-theme-underline {
695   text-decoration-line: underline;
696 }
697 .editor-theme-underline-strikethrough {
698   text-decoration: underline line-through;
699 }