Spaces:
Running
Running
File size: 2,668 Bytes
7086abd c5304fa 7086abd c5304fa 4f54883 7086abd c82d865 a1a6daf 7086abd a1a6daf 7086abd c5304fa 7086abd c5304fa a1a6daf 7086abd c5304fa a1a6daf 7086abd 7174ecf 06feee8 7174ecf 7086abd d9327c0 a1a6daf 7086abd c5304fa d9327c0 c5304fa d9327c0 7086abd 4f54883 c82d865 9fb0576 4f54883 c82d865 4f54883 c82d865 4f54883 c82d865 4f54883 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
<script lang="ts">
import { browser } from "$app/environment";
import { beforeNavigate } from "$app/navigation";
import { base } from "$app/paths";
import { page } from "$app/state";
import IconNew from "$lib/components/icons/IconNew.svelte";
import { createEventDispatcher } from "svelte";
import { fly } from "svelte/transition";
import CarbonClose from "~icons/carbon/close";
import CarbonTextAlignJustify from "~icons/carbon/text-align-justify";
import { swipe, type SwipeCustomEvent } from "svelte-gestures";
interface Props {
isOpen?: boolean;
title: string | undefined;
children?: import("svelte").Snippet;
}
let { isOpen = false, title = $bindable(), children }: Props = $props();
let closeEl: HTMLButtonElement | undefined = $state();
let openEl: HTMLButtonElement | undefined = $state();
$effect(() => {
title ??= "New Chat";
});
const dispatch = createEventDispatcher();
beforeNavigate(() => {
dispatch("toggle", false);
});
let shouldFocusClose = $derived(isOpen && closeEl);
let shouldRefocusOpen = $derived(!isOpen && browser && document.activeElement === closeEl);
$effect(() => {
if (shouldFocusClose) {
closeEl?.focus();
} else if (shouldRefocusOpen) {
openEl?.focus();
}
});
</script>
<nav
class="flex h-12 items-center justify-between border-b bg-gray-50 px-3 dark:border-gray-800 dark:bg-gray-800/70 md:hidden"
>
<button
type="button"
class="-ml-3 flex size-12 shrink-0 items-center justify-center text-lg"
onclick={() => dispatch("toggle", true)}
aria-label="Open menu"
bind:this={openEl}><CarbonTextAlignJustify /></button
>
<div class="flex h-full items-center justify-center">
<span class="truncate px-4" data-testid="chat-title">{title}</span>
</div>
<a
class:invisible={!page.params?.id}
href="{base}/"
class="-mr-3 flex size-12 shrink-0 items-center justify-center text-lg"><IconNew /></a
>
</nav>
{#if isOpen}
<nav
use:swipe={() => ({ timeframe: 300, minSwipeDistance: 60 })}
onswipe={(ev: SwipeCustomEvent) => {
if (ev.detail.direction === "left") {
dispatch("toggle", false);
}
}}
class="fixed inset-0 z-30 grid max-h-screen grid-cols-1 grid-rows-[auto,1fr,auto,auto] bg-white pt-4 dark:bg-gray-900"
in:fly={{ x: -window.innerWidth, duration: 250 }}
out:fly={{ x: -window.innerWidth, duration: 250 }}
>
{#if page.url.pathname === base + "/"}
<button
type="button"
class="absolute right-0 top-0 z-10 flex size-12 items-center justify-center text-lg"
onclick={() => dispatch("toggle", false)}
aria-label="Close menu"
bind:this={closeEl}><CarbonClose /></button
>
{/if}
{@render children?.()}
</nav>
{/if}
|