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