Added theme switcher
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// Animations on load
|
||||
@media screen and (prefers-reduced-motion: no-preference) {
|
||||
.appear-from-top {
|
||||
animation: fadeIn .2s cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
||||
animation: fadeIn .2s var(--timing-function);
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
cursor: pointer;
|
||||
transition-property: color, background-color, border-color;
|
||||
transition-duration: .2s;
|
||||
transition-timing-function: cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
||||
transition-timing-function: var(--timing-function);
|
||||
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
@@ -95,14 +95,14 @@
|
||||
outline: .2rem solid transparent;
|
||||
transition-property: color, background-color, border-color, outline-color;
|
||||
transition-duration: .15s;
|
||||
transition-timing-function: cubic-bezier(0.445, 0.05, 0.55, 0.95);
|
||||
transition-timing-function: var(--timing-function);
|
||||
|
||||
svg {
|
||||
fill: var(--foreground);
|
||||
width: 1.15em;
|
||||
transition-property: fill;
|
||||
transition-duration: .15s;
|
||||
transition-timing-function: cubic-bezier(0.445, 0.05, 0.55, 0.95);
|
||||
transition-timing-function: var(--timing-function);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
border-radius: var(--border-radius);
|
||||
transition-property: box-shadow;
|
||||
transition-duration: .2s;
|
||||
transition-timing-function: cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
||||
transition-timing-function: var(--timing-function);
|
||||
|
||||
&:focus-visible {
|
||||
box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--accent) 20%, transparent);
|
||||
|
||||
@@ -39,8 +39,11 @@
|
||||
box-shadow: none;
|
||||
border-bottom-left-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 {
|
||||
display: none;
|
||||
@@ -59,6 +62,9 @@
|
||||
color: var(--foreground);
|
||||
background-color: var(--background);
|
||||
border-color: var(--border);
|
||||
transition-property: color, background-color, border-color, outline-color;
|
||||
transition-duration: .15s;
|
||||
transition-timing-function: var(--timing-function);
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
@@ -71,6 +77,9 @@
|
||||
.leaflet-touch .leaflet-control-measure {
|
||||
color: var(--foreground);
|
||||
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 {
|
||||
color: var(--foreground);
|
||||
@@ -78,6 +87,9 @@
|
||||
border-color: var(--border);
|
||||
background-image: url('/icon/ruler.svg');
|
||||
background-size: 66%;
|
||||
transition-property: color, background-color, border-color, outline-color;
|
||||
transition-duration: .15s;
|
||||
transition-timing-function: var(--timing-function);
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
background-color: color-mix(in srgb, var(--black) 50%, transparent);
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
animation: show-overlay 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
animation: show-overlay 150ms var(--timing-function);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
background-color: var(--background);
|
||||
border: 1px solid var(--border);
|
||||
box-shadow: var(--shadow);
|
||||
animation: show-content 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
animation: show-content 150ms var(--timing-function);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
|
||||
@@ -51,20 +51,20 @@
|
||||
}
|
||||
}
|
||||
.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'] {
|
||||
animation: hide 100ms ease-in;
|
||||
animation: hide 100ms var(--timing-function);
|
||||
}
|
||||
.toast-root[data-swipe='move'] {
|
||||
transform: translateX(var(--radix-toast-swipe-move-x));
|
||||
}
|
||||
.toast-root[data-swipe='cancel'] {
|
||||
transform: translateX(0);
|
||||
transition: transform 200ms ease-out;
|
||||
transition: transform 200ms var(--timing-function);
|
||||
}
|
||||
.toast-root[data-swipe='end'] {
|
||||
animation: swipeOut 100ms ease-out;
|
||||
animation: swipeOut 100ms var(--timing-function);
|
||||
}
|
||||
|
||||
@keyframes hide {
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
|
||||
--border-radius: .25rem;
|
||||
--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 {
|
||||
|
||||
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 MapOverlayBreadcrumbs from "./MapOverlayBreadcrumbs.astro";
|
||||
import ToastService from "./overlay/ToastService.vue";
|
||||
import ThemeSwitch from "../global/ThemeSwitch.vue";
|
||||
|
||||
interface Props extends MapOverlayProps {}
|
||||
|
||||
@@ -41,9 +42,14 @@ const currentUrl = Astro.url
|
||||
</SearchMarkers>
|
||||
}
|
||||
|
||||
|
||||
<div class="right-menu">
|
||||
{ENABLE_I18N &&
|
||||
<LangSwitcher currentUrl={currentUrl} client:only="vue" />
|
||||
}
|
||||
|
||||
<ThemeSwitch client:only="vue" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{ENABLE_BREADCRUMB &&
|
||||
@@ -71,5 +77,15 @@ const currentUrl = Astro.url
|
||||
align-items: top;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.right-menu {
|
||||
display: grid;
|
||||
gap: .5rem;
|
||||
align-content: flex-start;
|
||||
|
||||
@media screen and (width >= 900px) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -54,6 +54,9 @@ menu {
|
||||
border-radius: 100vmax;
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;
|
||||
pointer-events: all;
|
||||
transition-property: color, background-color, border-color, outline-color;
|
||||
transition-duration: .15s;
|
||||
transition-timing-function: var(--timing-function);
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
|
||||
@@ -314,6 +314,9 @@ function resetAllFields(actionAfter?: "focusAfter") {
|
||||
border-radius: 25px;
|
||||
box-shadow: var(--shadow);
|
||||
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) {
|
||||
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" />
|
||||
<script is:inline type="text/javascript" src="/js/leaflet-measure.min.js"></script>
|
||||
</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 />
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user