mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-02 02:00:31 +08:00
Redesign the entire app with a new UI kit. Typography, colors, icons, avatars, and border radii have all been updated for a more polished, consistent appearance that matches our other products like radicle-explorer. - Replace blockies-based avatars with a new DID-based avatar system - Move Settings and Create Issue into fullscreen modals - Change the default theme to follow the system theme - Remove window decorations on macOS for a cleaner, more native feel - Update the app icon - Fix popovers and tooltips Navigation: - Rewrite app navigation and layouts - Add a sidebar that gives you access to all your repos - Change the startup screen to open directly to the notification inbox - Add a getting started guide shown to new users on first launch Settings: - Add a setting to disable the notification badge - Add a code font setting Bug fixes: - Fix reactions and edits incorrectly targeting the root comment instead of the intended reply - Restrict issue/patch state, labels and assignees to delegates only
156 lines
3.7 KiB
Svelte
156 lines
3.7 KiB
Svelte
<script lang="ts">
|
|
import type { NotificationsByRepo } from "@bindings/cob/inbox/NotificationsByRepo";
|
|
|
|
import Button from "@app/components/Button.svelte";
|
|
import ConfirmClear from "@app/components/ConfirmClear.svelte";
|
|
import Icon from "@app/components/Icon.svelte";
|
|
import NotificationTeaser from "@app/components/NotificationTeaser.svelte";
|
|
|
|
interface Props {
|
|
clearByIds: (ids: string[]) => Promise<void>;
|
|
clearByRepo: (rid: string) => Promise<void>;
|
|
count: number;
|
|
groupedNotifications: NotificationsByRepo["notifications"];
|
|
hidden: boolean;
|
|
name: string;
|
|
pinned: boolean;
|
|
rid: string;
|
|
showAll: (rid: string) => Promise<void>;
|
|
toggleHide: (rid: string) => void;
|
|
togglePin: (rid: string) => void;
|
|
}
|
|
|
|
const {
|
|
clearByIds,
|
|
clearByRepo,
|
|
count,
|
|
groupedNotifications,
|
|
hidden,
|
|
name,
|
|
pinned,
|
|
rid,
|
|
showAll,
|
|
toggleHide,
|
|
togglePin,
|
|
}: Props = $props();
|
|
</script>
|
|
|
|
<style>
|
|
.header {
|
|
display: flex;
|
|
align-items: center;
|
|
width: 100%;
|
|
min-height: 2rem;
|
|
gap: 0.75rem;
|
|
}
|
|
.container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1px;
|
|
}
|
|
.action-buttons {
|
|
display: flex;
|
|
gap: 0.25rem;
|
|
color: var(--color-text-tertiary);
|
|
}
|
|
.clear-repo {
|
|
margin-left: auto;
|
|
color: var(--color-text-tertiary);
|
|
}
|
|
.action-buttons,
|
|
.clear-repo {
|
|
display: none;
|
|
}
|
|
.header:hover .action-buttons,
|
|
.header:hover .clear-repo {
|
|
display: flex;
|
|
}
|
|
</style>
|
|
|
|
<div>
|
|
<div
|
|
class="header"
|
|
class:txt-missing={hidden}
|
|
style:margin-bottom={!hidden ? "1rem" : undefined}>
|
|
<span class="txt-body-l-semibold">
|
|
{name}
|
|
</span>
|
|
<span class="global-counter-badge">{count}</span>
|
|
<div
|
|
class="action-buttons"
|
|
style:display={pinned || hidden ? "flex" : undefined}>
|
|
{#if !hidden}
|
|
<Button
|
|
variant="naked"
|
|
stylePadding="0 0.25rem"
|
|
onclick={() => {
|
|
togglePin(rid);
|
|
}}>
|
|
<Icon name={pinned ? "pin-filled" : "pin-hollow"} />
|
|
</Button>
|
|
{/if}
|
|
{#if !pinned}
|
|
<Button
|
|
variant="naked"
|
|
stylePadding="0 0.25rem"
|
|
onclick={() => {
|
|
toggleHide(rid);
|
|
}}>
|
|
<Icon name={hidden ? "eye-slash" : "eye"} />
|
|
</Button>
|
|
{/if}
|
|
</div>
|
|
{#if count > 0 && !hidden}
|
|
<div class="clear-repo">
|
|
<ConfirmClear
|
|
{count}
|
|
clear={() => {
|
|
void clearByRepo(rid);
|
|
}} />
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
|
|
{#if !hidden}
|
|
<div class="container">
|
|
{#if groupedNotifications.length > 0}
|
|
{#each groupedNotifications as notificationGroup}
|
|
<NotificationTeaser
|
|
{clearByIds}
|
|
{rid}
|
|
kind={notificationGroup[0].type}
|
|
oid={notificationGroup[0].id}
|
|
notificationItems={notificationGroup} />
|
|
{/each}
|
|
{:else}
|
|
<div
|
|
class="global-flex"
|
|
style:height="100%"
|
|
style:align-items="center"
|
|
style:justify-content="center">
|
|
<div
|
|
class="txt-missing txt-body-m-regular global-flex"
|
|
style:gap="0.25rem">
|
|
<Icon name="none" />
|
|
No notifications.
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
|
|
{#if groupedNotifications.length > 0 && groupedNotifications.length < count}
|
|
<div style:width="100%" style:margin-top="1rem">
|
|
<div style:width="7rem" style:margin="auto">
|
|
<Button
|
|
variant="ghost"
|
|
onclick={async () => {
|
|
await showAll(rid);
|
|
}}>
|
|
<div style:width="100%" style:text-align="center">Show all</div>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
{/if}
|
|
</div>
|