diff --git a/apps/desktop2/src/components/col.tsx b/apps/desktop2/src/components/col.tsx index f952324c..54ced59d 100644 --- a/apps/desktop2/src/components/col.tsx +++ b/apps/desktop2/src/components/col.tsx @@ -1,13 +1,7 @@ -import { useCallback, useEffect, useMemo, useRef } from "react"; -import { - LogicalPosition, - LogicalSize, - getCurrent, -} from "@tauri-apps/api/window"; -import { Webview } from "@tauri-apps/api/webview"; +import { useEffect, useMemo, useRef, useState } from "react"; +import { getCurrent } from "@tauri-apps/api/window"; import { LumeColumn } from "@lume/types"; -import { useDebouncedCallback } from "use-debounce"; -import { type UnlistenFn } from "@tauri-apps/api/event"; +import { invoke } from "@tauri-apps/api/core"; export function Col({ column, @@ -18,66 +12,62 @@ export function Col({ account: string; isScroll: boolean; }) { - const mainWindow = useMemo(() => getCurrent(), []); - const childWindow = useRef(null); + const window = useMemo(() => getCurrent(), []); const container = useRef(null); - const initialRect = useRef(null); - const unlisten = useRef(null); - const handleResize = useDebouncedCallback(() => { - if (!childWindow.current) return; - const newRect = container.current.getBoundingClientRect(); - if (initialRect.current.height !== newRect.height) { - childWindow.current.setSize( - new LogicalSize(newRect.width, newRect.height), - ); - } - }, 500); - const trackResize = useCallback(async () => { - unlisten.current = await mainWindow.onResized(() => { - handleResize(); - }); - }, []); - - useEffect(() => { - if (!childWindow.current) return; - if (isScroll) { - const newRect = container.current.getBoundingClientRect(); - childWindow.current.setPosition( - new LogicalPosition(newRect.x, newRect.y), - ); - } - }, [isScroll]); - - useEffect(() => { - if (!mainWindow) return; - if (!container.current) return; - if (childWindow.current) return; + const [webview, setWebview] = useState(""); + 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}`; // create new webview - initialRect.current = rect; - childWindow.current = new Webview(mainWindow, name, { - url, + const label: string = await invoke("create_column", { + label: name, x: rect.x, y: rect.y, width: rect.width, height: rect.height, - transparent: true, - userAgent: "Lume/4.0", + url, }); - // track window resize event - trackResize(); + setWebview(label); + }; + const closeWebview = async () => { + await invoke("close_column", { + label: webview, + }); + }; + + const repositionWebview = async () => { + const newRect = container.current.getBoundingClientRect(); + await invoke("reposition_column", { + label: webview, + x: newRect.x, + y: newRect.y, + }); + }; + + useEffect(() => { + if (isScroll) { + repositionWebview(); + } + }, [isScroll]); + + useEffect(() => { + if (!window) return; + if (!container.current) return; + + // create webview for current column + createWebview(); + + // close webview when unmounted return () => { - if (unlisten.current) unlisten.current(); - if (childWindow.current) childWindow.current.close(); + closeWebview(); }; - }, []); + }, [window]); return
; } diff --git a/apps/desktop2/src/routes/$account.home.tsx b/apps/desktop2/src/routes/$account.home.tsx index 7061a691..3a302c99 100644 --- a/apps/desktop2/src/routes/$account.home.tsx +++ b/apps/desktop2/src/routes/$account.home.tsx @@ -1,31 +1,33 @@ import { Col } from "@/components/col"; import { Toolbar } from "@/components/toolbar"; import { LoaderIcon } from "@lume/icons"; +import { EventColumns, LumeColumn } from "@lume/types"; import { createFileRoute } from "@tanstack/react-router"; -import { useRef, useState } from "react"; +import { UnlistenFn } from "@tauri-apps/api/event"; +import { getCurrent } from "@tauri-apps/api/window"; +import { useEffect, useRef, useState } from "react"; import { VList, VListHandle } from "virtua"; export const Route = createFileRoute("/$account/home")({ component: Screen, pendingComponent: Pending, - loader: async () => { - const columns = [ - { name: "Newsfeed", content: "/newsfeed" }, - { name: "Lume Store", content: "/store/official" }, - ]; - return columns; - }, }); +const COLS: LumeColumn[] = [ + { id: 1, name: "Newsfeed", content: "/newsfeed" }, + { id: 2, name: "Lume Store", content: "/store/official" }, +]; + function Screen() { - const data = Route.useLoaderData(); const search = Route.useSearch(); const vlistRef = useRef(null); + const unlisten = useRef(null); + const [columns, setColumns] = useState(COLS); const [selectedIndex, setSelectedIndex] = useState(-1); const [isScroll, setIsScroll] = useState(false); - const moveLeft = () => { + const goLeft = () => { const prevIndex = Math.max(selectedIndex - 1, 0); setSelectedIndex(prevIndex); vlistRef.current.scrollToIndex(prevIndex, { @@ -33,14 +35,44 @@ function Screen() { }); }; - const moveRight = () => { - const nextIndex = Math.min(selectedIndex + 1, data.length - 1); + const goRight = () => { + const nextIndex = Math.min(selectedIndex + 1, columns.length - 1); setSelectedIndex(nextIndex); vlistRef.current.scrollToIndex(nextIndex, { align: "end", }); }; + const add = async (column: LumeColumn) => { + setColumns((prev) => [...prev, column]); + vlistRef?.current.scrollToIndex(columns.length); + }; + + const remove = async (id: number) => { + setColumns((prev) => prev.filter((t) => t.id !== id)); + }; + + useEffect(() => { + async function listenUpdateColumn() { + const mainWindow = getCurrent(); + 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); + }, + ); + } + + // listen for column changes + listenUpdateColumn(); + + // clean up + return () => { + if (unlisten.current) unlisten.current(); + }; + }, []); + return (
- {data.map((column, index) => ( + {columns.map((column, index) => ( ))} - +
); } diff --git a/apps/desktop2/src/routes/store.official.tsx b/apps/desktop2/src/routes/store.official.tsx index dff0b7e1..e43857a3 100644 --- a/apps/desktop2/src/routes/store.official.tsx +++ b/apps/desktop2/src/routes/store.official.tsx @@ -5,6 +5,13 @@ export const Route = createFileRoute("/store/official")({ }); function Screen() { + /* + const add = async (column: LumeColumn) => { + const mainWindow = getCurrent(); + await mainWindow.emit("columns", { type: "add", column }); + }; + */ + return (
diff --git a/apps/desktop2/src/routes/store.tsx b/apps/desktop2/src/routes/store.tsx index ca562681..f83c7b66 100644 --- a/apps/desktop2/src/routes/store.tsx +++ b/apps/desktop2/src/routes/store.tsx @@ -1,3 +1,4 @@ +import { GroupFeedsIcon, LaurelIcon } from "@lume/icons"; import { Column } from "@lume/ui"; import { cn } from "@lume/utils"; import { Link } from "@tanstack/react-router"; @@ -11,17 +12,18 @@ function Screen() { return ( -
+
{({ isActive }) => (
+ Official
)} @@ -30,12 +32,13 @@ function Screen() { {({ isActive }) => (
+ Community
)}