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