Pair the chat header plus button with a popover overflow menu (#427)

This commit is contained in:
Coracle Bot 2026-09-07 20:39:58 +00:00 committed by hodlbod
parent 6da908edd0
commit cfb5dd53b1
4 changed files with 44 additions and 42 deletions

View file

@ -474,7 +474,7 @@ test("US-034 track and clear unread conversations", async ({seed, as}) => {
await expect(unreadDots(bobChat)).toHaveCount(0)
// Mark all read clears what is left of them in one go
await alice.locator(".secondary-nav__header").getByRole("button").click()
await alice.locator(".secondary-nav__header").getByRole("button", {name: "Chat options"}).click()
await alice.getByRole("button", {name: "Mark all read"}).click()
await expect(unreadDots(chatList(alice))).toHaveCount(0)

View file

@ -1,43 +1,48 @@
<script lang="ts">
import {onMount} from "svelte"
import {assoc} from "@welshman/lib"
import Check from "@assets/icons/check.svg?dataurl"
import Bell from "@assets/icons/bell.svg?dataurl"
import BellOff from "@assets/icons/bell-off.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import Modal from "@lib/components/Modal.svelte"
import ModalBody from "@lib/components/ModalBody.svelte"
import {setChecked} from "@app/notifications"
import {notificationSettings} from "@app/settings"
const markAsRead = () => {
setChecked("/chat/*")
history.back()
type Props = {
onClick: () => void
}
const enableAlerts = () => notificationSettings.update(assoc("messages", true))
const {onClick}: Props = $props()
const disableAlerts = () => notificationSettings.update(assoc("messages", false))
const markAsRead = () => setChecked("/chat/*")
const toggleAlerts = () =>
notificationSettings.update(assoc("messages", !$notificationSettings.messages))
let ul: Element
onMount(() => {
ul.addEventListener("click", onClick)
})
</script>
<Modal>
<ModalBody>
<div class="flex flex-col gap-2">
<Button class="button button-neutral" onclick={markAsRead}>
<Icon size={5} icon={Check} />
Mark all read
</Button>
<ul class="menu whitespace-nowrap rounded-2xl bg-surface p-2" bind:this={ul}>
<li>
<Button onclick={markAsRead}>
<Icon size={4} icon={Check} />
Mark all read
</Button>
</li>
<li>
<Button onclick={toggleAlerts}>
{#if $notificationSettings.messages}
<Button class="button button-neutral" onclick={disableAlerts}>
<Icon size={4} icon={BellOff} />
Disable alerts
</Button>
<Icon size={4} icon={BellOff} />
Disable alerts
{:else}
<Button class="button button-neutral" onclick={enableAlerts}>
<Icon size={4} icon={Bell} />
Enable alerts
</Button>
<Icon size={4} icon={Bell} />
Enable alerts
{/if}
</div>
</ModalBody>
</Modal>
</Button>
</li>
</ul>

View file

@ -3,12 +3,13 @@
import {onMount} from "svelte"
import {page} from "$app/stores"
import {sleep} from "@welshman/lib"
import MenuDots from "@assets/icons/menu-dots.svg?dataurl"
import Add from "@assets/icons/add.svg?dataurl"
import ChatSquarePlus from "@assets/icons/chat-square-plus.svg?dataurl"
import Magnifier from "@assets/icons/magnifier.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import Page from "@lib/components/Page.svelte"
import Button from "@lib/components/Button.svelte"
import MenuButton from "@lib/components/MenuButton.svelte"
import Spinner from "@lib/components/Spinner.svelte"
import FAB from "@lib/components/FAB.svelte"
import SecondaryNav from "@lib/components/SecondaryNav.svelte"
@ -27,8 +28,6 @@
const {children}: Props = $props()
const openMenu = () => pushModal(ChatMenu)
const startChat = () => pushModal(ChatStart)
let term = $state("")
@ -46,14 +45,16 @@
<SecondaryNavSection>
<SecondaryNavHeader>
Chats
<Button onclick={openMenu}>
<Icon icon={MenuDots} />
</Button>
<div class="flex items-center">
<Button
class="button button-ghost button-sm button-circle"
aria-label="Start New Chat"
onclick={startChat}>
<Icon icon={Add} />
</Button>
<MenuButton component={ChatMenu} aria-label="Chat options" />
</div>
</SecondaryNavHeader>
<Button class="button button-primary button-sm w-full" onclick={startChat}>
<Icon icon={ChatSquarePlus} />
Start New Chat
</Button>
<label class="input input-sm flex items-center gap-2">
<Icon icon={Magnifier} />
<input bind:value={term} class="grow" type="text" />

View file

@ -1,11 +1,11 @@
<script lang="ts">
import InfoCircle from "@assets/icons/info-circle.svg?dataurl"
import Magnifier from "@assets/icons/magnifier.svg?dataurl"
import MenuDots from "@assets/icons/menu-dots.svg?dataurl"
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import PageContent from "@lib/components/PageContent.svelte"
import Button from "@lib/components/Button.svelte"
import MenuButton from "@lib/components/MenuButton.svelte"
import ContentSearch from "@lib/components/ContentSearch.svelte"
import ChatItem from "@app/components/ChatItem.svelte"
import ChatStart from "@app/components/ChatStart.svelte"
@ -17,8 +17,6 @@
const startChat = () => pushModal(ChatStart)
const openMenu = () => pushModal(ChatMenu)
const chats = $derived($chatSearch.searchOptions(term))
</script>
@ -45,9 +43,7 @@
type="text"
placeholder="Search for conversations..." />
</label>
<Button class="button button-neutral" onclick={openMenu}>
<Icon icon={MenuDots} />
</Button>
<MenuButton component={ChatMenu} class="button button-neutral" aria-label="Chat options" />
</div>
{/snippet}
{#snippet content()}