mirror of
https://github.com/lumehq/lume.git
synced 2025-03-17 21:32:32 +01:00
update
This commit is contained in:
parent
eb6e3e52df
commit
0518389f50
4
src-tauri/Cargo.lock
generated
4
src-tauri/Cargo.lock
generated
@ -3081,7 +3081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
|
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -7223,7 +7223,7 @@ version = "0.1.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -11,11 +11,10 @@ rust-version = "1.70"
|
|||||||
tauri-build = { version = "2.0.0", features = [] }
|
tauri-build = { version = "2.0.0", features = [] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tauri = { version = "2.0.0", features = [
|
tauri = { version = "2.0.0", features = [ "protocol-asset",
|
||||||
"unstable",
|
"unstable",
|
||||||
"tray-icon",
|
"tray-icon",
|
||||||
"macos-private-api",
|
"macos-private-api"
|
||||||
"protocol-asset",
|
|
||||||
] }
|
] }
|
||||||
tauri-plugin-window-state = "2.0.0"
|
tauri-plugin-window-state = "2.0.0"
|
||||||
tauri-plugin-clipboard-manager = "2.0.0"
|
tauri-plugin-clipboard-manager = "2.0.0"
|
||||||
|
@ -281,18 +281,33 @@ pub async fn get_group(id: String, state: State<'_, Nostr>) -> Result<String, St
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
#[specta::specta]
|
#[specta::specta]
|
||||||
pub async fn get_all_groups(id: String, state: State<'_, Nostr>) -> Result<Vec<RichEvent>, String> {
|
pub async fn get_all_newsfeeds(
|
||||||
|
id: String,
|
||||||
|
state: State<'_, Nostr>,
|
||||||
|
) -> Result<Vec<RichEvent>, String> {
|
||||||
let client = &state.client;
|
let client = &state.client;
|
||||||
let public_key = PublicKey::parse(&id).map_err(|e| e.to_string())?;
|
let public_key = PublicKey::parse(&id).map_err(|e| e.to_string())?;
|
||||||
let filter = Filter::new().kind(Kind::FollowSet).author(public_key);
|
|
||||||
|
|
||||||
match client
|
let groups = Filter::new().kind(Kind::FollowSet).author(public_key);
|
||||||
.fetch_events(vec![filter], Some(Duration::from_secs(3)))
|
let contacts = Filter::new()
|
||||||
|
.kind(Kind::ContactList)
|
||||||
|
.author(public_key)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
let remote_events = client
|
||||||
|
.fetch_events(vec![groups], Some(Duration::from_secs(3)))
|
||||||
.await
|
.await
|
||||||
{
|
.map_err(|e| e.to_string())?;
|
||||||
Ok(events) => Ok(process_event(client, events, false).await),
|
|
||||||
Err(e) => Err(e.to_string()),
|
let contact_events = client
|
||||||
}
|
.fetch_events(vec![contacts], Some(Duration::from_secs(3)))
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
let events = remote_events.merge(contact_events);
|
||||||
|
let alt_events = process_event(client, events, false).await;
|
||||||
|
|
||||||
|
Ok(alt_events)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
@ -47,7 +47,17 @@ pub async fn create_column(
|
|||||||
main_window: Window,
|
main_window: Window,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
match app_handle.get_webview(&column.label) {
|
match app_handle.get_webview(&column.label) {
|
||||||
Some(_) => Ok(column.label),
|
Some(webview) => {
|
||||||
|
if let Err(e) = webview.set_size(LogicalSize::new(column.width, column.height)) {
|
||||||
|
return Err(e.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = webview.set_position(LogicalPosition::new(column.x, column.y)) {
|
||||||
|
return Err(e.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(column.label)
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
let path = PathBuf::from(column.url);
|
let path = PathBuf::from(column.url);
|
||||||
let webview_url = WebviewUrl::App(path);
|
let webview_url = WebviewUrl::App(path);
|
||||||
@ -145,28 +155,15 @@ pub async fn close_column(label: String, app_handle: tauri::AppHandle) -> Result
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
#[specta::specta]
|
#[specta::specta]
|
||||||
pub async fn update_column(
|
pub async fn close_all_columns(app_handle: tauri::AppHandle) -> Result<(), String> {
|
||||||
label: String,
|
let mut webviews = app_handle.webviews();
|
||||||
width: f32,
|
webviews.remove("main");
|
||||||
height: f32,
|
|
||||||
x: f32,
|
|
||||||
y: f32,
|
|
||||||
app_handle: tauri::AppHandle,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
match app_handle.get_webview(&label) {
|
|
||||||
Some(webview) => {
|
|
||||||
if let Err(e) = webview.set_size(LogicalSize::new(width, height)) {
|
|
||||||
return Err(e.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) = webview.set_position(LogicalPosition::new(x, y)) {
|
for webview in webviews.values() {
|
||||||
return Err(e.to_string());
|
webview.close().unwrap()
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
None => Err("Cannot update, column not found.".into()),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
@ -97,7 +97,7 @@ fn main() {
|
|||||||
get_all_profiles,
|
get_all_profiles,
|
||||||
set_group,
|
set_group,
|
||||||
get_group,
|
get_group,
|
||||||
get_all_groups,
|
get_all_newsfeeds,
|
||||||
set_interest,
|
set_interest,
|
||||||
get_interest,
|
get_interest,
|
||||||
get_all_interests,
|
get_all_interests,
|
||||||
@ -129,9 +129,9 @@ fn main() {
|
|||||||
event_to_bech32,
|
event_to_bech32,
|
||||||
user_to_bech32,
|
user_to_bech32,
|
||||||
create_column,
|
create_column,
|
||||||
update_column,
|
|
||||||
reload_column,
|
reload_column,
|
||||||
close_column,
|
close_column,
|
||||||
|
close_all_columns,
|
||||||
open_window,
|
open_window,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -288,48 +288,46 @@ fn main() {
|
|||||||
|
|
||||||
let _ = client
|
let _ = client
|
||||||
.handle_notifications(|notification| async {
|
.handle_notifications(|notification| async {
|
||||||
#[allow(clippy::collapsible_match)]
|
if let RelayPoolNotification::Event {
|
||||||
if let RelayPoolNotification::Message { message, .. } = notification {
|
event,
|
||||||
if let RelayMessage::Event {
|
subscription_id,
|
||||||
event,
|
..
|
||||||
subscription_id,
|
} = notification
|
||||||
} = message
|
{
|
||||||
{
|
// Handle events from notification subscription
|
||||||
// Handle events from notification subscription
|
if subscription_id == notification_id {
|
||||||
if subscription_id == notification_id {
|
// Send native notification
|
||||||
// Send native notification
|
if allow_notification {
|
||||||
if allow_notification {
|
let author = client
|
||||||
let author = client
|
.database()
|
||||||
.database()
|
.profile(event.pubkey)
|
||||||
.profile(event.pubkey)
|
.await
|
||||||
.await
|
.unwrap_or_else(|_| {
|
||||||
.unwrap_or_else(|_| {
|
DatabaseProfile::new(event.pubkey, Metadata::new())
|
||||||
DatabaseProfile::new(event.pubkey, Metadata::new())
|
});
|
||||||
});
|
|
||||||
|
|
||||||
send_event_notification(
|
send_event_notification(
|
||||||
&event,
|
&event,
|
||||||
author.metadata(),
|
author.metadata(),
|
||||||
&handle_clone,
|
&handle_clone,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if event.kind != Kind::RelayList {
|
} else if event.kind != Kind::RelayList {
|
||||||
let payload = RichEvent {
|
let payload = RichEvent {
|
||||||
raw: event.as_json(),
|
raw: event.as_json(),
|
||||||
parsed: if event.kind == Kind::TextNote {
|
parsed: if event.kind == Kind::TextNote {
|
||||||
Some(parse_event(&event.content).await)
|
Some(parse_event(&event.content).await)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = handle_clone.emit_to(
|
if let Err(e) = handle_clone.emit_to(
|
||||||
EventTarget::labeled(subscription_id.to_string()),
|
EventTarget::labeled(subscription_id.to_string()),
|
||||||
"event",
|
"event",
|
||||||
payload,
|
payload,
|
||||||
) {
|
) {
|
||||||
println!("Emitter error: {}", e)
|
println!("Emitter error: {}", e)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,9 +200,9 @@ async getGroup(id: string) : Promise<Result<string, string>> {
|
|||||||
else return { status: "error", error: e as any };
|
else return { status: "error", error: e as any };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async getAllGroups(id: string) : Promise<Result<RichEvent[], string>> {
|
async getAllNewsfeeds(id: string) : Promise<Result<RichEvent[], string>> {
|
||||||
try {
|
try {
|
||||||
return { status: "ok", data: await TAURI_INVOKE("get_all_groups", { id }) };
|
return { status: "ok", data: await TAURI_INVOKE("get_all_newsfeeds", { id }) };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if(e instanceof Error) throw e;
|
if(e instanceof Error) throw e;
|
||||||
else return { status: "error", error: e as any };
|
else return { status: "error", error: e as any };
|
||||||
@ -456,14 +456,6 @@ async createColumn(column: Column) : Promise<Result<string, string>> {
|
|||||||
else return { status: "error", error: e as any };
|
else return { status: "error", error: e as any };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async updateColumn(label: string, width: number, height: number, x: number, y: number) : Promise<Result<null, string>> {
|
|
||||||
try {
|
|
||||||
return { status: "ok", data: await TAURI_INVOKE("update_column", { label, width, height, x, y }) };
|
|
||||||
} catch (e) {
|
|
||||||
if(e instanceof Error) throw e;
|
|
||||||
else return { status: "error", error: e as any };
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async reloadColumn(label: string) : Promise<Result<null, string>> {
|
async reloadColumn(label: string) : Promise<Result<null, string>> {
|
||||||
try {
|
try {
|
||||||
return { status: "ok", data: await TAURI_INVOKE("reload_column", { label }) };
|
return { status: "ok", data: await TAURI_INVOKE("reload_column", { label }) };
|
||||||
@ -480,6 +472,14 @@ async closeColumn(label: string) : Promise<Result<boolean, string>> {
|
|||||||
else return { status: "error", error: e as any };
|
else return { status: "error", error: e as any };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async closeAllColumns() : Promise<Result<null, string>> {
|
||||||
|
try {
|
||||||
|
return { status: "ok", data: await TAURI_INVOKE("close_all_columns") };
|
||||||
|
} catch (e) {
|
||||||
|
if(e instanceof Error) throw e;
|
||||||
|
else return { status: "error", error: e as any };
|
||||||
|
}
|
||||||
|
},
|
||||||
async openWindow(window: NewWindow) : Promise<Result<string, string>> {
|
async openWindow(window: NewWindow) : Promise<Result<string, string>> {
|
||||||
try {
|
try {
|
||||||
return { status: "ok", data: await TAURI_INVOKE("open_window", { window }) };
|
return { status: "ok", data: await TAURI_INVOKE("open_window", { window }) };
|
||||||
|
@ -4,67 +4,32 @@ import type { LumeColumn } from "@/types";
|
|||||||
import { CaretDown, Check } from "@phosphor-icons/react";
|
import { CaretDown, Check } from "@phosphor-icons/react";
|
||||||
import { Menu, MenuItem, PredefinedMenuItem } from "@tauri-apps/api/menu";
|
import { Menu, MenuItem, PredefinedMenuItem } from "@tauri-apps/api/menu";
|
||||||
import { getCurrentWindow } from "@tauri-apps/api/window";
|
import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||||
import { useCallback, useEffect, useLayoutEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { User } from "./user";
|
import { User } from "./user";
|
||||||
|
|
||||||
export function Column({ column }: { column: LumeColumn }) {
|
export function Column({ column }: { column: LumeColumn }) {
|
||||||
const [rect, ref] = useRect();
|
const [rect, ref] = useRect();
|
||||||
const [_error, setError] = useState<string>("");
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
if (rect) {
|
if (rect) {
|
||||||
const res = await commands.updateColumn(
|
const res = await commands.createColumn({
|
||||||
column.label,
|
label: column.label,
|
||||||
rect.width,
|
x: rect.x,
|
||||||
rect.height,
|
y: rect.y,
|
||||||
rect.x,
|
width: rect.width,
|
||||||
rect.y,
|
height: rect.height,
|
||||||
);
|
url: `${column.url}?label=${column.label}&name=${column.name}`,
|
||||||
|
});
|
||||||
|
|
||||||
if (res.status === "ok") {
|
if (res.status === "error") {
|
||||||
console.log("webview is updated: ", column.label);
|
setError(res.error);
|
||||||
} else {
|
|
||||||
console.log("webview error: ", res.error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}, [rect]);
|
}, [rect]);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
console.log(column.label);
|
|
||||||
if (ref.current) {
|
|
||||||
const initialRect = ref.current.getBoundingClientRect();
|
|
||||||
|
|
||||||
commands
|
|
||||||
.createColumn({
|
|
||||||
label: column.label,
|
|
||||||
x: initialRect.x,
|
|
||||||
y: initialRect.y,
|
|
||||||
width: initialRect.width,
|
|
||||||
height: initialRect.height,
|
|
||||||
url: `${column.url}?label=${column.label}&name=${column.name}`,
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
if (res.status === "ok") {
|
|
||||||
console.log("webview is created: ", column.label);
|
|
||||||
} else {
|
|
||||||
setError(res.error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
commands.closeColumn(column.label).then((res) => {
|
|
||||||
if (res.status === "ok") {
|
|
||||||
console.log("webview is closed: ", column.label);
|
|
||||||
} else {
|
|
||||||
console.log("webview error: ", res.error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full w-[440px] shrink-0 border-r border-black/5 dark:border-white/5">
|
<div className="h-full w-[440px] shrink-0 border-r border-black/5 dark:border-white/5">
|
||||||
<div className="flex flex-col gap-px size-full">
|
<div className="flex flex-col gap-px size-full">
|
||||||
@ -73,7 +38,13 @@ export function Column({ column }: { column: LumeColumn }) {
|
|||||||
name={column.name}
|
name={column.name}
|
||||||
account={column.account}
|
account={column.account}
|
||||||
/>
|
/>
|
||||||
<div ref={ref} className="flex-1 size-full" />
|
<div ref={ref} className="flex-1 size-full">
|
||||||
|
<div className="size-full flex flex-col items-center justify-center">
|
||||||
|
<div className="text-red-500 text-sm break-all">
|
||||||
|
{error?.length ? error : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -13,14 +13,14 @@ import { createFileRoute } from '@tanstack/react-router'
|
|||||||
// Import Routes
|
// Import Routes
|
||||||
|
|
||||||
import { Route as rootRoute } from './routes/__root'
|
import { Route as rootRoute } from './routes/__root'
|
||||||
import { Route as SetInterestImport } from './routes/set-interest'
|
|
||||||
import { Route as SetGroupImport } from './routes/set-group'
|
|
||||||
import { Route as BootstrapRelaysImport } from './routes/bootstrap-relays'
|
import { Route as BootstrapRelaysImport } from './routes/bootstrap-relays'
|
||||||
import { Route as AppImport } from './routes/_app'
|
import { Route as AppImport } from './routes/_app'
|
||||||
import { Route as NewPostIndexImport } from './routes/new-post/index'
|
import { Route as NewPostIndexImport } from './routes/new-post/index'
|
||||||
import { Route as AppIndexImport } from './routes/_app/index'
|
import { Route as AppIndexImport } from './routes/_app/index'
|
||||||
import { Route as ZapIdImport } from './routes/zap.$id'
|
import { Route as ZapIdImport } from './routes/zap.$id'
|
||||||
import { Route as ColumnsLayoutImport } from './routes/columns/_layout'
|
import { Route as ColumnsLayoutImport } from './routes/columns/_layout'
|
||||||
|
import { Route as IdSetInterestImport } from './routes/$id.set-interest'
|
||||||
|
import { Route as IdSetGroupImport } from './routes/$id.set-group'
|
||||||
import { Route as SettingsIdWalletImport } from './routes/settings.$id/wallet'
|
import { Route as SettingsIdWalletImport } from './routes/settings.$id/wallet'
|
||||||
import { Route as SettingsIdRelayImport } from './routes/settings.$id/relay'
|
import { Route as SettingsIdRelayImport } from './routes/settings.$id/relay'
|
||||||
import { Route as SettingsIdProfileImport } from './routes/settings.$id/profile'
|
import { Route as SettingsIdProfileImport } from './routes/settings.$id/profile'
|
||||||
@ -79,16 +79,6 @@ const NewLazyRoute = NewLazyImport.update({
|
|||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any).lazy(() => import('./routes/new.lazy').then((d) => d.Route))
|
} as any).lazy(() => import('./routes/new.lazy').then((d) => d.Route))
|
||||||
|
|
||||||
const SetInterestRoute = SetInterestImport.update({
|
|
||||||
path: '/set-interest',
|
|
||||||
getParentRoute: () => rootRoute,
|
|
||||||
} as any).lazy(() => import('./routes/set-interest.lazy').then((d) => d.Route))
|
|
||||||
|
|
||||||
const SetGroupRoute = SetGroupImport.update({
|
|
||||||
path: '/set-group',
|
|
||||||
getParentRoute: () => rootRoute,
|
|
||||||
} as any).lazy(() => import('./routes/set-group.lazy').then((d) => d.Route))
|
|
||||||
|
|
||||||
const BootstrapRelaysRoute = BootstrapRelaysImport.update({
|
const BootstrapRelaysRoute = BootstrapRelaysImport.update({
|
||||||
path: '/bootstrap-relays',
|
path: '/bootstrap-relays',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
@ -149,6 +139,18 @@ const ColumnsLayoutRoute = ColumnsLayoutImport.update({
|
|||||||
getParentRoute: () => ColumnsRoute,
|
getParentRoute: () => ColumnsRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
|
const IdSetInterestRoute = IdSetInterestImport.update({
|
||||||
|
path: '/$id/set-interest',
|
||||||
|
getParentRoute: () => rootRoute,
|
||||||
|
} as any).lazy(() =>
|
||||||
|
import('./routes/$id.set-interest.lazy').then((d) => d.Route),
|
||||||
|
)
|
||||||
|
|
||||||
|
const IdSetGroupRoute = IdSetGroupImport.update({
|
||||||
|
path: '/$id/set-group',
|
||||||
|
getParentRoute: () => rootRoute,
|
||||||
|
} as any).lazy(() => import('./routes/$id.set-group.lazy').then((d) => d.Route))
|
||||||
|
|
||||||
const ColumnsLayoutTrendingLazyRoute = ColumnsLayoutTrendingLazyImport.update({
|
const ColumnsLayoutTrendingLazyRoute = ColumnsLayoutTrendingLazyImport.update({
|
||||||
path: '/trending',
|
path: '/trending',
|
||||||
getParentRoute: () => ColumnsLayoutRoute,
|
getParentRoute: () => ColumnsLayoutRoute,
|
||||||
@ -309,20 +311,6 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof BootstrapRelaysImport
|
preLoaderRoute: typeof BootstrapRelaysImport
|
||||||
parentRoute: typeof rootRoute
|
parentRoute: typeof rootRoute
|
||||||
}
|
}
|
||||||
'/set-group': {
|
|
||||||
id: '/set-group'
|
|
||||||
path: '/set-group'
|
|
||||||
fullPath: '/set-group'
|
|
||||||
preLoaderRoute: typeof SetGroupImport
|
|
||||||
parentRoute: typeof rootRoute
|
|
||||||
}
|
|
||||||
'/set-interest': {
|
|
||||||
id: '/set-interest'
|
|
||||||
path: '/set-interest'
|
|
||||||
fullPath: '/set-interest'
|
|
||||||
preLoaderRoute: typeof SetInterestImport
|
|
||||||
parentRoute: typeof rootRoute
|
|
||||||
}
|
|
||||||
'/new': {
|
'/new': {
|
||||||
id: '/new'
|
id: '/new'
|
||||||
path: '/new'
|
path: '/new'
|
||||||
@ -330,6 +318,20 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof NewLazyImport
|
preLoaderRoute: typeof NewLazyImport
|
||||||
parentRoute: typeof rootRoute
|
parentRoute: typeof rootRoute
|
||||||
}
|
}
|
||||||
|
'/$id/set-group': {
|
||||||
|
id: '/$id/set-group'
|
||||||
|
path: '/$id/set-group'
|
||||||
|
fullPath: '/$id/set-group'
|
||||||
|
preLoaderRoute: typeof IdSetGroupImport
|
||||||
|
parentRoute: typeof rootRoute
|
||||||
|
}
|
||||||
|
'/$id/set-interest': {
|
||||||
|
id: '/$id/set-interest'
|
||||||
|
path: '/$id/set-interest'
|
||||||
|
fullPath: '/$id/set-interest'
|
||||||
|
preLoaderRoute: typeof IdSetInterestImport
|
||||||
|
parentRoute: typeof rootRoute
|
||||||
|
}
|
||||||
'/columns': {
|
'/columns': {
|
||||||
id: '/columns'
|
id: '/columns'
|
||||||
path: '/columns'
|
path: '/columns'
|
||||||
@ -636,9 +638,9 @@ const SettingsIdLazyRouteWithChildren = SettingsIdLazyRoute._addFileChildren(
|
|||||||
export interface FileRoutesByFullPath {
|
export interface FileRoutesByFullPath {
|
||||||
'': typeof AppRouteWithChildren
|
'': typeof AppRouteWithChildren
|
||||||
'/bootstrap-relays': typeof BootstrapRelaysRoute
|
'/bootstrap-relays': typeof BootstrapRelaysRoute
|
||||||
'/set-group': typeof SetGroupRoute
|
|
||||||
'/set-interest': typeof SetInterestRoute
|
|
||||||
'/new': typeof NewLazyRoute
|
'/new': typeof NewLazyRoute
|
||||||
|
'/$id/set-group': typeof IdSetGroupRoute
|
||||||
|
'/$id/set-interest': typeof IdSetInterestRoute
|
||||||
'/columns': typeof ColumnsLayoutRouteWithChildren
|
'/columns': typeof ColumnsLayoutRouteWithChildren
|
||||||
'/zap/$id': typeof ZapIdRoute
|
'/zap/$id': typeof ZapIdRoute
|
||||||
'/new-account/connect': typeof NewAccountConnectLazyRoute
|
'/new-account/connect': typeof NewAccountConnectLazyRoute
|
||||||
@ -671,9 +673,9 @@ export interface FileRoutesByFullPath {
|
|||||||
|
|
||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
'/bootstrap-relays': typeof BootstrapRelaysRoute
|
'/bootstrap-relays': typeof BootstrapRelaysRoute
|
||||||
'/set-group': typeof SetGroupRoute
|
|
||||||
'/set-interest': typeof SetInterestRoute
|
|
||||||
'/new': typeof NewLazyRoute
|
'/new': typeof NewLazyRoute
|
||||||
|
'/$id/set-group': typeof IdSetGroupRoute
|
||||||
|
'/$id/set-interest': typeof IdSetInterestRoute
|
||||||
'/columns': typeof ColumnsLayoutRouteWithChildren
|
'/columns': typeof ColumnsLayoutRouteWithChildren
|
||||||
'/zap/$id': typeof ZapIdRoute
|
'/zap/$id': typeof ZapIdRoute
|
||||||
'/new-account/connect': typeof NewAccountConnectLazyRoute
|
'/new-account/connect': typeof NewAccountConnectLazyRoute
|
||||||
@ -708,9 +710,9 @@ export interface FileRoutesById {
|
|||||||
__root__: typeof rootRoute
|
__root__: typeof rootRoute
|
||||||
'/_app': typeof AppRouteWithChildren
|
'/_app': typeof AppRouteWithChildren
|
||||||
'/bootstrap-relays': typeof BootstrapRelaysRoute
|
'/bootstrap-relays': typeof BootstrapRelaysRoute
|
||||||
'/set-group': typeof SetGroupRoute
|
|
||||||
'/set-interest': typeof SetInterestRoute
|
|
||||||
'/new': typeof NewLazyRoute
|
'/new': typeof NewLazyRoute
|
||||||
|
'/$id/set-group': typeof IdSetGroupRoute
|
||||||
|
'/$id/set-interest': typeof IdSetInterestRoute
|
||||||
'/columns': typeof ColumnsRouteWithChildren
|
'/columns': typeof ColumnsRouteWithChildren
|
||||||
'/columns/_layout': typeof ColumnsLayoutRouteWithChildren
|
'/columns/_layout': typeof ColumnsLayoutRouteWithChildren
|
||||||
'/zap/$id': typeof ZapIdRoute
|
'/zap/$id': typeof ZapIdRoute
|
||||||
@ -747,9 +749,9 @@ export interface FileRouteTypes {
|
|||||||
fullPaths:
|
fullPaths:
|
||||||
| ''
|
| ''
|
||||||
| '/bootstrap-relays'
|
| '/bootstrap-relays'
|
||||||
| '/set-group'
|
|
||||||
| '/set-interest'
|
|
||||||
| '/new'
|
| '/new'
|
||||||
|
| '/$id/set-group'
|
||||||
|
| '/$id/set-interest'
|
||||||
| '/columns'
|
| '/columns'
|
||||||
| '/zap/$id'
|
| '/zap/$id'
|
||||||
| '/new-account/connect'
|
| '/new-account/connect'
|
||||||
@ -781,9 +783,9 @@ export interface FileRouteTypes {
|
|||||||
fileRoutesByTo: FileRoutesByTo
|
fileRoutesByTo: FileRoutesByTo
|
||||||
to:
|
to:
|
||||||
| '/bootstrap-relays'
|
| '/bootstrap-relays'
|
||||||
| '/set-group'
|
|
||||||
| '/set-interest'
|
|
||||||
| '/new'
|
| '/new'
|
||||||
|
| '/$id/set-group'
|
||||||
|
| '/$id/set-interest'
|
||||||
| '/columns'
|
| '/columns'
|
||||||
| '/zap/$id'
|
| '/zap/$id'
|
||||||
| '/new-account/connect'
|
| '/new-account/connect'
|
||||||
@ -816,9 +818,9 @@ export interface FileRouteTypes {
|
|||||||
| '__root__'
|
| '__root__'
|
||||||
| '/_app'
|
| '/_app'
|
||||||
| '/bootstrap-relays'
|
| '/bootstrap-relays'
|
||||||
| '/set-group'
|
|
||||||
| '/set-interest'
|
|
||||||
| '/new'
|
| '/new'
|
||||||
|
| '/$id/set-group'
|
||||||
|
| '/$id/set-interest'
|
||||||
| '/columns'
|
| '/columns'
|
||||||
| '/columns/_layout'
|
| '/columns/_layout'
|
||||||
| '/zap/$id'
|
| '/zap/$id'
|
||||||
@ -854,9 +856,9 @@ export interface FileRouteTypes {
|
|||||||
export interface RootRouteChildren {
|
export interface RootRouteChildren {
|
||||||
AppRoute: typeof AppRouteWithChildren
|
AppRoute: typeof AppRouteWithChildren
|
||||||
BootstrapRelaysRoute: typeof BootstrapRelaysRoute
|
BootstrapRelaysRoute: typeof BootstrapRelaysRoute
|
||||||
SetGroupRoute: typeof SetGroupRoute
|
|
||||||
SetInterestRoute: typeof SetInterestRoute
|
|
||||||
NewLazyRoute: typeof NewLazyRoute
|
NewLazyRoute: typeof NewLazyRoute
|
||||||
|
IdSetGroupRoute: typeof IdSetGroupRoute
|
||||||
|
IdSetInterestRoute: typeof IdSetInterestRoute
|
||||||
ColumnsRoute: typeof ColumnsRouteWithChildren
|
ColumnsRoute: typeof ColumnsRouteWithChildren
|
||||||
ZapIdRoute: typeof ZapIdRoute
|
ZapIdRoute: typeof ZapIdRoute
|
||||||
NewAccountConnectLazyRoute: typeof NewAccountConnectLazyRoute
|
NewAccountConnectLazyRoute: typeof NewAccountConnectLazyRoute
|
||||||
@ -869,9 +871,9 @@ export interface RootRouteChildren {
|
|||||||
const rootRouteChildren: RootRouteChildren = {
|
const rootRouteChildren: RootRouteChildren = {
|
||||||
AppRoute: AppRouteWithChildren,
|
AppRoute: AppRouteWithChildren,
|
||||||
BootstrapRelaysRoute: BootstrapRelaysRoute,
|
BootstrapRelaysRoute: BootstrapRelaysRoute,
|
||||||
SetGroupRoute: SetGroupRoute,
|
|
||||||
SetInterestRoute: SetInterestRoute,
|
|
||||||
NewLazyRoute: NewLazyRoute,
|
NewLazyRoute: NewLazyRoute,
|
||||||
|
IdSetGroupRoute: IdSetGroupRoute,
|
||||||
|
IdSetInterestRoute: IdSetInterestRoute,
|
||||||
ColumnsRoute: ColumnsRouteWithChildren,
|
ColumnsRoute: ColumnsRouteWithChildren,
|
||||||
ZapIdRoute: ZapIdRoute,
|
ZapIdRoute: ZapIdRoute,
|
||||||
NewAccountConnectLazyRoute: NewAccountConnectLazyRoute,
|
NewAccountConnectLazyRoute: NewAccountConnectLazyRoute,
|
||||||
@ -895,9 +897,9 @@ export const routeTree = rootRoute
|
|||||||
"children": [
|
"children": [
|
||||||
"/_app",
|
"/_app",
|
||||||
"/bootstrap-relays",
|
"/bootstrap-relays",
|
||||||
"/set-group",
|
|
||||||
"/set-interest",
|
|
||||||
"/new",
|
"/new",
|
||||||
|
"/$id/set-group",
|
||||||
|
"/$id/set-interest",
|
||||||
"/columns",
|
"/columns",
|
||||||
"/zap/$id",
|
"/zap/$id",
|
||||||
"/new-account/connect",
|
"/new-account/connect",
|
||||||
@ -916,15 +918,15 @@ export const routeTree = rootRoute
|
|||||||
"/bootstrap-relays": {
|
"/bootstrap-relays": {
|
||||||
"filePath": "bootstrap-relays.tsx"
|
"filePath": "bootstrap-relays.tsx"
|
||||||
},
|
},
|
||||||
"/set-group": {
|
|
||||||
"filePath": "set-group.tsx"
|
|
||||||
},
|
|
||||||
"/set-interest": {
|
|
||||||
"filePath": "set-interest.tsx"
|
|
||||||
},
|
|
||||||
"/new": {
|
"/new": {
|
||||||
"filePath": "new.lazy.tsx"
|
"filePath": "new.lazy.tsx"
|
||||||
},
|
},
|
||||||
|
"/$id/set-group": {
|
||||||
|
"filePath": "$id.set-group.tsx"
|
||||||
|
},
|
||||||
|
"/$id/set-interest": {
|
||||||
|
"filePath": "$id.set-interest.tsx"
|
||||||
|
},
|
||||||
"/columns": {
|
"/columns": {
|
||||||
"filePath": "columns",
|
"filePath": "columns",
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -8,13 +8,13 @@ import { getCurrentWindow } from "@tauri-apps/api/window";
|
|||||||
import { message } from "@tauri-apps/plugin-dialog";
|
import { message } from "@tauri-apps/plugin-dialog";
|
||||||
import { useState, useTransition } from "react";
|
import { useState, useTransition } from "react";
|
||||||
|
|
||||||
export const Route = createLazyFileRoute("/set-group")({
|
export const Route = createLazyFileRoute("/$id/set-group")({
|
||||||
component: Screen,
|
component: Screen,
|
||||||
});
|
});
|
||||||
|
|
||||||
function Screen() {
|
function Screen() {
|
||||||
const contacts = Route.useLoaderData();
|
const contacts = Route.useLoaderData();
|
||||||
const { account } = Route.useSearch();
|
const { id } = Route.useParams();
|
||||||
const { queryClient } = Route.useRouteContext();
|
const { queryClient } = Route.useRouteContext();
|
||||||
|
|
||||||
const [title, setTitle] = useState("");
|
const [title, setTitle] = useState("");
|
||||||
@ -40,11 +40,11 @@ function Screen() {
|
|||||||
|
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
startTransition(async () => {
|
startTransition(async () => {
|
||||||
const signer = await commands.hasSigner(account);
|
const signer = await commands.hasSigner(id);
|
||||||
|
|
||||||
if (signer.status === "ok") {
|
if (signer.status === "ok") {
|
||||||
if (!signer.data) {
|
if (!signer.data) {
|
||||||
const res = await commands.setSigner(account);
|
const res = await commands.setSigner(id);
|
||||||
|
|
||||||
if (res.status === "error") {
|
if (res.status === "error") {
|
||||||
await message(res.error, { kind: "error" });
|
await message(res.error, { kind: "error" });
|
||||||
@ -63,7 +63,7 @@ function Screen() {
|
|||||||
|
|
||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: ["mygroups", account],
|
queryKey: ["others", "newsfeeds", id],
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create column in the main window
|
// Create column in the main window
|
||||||
@ -72,6 +72,7 @@ function Screen() {
|
|||||||
column: {
|
column: {
|
||||||
label: res.data,
|
label: res.data,
|
||||||
name: title,
|
name: title,
|
||||||
|
account: id,
|
||||||
url: `/columns/groups/${res.data}`,
|
url: `/columns/groups/${res.data}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
14
src/routes/$id.set-group.tsx
Normal file
14
src/routes/$id.set-group.tsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { commands } from "@/commands.gen";
|
||||||
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
export const Route = createFileRoute("/$id/set-group")({
|
||||||
|
loader: async ({ params }) => {
|
||||||
|
const res = await commands.getContactList(params.id);
|
||||||
|
|
||||||
|
if (res.status === "ok") {
|
||||||
|
return res.data;
|
||||||
|
} else {
|
||||||
|
throw new Error(res.error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
@ -23,7 +23,7 @@ const TOPICS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const Route = createLazyFileRoute("/set-interest")({
|
export const Route = createLazyFileRoute("/$id/set-interest")({
|
||||||
component: Screen,
|
component: Screen,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ function Screen() {
|
|||||||
const [hashtags, setHashtags] = useState<string[]>([]);
|
const [hashtags, setHashtags] = useState<string[]>([]);
|
||||||
const [isPending, startTransition] = useTransition();
|
const [isPending, startTransition] = useTransition();
|
||||||
|
|
||||||
const { account } = Route.useSearch();
|
const { id } = Route.useParams();
|
||||||
const { queryClient } = Route.useRouteContext();
|
const { queryClient } = Route.useRouteContext();
|
||||||
|
|
||||||
const toggleHashtag = (tag: string) => {
|
const toggleHashtag = (tag: string) => {
|
||||||
@ -52,11 +52,11 @@ function Screen() {
|
|||||||
|
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
startTransition(async () => {
|
startTransition(async () => {
|
||||||
const signer = await commands.hasSigner(account);
|
const signer = await commands.hasSigner(id);
|
||||||
|
|
||||||
if (signer.status === "ok") {
|
if (signer.status === "ok") {
|
||||||
if (!signer.data) {
|
if (!signer.data) {
|
||||||
const res = await commands.setSigner(account);
|
const res = await commands.setSigner(id);
|
||||||
|
|
||||||
if (res.status === "error") {
|
if (res.status === "error") {
|
||||||
await message(res.error, { kind: "error" });
|
await message(res.error, { kind: "error" });
|
||||||
@ -79,7 +79,7 @@ function Screen() {
|
|||||||
|
|
||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: ["myinterests", account],
|
queryKey: ["interests", id],
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create column in the main window
|
// Create column in the main window
|
||||||
@ -88,6 +88,7 @@ function Screen() {
|
|||||||
column: {
|
column: {
|
||||||
label: res.data,
|
label: res.data,
|
||||||
name: title,
|
name: title,
|
||||||
|
account: id,
|
||||||
url: `/columns/interests/${res.data}`,
|
url: `/columns/interests/${res.data}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
3
src/routes/$id.set-interest.tsx
Normal file
3
src/routes/$id.set-interest.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
export const Route = createFileRoute("/$id/set-interest")({});
|
@ -4,11 +4,12 @@ import { Column, Spinner } from "@/components";
|
|||||||
import { LumeWindow } from "@/system";
|
import { LumeWindow } from "@/system";
|
||||||
import type { ColumnEvent, LumeColumn, Metadata } from "@/types";
|
import type { ColumnEvent, LumeColumn, Metadata } from "@/types";
|
||||||
import { ArrowLeft, ArrowRight, Plus } from "@phosphor-icons/react";
|
import { ArrowLeft, ArrowRight, Plus } from "@phosphor-icons/react";
|
||||||
import { createLazyFileRoute } from "@tanstack/react-router";
|
import { createLazyFileRoute, useRouter } from "@tanstack/react-router";
|
||||||
import { useStore } from "@tanstack/react-store";
|
import { useStore } from "@tanstack/react-store";
|
||||||
import { listen } from "@tauri-apps/api/event";
|
import { listen } from "@tauri-apps/api/event";
|
||||||
import { Menu, MenuItem } from "@tauri-apps/api/menu";
|
import { Menu, MenuItem } from "@tauri-apps/api/menu";
|
||||||
import { getCurrentWindow } from "@tauri-apps/api/window";
|
import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||||
|
import { message } from "@tauri-apps/plugin-dialog";
|
||||||
import useEmblaCarousel from "embla-carousel-react";
|
import useEmblaCarousel from "embla-carousel-react";
|
||||||
import {
|
import {
|
||||||
type ReactNode,
|
type ReactNode,
|
||||||
@ -26,6 +27,7 @@ export const Route = createLazyFileRoute("/_app/")({
|
|||||||
|
|
||||||
function Screen() {
|
function Screen() {
|
||||||
const initialAppColumns = Route.useLoaderData();
|
const initialAppColumns = Route.useLoaderData();
|
||||||
|
const router = useRouter();
|
||||||
const columns = useStore(appColumns, (state) => state);
|
const columns = useStore(appColumns, (state) => state);
|
||||||
|
|
||||||
const [emblaRef, emblaApi] = useEmblaCarousel({
|
const [emblaRef, emblaApi] = useEmblaCarousel({
|
||||||
@ -45,6 +47,19 @@ function Screen() {
|
|||||||
getCurrentWindow().emit("scrolling", {});
|
getCurrentWindow().emit("scrolling", {});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const remove = useCallback(
|
||||||
|
async (label: string) => {
|
||||||
|
const res = await commands.closeColumn(label);
|
||||||
|
|
||||||
|
if (res.status === "ok") {
|
||||||
|
appColumns.setState((prev) => prev.filter((t) => t.label !== label));
|
||||||
|
} else {
|
||||||
|
await message(res.error, { kind: "errror" });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[columns],
|
||||||
|
);
|
||||||
|
|
||||||
const add = useDebouncedCallback((column: LumeColumn) => {
|
const add = useDebouncedCallback((column: LumeColumn) => {
|
||||||
const exist = columns.find((col) => col.label === column.label);
|
const exist = columns.find((col) => col.label === column.label);
|
||||||
|
|
||||||
@ -57,10 +72,6 @@ function Screen() {
|
|||||||
}
|
}
|
||||||
}, 150);
|
}, 150);
|
||||||
|
|
||||||
const remove = useDebouncedCallback((label: string) => {
|
|
||||||
appColumns.setState((prev) => prev.filter((t) => t.label !== label));
|
|
||||||
}, 150);
|
|
||||||
|
|
||||||
const move = useDebouncedCallback(
|
const move = useDebouncedCallback(
|
||||||
(label: string, direction: "left" | "right") => {
|
(label: string, direction: "left" | "right") => {
|
||||||
const newCols = [...columns];
|
const newCols = [...columns];
|
||||||
@ -122,6 +133,16 @@ function Screen() {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribeFn = router.subscribe("onBeforeNavigate", async () => {
|
||||||
|
await commands.closeAllColumns();
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribeFn();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (initialAppColumns) {
|
if (initialAppColumns) {
|
||||||
appColumns.setState(() => initialAppColumns);
|
appColumns.setState(() => initialAppColumns);
|
||||||
|
@ -3,7 +3,7 @@ import { cn, toLumeEvents } from "@/commons";
|
|||||||
import { Spinner, User } from "@/components";
|
import { Spinner, User } from "@/components";
|
||||||
import { LumeWindow } from "@/system";
|
import { LumeWindow } from "@/system";
|
||||||
import type { LumeColumn, NostrEvent } from "@/types";
|
import type { LumeColumn, NostrEvent } from "@/types";
|
||||||
import { ArrowClockwise, Plus } from "@phosphor-icons/react";
|
import { ArrowClockwise, ArrowRight, Plus } from "@phosphor-icons/react";
|
||||||
import * as ScrollArea from "@radix-ui/react-scroll-area";
|
import * as ScrollArea from "@radix-ui/react-scroll-area";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { createLazyFileRoute } from "@tanstack/react-router";
|
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||||
@ -24,7 +24,7 @@ function Screen() {
|
|||||||
className="overflow-hidden size-full"
|
className="overflow-hidden size-full"
|
||||||
>
|
>
|
||||||
<ScrollArea.Viewport className="relative h-full px-3 pb-3">
|
<ScrollArea.Viewport className="relative h-full px-3 pb-3">
|
||||||
<Groups />
|
<Newsfeeds />
|
||||||
<Interests />
|
<Interests />
|
||||||
<Core />
|
<Core />
|
||||||
</ScrollArea.Viewport>
|
</ScrollArea.Viewport>
|
||||||
@ -39,80 +39,12 @@ function Screen() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
function Newsfeeds() {
|
||||||
function SyncProgress() {
|
|
||||||
const { id } = Route.useParams();
|
|
||||||
const { queryClient } = Route.useRouteContext();
|
|
||||||
|
|
||||||
const [error, setError] = useState("");
|
|
||||||
const [progress, setProgress] = useState(0);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
(async () => {
|
|
||||||
if (progress >= 100) {
|
|
||||||
await queryClient.invalidateQueries();
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
}, [progress]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const channel = new Channel<number>();
|
|
||||||
|
|
||||||
channel.onmessage = (message) => {
|
|
||||||
setProgress(message);
|
|
||||||
};
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const res = await commands.syncAccount(id, channel);
|
|
||||||
|
|
||||||
if (res.status === "error") {
|
|
||||||
setError(res.error);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="size-full">
|
|
||||||
<div className="flex flex-col gap-3">
|
|
||||||
<div className="h-32 flex flex-col items-center justify-center rounded-xl overflow-hidden bg-white dark:bg-neutral-800/50 shadow-lg shadow-primary dark:ring-1 dark:ring-neutral-800">
|
|
||||||
<div className="w-2/3 flex flex-col gap-2">
|
|
||||||
<Progress.Root
|
|
||||||
className="relative overflow-hidden bg-black/20 dark:bg-white/20 rounded-full w-full h-1"
|
|
||||||
style={{
|
|
||||||
transform: "translateZ(0)",
|
|
||||||
}}
|
|
||||||
value={progress}
|
|
||||||
>
|
|
||||||
<Progress.Indicator
|
|
||||||
className="bg-blue-500 size-full transition-transform duration-[660ms] ease-[cubic-bezier(0.65, 0, 0.35, 1)]"
|
|
||||||
style={{ transform: `translateX(-${100 - progress}%)` }}
|
|
||||||
/>
|
|
||||||
</Progress.Root>
|
|
||||||
<span className="text-center text-xs">
|
|
||||||
{error ? error : "Syncing in Progress..."}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<a
|
|
||||||
href="https://github.com/hoytech/strfry/blob/nextneg/docs/negentropy.md"
|
|
||||||
target="_blank"
|
|
||||||
className="text-center !underline text-xs font-medium text-blue-500"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
Learn more about Negentropy
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
function Groups() {
|
|
||||||
const { id } = Route.useParams();
|
const { id } = Route.useParams();
|
||||||
const { isLoading, isError, error, data, refetch, isRefetching } = useQuery({
|
const { isLoading, isError, error, data, refetch, isRefetching } = useQuery({
|
||||||
queryKey: ["others", "groups", id],
|
queryKey: ["others", "newsfeeds", id],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await commands.getAllGroups(id);
|
const res = await commands.getAllNewsfeeds(id);
|
||||||
|
|
||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
const data = toLumeEvents(res.data);
|
const data = toLumeEvents(res.data);
|
||||||
@ -131,8 +63,14 @@ function Groups() {
|
|||||||
const renderItem = useCallback(
|
const renderItem = useCallback(
|
||||||
(item: NostrEvent) => {
|
(item: NostrEvent) => {
|
||||||
const name =
|
const name =
|
||||||
item.tags.find((tag) => tag[0] === "title")?.[1] || "Unnamed";
|
item.kind === 3
|
||||||
const label = item.tags.find((tag) => tag[0] === "d")?.[1] || nanoid();
|
? "Contacts"
|
||||||
|
: item.tags.find((tag) => tag[0] === "title")?.[1] || "Unnamed";
|
||||||
|
|
||||||
|
const label =
|
||||||
|
item.kind === 3
|
||||||
|
? `newsfeed-${id.slice(0, 5)}`
|
||||||
|
: item.tags.find((tag) => tag[0] === "d")?.[1] || nanoid();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -140,19 +78,34 @@ function Groups() {
|
|||||||
className="group flex flex-col rounded-xl overflow-hidden bg-white dark:bg-neutral-800/50 shadow-lg shadow-primary dark:ring-1 dark:ring-neutral-800"
|
className="group flex flex-col rounded-xl overflow-hidden bg-white dark:bg-neutral-800/50 shadow-lg shadow-primary dark:ring-1 dark:ring-neutral-800"
|
||||||
>
|
>
|
||||||
<div className="px-2 pt-2">
|
<div className="px-2 pt-2">
|
||||||
<div className="p-3 h-16 bg-neutral-100 dark:bg-neutral-800 rounded-lg flex flex-wrap items-center justify-center gap-2 overflow-y-auto">
|
<ScrollArea.Root
|
||||||
{item.tags
|
type={"scroll"}
|
||||||
.filter((tag) => tag[0] === "p")
|
scrollHideDelay={300}
|
||||||
.map((tag) => (
|
className="overflow-hidden size-full"
|
||||||
<div key={tag[1]}>
|
>
|
||||||
<User.Provider pubkey={tag[1]}>
|
<ScrollArea.Viewport className="p-3 h-16 bg-neutral-100 dark:bg-neutral-800 rounded-lg">
|
||||||
<User.Root>
|
<div className="flex flex-wrap items-center justify-center gap-2">
|
||||||
<User.Avatar className="size-8 rounded-full" />
|
{item.tags
|
||||||
</User.Root>
|
.filter((tag) => tag[0] === "p")
|
||||||
</User.Provider>
|
.map((tag) => (
|
||||||
</div>
|
<div key={tag[1]}>
|
||||||
))}
|
<User.Provider pubkey={tag[1]}>
|
||||||
</div>
|
<User.Root>
|
||||||
|
<User.Avatar className="size-8 rounded-full" />
|
||||||
|
</User.Root>
|
||||||
|
</User.Provider>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</ScrollArea.Viewport>
|
||||||
|
<ScrollArea.Scrollbar
|
||||||
|
className="flex select-none touch-none p-0.5 duration-[160ms] ease-out data-[orientation=vertical]:w-2"
|
||||||
|
orientation="vertical"
|
||||||
|
>
|
||||||
|
<ScrollArea.Thumb className="flex-1 bg-black/10 dark:bg-white/10 rounded-full relative before:content-[''] before:absolute before:top-1/2 before:left-1/2 before:-translate-x-1/2 before:-translate-y-1/2 before:w-full before:h-full before:min-w-[44px] before:min-h-[44px]" />
|
||||||
|
</ScrollArea.Scrollbar>
|
||||||
|
<ScrollArea.Corner className="bg-transparent" />
|
||||||
|
</ScrollArea.Root>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-2 flex items-center justify-between">
|
<div className="p-2 flex items-center justify-between">
|
||||||
<div className="inline-flex items-center gap-2">
|
<div className="inline-flex items-center gap-2">
|
||||||
@ -170,10 +123,14 @@ function Groups() {
|
|||||||
LumeWindow.openColumn({
|
LumeWindow.openColumn({
|
||||||
label,
|
label,
|
||||||
name,
|
name,
|
||||||
url: `/columns/groups/${item.id}`,
|
account: id,
|
||||||
|
url:
|
||||||
|
item.kind === 3
|
||||||
|
? `/columns/newsfeed/${id}`
|
||||||
|
: `/columns/groups/${item.id}`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
className="h-6 w-16 inline-flex items-center justify-center gap-1 text-xs font-semibold rounded-full bg-blue-600 hover:bg-blue-500 text-white"
|
className="h-6 w-16 inline-flex items-center justify-center gap-1 text-xs font-semibold rounded-full bg-neutral-100 group-hover:bg-blue-600 dark:group-hover:bg-blue-400 group-hover:text-white"
|
||||||
>
|
>
|
||||||
Add
|
Add
|
||||||
</button>
|
</button>
|
||||||
@ -188,7 +145,7 @@ function Groups() {
|
|||||||
return (
|
return (
|
||||||
<div className="mb-12 flex flex-col gap-3">
|
<div className="mb-12 flex flex-col gap-3">
|
||||||
<div className="flex items-center justify-between px-2">
|
<div className="flex items-center justify-between px-2">
|
||||||
<h3 className="font-semibold">Groups</h3>
|
<h3 className="font-semibold">Newsfeeds</h3>
|
||||||
<div className="inline-flex items-center justify-center gap-2">
|
<div className="inline-flex items-center justify-center gap-2">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@ -202,7 +159,7 @@ function Groups() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => LumeWindow.openPopup("/set-group", "New group")}
|
onClick={() => LumeWindow.openPopup(`${id}/set-group`, "New group")}
|
||||||
className="h-7 w-max px-2 inline-flex items-center justify-center gap-1 text-sm font-medium rounded-full bg-neutral-300 dark:bg-neutral-700 hover:bg-blue-500 hover:text-white"
|
className="h-7 w-max px-2 inline-flex items-center justify-center gap-1 text-sm font-medium rounded-full bg-neutral-300 dark:bg-neutral-700 hover:bg-blue-500 hover:text-white"
|
||||||
>
|
>
|
||||||
<Plus className="size-3" weight="bold" />
|
<Plus className="size-3" weight="bold" />
|
||||||
@ -227,6 +184,10 @@ function Groups() {
|
|||||||
) : (
|
) : (
|
||||||
data?.map((item) => renderItem(item))
|
data?.map((item) => renderItem(item))
|
||||||
)}
|
)}
|
||||||
|
<div className="h-12 px-3 flex items-center justify-between items-betwe bg-neutral-200/50 rounded-xl text-blue-600 dark:text-blue-400">
|
||||||
|
<span className="text-sm font-medium">Discover newsfeeds</span>
|
||||||
|
<ArrowRight className="size-4" weight="bold" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -266,15 +227,30 @@ function Interests() {
|
|||||||
className="group flex flex-col rounded-xl overflow-hidden bg-white dark:bg-neutral-800/50 shadow-lg shadow-primary dark:ring-1 dark:ring-neutral-800"
|
className="group flex flex-col rounded-xl overflow-hidden bg-white dark:bg-neutral-800/50 shadow-lg shadow-primary dark:ring-1 dark:ring-neutral-800"
|
||||||
>
|
>
|
||||||
<div className="px-2 pt-2">
|
<div className="px-2 pt-2">
|
||||||
<div className="p-3 h-16 bg-neutral-100 dark:bg-neutral-800 rounded-lg flex flex-wrap items-center justify-center gap-4 overflow-y-auto">
|
<ScrollArea.Root
|
||||||
{item.tags
|
type={"scroll"}
|
||||||
.filter((tag) => tag[0] === "t")
|
scrollHideDelay={300}
|
||||||
.map((tag) => (
|
className="overflow-hidden size-full"
|
||||||
<div key={tag[1]} className="text-sm font-medium">
|
>
|
||||||
{tag[1]}
|
<ScrollArea.Viewport className="p-3 h-16 bg-neutral-100 dark:bg-neutral-800 rounded-lg">
|
||||||
</div>
|
<div className="flex flex-wrap items-center justify-center gap-2">
|
||||||
))}
|
{item.tags
|
||||||
</div>
|
.filter((tag) => tag[0] === "t")
|
||||||
|
.map((tag) => (
|
||||||
|
<div key={tag[1]} className="text-sm font-medium">
|
||||||
|
{tag[1].includes("#") ? tag[1] : `#${tag[1]}`}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</ScrollArea.Viewport>
|
||||||
|
<ScrollArea.Scrollbar
|
||||||
|
className="flex select-none touch-none p-0.5 duration-[160ms] ease-out data-[orientation=vertical]:w-2"
|
||||||
|
orientation="vertical"
|
||||||
|
>
|
||||||
|
<ScrollArea.Thumb className="flex-1 bg-black/10 dark:bg-white/10 rounded-full relative before:content-[''] before:absolute before:top-1/2 before:left-1/2 before:-translate-x-1/2 before:-translate-y-1/2 before:w-full before:h-full before:min-w-[44px] before:min-h-[44px]" />
|
||||||
|
</ScrollArea.Scrollbar>
|
||||||
|
<ScrollArea.Corner className="bg-transparent" />
|
||||||
|
</ScrollArea.Root>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-3 flex items-center justify-between">
|
<div className="p-3 flex items-center justify-between">
|
||||||
<div className="inline-flex items-center gap-2">
|
<div className="inline-flex items-center gap-2">
|
||||||
@ -292,10 +268,11 @@ function Interests() {
|
|||||||
LumeWindow.openColumn({
|
LumeWindow.openColumn({
|
||||||
label,
|
label,
|
||||||
name,
|
name,
|
||||||
|
account: id,
|
||||||
url: `/columns/interests/${item.id}`,
|
url: `/columns/interests/${item.id}`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
className="h-6 w-16 inline-flex items-center justify-center gap-1 text-xs font-semibold rounded-full bg-blue-600 hover:bg-blue-500 text-white"
|
className="h-6 w-16 inline-flex items-center justify-center gap-1 text-xs font-semibold rounded-full bg-neutral-100 group-hover:bg-blue-600 dark:group-hover:bg-blue-400 group-hover:text-white"
|
||||||
>
|
>
|
||||||
Add
|
Add
|
||||||
</button>
|
</button>
|
||||||
@ -325,7 +302,7 @@ function Interests() {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
LumeWindow.openPopup("/set-interest", "New interest")
|
LumeWindow.openPopup(`${id}/set-interest`, "New interest")
|
||||||
}
|
}
|
||||||
className="h-7 w-max px-2 inline-flex items-center justify-center gap-1 text-sm font-medium rounded-full bg-neutral-300 dark:bg-neutral-700 hover:bg-blue-500 hover:text-white"
|
className="h-7 w-max px-2 inline-flex items-center justify-center gap-1 text-sm font-medium rounded-full bg-neutral-300 dark:bg-neutral-700 hover:bg-blue-500 hover:text-white"
|
||||||
>
|
>
|
||||||
@ -351,6 +328,10 @@ function Interests() {
|
|||||||
) : (
|
) : (
|
||||||
data?.map((item) => renderItem(item))
|
data?.map((item) => renderItem(item))
|
||||||
)}
|
)}
|
||||||
|
<div className="h-12 px-3 flex items-center justify-between items-betwe bg-neutral-200/50 rounded-xl text-blue-600 dark:text-blue-400">
|
||||||
|
<span className="text-sm font-medium">Discover interests</span>
|
||||||
|
<ArrowRight className="size-4" weight="bold" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -380,16 +361,6 @@ function Core() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="group flex flex-col rounded-xl overflow-hidden bg-white dark:bg-neutral-800/50 shadow-lg shadow-primary dark:ring-1 dark:ring-neutral-800">
|
<div className="group flex flex-col rounded-xl overflow-hidden bg-white dark:bg-neutral-800/50 shadow-lg shadow-primary dark:ring-1 dark:ring-neutral-800">
|
||||||
<div className="flex flex-col gap-2 p-2">
|
<div className="flex flex-col gap-2 p-2">
|
||||||
<div className="px-3 flex items-center justify-between h-11 rounded-lg bg-neutral-100 dark:bg-neutral-800">
|
|
||||||
<div className="text-sm font-medium">Newsfeed</div>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => LumeWindow.openNewsfeed(id)}
|
|
||||||
className="h-6 w-16 inline-flex items-center justify-center gap-1 text-xs font-semibold rounded-full bg-neutral-200 dark:bg-neutral-700 hover:bg-blue-500 hover:text-white"
|
|
||||||
>
|
|
||||||
Add
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="px-3 flex items-center justify-between h-11 rounded-lg bg-neutral-100 dark:bg-neutral-800">
|
<div className="px-3 flex items-center justify-between h-11 rounded-lg bg-neutral-100 dark:bg-neutral-800">
|
||||||
<div className="text-sm font-medium">Stories</div>
|
<div className="text-sm font-medium">Stories</div>
|
||||||
<button
|
<button
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
import { commands } from "@/commands.gen";
|
|
||||||
import { createFileRoute } from "@tanstack/react-router";
|
|
||||||
|
|
||||||
type RouteSearch = {
|
|
||||||
account: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/set-group")({
|
|
||||||
validateSearch: (search: Record<string, string>): RouteSearch => {
|
|
||||||
return {
|
|
||||||
account: search.account,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
loader: async () => {
|
|
||||||
const res = await commands.getContactList();
|
|
||||||
|
|
||||||
if (res.status === "ok") {
|
|
||||||
return res.data;
|
|
||||||
} else {
|
|
||||||
throw new Error(res.error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,13 +0,0 @@
|
|||||||
import { createFileRoute } from "@tanstack/react-router";
|
|
||||||
|
|
||||||
type RouteSearch = {
|
|
||||||
account: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/set-interest")({
|
|
||||||
validateSearch: (search: Record<string, string>): RouteSearch => {
|
|
||||||
return {
|
|
||||||
account: search.account,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
@ -15,7 +15,7 @@ export const LumeWindow = {
|
|||||||
await getCurrentWindow().emit("columns", {
|
await getCurrentWindow().emit("columns", {
|
||||||
type: "add",
|
type: "add",
|
||||||
column: {
|
column: {
|
||||||
label: "launchpad",
|
label: `launchpad-${account.slice(0, 5)}`,
|
||||||
name: "Launchpad",
|
name: "Launchpad",
|
||||||
url: `/columns/launchpad/${account}`,
|
url: `/columns/launchpad/${account}`,
|
||||||
account,
|
account,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user