feat: add nstore
This commit is contained in:
@@ -6,6 +6,7 @@ import type {
|
||||
EventWithReplies,
|
||||
Interests,
|
||||
Keys,
|
||||
LumeColumn,
|
||||
Metadata,
|
||||
Settings,
|
||||
} from "@lume/types";
|
||||
@@ -14,6 +15,13 @@ import { open } from "@tauri-apps/plugin-dialog";
|
||||
import { readFile } from "@tauri-apps/plugin-fs";
|
||||
import { generateContentTags } from "@lume/utils";
|
||||
|
||||
enum NSTORE_KEYS {
|
||||
settings = "lume_user_settings",
|
||||
interests = "lume_user_interests",
|
||||
columns = "lume_user_columns",
|
||||
group = "lume_group_",
|
||||
}
|
||||
|
||||
export class Ark {
|
||||
public windows: WebviewWindow[];
|
||||
|
||||
@@ -565,13 +573,36 @@ export class Ark {
|
||||
}
|
||||
}
|
||||
|
||||
public async get_settings(id: string) {
|
||||
public async get_columns() {
|
||||
try {
|
||||
const cmd: string = await invoke("get_settings", { id });
|
||||
if (!cmd) return null;
|
||||
if (!cmd.length) return null;
|
||||
const cmd: string = await invoke("get_nstore", {
|
||||
key: NSTORE_KEYS.columns,
|
||||
});
|
||||
const columns: LumeColumn[] = cmd ? JSON.parse(cmd) : [];
|
||||
return columns;
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
const settings: Settings = JSON.parse(cmd);
|
||||
public async set_columns(columns: LumeColumn[]) {
|
||||
try {
|
||||
const cmd: string = await invoke("set_nstore", {
|
||||
key: NSTORE_KEYS.columns,
|
||||
content: JSON.stringify(columns),
|
||||
});
|
||||
return cmd;
|
||||
} catch (e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public async get_settings() {
|
||||
try {
|
||||
const cmd: string = await invoke("get_nstore", {
|
||||
key: NSTORE_KEYS.settings,
|
||||
});
|
||||
const settings: Settings = cmd ? JSON.parse(cmd) : null;
|
||||
return settings;
|
||||
} catch {
|
||||
const defaultSettings: Settings = {
|
||||
@@ -585,7 +616,8 @@ export class Ark {
|
||||
|
||||
public async set_settings(settings: Settings) {
|
||||
try {
|
||||
const cmd: string = await invoke("set_settings", {
|
||||
const cmd: string = await invoke("set_nstore", {
|
||||
key: NSTORE_KEYS.settings,
|
||||
content: JSON.stringify(settings),
|
||||
});
|
||||
return cmd;
|
||||
@@ -594,13 +626,12 @@ export class Ark {
|
||||
}
|
||||
}
|
||||
|
||||
public async get_interest(id: string) {
|
||||
public async get_interest() {
|
||||
try {
|
||||
const cmd: string = await invoke("get_interest", { id });
|
||||
if (!cmd) return null;
|
||||
if (!cmd.length) return null;
|
||||
|
||||
const interests: Interests = JSON.parse(cmd);
|
||||
const cmd: string = await invoke("get_nstore", {
|
||||
key: NSTORE_KEYS.interests,
|
||||
});
|
||||
const interests: Interests = cmd ? JSON.parse(cmd) : null;
|
||||
return interests;
|
||||
} catch {
|
||||
return null;
|
||||
@@ -618,7 +649,8 @@ export class Ark {
|
||||
users: users ?? [],
|
||||
hashtags: hashtags ?? [],
|
||||
};
|
||||
const cmd: string = await invoke("set_interest", {
|
||||
const cmd: string = await invoke("set_nstore", {
|
||||
key: NSTORE_KEYS.interests,
|
||||
content: JSON.stringify(interests),
|
||||
});
|
||||
return cmd;
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
export function RefreshIcon(props: JSX.IntrinsicElements['svg']) {
|
||||
export function RefreshIcon(props: JSX.IntrinsicElements["svg"]) {
|
||||
return (
|
||||
<svg
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<path d="M17.5 2.474c.51 1.192.861 2.444 1.049 3.726a.479.479 0 0 1-.298.515l-.181.07M6.5 21.527A15 15 0 0 1 5.451 17.8a.48.48 0 0 1 .298-.515l.181-.07M14.5 7.67a15 15 0 0 0 3.57-.884m0 0a8 8 0 0 0-13.912 6.797m15.75-2.79A8 8 0 0 1 5.93 17.215m3.571-.885a15.002 15.002 0 0 0-3.57.884" />
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" {...props}>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M13 21a1 1 0 1 0 0-2 1 1 0 0 0 0 2Zm8-10a1 1 0 1 0-2 0 1 1 0 0 0 2 0Zm-1.07 3.268a1 1 0 1 1-1 1.732 1 1 0 0 1 1-1.732Zm-2.562 5.026a1 1 0 1 0-1-1.732 1 1 0 0 0 1 1.732ZM18.927 8a1 1 0 1 1-1-1.732 1 1 0 0 1 1 1.732Z"
|
||||
/>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
d="M9.25 14.75v5.5h-5.5M9 19.688a8.25 8.25 0 1 1 6.25-15.273"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
10
packages/types/index.d.ts
vendored
10
packages/types/index.d.ts
vendored
@@ -75,8 +75,14 @@ export interface RichContent {
|
||||
notes: string[];
|
||||
}
|
||||
|
||||
export interface ColumnRouteSearch {
|
||||
account: string;
|
||||
label: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface LumeColumn {
|
||||
id: number;
|
||||
label: string;
|
||||
name: string;
|
||||
content: URL | string;
|
||||
description?: string;
|
||||
@@ -89,7 +95,7 @@ export interface LumeColumn {
|
||||
|
||||
export interface EventColumns {
|
||||
type: "add" | "remove" | "update" | "left" | "right";
|
||||
id?: number;
|
||||
label?: string;
|
||||
column?: LumeColumn;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import { ChevronDownIcon, RefreshIcon, TrashIcon } from "@lume/icons";
|
||||
import { CancelIcon, RefreshIcon } from "@lume/icons";
|
||||
import { cn } from "@lume/utils";
|
||||
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
||||
import { getCurrent } from "@tauri-apps/api/window";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
export function ColumnHeader({
|
||||
id,
|
||||
label,
|
||||
name,
|
||||
className,
|
||||
children,
|
||||
}: {
|
||||
id: number;
|
||||
label: string;
|
||||
name: string;
|
||||
className?: string;
|
||||
children?: ReactNode;
|
||||
}) {
|
||||
const reload = () => {
|
||||
window.location.reload();
|
||||
@@ -18,46 +20,37 @@ export function ColumnHeader({
|
||||
|
||||
const close = async () => {
|
||||
const mainWindow = getCurrent();
|
||||
await mainWindow.emit("columns", { type: "remove", id });
|
||||
await mainWindow.emit("columns", { type: "remove", label });
|
||||
};
|
||||
|
||||
return (
|
||||
<DropdownMenu.Root>
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-11 w-full shrink-0 items-center justify-center gap-2 border-b border-neutral-100 dark:border-neutral-900",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<DropdownMenu.Trigger asChild>
|
||||
<button type="button" className="inline-flex items-center gap-2">
|
||||
<div className="text-[13px] font-medium">{name}</div>
|
||||
<ChevronDownIcon className="size-4" />
|
||||
</button>
|
||||
</DropdownMenu.Trigger>
|
||||
</div>
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content
|
||||
sideOffset={5}
|
||||
className="flex w-[200px] flex-col overflow-hidden rounded-xl bg-black p-1 focus:outline-none dark:bg-white"
|
||||
<div
|
||||
className={cn(
|
||||
"h-11 w-full flex items-center justify-between shrink-0 px-3 border-b border-neutral-100 dark:border-neutral-900",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{!children ? (
|
||||
<div className="text-[13px] font-medium">{name}</div>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
<div className="inline-flex items-center gap-1">
|
||||
<button
|
||||
type="button"
|
||||
onClick={reload}
|
||||
className="size-7 inline-flex hover:bg-neutral-100 rounded-md dark:hover:bg-neutral-900 items-center justify-center text-neutral-600 dark:text-neutral-400 hover:text-neutral-800 dark:hover:text-neutral-200"
|
||||
>
|
||||
<DropdownMenu.Item
|
||||
onClick={reload}
|
||||
className="inline-flex h-9 items-center gap-2 rounded-lg px-3 text-sm font-medium text-white hover:bg-neutral-900 focus:outline-none dark:text-black dark:hover:bg-neutral-100"
|
||||
>
|
||||
<RefreshIcon className="size-4" />
|
||||
Reload
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
onClick={close}
|
||||
className="inline-flex h-9 items-center gap-2 rounded-lg px-3 text-sm font-medium text-white hover:bg-neutral-900 focus:outline-none dark:text-black dark:hover:bg-neutral-100"
|
||||
>
|
||||
<TrashIcon className="size-4" />
|
||||
Close
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Arrow className="fill-black dark:fill-white" />
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Portal>
|
||||
</DropdownMenu.Root>
|
||||
<RefreshIcon className="size-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={close}
|
||||
className="size-7 inline-flex items-center hover:bg-neutral-100 rounded-md dark:hover:bg-neutral-900 justify-center text-neutral-600 dark:text-neutral-400 hover:text-neutral-800 dark:hover:text-neutral-200"
|
||||
>
|
||||
<CancelIcon className="size-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,20 +3,20 @@ import { ReactNode } from "react";
|
||||
|
||||
export function ColumnRoot({
|
||||
children,
|
||||
shadow = true,
|
||||
background = true,
|
||||
className,
|
||||
background = true,
|
||||
shadow = true,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
shadow?: boolean;
|
||||
background?: boolean;
|
||||
className?: string;
|
||||
background?: boolean;
|
||||
shadow?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div className="h-full w-full p-2">
|
||||
<div
|
||||
className={cn(
|
||||
"relative flex h-full w-full flex-col rounded-xl",
|
||||
"relative flex h-full w-full flex-col rounded-xl overflow-hidden",
|
||||
shadow ? "shadow-primary" : "",
|
||||
background ? "bg-white dark:bg-black" : "",
|
||||
className,
|
||||
|
||||
Reference in New Issue
Block a user