]> BookStack Code Mirror - bookstack/blob - resources/sass/_editor.scss
Lexical: Improved nested details interaction
[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 .editor-content-area details[contenteditable="false"],
441 .editor-content-area summary[contenteditable="false"] {
442   user-select: none;
443 }
444 .editor-content-area details[contenteditable="false"] > details * {
445   pointer-events: none;
446 }
447 .editor-content-area details summary {
448   caret-color: transparent;
449 }
450
451 .editor-table-marker {
452   position: fixed;
453   background-color: var(--editor-color-primary);
454   z-index: 3;
455   user-select: none;
456   opacity: 0;
457   &:hover, &.active {
458     opacity: 0.4;
459   }
460 }
461 .editor-table-marker-column {
462   width: 4px;
463   cursor: col-resize;
464 }
465 .editor-table-marker-row {
466   height: 4px;
467   cursor: row-resize;
468 }
469
470 .editor-code-block-wrap {
471   user-select: none;
472   > * {
473     pointer-events: none;
474   }
475   &.selected .cm-editor {
476     border: 1px dashed var(--editor-color-primary);
477   }
478 }
479 .editor-diagram.selected {
480   outline: 2px dashed var(--editor-color-primary);
481 }
482
483 .editor-media-wrap {
484   display: inline-block;
485   cursor: not-allowed;
486   iframe, video {
487     pointer-events: none;
488   }
489   &.align-left {
490     float: left;
491   }
492   &.align-right {
493     float: right;
494   }
495   &.align-center {
496     display: block;
497     margin-inline: auto;
498   }
499 }
500
501 /**
502  * Fake task list checkboxes
503  */
504 .editor-content-area .task-list-item {
505   margin-left: 0;
506   position: relative;
507 }
508 .editor-content-area .task-list-item > input[type="checkbox"] {
509   display: none;
510 }
511 .editor-content-area .task-list-item:before {
512   content: '';
513   display: inline-block;
514   border: 2px solid #CCC;
515   width: 12px;
516   height: 12px;
517   border-radius: 2px;
518   margin-right: 8px;
519   vertical-align: text-top;
520   cursor: pointer;
521   position: absolute;
522   left: -24px;
523   top: 4px;
524 }
525 .editor-content-area .task-list-item[checked]:before {
526   background-color: #CCC;
527   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>');
528   background-position: 50% 50%;
529   background-size: 100% 100%;
530 }
531
532 /**
533  * Form elements
534  */
535 $inputWidth: 260px;
536
537 .editor-form-field-wrapper {
538   margin-bottom: .5rem;
539 }
540 .editor-form-field-input {
541   display: block;
542   width: $inputWidth;
543   min-width: 100px;
544   max-width: 100%;
545   border: 1px solid;
546   @include mixins.lightDark(border-color, #DDD, #000);
547   padding: .5rem;
548   border-radius: 4px;
549   @include mixins.lightDark(color, #444, #BBB);
550 }
551
552 @include mixins.smaller-than(vars.$bp-xs) {
553   .editor-form-field-input {
554     min-width: 160px;
555   }
556 }
557
558 textarea.editor-form-field-input {
559   font-family: var(--font-code);
560   width: 350px;
561   height: 250px;
562   font-size: 12px;
563 }
564 .editor-form-field-label {
565   color: #444;
566   font-weight: 700;
567   font-size: 12px;
568 }
569 .editor-form-actions {
570   display: flex;
571   justify-content: end;
572   gap: vars.$s;
573   margin-top: vars.$m;
574 }
575 .editor-form-actions > button {
576   display: block;
577   font-size: 0.85rem;
578   line-height: 1.4em;
579   padding: vars.$xs*1.3 vars.$m;
580   font-weight: 400;
581   border-radius: 4px;
582   cursor: pointer;
583   box-shadow: none;
584   &:focus {
585     outline: 1px dotted currentColor;
586     outline-offset: -(vars.$xs);
587     box-shadow: none;
588     filter: brightness(90%);
589   }
590 }
591 .editor-form-action-primary {
592   background-color: var(--color-primary);
593   color: #FFF;
594   border: 1px solid var(--color-primary);
595   &:hover {
596     @include mixins.lightDark(box-shadow, vars.$bs-light, vars.$bs-dark);
597     filter: brightness(110%);
598   }
599 }
600 .editor-form-action-secondary {
601   border: 1px solid;
602   @include mixins.lightDark(border-color, #CCC, #666);
603   @include mixins.lightDark(color, #666, #AAA);
604   &:hover, &:focus, &:active {
605     @include mixins.lightDark(color, #444, #BBB);
606     border: 1px solid #CCC;
607     box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.1);
608     background-color: #F2F2F2;
609     @include mixins.lightDark(background-color, #f8f8f8, #444);
610     filter: none;
611   }
612   &:active {
613     border-color: #BBB;
614     background-color: #DDD;
615     color: #666;
616     box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.1);
617   }
618 }
619 .editor-form-tab-container {
620   display: flex;
621   flex-direction: row;
622   gap: 2rem;
623 }
624 .editor-form-tab-controls {
625   display: flex;
626   flex-direction: column;
627   align-items: stretch;
628   gap: .25rem;
629 }
630
631 @include mixins.smaller-than(vars.$bp-m) {
632   .editor-form-tab-container {
633     flex-direction: column;
634     gap: .5rem;
635   }
636   .editor-form-tab-controls {
637     flex-direction: row;
638   }
639 }
640
641 .editor-form-tab-control {
642   font-weight: bold;
643   font-size: 14px;
644   @include mixins.lightDark(color, #444, #666);
645   border-bottom: 2px solid transparent;
646   position: relative;
647   cursor: pointer;
648   padding: .25rem .5rem;
649   text-align: start;
650   &[aria-selected="true"] {
651     border-color: var(--editor-color-primary);
652     color: var(--editor-color-primary) !important;
653   }
654   &[aria-selected="true"]:after, &:hover:after {
655     background-color: var(--editor-color-primary);
656     opacity: .15;
657     content: '';
658     display: block;
659     position: absolute;
660     left: 0;
661     top: 0;
662     width: 100%;
663     height: 100%;
664   }
665 }
666 .editor-form-tab-contents {
667   width: $inputWidth;
668   max-width: 100%;
669 }
670 .editor-action-input-container {
671   display: flex;
672   flex-direction: row;
673   align-items: end;
674   justify-content: space-between;
675   gap: .1rem;
676   .editor-button {
677     margin-bottom: 12px;
678   }
679   input {
680     width: $inputWidth - 40px;
681   }
682 }
683 .editor-color-field-container {
684   position: relative;
685   input {
686     padding-left: 36px;
687   }
688   .editor-dropdown-menu-container {
689     position: absolute;
690     bottom: 0;
691   }
692 }
693
694 // Specific field styles
695 textarea.editor-form-field-input[name="source"] {
696   width: 1000px;
697   height: 600px;
698   max-height: 60vh;
699   max-width: 80vw;
700 }
701
702 // Editor theme styles
703 .editor-theme-bold {
704   font-weight: bold;
705 }
706 .editor-theme-italic {
707   font-style: italic;
708 }
709 .editor-theme-strikethrough {
710   text-decoration-line: line-through;
711 }
712 .editor-theme-underline {
713   text-decoration-line: underline;
714 }
715 .editor-theme-underline-strikethrough {
716   text-decoration: underline line-through;
717 }