feat: move column manager to rust
This commit is contained in:
@@ -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<VListHandle>(null);
|
||||
const unlisten = useRef<UnlistenFn>(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<EventColumns>(
|
||||
"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 (
|
||||
<div className="h-full w-full">
|
||||
<VList
|
||||
@@ -54,13 +86,13 @@ function Screen() {
|
||||
case "ArrowUp":
|
||||
case "ArrowLeft": {
|
||||
e.preventDefault();
|
||||
moveLeft();
|
||||
goLeft();
|
||||
break;
|
||||
}
|
||||
case "ArrowDown":
|
||||
case "ArrowRight": {
|
||||
e.preventDefault();
|
||||
moveRight();
|
||||
goRight();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -73,9 +105,9 @@ function Screen() {
|
||||
}}
|
||||
className="scrollbar-none h-full w-full overflow-x-auto focus:outline-none"
|
||||
>
|
||||
{data.map((column, index) => (
|
||||
{columns.map((column, index) => (
|
||||
<Col
|
||||
key={column.name + index}
|
||||
key={column.id + index}
|
||||
column={column}
|
||||
// @ts-ignore, yolo !!!
|
||||
account={search.acccount}
|
||||
@@ -83,7 +115,7 @@ function Screen() {
|
||||
/>
|
||||
))}
|
||||
</VList>
|
||||
<Toolbar moveLeft={moveLeft} moveRight={moveRight} />
|
||||
<Toolbar moveLeft={goLeft} moveRight={goRight} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
<div className="flex flex-col gap-3 px-3 pt-3">
|
||||
<div className="relative h-[200px] w-full overflow-hidden rounded-xl bg-gradient-to-tr from-orange-100 to-blue-200 px-3 pt-3">
|
||||
|
||||
@@ -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 (
|
||||
<Column.Root>
|
||||
<Column.Content>
|
||||
<div className="flex h-14 shrink-0 items-center gap-3 border-b border-neutral-100 px-3 dark:border-neutral-900">
|
||||
<div className="flex h-14 shrink-0 items-center gap-2 border-b border-neutral-100 px-3 dark:border-neutral-900">
|
||||
<Link to="/store/official">
|
||||
{({ isActive }) => (
|
||||
<div
|
||||
className={cn(
|
||||
"inline-flex h-8 w-max items-center justify-center rounded-full px-6 text-sm",
|
||||
"inline-flex h-8 w-max items-center justify-center gap-2 rounded-full px-6 text-sm font-medium",
|
||||
isActive
|
||||
? "bg-neutral-100 font-medium dark:bg-neutral-900"
|
||||
? "bg-neutral-100 dark:bg-neutral-900"
|
||||
: "opacity-50",
|
||||
)}
|
||||
>
|
||||
<LaurelIcon className="size-5" />
|
||||
Official
|
||||
</div>
|
||||
)}
|
||||
@@ -30,12 +32,13 @@ function Screen() {
|
||||
{({ isActive }) => (
|
||||
<div
|
||||
className={cn(
|
||||
"inline-flex h-8 w-max items-center justify-center rounded-full px-6 text-sm",
|
||||
"inline-flex h-8 w-max items-center justify-center gap-2 rounded-full px-6 text-sm font-medium",
|
||||
isActive
|
||||
? "bg-neutral-100 font-medium dark:bg-neutral-900"
|
||||
? "bg-neutral-100 dark:bg-neutral-900"
|
||||
: "opacity-50",
|
||||
)}
|
||||
>
|
||||
<GroupFeedsIcon className="size-5" />
|
||||
Community
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user