3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
||||
[submodule "modules/depot"]
|
||||
path = modules/depot
|
||||
url = https://github.com/luminous-devs/depot.git
|
@ -10,11 +10,14 @@
|
||||
"@columns/antenas": "workspace:^",
|
||||
"@columns/default": "workspace:^",
|
||||
"@columns/foryou": "workspace:^",
|
||||
"@columns/global": "workspace:^",
|
||||
"@columns/group": "workspace:^",
|
||||
"@columns/hashtag": "workspace:^",
|
||||
"@columns/thread": "workspace:^",
|
||||
"@columns/timeline": "workspace:^",
|
||||
"@columns/trending-notes": "workspace:^",
|
||||
"@columns/user": "workspace:^",
|
||||
"@columns/waifu": "workspace:^",
|
||||
"@getalby/sdk": "^3.2.3",
|
||||
"@lume/ark": "workspace:^",
|
||||
"@lume/icons": "workspace:^",
|
||||
@ -35,8 +38,8 @@
|
||||
"@radix-ui/react-switch": "^1.0.3",
|
||||
"@radix-ui/react-tooltip": "^1.0.7",
|
||||
"@tanstack/react-query": "^5.17.19",
|
||||
"framer-motion": "^10.18.0",
|
||||
"i18next": "^23.8.0",
|
||||
"framer-motion": "^11.0.3",
|
||||
"i18next": "^23.8.1",
|
||||
"i18next-resources-to-backend": "^1.2.0",
|
||||
"jotai": "^2.6.3",
|
||||
"minidenticons": "^4.2.0",
|
||||
@ -50,14 +53,14 @@
|
||||
"react-i18next": "^14.0.1",
|
||||
"react-router-dom": "^6.21.3",
|
||||
"smol-toml": "^1.1.4",
|
||||
"sonner": "^1.3.1",
|
||||
"virtua": "^0.21.1"
|
||||
"sonner": "^1.4.0",
|
||||
"virtua": "^0.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lume/tailwindcss": "workspace:^",
|
||||
"@lume/tsconfig": "workspace:^",
|
||||
"@lume/types": "workspace:^",
|
||||
"@types/node": "^20.11.6",
|
||||
"@types/node": "^20.11.10",
|
||||
"@types/react": "^18.2.48",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@vitejs/plugin-react-swc": "^3.5.0",
|
||||
|
BIN
apps/desktop/public/columns/global.jpg
Normal file
After Width: | Height: | Size: 119 KiB |
BIN
apps/desktop/public/columns/global@2x.jpg
Normal file
After Width: | Height: | Size: 448 KiB |
Before Width: | Height: | Size: 103 KiB |
BIN
apps/desktop/public/columns/trending-notes.jpg
Normal file
After Width: | Height: | Size: 102 KiB |
Before Width: | Height: | Size: 381 KiB After Width: | Height: | Size: 381 KiB |
BIN
apps/desktop/public/columns/waifu.jpg
Normal file
After Width: | Height: | Size: 121 KiB |
BIN
apps/desktop/public/columns/waifu@2x.jpg
Normal file
After Width: | Height: | Size: 457 KiB |
@ -36,7 +36,9 @@ export function CreateAccountScreen() {
|
||||
onClick={() => setMethod("self")}
|
||||
className={cn(
|
||||
"flex flex-col items-start px-4 py-3.5 bg-neutral-900 rounded-xl hover:bg-neutral-800",
|
||||
method === "self" ? "ring-1 ring-teal-500" : "",
|
||||
method === "self"
|
||||
? "ring-1 ring-offset-4 ring-offset-black ring-blue-500"
|
||||
: "",
|
||||
)}
|
||||
>
|
||||
<p className="font-semibold">{t("signup.selfManageMethod")}</p>
|
||||
@ -49,25 +51,57 @@ export function CreateAccountScreen() {
|
||||
onClick={() => setMethod("managed")}
|
||||
className={cn(
|
||||
"flex flex-col items-start px-4 py-3.5 bg-neutral-900 rounded-xl hover:bg-neutral-800",
|
||||
method === "managed" ? "ring-1 ring-teal-500" : "",
|
||||
method === "managed"
|
||||
? "ring-1 ring-offset-4 ring-offset-black ring-blue-500"
|
||||
: "",
|
||||
)}
|
||||
>
|
||||
<p className="font-semibold">{t("signup.providerMethod")}</p>
|
||||
<div className="inline-flex items-center gap-2">
|
||||
<p className="font-semibold">{t("signup.providerMethod")}</p>
|
||||
<span className="text-xs font-medium px-2.5 py-0.5 rounded-full bg-gradient-to-tr from-blue-300 via-sky-500 to-teal-200">
|
||||
Beta
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm font-medium text-neutral-500">
|
||||
{t("signup.providerMethodDescription")}
|
||||
</p>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={next}
|
||||
className="inline-flex items-center justify-center w-full h-12 text-lg font-medium text-white bg-blue-500 rounded-xl hover:bg-blue-600"
|
||||
>
|
||||
{loading ? (
|
||||
<LoaderIcon className="size-5 animate-spin" />
|
||||
) : (
|
||||
t("global.continue")
|
||||
)}
|
||||
</button>
|
||||
<div className="flex flex-col gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={next}
|
||||
className="inline-flex items-center justify-center w-full h-12 text-lg font-medium text-white bg-blue-500 rounded-xl hover:bg-blue-600"
|
||||
>
|
||||
{loading ? (
|
||||
<LoaderIcon className="size-5 animate-spin" />
|
||||
) : (
|
||||
t("global.continue")
|
||||
)}
|
||||
</button>
|
||||
{method === "managed" ? (
|
||||
<div className="flex flex-col gap-1 text-sm text-neutral-500">
|
||||
<p className="text-sm font-semibold text-neutral-300">
|
||||
Attention:
|
||||
</p>
|
||||
<p>
|
||||
You're chosing Managed by Provider, this feature still in
|
||||
"Beta".
|
||||
</p>
|
||||
<p>
|
||||
Some functions still missing or not work as expected, you
|
||||
shouldn't create your main account with this method
|
||||
</p>
|
||||
<a
|
||||
href="https://github.com/kind-0/nsecbunkerd/blob/master/OAUTH-LIKE-FLOW.md"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-blue-500"
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,11 +1,14 @@
|
||||
import { Antenas } from "@columns/antenas";
|
||||
import { Default } from "@columns/default";
|
||||
import { ForYou } from "@columns/foryou";
|
||||
import { Global } from "@columns/global";
|
||||
import { Group } from "@columns/group";
|
||||
import { Hashtag } from "@columns/hashtag";
|
||||
import { Thread } from "@columns/thread";
|
||||
import { Timeline } from "@columns/timeline";
|
||||
import { TrendingNotes } from "@columns/trending-notes";
|
||||
import { User } from "@columns/user";
|
||||
import { Waifu } from "@columns/waifu";
|
||||
import { useColumnContext } from "@lume/ark";
|
||||
import {
|
||||
ArrowLeftIcon,
|
||||
@ -45,6 +48,12 @@ export function HomeScreen() {
|
||||
return <Group key={column.id} column={column} />;
|
||||
case COL_TYPES.antenas:
|
||||
return <Antenas key={column.id} column={column} />;
|
||||
case COL_TYPES.global:
|
||||
return <Global key={column.id} column={column} />;
|
||||
case COL_TYPES.trendingNotes:
|
||||
return <TrendingNotes key={column.id} column={column} />;
|
||||
case COL_TYPES.waifu:
|
||||
return <Waifu key={column.id} column={column} />;
|
||||
default:
|
||||
return <Default key={column.id} column={column} />;
|
||||
}
|
||||
|
@ -51,11 +51,6 @@ export function ProfileSettingScreen() {
|
||||
|
||||
let content = {
|
||||
...data,
|
||||
username: data.name,
|
||||
display_name: data.displayName,
|
||||
bio: data.about,
|
||||
image: picture,
|
||||
cover: banner,
|
||||
picture,
|
||||
banner,
|
||||
};
|
||||
@ -140,7 +135,7 @@ export function ProfileSettingScreen() {
|
||||
</label>
|
||||
<input
|
||||
type={"text"}
|
||||
{...register("displayName")}
|
||||
{...register("display_name")}
|
||||
spellCheck={false}
|
||||
className="relative h-11 w-full rounded-lg border-transparent bg-neutral-100 px-3 py-1 text-neutral-900 !outline-none backdrop-blur-xl placeholder:text-neutral-500 focus:border-blue-500 focus:ring focus:ring-blue-200 dark:bg-neutral-900 dark:text-neutral-100"
|
||||
/>
|
||||
|
@ -13,7 +13,7 @@
|
||||
"@astrojs/check": "^0.4.1",
|
||||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@fontsource/geist-mono": "^5.0.1",
|
||||
"astro": "^4.2.4",
|
||||
"astro": "^4.2.6",
|
||||
"astro-seo-meta": "^4.1.0",
|
||||
"astro-seo-schema": "^4.0.0",
|
||||
"schema-dts": "^1.1.2",
|
||||
|
@ -1,13 +0,0 @@
|
||||
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
|
||||
index 87c23e40..bb84872e 100644
|
||||
--- a/src-tauri/tauri.conf.json
|
||||
+++ b/src-tauri/tauri.conf.json
|
||||
@@ -50,8 +50,6 @@
|
||||
"deb": {
|
||||
"depends": []
|
||||
},
|
||||
- "externalBin": ["bin/depot"],
|
||||
- "resources": ["resources/*"],
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
@ -35,15 +35,6 @@ RUN pnpm install --frozen-lockfile
|
||||
# Path for disable updater
|
||||
#ADD flatpak/0001-disable-tauri-updater.patch .
|
||||
#RUN patch -p1 -t -i flatpak/0001-disable-tauri-updater.patch
|
||||
#ADD flatpak/0002-depot-remove.patch .
|
||||
#RUN patch -p1 -t -i 0002-depot-remove.patch
|
||||
|
||||
# compile depot
|
||||
|
||||
#ADD flatpak/build-depot.sh build-depot.sh
|
||||
#RUN mv flatpak/build-depot.sh build-depot.sh
|
||||
#RUN sh build-depot.sh
|
||||
#RUN pnpm run build:depot
|
||||
|
||||
#ENV VITE_FLATPAK_RESOURCE="/app/lib/lume/resources/config.toml"
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
directory_bin="/lume/src-tauri/bin"
|
||||
target="x86_64-unknown-linux-gnu"
|
||||
|
||||
cd modules/depot
|
||||
|
||||
check_directory_keep=$(ls $directory_bin | grep -vE '.keep$' | wc -l)
|
||||
|
||||
echo $(ls $directory_bin | grep -vE '.keep$')
|
||||
|
||||
if [ $check_directory_keep -eq 0 ]; then
|
||||
cargo build --release
|
||||
mv target/release/depot "$directory_bin/depot-$target"
|
||||
fi
|
@ -1,50 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>nu.lume.Lume</id>
|
||||
<launchable type="desktop-id">nu.lume.Lume.desktop</launchable>
|
||||
|
||||
<name>Lume</name>
|
||||
<summary>A cross-platform desktop nostr client</summary>
|
||||
<developer_name>Ren Amamiya</developer_name>
|
||||
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-3.0-only</project_license>
|
||||
|
||||
<url type="homepage">https://lume.nu</url>
|
||||
<url type="bugtracker">https://github.com/luminous-devs/lume/issues</url>
|
||||
<url type="donation">https://nostree.me/npub1zfss807aer0j26mwp2la0ume0jqde3823rmu97ra6sgyyg956e0s6xw445</url>
|
||||
|
||||
<supports>
|
||||
<control>pointing</control>
|
||||
<control>keyboard</control>
|
||||
<control>touch</control>
|
||||
</supports>
|
||||
|
||||
<description>
|
||||
<p>
|
||||
Lume a cross-platform nostr client, supported nsbunker, chats and notifications
|
||||
</p>
|
||||
</description>
|
||||
|
||||
<custom>
|
||||
<value key="Purism::form_factor">workstation</value>
|
||||
<value key="Purism::form_factor">mobile</value>
|
||||
</custom>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image> https://raw.githubusercontent.com/kogeletey/lume-nostr/feat/package-flatpak/flatpak/screenshoots/login-screen.png </image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://raw.githubusercontent.com/kogeletey/lume-nostr/feat/package-flatpak/flatpak/screenshoots/collumns.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image> https://raw.githubusercontent.com/kogeletey/lume-nostr/feat/package-flatpak/flatpak/screenshoots/home-screen.png </image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
|
||||
|
||||
<releases>
|
||||
<release version="2.2.3" date="2023-12-07"/>
|
||||
</releases>
|
||||
<content_rating type="oars-1.1"/>
|
||||
<id>
|
||||
nu.lume.Lume
|
||||
</id>
|
||||
<launchable type="desktop-id">
|
||||
nu.lume.Lume.desktop
|
||||
</launchable>
|
||||
<name>
|
||||
Lume
|
||||
</name>
|
||||
<summary>
|
||||
A cross-platform desktop nostr client
|
||||
</summary>
|
||||
<developer_name>
|
||||
Ren Amamiya
|
||||
</developer_name>
|
||||
<metadata_license>
|
||||
CC0-1.0
|
||||
</metadata_license>
|
||||
<project_license>
|
||||
GPL-3.0-only
|
||||
</project_license>
|
||||
<url type="homepage">
|
||||
https://lume.nu
|
||||
</url>
|
||||
<url type="bugtracker">
|
||||
https://github.com/luminous-devs/lume/issues
|
||||
</url>
|
||||
<url type="donation">
|
||||
https://nostree.me/npub1zfss807aer0j26mwp2la0ume0jqde3823rmu97ra6sgyyg956e0s6xw445
|
||||
</url>
|
||||
<supports>
|
||||
<control>
|
||||
pointing
|
||||
</control>
|
||||
<control>
|
||||
keyboard
|
||||
</control>
|
||||
<control>
|
||||
touch
|
||||
</control>
|
||||
</supports>
|
||||
<description>
|
||||
<p>
|
||||
Lume a cross-platform nostr client, supported nsecbunker, chats and notifications
|
||||
</p>
|
||||
</description>
|
||||
<custom>
|
||||
<value key="Purism::form_factor">
|
||||
workstation
|
||||
</value>
|
||||
<value key="Purism::form_factor">
|
||||
mobile
|
||||
</value>
|
||||
</custom>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>
|
||||
https://raw.githubusercontent.com/luminous-devs/lume/flatpak/screenshots/login-screen.png
|
||||
</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>
|
||||
https://raw.githubusercontent.com/luminous-devs/lume/flatpak/screenshots/collumns.png
|
||||
</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>
|
||||
https://raw.githubusercontent.com/luminous-devs/lume/flatpak/screenshots/home-screen.png
|
||||
</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<releases>
|
||||
<release version="3.0.0" date="2024-15-01" />
|
||||
</releases>
|
||||
<content_rating type="oars-1.1" />
|
||||
</component>
|
||||
|
@ -32,9 +32,8 @@ modules:
|
||||
buildsystem: simple
|
||||
build-commands:
|
||||
- install -Dm755 bin/lume /app/bin/lume
|
||||
# - install -Dm755 bin/depot /app/bin/depot
|
||||
# - mkdir -p /app/lib/lume/resources
|
||||
# - cp -r lib/lume/resources /app/lib/lume/resources
|
||||
- mkdir -p /app/lib/lume/resources
|
||||
- cp -r lib/lume/resources /app/lib/lume/resources
|
||||
- mkdir -p /app/share/icons/hicolor/
|
||||
- cp -r share/icons/hicolor/ /app/share/icons/
|
||||
- install -Dm644 nu.lume.Lume.appdata.xml /app/share/metainfo/nu.lume.Lume.appdata.xml
|
||||
|
Before Width: | Height: | Size: 2.2 MiB After Width: | Height: | Size: 2.2 MiB |
Before Width: | Height: | Size: 2.5 MiB After Width: | Height: | Size: 2.5 MiB |
Before Width: | Height: | Size: 606 KiB After Width: | Height: | Size: 606 KiB |
@ -1 +0,0 @@
|
||||
Subproject commit 22f913f26ff365c6408b005b695200279586211f
|
@ -35,11 +35,11 @@
|
||||
"react-i18next": "^14.0.1",
|
||||
"react-router-dom": "^6.21.3",
|
||||
"react-string-replace": "^1.1.1",
|
||||
"sonner": "^1.3.1",
|
||||
"sonner": "^1.4.0",
|
||||
"string-strip-html": "^13.4.5",
|
||||
"tippy.js": "^6.3.7",
|
||||
"use-context-selector": "^1.4.1",
|
||||
"virtua": "^0.21.1"
|
||||
"virtua": "^0.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lume/tailwindcss": "workspace:^",
|
||||
|
@ -62,6 +62,10 @@ export class Ark {
|
||||
return sub;
|
||||
}
|
||||
|
||||
public getNDKEvent(event: NostrEvent) {
|
||||
return new NDKEvent(this.ndk, event);
|
||||
}
|
||||
|
||||
public async createEvent({
|
||||
kind,
|
||||
tags,
|
||||
|
@ -101,7 +101,7 @@ export function ColumnHeader({
|
||||
className="inline-flex items-center gap-3 px-3 text-sm font-medium text-red-500 rounded-lg h-9 hover:bg-red-500 hover:text-red-50 focus:outline-none"
|
||||
>
|
||||
<TrashIcon className="size-4" />
|
||||
{t("global.Delete")}
|
||||
{t("global.delete")}
|
||||
</button>
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
|
@ -7,12 +7,12 @@ function isImage(url: string) {
|
||||
|
||||
export function LinkPreview({ url }: { url: string }) {
|
||||
const domain = new URL(url);
|
||||
const { status, data } = useOpenGraph(url);
|
||||
const { isLoading, isError, data } = useOpenGraph(url);
|
||||
|
||||
if (status === "pending") {
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex flex-col w-full mt-1 mb-2.5 rounded-xl overflow-hidden bg-neutral-100 dark:bg-neutral-900 border border-black/5 dark:border-white/5">
|
||||
<div className="w-full h-48 animate-pulse bg-neutral-300 dark:bg-neutral-700" />
|
||||
<div className="w-full h-48 shrink-0 animate-pulse bg-neutral-300 dark:bg-neutral-700" />
|
||||
<div className="flex flex-col gap-2 px-3 py-3">
|
||||
<div className="w-2/3 h-3 rounded animate-pulse bg-neutral-300 dark:bg-neutral-700" />
|
||||
<div className="w-3/4 h-3 rounded animate-pulse bg-neutral-300 dark:bg-neutral-700" />
|
||||
@ -37,6 +37,19 @@ export function LinkPreview({ url }: { url: string }) {
|
||||
);
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<Link
|
||||
to={url}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-blue-500 hover:text-blue-600"
|
||||
>
|
||||
{url}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Link
|
||||
to={url}
|
||||
@ -50,7 +63,7 @@ export function LinkPreview({ url }: { url: string }) {
|
||||
alt={url}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
className="object-cover w-full h-48 bg-white rounded-t-lg"
|
||||
className="object-cover w-full h-48 shrink-0 bg-white rounded-t-lg"
|
||||
/>
|
||||
) : null}
|
||||
<div className="flex flex-col items-start p-3">
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { cn } from "@lume/utils";
|
||||
import * as HoverCard from "@radix-ui/react-hover-card";
|
||||
import { Link } from "react-router-dom";
|
||||
import { User } from "../user";
|
||||
import { useNoteContext } from "./provider";
|
||||
|
||||
@ -11,16 +13,47 @@ export function NoteUser({
|
||||
|
||||
return (
|
||||
<User.Provider pubkey={event.pubkey}>
|
||||
<User.Root className={cn("flex items-center gap-3", className)}>
|
||||
<User.Avatar className="size-9 shrink-0 rounded-lg object-cover ring-1 ring-neutral-200/50 dark:ring-neutral-800/50" />
|
||||
<div className="flex h-6 flex-1 items-start justify-between gap-2">
|
||||
<User.Name className="font-semibold text-neutral-950 dark:text-neutral-50" />
|
||||
<User.Time
|
||||
time={event.created_at}
|
||||
className="text-neutral-500 dark:text-neutral-400"
|
||||
/>
|
||||
</div>
|
||||
</User.Root>
|
||||
<HoverCard.Root>
|
||||
<User.Root className={cn("flex items-center gap-3", className)}>
|
||||
<HoverCard.Trigger>
|
||||
<User.Avatar className="size-9 shrink-0 rounded-lg object-cover ring-1 ring-neutral-200/50 dark:ring-neutral-800/50" />
|
||||
</HoverCard.Trigger>
|
||||
<div className="flex h-6 flex-1 items-start justify-between gap-2">
|
||||
<User.Name className="font-semibold text-neutral-950 dark:text-neutral-50" />
|
||||
<User.Time
|
||||
time={event.created_at}
|
||||
className="text-neutral-500 dark:text-neutral-400"
|
||||
/>
|
||||
</div>
|
||||
</User.Root>
|
||||
<HoverCard.Portal>
|
||||
<HoverCard.Content
|
||||
className="data-[side=bottom]:animate-slideUpAndFade w-[300px] shadow-lg shadow-neutral-500/20 rounded-xl bg-white dark:shadow-none dark:bg-neutral-900 dark:border dark:border-neutral-800 p-5 data-[state=open]:transition-all"
|
||||
sideOffset={5}
|
||||
>
|
||||
<div className="flex flex-col gap-2">
|
||||
<User.Avatar className="size-11 rounded-lg object-cover ring-1 ring-neutral-200/50 dark:ring-neutral-800/50" />
|
||||
<div className="flex flex-col gap-2">
|
||||
<div>
|
||||
<User.Name className="font-semibold leading-tight" />
|
||||
<User.NIP05
|
||||
pubkey={event.pubkey}
|
||||
className="text-neutral-600 dark:text-neutral-400"
|
||||
/>
|
||||
</div>
|
||||
<User.About className="line-clamp-3" />
|
||||
<Link
|
||||
to={`/users/${event.pubkey}`}
|
||||
className="mt-3 w-full h-8 text-sm font-medium bg-neutral-100 dark:bg-neutral-900 hover:bg-neutral-200 dark:hover:bg-neutral-800 rounded-lg inline-flex items-center justify-center"
|
||||
>
|
||||
View profile
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<HoverCard.Arrow className="fill-white dark:fill-neutral-800" />
|
||||
</HoverCard.Content>
|
||||
</HoverCard.Portal>
|
||||
</HoverCard.Root>
|
||||
</User.Provider>
|
||||
);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ export function UserName({ className }: { className?: string }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn("truncate", className)}>
|
||||
<div className={cn("max-w-[12rem] truncate", className)}>
|
||||
{user.displayName || user.name || "Anon"}
|
||||
</div>
|
||||
);
|
||||
|
@ -228,7 +228,7 @@ export const LumeProvider = ({ children }: PropsWithChildren<object>) => {
|
||||
return (
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
className="relative flex items-center justify-center w-screen h-screen"
|
||||
className="relative flex items-center justify-center w-screen h-screen bg-white dark:bg-black"
|
||||
>
|
||||
<div className="flex flex-col items-start max-w-2xl gap-1">
|
||||
<h5 className="font-semibold uppercase">TIP:</h5>
|
||||
|
@ -12,15 +12,15 @@
|
||||
"@tanstack/react-query": "^5.17.19",
|
||||
"react": "^18.2.0",
|
||||
"react-router-dom": "^6.21.3",
|
||||
"sonner": "^1.3.1",
|
||||
"virtua": "^0.21.1"
|
||||
"sonner": "^1.4.0",
|
||||
"virtua": "^0.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lume/tailwindcss": "workspace:^",
|
||||
"@lume/tsconfig": "workspace:^",
|
||||
"@lume/types": "workspace:^",
|
||||
"@types/react": "^18.2.48",
|
||||
"tailwind": "^4.0.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { Column } from "@lume/ark";
|
||||
import { GroupFeedsIcon } from "@lume/icons";
|
||||
import { IColumn } from "@lume/types";
|
||||
import { EventRoute, UserRoute } from "@lume/ui";
|
||||
import { AntenasForm } from "./components/form";
|
||||
import { HomeRoute } from "./home";
|
||||
import { EventRoute, UserRoute } from "@lume/ui";
|
||||
|
||||
export function Antenas({ column }: { column: IColumn }) {
|
||||
const colKey = `antenas-${column.id}`;
|
||||
@ -13,11 +12,7 @@ export function Antenas({ column }: { column: IColumn }) {
|
||||
<Column.Root>
|
||||
{created ? (
|
||||
<>
|
||||
<Column.Header
|
||||
id={column.id}
|
||||
title={column.title}
|
||||
icon={<GroupFeedsIcon className="size-4" />}
|
||||
/>
|
||||
<Column.Header id={column.id} title={column.title} />
|
||||
<Column.Content>
|
||||
<Column.Route
|
||||
path="/"
|
||||
|
@ -12,15 +12,15 @@
|
||||
"@tanstack/react-query": "^5.17.19",
|
||||
"react": "^18.2.0",
|
||||
"react-router-dom": "^6.21.3",
|
||||
"sonner": "^1.3.1",
|
||||
"virtua": "^0.21.1"
|
||||
"sonner": "^1.4.0",
|
||||
"virtua": "^0.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lume/tailwindcss": "workspace:^",
|
||||
"@lume/tsconfig": "workspace:^",
|
||||
"@lume/types": "workspace:^",
|
||||
"@types/react": "^18.2.48",
|
||||
"tailwind": "^4.0.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Column, useColumnContext } from "@lume/ark";
|
||||
import { ColumnIcon } from "@lume/icons";
|
||||
import { IColumn } from "@lume/types";
|
||||
import { COL_TYPES } from "@lume/utils";
|
||||
|
||||
@ -8,13 +7,9 @@ export function Default({ column }: { column: IColumn }) {
|
||||
|
||||
return (
|
||||
<Column.Root>
|
||||
<Column.Header
|
||||
id={column.id}
|
||||
title="Add columns"
|
||||
icon={<ColumnIcon className="size-4" />}
|
||||
/>
|
||||
<div className="h-full px-3 mt-3 flex flex-col gap-3 overflow-y-auto scrollbar-none">
|
||||
<div className="h-11 flex items-center gap-5">
|
||||
<Column.Header id={column.id} title="Add columns" />
|
||||
<div className="h-full flex-1 px-3 mt-3 flex flex-col gap-3 overflow-y-auto scrollbar-none">
|
||||
<div className="shrink-0 h-11 flex items-center gap-5">
|
||||
<button
|
||||
type="button"
|
||||
className="h-9 w-max px-3 text-sm font-semibold inline-flex items-center justify-center bg-neutral-100 dark:bg-neutral-900 rounded-lg"
|
||||
@ -29,7 +24,7 @@ export function Default({ column }: { column: IColumn }) {
|
||||
Community (Coming Soon)
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex flex-col rounded-xl overflow-hidden bg-neutral-50 dark:bg-neutral-950 ring-1 ring-neutral-100 dark:ring-neutral-900">
|
||||
<div className="shrink-0 flex flex-col rounded-xl overflow-hidden bg-neutral-50 dark:bg-neutral-950 ring-1 ring-neutral-100 dark:ring-neutral-900">
|
||||
<div className="h-[100px] w-full px-3 pt-3">
|
||||
<img
|
||||
src="/columns/group.jpg"
|
||||
@ -58,7 +53,7 @@ export function Default({ column }: { column: IColumn }) {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col rounded-xl overflow-hidden bg-neutral-50 dark:bg-neutral-950 ring-1 ring-neutral-100 dark:ring-neutral-900">
|
||||
<div className="shrink-0 flex flex-col rounded-xl overflow-hidden bg-neutral-50 dark:bg-neutral-950 ring-1 ring-neutral-100 dark:ring-neutral-900">
|
||||
<div className="h-[100px] w-full px-3 pt-3">
|
||||
<img
|
||||
src="/columns/antenas.jpg"
|
||||
@ -87,6 +82,106 @@ export function Default({ column }: { column: IColumn }) {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="shrink-0 flex flex-col rounded-xl overflow-hidden bg-neutral-50 dark:bg-neutral-950 ring-1 ring-neutral-100 dark:ring-neutral-900">
|
||||
<div className="h-[100px] w-full px-3 pt-3">
|
||||
<img
|
||||
src="/columns/trending-notes.jpg"
|
||||
srcSet="/columns/trending-notes@2x.jpg 2x"
|
||||
alt="trendingNotes"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
className="w-full h-auto object-cover rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
<div className="h-16 shrink-0 px-3 flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="font-semibold">Trending Notes</h1>
|
||||
<p className="max-w-[18rem] truncate text-sm text-neutral-600 dark:text-neutral-500">
|
||||
What is trending on Nostr?.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
addColumn({
|
||||
kind: COL_TYPES.trendingNotes,
|
||||
title: "",
|
||||
content: "",
|
||||
});
|
||||
}}
|
||||
className="shrink-0 w-16 h-8 rounded-lg text-sm font-semibold bg-neutral-100 dark:bg-neutral-900 text-blue-500 hover:bg-neutral-200 dark:hover:bg-neutral-800 inline-flex items-center justify-center"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="shrink-0 flex flex-col rounded-xl overflow-hidden bg-neutral-50 dark:bg-neutral-950 ring-1 ring-neutral-100 dark:ring-neutral-900">
|
||||
<div className="h-[100px] w-full px-3 pt-3">
|
||||
<img
|
||||
src="/columns/global.jpg"
|
||||
srcSet="/columns/global@2x.jpg 2x"
|
||||
alt="global"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
className="w-full h-auto object-cover rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
<div className="h-16 shrink-0 px-3 flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="font-semibold">Global</h1>
|
||||
<p className="max-w-[18rem] truncate text-sm text-neutral-600 dark:text-neutral-500">
|
||||
All things around the world.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
addColumn({
|
||||
kind: COL_TYPES.global,
|
||||
title: "",
|
||||
content: "",
|
||||
});
|
||||
}}
|
||||
className="shrink-0 w-16 h-8 rounded-lg text-sm font-semibold bg-neutral-100 dark:bg-neutral-900 text-blue-500 hover:bg-neutral-200 dark:hover:bg-neutral-800 inline-flex items-center justify-center"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="shrink-0 flex flex-col rounded-xl overflow-hidden bg-neutral-50 dark:bg-neutral-950 ring-1 ring-neutral-100 dark:ring-neutral-900">
|
||||
<div className="h-[100px] w-full px-3 pt-3">
|
||||
<img
|
||||
src="/columns/waifu.jpg"
|
||||
srcSet="/columns/waifu@2x.jpg 2x"
|
||||
alt="waifu"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
className="w-full h-auto object-cover rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
<div className="h-16 shrink-0 px-3 flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="font-semibold">Waifu</h1>
|
||||
<p className="max-w-[18rem] truncate text-sm text-neutral-600 dark:text-neutral-500">
|
||||
Show a random waifu image to boost your morale.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
addColumn({
|
||||
kind: COL_TYPES.waifu,
|
||||
title: "Waifu",
|
||||
content: "",
|
||||
});
|
||||
}}
|
||||
className="shrink-0 w-16 h-8 rounded-lg text-sm font-semibold bg-neutral-100 dark:bg-neutral-900 text-blue-500 hover:bg-neutral-200 dark:hover:bg-neutral-800 inline-flex items-center justify-center"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-3" />
|
||||
</div>
|
||||
</Column.Root>
|
||||
);
|
||||
|
@ -13,15 +13,15 @@
|
||||
"@tanstack/react-query": "^5.17.19",
|
||||
"react": "^18.2.0",
|
||||
"react-router-dom": "^6.21.3",
|
||||
"sonner": "^1.3.1",
|
||||
"virtua": "^0.21.1"
|
||||
"sonner": "^1.4.0",
|
||||
"virtua": "^0.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lume/tailwindcss": "workspace:^",
|
||||
"@lume/tsconfig": "workspace:^",
|
||||
"@lume/types": "workspace:^",
|
||||
"@types/react": "^18.2.48",
|
||||
"tailwind": "^4.0.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Column } from "@lume/ark";
|
||||
import { ForyouIcon } from "@lume/icons";
|
||||
import { useStorage } from "@lume/storage";
|
||||
import { IColumn } from "@lume/types";
|
||||
import { EventRoute, UserRoute } from "@lume/ui";
|
||||
@ -27,12 +26,7 @@ export function ForYou({ column }: { column: IColumn }) {
|
||||
|
||||
return (
|
||||
<Column.Root>
|
||||
<Column.Header
|
||||
id={column.id}
|
||||
queryKey={[colKey]}
|
||||
title="For You"
|
||||
icon={<ForyouIcon className="size-4" />}
|
||||
/>
|
||||
<Column.Header id={column.id} queryKey={[colKey]} title="For You" />
|
||||
{storage.interests?.hashtags ? (
|
||||
<Column.Live
|
||||
filter={{
|
||||
|
26
packages/lume-column-global/package.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@columns/global",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"main": "./src/index.tsx",
|
||||
"dependencies": {
|
||||
"@lume/ark": "workspace:^",
|
||||
"@lume/icons": "workspace:^",
|
||||
"@lume/ui": "workspace:^",
|
||||
"@lume/utils": "workspace:^",
|
||||
"@nostr-dev-kit/ndk": "^2.3.3",
|
||||
"@tanstack/react-query": "^5.17.19",
|
||||
"react": "^18.2.0",
|
||||
"react-router-dom": "^6.21.3",
|
||||
"sonner": "^1.4.0",
|
||||
"virtua": "^0.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lume/tailwindcss": "workspace:^",
|
||||
"@lume/tsconfig": "workspace:^",
|
||||
"@lume/types": "workspace:^",
|
||||
"@types/react": "^18.2.48",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
126
packages/lume-column-global/src/home.tsx
Normal file
@ -0,0 +1,126 @@
|
||||
import { RepostNote, TextNote, useArk } from "@lume/ark";
|
||||
import { ArrowRightCircleIcon, LoaderIcon, SearchIcon } from "@lume/icons";
|
||||
import { EmptyFeed } from "@lume/ui";
|
||||
import { FETCH_LIMIT } from "@lume/utils";
|
||||
import { type NDKEvent, NDKKind } from "@nostr-dev-kit/ndk";
|
||||
import { useInfiniteQuery } from "@tanstack/react-query";
|
||||
import { useEffect, useMemo, useRef } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { CacheSnapshot, VList, VListHandle } from "virtua";
|
||||
|
||||
export function HomeRoute({ colKey }: { colKey: string }) {
|
||||
const ark = useArk();
|
||||
const ref = useRef<VListHandle>();
|
||||
const cacheKey = `${colKey}-vlist`;
|
||||
|
||||
const [offset, cache] = useMemo(() => {
|
||||
const serialized = sessionStorage.getItem(cacheKey);
|
||||
if (!serialized) return [];
|
||||
return JSON.parse(serialized) as [number, CacheSnapshot];
|
||||
}, []);
|
||||
|
||||
const { data, hasNextPage, isLoading, isFetchingNextPage, fetchNextPage } =
|
||||
useInfiniteQuery({
|
||||
queryKey: [colKey],
|
||||
initialPageParam: 0,
|
||||
queryFn: async ({
|
||||
signal,
|
||||
pageParam,
|
||||
}: {
|
||||
signal: AbortSignal;
|
||||
pageParam: number;
|
||||
}) => {
|
||||
if (!ark.account.contacts.length) return [];
|
||||
|
||||
const events = await ark.getInfiniteEvents({
|
||||
filter: {
|
||||
kinds: [NDKKind.Text, NDKKind.Repost],
|
||||
},
|
||||
limit: FETCH_LIMIT,
|
||||
pageParam,
|
||||
signal,
|
||||
});
|
||||
|
||||
return events;
|
||||
},
|
||||
getNextPageParam: (lastPage) => {
|
||||
const lastEvent = lastPage.at(-1);
|
||||
if (!lastEvent) return;
|
||||
return lastEvent.created_at - 1;
|
||||
},
|
||||
select: (data) => data?.pages.flatMap((page) => page),
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnMount: false,
|
||||
});
|
||||
|
||||
const renderItem = (event: NDKEvent) => {
|
||||
switch (event.kind) {
|
||||
case NDKKind.Text:
|
||||
return <TextNote key={event.id} event={event} className="mt-3" />;
|
||||
case NDKKind.Repost:
|
||||
return <RepostNote key={event.id} event={event} className="mt-3" />;
|
||||
default:
|
||||
return <TextNote key={event.id} event={event} className="mt-3" />;
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!ref.current) return;
|
||||
const handle = ref.current;
|
||||
|
||||
if (offset) {
|
||||
handle.scrollTo(offset);
|
||||
}
|
||||
|
||||
return () => {
|
||||
sessionStorage.setItem(
|
||||
cacheKey,
|
||||
JSON.stringify([handle.scrollOffset, handle.cache]),
|
||||
);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="w-full h-full">
|
||||
<VList ref={ref} cache={cache} overscan={2} className="flex-1 px-3">
|
||||
{isLoading ? (
|
||||
<div className="w-full flex h-16 items-center justify-center gap-2 px-3 py-1.5">
|
||||
<LoaderIcon className="size-5 animate-spin" />
|
||||
</div>
|
||||
) : !data.length ? (
|
||||
<div className="px-3 mt-3">
|
||||
<EmptyFeed />
|
||||
<Link
|
||||
to="/suggest"
|
||||
className="mt-3 w-full gap-2 inline-flex items-center justify-center text-sm font-medium rounded-lg h-9 bg-blue-500 hover:bg-blue-600 text-white"
|
||||
>
|
||||
<SearchIcon className="size-5" />
|
||||
Find accounts to follow
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
data.map((item) => renderItem(item))
|
||||
)}
|
||||
<div className="flex items-center justify-center h-16">
|
||||
{hasNextPage ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => fetchNextPage()}
|
||||
disabled={!hasNextPage || isFetchingNextPage}
|
||||
className="inline-flex items-center justify-center w-full h-12 gap-2 font-medium bg-neutral-100 hover:bg-neutral-200 dark:bg-neutral-900 dark:hover:bg-neutral-800 rounded-xl focus:outline-none"
|
||||
>
|
||||
{isFetchingNextPage ? (
|
||||
<LoaderIcon className="size-5 animate-spin" />
|
||||
) : (
|
||||
<>
|
||||
<ArrowRightCircleIcon className="size-5" />
|
||||
Load more
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
</VList>
|
||||
</div>
|
||||
);
|
||||
}
|
19
packages/lume-column-global/src/index.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { Column } from "@lume/ark";
|
||||
import { IColumn } from "@lume/types";
|
||||
import { EventRoute, UserRoute } from "@lume/ui";
|
||||
import { HomeRoute } from "./home";
|
||||
|
||||
export function Global({ column }: { column: IColumn }) {
|
||||
const colKey = `global-${column.id}`;
|
||||
|
||||
return (
|
||||
<Column.Root>
|
||||
<Column.Header id={column.id} queryKey={[colKey]} title="Global" />
|
||||
<Column.Content>
|
||||
<Column.Route path="/" element={<HomeRoute colKey={colKey} />} />
|
||||
<Column.Route path="/events/:id" element={<EventRoute />} />
|
||||
<Column.Route path="/users/:id" element={<UserRoute />} />
|
||||
</Column.Content>
|
||||
</Column.Root>
|
||||
);
|
||||
}
|
8
packages/lume-column-global/tailwind.config.js
Normal file
@ -0,0 +1,8 @@
|
||||
import sharedConfig from "@lume/tailwindcss";
|
||||
|
||||
const config = {
|
||||
content: ["./src/**/*.{js,ts,jsx,tsx}"],
|
||||
presets: [sharedConfig],
|
||||
};
|
||||
|
||||
export default config;
|
8
packages/lume-column-global/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "@lume/tsconfig/base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
@ -12,15 +12,15 @@
|
||||
"@tanstack/react-query": "^5.17.19",
|
||||
"react": "^18.2.0",
|
||||
"react-router-dom": "^6.21.3",
|
||||
"sonner": "^1.3.1",
|
||||
"virtua": "^0.21.1"
|
||||
"sonner": "^1.4.0",
|
||||
"virtua": "^0.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lume/tailwindcss": "workspace:^",
|
||||
"@lume/tsconfig": "workspace:^",
|
||||
"@lume/types": "workspace:^",
|
||||
"@types/react": "^18.2.48",
|
||||
"tailwind": "^4.0.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { Column } from "@lume/ark";
|
||||
import { GroupFeedsIcon } from "@lume/icons";
|
||||
import { IColumn } from "@lume/types";
|
||||
import { EventRoute, UserRoute } from "@lume/ui";
|
||||
import { GroupForm } from "./components/form";
|
||||
import { HomeRoute } from "./home";
|
||||
import { EventRoute, UserRoute } from "@lume/ui";
|
||||
|
||||
export function Group({ column }: { column: IColumn }) {
|
||||
const colKey = `group-${column.id}`;
|
||||
@ -13,11 +12,7 @@ export function Group({ column }: { column: IColumn }) {
|
||||
<Column.Root>
|
||||
{created ? (
|
||||
<>
|
||||
<Column.Header
|
||||
id={column.id}
|
||||
title={column.title}
|
||||
icon={<GroupFeedsIcon className="size-4" />}
|
||||
/>
|
||||
<Column.Header id={column.id} title={column.title} />
|
||||
<Column.Content>
|
||||
<Column.Route
|
||||
path="/"
|
||||
|
@ -12,15 +12,15 @@
|
||||
"@tanstack/react-query": "^5.17.19",
|
||||
"react": "^18.2.0",
|
||||
"react-router-dom": "^6.21.3",
|
||||
"sonner": "^1.3.1",
|
||||
"virtua": "^0.21.1"
|
||||
"sonner": "^1.4.0",
|
||||
"virtua": "^0.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lume/tailwindcss": "workspace:^",
|
||||
"@lume/tsconfig": "workspace:^",
|
||||
"@lume/types": "workspace:^",
|
||||
"@types/react": "^18.2.48",
|
||||
"tailwind": "^4.0.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { Column } from "@lume/ark";
|
||||
import { HashtagIcon } from "@lume/icons";
|
||||
import { IColumn } from "@lume/types";
|
||||
import { HomeRoute } from "./home";
|
||||
import { EventRoute, UserRoute } from "@lume/ui";
|
||||
import { HomeRoute } from "./home";
|
||||
|
||||
export function Hashtag({ column }: { column: IColumn }) {
|
||||
const colKey = `hashtag-${column.id}`;
|
||||
@ -10,12 +9,7 @@ export function Hashtag({ column }: { column: IColumn }) {
|
||||
|
||||
return (
|
||||
<Column.Root>
|
||||
<Column.Header
|
||||
id={column.id}
|
||||
queryKey={[colKey]}
|
||||
title={hashtag}
|
||||
icon={<HashtagIcon className="size-4" />}
|
||||
/>
|
||||
<Column.Header id={column.id} queryKey={[colKey]} title={hashtag} />
|
||||
<Column.Content>
|
||||
<Column.Route
|
||||
path="/"
|
||||
|
@ -12,15 +12,15 @@
|
||||
"@tanstack/react-query": "^5.17.19",
|
||||
"react": "^18.2.0",
|
||||
"react-router-dom": "^6.21.3",
|
||||
"sonner": "^1.3.1",
|
||||
"virtua": "^0.21.1"
|
||||
"sonner": "^1.4.0",
|
||||
"virtua": "^0.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lume/tailwindcss": "workspace:^",
|
||||
"@lume/tsconfig": "workspace:^",
|
||||
"@lume/types": "workspace:^",
|
||||
"@types/react": "^18.2.48",
|
||||
"tailwind": "^4.0.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
||||
|
@ -12,15 +12,15 @@
|
||||
"@tanstack/react-query": "^5.17.19",
|
||||
"react": "^18.2.0",
|
||||
"react-router-dom": "^6.21.3",
|
||||
"sonner": "^1.3.1",
|
||||
"virtua": "^0.21.1"
|
||||
"sonner": "^1.4.0",
|
||||
"virtua": "^0.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lume/tailwindcss": "workspace:^",
|
||||
"@lume/tsconfig": "workspace:^",
|
||||
"@lume/types": "workspace:^",
|
||||
"@types/react": "^18.2.48",
|
||||
"tailwind": "^4.0.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { ArrowRightCircleIcon, LoaderIcon, SearchIcon } from "@lume/icons";
|
||||
import { EmptyFeed } from "@lume/ui";
|
||||
import { FETCH_LIMIT } from "@lume/utils";
|
||||
import { NDKEvent, NDKKind } from "@nostr-dev-kit/ndk";
|
||||
import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useInfiniteQuery } from "@tanstack/react-query";
|
||||
import { useEffect, useMemo, useRef } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { CacheSnapshot, VList, VListHandle } from "virtua";
|
||||
@ -12,7 +12,6 @@ export function HomeRoute({ colKey }: { colKey: string }) {
|
||||
const ark = useArk();
|
||||
const ref = useRef<VListHandle>();
|
||||
const cacheKey = `${colKey}-vlist`;
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const [offset, cache] = useMemo(() => {
|
||||
const serialized = sessionStorage.getItem(cacheKey);
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Column, useArk } from "@lume/ark";
|
||||
import { TimelineIcon } from "@lume/icons";
|
||||
import { IColumn } from "@lume/types";
|
||||
import { EventRoute, SuggestRoute, UserRoute } from "@lume/ui";
|
||||
import { NDKEvent, NDKKind } from "@nostr-dev-kit/ndk";
|
||||
@ -26,12 +25,7 @@ export function Timeline({ column }: { column: IColumn }) {
|
||||
|
||||
return (
|
||||
<Column.Root>
|
||||
<Column.Header
|
||||
id={column.id}
|
||||
queryKey={[colKey]}
|
||||
title="Timeline"
|
||||
icon={<TimelineIcon className="size-5" />}
|
||||
/>
|
||||
<Column.Header id={column.id} queryKey={[colKey]} title="Timeline" />
|
||||
{ark.account.contacts.length ? (
|
||||
<Column.Live
|
||||
filter={{
|
||||
|
26
packages/lume-column-trending-notes/package.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@columns/trending-notes",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"main": "./src/index.tsx",
|
||||
"dependencies": {
|
||||
"@lume/ark": "workspace:^",
|
||||
"@lume/icons": "workspace:^",
|
||||
"@lume/ui": "workspace:^",
|
||||
"@lume/utils": "workspace:^",
|
||||
"@nostr-dev-kit/ndk": "^2.3.3",
|
||||
"@tanstack/react-query": "^5.17.19",
|
||||
"react": "^18.2.0",
|
||||
"react-router-dom": "^6.21.3",
|
||||
"sonner": "^1.4.0",
|
||||
"virtua": "^0.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lume/tailwindcss": "workspace:^",
|
||||
"@lume/tsconfig": "workspace:^",
|
||||
"@lume/types": "workspace:^",
|
||||
"@types/react": "^18.2.48",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
71
packages/lume-column-trending-notes/src/home.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import { TextNote, useArk } from "@lume/ark";
|
||||
import { LoaderIcon } from "@lume/icons";
|
||||
import { type NDKEvent, type NostrEvent } from "@nostr-dev-kit/ndk";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { fetch } from "@tauri-apps/plugin-http";
|
||||
import { useEffect, useMemo, useRef } from "react";
|
||||
import { CacheSnapshot, VList, VListHandle } from "virtua";
|
||||
|
||||
export function HomeRoute({ colKey }: { colKey: string }) {
|
||||
const ark = useArk();
|
||||
const ref = useRef<VListHandle>();
|
||||
const cacheKey = `${colKey}-vlist`;
|
||||
|
||||
const [offset, cache] = useMemo(() => {
|
||||
const serialized = sessionStorage.getItem(cacheKey);
|
||||
if (!serialized) return [];
|
||||
return JSON.parse(serialized) as [number, CacheSnapshot];
|
||||
}, []);
|
||||
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: [colKey],
|
||||
queryFn: async ({ signal }: { signal: AbortSignal }) => {
|
||||
const res = await fetch("https://api.nostr.band/v0/trending/notes", {
|
||||
signal,
|
||||
});
|
||||
|
||||
if (!res) throw new Error("Failed to fetch trending notes");
|
||||
|
||||
const data = await res.json();
|
||||
const events = data.notes.map((item: { event: NostrEvent }) =>
|
||||
ark.getNDKEvent(item.event),
|
||||
);
|
||||
|
||||
return events as NDKEvent[];
|
||||
},
|
||||
refetchOnMount: false,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!ref.current) return;
|
||||
const handle = ref.current;
|
||||
|
||||
if (offset) {
|
||||
handle.scrollTo(offset);
|
||||
}
|
||||
|
||||
return () => {
|
||||
sessionStorage.setItem(
|
||||
cacheKey,
|
||||
JSON.stringify([handle.scrollOffset, handle.cache]),
|
||||
);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="w-full h-full">
|
||||
<VList ref={ref} cache={cache} overscan={2} className="flex-1 px-3">
|
||||
{isLoading ? (
|
||||
<div className="w-full flex h-16 items-center justify-center gap-2 px-3 py-1.5">
|
||||
<LoaderIcon className="size-5 animate-spin" />
|
||||
</div>
|
||||
) : (
|
||||
data.map((item) => (
|
||||
<TextNote key={item.id} event={item} className="mt-3" />
|
||||
))
|
||||
)}
|
||||
</VList>
|
||||
</div>
|
||||
);
|
||||
}
|
23
packages/lume-column-trending-notes/src/index.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import { Column } from "@lume/ark";
|
||||
import { IColumn } from "@lume/types";
|
||||
import { EventRoute, UserRoute } from "@lume/ui";
|
||||
import { HomeRoute } from "./home";
|
||||
|
||||
export function TrendingNotes({ column }: { column: IColumn }) {
|
||||
const colKey = `trending-notes-${column.id}`;
|
||||
|
||||
return (
|
||||
<Column.Root>
|
||||
<Column.Header
|
||||
id={column.id}
|
||||
queryKey={[colKey]}
|
||||
title="Trending Notes"
|
||||
/>
|
||||
<Column.Content>
|
||||
<Column.Route path="/" element={<HomeRoute colKey={colKey} />} />
|
||||
<Column.Route path="/events/:id" element={<EventRoute />} />
|
||||
<Column.Route path="/users/:id" element={<UserRoute />} />
|
||||
</Column.Content>
|
||||
</Column.Root>
|
||||
);
|
||||
}
|
8
packages/lume-column-trending-notes/tailwind.config.js
Normal file
@ -0,0 +1,8 @@
|
||||
import sharedConfig from "@lume/tailwindcss";
|
||||
|
||||
const config = {
|
||||
content: ["./src/**/*.{js,ts,jsx,tsx}"],
|
||||
presets: [sharedConfig],
|
||||
};
|
||||
|
||||
export default config;
|
8
packages/lume-column-trending-notes/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "@lume/tsconfig/base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
@ -12,15 +12,15 @@
|
||||
"@tanstack/react-query": "^5.17.19",
|
||||
"react": "^18.2.0",
|
||||
"react-router-dom": "^6.21.3",
|
||||
"sonner": "^1.3.1",
|
||||
"virtua": "^0.21.1"
|
||||
"sonner": "^1.4.0",
|
||||
"virtua": "^0.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lume/tailwindcss": "workspace:^",
|
||||
"@lume/tsconfig": "workspace:^",
|
||||
"@lume/types": "workspace:^",
|
||||
"@types/react": "^18.2.48",
|
||||
"tailwind": "^4.0.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,12 @@
|
||||
import { Column } from "@lume/ark";
|
||||
import { UserIcon } from "@lume/icons";
|
||||
import { IColumn } from "@lume/types";
|
||||
import { HomeRoute } from "./home";
|
||||
import { EventRoute, UserRoute } from "@lume/ui";
|
||||
import { HomeRoute } from "./home";
|
||||
|
||||
export function User({ column }: { column: IColumn }) {
|
||||
return (
|
||||
<Column.Root>
|
||||
<Column.Header
|
||||
id={column.id}
|
||||
title={column.title}
|
||||
icon={<UserIcon className="size-4" />}
|
||||
/>
|
||||
<Column.Header id={column.id} title={column.title} />
|
||||
<Column.Content>
|
||||
<Column.Route path="/" element={<HomeRoute id={column.content} />} />
|
||||
<Column.Route path="/events/:id" element={<EventRoute />} />
|
||||
|
23
packages/lume-column-waifu/package.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "@columns/waifu",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"main": "./src/index.tsx",
|
||||
"dependencies": {
|
||||
"@lume/ark": "workspace:^",
|
||||
"@lume/icons": "workspace:^",
|
||||
"@lume/ui": "workspace:^",
|
||||
"@lume/utils": "workspace:^",
|
||||
"@tanstack/react-query": "^5.17.19",
|
||||
"react": "^18.2.0",
|
||||
"react-router-dom": "^6.21.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lume/tailwindcss": "workspace:^",
|
||||
"@lume/tsconfig": "workspace:^",
|
||||
"@lume/types": "workspace:^",
|
||||
"@types/react": "^18.2.48",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
69
packages/lume-column-waifu/src/home.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
import { LoaderIcon, RefreshIcon } from "@lume/icons";
|
||||
import { cn } from "@lume/utils";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
export function HomeRoute({ colKey }: { colKey: string }) {
|
||||
const { data, isLoading, isError, isRefetching, refetch } = useQuery({
|
||||
queryKey: [colKey],
|
||||
queryFn: async ({ signal }: { signal: AbortSignal }) => {
|
||||
const apiUrl = "https://api.waifu.im/search";
|
||||
const params = {
|
||||
included_tags: "waifu",
|
||||
height: ">=2000",
|
||||
};
|
||||
|
||||
const queryParams = new URLSearchParams(params);
|
||||
const requestUrl = `${apiUrl}?${queryParams}`;
|
||||
|
||||
const res = await fetch(requestUrl, { signal });
|
||||
|
||||
if (!res.ok) throw new Error("Failed to get image url");
|
||||
|
||||
const data = await res.json();
|
||||
return data.images[0];
|
||||
},
|
||||
refetchOnMount: false,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="p-3 h-full flex flex-col justify-center items-center">
|
||||
{isLoading ? (
|
||||
<LoaderIcon className="size-5 animate-spin" />
|
||||
) : isError ? (
|
||||
<p className="text-center text-sm font-medium">
|
||||
Failed to get image, please try again later.
|
||||
</p>
|
||||
) : (
|
||||
<div className="relative min-h-0 flex-1 grow-0 w-full rounded-xl flex items-stretch">
|
||||
<img
|
||||
src={data.url}
|
||||
alt={data.signature}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
className="object-cover w-full rounded-xl ring-1 ring-black/5 dark:ring-white/5"
|
||||
/>
|
||||
<div className="absolute bottom-3 right-3 flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => refetch()}
|
||||
className="text-sm font-medium px-2 h-7 inline-flex items-center justify-center bg-black/50 hover:bg-black/30 backdrop-blur-2xl rounded-md text-white"
|
||||
>
|
||||
<RefreshIcon
|
||||
className={cn("size-4", isRefetching ? "animate-spin" : "")}
|
||||
/>
|
||||
</button>
|
||||
<a
|
||||
href={data.source}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-sm font-medium px-2 h-7 inline-flex items-center justify-center bg-black/50 hover:bg-black/30 backdrop-blur-2xl rounded-md text-white"
|
||||
>
|
||||
Source
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
16
packages/lume-column-waifu/src/index.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { Column } from "@lume/ark";
|
||||
import { IColumn } from "@lume/types";
|
||||
import { HomeRoute } from "./home";
|
||||
|
||||
export function Waifu({ column }: { column: IColumn }) {
|
||||
const colKey = `waifu-${column.id}`;
|
||||
|
||||
return (
|
||||
<Column.Root>
|
||||
<Column.Header id={column.id} title={column.title} />
|
||||
<Column.Content>
|
||||
<Column.Route path="/" element={<HomeRoute colKey={colKey} />} />
|
||||
</Column.Content>
|
||||
</Column.Root>
|
||||
);
|
||||
}
|
8
packages/lume-column-waifu/tailwind.config.js
Normal file
@ -0,0 +1,8 @@
|
||||
import sharedConfig from "@lume/tailwindcss";
|
||||
|
||||
const config = {
|
||||
content: ["./src/**/*.{js,ts,jsx,tsx}"],
|
||||
presets: [sharedConfig],
|
||||
};
|
||||
|
||||
export default config;
|
8
packages/lume-column-waifu/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "@lume/tsconfig/base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
"dependencies": {
|
||||
"@lume/storage": "workspace:*",
|
||||
"@nostr-dev-kit/ndk": "^2.3.3",
|
||||
"lru-cache": "^10.1.0",
|
||||
"lru-cache": "^10.2.0",
|
||||
"nostr-fetch": "^0.15.0",
|
||||
"nostr-tools": "1.17.0",
|
||||
"react": "^18.2.0"
|
||||
|
@ -18,7 +18,7 @@
|
||||
"@radix-ui/react-hover-card": "^1.0.7",
|
||||
"@radix-ui/react-popover": "^1.0.7",
|
||||
"@tanstack/react-query": "^5.17.19",
|
||||
"framer-motion": "^10.18.0",
|
||||
"framer-motion": "^11.0.3",
|
||||
"jotai": "^2.6.3",
|
||||
"minidenticons": "^4.2.0",
|
||||
"nostr-tools": "~1.17.0",
|
||||
@ -30,10 +30,10 @@
|
||||
"react-router-dom": "^6.21.3",
|
||||
"slate": "^0.101.5",
|
||||
"slate-react": "^0.101.6",
|
||||
"sonner": "^1.3.1",
|
||||
"sonner": "^1.4.0",
|
||||
"uqr": "^0.1.2",
|
||||
"use-debounce": "^10.0.0",
|
||||
"virtua": "^0.21.1"
|
||||
"virtua": "^0.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lume/tailwindcss": "workspace:^",
|
||||
|
@ -159,7 +159,7 @@ export function SearchDialog() {
|
||||
</Command.Group>
|
||||
</>
|
||||
)}
|
||||
{!loading ? (
|
||||
{!loading && !events.length ? (
|
||||
<div className="h-full flex items-center justify-center flex-col gap-3">
|
||||
<div className="size-16 bg-blue-100 dark:bg-blue-900 rounded-full inline-flex items-center justify-center text-blue-500">
|
||||
<SearchIcon className="size-6" />
|
||||
|
@ -57,9 +57,9 @@ export const COL_TYPES = {
|
||||
hashtag: 3,
|
||||
group: 4,
|
||||
antenas: 5,
|
||||
topic: 6,
|
||||
global: 6,
|
||||
trendingNotes: 9000,
|
||||
trendingAccounts: 9001,
|
||||
waifu: 9001,
|
||||
foryou: 9998,
|
||||
newsfeed: 9999,
|
||||
};
|
||||
|
@ -3,10 +3,10 @@ import { useQuery } from "@tanstack/react-query";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
export function useOpenGraph(url: string) {
|
||||
const { status, data, error } = useQuery({
|
||||
const { isLoading, isError, data } = useQuery({
|
||||
queryKey: ["opg", url],
|
||||
queryFn: async () => {
|
||||
const res: Opengraph = await invoke("opengraph", { url });
|
||||
const res: Opengraph = await invoke("fetch_opg", { url });
|
||||
if (!res) {
|
||||
throw new Error("fetch preview failed");
|
||||
}
|
||||
@ -19,8 +19,8 @@ export function useOpenGraph(url: string) {
|
||||
});
|
||||
|
||||
return {
|
||||
status,
|
||||
isLoading,
|
||||
isError,
|
||||
data,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
1855
pnpm-lock.yaml
generated
@ -1,25 +0,0 @@
|
||||
const fs = require('fs')
|
||||
|
||||
let extension = ''
|
||||
if (process.platform === 'win32') {
|
||||
extension = '.exe'
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const host = Bun.spawn(["rustc", '-vV']);
|
||||
const stdoutStr = await new Response(host.stdout).text();
|
||||
const targetTriple = /host: (\S+)/g.exec(stdoutStr)[1]
|
||||
|
||||
if (!targetTriple) {
|
||||
console.error('Failed to determine platform target triple')
|
||||
}
|
||||
|
||||
fs.renameSync(
|
||||
`src-tauri/bins/depot${extension}`,
|
||||
`src-tauri/bins/depot-${targetTriple}${extension}`,
|
||||
)
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
throw e
|
||||
})
|
91
src-tauri/Cargo.lock
generated
@ -114,9 +114,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.4"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
|
||||
checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
@ -242,9 +242,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb41eb19024a91746eba0773aa5e16036045bbf45733766661099e182ea6a744"
|
||||
checksum = "8f97ab0c5b00a7cdbe5a371b9a782ee7be1316095885c8a4ea1daf490eb0ef65"
|
||||
dependencies = [
|
||||
"async-lock 3.3.0",
|
||||
"cfg-if",
|
||||
@ -313,7 +313,7 @@ version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5"
|
||||
dependencies = [
|
||||
"async-io 2.3.0",
|
||||
"async-io 2.3.1",
|
||||
"async-lock 2.8.0",
|
||||
"atomic-waker",
|
||||
"cfg-if",
|
||||
@ -705,9 +705,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.32"
|
||||
version = "0.4.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41daef31d7a747c5c847246f36de49ced6f7403b4cdabc807a97b5cc184cda7a"
|
||||
checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
@ -1067,9 +1067,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.3"
|
||||
version = "0.20.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
|
||||
checksum = "da01daa5f6d41c91358398e8db4dde38e292378da1f28300b59ef4732b879454"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
@ -1077,9 +1077,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.3"
|
||||
version = "0.20.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
|
||||
checksum = "f44f6238b948a3c6c3073cdf53bb0c2d5e024ee27e0f35bfe9d556a12395808a"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
@ -1091,9 +1091,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.3"
|
||||
version = "0.20.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
||||
checksum = "0d2d88bd93979b1feb760a6b5c531ac5ba06bd63e74894c377af02faee07b9cd"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
@ -1953,7 +1953,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-crate 2.0.1",
|
||||
"proc-macro-crate 2.0.2",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2072,7 +2072,7 @@ dependencies = [
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http",
|
||||
"indexmap 2.1.0",
|
||||
"indexmap 2.2.1",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
@ -2319,9 +2319,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.1.0"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||
checksum = "433de089bd45971eecf4668ee0ee8f4cec17db4f8bd8f7bc3197a6ce37aa7d9b"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.3",
|
||||
@ -2393,9 +2393,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.0"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
@ -2506,9 +2506,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "keyring"
|
||||
version = "2.3.1"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85b479dcf9eae65481044dfda57af7fe2da6c1401180360f6898801fe9ed4db9"
|
||||
checksum = "1be8bc4c6b6e9d85ecdad090fcf342a9216f53d747a537cc05e3452fd650ca46"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"lazy_static",
|
||||
@ -2610,9 +2610,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.1.14"
|
||||
version = "1.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "295c17e837573c8c821dbaeb3cceb3d745ad082f7572191409e69cbc1b3fd050"
|
||||
checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@ -3599,7 +3599,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"indexmap 2.1.0",
|
||||
"indexmap 2.2.1",
|
||||
"line-wrap",
|
||||
"quick-xml 0.31.0",
|
||||
"serde",
|
||||
@ -3679,9 +3679,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a"
|
||||
checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24"
|
||||
dependencies = [
|
||||
"toml_datetime",
|
||||
"toml_edit 0.20.2",
|
||||
@ -3898,7 +3898,7 @@ checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata 0.4.4",
|
||||
"regex-automata 0.4.5",
|
||||
"regex-syntax 0.8.2",
|
||||
]
|
||||
|
||||
@ -3913,9 +3913,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.4"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a"
|
||||
checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@ -4204,18 +4204,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.195"
|
||||
version = "1.0.196"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
|
||||
checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.195"
|
||||
version = "1.0.196"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
|
||||
checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -4224,9 +4224,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.111"
|
||||
version = "1.0.113"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4"
|
||||
checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79"
|
||||
dependencies = [
|
||||
"itoa 1.0.10",
|
||||
"ryu",
|
||||
@ -4275,7 +4275,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"hex",
|
||||
"indexmap 1.9.3",
|
||||
"indexmap 2.1.0",
|
||||
"indexmap 2.2.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with_macros",
|
||||
@ -4555,7 +4555,7 @@ dependencies = [
|
||||
"futures-util",
|
||||
"hashlink",
|
||||
"hex",
|
||||
"indexmap 2.1.0",
|
||||
"indexmap 2.2.1",
|
||||
"log",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
@ -5630,7 +5630,7 @@ version = "0.19.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
||||
dependencies = [
|
||||
"indexmap 2.1.0",
|
||||
"indexmap 2.2.1",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
@ -5643,7 +5643,7 @@ version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
|
||||
dependencies = [
|
||||
"indexmap 2.1.0",
|
||||
"indexmap 2.2.1",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
@ -5720,9 +5720,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tray-icon"
|
||||
version = "0.11.1"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fad962d06d2bfd9b2ab4f665fc73b175523b834b1466a294520201c5845145f8"
|
||||
checksum = "fd26786733426b0bf632ebab410c162859a911f26c7c9e208b9e329a8ca94481"
|
||||
dependencies = [
|
||||
"cocoa",
|
||||
"core-graphics 0.23.1",
|
||||
@ -6064,15 +6064,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webpage"
|
||||
version = "1.6.0"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8598785beeb5af95abe95e7bb20c7e747d1188347080d6811d5a56d2b9a5f368"
|
||||
checksum = "3fb86b12e58d490a99867f561ce8466ffa7b73e24d015a8e7f5bc111d4424ba2"
|
||||
dependencies = [
|
||||
"curl",
|
||||
"html5ever",
|
||||
"markup5ever_rcdom",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6456,9 +6457,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.34"
|
||||
version = "0.5.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16"
|
||||
checksum = "1931d78a9c73861da0134f453bb1f790ce49b2e30eba8410b4b79bac72b46a2d"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
@ -6,7 +6,7 @@ authors = ["Ren Amamiya"]
|
||||
license = "GPL-3.0"
|
||||
repository = "https://github.com/luminous-devs/lume"
|
||||
edition = "2021"
|
||||
rust-version = "1.66"
|
||||
rust-version = "1.70"
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2.0.0-alpha", features = [] }
|
||||
@ -40,9 +40,14 @@ tauri-plugin-sql = {version="2.0.0-alpha", features = [
|
||||
sqlx-cli = { version = "0.7.0", default-features = false, features = [
|
||||
"sqlite",
|
||||
] }
|
||||
webpage = { version = "1.6.0", features = ["serde"] }
|
||||
webpage = { version = "2.0", features = ["serde"] }
|
||||
|
||||
[target.'cfg(not(target_os = "linux"))'.dependencies]
|
||||
keyring = "2"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
keyring = { version = "2", default_features = false, features = ["linux-secret-service"] }
|
||||
|
||||
[features]
|
||||
# by default Tauri runs in production mode
|
||||
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
|
||||
|
@ -1,140 +1,3 @@
|
||||
use keyring::Entry;
|
||||
use std::process::Command;
|
||||
use std::time::Duration;
|
||||
use webpage::{Webpage, WebpageOptions};
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn show_in_folder(path: String) {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
Command::new("explorer")
|
||||
.args(["/select,", &path]) // The comma after select is not a typo
|
||||
.spawn()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
use std::fs::metadata;
|
||||
use std::path::PathBuf;
|
||||
if path.contains(",") {
|
||||
// see https://gitlab.freedesktop.org/dbus/dbus/-/issues/76
|
||||
let new_path = match metadata(&path).unwrap().is_dir() {
|
||||
true => path,
|
||||
false => {
|
||||
let mut path2 = PathBuf::from(path);
|
||||
path2.pop();
|
||||
path2.into_os_string().into_string().unwrap()
|
||||
}
|
||||
};
|
||||
Command::new("xdg-open").arg(&new_path).spawn().unwrap();
|
||||
} else {
|
||||
Command::new("dbus-send")
|
||||
.args([
|
||||
"--session",
|
||||
"--dest=org.freedesktop.FileManager1",
|
||||
"--type=method_call",
|
||||
"/org/freedesktop/FileManager1",
|
||||
"org.freedesktop.FileManager1.ShowItems",
|
||||
format!("array:string:file://{path}").as_str(),
|
||||
"string:\"\"",
|
||||
])
|
||||
.spawn()
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
Command::new("open").args(["-R", &path]).spawn().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
pub struct OpenGraphResponse {
|
||||
title: String,
|
||||
description: String,
|
||||
url: String,
|
||||
image: String,
|
||||
}
|
||||
|
||||
pub async fn fetch_opengraph(url: String) -> OpenGraphResponse {
|
||||
let options = WebpageOptions {
|
||||
allow_insecure: false,
|
||||
max_redirections: 3,
|
||||
timeout: Duration::from_secs(15),
|
||||
useragent: "lume - desktop app".to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let result = match Webpage::from_url(&url, options) {
|
||||
Ok(webpage) => webpage,
|
||||
Err(_) => {
|
||||
return OpenGraphResponse {
|
||||
title: "".to_string(),
|
||||
description: "".to_string(),
|
||||
url: "".to_string(),
|
||||
image: "".to_string(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let html = result.html;
|
||||
|
||||
return OpenGraphResponse {
|
||||
title: html
|
||||
.opengraph
|
||||
.properties
|
||||
.get("title")
|
||||
.cloned()
|
||||
.unwrap_or_default(),
|
||||
description: html
|
||||
.opengraph
|
||||
.properties
|
||||
.get("description")
|
||||
.cloned()
|
||||
.unwrap_or_default(),
|
||||
url: html
|
||||
.opengraph
|
||||
.properties
|
||||
.get("url")
|
||||
.cloned()
|
||||
.unwrap_or_default(),
|
||||
image: html
|
||||
.opengraph
|
||||
.images
|
||||
.get(0)
|
||||
.and_then(|i| Some(i.url.clone()))
|
||||
.unwrap_or_default(),
|
||||
};
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn opengraph(url: String) -> OpenGraphResponse {
|
||||
let result = fetch_opengraph(url).await;
|
||||
return result;
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn secure_save(key: String, value: String) -> Result<(), ()> {
|
||||
let entry = Entry::new("Lume", &key).expect("Failed to create entry");
|
||||
let _ = entry.set_password(&value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn secure_load(key: String) -> Result<String, String> {
|
||||
let entry = Entry::new("Lume", &key).expect("Failed to create entry");
|
||||
if let Ok(password) = entry.get_password() {
|
||||
Ok(password)
|
||||
} else {
|
||||
Err("not found".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn secure_remove(key: String) -> Result<(), ()> {
|
||||
let entry = Entry::new("Lume", &key).expect("Failed to create entry");
|
||||
let _ = entry.delete_password();
|
||||
Ok(())
|
||||
}
|
||||
pub mod folder;
|
||||
pub mod opg;
|
||||
pub mod secret;
|
||||
|
48
src-tauri/src/commands/folder.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use std::process::Command;
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn show_in_folder(path: String) {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
Command::new("explorer")
|
||||
.args(["/select,", &path]) // The comma after select is not a typo
|
||||
.spawn()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
use std::fs::metadata;
|
||||
use std::path::PathBuf;
|
||||
if path.contains(",") {
|
||||
// see https://gitlab.freedesktop.org/dbus/dbus/-/issues/76
|
||||
let new_path = match metadata(&path).unwrap().is_dir() {
|
||||
true => path,
|
||||
false => {
|
||||
let mut path2 = PathBuf::from(path);
|
||||
path2.pop();
|
||||
path2.into_os_string().into_string().unwrap()
|
||||
}
|
||||
};
|
||||
Command::new("xdg-open").arg(&new_path).spawn().unwrap();
|
||||
} else {
|
||||
Command::new("dbus-send")
|
||||
.args([
|
||||
"--session",
|
||||
"--dest=org.freedesktop.FileManager1",
|
||||
"--type=method_call",
|
||||
"/org/freedesktop/FileManager1",
|
||||
"org.freedesktop.FileManager1.ShowItems",
|
||||
format!("array:string:file://{path}").as_str(),
|
||||
"string:\"\"",
|
||||
])
|
||||
.spawn()
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
Command::new("open").args(["-R", &path]).spawn().unwrap();
|
||||
}
|
||||
}
|
50
src-tauri/src/commands/opg.rs
Normal file
@ -0,0 +1,50 @@
|
||||
use std::time::Duration;
|
||||
use webpage::{Webpage, WebpageOptions};
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
pub struct OpenGraphResponse {
|
||||
title: String,
|
||||
description: String,
|
||||
url: String,
|
||||
image: String,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn fetch_opg(url: String) -> Result<OpenGraphResponse, ()> {
|
||||
let mut options = WebpageOptions::default();
|
||||
options.allow_insecure = true;
|
||||
options.max_redirections = 3;
|
||||
options.timeout = Duration::from_secs(15);
|
||||
|
||||
let info = Webpage::from_url(&url, options).expect("Failed");
|
||||
let html = info.html;
|
||||
|
||||
let result = OpenGraphResponse {
|
||||
title: html
|
||||
.opengraph
|
||||
.properties
|
||||
.get("title")
|
||||
.cloned()
|
||||
.unwrap_or_default(),
|
||||
description: html
|
||||
.opengraph
|
||||
.properties
|
||||
.get("description")
|
||||
.cloned()
|
||||
.unwrap_or_default(),
|
||||
url: html
|
||||
.opengraph
|
||||
.properties
|
||||
.get("url")
|
||||
.cloned()
|
||||
.unwrap_or_default(),
|
||||
image: html
|
||||
.opengraph
|
||||
.images
|
||||
.get(0)
|
||||
.and_then(|i| Some(i.url.clone()))
|
||||
.unwrap_or_default(),
|
||||
};
|
||||
|
||||
Ok(result.into())
|
||||
}
|
25
src-tauri/src/commands/secret.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use keyring::Entry;
|
||||
|
||||
#[tauri::command]
|
||||
pub fn secure_save(key: String, value: String) -> Result<(), ()> {
|
||||
let entry = Entry::new("Lume", &key).expect("Failed to create entry");
|
||||
let _ = entry.set_password(&value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn secure_load(key: String) -> Result<String, String> {
|
||||
let entry = Entry::new("Lume", &key).expect("Failed to create entry");
|
||||
if let Ok(password) = entry.get_password() {
|
||||
Ok(password.into())
|
||||
} else {
|
||||
Err("Not found".into())
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn secure_remove(key: String) -> Result<(), ()> {
|
||||
let entry = Entry::new("Lume", &key).expect("Failed to remove entry");
|
||||
let _ = entry.delete_password();
|
||||
Ok(())
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
windows_subsystem = "windows"
|
||||
)]
|
||||
|
||||
mod commands;
|
||||
pub mod commands;
|
||||
|
||||
use tauri_plugin_autostart::MacosLauncher;
|
||||
use tauri_plugin_sql::{Migration, MigrationKind};
|
||||
@ -23,14 +23,12 @@ fn main() {
|
||||
tauri_plugin_sql::Builder::default()
|
||||
.add_migrations(
|
||||
"sqlite:lume_v3.db",
|
||||
vec![
|
||||
Migration {
|
||||
version: 20230418013219,
|
||||
description: "initial data",
|
||||
sql: include_str!("../migrations/20230418013219_initial_data.sql"),
|
||||
kind: MigrationKind::Up,
|
||||
},
|
||||
],
|
||||
vec![Migration {
|
||||
version: 20230418013219,
|
||||
description: "initial data",
|
||||
sql: include_str!("../migrations/20230418013219_initial_data.sql"),
|
||||
kind: MigrationKind::Up,
|
||||
}],
|
||||
)
|
||||
.build(),
|
||||
)
|
||||
@ -50,11 +48,11 @@ fn main() {
|
||||
Some(vec![]),
|
||||
))
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
commands::opengraph,
|
||||
commands::secure_save,
|
||||
commands::secure_load,
|
||||
commands::secure_remove,
|
||||
commands::show_in_folder,
|
||||
commands::secret::secure_save,
|
||||
commands::secret::secure_load,
|
||||
commands::secret::secure_remove,
|
||||
commands::folder::show_in_folder,
|
||||
commands::opg::fetch_opg,
|
||||
])
|
||||
.run(ctx)
|
||||
.expect("error while running tauri application");
|
||||
|