...
This commit is contained in:
@@ -10,12 +10,17 @@
|
|||||||
import BusPage from "./pages/BusPage.svelte";
|
import BusPage from "./pages/BusPage.svelte";
|
||||||
import ContactPage from "./pages/ContactPage.svelte";
|
import ContactPage from "./pages/ContactPage.svelte";
|
||||||
import AccessibilityPage from "./pages/AccessibilityPage.svelte";
|
import AccessibilityPage from "./pages/AccessibilityPage.svelte";
|
||||||
|
import { getTheme } from "./lib/theme.svelte";
|
||||||
|
|
||||||
route("/", HomePage);
|
route("/", HomePage);
|
||||||
route("/taxi", TaxiPage);
|
route("/taxi", TaxiPage);
|
||||||
route("/bus", BusPage);
|
route("/bus", BusPage);
|
||||||
route("/contact", ContactPage);
|
route("/contact", ContactPage);
|
||||||
route("/accessibility", AccessibilityPage);
|
route("/accessibility", AccessibilityPage);
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
document.body.dataset.theme = getTheme();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex min-h-screen flex-col bg-primary-200 text-contrast-900">
|
<div class="flex min-h-screen flex-col bg-primary-200 text-contrast-900">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Link from "./lib/components/link/Link.svelte";
|
import Link from "./lib/components/link/Link.svelte";
|
||||||
import { Routes } from "./lib/global/routes";
|
import { Routes } from "./lib/routes";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<footer
|
<footer
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
import moonIcon from "./assets/icons/moon.svg";
|
import moonIcon from "./assets/icons/moon.svg";
|
||||||
import { slide } from "svelte/transition";
|
import { slide } from "svelte/transition";
|
||||||
import Toggle from "./lib/components/Toggle.svelte";
|
import Toggle from "./lib/components/Toggle.svelte";
|
||||||
import { darkTheme } from "./lib/stores/theme";
|
import { Routes } from "./lib/routes";
|
||||||
import { Routes } from "./lib/global/routes";
|
|
||||||
import { isCurrentPath } from "./lib/components/Router.svelte";
|
import { isCurrentPath } from "./lib/components/Router.svelte";
|
||||||
|
import { getTheme, toggleTheme } from "./lib/theme.svelte";
|
||||||
|
|
||||||
let sidebarOpen = false;
|
let sidebarOpen = false;
|
||||||
|
|
||||||
@@ -63,15 +63,7 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
<div class="flex w-fit flex-col items-center gap-3">
|
<div class="flex w-fit flex-col items-center gap-3">
|
||||||
<Toggle
|
<Toggle invertColor={true} checked={getTheme() == "dark"} leftIcon={sunIcon} rightIcon={moonIcon} on:change={toggleTheme} />
|
||||||
invertColor={true}
|
|
||||||
checked={$darkTheme}
|
|
||||||
leftIcon={sunIcon}
|
|
||||||
rightIcon={moonIcon}
|
|
||||||
on:change={() => {
|
|
||||||
$darkTheme = $darkTheme = !$darkTheme;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
80
src/app.css
80
src/app.css
@@ -2,72 +2,36 @@
|
|||||||
|
|
||||||
@custom-variant dark (&:where([data-theme='dark'], [data-theme='dark'] *));
|
@custom-variant dark (&:where([data-theme='dark'], [data-theme='dark'] *));
|
||||||
|
|
||||||
:root {
|
body {
|
||||||
--mb-color-primary-100: rgb(250 250 250);
|
color-scheme: light;
|
||||||
--mb-color-primary-200: rgb(240 240 240);
|
|
||||||
--mb-color-primary-300: rgb(230 230 230);
|
|
||||||
--mb-color-primary-400: rgb(220 220 220);
|
|
||||||
--mb-color-primary-500: rgb(210 210 210);
|
|
||||||
--mb-color-primary-600: rgb(200 200 200);
|
|
||||||
--mb-color-primary-700: rgb(190 190 190);
|
|
||||||
--mb-color-primary-800: rgb(180 180 180);
|
|
||||||
--mb-color-primary-900: rgb(170 170 170);
|
|
||||||
|
|
||||||
--mb-color-contrast-100: rgb(220 220 220);
|
|
||||||
--mb-color-contrast-200: rgb(200 200 200);
|
|
||||||
--mb-color-contrast-300: rgb(180 180 180);
|
|
||||||
--mb-color-contrast-400: rgb(160 160 160);
|
|
||||||
--mb-color-contrast-500: rgb(140 140 140);
|
|
||||||
--mb-color-contrast-600: rgb(110 110 110);
|
|
||||||
--mb-color-contrast-700: rgb(80 80 80);
|
|
||||||
--mb-color-contrast-800: rgb(60 60 60);
|
|
||||||
--mb-color-contrast-900: rgb(30 30 30);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] {
|
body[data-theme="dark"] {
|
||||||
--mb-color-primary-100: rgb(28 28 28);
|
color-scheme: dark;
|
||||||
--mb-color-primary-200: rgb(32 32 32);
|
|
||||||
--mb-color-primary-300: rgb(38 38 38);
|
|
||||||
--mb-color-primary-400: rgb(44 44 44);
|
|
||||||
--mb-color-primary-500: rgb(50 50 50);
|
|
||||||
--mb-color-primary-600: rgb(56 56 56);
|
|
||||||
--mb-color-primary-700: rgb(62 62 62);
|
|
||||||
--mb-color-primary-800: rgb(68 68 68);
|
|
||||||
--mb-color-primary-900: rgb(74 74 74);
|
|
||||||
|
|
||||||
--mb-color-contrast-100: rgb(25 25 25);
|
|
||||||
--mb-color-contrast-200: rgb(50 50 50);
|
|
||||||
--mb-color-contrast-300: rgb(80 80 80);
|
|
||||||
--mb-color-contrast-400: rgb(110 110 110);
|
|
||||||
--mb-color-contrast-500: rgb(140 140 140);
|
|
||||||
--mb-color-contrast-600: rgb(160 160 160);
|
|
||||||
--mb-color-contrast-700: rgb(180 180 180);
|
|
||||||
--mb-color-contrast-800: rgb(200 200 200);
|
|
||||||
--mb-color-contrast-900: rgb(220 220 220);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
--color-accent: rgb(255 29 37);
|
--color-accent: rgb(255 29 37);
|
||||||
|
|
||||||
--color-primary-100: var(--mb-color-primary-100);
|
--color-primary-100: light-dark(rgb(250 250 250), rgb(28 28 28));
|
||||||
--color-primary-200: var(--mb-color-primary-200);
|
--color-primary-200: light-dark(rgb(240 240 240), rgb(32 32 32));
|
||||||
--color-primary-300: var(--mb-color-primary-300);
|
--color-primary-300: light-dark(rgb(230 230 230), rgb(38 38 38));
|
||||||
--color-primary-400: var(--mb-color-primary-400);
|
--color-primary-400: light-dark(rgb(220 220 220), rgb(44 44 44));
|
||||||
--color-primary-500: var(--mb-color-primary-500);
|
--color-primary-500: light-dark(rgb(210 210 210), rgb(50 50 50));
|
||||||
--color-primary-600: var(--mb-color-primary-600);
|
--color-primary-600: light-dark(rgb(200 200 200), rgb(56 56 56));
|
||||||
--color-primary-700: var(--mb-color-primary-700);
|
--color-primary-700: light-dark(rgb(190 190 190), rgb(62 62 62));
|
||||||
--color-primary-800: var(--mb-color-primary-800);
|
--color-primary-800: light-dark(rgb(180 180 180), rgb(68 68 68));
|
||||||
--color-primary-900: var(--mb-color-primary-900);
|
--color-primary-900: light-dark(rgb(170 170 170), rgb(74 74 74));
|
||||||
|
|
||||||
--color-contrast-100: var(--mb-color-contrast-100);
|
--color-contrast-100: light-dark(rgb(220 220 220), rgb(25 25 25));
|
||||||
--color-contrast-200: var(--mb-color-contrast-200);
|
--color-contrast-200: light-dark(rgb(200 200 200), rgb(50 50 50));
|
||||||
--color-contrast-300: var(--mb-color-contrast-300);
|
--color-contrast-300: light-dark(rgb(180 180 180), rgb(80 80 80));
|
||||||
--color-contrast-400: var(--mb-color-contrast-400);
|
--color-contrast-400: light-dark(rgb(160 160 160), rgb(110 110 110));
|
||||||
--color-contrast-500: var(--mb-color-contrast-500);
|
--color-contrast-500: light-dark(rgb(140 140 140), rgb(140 140 140));
|
||||||
--color-contrast-600: var(--mb-color-contrast-600);
|
--color-contrast-600: light-dark(rgb(110 110 110), rgb(160 160 160));
|
||||||
--color-contrast-700: var(--mb-color-contrast-700);
|
--color-contrast-700: light-dark(rgb(80 80 80), rgb(180 180 180));
|
||||||
--color-contrast-800: var(--mb-color-contrast-800);
|
--color-contrast-800: light-dark(rgb(60 60 60), rgb(200 200 200));
|
||||||
--color-contrast-900: var(--mb-color-contrast-900);
|
--color-contrast-900: light-dark(rgb(30 30 30), rgb(220 220 220));
|
||||||
|
|
||||||
--shadow-t-lg: 0px -4px 6px -1px rgba(0, 0, 0, 0.1);
|
--shadow-t-lg: 0px -4px 6px -1px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
export class RouteError extends Error {}
|
export class RouteError extends Error {}
|
||||||
export class MissingRouteError extends RouteError {}
|
export class MissingRouteError extends RouteError {}
|
||||||
export class RouteFormatError extends RouteError {}
|
export class RouteFormatError extends RouteError {}
|
||||||
export class DuplicateRouteError extends RouteError {}
|
|
||||||
|
|
||||||
type RouteInfo = {
|
type RouteInfo = {
|
||||||
path: string;
|
path: string;
|
||||||
@@ -67,7 +66,8 @@
|
|||||||
*/
|
*/
|
||||||
export function route(path: string, component: Component<{}>): void {
|
export function route(path: string, component: Component<{}>): void {
|
||||||
if (routes.has(path)) {
|
if (routes.has(path)) {
|
||||||
throw new DuplicateRouteError(`Route already registered for path: '${path}'.`);
|
console.warn(`Route already registered for path: '${path}'.`);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = Array.from(path.matchAll(/\[([^\]]+)\]/g)).map((x) => x[1]);
|
const params = Array.from(path.matchAll(/\[([^\]]+)\]/g)).map((x) => x[1]);
|
||||||
@@ -179,53 +179,6 @@
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
window.navigation.removeEventListener("navigate", handleNavigate);
|
window.navigation.removeEventListener("navigate", handleNavigate);
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
function refresh() {
|
|
||||||
currentUrl = new URL(window.location.href);
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeProxy(target: any) {
|
|
||||||
return new Proxy(target, {
|
|
||||||
apply: (target, thisArg, argArray) => {
|
|
||||||
const result = target.apply(thisArg, argArray);
|
|
||||||
refresh();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
window.history.pushState = makeProxy(window.history.pushState);
|
|
||||||
window.history.replaceState = makeProxy(window.history.replaceState);
|
|
||||||
window.history.go = makeProxy(window.history.go);
|
|
||||||
window.history.forward = makeProxy(window.history.forward);
|
|
||||||
window.history.back = makeProxy(window.history.back);
|
|
||||||
|
|
||||||
function handleClick(e: MouseEvent) {
|
|
||||||
if (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const anchor = (e.target as Element)?.closest("a");
|
|
||||||
if (!(anchor instanceof HTMLAnchorElement)) return;
|
|
||||||
if (anchor.target === "_blank") return;
|
|
||||||
|
|
||||||
const targetUrl = new URL(anchor.href, document.baseURI);
|
|
||||||
const documentUrl = new URL(document.baseURI);
|
|
||||||
|
|
||||||
if (targetUrl.origin === documentUrl.origin) {
|
|
||||||
e.preventDefault();
|
|
||||||
history.pushState({}, "", targetUrl);
|
|
||||||
currentUrl = targetUrl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("popstate", refresh);
|
|
||||||
document.addEventListener("click", handleClick);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener("popstate", refresh);
|
|
||||||
document.removeEventListener("click", handleClick);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import homeIcon from "../../assets/icons/home_icon.svg";
|
import homeIcon from "../assets/icons/home_icon.svg";
|
||||||
import contactIcon from "../../assets/icons/contact_icon.svg";
|
import contactIcon from "../assets/icons/contact_icon.svg";
|
||||||
import busIcon from "../../assets/icons/bus_icon.svg";
|
import busIcon from "../assets/icons/bus_icon.svg";
|
||||||
|
|
||||||
type Route = {
|
type Route = {
|
||||||
url: string;
|
url: string;
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
import { writable } from "svelte/store";
|
|
||||||
|
|
||||||
function createThemeToggler() {
|
|
||||||
let defaultValue = false;
|
|
||||||
let savedValue = localStorage.getItem("dark_theme");
|
|
||||||
|
|
||||||
if (savedValue) {
|
|
||||||
defaultValue = JSON.parse(savedValue);
|
|
||||||
} else if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
||||||
defaultValue = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defaultValue) {
|
|
||||||
document.body.dataset.theme = "dark";
|
|
||||||
} else {
|
|
||||||
document.body.dataset.theme = "light";
|
|
||||||
}
|
|
||||||
|
|
||||||
const { subscribe, update } = writable(defaultValue);
|
|
||||||
|
|
||||||
return {
|
|
||||||
subscribe,
|
|
||||||
set: (value: boolean) => {
|
|
||||||
update(() => value);
|
|
||||||
if (value) {
|
|
||||||
document.body.dataset.theme = "dark";
|
|
||||||
} else {
|
|
||||||
document.body.dataset.theme = "light";
|
|
||||||
}
|
|
||||||
|
|
||||||
localStorage.setItem("dark_theme", JSON.stringify(value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const darkTheme = createThemeToggler();
|
|
||||||
24
src/lib/theme.svelte.ts
Normal file
24
src/lib/theme.svelte.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
function loadTheme() {
|
||||||
|
let theme = localStorage.getItem("theme");
|
||||||
|
if (!theme) {
|
||||||
|
if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
||||||
|
theme = "dark";
|
||||||
|
} else {
|
||||||
|
theme = "light";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentTheme = $state(loadTheme());
|
||||||
|
|
||||||
|
export function toggleTheme() {
|
||||||
|
const newTheme = currentTheme === "dark" ? "light" : "dark";
|
||||||
|
localStorage.setItem("theme", newTheme);
|
||||||
|
currentTheme = newTheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTheme(): string {
|
||||||
|
return currentTheme;
|
||||||
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
export function debounce<T extends Function>(cb: T, wait = 500) {
|
|
||||||
let h: any;
|
|
||||||
let callable = () => {
|
|
||||||
clearTimeout(h);
|
|
||||||
h = setTimeout(() => cb(), wait);
|
|
||||||
};
|
|
||||||
return callable;
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
import twoTourBusses from "../assets/images/two_tour_busses.jpg";
|
import twoTourBusses from "../assets/images/two_tour_busses.jpg";
|
||||||
import van from "../assets/images/van.webp";
|
import van from "../assets/images/van.webp";
|
||||||
import Link from "../lib/components/link/Link.svelte";
|
import Link from "../lib/components/link/Link.svelte";
|
||||||
import { Routes } from "../lib/global/routes";
|
import { Routes } from "../lib/routes";
|
||||||
|
|
||||||
type CardCarouselItem = {
|
type CardCarouselItem = {
|
||||||
header: string;
|
header: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user