resizable widget

This commit is contained in:
Ren Amamiya
2023-09-20 14:31:14 +07:00
parent 296136203a
commit 0e5adb246f
18 changed files with 141 additions and 37 deletions

View File

@@ -7,6 +7,7 @@ import { useNDK } from '@libs/ndk/provider';
import { ArticleNote, NoteSkeleton, NoteWrapper } from '@shared/notes';
import { TitleBar } from '@shared/titleBar';
import { WidgetWrapper } from '@shared/widgets';
import { Widget } from '@utils/types';
@@ -51,7 +52,7 @@ export function GlobalArticlesWidget({ params }: { params: Widget }) {
);
return (
<div className="relative shrink-0 grow-0 basis-[400px] bg-white/10 backdrop-blur-xl">
<WidgetWrapper>
<TitleBar id={params.id} title={params.title} />
<div ref={parentRef} className="scrollbar-hide h-full overflow-y-auto pb-20">
{status === 'loading' ? (
@@ -89,6 +90,6 @@ export function GlobalArticlesWidget({ params }: { params: Widget }) {
</div>
)}
</div>
</div>
</WidgetWrapper>
);
}

View File

@@ -7,6 +7,7 @@ import { useNDK } from '@libs/ndk/provider';
import { FileNote, NoteSkeleton, NoteWrapper } from '@shared/notes';
import { TitleBar } from '@shared/titleBar';
import { WidgetWrapper } from '@shared/widgets';
import { Widget } from '@utils/types';
@@ -52,7 +53,7 @@ export function GlobalFilesWidget({ params }: { params: Widget }) {
);
return (
<div className="relative shrink-0 grow-0 basis-[400px] bg-white/10 backdrop-blur-xl">
<WidgetWrapper>
<TitleBar id={params.id} title={params.title} />
<div ref={parentRef} className="scrollbar-hide h-full overflow-y-auto pb-20">
{status === 'loading' ? (
@@ -90,6 +91,6 @@ export function GlobalFilesWidget({ params }: { params: Widget }) {
</div>
)}
</div>
</div>
</WidgetWrapper>
);
}

View File

@@ -15,6 +15,7 @@ import {
UnknownNote,
} from '@shared/notes';
import { TitleBar } from '@shared/titleBar';
import { WidgetWrapper } from '@shared/widgets';
import { nHoursAgo } from '@utils/date';
import { Widget } from '@utils/types';
@@ -114,7 +115,7 @@ export function GlobalHashtagWidget({ params }: { params: Widget }) {
);
return (
<div className="relative shrink-0 grow-0 basis-[400px] bg-white/10 backdrop-blur-xl">
<WidgetWrapper>
<TitleBar id={params.id} title={params.title + ' in 24 hours ago'} />
<div ref={parentRef} className="scrollbar-hide h-full overflow-y-auto pb-20">
{status === 'loading' ? (
@@ -152,6 +153,6 @@ export function GlobalHashtagWidget({ params }: { params: Widget }) {
</div>
)}
</div>
</div>
</WidgetWrapper>
);
}

View File

@@ -1,3 +1,4 @@
export * from './wrapper';
export * from './local/feeds';
export * from './local/network';
export * from './local/user';

View File

@@ -8,6 +8,7 @@ import { useStorage } from '@libs/storage/provider';
import { ArrowRightCircleIcon, LoaderIcon } from '@shared/icons';
import { FileNote, NoteSkeleton, NoteWrapper } from '@shared/notes';
import { TitleBar } from '@shared/titleBar';
import { WidgetWrapper } from '@shared/widgets';
import { DBEvent, Widget } from '@utils/types';
@@ -53,7 +54,7 @@ export function LocalArticlesWidget({ params }: { params: Widget }) {
);
return (
<div className="relative shrink-0 grow-0 basis-[400px] bg-white/10 backdrop-blur-xl">
<WidgetWrapper>
<TitleBar id={params.id} title={params.title} />
<div ref={parentRef} className="scrollbar-hide h-full overflow-y-auto pb-20">
{status === 'loading' ? (
@@ -125,6 +126,6 @@ export function LocalArticlesWidget({ params }: { params: Widget }) {
</button>
</div>
</div>
</div>
</WidgetWrapper>
);
}

View File

@@ -16,6 +16,7 @@ import {
} from '@shared/notes';
import { NoteSkeleton } from '@shared/notes/skeleton';
import { TitleBar } from '@shared/titleBar';
import { WidgetWrapper } from '@shared/widgets';
import { DBEvent, Widget } from '@utils/types';
@@ -116,7 +117,7 @@ export function LocalFeedsWidget({ params }: { params: Widget }) {
);
return (
<div className="relative shrink-0 grow-0 basis-[400px] bg-white/10 backdrop-blur-xl">
<WidgetWrapper>
<TitleBar id={params.id} title={params.title} />
<div ref={parentRef} className="scrollbar-hide h-full overflow-y-auto pb-20">
{status === 'loading' ? (
@@ -188,6 +189,6 @@ export function LocalFeedsWidget({ params }: { params: Widget }) {
</button>
</div>
</div>
</div>
</WidgetWrapper>
);
}

View File

@@ -8,6 +8,7 @@ import { useStorage } from '@libs/storage/provider';
import { ArrowRightCircleIcon, LoaderIcon } from '@shared/icons';
import { FileNote, NoteSkeleton, NoteWrapper } from '@shared/notes';
import { TitleBar } from '@shared/titleBar';
import { WidgetWrapper } from '@shared/widgets';
import { DBEvent, Widget } from '@utils/types';
@@ -53,7 +54,7 @@ export function LocalFilesWidget({ params }: { params: Widget }) {
);
return (
<div className="relative shrink-0 grow-0 basis-[400px] bg-white/10 backdrop-blur-xl">
<WidgetWrapper>
<TitleBar id={params.id} title={params.title} />
<div ref={parentRef} className="scrollbar-hide h-full overflow-y-auto pb-20">
{status === 'loading' ? (
@@ -125,6 +126,6 @@ export function LocalFilesWidget({ params }: { params: Widget }) {
</button>
</div>
</div>
</div>
</WidgetWrapper>
);
}

View File

@@ -16,6 +16,7 @@ import {
} from '@shared/notes';
import { NoteSkeleton } from '@shared/notes/skeleton';
import { TitleBar } from '@shared/titleBar';
import { WidgetWrapper } from '@shared/widgets';
import { DBEvent, Widget } from '@utils/types';
@@ -115,7 +116,7 @@ export function LocalFollowsWidget({ params }: { params: Widget }) {
);
return (
<div className="relative shrink-0 grow-0 basis-[400px] bg-white/10 backdrop-blur-xl">
<WidgetWrapper>
<TitleBar id={params.id} title="Follows" />
<div ref={parentRef} className="scrollbar-hide h-full overflow-y-auto pb-20">
{status === 'loading' ? (
@@ -193,6 +194,6 @@ export function LocalFollowsWidget({ params }: { params: Widget }) {
) : null}
</div>
</div>
</div>
</WidgetWrapper>
);
}

View File

@@ -16,6 +16,7 @@ import {
} from '@shared/notes';
import { NoteSkeleton } from '@shared/notes/skeleton';
import { TitleBar } from '@shared/titleBar';
import { WidgetWrapper } from '@shared/widgets';
import { useNostr } from '@utils/hooks/useNostr';
import { toRawEvent } from '@utils/rawEvent';
@@ -127,19 +128,15 @@ export function LocalNetworkWidget() {
since: db.account.last_login_at ?? Math.floor(Date.now() / 1000),
};
sub(
filter,
async (event) => {
const rawEvent = toRawEvent(event);
await db.createEvent(rawEvent);
},
false // don't close sub on eose
);
sub(filter, async (event) => {
const rawEvent = toRawEvent(event);
await db.createEvent(rawEvent);
});
}
}, []);
return (
<div className="relative shrink-0 grow-0 basis-[400px] bg-white/10 backdrop-blur-xl">
<WidgetWrapper>
<TitleBar title="👋 Network" />
<div ref={parentRef} className="scrollbar-hide h-full overflow-y-auto pb-20">
{status === 'loading' ? (
@@ -217,6 +214,6 @@ export function LocalNetworkWidget() {
) : null}
</div>
</div>
</div>
</WidgetWrapper>
);
}

View File

@@ -16,6 +16,7 @@ import { RepliesList } from '@shared/notes/replies/list';
import { NoteSkeleton } from '@shared/notes/skeleton';
import { TitleBar } from '@shared/titleBar';
import { User } from '@shared/user';
import { WidgetWrapper } from '@shared/widgets';
import { useEvent } from '@utils/hooks/useEvent';
import { Widget } from '@utils/types';
@@ -41,7 +42,7 @@ export function LocalThreadWidget({ params }: { params: Widget }) {
);
return (
<div className="scrollbar-hide relative shrink-0 grow-0 basis-[400px] overflow-y-auto bg-white/10 backdrop-blur-xl">
<WidgetWrapper>
<TitleBar id={params.id} title={params.title} />
<div className="h-full">
{status === 'loading' ? (
@@ -69,6 +70,6 @@ export function LocalThreadWidget({ params }: { params: Widget }) {
<RepliesList id={params.content} />
</div>
</div>
</div>
</WidgetWrapper>
);
}

View File

@@ -16,6 +16,7 @@ import {
} from '@shared/notes';
import { TitleBar } from '@shared/titleBar';
import { UserProfile } from '@shared/userProfile';
import { WidgetWrapper } from '@shared/widgets';
import { nHoursAgo } from '@utils/date';
import { Widget } from '@utils/types';
@@ -120,7 +121,7 @@ export function LocalUserWidget({ params }: { params: Widget }) {
);
return (
<div className="relative shrink-0 grow-0 basis-[400px] bg-white/10 backdrop-blur-xl">
<WidgetWrapper>
<TitleBar id={params.id} title={params.title} />
<div ref={parentRef} className="scrollbar-hide h-full overflow-y-auto pb-20">
<div className="px-3 pt-1.5">
@@ -166,6 +167,6 @@ export function LocalUserWidget({ params }: { params: Widget }) {
</div>
</div>
</div>
</div>
</WidgetWrapper>
);
}

View File

@@ -2,6 +2,7 @@ import { useQuery } from '@tanstack/react-query';
import { NoteSkeleton } from '@shared/notes/skeleton';
import { TitleBar } from '@shared/titleBar';
import { WidgetWrapper } from '@shared/widgets';
import { NostrBandUserProfile, type Profile } from '@shared/widgets/nostrBandUserProfile';
import { Widget } from '@utils/types';
@@ -31,7 +32,7 @@ export function TrendingAccountsWidget({ params }: { params: Widget }) {
);
return (
<div className="relative shrink-0 grow-0 basis-[400px] bg-white/10 backdrop-blur-xl">
<WidgetWrapper>
<TitleBar id={params.id} title="Trending Accounts" />
<div className="scrollbar-hide h-full max-w-full overflow-y-auto pb-20">
{status === 'loading' ? (
@@ -56,6 +57,6 @@ export function TrendingAccountsWidget({ params }: { params: Widget }) {
</div>
)}
</div>
</div>
</WidgetWrapper>
);
}

View File

@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query';
import { NoteSkeleton, NoteWrapper, TextNote } from '@shared/notes';
import { TitleBar } from '@shared/titleBar';
import { WidgetWrapper } from '@shared/widgets';
import { Widget } from '@utils/types';
@@ -31,7 +32,7 @@ export function TrendingNotesWidget({ params }: { params: Widget }) {
);
return (
<div className="relative shrink-0 grow-0 basis-[400px] bg-white/10 backdrop-blur-xl">
<WidgetWrapper>
<TitleBar id={params.id} title="Trending Notes" />
<div className="scrollbar-hide h-full max-w-full overflow-y-auto pb-20">
{status === 'loading' ? (
@@ -58,6 +59,6 @@ export function TrendingNotesWidget({ params }: { params: Widget }) {
</div>
)}
</div>
</div>
</WidgetWrapper>
);
}

View File

@@ -2,6 +2,7 @@ import { useNavigate } from 'react-router-dom';
import { ArrowRightIcon } from '@shared/icons';
import { TitleBar } from '@shared/titleBar';
import { WidgetWrapper } from '@shared/widgets';
import { useResources } from '@stores/resources';
@@ -21,7 +22,7 @@ export function LearnNostrWidget({ params }: { params: Widget }) {
};
return (
<div className="relative shrink-0 grow-0 basis-[400px] bg-white/10 backdrop-blur-xl">
<WidgetWrapper>
<TitleBar id={params.id} title="The Joy of Nostr" />
<div className="scrollbar-hide h-full overflow-y-auto px-3 pb-20">
{resources.map((resource, index) => (
@@ -58,6 +59,6 @@ export function LearnNostrWidget({ params }: { params: Widget }) {
</div>
))}
</div>
</div>
</WidgetWrapper>
);
}

View File

@@ -0,0 +1,32 @@
import { Resizable } from 're-resizable';
import { ReactNode, useState } from 'react';
import { twMerge } from 'tailwind-merge';
export function WidgetWrapper({
children,
className,
}: {
children: ReactNode;
className?: string;
}) {
const [width, setWidth] = useState(400);
return (
<Resizable
size={{ width: width, height: '100vh' }}
onResizeStart={(e) => e.preventDefault()}
onResizeStop={(e, direction, ref, d) => {
setWidth((prevWidth) => prevWidth + d.width);
}}
minWidth={400}
minHeight={'100vh'}
className={twMerge(
'relative shrink-0 grow-0 basis-[400px] bg-white/10 backdrop-blur-xl',
className
)}
enable={{ right: true }}
>
{children}
</Resizable>
);
}

View File

@@ -10,6 +10,7 @@ interface WidgetState {
fetchWidgets: (db: LumeStorage) => void;
setWidget: (db: LumeStorage, { kind, title, content }: Widget) => void;
removeWidget: (db: LumeStorage, id: string) => void;
reorderWidget: (id: string, position: number) => void;
}
export const WidgetKinds = {
@@ -141,6 +142,18 @@ export const useWidgets = create<WidgetState>()(
await db.removeWidget(id);
set((state) => ({ widgets: state.widgets.filter((widget) => widget.id !== id) }));
},
reorderWidget: (id: string, position: number) =>
set((state) => {
const widgets = [...state.widgets];
const widget = widgets.find((widget) => widget.id === id);
if (!widget) return { widgets };
const idx = widgets.indexOf(widget);
widgets.splice(idx, 1);
widgets.splice(position, 0, widget);
return { widgets };
}),
}),
{
name: 'widgets',