mirror of
https://github.com/luminous-devs/lume.git
synced 2024-09-19 19:46:34 +00:00
updated create channel modal
This commit is contained in:
parent
97c45a8c8f
commit
340e453b3e
@ -1,26 +1,15 @@
|
|||||||
import { ChannelListItem } from '@components/channels/channelListItem';
|
import { ChannelListItem } from '@components/channels/channelListItem';
|
||||||
|
import { CreateChannelModal } from '@components/channels/createChannelModal';
|
||||||
|
|
||||||
import { DEFAULT_CHANNELS } from '@stores/constants';
|
import { DEFAULT_CHANNELS } from '@stores/constants';
|
||||||
|
|
||||||
import { Plus } from 'iconoir-react';
|
|
||||||
|
|
||||||
export default function ChannelList() {
|
export default function ChannelList() {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-px">
|
<div className="flex flex-col gap-px">
|
||||||
{DEFAULT_CHANNELS.map((item) => (
|
{DEFAULT_CHANNELS.map((item) => (
|
||||||
<ChannelListItem key={item.event_id} data={item} />
|
<ChannelListItem key={item.event_id} data={item} />
|
||||||
))}
|
))}
|
||||||
<a
|
<CreateChannelModal />
|
||||||
href="/create-channel"
|
|
||||||
className="group inline-flex items-center gap-2 rounded-md px-2.5 py-1.5 hover:bg-zinc-900"
|
|
||||||
>
|
|
||||||
<div className="inline-flex h-5 w-5 shrink items-center justify-center rounded bg-zinc-900 group-hover:bg-zinc-800">
|
|
||||||
<Plus width={12} height={12} className="text-zinc-500" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h5 className="text-sm font-medium text-zinc-500 group-hover:text-zinc-400">Add a new channel</h5>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import { RelayContext } from '@components/relaysProvider';
|
import { RelayContext } from '@components/relaysProvider';
|
||||||
|
|
||||||
|
import { FULL_RELAYS } from '@stores/constants';
|
||||||
|
|
||||||
import { dateToUnix } from '@utils/getDate';
|
import { dateToUnix } from '@utils/getDate';
|
||||||
|
import { createChannel } from '@utils/storage';
|
||||||
|
|
||||||
import * as Dialog from '@radix-ui/react-dialog';
|
import * as Dialog from '@radix-ui/react-dialog';
|
||||||
import useLocalStorage from '@rehooks/local-storage';
|
import useLocalStorage from '@rehooks/local-storage';
|
||||||
@ -10,7 +13,7 @@ import { useContext, useState } from 'react';
|
|||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
|
|
||||||
export const CreateChannelModal = () => {
|
export const CreateChannelModal = () => {
|
||||||
const [pool, relays]: any = useContext(RelayContext);
|
const [pool]: any = useContext(RelayContext);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [activeAccount]: any = useLocalStorage('account', {});
|
const [activeAccount]: any = useLocalStorage('account', {});
|
||||||
|
|
||||||
@ -21,7 +24,7 @@ export const CreateChannelModal = () => {
|
|||||||
formState: { isDirty, isValid },
|
formState: { isDirty, isValid },
|
||||||
} = useForm();
|
} = useForm();
|
||||||
|
|
||||||
const onSubmit = (data) => {
|
const onSubmit = (data: any) => {
|
||||||
const event: any = {
|
const event: any = {
|
||||||
content: JSON.stringify(data),
|
content: JSON.stringify(data),
|
||||||
created_at: dateToUnix(),
|
created_at: dateToUnix(),
|
||||||
@ -33,7 +36,9 @@ export const CreateChannelModal = () => {
|
|||||||
event.sig = signEvent(event, activeAccount.privkey);
|
event.sig = signEvent(event, activeAccount.privkey);
|
||||||
|
|
||||||
// publish channel
|
// publish channel
|
||||||
pool.publish(event, relays);
|
pool.publish(event, FULL_RELAYS);
|
||||||
|
// insert to database
|
||||||
|
createChannel(event.id, event.content, event.created_at);
|
||||||
// close modal
|
// close modal
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
// reset form
|
// reset form
|
||||||
@ -53,43 +58,48 @@ export const CreateChannelModal = () => {
|
|||||||
</div>
|
</div>
|
||||||
</Dialog.Trigger>
|
</Dialog.Trigger>
|
||||||
<Dialog.Portal>
|
<Dialog.Portal>
|
||||||
<Dialog.Overlay className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-sm data-[state=open]:animate-overlayShow" />
|
<Dialog.Overlay className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-md data-[state=open]:animate-overlayShow" />
|
||||||
<Dialog.Content className="fixed inset-0 z-50 overflow-y-auto">
|
<Dialog.Content className="fixed inset-0 z-50 overflow-y-auto">
|
||||||
<div className="flex min-h-full items-center justify-center">
|
<div className="flex min-h-full items-center justify-center">
|
||||||
<div className="relative flex h-min w-full max-w-xl flex-col rounded-lg shadow-modal">
|
<div className="relative flex h-min w-full max-w-lg flex-col gap-2 rounded-lg border border-zinc-800 bg-zinc-900">
|
||||||
<div className="sticky left-0 top-0 flex h-12 w-full shrink-0 items-center justify-between rounded-t-lg bg-zinc-950 px-3">
|
<div className="h-min w-full shrink-0 border-b border-zinc-800 px-5 py-6">
|
||||||
<div className="flex w-full items-center justify-between">
|
<div className="flex flex-col gap-2">
|
||||||
<h5 className="font-medium leading-none text-zinc-500"># Create channel</h5>
|
<div className="flex items-center justify-between">
|
||||||
<Dialog.Close asChild>
|
<h5 className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-2xl font-semibold leading-none text-transparent">
|
||||||
<button
|
Create channel
|
||||||
autoFocus={false}
|
</h5>
|
||||||
className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-900"
|
<Dialog.Close asChild>
|
||||||
>
|
<button
|
||||||
<Cancel width={12} height={12} className="text-zinc-500" />
|
autoFocus={false}
|
||||||
</button>
|
className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-900"
|
||||||
</Dialog.Close>
|
>
|
||||||
|
<Cancel width={20} height={20} className="text-zinc-300" />
|
||||||
|
</button>
|
||||||
|
</Dialog.Close>
|
||||||
|
</div>
|
||||||
|
<p className="leading-tight text-zinc-400">
|
||||||
|
Channels are freedom square, everyone can speech freely, no one can stop you or deceive what to
|
||||||
|
speech
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex h-full w-full flex-col overflow-y-auto rounded-b-lg bg-zinc-950 px-3 pb-3">
|
<div className="flex h-full w-full flex-col overflow-y-auto px-5 pb-5 pt-3">
|
||||||
<form
|
<form onSubmit={handleSubmit(onSubmit)} className="flex h-full w-full flex-col gap-4">
|
||||||
onSubmit={handleSubmit(onSubmit)}
|
|
||||||
className="flex h-full w-full flex-col gap-4 rounded-lg border border-white/20 bg-zinc-900 p-4"
|
|
||||||
>
|
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<label className="text-xs font-semibold uppercase tracking-wider text-zinc-300">
|
<label className="text-xs font-semibold uppercase tracking-wider text-zinc-400">
|
||||||
Channel name *
|
Channel name *
|
||||||
</label>
|
</label>
|
||||||
<div className="relative w-full shrink-0 overflow-hidden before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] before:border before:border-fuchsia-500 before:opacity-0 before:ring-2 before:ring-fuchsia-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[7px] after:shadow-highlight after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-fuchsia-500/100 dark:focus-within:after:shadow-fuchsia-500/20">
|
<div className="relative w-full shrink-0 overflow-hidden before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] before:border before:border-fuchsia-500 before:opacity-0 before:ring-2 before:ring-fuchsia-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[7px] after:shadow-highlight after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-fuchsia-500/100 dark:focus-within:after:shadow-fuchsia-500/20">
|
||||||
<input
|
<input
|
||||||
type={'text'}
|
type={'text'}
|
||||||
{...register('name', { required: true })}
|
{...register('name', { required: true, minLength: 4 })}
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
className="relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-200 dark:shadow-black/10 dark:placeholder:text-zinc-500"
|
className="relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-200 dark:shadow-black/10 dark:placeholder:text-zinc-500"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<label className="text-xs font-semibold uppercase tracking-wider text-zinc-300">Picture</label>
|
<label className="text-xs font-semibold uppercase tracking-wider text-zinc-400">Picture</label>
|
||||||
<div className="relative w-full shrink-0 overflow-hidden before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] before:border before:border-fuchsia-500 before:opacity-0 before:ring-2 before:ring-fuchsia-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[7px] after:shadow-highlight after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-fuchsia-500/100 dark:focus-within:after:shadow-fuchsia-500/20">
|
<div className="relative w-full shrink-0 overflow-hidden before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] before:border before:border-fuchsia-500 before:opacity-0 before:ring-2 before:ring-fuchsia-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[7px] after:shadow-highlight after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-fuchsia-500/100 dark:focus-within:after:shadow-fuchsia-500/20">
|
||||||
<input
|
<input
|
||||||
type={'text'}
|
type={'text'}
|
||||||
@ -100,7 +110,7 @@ export const CreateChannelModal = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<label className="text-xs font-semibold uppercase tracking-wider text-zinc-300">About</label>
|
<label className="text-xs font-semibold uppercase tracking-wider text-zinc-400">Description</label>
|
||||||
<div className="relative h-20 w-full shrink-0 overflow-hidden before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] before:border before:border-fuchsia-500 before:opacity-0 before:ring-2 before:ring-fuchsia-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[7px] after:shadow-highlight after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-fuchsia-500/100 dark:focus-within:after:shadow-fuchsia-500/20">
|
<div className="relative h-20 w-full shrink-0 overflow-hidden before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] before:border before:border-fuchsia-500 before:opacity-0 before:ring-2 before:ring-fuchsia-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[7px] after:shadow-highlight after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-fuchsia-500/100 dark:focus-within:after:shadow-fuchsia-500/20">
|
||||||
<textarea
|
<textarea
|
||||||
{...register('about')}
|
{...register('about')}
|
||||||
@ -109,6 +119,31 @@ export const CreateChannelModal = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex h-14 items-center justify-between gap-1 rounded-lg bg-zinc-800 px-4 py-2">
|
||||||
|
<div className="flex flex-col gap-0.5">
|
||||||
|
<div className="inline-flex items-center gap-1">
|
||||||
|
<span className="text-sm font-bold leading-none text-zinc-200">Make Private</span>
|
||||||
|
<div className="inline-flex items-center rounded-md bg-zinc-400/10 px-2 py-0.5 text-xs font-medium ring-1 ring-inset ring-zinc-400/20">
|
||||||
|
<span className="bg-gradient-to-r from-fuchsia-300 via-orange-100 to-amber-300 bg-clip-text text-transparent">
|
||||||
|
Coming soon
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm leading-none text-zinc-400">
|
||||||
|
Private channels can only be viewed by member
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
disabled
|
||||||
|
className="relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent bg-zinc-900 transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-fuchsia-600 focus:ring-offset-2"
|
||||||
|
role="switch"
|
||||||
|
aria-checked="false"
|
||||||
|
>
|
||||||
|
<span className="pointer-events-none inline-block h-5 w-5 translate-x-0 transform rounded-full bg-zinc-600 shadow ring-0 transition duration-200 ease-in-out"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
|
31
src/components/layouts/channel.tsx
Normal file
31
src/components/layouts/channel.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import AppHeader from '@components/appHeader';
|
||||||
|
import MultiAccounts from '@components/multiAccounts';
|
||||||
|
import Navigation from '@components/navigation';
|
||||||
|
|
||||||
|
export default function ChannelLayout({ children }: { children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<div className="h-screen w-screen bg-zinc-50 text-zinc-900 dark:bg-black dark:text-white">
|
||||||
|
<div className="flex h-screen w-full flex-col">
|
||||||
|
<div
|
||||||
|
data-tauri-drag-region
|
||||||
|
className="relative h-11 shrink-0 border-b border-zinc-100 bg-white dark:border-zinc-900 dark:bg-black"
|
||||||
|
>
|
||||||
|
<AppHeader collector={true} />
|
||||||
|
</div>
|
||||||
|
<div className="relative flex min-h-0 w-full flex-1">
|
||||||
|
<div className="relative w-[68px] shrink-0 border-r border-zinc-900">
|
||||||
|
<MultiAccounts />
|
||||||
|
</div>
|
||||||
|
<div className="grid w-full grid-cols-4 xl:grid-cols-5">
|
||||||
|
<div className="scrollbar-hide col-span-1 overflow-y-auto overflow-x-hidden border-r border-zinc-900">
|
||||||
|
<Navigation />
|
||||||
|
</div>
|
||||||
|
<div className="col-span-3 m-3 overflow-hidden xl:col-span-4 xl:mr-1.5">
|
||||||
|
<div className="h-full w-full rounded-lg">{children}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
import NewsfeedLayout from '@components/layouts/newsfeed';
|
|
||||||
|
|
||||||
export function Page() {
|
|
||||||
return (
|
|
||||||
<NewsfeedLayout>
|
|
||||||
<h1>TODO</h1>
|
|
||||||
</NewsfeedLayout>
|
|
||||||
);
|
|
||||||
}
|
|
@ -2,7 +2,6 @@ import { RelayContext } from '@components/relaysProvider';
|
|||||||
|
|
||||||
import { dateToUnix, hoursAgo } from '@utils/getDate';
|
import { dateToUnix, hoursAgo } from '@utils/getDate';
|
||||||
import {
|
import {
|
||||||
countTotalChannels,
|
|
||||||
countTotalNotes,
|
countTotalNotes,
|
||||||
createChannel,
|
createChannel,
|
||||||
createChat,
|
createChat,
|
||||||
@ -30,7 +29,6 @@ export function Page() {
|
|||||||
async (account: { id: number; pubkey: string; chats: string[] }, tags: any) => {
|
async (account: { id: number; pubkey: string; chats: string[] }, tags: any) => {
|
||||||
const lastLogin = await getLastLogin();
|
const lastLogin = await getLastLogin();
|
||||||
const notes = await countTotalNotes();
|
const notes = await countTotalNotes();
|
||||||
const channels = await countTotalChannels();
|
|
||||||
|
|
||||||
const chats = account.chats?.length || 0;
|
const chats = account.chats?.length || 0;
|
||||||
const follows = JSON.parse(tags);
|
const follows = JSON.parse(tags);
|
||||||
@ -64,6 +62,7 @@ export function Page() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
// kind 40 (channels) query
|
// kind 40 (channels) query
|
||||||
|
/*
|
||||||
if (channels.total === 0) {
|
if (channels.total === 0) {
|
||||||
query.push({
|
query.push({
|
||||||
kinds: [40],
|
kinds: [40],
|
||||||
@ -71,6 +70,7 @@ export function Page() {
|
|||||||
until: dateToUnix(now.current),
|
until: dateToUnix(now.current),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// subscribe relays
|
// subscribe relays
|
||||||
const unsubscribe = pool.subscribe(
|
const unsubscribe = pool.subscribe(
|
||||||
query,
|
query,
|
||||||
|
Loading…
Reference in New Issue
Block a user