mirror of
https://github.com/lumehq/lume.git
synced 2025-09-18 19:40:34 +02:00
add muted popover
This commit is contained in:
52
src/components/channels/channelBlackList.tsx
Normal file
52
src/components/channels/channelBlackList.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { UserMuted } from '@components/user/muted';
|
||||
|
||||
import { Popover, Transition } from '@headlessui/react';
|
||||
import { MicMute } from 'iconoir-react';
|
||||
import { Fragment } from 'react';
|
||||
|
||||
export const ChannelBlackList = ({ blacklist }: { blacklist: any }) => {
|
||||
return (
|
||||
<Popover className="relative">
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Popover.Button
|
||||
className={`group inline-flex h-8 w-8 items-center justify-center rounded-md ${
|
||||
open ? 'bg-zinc-800 hover:bg-zinc-700' : 'bg-zinc-900 hover:bg-zinc-800'
|
||||
}`}
|
||||
>
|
||||
<MicMute width={16} height={16} className="text-zinc-400 group-hover:text-zinc-200" />
|
||||
</Popover.Button>
|
||||
<Transition
|
||||
as={Fragment}
|
||||
enter="transition ease-out duration-200"
|
||||
enterFrom="opacity-0 translate-y-1"
|
||||
enterTo="opacity-100 translate-y-0"
|
||||
leave="transition ease-in duration-150"
|
||||
leaveFrom="opacity-100 translate-y-0"
|
||||
leaveTo="opacity-0 translate-y-1"
|
||||
>
|
||||
<Popover.Panel className="absolute right-0 z-10 mt-1 w-screen max-w-xs transform px-4 sm:px-0">
|
||||
<div className="flex flex-col gap-2 overflow-hidden rounded-lg border border-zinc-800 bg-zinc-900 shadow-popover">
|
||||
<div className="h-min w-full shrink-0 border-b border-zinc-800 p-3">
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<h3 className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text font-semibold leading-none text-transparent">
|
||||
Your muted list
|
||||
</h3>
|
||||
<p className="text-xs leading-tight text-zinc-400">
|
||||
Currently, unmute only affect locally, when you move to new client, muted list will loaded again
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-3 pb-3 pt-1">
|
||||
{blacklist.map((item: any) => (
|
||||
<UserMuted key={item.id} data={item} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Popover.Panel>
|
||||
</Transition>
|
||||
</>
|
||||
)}
|
||||
</Popover>
|
||||
);
|
||||
};
|
@@ -125,8 +125,8 @@ export const UpdateChannelModal = ({ id }: { id: string }) => {
|
||||
</button>
|
||||
</div>
|
||||
<Dialog.Description className="leading-tight text-zinc-400">
|
||||
Channels are freedom square, everyone can speech freely, no one can stop you or deceive what to
|
||||
speech
|
||||
New metadata will be published on all relays, and will be immediately available to all users, so
|
||||
please carefully.
|
||||
</Dialog.Description>
|
||||
</div>
|
||||
</div>
|
||||
|
65
src/components/user/muted.tsx
Normal file
65
src/components/user/muted.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import { DEFAULT_AVATAR } from '@stores/constants';
|
||||
|
||||
import { useProfileMetadata } from '@utils/hooks/useProfileMetadata';
|
||||
import { shortenKey } from '@utils/shortenKey';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
export const UserMuted = ({ data }: { data: any }) => {
|
||||
const profile = useProfileMetadata(data.content);
|
||||
const [status, setStatus] = useState(data.status);
|
||||
|
||||
const unmute = async () => {
|
||||
const { updateItemInBlacklist } = await import('@utils/storage');
|
||||
const res = await updateItemInBlacklist(data.content, 0);
|
||||
if (res) {
|
||||
setStatus(0);
|
||||
}
|
||||
};
|
||||
|
||||
const mute = async () => {
|
||||
const { updateItemInBlacklist } = await import('@utils/storage');
|
||||
const res = await updateItemInBlacklist(data.content, 1);
|
||||
if (res) {
|
||||
setStatus(1);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<div className="relative h-9 w-9 shrink rounded-md">
|
||||
<img
|
||||
src={profile?.picture || DEFAULT_AVATAR}
|
||||
alt={data.content}
|
||||
className="h-9 w-9 rounded-md object-cover"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex w-full flex-1 flex-col items-start gap-0.5 text-start">
|
||||
<span className="truncate text-sm font-medium leading-none text-zinc-200">
|
||||
{profile?.display_name || profile?.name}
|
||||
</span>
|
||||
<span className="text-xs leading-none text-zinc-400">{shortenKey(data.content)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{status === 1 ? (
|
||||
<button
|
||||
onClick={() => unmute()}
|
||||
className="inline-flex h-6 w-min items-center justify-center rounded px-1.5 text-xs font-medium leading-none text-zinc-400 hover:bg-zinc-800 hover:text-fuchsia-500"
|
||||
>
|
||||
Unmute
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => mute()}
|
||||
className="inline-flex h-6 w-min items-center justify-center rounded px-1.5 text-xs font-medium leading-none text-zinc-400 hover:bg-zinc-800 hover:text-fuchsia-500"
|
||||
>
|
||||
Mute
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@@ -1,4 +1,5 @@
|
||||
import { AccountContext } from '@components/accountProvider';
|
||||
import { ChannelBlackList } from '@components/channels/channelBlackList';
|
||||
import { ChannelProfile } from '@components/channels/channelProfile';
|
||||
import { UpdateChannelModal } from '@components/channels/updateChannelModal';
|
||||
import { FormChannel } from '@components/form/channel';
|
||||
@@ -12,7 +13,6 @@ import { dateToUnix, hoursAgo } from '@utils/getDate';
|
||||
import { usePageContext } from '@utils/hooks/usePageContext';
|
||||
import { arrayObjToPureArr } from '@utils/transform';
|
||||
|
||||
import { EyeClose } from 'iconoir-react';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useResetAtom } from 'jotai/utils';
|
||||
import { Suspense, lazy, useContext, useRef } from 'react';
|
||||
@@ -21,12 +21,14 @@ import useSWRSubscription from 'swr/subscription';
|
||||
const ChannelMessages = lazy(() => import('@components/channels/messages'));
|
||||
|
||||
let mutedList: any = [];
|
||||
let hidedList: any = [];
|
||||
let activeMutedList: any = [];
|
||||
let activeHidedList: any = [];
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
const { getBlacklist, getActiveAccount } = await import('@utils/storage');
|
||||
const { getBlacklist, getActiveBlacklist, getActiveAccount } = await import('@utils/storage');
|
||||
const activeAccount = await getActiveAccount();
|
||||
hidedList = await getBlacklist(activeAccount.id, 43);
|
||||
activeHidedList = await getActiveBlacklist(activeAccount.id, 43);
|
||||
activeMutedList = await getActiveBlacklist(activeAccount.id, 44);
|
||||
mutedList = await getBlacklist(activeAccount.id, 44);
|
||||
}
|
||||
|
||||
@@ -45,8 +47,8 @@ export function Page() {
|
||||
const resetChannelReply = useResetAtom(channelReplyAtom);
|
||||
|
||||
const now = useRef(new Date());
|
||||
const hided = arrayObjToPureArr(hidedList);
|
||||
const muted = arrayObjToPureArr(mutedList);
|
||||
const hided = arrayObjToPureArr(activeHidedList);
|
||||
const muted = arrayObjToPureArr(activeMutedList);
|
||||
|
||||
useSWRSubscription(id, () => {
|
||||
// reset channel reply
|
||||
@@ -87,9 +89,7 @@ export function Page() {
|
||||
<ChannelProfile id={id} pubkey={channelPubkey} />
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="inline-flex h-8 w-8 items-center justify-center rounded-md bg-zinc-900">
|
||||
<EyeClose width={16} height={16} className="text-zinc-400" />
|
||||
</div>
|
||||
<ChannelBlackList blacklist={mutedList} />
|
||||
{activeAccount.pubkey === channelPubkey && <UpdateChannelModal id={id} />}
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -174,7 +174,15 @@ export async function updateLastLogin(value: number) {
|
||||
// get blacklist by kind and account id
|
||||
export async function getBlacklist(account_id: number, kind: number) {
|
||||
const db = await connect();
|
||||
return await db.select(`SELECT content FROM blacklist WHERE account_id = "${account_id}" AND kind = "${kind}";`);
|
||||
return await db.select(`SELECT * FROM blacklist WHERE account_id = "${account_id}" AND kind = "${kind}";`);
|
||||
}
|
||||
|
||||
// get active blacklist by kind and account id
|
||||
export async function getActiveBlacklist(account_id: number, kind: number) {
|
||||
const db = await connect();
|
||||
return await db.select(
|
||||
`SELECT content FROM blacklist WHERE account_id = "${account_id}" AND kind = "${kind}" AND status = 1;`
|
||||
);
|
||||
}
|
||||
|
||||
// add to blacklist
|
||||
|
@@ -25,6 +25,7 @@ module.exports = {
|
||||
inset 0 0 0 0.3px hsl(0deg 0% 100% / 30%),
|
||||
0 0 0 0.5px hsl(0deg 0% 100% / 40%);
|
||||
`,
|
||||
popover: `0px 0px 7px rgba(0,0,0,0.52)`,
|
||||
inner: `
|
||||
0 2px 2px rgb(4 4 7 / 45%),
|
||||
0 8px 24px rgb(4 4 7 / 60%)
|
||||
|
Reference in New Issue
Block a user