add members to channel and update note
This commit is contained in:
@@ -10,7 +10,7 @@ export default function ChannelBlackList({ blacklist }: { blacklist: any }) {
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Popover.Button
|
||||
className={`group inline-flex h-8 w-8 items-center justify-center rounded-md ${
|
||||
className={`group inline-flex h-8 w-8 items-center justify-center rounded-md ring-2 ring-zinc-950 ${
|
||||
open ? 'bg-zinc-800 hover:bg-zinc-700' : 'bg-zinc-900 hover:bg-zinc-800'
|
||||
}`}
|
||||
>
|
||||
|
||||
39
src/app/channel/components/members.tsx
Normal file
39
src/app/channel/components/members.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import MiniMember from '@lume/app/channel/components/miniMember';
|
||||
import { channelMembersAtom } from '@lume/stores/channel';
|
||||
|
||||
import { useAtomValue } from 'jotai';
|
||||
|
||||
export default function ChannelMembers() {
|
||||
const membersAsSet = useAtomValue(channelMembersAtom);
|
||||
const membersAsArray = [...membersAsSet];
|
||||
const miniMembersList = membersAsArray.slice(0, 4);
|
||||
const totalMembers =
|
||||
membersAsArray.length > 0
|
||||
? '+' +
|
||||
Intl.NumberFormat('en-US', {
|
||||
notation: 'compact',
|
||||
maximumFractionDigits: 1,
|
||||
}).format(membersAsArray.length)
|
||||
: 0;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="group flex -space-x-2 overflow-hidden hover:-space-x-1">
|
||||
{miniMembersList.map((member, index) => (
|
||||
<MiniMember key={index} pubkey={member} />
|
||||
))}
|
||||
{totalMembers > 0 ? (
|
||||
<div className="inline-block inline-flex h-8 w-8 items-center justify-center rounded-md bg-zinc-900 ring-2 ring-zinc-950 transition-all duration-150 ease-in-out group-hover:bg-zinc-800">
|
||||
<span className="text-xs font-medium text-zinc-400 group-hover:text-zinc-200">{totalMembers}</span>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<button className="inline-flex h-8 items-center justify-center rounded-md bg-fuchsia-500 px-4 text-sm text-white shadow-button">
|
||||
Invite
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
import ChannelMessageItem from '@lume/app/channel/components/messages/item';
|
||||
import { sortedChannelMessagesAtom } from '@lume/stores/channel';
|
||||
import { hoursAgo } from '@lume/utils/getDate';
|
||||
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { Virtuoso } from 'react-virtuoso';
|
||||
|
||||
export default function ChannelMessageList() {
|
||||
const now = useRef(new Date());
|
||||
const virtuosoRef = useRef(null);
|
||||
const data = useAtomValue(sortedChannelMessagesAtom);
|
||||
|
||||
@@ -29,6 +31,31 @@ export default function ChannelMessageList() {
|
||||
ref={virtuosoRef}
|
||||
data={data}
|
||||
itemContent={itemContent}
|
||||
components={{
|
||||
Header: () => (
|
||||
<div className="relative py-4">
|
||||
<div className="absolute inset-0 flex items-center" aria-hidden="true">
|
||||
<div className="w-full border-t border-zinc-800" />
|
||||
</div>
|
||||
<div className="relative flex justify-center">
|
||||
<div className="inline-flex items-center gap-x-1.5 rounded-full bg-zinc-900 px-3 py-1.5 text-xs font-medium text-zinc-400 shadow-sm ring-1 ring-inset ring-zinc-800">
|
||||
{hoursAgo(24, now.current).toLocaleDateString('en-US', {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
EmptyPlaceholder: () => (
|
||||
<div className="flex flex-col gap-1 text-center">
|
||||
<h3 className="text-sm font-semibold leading-none text-zinc-200">Nothing to see here yet</h3>
|
||||
<p className="text-sm leading-none text-zinc-400">Be the first to share a message in this channel.</p>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
computeItemKey={computeItemKey}
|
||||
initialTopMostItemIndex={data.length - 1}
|
||||
alignToBottom={true}
|
||||
|
||||
@@ -21,7 +21,7 @@ export default function ChannelMetadata({ id, pubkey }: { id: string; pubkey: st
|
||||
<img
|
||||
src={metadata?.picture || DEFAULT_AVATAR}
|
||||
alt={id}
|
||||
className="h-8 w-8 rounded bg-zinc-900 object-contain"
|
||||
className="h-8 w-8 rounded bg-zinc-900 object-contain ring-2 ring-zinc-950"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
|
||||
20
src/app/channel/components/miniMember.tsx
Normal file
20
src/app/channel/components/miniMember.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { DEFAULT_AVATAR } from '@lume/stores/constants';
|
||||
import { useProfile } from '@lume/utils/hooks/useProfile';
|
||||
|
||||
export default function MiniMember({ pubkey }: { pubkey: string }) {
|
||||
const { user, isError, isLoading } = useProfile(pubkey);
|
||||
|
||||
return (
|
||||
<>
|
||||
{isError || isLoading ? (
|
||||
<div className="h-8 w-8 animate-pulse rounded-md bg-zinc-800"></div>
|
||||
) : (
|
||||
<img
|
||||
className="inline-block h-8 w-8 rounded-md bg-white ring-2 ring-zinc-950 transition-all duration-150 ease-in-out"
|
||||
src={user?.picture || DEFAULT_AVATAR}
|
||||
alt={user?.pubkey || 'user avatar'}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import ChannelBlackList from '@lume/app/channel/components/blacklist';
|
||||
import ChannelMembers from '@lume/app/channel/components/members';
|
||||
import ChannelMessageForm from '@lume/app/channel/components/messages/form';
|
||||
import ChannelMetadata from '@lume/app/channel/components/metadata';
|
||||
import ChannelUpdateModal from '@lume/app/channel/components/updateModal';
|
||||
@@ -54,7 +55,7 @@ export function Page() {
|
||||
{
|
||||
'#e': [key],
|
||||
kinds: [42],
|
||||
since: dateToUnix(hoursAgo(72, now.current)),
|
||||
since: dateToUnix(hoursAgo(24, now.current)),
|
||||
limit: 20,
|
||||
},
|
||||
],
|
||||
@@ -62,7 +63,7 @@ export function Page() {
|
||||
(event) => {
|
||||
const message: any = event;
|
||||
if (hided.includes(event.id)) {
|
||||
message.push({ hide: true });
|
||||
message['hide'] = true;
|
||||
}
|
||||
if (!muted.includes(event.pubkey)) {
|
||||
setChannelMessages((prev) => [...prev, message]);
|
||||
@@ -89,6 +90,7 @@ export function Page() {
|
||||
<ChannelMetadata id={channelID} pubkey={channelPubkey} />
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<ChannelMembers />
|
||||
<ChannelBlackList blacklist={mutedList} />
|
||||
{!isLoading && !isError && account ? (
|
||||
account.pubkey === channelPubkey && <ChannelUpdateModal id={account.id} />
|
||||
|
||||
Reference in New Issue
Block a user