mirror of
https://github.com/luminous-devs/lume.git
synced 2024-09-19 19:46:34 +00:00
update layout
This commit is contained in:
parent
50e29beda4
commit
53fd29ddb8
@ -6,15 +6,7 @@ import { usePageContext } from '@utils/hooks/usePageContext';
|
|||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export const ChannelListItem = ({ data }: { data: any }) => {
|
export const ChannelListItem = ({ data }: { data: any }) => {
|
||||||
let fallback: any;
|
const channel: any = useChannelMetadata(data.event_id);
|
||||||
|
|
||||||
if (typeof data.metadata === 'object') {
|
|
||||||
fallback = data.metadata;
|
|
||||||
} else {
|
|
||||||
fallback = JSON.parse(data.metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
const channel: any = useChannelMetadata(data.event_id, fallback);
|
|
||||||
const pageContext = usePageContext();
|
const pageContext = usePageContext();
|
||||||
|
|
||||||
const searchParams: any = pageContext.urlParsed.search;
|
const searchParams: any = pageContext.urlParsed.search;
|
||||||
|
23
src/components/channels/channelProfile.tsx
Normal file
23
src/components/channels/channelProfile.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { useChannelMetadata } from '@utils/hooks/useChannelMetadata';
|
||||||
|
|
||||||
|
import { nip19 } from 'nostr-tools';
|
||||||
|
import Skeleton from 'react-loading-skeleton';
|
||||||
|
|
||||||
|
export const ChannelProfile = ({ id }: { id: string }) => {
|
||||||
|
const metadata = useChannelMetadata(id);
|
||||||
|
const noteID = nip19.noteEncode(id);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="inline-flex items-center gap-2">
|
||||||
|
<div className="relative shrink-0 rounded-md">
|
||||||
|
<img src={metadata?.picture || <Skeleton />} alt={id} className="h-8 w-8 rounded bg-zinc-900 object-cover" />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<h5 className="truncate font-medium leading-none text-zinc-100">{metadata?.name || <Skeleton />}</h5>
|
||||||
|
<p className="text-xs leading-none text-zinc-400">
|
||||||
|
{metadata?.about || noteID.substring(0, 24) + '...' || <Skeleton />}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -20,9 +20,7 @@ export default function NewsfeedLayout({ children }: { children: React.ReactNode
|
|||||||
<div className="scrollbar-hide col-span-1 overflow-y-auto overflow-x-hidden border-r border-zinc-900">
|
<div className="scrollbar-hide col-span-1 overflow-y-auto overflow-x-hidden border-r border-zinc-900">
|
||||||
<Navigation />
|
<Navigation />
|
||||||
</div>
|
</div>
|
||||||
<div className="col-span-3 m-3 overflow-hidden rounded-lg border border-zinc-800 bg-zinc-900 shadow-input shadow-black/20 xl:col-span-4 xl:mr-1.5">
|
<div className="col-span-3 m-3 overflow-hidden xl:col-span-4">{children}</div>
|
||||||
<div className="h-full w-full rounded-lg">{children}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { AccountContext } from '@components/accountProvider';
|
import { AccountContext } from '@components/accountProvider';
|
||||||
|
import { ChannelProfile } from '@components/channels/channelProfile';
|
||||||
import { FormChannel } from '@components/form/channel';
|
import { FormChannel } from '@components/form/channel';
|
||||||
import NewsfeedLayout from '@components/layouts/newsfeed';
|
import NewsfeedLayout from '@components/layouts/newsfeed';
|
||||||
import { RelayContext } from '@components/relaysProvider';
|
import { RelayContext } from '@components/relaysProvider';
|
||||||
@ -9,6 +10,7 @@ import { MESSAGE_RELAYS } from '@stores/constants';
|
|||||||
import { dateToUnix, hoursAgo } from '@utils/getDate';
|
import { dateToUnix, hoursAgo } from '@utils/getDate';
|
||||||
import { usePageContext } from '@utils/hooks/usePageContext';
|
import { usePageContext } from '@utils/hooks/usePageContext';
|
||||||
|
|
||||||
|
import { EyeClose, MicMute } from 'iconoir-react';
|
||||||
import { useSetAtom } from 'jotai';
|
import { useSetAtom } from 'jotai';
|
||||||
import { useResetAtom } from 'jotai/utils';
|
import { useResetAtom } from 'jotai/utils';
|
||||||
import { Suspense, lazy, useContext, useRef } from 'react';
|
import { Suspense, lazy, useContext, useRef } from 'react';
|
||||||
@ -77,12 +79,27 @@ export function Page() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<NewsfeedLayout>
|
<NewsfeedLayout>
|
||||||
<div className="flex h-full w-full flex-col justify-between">
|
<div className="flex h-full flex-col justify-between gap-2">
|
||||||
<Suspense fallback={<p>Loading...</p>}>
|
<div className="flex h-11 w-full shrink-0 items-center justify-between">
|
||||||
<ChannelMessages />
|
<div>
|
||||||
</Suspense>
|
<ChannelProfile id={id} />
|
||||||
<div className="shrink-0 p-3">
|
</div>
|
||||||
<FormChannel eventId={id} />
|
<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>
|
||||||
|
<div className="inline-flex h-8 w-8 items-center justify-center rounded-md bg-zinc-900">
|
||||||
|
<MicMute width={16} height={16} className="text-zinc-400" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="relative flex w-full flex-1 flex-col justify-between rounded-lg border border-zinc-800 bg-zinc-900 shadow-input shadow-black/20">
|
||||||
|
<Suspense fallback={<p>Loading...</p>}>
|
||||||
|
<ChannelMessages />
|
||||||
|
</Suspense>
|
||||||
|
<div className="shrink-0 p-3">
|
||||||
|
<FormChannel eventId={id} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</NewsfeedLayout>
|
</NewsfeedLayout>
|
||||||
|
@ -57,7 +57,7 @@ export function Page() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<NewsfeedLayout>
|
<NewsfeedLayout>
|
||||||
<div className="flex h-full w-full flex-col justify-between">
|
<div className="relative flex h-full w-full flex-col justify-between rounded-lg border border-zinc-800 bg-zinc-900 shadow-input shadow-black/20">
|
||||||
<Suspense fallback={<p>Loading...</p>}>
|
<Suspense fallback={<p>Loading...</p>}>
|
||||||
<MessageList />
|
<MessageList />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
@ -3,8 +3,12 @@ import NewsfeedLayout from '@components/layouts/newsfeed';
|
|||||||
export function Page() {
|
export function Page() {
|
||||||
return (
|
return (
|
||||||
<NewsfeedLayout>
|
<NewsfeedLayout>
|
||||||
<div className="flex h-full w-full items-center justify-center">
|
<div className="relative h-full w-full rounded-lg border border-zinc-800 bg-zinc-900 shadow-input shadow-black/20">
|
||||||
<p className="text-sm text-zinc-400">Sorry, this feature under development, it will come in the next version</p>
|
<div className="flex h-full w-full items-center justify-center">
|
||||||
|
<p className="text-sm text-zinc-400">
|
||||||
|
Sorry, this feature under development, it will come in the next version
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</NewsfeedLayout>
|
</NewsfeedLayout>
|
||||||
);
|
);
|
||||||
|
@ -82,7 +82,7 @@ export function Page() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<NewsfeedLayout>
|
<NewsfeedLayout>
|
||||||
<div className="relative h-full w-full">
|
<div className="relative h-full w-full rounded-lg border border-zinc-800 bg-zinc-900 shadow-input shadow-black/20">
|
||||||
{hasNewerNote && (
|
{hasNewerNote && (
|
||||||
<div className="absolute left-1/2 top-2 z-50 -translate-x-1/2 transform">
|
<div className="absolute left-1/2 top-2 z-50 -translate-x-1/2 transform">
|
||||||
<button
|
<button
|
||||||
|
@ -3,28 +3,42 @@ import { RelayContext } from '@components/relaysProvider';
|
|||||||
import { DEFAULT_RELAYS } from '@stores/constants';
|
import { DEFAULT_RELAYS } from '@stores/constants';
|
||||||
|
|
||||||
import { updateChannelMetadata } from '@utils/storage';
|
import { updateChannelMetadata } from '@utils/storage';
|
||||||
|
import { getChannel } from '@utils/storage';
|
||||||
|
|
||||||
import { useCallback, useContext, useEffect, useState } from 'react';
|
import { useCallback, useContext, useEffect, useState } from 'react';
|
||||||
|
|
||||||
export const useChannelMetadata = (id: string, fallback: any) => {
|
export const useChannelMetadata = (id: string) => {
|
||||||
const pool: any = useContext(RelayContext);
|
const pool: any = useContext(RelayContext);
|
||||||
const [metadata, setMetadata] = useState(fallback);
|
const [metadata, setMetadata] = useState(null);
|
||||||
|
|
||||||
const fetchMetadata = useCallback(() => {
|
const fetchFromRelay = useCallback(() => {
|
||||||
const unsubscribe = pool.subscribe(
|
const unsubscribe = pool.subscribe(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
kinds: [41],
|
kinds: [41],
|
||||||
'#e': [id],
|
'#e': [id],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ids: [id],
|
||||||
|
kinds: [40],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
DEFAULT_RELAYS,
|
DEFAULT_RELAYS,
|
||||||
(event: { content: string }) => {
|
(event: { kind: number; content: string }) => {
|
||||||
const json = JSON.parse(event.content);
|
switch (event.kind) {
|
||||||
// update state
|
case 41:
|
||||||
setMetadata(json);
|
const json = JSON.parse(event.content);
|
||||||
// update metadata in database
|
// update state
|
||||||
updateChannelMetadata(id, event.content);
|
setMetadata(json);
|
||||||
|
// update metadata in database
|
||||||
|
updateChannelMetadata(id, event.content);
|
||||||
|
break;
|
||||||
|
case 40:
|
||||||
|
// update state
|
||||||
|
setMetadata(JSON.parse(event.content));
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
@ -39,18 +53,28 @@ export const useChannelMetadata = (id: string, fallback: any) => {
|
|||||||
};
|
};
|
||||||
}, [id, pool]);
|
}, [id, pool]);
|
||||||
|
|
||||||
|
const getChannelFromDB = useCallback(async () => {
|
||||||
|
return await getChannel(id);
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let ignore = false;
|
let ignore = false;
|
||||||
|
|
||||||
if (!ignore) {
|
if (!ignore) {
|
||||||
// fetch kind 41
|
getChannelFromDB().then((res) => {
|
||||||
fetchMetadata();
|
console.log(res);
|
||||||
|
if (res) {
|
||||||
|
setMetadata(JSON.parse(res.metadata));
|
||||||
|
} else {
|
||||||
|
fetchFromRelay();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
ignore = true;
|
ignore = true;
|
||||||
};
|
};
|
||||||
}, [fetchMetadata, fallback]);
|
}, [fetchFromRelay, getChannelFromDB]);
|
||||||
|
|
||||||
return metadata;
|
return metadata;
|
||||||
};
|
};
|
||||||
|
@ -120,6 +120,13 @@ export async function getChannels(limit: number, offset: number) {
|
|||||||
return await db.select(`SELECT * FROM channels ORDER BY created_at DESC LIMIT "${limit}" OFFSET "${offset}";`);
|
return await db.select(`SELECT * FROM channels ORDER BY created_at DESC LIMIT "${limit}" OFFSET "${offset}";`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get channel by id
|
||||||
|
export async function getChannel(id: string) {
|
||||||
|
const db = await connect();
|
||||||
|
const result = await db.select(`SELECT * FROM channels WHERE event_id = "${id}";`);
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
|
||||||
// create channel
|
// create channel
|
||||||
export async function createChannel(event_id: string, metadata: string, created_at: number) {
|
export async function createChannel(event_id: string, metadata: string, created_at: number) {
|
||||||
const db = await connect();
|
const db = await connect();
|
||||||
|
Loading…
Reference in New Issue
Block a user