]> git.openstreetmap.org Git - rails.git/blob - app/assets/stylesheets/common.scss
Merge remote-tracking branch 'upstream/pull/5681'
[rails.git] / app / assets / stylesheets / common.scss
1 @use "sass:map";
2 @import "parameters";
3 @import "bootstrap";
4 @import "rails_bootstrap_forms";
5
6 /* Styles common to large and small screens */
7
8 /* Default rules for the body of every page */
9
10 body {
11   font-size: $typeheight;
12   --dark-mode-map-filter: none;
13 }
14
15 time[title] {
16   text-decoration: underline dotted;
17 }
18
19 /* Rules for icons */
20
21 .icon {
22   display: inline-block;
23   vertical-align: top;
24   width: 20px;
25   height: 20px;
26   background: transparent image-url("sprite.svg") no-repeat 0 0;
27   text-indent: -9999px;
28   overflow: hidden;
29 }
30
31 .icon.search      { /*rtl:ignore*/ background-position: 0 0; }
32 .icon.donate      { /*rtl:ignore*/ background-position: -20px 0; }
33 .icon.zoomin      { /*rtl:ignore*/ background-position: -40px 0; }
34 .icon.zoomout     { /*rtl:ignore*/ background-position: -60px 0; }
35 .icon.geolocate   { /*rtl:ignore*/ background-position: -80px 0; }
36 .active .icon.geolocate   { /*rtl:ignore*/ background-position: -80px -20px; }
37 .icon.layers      { /*rtl:ignore*/ background-position: -100px 0; }
38 .icon.key         { /*rtl:ignore*/ background-position: -120px 0; }
39 .icon.share       { /*rtl:ignore*/ background-position: -140px 0; }
40 .icon.clipboard   { /*rtl:ignore*/ background-position: -160px 0; }
41 .icon.link        { /*rtl:ignore*/ background-position: -180px 0; }
42 .icon.close       { /*rtl:ignore*/ background-position: -200px 0; }
43 .icon.close:hover { /*rtl:ignore*/ background-position: -200px -20px; }
44 .icon.check       { /*rtl:ignore*/ background-position: -220px 0; }
45 .icon.note        { /*rtl:ignore*/ background-position: -240px 0; }
46 .icon.note.grey   { /*rtl:ignore*/ background-position: -240px -20px; }
47 .icon.query       { /*rtl:ignore*/ background-position: -260px 0; }
48
49 /* Utility for de-emphasizing content */
50
51 .text-body-secondary a {
52   color: $blue;
53 }
54
55 /* Bootstrap contextual table classes overrides in dark mode */
56
57 @include color-mode(dark) {
58   .table-primary {
59     --bs-table-bg: rgb(var(--bs-primary-rgb), .25);
60   }
61   .table-secondary {
62     --bs-table-bg: rgb(var(--bs-secondary-rgb), .25);
63   }
64   .table-success {
65     --bs-table-bg: rgb(var(--bs-success-rgb), .25);
66   }
67   .table-primary, .table-secondary, .table-success {
68     --bs-table-color: initial;
69     border-color: inherit;
70   }
71 }
72
73 /* Utility for delayed loading spinner */
74
75 .delayed-fade-in {
76   animation: 300ms linear forwards delayed-fade-in;
77 }
78
79 @keyframes delayed-fade-in {
80   0%   { opacity: 0 }
81   66%  { opacity: 0 }
82   100% { opacity: 1 }
83 }
84
85 /* Bootstrap close button overrides for nested light/dark themes */
86
87 [data-bs-theme="dark"] .btn-close {
88   filter: var(--bs-btn-close-white-filter);
89 }
90
91 [data-bs-theme="light"] .btn-close {
92   filter: none;
93 }
94
95 /* Rules for the header */
96
97 #menu-icon {
98   display: none;
99   position: absolute;
100   top: 0;
101   right: 0;
102   background: image-url("menu-icon.svg") no-repeat;
103   background-size: 30px 30px;
104   width: 30px;
105   height: 30px;
106   margin: 14px 10px 0 0;
107   opacity: 0.6;
108 }
109
110 @include color-mode(dark) {
111   #menu-icon {
112     filter: invert(1);
113   }
114 }
115
116 header {
117   height: $headerHeight;
118   position: relative;
119   font-size: 14px;
120
121   > * {
122     padding: $lineheight * 0.5;
123   }
124
125   h1 {
126     height: $headerHeight;
127     font-size: 18px;
128   }
129
130   .btn {
131     font-size: 14px;
132   }
133
134   .username {
135     max-width: 12em;
136   }
137 }
138
139 nav.primary {
140   #edit_tab .btn-outline-primary {
141     @include button-outline-variant($green, $color-hover: $white, $active-color: $white);
142   }
143
144   .disabled {
145     .btn-outline-primary {
146       color: $grey;
147       cursor: default;
148
149       .caret {
150         border-top-color: $grey;
151       }
152
153       &:hover {
154         background-color: lighten($green, 30%);
155       }
156     }
157   }
158
159   // Small tweaks to the toggle to stop the primary colour showing through
160   // when the menu is shown
161   .show > .btn-outline-primary.dropdown-toggle {
162     background-color: $green;
163     border-color: $green;
164
165     &:focus {
166       box-shadow: 0 0 0 0.2rem fade-out($green, 0.5);
167     }
168   }
169 }
170
171 nav.secondary {
172   .nav-link {
173     padding: 0 0.3rem;
174   }
175
176   > ul {
177     height: 1.5em;
178   }
179 }
180
181 nav.primary, nav.secondary {
182   .dropdown-item {
183     &:hover, &:active {
184       background-color: $green;
185       color: white;
186     }
187   }
188 }
189
190 #compact-secondary-nav {
191   display: none;
192 }
193
194 body.small-nav {
195   #menu-icon {
196     display: block;
197   }
198
199   header {
200     flex-direction: column;
201     height: auto;
202     min-height: $headerHeight;
203
204     &.closed nav {
205       display: none !important;
206     }
207
208     .search_forms {
209       display: block;
210     }
211
212     .username {
213       max-width: unset;
214     }
215   }
216
217   #sidebar .search_forms {
218     display: none;
219   }
220
221   nav.primary {
222     margin-right: 0;
223     padding: 0;
224
225     #edit_tab {
226       width: 100%;
227       padding: 10px;
228     }
229   }
230
231   nav.secondary {
232     flex-direction: column;
233
234     > ul {
235       height: auto;
236     }
237
238     .user-menu, .login-menu {
239       width: 100%;
240     }
241   }
242
243   #compact-secondary-nav {
244     display: none;
245   }
246
247   .compact-hide {
248     display: inline-block;
249   }
250
251   .overlay-sidebar #sidebar .welcome {
252     display: none;
253   }
254
255   .overlay-sidebar #sidebar #banner {
256     display: none;
257   }
258 }
259
260 /* Utility for styling notification numbers */
261
262 .count-number {
263   background: transparentize(lighten($green, 25%), .25);
264   color: $gray-800;
265   font-weight: $font-weight-normal;
266 }
267
268 /* Rules for Leaflet maps */
269
270 .leaflet-top.leaflet-right,
271 .leaflet-top.leaflet-left {
272   height: 100%;
273   column-gap: 10px;
274   display: flex;
275   flex-direction: column;
276   flex-wrap: wrap-reverse;
277 }
278
279 .leaflet-control .control-button {
280   display: block;
281   height: 40px;
282   width: 40px;
283   background-color: #333;
284   background-color: rgba(0,0,0,.6);
285   outline: none;
286
287   &:hover,
288   &:focus {
289     background-color: black;
290   }
291
292   &.disabled,
293   &.leaflet-disabled {
294     background-color: #333;
295     background-color: rgba(0,0,0,.5);
296     cursor: default;
297   }
298
299   &.active {
300     background-color: $vibrant-green;
301   }
302
303   &-first {
304     border-start-start-radius: 4px;
305   }
306
307   &-last {
308     border-end-start-radius: 4px;
309     margin-bottom: 10px;
310   }
311
312   .icon {
313     margin: 10px;
314   }
315 }
316
317 /* Rules for the sidebar and main map area */
318
319 .map-layout {
320   #content {
321     overflow: hidden;
322     position: absolute;
323     top: $headerHeight;
324     bottom: 0;
325     width: 100%;
326   }
327
328   #sidebar, #map {
329     position: relative;
330     height: 100%;
331     overflow-x: hidden;
332     overflow-y: auto;
333   }
334
335   #sidebar {
336     float: left;
337     width: $sidebarWidth;
338
339     #sidebar_loader {
340       display: none;
341     }
342   }
343
344   .overlay-sidebar #sidebar {
345     position: absolute;
346     height: auto;
347     overflow: hidden;
348
349     #banner {
350       display: block;
351     }
352
353     .welcome {
354       display: block;
355     }
356
357     #sidebar_content {
358       display: none;
359     }
360   }
361
362   .welcome {
363     display: none;
364   }
365
366   #banner {
367     display: none;
368
369     img {
370       display: block;
371       width: $sidebarWidth;
372     }
373   }
374
375   #map {
376     height: 100%;
377     overflow: hidden;
378
379     &.query-active {
380       cursor: help;
381     }
382
383     &.query-disabled {
384       cursor: not-allowed;
385     }
386
387     .leaflet-marker-draggable {
388       cursor: move;
389     }
390
391     .query-marker {
392       animation: 1500ms forwards query-marker-fade;
393
394       @keyframes query-marker-fade {
395         to { opacity: 0 }
396       }
397     }
398   }
399
400   #map-ui {
401     display: none;
402     position: relative;
403     float: right;
404     width: 250px;
405     height: 100%;
406     overflow: auto;
407   }
408 }
409
410 @include media-breakpoint-down(md) {
411   body.map-layout {
412     #sidebar, #map {
413       position: relative;
414       overflow-x: hidden;
415       width: 100%;
416       height: 50%;
417     }
418
419     #map-ui {
420       width: 100%;
421       height: 50%;
422       overflow-y: scroll;
423     }
424
425     .overlay-sidebar.overlay-right-sidebar {
426       #sidebar {
427         position: absolute;
428         width: 350px;
429         height: auto;
430         overflow: hidden;
431       }
432
433       #map {
434         height: 100%;
435       }
436     }
437   }
438 }
439
440 .layers-ui {
441   .base-layers > * {
442     height: 3.5rem;
443
444     > .btn {
445       box-sizing: content-box;
446       top: - map.get($border-widths, 4);
447       left: - map.get($border-widths, 4);
448       --bs-btn-border-color: var(--bs-body-bg);
449     }
450     > .btn:hover {
451       --bs-btn-border-color: var(--bs-primary-border-subtle);
452     }
453   }
454
455   .overlay-layers {
456     li.disabled { color: $darkgrey; }
457   }
458 }
459
460 .share-ui {
461   #mapnik_scale {
462     width: 100px;
463   }
464 }
465
466 .leaflet-top {
467   top: 10px !important;
468   .leaflet-control {
469     margin-right: 0px !important;
470     margin-top: 0px !important;
471   }
472 }
473
474 .leaflet-popup-scrolled {
475   padding-right: $lineheight;
476   border-bottom: 0px !important;
477   border-top: 0px !important;
478 }
479
480 .leaflet-popup-content-wrapper, .leaflet-popup-tip,
481 .leaflet-contextmenu, .leaflet-contextmenu-item,
482 .leaflet-control-attribution, .leaflet-control-scale-line {
483   @extend .bg-body, .text-body;
484 }
485
486 .leaflet-control-attribution, .leaflet-control-scale-line {
487   @extend .bg-opacity-75;
488   text-shadow: none !important;
489 }
490
491 .leaflet-contextmenu-item.over {
492   @extend .bg-body-secondary, .border-secondary, .border-opacity-10;
493 }
494
495 .leaflet-popup-content-wrapper {
496   @extend .rounded-1;
497
498   a {
499     color: var(--bs-link-color) !important;
500   }
501 }
502
503 @include color-mode(dark) {
504   .leaflet-container .leaflet-control-attribution a {
505     color: var(--bs-link-color);
506   }
507
508   .leaflet-control-scale-line {
509     border-color: rgba(var(--bs-light-rgb), .75) !important;
510   }
511 }
512
513 @mixin dark-map-color-scheme {
514   .leaflet-tile-container,
515   .mapkey-table-entry td:first-child > * {
516     filter: var(--dark-mode-map-filter);
517   }
518
519   .leaflet-tile-container .leaflet-tile {
520     filter: none;
521   }
522 }
523
524 body[data-map-theme="dark"] {
525   @include dark-map-color-scheme;
526 }
527
528 @include color-mode(dark) {
529   body:not([data-map-theme]) {
530     @include dark-map-color-scheme;
531   }
532 }
533
534 /* Rules for attribution text under the main map shown on printouts */
535
536 .donate-attr { color: darken($green, 10%) !important; }
537
538 /* Temporary label size override until we remove site-wide font customisation */
539
540 form {
541   label {
542     font-size: 16px;
543   }
544   .col-form-label {
545     font-size: 16px;
546   }
547 }
548
549 /* Stop bootstrap 5 from floating legends when they don't need to be */
550 legend {
551   float: none;
552 }
553
554 /* Override the text colour for primary and secondary buttons, to match our
555    bootstrap 4 colours. Note this has accessibility issues, which is why
556    bootstrap 5 calculates black as the appropriate colour, and we should
557    reconsider our colours at some point with that in mind. */
558
559 .btn-primary {
560   @include button-variant($primary, $primary, $color: $white, $hover-color: $white, $active-color: $white, $disabled-color: $white);
561 }
562
563 .btn-secondary {
564   @include button-variant($secondary, $secondary, $color: $white, $hover-color: $white, $active-color: $white, $disabled-color: $white);
565 }
566
567 .btn-outline-secondary {
568   @include button-outline-variant($secondary, $color-hover: $white, $active-color: $white);
569 }
570
571 /* Rules for the search and direction forms */
572
573 header .search_forms,
574 .directions_form {
575   display: none;
576 }
577
578 .search_form {
579   .describe_location {
580     font-size: 10px;
581   }
582 }
583
584 /* Rules for search sidebar */
585
586 #sidebar .search_results_entry {
587   .search_more .loader {
588     display: none;
589   }
590 }
591
592 /* Rules for routing */
593
594 div.direction {
595   background-image: image-url('routing-sprite.svg');
596   width: 20px;
597   height: 20px;
598   background-repeat: no-repeat;
599 }
600 @for $i from 0 through 25 {
601 div.direction.i#{$i} { background-position: #{($i)*-20}px 0px; }
602 }
603
604 @include color-mode(dark) {
605   div.direction {
606     filter: invert(1);
607   }
608 }
609
610 td.distance {
611     font-size: x-small;
612 }
613 tr.turn {
614     cursor: pointer;
615 }
616
617 .routing_marker_column {
618   width: 15px;
619
620   img {
621     cursor: move;
622   }
623 }
624
625 /* Rules for the history sidebar */
626
627 #sidebar .changesets {
628   li {
629     &.selected {
630       @extend :hover;
631     }
632
633     a.stretched-link > span, a:not(.stretched-link), [title] {
634       position: relative;
635       z-index: 2; /* needs to be higher than Bootstrap's stretched link ::after z-index */
636     }
637   }
638
639   .changeset_more .loader {
640     display: none;
641     width: 100%;
642   }
643 }
644
645 /* Rules for the browse sidebar */
646
647 #sidebar_content {
648   .browse-section {
649     padding-bottom: $spacer;
650     margin-bottom: $spacer;
651     border-bottom: 1px solid $grey;
652
653     h4:first-child {
654       word-wrap: break-word;
655     }
656   }
657
658   .browse-section:last-of-type {
659     border-bottom: none;
660   }
661
662   .browse-tag-list {
663     table-layout: fixed;
664     white-space: pre-wrap;
665     word-wrap: break-word;
666     word-break: break-word;
667
668     tr:last-child th, tr:last-child td {
669       border-bottom: 0;
670     }
671   }
672
673   .query-results {
674     display: none;
675   }
676 }
677
678 /* Force LTR/RTL alignment for placeholder text */
679
680 .form-control::placeholder {
681   text-align: left;
682 }
683
684 /* Rules for export sidebar */
685
686 .export_form {
687   .export_area_inputs {
688     input[type="text"] {
689       width: 100px;
690     }
691   }
692
693   .export_boxy {
694     > * {
695         margin: -1px;
696     }
697     #minlon {
698       /*rtl:ignore*/ float: left;
699     }
700     #maxlon {
701       /*rtl:ignore*/ float: right;
702     }
703   }
704 }
705
706 /* Rules for edit pages */
707
708 .site-edit {
709   #content {
710     position: absolute;
711     top: $headerHeight;
712     bottom: 0;
713     width: 100%;
714   }
715 }
716
717 /* Rules for non-map content pages */
718
719 .content-inner {
720   position: relative;
721   max-width: 960px;
722   margin: auto;
723   padding: $lineheight;
724 }
725
726 /* Rules for login and signup pages */
727
728 .sessions-new, .users-new, .users-create {
729   #content .content-inner {
730     max-width: 760px;
731   }
732 }
733
734 .header-illustration {
735   background-position: right;
736   background-repeat: no-repeat;
737   position: relative;
738   min-height: 200px;
739   width: 100%;
740   left: 0;
741   bottom: 0;
742
743   &.new-user-main {
744     background-image: image-url("sign-up-illustration.svg");
745     background-position-x: 70px;
746   }
747
748   &.confirm-main {
749     background-image: image-url("confirm-illustration.svg");
750   }
751
752   &.new-user-terms {
753     background-image: image-url("terms-illustration.svg");
754   }
755 }
756
757 [dir=rtl] .header-illustration {
758   transform: scaleX(-1);
759
760   h1 {
761     transform: scaleX(-1);
762   }
763
764   ul {
765     transform: scaleX(-1);
766   }
767 }
768
769 /* Rules for small maps in content areas */
770
771 .content_map {
772   height: 200px;
773   margin-bottom: $lineheight;
774 }
775
776 @include media-breakpoint-up(md) {
777   .content_map {
778     height: 400px;
779   }
780 }
781
782 /* Rules for the user map */
783
784 .content_map .leaflet-popup-content {
785   margin: $spacer;
786   min-height: 50px;
787 }
788
789 /* Rules for user popups on maps */
790
791 .user_popup {
792   p {
793     padding: 0 0 5px 0;
794     margin: 0 0 0 60px;
795     font-size: 12px;
796   }
797 }
798
799 /* Rules for the diary entry page */
800
801 .diary_entries {
802   #map {
803     height: 400px;
804     display: none;
805   }
806   .diary-comment .col-auto {
807     width: 62px;
808   }
809   .diary-comment .col {
810     max-width: 690px;
811   }
812 }
813
814 /* Rules for the issues page */
815
816 .issues.issues-index {
817   td.reporting_users {
818     max-width: 5rem;
819   }
820 }
821
822 /* Rules for the account confirmation page */
823
824 .accounts-terms-show {
825   .legale {
826     padding: $lineheight;
827     margin-bottom: $lineheight;
828     overflow: auto;
829     height: 20em;
830
831     li {
832       list-style: inherit;
833     }
834
835     ol ol {
836       list-style-type: lower-alpha;
837     }
838   }
839 }
840
841 /* Rules for user images */
842
843 img.user_image {
844   max-width: 100px;
845   max-height: 100px;
846 }
847
848 img.user_thumbnail {
849   max-width: 50px;
850   max-height: 50px;
851 }
852
853 img.user_thumbnail_tiny {
854   width: 25px;
855   height: 25px;
856   object-fit: contain;
857 }
858
859 /* General styles for action lists / subnavs */
860
861 nav.secondary-actions {
862   margin-left: -11px;
863   overflow: hidden;
864   > ul {
865     display: flex;
866     flex-direction: row;
867     flex-wrap: wrap;
868     margin-bottom: 0;
869     margin-left: -1px;
870     padding: 0;
871     > li {
872       flex-basis: auto;
873       list-style: none;
874       border-left: 1px solid $grey;
875       padding-left: $lineheight * 0.5;
876       margin-right: $lineheight * 0.5;
877       margin-bottom: $lineheight * 0.125;
878     }
879   }
880 }
881
882 div.secondary-actions {
883   padding: 10px;
884   text-align: center;
885 }
886
887 /* Rules for rich text */
888
889 .richtext {
890   code {
891     background: var(--bs-secondary-bg);
892     padding: 2px 3px;
893   }
894
895   pre {
896     background: var(--bs-secondary-bg);
897     padding: 2px 3px;
898     white-space: pre-wrap;
899
900     code {
901       padding: 0;
902     }
903   }
904
905   img {
906     padding: $lineheight;
907     background-color: var(--bs-tertiary-bg);
908     display: block;
909     max-width: 100%;
910     margin: auto;
911   }
912
913   blockquote {
914     border-left: $lineheight solid var(--bs-tertiary-bg);
915     padding-left: $lineheight;
916     margin: 0;
917     color: var(--bs-secondary-color);
918   }
919 }
920
921 /* Rules for the "About" page */
922
923 .site-about #content {
924   .content-inner {
925     max-width: 760px;
926   }
927
928   .attr {
929     margin-top: -20px;
930
931     h1 {
932       span {
933         color: $vibrant-green;
934       }
935     }
936
937     .user-image {
938       height: 150px;
939       background-position: 0 50%;
940       background-repeat: no-repeat;
941       background-image: image-url('about/osm.png');
942       background-size: cover;
943       background-color: $vibrant-green;
944     }
945
946     .byosm {
947       background: $vibrant-green;
948     }
949
950     .byosm span {
951       display: inline-block;
952       width: 1em;
953       margin-left: -1em;
954     }
955   }
956 }
957
958 /* Rules for tables with usernames */
959
960 .messages-table .username,
961 #block_list .username {
962   max-width: 20em;
963 }
964
965 /* Rules for navigation tabs */
966
967 .nav-tabs .username {
968   max-width: 20em;
969 }
970
971 .bg-body-secondary .nav-tabs {
972   --bs-border-color: var(--bs-secondary-border-subtle);
973   --bs-secondary-bg: var(--bs-secondary-border-subtle);
974   margin-bottom: -1px;
975 }
976
977 /* Rules for traces */
978
979 img.trace_image {
980   mix-blend-mode: darken;
981 }
982
983 @include color-mode(dark) {
984   img.trace_image {
985     filter: invert(1);
986     mix-blend-mode: lighten;
987   }
988 }
989
990 /* Rules for map sidebar icons */
991
992 .browse-section .browse-element-list {
993   line-height: 1.25rem;
994
995   .browse-icon {
996     height: 1.25rem;
997   }
998
999   .d-flex > .browse-icon {
1000     height: max(20px, 1.25rem);
1001   }
1002
1003   @include color-mode(dark) {
1004     .browse-icon-invertible {
1005       filter: invert(.8) hue-rotate(180deg);
1006     }
1007   }
1008 }