]> git.openstreetmap.org Git - rails.git/blob - app/assets/stylesheets/common.scss
Unify active control button behaviour
[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 .icon.layers      { /*rtl:ignore*/ background-position: -100px 0; }
37 .icon.key         { /*rtl:ignore*/ background-position: -120px 0; }
38 .icon.share       { /*rtl:ignore*/ background-position: -140px 0; }
39 .icon.clipboard   { /*rtl:ignore*/ background-position: -160px 0; }
40 .icon.link        { /*rtl:ignore*/ background-position: -180px 0; }
41 .icon.close       { /*rtl:ignore*/ background-position: -200px 0; }
42 .icon.close:hover { /*rtl:ignore*/ background-position: -200px -20px; }
43 .icon.check       { /*rtl:ignore*/ background-position: -220px 0; }
44 .icon.note        { /*rtl:ignore*/ background-position: -240px 0; }
45 .icon.note.grey   { /*rtl:ignore*/ background-position: -240px -20px; }
46 .icon.query       { /*rtl:ignore*/ background-position: -260px 0; }
47
48 /* Utility for de-emphasizing content */
49
50 .text-body-secondary a {
51   color: $blue;
52 }
53
54 /* Bootstrap contextual table classes overrides in dark mode */
55
56 @include color-mode(dark) {
57   .table-primary {
58     --bs-table-bg: rgb(var(--bs-primary-rgb), .25);
59   }
60   .table-secondary {
61     --bs-table-bg: rgb(var(--bs-secondary-rgb), .25);
62   }
63   .table-success {
64     --bs-table-bg: rgb(var(--bs-success-rgb), .25);
65   }
66   .table-primary, .table-secondary, .table-success {
67     --bs-table-color: initial;
68     border-color: inherit;
69   }
70 }
71
72 /* Utility for delayed loading spinner */
73
74 .delayed-fade-in {
75   animation: 300ms linear forwards delayed-fade-in;
76 }
77
78 @keyframes delayed-fade-in {
79   0%   { opacity: 0 }
80   66%  { opacity: 0 }
81   100% { opacity: 1 }
82 }
83
84 /* Bootstrap close button overrides for nested light/dark themes */
85
86 [data-bs-theme="dark"],
87 [data-bs-theme] [data-bs-theme="dark"] {
88   --bs-btn-close-filter: invert(1) grayscale(100%) brightness(200%);
89 }
90
91 [data-bs-theme="light"],
92 [data-bs-theme] [data-bs-theme="light"] {
93   --bs-btn-close-filter: none;
94 }
95
96 /* Rules for the header */
97
98 #menu-icon {
99   display: none;
100   position: absolute;
101   top: 0;
102   right: 0;
103   background: image-url("menu-icon.svg") no-repeat;
104   background-size: 30px 30px;
105   width: 30px;
106   height: 30px;
107   margin: 14px 10px 0 0;
108   opacity: 0.6;
109 }
110
111 @include color-mode(dark) {
112   #menu-icon {
113     filter: invert(1);
114   }
115 }
116
117 header {
118   height: $headerHeight;
119   position: relative;
120   font-size: 14px;
121
122   > * {
123     padding: $lineheight * 0.5;
124   }
125
126   h1 {
127     height: $headerHeight;
128     font-size: 18px;
129   }
130
131   .btn {
132     font-size: 14px;
133   }
134
135   .username {
136     max-width: 12em;
137   }
138 }
139
140 nav.primary {
141   #edit_tab .btn-outline-primary {
142     @include button-outline-variant($green, $color-hover: $white, $active-color: $white);
143   }
144
145   .disabled {
146     .btn-outline-primary {
147       color: $grey;
148       cursor: default;
149
150       .caret {
151         border-top-color: $grey;
152       }
153
154       &:hover {
155         background-color: lighten($green, 30%);
156       }
157     }
158   }
159
160   // Small tweaks to the toggle to stop the primary colour showing through
161   // when the menu is shown
162   .show > .btn-outline-primary.dropdown-toggle {
163     background-color: $green;
164     border-color: $green;
165
166     &:focus {
167       box-shadow: 0 0 0 0.2rem fade-out($green, 0.5);
168     }
169   }
170 }
171
172 nav.secondary {
173   .nav-link {
174     padding: 0 0.3rem;
175   }
176
177   > ul {
178     height: 1.5em;
179   }
180 }
181
182 nav.primary, nav.secondary {
183   .dropdown-item {
184     &:hover, &:active {
185       background-color: $green;
186       color: white;
187     }
188   }
189 }
190
191 #compact-secondary-nav {
192   display: none;
193 }
194
195 body.small-nav {
196   #menu-icon {
197     display: block;
198   }
199
200   header {
201     flex-direction: column;
202     height: auto;
203     min-height: $headerHeight;
204
205     &.closed nav {
206       display: none !important;
207     }
208
209     .search_forms {
210       display: block;
211     }
212
213     .username {
214       max-width: unset;
215     }
216   }
217
218   #sidebar .search_forms {
219     display: none;
220   }
221
222   nav.primary {
223     margin-right: 0;
224     padding: 0;
225
226     #edit_tab {
227       width: 100%;
228       padding: 10px;
229     }
230   }
231
232   nav.secondary {
233     flex-direction: column;
234
235     > ul {
236       height: auto;
237       justify-content: center;
238     }
239
240     .user-menu, .login-menu {
241       width: 100%;
242     }
243   }
244
245   #compact-secondary-nav {
246     display: none;
247   }
248
249   .compact-hide {
250     display: inline-block;
251   }
252
253   .overlay-sidebar #sidebar .welcome {
254     display: none;
255   }
256
257   .overlay-sidebar #sidebar #banner {
258     display: none;
259   }
260 }
261
262 /* Utility for styling notification numbers */
263
264 .count-number {
265   background: transparentize(lighten($green, 25%), .25);
266   color: $gray-800;
267   font-weight: $font-weight-normal;
268 }
269
270 /* Rules for Leaflet maps */
271
272 .leaflet-top.leaflet-right,
273 .leaflet-top.leaflet-left {
274   height: 100%;
275   column-gap: 10px;
276   display: flex;
277   flex-direction: column;
278   flex-wrap: wrap-reverse;
279 }
280
281 .leaflet-control .control-button {
282   display: block;
283   height: 40px;
284   width: 40px;
285   background-color: #333;
286   background-color: rgba(0,0,0,.6);
287   outline: none;
288
289   &:hover,
290   &:focus {
291     background-color: black;
292   }
293
294   &.disabled,
295   &.leaflet-disabled {
296     background-color: #333;
297     background-color: rgba(0,0,0,.5);
298     cursor: default;
299   }
300
301   &-first {
302     border-start-start-radius: 4px;
303   }
304
305   &-last {
306     border-end-start-radius: 4px;
307     margin-bottom: 10px;
308   }
309
310   .icon {
311     margin: 10px;
312   }
313 }
314
315 .leaflet-control.active .control-button {
316   background-color: $vibrant-green;
317 }
318
319 /* Rules for the sidebar and main map area */
320
321 .map-layout {
322   #content {
323     overflow: hidden;
324     position: absolute;
325     top: $headerHeight;
326     bottom: 0;
327     width: 100%;
328   }
329
330   #sidebar, #map {
331     position: relative;
332     height: 100%;
333     overflow-x: hidden;
334     overflow-y: auto;
335   }
336
337   #sidebar {
338     float: left;
339     width: $sidebarWidth;
340   }
341
342   .overlay-sidebar #sidebar {
343     position: absolute;
344     height: auto;
345     overflow: hidden;
346
347     #banner {
348       display: block;
349     }
350
351     .welcome {
352       display: block;
353     }
354
355     .sidebar-close-controls,
356     #sidebar_loader,
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 routing */
585
586 td.distance {
587     font-size: x-small;
588 }
589 tr.turn {
590     cursor: pointer;
591 }
592
593 .routing_marker_column {
594   margin-left: .35rem;
595   margin-right: .35rem;
596   width: 15px;
597
598   img {
599     cursor: move;
600   }
601 }
602
603 /* Rules for the history sidebar */
604
605 .changeset-above-sidebar-viewport {
606   --changeset-border-color: #CC6655;
607   --changeset-fill-color: #DDBBBB;
608   --changeset-outline-color: #FFF4F4;
609 }
610 .changeset-in-sidebar-viewport {
611   --changeset-border-color: #FF9500;
612   &.changeset-highlighted {
613     --changeset-border-color: #FF6600;
614   }
615   --changeset-fill-color: #FFFFAF;
616   --changeset-outline-color: #FFFFFF;
617 }
618 .changeset-below-sidebar-viewport {
619   --changeset-border-color: #8888AA;
620   --changeset-fill-color: #CCCCDD;
621   --changeset-outline-color: #F4F4FF;
622 }
623
624 #sidebar .changesets {
625   .changeset-color-hint-bar {
626     height: 2px;
627     background: var(--changeset-border-color);
628   }
629
630   li {
631     &.selected {
632       @extend :hover;
633     }
634
635     a.stretched-link > span, a:not(.stretched-link), [title] {
636       position: relative;
637       z-index: 2; /* needs to be higher than Bootstrap's stretched link ::after z-index */
638     }
639   }
640 }
641
642 /* Rules for the browse sidebar */
643
644 #sidebar_content {
645   .browse-section {
646     padding-bottom: $spacer;
647     margin-bottom: $spacer;
648     border-bottom: 1px solid $grey;
649
650     h4:first-child {
651       word-wrap: break-word;
652     }
653   }
654
655   .browse-section:last-of-type {
656     border-bottom: none;
657   }
658
659   .browse-tag-list {
660     table-layout: fixed;
661     white-space: pre-wrap;
662     word-wrap: break-word;
663     word-break: break-word;
664
665     tr:last-child th, tr:last-child td {
666       border-bottom: 0;
667     }
668   }
669
670   .query-results {
671     display: none;
672   }
673 }
674
675 /* Force LTR/RTL alignment for placeholder text */
676
677 .form-control::placeholder {
678   text-align: left;
679 }
680
681 /* Rules for export sidebar */
682
683 .export_form {
684   .export_area_inputs {
685     input[type="text"] {
686       width: 100px;
687     }
688   }
689
690   .export_boxy {
691     > * {
692         margin: -1px;
693     }
694   }
695 }
696
697 /* Rules for edit pages */
698
699 .site-edit {
700   #content {
701     position: absolute;
702     top: $headerHeight;
703     bottom: 0;
704     width: 100%;
705   }
706 }
707
708 /* Rules for non-map content pages */
709
710 .content-inner {
711   max-width: 960px;
712   padding: $lineheight;
713 }
714
715 /* Rules for login and signup pages */
716
717 .sessions-new, .users-new, .users-create {
718   #content .content-inner {
719     max-width: 760px;
720   }
721 }
722
723 .header-illustration {
724   background-position: right;
725   background-repeat: no-repeat;
726   position: relative;
727   min-height: 200px;
728   width: 100%;
729   left: 0;
730   bottom: 0;
731
732   &.new-user-main {
733     background-image: image-url("sign-up-illustration.svg");
734     background-position-x: 70px;
735   }
736
737   &.confirm-main {
738     background-image: image-url("confirm-illustration.svg");
739   }
740
741   &.new-user-terms {
742     background-image: image-url("terms-illustration.svg");
743   }
744 }
745
746 [dir=rtl] .header-illustration {
747   transform: scaleX(-1);
748
749   h1 {
750     transform: scaleX(-1);
751   }
752
753   ul {
754     transform: scaleX(-1);
755   }
756 }
757
758 /* Rules for small maps in content areas */
759
760 .content_map {
761   height: 200px;
762   margin-bottom: $lineheight;
763 }
764
765 @include media-breakpoint-up(md) {
766   .content_map {
767     height: 400px;
768   }
769 }
770
771 /* Rules for the user map */
772
773 .content_map .leaflet-popup-content {
774   margin: $spacer;
775   min-height: 50px;
776 }
777
778 /* Rules for user popups on maps */
779
780 .user_popup {
781   p {
782     padding: 0 0 5px 0;
783     margin: 0 0 0 60px;
784     font-size: 12px;
785   }
786 }
787
788 /* Rules for the diary entry page */
789
790 .diary_entries {
791   #map {
792     height: 400px;
793     display: none;
794   }
795   .diary-comment .col-auto {
796     width: 62px;
797   }
798   .diary-comment .col {
799     max-width: 690px;
800   }
801 }
802
803 /* Rules for the issues page */
804
805 .issues.issues-index {
806   td.reporting_users {
807     max-width: 5rem;
808   }
809 }
810
811 /* Rules for the account confirmation page */
812
813 .accounts-terms-show {
814   .legale {
815     padding: $lineheight;
816     margin-bottom: $lineheight;
817     overflow: auto;
818     height: 20em;
819
820     li {
821       list-style: inherit;
822     }
823
824     ol ol {
825       list-style-type: lower-alpha;
826     }
827   }
828 }
829
830 /* Rules for user images */
831
832 img.user_image {
833   max-width: 100px;
834   max-height: 100px;
835 }
836
837 img.user_thumbnail {
838   max-width: 50px;
839   max-height: 50px;
840 }
841
842 img.user_thumbnail_tiny {
843   width: 25px;
844   height: 25px;
845   object-fit: contain;
846 }
847
848 /* General styles for action lists / subnavs */
849
850 nav.secondary-actions {
851   margin-left: -11px;
852   overflow: hidden;
853   > ul {
854     display: flex;
855     flex-direction: row;
856     flex-wrap: wrap;
857     margin-bottom: 0;
858     margin-left: -1px;
859     padding: 0;
860     > li {
861       flex-basis: auto;
862       list-style: none;
863       border-left: 1px solid $grey;
864       padding-left: $lineheight * 0.5;
865       margin-right: $lineheight * 0.5;
866       margin-bottom: $lineheight * 0.125;
867     }
868   }
869 }
870
871 div.secondary-actions {
872   padding: 10px;
873   text-align: center;
874 }
875
876 /* Rules for rich text */
877
878 .richtext {
879   code {
880     background: var(--bs-secondary-bg);
881     padding: 2px 3px;
882   }
883
884   pre {
885     background: var(--bs-secondary-bg);
886     padding: 2px 3px;
887     white-space: pre-wrap;
888
889     code {
890       padding: 0;
891     }
892   }
893
894   img {
895     padding: $lineheight;
896     background-color: var(--bs-tertiary-bg);
897     display: block;
898     max-width: 100%;
899     margin: auto;
900   }
901
902   blockquote {
903     border-left: $lineheight solid var(--bs-tertiary-bg);
904     padding-left: $lineheight;
905     margin: 0;
906     color: var(--bs-secondary-color);
907   }
908 }
909
910 /* Rules for the "About" page */
911
912 .site-about #content {
913   .content-inner {
914     max-width: 760px;
915   }
916
917   .attr {
918     margin-top: -20px;
919
920     h1 {
921       span {
922         color: $vibrant-green;
923       }
924     }
925
926     .user-image {
927       height: 150px;
928       background-position: 0 50%;
929       background-repeat: no-repeat;
930       background-image: image-url('about/osm.png');
931       background-size: cover;
932       background-color: $vibrant-green;
933     }
934
935     .byosm {
936       background: $vibrant-green;
937     }
938
939     .byosm span {
940       display: inline-block;
941       width: 1em;
942       margin-left: -1em;
943     }
944   }
945 }
946
947 /* Rules for tables with usernames */
948
949 .messages-table .username,
950 #block_list .username {
951   max-width: 20em;
952 }
953
954 /* Rules for navigation tabs */
955
956 .nav-tabs .username {
957   max-width: 20em;
958 }
959
960 .bg-body-secondary .nav-tabs {
961   --bs-border-color: var(--bs-secondary-border-subtle);
962   --bs-secondary-bg: var(--bs-secondary-border-subtle);
963   margin-bottom: -1px;
964 }
965
966 /* Rules for traces */
967
968 img.trace_image {
969   mix-blend-mode: darken;
970 }
971
972 @include color-mode(dark) {
973   img.trace_image {
974     filter: invert(1);
975     mix-blend-mode: lighten;
976   }
977 }
978
979 /* Rules for map sidebar icons */
980
981 .browse-section .browse-element-list {
982   line-height: 1.25rem;
983
984   .browse-icon {
985     height: 1.25rem;
986   }
987
988   .d-flex > .browse-icon {
989     height: max(20px, 1.25rem);
990   }
991
992   @include color-mode(dark) {
993     .browse-icon-invertible {
994       filter: invert(.8) hue-rotate(180deg);
995     }
996   }
997 }
998
999 .heatmap-wrapper {
1000   height: 130px;
1001 }