wip: timeline
This commit is contained in:
@@ -59,6 +59,13 @@ const router = createBrowserRouter([
|
||||
return { Component: SpaceScreen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'timeline',
|
||||
async lazy() {
|
||||
const { TimelineScreen } = await import('@app/timeline');
|
||||
return { Component: TimelineScreen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'users/:pubkey',
|
||||
async lazy() {
|
||||
|
||||
@@ -11,7 +11,7 @@ export function ChatsListItem({ pubkey }: { pubkey: string }) {
|
||||
|
||||
if (status === 'loading') {
|
||||
return (
|
||||
<div className="inline-flex h-10 items-center gap-2.5 rounded-md px-2">
|
||||
<div className="inline-flex h-10 items-center gap-2.5 rounded-md px-3">
|
||||
<div className="relative h-7 w-7 shrink-0 animate-pulse rounded bg-white/10 backdrop-blur-xl" />
|
||||
<div className="h-2.5 w-2/3 animate-pulse rounded bg-white/10 backdrop-blur-xl" />
|
||||
</div>
|
||||
@@ -24,7 +24,7 @@ export function ChatsListItem({ pubkey }: { pubkey: string }) {
|
||||
preventScrollReset={true}
|
||||
className={({ isActive }) =>
|
||||
twMerge(
|
||||
'flex h-10 items-center gap-2.5 rounded-r-lg border-l-2 pl-4 pr-2',
|
||||
'flex h-10 items-center gap-2.5 rounded-r-lg border-l-2 pl-4 pr-3',
|
||||
isActive
|
||||
? 'border-fuchsia-500 bg-white/5 text-white'
|
||||
: 'border-transparent text-white/70'
|
||||
|
||||
@@ -23,7 +23,7 @@ export function NewMessageModal() {
|
||||
<Dialog.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-10 items-center gap-2.5 rounded-r-lg border-l-2 border-transparent pl-4 pr-2"
|
||||
className="inline-flex h-10 items-center gap-2.5 rounded-r-lg border-l-2 border-transparent pl-4 pr-3"
|
||||
>
|
||||
<div className="inline-flex h-7 w-7 shrink-0 items-center justify-center rounded bg-white/10 backdrop-blur-xl">
|
||||
<PlusIcon className="h-4 w-4 text-white" />
|
||||
|
||||
@@ -21,7 +21,7 @@ export function UnknownsModal({ data }: { data: string[] }) {
|
||||
<Dialog.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-10 items-center gap-2.5 rounded-r-lg border-l-2 border-transparent pl-4 pr-2"
|
||||
className="inline-flex h-10 items-center gap-2.5 rounded-r-lg border-l-2 border-transparent pl-4 pr-3"
|
||||
>
|
||||
<div className="inline-flex h-7 w-7 shrink-0 items-center justify-center rounded bg-white/10 backdrop-blur-xl">
|
||||
<StrangersIcon className="h-4 w-4 text-white" />
|
||||
|
||||
7
src/app/timeline/index.tsx
Normal file
7
src/app/timeline/index.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
export function TimelineScreen() {
|
||||
return (
|
||||
<div>
|
||||
<p>TODO</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
import { NDKFilter, NDKKind } from '@nostr-dev-kit/ndk';
|
||||
import { useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { AccountMoreActions } from '@shared/accounts/more';
|
||||
import { SettingsIcon } from '@shared/icons';
|
||||
import { Image } from '@shared/image';
|
||||
import { Logout } from '@shared/logout';
|
||||
|
||||
import { useActivities } from '@stores/activities';
|
||||
|
||||
@@ -63,23 +65,31 @@ export function ActiveAccount() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-16 items-center justify-between border-l-2 border-transparent pb-2 pl-4 pr-2">
|
||||
<div className="flex items-center gap-2.5">
|
||||
<div className="flex h-16 items-center justify-between border-l-2 border-transparent pb-2 pl-4 pr-3">
|
||||
<Link to={`/users/${db.account.pubkey}`} className="flex items-center gap-1.5">
|
||||
<Image
|
||||
src={user?.picture || user?.image}
|
||||
alt={db.account.npub}
|
||||
className="h-10 w-10 shrink-0 rounded-lg object-cover"
|
||||
className="h-9 w-9 shrink-0 rounded-lg object-cover"
|
||||
/>
|
||||
<div className="flex w-full flex-1 flex-col items-start gap-1.5">
|
||||
<p className="max-w-[10rem] truncate font-bold leading-none text-white">
|
||||
<div className="flex w-full flex-1 flex-col items-start gap-0.5">
|
||||
<p className="max-w-[10rem] truncate font-semibold leading-none text-white">
|
||||
{user?.name || user?.display_name}
|
||||
</p>
|
||||
<span className="max-w-[8rem] truncate text-sm leading-none text-white/50">
|
||||
{displayNpub(db.account.pubkey, 16)}
|
||||
<span className="max-w-[7rem] truncate text-sm leading-none text-white/50">
|
||||
{user?.nip05 || displayNpub(db.account.pubkey, 12)}
|
||||
</span>
|
||||
</div>
|
||||
</Link>
|
||||
<div className="inline-flex divide-x divide-white/5 rounded-lg border-t border-white/10 bg-white/20">
|
||||
<Link
|
||||
to="/settings/"
|
||||
className="inline-flex h-9 w-9 items-center justify-center hover:bg-white/10"
|
||||
>
|
||||
<SettingsIcon className="h-4 w-4 text-white" />
|
||||
</Link>
|
||||
<Logout />
|
||||
</div>
|
||||
<AccountMoreActions pubkey={db.account.pubkey} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -28,12 +28,10 @@ export function ComposerModal() {
|
||||
<Dialog.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="flex h-10 items-center gap-2.5 rounded-r-lg border-l-2 border-transparent pl-4 pr-2 text-white/80"
|
||||
className="flex h-9 items-center gap-2 rounded-full border-t border-white/10 bg-white/20 px-4 text-sm font-semibold leading-none text-white/80 hover:bg-fuchsia-500 hover:text-white"
|
||||
>
|
||||
<span className="inline-flex h-7 w-7 shrink-0 items-center justify-center rounded bg-white/10 backdrop-blur-xl">
|
||||
<ComposeIcon className="h-4 w-4 text-white" />
|
||||
</span>
|
||||
New postr
|
||||
New
|
||||
<ComposeIcon className="h-4 w-4 text-white" />
|
||||
</button>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Portal className="relative z-10">
|
||||
|
||||
@@ -64,3 +64,4 @@ export * from './follows';
|
||||
export * from './alby';
|
||||
export * from './stars';
|
||||
export * from './nwc';
|
||||
export * from './timeline';
|
||||
|
||||
22
src/shared/icons/timeline.tsx
Normal file
22
src/shared/icons/timeline.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { SVGProps } from 'react';
|
||||
|
||||
export function TimeLineIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
d="M22.25 15C17.215 15 15 17.215 15 22.25 15 17.215 12.785 15 7.75 15 12.785 15 15 12.785 15 7.75c0 5.035 2.215 7.25 7.25 7.25zM11.25 6.5c-3.299 0-4.75 1.451-4.75 4.75 0-3.299-1.451-4.75-4.75-4.75 3.299 0 4.75-1.451 4.75-4.75 0 3.299 1.451 4.75 4.75 4.75z"
|
||||
clipRule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -3,6 +3,8 @@ import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { LogoutIcon } from '@shared/icons';
|
||||
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
export function Logout() {
|
||||
@@ -25,9 +27,9 @@ export function Logout() {
|
||||
<AlertDialog.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-10 items-center rounded-lg px-2 text-sm font-medium text-white hover:bg-white/10"
|
||||
className="inline-flex h-9 w-9 items-center justify-center hover:bg-white/10"
|
||||
>
|
||||
Logout
|
||||
<LogoutIcon className="h-4 w-4 text-white" />
|
||||
</button>
|
||||
</AlertDialog.Trigger>
|
||||
<AlertDialog.Portal className="relative z-10">
|
||||
|
||||
@@ -4,12 +4,16 @@ import { twMerge } from 'tailwind-merge';
|
||||
|
||||
import { ChatsList } from '@app/chats/components/list';
|
||||
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { ActiveAccount } from '@shared/accounts/active';
|
||||
import { ComposerModal } from '@shared/composer';
|
||||
import { Frame } from '@shared/frame';
|
||||
import { BellIcon, NavArrowDownIcon, NwcIcon, SpaceIcon } from '@shared/icons';
|
||||
import {
|
||||
BellIcon,
|
||||
NavArrowDownIcon,
|
||||
NwcIcon,
|
||||
SpaceIcon,
|
||||
TimeLineIcon,
|
||||
} from '@shared/icons';
|
||||
|
||||
import { useActivities } from '@stores/activities';
|
||||
import { useSidebar } from '@stores/sidebar';
|
||||
@@ -17,8 +21,6 @@ import { useSidebar } from '@stores/sidebar';
|
||||
import { compactNumber } from '@utils/number';
|
||||
|
||||
export function Navigation() {
|
||||
const { db } = useStorage();
|
||||
|
||||
const [totalNewActivities] = useActivities((state) => [state.totalNewActivities]);
|
||||
const [chats, toggleChats] = useSidebar((state) => [state.chats, state.toggleChats]);
|
||||
const [integrations, toggleIntegrations] = useSidebar((state) => [
|
||||
@@ -28,18 +30,37 @@ export function Navigation() {
|
||||
|
||||
return (
|
||||
<Frame className="relative flex h-full w-[232px] flex-col" lighter>
|
||||
{db.platform === 'darwin' ? (
|
||||
<div data-tauri-drag-region className="h-11 w-full shrink-0" />
|
||||
) : null}
|
||||
<div className="scrollbar-hide flex h-full flex-1 flex-col gap-6 overflow-y-auto pb-32">
|
||||
<div className="flex flex-col pr-2">
|
||||
<ComposerModal />
|
||||
<div className="inline-flex h-16 w-full items-center justify-end px-3">
|
||||
<ComposerModal />
|
||||
</div>
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
className="scrollbar-hide flex h-full flex-1 flex-col gap-6 overflow-y-auto pb-32"
|
||||
>
|
||||
<div className="flex flex-col pr-3">
|
||||
<NavLink
|
||||
to="/timeline"
|
||||
preventScrollReset={true}
|
||||
className={({ isActive }) =>
|
||||
twMerge(
|
||||
'flex h-10 items-center gap-2.5 rounded-r-lg border-l-2 pl-4 pr-3',
|
||||
isActive
|
||||
? 'border-fuchsia-500 bg-white/5 text-white'
|
||||
: 'border-transparent text-white/70'
|
||||
)
|
||||
}
|
||||
>
|
||||
<span className="inline-flex h-7 w-7 shrink-0 items-center justify-center rounded bg-white/10 backdrop-blur-xl">
|
||||
<TimeLineIcon className="h-4 w-4 text-white" />
|
||||
</span>
|
||||
Timeline
|
||||
</NavLink>
|
||||
<NavLink
|
||||
to="/"
|
||||
preventScrollReset={true}
|
||||
className={({ isActive }) =>
|
||||
twMerge(
|
||||
'flex h-10 items-center gap-2.5 rounded-r-lg border-l-2 pl-4 pr-2',
|
||||
'flex h-10 items-center gap-2.5 rounded-r-lg border-l-2 pl-4 pr-3',
|
||||
isActive
|
||||
? 'border-fuchsia-500 bg-white/5 text-white'
|
||||
: 'border-transparent text-white/70'
|
||||
@@ -56,7 +77,7 @@ export function Navigation() {
|
||||
preventScrollReset={true}
|
||||
className={({ isActive }) =>
|
||||
twMerge(
|
||||
'flex h-10 items-center justify-between rounded-r-lg border-l-2 pl-4 pr-2',
|
||||
'flex h-10 items-center justify-between rounded-r-lg border-l-2 pl-4 pr-3',
|
||||
isActive
|
||||
? 'border-fuchsia-500 bg-white/5 text-white'
|
||||
: 'border-transparent text-white/70'
|
||||
@@ -81,7 +102,7 @@ export function Navigation() {
|
||||
</NavLink>
|
||||
</div>
|
||||
<Collapsible.Root open={integrations} onOpenChange={toggleIntegrations}>
|
||||
<div className="flex flex-col gap-1 pr-2">
|
||||
<div className="flex flex-col gap-1 pr-3">
|
||||
<Collapsible.Trigger asChild>
|
||||
<button className="flex items-center gap-1 pl-[20px] pr-4">
|
||||
<div
|
||||
@@ -103,7 +124,7 @@ export function Navigation() {
|
||||
preventScrollReset={true}
|
||||
className={({ isActive }) =>
|
||||
twMerge(
|
||||
'flex h-10 items-center gap-2.5 rounded-r-lg border-l-2 pl-4 pr-2',
|
||||
'flex h-10 items-center gap-2.5 rounded-r-lg border-l-2 pl-4 pr-3',
|
||||
isActive
|
||||
? 'border-fuchsia-500 bg-white/5 text-white'
|
||||
: 'border-transparent text-white/70'
|
||||
@@ -119,7 +140,7 @@ export function Navigation() {
|
||||
</div>
|
||||
</Collapsible.Root>
|
||||
<Collapsible.Root open={chats} onOpenChange={toggleChats}>
|
||||
<div className="flex flex-col gap-1 pr-2">
|
||||
<div className="flex flex-col gap-1 pr-3">
|
||||
<Collapsible.Trigger asChild>
|
||||
<button className="flex items-center gap-1 pl-[20px] pr-4">
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user