Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0c49c5141 | ||
|
|
2ed2cb3afd | ||
|
|
2bcda1f2ef | ||
|
|
ca20bbd298 | ||
|
|
c6da06cd4d | ||
|
|
50bf6c04c1 |
+18
-18
@@ -20,38 +20,38 @@
|
||||
"@radix-ui/react-switch": "^1.1.1",
|
||||
"@radix-ui/react-tabs": "^1.1.1",
|
||||
"@radix-ui/react-tooltip": "^1.1.3",
|
||||
"@tanstack/query-broadcast-client-experimental": "^5.59.16",
|
||||
"@tanstack/query-persist-client-core": "^5.59.16",
|
||||
"@tanstack/react-query": "^5.59.16",
|
||||
"@tanstack/react-router": "^1.77.5",
|
||||
"@tauri-apps/api": "^2.0.3",
|
||||
"@tanstack/query-broadcast-client-experimental": "^5.59.20",
|
||||
"@tanstack/query-persist-client-core": "^5.59.20",
|
||||
"@tanstack/react-query": "^5.59.20",
|
||||
"@tanstack/react-router": "^1.81.0",
|
||||
"@tauri-apps/api": "^2.1.0",
|
||||
"@tauri-apps/plugin-clipboard-manager": "^2.0.0",
|
||||
"@tauri-apps/plugin-dialog": "^2.0.1",
|
||||
"@tauri-apps/plugin-fs": "^2.0.1",
|
||||
"@tauri-apps/plugin-fs": "^2.0.2",
|
||||
"@tauri-apps/plugin-http": "^2.0.1",
|
||||
"@tauri-apps/plugin-os": "^2.0.0",
|
||||
"@tauri-apps/plugin-process": "^2.0.0",
|
||||
"@tauri-apps/plugin-shell": "^2.0.1",
|
||||
"@tauri-apps/plugin-store": "github:tauri-apps/tauri-plugin-store#a564510",
|
||||
"@tauri-apps/plugin-updater": "^2.0.0",
|
||||
"@tauri-apps/plugin-upload": "^2.0.0",
|
||||
"@tauri-apps/plugin-upload": "^2.1.0",
|
||||
"@tauri-apps/plugin-window-state": "^2.0.0",
|
||||
"bitcoin-units": "^1.0.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"embla-carousel-react": "^8.3.0",
|
||||
"i18next": "^23.16.4",
|
||||
"embla-carousel-react": "^8.3.1",
|
||||
"i18next": "^23.16.5",
|
||||
"i18next-resources-to-backend": "^1.2.1",
|
||||
"light-bolt11-decoder": "^3.2.0",
|
||||
"minidenticons": "^4.2.1",
|
||||
"nanoid": "^5.0.7",
|
||||
"nostr-tools": "^2.9.4",
|
||||
"nanoid": "^5.0.8",
|
||||
"nostr-tools": "^2.10.1",
|
||||
"react": "19.0.0-rc-cae764ce-20241025",
|
||||
"react-currency-input-field": "^3.8.0",
|
||||
"react-dom": "19.0.0-rc-cae764ce-20241025",
|
||||
"react-hook-form": "^7.53.1",
|
||||
"react-i18next": "^15.1.0",
|
||||
"react-hook-form": "^7.53.2",
|
||||
"react-i18next": "^15.1.1",
|
||||
"react-string-replace": "^1.1.1",
|
||||
"rich-textarea": "^0.26.3",
|
||||
"rich-textarea": "^0.26.4",
|
||||
"use-debounce": "^10.0.4",
|
||||
"virtua": "^0.34.2"
|
||||
},
|
||||
@@ -59,9 +59,9 @@
|
||||
"@biomejs/biome": "^1.9.4",
|
||||
"@tailwindcss/forms": "^0.5.9",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@tanstack/router-devtools": "^1.77.5",
|
||||
"@tanstack/router-plugin": "^1.76.4",
|
||||
"@tauri-apps/cli": "^2.0.4",
|
||||
"@tanstack/router-devtools": "^1.81.0",
|
||||
"@tanstack/router-plugin": "^1.79.0",
|
||||
"@tauri-apps/cli": "^2.1.0",
|
||||
"@types/react": "npm:types-react@19.0.0-rc.1",
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1",
|
||||
"@vitejs/plugin-react": "^4.3.3",
|
||||
@@ -76,7 +76,7 @@
|
||||
"tailwindcss-content-visibility": "^1.0.0",
|
||||
"typescript": "^5.6.3",
|
||||
"vite": "^5.4.10",
|
||||
"vite-tsconfig-paths": "^5.0.1"
|
||||
"vite-tsconfig-paths": "^5.1.1"
|
||||
},
|
||||
"overrides": {
|
||||
"@types/react": "npm:types-react@rc",
|
||||
|
||||
Generated
+300
-300
File diff suppressed because it is too large
Load Diff
Generated
+761
-767
File diff suppressed because it is too large
Load Diff
@@ -33,9 +33,6 @@ tauri-plugin-theme = "2.1.2"
|
||||
tauri-plugin-decorum = { git = "https://github.com/clearlysid/tauri-plugin-decorum" }
|
||||
tauri-specta = { version = "2.0.0-rc.15", features = ["derive", "typescript"] }
|
||||
|
||||
nostr-sdk = { git = "https://github.com/rust-nostr/nostr", features = ["lmdb", "webln", "all-nips"] }
|
||||
nostr-connect = { git = "https://github.com/rust-nostr/nostr" }
|
||||
|
||||
specta = "^2.0.0-rc.20"
|
||||
specta-typescript = "0.0.7"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
@@ -49,10 +46,15 @@ regex = "1.10.4"
|
||||
keyring = { version = "3", features = ["apple-native", "windows-native"] }
|
||||
keyring-search = { git = "https://github.com/reyamir/keyring-search" }
|
||||
tracing-subscriber = { version = "0.3.18", features = ["fmt"] }
|
||||
async-trait = "0.1.83"
|
||||
webbrowser = "1.0.2"
|
||||
|
||||
nostr-sdk = { git = "https://github.com/rust-nostr/nostr", features = ["lmdb", "webln", "all-nips"] }
|
||||
nostr-connect = { git = "https://github.com/rust-nostr/nostr" }
|
||||
|
||||
[patch.'https://github.com/rust-nostr/nostr']
|
||||
nostr-sdk = { git = "https://github.com/reyamir/nostr", branch = "feat/open-auth-url", features = ["lmdb", "webln", "all-nips"] }
|
||||
nostr-connect = { git = "https://github.com/reyamir/nostr", branch = "feat/open-auth-url" }
|
||||
nostr-sdk = { git = "https://github.com/reyamir/nostr", branch = "feat/nip-22", features = ["lmdb", "webln", "all-nips"] }
|
||||
nostr-connect = { git = "https://github.com/reyamir/nostr", branch = "feat/nip-22" }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
border = { git = "https://github.com/ahkohd/tauri-toolkit", branch = "v2" }
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
],
|
||||
"definitions": {
|
||||
"Capability": {
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, \"platforms\": [\"macOS\",\"windows\"] } ```",
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"identifier",
|
||||
@@ -84,7 +84,7 @@
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"description": "List of permissions attached to this capability.\n\nMust include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`. For commands directly implemented in the application itself only `${permission-name}` is required.\n\n## Example\n\n```json [ \"core:default\", \"shell:allow-open\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] } ```",
|
||||
"description": "List of permissions attached to this capability.\n\nMust include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`. For commands directly implemented in the application itself only `${permission-name}` is required.\n\n## Example\n\n```json [ \"core:default\", \"shell:allow-open\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] } ] ```",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/PermissionEntry"
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
],
|
||||
"definitions": {
|
||||
"Capability": {
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, \"platforms\": [\"macOS\",\"windows\"] } ```",
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"identifier",
|
||||
@@ -84,7 +84,7 @@
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"description": "List of permissions attached to this capability.\n\nMust include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`. For commands directly implemented in the application itself only `${permission-name}` is required.\n\n## Example\n\n```json [ \"core:default\", \"shell:allow-open\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] } ```",
|
||||
"description": "List of permissions attached to this capability.\n\nMust include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`. For commands directly implemented in the application itself only `${permission-name}` is required.\n\n## Example\n\n```json [ \"core:default\", \"shell:allow-open\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] } ] ```",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/PermissionEntry"
|
||||
|
||||
@@ -14,6 +14,17 @@ struct Account {
|
||||
nostr_connect: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct AuthHandler;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl AuthUrlHandler for AuthHandler {
|
||||
async fn on_auth_url(&self, auth_url: Url) -> Result<()> {
|
||||
webbrowser::open(auth_url.as_str())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub fn get_accounts() -> Vec<String> {
|
||||
@@ -94,19 +105,29 @@ pub async fn connect_account(uri: String, state: State<'_, Nostr>) -> Result<Str
|
||||
let remote_npub = remote_user.to_bech32().map_err(|err| err.to_string())?;
|
||||
|
||||
// Init nostr connect
|
||||
let nostr_connect = NostrConnect::new(bunker_uri, app_keys, Duration::from_secs(120), None)
|
||||
let mut nostr_connect = NostrConnect::new(bunker_uri, app_keys, Duration::from_secs(120), None)
|
||||
.map_err(|err| err.to_string())?;
|
||||
|
||||
let bunker_uri = nostr_connect
|
||||
// Handle auth url
|
||||
nostr_connect.auth_url_handler(AuthHandler);
|
||||
|
||||
let keyring = Entry::new("Lume Safe Storage", &remote_npub).map_err(|err| err.to_string())?;
|
||||
|
||||
let reuse_bunker = nostr_connect
|
||||
.bunker_uri()
|
||||
.await
|
||||
.map_err(|err| err.to_string())?;
|
||||
|
||||
let keyring = Entry::new("Lume Safe Storage", &remote_npub).map_err(|err| err.to_string())?;
|
||||
let mut reuse_uri = reuse_bunker.to_string();
|
||||
|
||||
if let Some(secret) = reuse_bunker.secret() {
|
||||
let replace = format!("&secret={}", secret);
|
||||
reuse_uri = reuse_uri.replace(replace.as_str(), "");
|
||||
}
|
||||
|
||||
let account = Account {
|
||||
secret_key: app_secret,
|
||||
nostr_connect: Some(bunker_uri.to_string()),
|
||||
nostr_connect: Some(reuse_uri),
|
||||
};
|
||||
|
||||
// Save secret key to keyring
|
||||
@@ -217,7 +238,9 @@ pub async fn set_signer(
|
||||
let app_keys = Keys::from_str(&account.secret_key).map_err(|e| e.to_string())?;
|
||||
|
||||
match NostrConnect::new(uri, app_keys, Duration::from_secs(120), None) {
|
||||
Ok(signer) => {
|
||||
Ok(mut signer) => {
|
||||
// Handle auth url
|
||||
signer.auth_url_handler(AuthHandler);
|
||||
// Update signer
|
||||
client.set_signer(signer).await;
|
||||
// Emit to front-end
|
||||
|
||||
@@ -71,11 +71,11 @@ pub async fn get_meta_from_event(content: String) -> Result<Meta, ()> {
|
||||
#[specta::specta]
|
||||
pub async fn get_replies(id: String, state: State<'_, Nostr>) -> Result<Vec<RichEvent>, String> {
|
||||
let client = &state.client;
|
||||
let event_id = EventId::parse(&id).map_err(|err| err.to_string())?;
|
||||
|
||||
let event_id = EventId::parse(&id).map_err(|err| err.to_string())?;
|
||||
let filter = Filter::new()
|
||||
.kinds(vec![Kind::TextNote, Kind::Custom(1111)])
|
||||
.event(event_id);
|
||||
.kind(Kind::Comment)
|
||||
.custom_tag(SingleLetterTag::uppercase(Alphabet::E), [event_id]);
|
||||
|
||||
let mut events = Events::new(&[filter.clone()]);
|
||||
|
||||
@@ -523,39 +523,31 @@ pub async fn reply(content: String, to: String, state: State<'_, Nostr>) -> Resu
|
||||
Err(e) => return Err(e.to_string()),
|
||||
};
|
||||
|
||||
// Detect root event from reply
|
||||
let root_ids: Vec<&EventId> = reply_to
|
||||
// Find root event from reply
|
||||
let root_tag = reply_to
|
||||
.tags
|
||||
.filter_standardized(TagKind::e())
|
||||
.filter_map(|t| match t {
|
||||
TagStandard::Event {
|
||||
event_id, marker, ..
|
||||
} => {
|
||||
if let Some(mkr) = marker {
|
||||
match mkr {
|
||||
Marker::Root => Some(event_id),
|
||||
Marker::Reply => Some(event_id),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
Some(event_id)
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
.find(TagKind::SingleLetter(SingleLetterTag::uppercase(
|
||||
Alphabet::E,
|
||||
)));
|
||||
|
||||
// Get root event if exist
|
||||
let root = match root_ids.first() {
|
||||
Some(&id) => client
|
||||
.database()
|
||||
.event_by_id(id)
|
||||
.await
|
||||
.map_err(|err| err.to_string())?,
|
||||
let root = match root_tag {
|
||||
Some(tag) => match tag.content() {
|
||||
Some(content) => {
|
||||
let id = EventId::parse(content).map_err(|err| err.to_string())?;
|
||||
|
||||
client
|
||||
.database()
|
||||
.event_by_id(&id)
|
||||
.await
|
||||
.map_err(|err| err.to_string())?
|
||||
}
|
||||
None => None,
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
let builder = EventBuilder::text_note_reply(content, &reply_to, root.as_ref(), None)
|
||||
let builder = EventBuilder::comment(content, &reply_to, root.as_ref(), None)
|
||||
.add_tags(tags)
|
||||
.pow(DEFAULT_DIFFICULTY);
|
||||
|
||||
|
||||
@@ -105,28 +105,27 @@ pub async fn create_column(
|
||||
});
|
||||
}
|
||||
} else if let Ok(event_id) = EventId::parse(&id) {
|
||||
let is_thread = payload.url().to_string().contains("events");
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let state = webview.state::<Nostr>();
|
||||
let client = &state.client;
|
||||
|
||||
if is_thread {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let state = webview.state::<Nostr>();
|
||||
let client = &state.client;
|
||||
let subscription_id = SubscriptionId::new(webview.label());
|
||||
|
||||
let subscription_id = SubscriptionId::new(webview.label());
|
||||
let filter = Filter::new()
|
||||
.custom_tag(
|
||||
SingleLetterTag::uppercase(Alphabet::E),
|
||||
[event_id],
|
||||
)
|
||||
.kind(Kind::Comment)
|
||||
.since(Timestamp::now());
|
||||
|
||||
let filter = Filter::new()
|
||||
.event(event_id)
|
||||
.kinds(vec![Kind::TextNote, Kind::Custom(1111)])
|
||||
.since(Timestamp::now());
|
||||
|
||||
if let Err(e) = client
|
||||
.subscribe_with_id(subscription_id, vec![filter], None)
|
||||
.await
|
||||
{
|
||||
println!("Subscription error: {}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
if let Err(e) = client
|
||||
.subscribe_with_id(subscription_id, vec![filter], None)
|
||||
.await
|
||||
{
|
||||
println!("Subscription error: {}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-17
@@ -56,13 +56,6 @@ pub fn create_tags(content: &str) -> Vec<Tag> {
|
||||
// Get words
|
||||
let words: Vec<_> = content.split_whitespace().collect();
|
||||
|
||||
// Get mentions
|
||||
let mentions = words
|
||||
.iter()
|
||||
.filter(|&&word| ["nostr:", "@"].iter().any(|&el| word.starts_with(el)))
|
||||
.map(|&s| s.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Get hashtags
|
||||
let hashtags = words
|
||||
.iter()
|
||||
@@ -70,6 +63,13 @@ pub fn create_tags(content: &str) -> Vec<Tag> {
|
||||
.map(|&s| s.to_string().replace("#", "").to_lowercase())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Get mentions
|
||||
let mentions = words
|
||||
.iter()
|
||||
.filter(|&&word| ["nostr:", "@"].iter().any(|&el| word.starts_with(el)))
|
||||
.map(|&s| s.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for mention in mentions {
|
||||
let entity = mention.replace("nostr:", "").replace('@', "");
|
||||
|
||||
@@ -92,8 +92,11 @@ pub fn create_tags(content: &str) -> Vec<Tag> {
|
||||
}
|
||||
if entity.starts_with("note") {
|
||||
if let Ok(event_id) = EventId::from_bech32(&entity) {
|
||||
let hex = event_id.to_hex();
|
||||
let tag = Tag::parse(&["e", &hex, "", "mention"]).unwrap();
|
||||
let tag = Tag::from_standardized(TagStandard::Quote {
|
||||
event_id,
|
||||
relay_url: None,
|
||||
public_key: None,
|
||||
});
|
||||
tags.push(tag);
|
||||
} else {
|
||||
continue;
|
||||
@@ -101,14 +104,12 @@ pub fn create_tags(content: &str) -> Vec<Tag> {
|
||||
}
|
||||
if entity.starts_with("nevent") {
|
||||
if let Ok(event) = Nip19Event::from_bech32(&entity) {
|
||||
let hex = event.event_id.to_hex();
|
||||
let relay = event.clone().relays.into_iter().next().unwrap_or("".into());
|
||||
let tag = Tag::parse(&["e", &hex, &relay, "mention"]).unwrap();
|
||||
|
||||
if let Some(author) = event.author {
|
||||
let tag = Tag::public_key(author);
|
||||
tags.push(tag);
|
||||
}
|
||||
let relay_url = event.relays.first().map(UncheckedUrl::from);
|
||||
let tag = Tag::from_standardized(TagStandard::Quote {
|
||||
event_id: event.event_id,
|
||||
relay_url,
|
||||
public_key: event.author,
|
||||
});
|
||||
|
||||
tags.push(tag);
|
||||
} else {
|
||||
|
||||
@@ -236,8 +236,8 @@ fn main() {
|
||||
// Config
|
||||
let opts = Options::new()
|
||||
.gossip(true)
|
||||
.max_avg_latency(Duration::from_millis(500))
|
||||
.timeout(Duration::from_secs(5));
|
||||
.max_avg_latency(Duration::from_secs(2))
|
||||
.timeout(Duration::from_secs(10));
|
||||
|
||||
// Setup nostr client
|
||||
let client = ClientBuilder::default()
|
||||
@@ -532,7 +532,7 @@ fn main() {
|
||||
if let Err(e) = handle_clone.emit("metadata", event.as_json()) {
|
||||
println!("Emit error: {}", e)
|
||||
}
|
||||
} else if event.kind == Kind::TextNote {
|
||||
} else if event.kind == Kind::Comment {
|
||||
let payload = RichEvent {
|
||||
raw: event.as_json(),
|
||||
parsed: if event.kind == Kind::TextNote {
|
||||
@@ -544,7 +544,7 @@ fn main() {
|
||||
|
||||
if let Err(e) = handle_clone.emit_to(
|
||||
EventTarget::labeled(subscription_id.to_string()),
|
||||
"event",
|
||||
"comment",
|
||||
payload,
|
||||
) {
|
||||
println!("Emit error: {}", e)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||
"productName": "Lume",
|
||||
"version": "24.11.5",
|
||||
"version": "24.11.7",
|
||||
"identifier": "nu.lume.Lume",
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
|
||||
+3
-5
@@ -1,12 +1,12 @@
|
||||
/* prettier-ignore-start */
|
||||
|
||||
/* eslint-disable */
|
||||
|
||||
// @ts-nocheck
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
|
||||
// This file is auto-generated by TanStack Router
|
||||
// This file was automatically generated by TanStack Router.
|
||||
// You should NOT make any changes in this file as it will be overwritten.
|
||||
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
||||
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
|
||||
@@ -1036,8 +1036,6 @@ export const routeTree = rootRoute
|
||||
._addFileChildren(rootRouteChildren)
|
||||
._addFileTypes<FileRouteTypes>()
|
||||
|
||||
/* prettier-ignore-end */
|
||||
|
||||
/* ROUTE_MANIFEST_START
|
||||
{
|
||||
"routes": {
|
||||
|
||||
@@ -99,14 +99,9 @@ function ReplyList() {
|
||||
const res = await commands.getReplies(id);
|
||||
|
||||
if (res.status === "ok") {
|
||||
const events = res.data
|
||||
// Create Lume Events
|
||||
.map((item) => LumeEvent.from(item.raw, item.parsed))
|
||||
// Filter quote
|
||||
.filter(
|
||||
(ev) =>
|
||||
!ev.tags.filter((t) => t[0] === "q" || t[3] === "mention").length,
|
||||
);
|
||||
const events = res.data.map((item) =>
|
||||
LumeEvent.from(item.raw, item.parsed),
|
||||
);
|
||||
|
||||
return events;
|
||||
} else {
|
||||
@@ -179,7 +174,7 @@ function ReplyList() {
|
||||
|
||||
useEffect(() => {
|
||||
const unlisten = getCurrentWindow().listen<EventPayload>(
|
||||
"event",
|
||||
"comment",
|
||||
async (data) => {
|
||||
const event = LumeEvent.from(data.payload.raw, data.payload.parsed);
|
||||
|
||||
@@ -216,7 +211,7 @@ function ReplyList() {
|
||||
{isLoading ? (
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<Spinner className="size-4" />
|
||||
<span className="text-sm font-medium">Getting replies...</span>
|
||||
<span className="text-sm font-medium">Loading replies...</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col gap-3">
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
import { commands } from "@/commands.gen";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/columns/_layout/events/$id")({
|
||||
beforeLoad: async () => {
|
||||
const accounts = await commands.getAccounts();
|
||||
return { accounts };
|
||||
},
|
||||
});
|
||||
export const Route = createFileRoute("/columns/_layout/events/$id")();
|
||||
|
||||
@@ -73,7 +73,7 @@ function Newsfeeds() {
|
||||
: item.tags.find((tag) => tag[0] === "title")?.[1] || "Unnamed";
|
||||
const label =
|
||||
item.kind === 3
|
||||
? `newsfeed-${id.slice(0, 5)}`
|
||||
? `newsfeed-${item.pubkey.slice(0, 5)}`
|
||||
: item.tags.find((tag) => tag[0] === "d")?.[1] || nanoid();
|
||||
|
||||
return (
|
||||
|
||||
@@ -120,19 +120,19 @@ function Screen() {
|
||||
>
|
||||
<Tabs.List className="h-11 shrink-0 flex items-center">
|
||||
<Tabs.Trigger
|
||||
className="flex-1 inline-flex h-11 items-center justify-center gap-2 px-3 text-sm font-medium border-b border-neutral-100 dark:border-neutral-900 data-[state=active]:border-neutral-200 dark:data-[state=active]:border-neutral-800 data-[state=inactive]:opacity-50"
|
||||
className="flex-1 inline-flex h-11 items-center justify-center gap-2 px-3 text-sm font-medium border-b border-neutral-100 dark:border-neutral-700 data-[state=active]:border-neutral-200 dark:data-[state=active]:border-neutral-600 data-[state=inactive]:opacity-50"
|
||||
value="replies"
|
||||
>
|
||||
Replies
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger
|
||||
className="flex-1 inline-flex h-11 items-center justify-center gap-2 px-3 text-sm font-medium border-b border-neutral-100 dark:border-neutral-900 data-[state=active]:border-neutral-200 dark:data-[state=active]:border-neutral-800 data-[state=inactive]:opacity-50"
|
||||
className="flex-1 inline-flex h-11 items-center justify-center gap-2 px-3 text-sm font-medium border-b border-neutral-100 dark:border-neutral-700 data-[state=active]:border-neutral-200 dark:data-[state=active]:border-neutral-600 data-[state=inactive]:opacity-50"
|
||||
value="reactions"
|
||||
>
|
||||
Reactions
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger
|
||||
className="flex-1 inline-flex h-11 items-center justify-center gap-2 px-3 text-sm font-medium border-b border-neutral-100 dark:border-neutral-900 data-[state=active]:border-neutral-200 dark:data-[state=active]:border-neutral-800 data-[state=inactive]:opacity-50"
|
||||
className="flex-1 inline-flex h-11 items-center justify-center gap-2 px-3 text-sm font-medium border-b border-neutral-100 dark:border-neutral-700 data-[state=active]:border-neutral-200 dark:data-[state=active]:border-neutral-600 data-[state=inactive]:opacity-50"
|
||||
value="zaps"
|
||||
>
|
||||
Zaps
|
||||
|
||||
@@ -70,7 +70,7 @@ export const Route = createLazyFileRoute("/new-post/")({
|
||||
|
||||
function Screen() {
|
||||
const { reply_to } = Route.useSearch();
|
||||
const { accounts, initialValue, queryClient } = Route.useRouteContext();
|
||||
const { accounts, initialValue } = Route.useRouteContext();
|
||||
const { deferMentionList } = Route.useLoaderData();
|
||||
const users = useAwaited({ promise: deferMentionList })[0];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user