Skip to content

Commit

Permalink
Added UI for notifications log system
Browse files Browse the repository at this point in the history
  • Loading branch information
Zequez committed Dec 24, 2024
1 parent 9dfd918 commit 4597f49
Show file tree
Hide file tree
Showing 7 changed files with 359 additions and 13 deletions.
1 change: 1 addition & 0 deletions ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
</head>
<body class="bg-main-800 text-black/70 flex flex-col min-h-0">
<script type="module" src="./src/main.ts"></script>
<div id="tooltips" class="z-1000"></div>
</body>
</html>
17 changes: 17 additions & 0 deletions ui/src/GameSpace/GameSpace.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import { cloneDeep } from 'lodash';
import { COLORS, colorSequence, uuid } from '~/lib/util';
import NameTitleInput from './ui/NameTitleInput.svelte';
import ActivityLog from './topbar/ActivityLog.svelte';
export let gameSpace: GameSpaceSyn;
export let asAsset: boolean = false;
Expand Down Expand Up @@ -146,6 +147,13 @@

{#if $state}
<div class="h-full flex flex-col">
<!-- ████████╗ ██████╗ ██████╗ ██████╗ █████╗ ██████╗
╚══██╔══╝██╔═══██╗██╔══██╗ ██╔══██╗██╔══██╗██╔══██╗
██║ ██║ ██║██████╔╝ ██████╔╝███████║██████╔╝
██║ ██║ ██║██╔═══╝ ██╔══██╗██╔══██║██╔══██╗
██║ ╚██████╔╝██║ ██████╔╝██║ ██║██║ ██║
╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝
-->
<div class="bg-main-400 h-12 pl1 flexcc relative">
{#if !asAsset}
<button
Expand Down Expand Up @@ -198,7 +206,16 @@
onChangePlayersSlots={handlePlayersSlotsChange}
/>
{/if}
<ActivityLog agentKey={gameSpace.pubKey} />
</div>

<!-- ███╗ ███╗ █████╗ ██╗███╗ ██╗ ███████╗██████╗ █████╗ ██████╗███████╗
████╗ ████║██╔══██╗██║████╗ ██║ ██╔════╝██╔══██╗██╔══██╗██╔════╝██╔════╝
██╔████╔██║███████║██║██╔██╗ ██║ ███████╗██████╔╝███████║██║ █████╗
██║╚██╔╝██║██╔══██║██║██║╚██╗██║ ╚════██║██╔═══╝ ██╔══██║██║ ██╔══╝
██║ ╚═╝ ██║██║ ██║██║██║ ╚████║ ███████║██║ ██║ ██║╚██████╗███████╗
╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝
-->
<div class="flex flex-grow relative">
{#if !$permissions.isArchived}
{#if sidebar === 'elementsLibrary' && $isSteward}
Expand Down
190 changes: 190 additions & 0 deletions ui/src/GameSpace/topbar/ActivityLog.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
<script lang="ts">
import BellIcon from '~icons/fa6-solid/bell';
import BellSlashIcon from '~icons/fa6-regular/bell-slash';
import cx from 'classnames';
import { relativeTimeFormat, timeFormat } from '~/lib/util';
import { tooltip } from '~/shared/tooltip';
import TopBarDropButton from '../ui/TopBarDropButton.svelte';
export let agentKey: string;
type AgentKey = string;
type LogType = 'turn' | 'move' | 'join' | 'left';
type Log = {
message: string;
time: number;
seenBy: string[];
type: LogType;
agentKey: AgentKey;
};
const DEFAULT_NOTIFICATIONS_CONFIG: Record<LogType, boolean> = {
turn: true,
move: false,
join: true,
left: true,
};
const NOTIFICATIONS_CONFIG_OVERRIDE: Record<AgentKey, Record<LogType, boolean>> = {};
let log: Log[] = [
{
message: 'Ezequiel joined at slot 4',
time: 1735041958600,
seenBy: [],
type: 'join',
agentKey: '',
},
{
message: 'Ezequiel moved piece',
time: 1735021958600,
seenBy: [],
type: 'move',
agentKey: '',
},
{
message: 'Ezequiel moved piece',
time: 1735020958600,
seenBy: [],
type: 'move',
agentKey: '',
},
{
message: 'Ezequiel ended his turn',
time: 1735011958600,
seenBy: [],
type: 'turn',
agentKey: '',
},
{
message: 'Ezequiel moved piece',
time: 1735020958600,
seenBy: [],
type: 'move',
agentKey: '',
},
{
message: 'Ezequiel ended his turn',
time: 1735011958600,
seenBy: [],
type: 'turn',
agentKey: '',
},
{
message: 'Ezequiel moved piece',
time: 1735020958600,
seenBy: [],
type: 'move',
agentKey: '',
},
{
message: 'Ezequiel ended his turn',
time: 1735011958600,
seenBy: [],
type: 'turn',
agentKey: '',
},
{
message: 'Ezequiel moved piece',
time: 1735020958600,
seenBy: [],
type: 'move',
agentKey: '',
},
{
message: 'Ezequiel ended his turn',
time: 1735011958600,
seenBy: [],
type: 'turn',
agentKey: '',
},
{
message: 'Ezequiel moved piece',
time: 1735020958600,
seenBy: [],
type: 'move',
agentKey: '',
},
{
message: 'Ezequiel ended his turn',
time: 1735011958600,
seenBy: [],
type: 'turn',
agentKey: '',
},
];
$: notificationsCount = log.filter((l) => !l.seenBy.includes(agentKey)).length;
const LOG_TYPES_ICONS: Record<LogType, string> = {
turn: '',
move: '🫳',
join: '👤',
left: '👋',
};
function isUnseen(log: Log) {
return !log.seenBy.includes(agentKey);
}
function markAsSeen() {
log = log.map((l) => ({ ...l, seenBy: [...l.seenBy, agentKey] }));
}
$: notificationIsActivatedForLogType = (logType: LogType) =>
NOTIFICATIONS_CONFIG_OVERRIDE[agentKey]?.[logType] ?? DEFAULT_NOTIFICATIONS_CONFIG[logType];
function setNotificationForLogType(logType: LogType, value: boolean) {
NOTIFICATIONS_CONFIG_OVERRIDE[agentKey] = {
...NOTIFICATIONS_CONFIG_OVERRIDE[agentKey],
[logType]: value,
};
}
</script>

<TopBarDropButton title="Activity" counter={notificationsCount} onClose={markAsSeen}>
<BellIcon slot="icon" />
<div class="w-100">
{#each log as l}
{@const unseen = isUnseen(l)}
{@const date = new Date(l.time)}
{@const notificationActivated = notificationIsActivatedForLogType(l.type)}
<div
class={cx('first:b-t last:rounded-b-md b-b b-black/10 py2 bg-black/5 flexcs', {
'bg-main-800!': unseen,
})}
>
<span class="text-lg mr1 flex-shrink-0 w12 inline-block text-center"
>{LOG_TYPES_ICONS[l.type]}</span
>
<div class="flex-grow">
{l.message}
<span class="position-relative opacity-50 text-xs" use:tooltip={timeFormat(date)}
>{relativeTimeFormat(date)}</span
>
</div>
<div class="w8 flex-shrink-0 flexcc">
{#if unseen}
<div
class="bg-main-500 h3 w3 flexcc rounded-full"
use:tooltip={{ content: 'New', placement: 'left' }}
></div>
{/if}
</div>
<button
class="w8 flex-shrink-0 flexcc"
use:tooltip={{
content: notificationActivated
? 'Disable notifications for this activity type'
: 'Enable notifications for this activity type',
placement: 'left',
}}
on:click={() => setNotificationForLogType(l.type, !notificationActivated)}
>
{#if notificationActivated}
<span class="text-main-500"><BellIcon /></span>
{:else}
<span class="text-main-500 opacity-50"><BellSlashIcon /></span>
{/if}
</button>
</div>
{/each}
</div>
</TopBarDropButton>
27 changes: 17 additions & 10 deletions ui/src/GameSpace/topbar/PeopleBar.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script lang="ts">
import cx from 'classnames';
import UsersIcon from '~icons/fa6-solid/users';
import AgentAvatar from '~/shared/AgentAvatar.svelte';
import AgentName from '~/shared/AgentName.svelte';
import type { PlayerSlot } from '~/store/types';
import TopBarDropButton from '../ui/TopBarDropButton.svelte';
import PlayersSlots from './PlayersSlots.svelte';
export let pubKey: string;
Expand All @@ -15,12 +15,6 @@
export let onJoin: () => void;
export let onLeave: () => void;
export let onChangePlayersSlots: (playersSlots: PlayerSlot[]) => void;
let showingParticipants = false;
const toggleParticipants = () => {
showingParticipants = !showingParticipants;
};
</script>

<div class="flex-grow flexce space-x-1 relative">
Expand All @@ -41,7 +35,18 @@
>
{/if}
<PlayersSlots {pubKey} {playersSlots} {canJoinGame} onChange={onChangePlayersSlots} />
<button
<TopBarDropButton title="Participants in space" counter={participants.length}>
<UsersIcon slot="icon" />
<div class="w-60">
{#each participants as participant}
<div class="flexcs px4 py2 bg-black/5 b-t b-black/10">
<AgentAvatar pubKey={participant} size={28} />
<AgentName class="ml2" pubKey={participant} />
</div>
{/each}
</div>
</TopBarDropButton>
<!-- <button
class={cx('h12 w12 text-white flexcc hover:bg-black/10', {
'bg-black/30!': showingParticipants,
})}
Expand All @@ -54,7 +59,9 @@
</div>
</button>
{#if showingParticipants}
<div class="bg-main-900 p4 rounded-bl-md top-full w-60 absolute flex flex-col space-y-2 z-1000">
<div
class="bg-main-900 p4 rounded-b-md top-full w-60 absolute flex flex-col space-y-2 z-1000 shadow-lg"
>
<div>In the space</div>
{#each participants as participant}
<div class="flexcs">
Expand All @@ -63,5 +70,5 @@
</div>
{/each}
</div>
{/if}
{/if} -->
</div>
72 changes: 72 additions & 0 deletions ui/src/GameSpace/ui/TopBarDropButton.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<script lang="ts">
import { cx } from '~/lib/util';
import { tooltip } from '~/shared/tooltip';
export let onClose = () => {};
export let counter = 0;
export let title: string;
let isOpen = false;
let closeOnWindowClick = false;
function toggleOpen() {
isOpen = !isOpen;
if (isOpen) {
setTimeout(() => {
closeOnWindowClick = true;
}, 100);
computeMaxHeight();
} else {
onClose();
closeOnWindowClick = false;
}
}
function computeMaxHeight() {
const { top, height } = buttonEl.getBoundingClientRect();
const documentHeight = document.documentElement.clientHeight;
maxHeight = documentHeight - top - height;
}
$: handleClickWindow = () => {
if (closeOnWindowClick && isOpen) {
toggleOpen();
}
};
let buttonEl: HTMLButtonElement;
let maxHeight: 1200;
</script>

<svelte:window on:click={handleClickWindow} on:resize={computeMaxHeight} />

<div class="relative">
<button
bind:this={buttonEl}
use:tooltip={title}
class={cx('h12 w12 text-white flexcc hover:bg-black/10', {
'bg-black/30!': isOpen,
})}
on:click={toggleOpen}
>
<slot name="icon" />
{#if counter > 0}
<div
class="bg-red-500 text-sm text-white h4 w4 flexcc rounded-full absolute bottom-2 right-2"
>
{counter}
</div>
{/if}
</button>
{#if isOpen}
<div
class="bg-main-900 rounded-b-md top-full right-0 absolute flex flex-col z-50 shadow-lg"
on:click={(ev) => ev.stopPropagation()}
style={`max-height: ${maxHeight}px`}
>
<div class="p4">{title}</div>
<div class="flex-grow overflow-auto">
<slot />
</div>
</div>
{/if}
</div>
Loading

0 comments on commit 4597f49

Please sign in to comment.