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}