]> git.openstreetmap.org Git - rails.git/blob - app/assets/stylesheets/common.scss
Merge remote-tracking branch 'upstream/pull/6470'
[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 .leaflet-popup-content-wrapper, .leaflet-popup-tip,
423 .leaflet-control-attribution, .leaflet-control-scale-line {
424   @extend .bg-body, .text-body;
425 }
426
427 .leaflet-control-attribution, .leaflet-control-scale-line {
428   @extend .bg-opacity-75;
429   text-shadow: none !important;
430 }
431
432 .leaflet-popup-content-wrapper {
433   @extend .rounded-1;
434
435   a {
436     color: var(--bs-link-color) !important;
437   }
438 }
439
440 @include color-mode(dark) {
441   .leaflet-container .leaflet-control-attribution a {
442     color: var(--bs-link-color);
443   }
444
445   .leaflet-control-scale-line {
446     border-color: rgba(var(--bs-light-rgb), .75) !important;
447   }
448 }
449
450 @mixin dark-map-color-scheme {
451   .leaflet-tile-container,
452   #legend .filtered-image {
453     filter: var(--dark-mode-map-filter);
454   }
455
456   .leaflet-tile-container .leaflet-tile {
457     filter: none;
458   }
459 }
460
461 body[data-map-theme="dark"] {
462   @include dark-map-color-scheme;
463 }
464
465 @include color-mode(dark) {
466   body:not([data-map-theme]) {
467     @include dark-map-color-scheme;
468   }
469 }
470
471 /* Rules for attribution text under the main map shown on printouts */
472
473 .donate-attr { color: darken($green, 10%) !important; }
474
475 /* Temporary label size override until we remove site-wide font customisation */
476
477 form {
478   label {
479     font-size: 16px;
480   }
481   .col-form-label {
482     font-size: 16px;
483   }
484 }
485
486 /* Stop bootstrap 5 from floating legends when they don't need to be */
487 legend {
488   float: none;
489 }
490
491 /* Override the text colour for primary and secondary buttons, to match our
492    bootstrap 4 colours. Note this has accessibility issues, which is why
493    bootstrap 5 calculates black as the appropriate colour, and we should
494    reconsider our colours at some point with that in mind. */
495
496 .btn-primary {
497   @include button-variant($primary, $primary, $color: $white, $hover-color: $white, $active-color: $white, $disabled-color: $white);
498 }
499
500 .btn-secondary {
501   @include button-variant($secondary, $secondary, $color: $white, $hover-color: $white, $active-color: $white, $disabled-color: $white);
502 }
503
504 .btn-outline-secondary {
505   @include button-outline-variant($secondary, $color-hover: $white, $active-color: $white);
506 }
507
508 /* Rules for the search and direction forms */
509
510 .directions_form {
511   display: none;
512 }
513
514 .search_form {
515   .describe_location {
516     font-size: 10px;
517   }
518
519   input:not(:placeholder-shown) + .input-group-text .describe_location {
520     display: none;
521   }
522 }
523
524 /* Rules for search results */
525
526 .search_results_entry li.list-group-item {
527   border-right: 1em solid var(--marker-color);
528 }
529
530 .leaflet-marker-icon.activatable:is(.active, :hover) > svg {
531   transform: scale(1.5);
532   transform-origin: bottom;
533 }
534
535 /* Rules for routing */
536
537 td.distance {
538     font-size: x-small;
539 }
540 tr.turn {
541     cursor: pointer;
542 }
543
544 .routing_marker_column {
545   margin-left: .35rem;
546   margin-right: .35rem;
547   width: 15px;
548
549   svg {
550     cursor: move;
551   }
552 }
553
554 /* Rules for the history sidebar */
555
556 .changeset-above-sidebar-viewport {
557   --changeset-border-color: #CC6655;
558   --changeset-fill-color: #DDBBBB;
559   --changeset-outline-color: #FFF4F4;
560 }
561 .changeset-in-sidebar-viewport {
562   --changeset-border-color: #FF9500;
563   --changeset-fill-color: #FFFFAF;
564   --changeset-outline-color: #FFFFFF;
565   &.changeset-highlight-outline {
566     filter: drop-shadow(0px 0px 2px rgba(0, 0, 0, .75));
567   }
568 }
569 .changeset-below-sidebar-viewport {
570   --changeset-border-color: #8888AA;
571   --changeset-fill-color: #CCCCDD;
572   --changeset-outline-color: #F4F4FF;
573 }
574 .changeset-highlight-outline {
575   filter: drop-shadow(0px 0px 2px rgba(0, 0, 0, .25));
576 }
577
578 #sidebar .changesets {
579   .changeset-color-hint-bar {
580     height: 2px;
581     background: var(--changeset-border-color);
582   }
583
584   li {
585     &.selected {
586       @extend :hover;
587     }
588
589     a.stretched-link > bdi, a:not(.stretched-link), [title] {
590       position: relative;
591       z-index: 2; /* needs to be higher than Bootstrap's stretched link ::after z-index */
592     }
593   }
594 }
595
596 #sidebar .changeset_line .changeset_num_comments {
597   min-width: 2.5em;
598 }
599
600 /* Rules for the browse sidebar */
601
602 #sidebar_content {
603   .browse-tag-list {
604     table-layout: fixed;
605
606     tr > *:not([colspan]) {
607       white-space: pre-wrap;
608       word-wrap: break-word;
609       word-break: break-word;
610     }
611
612     tr:last-child > * {
613       border-bottom: 0;
614     }
615   }
616
617   .browse-element-list {
618     line-height: 1.25rem;
619
620     .browse-icon {
621       height: 1.25rem;
622     }
623
624     .d-flex > .browse-icon {
625       height: max(20px, 1.25rem);
626     }
627   }
628
629   .query-results {
630     display: none;
631   }
632 }
633
634 @include color-mode(dark) {
635   #sidebar_content .browse-element-list .browse-icon-invertible {
636     filter: invert(.8) hue-rotate(180deg);
637   }
638 }
639
640 /* Force LTR/RTL alignment for placeholder text */
641
642 .form-control::placeholder {
643   text-align: left;
644 }
645
646 /* Rules for export sidebar */
647
648 .export_form {
649   .export_area_inputs {
650     input[type="text"] {
651       width: 100px;
652     }
653   }
654
655   .export_boxy {
656     > * {
657         margin: -1px;
658     }
659   }
660 }
661
662 /* Rules for edit pages */
663
664 .site-edit {
665   #content {
666     position: absolute;
667     top: $headerHeight;
668     bottom: 0;
669     width: 100%;
670   }
671 }
672
673 /* Rules for non-map content pages */
674
675 .content-inner {
676   max-width: 960px;
677   padding: $lineheight;
678 }
679
680 /* Rules for login and signup pages */
681
682 .sessions-new, .users-new, .users-create {
683   #content .content-inner {
684     max-width: 760px;
685   }
686 }
687
688 .header-illustration {
689   background-position: right;
690   background-repeat: no-repeat;
691   position: relative;
692   min-height: 200px;
693   width: 100%;
694   left: 0;
695   bottom: 0;
696
697   &.new-user-main {
698     background-image: image-url("sign-up-illustration.svg");
699     background-position-x: 70px;
700   }
701
702   &.confirm-main {
703     background-image: image-url("confirm-illustration.svg");
704   }
705
706   &.new-user-terms {
707     background-image: image-url("terms-illustration.svg");
708   }
709 }
710
711 [dir=rtl] .header-illustration {
712   transform: scaleX(-1);
713
714   h1 {
715     transform: scaleX(-1);
716   }
717
718   ul {
719     transform: scaleX(-1);
720   }
721 }
722
723 /* Rules for small maps in content areas */
724
725 .content_map {
726   height: 200px;
727   margin-bottom: $lineheight;
728 }
729
730 @include media-breakpoint-up(md) {
731   .content_map {
732     height: 400px;
733   }
734 }
735
736 /* Rules for the user map */
737
738 .content_map .leaflet-popup-content {
739   margin: $spacer;
740 }
741
742 /* Rules for user popups on maps */
743
744 .user_popup {
745   p {
746     margin: 0 0 5px 0 !important;
747     font-size: 12px;
748   }
749 }
750
751 /* Rules for the diary entry page */
752
753 .diary_entries {
754   #map {
755     height: 400px;
756     display: none;
757   }
758   .diary-comment .col-auto {
759     width: 62px;
760   }
761   .diary-comment .col {
762     max-width: 690px;
763   }
764 }
765
766 /* Rules for the issues page */
767
768 .issues.issues-index {
769   td.reporting_users {
770     max-width: 5rem;
771   }
772 }
773
774 /* Rules for the account confirmation page */
775
776 .accounts-terms-show {
777   .legale {
778     padding: $lineheight;
779     margin-bottom: $lineheight;
780     overflow: auto;
781     height: 20em;
782
783     li {
784       list-style: inherit;
785     }
786
787     ol ol {
788       list-style-type: lower-alpha;
789     }
790   }
791 }
792
793 /* Rules for user images */
794
795 img.user_image {
796   max-width: 100px;
797   max-height: 100px;
798 }
799
800 img.user_thumbnail {
801   max-width: 50px;
802   max-height: 50px;
803 }
804
805 img.user_thumbnail_tiny {
806   width: 25px;
807   height: 25px;
808   object-fit: contain;
809 }
810
811 /* General styles for action lists / subnavs */
812
813 nav.secondary-actions {
814   margin-left: -11px;
815   overflow: hidden;
816   > ul {
817     display: flex;
818     flex-direction: row;
819     flex-wrap: wrap;
820     margin-bottom: 0;
821     margin-left: -1px;
822     padding: 0;
823     > li {
824       flex-basis: auto;
825       list-style: none;
826       border-left: 1px solid $grey;
827       padding-left: $lineheight * 0.5;
828       margin-right: $lineheight * 0.5;
829       margin-bottom: $lineheight * 0.125;
830     }
831   }
832 }
833
834 div.secondary-actions {
835   padding: 10px;
836   text-align: center;
837 }
838
839 /* Rules for rich text */
840
841 .richtext {
842   code {
843     background: var(--bs-secondary-bg);
844     padding: 2px 3px;
845   }
846
847   pre {
848     background: var(--bs-secondary-bg);
849     padding: 2px 3px;
850     white-space: pre-wrap;
851
852     code {
853       padding: 0;
854     }
855   }
856
857   img {
858     padding: $lineheight;
859     background-color: var(--bs-tertiary-bg);
860     display: block;
861     max-width: 100%;
862     margin: auto;
863   }
864
865   blockquote {
866     border-left: $lineheight solid var(--bs-tertiary-bg);
867     padding-left: $lineheight;
868     margin: 0;
869     color: var(--bs-secondary-color);
870   }
871 }
872
873 /* Rules for the "About" page */
874
875 .site-about #content {
876   .content-inner {
877     max-width: 760px;
878   }
879
880   .attr {
881     margin-top: -20px;
882
883     h1 {
884       span {
885         color: $vibrant-green;
886       }
887     }
888
889     .user-image {
890       height: 150px;
891       background-position: 0 50%;
892       background-repeat: no-repeat;
893       background-image: image-url('about/osm.png');
894       background-size: cover;
895       background-color: $vibrant-green;
896     }
897
898     .byosm {
899       background: $vibrant-green;
900     }
901
902     .byosm span {
903       display: inline-block;
904       width: 1em;
905       margin-left: -1em;
906     }
907   }
908 }
909
910 /* Rules for tables with usernames */
911
912 .messages-table .username,
913 #block_list .username {
914   max-width: 20em;
915 }
916
917 /* Rules for navigation tabs */
918
919 .nav-tabs .username {
920   max-width: 20em;
921 }
922
923 .bg-body-secondary .nav-tabs {
924   --bs-border-color: var(--bs-secondary-border-subtle);
925   --bs-secondary-bg: var(--bs-secondary-border-subtle);
926   margin-bottom: -1px;
927 }
928
929 /* Rules for traces */
930
931 img.trace_image {
932   mix-blend-mode: darken;
933 }
934
935 @include color-mode(dark) {
936   img.trace_image {
937     filter: invert(1);
938     mix-blend-mode: lighten;
939   }
940 }
941
942 /* Rules for the heatmap */
943
944 .heatmap {
945   grid-template-columns: auto;
946   grid-auto-columns: minmax(1em, 1fr);
947   grid-template-rows: auto;
948   grid-auto-rows: minmax(1em, 1fr);
949   font-size: x-small;
950   gap: 0.3em;
951
952   [data-date], [data-date] span {
953     display: block;
954     aspect-ratio: 1;
955     border-radius: 25%;
956   }
957
958   [data-date] {
959     background-color: #ededed;
960     span {
961       background-color: #14432a;
962     }
963     &[data-count] {
964       background-color: #4dd05a;
965     }
966     &:hover {
967       box-shadow: 0px 0px 0px 1px #8884;
968     }
969   }
970 }
971
972 @include color-mode(dark) {
973   .heatmap {
974     [data-date] {
975       background-color: #2d333b;
976       span {
977         background-color: #4dd05a;
978       }
979       &[data-count] {
980         background-color: #14432a;
981       }
982     }
983   }
984 }
985
986 .tooltip.wide {
987   --bs-tooltip-max-width: none;
988 }
989
990 /* Rules for auth provider logos */
991
992 .apple-logo rect { fill: black; }
993 .apple-logo path { fill: white; }
994
995 @media (prefers-color-scheme: dark) {
996   .apple-logo rect { fill: white; }
997   .apple-logo path { fill: black; }
998 }
999
1000 .github-logo rect { fill: white; }
1001 .github-logo path { fill: black; }
1002
1003 @media (prefers-color-scheme: dark) {
1004   .github-logo rect { fill: black; }
1005   .github-logo path { fill: white; }
1006 }
1007
1008 /* Rules for contextmenu */
1009
1010 #map-context-menu {
1011   .dropdown-item {
1012     &:hover, &:active {
1013       background-color: $gray-200;
1014     }
1015   }
1016   &.cm_dropdown {
1017     position: absolute;
1018     z-index: 1000;
1019   }
1020   &.cm_dropdown_menu {
1021     position: absolute;
1022     display: block;
1023     min-width: 200px;
1024   }
1025 }
1026
1027 @media (prefers-color-scheme: dark) {
1028   #map-context-menu {
1029     .dropdown-item {
1030       &:hover, &:active {
1031         background-color: $gray-700;
1032       }
1033     }
1034   }
1035 }