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';
.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 {
@@ -11,7 +11,7 @@
}
.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 {
@@ -23,7 +23,7 @@
}
.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 {
@@ -31,7 +31,7 @@
}
.tab:hover {
@apply bg-gray-100
@apply bg-menu-item-background-hover
}
.tab-active {

View File

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

View File

@@ -14,7 +14,7 @@
<div class="flex items-center gap-2">
<input
{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:bg-red-50={error.length > 0}
type="date"

View File

@@ -15,15 +15,15 @@
{id}
tabindex="-1"
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 -->
<div class="relative bg-white shadow dark:bg-gray-700">
<div class="relative bg-background shadow">
<!-- Modal header -->
<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}
</h3>
<button
@@ -41,7 +41,7 @@
</div>
<!-- Modal footer -->
<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} />
</div>

View File

@@ -29,7 +29,7 @@
type="radio"
checked={i == selected}
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)}
/>
<label for="{name}-radio-{i}" class="ms-2 text-sm">{item.text}</label>

View File

@@ -14,7 +14,7 @@
value="1"
/>
<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>
<span class="ms-3 text-sm font-medium">{label}</span>
</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 { T, forwardEventHandlers } from "@threlte/core";
import { useGltf } from "@threlte/extras";
import { backIn, backInOut, backOut, cubicInOut } from "svelte/easing";
import { backInOut } from "svelte/easing";
import { tweened } from "svelte/motion";
import { Group } from "three";
@@ -19,15 +19,15 @@ Command: npx @threlte/gltf@2.0.1 static/models/earth.glb
const component = forwardEventHandlers();
const sunXRotation = tweened(0, {
duration: 1500,
const sunXRotation = tweened($theme == "light" ? 0 : -Math.PI, {
duration: 1000,
easing: backInOut
});
const sunLightIntensitiy = tweened(2.5, {
const sunLightIntensitiy = tweened($theme == "light" ? 2.5 : 0.1, {
duration: 500,
});
const moonLightIntensitiy = tweened(2.5, {
const moonLightIntensitiy = tweened($theme == "dark" ? 2.5 : 0.1, {
duration: 500,
});
$: 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>
<!-- /Airplane -->
<!-- Sun -->
<!-- Sun & Moon -->
<T.Group rotation={[$sunXRotation, 0, 0]}>
<T.Mesh
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"]}
position={[0, -2, 0]}
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>

View File

@@ -1,11 +1,11 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { afterNavigate, goto } from "$app/navigation";
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 { backInOut, cubicOut } from "svelte/easing";
import { tweened } from "svelte/motion";
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";
const navBarItems = [
@@ -31,23 +31,50 @@
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 }) {
if (item.value == "logout") {
logout();
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>
<nav class="flex justify-between items-center p-6">
@@ -59,15 +86,14 @@
{/if}
</a>
{#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
class="absolute h-full w-16 bg-menu-background rounded-xl top-0 z-0"
style="width: {$indicatorWidth}px; left: {$indicatorPosition}px"
class="absolute h-full w-16 bg-menu-item-background-hover rounded-xl top-0 z-0"
style="width: {$indicatorWidth}px; left: {$indicatorPosition}px; scale: {$indicatorScale}"
></div>
{#each navBarItems as item}
<a
class="font-semibold z-10"
on:click={(e) => setActiveItem(e.target)}
href={item.value}
data-sveltekit-preload-data="tap">{item.text}</a
>

View File

@@ -3,18 +3,38 @@
import { T, useTask } from "@threlte/core";
import { tweened } from "svelte/motion";
import Earth from "./earth.svelte";
import { onMount } from "svelte";
import * as THREE from "three";
let rotation = 0;
useTask((delta) => {
rotation += delta / 4;
});
const ambientIntensitiy = tweened(1.2, {
const ambientIntensitiy = tweened($theme == "light" ? 1.2 : 0, {
duration: 500,
});
$: ambientColor = $theme == "light" ? "#ffffff" : "#4c7fe6";
$: 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>
<T.PerspectiveCamera
@@ -25,6 +45,10 @@
}}
/>
{#if starsGeometry && starsMaterial}
<T.Points geometry={starsGeometry} material={starsMaterial}></T.Points>
{/if}
<T.AmbientLight color={ambientColor} intensity={$ambientIntensitiy} />
<Earth {rotation}></Earth>

View File

@@ -12,7 +12,7 @@
];
</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">
<h5 class="font-medium mr-2">{format(log.date, 'dd.MM.yyyy')}</h5>

View File

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

View File

@@ -11,7 +11,7 @@
];
</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">
<h5>
<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";
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() {
if (get(theme) === "light") {
theme.set("dark")
} else {
theme.set("light");
}
const newTheme = get(theme) === "light" ? "dark" : "light";
theme.set(newTheme)
localStorage.setItem("theme", newTheme);
}

View File

@@ -42,7 +42,7 @@
description: `City | ${
country_codes[t["country code"] as keyof typeof country_codes]
}`,
value: t.id,
value: t,
icon: "city",
}));
@@ -50,7 +50,10 @@
}
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}`);
}
}

View File

@@ -216,7 +216,7 @@
<main class="grid grid-cols-[400px_1fr]">
<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
extraClasses="w-full"

View File

@@ -343,7 +343,7 @@
<main class="grid grid-cols-[400px_1fr]">
<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}
>
<h3 class="text-xl font-semibold">Pick a trail</h3>
@@ -435,9 +435,9 @@
>
<hr class="border-separator"/>
<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
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"
on:click={openPhotoBrowser}><i class="fa fa-plus"></i></button
>

View File

@@ -195,7 +195,7 @@
id="{category.name}-checkbox"
type="checkbox"
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)}
/>
<label