1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-21 22:09:36 +02:00
AdventureLog/frontend/src/lib/components/Navbar.svelte

334 lines
9.5 KiB
Svelte
Raw Normal View History

2024-07-08 11:44:39 -04:00
<script lang="ts">
import { enhance } from '$app/forms';
import { goto } from '$app/navigation';
export let data: any;
import type { SubmitFunction } from '@sveltejs/kit';
import DotsHorizontal from '~icons/mdi/dots-horizontal';
import Calendar from '~icons/mdi/calendar';
2024-07-08 11:44:39 -04:00
import AboutModal from './AboutModal.svelte';
2024-09-07 17:39:47 -04:00
import AccountMultiple from '~icons/mdi/account-multiple';
import MapMarker from '~icons/mdi/map-marker';
import FormatListBulletedSquare from '~icons/mdi/format-list-bulleted-square';
import Earth from '~icons/mdi/earth';
import Magnify from '~icons/mdi/magnify';
import Map from '~icons/mdi/map';
2024-07-08 11:44:39 -04:00
import Avatar from './Avatar.svelte';
import { page } from '$app/stores';
2024-10-28 13:56:57 -04:00
import { t, locale, locales } from 'svelte-i18n';
2024-11-26 17:39:10 -05:00
import { themes } from '$lib';
import { onMount } from 'svelte';
let inputElement: HTMLInputElement | null = null;
let theme = '';
// Event listener for focusing input
function handleKeydown(event: KeyboardEvent) {
// Ignore any keypresses in an input/textarea field, so we don't interfere with typing.
if (
event.key === '/' &&
!['INPUT', 'TEXTAREA'].includes((event.target as HTMLElement)?.tagName)
) {
event.preventDefault(); // Prevent browser's search shortcut
if (inputElement) {
inputElement.focus();
}
}
}
onMount(() => {
// Attach event listener on component mount
document.addEventListener('keydown', handleKeydown);
// @ts-ignore
theme = document.documentElement.getAttribute('data-theme');
// Cleanup event listener on component destruction
return () => {
document.removeEventListener('keydown', handleKeydown);
};
});
let languages: { [key: string]: string } = {
en: 'English',
de: 'Deutsch',
es: 'Español',
fr: 'Français',
it: 'Italiano',
nl: 'Nederlands',
sv: 'Svenska',
zh: '中文',
pl: 'Polski',
2025-04-01 22:35:03 +02:00
ko: '한국어',
no: 'Norsk'
};
let query: string = '';
2024-07-08 11:44:39 -04:00
let isAboutModalOpen: boolean = false;
2024-10-28 13:56:57 -04:00
const submitLocaleChange = (event: Event) => {
const select = event.target as HTMLSelectElement;
const newLocale = select.value;
document.cookie = `locale=${newLocale}; path=/; max-age=${60 * 60 * 24 * 365}; SameSite=Lax`;
2024-10-28 13:56:57 -04:00
locale.set(newLocale);
window.location.reload();
};
const submitThemeChange = (event: Event) => {
// @ts-ignore
const theme = event.target.value;
// @ts-ignore
const themeForm = event.target.parentNode;
themeForm.action = `/?/setTheme&theme=${theme}`;
themeForm.submit();
};
2024-07-08 11:44:39 -04:00
const submitUpdateTheme: SubmitFunction = ({ action }) => {
const theme = action.searchParams.get('theme');
if (theme) {
document.documentElement.setAttribute('data-theme', theme);
}
};
const searchGo = async (e: Event) => {
e.preventDefault();
if ($page.url.pathname === '/search') {
let url = new URL(window.location.href);
url.searchParams.set('query', query);
goto(url.toString(), { invalidateAll: true });
}
if (query) {
goto(`/search?query=${query}`);
}
};
2024-07-08 11:44:39 -04:00
</script>
{#if isAboutModalOpen}
<AboutModal on:close={() => (isAboutModalOpen = false)} />
{/if}
<div class="navbar bg-base-100">
<div class="navbar-start">
<div class="dropdown z-50">
2024-07-08 11:44:39 -04:00
<div tabindex="0" role="button" class="btn btn-ghost lg:hidden">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
><path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h8m-8 6h16"
/></svg
>
</div>
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<ul
tabindex="0"
class="menu dropdown-content mt-3 z-[1] p-2 shadow bg-neutral text-base text-neutral-content rounded-box gap-2 w-96"
2024-07-08 11:44:39 -04:00
>
{#if data.user}
<li>
2024-10-26 23:03:35 -04:00
<button on:click={() => goto('/adventures')}>{$t('navbar.adventures')}</button>
2024-07-08 11:44:39 -04:00
</li>
2024-07-15 09:36:07 -04:00
<li>
2024-10-26 23:03:35 -04:00
<button on:click={() => goto('/collections')}>{$t('navbar.collections')}</button>
2024-07-15 09:36:07 -04:00
</li>
2024-07-08 11:44:39 -04:00
<li>
2024-10-26 23:03:35 -04:00
<button on:click={() => goto('/worldtravel')}>{$t('navbar.worldtravel')}</button>
2024-07-08 11:44:39 -04:00
</li>
2024-07-08 15:04:23 -04:00
<li>
2024-10-26 23:03:35 -04:00
<button on:click={() => goto('/map')}>{$t('navbar.map')}</button>
2024-07-08 15:04:23 -04:00
</li>
<li>
<button on:click={() => goto('/calendar')}>{$t('navbar.calendar')}</button>
</li>
2024-09-07 17:39:47 -04:00
<li>
2024-10-26 23:03:35 -04:00
<button on:click={() => goto('/users')}>{$t('navbar.users')}</button>
2024-09-07 17:39:47 -04:00
</li>
2024-07-08 11:44:39 -04:00
{/if}
{#if !data.user}
<li>
2024-10-26 23:03:35 -04:00
<button class="btn btn-primary" on:click={() => goto('/login')}
>{$t('auth.login')}</button
2024-10-26 23:03:35 -04:00
>
2024-07-08 11:44:39 -04:00
</li>
<li>
2024-10-26 23:03:35 -04:00
<button class="btn btn-primary" on:click={() => goto('/signup')}
>{$t('auth.signup')}</button
2024-10-26 23:03:35 -04:00
>
2024-07-08 11:44:39 -04:00
</li>
{/if}
{#if data.user}
<form class="flex gap-2">
<label class="input input-bordered flex items-center gap-2">
<input type="text" bind:value={query} placeholder={$t('navbar.search')} />
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="h-4 w-4 opacity-70"
>
<path
fill-rule="evenodd"
d="M9.965 11.026a5 5 0 1 1 1.06-1.06l2.755 2.754a.75.75 0 1 1-1.06 1.06l-2.755-2.754ZM10.5 7a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0Z"
clip-rule="evenodd"
/>
</svg>
</label>
<button on:click={searchGo} type="submit" class="btn btn-primary"
>{$t('navbar.search')}</button
>
</form>
{/if}
2024-07-08 11:44:39 -04:00
</ul>
</div>
<a class="btn btn-ghost p-0 text-2xl font-bold tracking-normal" href="/">
<span class="sm:inline hidden">AdventureLog</span>
<img src="/favicon.png" alt="Map Logo" class="w-10" />
</a>
2024-07-08 11:44:39 -04:00
</div>
<div class="navbar-center hidden lg:flex">
<ul class="menu menu-horizontal px-1 gap-2">
{#if data.user}
<li>
<button
class="btn btn-neutral flex items-center gap-1"
on:click={() => goto('/adventures')}
2024-10-26 23:03:35 -04:00
>
<MapMarker class="w-5 h-5" />
<span>{$t('navbar.adventures')}</span>
</button>
2024-07-08 11:44:39 -04:00
</li>
2024-07-15 09:36:07 -04:00
<li>
<button
class="btn btn-neutral flex items-center gap-1"
on:click={() => goto('/collections')}
>
<FormatListBulletedSquare class="w-5 h-5" />
{$t('navbar.collections')}</button
2024-10-26 23:03:35 -04:00
>
2024-07-15 09:36:07 -04:00
</li>
2024-07-08 11:44:39 -04:00
<li>
<button
class="btn btn-neutral flex items-center gap-1"
on:click={() => goto('/worldtravel')}
2024-07-08 11:44:39 -04:00
>
<Earth class="w-5 h-5" />
{$t('navbar.worldtravel')}
</button>
2024-07-08 11:44:39 -04:00
</li>
2024-07-08 15:04:23 -04:00
<li>
<button class="btn btn-neutral flex items-center gap-1" on:click={() => goto('/map')}>
<Map class="w-5 h-5" />
</button>
2024-07-08 15:04:23 -04:00
</li>
<li>
<button class="btn btn-neutral flex items-center gap-1" on:click={() => goto('/calendar')}
><Calendar /></button
>
</li>
2024-09-07 17:39:47 -04:00
<li>
<button class="btn btn-neutral flex items-center gap-1" on:click={() => goto('/users')}
2024-09-07 17:39:47 -04:00
><AccountMultiple /></button
>
</li>
2024-07-08 11:44:39 -04:00
{/if}
{#if !data.user}
<li>
<button class="btn btn-primary" on:click={() => goto('/login')}>{$t('auth.login')}</button
2024-10-26 23:03:35 -04:00
>
2024-07-08 11:44:39 -04:00
</li>
<li>
2024-10-26 23:03:35 -04:00
<button class="btn btn-primary" on:click={() => goto('/signup')}
>{$t('auth.signup')}</button
2024-10-26 23:03:35 -04:00
>
2024-07-08 11:44:39 -04:00
</li>
{/if}
{#if data.user}
<form class="flex gap-2">
<label class="input input-bordered flex items-center gap-2">
<input
type="text"
bind:value={query}
class="grow"
placeholder={$t('navbar.search')}
bind:this={inputElement}
/><kbd class="kbd">/</kbd>
</label>
<button on:click={searchGo} type="submit" class="btn btn-neutral flex items-center gap-1">
<Magnify class="w-5 h-5" />
</button>
</form>
{/if}
2024-07-08 11:44:39 -04:00
</ul>
</div>
<div class="navbar-end">
{#if data.user}
<Avatar user={data.user} />
{/if}
<div class="dropdown dropdown-bottom dropdown-end">
<div tabindex="0" role="button" class="btn m-1 p-2">
2024-07-08 11:44:39 -04:00
<DotsHorizontal class="w-6 h-6" />
</div>
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
2024-08-06 12:11:50 -04:00
<ul
tabindex="0"
class="dropdown-content bg-neutral text-neutral-content z-[1] menu p-2 shadow rounded-box w-52"
>
2024-10-28 13:56:57 -04:00
<button class="btn" on:click={() => (isAboutModalOpen = true)}>{$t('navbar.about')}</button>
2024-08-07 17:56:53 -04:00
<button
class="btn btn-sm mt-2"
2024-11-26 17:39:10 -05:00
on:click={() => (window.location.href = 'https://adventurelog.app')}
2024-10-28 13:56:57 -04:00
>{$t('navbar.documentation')}</button
2024-08-07 17:56:53 -04:00
>
<button
class="btn btn-sm mt-2"
on:click={() => (window.location.href = 'https://discord.gg/wRbQ9Egr8C')}>Discord</button
>
2024-11-26 17:39:10 -05:00
<button
class="btn btn-sm mt-2"
on:click={() => (window.location.href = 'https://seanmorley.com/sponsor')}
2024-11-26 17:39:10 -05:00
>{$t('navbar.support')} 💖</button
>
<p class="font-bold m-4 text-lg text-center">{$t('navbar.language_selection')}</p>
<form method="POST" use:enhance>
<select
class="select select-bordered w-full max-w-xs bg-base-100 text-base-content"
on:change={submitLocaleChange}
bind:value={$locale}
>
{#each $locales as loc (loc)}
<option value={loc} class="text-base-content">{languages[loc]}</option>
2024-11-26 17:39:10 -05:00
{/each}
</select>
<input type="hidden" name="locale" value={$locale} />
</form>
<p class="font-bold m-4 text-lg text-center">{$t('navbar.theme_selection')}</p>
2024-07-08 11:44:39 -04:00
<form method="POST" use:enhance={submitUpdateTheme}>
<select
class="select select-bordered w-full max-w-xs bg-base-100 text-base-content"
bind:value={theme}
on:change={submitThemeChange}
>
{#each themes as theme}
<option value={theme.name} class="text-base-content"
>{$t(`navbar.themes.${theme.name}`)}</option
>
{/each}
</select>
2024-07-08 11:44:39 -04:00
</form>
</ul>
</div>
</div>
</div>