Added theme switcher
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
// Animations on load
|
// Animations on load
|
||||||
@media screen and (prefers-reduced-motion: no-preference) {
|
@media screen and (prefers-reduced-motion: no-preference) {
|
||||||
.appear-from-top {
|
.appear-from-top {
|
||||||
animation: fadeIn .2s cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
animation: fadeIn .2s var(--timing-function);
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fadeIn {
|
@keyframes fadeIn {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition-property: color, background-color, border-color;
|
transition-property: color, background-color, border-color;
|
||||||
transition-duration: .2s;
|
transition-duration: .2s;
|
||||||
transition-timing-function: cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
transition-timing-function: var(--timing-function);
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
@@ -95,14 +95,14 @@
|
|||||||
outline: .2rem solid transparent;
|
outline: .2rem solid transparent;
|
||||||
transition-property: color, background-color, border-color, outline-color;
|
transition-property: color, background-color, border-color, outline-color;
|
||||||
transition-duration: .15s;
|
transition-duration: .15s;
|
||||||
transition-timing-function: cubic-bezier(0.445, 0.05, 0.55, 0.95);
|
transition-timing-function: var(--timing-function);
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
fill: var(--foreground);
|
fill: var(--foreground);
|
||||||
width: 1.15em;
|
width: 1.15em;
|
||||||
transition-property: fill;
|
transition-property: fill;
|
||||||
transition-duration: .15s;
|
transition-duration: .15s;
|
||||||
transition-timing-function: cubic-bezier(0.445, 0.05, 0.55, 0.95);
|
transition-timing-function: var(--timing-function);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
transition-property: box-shadow;
|
transition-property: box-shadow;
|
||||||
transition-duration: .2s;
|
transition-duration: .2s;
|
||||||
transition-timing-function: cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
transition-timing-function: var(--timing-function);
|
||||||
|
|
||||||
&:focus-visible {
|
&:focus-visible {
|
||||||
box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--accent) 20%, transparent);
|
box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--accent) 20%, transparent);
|
||||||
|
|||||||
@@ -39,8 +39,11 @@
|
|||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
|
transition-property: color, text-shadow;
|
||||||
|
transition-duration: .15s;
|
||||||
|
transition-timing-function: var(--timing-function);
|
||||||
|
|
||||||
@include text.stroke(2, color-mix(in srgb, var(--foreground) 10%, var(--background)));
|
@include text.stroke(2, var(--background));
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -59,6 +62,9 @@
|
|||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
border-color: var(--border);
|
border-color: var(--border);
|
||||||
|
transition-property: color, background-color, border-color, outline-color;
|
||||||
|
transition-duration: .15s;
|
||||||
|
transition-timing-function: var(--timing-function);
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus-visible {
|
&:focus-visible {
|
||||||
@@ -71,6 +77,9 @@
|
|||||||
.leaflet-touch .leaflet-control-measure {
|
.leaflet-touch .leaflet-control-measure {
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
|
transition-property: color, background-color, border-color, outline-color;
|
||||||
|
transition-duration: .15s;
|
||||||
|
transition-timing-function: var(--timing-function);
|
||||||
|
|
||||||
.leaflet-control-measure-toggle {
|
.leaflet-control-measure-toggle {
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
@@ -78,6 +87,9 @@
|
|||||||
border-color: var(--border);
|
border-color: var(--border);
|
||||||
background-image: url('/icon/ruler.svg');
|
background-image: url('/icon/ruler.svg');
|
||||||
background-size: 66%;
|
background-size: 66%;
|
||||||
|
transition-property: color, background-color, border-color, outline-color;
|
||||||
|
transition-duration: .15s;
|
||||||
|
transition-timing-function: var(--timing-function);
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus-visible {
|
&:focus-visible {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
background-color: color-mix(in srgb, var(--black) 50%, transparent);
|
background-color: color-mix(in srgb, var(--black) 50%, transparent);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
animation: show-overlay 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
animation: show-overlay 150ms var(--timing-function);
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
animation: show-content 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
animation: show-content 150ms var(--timing-function);
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
|
|||||||
@@ -51,20 +51,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.toast-root[data-state='open'] {
|
.toast-root[data-state='open'] {
|
||||||
animation: slideIn 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
animation: slideIn 150ms var(--timing-function);
|
||||||
}
|
}
|
||||||
.toast-root[data-state='closed'] {
|
.toast-root[data-state='closed'] {
|
||||||
animation: hide 100ms ease-in;
|
animation: hide 100ms var(--timing-function);
|
||||||
}
|
}
|
||||||
.toast-root[data-swipe='move'] {
|
.toast-root[data-swipe='move'] {
|
||||||
transform: translateX(var(--radix-toast-swipe-move-x));
|
transform: translateX(var(--radix-toast-swipe-move-x));
|
||||||
}
|
}
|
||||||
.toast-root[data-swipe='cancel'] {
|
.toast-root[data-swipe='cancel'] {
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
transition: transform 200ms ease-out;
|
transition: transform 200ms var(--timing-function);
|
||||||
}
|
}
|
||||||
.toast-root[data-swipe='end'] {
|
.toast-root[data-swipe='end'] {
|
||||||
animation: swipeOut 100ms ease-out;
|
animation: swipeOut 100ms var(--timing-function);
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes hide {
|
@keyframes hide {
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
|
|
||||||
--border-radius: .25rem;
|
--border-radius: .25rem;
|
||||||
--shadow: color-mix(in srgb, var(--foreground) 10%, transparent) 0px 4px 12px;
|
--shadow: color-mix(in srgb, var(--foreground) 10%, transparent) 0px 4px 12px;
|
||||||
|
--timing-function: cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
|
|||||||
30
src/components/global/ThemeSwitch.vue
Normal file
30
src/components/global/ThemeSwitch.vue
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { useDark, useToggle } from '@vueuse/core'
|
||||||
|
|
||||||
|
const isDark = useDark({ storageKey: "theme", disableTransition: false })
|
||||||
|
const toggleDark = useToggle(isDark)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div data-theme-toggle id="theme-switcher" class="wrapper appear-from-top">
|
||||||
|
<button @click="toggleDark()" class="btn-round">
|
||||||
|
<svg v-if="isDark" xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M120,40V32a8,8,0,0,1,16,0v8a8,8,0,0,1-16,0Zm72,88a64,64,0,1,1-64-64A64.07,64.07,0,0,1,192,128Zm-16,0a48,48,0,1,0-48,48A48.05,48.05,0,0,0,176,128ZM58.34,69.66A8,8,0,0,0,69.66,58.34l-8-8A8,8,0,0,0,50.34,61.66Zm0,116.68-8,8a8,8,0,0,0,11.32,11.32l8-8a8,8,0,0,0-11.32-11.32ZM192,72a8,8,0,0,0,5.66-2.34l8-8a8,8,0,0,0-11.32-11.32l-8,8A8,8,0,0,0,192,72Zm5.66,114.34a8,8,0,0,0-11.32,11.32l8,8a8,8,0,0,0,11.32-11.32ZM40,120H32a8,8,0,0,0,0,16h8a8,8,0,0,0,0-16Zm88,88a8,8,0,0,0-8,8v8a8,8,0,0,0,16,0v-8A8,8,0,0,0,128,208Zm96-88h-8a8,8,0,0,0,0,16h8a8,8,0,0,0,0-16Z"></path></svg>
|
||||||
|
<svg v-else xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M233.54,142.23a8,8,0,0,0-8-2,88.08,88.08,0,0,1-109.8-109.8,8,8,0,0,0-10-10,104.84,104.84,0,0,0-52.91,37A104,104,0,0,0,136,224a103.09,103.09,0,0,0,62.52-20.88,104.84,104.84,0,0,0,37-52.91A8,8,0,0,0,233.54,142.23ZM188.9,190.34A88,88,0,0,1,65.66,67.11a89,89,0,0,1,31.4-26A106,106,0,0,0,96,56,104.11,104.11,0,0,0,200,160a106,106,0,0,0,14.92-1.06A89,89,0,0,1,188.9,190.34Z"></path></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.wrapper {
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-round {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
> svg {
|
||||||
|
width: 1.25em;
|
||||||
|
height: 1.25em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -8,6 +8,7 @@ import SearchMarkers from "./overlay/SearchMarkers.vue";
|
|||||||
import LangSwitcher from "./overlay/LangSwitcher.vue";
|
import LangSwitcher from "./overlay/LangSwitcher.vue";
|
||||||
import MapOverlayBreadcrumbs from "./MapOverlayBreadcrumbs.astro";
|
import MapOverlayBreadcrumbs from "./MapOverlayBreadcrumbs.astro";
|
||||||
import ToastService from "./overlay/ToastService.vue";
|
import ToastService from "./overlay/ToastService.vue";
|
||||||
|
import ThemeSwitch from "../global/ThemeSwitch.vue";
|
||||||
|
|
||||||
interface Props extends MapOverlayProps {}
|
interface Props extends MapOverlayProps {}
|
||||||
|
|
||||||
@@ -41,9 +42,14 @@ const currentUrl = Astro.url
|
|||||||
</SearchMarkers>
|
</SearchMarkers>
|
||||||
}
|
}
|
||||||
|
|
||||||
{ENABLE_I18N &&
|
|
||||||
<LangSwitcher currentUrl={currentUrl} client:only="vue" />
|
<div class="right-menu">
|
||||||
}
|
{ENABLE_I18N &&
|
||||||
|
<LangSwitcher currentUrl={currentUrl} client:only="vue" />
|
||||||
|
}
|
||||||
|
|
||||||
|
<ThemeSwitch client:only="vue" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{ENABLE_BREADCRUMB &&
|
{ENABLE_BREADCRUMB &&
|
||||||
@@ -71,5 +77,15 @@ const currentUrl = Astro.url
|
|||||||
align-items: top;
|
align-items: top;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.right-menu {
|
||||||
|
display: grid;
|
||||||
|
gap: .5rem;
|
||||||
|
align-content: flex-start;
|
||||||
|
|
||||||
|
@media screen and (width >= 900px) {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ menu {
|
|||||||
border-radius: 100vmax;
|
border-radius: 100vmax;
|
||||||
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;
|
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
|
transition-property: color, background-color, border-color, outline-color;
|
||||||
|
transition-duration: .15s;
|
||||||
|
transition-timing-function: var(--timing-function);
|
||||||
|
|
||||||
li {
|
li {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -314,6 +314,9 @@ function resetAllFields(actionAfter?: "focusAfter") {
|
|||||||
border-radius: 25px;
|
border-radius: 25px;
|
||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
|
transition-property: color, background-color, border-color, outline-color;
|
||||||
|
transition-duration: .15s;
|
||||||
|
transition-timing-function: var(--timing-function);
|
||||||
|
|
||||||
@media screen and (width >= 900px) {
|
@media screen and (width >= 900px) {
|
||||||
width: clamp(25rem, 35dvw, 30rem);
|
width: clamp(25rem, 35dvw, 30rem);
|
||||||
|
|||||||
@@ -58,7 +58,55 @@ const lang = getLangFromUrl(Astro.url) || defaultLang;
|
|||||||
<link rel="stylesheet" href="/leaflet-measure/leaflet-measure.css" rel="preload" />
|
<link rel="stylesheet" href="/leaflet-measure/leaflet-measure.css" rel="preload" />
|
||||||
<script is:inline type="text/javascript" src="/js/leaflet-measure.min.js"></script>
|
<script is:inline type="text/javascript" src="/js/leaflet-measure.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="dark">
|
<body>
|
||||||
|
<script is:inline>
|
||||||
|
let initialTheme = localStorage.getItem("theme");
|
||||||
|
const darkModeMq = window.matchMedia("(prefers-color-scheme: dark)");
|
||||||
|
|
||||||
|
// Initial paint from localstorage
|
||||||
|
switch (initialTheme) {
|
||||||
|
case "light":
|
||||||
|
enableLightTheme();
|
||||||
|
break;
|
||||||
|
case "system":
|
||||||
|
resetTheme();
|
||||||
|
break;
|
||||||
|
case "dark":
|
||||||
|
default:
|
||||||
|
enableDarkTheme();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enables dark theme and updates preferences
|
||||||
|
function enableDarkTheme() {
|
||||||
|
document.documentElement.classList.add('dark');
|
||||||
|
document.documentElement.classList.remove('light');
|
||||||
|
localStorage.setItem("theme", "dark");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enables light theme and updates preferences
|
||||||
|
function enableLightTheme() {
|
||||||
|
document.documentElement.classList.add('light');
|
||||||
|
document.documentElement.classList.remove('dark');
|
||||||
|
localStorage.setItem("theme", "light");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset theme to OS values
|
||||||
|
function resetTheme() {
|
||||||
|
const prefersDark = darkModeMq.matches;
|
||||||
|
|
||||||
|
if (prefersDark) {
|
||||||
|
document.documentElement.classList.add('dark');
|
||||||
|
document.documentElement.classList.remove('light');
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.add('light');
|
||||||
|
document.documentElement.classList.remove('dark');
|
||||||
|
}
|
||||||
|
|
||||||
|
localStorage.setItem("theme", "system");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<slot />
|
<slot />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user