From 0e5adb246fd03e403684ea9b4ed531ec48ff5185 Mon Sep 17 00:00:00 2001 From: Ren Amamiya <123083837+reyamir@users.noreply.github.com> Date: Wed, 20 Sep 2023 14:31:14 +0700 Subject: [PATCH] resizable widget --- package.json | 2 + pnpm-lock.yaml | 53 +++++++++++++++++-- src/shared/widgets/global/articles.tsx | 5 +- src/shared/widgets/global/files.tsx | 5 +- src/shared/widgets/global/hashtag.tsx | 5 +- src/shared/widgets/index.ts | 1 + src/shared/widgets/local/articles.tsx | 5 +- src/shared/widgets/local/feeds.tsx | 5 +- src/shared/widgets/local/files.tsx | 5 +- src/shared/widgets/local/follows.tsx | 5 +- src/shared/widgets/local/network.tsx | 17 +++--- src/shared/widgets/local/thread.tsx | 5 +- src/shared/widgets/local/user.tsx | 5 +- .../widgets/nostrBand/trendingAccounts.tsx | 5 +- .../widgets/nostrBand/trendingNotes.tsx | 5 +- src/shared/widgets/other/learnNostr.tsx | 5 +- src/shared/widgets/wrapper.tsx | 32 +++++++++++ src/stores/widgets.ts | 13 +++++ 18 files changed, 141 insertions(+), 37 deletions(-) create mode 100644 src/shared/widgets/wrapper.tsx diff --git a/package.json b/package.json index 7a0ea3e9..933b4147 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "**/*.{ts, tsx, css, md, html, json}": "prettier --cache --write" }, "dependencies": { + "@dnd-kit/core": "^6.0.8", "@getalby/sdk": "^2.4.0", "@nostr-dev-kit/ndk": "^1.2.1", "@nostr-fetch/adapter-ndk": "^0.12.2", @@ -47,6 +48,7 @@ "nostr-fetch": "^0.13.0", "nostr-tools": "^1.15.0", "qrcode.react": "^3.1.0", + "re-resizable": "^6.9.11", "react": "^18.2.0", "react-currency-input-field": "^3.6.11", "react-dom": "^18.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fc164463..817f014b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,9 @@ settings: excludeLinksFromLockfile: false dependencies: + '@dnd-kit/core': + specifier: ^6.0.8 + version: 6.0.8(react-dom@18.2.0)(react@18.2.0) '@getalby/sdk': specifier: ^2.4.0 version: 2.4.0 @@ -92,6 +95,9 @@ dependencies: qrcode.react: specifier: ^3.1.0 version: 3.1.0(react@18.2.0) + re-resizable: + specifier: ^6.9.11 + version: 6.9.11(react-dom@18.2.0)(react@18.2.0) react: specifier: ^18.2.0 version: 18.2.0 @@ -124,7 +130,7 @@ dependencies: version: 3.0.1 tauri-plugin-sql-api: specifier: github:tauri-apps/tauri-plugin-sql#v1 - version: github.com/tauri-apps/tauri-plugin-sql/b8fd19dac907cc8c3d78681cd4803a326b8b861e + version: github.com/tauri-apps/tauri-plugin-sql/26467343db277e79daf3a216372ba25e1fec0deb tauri-plugin-store-api: specifier: github:tauri-apps/tauri-plugin-store#v1 version: github.com/tauri-apps/tauri-plugin-store/a65ce9bfb168a9a3cd7ed4102b9f22770cc3abfa @@ -369,6 +375,37 @@ packages: to-fast-properties: 2.0.0 dev: true + /@dnd-kit/accessibility@3.0.1(react@18.2.0): + resolution: {integrity: sha512-HXRrwS9YUYQO9lFRc/49uO/VICbM+O+ZRpFDe9Pd1rwVv2PCNkRiTZRdxrDgng/UkvdC3Re9r2vwPpXXrWeFzg==} + peerDependencies: + react: '>=16.8.0' + dependencies: + react: 18.2.0 + tslib: 2.6.2 + dev: false + + /@dnd-kit/core@6.0.8(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@dnd-kit/accessibility': 3.0.1(react@18.2.0) + '@dnd-kit/utilities': 3.2.1(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + tslib: 2.6.2 + dev: false + + /@dnd-kit/utilities@3.2.1(react@18.2.0): + resolution: {integrity: sha512-OOXqISfvBw/1REtkSK2N3Fi2EQiLMlWUlqnOK/UpOISqBZPWpE6TqL+jcPtMOkE8TqYGiURvRdPSI9hltNUjEA==} + peerDependencies: + react: '>=16.8.0' + dependencies: + react: 18.2.0 + tslib: 2.6.2 + dev: false + /@esbuild/android-arm64@0.18.20: resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} @@ -5134,6 +5171,16 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true + /re-resizable@6.9.11(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-a3hiLWck/NkmyLvGWUuvkAmN1VhwAz4yOhS6FdMTaxCUVN9joIWkT11wsO68coG/iEYuwn+p/7qAmfQzRhiPLQ==} + peerDependencies: + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /react-currency-input-field@3.6.11(react@18.2.0): resolution: {integrity: sha512-M9vOx1eaioSaYWirm7W2WSBi4bpLg+LK4Gf7C1kNhy6MvoSoOzd0mYZPxA78OC9UBIQ2nM080Wu9D1CwTY6n3w==} peerDependencies: @@ -6314,8 +6361,8 @@ packages: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} dev: false - github.com/tauri-apps/tauri-plugin-sql/b8fd19dac907cc8c3d78681cd4803a326b8b861e: - resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-sql/tar.gz/b8fd19dac907cc8c3d78681cd4803a326b8b861e} + github.com/tauri-apps/tauri-plugin-sql/26467343db277e79daf3a216372ba25e1fec0deb: + resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-sql/tar.gz/26467343db277e79daf3a216372ba25e1fec0deb} name: tauri-plugin-sql-api version: 0.0.0 dependencies: diff --git a/src/shared/widgets/global/articles.tsx b/src/shared/widgets/global/articles.tsx index c12f530e..fa19b01f 100644 --- a/src/shared/widgets/global/articles.tsx +++ b/src/shared/widgets/global/articles.tsx @@ -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 ( -
+
{status === 'loading' ? ( @@ -89,6 +90,6 @@ export function GlobalArticlesWidget({ params }: { params: Widget }) {
)}
- + ); } diff --git a/src/shared/widgets/global/files.tsx b/src/shared/widgets/global/files.tsx index d82857b7..56011e19 100644 --- a/src/shared/widgets/global/files.tsx +++ b/src/shared/widgets/global/files.tsx @@ -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 ( -
+
{status === 'loading' ? ( @@ -90,6 +91,6 @@ export function GlobalFilesWidget({ params }: { params: Widget }) {
)}
- + ); } diff --git a/src/shared/widgets/global/hashtag.tsx b/src/shared/widgets/global/hashtag.tsx index 7833c377..374b87c0 100644 --- a/src/shared/widgets/global/hashtag.tsx +++ b/src/shared/widgets/global/hashtag.tsx @@ -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 ( -
+
{status === 'loading' ? ( @@ -152,6 +153,6 @@ export function GlobalHashtagWidget({ params }: { params: Widget }) {
)}
- + ); } diff --git a/src/shared/widgets/index.ts b/src/shared/widgets/index.ts index 7b29f9d0..fd0dcdbf 100644 --- a/src/shared/widgets/index.ts +++ b/src/shared/widgets/index.ts @@ -1,3 +1,4 @@ +export * from './wrapper'; export * from './local/feeds'; export * from './local/network'; export * from './local/user'; diff --git a/src/shared/widgets/local/articles.tsx b/src/shared/widgets/local/articles.tsx index 11fecff0..fd49fc1e 100644 --- a/src/shared/widgets/local/articles.tsx +++ b/src/shared/widgets/local/articles.tsx @@ -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 ( -
+
{status === 'loading' ? ( @@ -125,6 +126,6 @@ export function LocalArticlesWidget({ params }: { params: Widget }) {
- + ); } diff --git a/src/shared/widgets/local/feeds.tsx b/src/shared/widgets/local/feeds.tsx index ac1dc890..23a4bf9a 100644 --- a/src/shared/widgets/local/feeds.tsx +++ b/src/shared/widgets/local/feeds.tsx @@ -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 ( -
+
{status === 'loading' ? ( @@ -188,6 +189,6 @@ export function LocalFeedsWidget({ params }: { params: Widget }) {
- + ); } diff --git a/src/shared/widgets/local/files.tsx b/src/shared/widgets/local/files.tsx index ec5f3ced..d8328cc0 100644 --- a/src/shared/widgets/local/files.tsx +++ b/src/shared/widgets/local/files.tsx @@ -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 ( -
+
{status === 'loading' ? ( @@ -125,6 +126,6 @@ export function LocalFilesWidget({ params }: { params: Widget }) {
- + ); } diff --git a/src/shared/widgets/local/follows.tsx b/src/shared/widgets/local/follows.tsx index 73810d4e..0d22b0f8 100644 --- a/src/shared/widgets/local/follows.tsx +++ b/src/shared/widgets/local/follows.tsx @@ -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 ( -
+
{status === 'loading' ? ( @@ -193,6 +194,6 @@ export function LocalFollowsWidget({ params }: { params: Widget }) { ) : null}
- + ); } diff --git a/src/shared/widgets/local/network.tsx b/src/shared/widgets/local/network.tsx index 68aa833e..fd177ad1 100644 --- a/src/shared/widgets/local/network.tsx +++ b/src/shared/widgets/local/network.tsx @@ -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 ( -
+
{status === 'loading' ? ( @@ -217,6 +214,6 @@ export function LocalNetworkWidget() { ) : null}
- + ); } diff --git a/src/shared/widgets/local/thread.tsx b/src/shared/widgets/local/thread.tsx index 1d754610..8236e558 100644 --- a/src/shared/widgets/local/thread.tsx +++ b/src/shared/widgets/local/thread.tsx @@ -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 ( -
+
{status === 'loading' ? ( @@ -69,6 +70,6 @@ export function LocalThreadWidget({ params }: { params: Widget }) {
- + ); } diff --git a/src/shared/widgets/local/user.tsx b/src/shared/widgets/local/user.tsx index 4266d76c..fc920bc9 100644 --- a/src/shared/widgets/local/user.tsx +++ b/src/shared/widgets/local/user.tsx @@ -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 ( -
+
@@ -166,6 +167,6 @@ export function LocalUserWidget({ params }: { params: Widget }) {
- + ); } diff --git a/src/shared/widgets/nostrBand/trendingAccounts.tsx b/src/shared/widgets/nostrBand/trendingAccounts.tsx index c8e3286d..6dfa8358 100644 --- a/src/shared/widgets/nostrBand/trendingAccounts.tsx +++ b/src/shared/widgets/nostrBand/trendingAccounts.tsx @@ -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 ( -
+
{status === 'loading' ? ( @@ -56,6 +57,6 @@ export function TrendingAccountsWidget({ params }: { params: Widget }) {
)}
- + ); } diff --git a/src/shared/widgets/nostrBand/trendingNotes.tsx b/src/shared/widgets/nostrBand/trendingNotes.tsx index 321b2b88..5056e9e9 100644 --- a/src/shared/widgets/nostrBand/trendingNotes.tsx +++ b/src/shared/widgets/nostrBand/trendingNotes.tsx @@ -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 ( -
+
{status === 'loading' ? ( @@ -58,6 +59,6 @@ export function TrendingNotesWidget({ params }: { params: Widget }) {
)}
- + ); } diff --git a/src/shared/widgets/other/learnNostr.tsx b/src/shared/widgets/other/learnNostr.tsx index aee20b27..b48de3d6 100644 --- a/src/shared/widgets/other/learnNostr.tsx +++ b/src/shared/widgets/other/learnNostr.tsx @@ -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 ( -
+
{resources.map((resource, index) => ( @@ -58,6 +59,6 @@ export function LearnNostrWidget({ params }: { params: Widget }) {
))}
- + ); } diff --git a/src/shared/widgets/wrapper.tsx b/src/shared/widgets/wrapper.tsx new file mode 100644 index 00000000..72e8587f --- /dev/null +++ b/src/shared/widgets/wrapper.tsx @@ -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 ( + 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} + + ); +} diff --git a/src/stores/widgets.ts b/src/stores/widgets.ts index d1805eef..60f6745d 100644 --- a/src/stores/widgets.ts +++ b/src/stores/widgets.ts @@ -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()( 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',