adds dark mode

This commit is contained in:
Christian Beutel
2024-02-22 02:53:06 +01:00
parent 442e13b7c7
commit e41649e395
18 changed files with 113 additions and 56 deletions

View File

@@ -3,7 +3,7 @@
@import 'tailwindcss/components'; @import 'tailwindcss/components';
.btn-primary { .btn-primary {
@apply h-10 text-white rounded-lg px-4 py-2 bg-primary font-semibold transition-all hover:bg-primary-hover focus:ring-4 ring-input-border-focus @apply h-10 text-white rounded-lg px-4 py-2 bg-primary font-semibold transition-all hover:bg-primary-hover focus:ring-4 ring-input-ring
} }
.btn-large { .btn-large {
@@ -11,7 +11,7 @@
} }
.btn-secondary { .btn-secondary {
@apply rounded-lg px-4 py-2 border border-input-border-focus font-medium transition-all hover:bg-secondary-hover focus:ring-4 ring-input-border-focus @apply rounded-lg px-4 py-2 border border-input-border-focus font-medium transition-all hover:bg-secondary-hover focus:ring-4 ring-input-ring
} }
.btn-danger { .btn-danger {
@@ -23,7 +23,7 @@
} }
.btn-icon { .btn-icon {
@apply rounded-full aspect-square h-7 hover:bg-secondary-hover focus:ring-4 ring-input-border-focus transition-colors; @apply rounded-full aspect-square h-7 hover:bg-secondary-hover focus:ring-4 ring-input-ring transition-colors;
} }
.tab { .tab {
@@ -31,7 +31,7 @@
} }
.tab:hover { .tab:hover {
@apply bg-gray-100 @apply bg-menu-item-background-hover
} }
.tab-active { .tab-active {

View File

@@ -9,6 +9,7 @@
--input-background: 249, 250, 251; --input-background: 249, 250, 251;
--input-border: 209, 213, 219; --input-border: 209, 213, 219;
--input-border-focus: 36, 39, 52; --input-border-focus: 36, 39, 52;
--input-ring: 148, 163, 184;
--menu-background: 255, 255, 255; --menu-background: 255, 255, 255;
--menu-item-background-hover: 243, 244, 246; --menu-item-background-hover: 243, 244, 246;
@@ -16,7 +17,7 @@
--footer-background: 36, 39, 52; --footer-background: 36, 39, 52;
--separator: 17, 24, 39; --separator: 148, 163, 184;
background: rgba(var(--background)); background: rgba(var(--background));
color: rgba(var(--content)); color: rgba(var(--content));
@@ -33,6 +34,7 @@
--input-background: 36, 39, 52; --input-background: 36, 39, 52;
--input-border: 43, 46, 61; --input-border: 43, 46, 61;
--input-border-focus: 108, 115, 150; --input-border-focus: 108, 115, 150;
--input-ring: 108, 115, 150;
--menu-background: 33, 36, 54; --menu-background: 33, 36, 54;
--menu-item-background-hover: 43, 46, 69; --menu-item-background-hover: 43, 46, 69;

View File

@@ -14,7 +14,7 @@
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<input <input
{name} {name}
class="bg-gray-50 border rounded-md p-3 transition-colors focus:border-primary focus:outline-none focus:ring-0 w-full" class="bg-input-background border border-input-border rounded-md p-3 transition-colors focus:border-input-border-focus focus:outline-none focus:ring-0 w-full"
class:border-red-400={error.length > 0} class:border-red-400={error.length > 0}
class:bg-red-50={error.length > 0} class:bg-red-50={error.length > 0}
type="date" type="date"

View File

@@ -15,15 +15,15 @@
{id} {id}
tabindex="-1" tabindex="-1"
aria-hidden="true" aria-hidden="true"
class="relative w-full max-w-2xl max-h-full rounded-xl" class="relative w-full max-w-2xl max-h-full rounded-xl text-content"
> >
<!-- Modal content --> <!-- Modal content -->
<div class="relative bg-white shadow dark:bg-gray-700"> <div class="relative bg-background shadow">
<!-- Modal header --> <!-- Modal header -->
<div <div
class="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600" class="flex items-center justify-between p-4 md:p-5 border-b border-separator rounded-t"
> >
<h3 class="text-xl font-semibold text-gray-900 dark:text-white"> <h3 class="text-xl font-semibold">
{title} {title}
</h3> </h3>
<button <button
@@ -41,7 +41,7 @@
</div> </div>
<!-- Modal footer --> <!-- Modal footer -->
<div <div
class="p-4 md:p-5 border-t border-gray-200 rounded-b dark:border-gray-600" class="p-4 md:p-5 border-t border-separator rounded-b"
> >
<slot name="footer" {closeModal} /> <slot name="footer" {closeModal} />
</div> </div>

View File

@@ -29,7 +29,7 @@
type="radio" type="radio"
checked={i == selected} checked={i == selected}
value={item.value} value={item.value}
class="w-4 h-4 accent-input-background border-input-border focus:ring-input-border-focus focus:ring-2" class="w-4 h-4 accent-input-background border-input-border focus:ring-input-ring focus:ring-2"
on:change={() => handleRadioChange(i)} on:change={() => handleRadioChange(i)}
/> />
<label for="{name}-radio-{i}" class="ms-2 text-sm">{item.text}</label> <label for="{name}-radio-{i}" class="ms-2 text-sm">{item.text}</label>

View File

@@ -14,7 +14,7 @@
value="1" value="1"
/> />
<div <div
class="w-11 h-6 bg-input-background peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-input-border-focus rounded-full peer peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-input-background" class="w-11 h-6 bg-input-background border border-input-border peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-input-ring rounded-full peer peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-primary"
></div> ></div>
<span class="ms-3 text-sm font-medium">{label}</span> <span class="ms-3 text-sm font-medium">{label}</span>
</label> </label>

View File

@@ -7,7 +7,7 @@ Command: npx @threlte/gltf@2.0.1 static/models/earth.glb
import { theme } from "$lib/stores/theme_store"; import { theme } from "$lib/stores/theme_store";
import { T, forwardEventHandlers } from "@threlte/core"; import { T, forwardEventHandlers } from "@threlte/core";
import { useGltf } from "@threlte/extras"; import { useGltf } from "@threlte/extras";
import { backIn, backInOut, backOut, cubicInOut } from "svelte/easing"; import { backInOut } from "svelte/easing";
import { tweened } from "svelte/motion"; import { tweened } from "svelte/motion";
import { Group } from "three"; import { Group } from "three";
@@ -19,15 +19,15 @@ Command: npx @threlte/gltf@2.0.1 static/models/earth.glb
const component = forwardEventHandlers(); const component = forwardEventHandlers();
const sunXRotation = tweened(0, { const sunXRotation = tweened($theme == "light" ? 0 : -Math.PI, {
duration: 1500, duration: 1000,
easing: backInOut easing: backInOut
}); });
const sunLightIntensitiy = tweened(2.5, { const sunLightIntensitiy = tweened($theme == "light" ? 2.5 : 0.1, {
duration: 500, duration: 500,
}); });
const moonLightIntensitiy = tweened(2.5, { const moonLightIntensitiy = tweened($theme == "dark" ? 2.5 : 0.1, {
duration: 500, duration: 500,
}); });
$: sunLightIntensitiy.set($theme == "light" ? 2.5 : 0.1); $: sunLightIntensitiy.set($theme == "light" ? 2.5 : 0.1);
@@ -105,7 +105,7 @@ Command: npx @threlte/gltf@2.0.1 static/models/earth.glb
</T.Group> </T.Group>
<!-- /Airplane --> <!-- /Airplane -->
<!-- Sun --> <!-- Sun & Moon -->
<T.Group rotation={[$sunXRotation, 0, 0]}> <T.Group rotation={[$sunXRotation, 0, 0]}>
<T.Mesh <T.Mesh
geometry={gltf.nodes.Icosphere007.geometry} geometry={gltf.nodes.Icosphere007.geometry}
@@ -131,7 +131,7 @@ Command: npx @threlte/gltf@2.0.1 static/models/earth.glb
material={gltf.materials["Material.011"]} material={gltf.materials["Material.011"]}
position={[0, -2, 0]} position={[0, -2, 0]}
rotation={[Math.PI / 2, 0, Math.PI]} rotation={[Math.PI / 2, 0, Math.PI]}
scale={0.055} scale={0.045}
> >
<T.PointLight position={[0, 0.4, 0]} color="#a2cbf5" intensity={0.15} <T.PointLight position={[0, 0.4, 0]} color="#a2cbf5" intensity={0.15}
></T.PointLight> ></T.PointLight>

View File

@@ -1,11 +1,11 @@
<script lang="ts"> <script lang="ts">
import { goto } from "$app/navigation"; import { afterNavigate, goto } from "$app/navigation";
import LogoText from "$lib/components/logo/logo_text.svelte"; import LogoText from "$lib/components/logo/logo_text.svelte";
import { theme, toggleTheme } from "$lib/stores/theme_store";
import { currentUser, logout } from "$lib/stores/user_store"; import { currentUser, logout } from "$lib/stores/user_store";
import { backInOut, cubicOut } from "svelte/easing";
import { tweened } from "svelte/motion"; import { tweened } from "svelte/motion";
import Dropdown from "./base/dropdown.svelte"; import Dropdown from "./base/dropdown.svelte";
import { cubicOut } from "svelte/easing";
import { theme, toggleTheme } from "$lib/stores/theme_store";
import LogoTextLight from "./logo/logo_text_light.svelte"; import LogoTextLight from "./logo/logo_text_light.svelte";
const navBarItems = [ const navBarItems = [
@@ -31,23 +31,50 @@
easing: cubicOut, easing: cubicOut,
}); });
const indicatorScale = tweened(0, {
duration: 600,
easing: backInOut,
});
afterNavigate((e) => {
const routeId = e.to?.route.id;
const navBarLinks = document.getElementById("nav-bar-links");
let childPosition = -1;
switch (routeId) {
case "/":
childPosition = 1;
break;
case "/trails":
childPosition = 2;
break;
case "/map":
childPosition = 3;
break;
default:
break;
}
if (childPosition !== -1) {
const childElement = navBarLinks?.children[
childPosition
] as HTMLElement;
const newWidth = childElement?.getBoundingClientRect().width ?? 0;
const newPosition = childElement.offsetLeft;
const padding = 16;
indicatorScale.set(1);
indicatorWidth.set(newWidth + padding);
indicatorPosition.set(newPosition - padding / 2);
} else {
indicatorScale.set(0);
}
});
function handleDropdownClick(item: { text: string; value: any }) { function handleDropdownClick(item: { text: string; value: any }) {
if (item.value == "logout") { if (item.value == "logout") {
logout(); logout();
goto("/login"); goto("/login");
} }
} }
function setActiveItem(target: EventTarget | null) {
if (!target) {
return;
}
const element = target as HTMLElement;
const rect = element.getBoundingClientRect();
const padding = 16;
indicatorWidth.set(rect.width + padding);
indicatorPosition.set(element.offsetLeft - padding / 2);
}
</script> </script>
<nav class="flex justify-between items-center p-6"> <nav class="flex justify-between items-center p-6">
@@ -59,15 +86,14 @@
{/if} {/if}
</a> </a>
{#if $currentUser} {#if $currentUser}
<menu class="flex gap-8 relative py-1 px-2"> <menu id="nav-bar-links" class="flex gap-8 relative py-1 px-2">
<div <div
class="absolute h-full w-16 bg-menu-background rounded-xl top-0 z-0" class="absolute h-full w-16 bg-menu-item-background-hover rounded-xl top-0 z-0"
style="width: {$indicatorWidth}px; left: {$indicatorPosition}px" style="width: {$indicatorWidth}px; left: {$indicatorPosition}px; scale: {$indicatorScale}"
></div> ></div>
{#each navBarItems as item} {#each navBarItems as item}
<a <a
class="font-semibold z-10" class="font-semibold z-10"
on:click={(e) => setActiveItem(e.target)}
href={item.value} href={item.value}
data-sveltekit-preload-data="tap">{item.text}</a data-sveltekit-preload-data="tap">{item.text}</a
> >

View File

@@ -3,18 +3,38 @@
import { T, useTask } from "@threlte/core"; import { T, useTask } from "@threlte/core";
import { tweened } from "svelte/motion"; import { tweened } from "svelte/motion";
import Earth from "./earth.svelte"; import Earth from "./earth.svelte";
import { onMount } from "svelte";
import * as THREE from "three";
let rotation = 0; let rotation = 0;
useTask((delta) => { useTask((delta) => {
rotation += delta / 4; rotation += delta / 4;
}); });
const ambientIntensitiy = tweened(1.2, { const ambientIntensitiy = tweened($theme == "light" ? 1.2 : 0, {
duration: 500, duration: 500,
}); });
$: ambientColor = $theme == "light" ? "#ffffff" : "#4c7fe6"; $: ambientColor = $theme == "light" ? "#ffffff" : "#4c7fe6";
$: ambientIntensitiy.set($theme == "light" ? 1.2 : 0); $: ambientIntensitiy.set($theme == "light" ? 1.2 : 0);
let starsGeometry!: THREE.BufferGeometry;
let starsMaterial!: THREE.PointsMaterial;
onMount(() => {
const stars = new Array(0);
for (var i = 0; i < 500; i++) {
let x = THREE.MathUtils.randFloatSpread(500);
let y = THREE.MathUtils.randFloatSpread(500);
let z = THREE.MathUtils.randFloatSpread(500);
stars.push(x, y, z);
}
starsGeometry = new THREE.BufferGeometry();
starsGeometry.setAttribute(
"position",
new THREE.Float32BufferAttribute(stars, 3),
);
starsMaterial = new THREE.PointsMaterial({ color: 0xffffff });
});
</script> </script>
<T.PerspectiveCamera <T.PerspectiveCamera
@@ -25,6 +45,10 @@
}} }}
/> />
{#if starsGeometry && starsMaterial}
<T.Points geometry={starsGeometry} material={starsMaterial}></T.Points>
{/if}
<T.AmbientLight color={ambientColor} intensity={$ambientIntensitiy} /> <T.AmbientLight color={ambientColor} intensity={$ambientIntensitiy} />
<Earth {rotation}></Earth> <Earth {rotation}></Earth>

View File

@@ -12,7 +12,7 @@
]; ];
</script> </script>
<div class="p-4 my-2 border rounded-xl"> <div class="p-4 my-2 border border-input-border rounded-xl">
<div class="flex justify-between items-center mb-2"> <div class="flex justify-between items-center mb-2">
<h5 class="font-medium mr-2">{format(log.date, 'dd.MM.yyyy')}</h5> <h5 class="font-medium mr-2">{format(log.date, 'dd.MM.yyyy')}</h5>

View File

@@ -3,7 +3,7 @@
export let activeTab: number; export let activeTab: number;
</script> </script>
<div class="flex gap-2 overflow-x-scroll"> <div class="flex gap-2 overflow-x-auto">
{#each tabs as tab, i} {#each tabs as tab, i}
<button class="tab" class:tab-active={activeTab == i} on:click={() => activeTab = i}>{tab}</button> <button class="tab" class:tab-active={activeTab == i} on:click={() => activeTab = i}>{tab}</button>
{/each} {/each}

View File

@@ -11,7 +11,7 @@
]; ];
</script> </script>
<div class="p-4 border rounded-md my-2 hover:bg-gray-50"> <div class="p-4 border border-input-border rounded-md my-2 hover:bg-menu-item-background-hover">
<div class="flex justify-between items-center mb-2"> <div class="flex justify-between items-center mb-2">
<h5> <h5>
<i class="fa fa-{waypoint.icon} mr-2"></i>{waypoint.name} <i class="fa fa-{waypoint.icon} mr-2"></i>{waypoint.name}

View File

@@ -1,14 +1,12 @@
import { browser } from "$app/environment";
import { get, writable, type Writable } from "svelte/store"; import { get, writable, type Writable } from "svelte/store";
type Theme = "dark" | "light" type Theme = "dark" | "light"
export const theme: Writable<Theme> = writable("light"); export const theme: Writable<Theme> = writable(browser && localStorage.getItem("theme") as Theme || "light" );
export function toggleTheme() { export function toggleTheme() {
if (get(theme) === "light") { const newTheme = get(theme) === "light" ? "dark" : "light";
theme.set("dark") theme.set(newTheme)
} else { localStorage.setItem("theme", newTheme);
theme.set("light");
}
} }

View File

@@ -42,7 +42,7 @@
description: `City | ${ description: `City | ${
country_codes[t["country code"] as keyof typeof country_codes] country_codes[t["country code"] as keyof typeof country_codes]
}`, }`,
value: t.id, value: t,
icon: "city", icon: "city",
})); }));
@@ -50,7 +50,10 @@
} }
function handleSearchClick(item: SearchItem) { function handleSearchClick(item: SearchItem) {
if (item.icon == "route") {
if(item.icon == "city") {
goto(`/map/?lat=${item.value._geo.lat}&lon=${item.value._geo.lng}`);
} if (item.icon == "route") {
goto(`/trail/view/${item.value}`); goto(`/trail/view/${item.value}`);
} }
} }

View File

@@ -216,7 +216,7 @@
<main class="grid grid-cols-[400px_1fr]"> <main class="grid grid-cols-[400px_1fr]">
<div <div
class="overflow-y-scroll overflow-x-hidden flex flex-col items-center gap-4 px-8" class="overflow-y-auto overflow-x-hidden flex flex-col items-center gap-4 px-8"
> >
<Search <Search
extraClasses="w-full" extraClasses="w-full"

View File

@@ -343,7 +343,7 @@
<main class="grid grid-cols-[400px_1fr]"> <main class="grid grid-cols-[400px_1fr]">
<form <form
id="trail-form" id="trail-form"
class="overflow-y-scroll overflow-x-hidden flex flex-col gap-4 px-8" class="overflow-y-auto overflow-x-hidden flex flex-col gap-4 px-8"
on:submit={handleSubmit} on:submit={handleSubmit}
> >
<h3 class="text-xl font-semibold">Pick a trail</h3> <h3 class="text-xl font-semibold">Pick a trail</h3>
@@ -435,9 +435,9 @@
> >
<hr class="border-separator"/> <hr class="border-separator"/>
<h3 class="text-xl font-semibold">Photos</h3> <h3 class="text-xl font-semibold">Photos</h3>
<div class="flex gap-4 max-w-full overflow-x-scroll shrink-0"> <div class="flex gap-4 max-w-full overflow-x-auto shrink-0">
<button <button
class="btn-secondary h-32 w-32 shrink-0 grow-0 basis-auto" class="btn-secondary h-32 w-32 m-2 shrink-0 grow-0 basis-auto"
type="button" type="button"
on:click={openPhotoBrowser}><i class="fa fa-plus"></i></button on:click={openPhotoBrowser}><i class="fa fa-plus"></i></button
> >

View File

@@ -195,7 +195,7 @@
id="{category.name}-checkbox" id="{category.name}-checkbox"
type="checkbox" type="checkbox"
value={category.id} value={category.id}
class="w-4 h-4 accent-input-background border-input-border focus:ring-input-border-focus focus:ring-2" class="w-4 h-4 accent-input-background border-input-border focus:ring-input-ring focus:ring-2"
on:change={() => setCategoryFilter(category)} on:change={() => setCategoryFilter(category)}
/> />
<label <label

View File

@@ -4,6 +4,9 @@ export default {
theme: { theme: {
extend: { extend: {
colors: { colors: {
'background': 'rgba(var(--background))',
'content': 'rgba(var(--content))',
'primary': 'rgba(var(--primary))', 'primary': 'rgba(var(--primary))',
'primary-hover': 'rgba(var(--primary-hover))', 'primary-hover': 'rgba(var(--primary-hover))',
'secondary-hover': 'rgba(var(--secondary-hover))', 'secondary-hover': 'rgba(var(--secondary-hover))',
@@ -11,6 +14,7 @@ export default {
'input-background': 'rgba(var(--input-background))', 'input-background': 'rgba(var(--input-background))',
'input-border': 'rgba(var(--input-border))', 'input-border': 'rgba(var(--input-border))',
'input-border-focus': 'rgba(var(--input-border-focus))', 'input-border-focus': 'rgba(var(--input-border-focus))',
'input-ring': 'rgba(var(--input-ring))',
'menu-background': 'rgba(var(--menu-background))', 'menu-background': 'rgba(var(--menu-background))',
'menu-item-background-hover': 'rgba(var(--menu-item-background-hover))', 'menu-item-background-hover': 'rgba(var(--menu-item-background-hover))',