Compare commits
3 Commits
73c1343b0d
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8dfbfc564d | ||
|
|
e496147aa4 | ||
|
|
ca036467ca |
21
.gitignore
vendored
21
.gitignore
vendored
@@ -1,24 +1,3 @@
|
|||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
pnpm-debug.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
dist-ssr
|
|
||||||
*.local
|
*.local
|
||||||
|
|
||||||
# Editor directories and files
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/extensions.json
|
|
||||||
.idea
|
|
||||||
.DS_Store
|
|
||||||
*.suo
|
|
||||||
*.ntvs*
|
|
||||||
*.njsproj
|
|
||||||
*.sln
|
|
||||||
*.sw?
|
|
||||||
|
|||||||
@@ -1,43 +1,20 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Router, { route } from "./lib/components/Router.svelte";
|
import Router, { route } from "./lib/components/Router.svelte";
|
||||||
import "./app.css";
|
|
||||||
|
|
||||||
import HomePage from "./pages/HomePage.svelte";
|
|
||||||
import ToastProvider from "./lib/components/toast/ToastProvider.svelte";
|
|
||||||
import Navigation from "./Navigation.svelte";
|
|
||||||
import Footer from "./Footer.svelte";
|
|
||||||
import TaxiPage from "./pages/TaxiPage.svelte";
|
|
||||||
import BusPage from "./pages/BusPage.svelte";
|
|
||||||
import ContactPage from "./pages/ContactPage.svelte";
|
|
||||||
import AccessibilityPage from "./pages/AccessibilityPage.svelte";
|
|
||||||
import { getTheme } from "./lib/theme.svelte";
|
import { getTheme } from "./lib/theme.svelte";
|
||||||
|
import Layout from "./Layout.svelte";
|
||||||
route("/", HomePage);
|
import "./app.css";
|
||||||
route("/taxi", TaxiPage);
|
|
||||||
route("/bus", BusPage);
|
|
||||||
route("/contact", ContactPage);
|
|
||||||
route("/accessibility", AccessibilityPage);
|
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
document.body.dataset.theme = getTheme();
|
document.body.dataset.theme = getTheme();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex min-h-screen flex-col bg-primary-200 text-contrast-900">
|
<Layout>
|
||||||
<Navigation>
|
<Router>
|
||||||
<main class="grow px-4 pb-16 pt-8">
|
{#snippet notfound()}
|
||||||
<div class="mx-auto max-w-7xl">
|
<h1>Not found</h1>
|
||||||
<Router>
|
<p>Sorry, the page you are looking for does not exist.</p>
|
||||||
{#snippet notfound()}
|
<p>Return to <a href="/">home</a>.</p>
|
||||||
<h1>Not found</h1>
|
{/snippet}
|
||||||
<p>Sorry, the page you are looking for does not exist.</p>
|
</Router>
|
||||||
<p>Return to <a href="/">home</a>.</p>
|
</Layout>
|
||||||
{/snippet}
|
|
||||||
</Router>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<Footer />
|
|
||||||
</Navigation>
|
|
||||||
</div>
|
|
||||||
<ToastProvider />
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import Link from "./lib/components/link/Link.svelte";
|
|
||||||
import { Routes } from "./lib/routes";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<footer
|
|
||||||
class="flex flex-col items-center border-t-2 border-contrast-900 bg-contrast-900 px-2 py-8 text-primary-200 dark:border-primary-300 dark:bg-primary-100 dark:text-contrast-900"
|
|
||||||
>
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-8 text-center md:text-lg">
|
|
||||||
{#each Routes.footerRoutes as section}
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<h6 class="font-semibold">{section.text}</h6>
|
|
||||||
</li>
|
|
||||||
{#each section.routes as route}
|
|
||||||
<li>
|
|
||||||
<Link target={route.target} href={route.url}>
|
|
||||||
{route.text}
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
<div class="mt-8 text-center font-semibold">Org nr: 816 230 942</div>
|
|
||||||
<div class="mt-2 text-center font-semibold">© 2026 minibusservice.no - All Rights Reserved.</div>
|
|
||||||
</footer>
|
|
||||||
133
src/Layout.svelte
Normal file
133
src/Layout.svelte
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Logo from "./lib/components/icons/logo/Logo.svelte";
|
||||||
|
import sunIcon from "./assets/icons/sun.svg";
|
||||||
|
import moonIcon from "./assets/icons/moon.svg";
|
||||||
|
import { slide } from "svelte/transition";
|
||||||
|
import Toggle from "./lib/components/Toggle.svelte";
|
||||||
|
import { Routes } from "./lib/routes";
|
||||||
|
import { isCurrentPath } from "./lib/components/Router.svelte";
|
||||||
|
import { getTheme, toggleTheme } from "./lib/theme.svelte";
|
||||||
|
import ToastProvider from "./lib/components/toast/ToastProvider.svelte";
|
||||||
|
import Link from "./lib/components/link/Link.svelte";
|
||||||
|
|
||||||
|
let sidebarOpen = $state(false);
|
||||||
|
|
||||||
|
let { children } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex min-h-screen flex-col bg-primary-200 text-contrast-900">
|
||||||
|
<header class="sticky top-0 z-20 flex h-16 justify-center border-b-2 border-contrast-100 bg-primary-100 shadow-lg">
|
||||||
|
<div class="flex w-full max-w-7xl flex-row items-center justify-between p-4">
|
||||||
|
<a class="h-full grow" href="/">
|
||||||
|
<Logo />
|
||||||
|
</a>
|
||||||
|
<ul class="hidden flex-row justify-end gap-10 font-medium uppercase md:text-lg lg:flex">
|
||||||
|
{#each Routes.topbarRoutes as route}
|
||||||
|
<li>
|
||||||
|
<a class:border-b-2={isCurrentPath(route.url)} class="border-b-0 border-accent transition-colors hover:text-accent" href={route.url} target={route.target}>
|
||||||
|
{route.text}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
<div class="ml-12 flex aspect-square h-full items-center justify-center p-1">
|
||||||
|
<button
|
||||||
|
class="hamburger-icon relative inline-block h-full w-full cursor-pointer text-contrast-100"
|
||||||
|
aria-label="open sidebar"
|
||||||
|
class:open={sidebarOpen}
|
||||||
|
onclick={() => (sidebarOpen = !sidebarOpen)}
|
||||||
|
>
|
||||||
|
<div class="line absolute top-0 h-0.5 w-full origin-top-left rounded-full bg-contrast-900 transition-all"></div>
|
||||||
|
<div class="line middle absolute top-1/2 h-0.5 w-full -translate-y-1/2 rounded-full bg-contrast-900 transition-all delay-100"></div>
|
||||||
|
<div class="line absolute bottom-0 h-0.5 w-full origin-bottom-left rounded-full bg-contrast-900 transition-all"></div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{#if sidebarOpen}
|
||||||
|
<aside>
|
||||||
|
<nav
|
||||||
|
transition:slide={{ axis: "x" }}
|
||||||
|
class="fixed bottom-14 right-0 top-16 z-10 flex max-w-full flex-col overflow-auto border-l-2 border-contrast-100 bg-primary-100 px-4 py-8 shadow-lg sm:bottom-0"
|
||||||
|
>
|
||||||
|
<ul class="flex grow flex-col gap-2 pr-20 text-lg font-medium lg:text-xl">
|
||||||
|
{#each Routes.sidebarRoutes as route}
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
class:border-b-2={isCurrentPath(route.url)}
|
||||||
|
class="border-b-0 border-accent transition-colors hover:text-accent"
|
||||||
|
href={route.url}
|
||||||
|
target={route.target}
|
||||||
|
>
|
||||||
|
{route.text}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
<div class="flex w-fit flex-col items-center gap-3">
|
||||||
|
<Toggle invertColor={true} checked={getTheme() == "dark"} leftIcon={sunIcon} rightIcon={moonIcon} on:change={toggleTheme} />
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
{/if}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="grow px-4 pb-16 pt-8">
|
||||||
|
<div class="mx-auto max-w-7xl">
|
||||||
|
{@render children()}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer
|
||||||
|
class="flex flex-col items-center border-t-2 border-contrast-900 bg-contrast-900 px-2 py-8 text-primary-200 dark:border-primary-300 dark:bg-primary-100 dark:text-contrast-900"
|
||||||
|
>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-8 text-center md:text-lg">
|
||||||
|
{#each Routes.footerRoutes as section}
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<h6 class="font-semibold">{section.text}</h6>
|
||||||
|
</li>
|
||||||
|
{#each section.routes as route}
|
||||||
|
<li>
|
||||||
|
<Link target={route.target} href={route.url}>
|
||||||
|
{route.text}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div class="mt-8 text-center font-semibold">Org nr: 816 230 942</div>
|
||||||
|
<div class="mt-2 text-center font-semibold">© 2026 minibusservice.no - All Rights Reserved.</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<!-- Mobile navigation -->
|
||||||
|
<nav class="sticky bottom-0 z-10 flex h-14 flex-row items-center justify-around border-t-2 border-contrast-100 bg-primary-100 px-2 text-xs shadow-t-lg sm:hidden">
|
||||||
|
{#each Routes.topbarRoutes as route}
|
||||||
|
<a
|
||||||
|
href={route.url}
|
||||||
|
target={route.target}
|
||||||
|
class={`flex flex-col items-center decoration-accent transition-opacity ${isCurrentPath(route.url) ? "underline opacity-100" : "opacity-50"}`}
|
||||||
|
>
|
||||||
|
<img src={route.icon} alt={route.text} class="h-6 dark:invert" />
|
||||||
|
<span> {route.text} </span>
|
||||||
|
</a>
|
||||||
|
{/each}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ToastProvider />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.hamburger-icon.open .line:first-child {
|
||||||
|
transform: rotate(45deg) translateX(15%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-icon.open .line:last-child {
|
||||||
|
transform: rotate(-45deg) translateX(15%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-icon.open .line.middle {
|
||||||
|
width: 0;
|
||||||
|
transition: transform 0.1s;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import Logo from "./lib/components/icons/logo/Logo.svelte";
|
|
||||||
import sunIcon from "./assets/icons/sun.svg";
|
|
||||||
import moonIcon from "./assets/icons/moon.svg";
|
|
||||||
import { slide } from "svelte/transition";
|
|
||||||
import Toggle from "./lib/components/Toggle.svelte";
|
|
||||||
import { Routes } from "./lib/routes";
|
|
||||||
import { isCurrentPath } from "./lib/components/Router.svelte";
|
|
||||||
import { getTheme, toggleTheme } from "./lib/theme.svelte";
|
|
||||||
|
|
||||||
let sidebarOpen = false;
|
|
||||||
|
|
||||||
function toggleMenuOpen() {
|
|
||||||
sidebarOpen = !sidebarOpen;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<header class="sticky top-0 z-20 flex h-16 justify-center border-b-2 border-contrast-100 bg-primary-100 shadow-lg">
|
|
||||||
<div class="flex w-full max-w-7xl flex-row items-center justify-between p-4">
|
|
||||||
<a class="h-full grow" href="/">
|
|
||||||
<Logo />
|
|
||||||
</a>
|
|
||||||
<ul class="hidden flex-row justify-end gap-10 font-medium uppercase md:text-lg lg:flex">
|
|
||||||
{#each Routes.topbarRoutes as route}
|
|
||||||
<li>
|
|
||||||
<a class:border-b-2={isCurrentPath(route.url)} class="border-b-0 border-accent transition-colors hover:text-accent" href={route.url} target={route.target}>
|
|
||||||
{route.text}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
<div class="ml-12 flex aspect-square h-full items-center justify-center p-1">
|
|
||||||
<button
|
|
||||||
class="hamburger-icon relative inline-block h-full w-full cursor-pointer text-contrast-100"
|
|
||||||
aria-label="open sidebar"
|
|
||||||
class:open={sidebarOpen}
|
|
||||||
on:click={toggleMenuOpen}
|
|
||||||
>
|
|
||||||
<div class="line absolute top-0 h-0.5 w-full origin-top-left rounded-full bg-contrast-900 transition-all"></div>
|
|
||||||
<div class="line middle absolute top-1/2 h-0.5 w-full -translate-y-1/2 rounded-full bg-contrast-900 transition-all delay-100"></div>
|
|
||||||
<div class="line absolute bottom-0 h-0.5 w-full origin-bottom-left rounded-full bg-contrast-900 transition-all"></div>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{#if sidebarOpen}
|
|
||||||
<aside>
|
|
||||||
<nav
|
|
||||||
transition:slide={{ axis: "x" }}
|
|
||||||
class="fixed bottom-14 right-0 top-16 z-10 flex max-w-full flex-col overflow-auto border-l-2 border-contrast-100 bg-primary-100 px-4 py-8 shadow-lg sm:bottom-0"
|
|
||||||
>
|
|
||||||
<ul class="flex grow flex-col gap-2 pr-20 text-lg font-medium lg:text-xl">
|
|
||||||
{#each Routes.sidebarRoutes as route}
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
class:border-b-2={isCurrentPath(route.url)}
|
|
||||||
class="border-b-0 border-accent transition-colors hover:text-accent"
|
|
||||||
href={route.url}
|
|
||||||
target={route.target}
|
|
||||||
>
|
|
||||||
{route.text}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
<div class="flex w-fit flex-col items-center gap-3">
|
|
||||||
<Toggle invertColor={true} checked={getTheme() == "dark"} leftIcon={sunIcon} rightIcon={moonIcon} on:change={toggleTheme} />
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
</aside>
|
|
||||||
{/if}
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<slot />
|
|
||||||
|
|
||||||
<!-- Mobile navigation -->
|
|
||||||
<nav class="sticky bottom-0 z-10 flex h-14 flex-row items-center justify-around border-t-2 border-contrast-100 bg-primary-100 px-2 text-xs shadow-t-lg sm:hidden">
|
|
||||||
{#each Routes.topbarRoutes as route}
|
|
||||||
<a
|
|
||||||
href={route.url}
|
|
||||||
target={route.target}
|
|
||||||
class={`flex flex-col items-center decoration-accent transition-opacity ${isCurrentPath(route.url) ? "underline opacity-100" : "opacity-50"}`}
|
|
||||||
>
|
|
||||||
<img src={route.icon} alt={route.text} class="h-6 dark:invert" />
|
|
||||||
<span> {route.text} </span>
|
|
||||||
</a>
|
|
||||||
{/each}
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.hamburger-icon.open .line:first-child {
|
|
||||||
transform: rotate(45deg) translateX(15%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hamburger-icon.open .line:last-child {
|
|
||||||
transform: rotate(-45deg) translateX(15%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hamburger-icon.open .line.middle {
|
|
||||||
width: 0;
|
|
||||||
transition: transform 0.1s;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
<label class="relative inline-flex cursor-pointer items-center">
|
<label class="relative inline-flex cursor-pointer items-center">
|
||||||
<input on:change {checked} type="checkbox" value="" class="peer sr-only" />
|
<input on:change {checked} type="checkbox" value="" class="peer sr-only" />
|
||||||
<div
|
<div
|
||||||
class="h-6 w-11 rounded-full border-2 border-contrast-100 outline-2 transition-colors after:absolute after:left-[2px] after:top-[2px] after:h-5 after:w-5 after:rounded-full after:border-2 after:border-contrast-100 after:bg-contrast-900 after:transition-all after:content-[''] peer-checked:bg-accent peer-checked:after:translate-x-full dark:peer-focus:ring-accent"
|
class="h-6 w-11 rounded-full border-2 border-contrast-100 outline-2 transition-colors after:absolute after:left-0.5 after:top-0.5 after:h-5 after:w-5 after:rounded-full after:border-2 after:border-contrast-100 after:bg-contrast-900 after:transition-all after:content-[''] peer-checked:bg-accent peer-checked:after:translate-x-full dark:peer-focus:ring-accent"
|
||||||
></div>
|
></div>
|
||||||
</label>
|
</label>
|
||||||
{#if rightIcon}
|
{#if rightIcon}
|
||||||
|
|||||||
13
src/main.ts
13
src/main.ts
@@ -1,6 +1,19 @@
|
|||||||
import { mount } from "svelte";
|
import { mount } from "svelte";
|
||||||
|
import { route } from "./lib/components/Router.svelte";
|
||||||
import App from "./App.svelte";
|
import App from "./App.svelte";
|
||||||
|
|
||||||
|
import HomePage from "./pages/HomePage.svelte";
|
||||||
|
import TaxiPage from "./pages/TaxiPage.svelte";
|
||||||
|
import BusPage from "./pages/BusPage.svelte";
|
||||||
|
import ContactPage from "./pages/ContactPage.svelte";
|
||||||
|
import AccessibilityPage from "./pages/AccessibilityPage.svelte";
|
||||||
|
|
||||||
|
route("/", HomePage);
|
||||||
|
route("/taxi", TaxiPage);
|
||||||
|
route("/bus", BusPage);
|
||||||
|
route("/contact", ContactPage);
|
||||||
|
route("/accessibility", AccessibilityPage);
|
||||||
|
|
||||||
const app = mount(App, {
|
const app = mount(App, {
|
||||||
target: document.getElementById("app")!
|
target: document.getElementById("app")!
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user