From ec0f3fabc0ba0ec38dbfeed5cf75d8037e5d08a2 Mon Sep 17 00:00:00 2001 From: reya Date: Fri, 22 Mar 2024 11:28:54 +0700 Subject: [PATCH] feat: improve column management --- apps/desktop2/src/components/col.tsx | 29 ++++---- apps/desktop2/src/routes/$account.home.tsx | 62 +++++++++++----- apps/desktop2/src/routes/antenas.lazy.tsx | 4 +- apps/desktop2/src/routes/foryou.lazy.tsx | 4 +- apps/desktop2/src/routes/global.lazy.tsx | 4 +- apps/desktop2/src/routes/group.lazy.tsx | 4 +- apps/desktop2/src/routes/newsfeed.lazy.tsx | 10 +-- apps/desktop2/src/routes/open.lazy.tsx | 36 ++++++++++ apps/desktop2/src/routes/store.official.tsx | 20 ++---- apps/desktop2/src/routes/store.tsx | 78 ++++++++++++--------- apps/desktop2/src/routes/trending.lazy.tsx | 4 +- apps/desktop2/src/routes/waifu.lazy.tsx | 18 ----- packages/icons/src/cancel.tsx | 4 +- packages/icons/src/trash.tsx | 20 ++---- packages/ui/src/column/header.tsx | 19 ++++- packages/ui/src/column/root.tsx | 5 +- packages/ui/src/user/nip05.tsx | 2 +- src-tauri/src/commands/window.rs | 1 - 18 files changed, 194 insertions(+), 130 deletions(-) create mode 100644 apps/desktop2/src/routes/open.lazy.tsx delete mode 100644 apps/desktop2/src/routes/waifu.lazy.tsx diff --git a/apps/desktop2/src/components/col.tsx b/apps/desktop2/src/components/col.tsx index 664f946d..535e0096 100644 --- a/apps/desktop2/src/components/col.tsx +++ b/apps/desktop2/src/components/col.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useRef, useState } from "react"; +import { useEffect, useMemo, useRef } from "react"; import { getCurrent } from "@tauri-apps/api/window"; import { LumeColumn } from "@lume/types"; import { invoke } from "@tauri-apps/api/core"; @@ -13,39 +13,39 @@ export function Col({ isScroll: boolean; }) { const window = useMemo(() => getCurrent(), []); + const webview = useRef(null); const container = useRef(null); - const [webview, setWebview] = useState(null); - const createWebview = async () => { const rect = container.current.getBoundingClientRect(); - const name = `column-${column.name.toLowerCase().replace(/\W/g, "")}`; - const url = column.content + `?account=${account}&name=${column.name}`; + const label = `column-${column.id}`; + const url = + column.content + + `?account=${account}&id=${column.id}&name=${column.name}`; // create new webview - const label: string = await invoke("create_column", { - label: name, + webview.current = await invoke("create_column", { + label, x: rect.x, y: rect.y, width: rect.width, height: rect.height, url, }); - - setWebview(label); }; const closeWebview = async () => { - if (!webview) return; - await invoke("close_column", { - label: webview, + const close = await invoke("close_column", { + label: webview.current, }); + if (close) webview.current = null; }; const repositionWebview = async () => { + if (!webview.current) return; const newRect = container.current.getBoundingClientRect(); await invoke("reposition_column", { - label: webview, + label: webview.current, x: newRect.x, y: newRect.y, }); @@ -60,13 +60,14 @@ export function Col({ useEffect(() => { if (!window) return; if (!container.current) return; + if (webview.current) return; // create webview for current column createWebview(); // close webview when unmounted return () => { - closeWebview(); + if (webview.current) closeWebview(); }; }, []); diff --git a/apps/desktop2/src/routes/$account.home.tsx b/apps/desktop2/src/routes/$account.home.tsx index 4afe7fa6..f8f7afef 100644 --- a/apps/desktop2/src/routes/$account.home.tsx +++ b/apps/desktop2/src/routes/$account.home.tsx @@ -1,6 +1,6 @@ import { Col } from "@/components/col"; import { Toolbar } from "@/components/toolbar"; -import { LoaderIcon, PlusIcon } from "@lume/icons"; +import { LoaderIcon } from "@lume/icons"; import { EventColumns, LumeColumn } from "@lume/types"; import { createFileRoute } from "@tanstack/react-router"; import { UnlistenFn } from "@tauri-apps/api/event"; @@ -14,13 +14,14 @@ export const Route = createFileRoute("/$account/home")({ }); const DEFAULT_COLUMNS: LumeColumn[] = [ - { id: 1, name: "Newsfeed", content: "/newsfeed" }, + { id: 10001, name: "Newsfeed", content: "/newsfeed" }, + { id: 10002, name: "For You", content: "/foryou" }, + { id: 10000, name: "Open Lume Store", content: "/open" }, ]; function Screen() { const search = Route.useSearch(); const vlistRef = useRef(null); - const unlisten = useRef(null); const [columns, setColumns] = useState(DEFAULT_COLUMNS); const [selectedIndex, setSelectedIndex] = useState(-1); @@ -43,27 +44,51 @@ function Screen() { }; const add = (column: LumeColumn) => { - const col = columns.find((item) => item.id === column.id); - if (!col) { - setColumns((prev) => [...prev, column]); + const existed = columns.find((item) => item.id === column.id); + if (!existed) { + let lastColIndex: number; + const openColIndex = columns.findIndex((item) => item.id === 10000); + const storeColIndex = columns.findIndex((item) => item.id === 9999); + + if (storeColIndex) { + lastColIndex = storeColIndex; + } else { + lastColIndex = openColIndex; + } + + const newColumns = [ + ...columns.slice(0, lastColIndex), + column, + ...columns.slice(lastColIndex), + ]; + + // update state & scroll to new column + setColumns(newColumns); + setSelectedIndex(newColumns.length - 1); + vlistRef.current.scrollToIndex(newColumns.length - 1, { + align: "center", + }); } }; const remove = (id: number) => { setColumns((prev) => prev.filter((t) => t.id !== id)); + setSelectedIndex(columns.length); + vlistRef.current.scrollToIndex(columns.length, { + align: "center", + }); }; useEffect(() => { + let unlisten: UnlistenFn = undefined; + const listenColumnEvent = async () => { const mainWindow = getCurrent(); if (!unlisten) { - unlisten.current = await mainWindow.listen( - "columns", - (data) => { - if (data.payload.type === "add") add(data.payload.column); - if (data.payload.type === "remove") remove(data.payload.id); - }, - ); + unlisten = await mainWindow.listen("columns", (data) => { + if (data.payload.type === "add") add(data.payload.column); + if (data.payload.type === "remove") remove(data.payload.id); + }); } }; @@ -71,7 +96,12 @@ function Screen() { listenColumnEvent(); // clean up - return () => unlisten.current?.(); + return () => { + if (unlisten) { + unlisten(); + unlisten = null; + } + }; }, []); return ( @@ -106,9 +136,9 @@ function Screen() { }} className="scrollbar-none h-full w-full overflow-x-auto focus:outline-none" > - {columns.map((column, index) => ( + {columns.map((column) => ( - + {isLoading || isRefetching ? (
diff --git a/apps/desktop2/src/routes/foryou.lazy.tsx b/apps/desktop2/src/routes/foryou.lazy.tsx index 1ba6360c..8d2b5207 100644 --- a/apps/desktop2/src/routes/foryou.lazy.tsx +++ b/apps/desktop2/src/routes/foryou.lazy.tsx @@ -15,7 +15,7 @@ export const Route = createLazyFileRoute("/foryou")({ export function Screen() { // @ts-ignore, just work!!! - const { name, account } = Route.useSearch(); + const { id, name, account } = Route.useSearch(); const { t } = useTranslation(); const { data, @@ -38,7 +38,7 @@ export function Screen() { return ( - + {isLoading || isRefetching ? (
diff --git a/apps/desktop2/src/routes/global.lazy.tsx b/apps/desktop2/src/routes/global.lazy.tsx index 96eb3ab8..221d5cc7 100644 --- a/apps/desktop2/src/routes/global.lazy.tsx +++ b/apps/desktop2/src/routes/global.lazy.tsx @@ -15,7 +15,7 @@ export const Route = createLazyFileRoute("/global")({ export function Screen() { // @ts-ignore, just work!!! - const { name, account } = Route.useSearch(); + const { id, name, account } = Route.useSearch(); const { t } = useTranslation(); const { data, @@ -38,7 +38,7 @@ export function Screen() { return ( - + {isLoading || isRefetching ? (
diff --git a/apps/desktop2/src/routes/group.lazy.tsx b/apps/desktop2/src/routes/group.lazy.tsx index f3edabdb..5178ccd0 100644 --- a/apps/desktop2/src/routes/group.lazy.tsx +++ b/apps/desktop2/src/routes/group.lazy.tsx @@ -15,7 +15,7 @@ export const Route = createLazyFileRoute("/group")({ export function Screen() { // @ts-ignore, just work!!! - const { name, account } = Route.useSearch(); + const { id, name, account } = Route.useSearch(); const { t } = useTranslation(); const { data, @@ -38,7 +38,7 @@ export function Screen() { return ( - + {isLoading || isRefetching ? (
diff --git a/apps/desktop2/src/routes/newsfeed.lazy.tsx b/apps/desktop2/src/routes/newsfeed.lazy.tsx index f9fcdb54..681217d7 100644 --- a/apps/desktop2/src/routes/newsfeed.lazy.tsx +++ b/apps/desktop2/src/routes/newsfeed.lazy.tsx @@ -15,7 +15,7 @@ export const Route = createLazyFileRoute("/newsfeed")({ export function Screen() { // @ts-ignore, just work!!! - const { name, account } = Route.useSearch(); + const { id, name, account } = Route.useSearch(); const { t } = useTranslation(); const { data, @@ -38,7 +38,7 @@ export function Screen() { return ( - + {isLoading || isRefetching ? (
@@ -61,11 +61,13 @@ export function Screen() { )}
- {hasNextPage ? ( + {!isLoading && hasNextPage ? ( + + + ); +} diff --git a/apps/desktop2/src/routes/store.official.tsx b/apps/desktop2/src/routes/store.official.tsx index 70d0813d..881a4bd7 100644 --- a/apps/desktop2/src/routes/store.official.tsx +++ b/apps/desktop2/src/routes/store.official.tsx @@ -7,7 +7,7 @@ export const Route = createFileRoute("/store/official")({ loader: () => { const columns: LumeColumn[] = [ { - id: 10000, + id: 10002, name: "For you", content: "/foryou", logo: "", @@ -17,7 +17,7 @@ export const Route = createFileRoute("/store/official")({ description: "Keep up to date with content based on your interests.", }, { - id: 10001, + id: 10003, name: "Group Feeds", content: "/group", logo: "", @@ -27,7 +27,7 @@ export const Route = createFileRoute("/store/official")({ description: "Collective of people you're interested in.", }, { - id: 10002, + id: 10004, name: "Antenas", content: "/antenas", logo: "", @@ -37,7 +37,7 @@ export const Route = createFileRoute("/store/official")({ description: "Keep track to specific content.", }, { - id: 10003, + id: 10005, name: "Trending", content: "/trending", logo: "", @@ -47,7 +47,7 @@ export const Route = createFileRoute("/store/official")({ description: "What is trending on Nostr?.", }, { - id: 10004, + id: 10006, name: "Global", content: "/global", logo: "", @@ -56,16 +56,6 @@ export const Route = createFileRoute("/store/official")({ author: "Lume", description: "All events from connected relays.", }, - { - id: 10005, - name: "Waifu", - content: "/waifu", - logo: "", - cover: "/waifu.png", - coverRetina: "/waifu@2x.png", - author: "Lume", - description: "Show a random waifu image to boost your morale.", - }, ]; return columns; }, diff --git a/apps/desktop2/src/routes/store.tsx b/apps/desktop2/src/routes/store.tsx index 9c2dcbb3..905e9a7a 100644 --- a/apps/desktop2/src/routes/store.tsx +++ b/apps/desktop2/src/routes/store.tsx @@ -1,48 +1,62 @@ -import { GlobalIcon, LaurelIcon } from "@lume/icons"; +import { CancelIcon, GlobalIcon, LaurelIcon } from "@lume/icons"; import { Column } from "@lume/ui"; import { cn } from "@lume/utils"; import { Link } from "@tanstack/react-router"; import { Outlet, createFileRoute } from "@tanstack/react-router"; +import { getCurrent } from "@tauri-apps/api/window"; export const Route = createFileRoute("/store")({ component: Screen, }); function Screen() { + // @ts-ignore, just work!!! + const { id } = Route.useSearch(); + + const close = async () => { + const mainWindow = getCurrent(); + await mainWindow.emit("columns", { type: "remove", id }); + }; + return ( -
- - {({ isActive }) => ( -
- - Official -
- )} - - - {({ isActive }) => ( -
- - Community -
- )} - +
+
+ + {({ isActive }) => ( +
+ + Official +
+ )} + + + {({ isActive }) => ( +
+ + Community +
+ )} + +
+
diff --git a/apps/desktop2/src/routes/trending.lazy.tsx b/apps/desktop2/src/routes/trending.lazy.tsx index b0ba05e5..949a7542 100644 --- a/apps/desktop2/src/routes/trending.lazy.tsx +++ b/apps/desktop2/src/routes/trending.lazy.tsx @@ -15,7 +15,7 @@ export const Route = createLazyFileRoute("/trending")({ export function Screen() { // @ts-ignore, just work!!! - const { name, account } = Route.useSearch(); + const { id, name, account } = Route.useSearch(); const { t } = useTranslation(); const { data, @@ -38,7 +38,7 @@ export function Screen() { return ( - + {isLoading || isRefetching ? (
diff --git a/apps/desktop2/src/routes/waifu.lazy.tsx b/apps/desktop2/src/routes/waifu.lazy.tsx deleted file mode 100644 index 52686c4a..00000000 --- a/apps/desktop2/src/routes/waifu.lazy.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Column } from "@lume/ui"; -import { createLazyFileRoute } from "@tanstack/react-router"; - -export const Route = createLazyFileRoute("/waifu")({ - component: Screen, -}); - -function Screen() { - // @ts-ignore, just work!!! - const { name } = Route.useSearch(); - - return ( - - - waifu - - ); -} diff --git a/packages/icons/src/cancel.tsx b/packages/icons/src/cancel.tsx index 50644f62..55c1adf2 100644 --- a/packages/icons/src/cancel.tsx +++ b/packages/icons/src/cancel.tsx @@ -4,8 +4,8 @@ export function CancelIcon(props: JSX.IntrinsicElements["svg"]) { ); diff --git a/packages/icons/src/trash.tsx b/packages/icons/src/trash.tsx index 0078ac7b..a772b804 100644 --- a/packages/icons/src/trash.tsx +++ b/packages/icons/src/trash.tsx @@ -1,18 +1,10 @@ -export function TrashIcon(props: JSX.IntrinsicElements['svg']) { +export function TrashIcon(props: JSX.IntrinsicElements["svg"]) { return ( - - + + ); } diff --git a/packages/ui/src/column/header.tsx b/packages/ui/src/column/header.tsx index 48112f73..c3e48e45 100644 --- a/packages/ui/src/column/header.tsx +++ b/packages/ui/src/column/header.tsx @@ -1,11 +1,14 @@ -import { ChevronDownIcon, RefreshIcon } from "@lume/icons"; +import { ChevronDownIcon, RefreshIcon, TrashIcon } from "@lume/icons"; import { cn } from "@lume/utils"; import * as DropdownMenu from "@radix-ui/react-dropdown-menu"; +import { getCurrent } from "@tauri-apps/api/window"; export function ColumnHeader({ + id, name, className, }: { + id: number; name: string; className?: string; }) { @@ -13,6 +16,11 @@ export function ColumnHeader({ window.location.reload(); }; + const close = async () => { + const mainWindow = getCurrent(); + await mainWindow.emit("columns", { type: "remove", id }); + }; + return (
Reload + + + Close + diff --git a/packages/ui/src/column/root.tsx b/packages/ui/src/column/root.tsx index 428c2bd7..dcc46107 100644 --- a/packages/ui/src/column/root.tsx +++ b/packages/ui/src/column/root.tsx @@ -4,18 +4,21 @@ import { ReactNode } from "react"; export function ColumnRoot({ children, shadow = true, + background = true, className, }: { children: ReactNode; shadow?: boolean; + background?: boolean; className?: string; }) { return (
diff --git a/packages/ui/src/user/nip05.tsx b/packages/ui/src/user/nip05.tsx index 6355860e..91228177 100644 --- a/packages/ui/src/user/nip05.tsx +++ b/packages/ui/src/user/nip05.tsx @@ -23,7 +23,7 @@ export function UserNip05({ className }: { className?: string }) {

{!user.profile?.nip05 ? displayNpub(user.pubkey, 16) - : user.profile?.nip05.length > 16 + : user.profile?.nip05.length > 50 ? displayLongHandle(user.profile?.nip05) : user.profile.nip05?.replace("_@", "")}

diff --git a/src-tauri/src/commands/window.rs b/src-tauri/src/commands/window.rs index 2c85ba42..3c9f6a50 100644 --- a/src-tauri/src/commands/window.rs +++ b/src-tauri/src/commands/window.rs @@ -18,7 +18,6 @@ pub fn create_column( let path = PathBuf::from(url); let webview_url = WebviewUrl::App(path); let builder = tauri::webview::WebviewBuilder::new(label, webview_url) - .auto_resize() .user_agent("Lume/4.0") .transparent(true); match main_window.add_child(