Skip to content

Commit

Permalink
feat: better notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
ImLunaHey committed Jan 3, 2025
1 parent 1ebb84f commit 679ffda
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 53 deletions.
17 changes: 14 additions & 3 deletions src/components/ui/tab-list.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import { cn } from '@/lib/utils';
import * as Ariakit from '@ariakit/react';

export const TabList = ({ children, label }: { children: React.ReactNode; label: string }) => {
export const TabList = ({
children,
label,
className,
}: {
children: React.ReactNode;
label: string;
className?: string;
}) => {
return (
<Ariakit.TabList
// hide scrollbars
className="flex flex-row max-w-full overflow-x-scroll overflow-y-hidden scrollbar-hide border-b border-gray-200 dark:border-gray-800 touch-none touch-pan-x"
className={cn(
'flex flex-row max-w-full overflow-x-scroll overflow-y-hidden scrollbar-hide border-b border-gray-200 dark:border-gray-800 touch-none touch-pan-x',
className,
)}
aria-label={label}
>
{children}
Expand Down
3 changes: 2 additions & 1 deletion src/lib/bluesky/types/BSkyNotification.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Static, Type } from '@sinclair/typebox';
import { BSkyAuthor } from './BskyAuthor';
import { BSkyPost } from './BSkyPost';

export const BSkyNotificationFeedLike = Type.Object({
$type: Type.Literal('app.bsky.feed.like'),
Expand Down Expand Up @@ -118,7 +119,7 @@ export const BSkyReplyNotification = Type.Object({
author: BSkyAuthor,
reason: Type.Literal('reply'),
reasonSubject: Type.Optional(Type.String()),
record: Type.Any(), // TODO <--
record: BSkyPost['record'],
isRead: Type.Boolean(),
indexedAt: Type.String(),
labels: Type.Optional(Type.Array(Type.Any())),
Expand Down
23 changes: 16 additions & 7 deletions src/routes/notifications/components/FollowNotification.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
import { Avatar } from '@/components/ui/avatar';
import { Link } from '@/components/ui/Link';
import { BSkyFollowNotification } from '@/lib/bluesky/types/BSkyNotification';
import { useTranslation } from 'react-i18next';

export function FollowNotification({ notification }: { notification: BSkyFollowNotification }) {
const { t } = useTranslation('notifications');
return (
<div>
<div className="flex flex-row gap-1 overflow-hidden max-h-16">
<Avatar handle={notification.author.handle} avatar={notification.author.avatar} className="size-8 " />
<Link
to="/profile/$handle"
params={{
handle: notification.author.handle,
}}
className="hover:no-underline"
>
<div className="p-2">
<div className="flex flex-row gap-1 overflow-hidden max-h-16">
<Avatar handle={notification.author.handle} avatar={notification.author.avatar} className="size-8 " />
</div>
<div>
{notification.author.displayName} {t('followedYou')}
</div>
</div>
<div>
{notification.author.displayName} {t('followedYou')}
</div>
</div>
</Link>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export function GroupedNotifications() {
itemContent={(index: number) => {
if (!list[index]) return null;
return (
<div key={list[index][0]?.uri} className="p-2 bg-neutral-800 rounded-lg">
<div key={list[index][0]?.uri} className="border-b border-neutral-700 hover:bg-neutral-500 hover:bg-opacity-10">
<GroupNotification key={list[index][0]?.uri} notifications={list[index]} />
</div>
);
Expand Down
36 changes: 21 additions & 15 deletions src/routes/notifications/components/LikeNotification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,26 @@ export function LikeNotification({ notifications }: { notifications: BSkyLikeNot
if (!isBSkyLikeNotification(notification)) throw new Error('Notification is not a like notification');

return (
<div>
<Debug value={notification} />
<div className="flex flex-row gap-1 overflow-hidden max-h-16">
{notifications.map((notification) => (
<Avatar
key={notification.author.did}
handle={notification.author.handle}
avatar={notification.author.avatar}
className="size-8"
/>
))}
</div>
<div>
<Handle handle={notification.author.handle} />
<Link
to="/profile/$handle/post/$postId"
params={{
handle: session.did!,
postId: notification.record.subject.uri.split('/')[notification.record.subject.uri.split('/').length - 1]!,
}}
className="hover:no-underline"
>
<div className="p-2">
<Debug value={notification} />
<div className="flex flex-row gap-1 overflow-hidden max-h-16">
{notifications.map((notification) => (
<Avatar
key={notification.author.did}
handle={notification.author.handle}
avatar={notification.author.avatar}
className="size-8"
/>
))}
</div>
{notifications.map((notification) => notification.author.displayName).slice(-1)}
{notifications.length - 1 >= 1 &&
`${t('and')} ${othersCount} ${othersCount >= 1 && (othersCount === 1 ? t('other') : t('others'))} `}{' '}
Expand All @@ -44,6 +50,6 @@ export function LikeNotification({ notifications }: { notifications: BSkyLikeNot
{t('likedYourPost')}
</Link>
</div>
</div>
</Link>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
export function MentionNotification({ notification }: { notification: BSkyMentionNotification }) {
const { t } = useTranslation('notifications');
return (
<div>
<div className="p-2">
<div className="flex flex-row gap-1 overflow-hidden max-h-16">
<Avatar handle={notification.author.handle} avatar={notification.author.avatar} className="size-8 " />
</div>
Expand Down
4 changes: 3 additions & 1 deletion src/routes/notifications/components/ReplyNotification.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { Avatar } from '@/components/ui/avatar';
import { FormattedText } from '@/components/ui/FormattedText';
import { BSkyReplyNotification } from '@/lib/bluesky/types/BSkyNotification';
import { useTranslation } from 'react-i18next';

export function ReplyNotification({ notification }: { notification: BSkyReplyNotification }) {
const { t } = useTranslation('notifications');
return (
<div>
<div className="p-2">
<div className="flex flex-row gap-1 overflow-hidden max-h-16">
<Avatar handle={notification.author.handle} avatar={notification.author.avatar} className="size-8 " />
</div>
<div>
{notification.author.displayName} {t('repliedToYourPost')}
</div>
<FormattedText text={notification.record.text} />
</div>
);
}
2 changes: 1 addition & 1 deletion src/routes/notifications/components/RepostNotification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
export function RepostNotification({ notification }: { notification: BSkyRepostNotification }) {
const { t } = useTranslation('notifications');
return (
<div>
<div className="p-2">
<div className="flex flex-row gap-1 overflow-hidden max-h-16">
<Avatar handle={notification.author.handle} avatar={notification.author.avatar} className="size-8 " />
</div>
Expand Down
31 changes: 8 additions & 23 deletions src/routes/notifications/index.lazy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import * as Ariakit from '@ariakit/react';
import { createLazyFileRoute } from '@tanstack/react-router';
import { useTranslation } from 'react-i18next';
import { useState } from 'react';
import { cn } from '@/lib/utils';
import { useNotifications } from '@/lib/bluesky/hooks/useNotifications';
import { Loading } from '@/components/ui/loading';
import { GroupedNotifications } from './components/GroupedNotifications';
import { Notification } from './components/Notification';
import { Helmet } from 'react-helmet';
import { TabList } from '@/components/ui/tab-list';
import { Tab } from '@/components/ui/tab';

export const Route = createLazyFileRoute('/notifications/')({
component: RouteComponent,
Expand All @@ -30,39 +31,23 @@ function RouteComponent() {
<Helmet>
<title>{t('notifications:notifications')}</title>
</Helmet>
<div className="flex flex-col gap-2 rounded-lg">
<div className="flex flex-col gap-2 border">
<Ariakit.TabProvider
defaultSelectedId={selectedTab}
setSelectedId={(selectedId) => {
if (!selectedId) return;
setSelectedTab(selectedId);
}}
>
<Ariakit.TabList className="grid grid-cols-2 gap-4 max-w-full overflow-x-scroll bg-neutral-900 p-2 m-2 mb-0 rounded-md">
<Ariakit.Tab
id="all"
className={cn(
'flex h-10 items-center justify-center whitespace-nowrap bg-neutral-800 px-4',
selectedTab === 'all' && 'bg-neutral-700',
)}
>
{t('notifications:tabs.all')}
</Ariakit.Tab>
<Ariakit.Tab
id="mentions"
className={cn(
'flex h-10 items-center justify-center whitespace-nowrap bg-neutral-800 px-4',
selectedTab === 'mentions' && 'bg-neutral-700',
)}
>
{t('notifications:tabs.mentions')}
</Ariakit.Tab>
</Ariakit.TabList>
<TabList label="notifications" className="justify-between grid grid-cols-2">
<Tab id="all" name={t('notifications:tabs.all')} selectedTab={selectedTab} />
<Tab id="mentions" name={t('notifications:tabs.mentions')} selectedTab={selectedTab} />
</TabList>
<div className="p-2">
<Ariakit.TabPanel tabId="all">{notifications && <GroupedNotifications />}</Ariakit.TabPanel>
<Ariakit.TabPanel tabId="mentions" className="flex flex-col gap-2">
{mentions?.map((notification) => (
<div className="p-2 bg-neutral-800 rounded-lg" key={notification.uri}>
<div key={notification.uri} className="border-b border-neutral-700 hover:bg-neutral-500 hover:bg-opacity-10">
<Notification key={notification.uri} notification={notification} />
</div>
))}
Expand Down

0 comments on commit 679ffda

Please sign in to comment.