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