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