From fe3c844fe62d359912c913ad3be420b2edeb95cf Mon Sep 17 00:00:00 2001 From: Dorian Date: Thu, 9 Apr 2026 20:42:09 +0200 Subject: [PATCH] fix: AIUI /aiui/ base path, nginx alias cycle, VPN auth, container boot - AIUI: rebuild with /aiui/ base path (router, chunk loader, SW scope) - nginx: remove alias from /aiui/ location (caused try_files redirect cycle) - VPN: WireGuard standalone setup, auth improvements - ISO: build script hardening, service file updates - first-boot-containers: networking stack fixes Co-Authored-By: Claude Opus 4.6 --- core/archipelago/src/api/rpc/auth.rs | 20 +++ core/archipelago/src/api/rpc/vpn.rs | 8 +- core/archipelago/src/vpn.rs | 95 +++++++++++++- ...age-DDnfUhk3.js => BrowsePage-C71ADslt.js} | 2 +- ...tPage-0cJYh78p.js => ChatPage-BOjiIMc2.js} | 8 +- ...w-KqUPCuYg.css => ChatWindow-D6NcMh5O.css} | 2 +- ...e_type_script_setup_true_lang-DoshhDBV.js} | 124 +++++++++--------- ....js => ConversationViewerPage-1f3wXZHu.js} | 2 +- ...ail-D1axS-VK.js => FilmDetail-XFjPooKR.js} | 2 +- ...e_type_script_setup_true_lang-Cg4zvjy1.js} | 2 +- demo/aiui/assets/FilmGrid-Ce24sGyN.js | 1 - demo/aiui/assets/FilmGrid-EKTg8OUS.js | 1 + ...e_type_script_setup_true_lang-CWkUdZ32.js} | 2 +- ...Page-BHJ1yOj7.js => GuidePage-CpiR8yAR.js} | 2 +- ...ail-DedB-36E.js => SongDetail-DCzBBkzH.js} | 2 +- ...e_type_script_setup_true_lang-CvC0ROCb.js} | 2 +- demo/aiui/assets/SongGrid-BgCYmw2O.js | 1 + demo/aiui/assets/SongGrid-BjgAbnhC.js | 1 - ...e_type_script_setup_true_lang-CW1T9zpX.js} | 2 +- ...ode-Jt8WlAUM.js => ThreadNode-Bt5yTyUn.js} | 2 +- ...D7wMN-ak.js => WidgetDemoPage-O5Vfu1LQ.js} | 2 +- ...By-BruevaAz.js => _basePickBy-BlfxZvco.js} | 2 +- ...Uniq-Blm_akxr.js => _baseUniq-C5dU7AKy.js} | 2 +- .../{arc-BfzAnNAP.js => arc-M-sFvFvX.js} | 2 +- ... architectureDiagram-VXUJARFQ-CtiOagZF.js} | 2 +- ...p.js => blockDiagram-VD42YOAC-DFxYaCGe.js} | 2 +- ...28t2.js => c4Diagram-YG6GDRKO-DqniwIVA.js} | 2 +- demo/aiui/assets/channel-DZA6uvxN.js | 1 + demo/aiui/assets/channel-uO_MEpg2.js | 1 - .../{chat-CR1al33K.js => chat-BEnAHpY-.js} | 2 +- ...82LsI6ZO.js => chunk-4BX2VUAB-WOh8BXBb.js} | 2 +- ...dQzh7akv.js => chunk-55IACEB6-CWcaiZ1g.js} | 2 +- ...BD6WP8Dt.js => chunk-B4BG7PRW-1SR22WeC.js} | 2 +- ...Dor0sVJI.js => chunk-DI55MBZ5-CqWBFVaC.js} | 2 +- ...B-XoLeQw.js => chunk-FMBD7UC4-DGED6SBi.js} | 2 +- ...aWjw7low.js => chunk-QN33PNHL-C8Gh8Kbh.js} | 2 +- ...Bi1rVrMI.js => chunk-QZHKN3VN-BpY3MN1h.js} | 2 +- ...BzDureVr.js => chunk-TZMSLE5B-Did4v35P.js} | 2 +- .../assets/classDiagram-2ON5EDUG-DYkXo-yO.js | 1 - .../assets/classDiagram-2ON5EDUG-pG5FcKCa.js | 1 + .../classDiagram-v2-WZHVMYZB-DYkXo-yO.js | 1 - .../classDiagram-v2-WZHVMYZB-pG5FcKCa.js | 1 + demo/aiui/assets/claude-provider-BpBBcvvu.js | 2 + demo/aiui/assets/claude-provider-DnmgFFcN.js | 2 - demo/aiui/assets/clone-BbeogWA3.js | 1 - demo/aiui/assets/clone-CJT8Sng7.js | 1 + ...u.js => cose-bilkent-S5V4N54A-CceqRbLG.js} | 2 +- ...D3-DYqn2.js => dagre-6UL2VRFP-pL4oLzgR.js} | 2 +- ...TfOYmW.js => diagram-PSM6KHXK-u9Bq7oQj.js} | 2 +- ...AGvEAB.js => diagram-QEK2KX5R--DLuyaBU.js} | 2 +- ...t74Kga.js => diagram-S2PKOQOG-pDeg6Fn3.js} | 2 +- ...Ldbe.js => erDiagram-Q2GNP2WA-Ar7Pe8f0.js} | 2 +- demo/aiui/assets/film-renderer-BjBNXUs-.js | 2 - demo/aiui/assets/film-renderer-Ds7Zr4Tu.js | 2 + ...xg.js => flowDiagram-NV44I4VS-D5zBfsz-.js} | 2 +- demo/aiui/assets/freeFilms-B9DmMKj5.js | 1 + demo/aiui/assets/freeFilms-DLEVjUOb.js | 1 - ...h.js => ganttDiagram-JELNMOA3-DicMT2oN.js} | 2 +- ...s => gitGraphDiagram-V2S2FVAM-BTxiEL-p.js} | 2 +- .../{graph-BI4iNatD.js => graph-mkJTNBrq.js} | 2 +- .../{index-BzKy-nNf.js => index-Lh5NfTCq.js} | 8 +- ...68.js => infoDiagram-HS3SLOUP-oVb3Z8wT.js} | 2 +- ...js => journeyDiagram-XKPGCS4Q-2pQB6VmZ.js} | 2 +- ...=> kanban-definition-3W4ZIXB7-4--rMebd.js} | 2 +- ...{layout-Dn20ATE3.js => layout-T-4jL0RA.js} | 2 +- ...{linear-G5w56VQ9.js => linear-BI0BnS_D.js} | 2 +- ...e-Bp72wBaC.js => mermaid.core-DaNhpuX9.js} | 8 +- ...> mindmap-definition-VGOIOE7T-BbRYcaHR.js} | 2 +- demo/aiui/assets/ollama-provider-BPRxN1UO.js | 2 - demo/aiui/assets/ollama-provider-Ck1Tq0Ld.js | 2 + ...yZx.js => pieDiagram-ADFJNKIX-DskAbgnA.js} | 2 +- ...s => quadrantDiagram-AYHSOK5B-Bp8ks7mP.js} | 2 +- ...> requirementDiagram-UZGBJVZJ-BhL2HWfZ.js} | 2 +- ....js => sankeyDiagram-TZEHDZUN-DqQOGyyA.js} | 2 +- ...s => sequenceDiagram-WL72ISMW-BukSiqtq.js} | 2 +- demo/aiui/assets/song-renderer-DRNqTHD0.js | 2 + demo/aiui/assets/song-renderer-DThhTKU4.js | 2 - ...-.js => stateDiagram-FKZM4ZOC-VzKqVF4W.js} | 2 +- .../stateDiagram-v2-4FDKWEC3-BBfEPULu.js | 1 - .../stateDiagram-v2-4FDKWEC3-DCr2kVu5.js | 1 + ... timeline-definition-IT6M3QCI-D5HR-Z95.js} | 2 +- ...nGbe1r.js => treemap-GDKQZRPO-yRLasM0b.js} | 2 +- ...FPc94o.js => useContentImages-CagIZs4M.js} | 2 +- ...Nostr-zyhtrXba.js => useNostr-DYbkCQxC.js} | 2 +- ...js => xychartDiagram-PRI3JC2R-CAhXzwZ1.js} | 2 +- demo/aiui/index.html | 10 +- demo/aiui/registerSW.js | 2 +- demo/aiui/sw.js | 2 +- .../archipelago-scripts/install-to-disk.sh | 10 +- image-recipe/build-auto-installer-iso.sh | 46 +++++-- image-recipe/configs/archipelago.service | 15 +-- image-recipe/configs/nginx-archipelago.conf | 4 - image-recipe/configs/nostr-vpn.service | 4 +- scripts/first-boot-containers.sh | 111 ++++++++++------ 94 files changed, 382 insertions(+), 233 deletions(-) rename demo/aiui/assets/{BrowsePage-DDnfUhk3.js => BrowsePage-C71ADslt.js} (99%) rename demo/aiui/assets/{ChatPage-0cJYh78p.js => ChatPage-BOjiIMc2.js} (92%) rename demo/aiui/assets/{ChatWindow-KqUPCuYg.css => ChatWindow-D6NcMh5O.css} (71%) rename demo/aiui/assets/{ChatWindow.vue_vue_type_script_setup_true_lang-CiskBM0U.js => ChatWindow.vue_vue_type_script_setup_true_lang-DoshhDBV.js} (52%) rename demo/aiui/assets/{ConversationViewerPage-BEZVAgnq.js => ConversationViewerPage-1f3wXZHu.js} (96%) rename demo/aiui/assets/{FilmDetail-D1axS-VK.js => FilmDetail-XFjPooKR.js} (51%) rename demo/aiui/assets/{FilmDetail.vue_vue_type_script_setup_true_lang-TCAQqc_e.js => FilmDetail.vue_vue_type_script_setup_true_lang-Cg4zvjy1.js} (97%) delete mode 100644 demo/aiui/assets/FilmGrid-Ce24sGyN.js create mode 100644 demo/aiui/assets/FilmGrid-EKTg8OUS.js rename demo/aiui/assets/{FilmGrid.vue_vue_type_script_setup_true_lang-BDhsWNsb.js => FilmGrid.vue_vue_type_script_setup_true_lang-CWkUdZ32.js} (97%) rename demo/aiui/assets/{GuidePage-BHJ1yOj7.js => GuidePage-CpiR8yAR.js} (98%) rename demo/aiui/assets/{SongDetail-DedB-36E.js => SongDetail-DCzBBkzH.js} (51%) rename demo/aiui/assets/{SongDetail.vue_vue_type_script_setup_true_lang-B41kpCIv.js => SongDetail.vue_vue_type_script_setup_true_lang-CvC0ROCb.js} (98%) create mode 100644 demo/aiui/assets/SongGrid-BgCYmw2O.js delete mode 100644 demo/aiui/assets/SongGrid-BjgAbnhC.js rename demo/aiui/assets/{SongGrid.vue_vue_type_script_setup_true_lang-BGfZFkPO.js => SongGrid.vue_vue_type_script_setup_true_lang-CW1T9zpX.js} (97%) rename demo/aiui/assets/{ThreadNode-Jt8WlAUM.js => ThreadNode-Bt5yTyUn.js} (95%) rename demo/aiui/assets/{WidgetDemoPage-D7wMN-ak.js => WidgetDemoPage-O5Vfu1LQ.js} (97%) rename demo/aiui/assets/{_basePickBy-BruevaAz.js => _basePickBy-BlfxZvco.js} (95%) rename demo/aiui/assets/{_baseUniq-Blm_akxr.js => _baseUniq-C5dU7AKy.js} (98%) rename demo/aiui/assets/{arc-BfzAnNAP.js => arc-M-sFvFvX.js} (98%) rename demo/aiui/assets/{architectureDiagram-VXUJARFQ-D3hZ4FnX.js => architectureDiagram-VXUJARFQ-CtiOagZF.js} (99%) rename demo/aiui/assets/{blockDiagram-VD42YOAC-DFZc3bbp.js => blockDiagram-VD42YOAC-DFxYaCGe.js} (99%) rename demo/aiui/assets/{c4Diagram-YG6GDRKO-xM4z28t2.js => c4Diagram-YG6GDRKO-DqniwIVA.js} (99%) create mode 100644 demo/aiui/assets/channel-DZA6uvxN.js delete mode 100644 demo/aiui/assets/channel-uO_MEpg2.js rename demo/aiui/assets/{chat-CR1al33K.js => chat-BEnAHpY-.js} (99%) rename demo/aiui/assets/{chunk-4BX2VUAB-82LsI6ZO.js => chunk-4BX2VUAB-WOh8BXBb.js} (71%) rename demo/aiui/assets/{chunk-55IACEB6-dQzh7akv.js => chunk-55IACEB6-CWcaiZ1g.js} (72%) rename demo/aiui/assets/{chunk-B4BG7PRW-BD6WP8Dt.js => chunk-B4BG7PRW-1SR22WeC.js} (99%) rename demo/aiui/assets/{chunk-DI55MBZ5-Dor0sVJI.js => chunk-DI55MBZ5-CqWBFVaC.js} (99%) rename demo/aiui/assets/{chunk-FMBD7UC4-B-XoLeQw.js => chunk-FMBD7UC4-DGED6SBi.js} (83%) rename demo/aiui/assets/{chunk-QN33PNHL-aWjw7low.js => chunk-QN33PNHL-C8Gh8Kbh.js} (87%) rename demo/aiui/assets/{chunk-QZHKN3VN-Bi1rVrMI.js => chunk-QZHKN3VN-BpY3MN1h.js} (66%) rename demo/aiui/assets/{chunk-TZMSLE5B-BzDureVr.js => chunk-TZMSLE5B-Did4v35P.js} (95%) delete mode 100644 demo/aiui/assets/classDiagram-2ON5EDUG-DYkXo-yO.js create mode 100644 demo/aiui/assets/classDiagram-2ON5EDUG-pG5FcKCa.js delete mode 100644 demo/aiui/assets/classDiagram-v2-WZHVMYZB-DYkXo-yO.js create mode 100644 demo/aiui/assets/classDiagram-v2-WZHVMYZB-pG5FcKCa.js create mode 100644 demo/aiui/assets/claude-provider-BpBBcvvu.js delete mode 100644 demo/aiui/assets/claude-provider-DnmgFFcN.js delete mode 100644 demo/aiui/assets/clone-BbeogWA3.js create mode 100644 demo/aiui/assets/clone-CJT8Sng7.js rename demo/aiui/assets/{cose-bilkent-S5V4N54A-B3h2gisu.js => cose-bilkent-S5V4N54A-CceqRbLG.js} (99%) rename demo/aiui/assets/{dagre-6UL2VRFP-D3-DYqn2.js => dagre-6UL2VRFP-pL4oLzgR.js} (97%) rename demo/aiui/assets/{diagram-PSM6KHXK-BRTfOYmW.js => diagram-PSM6KHXK-u9Bq7oQj.js} (97%) rename demo/aiui/assets/{diagram-QEK2KX5R-DVAGvEAB.js => diagram-QEK2KX5R--DLuyaBU.js} (94%) rename demo/aiui/assets/{diagram-S2PKOQOG-CYt74Kga.js => diagram-S2PKOQOG-pDeg6Fn3.js} (92%) rename demo/aiui/assets/{erDiagram-Q2GNP2WA-LFDWLdbe.js => erDiagram-Q2GNP2WA-Ar7Pe8f0.js} (98%) delete mode 100644 demo/aiui/assets/film-renderer-BjBNXUs-.js create mode 100644 demo/aiui/assets/film-renderer-Ds7Zr4Tu.js rename demo/aiui/assets/{flowDiagram-NV44I4VS-BZiwTlxg.js => flowDiagram-NV44I4VS-D5zBfsz-.js} (99%) create mode 100644 demo/aiui/assets/freeFilms-B9DmMKj5.js delete mode 100644 demo/aiui/assets/freeFilms-DLEVjUOb.js rename demo/aiui/assets/{ganttDiagram-JELNMOA3-D9WdDFmh.js => ganttDiagram-JELNMOA3-DicMT2oN.js} (99%) rename demo/aiui/assets/{gitGraphDiagram-V2S2FVAM-Z60Qif5y.js => gitGraphDiagram-V2S2FVAM-BTxiEL-p.js} (98%) rename demo/aiui/assets/{graph-BI4iNatD.js => graph-mkJTNBrq.js} (97%) rename demo/aiui/assets/{index-BzKy-nNf.js => index-Lh5NfTCq.js} (54%) rename demo/aiui/assets/{infoDiagram-HS3SLOUP-BUtAMk68.js => infoDiagram-HS3SLOUP-oVb3Z8wT.js} (62%) rename demo/aiui/assets/{journeyDiagram-XKPGCS4Q-DrVt-4mP.js => journeyDiagram-XKPGCS4Q-2pQB6VmZ.js} (98%) rename demo/aiui/assets/{kanban-definition-3W4ZIXB7-C9WSxADn.js => kanban-definition-3W4ZIXB7-4--rMebd.js} (99%) rename demo/aiui/assets/{layout-Dn20ATE3.js => layout-T-4jL0RA.js} (99%) rename demo/aiui/assets/{linear-G5w56VQ9.js => linear-BI0BnS_D.js} (98%) rename demo/aiui/assets/{mermaid.core-Bp72wBaC.js => mermaid.core-DaNhpuX9.js} (99%) rename demo/aiui/assets/{mindmap-definition-VGOIOE7T-Cv8kGwbk.js => mindmap-definition-VGOIOE7T-BbRYcaHR.js} (99%) delete mode 100644 demo/aiui/assets/ollama-provider-BPRxN1UO.js create mode 100644 demo/aiui/assets/ollama-provider-Ck1Tq0Ld.js rename demo/aiui/assets/{pieDiagram-ADFJNKIX-dv9eWyZx.js => pieDiagram-ADFJNKIX-DskAbgnA.js} (92%) rename demo/aiui/assets/{quadrantDiagram-AYHSOK5B-CYUMAZxF.js => quadrantDiagram-AYHSOK5B-Bp8ks7mP.js} (99%) rename demo/aiui/assets/{requirementDiagram-UZGBJVZJ-YSWU7wM2.js => requirementDiagram-UZGBJVZJ-BhL2HWfZ.js} (99%) rename demo/aiui/assets/{sankeyDiagram-TZEHDZUN-T-T7pPL5.js => sankeyDiagram-TZEHDZUN-DqQOGyyA.js} (99%) rename demo/aiui/assets/{sequenceDiagram-WL72ISMW-D6JvJDMe.js => sequenceDiagram-WL72ISMW-BukSiqtq.js} (99%) create mode 100644 demo/aiui/assets/song-renderer-DRNqTHD0.js delete mode 100644 demo/aiui/assets/song-renderer-DThhTKU4.js rename demo/aiui/assets/{stateDiagram-FKZM4ZOC-CsEu5A1-.js => stateDiagram-FKZM4ZOC-VzKqVF4W.js} (96%) delete mode 100644 demo/aiui/assets/stateDiagram-v2-4FDKWEC3-BBfEPULu.js create mode 100644 demo/aiui/assets/stateDiagram-v2-4FDKWEC3-DCr2kVu5.js rename demo/aiui/assets/{timeline-definition-IT6M3QCI-DAvrjQlO.js => timeline-definition-IT6M3QCI-D5HR-Z95.js} (99%) rename demo/aiui/assets/{treemap-GDKQZRPO-AdnGbe1r.js => treemap-GDKQZRPO-yRLasM0b.js} (99%) rename demo/aiui/assets/{useContentImages-h7FPc94o.js => useContentImages-CagIZs4M.js} (90%) rename demo/aiui/assets/{useNostr-zyhtrXba.js => useNostr-DYbkCQxC.js} (98%) rename demo/aiui/assets/{xychartDiagram-PRI3JC2R-DCRwYb86.js => xychartDiagram-PRI3JC2R-CAhXzwZ1.js} (99%) diff --git a/core/archipelago/src/api/rpc/auth.rs b/core/archipelago/src/api/rpc/auth.rs index d09888f5..2da45ad7 100644 --- a/core/archipelago/src/api/rpc/auth.rs +++ b/core/archipelago/src/api/rpc/auth.rs @@ -32,6 +32,26 @@ impl RpcHandler { } tracing::info!("[onboarding] login successful"); + + // Ensure NostrVPN config exists — covers the case where onboardingComplete + // was never called (e.g., user took the "already set up" shortcut). + let data_dir = self.config.data_dir.clone(); + tokio::spawn(async move { + // Quick check: if config.toml already exists, skip + let config_path = data_dir.join("nostr-vpn/.config/nvpn/config.toml"); + if config_path.exists() { + return; + } + // Identity must exist for VPN config + if !data_dir.join("identity/nostr_pubkey").exists() { + return; + } + match crate::vpn::configure_nostr_vpn(&data_dir).await { + Ok(()) => tracing::info!("[login] NostrVPN auto-configured on first login"), + Err(e) => tracing::debug!("[login] NostrVPN auto-config skipped: {}", e), + } + }); + Ok(serde_json::Value::Null) } diff --git a/core/archipelago/src/api/rpc/vpn.rs b/core/archipelago/src/api/rpc/vpn.rs index 33fcd644..aeae27f2 100644 --- a/core/archipelago/src/api/rpc/vpn.rs +++ b/core/archipelago/src/api/rpc/vpn.rs @@ -36,7 +36,8 @@ impl RpcHandler { Err(_) => None, }; - let node_npub = vpn::read_nvpn_config_value("nostr", "public_key").await; + let node_npub = vpn::read_nvpn_config_value("nostr", "public_key").await + .map(|k| vpn::ensure_npub(&k)); let (relay_onion, relay_direct) = vpn::get_relay_urls().await; // Prefer onion (always works), fall back to direct IP let relay_url = relay_onion.clone().or(relay_direct.clone()); @@ -260,9 +261,10 @@ impl RpcHandler { } } - // Read nvpn config to build invite + // Read nvpn config to build invite (convert hex to npub1 if needed) let npub = vpn::read_nvpn_config_value("nostr", "public_key").await - .ok_or_else(|| anyhow::anyhow!("No Nostr public key in nvpn config"))?; + .map(|k| vpn::ensure_npub(&k)) + .ok_or_else(|| anyhow::anyhow!("No Nostr public key in nvpn config — VPN not configured"))?; // network_id is in [[networks]] array — read first entry let network_id = vpn::read_nvpn_config_list_entry("networks", "network_id").await .unwrap_or_else(|| "nostr-vpn".to_string()); diff --git a/core/archipelago/src/vpn.rs b/core/archipelago/src/vpn.rs index e7461c4b..0f612346 100644 --- a/core/archipelago/src/vpn.rs +++ b/core/archipelago/src/vpn.rs @@ -4,6 +4,7 @@ //! VPN interface status for remote access to the Archipelago node. use anyhow::{Context, Result}; +use nostr_sdk::ToBech32; use serde::{Deserialize, Serialize}; use std::path::Path; use tokio::fs; @@ -336,24 +337,61 @@ async fn get_nostr_vpn_status() -> Result { }) } +/// Convert a hex public key to npub1... bech32 format. +/// Returns the original string if already npub1 or conversion fails. +pub fn ensure_npub(key: &str) -> String { + let key = key.trim(); + if key.starts_with("npub1") { + return key.to_string(); + } + nostr_sdk::PublicKey::from_hex(key) + .ok() + .and_then(|pk| pk.to_bech32().ok()) + .unwrap_or_else(|| key.to_string()) +} + +/// Convert a hex secret key to nsec1... bech32 format. +/// Returns the original string if already nsec1 or conversion fails. +fn ensure_nsec(key: &str) -> String { + let key = key.trim(); + if key.starts_with("nsec1") { + return key.to_string(); + } + nostr_sdk::SecretKey::from_hex(key) + .ok() + .and_then(|sk| sk.to_bech32().ok()) + .unwrap_or_else(|| key.to_string()) +} + /// Configure NostrVPN with the node's Nostr identity. +/// Writes both the env file (for systemd) and config.toml (for vpn.invite/status). pub async fn configure_nostr_vpn(data_dir: &Path) -> Result<()> { - let nostr_secret = tokio::fs::read_to_string( + let nostr_secret_hex = tokio::fs::read_to_string( data_dir.join("identity/nostr_secret") ).await.context("No Nostr secret key — complete onboarding first")?; - let nostr_pubkey = tokio::fs::read_to_string( + let nostr_pubkey_hex = tokio::fs::read_to_string( data_dir.join("identity/nostr_pubkey") ).await.unwrap_or_default(); + let nostr_secret_hex = nostr_secret_hex.trim(); + let nostr_pubkey_hex = nostr_pubkey_hex.trim(); + + if nostr_pubkey_hex.is_empty() { + anyhow::bail!("Empty Nostr public key — identity not ready"); + } + + // Convert hex keys to bech32 (npub1.../nsec1...) + let npub = ensure_npub(nostr_pubkey_hex); + let nsec = ensure_nsec(nostr_secret_hex); + let vpn_dir = data_dir.join("nostr-vpn"); tokio::fs::create_dir_all(&vpn_dir).await.context("Failed to create nostr-vpn dir")?; // Write env file for the systemd service let env_content = format!( "NOSTR_SECRET={}\nNOSTR_PUBKEY={}\n", - nostr_secret.trim(), - nostr_pubkey.trim() + nostr_secret_hex, nostr_pubkey_hex ); tokio::fs::write(vpn_dir.join("env"), &env_content) .await @@ -368,6 +406,55 @@ pub async fn configure_nostr_vpn(data_dir: &Path) -> Result<()> { ).ok(); } + // Write nvpn config.toml so vpn.invite and vpn.status can read the node identity. + // This is the primary fix: previously only env was written, but all VPN RPC handlers + // read from config.toml — not env vars. + let config_dir = vpn_dir.join(".config/nvpn"); + tokio::fs::create_dir_all(&config_dir).await.context("Failed to create nvpn config dir")?; + + let config_path = config_dir.join("config.toml"); + // Only write if config doesn't exist or has no public_key + // (avoid clobbering participants list added by vpn.add-participant) + let should_write = if let Ok(existing) = tokio::fs::read_to_string(&config_path).await { + !existing.contains("public_key") + } else { + true + }; + + if should_write { + // Gather relay URLs for the config + let (relay_onion, relay_direct) = get_relay_urls().await; + let mut relays = Vec::new(); + if let Some(ref onion) = relay_onion { + relays.push(format!("\"{}\"", onion)); + } + if let Some(ref direct) = relay_direct { + relays.push(format!("\"{}\"", direct)); + } + if relays.is_empty() { + relays.push("\"wss://relay.damus.io\"".to_string()); + relays.push("\"wss://relay.primal.net\"".to_string()); + } + + let config_toml = format!( + "[nostr]\npublic_key = \"{npub}\"\nsecret_key = \"{nsec}\"\nrelays = [{relays}]\n\n[[networks]]\nnetwork_id = \"archipelago\"\nparticipants = []\n", + npub = npub, + nsec = nsec, + relays = relays.join(", "), + ); + tokio::fs::write(&config_path, &config_toml) + .await + .context("Failed to write nvpn config.toml")?; + + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + std::fs::set_permissions(&config_path, std::fs::Permissions::from_mode(0o600)).ok(); + } + + tracing::info!("Wrote nvpn config.toml with node npub"); + } + // Reset any previous failure state (systemd rate-limits restarts before onboarding) let _ = tokio::process::Command::new("systemctl") .args(["reset-failed", "nostr-vpn"]) diff --git a/demo/aiui/assets/BrowsePage-DDnfUhk3.js b/demo/aiui/assets/BrowsePage-C71ADslt.js similarity index 99% rename from demo/aiui/assets/BrowsePage-DDnfUhk3.js rename to demo/aiui/assets/BrowsePage-C71ADslt.js index d1958d76..40258f97 100644 --- a/demo/aiui/assets/BrowsePage-DDnfUhk3.js +++ b/demo/aiui/assets/BrowsePage-C71ADslt.js @@ -1,2 +1,2 @@ -import{a as M,c as o,F as b,g as E,b as s,e,n as F,t as p,L as g,i as y,r as w,P as B,k as D,K as L,o as T,M as H,Q as z,V as S,W as j}from"./index-BzKy-nNf.js";const V={class:"space-y-0.5"},A=["onClick"],O={key:1,class:"w-3 shrink-0"},I=["d"],R={class:"text-sm truncate"},N={key:0,class:"pl-4 ml-[18px] border-l border-white/5"},W="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z",U="M5 19a2 2 0 01-2-2V7a2 2 0 012-2h4l2 2h4a2 2 0 012 2v1M5 19h14a2 2 0 002-2v-5a2 2 0 00-2-2H9a2 2 0 00-2 2v5a2 2 0 01-2 2z",G="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4",K="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z",X="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z",q=M({__name:"FileTree",props:{items:{}},emits:["selectFile"],setup(m,{emit:_}){const h=w(new Set),v=_;function n(l){if(l.isDirectory){const a=new Set(h.value);a.has(l.path)?a.delete(l.path):a.add(l.path),h.value=a}else v("selectFile",l)}const r=new Set(["ts","tsx","js","jsx","vue","svelte","py","rs","go","java","c","cpp","h","hpp","rb","php","swift","kt","cs","css","scss","less","html","xml","yaml","yml","toml","json","sh","bash","zsh","sql","md","mdx"]),c=new Set(["png","jpg","jpeg","gif","svg","webp","ico","bmp","avif"]);function x(l){return l.split(".").pop()?.toLowerCase()??""}function k(l){if(l.isDirectory)return"text-yellow-500/70";const a=x(l.name);return r.has(a)?"text-blue-400/70":c.has(a)?"text-green-400/70":"text-white/40"}function $(l){if(l.isDirectory)return h.value.has(l.path)?U:W;const a=x(l.name);return r.has(a)?G:c.has(a)?K:X}return(l,a)=>{const C=B("FileTree",!0);return s(),o("div",V,[(s(!0),o(b,null,E(m.items,u=>(s(),o("div",{key:u.path},[e("button",{class:F(["w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left transition-colors min-h-[32px]",u.isDirectory?"hover:bg-white/5 text-white/70 hover:text-white/80":"hover:bg-white/8 text-white/60 hover:text-white/80"]),onClick:i=>n(u)},[u.isDirectory?(s(),o("svg",{key:0,class:F(["w-3 h-3 text-white/30 shrink-0 transition-transform duration-150",{"rotate-90":h.value.has(u.path)}]),fill:"currentColor",viewBox:"0 0 20 20"},[...a[1]||(a[1]=[e("path",{"fill-rule":"evenodd",d:"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z","clip-rule":"evenodd"},null,-1)])],2)):(s(),o("span",O)),(s(),o("svg",{class:F(["w-4 h-4 shrink-0",k(u)]),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:$(u)},null,8,I)],2)),e("span",R,p(u.name),1)],10,A),u.isDirectory&&u.children?.length&&h.value.has(u.path)?(s(),o("div",N,[g(C,{items:u.children,onSelectFile:a[0]||(a[0]=i=>l.$emit("selectFile",i))},null,8,["items"])])):y("",!0)]))),128))])}}}),Q={class:"h-full flex flex-col"},J={class:"flex items-center justify-between px-4 py-3 border-b border-white/5 shrink-0"},Y={class:"min-w-0 flex-1"},Z={class:"text-sm font-medium text-white/80 truncate"},ee={class:"text-xs text-white/30 truncate mt-0.5"},te={class:"flex items-center gap-2 shrink-0 ml-3"},se={class:"text-xs text-white/25 font-mono"},oe={class:"flex-1 overflow-auto"},ne={class:"text-xs font-mono leading-relaxed w-full"},le={class:"text-white/20 text-right pr-4 pl-4 py-0 select-none align-top whitespace-nowrap sticky left-0 bg-[#0a0a0a]"},ae={class:"text-white/70 pr-4 py-0 whitespace-pre"},P=M({__name:"FilePreview",props:{file:{}},emits:["close"],setup(m){const _=m,h=D(()=>_.file.content.split(` +import{a as M,c as o,F as b,g as E,b as s,e,n as F,t as p,L as g,i as y,r as w,P as B,k as D,K as L,o as T,M as H,Q as z,V as S,W as j}from"./index-Lh5NfTCq.js";const V={class:"space-y-0.5"},A=["onClick"],O={key:1,class:"w-3 shrink-0"},I=["d"],R={class:"text-sm truncate"},N={key:0,class:"pl-4 ml-[18px] border-l border-white/5"},W="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z",U="M5 19a2 2 0 01-2-2V7a2 2 0 012-2h4l2 2h4a2 2 0 012 2v1M5 19h14a2 2 0 002-2v-5a2 2 0 00-2-2H9a2 2 0 00-2 2v5a2 2 0 01-2 2z",G="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4",K="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z",X="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z",q=M({__name:"FileTree",props:{items:{}},emits:["selectFile"],setup(m,{emit:_}){const h=w(new Set),v=_;function n(l){if(l.isDirectory){const a=new Set(h.value);a.has(l.path)?a.delete(l.path):a.add(l.path),h.value=a}else v("selectFile",l)}const r=new Set(["ts","tsx","js","jsx","vue","svelte","py","rs","go","java","c","cpp","h","hpp","rb","php","swift","kt","cs","css","scss","less","html","xml","yaml","yml","toml","json","sh","bash","zsh","sql","md","mdx"]),c=new Set(["png","jpg","jpeg","gif","svg","webp","ico","bmp","avif"]);function x(l){return l.split(".").pop()?.toLowerCase()??""}function k(l){if(l.isDirectory)return"text-yellow-500/70";const a=x(l.name);return r.has(a)?"text-blue-400/70":c.has(a)?"text-green-400/70":"text-white/40"}function $(l){if(l.isDirectory)return h.value.has(l.path)?U:W;const a=x(l.name);return r.has(a)?G:c.has(a)?K:X}return(l,a)=>{const C=B("FileTree",!0);return s(),o("div",V,[(s(!0),o(b,null,E(m.items,u=>(s(),o("div",{key:u.path},[e("button",{class:F(["w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left transition-colors min-h-[32px]",u.isDirectory?"hover:bg-white/5 text-white/70 hover:text-white/80":"hover:bg-white/8 text-white/60 hover:text-white/80"]),onClick:i=>n(u)},[u.isDirectory?(s(),o("svg",{key:0,class:F(["w-3 h-3 text-white/30 shrink-0 transition-transform duration-150",{"rotate-90":h.value.has(u.path)}]),fill:"currentColor",viewBox:"0 0 20 20"},[...a[1]||(a[1]=[e("path",{"fill-rule":"evenodd",d:"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z","clip-rule":"evenodd"},null,-1)])],2)):(s(),o("span",O)),(s(),o("svg",{class:F(["w-4 h-4 shrink-0",k(u)]),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:$(u)},null,8,I)],2)),e("span",R,p(u.name),1)],10,A),u.isDirectory&&u.children?.length&&h.value.has(u.path)?(s(),o("div",N,[g(C,{items:u.children,onSelectFile:a[0]||(a[0]=i=>l.$emit("selectFile",i))},null,8,["items"])])):y("",!0)]))),128))])}}}),Q={class:"h-full flex flex-col"},J={class:"flex items-center justify-between px-4 py-3 border-b border-white/5 shrink-0"},Y={class:"min-w-0 flex-1"},Z={class:"text-sm font-medium text-white/80 truncate"},ee={class:"text-xs text-white/30 truncate mt-0.5"},te={class:"flex items-center gap-2 shrink-0 ml-3"},se={class:"text-xs text-white/25 font-mono"},oe={class:"flex-1 overflow-auto"},ne={class:"text-xs font-mono leading-relaxed w-full"},le={class:"text-white/20 text-right pr-4 pl-4 py-0 select-none align-top whitespace-nowrap sticky left-0 bg-[#0a0a0a]"},ae={class:"text-white/70 pr-4 py-0 whitespace-pre"},P=M({__name:"FilePreview",props:{file:{}},emits:["close"],setup(m){const _=m,h=D(()=>_.file.content.split(` `));function v(n){return n<1024?`${n} B`:n<1024*1024?`${(n/1024).toFixed(1)} KB`:`${(n/(1024*1024)).toFixed(1)} MB`}return(n,r)=>(s(),o("div",Q,[e("div",J,[e("div",Y,[e("p",Z,p(m.file.name),1),e("p",ee,p(m.file.path),1)]),e("div",te,[e("span",se,p(v(m.file.size)),1),e("button",{class:"min-w-[32px] min-h-[32px] flex items-center justify-center rounded-md text-white/40 hover:text-white/70 hover:bg-white/10 transition-colors","aria-label":"Close preview",onClick:r[0]||(r[0]=c=>n.$emit("close"))},[...r[1]||(r[1]=[e("svg",{class:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M6 18L18 6M6 6l12 12"})],-1)])])])]),e("div",oe,[e("table",ne,[e("tbody",null,[(s(!0),o(b,null,E(h.value,(c,x)=>(s(),o("tr",{key:x,class:"hover:bg-white/3"},[e("td",le,p(x+1),1),e("td",ae,p(c),1)]))),128))])])])]))}}),ie={class:"h-full flex flex-col bg-[#0a0a0a]"},re={class:"glass shrink-0 px-4 py-3 flex items-center gap-3 border-b border-white/5"},ce={class:"px-4 py-2 flex items-center gap-1 text-xs text-white/40 shrink-0"},ue={class:"text-white/60 min-h-[28px] px-1 flex items-center"},he={class:"flex-1 overflow-hidden flex"},de={class:"flex-1 overflow-y-auto px-2 py-2"},pe={key:0,class:"flex items-center justify-center h-32"},ve={key:1,class:"flex items-center justify-center h-32"},fe={class:"text-sm text-red-400/70"},xe={key:2,class:"space-y-1"},we=["onClick"],me={class:"min-w-0 flex-1"},_e={class:"text-sm text-white/80 truncate group-hover:text-white/90"},ke={class:"text-xs text-white/25 truncate"},ge={key:0,class:"w-[400px] xl:w-[500px] border-l border-white/5 overflow-y-auto shrink-0"},ye={key:0,class:"fixed inset-0 z-50 bg-[#0a0a0a] overflow-y-auto"},Ce=M({__name:"BrowsePage",setup(m){const _=w([]),h=w([]),v=w(!0),n=w(""),r=w(null),c=w(null),x=w(window.innerWidth),k=D(()=>x.value<1024);async function $(){v.value=!0,n.value="";try{const i=await j("/api/fs/list");if(!i.ok)throw new Error(`Failed to load: ${i.status}`);const t=await i.json();_.value=t.projects??[]}catch(i){n.value=i instanceof Error?i.message:"Failed to load projects"}finally{v.value=!1}}async function l(i){r.value=i,c.value=null,v.value=!0,n.value="";try{const t=await j(`/api/fs/tree?path=${encodeURIComponent(i.path)}`);if(!t.ok)throw new Error(`Failed to load: ${t.status}`);const d=await t.json();h.value=d.files??[]}catch(t){n.value=t instanceof Error?t.message:"Failed to load files"}finally{v.value=!1}}function a(){r.value=null,c.value=null,h.value=[]}async function C(i){if(!r.value)return;const t=r.value.path+"/"+i.path;try{const d=await j(`/api/fs/read?path=${encodeURIComponent(t)}`);if(!d.ok){if(d.status===413){n.value="File too large to preview (max 1MB)";return}throw new Error(`Failed to read: ${d.status}`)}const f=await d.json();c.value={name:i.name,path:i.path,content:f.content,size:f.size}}catch(d){n.value=d instanceof Error?d.message:"Failed to read file"}}function u(){x.value=window.innerWidth}return L(()=>{$(),window.addEventListener("resize",u)}),T(()=>{window.removeEventListener("resize",u)}),(i,t)=>{const d=B("router-link");return s(),o("div",ie,[e("header",re,[g(d,{to:"/",class:"min-w-[44px] min-h-[44px] flex items-center justify-center rounded-lg text-white/60 hover:text-white/80 hover:bg-white/10 transition-colors","aria-label":"Back to chat"},{default:H(()=>[...t[2]||(t[2]=[e("svg",{class:"w-5 h-5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M15 19l-7-7 7-7"})],-1)])]),_:1}),t[3]||(t[3]=e("h1",{class:"text-white/90 text-base font-medium truncate"},"Files",-1))]),e("nav",ce,[e("button",{class:"hover:text-white/70 transition-colors min-h-[28px] px-1",onClick:a}," Projects "),r.value?(s(),o(b,{key:0},[t[4]||(t[4]=e("span",{class:"text-white/20"},"/",-1)),e("span",ue,p(r.value.name),1)],64)):y("",!0)]),e("main",he,[e("div",de,[v.value?(s(),o("div",pe,[...t[5]||(t[5]=[e("span",{class:"text-sm text-white/50"},"Loading...",-1)])])):n.value?(s(),o("div",ve,[e("span",fe,p(n.value),1)])):r.value?(s(),z(q,{key:3,items:h.value,onSelectFile:C},null,8,["items"])):(s(),o("div",xe,[(s(!0),o(b,null,E(_.value,f=>(s(),o("button",{key:f.path,class:"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-left hover:bg-white/5 transition-colors group",onClick:be=>l(f)},[t[6]||(t[6]=e("svg",{class:"w-5 h-5 text-white/30 shrink-0",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"})],-1)),e("div",me,[e("p",_e,p(f.name),1),e("p",ke,p(f.language),1)])],8,we))),128))]))]),c.value&&!k.value?(s(),o("aside",ge,[g(P,{file:c.value,onClose:t[0]||(t[0]=f=>c.value=null)},null,8,["file"])])):y("",!0)]),(s(),z(S,{to:"body"},[c.value&&k.value?(s(),o("div",ye,[g(P,{file:c.value,onClose:t[1]||(t[1]=f=>c.value=null)},null,8,["file"])])):y("",!0)]))])}}});export{Ce as default}; diff --git a/demo/aiui/assets/ChatPage-0cJYh78p.js b/demo/aiui/assets/ChatPage-BOjiIMc2.js similarity index 92% rename from demo/aiui/assets/ChatPage-0cJYh78p.js rename to demo/aiui/assets/ChatPage-BOjiIMc2.js index a2ef1e71..9b3c226e 100644 --- a/demo/aiui/assets/ChatPage-0cJYh78p.js +++ b/demo/aiui/assets/ChatPage-BOjiIMc2.js @@ -1,5 +1,5 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/useNostr-zyhtrXba.js","assets/index-BzKy-nNf.js","assets/index-CHQ7uqBj.css","assets/ThreadNode-Jt8WlAUM.js"])))=>i.map(i=>d[i]); -import{a as q,Z as Ht,$ as ut,p as Ne,b as s,c as n,e,h as G,u as t,n as o,t as d,f as ie,w as W,v as Q,F as I,g as B,i as m,j as J,r as M,k as L,a0 as Wt,a1 as xt,N as ne,a2 as ht,a3 as pt,a4 as gt,a5 as vt,U as De,a6 as Kt,a7 as Yt,a8 as Qt,P as Jt,z as he,Q as E,K as le,a9 as ae,aa as ye,_ as bt,A as ce,B as Pe,d as Zt,ab as Xt,L as se,ac as es,ad as ts,ae as ss,af as ns,S as ls,q as os,ag as as,o as is,M as ue,ah as Be,ai as rs}from"./index-BzKy-nNf.js";import{u as cs}from"./chat-CR1al33K.js";import{u as $e,a as pe,e as Ye,d as ft,M as ds,b as us,s as xs,c as hs,f as be,_ as lt}from"./ChatWindow.vue_vue_type_script_setup_true_lang-CiskBM0U.js";import{_ as ps}from"./FilmGrid.vue_vue_type_script_setup_true_lang-BDhsWNsb.js";import{u as Ae}from"./useContentImages-h7FPc94o.js";import{_ as gs}from"./SongGrid.vue_vue_type_script_setup_true_lang-BGfZFkPO.js";import{useNostr as Le}from"./useNostr-zyhtrXba.js";import{u as mt,_ as vs}from"./FilmDetail.vue_vue_type_script_setup_true_lang-TCAQqc_e.js";import{_ as bs}from"./SongDetail.vue_vue_type_script_setup_true_lang-B41kpCIv.js";const fs={class:"h-full flex flex-col"},ms={class:"flex items-center justify-between gap-2"},ws={class:"flex items-center gap-2 shrink-0"},ys={key:0,class:"flex flex-wrap gap-1.5"},ks=["onClick"],$s={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-4 pb-16"},_s={class:"grid grid-cols-2 sm:grid-cols-3 gap-4"},Cs=["aria-label","onClick"],Ss={class:"cover-card flex-1 min-h-0 relative"},js={key:0,class:"absolute inset-0 animate-shimmer"},Ms=["src","alt","onError"],Ts=["src","alt"],Ds={key:3,class:"absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent pointer-events-none"},Ls={class:"absolute bottom-0 left-0 right-0 p-2"},Is={class:"text-xs font-semibold text-white/90 leading-tight truncate"},Bs={class:"text-xs text-white/40 truncate mt-0.5"},Ps={key:4,class:"absolute top-1.5 left-1.5"},Ns={class:"text-xs px-1.5 py-0.5 rounded bg-black/60 text-amber-400 backdrop-blur-sm font-medium"},As={key:5,class:"absolute top-1.5 right-1.5"},zs={class:"text-xs px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"},Fs={key:0,class:"flex items-center justify-center py-12"},Es=q({__name:"BookGrid",props:{books:{},title:{default:"Recommended Books"}},emits:["selectBook"],setup(a){const c=a,{isDark:l}=J(),w=M(""),g=M(null),{coverSrc:b,fallbackSrc:p,onError:v,isLoading:_}=Ae({items:Ne(c,"books"),id:u=>u.id,existingUrl:u=>u.coverUrl,fetch:u=>ut(u.title,u.author),fallback:u=>Ht(u.title,u.author)}),C=L(()=>{const u=new Map;for(const i of c.books)for(const r of i.genres??[])u.set(r,(u.get(r)??0)+1);return[...u.entries()].sort((i,r)=>r[1]-i[1]).slice(0,8).map(([i])=>i)}),f=L(()=>{let u=c.books;if(w.value){const i=w.value.toLowerCase();u=u.filter(r=>r.title.toLowerCase().includes(i)||r.author.toLowerCase().includes(i)||(r.genres??[]).some(x=>x.toLowerCase().includes(i)))}return g.value&&(u=u.filter(i=>(i.genres??[]).includes(g.value))),u});return(u,i)=>(s(),n("div",fs,[e("div",{class:"p-4 space-y-3",style:G(t(l)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",ms,[e("h3",{class:o(["text-sm font-bold",t(l)?"text-white/90":"text-gray-900"])},d(a.title),3),e("div",ws,[e("span",{class:o(["text-xs font-mono",t(l)?"text-white/30":"text-gray-400"])},d(f.value.length)+" books ",3),ie(u.$slots,"header-actions")])]),W(e("input",{"onUpdate:modelValue":i[0]||(i[0]=r=>w.value=r),type:"text",placeholder:"Search books...",class:o(["w-full px-3 py-2 rounded-lg text-base outline-none transition-colors",t(l)?"bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10":"bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5"])},null,2),[[Q,w.value]]),C.value.length>0?(s(),n("div",ys,[(s(!0),n(I,null,B(C.value,r=>(s(),n("button",{key:r,class:o(["text-xs px-2 py-1 rounded-md transition-all duration-150",g.value===r?"nav-tab-active":t(l)?"text-white/40 hover:text-white/70 hover:bg-white/5":"text-gray-500 hover:text-gray-800 hover:bg-black/5"]),onClick:x=>g.value=g.value===r?null:r},d(r),11,ks))),128))])):m("",!0)],4),e("div",$s,[e("div",_s,[(s(!0),n(I,null,B(f.value,r=>(s(),n("button",{key:r.id,class:"group flex flex-col items-stretch text-left w-full path-glass-bubble rounded-2xl overflow-hidden transition-all duration-200 hover:brightness-105","aria-label":`${r.title} by ${r.author}`,onClick:x=>u.$emit("selectBook",r)},[e("div",Ss,[e("div",{class:o(["aspect-[2/3] relative w-full overflow-hidden rounded-[10px]",t(b)(r)?"":t(l)?"bg-white/[0.06]":"bg-black/[0.04]"])},[t(_)(r)?(s(),n("div",js)):m("",!0),t(b)(r)?(s(),n("img",{key:1,src:t(b)(r),alt:`${r.title} by ${r.author}`,class:"w-full h-full object-cover transition-transform duration-300 group-hover:scale-110",loading:"lazy",onError:x=>t(v)(r)},null,40,Ms)):t(_)(r)?m("",!0):(s(),n("img",{key:2,src:t(p)(r),alt:r.title,class:"w-full h-full object-cover"},null,8,Ts)),t(b)(r)?(s(),n("div",Ds)):m("",!0),e("div",Ls,[e("p",Is,d(r.title),1),e("p",Bs,d(r.author),1)]),r.rating?(s(),n("div",Ps,[e("span",Ns," ★ "+d(r.rating.toFixed(1)),1)])):m("",!0),r.year?(s(),n("div",As,[e("span",zs,d(r.year),1)])):m("",!0)],2)])],8,Cs))),128))]),f.value.length===0?(s(),n("div",Fs,[e("p",{class:o(["text-sm",t(l)?"text-white/30":"text-gray-400"])}," No books match your search ",2)])):m("",!0)])]))}}),Rs={class:"h-full flex flex-col"},Vs={class:"flex items-center justify-between gap-2"},Us={class:"flex items-center gap-2 shrink-0"},qs={key:0,class:"flex flex-wrap gap-1.5"},Gs=["onClick"],Os={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-4 pb-16"},Hs={class:"grid grid-cols-2 sm:grid-cols-3 gap-4"},Ws=["aria-label","onClick"],Ks={class:"cover-card flex-1 min-h-0 relative"},Ys={key:0,class:"absolute inset-0 animate-shimmer"},Qs=["src","alt","onError"],Js=["src","alt"],Zs={key:3,class:"absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent pointer-events-none"},Xs={class:"absolute bottom-0 left-0 right-0 p-2"},en={class:"text-xs font-semibold text-white/90 leading-tight truncate"},tn={class:"text-xs text-white/40 truncate mt-0.5"},sn={key:4,class:"absolute top-1.5 left-1.5"},nn={class:"text-xs px-1.5 py-0.5 rounded bg-black/60 text-amber-400 backdrop-blur-sm font-medium"},ln={key:5,class:"absolute top-1.5 right-1.5"},on={class:"absolute top-1.5 right-1.5 flex gap-0.5 flex-wrap justify-end max-w-[60%]"},an={key:0,class:"flex items-center justify-center py-12"},rn=q({__name:"TVSeriesGrid",props:{series:{},title:{default:"Recommended TV Series"}},emits:["selectSeries"],setup(a){const c=a,{isDark:l}=J(),w=M(""),g=M(null),{coverSrc:b,fallbackSrc:p,onError:v,isLoading:_}=Ae({items:Ne(c,"series"),id:i=>i.id,existingUrl:i=>i.posterUrl||i.backdropUrl,fetch:i=>xt(i.title,i.year).then(r=>r.posterUrl),fallback:i=>Wt(i.title,i.year)});function C(i){return i.year?i.endYear&&i.endYear!==i.year?`${i.year}–${i.endYear}`:i.status==="ongoing"?`${i.year}–`:String(i.year):""}const f=L(()=>{const i=new Map;for(const r of c.series)for(const x of r.genres??[])i.set(x,(i.get(x)??0)+1);return[...i.entries()].sort((r,x)=>x[1]-r[1]).slice(0,8).map(([r])=>r)}),u=L(()=>{let i=c.series;if(w.value){const r=w.value.toLowerCase();i=i.filter(x=>x.title.toLowerCase().includes(r)||(x.creator??"").toLowerCase().includes(r)||(x.network??"").toLowerCase().includes(r)||(x.genres??[]).some(S=>S.toLowerCase().includes(r)))}return g.value&&(i=i.filter(r=>(r.genres??[]).includes(g.value))),i});return(i,r)=>(s(),n("div",Rs,[e("div",{class:"p-4 space-y-3",style:G(t(l)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",Vs,[e("h3",{class:o(["text-sm font-bold",t(l)?"text-white/90":"text-gray-900"])},d(a.title),3),e("div",Us,[e("span",{class:o(["text-xs font-mono",t(l)?"text-white/30":"text-gray-400"])},d(u.value.length)+" series ",3),ie(i.$slots,"header-actions")])]),W(e("input",{"onUpdate:modelValue":r[0]||(r[0]=x=>w.value=x),type:"text",placeholder:"Search TV series...",class:o(["w-full px-3 py-2 rounded-lg text-base outline-none transition-colors",t(l)?"bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10":"bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5"])},null,2),[[Q,w.value]]),f.value.length>0?(s(),n("div",qs,[(s(!0),n(I,null,B(f.value,x=>(s(),n("button",{key:x,class:o(["text-xs px-2 py-1 rounded-md transition-all duration-150",g.value===x?"nav-tab-active":t(l)?"text-white/40 hover:text-white/70 hover:bg-white/5":"text-gray-500 hover:text-gray-800 hover:bg-black/5"]),onClick:S=>g.value=g.value===x?null:x},d(x),11,Gs))),128))])):m("",!0)],4),e("div",Os,[e("div",Hs,[(s(!0),n(I,null,B(u.value,x=>(s(),n("button",{key:x.id,class:"group flex flex-col items-stretch text-left w-full path-glass-bubble rounded-2xl overflow-hidden transition-all duration-200 hover:brightness-105","aria-label":x.title,onClick:S=>i.$emit("selectSeries",x)},[e("div",Ks,[e("div",{class:o(["aspect-[2/3] relative w-full overflow-hidden rounded-[10px]",t(b)(x)?"":t(l)?"bg-white/[0.06]":"bg-black/[0.04]"])},[t(_)(x)?(s(),n("div",Ys)):m("",!0),t(b)(x)?(s(),n("img",{key:1,src:t(b)(x),alt:`${x.title} — TV Series`,class:"w-full h-full object-cover transition-transform duration-300 group-hover:scale-110",loading:"lazy",onError:S=>t(v)(x)},null,40,Qs)):t(_)(x)?m("",!0):(s(),n("img",{key:2,src:t(p)(x),alt:x.title,class:"w-full h-full object-cover"},null,8,Js)),t(b)(x)?(s(),n("div",Zs)):m("",!0),e("div",Xs,[e("p",en,d(x.title),1),e("p",tn,[ne(d(C(x)),1),x.seasons?(s(),n(I,{key:0},[ne(" · "+d(x.seasons)+"S",1)],64)):m("",!0)])]),x.rating?(s(),n("div",sn,[e("span",nn," ★ "+d(x.rating.toFixed(1)),1)])):m("",!0),x.status==="ongoing"?(s(),n("div",ln,[...r[1]||(r[1]=[e("span",{class:"text-xs px-1 py-0.5 rounded bg-emerald-500/80 text-white backdrop-blur-sm"}," ongoing ",-1)])])):m("",!0),e("div",on,[(s(!0),n(I,null,B((x.sources??[]).slice(0,2),S=>(s(),n("span",{key:S.type,class:"text-xs px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"},d(S.type),1))),128))])],2)])],8,Ws))),128))]),u.value.length===0?(s(),n("div",an,[e("p",{class:o(["text-sm",t(l)?"text-white/30":"text-gray-400"])}," No TV series match your search ",2)])):m("",!0)])]))}}),cn={class:"h-full flex flex-col"},dn={class:"flex items-center justify-between gap-2"},un={class:"flex items-center gap-2 shrink-0"},xn={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-4 pb-16"},hn={class:"columns-2 sm:columns-3 gap-3 space-y-3"},pn=["aria-label","onClick"],gn=["src","alt","onError"],vn={key:2,class:"absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/70 via-black/30 to-transparent"},bn={key:0,class:"text-xs font-medium text-white/90 truncate"},fn={key:1,class:"text-xs text-white/50 truncate"},mn={key:0,class:"flex items-center justify-center py-12"},wn=q({__name:"ImageGrid",props:{images:{},title:{default:"Images"}},emits:["selectImage"],setup(a){const{isDark:c}=J(),l=M(new Set);function w(g){l.value.add(g.id),l.value=new Set(l.value)}return(g,b)=>(s(),n("div",cn,[e("div",{class:"p-4 space-y-3",style:G(t(c)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",dn,[e("h3",{class:o(["text-sm font-bold",t(c)?"text-white/90":"text-gray-900"])},d(a.title),3),e("div",un,[e("span",{class:o(["text-xs font-mono",t(c)?"text-white/30":"text-gray-400"])},d(a.images.length)+" images ",3),ie(g.$slots,"header-actions")])])],4),e("div",xn,[e("div",hn,[(s(!0),n(I,null,B(a.images,p=>(s(),n("button",{key:p.id,class:o(["group w-full break-inside-avoid text-left rounded-xl overflow-hidden transition-all duration-200 hover:brightness-110 relative",t(c)?"bg-white/5":"bg-black/3"]),"aria-label":p.alt||p.title||"Image",onClick:v=>g.$emit("selectImage",p)},[l.value.has(p.id)?(s(),n("div",{key:1,class:o(["w-full aspect-[4/3] flex items-center justify-center",t(c)?"bg-white/5":"bg-black/5"])},[(s(),n("svg",{class:o(["w-8 h-8",t(c)?"text-white/15":"text-gray-300"]),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[...b[0]||(b[0]=[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"},null,-1)])],2))],2)):(s(),n("img",{key:0,src:p.url,alt:p.alt||p.title||"Image",class:"w-full block transition-transform duration-300 group-hover:scale-[1.03]",loading:"lazy",onError:v=>w(p)},null,40,gn)),p.title||p.source?(s(),n("div",vn,[p.title?(s(),n("p",bn,d(p.title),1)):m("",!0),p.source?(s(),n("p",fn,d(p.source),1)):m("",!0)])):m("",!0)],10,pn))),128))]),a.images.length===0?(s(),n("div",mn,[e("p",{class:o(["text-sm",t(c)?"text-white/30":"text-gray-400"])}," No images found ",2)])):m("",!0)])]))}}),yn={class:"h-full flex flex-col"},kn={class:"p-4 space-y-3"},$n={class:"flex items-center justify-between"},_n={class:"shrink-0 flex items-center gap-2"},Cn={key:0,class:"flex flex-wrap gap-1.5"},Sn=["onClick"],jn={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pb-16"},Mn={class:"grid grid-cols-2 sm:grid-cols-3 gap-3"},Tn=["aria-label","onClick"],Dn={class:"aspect-[4/3] relative w-full overflow-hidden rounded-t-[10px]"},Ln={key:0,class:"absolute inset-0 animate-shimmer"},In=["src","alt","onError"],Bn=["src","alt"],Pn={key:3,class:"absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent pointer-events-none"},Nn={class:"absolute bottom-0 left-0 right-0 p-2"},An={class:"text-xs font-semibold text-white/90 truncate"},zn={class:"text-xs text-white/40 truncate mt-0.5"},Fn={key:4,class:"absolute top-1.5 right-1.5"},En={class:"text-xs px-1.5 py-0.5 rounded bg-black/60 text-amber-400 backdrop-blur-sm font-semibold"},Rn={key:5,class:"absolute top-1.5 left-1.5"},Vn={class:"text-xs px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"},Un={key:0,class:"flex items-center justify-center py-12"},qn=q({__name:"PlaceGrid",props:{places:{},title:{default:"Places"}},emits:["selectPlace"],setup(a){const c=a,{isDark:l}=J(),w=M(""),g=M(null),{coverSrc:b,fallbackSrc:p,onError:v,isLoading:_}=Ae({items:Ne(c,"places"),id:u=>u.id,existingUrl:u=>u.photoUrl,fetch:u=>pt(u.name,u.city),fallback:u=>ht(u.name,u.cuisine||u.category)}),C=L(()=>{const u=new Map;for(const i of c.places){const r=i.cuisine||i.category;r&&u.set(r,(u.get(r)??0)+1)}return[...u.entries()].sort((i,r)=>r[1]-i[1]).slice(0,8).map(([i])=>i)}),f=L(()=>{let u=c.places;if(w.value){const i=w.value.toLowerCase();u=u.filter(r=>r.name.toLowerCase().includes(i)||r.cuisine?.toLowerCase().includes(i)||r.category?.toLowerCase().includes(i)||r.city?.toLowerCase().includes(i)||r.address?.toLowerCase().includes(i))}return g.value&&(u=u.filter(i=>i.cuisine===g.value||i.category===g.value)),u});return(u,i)=>(s(),n("div",yn,[e("div",kn,[e("div",$n,[e("h3",{class:o(["text-base font-bold",t(l)?"text-white/90":"text-gray-900"])},d(a.title||"Places"),3),e("div",_n,[e("span",{class:o(["text-xs",t(l)?"text-white/30":"text-gray-400"])},d(f.value.length)+" places ",3),ie(u.$slots,"header-actions")])]),W(e("input",{"onUpdate:modelValue":i[0]||(i[0]=r=>w.value=r),type:"text",placeholder:"Search places...",class:o(["w-full text-base px-3 py-2 rounded-lg outline-none transition-colors",t(l)?"bg-white/5 text-white/80 placeholder-white/25 focus:bg-white/8":"bg-black/5 text-gray-800 placeholder-gray-400 focus:bg-black/8"])},null,2),[[Q,w.value]]),C.value.length>1?(s(),n("div",Cn,[(s(!0),n(I,null,B(C.value,r=>(s(),n("button",{key:r,class:o(["text-xs px-2 py-1 rounded-md font-medium transition-all duration-150",g.value===r?"nav-tab-active":t(l)?"bg-white/5 text-white/40 hover:text-white/70":"bg-black/5 text-gray-500 hover:text-gray-800"]),onClick:x=>g.value=g.value===r?null:r},d(r),11,Sn))),128))])):m("",!0)]),e("div",jn,[e("div",Mn,[(s(!0),n(I,null,B(f.value,r=>(s(),n("button",{key:r.id,class:"group flex flex-col items-stretch text-left w-full path-glass-bubble rounded-2xl overflow-hidden transition-all duration-200 hover:brightness-105","aria-label":r.name,onClick:x=>u.$emit("selectPlace",r)},[e("div",Dn,[t(_)(r)?(s(),n("div",Ln)):m("",!0),t(b)(r)?(s(),n("img",{key:1,src:t(b)(r),alt:r.name,class:"w-full h-full object-cover transition-transform duration-300 group-hover:scale-110",loading:"lazy",onError:x=>t(v)(r)},null,40,In)):t(_)(r)?m("",!0):(s(),n("img",{key:2,src:t(p)(r),alt:r.name,class:"w-full h-full object-cover"},null,8,Bn)),t(b)(r)?(s(),n("div",Pn)):m("",!0),e("div",Nn,[e("p",An,d(r.name),1),e("p",zn,d(r.cuisine||r.category),1)]),r.rating?(s(),n("div",Fn,[e("span",En," ★ "+d(r.rating.toFixed(1)),1)])):m("",!0),r.priceLevel?(s(),n("div",Rn,[e("span",Vn,d("$".repeat(r.priceLevel)),1)])):m("",!0)])],8,Tn))),128))]),f.value.length===0?(s(),n("div",Un,[e("p",{class:o(["text-xs",t(l)?"text-white/30":"text-gray-400"])}," No places match your search ",2)])):m("",!0)])]))}}),Gn={class:"h-full flex flex-col"},On={class:"flex items-center justify-between gap-2"},Hn={class:"flex items-center gap-2 shrink-0"},Wn={key:0,class:"flex flex-wrap gap-1.5"},Kn=["onClick"],Yn={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-4 pb-16"},Qn={class:"grid grid-cols-2 sm:grid-cols-3 gap-4"},Jn=["aria-label","onClick"],Zn={class:"cover-card flex-1 min-h-0 relative"},Xn={key:0,class:"absolute inset-0 animate-shimmer"},el=["src","alt","onError"],tl=["src","alt"],sl={key:3,class:"absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent pointer-events-none"},nl={class:"absolute bottom-0 left-0 right-0 p-2"},ll={class:"text-xs font-semibold text-white/90 leading-tight truncate"},ol={class:"text-xs text-white/40 truncate mt-0.5"},al={class:"absolute top-1.5 right-1.5 flex gap-0.5 flex-wrap justify-end max-w-[60%]"},il={key:0,class:"flex items-center justify-center py-12"},rl=q({__name:"PodcastGrid",props:{podcasts:{},title:{default:"Recommended Podcasts"}},emits:["selectPodcast"],setup(a){const c=a,{isDark:l}=J(),w=M(""),g=M(null),{coverSrc:b,fallbackSrc:p,onError:v,isLoading:_}=Ae({items:Ne(c,"podcasts"),id:u=>u.id,existingUrl:u=>u.coverUrl,fetch:u=>vt(u.title,u.host),fallback:u=>gt(u.title,u.host)}),C=L(()=>{const u=new Map;for(const i of c.podcasts)for(const r of i.genres??[])u.set(r,(u.get(r)??0)+1);return[...u.entries()].sort((i,r)=>r[1]-i[1]).slice(0,8).map(([i])=>i)}),f=L(()=>{let u=c.podcasts;if(w.value){const i=w.value.toLowerCase();u=u.filter(r=>r.title.toLowerCase().includes(i)||(r.host??"").toLowerCase().includes(i)||(r.genres??[]).some(x=>x.toLowerCase().includes(i)))}return g.value&&(u=u.filter(i=>(i.genres??[]).includes(g.value))),u});return(u,i)=>(s(),n("div",Gn,[e("div",{class:"p-4 space-y-3",style:G(t(l)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",On,[e("h3",{class:o(["text-sm font-bold",t(l)?"text-white/90":"text-gray-900"])},d(a.title),3),e("div",Hn,[e("span",{class:o(["text-xs font-mono",t(l)?"text-white/30":"text-gray-400"])},d(f.value.length)+" podcasts ",3),ie(u.$slots,"header-actions")])]),W(e("input",{"onUpdate:modelValue":i[0]||(i[0]=r=>w.value=r),type:"text",placeholder:"Search podcasts...",class:o(["w-full px-3 py-2 rounded-lg text-base outline-none transition-colors",t(l)?"bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10":"bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5"])},null,2),[[Q,w.value]]),C.value.length>0?(s(),n("div",Wn,[(s(!0),n(I,null,B(C.value,r=>(s(),n("button",{key:r,class:o(["text-xs px-2 py-1 rounded-md transition-all duration-150",g.value===r?"nav-tab-active":t(l)?"text-white/40 hover:text-white/70 hover:bg-white/5":"text-gray-500 hover:text-gray-800 hover:bg-black/5"]),onClick:x=>g.value=g.value===r?null:r},d(r),11,Kn))),128))])):m("",!0)],4),e("div",Yn,[e("div",Qn,[(s(!0),n(I,null,B(f.value,r=>(s(),n("button",{key:r.id,class:"group flex flex-col items-stretch text-left w-full path-glass-bubble rounded-2xl overflow-hidden transition-all duration-200 hover:brightness-105","aria-label":r.title,onClick:x=>u.$emit("selectPodcast",r)},[e("div",Zn,[e("div",{class:o(["aspect-square relative w-full overflow-hidden rounded-[10px]",t(b)(r)?"":t(l)?"bg-white/[0.06]":"bg-black/[0.04]"])},[t(_)(r)?(s(),n("div",Xn)):m("",!0),t(b)(r)?(s(),n("img",{key:1,src:t(b)(r),alt:r.title,class:"w-full h-full object-cover transition-transform duration-300 group-hover:scale-110",loading:"lazy",onError:x=>t(v)(r)},null,40,el)):t(_)(r)?m("",!0):(s(),n("img",{key:2,src:t(p)(r),alt:r.title,class:"w-full h-full object-cover"},null,8,tl)),t(b)(r)?(s(),n("div",sl)):m("",!0),e("div",nl,[e("p",ll,d(r.title),1),e("p",ol,d(r.host||"Podcast"),1)]),e("div",al,[(s(!0),n(I,null,B(r.sources.slice(0,2),x=>(s(),n("span",{key:x.type,class:"text-xs px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"},d(x.type),1))),128))])],2)])],8,Jn))),128))]),f.value.length===0?(s(),n("div",il,[e("p",{class:o(["text-sm",t(l)?"text-white/30":"text-gray-400"])}," No podcasts match your search ",2)])):m("",!0)])]))}}),cl={class:"shrink-0"},dl={class:"flex-1 overflow-y-auto custom-scrollbar"},ul={key:0,class:"relative overflow-hidden",style:{minHeight:"180px"}},xl={class:"absolute inset-0"},hl=["src"],pl={class:"relative z-10 flex flex-col justify-end h-full px-5 pb-5 pt-12",style:{"min-height":"180px"}},gl={class:"px-3 pt-2 pb-8"},vl={key:0,"stroke-linecap":"round","stroke-linejoin":"round",d:"M12 2a10 10 0 100 20 10 10 0 000-20zm0 0v2m0 16v2m10-10h-2M4 12H2m15.07-5.07l-1.41 1.41M8.34 15.66l-1.41 1.41m0-11.14l1.41 1.41m7.32 7.32l1.41 1.41"},bl={key:1,"stroke-linecap":"round","stroke-linejoin":"round",d:"M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z"},fl={key:2,"stroke-linecap":"round","stroke-linejoin":"round",d:"M13 2L3 14h9l-1 8 10-12h-9l1-8z"},ml={key:3,"stroke-linecap":"round","stroke-linejoin":"round",d:"M4 6h16M4 12h16M4 18h7"},wl=["onClick"],yl=["onClick"],kl={key:1,class:"flex items-center justify-center py-16 px-4"},$l=q({__name:"MagazineGrid",props:{sections:{},heroImageUrl:{default:null},title:{default:"Brief"},query:{default:""}},setup(a){const c=a,{isDark:l}=J(),{openMagazineSectionDetail:w}=$e(),g=["compass","bookmark","lightning","lines"];function b(f){return f.replace(/\[([^\]]*)\]\([^)]+\)/g,"$1").replace(/https?:\/\/\S+/g,"").replace(/\uFE0F/g,"").replace(new RegExp("(?:^|(?<=\\s))[\\p{Emoji_Presentation}\\p{Extended_Pictographic}]+\\s*","gu"),"").replace(/---+/g,"").replace(/^#+\s*/gm,"").replace(/\*\*/g,"").replace(/\*([^*\n]+)\*/g,"$1").replace(/\|/g,", ").replace(/,\s*,+/g,",").replace(/^\s*[-•]\s+/gm,"").replace(/\n+/g," ").replace(/(^|\s),\s*/g,"$1").trim()}function p(f,u){const i=b(f);return i.length<=u?i:i.slice(0,u).replace(/\s+\S*$/,"")+" ..."}const v=L(()=>{const f=[],u=c.sections;if(!u.length)return f;let i=0;for(const j of c.query||"brief")i=(i<<5)-i+j.charCodeAt(0)|0;let r="",x=0,S=!1;return u.forEach((j,P)=>{if(P===0&&!j.group){f.push({type:"wide",title:j.title,text:p(j.content,200),label:"The Lead",author:j.author,section:j});return}const D=j.group||"";if(D&&D!==r&&(S&&(f.push({type:"dark",title:"",text:""}),S=!1),f.push({type:"banner",title:"",text:"",icon:g[x%g.length],label:D}),x++,r=D),D){const y=S?"dark":"half",k=b(j.content),h=b(j.title),$=k.toLowerCase().startsWith(h.toLowerCase().slice(0,30));f.push({type:y,title:$?"":j.title,text:p(j.content,$?160:100),section:j}),S=!S}else S&&(f.push({type:"dark",title:"",text:""}),S=!1),f.push({type:"wide",title:j.title,text:p(j.content,180),author:j.author,section:j})}),S&&f.push({type:"dark",title:"",text:""}),f});function _(f){const u=c.sections.indexOf(f);w(f,u>=0?u:0)}const C=L(()=>{const f=(c.query??"").trim();return f?f.length>100?f.slice(0,97)+"...":f:c.title});return(f,u)=>(s(),n("div",{class:o(["magazine h-full flex flex-col",t(l)?"magazine-dark":"magazine-light"])},[e("header",{class:o(["shrink-0 px-5 py-4 flex items-center justify-between border-b",t(l)?"border-white/10":"border-black/10"])},[e("h1",{class:o(["font-serif text-xl font-bold tracking-tight",t(l)?"text-white":"text-black"])}," AI Brief ",2),e("div",cl,[ie(f.$slots,"header-actions",{},void 0,!0)])],2),e("div",dl,[C.value?(s(),n("div",ul,[e("div",xl,[a.heroImageUrl?(s(),n("img",{key:0,src:a.heroImageUrl,alt:"",class:"w-full h-full object-cover",style:{filter:"saturate(0.3) contrast(1.1)"}},null,8,hl)):(s(),n("div",{key:1,class:o(["w-full h-full",t(l)?"bg-gradient-to-br from-white/[0.04] via-white/[0.02] to-transparent":"bg-gradient-to-br from-black/[0.06] via-black/[0.03] to-transparent"])},null,2))]),e("div",{class:o(["absolute inset-0",t(l)?"bg-gradient-to-t from-[#0a0a0a] via-[#0a0a0a]/80 to-[#0a0a0a]/60":"bg-gradient-to-t from-[#faf9f6] via-[#faf9f6]/85 to-[#faf9f6]/65"])},null,2),e("div",pl,[e("p",{class:o(["text-xs uppercase tracking-[0.3em] font-medium mb-2",t(l)?"text-white/40":"text-black/40"])}," In response to ",2),e("p",{class:o(["font-serif text-2xl italic leading-tight",t(l)?"text-white/70":"text-black/60"])},d(C.value),3)])])):m("",!0),e("div",gl,[e("div",{class:o(["grid grid-cols-2 gap-px",t(l)?"bg-white/12":"bg-black/10"])},[(s(!0),n(I,null,B(v.value,(i,r)=>(s(),n(I,{key:r},[i.type==="banner"?(s(),n("div",{key:0,class:o(["col-span-2 flex flex-col items-center justify-center py-8 px-5",t(l)?"bg-[#0a0a0a]":"bg-[#faf9f6]"])},[(s(),n("svg",{class:o(["w-5 h-5 mb-2.5",t(l)?"text-white/20":"text-black/15"]),viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"1.5"},[i.icon==="compass"?(s(),n("path",vl)):i.icon==="bookmark"?(s(),n("path",bl)):i.icon==="lightning"?(s(),n("path",fl)):(s(),n("path",ml))],2)),e("p",{class:o(["text-xs uppercase tracking-[0.3em] font-semibold text-center",t(l)?"text-white/30":"text-black/30"])},d(i.label),3)],2)):i.type==="wide"?(s(),n("button",{key:1,class:o(["col-span-2 text-left px-5 py-5 transition-colors cursor-pointer",t(l)?"bg-[#0a0a0a] hover:bg-white/[0.03]":"bg-[#faf9f6] hover:bg-black/[0.02]"]),onClick:x=>i.section&&_(i.section)},[i.label?(s(),n("p",{key:0,class:o(["text-xs uppercase tracking-[0.3em] font-semibold mb-2",t(l)?"text-white/30":"text-black/35"])},d(i.label),3)):m("",!0),e("h2",{class:o(["font-serif text-lg font-bold leading-snug mb-2",t(l)?"text-white/95":"text-black/90"])},d(i.title),3),i.author?(s(),n("p",{key:1,class:o(["text-xs mb-2",t(l)?"text-white/40":"text-black/40"])}," By "+d(i.author),3)):m("",!0),e("p",{class:o(["font-serif text-sm leading-relaxed",t(l)?"text-white/70":"text-black/60"])},d(i.text),3)],10,wl)):(s(),n("button",{key:2,class:o(["text-left px-4 py-4 transition-colors flex flex-col cursor-pointer",[t(l)?"bg-[#0a0a0a] hover:bg-white/[0.03]":"bg-[#faf9f6] hover:bg-black/[0.02]",i.type==="dark"?t(l)?"bg-white/[0.04]":"bg-black/[0.04]":""]]),onClick:x=>i.section&&_(i.section)},[i.label?(s(),n("p",{key:0,class:o(["text-xs uppercase tracking-[0.25em] font-semibold mb-1.5",t(l)?"text-white/25":"text-black/30"])},d(i.label),3)):m("",!0),i.title?(s(),n("h3",{key:1,class:o(["font-serif text-sm font-bold leading-snug mb-1",t(l)?"text-white/90":"text-black/85"])},d(i.title),3)):m("",!0),e("p",{class:o(["font-serif text-xs leading-relaxed flex-1",[t(l)?"text-white/55":"text-black/50",i.title?"":"italic"]])},d(i.text),3)],10,yl))],64))),128))],2)]),a.sections.length===0?(s(),n("div",kl,[e("p",{class:o(["text-sm",t(l)?"text-white/40":"text-gray-400"])}," No sections to display ",2)])):m("",!0)])],2))}}),ot=De($l,[["__scopeId","data-v-02741b8c"]]),_l={class:"h-full flex flex-col"},Cl={class:"flex items-center justify-between gap-2"},Sl={class:"flex items-center gap-2 shrink-0"},jl=["placeholder"],Ml={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-4 pb-16"},Tl={class:"grid grid-cols-2 sm:grid-cols-3 gap-4"},Dl=["aria-label","onClick"],Ll={class:"cover-card flex-1 min-h-0 relative"},Il={class:"aspect-[4/3] flex flex-col w-full overflow-hidden rounded-[10px]"},Bl={class:"flex-1 min-h-0 relative"},Pl=["src","alt","onError"],Nl={key:2,class:"absolute inset-0 bg-gradient-to-t from-black/60 via-black/20 to-transparent pointer-events-none"},Al={key:0,class:"flex items-center justify-center py-12"},at=q({__name:"NewsGrid",props:{articles:{},title:{default:"News & Articles"},query:{default:""},variant:{default:"news"}},setup(a){const c=a,{isDark:l}=J(),{openArticleDetail:w,openWebsiteDetail:g}=$e(),b=M(""),p=M(new Set);function v(x){return!x||typeof x!="string"?!1:/^https?:\/\//i.test(x.trim())}function _(x){p.value=new Set([...p.value,x])}function C(x){try{return new URL(x).hostname.replace(/^www\./,"")}catch{return x}}function f(x){return c.variant==="websites"?Kt(x.title,C(x.url)):Yt(x.title,C(x.url))}function u(x){c.variant==="websites"?g(x):w(x)}function i(x,S){if(!S.trim())return 0;const P=S.toLowerCase().split(/\s+/).filter($=>$.length>1);if(P.length===0)return 0;const D=x.title.toLowerCase(),y=(x.content??"").toLowerCase(),k=x.url.toLowerCase();let h=0;for(const $ of P)D.includes($)&&(h+=3),y.includes($)&&(h+=2),k.includes($)&&(h+=1);return h}const r=L(()=>{let x=c.articles;if(b.value.trim()){const S=b.value.toLowerCase();x=x.filter(j=>j.title.toLowerCase().includes(S)||(j.content??"").toLowerCase().includes(S)||j.url.toLowerCase().includes(S))}return c.query.trim()?[...x].sort((S,j)=>i(j,c.query)-i(S,c.query)):x});return(x,S)=>(s(),n("div",_l,[e("div",{class:"p-4 space-y-3",style:G(t(l)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",Cl,[e("h3",{class:o(["text-sm font-bold",t(l)?"text-white/90":"text-gray-900"])},d(a.title),3),e("div",Sl,[e("span",{class:o(["text-xs font-mono",t(l)?"text-white/30":"text-gray-400"])},d(r.value.length)+" "+d(a.variant==="websites"?"websites":"articles"),3),ie(x.$slots,"header-actions")])]),W(e("input",{"onUpdate:modelValue":S[0]||(S[0]=j=>b.value=j),type:"text",placeholder:a.variant==="websites"?"Search websites...":"Search articles...",class:o(["w-full px-3 py-2 rounded-lg text-base outline-none transition-colors",t(l)?"bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10":"bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5"])},null,10,jl),[[Q,b.value]])],4),e("div",Ml,[e("div",Tl,[(s(!0),n(I,null,B(r.value,(j,P)=>(s(),n("button",{key:P,class:"group flex flex-col items-stretch text-left w-full path-glass-bubble rounded-2xl overflow-hidden transition-all duration-200 hover:brightness-105","aria-label":j.title,onClick:D=>u(j)},[e("div",Ll,[e("div",Il,[e("div",Bl,[v(j.imgSrc)&&!p.value.has(j.url)?(s(),n("img",{key:0,src:j.imgSrc,alt:j.title,class:"absolute inset-0 w-full h-full object-cover transition-transform duration-300 group-hover:scale-110",loading:"lazy",onError:D=>_(j.url)},null,40,Pl)):(s(),n("div",{key:1,class:"absolute inset-0 bg-cover bg-center",style:G({backgroundImage:`url(${f(j)})`})},null,4)),v(j.imgSrc)&&!p.value.has(j.url)?(s(),n("div",Nl)):m("",!0)]),e("div",{class:o(["shrink-0 p-2 backdrop-blur-md rounded-b-[10px]",[t(l)?"bg-black shadow-[inset_0_1px_0_rgba(255,255,255,0.12)]":"bg-white shadow-[inset_0_1px_0_rgba(0,0,0,0.06)]"]])},[e("p",{class:o(["text-xs font-semibold leading-tight line-clamp-2",t(l)?"text-white/95":"text-gray-900"])},d(j.title),3),j.content?(s(),n("p",{key:0,class:o(["text-xs line-clamp-1 mt-0.5",t(l)?"text-white/70":"text-gray-600"])},d(j.content),3)):m("",!0),e("p",{class:o(["text-xs truncate mt-0.5",t(l)?"text-white/50":"text-gray-500"])},d(C(j.url)),3)],2)])])],8,Dl))),128))]),r.value.length===0?(s(),n("div",Al,[e("p",{class:o(["text-sm",t(l)?"text-white/30":"text-gray-400"])},d(a.variant==="websites"?"No websites match your search":"No articles match your search"),3)])):m("",!0)])]))}}),zl={class:"h-full flex flex-col"},Fl={class:"flex items-center justify-between gap-2"},El={class:"flex items-center gap-2 shrink-0"},Rl={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-4 pb-16"},Vl={class:"grid grid-cols-1 sm:grid-cols-2 gap-3"},Ul=["aria-label","onClick"],ql={class:"aspect-[3/1] relative w-full overflow-hidden"},Gl=["src","alt"],Ol={class:"p-3"},Hl={class:"flex items-center gap-3 mt-2 flex-wrap"},Wl={key:0,class:"flex items-center justify-center py-12"},Kl=q({__name:"RecipeGrid",props:{recipes:{},title:{default:"Recipes"}},emits:["selectRecipe"],setup(a){const c=a,{isDark:l}=J(),w=M(""),g=L(()=>{if(!w.value.trim())return c.recipes;const b=w.value.toLowerCase();return c.recipes.filter(p=>p.title.toLowerCase().includes(b)||p.ingredients.some(v=>v.toLowerCase().includes(b)))});return(b,p)=>(s(),n("div",zl,[e("div",{class:"p-4 space-y-3",style:G(t(l)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",Fl,[e("h3",{class:o(["text-sm font-bold",t(l)?"text-white/90":"text-gray-900"])},d(a.title),3),e("div",El,[e("span",{class:o(["text-xs font-mono",t(l)?"text-white/30":"text-gray-400"])},d(g.value.length)+" recipes ",3),ie(b.$slots,"header-actions")])]),a.recipes.length>3?W((s(),n("input",{key:0,"onUpdate:modelValue":p[0]||(p[0]=v=>w.value=v),type:"text",placeholder:"Search recipes...",class:o(["w-full px-3 py-2 rounded-lg text-base outline-none transition-colors",t(l)?"bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10":"bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5"])},null,2)),[[Q,w.value]]):m("",!0)],4),e("div",Rl,[e("div",Vl,[(s(!0),n(I,null,B(g.value,(v,_)=>(s(),n("button",{key:_,class:o(["group flex flex-col items-stretch text-left w-full rounded-2xl overflow-hidden transition-all duration-200 hover:brightness-105",t(l)?"bg-white/[0.04] border border-white/8 hover:bg-white/[0.07]":"bg-black/[0.02] border border-black/5 hover:bg-black/[0.05]"]),"aria-label":v.title,onClick:C=>b.$emit("selectRecipe",v)},[e("div",ql,[e("img",{src:t(Qt)(v.title,v.time),alt:v.title,class:"w-full h-full object-cover"},null,8,Gl)]),e("div",Ol,[e("p",{class:o(["text-sm font-semibold leading-tight line-clamp-2",t(l)?"text-white/90":"text-gray-900"])},d(v.title),3),e("div",Hl,[v.time?(s(),n("span",{key:0,class:o(["flex items-center gap-1 text-xs",t(l)?"text-white/40":"text-gray-500"])},[p[1]||(p[1]=e("svg",{class:"w-3 h-3",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"})],-1)),ne(" "+d(v.time),1)],2)):m("",!0),v.servings?(s(),n("span",{key:1,class:o(["flex items-center gap-1 text-xs",t(l)?"text-white/40":"text-gray-500"])},[p[2]||(p[2]=e("svg",{class:"w-3 h-3",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"})],-1)),ne(" "+d(v.servings),1)],2)):m("",!0),v.calories?(s(),n("span",{key:2,class:o(["text-xs",t(l)?"text-white/40":"text-gray-500"])},d(v.calories)+" cal ",3)):m("",!0)]),v.ingredients.length>0?(s(),n("p",{key:0,class:o(["text-xs mt-2 line-clamp-1",t(l)?"text-white/25":"text-gray-400"])},d(v.ingredients.slice(0,4).join(" · ")),3)):m("",!0)])],10,Ul))),128))]),g.value.length===0?(s(),n("div",Wl,[e("p",{class:o(["text-sm",t(l)?"text-white/30":"text-gray-400"])}," No recipes match your search ",2)])):m("",!0)])]))}}),Yl={class:"h-full flex flex-col"},Ql={class:"flex items-center justify-between gap-2"},Jl={class:"flex flex-wrap gap-1.5"},Zl=["onClick"],Xl={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-4 pb-16"},eo={class:"space-y-2"},to=["aria-label","onClick"],so={class:"text-white/90"},no={class:"flex-1 min-w-0"},lo={class:"flex items-center gap-2"},oo={class:"flex gap-1 mt-1.5"},ao={key:0,class:"flex items-center justify-center py-12"},io=q({__name:"AppsGrid",props:{apps:{},title:{default:"Recommended Apps"}},emits:["selectApp"],setup(a){const c=a,{isDark:l}=J(),w=M(""),g=M(null),b=[{value:"nostr-client",label:"Nostr"},{value:"lightning-wallet",label:"Lightning"},{value:"bitcoin-wallet",label:"Bitcoin"},{value:"privacy",label:"Privacy"},{value:"node",label:"Nodes"},{value:"dev-tool",label:"Dev"}];function p(f){return b.find(u=>u.value===f)?.label??f}function v(f){return{ios:"iOS",android:"Android",web:"Web",desktop:"Desktop",cli:"CLI",nodeos:"Node"}[f]??f}function _(f){let u=0;for(let r=0;r{let f=c.apps;if(w.value){const u=w.value.toLowerCase();f=f.filter(i=>i.name.toLowerCase().includes(u)||i.description.toLowerCase().includes(u)||i.keywords.some(r=>r.toLowerCase().includes(u)))}return g.value&&(f=f.filter(u=>u.category===g.value)),f});return(f,u)=>(s(),n("div",Yl,[e("div",{class:"p-4 space-y-3",style:G(t(l)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",Ql,[e("h3",{class:o(["text-sm font-bold",t(l)?"text-white/90":"text-gray-900"])},d(a.title),3),e("span",{class:o(["text-xs font-mono",t(l)?"text-white/30":"text-gray-400"])},d(C.value.length)+" apps ",3)]),W(e("input",{"onUpdate:modelValue":u[0]||(u[0]=i=>w.value=i),type:"text",placeholder:"Search apps...",class:o(["w-full px-3 py-2 rounded-lg text-base outline-none transition-colors",t(l)?"bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10":"bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5"])},null,2),[[Q,w.value]]),e("div",Jl,[(s(),n(I,null,B(b,i=>e("button",{key:i.value,class:o(["text-xs px-2 py-1 rounded-md transition-all duration-150",g.value===i.value?"nav-tab-active":t(l)?"text-white/40 hover:text-white/70 hover:bg-white/5":"text-gray-500 hover:text-gray-800 hover:bg-black/5"]),onClick:r=>g.value=g.value===i.value?null:i.value},d(i.label),11,Zl)),64))])],4),e("div",Xl,[e("div",eo,[(s(!0),n(I,null,B(C.value,i=>(s(),n("button",{key:i.id,class:o(["w-full text-left p-3 rounded-xl transition-all duration-200 flex items-start gap-3",t(l)?"bg-white/5 hover:bg-white/10":"bg-black/3 hover:bg-black/5"]),"aria-label":i.name,onClick:r=>f.$emit("selectApp",i)},[e("div",{class:"w-10 h-10 rounded-xl flex items-center justify-center text-lg font-bold shrink-0",style:G({background:_(i.id)})},[e("span",so,d(i.name.charAt(0)),1)],4),e("div",no,[e("div",lo,[e("p",{class:o(["text-xs font-semibold truncate",t(l)?"text-white/90":"text-gray-900"])},d(i.name),3),e("span",{class:o(["text-xs px-1.5 py-0.5 rounded font-medium shrink-0",t(l)?"bg-white/10 text-white/50":"bg-black/5 text-gray-500"])},d(p(i.category)),3)]),e("p",{class:o(["text-xs mt-0.5 line-clamp-2",t(l)?"text-white/50":"text-gray-500"])},d(i.description),3),e("div",oo,[(s(!0),n(I,null,B(i.platforms,r=>(s(),n("span",{key:r,class:o(["text-xs px-1 py-0.5 rounded",t(l)?"bg-white/5 text-white/30":"bg-black/3 text-gray-400"])},d(v(r)),3))),128))])])],10,to))),128))]),C.value.length===0?(s(),n("div",ao,[e("p",{class:o(["text-sm",t(l)?"text-white/30":"text-gray-400"])}," No apps match your search ",2)])):m("",!0)])]))}}),ro={class:"group/node"},co={key:0,"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"},uo={key:1,"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"},xo={class:"truncate flex-1"},ho={key:0,class:"w-2.5 h-2.5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},po={key:0,class:"w-2.5 h-2.5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},go={key:0},vo=q({__name:"FileTreeNode",props:{entry:{},activeFile:{},depth:{}},emits:["select","toggle-context"],setup(a,{emit:c}){const l=a,{isFileSelected:w}=pe(),g=c,{isDark:b}=J(),p=M(l.depth<1),v=L(()=>!l.entry.isDirectory&&l.activeFile===l.entry.path),_=L(()=>!l.entry.isDirectory&&w(l.entry.path)),C=L(()=>l.entry.isDirectory&&w(l.entry.path));function f(){l.entry.isDirectory?p.value=!p.value:g("select",l.entry.path)}function u(){g("toggle-context",l.entry.path)}function i(){g("toggle-context",l.entry.path)}return(r,x)=>{const S=Jt("FileTreeNode",!0);return s(),n("div",ro,[e("div",{class:o(["w-full flex items-center gap-1.5 py-1 px-2 rounded-lg text-xs transition-colors cursor-pointer",[v.value?t(b)?"bg-white/10 text-white/90":"bg-black/8 text-gray-900":t(b)?"text-white/60 hover:bg-white/[0.04] hover:text-white/80":"text-gray-600 hover:bg-black/[0.03] hover:text-gray-800"]]),style:G({paddingLeft:`${a.depth*12+8}px`}),onClick:f},[a.entry.isDirectory?(s(),n("svg",{key:0,class:o(["w-3 h-3 shrink-0 transition-transform duration-150",p.value?"rotate-90":""]),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[...x[2]||(x[2]=[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M9 5l7 7-7 7"},null,-1)])],2)):m("",!0),(s(),n("svg",{class:o(["w-3.5 h-3.5 shrink-0",a.entry.isDirectory?"text-accent/70":t(b)?"text-white/30":"text-gray-400"]),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[a.entry.isDirectory?(s(),n("path",co)):(s(),n("path",uo))],2)),e("span",xo,d(a.entry.name),1),a.entry.isDirectory?m("",!0):(s(),n("button",{key:1,class:o(["shrink-0 w-4 h-4 rounded-full border flex items-center justify-center transition-all ml-auto",[_.value?"bg-accent border-accent text-white":t(b)?"border-white/20 opacity-0 group-hover/node:opacity-100 hover:border-white/40":"border-black/15 opacity-0 group-hover/node:opacity-100 hover:border-black/30"]]),"aria-label":"Toggle file for chat context",onClick:he(u,["stop"])},[_.value?(s(),n("svg",ho,[...x[3]||(x[3]=[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"3",d:"M5 13l4 4L19 7"},null,-1)])])):m("",!0)],2)),a.entry.isDirectory?(s(),n("button",{key:2,class:o(["shrink-0 w-4 h-4 rounded-full border flex items-center justify-center transition-all ml-auto",[C.value?"bg-accent border-accent text-white":t(b)?"border-white/20 opacity-0 group-hover/node:opacity-100 hover:border-white/40":"border-black/15 opacity-0 group-hover/node:opacity-100 hover:border-black/30"]]),"aria-label":"Add folder to chat context",onClick:he(i,["stop"])},[C.value?(s(),n("svg",po,[...x[4]||(x[4]=[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"3",d:"M5 13l4 4L19 7"},null,-1)])])):m("",!0)],2)):m("",!0)],6),a.entry.isDirectory&&p.value&&a.entry.children?(s(),n("div",go,[(s(!0),n(I,null,B(a.entry.children,j=>(s(),E(S,{key:j.path,entry:j,"active-file":a.activeFile,depth:a.depth+1,onSelect:x[0]||(x[0]=P=>r.$emit("select",P)),onToggleContext:x[1]||(x[1]=P=>r.$emit("toggle-context",P))},null,8,["entry","active-file","depth"]))),128))])):m("",!0)])}}}),bo={class:"flex flex-col h-full"},fo={class:"flex items-center gap-1 min-w-0 flex-1"},mo={class:"flex items-center gap-2 shrink-0"},wo={key:0,class:"flex-1 overflow-y-auto custom-scrollbar p-3"},yo={class:"mb-3 flex gap-2"},ko={class:"flex justify-end gap-2"},$o=["disabled"],_o={class:"grid grid-cols-2 gap-2"},Co=["onClick"],So={key:1,class:"flex-1 overflow-y-auto custom-scrollbar p-2"},jo={key:0,class:"flex items-center justify-center py-12"},Mo=q({__name:"ProjectGrid",props:{isWideDesktop:{type:Boolean},isMobile:{type:Boolean}},setup(a){const{isDark:c}=J(),{projectList:l,activeProject:w,fileTree:g,activeFile:b,codeMode:p,selectedFiles:v,selectProject:_,openFile:C,createProject:f,clearActiveFile:u,toggleFileSelection:i,isFileSelected:r,loadProjects:x}=pe();le(()=>{l.value.length===0&&x()});const S=M(""),j=M(!1),P=M(""),D=M(null),y=L(()=>w.value?"filetree":"projects"),k=L(()=>y.value==="projects"?"Projects":w.value?.name??"Projects"),h=L(()=>{const V=S.value.toLowerCase();return V?l.value.filter(H=>H.name.toLowerCase().includes(V)||(H.language??"").toLowerCase().includes(V)):l.value});function $(V){_(V)}function N(){const{activeProject:V,fileTree:H}=pe();V.value=null,H.value=[],u()}function U(V){C(V)}function F(V){i(V)}function K(){j.value=!0,P.value="",ye(()=>D.value?.focus())}function O(){j.value=!1,P.value=""}function Z(){const V=P.value.trim();V&&(f(V),j.value=!1,P.value="")}return(V,H)=>(s(),n("div",bo,[e("div",{class:"shrink-0 px-4 py-3 flex items-center justify-between gap-2",style:G(t(c)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",fo,[y.value!=="projects"?(s(),n("button",{key:0,class:o(["text-xs shrink-0 transition-colors",t(c)?"text-white/40 hover:text-white/70 hover:underline":"text-gray-400 hover:text-gray-700 hover:underline"]),onClick:N}," Projects ",2)):m("",!0),y.value!=="projects"?(s(),n("span",{key:1,class:o(["text-xs shrink-0",t(c)?"text-white/20":"text-gray-300"])},"/",2)):m("",!0),e("span",{class:o(["text-sm font-semibold truncate",t(c)?"text-white/90":"text-gray-900"])},d(k.value),3)]),e("div",mo,[y.value==="projects"?(s(),n("p",{key:0,class:o(["text-xs",t(c)?"text-white/30":"text-gray-400"])},d(t(l).length)+" repos ",3)):y.value==="filetree"?(s(),n("p",{key:1,class:o(["text-xs",t(c)?"text-white/30":"text-gray-400"])},d(t(w)?.language),3)):m("",!0),ie(V.$slots,"header-actions")])],4),y.value==="projects"?(s(),n("div",wo,[e("div",yo,[W(e("input",{"onUpdate:modelValue":H[0]||(H[0]=X=>S.value=X),type:"text",placeholder:"Search projects...",class:o(["flex-1 min-w-0 px-3 py-2 rounded-lg text-base bg-transparent outline-none",t(c)?"text-white/80 placeholder:text-white/20 border border-white/10 focus:border-white/25":"text-gray-800 placeholder:text-gray-400 border border-black/10 focus:border-black/20"])},null,2),[[Q,S.value]]),e("button",{class:o(["shrink-0 px-3 py-2 rounded-lg text-xs font-medium transition-colors flex items-center gap-1.5",t(c)?"bg-accent/20 text-accent hover:bg-accent/30":"bg-accent/10 text-accent hover:bg-accent/20"]),onClick:K},[...H[2]||(H[2]=[e("svg",{class:"w-3.5 h-3.5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M12 4v16m8-8H4"})],-1),ne(" New ",-1)])],2)]),j.value?(s(),n("div",{key:0,class:o(["mb-3 p-3 rounded-xl",t(c)?"bg-white/[0.05] border border-white/10":"bg-black/[0.03] border border-black/8"])},[e("p",{class:o(["text-xs font-medium mb-2",t(c)?"text-white/70":"text-gray-700"])}," New Project ",2),W(e("input",{ref_key:"newProjectInputRef",ref:D,"onUpdate:modelValue":H[1]||(H[1]=X=>P.value=X),type:"text",placeholder:"Project name...",class:o(["w-full px-3 py-2 rounded-lg text-base bg-transparent outline-none mb-2",t(c)?"text-white/80 placeholder:text-white/20 border border-white/10 focus:border-white/25":"text-gray-800 placeholder:text-gray-400 border border-black/10 focus:border-black/20"]),onKeydown:[ae(Z,["enter"]),ae(O,["escape"])]},null,34),[[Q,P.value]]),e("div",ko,[e("button",{class:o(["text-xs px-2.5 py-1 rounded-lg transition-colors",t(c)?"text-white/40 hover:text-white/70":"text-gray-500 hover:text-gray-800"]),onClick:O}," Cancel ",2),e("button",{class:o(["text-xs px-2.5 py-1 rounded-lg font-medium transition-colors",t(c)?"bg-accent/20 text-accent hover:bg-accent/30":"bg-accent/10 text-accent hover:bg-accent/20"]),disabled:!P.value.trim(),onClick:Z}," Create ",10,$o)])],2)):m("",!0),e("div",_o,[(s(!0),n(I,null,B(h.value,X=>(s(),n("button",{key:X.path,class:o(["text-left p-3 rounded-xl transition-all duration-150",t(c)?"bg-white/[0.03] hover:bg-white/[0.07] border border-white/5":"bg-black/[0.02] hover:bg-black/[0.05] border border-black/5"]),onClick:ge=>$(X)},[e("div",{class:o(["w-8 h-8 rounded-lg flex items-center justify-center mb-2",t(c)?"bg-white/5":"bg-black/5"])},[(s(),n("svg",{class:o(["w-4 h-4",X.isGit?"text-accent":t(c)?"text-white/40":"text-gray-400"]),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[...H[3]||(H[3]=[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"},null,-1)])],2))],2),e("p",{class:o(["text-xs font-medium truncate",t(c)?"text-white/80":"text-gray-800"])},d(X.name),3),e("p",{class:o(["text-xs mt-0.5 truncate",t(c)?"text-white/25":"text-gray-400"])},d(X.language),3)],10,Co))),128))])])):y.value==="filetree"?(s(),n("div",So,[(s(!0),n(I,null,B(t(g),X=>(s(),E(vo,{key:X.path,entry:X,"active-file":t(b),depth:0,onSelect:U,onToggleContext:F},null,8,["entry","active-file"]))),128)),t(g).length===0?(s(),n("div",jo,[e("p",{class:o(["text-xs",t(c)?"text-white/30":"text-gray-400"])}," Loading file tree... ",2)])):m("",!0)])):m("",!0)]))}}),To={class:"flex flex-col h-full"},Do={class:"shrink-0 px-4 py-2 flex gap-1.5 overflow-x-auto scrollbar-hide"},Lo=["onClick"],Io={class:"flex-1 overflow-y-auto px-4 py-3"},Bo={class:"grid grid-cols-2 gap-2"},Po=["onClick"],No=["onClick"],Ao={key:0,class:"w-3 h-3 text-white",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},zo={key:2,class:"h-8 flex items-end gap-0.5 mb-2"},Fo={key:3,class:"h-8 flex items-center mb-2"},Eo={key:0,"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"},Ro={key:1,"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"},Vo={key:2,"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"},Uo={key:3,"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01"},qo=q({__name:"DesignSystemGrid",setup(a){const{isDark:c}=J(),{openDesignSystemItem:l}=$e(),{codeMode:w,toggleDesignToken:g,isDesignTokenSelected:b}=pe(),p=M("all"),v=[{id:"all",label:"All"},{id:"colors",label:"Colors"},{id:"typography",label:"Typography"},{id:"spacing",label:"Spacing"},{id:"atoms",label:"Atoms"},{id:"molecules",label:"Molecules"},{id:"organisms",label:"Organisms"}],_=[{id:"color-bg",name:"Background",category:"colors",preview:"inline",description:"Primary app background",code:`background-color: #0a0a0a; +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/useNostr-DYbkCQxC.js","assets/index-Lh5NfTCq.js","assets/index-CHQ7uqBj.css","assets/ThreadNode-Bt5yTyUn.js"])))=>i.map(i=>d[i]); +import{a as q,Z as Ht,$ as ut,p as Ne,b as s,c as n,e,h as G,u as t,n as o,t as d,f as ie,w as W,v as Q,F as I,g as B,i as m,j as J,r as M,k as L,a0 as Wt,a1 as xt,N as ne,a2 as ht,a3 as pt,a4 as gt,a5 as vt,U as De,a6 as Kt,a7 as Yt,a8 as Qt,P as Jt,z as he,Q as E,K as le,a9 as ae,aa as ye,_ as bt,A as ce,B as Pe,d as Zt,ab as Xt,L as se,ac as es,ad as ts,ae as ss,af as ns,S as ls,q as os,ag as as,o as is,M as ue,ah as Be,ai as rs}from"./index-Lh5NfTCq.js";import{u as cs}from"./chat-BEnAHpY-.js";import{u as $e,a as pe,e as Ye,d as ft,M as ds,b as us,s as xs,c as hs,f as be,_ as lt}from"./ChatWindow.vue_vue_type_script_setup_true_lang-DoshhDBV.js";import{_ as ps}from"./FilmGrid.vue_vue_type_script_setup_true_lang-CWkUdZ32.js";import{u as Ae}from"./useContentImages-CagIZs4M.js";import{_ as gs}from"./SongGrid.vue_vue_type_script_setup_true_lang-CW1T9zpX.js";import{useNostr as Le}from"./useNostr-DYbkCQxC.js";import{u as mt,_ as vs}from"./FilmDetail.vue_vue_type_script_setup_true_lang-Cg4zvjy1.js";import{_ as bs}from"./SongDetail.vue_vue_type_script_setup_true_lang-CvC0ROCb.js";const fs={class:"h-full flex flex-col"},ms={class:"flex items-center justify-between gap-2"},ws={class:"flex items-center gap-2 shrink-0"},ys={key:0,class:"flex flex-wrap gap-1.5"},ks=["onClick"],$s={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-4 pb-16"},_s={class:"grid grid-cols-2 sm:grid-cols-3 gap-4"},Cs=["aria-label","onClick"],Ss={class:"cover-card flex-1 min-h-0 relative"},js={key:0,class:"absolute inset-0 animate-shimmer"},Ms=["src","alt","onError"],Ts=["src","alt"],Ds={key:3,class:"absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent pointer-events-none"},Ls={class:"absolute bottom-0 left-0 right-0 p-2"},Is={class:"text-xs font-semibold text-white/90 leading-tight truncate"},Bs={class:"text-xs text-white/40 truncate mt-0.5"},Ps={key:4,class:"absolute top-1.5 left-1.5"},Ns={class:"text-xs px-1.5 py-0.5 rounded bg-black/60 text-amber-400 backdrop-blur-sm font-medium"},As={key:5,class:"absolute top-1.5 right-1.5"},zs={class:"text-xs px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"},Fs={key:0,class:"flex items-center justify-center py-12"},Es=q({__name:"BookGrid",props:{books:{},title:{default:"Recommended Books"}},emits:["selectBook"],setup(a){const c=a,{isDark:l}=J(),w=M(""),g=M(null),{coverSrc:b,fallbackSrc:p,onError:v,isLoading:_}=Ae({items:Ne(c,"books"),id:u=>u.id,existingUrl:u=>u.coverUrl,fetch:u=>ut(u.title,u.author),fallback:u=>Ht(u.title,u.author)}),C=L(()=>{const u=new Map;for(const i of c.books)for(const r of i.genres??[])u.set(r,(u.get(r)??0)+1);return[...u.entries()].sort((i,r)=>r[1]-i[1]).slice(0,8).map(([i])=>i)}),f=L(()=>{let u=c.books;if(w.value){const i=w.value.toLowerCase();u=u.filter(r=>r.title.toLowerCase().includes(i)||r.author.toLowerCase().includes(i)||(r.genres??[]).some(x=>x.toLowerCase().includes(i)))}return g.value&&(u=u.filter(i=>(i.genres??[]).includes(g.value))),u});return(u,i)=>(s(),n("div",fs,[e("div",{class:"p-4 space-y-3",style:G(t(l)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",ms,[e("h3",{class:o(["text-sm font-bold",t(l)?"text-white/90":"text-gray-900"])},d(a.title),3),e("div",ws,[e("span",{class:o(["text-xs font-mono",t(l)?"text-white/30":"text-gray-400"])},d(f.value.length)+" books ",3),ie(u.$slots,"header-actions")])]),W(e("input",{"onUpdate:modelValue":i[0]||(i[0]=r=>w.value=r),type:"text",placeholder:"Search books...",class:o(["w-full px-3 py-2 rounded-lg text-base outline-none transition-colors",t(l)?"bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10":"bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5"])},null,2),[[Q,w.value]]),C.value.length>0?(s(),n("div",ys,[(s(!0),n(I,null,B(C.value,r=>(s(),n("button",{key:r,class:o(["text-xs px-2 py-1 rounded-md transition-all duration-150",g.value===r?"nav-tab-active":t(l)?"text-white/40 hover:text-white/70 hover:bg-white/5":"text-gray-500 hover:text-gray-800 hover:bg-black/5"]),onClick:x=>g.value=g.value===r?null:r},d(r),11,ks))),128))])):m("",!0)],4),e("div",$s,[e("div",_s,[(s(!0),n(I,null,B(f.value,r=>(s(),n("button",{key:r.id,class:"group flex flex-col items-stretch text-left w-full path-glass-bubble rounded-2xl overflow-hidden transition-all duration-200 hover:brightness-105","aria-label":`${r.title} by ${r.author}`,onClick:x=>u.$emit("selectBook",r)},[e("div",Ss,[e("div",{class:o(["aspect-[2/3] relative w-full overflow-hidden rounded-[10px]",t(b)(r)?"":t(l)?"bg-white/[0.06]":"bg-black/[0.04]"])},[t(_)(r)?(s(),n("div",js)):m("",!0),t(b)(r)?(s(),n("img",{key:1,src:t(b)(r),alt:`${r.title} by ${r.author}`,class:"w-full h-full object-cover transition-transform duration-300 group-hover:scale-110",loading:"lazy",onError:x=>t(v)(r)},null,40,Ms)):t(_)(r)?m("",!0):(s(),n("img",{key:2,src:t(p)(r),alt:r.title,class:"w-full h-full object-cover"},null,8,Ts)),t(b)(r)?(s(),n("div",Ds)):m("",!0),e("div",Ls,[e("p",Is,d(r.title),1),e("p",Bs,d(r.author),1)]),r.rating?(s(),n("div",Ps,[e("span",Ns," ★ "+d(r.rating.toFixed(1)),1)])):m("",!0),r.year?(s(),n("div",As,[e("span",zs,d(r.year),1)])):m("",!0)],2)])],8,Cs))),128))]),f.value.length===0?(s(),n("div",Fs,[e("p",{class:o(["text-sm",t(l)?"text-white/30":"text-gray-400"])}," No books match your search ",2)])):m("",!0)])]))}}),Rs={class:"h-full flex flex-col"},Vs={class:"flex items-center justify-between gap-2"},Us={class:"flex items-center gap-2 shrink-0"},qs={key:0,class:"flex flex-wrap gap-1.5"},Gs=["onClick"],Os={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-4 pb-16"},Hs={class:"grid grid-cols-2 sm:grid-cols-3 gap-4"},Ws=["aria-label","onClick"],Ks={class:"cover-card flex-1 min-h-0 relative"},Ys={key:0,class:"absolute inset-0 animate-shimmer"},Qs=["src","alt","onError"],Js=["src","alt"],Zs={key:3,class:"absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent pointer-events-none"},Xs={class:"absolute bottom-0 left-0 right-0 p-2"},en={class:"text-xs font-semibold text-white/90 leading-tight truncate"},tn={class:"text-xs text-white/40 truncate mt-0.5"},sn={key:4,class:"absolute top-1.5 left-1.5"},nn={class:"text-xs px-1.5 py-0.5 rounded bg-black/60 text-amber-400 backdrop-blur-sm font-medium"},ln={key:5,class:"absolute top-1.5 right-1.5"},on={class:"absolute top-1.5 right-1.5 flex gap-0.5 flex-wrap justify-end max-w-[60%]"},an={key:0,class:"flex items-center justify-center py-12"},rn=q({__name:"TVSeriesGrid",props:{series:{},title:{default:"Recommended TV Series"}},emits:["selectSeries"],setup(a){const c=a,{isDark:l}=J(),w=M(""),g=M(null),{coverSrc:b,fallbackSrc:p,onError:v,isLoading:_}=Ae({items:Ne(c,"series"),id:i=>i.id,existingUrl:i=>i.posterUrl||i.backdropUrl,fetch:i=>xt(i.title,i.year).then(r=>r.posterUrl),fallback:i=>Wt(i.title,i.year)});function C(i){return i.year?i.endYear&&i.endYear!==i.year?`${i.year}–${i.endYear}`:i.status==="ongoing"?`${i.year}–`:String(i.year):""}const f=L(()=>{const i=new Map;for(const r of c.series)for(const x of r.genres??[])i.set(x,(i.get(x)??0)+1);return[...i.entries()].sort((r,x)=>x[1]-r[1]).slice(0,8).map(([r])=>r)}),u=L(()=>{let i=c.series;if(w.value){const r=w.value.toLowerCase();i=i.filter(x=>x.title.toLowerCase().includes(r)||(x.creator??"").toLowerCase().includes(r)||(x.network??"").toLowerCase().includes(r)||(x.genres??[]).some(S=>S.toLowerCase().includes(r)))}return g.value&&(i=i.filter(r=>(r.genres??[]).includes(g.value))),i});return(i,r)=>(s(),n("div",Rs,[e("div",{class:"p-4 space-y-3",style:G(t(l)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",Vs,[e("h3",{class:o(["text-sm font-bold",t(l)?"text-white/90":"text-gray-900"])},d(a.title),3),e("div",Us,[e("span",{class:o(["text-xs font-mono",t(l)?"text-white/30":"text-gray-400"])},d(u.value.length)+" series ",3),ie(i.$slots,"header-actions")])]),W(e("input",{"onUpdate:modelValue":r[0]||(r[0]=x=>w.value=x),type:"text",placeholder:"Search TV series...",class:o(["w-full px-3 py-2 rounded-lg text-base outline-none transition-colors",t(l)?"bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10":"bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5"])},null,2),[[Q,w.value]]),f.value.length>0?(s(),n("div",qs,[(s(!0),n(I,null,B(f.value,x=>(s(),n("button",{key:x,class:o(["text-xs px-2 py-1 rounded-md transition-all duration-150",g.value===x?"nav-tab-active":t(l)?"text-white/40 hover:text-white/70 hover:bg-white/5":"text-gray-500 hover:text-gray-800 hover:bg-black/5"]),onClick:S=>g.value=g.value===x?null:x},d(x),11,Gs))),128))])):m("",!0)],4),e("div",Os,[e("div",Hs,[(s(!0),n(I,null,B(u.value,x=>(s(),n("button",{key:x.id,class:"group flex flex-col items-stretch text-left w-full path-glass-bubble rounded-2xl overflow-hidden transition-all duration-200 hover:brightness-105","aria-label":x.title,onClick:S=>i.$emit("selectSeries",x)},[e("div",Ks,[e("div",{class:o(["aspect-[2/3] relative w-full overflow-hidden rounded-[10px]",t(b)(x)?"":t(l)?"bg-white/[0.06]":"bg-black/[0.04]"])},[t(_)(x)?(s(),n("div",Ys)):m("",!0),t(b)(x)?(s(),n("img",{key:1,src:t(b)(x),alt:`${x.title} — TV Series`,class:"w-full h-full object-cover transition-transform duration-300 group-hover:scale-110",loading:"lazy",onError:S=>t(v)(x)},null,40,Qs)):t(_)(x)?m("",!0):(s(),n("img",{key:2,src:t(p)(x),alt:x.title,class:"w-full h-full object-cover"},null,8,Js)),t(b)(x)?(s(),n("div",Zs)):m("",!0),e("div",Xs,[e("p",en,d(x.title),1),e("p",tn,[ne(d(C(x)),1),x.seasons?(s(),n(I,{key:0},[ne(" · "+d(x.seasons)+"S",1)],64)):m("",!0)])]),x.rating?(s(),n("div",sn,[e("span",nn," ★ "+d(x.rating.toFixed(1)),1)])):m("",!0),x.status==="ongoing"?(s(),n("div",ln,[...r[1]||(r[1]=[e("span",{class:"text-xs px-1 py-0.5 rounded bg-emerald-500/80 text-white backdrop-blur-sm"}," ongoing ",-1)])])):m("",!0),e("div",on,[(s(!0),n(I,null,B((x.sources??[]).slice(0,2),S=>(s(),n("span",{key:S.type,class:"text-xs px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"},d(S.type),1))),128))])],2)])],8,Ws))),128))]),u.value.length===0?(s(),n("div",an,[e("p",{class:o(["text-sm",t(l)?"text-white/30":"text-gray-400"])}," No TV series match your search ",2)])):m("",!0)])]))}}),cn={class:"h-full flex flex-col"},dn={class:"flex items-center justify-between gap-2"},un={class:"flex items-center gap-2 shrink-0"},xn={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-4 pb-16"},hn={class:"columns-2 sm:columns-3 gap-3 space-y-3"},pn=["aria-label","onClick"],gn=["src","alt","onError"],vn={key:2,class:"absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/70 via-black/30 to-transparent"},bn={key:0,class:"text-xs font-medium text-white/90 truncate"},fn={key:1,class:"text-xs text-white/50 truncate"},mn={key:0,class:"flex items-center justify-center py-12"},wn=q({__name:"ImageGrid",props:{images:{},title:{default:"Images"}},emits:["selectImage"],setup(a){const{isDark:c}=J(),l=M(new Set);function w(g){l.value.add(g.id),l.value=new Set(l.value)}return(g,b)=>(s(),n("div",cn,[e("div",{class:"p-4 space-y-3",style:G(t(c)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",dn,[e("h3",{class:o(["text-sm font-bold",t(c)?"text-white/90":"text-gray-900"])},d(a.title),3),e("div",un,[e("span",{class:o(["text-xs font-mono",t(c)?"text-white/30":"text-gray-400"])},d(a.images.length)+" images ",3),ie(g.$slots,"header-actions")])])],4),e("div",xn,[e("div",hn,[(s(!0),n(I,null,B(a.images,p=>(s(),n("button",{key:p.id,class:o(["group w-full break-inside-avoid text-left rounded-xl overflow-hidden transition-all duration-200 hover:brightness-110 relative",t(c)?"bg-white/5":"bg-black/3"]),"aria-label":p.alt||p.title||"Image",onClick:v=>g.$emit("selectImage",p)},[l.value.has(p.id)?(s(),n("div",{key:1,class:o(["w-full aspect-[4/3] flex items-center justify-center",t(c)?"bg-white/5":"bg-black/5"])},[(s(),n("svg",{class:o(["w-8 h-8",t(c)?"text-white/15":"text-gray-300"]),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[...b[0]||(b[0]=[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"},null,-1)])],2))],2)):(s(),n("img",{key:0,src:p.url,alt:p.alt||p.title||"Image",class:"w-full block transition-transform duration-300 group-hover:scale-[1.03]",loading:"lazy",onError:v=>w(p)},null,40,gn)),p.title||p.source?(s(),n("div",vn,[p.title?(s(),n("p",bn,d(p.title),1)):m("",!0),p.source?(s(),n("p",fn,d(p.source),1)):m("",!0)])):m("",!0)],10,pn))),128))]),a.images.length===0?(s(),n("div",mn,[e("p",{class:o(["text-sm",t(c)?"text-white/30":"text-gray-400"])}," No images found ",2)])):m("",!0)])]))}}),yn={class:"h-full flex flex-col"},kn={class:"p-4 space-y-3"},$n={class:"flex items-center justify-between"},_n={class:"shrink-0 flex items-center gap-2"},Cn={key:0,class:"flex flex-wrap gap-1.5"},Sn=["onClick"],jn={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pb-16"},Mn={class:"grid grid-cols-2 sm:grid-cols-3 gap-3"},Tn=["aria-label","onClick"],Dn={class:"aspect-[4/3] relative w-full overflow-hidden rounded-t-[10px]"},Ln={key:0,class:"absolute inset-0 animate-shimmer"},In=["src","alt","onError"],Bn=["src","alt"],Pn={key:3,class:"absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent pointer-events-none"},Nn={class:"absolute bottom-0 left-0 right-0 p-2"},An={class:"text-xs font-semibold text-white/90 truncate"},zn={class:"text-xs text-white/40 truncate mt-0.5"},Fn={key:4,class:"absolute top-1.5 right-1.5"},En={class:"text-xs px-1.5 py-0.5 rounded bg-black/60 text-amber-400 backdrop-blur-sm font-semibold"},Rn={key:5,class:"absolute top-1.5 left-1.5"},Vn={class:"text-xs px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"},Un={key:0,class:"flex items-center justify-center py-12"},qn=q({__name:"PlaceGrid",props:{places:{},title:{default:"Places"}},emits:["selectPlace"],setup(a){const c=a,{isDark:l}=J(),w=M(""),g=M(null),{coverSrc:b,fallbackSrc:p,onError:v,isLoading:_}=Ae({items:Ne(c,"places"),id:u=>u.id,existingUrl:u=>u.photoUrl,fetch:u=>pt(u.name,u.city),fallback:u=>ht(u.name,u.cuisine||u.category)}),C=L(()=>{const u=new Map;for(const i of c.places){const r=i.cuisine||i.category;r&&u.set(r,(u.get(r)??0)+1)}return[...u.entries()].sort((i,r)=>r[1]-i[1]).slice(0,8).map(([i])=>i)}),f=L(()=>{let u=c.places;if(w.value){const i=w.value.toLowerCase();u=u.filter(r=>r.name.toLowerCase().includes(i)||r.cuisine?.toLowerCase().includes(i)||r.category?.toLowerCase().includes(i)||r.city?.toLowerCase().includes(i)||r.address?.toLowerCase().includes(i))}return g.value&&(u=u.filter(i=>i.cuisine===g.value||i.category===g.value)),u});return(u,i)=>(s(),n("div",yn,[e("div",kn,[e("div",$n,[e("h3",{class:o(["text-base font-bold",t(l)?"text-white/90":"text-gray-900"])},d(a.title||"Places"),3),e("div",_n,[e("span",{class:o(["text-xs",t(l)?"text-white/30":"text-gray-400"])},d(f.value.length)+" places ",3),ie(u.$slots,"header-actions")])]),W(e("input",{"onUpdate:modelValue":i[0]||(i[0]=r=>w.value=r),type:"text",placeholder:"Search places...",class:o(["w-full text-base px-3 py-2 rounded-lg outline-none transition-colors",t(l)?"bg-white/5 text-white/80 placeholder-white/25 focus:bg-white/8":"bg-black/5 text-gray-800 placeholder-gray-400 focus:bg-black/8"])},null,2),[[Q,w.value]]),C.value.length>1?(s(),n("div",Cn,[(s(!0),n(I,null,B(C.value,r=>(s(),n("button",{key:r,class:o(["text-xs px-2 py-1 rounded-md font-medium transition-all duration-150",g.value===r?"nav-tab-active":t(l)?"bg-white/5 text-white/40 hover:text-white/70":"bg-black/5 text-gray-500 hover:text-gray-800"]),onClick:x=>g.value=g.value===r?null:r},d(r),11,Sn))),128))])):m("",!0)]),e("div",jn,[e("div",Mn,[(s(!0),n(I,null,B(f.value,r=>(s(),n("button",{key:r.id,class:"group flex flex-col items-stretch text-left w-full path-glass-bubble rounded-2xl overflow-hidden transition-all duration-200 hover:brightness-105","aria-label":r.name,onClick:x=>u.$emit("selectPlace",r)},[e("div",Dn,[t(_)(r)?(s(),n("div",Ln)):m("",!0),t(b)(r)?(s(),n("img",{key:1,src:t(b)(r),alt:r.name,class:"w-full h-full object-cover transition-transform duration-300 group-hover:scale-110",loading:"lazy",onError:x=>t(v)(r)},null,40,In)):t(_)(r)?m("",!0):(s(),n("img",{key:2,src:t(p)(r),alt:r.name,class:"w-full h-full object-cover"},null,8,Bn)),t(b)(r)?(s(),n("div",Pn)):m("",!0),e("div",Nn,[e("p",An,d(r.name),1),e("p",zn,d(r.cuisine||r.category),1)]),r.rating?(s(),n("div",Fn,[e("span",En," ★ "+d(r.rating.toFixed(1)),1)])):m("",!0),r.priceLevel?(s(),n("div",Rn,[e("span",Vn,d("$".repeat(r.priceLevel)),1)])):m("",!0)])],8,Tn))),128))]),f.value.length===0?(s(),n("div",Un,[e("p",{class:o(["text-xs",t(l)?"text-white/30":"text-gray-400"])}," No places match your search ",2)])):m("",!0)])]))}}),Gn={class:"h-full flex flex-col"},On={class:"flex items-center justify-between gap-2"},Hn={class:"flex items-center gap-2 shrink-0"},Wn={key:0,class:"flex flex-wrap gap-1.5"},Kn=["onClick"],Yn={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-4 pb-16"},Qn={class:"grid grid-cols-2 sm:grid-cols-3 gap-4"},Jn=["aria-label","onClick"],Zn={class:"cover-card flex-1 min-h-0 relative"},Xn={key:0,class:"absolute inset-0 animate-shimmer"},el=["src","alt","onError"],tl=["src","alt"],sl={key:3,class:"absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent pointer-events-none"},nl={class:"absolute bottom-0 left-0 right-0 p-2"},ll={class:"text-xs font-semibold text-white/90 leading-tight truncate"},ol={class:"text-xs text-white/40 truncate mt-0.5"},al={class:"absolute top-1.5 right-1.5 flex gap-0.5 flex-wrap justify-end max-w-[60%]"},il={key:0,class:"flex items-center justify-center py-12"},rl=q({__name:"PodcastGrid",props:{podcasts:{},title:{default:"Recommended Podcasts"}},emits:["selectPodcast"],setup(a){const c=a,{isDark:l}=J(),w=M(""),g=M(null),{coverSrc:b,fallbackSrc:p,onError:v,isLoading:_}=Ae({items:Ne(c,"podcasts"),id:u=>u.id,existingUrl:u=>u.coverUrl,fetch:u=>vt(u.title,u.host),fallback:u=>gt(u.title,u.host)}),C=L(()=>{const u=new Map;for(const i of c.podcasts)for(const r of i.genres??[])u.set(r,(u.get(r)??0)+1);return[...u.entries()].sort((i,r)=>r[1]-i[1]).slice(0,8).map(([i])=>i)}),f=L(()=>{let u=c.podcasts;if(w.value){const i=w.value.toLowerCase();u=u.filter(r=>r.title.toLowerCase().includes(i)||(r.host??"").toLowerCase().includes(i)||(r.genres??[]).some(x=>x.toLowerCase().includes(i)))}return g.value&&(u=u.filter(i=>(i.genres??[]).includes(g.value))),u});return(u,i)=>(s(),n("div",Gn,[e("div",{class:"p-4 space-y-3",style:G(t(l)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",On,[e("h3",{class:o(["text-sm font-bold",t(l)?"text-white/90":"text-gray-900"])},d(a.title),3),e("div",Hn,[e("span",{class:o(["text-xs font-mono",t(l)?"text-white/30":"text-gray-400"])},d(f.value.length)+" podcasts ",3),ie(u.$slots,"header-actions")])]),W(e("input",{"onUpdate:modelValue":i[0]||(i[0]=r=>w.value=r),type:"text",placeholder:"Search podcasts...",class:o(["w-full px-3 py-2 rounded-lg text-base outline-none transition-colors",t(l)?"bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10":"bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5"])},null,2),[[Q,w.value]]),C.value.length>0?(s(),n("div",Wn,[(s(!0),n(I,null,B(C.value,r=>(s(),n("button",{key:r,class:o(["text-xs px-2 py-1 rounded-md transition-all duration-150",g.value===r?"nav-tab-active":t(l)?"text-white/40 hover:text-white/70 hover:bg-white/5":"text-gray-500 hover:text-gray-800 hover:bg-black/5"]),onClick:x=>g.value=g.value===r?null:r},d(r),11,Kn))),128))])):m("",!0)],4),e("div",Yn,[e("div",Qn,[(s(!0),n(I,null,B(f.value,r=>(s(),n("button",{key:r.id,class:"group flex flex-col items-stretch text-left w-full path-glass-bubble rounded-2xl overflow-hidden transition-all duration-200 hover:brightness-105","aria-label":r.title,onClick:x=>u.$emit("selectPodcast",r)},[e("div",Zn,[e("div",{class:o(["aspect-square relative w-full overflow-hidden rounded-[10px]",t(b)(r)?"":t(l)?"bg-white/[0.06]":"bg-black/[0.04]"])},[t(_)(r)?(s(),n("div",Xn)):m("",!0),t(b)(r)?(s(),n("img",{key:1,src:t(b)(r),alt:r.title,class:"w-full h-full object-cover transition-transform duration-300 group-hover:scale-110",loading:"lazy",onError:x=>t(v)(r)},null,40,el)):t(_)(r)?m("",!0):(s(),n("img",{key:2,src:t(p)(r),alt:r.title,class:"w-full h-full object-cover"},null,8,tl)),t(b)(r)?(s(),n("div",sl)):m("",!0),e("div",nl,[e("p",ll,d(r.title),1),e("p",ol,d(r.host||"Podcast"),1)]),e("div",al,[(s(!0),n(I,null,B(r.sources.slice(0,2),x=>(s(),n("span",{key:x.type,class:"text-xs px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"},d(x.type),1))),128))])],2)])],8,Jn))),128))]),f.value.length===0?(s(),n("div",il,[e("p",{class:o(["text-sm",t(l)?"text-white/30":"text-gray-400"])}," No podcasts match your search ",2)])):m("",!0)])]))}}),cl={class:"shrink-0"},dl={class:"flex-1 overflow-y-auto custom-scrollbar"},ul={key:0,class:"relative overflow-hidden",style:{minHeight:"180px"}},xl={class:"absolute inset-0"},hl=["src"],pl={class:"relative z-10 flex flex-col justify-end h-full px-5 pb-5 pt-12",style:{"min-height":"180px"}},gl={class:"px-3 pt-2 pb-8"},vl={key:0,"stroke-linecap":"round","stroke-linejoin":"round",d:"M12 2a10 10 0 100 20 10 10 0 000-20zm0 0v2m0 16v2m10-10h-2M4 12H2m15.07-5.07l-1.41 1.41M8.34 15.66l-1.41 1.41m0-11.14l1.41 1.41m7.32 7.32l1.41 1.41"},bl={key:1,"stroke-linecap":"round","stroke-linejoin":"round",d:"M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z"},fl={key:2,"stroke-linecap":"round","stroke-linejoin":"round",d:"M13 2L3 14h9l-1 8 10-12h-9l1-8z"},ml={key:3,"stroke-linecap":"round","stroke-linejoin":"round",d:"M4 6h16M4 12h16M4 18h7"},wl=["onClick"],yl=["onClick"],kl={key:1,class:"flex items-center justify-center py-16 px-4"},$l=q({__name:"MagazineGrid",props:{sections:{},heroImageUrl:{default:null},title:{default:"Brief"},query:{default:""}},setup(a){const c=a,{isDark:l}=J(),{openMagazineSectionDetail:w}=$e(),g=["compass","bookmark","lightning","lines"];function b(f){return f.replace(/\[([^\]]*)\]\([^)]+\)/g,"$1").replace(/https?:\/\/\S+/g,"").replace(/\uFE0F/g,"").replace(new RegExp("(?:^|(?<=\\s))[\\p{Emoji_Presentation}\\p{Extended_Pictographic}]+\\s*","gu"),"").replace(/---+/g,"").replace(/^#+\s*/gm,"").replace(/\*\*/g,"").replace(/\*([^*\n]+)\*/g,"$1").replace(/\|/g,", ").replace(/,\s*,+/g,",").replace(/^\s*[-•]\s+/gm,"").replace(/\n+/g," ").replace(/(^|\s),\s*/g,"$1").trim()}function p(f,u){const i=b(f);return i.length<=u?i:i.slice(0,u).replace(/\s+\S*$/,"")+" ..."}const v=L(()=>{const f=[],u=c.sections;if(!u.length)return f;let i=0;for(const j of c.query||"brief")i=(i<<5)-i+j.charCodeAt(0)|0;let r="",x=0,S=!1;return u.forEach((j,P)=>{if(P===0&&!j.group){f.push({type:"wide",title:j.title,text:p(j.content,200),label:"The Lead",author:j.author,section:j});return}const D=j.group||"";if(D&&D!==r&&(S&&(f.push({type:"dark",title:"",text:""}),S=!1),f.push({type:"banner",title:"",text:"",icon:g[x%g.length],label:D}),x++,r=D),D){const y=S?"dark":"half",k=b(j.content),h=b(j.title),$=k.toLowerCase().startsWith(h.toLowerCase().slice(0,30));f.push({type:y,title:$?"":j.title,text:p(j.content,$?160:100),section:j}),S=!S}else S&&(f.push({type:"dark",title:"",text:""}),S=!1),f.push({type:"wide",title:j.title,text:p(j.content,180),author:j.author,section:j})}),S&&f.push({type:"dark",title:"",text:""}),f});function _(f){const u=c.sections.indexOf(f);w(f,u>=0?u:0)}const C=L(()=>{const f=(c.query??"").trim();return f?f.length>100?f.slice(0,97)+"...":f:c.title});return(f,u)=>(s(),n("div",{class:o(["magazine h-full flex flex-col",t(l)?"magazine-dark":"magazine-light"])},[e("header",{class:o(["shrink-0 px-5 py-4 flex items-center justify-between border-b",t(l)?"border-white/10":"border-black/10"])},[e("h1",{class:o(["font-serif text-xl font-bold tracking-tight",t(l)?"text-white":"text-black"])}," AI Brief ",2),e("div",cl,[ie(f.$slots,"header-actions",{},void 0,!0)])],2),e("div",dl,[C.value?(s(),n("div",ul,[e("div",xl,[a.heroImageUrl?(s(),n("img",{key:0,src:a.heroImageUrl,alt:"",class:"w-full h-full object-cover",style:{filter:"saturate(0.3) contrast(1.1)"}},null,8,hl)):(s(),n("div",{key:1,class:o(["w-full h-full",t(l)?"bg-gradient-to-br from-white/[0.04] via-white/[0.02] to-transparent":"bg-gradient-to-br from-black/[0.06] via-black/[0.03] to-transparent"])},null,2))]),e("div",{class:o(["absolute inset-0",t(l)?"bg-gradient-to-t from-[#0a0a0a] via-[#0a0a0a]/80 to-[#0a0a0a]/60":"bg-gradient-to-t from-[#faf9f6] via-[#faf9f6]/85 to-[#faf9f6]/65"])},null,2),e("div",pl,[e("p",{class:o(["text-xs uppercase tracking-[0.3em] font-medium mb-2",t(l)?"text-white/40":"text-black/40"])}," In response to ",2),e("p",{class:o(["font-serif text-2xl italic leading-tight",t(l)?"text-white/70":"text-black/60"])},d(C.value),3)])])):m("",!0),e("div",gl,[e("div",{class:o(["grid grid-cols-2 gap-px",t(l)?"bg-white/12":"bg-black/10"])},[(s(!0),n(I,null,B(v.value,(i,r)=>(s(),n(I,{key:r},[i.type==="banner"?(s(),n("div",{key:0,class:o(["col-span-2 flex flex-col items-center justify-center py-8 px-5",t(l)?"bg-[#0a0a0a]":"bg-[#faf9f6]"])},[(s(),n("svg",{class:o(["w-5 h-5 mb-2.5",t(l)?"text-white/20":"text-black/15"]),viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"1.5"},[i.icon==="compass"?(s(),n("path",vl)):i.icon==="bookmark"?(s(),n("path",bl)):i.icon==="lightning"?(s(),n("path",fl)):(s(),n("path",ml))],2)),e("p",{class:o(["text-xs uppercase tracking-[0.3em] font-semibold text-center",t(l)?"text-white/30":"text-black/30"])},d(i.label),3)],2)):i.type==="wide"?(s(),n("button",{key:1,class:o(["col-span-2 text-left px-5 py-5 transition-colors cursor-pointer",t(l)?"bg-[#0a0a0a] hover:bg-white/[0.03]":"bg-[#faf9f6] hover:bg-black/[0.02]"]),onClick:x=>i.section&&_(i.section)},[i.label?(s(),n("p",{key:0,class:o(["text-xs uppercase tracking-[0.3em] font-semibold mb-2",t(l)?"text-white/30":"text-black/35"])},d(i.label),3)):m("",!0),e("h2",{class:o(["font-serif text-lg font-bold leading-snug mb-2",t(l)?"text-white/95":"text-black/90"])},d(i.title),3),i.author?(s(),n("p",{key:1,class:o(["text-xs mb-2",t(l)?"text-white/40":"text-black/40"])}," By "+d(i.author),3)):m("",!0),e("p",{class:o(["font-serif text-sm leading-relaxed",t(l)?"text-white/70":"text-black/60"])},d(i.text),3)],10,wl)):(s(),n("button",{key:2,class:o(["text-left px-4 py-4 transition-colors flex flex-col cursor-pointer",[t(l)?"bg-[#0a0a0a] hover:bg-white/[0.03]":"bg-[#faf9f6] hover:bg-black/[0.02]",i.type==="dark"?t(l)?"bg-white/[0.04]":"bg-black/[0.04]":""]]),onClick:x=>i.section&&_(i.section)},[i.label?(s(),n("p",{key:0,class:o(["text-xs uppercase tracking-[0.25em] font-semibold mb-1.5",t(l)?"text-white/25":"text-black/30"])},d(i.label),3)):m("",!0),i.title?(s(),n("h3",{key:1,class:o(["font-serif text-sm font-bold leading-snug mb-1",t(l)?"text-white/90":"text-black/85"])},d(i.title),3)):m("",!0),e("p",{class:o(["font-serif text-xs leading-relaxed flex-1",[t(l)?"text-white/55":"text-black/50",i.title?"":"italic"]])},d(i.text),3)],10,yl))],64))),128))],2)]),a.sections.length===0?(s(),n("div",kl,[e("p",{class:o(["text-sm",t(l)?"text-white/40":"text-gray-400"])}," No sections to display ",2)])):m("",!0)])],2))}}),ot=De($l,[["__scopeId","data-v-02741b8c"]]),_l={class:"h-full flex flex-col"},Cl={class:"flex items-center justify-between gap-2"},Sl={class:"flex items-center gap-2 shrink-0"},jl=["placeholder"],Ml={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-4 pb-16"},Tl={class:"grid grid-cols-2 sm:grid-cols-3 gap-4"},Dl=["aria-label","onClick"],Ll={class:"cover-card flex-1 min-h-0 relative"},Il={class:"aspect-[4/3] flex flex-col w-full overflow-hidden rounded-[10px]"},Bl={class:"flex-1 min-h-0 relative"},Pl=["src","alt","onError"],Nl={key:2,class:"absolute inset-0 bg-gradient-to-t from-black/60 via-black/20 to-transparent pointer-events-none"},Al={key:0,class:"flex items-center justify-center py-12"},at=q({__name:"NewsGrid",props:{articles:{},title:{default:"News & Articles"},query:{default:""},variant:{default:"news"}},setup(a){const c=a,{isDark:l}=J(),{openArticleDetail:w,openWebsiteDetail:g}=$e(),b=M(""),p=M(new Set);function v(x){return!x||typeof x!="string"?!1:/^https?:\/\//i.test(x.trim())}function _(x){p.value=new Set([...p.value,x])}function C(x){try{return new URL(x).hostname.replace(/^www\./,"")}catch{return x}}function f(x){return c.variant==="websites"?Kt(x.title,C(x.url)):Yt(x.title,C(x.url))}function u(x){c.variant==="websites"?g(x):w(x)}function i(x,S){if(!S.trim())return 0;const P=S.toLowerCase().split(/\s+/).filter($=>$.length>1);if(P.length===0)return 0;const D=x.title.toLowerCase(),y=(x.content??"").toLowerCase(),k=x.url.toLowerCase();let h=0;for(const $ of P)D.includes($)&&(h+=3),y.includes($)&&(h+=2),k.includes($)&&(h+=1);return h}const r=L(()=>{let x=c.articles;if(b.value.trim()){const S=b.value.toLowerCase();x=x.filter(j=>j.title.toLowerCase().includes(S)||(j.content??"").toLowerCase().includes(S)||j.url.toLowerCase().includes(S))}return c.query.trim()?[...x].sort((S,j)=>i(j,c.query)-i(S,c.query)):x});return(x,S)=>(s(),n("div",_l,[e("div",{class:"p-4 space-y-3",style:G(t(l)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",Cl,[e("h3",{class:o(["text-sm font-bold",t(l)?"text-white/90":"text-gray-900"])},d(a.title),3),e("div",Sl,[e("span",{class:o(["text-xs font-mono",t(l)?"text-white/30":"text-gray-400"])},d(r.value.length)+" "+d(a.variant==="websites"?"websites":"articles"),3),ie(x.$slots,"header-actions")])]),W(e("input",{"onUpdate:modelValue":S[0]||(S[0]=j=>b.value=j),type:"text",placeholder:a.variant==="websites"?"Search websites...":"Search articles...",class:o(["w-full px-3 py-2 rounded-lg text-base outline-none transition-colors",t(l)?"bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10":"bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5"])},null,10,jl),[[Q,b.value]])],4),e("div",Ml,[e("div",Tl,[(s(!0),n(I,null,B(r.value,(j,P)=>(s(),n("button",{key:P,class:"group flex flex-col items-stretch text-left w-full path-glass-bubble rounded-2xl overflow-hidden transition-all duration-200 hover:brightness-105","aria-label":j.title,onClick:D=>u(j)},[e("div",Ll,[e("div",Il,[e("div",Bl,[v(j.imgSrc)&&!p.value.has(j.url)?(s(),n("img",{key:0,src:j.imgSrc,alt:j.title,class:"absolute inset-0 w-full h-full object-cover transition-transform duration-300 group-hover:scale-110",loading:"lazy",onError:D=>_(j.url)},null,40,Pl)):(s(),n("div",{key:1,class:"absolute inset-0 bg-cover bg-center",style:G({backgroundImage:`url(${f(j)})`})},null,4)),v(j.imgSrc)&&!p.value.has(j.url)?(s(),n("div",Nl)):m("",!0)]),e("div",{class:o(["shrink-0 p-2 backdrop-blur-md rounded-b-[10px]",[t(l)?"bg-black shadow-[inset_0_1px_0_rgba(255,255,255,0.12)]":"bg-white shadow-[inset_0_1px_0_rgba(0,0,0,0.06)]"]])},[e("p",{class:o(["text-xs font-semibold leading-tight line-clamp-2",t(l)?"text-white/95":"text-gray-900"])},d(j.title),3),j.content?(s(),n("p",{key:0,class:o(["text-xs line-clamp-1 mt-0.5",t(l)?"text-white/70":"text-gray-600"])},d(j.content),3)):m("",!0),e("p",{class:o(["text-xs truncate mt-0.5",t(l)?"text-white/50":"text-gray-500"])},d(C(j.url)),3)],2)])])],8,Dl))),128))]),r.value.length===0?(s(),n("div",Al,[e("p",{class:o(["text-sm",t(l)?"text-white/30":"text-gray-400"])},d(a.variant==="websites"?"No websites match your search":"No articles match your search"),3)])):m("",!0)])]))}}),zl={class:"h-full flex flex-col"},Fl={class:"flex items-center justify-between gap-2"},El={class:"flex items-center gap-2 shrink-0"},Rl={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-4 pb-16"},Vl={class:"grid grid-cols-1 sm:grid-cols-2 gap-3"},Ul=["aria-label","onClick"],ql={class:"aspect-[3/1] relative w-full overflow-hidden"},Gl=["src","alt"],Ol={class:"p-3"},Hl={class:"flex items-center gap-3 mt-2 flex-wrap"},Wl={key:0,class:"flex items-center justify-center py-12"},Kl=q({__name:"RecipeGrid",props:{recipes:{},title:{default:"Recipes"}},emits:["selectRecipe"],setup(a){const c=a,{isDark:l}=J(),w=M(""),g=L(()=>{if(!w.value.trim())return c.recipes;const b=w.value.toLowerCase();return c.recipes.filter(p=>p.title.toLowerCase().includes(b)||p.ingredients.some(v=>v.toLowerCase().includes(b)))});return(b,p)=>(s(),n("div",zl,[e("div",{class:"p-4 space-y-3",style:G(t(l)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",Fl,[e("h3",{class:o(["text-sm font-bold",t(l)?"text-white/90":"text-gray-900"])},d(a.title),3),e("div",El,[e("span",{class:o(["text-xs font-mono",t(l)?"text-white/30":"text-gray-400"])},d(g.value.length)+" recipes ",3),ie(b.$slots,"header-actions")])]),a.recipes.length>3?W((s(),n("input",{key:0,"onUpdate:modelValue":p[0]||(p[0]=v=>w.value=v),type:"text",placeholder:"Search recipes...",class:o(["w-full px-3 py-2 rounded-lg text-base outline-none transition-colors",t(l)?"bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10":"bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5"])},null,2)),[[Q,w.value]]):m("",!0)],4),e("div",Rl,[e("div",Vl,[(s(!0),n(I,null,B(g.value,(v,_)=>(s(),n("button",{key:_,class:o(["group flex flex-col items-stretch text-left w-full rounded-2xl overflow-hidden transition-all duration-200 hover:brightness-105",t(l)?"bg-white/[0.04] border border-white/8 hover:bg-white/[0.07]":"bg-black/[0.02] border border-black/5 hover:bg-black/[0.05]"]),"aria-label":v.title,onClick:C=>b.$emit("selectRecipe",v)},[e("div",ql,[e("img",{src:t(Qt)(v.title,v.time),alt:v.title,class:"w-full h-full object-cover"},null,8,Gl)]),e("div",Ol,[e("p",{class:o(["text-sm font-semibold leading-tight line-clamp-2",t(l)?"text-white/90":"text-gray-900"])},d(v.title),3),e("div",Hl,[v.time?(s(),n("span",{key:0,class:o(["flex items-center gap-1 text-xs",t(l)?"text-white/40":"text-gray-500"])},[p[1]||(p[1]=e("svg",{class:"w-3 h-3",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"})],-1)),ne(" "+d(v.time),1)],2)):m("",!0),v.servings?(s(),n("span",{key:1,class:o(["flex items-center gap-1 text-xs",t(l)?"text-white/40":"text-gray-500"])},[p[2]||(p[2]=e("svg",{class:"w-3 h-3",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"})],-1)),ne(" "+d(v.servings),1)],2)):m("",!0),v.calories?(s(),n("span",{key:2,class:o(["text-xs",t(l)?"text-white/40":"text-gray-500"])},d(v.calories)+" cal ",3)):m("",!0)]),v.ingredients.length>0?(s(),n("p",{key:0,class:o(["text-xs mt-2 line-clamp-1",t(l)?"text-white/25":"text-gray-400"])},d(v.ingredients.slice(0,4).join(" · ")),3)):m("",!0)])],10,Ul))),128))]),g.value.length===0?(s(),n("div",Wl,[e("p",{class:o(["text-sm",t(l)?"text-white/30":"text-gray-400"])}," No recipes match your search ",2)])):m("",!0)])]))}}),Yl={class:"h-full flex flex-col"},Ql={class:"flex items-center justify-between gap-2"},Jl={class:"flex flex-wrap gap-1.5"},Zl=["onClick"],Xl={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-4 pb-16"},eo={class:"space-y-2"},to=["aria-label","onClick"],so={class:"text-white/90"},no={class:"flex-1 min-w-0"},lo={class:"flex items-center gap-2"},oo={class:"flex gap-1 mt-1.5"},ao={key:0,class:"flex items-center justify-center py-12"},io=q({__name:"AppsGrid",props:{apps:{},title:{default:"Recommended Apps"}},emits:["selectApp"],setup(a){const c=a,{isDark:l}=J(),w=M(""),g=M(null),b=[{value:"nostr-client",label:"Nostr"},{value:"lightning-wallet",label:"Lightning"},{value:"bitcoin-wallet",label:"Bitcoin"},{value:"privacy",label:"Privacy"},{value:"node",label:"Nodes"},{value:"dev-tool",label:"Dev"}];function p(f){return b.find(u=>u.value===f)?.label??f}function v(f){return{ios:"iOS",android:"Android",web:"Web",desktop:"Desktop",cli:"CLI",nodeos:"Node"}[f]??f}function _(f){let u=0;for(let r=0;r{let f=c.apps;if(w.value){const u=w.value.toLowerCase();f=f.filter(i=>i.name.toLowerCase().includes(u)||i.description.toLowerCase().includes(u)||i.keywords.some(r=>r.toLowerCase().includes(u)))}return g.value&&(f=f.filter(u=>u.category===g.value)),f});return(f,u)=>(s(),n("div",Yl,[e("div",{class:"p-4 space-y-3",style:G(t(l)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",Ql,[e("h3",{class:o(["text-sm font-bold",t(l)?"text-white/90":"text-gray-900"])},d(a.title),3),e("span",{class:o(["text-xs font-mono",t(l)?"text-white/30":"text-gray-400"])},d(C.value.length)+" apps ",3)]),W(e("input",{"onUpdate:modelValue":u[0]||(u[0]=i=>w.value=i),type:"text",placeholder:"Search apps...",class:o(["w-full px-3 py-2 rounded-lg text-base outline-none transition-colors",t(l)?"bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10":"bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5"])},null,2),[[Q,w.value]]),e("div",Jl,[(s(),n(I,null,B(b,i=>e("button",{key:i.value,class:o(["text-xs px-2 py-1 rounded-md transition-all duration-150",g.value===i.value?"nav-tab-active":t(l)?"text-white/40 hover:text-white/70 hover:bg-white/5":"text-gray-500 hover:text-gray-800 hover:bg-black/5"]),onClick:r=>g.value=g.value===i.value?null:i.value},d(i.label),11,Zl)),64))])],4),e("div",Xl,[e("div",eo,[(s(!0),n(I,null,B(C.value,i=>(s(),n("button",{key:i.id,class:o(["w-full text-left p-3 rounded-xl transition-all duration-200 flex items-start gap-3",t(l)?"bg-white/5 hover:bg-white/10":"bg-black/3 hover:bg-black/5"]),"aria-label":i.name,onClick:r=>f.$emit("selectApp",i)},[e("div",{class:"w-10 h-10 rounded-xl flex items-center justify-center text-lg font-bold shrink-0",style:G({background:_(i.id)})},[e("span",so,d(i.name.charAt(0)),1)],4),e("div",no,[e("div",lo,[e("p",{class:o(["text-xs font-semibold truncate",t(l)?"text-white/90":"text-gray-900"])},d(i.name),3),e("span",{class:o(["text-xs px-1.5 py-0.5 rounded font-medium shrink-0",t(l)?"bg-white/10 text-white/50":"bg-black/5 text-gray-500"])},d(p(i.category)),3)]),e("p",{class:o(["text-xs mt-0.5 line-clamp-2",t(l)?"text-white/50":"text-gray-500"])},d(i.description),3),e("div",oo,[(s(!0),n(I,null,B(i.platforms,r=>(s(),n("span",{key:r,class:o(["text-xs px-1 py-0.5 rounded",t(l)?"bg-white/5 text-white/30":"bg-black/3 text-gray-400"])},d(v(r)),3))),128))])])],10,to))),128))]),C.value.length===0?(s(),n("div",ao,[e("p",{class:o(["text-sm",t(l)?"text-white/30":"text-gray-400"])}," No apps match your search ",2)])):m("",!0)])]))}}),ro={class:"group/node"},co={key:0,"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"},uo={key:1,"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"},xo={class:"truncate flex-1"},ho={key:0,class:"w-2.5 h-2.5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},po={key:0,class:"w-2.5 h-2.5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},go={key:0},vo=q({__name:"FileTreeNode",props:{entry:{},activeFile:{},depth:{}},emits:["select","toggle-context"],setup(a,{emit:c}){const l=a,{isFileSelected:w}=pe(),g=c,{isDark:b}=J(),p=M(l.depth<1),v=L(()=>!l.entry.isDirectory&&l.activeFile===l.entry.path),_=L(()=>!l.entry.isDirectory&&w(l.entry.path)),C=L(()=>l.entry.isDirectory&&w(l.entry.path));function f(){l.entry.isDirectory?p.value=!p.value:g("select",l.entry.path)}function u(){g("toggle-context",l.entry.path)}function i(){g("toggle-context",l.entry.path)}return(r,x)=>{const S=Jt("FileTreeNode",!0);return s(),n("div",ro,[e("div",{class:o(["w-full flex items-center gap-1.5 py-1 px-2 rounded-lg text-xs transition-colors cursor-pointer",[v.value?t(b)?"bg-white/10 text-white/90":"bg-black/8 text-gray-900":t(b)?"text-white/60 hover:bg-white/[0.04] hover:text-white/80":"text-gray-600 hover:bg-black/[0.03] hover:text-gray-800"]]),style:G({paddingLeft:`${a.depth*12+8}px`}),onClick:f},[a.entry.isDirectory?(s(),n("svg",{key:0,class:o(["w-3 h-3 shrink-0 transition-transform duration-150",p.value?"rotate-90":""]),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[...x[2]||(x[2]=[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M9 5l7 7-7 7"},null,-1)])],2)):m("",!0),(s(),n("svg",{class:o(["w-3.5 h-3.5 shrink-0",a.entry.isDirectory?"text-accent/70":t(b)?"text-white/30":"text-gray-400"]),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[a.entry.isDirectory?(s(),n("path",co)):(s(),n("path",uo))],2)),e("span",xo,d(a.entry.name),1),a.entry.isDirectory?m("",!0):(s(),n("button",{key:1,class:o(["shrink-0 w-4 h-4 rounded-full border flex items-center justify-center transition-all ml-auto",[_.value?"bg-accent border-accent text-white":t(b)?"border-white/20 opacity-0 group-hover/node:opacity-100 hover:border-white/40":"border-black/15 opacity-0 group-hover/node:opacity-100 hover:border-black/30"]]),"aria-label":"Toggle file for chat context",onClick:he(u,["stop"])},[_.value?(s(),n("svg",ho,[...x[3]||(x[3]=[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"3",d:"M5 13l4 4L19 7"},null,-1)])])):m("",!0)],2)),a.entry.isDirectory?(s(),n("button",{key:2,class:o(["shrink-0 w-4 h-4 rounded-full border flex items-center justify-center transition-all ml-auto",[C.value?"bg-accent border-accent text-white":t(b)?"border-white/20 opacity-0 group-hover/node:opacity-100 hover:border-white/40":"border-black/15 opacity-0 group-hover/node:opacity-100 hover:border-black/30"]]),"aria-label":"Add folder to chat context",onClick:he(i,["stop"])},[C.value?(s(),n("svg",po,[...x[4]||(x[4]=[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"3",d:"M5 13l4 4L19 7"},null,-1)])])):m("",!0)],2)):m("",!0)],6),a.entry.isDirectory&&p.value&&a.entry.children?(s(),n("div",go,[(s(!0),n(I,null,B(a.entry.children,j=>(s(),E(S,{key:j.path,entry:j,"active-file":a.activeFile,depth:a.depth+1,onSelect:x[0]||(x[0]=P=>r.$emit("select",P)),onToggleContext:x[1]||(x[1]=P=>r.$emit("toggle-context",P))},null,8,["entry","active-file","depth"]))),128))])):m("",!0)])}}}),bo={class:"flex flex-col h-full"},fo={class:"flex items-center gap-1 min-w-0 flex-1"},mo={class:"flex items-center gap-2 shrink-0"},wo={key:0,class:"flex-1 overflow-y-auto custom-scrollbar p-3"},yo={class:"mb-3 flex gap-2"},ko={class:"flex justify-end gap-2"},$o=["disabled"],_o={class:"grid grid-cols-2 gap-2"},Co=["onClick"],So={key:1,class:"flex-1 overflow-y-auto custom-scrollbar p-2"},jo={key:0,class:"flex items-center justify-center py-12"},Mo=q({__name:"ProjectGrid",props:{isWideDesktop:{type:Boolean},isMobile:{type:Boolean}},setup(a){const{isDark:c}=J(),{projectList:l,activeProject:w,fileTree:g,activeFile:b,codeMode:p,selectedFiles:v,selectProject:_,openFile:C,createProject:f,clearActiveFile:u,toggleFileSelection:i,isFileSelected:r,loadProjects:x}=pe();le(()=>{l.value.length===0&&x()});const S=M(""),j=M(!1),P=M(""),D=M(null),y=L(()=>w.value?"filetree":"projects"),k=L(()=>y.value==="projects"?"Projects":w.value?.name??"Projects"),h=L(()=>{const V=S.value.toLowerCase();return V?l.value.filter(H=>H.name.toLowerCase().includes(V)||(H.language??"").toLowerCase().includes(V)):l.value});function $(V){_(V)}function N(){const{activeProject:V,fileTree:H}=pe();V.value=null,H.value=[],u()}function U(V){C(V)}function F(V){i(V)}function K(){j.value=!0,P.value="",ye(()=>D.value?.focus())}function O(){j.value=!1,P.value=""}function Z(){const V=P.value.trim();V&&(f(V),j.value=!1,P.value="")}return(V,H)=>(s(),n("div",bo,[e("div",{class:"shrink-0 px-4 py-3 flex items-center justify-between gap-2",style:G(t(c)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("div",fo,[y.value!=="projects"?(s(),n("button",{key:0,class:o(["text-xs shrink-0 transition-colors",t(c)?"text-white/40 hover:text-white/70 hover:underline":"text-gray-400 hover:text-gray-700 hover:underline"]),onClick:N}," Projects ",2)):m("",!0),y.value!=="projects"?(s(),n("span",{key:1,class:o(["text-xs shrink-0",t(c)?"text-white/20":"text-gray-300"])},"/",2)):m("",!0),e("span",{class:o(["text-sm font-semibold truncate",t(c)?"text-white/90":"text-gray-900"])},d(k.value),3)]),e("div",mo,[y.value==="projects"?(s(),n("p",{key:0,class:o(["text-xs",t(c)?"text-white/30":"text-gray-400"])},d(t(l).length)+" repos ",3)):y.value==="filetree"?(s(),n("p",{key:1,class:o(["text-xs",t(c)?"text-white/30":"text-gray-400"])},d(t(w)?.language),3)):m("",!0),ie(V.$slots,"header-actions")])],4),y.value==="projects"?(s(),n("div",wo,[e("div",yo,[W(e("input",{"onUpdate:modelValue":H[0]||(H[0]=X=>S.value=X),type:"text",placeholder:"Search projects...",class:o(["flex-1 min-w-0 px-3 py-2 rounded-lg text-base bg-transparent outline-none",t(c)?"text-white/80 placeholder:text-white/20 border border-white/10 focus:border-white/25":"text-gray-800 placeholder:text-gray-400 border border-black/10 focus:border-black/20"])},null,2),[[Q,S.value]]),e("button",{class:o(["shrink-0 px-3 py-2 rounded-lg text-xs font-medium transition-colors flex items-center gap-1.5",t(c)?"bg-accent/20 text-accent hover:bg-accent/30":"bg-accent/10 text-accent hover:bg-accent/20"]),onClick:K},[...H[2]||(H[2]=[e("svg",{class:"w-3.5 h-3.5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M12 4v16m8-8H4"})],-1),ne(" New ",-1)])],2)]),j.value?(s(),n("div",{key:0,class:o(["mb-3 p-3 rounded-xl",t(c)?"bg-white/[0.05] border border-white/10":"bg-black/[0.03] border border-black/8"])},[e("p",{class:o(["text-xs font-medium mb-2",t(c)?"text-white/70":"text-gray-700"])}," New Project ",2),W(e("input",{ref_key:"newProjectInputRef",ref:D,"onUpdate:modelValue":H[1]||(H[1]=X=>P.value=X),type:"text",placeholder:"Project name...",class:o(["w-full px-3 py-2 rounded-lg text-base bg-transparent outline-none mb-2",t(c)?"text-white/80 placeholder:text-white/20 border border-white/10 focus:border-white/25":"text-gray-800 placeholder:text-gray-400 border border-black/10 focus:border-black/20"]),onKeydown:[ae(Z,["enter"]),ae(O,["escape"])]},null,34),[[Q,P.value]]),e("div",ko,[e("button",{class:o(["text-xs px-2.5 py-1 rounded-lg transition-colors",t(c)?"text-white/40 hover:text-white/70":"text-gray-500 hover:text-gray-800"]),onClick:O}," Cancel ",2),e("button",{class:o(["text-xs px-2.5 py-1 rounded-lg font-medium transition-colors",t(c)?"bg-accent/20 text-accent hover:bg-accent/30":"bg-accent/10 text-accent hover:bg-accent/20"]),disabled:!P.value.trim(),onClick:Z}," Create ",10,$o)])],2)):m("",!0),e("div",_o,[(s(!0),n(I,null,B(h.value,X=>(s(),n("button",{key:X.path,class:o(["text-left p-3 rounded-xl transition-all duration-150",t(c)?"bg-white/[0.03] hover:bg-white/[0.07] border border-white/5":"bg-black/[0.02] hover:bg-black/[0.05] border border-black/5"]),onClick:ge=>$(X)},[e("div",{class:o(["w-8 h-8 rounded-lg flex items-center justify-center mb-2",t(c)?"bg-white/5":"bg-black/5"])},[(s(),n("svg",{class:o(["w-4 h-4",X.isGit?"text-accent":t(c)?"text-white/40":"text-gray-400"]),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[...H[3]||(H[3]=[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"},null,-1)])],2))],2),e("p",{class:o(["text-xs font-medium truncate",t(c)?"text-white/80":"text-gray-800"])},d(X.name),3),e("p",{class:o(["text-xs mt-0.5 truncate",t(c)?"text-white/25":"text-gray-400"])},d(X.language),3)],10,Co))),128))])])):y.value==="filetree"?(s(),n("div",So,[(s(!0),n(I,null,B(t(g),X=>(s(),E(vo,{key:X.path,entry:X,"active-file":t(b),depth:0,onSelect:U,onToggleContext:F},null,8,["entry","active-file"]))),128)),t(g).length===0?(s(),n("div",jo,[e("p",{class:o(["text-xs",t(c)?"text-white/30":"text-gray-400"])}," Loading file tree... ",2)])):m("",!0)])):m("",!0)]))}}),To={class:"flex flex-col h-full"},Do={class:"shrink-0 px-4 py-2 flex gap-1.5 overflow-x-auto scrollbar-hide"},Lo=["onClick"],Io={class:"flex-1 overflow-y-auto px-4 py-3"},Bo={class:"grid grid-cols-2 gap-2"},Po=["onClick"],No=["onClick"],Ao={key:0,class:"w-3 h-3 text-white",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},zo={key:2,class:"h-8 flex items-end gap-0.5 mb-2"},Fo={key:3,class:"h-8 flex items-center mb-2"},Eo={key:0,"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"},Ro={key:1,"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"},Vo={key:2,"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"},Uo={key:3,"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01"},qo=q({__name:"DesignSystemGrid",setup(a){const{isDark:c}=J(),{openDesignSystemItem:l}=$e(),{codeMode:w,toggleDesignToken:g,isDesignTokenSelected:b}=pe(),p=M("all"),v=[{id:"all",label:"All"},{id:"colors",label:"Colors"},{id:"typography",label:"Typography"},{id:"spacing",label:"Spacing"},{id:"atoms",label:"Atoms"},{id:"molecules",label:"Molecules"},{id:"organisms",label:"Organisms"}],_=[{id:"color-bg",name:"Background",category:"colors",preview:"inline",description:"Primary app background",code:`background-color: #0a0a0a; /* Tailwind: bg-[#0a0a0a] */`,usedIn:"ChatPage, all panels, base layout"},{id:"color-accent",name:"Accent / Bitcoin",category:"colors",preview:"inline",description:"Primary action color, Bitcoin orange",code:`color: #F7931A; /* Tailwind: text-accent */`,usedIn:"Gradient buttons, active tabs, zap counts, CTA elements"},{id:"color-primary",name:"Primary",category:"colors",preview:"inline",description:"Primary neutral tone",code:`color: #606060; /* Tailwind: text-primary */`,usedIn:"Secondary text, borders, muted elements"},{id:"color-surface",name:"Glass Surface",category:"colors",preview:"inline",description:"Glass morphism panel background",code:`background: rgba(0, 0, 0, 0.35); @@ -238,7 +238,7 @@ rounded-full /* pill buttons */`,usedIn:"Badges (md), buttons (lg), cards (xl), opacity: 1; transform: scale(1); } -}`,usedIn:"Modal entries, tooltip appearances, popovers"}],C=L(()=>p.value==="all"?_:_.filter(i=>i.category===p.value));function f(i){l(i)}function u(i){const r=/(?:background-color|color|background):\s*([^;]+)/i.exec(i);if(!r)return"#333";const x=r[1].trim();return x.startsWith("#")||x.startsWith("rgb")||x.startsWith("hsl")?x:"#333"}return(i,r)=>(s(),n("div",To,[e("div",{class:"shrink-0 px-4 py-3 flex items-center justify-between gap-2",style:G(t(c)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("span",{class:o(["text-sm font-semibold",t(c)?"text-white/90":"text-gray-900"])}," Design System ",2),e("p",{class:o(["text-xs",t(c)?"text-white/30":"text-gray-400"])},d(C.value.length)+" items ",3)],4),e("div",Do,[(s(),n(I,null,B(v,x=>e("button",{key:x.id,class:o(["text-xs px-2.5 py-1 rounded-md font-medium whitespace-nowrap transition-colors",p.value===x.id?"bg-accent/20 text-accent":t(c)?"bg-white/5 text-white/50 hover:bg-white/10":"bg-black/5 text-gray-500 hover:bg-black/10"]),onClick:S=>p.value=x.id},d(x.label),11,Lo)),64))]),e("div",Io,[e("div",Bo,[(s(!0),n(I,null,B(C.value,x=>(s(),n("button",{key:x.id,class:o(["text-left p-3 rounded-xl transition-all duration-150 group relative",[t(w)&&t(b)(x.id)?"ring-2 ring-accent/50 bg-accent/10 cursor-pointer":t(c)?"bg-white/[0.03] hover:bg-white/[0.07] cursor-pointer":"bg-black/[0.02] hover:bg-black/[0.05] cursor-pointer"]]),onClick:S=>f(x)},[t(w)?(s(),n("div",{key:0,class:o(["absolute top-2 right-2 min-w-[44px] min-h-[44px] rounded-full flex items-center justify-center z-10 cursor-pointer transition-colors",t(b)(x.id)?"bg-accent":t(c)?"bg-white/10 hover:bg-white/20":"bg-black/10 hover:bg-black/20"]),onClick:he(S=>t(g)(x.id),["stop"])},[t(b)(x.id)?(s(),n("svg",Ao,[...r[0]||(r[0]=[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"3",d:"M5 13l4 4L19 7"},null,-1)])])):m("",!0)],10,No)):m("",!0),x.category==="colors"&&x.preview==="inline"?(s(),n("div",{key:1,class:o(["h-8 rounded-md mb-2 border",t(c)?"border-white/10":"border-black/10"]),style:G({background:u(x.code)})},null,6)):x.category==="spacing"&&x.preview==="inline"?(s(),n("div",zo,[...r[1]||(r[1]=[e("div",{class:"bg-accent/40 rounded-sm",style:{width:"4px",height:"30%"}},null,-1),e("div",{class:"bg-accent/40 rounded-sm",style:{width:"4px",height:"50%"}},null,-1),e("div",{class:"bg-accent/40 rounded-sm",style:{width:"4px",height:"70%"}},null,-1),e("div",{class:"bg-accent/40 rounded-sm",style:{width:"4px",height:"100%"}},null,-1)])])):(s(),n("div",Fo,[(s(),n("svg",{class:o(["w-5 h-5 transition-colors",t(c)?"text-white/20 group-hover:text-white/40":"text-black/15 group-hover:text-black/30"]),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[x.category==="atoms"?(s(),n("path",Eo)):x.category==="molecules"?(s(),n("path",Ro)):x.category==="organisms"?(s(),n("path",Vo)):(s(),n("path",Uo))],2))])),e("h3",{class:o(["text-xs font-semibold leading-tight mb-0.5",t(c)?"text-white/80":"text-gray-800"])},d(x.name),3),e("p",{class:o(["text-xs leading-snug line-clamp-2",t(c)?"text-white/40":"text-gray-400"])},d(x.description),3)],10,Po))),128))])])]))}}),we=M(null),it=M(!1),qe=M(!1),xe=M(null);function fe(){const a=L(()=>{if(!we.value)return null;try{return Ye(we.value)}catch{return null}}),c=L(()=>!!we.value),l=L(()=>a.value?a.value.slice(0,12)+"..."+a.value.slice(-8):null);function w(){it.value=typeof window<"u"&&!!window.nostr}async function g(){if(xe.value=null,!window.nostr){xe.value="No Nostr extension detected. Install nos2x, Alby, or another NIP-07 extension.";return}qe.value=!0;try{const v=await window.nostr.getPublicKey();we.value=v}catch(v){xe.value=v instanceof Error?v.message:"Failed to get public key"}finally{qe.value=!1}}async function b(v){if(xe.value=null,!window.nostr)return xe.value="No Nostr extension detected",null;try{return await window.nostr.signEvent(v)}catch(_){return xe.value=_ instanceof Error?_.message:"Failed to sign event",null}}function p(){we.value=null,xe.value=null}return le(()=>{w(),setTimeout(w,500)}),{pubkey:we,npub:a,isAvailable:it,isLoggedIn:c,isLoading:qe,error:xe,truncatedNpub:l,login:g,logout:p,signEvent:b,checkAvailability:w}}const Go="aiui-nostr-dms",Oo=1,ke="messages",Se=M([]),je=M(null),Ge=M(!1);let Me=null;function wt(){return Me||(Me=new Promise((a,c)=>{const l=indexedDB.open(Go,Oo);l.onupgradeneeded=()=>{const w=l.result;if(!w.objectStoreNames.contains(ke)){const g=w.createObjectStore(ke,{keyPath:"id"});g.createIndex("contact","contactPubkey",{unique:!1}),g.createIndex("created_at","created_at",{unique:!1})}},l.onsuccess=()=>a(l.result),l.onerror=()=>{Me=null,c(l.error)}}),Me)}function Ho(a){return a.length<=12?a:a.slice(0,8)+"..."+a.slice(-4)}async function rt(a,c){const l=await wt(),w=a.fromPubkey===c?a.toPubkey:a.fromPubkey,g={...a,contactPubkey:w};return new Promise((b,p)=>{const v=l.transaction(ke,"readwrite");v.objectStore(ke).put(g),v.oncomplete=()=>b(),v.onerror=()=>p(v.error)})}async function Oe(){const a=await wt();return new Promise((c,l)=>{const g=a.transaction(ke,"readonly").objectStore(ke).getAll();g.onsuccess=()=>c(g.result),g.onerror=()=>l(g.error)})}function He(a){const c=new Map;for(const w of a){const g=c.get(w.contactPubkey)??[];g.push(w),c.set(w.contactPubkey,g)}const l=[];for(const[w,g]of c)g.sort((b,p)=>b.created_at-p.created_at),l.push({contactPubkey:w,contactName:Ho(w),messages:g,lastMessage:g[g.length-1]??null,unread:0});return l.sort((w,g)=>(g.lastMessage?.created_at??0)-(w.lastMessage?.created_at??0)),l}function Wo(){const{pubkey:a,isLoggedIn:c}=fe(),l=L(()=>je.value?Se.value.find(_=>_.contactPubkey===je.value)??null:null);async function w(){if(c.value){Ge.value=!0;try{const _=await Oe();Se.value=He(_)}catch{}finally{Ge.value=!1}}}async function g(_,C){if(!window.nostr?.nip04||!a.value)return!1;try{const f=await window.nostr.nip04.encrypt(_,C),u={kind:4,created_at:Math.floor(Date.now()/1e3),tags:[["p",_]],content:f},i=await window.nostr.signEvent(u);if(!i)return!1;const r={id:i.id,fromPubkey:a.value,toPubkey:_,content:C,created_at:i.created_at,decrypted:!0};await rt(r,a.value);const{publishEvent:x}=await bt(()=>import("./useNostr-zyhtrXba.js"),__vite__mapDeps([0,1,2])).then(j=>j.useNostr());await x(i);const S=await Oe();return Se.value=He(S),!0}catch{return!1}}async function b(_,C,f,u){if(!(!window.nostr?.nip04||!a.value))try{const i=await window.nostr.nip04.decrypt(C,f),r={id:_,fromPubkey:C,toPubkey:a.value,content:i,created_at:u,decrypted:!0};await rt(r,a.value);const x=await Oe();Se.value=He(x)}catch{}}function p(_){je.value=_}function v(){je.value=null}return{threads:Se,activeThread:l,activeContact:je,isLoading:Ge,loadDMs:w,sendDM:g,receiveDM:b,selectContact:p,clearActiveContact:v}}const Ko={class:"h-full flex flex-col"},Yo={class:"flex items-center gap-2 px-4 py-3 border-b border-white/[0.08]"},Qo={class:"flex-1 min-w-0"},Jo={class:"text-xs font-semibold text-white/80 truncate"},Zo={class:"text-xs text-white/30 font-mono truncate"},Xo={class:"text-xs leading-relaxed break-words"},ea={class:"text-xs mt-1 text-white/25 tabular-nums"},ta={class:"px-4 py-3 border-t border-white/[0.08]"},sa={class:"flex gap-2"},na=["disabled"],la={class:"p-4 border-b border-white/[0.08]"},oa={class:"flex items-center justify-between gap-2 mb-3"},aa={key:0,class:"space-y-2 mb-3"},ia=["disabled"],ra={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-3 pb-16 space-y-1"},ca={key:0,class:"flex items-center justify-center py-12"},da={key:1,class:"flex items-center justify-center py-12"},ua={key:2,class:"flex items-center justify-center py-12"},xa=["onClick"],ha={class:"flex items-start gap-2.5"},pa={class:"w-8 h-8 rounded-full shrink-0 flex items-center justify-center text-xs font-bold bg-accent/20 text-accent"},ga={class:"flex-1 min-w-0"},va={class:"flex items-center gap-1.5"},ba={class:"text-xs font-semibold truncate text-white/80"},fa={key:0,class:"text-xs ml-auto shrink-0 text-white/20"},ma={key:0,class:"text-xs mt-1 text-white/40 truncate"},wa=q({__name:"NostrDMs",setup(a){const{threads:c,activeThread:l,activeContact:w,isLoading:g,loadDMs:b,sendDM:p,selectContact:v,clearActiveContact:_}=Wo(),{pubkey:C,isLoggedIn:f}=fe(),u=M(""),i=M(!1),r=M(null),x=M(!1),S=M("");function j(k){const h=new Date(k*1e3),N=Math.floor((new Date().getTime()-h.getTime())/864e5);return N===0?h.toLocaleTimeString("en",{hour:"2-digit",minute:"2-digit"}):N<7?h.toLocaleDateString("en",{weekday:"short"}):h.toLocaleDateString("en",{month:"short",day:"numeric"})}async function P(){if(!u.value.trim()||i.value||!w.value)return;i.value=!0,await p(w.value,u.value.trim())&&(u.value="",await ye(),D()),i.value=!1}function D(){r.value&&(r.value.scrollTop=r.value.scrollHeight)}function y(){let k=S.value.trim();if(k.startsWith("npub"))try{k=ft(k)}catch{return}k.length===64&&(v(k),x.value=!1,S.value="")}return ce(w,async()=>{await ye(),D()}),le(()=>{b()}),(k,h)=>(s(),n("div",Ko,[t(l)?(s(),n(I,{key:0},[e("div",Yo,[e("button",{class:"min-w-[44px] min-h-[44px] flex items-center justify-center rounded-lg text-white/60 hover:text-white/80 hover:bg-white/10 transition-colors",onClick:h[0]||(h[0]=(...$)=>t(_)&&t(_)(...$))},[...h[4]||(h[4]=[e("svg",{class:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M15 19l-7-7 7-7"})],-1)])]),e("div",Qo,[e("p",Jo,d(t(l).contactName),1),e("p",Zo,d(t(l).contactPubkey),1)])]),e("div",{ref_key:"messagesRef",ref:r,class:"flex-1 overflow-y-auto custom-scrollbar px-4 py-3 space-y-2"},[(s(!0),n(I,null,B(t(l).messages,$=>(s(),n("div",{key:$.id,class:o(["flex",$.fromPubkey===t(C)?"justify-end":"justify-start"])},[e("div",{class:o(["max-w-[80%] rounded-xl px-3 py-2",$.fromPubkey===t(C)?"bg-accent/15 text-white/80":"bg-white/5 text-white/70"])},[e("p",Xo,d($.content),1),e("p",ea,d(j($.created_at)),1)],2)],2))),128))],512),e("div",ta,[e("div",sa,[W(e("input",{"onUpdate:modelValue":h[1]||(h[1]=$=>u.value=$),type:"text",placeholder:"Type a message...",class:"flex-1 px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors",onKeydown:ae(P,["enter"])},null,544),[[Q,u.value]]),e("button",{class:"px-3 py-2 rounded-lg text-xs bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30",disabled:!u.value.trim()||i.value,onClick:P}," Send ",8,na)])])],64)):(s(),n(I,{key:1},[e("div",la,[e("div",oa,[h[5]||(h[5]=e("h3",{class:"text-sm font-bold text-white/90"},"Messages",-1)),e("button",{class:"text-xs px-2.5 py-1 rounded bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors",onClick:h[2]||(h[2]=$=>x.value=!x.value)},d(x.value?"Cancel":"New"),1)]),x.value?(s(),n("div",aa,[W(e("input",{"onUpdate:modelValue":h[3]||(h[3]=$=>S.value=$),type:"text",placeholder:"Recipient hex pubkey or npub...",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"},null,512),[[Q,S.value]]),e("button",{class:"text-xs px-2.5 py-1 rounded bg-white/5 text-white/60 hover:bg-white/10 transition-colors disabled:opacity-30",disabled:!S.value.trim(),onClick:y}," Start conversation ",8,ia)])):m("",!0)]),e("div",ra,[t(f)?t(g)?(s(),n("div",da,[...h[7]||(h[7]=[e("p",{class:"text-xs text-white/30"},"Loading messages...",-1)])])):t(c).length===0?(s(),n("div",ua,[...h[8]||(h[8]=[e("p",{class:"text-xs text-white/30"},"No messages yet",-1)])])):m("",!0):(s(),n("div",ca,[...h[6]||(h[6]=[e("p",{class:"text-xs text-white/30"},"Sign in with Nostr to use DMs",-1)])])),(s(!0),n(I,null,B(t(c),$=>(s(),n("button",{key:$.contactPubkey,class:"w-full text-left p-3 rounded-xl transition-all duration-150 bg-white/[0.03] hover:bg-white/[0.07] border border-white/5",onClick:N=>t(v)($.contactPubkey)},[e("div",ha,[e("div",pa,d($.contactName.charAt(0).toUpperCase()),1),e("div",ga,[e("div",va,[e("span",ba,d($.contactName),1),$.lastMessage?(s(),n("span",fa,d(j($.lastMessage.created_at)),1)):m("",!0)]),$.lastMessage?(s(),n("p",ma,d($.lastMessage.content),1)):m("",!0)])])],8,xa))),128))])],64))]))}}),ya={class:"h-full flex flex-col"},ka={class:"p-4 border-b border-white/[0.08]"},$a={class:"flex gap-2"},_a=["disabled"],Ca={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-3 pb-16 space-y-2"},Sa={class:"flex items-center gap-2"},ja={class:"text-xs font-mono text-white/70 truncate flex-1"},Ma={class:"flex items-center gap-2 flex-wrap"},Ta=["onClick"],Da=["onClick"],La=["disabled","onClick"],Ia=["onClick"],Ba={key:0,class:"mt-4 pt-4 border-t border-white/5"},Pa=["disabled"],Na={key:0,class:"text-xs mt-1 text-white/30"},Aa=q({__name:"NostrRelayManager",setup(a){const{relayStates:c,addRelay:l,removeRelay:w,toggleRelayRead:g,toggleRelayWrite:b,testRelay:p,importNIP65Relays:v,fetchNote:_}=Le(),{isLoggedIn:C,pubkey:f}=fe(),u=M(""),i=M(null),r=Pe({}),x=M(!1),S=M("");function j(){let y=u.value.trim();y&&(!y.startsWith("wss://")&&!y.startsWith("ws://")&&(y="wss://"+y),l(y),u.value="")}async function P(y){i.value=y;const k=await p(y);r[y]=k,i.value=null}async function D(){if(!f.value)return;x.value=!0,S.value="Fetching relay list...";const y=await _(f.value,5e3);y?(v({id:y.id,pubkey:y.pubkey,kind:10002,content:y.content,created_at:y.created_at,tags:y.tags,sig:""}),S.value="Imported relays from NIP-65"):S.value="No NIP-65 relay list found",x.value=!1}return(y,k)=>(s(),n("div",ya,[e("div",ka,[k[1]||(k[1]=e("h3",{class:"text-sm font-bold text-white/90 mb-3"},"Relay Management",-1)),e("div",$a,[W(e("input",{"onUpdate:modelValue":k[0]||(k[0]=h=>u.value=h),type:"text",placeholder:"wss://relay.example.com",class:"flex-1 px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono",onKeydown:ae(j,["enter"])},null,544),[[Q,u.value]]),e("button",{class:"px-4 min-h-[44px] rounded-lg text-sm bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30",disabled:!u.value.trim(),onClick:j}," Add ",8,_a)])]),e("div",Ca,[(s(!0),n(I,null,B(t(c),h=>(s(),n("div",{key:h.url,class:"rounded-xl bg-white/[0.03] border border-white/5 p-3 space-y-2"},[e("div",Sa,[e("span",{class:o(["w-2 h-2 rounded-full shrink-0",h.connected?"bg-emerald-500":"bg-red-400/60"])},null,2),e("span",ja,d(h.url),1),h.latencyMs!==null?(s(),n("span",{key:0,class:o(["text-xs tabular-nums shrink-0",h.latencyMs<200?"text-emerald-400/60":h.latencyMs<500?"text-yellow-400/60":"text-red-400/60"])},d(h.latencyMs)+"ms ",3)):m("",!0),e("span",{class:o(["text-xs shrink-0",h.connected?"text-emerald-400/60":"text-red-400/60"])},d(h.connected?"Connected":"Disconnected"),3)]),e("div",Ma,[e("button",{class:o(["text-sm px-3 min-h-[44px] rounded-lg transition-colors",h.read?"bg-accent/15 text-accent/80":"bg-white/5 text-white/30 hover:text-white/50"]),onClick:$=>t(g)(h.url)}," Read ",10,Ta),e("button",{class:o(["text-sm px-3 min-h-[44px] rounded-lg transition-colors",h.write?"bg-accent/15 text-accent/80":"bg-white/5 text-white/30 hover:text-white/50"]),onClick:$=>t(b)(h.url)}," Write ",10,Da),k[2]||(k[2]=e("div",{class:"flex-1"},null,-1)),e("button",{class:"text-sm px-3 min-h-[44px] rounded-lg bg-white/5 text-white/30 hover:text-white/50 transition-colors",disabled:i.value===h.url,onClick:$=>P(h.url)},d(i.value===h.url?"Testing...":"Test"),9,La),e("button",{class:"text-sm px-3 min-h-[44px] rounded-lg bg-white/5 text-red-400/50 hover:text-red-400/80 hover:bg-red-400/10 transition-colors",onClick:$=>t(w)(h.url)}," Remove ",8,Ia)]),r[h.url]!==void 0?(s(),n("p",{key:0,class:o(["text-xs",r[h.url]!==null?"text-emerald-400/60":"text-red-400/60"])},d(r[h.url]!==null?`Reachable (${r[h.url]}ms)`:"Unreachable"),3)):m("",!0)]))),128)),t(C)?(s(),n("div",Ba,[e("button",{class:"w-full text-left px-3 min-h-[44px] rounded-lg text-sm bg-white/5 text-white/40 hover:text-white/60 hover:bg-white/10 transition-colors",disabled:x.value,onClick:D},d(x.value?"Importing...":"Import relays from NIP-65 (kind:10002)"),9,Pa),S.value?(s(),n("p",Na,d(S.value),1)):m("",!0)])):m("",!0)])]))}}),za={class:"h-full flex flex-col"},Fa={key:0,class:"flex-1 flex items-center justify-center"},Ea={key:1,class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-3 pb-16 space-y-4"},Ra={class:"rounded-xl overflow-hidden border border-white/5"},Va={class:"px-4 pb-4 -mt-8"},Ua={key:0,class:"text-lg font-bold text-accent"},qa={class:"text-sm font-bold text-white/90 mt-2"},Ga={key:0,class:"text-xs text-purple-400/60"},Oa={key:1,class:"text-xs text-white/50 mt-1 line-clamp-2"},Ha={class:"space-y-3"},Wa=["disabled"],Ka=q({__name:"NostrProfileEditor",setup(a){const{isLoggedIn:c,signEvent:l,pubkey:w}=fe(),{publishEvent:g,fetchNote:b}=Le(),p=Pe({name:"",display_name:"",about:"",picture:"",banner:"",website:"",nip05:"",lud16:""}),v=M(!1),_=M(""),C=M(!1);async function f(){if(!w.value)return;const i=await b(w.value,5e3);if(i&&i.kind===0)try{const r=JSON.parse(i.content);Object.assign(p,r)}catch{}}async function u(){if(!c.value)return;v.value=!0,_.value="";const i={};for(const[P,D]of Object.entries(p))D&&(i[P]=D);const r={kind:0,created_at:Math.floor(Date.now()/1e3),tags:[],content:JSON.stringify(i)},x=await l(r);if(!x){v.value=!1,_.value="Signing failed",C.value=!1;return}const S=await g(x),j=S.filter(P=>P.success).length;v.value=!1,j>0?(_.value=`Published to ${j}/${S.length} relays`,C.value=!0):(_.value="Failed to publish to any relay",C.value=!1)}return le(()=>{f()}),(i,r)=>(s(),n("div",za,[r[17]||(r[17]=e("div",{class:"p-4 border-b border-white/[0.08]"},[e("h3",{class:"text-sm font-bold text-white/90"},"Nostr Profile")],-1)),t(c)?(s(),n("div",Ea,[e("div",Ra,[e("div",{class:o(["h-24 bg-cover bg-center",p.banner?"":"bg-gradient-to-r from-accent/20 to-purple-500/20"]),style:G(p.banner?{backgroundImage:`url(${p.banner})`}:{})},null,6),e("div",Va,[e("div",{class:o(["w-16 h-16 rounded-full border-2 border-black bg-cover bg-center flex items-center justify-center",p.picture?"":"bg-accent/20"]),style:G(p.picture?{backgroundImage:`url(${p.picture})`}:{})},[p.picture?m("",!0):(s(),n("span",Ua,d((p.display_name||p.name||"?").charAt(0).toUpperCase()),1))],6),e("p",qa,d(p.display_name||p.name||"Anonymous"),1),p.nip05?(s(),n("p",Ga,d(p.nip05),1)):m("",!0),p.about?(s(),n("p",Oa,d(p.about),1)):m("",!0)])]),e("div",Ha,[e("div",null,[r[9]||(r[9]=e("label",{class:"text-xs text-white/30 block mb-1"},"Display Name",-1)),W(e("input",{"onUpdate:modelValue":r[0]||(r[0]=x=>p.display_name=x),type:"text",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors",placeholder:"Your display name"},null,512),[[Q,p.display_name]])]),e("div",null,[r[10]||(r[10]=e("label",{class:"text-xs text-white/30 block mb-1"},"Username",-1)),W(e("input",{"onUpdate:modelValue":r[1]||(r[1]=x=>p.name=x),type:"text",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors",placeholder:"username"},null,512),[[Q,p.name]])]),e("div",null,[r[11]||(r[11]=e("label",{class:"text-xs text-white/30 block mb-1"},"Bio",-1)),W(e("textarea",{"onUpdate:modelValue":r[2]||(r[2]=x=>p.about=x),class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors resize-none min-h-[60px]",placeholder:"Tell the world about yourself"},null,512),[[Q,p.about]])]),e("div",null,[r[12]||(r[12]=e("label",{class:"text-xs text-white/30 block mb-1"},"Avatar URL",-1)),W(e("input",{"onUpdate:modelValue":r[3]||(r[3]=x=>p.picture=x),type:"url",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono",placeholder:"https://example.com/avatar.jpg"},null,512),[[Q,p.picture]])]),e("div",null,[r[13]||(r[13]=e("label",{class:"text-xs text-white/30 block mb-1"},"Banner URL",-1)),W(e("input",{"onUpdate:modelValue":r[4]||(r[4]=x=>p.banner=x),type:"url",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono",placeholder:"https://example.com/banner.jpg"},null,512),[[Q,p.banner]])]),e("div",null,[r[14]||(r[14]=e("label",{class:"text-xs text-white/30 block mb-1"},"Website",-1)),W(e("input",{"onUpdate:modelValue":r[5]||(r[5]=x=>p.website=x),type:"url",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono",placeholder:"https://example.com"},null,512),[[Q,p.website]])]),e("div",null,[r[15]||(r[15]=e("label",{class:"text-xs text-white/30 block mb-1"},"NIP-05 Address",-1)),W(e("input",{"onUpdate:modelValue":r[6]||(r[6]=x=>p.nip05=x),type:"text",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono",placeholder:"you@example.com"},null,512),[[Q,p.nip05]])]),e("div",null,[r[16]||(r[16]=e("label",{class:"text-xs text-white/30 block mb-1"},"Lightning Address",-1)),W(e("input",{"onUpdate:modelValue":r[7]||(r[7]=x=>p.lud16=x),type:"text",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono",placeholder:"you@getalby.com"},null,512),[[Q,p.lud16]])]),e("button",{class:"w-full min-h-[44px] rounded-lg text-sm font-medium bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30",disabled:v.value,onClick:u},d(v.value?"Publishing...":"Publish Profile (kind:0)"),9,Wa),_.value?(s(),n("div",{key:0,class:o(["text-xs text-center",C.value?"text-emerald-400/60":"text-red-400/60"])},d(_.value),3)):m("",!0)])])):(s(),n("div",Fa,[...r[8]||(r[8]=[e("p",{class:"text-xs text-white/30"},"Sign in with Nostr to edit your profile",-1)])]))]))}}),Ya={class:"relative glass-card w-[320px] max-w-[90vw] p-5 space-y-4 animate-scale-in"},Qa={class:"flex items-center justify-between"},Ja={class:"text-xs text-white/40 truncate font-mono"},Za={class:"flex gap-1.5 flex-wrap"},Xa=["onClick"],ei=["disabled"],ti={key:0,class:"space-y-2"},si={class:"flex justify-center"},ni={class:"flex gap-1"},li=["value"],oi=["href"],ai={key:1,class:"text-xs text-red-400/60 text-center"},ii=q({__name:"ZapDialog",props:{isOpen:{type:Boolean},targetName:{},lightningAddress:{}},emits:["close"],setup(a,{emit:c}){const l=a,w=c,g=M(null),b=M(null),p=[21,100,500,1e3,5e3,1e4],v=M(21),_=M(""),C=M(""),f=M(!1),u=M(""),i=M(!1),r=M(null);function x(k){return k>=1e3?`${(k/1e3).toFixed(k%1e3===0?0:1)}k`:String(k)}function S(){w("close"),C.value="",u.value="",_.value=""}async function j(){if(!(!l.lightningAddress||!v.value)){f.value=!0,u.value="",C.value="";try{const[k,h]=l.lightningAddress.split("@");if(!k||!h)throw new Error("Invalid Lightning address");const $=await fetch(`https://${h}/.well-known/lnurlp/${k}`);if(!$.ok)throw new Error("Failed to fetch LNURL");const N=await $.json();if(N.status==="ERROR")throw new Error(N.reason||"LNURL error");const U=v.value*1e3;if(U<(N.minSendable??0))throw new Error(`Minimum: ${Math.ceil((N.minSendable??0)/1e3)} sats`);if(U>(N.maxSendable??1/0))throw new Error(`Maximum: ${Math.floor((N.maxSendable??0)/1e3)} sats`);let F=N.callback;const K=F.includes("?")?"&":"?";F+=`${K}amount=${U}`,_.value&&(F+=`&comment=${encodeURIComponent(_.value)}`);const O=await fetch(F);if(!O.ok)throw new Error("Failed to get invoice");const Z=await O.json();if(Z.status==="ERROR")throw new Error(Z.reason||"Invoice error");C.value=Z.pr,await ye(),P(Z.pr)}catch(k){u.value=k instanceof Error?k.message:"Zap failed"}finally{f.value=!1}}}function P(k){const h=r.value;if(!h)return;const $=h.getContext("2d");if(!$)return;$.fillStyle="#1a1a1a",$.fillRect(0,0,200,200),$.fillStyle="#F7931A",$.font="10px monospace",$.textAlign="center";const N=[];for(let F=0;F{$.fillText(F,100,U+K*12)})}function D(){navigator.clipboard.writeText(C.value),i.value=!0,setTimeout(()=>{i.value=!1},2e3)}function y(k){const h=g.value;if(!h)return;const $=h.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');if($.length===0)return;const N=$[0],U=$[$.length-1];k.shiftKey&&document.activeElement===N?(k.preventDefault(),U.focus()):!k.shiftKey&&document.activeElement===U&&(k.preventDefault(),N.focus())}return ce(()=>l.isOpen,async k=>{k?(await ye(),b.value?.focus()):(C.value="",u.value="")}),(k,h)=>a.isOpen?(s(),n("div",{key:0,ref_key:"dialogRef",ref:g,role:"dialog","aria-modal":"true","aria-label":"Send zap",class:"fixed inset-0 z-50 flex items-center justify-center",onClick:he(S,["self"]),onKeydown:[ae(S,["escape"]),ae(y,["tab"])]},[e("div",{class:"absolute inset-0 bg-black/60 backdrop-blur-sm",onClick:S}),e("div",Ya,[e("div",Qa,[h[3]||(h[3]=e("h3",{class:"text-sm font-bold text-white/90"},"Zap",-1)),e("button",{ref_key:"closeButtonRef",ref:b,class:"min-w-[44px] min-h-[44px] flex items-center justify-center rounded text-white/40 hover:text-white/70 transition-colors","aria-label":"Close",onClick:S},[...h[2]||(h[2]=[e("svg",{class:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M6 18L18 6M6 6l12 12"})],-1)])],512)]),e("p",Ja,d(a.targetName),1),e("div",Za,[(s(),n(I,null,B(p,$=>e("button",{key:$,class:o(["text-xs px-2.5 py-1.5 rounded-lg transition-colors",v.value===$?"bg-accent/20 text-accent border border-accent/30":"bg-white/5 text-white/50 hover:bg-white/10"]),onClick:N=>v.value=$},d(x($)),11,Xa)),64))]),e("div",null,[h[4]||(h[4]=e("label",{class:"text-xs text-white/30 block mb-1"},"Amount (sats)",-1)),W(e("input",{"onUpdate:modelValue":h[0]||(h[0]=$=>v.value=$),type:"number",min:"1",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors tabular-nums",placeholder:"21"},null,512),[[Q,v.value,void 0,{number:!0}]])]),e("div",null,[h[5]||(h[5]=e("label",{class:"text-xs text-white/30 block mb-1"},"Message (optional)",-1)),W(e("input",{"onUpdate:modelValue":h[1]||(h[1]=$=>_.value=$),type:"text",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors",placeholder:"Great post!"},null,512),[[Q,_.value]])]),e("button",{class:"w-full py-2.5 rounded-lg text-xs font-medium bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30",disabled:!v.value||v.value<1||f.value,onClick:j},d(f.value?"Generating invoice...":`Zap ${x(v.value)} sats`),9,ei),C.value?(s(),n("div",ti,[h[6]||(h[6]=e("p",{class:"text-xs text-white/30 text-center"},"Scan or tap to pay",-1)),e("div",si,[e("canvas",{ref_key:"qrCanvas",ref:r,class:"rounded-lg",width:"200",height:"200"},null,512)]),e("div",ni,[e("input",{value:C.value,readonly:"",class:"flex-1 px-2 py-1.5 rounded text-base bg-white/5 text-white/40 font-mono truncate outline-none"},null,8,li),e("button",{class:"px-2 py-1.5 rounded text-xs bg-white/5 text-white/40 hover:text-white/60 transition-colors",onClick:D},d(i.value?"Copied":"Copy"),1)]),e("a",{href:"lightning:"+C.value,class:"block w-full py-2 rounded-lg text-xs text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"}," Open in wallet ",8,oi)])):m("",!0),u.value?(s(),n("p",ai,d(u.value),1)):m("",!0)])],544)):m("",!0)}}),ri={class:"h-full flex flex-col"},ci={class:"flex items-center gap-2 px-4 py-3 border-b border-white/[0.08]"},di={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-3 pb-16 space-y-2"},ui={key:0,class:"flex items-center justify-center py-12"},xi={key:1,class:"rounded-xl bg-white/[0.05] border border-white/10 p-3"},hi={class:"flex items-center gap-1.5 mb-1"},pi={class:"w-6 h-6 rounded-full shrink-0 flex items-center justify-center text-xs font-bold bg-purple-500/20 text-purple-400"},gi={class:"text-xs font-semibold text-white/80"},vi={class:"text-xs ml-auto text-white/20"},bi={class:"text-xs text-white/70 leading-relaxed whitespace-pre-wrap"},fi={key:2,class:"space-y-1"},mi={class:"text-xs text-white/30 font-medium mt-3 mb-1"},wi={key:3,class:"flex items-center justify-center py-12"},yi={key:0,class:"px-4 py-3 border-t border-white/[0.08]"},ki={key:0,class:"text-xs text-white/30 mb-1"},$i={class:"flex gap-2"},_i=["disabled"],Ci=q({__name:"NostrThread",props:{noteId:{}},emits:["back"],setup(a){const c=Zt(()=>bt(()=>import("./ThreadNode-Jt8WlAUM.js"),__vite__mapDeps([3,1,2]))),l=a,{fetchNote:w,publishEvent:g}=Le(),{isLoggedIn:b,signEvent:p,pubkey:v}=fe(),_=M(null),C=M([]),f=M(!0),u=M(null),i=M("");function r(k){const h=new Date(k*1e3);return h.toLocaleTimeString("en",{hour:"2-digit",minute:"2-digit"})+" "+h.toLocaleDateString("en",{month:"short",day:"numeric"})}function x(k){return k.length<=12?k:k.slice(0,8)+"..."+k.slice(-4)}async function S(){f.value=!0;const k=await w(l.noteId);if(!k){f.value=!1;return}_.value=k;const h=await j(l.noteId);C.value=P(h,l.noteId),f.value=!1}async function j(k){return new Promise(h=>{const $=[],N="thread-"+Math.random().toString(36).slice(2,8);let U=!1;const F=setTimeout(()=>{U||(U=!0,h($))},8e3),K="wss://relay.nostr.band";try{const O=new WebSocket(K);O.onopen=()=>{O.send(JSON.stringify(["REQ",N,{kinds:[1],"#e":[k],limit:100}]))},O.onmessage=Z=>{try{const V=JSON.parse(Z.data);if(Array.isArray(V)&&V[0]==="EVENT"&&V[1]===N&&V[2]){const H=V[2];$.find(X=>X.id===H.id)||$.push({id:H.id,pubkey:H.pubkey,authorName:x(H.pubkey),kind:H.kind,content:H.content,created_at:H.created_at,tags:H.tags??[]})}Array.isArray(V)&&V[0]==="EOSE"&&V[1]===N&&(clearTimeout(F),O.close(),U||(U=!0,h($)))}catch{}},O.onerror=()=>{clearTimeout(F),U||(U=!0,h($))},O.onclose=()=>{U||(U=!0,h($))}}catch{clearTimeout(F),h($)}})}function P(k,h,$=5){const N=new Map;for(const F of k){let K=h;const O=F.tags.filter(V=>V[0]==="e");if(O.length>0){const V=O.find(H=>H[3]==="reply");K=V?V[1]:O[O.length-1][1]}const Z=N.get(K)??[];Z.push(F),N.set(K,Z)}function U(F,K){const O=N.get(F)??[];return O.sort((Z,V)=>Z.created_at-V.created_at),O.map(Z=>({note:Z,children:K<$?U(Z.id,K+1):[]}))}return U(h,0)}function D(k){u.value=k}async function y(){if(!i.value.trim()||!v.value)return;const k=u.value??_.value;if(!k)return;const h=[["e",l.noteId,"","root"]];k.id!==l.noteId&&h.push(["e",k.id,"","reply"]),h.push(["p",k.pubkey]);const $={kind:1,created_at:Math.floor(Date.now()/1e3),tags:h,content:i.value.trim()},N=await p($);N&&(await g(N),i.value="",u.value=null,await S())}return le(()=>{S()}),(k,h)=>(s(),n("div",ri,[e("div",ci,[e("button",{class:"min-w-[44px] min-h-[44px] flex items-center justify-center rounded-lg text-white/60 hover:text-white/80 hover:bg-white/10 transition-colors",onClick:h[0]||(h[0]=$=>k.$emit("back"))},[...h[3]||(h[3]=[e("svg",{class:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M15 19l-7-7 7-7"})],-1)])]),h[4]||(h[4]=e("h3",{class:"text-sm font-bold text-white/90"},"Thread",-1))]),e("div",di,[f.value?(s(),n("div",ui,[...h[5]||(h[5]=[e("p",{class:"text-xs text-white/30"},"Loading thread...",-1)])])):m("",!0),_.value?(s(),n("div",xi,[e("div",hi,[e("div",pi,d(_.value.authorName?.charAt(0)?.toUpperCase()??"?"),1),e("span",gi,d(_.value.authorName??"anon"),1),e("span",vi,d(r(_.value.created_at)),1)]),e("p",bi,d(_.value.content),1)])):m("",!0),C.value.length>0?(s(),n("div",fi,[e("p",mi,d(C.value.length)+" replies",1),(s(!0),n(I,null,B(C.value,$=>(s(),E(t(c),{key:$.note.id,node:$,depth:0,onReply:D},null,8,["node"]))),128))])):m("",!0),!f.value&&!_.value?(s(),n("div",wi,[...h[6]||(h[6]=[e("p",{class:"text-xs text-white/30"},"Thread not found",-1)])])):m("",!0)]),_.value&&t(b)?(s(),n("div",yi,[u.value?(s(),n("p",ki,[ne(" Replying to "+d(u.value.authorName??"anon")+" ",1),e("button",{class:"text-accent/60 ml-1",onClick:h[1]||(h[1]=$=>u.value=null)},"cancel")])):m("",!0),e("div",$i,[W(e("input",{"onUpdate:modelValue":h[2]||(h[2]=$=>i.value=$),type:"text",placeholder:"Reply...",class:"flex-1 px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors",onKeydown:ae(y,["enter"])},null,544),[[Q,i.value]]),e("button",{class:"px-3 py-2 rounded-lg text-xs bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30",disabled:!i.value.trim(),onClick:y}," Reply ",8,_i)])])):m("",!0)]))}}),Si={class:"h-full flex flex-col"},ji={class:"p-4 border-b border-white/[0.08]"},Mi={class:"flex gap-1.5 flex-wrap"},Ti=["onClick"],Di={key:0,class:"flex-1 flex items-center justify-center"},Li={key:1,class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-3 pb-16 space-y-2"},Ii={key:0,class:"flex items-center justify-center py-12"},Bi={class:"flex gap-2 mb-3"},Pi=["placeholder"],Ni=["disabled"],Ai={class:"w-6 h-6 rounded-full shrink-0 flex items-center justify-center text-xs font-bold bg-purple-500/20 text-purple-400"},zi={class:"flex-1 min-w-0"},Fi={class:"text-xs text-white/60 font-mono truncate"},Ei={key:0,class:"text-xs text-white/30"},Ri=["onClick"],Vi={key:1,class:"flex items-center justify-center py-12"},Ui=["disabled"],qi=q({__name:"NostrLists",setup(a){const{isLoggedIn:c,signEvent:l,pubkey:w}=fe(),{publishEvent:g}=Le(),b=[{kind:3,label:"Follows"},{kind:1e4,label:"Mute"},{kind:10001,label:"Pin"},{kind:10003,label:"Bookmarks"}],p=M(3),v=M([]),_=M(!1),C=M(!1),f=M(""),u=M(!1),i=M(""),r=M(!1);function x(k){return k.length<=16?k:k.slice(0,8)+"..."+k.slice(-8)}function S(k){return k.filter(h=>h[0]==="p"||h[0]==="e"||h[0]==="t").map(h=>{let $=x(h[1]);if(h[0]==="p")try{$=Ye(h[1])}catch{}return{tag:h[0],value:h[1],displayValue:$,relay:h[2]||void 0,petname:h[3]||void 0}})}async function j(k){if(w.value){_.value=!0,C.value=!1,v.value=[];try{const h=new WebSocket("wss://relay.nostr.band"),$="list-"+Math.random().toString(36).slice(2,8),N=setTimeout(()=>{h.close(),_.value=!1},8e3);h.onopen=()=>{h.send(JSON.stringify(["REQ",$,{kinds:[k],authors:[w.value],limit:1}]))},h.onmessage=U=>{try{const F=JSON.parse(U.data);if(Array.isArray(F)&&F[0]==="EVENT"&&F[1]===$&&F[2]){const K=F[2];v.value=S(K.tags)}Array.isArray(F)&&F[0]==="EOSE"&&(clearTimeout(N),h.close(),_.value=!1)}catch{}},h.onerror=()=>{clearTimeout(N),_.value=!1}}catch{_.value=!1}}}function P(){let k=f.value.trim();if(!k)return;let h=k;const $=p.value===3||p.value===1e4?"p":"e";if(k.startsWith("npub"))try{h=ft(k)}catch{return}if(v.value.find(U=>U.value===h))return;let N=x(h);if($==="p")try{N=Ye(h)}catch{}v.value.push({tag:$,value:h,displayValue:N}),C.value=!0,f.value=""}function D(k){v.value=v.value.filter(h=>h.value!==k.value),C.value=!0}async function y(){if(!w.value)return;u.value=!0,i.value="";const k=v.value.map(F=>{const K=[F.tag,F.value];return F.relay&&K.push(F.relay),F.petname&&K.push(F.petname),K}),h={kind:p.value,created_at:Math.floor(Date.now()/1e3),tags:k,content:""},$=await l(h);if(!$){u.value=!1,i.value="Signing failed",r.value=!1;return}const N=await g($),U=N.filter(F=>F.success).length;u.value=!1,C.value=!1,U>0?(i.value=`Published to ${U}/${N.length} relays`,r.value=!0):(i.value="Failed to publish",r.value=!1)}return le(()=>{j(p.value)}),(k,h)=>(s(),n("div",Si,[e("div",ji,[h[1]||(h[1]=e("h3",{class:"text-sm font-bold text-white/90 mb-3"},"Nostr Lists",-1)),e("div",Mi,[(s(),n(I,null,B(b,$=>e("button",{key:$.kind,class:o(["text-xs px-2 py-1 rounded-md transition-all duration-150",p.value===$.kind?"nav-tab-active":"text-white/40 hover:text-white/70 hover:bg-white/5"]),onClick:N=>{p.value=$.kind,j($.kind)}},d($.label),11,Ti)),64))])]),t(c)?(s(),n("div",Li,[_.value?(s(),n("div",Ii,[...h[3]||(h[3]=[e("p",{class:"text-xs text-white/30"},"Loading list...",-1)])])):m("",!0),e("div",Bi,[W(e("input",{"onUpdate:modelValue":h[0]||(h[0]=$=>f.value=$),type:"text",placeholder:p.value===3?"Add npub or hex pubkey...":"Add item (hex id or npub)...",class:"flex-1 px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono",onKeydown:ae(P,["enter"])},null,40,Pi),[[Q,f.value]]),e("button",{class:"px-2.5 py-2 rounded-lg text-xs bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30",disabled:!f.value.trim(),onClick:P}," Add ",8,Ni)]),(s(!0),n(I,null,B(v.value,$=>(s(),n("div",{key:$.value,class:"flex items-center gap-2 p-2.5 rounded-xl bg-white/[0.03] border border-white/5"},[e("div",Ai,d($.tag==="p"?"P":$.tag==="e"?"E":$.tag==="t"?"#":"?"),1),e("div",zi,[e("p",Fi,d($.displayValue),1),$.petname?(s(),n("p",Ei,d($.petname),1)):m("",!0)]),e("button",{class:"text-xs px-2 py-1 rounded bg-white/5 text-red-400/50 hover:text-red-400/80 hover:bg-red-400/10 transition-colors shrink-0",onClick:N=>D($)}," Remove ",8,Ri)]))),128)),!_.value&&v.value.length===0?(s(),n("div",Vi,[...h[4]||(h[4]=[e("p",{class:"text-xs text-white/30"},"List is empty",-1)])])):m("",!0),C.value?(s(),n("button",{key:2,class:"w-full py-2.5 rounded-lg text-xs font-medium bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30 mt-4",disabled:u.value,onClick:y},d(u.value?"Publishing...":"Publish updated list"),9,Ui)):m("",!0),i.value?(s(),n("p",{key:3,class:o(["text-xs text-center",r.value?"text-emerald-400/60":"text-red-400/60"])},d(i.value),3)):m("",!0)])):(s(),n("div",Di,[...h[2]||(h[2]=[e("p",{class:"text-xs text-white/30"},"Sign in with Nostr to manage lists",-1)])]))]))}}),Gi={class:"article-reader h-full flex"},Oi={key:0,class:"hidden lg:flex flex-col w-56 shrink-0 border-r border-white/5 overflow-y-auto scrollbar-hide py-4 px-3"},Hi=["onClick"],Wi={class:"sticky top-0 z-10 flex items-center gap-2 px-4 py-2 bg-black/60 backdrop-blur-md border-b border-white/5"},Ki={class:"flex-1 text-xs text-white/40 truncate"},Yi=["disabled"],Qi=["disabled"],Ji={key:0,class:"lg:hidden bg-black/40 backdrop-blur-md border-b border-white/5 px-4 py-2 space-y-0.5 animate-fade-up-fast"},Zi=["onClick"],Xi={key:0,class:"text-xl font-bold text-white/96 mb-4"},er=["innerHTML"],tr=q({__name:"ArticleReader",props:{content:{},title:{}},emits:["back"],setup(a){const c=a,l=[13,15,17,19,21],w=localStorage.getItem("aiui-article-font-size"),g=M(w?parseInt(w,10):1);ce(g,D=>{localStorage.setItem("aiui-article-font-size",String(D))});const b=M(!1),p=new ds({html:!1,linkify:!0,breaks:!0});p.renderer.rules.heading_open=(D,y,k,h,$)=>{const N=D[y],U=parseInt(N.tag.slice(1),10);if(U===2||U===3){const O=(D[y+1]?.children?.reduce((Z,V)=>Z+(V.content||""),"")||"").toLowerCase().replace(/[^\w]+/g,"-").replace(/(^-|-$)/g,"");N.attrSet("id",O)}return $.renderToken(D,y,k)};const v=p.renderer.rules.link_open||function(D,y,k,h,$){return $.renderToken(D,y,k)};p.renderer.rules.link_open=function(D,y,k,h,$){return D[y].attrSet("target","_blank"),D[y].attrSet("rel","noopener noreferrer"),v(D,y,k,h,$)};const _=L(()=>p.render(c.content)),C=L(()=>{const D=[],y=/^(#{2,3})\s+(.+)$/gm;let k;for(;(k=y.exec(c.content))!==null;){const h=k[2].trim(),$=h.toLowerCase().replace(/[^\w]+/g,"-").replace(/(^-|-$)/g,"");D.push({text:h,id:$,level:k[1].length})}return D}),f=L(()=>{const D=c.content.split(/\s+/).length;return Math.max(1,Math.ceil(D/200))}),u=M(null),i=M(null),r=M(0);let x=null;function S(){if(!u.value)return;x?.disconnect(),x=new IntersectionObserver(y=>{for(const k of y)if(k.isIntersecting){const h=k.target.id,$=C.value.findIndex(N=>N.id===h);$>=0&&(r.value=$)}},{root:u.value,rootMargin:"-20% 0px -60% 0px",threshold:0}),i.value?.querySelectorAll("h2[id], h3[id]")?.forEach(y=>x.observe(y))}le(()=>{setTimeout(S,100)}),ce(()=>c.content,()=>{setTimeout(S,100)}),Xt(()=>{x?.disconnect()});function j(D){i.value?.querySelector(`#${CSS.escape(D)}`)?.scrollIntoView({behavior:"smooth",block:"start"})}function P(){const D=window.open("","_blank");D&&(D.document.write(` +}`,usedIn:"Modal entries, tooltip appearances, popovers"}],C=L(()=>p.value==="all"?_:_.filter(i=>i.category===p.value));function f(i){l(i)}function u(i){const r=/(?:background-color|color|background):\s*([^;]+)/i.exec(i);if(!r)return"#333";const x=r[1].trim();return x.startsWith("#")||x.startsWith("rgb")||x.startsWith("hsl")?x:"#333"}return(i,r)=>(s(),n("div",To,[e("div",{class:"shrink-0 px-4 py-3 flex items-center justify-between gap-2",style:G(t(c)?"border-bottom: 1px solid rgba(255, 255, 255, 0.08)":"border-bottom: 1px solid rgba(0, 0, 0, 0.06)")},[e("span",{class:o(["text-sm font-semibold",t(c)?"text-white/90":"text-gray-900"])}," Design System ",2),e("p",{class:o(["text-xs",t(c)?"text-white/30":"text-gray-400"])},d(C.value.length)+" items ",3)],4),e("div",Do,[(s(),n(I,null,B(v,x=>e("button",{key:x.id,class:o(["text-xs px-2.5 py-1 rounded-md font-medium whitespace-nowrap transition-colors",p.value===x.id?"bg-accent/20 text-accent":t(c)?"bg-white/5 text-white/50 hover:bg-white/10":"bg-black/5 text-gray-500 hover:bg-black/10"]),onClick:S=>p.value=x.id},d(x.label),11,Lo)),64))]),e("div",Io,[e("div",Bo,[(s(!0),n(I,null,B(C.value,x=>(s(),n("button",{key:x.id,class:o(["text-left p-3 rounded-xl transition-all duration-150 group relative",[t(w)&&t(b)(x.id)?"ring-2 ring-accent/50 bg-accent/10 cursor-pointer":t(c)?"bg-white/[0.03] hover:bg-white/[0.07] cursor-pointer":"bg-black/[0.02] hover:bg-black/[0.05] cursor-pointer"]]),onClick:S=>f(x)},[t(w)?(s(),n("div",{key:0,class:o(["absolute top-2 right-2 min-w-[44px] min-h-[44px] rounded-full flex items-center justify-center z-10 cursor-pointer transition-colors",t(b)(x.id)?"bg-accent":t(c)?"bg-white/10 hover:bg-white/20":"bg-black/10 hover:bg-black/20"]),onClick:he(S=>t(g)(x.id),["stop"])},[t(b)(x.id)?(s(),n("svg",Ao,[...r[0]||(r[0]=[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"3",d:"M5 13l4 4L19 7"},null,-1)])])):m("",!0)],10,No)):m("",!0),x.category==="colors"&&x.preview==="inline"?(s(),n("div",{key:1,class:o(["h-8 rounded-md mb-2 border",t(c)?"border-white/10":"border-black/10"]),style:G({background:u(x.code)})},null,6)):x.category==="spacing"&&x.preview==="inline"?(s(),n("div",zo,[...r[1]||(r[1]=[e("div",{class:"bg-accent/40 rounded-sm",style:{width:"4px",height:"30%"}},null,-1),e("div",{class:"bg-accent/40 rounded-sm",style:{width:"4px",height:"50%"}},null,-1),e("div",{class:"bg-accent/40 rounded-sm",style:{width:"4px",height:"70%"}},null,-1),e("div",{class:"bg-accent/40 rounded-sm",style:{width:"4px",height:"100%"}},null,-1)])])):(s(),n("div",Fo,[(s(),n("svg",{class:o(["w-5 h-5 transition-colors",t(c)?"text-white/20 group-hover:text-white/40":"text-black/15 group-hover:text-black/30"]),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[x.category==="atoms"?(s(),n("path",Eo)):x.category==="molecules"?(s(),n("path",Ro)):x.category==="organisms"?(s(),n("path",Vo)):(s(),n("path",Uo))],2))])),e("h3",{class:o(["text-xs font-semibold leading-tight mb-0.5",t(c)?"text-white/80":"text-gray-800"])},d(x.name),3),e("p",{class:o(["text-xs leading-snug line-clamp-2",t(c)?"text-white/40":"text-gray-400"])},d(x.description),3)],10,Po))),128))])])]))}}),we=M(null),it=M(!1),qe=M(!1),xe=M(null);function fe(){const a=L(()=>{if(!we.value)return null;try{return Ye(we.value)}catch{return null}}),c=L(()=>!!we.value),l=L(()=>a.value?a.value.slice(0,12)+"..."+a.value.slice(-8):null);function w(){it.value=typeof window<"u"&&!!window.nostr}async function g(){if(xe.value=null,!window.nostr){xe.value="No Nostr extension detected. Install nos2x, Alby, or another NIP-07 extension.";return}qe.value=!0;try{const v=await window.nostr.getPublicKey();we.value=v}catch(v){xe.value=v instanceof Error?v.message:"Failed to get public key"}finally{qe.value=!1}}async function b(v){if(xe.value=null,!window.nostr)return xe.value="No Nostr extension detected",null;try{return await window.nostr.signEvent(v)}catch(_){return xe.value=_ instanceof Error?_.message:"Failed to sign event",null}}function p(){we.value=null,xe.value=null}return le(()=>{w(),setTimeout(w,500)}),{pubkey:we,npub:a,isAvailable:it,isLoggedIn:c,isLoading:qe,error:xe,truncatedNpub:l,login:g,logout:p,signEvent:b,checkAvailability:w}}const Go="aiui-nostr-dms",Oo=1,ke="messages",Se=M([]),je=M(null),Ge=M(!1);let Me=null;function wt(){return Me||(Me=new Promise((a,c)=>{const l=indexedDB.open(Go,Oo);l.onupgradeneeded=()=>{const w=l.result;if(!w.objectStoreNames.contains(ke)){const g=w.createObjectStore(ke,{keyPath:"id"});g.createIndex("contact","contactPubkey",{unique:!1}),g.createIndex("created_at","created_at",{unique:!1})}},l.onsuccess=()=>a(l.result),l.onerror=()=>{Me=null,c(l.error)}}),Me)}function Ho(a){return a.length<=12?a:a.slice(0,8)+"..."+a.slice(-4)}async function rt(a,c){const l=await wt(),w=a.fromPubkey===c?a.toPubkey:a.fromPubkey,g={...a,contactPubkey:w};return new Promise((b,p)=>{const v=l.transaction(ke,"readwrite");v.objectStore(ke).put(g),v.oncomplete=()=>b(),v.onerror=()=>p(v.error)})}async function Oe(){const a=await wt();return new Promise((c,l)=>{const g=a.transaction(ke,"readonly").objectStore(ke).getAll();g.onsuccess=()=>c(g.result),g.onerror=()=>l(g.error)})}function He(a){const c=new Map;for(const w of a){const g=c.get(w.contactPubkey)??[];g.push(w),c.set(w.contactPubkey,g)}const l=[];for(const[w,g]of c)g.sort((b,p)=>b.created_at-p.created_at),l.push({contactPubkey:w,contactName:Ho(w),messages:g,lastMessage:g[g.length-1]??null,unread:0});return l.sort((w,g)=>(g.lastMessage?.created_at??0)-(w.lastMessage?.created_at??0)),l}function Wo(){const{pubkey:a,isLoggedIn:c}=fe(),l=L(()=>je.value?Se.value.find(_=>_.contactPubkey===je.value)??null:null);async function w(){if(c.value){Ge.value=!0;try{const _=await Oe();Se.value=He(_)}catch{}finally{Ge.value=!1}}}async function g(_,C){if(!window.nostr?.nip04||!a.value)return!1;try{const f=await window.nostr.nip04.encrypt(_,C),u={kind:4,created_at:Math.floor(Date.now()/1e3),tags:[["p",_]],content:f},i=await window.nostr.signEvent(u);if(!i)return!1;const r={id:i.id,fromPubkey:a.value,toPubkey:_,content:C,created_at:i.created_at,decrypted:!0};await rt(r,a.value);const{publishEvent:x}=await bt(()=>import("./useNostr-DYbkCQxC.js"),__vite__mapDeps([0,1,2])).then(j=>j.useNostr());await x(i);const S=await Oe();return Se.value=He(S),!0}catch{return!1}}async function b(_,C,f,u){if(!(!window.nostr?.nip04||!a.value))try{const i=await window.nostr.nip04.decrypt(C,f),r={id:_,fromPubkey:C,toPubkey:a.value,content:i,created_at:u,decrypted:!0};await rt(r,a.value);const x=await Oe();Se.value=He(x)}catch{}}function p(_){je.value=_}function v(){je.value=null}return{threads:Se,activeThread:l,activeContact:je,isLoading:Ge,loadDMs:w,sendDM:g,receiveDM:b,selectContact:p,clearActiveContact:v}}const Ko={class:"h-full flex flex-col"},Yo={class:"flex items-center gap-2 px-4 py-3 border-b border-white/[0.08]"},Qo={class:"flex-1 min-w-0"},Jo={class:"text-xs font-semibold text-white/80 truncate"},Zo={class:"text-xs text-white/30 font-mono truncate"},Xo={class:"text-xs leading-relaxed break-words"},ea={class:"text-xs mt-1 text-white/25 tabular-nums"},ta={class:"px-4 py-3 border-t border-white/[0.08]"},sa={class:"flex gap-2"},na=["disabled"],la={class:"p-4 border-b border-white/[0.08]"},oa={class:"flex items-center justify-between gap-2 mb-3"},aa={key:0,class:"space-y-2 mb-3"},ia=["disabled"],ra={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-3 pb-16 space-y-1"},ca={key:0,class:"flex items-center justify-center py-12"},da={key:1,class:"flex items-center justify-center py-12"},ua={key:2,class:"flex items-center justify-center py-12"},xa=["onClick"],ha={class:"flex items-start gap-2.5"},pa={class:"w-8 h-8 rounded-full shrink-0 flex items-center justify-center text-xs font-bold bg-accent/20 text-accent"},ga={class:"flex-1 min-w-0"},va={class:"flex items-center gap-1.5"},ba={class:"text-xs font-semibold truncate text-white/80"},fa={key:0,class:"text-xs ml-auto shrink-0 text-white/20"},ma={key:0,class:"text-xs mt-1 text-white/40 truncate"},wa=q({__name:"NostrDMs",setup(a){const{threads:c,activeThread:l,activeContact:w,isLoading:g,loadDMs:b,sendDM:p,selectContact:v,clearActiveContact:_}=Wo(),{pubkey:C,isLoggedIn:f}=fe(),u=M(""),i=M(!1),r=M(null),x=M(!1),S=M("");function j(k){const h=new Date(k*1e3),N=Math.floor((new Date().getTime()-h.getTime())/864e5);return N===0?h.toLocaleTimeString("en",{hour:"2-digit",minute:"2-digit"}):N<7?h.toLocaleDateString("en",{weekday:"short"}):h.toLocaleDateString("en",{month:"short",day:"numeric"})}async function P(){if(!u.value.trim()||i.value||!w.value)return;i.value=!0,await p(w.value,u.value.trim())&&(u.value="",await ye(),D()),i.value=!1}function D(){r.value&&(r.value.scrollTop=r.value.scrollHeight)}function y(){let k=S.value.trim();if(k.startsWith("npub"))try{k=ft(k)}catch{return}k.length===64&&(v(k),x.value=!1,S.value="")}return ce(w,async()=>{await ye(),D()}),le(()=>{b()}),(k,h)=>(s(),n("div",Ko,[t(l)?(s(),n(I,{key:0},[e("div",Yo,[e("button",{class:"min-w-[44px] min-h-[44px] flex items-center justify-center rounded-lg text-white/60 hover:text-white/80 hover:bg-white/10 transition-colors",onClick:h[0]||(h[0]=(...$)=>t(_)&&t(_)(...$))},[...h[4]||(h[4]=[e("svg",{class:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M15 19l-7-7 7-7"})],-1)])]),e("div",Qo,[e("p",Jo,d(t(l).contactName),1),e("p",Zo,d(t(l).contactPubkey),1)])]),e("div",{ref_key:"messagesRef",ref:r,class:"flex-1 overflow-y-auto custom-scrollbar px-4 py-3 space-y-2"},[(s(!0),n(I,null,B(t(l).messages,$=>(s(),n("div",{key:$.id,class:o(["flex",$.fromPubkey===t(C)?"justify-end":"justify-start"])},[e("div",{class:o(["max-w-[80%] rounded-xl px-3 py-2",$.fromPubkey===t(C)?"bg-accent/15 text-white/80":"bg-white/5 text-white/70"])},[e("p",Xo,d($.content),1),e("p",ea,d(j($.created_at)),1)],2)],2))),128))],512),e("div",ta,[e("div",sa,[W(e("input",{"onUpdate:modelValue":h[1]||(h[1]=$=>u.value=$),type:"text",placeholder:"Type a message...",class:"flex-1 px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors",onKeydown:ae(P,["enter"])},null,544),[[Q,u.value]]),e("button",{class:"px-3 py-2 rounded-lg text-xs bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30",disabled:!u.value.trim()||i.value,onClick:P}," Send ",8,na)])])],64)):(s(),n(I,{key:1},[e("div",la,[e("div",oa,[h[5]||(h[5]=e("h3",{class:"text-sm font-bold text-white/90"},"Messages",-1)),e("button",{class:"text-xs px-2.5 py-1 rounded bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors",onClick:h[2]||(h[2]=$=>x.value=!x.value)},d(x.value?"Cancel":"New"),1)]),x.value?(s(),n("div",aa,[W(e("input",{"onUpdate:modelValue":h[3]||(h[3]=$=>S.value=$),type:"text",placeholder:"Recipient hex pubkey or npub...",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"},null,512),[[Q,S.value]]),e("button",{class:"text-xs px-2.5 py-1 rounded bg-white/5 text-white/60 hover:bg-white/10 transition-colors disabled:opacity-30",disabled:!S.value.trim(),onClick:y}," Start conversation ",8,ia)])):m("",!0)]),e("div",ra,[t(f)?t(g)?(s(),n("div",da,[...h[7]||(h[7]=[e("p",{class:"text-xs text-white/30"},"Loading messages...",-1)])])):t(c).length===0?(s(),n("div",ua,[...h[8]||(h[8]=[e("p",{class:"text-xs text-white/30"},"No messages yet",-1)])])):m("",!0):(s(),n("div",ca,[...h[6]||(h[6]=[e("p",{class:"text-xs text-white/30"},"Sign in with Nostr to use DMs",-1)])])),(s(!0),n(I,null,B(t(c),$=>(s(),n("button",{key:$.contactPubkey,class:"w-full text-left p-3 rounded-xl transition-all duration-150 bg-white/[0.03] hover:bg-white/[0.07] border border-white/5",onClick:N=>t(v)($.contactPubkey)},[e("div",ha,[e("div",pa,d($.contactName.charAt(0).toUpperCase()),1),e("div",ga,[e("div",va,[e("span",ba,d($.contactName),1),$.lastMessage?(s(),n("span",fa,d(j($.lastMessage.created_at)),1)):m("",!0)]),$.lastMessage?(s(),n("p",ma,d($.lastMessage.content),1)):m("",!0)])])],8,xa))),128))])],64))]))}}),ya={class:"h-full flex flex-col"},ka={class:"p-4 border-b border-white/[0.08]"},$a={class:"flex gap-2"},_a=["disabled"],Ca={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-3 pb-16 space-y-2"},Sa={class:"flex items-center gap-2"},ja={class:"text-xs font-mono text-white/70 truncate flex-1"},Ma={class:"flex items-center gap-2 flex-wrap"},Ta=["onClick"],Da=["onClick"],La=["disabled","onClick"],Ia=["onClick"],Ba={key:0,class:"mt-4 pt-4 border-t border-white/5"},Pa=["disabled"],Na={key:0,class:"text-xs mt-1 text-white/30"},Aa=q({__name:"NostrRelayManager",setup(a){const{relayStates:c,addRelay:l,removeRelay:w,toggleRelayRead:g,toggleRelayWrite:b,testRelay:p,importNIP65Relays:v,fetchNote:_}=Le(),{isLoggedIn:C,pubkey:f}=fe(),u=M(""),i=M(null),r=Pe({}),x=M(!1),S=M("");function j(){let y=u.value.trim();y&&(!y.startsWith("wss://")&&!y.startsWith("ws://")&&(y="wss://"+y),l(y),u.value="")}async function P(y){i.value=y;const k=await p(y);r[y]=k,i.value=null}async function D(){if(!f.value)return;x.value=!0,S.value="Fetching relay list...";const y=await _(f.value,5e3);y?(v({id:y.id,pubkey:y.pubkey,kind:10002,content:y.content,created_at:y.created_at,tags:y.tags,sig:""}),S.value="Imported relays from NIP-65"):S.value="No NIP-65 relay list found",x.value=!1}return(y,k)=>(s(),n("div",ya,[e("div",ka,[k[1]||(k[1]=e("h3",{class:"text-sm font-bold text-white/90 mb-3"},"Relay Management",-1)),e("div",$a,[W(e("input",{"onUpdate:modelValue":k[0]||(k[0]=h=>u.value=h),type:"text",placeholder:"wss://relay.example.com",class:"flex-1 px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono",onKeydown:ae(j,["enter"])},null,544),[[Q,u.value]]),e("button",{class:"px-4 min-h-[44px] rounded-lg text-sm bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30",disabled:!u.value.trim(),onClick:j}," Add ",8,_a)])]),e("div",Ca,[(s(!0),n(I,null,B(t(c),h=>(s(),n("div",{key:h.url,class:"rounded-xl bg-white/[0.03] border border-white/5 p-3 space-y-2"},[e("div",Sa,[e("span",{class:o(["w-2 h-2 rounded-full shrink-0",h.connected?"bg-emerald-500":"bg-red-400/60"])},null,2),e("span",ja,d(h.url),1),h.latencyMs!==null?(s(),n("span",{key:0,class:o(["text-xs tabular-nums shrink-0",h.latencyMs<200?"text-emerald-400/60":h.latencyMs<500?"text-yellow-400/60":"text-red-400/60"])},d(h.latencyMs)+"ms ",3)):m("",!0),e("span",{class:o(["text-xs shrink-0",h.connected?"text-emerald-400/60":"text-red-400/60"])},d(h.connected?"Connected":"Disconnected"),3)]),e("div",Ma,[e("button",{class:o(["text-sm px-3 min-h-[44px] rounded-lg transition-colors",h.read?"bg-accent/15 text-accent/80":"bg-white/5 text-white/30 hover:text-white/50"]),onClick:$=>t(g)(h.url)}," Read ",10,Ta),e("button",{class:o(["text-sm px-3 min-h-[44px] rounded-lg transition-colors",h.write?"bg-accent/15 text-accent/80":"bg-white/5 text-white/30 hover:text-white/50"]),onClick:$=>t(b)(h.url)}," Write ",10,Da),k[2]||(k[2]=e("div",{class:"flex-1"},null,-1)),e("button",{class:"text-sm px-3 min-h-[44px] rounded-lg bg-white/5 text-white/30 hover:text-white/50 transition-colors",disabled:i.value===h.url,onClick:$=>P(h.url)},d(i.value===h.url?"Testing...":"Test"),9,La),e("button",{class:"text-sm px-3 min-h-[44px] rounded-lg bg-white/5 text-red-400/50 hover:text-red-400/80 hover:bg-red-400/10 transition-colors",onClick:$=>t(w)(h.url)}," Remove ",8,Ia)]),r[h.url]!==void 0?(s(),n("p",{key:0,class:o(["text-xs",r[h.url]!==null?"text-emerald-400/60":"text-red-400/60"])},d(r[h.url]!==null?`Reachable (${r[h.url]}ms)`:"Unreachable"),3)):m("",!0)]))),128)),t(C)?(s(),n("div",Ba,[e("button",{class:"w-full text-left px-3 min-h-[44px] rounded-lg text-sm bg-white/5 text-white/40 hover:text-white/60 hover:bg-white/10 transition-colors",disabled:x.value,onClick:D},d(x.value?"Importing...":"Import relays from NIP-65 (kind:10002)"),9,Pa),S.value?(s(),n("p",Na,d(S.value),1)):m("",!0)])):m("",!0)])]))}}),za={class:"h-full flex flex-col"},Fa={key:0,class:"flex-1 flex items-center justify-center"},Ea={key:1,class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-3 pb-16 space-y-4"},Ra={class:"rounded-xl overflow-hidden border border-white/5"},Va={class:"px-4 pb-4 -mt-8"},Ua={key:0,class:"text-lg font-bold text-accent"},qa={class:"text-sm font-bold text-white/90 mt-2"},Ga={key:0,class:"text-xs text-purple-400/60"},Oa={key:1,class:"text-xs text-white/50 mt-1 line-clamp-2"},Ha={class:"space-y-3"},Wa=["disabled"],Ka=q({__name:"NostrProfileEditor",setup(a){const{isLoggedIn:c,signEvent:l,pubkey:w}=fe(),{publishEvent:g,fetchNote:b}=Le(),p=Pe({name:"",display_name:"",about:"",picture:"",banner:"",website:"",nip05:"",lud16:""}),v=M(!1),_=M(""),C=M(!1);async function f(){if(!w.value)return;const i=await b(w.value,5e3);if(i&&i.kind===0)try{const r=JSON.parse(i.content);Object.assign(p,r)}catch{}}async function u(){if(!c.value)return;v.value=!0,_.value="";const i={};for(const[P,D]of Object.entries(p))D&&(i[P]=D);const r={kind:0,created_at:Math.floor(Date.now()/1e3),tags:[],content:JSON.stringify(i)},x=await l(r);if(!x){v.value=!1,_.value="Signing failed",C.value=!1;return}const S=await g(x),j=S.filter(P=>P.success).length;v.value=!1,j>0?(_.value=`Published to ${j}/${S.length} relays`,C.value=!0):(_.value="Failed to publish to any relay",C.value=!1)}return le(()=>{f()}),(i,r)=>(s(),n("div",za,[r[17]||(r[17]=e("div",{class:"p-4 border-b border-white/[0.08]"},[e("h3",{class:"text-sm font-bold text-white/90"},"Nostr Profile")],-1)),t(c)?(s(),n("div",Ea,[e("div",Ra,[e("div",{class:o(["h-24 bg-cover bg-center",p.banner?"":"bg-gradient-to-r from-accent/20 to-purple-500/20"]),style:G(p.banner?{backgroundImage:`url(${p.banner})`}:{})},null,6),e("div",Va,[e("div",{class:o(["w-16 h-16 rounded-full border-2 border-black bg-cover bg-center flex items-center justify-center",p.picture?"":"bg-accent/20"]),style:G(p.picture?{backgroundImage:`url(${p.picture})`}:{})},[p.picture?m("",!0):(s(),n("span",Ua,d((p.display_name||p.name||"?").charAt(0).toUpperCase()),1))],6),e("p",qa,d(p.display_name||p.name||"Anonymous"),1),p.nip05?(s(),n("p",Ga,d(p.nip05),1)):m("",!0),p.about?(s(),n("p",Oa,d(p.about),1)):m("",!0)])]),e("div",Ha,[e("div",null,[r[9]||(r[9]=e("label",{class:"text-xs text-white/30 block mb-1"},"Display Name",-1)),W(e("input",{"onUpdate:modelValue":r[0]||(r[0]=x=>p.display_name=x),type:"text",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors",placeholder:"Your display name"},null,512),[[Q,p.display_name]])]),e("div",null,[r[10]||(r[10]=e("label",{class:"text-xs text-white/30 block mb-1"},"Username",-1)),W(e("input",{"onUpdate:modelValue":r[1]||(r[1]=x=>p.name=x),type:"text",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors",placeholder:"username"},null,512),[[Q,p.name]])]),e("div",null,[r[11]||(r[11]=e("label",{class:"text-xs text-white/30 block mb-1"},"Bio",-1)),W(e("textarea",{"onUpdate:modelValue":r[2]||(r[2]=x=>p.about=x),class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors resize-none min-h-[60px]",placeholder:"Tell the world about yourself"},null,512),[[Q,p.about]])]),e("div",null,[r[12]||(r[12]=e("label",{class:"text-xs text-white/30 block mb-1"},"Avatar URL",-1)),W(e("input",{"onUpdate:modelValue":r[3]||(r[3]=x=>p.picture=x),type:"url",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono",placeholder:"https://example.com/avatar.jpg"},null,512),[[Q,p.picture]])]),e("div",null,[r[13]||(r[13]=e("label",{class:"text-xs text-white/30 block mb-1"},"Banner URL",-1)),W(e("input",{"onUpdate:modelValue":r[4]||(r[4]=x=>p.banner=x),type:"url",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono",placeholder:"https://example.com/banner.jpg"},null,512),[[Q,p.banner]])]),e("div",null,[r[14]||(r[14]=e("label",{class:"text-xs text-white/30 block mb-1"},"Website",-1)),W(e("input",{"onUpdate:modelValue":r[5]||(r[5]=x=>p.website=x),type:"url",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono",placeholder:"https://example.com"},null,512),[[Q,p.website]])]),e("div",null,[r[15]||(r[15]=e("label",{class:"text-xs text-white/30 block mb-1"},"NIP-05 Address",-1)),W(e("input",{"onUpdate:modelValue":r[6]||(r[6]=x=>p.nip05=x),type:"text",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono",placeholder:"you@example.com"},null,512),[[Q,p.nip05]])]),e("div",null,[r[16]||(r[16]=e("label",{class:"text-xs text-white/30 block mb-1"},"Lightning Address",-1)),W(e("input",{"onUpdate:modelValue":r[7]||(r[7]=x=>p.lud16=x),type:"text",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono",placeholder:"you@getalby.com"},null,512),[[Q,p.lud16]])]),e("button",{class:"w-full min-h-[44px] rounded-lg text-sm font-medium bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30",disabled:v.value,onClick:u},d(v.value?"Publishing...":"Publish Profile (kind:0)"),9,Wa),_.value?(s(),n("div",{key:0,class:o(["text-xs text-center",C.value?"text-emerald-400/60":"text-red-400/60"])},d(_.value),3)):m("",!0)])])):(s(),n("div",Fa,[...r[8]||(r[8]=[e("p",{class:"text-xs text-white/30"},"Sign in with Nostr to edit your profile",-1)])]))]))}}),Ya={class:"relative glass-card w-[320px] max-w-[90vw] p-5 space-y-4 animate-scale-in"},Qa={class:"flex items-center justify-between"},Ja={class:"text-xs text-white/40 truncate font-mono"},Za={class:"flex gap-1.5 flex-wrap"},Xa=["onClick"],ei=["disabled"],ti={key:0,class:"space-y-2"},si={class:"flex justify-center"},ni={class:"flex gap-1"},li=["value"],oi=["href"],ai={key:1,class:"text-xs text-red-400/60 text-center"},ii=q({__name:"ZapDialog",props:{isOpen:{type:Boolean},targetName:{},lightningAddress:{}},emits:["close"],setup(a,{emit:c}){const l=a,w=c,g=M(null),b=M(null),p=[21,100,500,1e3,5e3,1e4],v=M(21),_=M(""),C=M(""),f=M(!1),u=M(""),i=M(!1),r=M(null);function x(k){return k>=1e3?`${(k/1e3).toFixed(k%1e3===0?0:1)}k`:String(k)}function S(){w("close"),C.value="",u.value="",_.value=""}async function j(){if(!(!l.lightningAddress||!v.value)){f.value=!0,u.value="",C.value="";try{const[k,h]=l.lightningAddress.split("@");if(!k||!h)throw new Error("Invalid Lightning address");const $=await fetch(`https://${h}/.well-known/lnurlp/${k}`);if(!$.ok)throw new Error("Failed to fetch LNURL");const N=await $.json();if(N.status==="ERROR")throw new Error(N.reason||"LNURL error");const U=v.value*1e3;if(U<(N.minSendable??0))throw new Error(`Minimum: ${Math.ceil((N.minSendable??0)/1e3)} sats`);if(U>(N.maxSendable??1/0))throw new Error(`Maximum: ${Math.floor((N.maxSendable??0)/1e3)} sats`);let F=N.callback;const K=F.includes("?")?"&":"?";F+=`${K}amount=${U}`,_.value&&(F+=`&comment=${encodeURIComponent(_.value)}`);const O=await fetch(F);if(!O.ok)throw new Error("Failed to get invoice");const Z=await O.json();if(Z.status==="ERROR")throw new Error(Z.reason||"Invoice error");C.value=Z.pr,await ye(),P(Z.pr)}catch(k){u.value=k instanceof Error?k.message:"Zap failed"}finally{f.value=!1}}}function P(k){const h=r.value;if(!h)return;const $=h.getContext("2d");if(!$)return;$.fillStyle="#1a1a1a",$.fillRect(0,0,200,200),$.fillStyle="#F7931A",$.font="10px monospace",$.textAlign="center";const N=[];for(let F=0;F{$.fillText(F,100,U+K*12)})}function D(){navigator.clipboard.writeText(C.value),i.value=!0,setTimeout(()=>{i.value=!1},2e3)}function y(k){const h=g.value;if(!h)return;const $=h.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');if($.length===0)return;const N=$[0],U=$[$.length-1];k.shiftKey&&document.activeElement===N?(k.preventDefault(),U.focus()):!k.shiftKey&&document.activeElement===U&&(k.preventDefault(),N.focus())}return ce(()=>l.isOpen,async k=>{k?(await ye(),b.value?.focus()):(C.value="",u.value="")}),(k,h)=>a.isOpen?(s(),n("div",{key:0,ref_key:"dialogRef",ref:g,role:"dialog","aria-modal":"true","aria-label":"Send zap",class:"fixed inset-0 z-50 flex items-center justify-center",onClick:he(S,["self"]),onKeydown:[ae(S,["escape"]),ae(y,["tab"])]},[e("div",{class:"absolute inset-0 bg-black/60 backdrop-blur-sm",onClick:S}),e("div",Ya,[e("div",Qa,[h[3]||(h[3]=e("h3",{class:"text-sm font-bold text-white/90"},"Zap",-1)),e("button",{ref_key:"closeButtonRef",ref:b,class:"min-w-[44px] min-h-[44px] flex items-center justify-center rounded text-white/40 hover:text-white/70 transition-colors","aria-label":"Close",onClick:S},[...h[2]||(h[2]=[e("svg",{class:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M6 18L18 6M6 6l12 12"})],-1)])],512)]),e("p",Ja,d(a.targetName),1),e("div",Za,[(s(),n(I,null,B(p,$=>e("button",{key:$,class:o(["text-xs px-2.5 py-1.5 rounded-lg transition-colors",v.value===$?"bg-accent/20 text-accent border border-accent/30":"bg-white/5 text-white/50 hover:bg-white/10"]),onClick:N=>v.value=$},d(x($)),11,Xa)),64))]),e("div",null,[h[4]||(h[4]=e("label",{class:"text-xs text-white/30 block mb-1"},"Amount (sats)",-1)),W(e("input",{"onUpdate:modelValue":h[0]||(h[0]=$=>v.value=$),type:"number",min:"1",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors tabular-nums",placeholder:"21"},null,512),[[Q,v.value,void 0,{number:!0}]])]),e("div",null,[h[5]||(h[5]=e("label",{class:"text-xs text-white/30 block mb-1"},"Message (optional)",-1)),W(e("input",{"onUpdate:modelValue":h[1]||(h[1]=$=>_.value=$),type:"text",class:"w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors",placeholder:"Great post!"},null,512),[[Q,_.value]])]),e("button",{class:"w-full py-2.5 rounded-lg text-xs font-medium bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30",disabled:!v.value||v.value<1||f.value,onClick:j},d(f.value?"Generating invoice...":`Zap ${x(v.value)} sats`),9,ei),C.value?(s(),n("div",ti,[h[6]||(h[6]=e("p",{class:"text-xs text-white/30 text-center"},"Scan or tap to pay",-1)),e("div",si,[e("canvas",{ref_key:"qrCanvas",ref:r,class:"rounded-lg",width:"200",height:"200"},null,512)]),e("div",ni,[e("input",{value:C.value,readonly:"",class:"flex-1 px-2 py-1.5 rounded text-base bg-white/5 text-white/40 font-mono truncate outline-none"},null,8,li),e("button",{class:"px-2 py-1.5 rounded text-xs bg-white/5 text-white/40 hover:text-white/60 transition-colors",onClick:D},d(i.value?"Copied":"Copy"),1)]),e("a",{href:"lightning:"+C.value,class:"block w-full py-2 rounded-lg text-xs text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"}," Open in wallet ",8,oi)])):m("",!0),u.value?(s(),n("p",ai,d(u.value),1)):m("",!0)])],544)):m("",!0)}}),ri={class:"h-full flex flex-col"},ci={class:"flex items-center gap-2 px-4 py-3 border-b border-white/[0.08]"},di={class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-3 pb-16 space-y-2"},ui={key:0,class:"flex items-center justify-center py-12"},xi={key:1,class:"rounded-xl bg-white/[0.05] border border-white/10 p-3"},hi={class:"flex items-center gap-1.5 mb-1"},pi={class:"w-6 h-6 rounded-full shrink-0 flex items-center justify-center text-xs font-bold bg-purple-500/20 text-purple-400"},gi={class:"text-xs font-semibold text-white/80"},vi={class:"text-xs ml-auto text-white/20"},bi={class:"text-xs text-white/70 leading-relaxed whitespace-pre-wrap"},fi={key:2,class:"space-y-1"},mi={class:"text-xs text-white/30 font-medium mt-3 mb-1"},wi={key:3,class:"flex items-center justify-center py-12"},yi={key:0,class:"px-4 py-3 border-t border-white/[0.08]"},ki={key:0,class:"text-xs text-white/30 mb-1"},$i={class:"flex gap-2"},_i=["disabled"],Ci=q({__name:"NostrThread",props:{noteId:{}},emits:["back"],setup(a){const c=Zt(()=>bt(()=>import("./ThreadNode-Bt5yTyUn.js"),__vite__mapDeps([3,1,2]))),l=a,{fetchNote:w,publishEvent:g}=Le(),{isLoggedIn:b,signEvent:p,pubkey:v}=fe(),_=M(null),C=M([]),f=M(!0),u=M(null),i=M("");function r(k){const h=new Date(k*1e3);return h.toLocaleTimeString("en",{hour:"2-digit",minute:"2-digit"})+" "+h.toLocaleDateString("en",{month:"short",day:"numeric"})}function x(k){return k.length<=12?k:k.slice(0,8)+"..."+k.slice(-4)}async function S(){f.value=!0;const k=await w(l.noteId);if(!k){f.value=!1;return}_.value=k;const h=await j(l.noteId);C.value=P(h,l.noteId),f.value=!1}async function j(k){return new Promise(h=>{const $=[],N="thread-"+Math.random().toString(36).slice(2,8);let U=!1;const F=setTimeout(()=>{U||(U=!0,h($))},8e3),K="wss://relay.nostr.band";try{const O=new WebSocket(K);O.onopen=()=>{O.send(JSON.stringify(["REQ",N,{kinds:[1],"#e":[k],limit:100}]))},O.onmessage=Z=>{try{const V=JSON.parse(Z.data);if(Array.isArray(V)&&V[0]==="EVENT"&&V[1]===N&&V[2]){const H=V[2];$.find(X=>X.id===H.id)||$.push({id:H.id,pubkey:H.pubkey,authorName:x(H.pubkey),kind:H.kind,content:H.content,created_at:H.created_at,tags:H.tags??[]})}Array.isArray(V)&&V[0]==="EOSE"&&V[1]===N&&(clearTimeout(F),O.close(),U||(U=!0,h($)))}catch{}},O.onerror=()=>{clearTimeout(F),U||(U=!0,h($))},O.onclose=()=>{U||(U=!0,h($))}}catch{clearTimeout(F),h($)}})}function P(k,h,$=5){const N=new Map;for(const F of k){let K=h;const O=F.tags.filter(V=>V[0]==="e");if(O.length>0){const V=O.find(H=>H[3]==="reply");K=V?V[1]:O[O.length-1][1]}const Z=N.get(K)??[];Z.push(F),N.set(K,Z)}function U(F,K){const O=N.get(F)??[];return O.sort((Z,V)=>Z.created_at-V.created_at),O.map(Z=>({note:Z,children:K<$?U(Z.id,K+1):[]}))}return U(h,0)}function D(k){u.value=k}async function y(){if(!i.value.trim()||!v.value)return;const k=u.value??_.value;if(!k)return;const h=[["e",l.noteId,"","root"]];k.id!==l.noteId&&h.push(["e",k.id,"","reply"]),h.push(["p",k.pubkey]);const $={kind:1,created_at:Math.floor(Date.now()/1e3),tags:h,content:i.value.trim()},N=await p($);N&&(await g(N),i.value="",u.value=null,await S())}return le(()=>{S()}),(k,h)=>(s(),n("div",ri,[e("div",ci,[e("button",{class:"min-w-[44px] min-h-[44px] flex items-center justify-center rounded-lg text-white/60 hover:text-white/80 hover:bg-white/10 transition-colors",onClick:h[0]||(h[0]=$=>k.$emit("back"))},[...h[3]||(h[3]=[e("svg",{class:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[e("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M15 19l-7-7 7-7"})],-1)])]),h[4]||(h[4]=e("h3",{class:"text-sm font-bold text-white/90"},"Thread",-1))]),e("div",di,[f.value?(s(),n("div",ui,[...h[5]||(h[5]=[e("p",{class:"text-xs text-white/30"},"Loading thread...",-1)])])):m("",!0),_.value?(s(),n("div",xi,[e("div",hi,[e("div",pi,d(_.value.authorName?.charAt(0)?.toUpperCase()??"?"),1),e("span",gi,d(_.value.authorName??"anon"),1),e("span",vi,d(r(_.value.created_at)),1)]),e("p",bi,d(_.value.content),1)])):m("",!0),C.value.length>0?(s(),n("div",fi,[e("p",mi,d(C.value.length)+" replies",1),(s(!0),n(I,null,B(C.value,$=>(s(),E(t(c),{key:$.note.id,node:$,depth:0,onReply:D},null,8,["node"]))),128))])):m("",!0),!f.value&&!_.value?(s(),n("div",wi,[...h[6]||(h[6]=[e("p",{class:"text-xs text-white/30"},"Thread not found",-1)])])):m("",!0)]),_.value&&t(b)?(s(),n("div",yi,[u.value?(s(),n("p",ki,[ne(" Replying to "+d(u.value.authorName??"anon")+" ",1),e("button",{class:"text-accent/60 ml-1",onClick:h[1]||(h[1]=$=>u.value=null)},"cancel")])):m("",!0),e("div",$i,[W(e("input",{"onUpdate:modelValue":h[2]||(h[2]=$=>i.value=$),type:"text",placeholder:"Reply...",class:"flex-1 px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors",onKeydown:ae(y,["enter"])},null,544),[[Q,i.value]]),e("button",{class:"px-3 py-2 rounded-lg text-xs bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30",disabled:!i.value.trim(),onClick:y}," Reply ",8,_i)])])):m("",!0)]))}}),Si={class:"h-full flex flex-col"},ji={class:"p-4 border-b border-white/[0.08]"},Mi={class:"flex gap-1.5 flex-wrap"},Ti=["onClick"],Di={key:0,class:"flex-1 flex items-center justify-center"},Li={key:1,class:"flex-1 overflow-y-auto custom-scrollbar px-4 pt-3 pb-16 space-y-2"},Ii={key:0,class:"flex items-center justify-center py-12"},Bi={class:"flex gap-2 mb-3"},Pi=["placeholder"],Ni=["disabled"],Ai={class:"w-6 h-6 rounded-full shrink-0 flex items-center justify-center text-xs font-bold bg-purple-500/20 text-purple-400"},zi={class:"flex-1 min-w-0"},Fi={class:"text-xs text-white/60 font-mono truncate"},Ei={key:0,class:"text-xs text-white/30"},Ri=["onClick"],Vi={key:1,class:"flex items-center justify-center py-12"},Ui=["disabled"],qi=q({__name:"NostrLists",setup(a){const{isLoggedIn:c,signEvent:l,pubkey:w}=fe(),{publishEvent:g}=Le(),b=[{kind:3,label:"Follows"},{kind:1e4,label:"Mute"},{kind:10001,label:"Pin"},{kind:10003,label:"Bookmarks"}],p=M(3),v=M([]),_=M(!1),C=M(!1),f=M(""),u=M(!1),i=M(""),r=M(!1);function x(k){return k.length<=16?k:k.slice(0,8)+"..."+k.slice(-8)}function S(k){return k.filter(h=>h[0]==="p"||h[0]==="e"||h[0]==="t").map(h=>{let $=x(h[1]);if(h[0]==="p")try{$=Ye(h[1])}catch{}return{tag:h[0],value:h[1],displayValue:$,relay:h[2]||void 0,petname:h[3]||void 0}})}async function j(k){if(w.value){_.value=!0,C.value=!1,v.value=[];try{const h=new WebSocket("wss://relay.nostr.band"),$="list-"+Math.random().toString(36).slice(2,8),N=setTimeout(()=>{h.close(),_.value=!1},8e3);h.onopen=()=>{h.send(JSON.stringify(["REQ",$,{kinds:[k],authors:[w.value],limit:1}]))},h.onmessage=U=>{try{const F=JSON.parse(U.data);if(Array.isArray(F)&&F[0]==="EVENT"&&F[1]===$&&F[2]){const K=F[2];v.value=S(K.tags)}Array.isArray(F)&&F[0]==="EOSE"&&(clearTimeout(N),h.close(),_.value=!1)}catch{}},h.onerror=()=>{clearTimeout(N),_.value=!1}}catch{_.value=!1}}}function P(){let k=f.value.trim();if(!k)return;let h=k;const $=p.value===3||p.value===1e4?"p":"e";if(k.startsWith("npub"))try{h=ft(k)}catch{return}if(v.value.find(U=>U.value===h))return;let N=x(h);if($==="p")try{N=Ye(h)}catch{}v.value.push({tag:$,value:h,displayValue:N}),C.value=!0,f.value=""}function D(k){v.value=v.value.filter(h=>h.value!==k.value),C.value=!0}async function y(){if(!w.value)return;u.value=!0,i.value="";const k=v.value.map(F=>{const K=[F.tag,F.value];return F.relay&&K.push(F.relay),F.petname&&K.push(F.petname),K}),h={kind:p.value,created_at:Math.floor(Date.now()/1e3),tags:k,content:""},$=await l(h);if(!$){u.value=!1,i.value="Signing failed",r.value=!1;return}const N=await g($),U=N.filter(F=>F.success).length;u.value=!1,C.value=!1,U>0?(i.value=`Published to ${U}/${N.length} relays`,r.value=!0):(i.value="Failed to publish",r.value=!1)}return le(()=>{j(p.value)}),(k,h)=>(s(),n("div",Si,[e("div",ji,[h[1]||(h[1]=e("h3",{class:"text-sm font-bold text-white/90 mb-3"},"Nostr Lists",-1)),e("div",Mi,[(s(),n(I,null,B(b,$=>e("button",{key:$.kind,class:o(["text-xs px-2 py-1 rounded-md transition-all duration-150",p.value===$.kind?"nav-tab-active":"text-white/40 hover:text-white/70 hover:bg-white/5"]),onClick:N=>{p.value=$.kind,j($.kind)}},d($.label),11,Ti)),64))])]),t(c)?(s(),n("div",Li,[_.value?(s(),n("div",Ii,[...h[3]||(h[3]=[e("p",{class:"text-xs text-white/30"},"Loading list...",-1)])])):m("",!0),e("div",Bi,[W(e("input",{"onUpdate:modelValue":h[0]||(h[0]=$=>f.value=$),type:"text",placeholder:p.value===3?"Add npub or hex pubkey...":"Add item (hex id or npub)...",class:"flex-1 px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono",onKeydown:ae(P,["enter"])},null,40,Pi),[[Q,f.value]]),e("button",{class:"px-2.5 py-2 rounded-lg text-xs bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30",disabled:!f.value.trim(),onClick:P}," Add ",8,Ni)]),(s(!0),n(I,null,B(v.value,$=>(s(),n("div",{key:$.value,class:"flex items-center gap-2 p-2.5 rounded-xl bg-white/[0.03] border border-white/5"},[e("div",Ai,d($.tag==="p"?"P":$.tag==="e"?"E":$.tag==="t"?"#":"?"),1),e("div",zi,[e("p",Fi,d($.displayValue),1),$.petname?(s(),n("p",Ei,d($.petname),1)):m("",!0)]),e("button",{class:"text-xs px-2 py-1 rounded bg-white/5 text-red-400/50 hover:text-red-400/80 hover:bg-red-400/10 transition-colors shrink-0",onClick:N=>D($)}," Remove ",8,Ri)]))),128)),!_.value&&v.value.length===0?(s(),n("div",Vi,[...h[4]||(h[4]=[e("p",{class:"text-xs text-white/30"},"List is empty",-1)])])):m("",!0),C.value?(s(),n("button",{key:2,class:"w-full py-2.5 rounded-lg text-xs font-medium bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30 mt-4",disabled:u.value,onClick:y},d(u.value?"Publishing...":"Publish updated list"),9,Ui)):m("",!0),i.value?(s(),n("p",{key:3,class:o(["text-xs text-center",r.value?"text-emerald-400/60":"text-red-400/60"])},d(i.value),3)):m("",!0)])):(s(),n("div",Di,[...h[2]||(h[2]=[e("p",{class:"text-xs text-white/30"},"Sign in with Nostr to manage lists",-1)])]))]))}}),Gi={class:"article-reader h-full flex"},Oi={key:0,class:"hidden lg:flex flex-col w-56 shrink-0 border-r border-white/5 overflow-y-auto scrollbar-hide py-4 px-3"},Hi=["onClick"],Wi={class:"sticky top-0 z-10 flex items-center gap-2 px-4 py-2 bg-black/60 backdrop-blur-md border-b border-white/5"},Ki={class:"flex-1 text-xs text-white/40 truncate"},Yi=["disabled"],Qi=["disabled"],Ji={key:0,class:"lg:hidden bg-black/40 backdrop-blur-md border-b border-white/5 px-4 py-2 space-y-0.5 animate-fade-up-fast"},Zi=["onClick"],Xi={key:0,class:"text-xl font-bold text-white/96 mb-4"},er=["innerHTML"],tr=q({__name:"ArticleReader",props:{content:{},title:{}},emits:["back"],setup(a){const c=a,l=[13,15,17,19,21],w=localStorage.getItem("aiui-article-font-size"),g=M(w?parseInt(w,10):1);ce(g,D=>{localStorage.setItem("aiui-article-font-size",String(D))});const b=M(!1),p=new ds({html:!1,linkify:!0,breaks:!0});p.renderer.rules.heading_open=(D,y,k,h,$)=>{const N=D[y],U=parseInt(N.tag.slice(1),10);if(U===2||U===3){const O=(D[y+1]?.children?.reduce((Z,V)=>Z+(V.content||""),"")||"").toLowerCase().replace(/[^\w]+/g,"-").replace(/(^-|-$)/g,"");N.attrSet("id",O)}return $.renderToken(D,y,k)};const v=p.renderer.rules.link_open||function(D,y,k,h,$){return $.renderToken(D,y,k)};p.renderer.rules.link_open=function(D,y,k,h,$){return D[y].attrSet("target","_blank"),D[y].attrSet("rel","noopener noreferrer"),v(D,y,k,h,$)};const _=L(()=>p.render(c.content)),C=L(()=>{const D=[],y=/^(#{2,3})\s+(.+)$/gm;let k;for(;(k=y.exec(c.content))!==null;){const h=k[2].trim(),$=h.toLowerCase().replace(/[^\w]+/g,"-").replace(/(^-|-$)/g,"");D.push({text:h,id:$,level:k[1].length})}return D}),f=L(()=>{const D=c.content.split(/\s+/).length;return Math.max(1,Math.ceil(D/200))}),u=M(null),i=M(null),r=M(0);let x=null;function S(){if(!u.value)return;x?.disconnect(),x=new IntersectionObserver(y=>{for(const k of y)if(k.isIntersecting){const h=k.target.id,$=C.value.findIndex(N=>N.id===h);$>=0&&(r.value=$)}},{root:u.value,rootMargin:"-20% 0px -60% 0px",threshold:0}),i.value?.querySelectorAll("h2[id], h3[id]")?.forEach(y=>x.observe(y))}le(()=>{setTimeout(S,100)}),ce(()=>c.content,()=>{setTimeout(S,100)}),Xt(()=>{x?.disconnect()});function j(D){i.value?.querySelector(`#${CSS.escape(D)}`)?.scrollIntoView({behavior:"smooth",block:"start"})}function P(){const D=window.open("","_blank");D&&(D.document.write(` ${c.title||"Article"} "+v+""+h+"":f==="javascript"||f==="js"?""+v+""+b+h+g+"":f==="css"?"
CSS Preview
':""}function a(){n.value=[],s.value=!1,requestAnimationFrame(()=>{s.value=!0})}function l(){n.value=[]}function c(f){f.data?.type==="code-runner-console"&&n.value.push({type:f.data.level==="error"?"error":"log",text:f.data.text})}return Re(()=>{window.addEventListener("message",c)}),Bo(()=>{window.removeEventListener("message",c)}),(f,h)=>(p(),m("div",fh,[d("div",ph,[d("span",hh,C(e.language),1),h[0]||(h[0]=d("div",{class:"flex-1"},null,-1)),d("button",{class:"text-xs px-2.5 py-1 rounded bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors",onClick:a}," Run "),n.value.length>0?(p(),m("button",{key:0,class:"text-xs px-2 py-1 rounded bg-white/5 text-white/40 hover:text-white/60 hover:bg-white/10 transition-colors",onClick:l}," Clear ")):D("",!0)]),d("pre",mh,[d("code",null,C(e.code),1)]),s.value?(p(),m("iframe",{key:0,ref_key:"iframeRef",ref:o,srcdoc:r.value,sandbox:"allow-scripts",class:F(["w-full border-t border-white/5",u.value?"h-48":"h-0 invisible"]),title:"Code output"},null,10,gh)):D("",!0),n.value.length>0?(p(),m("div",bh,[h[1]||(h[1]=d("p",{class:"text-xs text-white/20 uppercase tracking-wider mb-1"},"Console",-1)),(p(!0),m(H,null,Z(n.value,(b,g)=>(p(),m("div",{key:g,class:F(["text-xs font-mono leading-relaxed",b.type==="error"?"text-red-400/80":"text-white/60"])},C(b.text),3))),128))])):D("",!0)]))}}),vh={class:"rounded-xl bg-white/5 border border-white/10 p-3 space-y-2"},yh={class:"flex items-center gap-2"},wh={class:"text-xs px-1.5 py-0.5 rounded bg-white/5 text-white/30"},kh={class:"text-xs font-mono text-white/70 break-all leading-relaxed select-all"},Ch={class:"flex justify-center py-2"},_h={class:"flex gap-2"},Ah=["href"],Dh=ne({__name:"BitcoinAddressCard",props:{address:{}},setup(e){const t=e,n=k(null),s=k(!1),o=_(()=>{const a=t.address;return a.startsWith("bc1q")?"SegWit (bech32)":a.startsWith("bc1p")?"Taproot (bech32m)":a.startsWith("1")?"Legacy (P2PKH)":a.startsWith("3")?"Nested SegWit (P2SH)":a.startsWith("tb1")||a.startsWith("2")||a.startsWith("m")||a.startsWith("n")?"Testnet":"Unknown"}),u=_(()=>`https://mempool.space/address/${t.address}`);function r(){navigator.clipboard.writeText(t.address),s.value=!0,setTimeout(()=>{s.value=!1},2e3)}function i(){const a=n.value;if(!a)return;const l=a.getContext("2d");if(!l)return;l.fillStyle="#1a1a1a",l.fillRect(0,0,160,160),l.fillStyle="#F7931A",l.font="8px monospace",l.textAlign="center";const c=`bitcoin:${t.address}`,f=[];for(let b=0;b{l.fillText(b,80,h+g*10)})}return Re(()=>{i()}),(a,l)=>(p(),m("div",vh,[d("div",yh,[l[0]||(l[0]=d("span",{class:"text-xs text-accent/60 uppercase tracking-wider font-bold"},"Bitcoin Address",-1)),d("span",wh,C(o.value),1)]),d("p",kh,C(e.address),1),d("div",Ch,[d("canvas",{ref_key:"qrCanvas",ref:n,class:"rounded-lg",width:"160",height:"160"},null,512)]),d("div",_h,[d("button",{class:"flex-1 py-2 rounded-lg text-xs bg-white/5 text-white/50 hover:text-white/70 hover:bg-white/10 transition-colors",onClick:r},C(s.value?"Copied!":"Copy Address"),1),d("a",{href:u.value,target:"_blank",rel:"noopener noreferrer",class:"flex-1 py-2 rounded-lg text-xs text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"}," View on Mempool ",8,Ah)])]))}}),Sh={class:"rounded-xl bg-white/5 border border-white/10 p-3 space-y-2"},Eh={class:"flex items-center gap-2"},$h={key:0,class:"text-xs px-1.5 py-0.5 rounded bg-red-400/15 text-red-400/80"},Fh={key:0,class:"flex items-center gap-2"},Mh={class:"text-lg font-bold text-accent tabular-nums"},Th={key:1,class:"text-xs text-white/50"},Ih={key:2,class:"flex items-center gap-1.5"},Ph={class:"text-xs font-mono text-white/30 break-all line-clamp-2 select-all"},Lh={class:"flex gap-2"},zh=["href"],Bh=ne({__name:"Bolt11InvoiceCard",props:{invoice:{}},setup(e){const t=e,n=k(!1),s=k(Math.floor(Date.now()/1e3));let o=null;const u=_(()=>{const g=t.invoice.toLowerCase().match(/^lnbc(\d+)([munp]?)1/);if(!g)return null;const v=parseInt(g[1]);switch(g[2]){case"m":return v*1e5;case"u":return v*100;case"n":return Math.round(v*.1);case"p":return Math.round(v*1e-4);default:return v*1e8}}),r=_(()=>null),i=_(()=>null),a=_(()=>i.value?s.value>i.value:!1),l=_(()=>i.value?i.value-s.value<300:!1),c=_(()=>{if(!i.value)return null;const b=i.value-s.value;if(b<=0)return"Expired";const g=Math.floor(b/60);return g<60?`Expires in ${g}m`:`Expires in ${Math.floor(g/60)}h ${g%60}m`});function f(b){return b.toLocaleString()}function h(){navigator.clipboard.writeText(t.invoice),n.value=!0,setTimeout(()=>{n.value=!1},2e3)}return Re(()=>{o=setInterval(()=>{s.value=Math.floor(Date.now()/1e3)},1e3)}),Bo(()=>{o&&clearInterval(o)}),(b,g)=>(p(),m("div",Sh,[d("div",Eh,[g[0]||(g[0]=d("span",{class:"text-xs text-accent/60 uppercase tracking-wider font-bold"},"Lightning Invoice",-1)),a.value?(p(),m("span",$h," Expired ")):D("",!0)]),u.value?(p(),m("div",Fh,[d("span",Mh,C(f(u.value)),1),g[1]||(g[1]=d("span",{class:"text-xs text-white/30"},"sats",-1))])):D("",!0),r.value?(p(),m("p",Th,C(r.value),1)):D("",!0),c.value?(p(),m("div",Ih,[d("span",{class:F(["text-xs tabular-nums",a.value||l.value?"text-red-400/60":"text-white/30"])},C(c.value),3)])):D("",!0),d("p",Ph,C(e.invoice),1),d("div",Lh,[d("button",{class:"flex-1 py-2 rounded-lg text-xs bg-white/5 text-white/50 hover:text-white/70 hover:bg-white/10 transition-colors",onClick:h},C(n.value?"Copied!":"Copy"),1),d("a",{href:"lightning:"+e.invoice,class:"flex-1 py-2 rounded-lg text-xs text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"}," Pay with wallet ",8,zh)])]))}}),Rh={class:"rounded-xl bg-white/5 border border-white/10 p-3 space-y-2"},jh={class:"text-xs font-mono text-white/50 break-all line-clamp-2 select-all"},Nh={class:"flex justify-center py-2"},Uh={class:"flex gap-2"},Oh=["href"],qh=ne({__name:"Bolt12OfferCard",props:{offer:{}},setup(e){const t=e,n=k(null),s=k(!1);function o(){navigator.clipboard.writeText(t.offer),s.value=!0,setTimeout(()=>{s.value=!1},2e3)}function u(){const r=n.value;if(!r)return;const i=r.getContext("2d");if(!i)return;i.fillStyle="#1a1a1a",i.fillRect(0,0,140,140),i.fillStyle="#F7931A",i.font="7px monospace",i.textAlign="center";const a=[];for(let c=0;c{i.fillText(c,70,l+f*9)})}return Re(()=>{u()}),(r,i)=>(p(),m("div",Rh,[i[0]||(i[0]=d("div",{class:"flex items-center gap-2"},[d("span",{class:"text-xs text-accent/60 uppercase tracking-wider font-bold"},"BOLT12 Offer")],-1)),d("p",jh,C(e.offer),1),d("div",Nh,[d("canvas",{ref_key:"qrCanvas",ref:n,class:"rounded-lg",width:"140",height:"140"},null,512)]),d("div",Uh,[d("button",{class:"flex-1 py-2 rounded-lg text-xs bg-white/5 text-white/50 hover:text-white/70 hover:bg-white/10 transition-colors",onClick:o},C(s.value?"Copied!":"Copy Offer"),1),d("a",{href:"lightning:"+e.offer,class:"flex-1 py-2 rounded-lg text-xs text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"}," Pay with wallet ",8,Oh)])]))}}),Hh={class:"rounded-xl bg-white/5 border border-white/10 p-3 space-y-2"},Wh={class:"flex items-center gap-2"},Vh={class:"text-xs font-mono text-white/40 break-all select-all"},Gh={key:0,class:"grid grid-cols-2 gap-2 text-xs"},Kh={class:"text-white/60 tabular-nums"},Jh={class:"text-white/60 tabular-nums"},Zh={class:"text-white/60 tabular-nums"},Yh={class:"text-white/60 tabular-nums"},Xh={key:1,class:"py-2"},Qh={key:2,class:"py-2"},e1={class:"text-xs text-red-400/60"},t1=["href"],n1=ne({__name:"MempoolTxCard",props:{txid:{}},setup(e){const t=e,n=k(null),s=k(!0),o=k("");async function u(){s.value=!0,o.value="";try{const r=await fetch(`https://mempool.space/api/tx/${t.txid}`);if(!r.ok)throw new Error("Transaction not found");const i=await r.json(),a=!!i.status?.confirmed;let l=0;if(a&&i.status?.block_height){const c=await fetch("https://mempool.space/api/blocks/tip/height");c.ok&&(l=parseInt(await c.text())-i.status.block_height+1)}n.value={fee:i.fee??0,feeRate:i.weight?Math.round(i.fee/i.weight*4):0,size:i.weight?Math.round(i.weight/4):i.size??0,confirmed:a,confirmations:l,blockHeight:i.status?.block_height??null}}catch(r){o.value=r instanceof Error?r.message:"Failed to load transaction"}finally{s.value=!1}}return Re(()=>{u()}),(r,i)=>(p(),m("div",Hh,[d("div",Wh,[i[0]||(i[0]=d("span",{class:"text-xs text-accent/60 uppercase tracking-wider font-bold"},"Transaction",-1)),n.value?(p(),m("span",{key:0,class:F(["text-xs px-1.5 py-0.5 rounded",n.value.confirmed?"bg-emerald-400/15 text-emerald-400/80":"bg-yellow-400/15 text-yellow-400/80"])},C(n.value.confirmed?`${n.value.confirmations} confirmations`:"Unconfirmed"),3)):D("",!0)]),d("p",Vh,C(e.txid),1),n.value?(p(),m("div",Gh,[d("div",null,[i[1]||(i[1]=d("p",{class:"text-white/25"},"Fee",-1)),d("p",Kh,C(n.value.fee.toLocaleString())+" sats",1)]),d("div",null,[i[2]||(i[2]=d("p",{class:"text-white/25"},"Fee Rate",-1)),d("p",Jh,C(n.value.feeRate)+" sat/vB",1)]),d("div",null,[i[3]||(i[3]=d("p",{class:"text-white/25"},"Size",-1)),d("p",Zh,C(n.value.size)+" vB",1)]),d("div",null,[i[4]||(i[4]=d("p",{class:"text-white/25"},"Block",-1)),d("p",Yh,C(n.value.blockHeight??"Pending"),1)])])):s.value?(p(),m("div",Xh,[...i[5]||(i[5]=[d("p",{class:"text-xs text-white/30"},"Loading transaction...",-1)])])):o.value?(p(),m("div",Qh,[d("p",e1,C(o.value),1)])):D("",!0),d("a",{href:`https://mempool.space/tx/${e.txid}`,target:"_blank",rel:"noopener noreferrer",class:"block w-full py-2 rounded-lg text-xs text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"}," View on Mempool.space ",8,t1)]))}}),s1=/\b(bc1q[a-z0-9]{38,62})\b/gi,o1=/\b(bc1p[a-z0-9]{38,62})\b/gi,u1=/\b(1[13456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{25,34})\b/g,r1=/\b(3[13456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{25,34})\b/g,i1=/\b(tb1[a-z0-9]{38,62})\b/gi,a1=/\b(lnbc[a-z0-9]+)\b/gi,l1=/\b(lno1[a-z0-9]+)\b/gi,c1=/\b([a-f0-9]{64})\b/gi;function d1(e){const t=[],n=new Set;for(const s of e.matchAll(s1))n.has(s[1].toLowerCase())||(n.add(s[1].toLowerCase()),t.push({address:s[1],type:"bech32"}));for(const s of e.matchAll(o1))n.has(s[1].toLowerCase())||(n.add(s[1].toLowerCase()),t.push({address:s[1],type:"bech32m"}));for(const s of e.matchAll(u1))n.has(s[1])||(n.add(s[1]),t.push({address:s[1],type:"p2pkh"}));for(const s of e.matchAll(r1))n.has(s[1])||(n.add(s[1]),t.push({address:s[1],type:"p2sh"}));for(const s of e.matchAll(i1))n.has(s[1].toLowerCase())||(n.add(s[1].toLowerCase()),t.push({address:s[1],type:"testnet"}));return t}function f1(e){const t=[],n=new Set;for(const s of e.matchAll(a1)){const o=s[1].toLowerCase();n.has(o)||(n.add(o),t.push({invoice:s[1]}))}return t}function p1(e){const t=[],n=new Set;for(const s of e.matchAll(l1)){const o=s[1].toLowerCase();n.has(o)||(n.add(o),t.push({offer:s[1]}))}return t}function h1(e){const t=[],n=new Set;for(const s of e.matchAll(c1))n.has(s[1])||(n.add(s[1]),t.push({txid:s[1]}));return t}const xr=/^(\|[^\n]+\|)\n(\|[\s:|-]+\|)\n((?:\|[^\n]+\|\n?)+)/gm;function m1(e){const t=[];let n;const s=new RegExp(xr.source,xr.flags);for(;(n=s.exec(e))!==null;){const o=n[1],u=n[3],r=vr(o),i=u.trim().split(` -`).map(vr).filter(a=>a.length>0);r.length>0&&i.length>0&&t.push({headers:r,rows:i,raw:n[0]})}return t}function vr(e){return e.replace(/^\|/,"").replace(/\|$/,"").split("|").map(t=>t.trim())}const g1=new Set(["html","javascript","js","css"]),yr=/```(html|javascript|js|css)\n([\s\S]*?)```/gi;function b1(e){const t=[];let n;const s=new RegExp(yr.source,yr.flags);for(;(n=s.exec(e))!==null;){const o=n[1].toLowerCase(),u=n[2].trim();g1.has(o)&&u.length>0&&t.push({language:o,code:u})}return t}const x1={class:"relative max-w-[85%] md:max-w-[75%]"},v1={class:"flex items-center gap-2 px-1 py-0.5 rounded-lg bg-black/60 backdrop-blur-md border border-white/10 shadow-lg"},y1={key:3,class:"w-px h-4 bg-white/10 mx-0.5"},w1=["onKeydown"],k1={key:0,class:"flex gap-2 flex-wrap mb-2"},C1=["src","alt"],_1=["innerHTML"],A1={key:2,class:"text-sm leading-relaxed whitespace-pre-wrap break-words text-white/90"},D1={key:21,class:"flex items-center gap-2 mt-1.5"},S1={class:"text-xs select-none text-white/30"},E1={key:0,class:"text-xs text-white/25 select-none"},$1=["title"],F1={key:2,class:"text-xs select-none"},M1=ne({__name:"ChatMessage",props:{message:{},index:{},triggeringQuery:{default:""}},emits:["edit","regenerate","branch","reply","feedback"],setup(e,{emit:t}){const n=e,s=t;function o(q){const M=n.message.feedback===q?void 0:q;s("feedback",n.message.id,M)}const u=k(!1),r=k(""),i=k(null);function a(){r.value=n.message.content,u.value=!0,Ie(()=>{i.value?.focus(),i.value&&(i.value.style.height="auto",i.value.style.height=i.value.scrollHeight+"px")})}function l(){u.value=!1,r.value=""}function c(){const q=r.value.trim();q&&(s("edit",n.message.id,q),u.value=!1,r.value="")}const{getContextualInlineContent:f,stripContentTags:h,stripMarkdownLinks:b,updatePanelFromText:g,panelOpen:v,availableTabs:E,setActiveTab:A,openFilmDetail:y,openBookDetail:w,openTVSeriesDetail:x,openPlaceDetail:$,openSongDetail:P,openPodcastDetail:U,openArticleDetail:se,openWebsiteDetail:R,openLongFormArticle:j,openMapView:X,closeFilmDetail:Q,closeBookDetail:J,closeTVSeriesDetail:I,closePlaceDetail:Y,closeSongDetail:pe,closePodcastDetail:ge}=_s(),Ye=No(),ee=_(()=>n.message.role==="user"),Ae=_(()=>ee.value?{films:[],books:[],tvSeries:[],images:[],places:[],songs:[],podcasts:[],newsLinks:[],websitesLinks:[],magazineSections:[]}:f(n.message.content,n.triggeringQuery,n.message.webResults??[])),ft=_(()=>ee.value?"path-glass-bubble-user rounded-br-md rounded-2xl":"path-glass-bubble rounded-bl-md rounded-2xl"),O=_(()=>Ae.value.films),V=_(()=>Ae.value.books??[]),ae=_(()=>Ae.value.tvSeries??[]),be=_(()=>Ae.value.images??[]),T=_(()=>Ae.value.places??[]),N=_(()=>Ae.value.songs),he=_(()=>Ae.value.podcasts),ve=_(()=>Ae.value.newsLinks??[]),ye=_(()=>Ae.value.websitesLinks??[]),Fe=_(()=>Ae.value.magazineSections??[]),Oe=/nostr:(note1[a-z0-9]{58}|npub1[a-z0-9]{58}|nevent1[a-z0-9]+|nprofile1[a-z0-9]+)/g,z=_(()=>{if(ee.value)return[];const q=n.message.content.match(Oe);return q?[...new Set(q)]:[]}),L=_(()=>ee.value?[]:rp(n.message.content)),ue=_(()=>ee.value?[]:Eo(n.message.content)),le=_(()=>ee.value?[]:m1(n.message.content)),oe=_(()=>ee.value?[]:gl(n.message.content)),xe=_(()=>ee.value?[]:b1(n.message.content)),Me=_(()=>ee.value?[]:d1(n.message.content)),Tt=_(()=>ee.value?[]:f1(n.message.content)),Ct=_(()=>ee.value?[]:p1(n.message.content)),_t=_(()=>ee.value?[]:h1(n.message.content)),pt=_(()=>!ee.value&&n.triggeringQuery.trim().toLowerCase()==="/code"),At=_(()=>!ee.value&&(pt.value||O.value.length>0||V.value.length>0||ae.value.length>0||be.value.length>0||N.value.length>0||he.value.length>0||ve.value.length>0||ye.value.length>0||Fe.value.length>0)),ht=new Ue({html:!1,linkify:!0,breaks:!0}),mt=ht.renderer.rules.link_open||function(q,M,B,te,Le){return Le.renderToken(q,M,B)};ht.renderer.rules.link_open=function(q,M,B,te,Le){return q[M].attrSet("target","_blank"),q[M].attrSet("rel","noopener noreferrer"),mt(q,M,B,te,Le)};const Xe=_(()=>{if(ee.value)return n.message.content;let q=h(n.message.content);if((ve.value.length>0||ye.value.length>0)&&(q=b(q)),z.value.length>0&&(q=q.replace(Oe,"").replace(/\n{3,}/g,` +`)?`"${f.replace(/"/g,'""')}"`:f}return(f,h)=>(p(),m("div",Wp,[d("div",Vp,[Se(d("input",{"onUpdate:modelValue":h[0]||(h[0]=b=>n.value=b),type:"text",class:"flex-1 bg-white/5 border border-white/10 rounded px-2 py-1 text-base text-white/80 outline-none focus:border-accent/40 placeholder:text-white/25",placeholder:"Filter rows..."},null,512),[[Te,n.value]]),d("button",{class:"text-xs px-2 py-1 rounded bg-white/5 border border-white/10 text-white/50 hover:text-white/80 hover:bg-white/10 transition-colors",title:"Export CSV",onClick:l}," CSV ")]),d("div",Gp,[d("table",Kp,[d("thead",null,[d("tr",Jp,[(p(!0),m(H,null,Z(e.headers,(b,g)=>(p(),m("th",{key:g,class:"px-3 py-2 text-left text-white/50 font-medium cursor-pointer hover:text-white/70 select-none whitespace-nowrap",onClick:v=>u(g)},[d("span",Yp,[ce(C(b)+" ",1),s.value===g?(p(),m("span",Xp,C(o.value==="asc"?"↑":"↓"),1)):D("",!0)])],8,Zp))),128))])]),d("tbody",null,[(p(!0),m(H,null,Z(a.value,(b,g)=>(p(),m("tr",{key:g,class:"border-b border-white/5 hover:bg-white/5 transition-colors"},[(p(!0),m(H,null,Z(b,(v,E)=>(p(),m("td",{key:E,class:"px-3 py-1.5 text-white/70 whitespace-nowrap"},C(v),1))),128))]))),128))])])]),r.value.length===0?(p(),m("div",Qp," No matching rows ")):D("",!0),r.value.length>0?(p(),m("div",eh,[ce(C(r.value.length)+" row"+C(r.value.length===1?"":"s")+" ",1),n.value?(p(),m("span",th," (filtered from "+C(e.rows.length)+")",1)):D("",!0)])):D("",!0)]))}}),sh={class:"timeline-renderer my-4"},oh={class:"relative"},uh={class:"text-xs text-white/40 tabular-nums pt-1"},rh={class:"ml-10 md:ml-0 md:w-[calc(50%-2rem)] shrink-0"},ih={class:"rounded-lg bg-white/5 border border-white/10 px-3 py-2"},ah={class:"text-xs text-white/30 md:hidden tabular-nums"},lh={class:"text-xs font-medium text-white/90"},ch={key:0,class:"text-xs text-white/40 mt-0.5"},dh={key:1,class:"text-xs text-white/50 mt-1 line-clamp-2"},fh=se({__name:"TimelineRenderer",props:{events:{}},setup(e){function t(n){if(!n)return"";const s=new Date(n);return isNaN(s.getTime())?n:s.toLocaleDateString("en",{year:"numeric",month:"short",day:"numeric"})}return(n,s)=>(p(),m("div",sh,[d("div",oh,[s[1]||(s[1]=d("div",{class:"absolute left-4 md:left-1/2 top-0 bottom-0 w-px bg-white/10 md:-translate-x-px"},null,-1)),(p(!0),m(H,null,Z(e.events,(o,u)=>(p(),m("div",{key:u,class:F(["relative flex items-start gap-4 mb-6 animate-fade-up-fast",u%2===0?"md:flex-row":"md:flex-row-reverse"]),style:Ee({animationDelay:`${u*80}ms`})},[s[0]||(s[0]=d("div",{class:"absolute left-4 md:left-1/2 w-3 h-3 rounded-full bg-accent border-2 border-black z-10 md:-translate-x-1.5",style:{top:"6px"}},null,-1)),d("div",{class:F(["hidden md:block w-[calc(50%-2rem)] text-right shrink-0",u%2===0?"":"order-last text-left"])},[d("p",uh,C(t(o.date)),1)],2),d("div",rh,[d("div",ih,[d("p",ah,C(t(o.date)),1),d("h4",lh,C(o.title),1),o.location?(p(),m("p",ch,C(o.location),1)):D("",!0),o.description?(p(),m("p",dh,C(o.description),1)):D("",!0)])])],6))),128))])]))}}),ph={class:"code-runner rounded-xl bg-white/5 border border-white/10 overflow-hidden"},hh={class:"flex items-center gap-2 px-3 py-2 border-b border-white/5"},mh={class:"text-xs text-white/30 uppercase tracking-wider"},gh={class:"px-3 py-2 text-xs text-white/70 overflow-x-auto max-h-48 bg-black/20"},bh=["srcdoc"],xh={key:1,class:"border-t border-white/5 bg-black/30 px-3 py-2 max-h-32 overflow-y-auto"},vh=se({__name:"CodeRunner",props:{code:{},language:{}},setup(e){const t=e,n=k([]),s=k(!1),o=k(null),u=_(()=>t.language==="html"),r=_(()=>i(t.language,t.code));function i(f,h){const b=" - - + + +
diff --git a/demo/aiui/registerSW.js b/demo/aiui/registerSW.js index d42ac9ed..2ad529f7 100644 --- a/demo/aiui/registerSW.js +++ b/demo/aiui/registerSW.js @@ -1 +1 @@ -if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/sw.js', { scope: '/' })})} \ No newline at end of file +if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/aiui/sw.js', { scope: '/aiui/' })})} \ No newline at end of file diff --git a/demo/aiui/sw.js b/demo/aiui/sw.js index f43d2f11..9f7a5a14 100644 --- a/demo/aiui/sw.js +++ b/demo/aiui/sw.js @@ -1 +1 @@ -if(!self.define){let s,e={};const i=(i,l)=>(i=new URL(i+".js",l).href,e[i]||new Promise(e=>{if("document"in self){const s=document.createElement("script");s.src=i,s.onload=e,document.head.appendChild(s)}else s=i,importScripts(i),e()}).then(()=>{let s=e[i];if(!s)throw new Error(`Module ${i} didn’t register its module`);return s}));self.define=(l,n)=>{const r=s||("document"in self?document.currentScript.src:"")||location.href;if(e[r])return;let a={};const u=s=>i(s,r),t={module:{uri:r},exports:a,require:u};e[r]=Promise.all(l.map(s=>t[s]||u(s))).then(s=>(n(...s),a))}}define(["./workbox-3c177d20"],function(s){"use strict";self.skipWaiting(),s.clientsClaim(),s.precacheAndRoute([{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"index.html",revision:"62094adf58eea51dd2e81793ef80fba5"},{url:"icon.svg",revision:"dba94027bbb3b869c0ebf9b6beee1953"},{url:"favicon.svg",revision:"72e74ad8f660d9400c34fa69912b94a3"},{url:"images/loading-poster.svg",revision:"97c56238c72450e4953e1d7db2f6e8e6"},{url:"assets/xychartDiagram-PRI3JC2R-DCRwYb86.js",revision:null},{url:"assets/wikipedia-BNDKhpH7.js",revision:null},{url:"assets/useNostr-zyhtrXba.js",revision:null},{url:"assets/useContentImages-h7FPc94o.js",revision:null},{url:"assets/treemap-GDKQZRPO-AdnGbe1r.js",revision:null},{url:"assets/timeline-definition-IT6M3QCI-DAvrjQlO.js",revision:null},{url:"assets/stateDiagram-v2-4FDKWEC3-BBfEPULu.js",revision:null},{url:"assets/stateDiagram-FKZM4ZOC-CsEu5A1-.js",revision:null},{url:"assets/song-renderer-DThhTKU4.js",revision:null},{url:"assets/sequenceDiagram-WL72ISMW-D6JvJDMe.js",revision:null},{url:"assets/seedPrompts-CLWaUv28.js",revision:null},{url:"assets/sankeyDiagram-TZEHDZUN-T-T7pPL5.js",revision:null},{url:"assets/requirementDiagram-UZGBJVZJ-YSWU7wM2.js",revision:null},{url:"assets/quadrantDiagram-AYHSOK5B-CYUMAZxF.js",revision:null},{url:"assets/pieDiagram-ADFJNKIX-dv9eWyZx.js",revision:null},{url:"assets/ordinal-Cboi1Yqb.js",revision:null},{url:"assets/openlibrary-B8IPeH2e.js",revision:null},{url:"assets/ollama-provider-BPRxN1UO.js",revision:null},{url:"assets/nodeDemoPrompts-DjnuaxJP.js",revision:null},{url:"assets/mindmap-definition-VGOIOE7T-Cv8kGwbk.js",revision:null},{url:"assets/mermaid.core-Bp72wBaC.js",revision:null},{url:"assets/linear-G5w56VQ9.js",revision:null},{url:"assets/layout-Dn20ATE3.js",revision:null},{url:"assets/katex.min-CASE1JAf.css",revision:null},{url:"assets/katex-DGN8GczM.js",revision:null},{url:"assets/kanban-definition-3W4ZIXB7-C9WSxADn.js",revision:null},{url:"assets/journeyDiagram-XKPGCS4Q-DrVt-4mP.js",revision:null},{url:"assets/init-Gi6I4Gst.js",revision:null},{url:"assets/infoDiagram-HS3SLOUP-BUtAMk68.js",revision:null},{url:"assets/index-CHQ7uqBj.css",revision:null},{url:"assets/index-BzKy-nNf.js",revision:null},{url:"assets/guideConversation-BYC5cBFP.js",revision:null},{url:"assets/graph-BI4iNatD.js",revision:null},{url:"assets/gitGraphDiagram-V2S2FVAM-Z60Qif5y.js",revision:null},{url:"assets/ganttDiagram-JELNMOA3-D9WdDFmh.js",revision:null},{url:"assets/freeFilms-DLEVjUOb.js",revision:null},{url:"assets/flowDiagram-NV44I4VS-BZiwTlxg.js",revision:null},{url:"assets/film-renderer-BjBNXUs-.js",revision:null},{url:"assets/erDiagram-Q2GNP2WA-LFDWLdbe.js",revision:null},{url:"assets/diagram-S2PKOQOG-CYt74Kga.js",revision:null},{url:"assets/diagram-QEK2KX5R-DVAGvEAB.js",revision:null},{url:"assets/diagram-PSM6KHXK-BRTfOYmW.js",revision:null},{url:"assets/defaultLocale-DX6XiGOO.js",revision:null},{url:"assets/dagre-6UL2VRFP-D3-DYqn2.js",revision:null},{url:"assets/cytoscape.esm-5J0xJHOV.js",revision:null},{url:"assets/cose-bilkent-S5V4N54A-B3h2gisu.js",revision:null},{url:"assets/clone-BbeogWA3.js",revision:null},{url:"assets/claude-provider-DnmgFFcN.js",revision:null},{url:"assets/classDiagram-v2-WZHVMYZB-DYkXo-yO.js",revision:null},{url:"assets/classDiagram-2ON5EDUG-DYkXo-yO.js",revision:null},{url:"assets/chunk-TZMSLE5B-BzDureVr.js",revision:null},{url:"assets/chunk-QZHKN3VN-Bi1rVrMI.js",revision:null},{url:"assets/chunk-QN33PNHL-aWjw7low.js",revision:null},{url:"assets/chunk-FMBD7UC4-B-XoLeQw.js",revision:null},{url:"assets/chunk-DI55MBZ5-Dor0sVJI.js",revision:null},{url:"assets/chunk-B4BG7PRW-BD6WP8Dt.js",revision:null},{url:"assets/chunk-55IACEB6-dQzh7akv.js",revision:null},{url:"assets/chunk-4BX2VUAB-82LsI6ZO.js",revision:null},{url:"assets/chat-CR1al33K.js",revision:null},{url:"assets/channel-uO_MEpg2.js",revision:null},{url:"assets/c4Diagram-YG6GDRKO-xM4z28t2.js",revision:null},{url:"assets/blockDiagram-VD42YOAC-DFZc3bbp.js",revision:null},{url:"assets/architectureDiagram-VXUJARFQ-D3hZ4FnX.js",revision:null},{url:"assets/arc-BfzAnNAP.js",revision:null},{url:"assets/_baseUniq-Blm_akxr.js",revision:null},{url:"assets/_basePickBy-BruevaAz.js",revision:null},{url:"assets/WidgetDemoPage-D7wMN-ak.js",revision:null},{url:"assets/WidgetDemoPage-BSWX2CxO.css",revision:null},{url:"assets/ThreadNode-Jt8WlAUM.js",revision:null},{url:"assets/SongGrid.vue_vue_type_script_setup_true_lang-BGfZFkPO.js",revision:null},{url:"assets/SongGrid-BjgAbnhC.js",revision:null},{url:"assets/SongDetail.vue_vue_type_script_setup_true_lang-B41kpCIv.js",revision:null},{url:"assets/SongDetail-DedB-36E.js",revision:null},{url:"assets/GuidePage-BvYaLEzG.css",revision:null},{url:"assets/GuidePage-BHJ1yOj7.js",revision:null},{url:"assets/FilmGrid.vue_vue_type_script_setup_true_lang-BDhsWNsb.js",revision:null},{url:"assets/FilmGrid-Ce24sGyN.js",revision:null},{url:"assets/FilmDetail.vue_vue_type_script_setup_true_lang-TCAQqc_e.js",revision:null},{url:"assets/FilmDetail-D1axS-VK.js",revision:null},{url:"assets/ConversationViewerPage-BEZVAgnq.js",revision:null},{url:"assets/ChatWindow.vue_vue_type_script_setup_true_lang-CiskBM0U.js",revision:null},{url:"assets/ChatWindow-KqUPCuYg.css",revision:null},{url:"assets/ChatPage-UEkXBR6z.css",revision:null},{url:"assets/ChatPage-0cJYh78p.js",revision:null},{url:"assets/BrowsePage-DDnfUhk3.js",revision:null},{url:"assets/icons/microphone.svg",revision:null},{url:"apple-touch-icon-180x180.png",revision:"7c24333289dd2af70268ed3018b06188"},{url:"favicon.svg",revision:"72e74ad8f660d9400c34fa69912b94a3"},{url:"icon.svg",revision:"dba94027bbb3b869c0ebf9b6beee1953"},{url:"pwa-192x192.png",revision:"b808488f273b70ad731254043774b56f"},{url:"pwa-512x512.png",revision:"93c28a922e11a852a2ff9c277dc60037"},{url:"manifest.webmanifest",revision:"28fc12e11969e378feb1aaa569dafb80"}],{}),s.cleanupOutdatedCaches(),s.registerRoute(new s.NavigationRoute(s.createHandlerBoundToURL("index.html"))),s.registerRoute(/^https:\/\/api\.anthropic\.com\/.*/i,new s.NetworkOnly,"GET"),s.registerRoute(/^https:\/\/openrouter\.ai\/.*/i,new s.NetworkOnly,"GET"),s.registerRoute(/\/api\/web-search\?.*/i,new s.NetworkOnly,"GET"),s.registerRoute(/\/api\/ollama\/.*/i,new s.NetworkOnly,"GET"),s.registerRoute(/\/api\/rss-articles\?.*/i,new s.NetworkOnly,"GET"),s.registerRoute(/\/api\/tmdb\/.*/i,new s.StaleWhileRevalidate({cacheName:"tmdb-cache",plugins:[new s.ExpirationPlugin({maxEntries:200,maxAgeSeconds:86400})]}),"GET"),s.registerRoute(/^https:\/\/image\.tmdb\.org\/.*/i,new s.CacheFirst({cacheName:"tmdb-images",plugins:[new s.ExpirationPlugin({maxEntries:500,maxAgeSeconds:604800})]}),"GET"),s.registerRoute(/^https:\/\/upload\.wikimedia\.org\/.*/i,new s.CacheFirst({cacheName:"wiki-images",plugins:[new s.ExpirationPlugin({maxEntries:200,maxAgeSeconds:604800})]}),"GET"),s.registerRoute(/^https:\/\/d12wklypp119aj\.cloudfront\.net\/image\/.*/i,new s.CacheFirst({cacheName:"wavlake-images",plugins:[new s.ExpirationPlugin({maxEntries:300,maxAgeSeconds:604800})]}),"GET")}); +if(!self.define){let s,e={};const i=(i,l)=>(i=new URL(i+".js",l).href,e[i]||new Promise(e=>{if("document"in self){const s=document.createElement("script");s.src=i,s.onload=e,document.head.appendChild(s)}else s=i,importScripts(i),e()}).then(()=>{let s=e[i];if(!s)throw new Error(`Module ${i} didn’t register its module`);return s}));self.define=(l,n)=>{const r=s||("document"in self?document.currentScript.src:"")||location.href;if(e[r])return;let a={};const u=s=>i(s,r),t={module:{uri:r},exports:a,require:u};e[r]=Promise.all(l.map(s=>t[s]||u(s))).then(s=>(n(...s),a))}}define(["./workbox-3c177d20"],function(s){"use strict";self.skipWaiting(),s.clientsClaim(),s.precacheAndRoute([{url:"registerSW.js",revision:"c492f944af160ee2e9a237c509dd270a"},{url:"index.html",revision:"43b4546ee8edc33febfebaca63124268"},{url:"icon.svg",revision:"dba94027bbb3b869c0ebf9b6beee1953"},{url:"favicon.svg",revision:"72e74ad8f660d9400c34fa69912b94a3"},{url:"images/loading-poster.svg",revision:"97c56238c72450e4953e1d7db2f6e8e6"},{url:"assets/xychartDiagram-PRI3JC2R-CAhXzwZ1.js",revision:null},{url:"assets/wikipedia-BNDKhpH7.js",revision:null},{url:"assets/useNostr-DYbkCQxC.js",revision:null},{url:"assets/useContentImages-CagIZs4M.js",revision:null},{url:"assets/treemap-GDKQZRPO-yRLasM0b.js",revision:null},{url:"assets/timeline-definition-IT6M3QCI-D5HR-Z95.js",revision:null},{url:"assets/stateDiagram-v2-4FDKWEC3-DCr2kVu5.js",revision:null},{url:"assets/stateDiagram-FKZM4ZOC-VzKqVF4W.js",revision:null},{url:"assets/song-renderer-DRNqTHD0.js",revision:null},{url:"assets/sequenceDiagram-WL72ISMW-BukSiqtq.js",revision:null},{url:"assets/seedPrompts-CLWaUv28.js",revision:null},{url:"assets/sankeyDiagram-TZEHDZUN-DqQOGyyA.js",revision:null},{url:"assets/requirementDiagram-UZGBJVZJ-BhL2HWfZ.js",revision:null},{url:"assets/quadrantDiagram-AYHSOK5B-Bp8ks7mP.js",revision:null},{url:"assets/pieDiagram-ADFJNKIX-DskAbgnA.js",revision:null},{url:"assets/ordinal-Cboi1Yqb.js",revision:null},{url:"assets/openlibrary-B8IPeH2e.js",revision:null},{url:"assets/ollama-provider-Ck1Tq0Ld.js",revision:null},{url:"assets/nodeDemoPrompts-DjnuaxJP.js",revision:null},{url:"assets/mindmap-definition-VGOIOE7T-BbRYcaHR.js",revision:null},{url:"assets/mermaid.core-DaNhpuX9.js",revision:null},{url:"assets/linear-BI0BnS_D.js",revision:null},{url:"assets/layout-T-4jL0RA.js",revision:null},{url:"assets/katex.min-CASE1JAf.css",revision:null},{url:"assets/katex-DGN8GczM.js",revision:null},{url:"assets/kanban-definition-3W4ZIXB7-4--rMebd.js",revision:null},{url:"assets/journeyDiagram-XKPGCS4Q-2pQB6VmZ.js",revision:null},{url:"assets/init-Gi6I4Gst.js",revision:null},{url:"assets/infoDiagram-HS3SLOUP-oVb3Z8wT.js",revision:null},{url:"assets/index-Lh5NfTCq.js",revision:null},{url:"assets/index-CHQ7uqBj.css",revision:null},{url:"assets/guideConversation-BYC5cBFP.js",revision:null},{url:"assets/graph-mkJTNBrq.js",revision:null},{url:"assets/gitGraphDiagram-V2S2FVAM-BTxiEL-p.js",revision:null},{url:"assets/ganttDiagram-JELNMOA3-DicMT2oN.js",revision:null},{url:"assets/freeFilms-B9DmMKj5.js",revision:null},{url:"assets/flowDiagram-NV44I4VS-D5zBfsz-.js",revision:null},{url:"assets/film-renderer-Ds7Zr4Tu.js",revision:null},{url:"assets/erDiagram-Q2GNP2WA-Ar7Pe8f0.js",revision:null},{url:"assets/diagram-S2PKOQOG-pDeg6Fn3.js",revision:null},{url:"assets/diagram-QEK2KX5R--DLuyaBU.js",revision:null},{url:"assets/diagram-PSM6KHXK-u9Bq7oQj.js",revision:null},{url:"assets/defaultLocale-DX6XiGOO.js",revision:null},{url:"assets/dagre-6UL2VRFP-pL4oLzgR.js",revision:null},{url:"assets/cytoscape.esm-5J0xJHOV.js",revision:null},{url:"assets/cose-bilkent-S5V4N54A-CceqRbLG.js",revision:null},{url:"assets/clone-CJT8Sng7.js",revision:null},{url:"assets/claude-provider-BpBBcvvu.js",revision:null},{url:"assets/classDiagram-v2-WZHVMYZB-pG5FcKCa.js",revision:null},{url:"assets/classDiagram-2ON5EDUG-pG5FcKCa.js",revision:null},{url:"assets/chunk-TZMSLE5B-Did4v35P.js",revision:null},{url:"assets/chunk-QZHKN3VN-BpY3MN1h.js",revision:null},{url:"assets/chunk-QN33PNHL-C8Gh8Kbh.js",revision:null},{url:"assets/chunk-FMBD7UC4-DGED6SBi.js",revision:null},{url:"assets/chunk-DI55MBZ5-CqWBFVaC.js",revision:null},{url:"assets/chunk-B4BG7PRW-1SR22WeC.js",revision:null},{url:"assets/chunk-55IACEB6-CWcaiZ1g.js",revision:null},{url:"assets/chunk-4BX2VUAB-WOh8BXBb.js",revision:null},{url:"assets/chat-BEnAHpY-.js",revision:null},{url:"assets/channel-DZA6uvxN.js",revision:null},{url:"assets/c4Diagram-YG6GDRKO-DqniwIVA.js",revision:null},{url:"assets/blockDiagram-VD42YOAC-DFxYaCGe.js",revision:null},{url:"assets/architectureDiagram-VXUJARFQ-CtiOagZF.js",revision:null},{url:"assets/arc-M-sFvFvX.js",revision:null},{url:"assets/_baseUniq-C5dU7AKy.js",revision:null},{url:"assets/_basePickBy-BlfxZvco.js",revision:null},{url:"assets/WidgetDemoPage-O5Vfu1LQ.js",revision:null},{url:"assets/WidgetDemoPage-BSWX2CxO.css",revision:null},{url:"assets/ThreadNode-Bt5yTyUn.js",revision:null},{url:"assets/SongGrid.vue_vue_type_script_setup_true_lang-CW1T9zpX.js",revision:null},{url:"assets/SongGrid-BgCYmw2O.js",revision:null},{url:"assets/SongDetail.vue_vue_type_script_setup_true_lang-CvC0ROCb.js",revision:null},{url:"assets/SongDetail-DCzBBkzH.js",revision:null},{url:"assets/GuidePage-CpiR8yAR.js",revision:null},{url:"assets/GuidePage-BvYaLEzG.css",revision:null},{url:"assets/FilmGrid.vue_vue_type_script_setup_true_lang-CWkUdZ32.js",revision:null},{url:"assets/FilmGrid-EKTg8OUS.js",revision:null},{url:"assets/FilmDetail.vue_vue_type_script_setup_true_lang-Cg4zvjy1.js",revision:null},{url:"assets/FilmDetail-XFjPooKR.js",revision:null},{url:"assets/ConversationViewerPage-1f3wXZHu.js",revision:null},{url:"assets/ChatWindow.vue_vue_type_script_setup_true_lang-DoshhDBV.js",revision:null},{url:"assets/ChatWindow-D6NcMh5O.css",revision:null},{url:"assets/ChatPage-UEkXBR6z.css",revision:null},{url:"assets/ChatPage-BOjiIMc2.js",revision:null},{url:"assets/BrowsePage-C71ADslt.js",revision:null},{url:"assets/icons/microphone.svg",revision:null},{url:"apple-touch-icon-180x180.png",revision:"7c24333289dd2af70268ed3018b06188"},{url:"favicon.svg",revision:"72e74ad8f660d9400c34fa69912b94a3"},{url:"icon.svg",revision:"dba94027bbb3b869c0ebf9b6beee1953"},{url:"pwa-192x192.png",revision:"b808488f273b70ad731254043774b56f"},{url:"pwa-512x512.png",revision:"93c28a922e11a852a2ff9c277dc60037"},{url:"manifest.webmanifest",revision:"28fc12e11969e378feb1aaa569dafb80"}],{}),s.cleanupOutdatedCaches(),s.registerRoute(new s.NavigationRoute(s.createHandlerBoundToURL("index.html"))),s.registerRoute(/^https:\/\/api\.anthropic\.com\/.*/i,new s.NetworkOnly,"GET"),s.registerRoute(/^https:\/\/openrouter\.ai\/.*/i,new s.NetworkOnly,"GET"),s.registerRoute(/\/api\/web-search\?.*/i,new s.NetworkOnly,"GET"),s.registerRoute(/\/api\/ollama\/.*/i,new s.NetworkOnly,"GET"),s.registerRoute(/\/api\/rss-articles\?.*/i,new s.NetworkOnly,"GET"),s.registerRoute(/\/api\/tmdb\/.*/i,new s.StaleWhileRevalidate({cacheName:"tmdb-cache",plugins:[new s.ExpirationPlugin({maxEntries:200,maxAgeSeconds:86400})]}),"GET"),s.registerRoute(/^https:\/\/image\.tmdb\.org\/.*/i,new s.CacheFirst({cacheName:"tmdb-images",plugins:[new s.ExpirationPlugin({maxEntries:500,maxAgeSeconds:604800})]}),"GET"),s.registerRoute(/^https:\/\/upload\.wikimedia\.org\/.*/i,new s.CacheFirst({cacheName:"wiki-images",plugins:[new s.ExpirationPlugin({maxEntries:200,maxAgeSeconds:604800})]}),"GET"),s.registerRoute(/^https:\/\/d12wklypp119aj\.cloudfront\.net\/image\/.*/i,new s.CacheFirst({cacheName:"wavlake-images",plugins:[new s.ExpirationPlugin({maxEntries:300,maxAgeSeconds:604800})]}),"GET")}); diff --git a/image-recipe/archipelago-scripts/install-to-disk.sh b/image-recipe/archipelago-scripts/install-to-disk.sh index 4d5c710e..7f50dc29 100755 --- a/image-recipe/archipelago-scripts/install-to-disk.sh +++ b/image-recipe/archipelago-scripts/install-to-disk.sh @@ -108,11 +108,11 @@ echo "📋 Installing base system..." # Install base system using debootstrap if command -v debootstrap >/dev/null 2>&1; then - debootstrap --arch=amd64 bookworm /mnt/archipelago http://deb.debian.org/debian + debootstrap --arch=amd64 trixie /mnt/archipelago http://deb.debian.org/debian else echo "❌ debootstrap not found. Installing..." apt-get update && apt-get install -y debootstrap - debootstrap --arch=amd64 bookworm /mnt/archipelago http://deb.debian.org/debian + debootstrap --arch=amd64 trixie /mnt/archipelago http://deb.debian.org/debian fi echo "⚙️ Configuring system..." @@ -149,9 +149,9 @@ echo "📦 Configuring package sources..." # Create sources.list cat > /mnt/archipelago/etc/apt/sources.list </dev/null; then + if ! $CONTAINER_CMD run --rm debian:trixie true 2>/dev/null; then echo " Root podman D-Bus issue detected, using cgroupfs manager" CONTAINER_CMD="podman --cgroup-manager=cgroupfs" fi @@ -239,7 +239,7 @@ if [ ! -f "$ROOTFS_TAR" ] || [ "$1" == "--rebuild" ]; then # Create a Dockerfile for building the rootfs cat > "$WORK_DIR/Dockerfile.rootfs" < /etc/apt/sources.list && \ - echo "deb http://deb.debian.org/debian bookworm-updates main non-free-firmware" >> /etc/apt/sources.list && \ - echo "deb http://deb.debian.org/debian-security bookworm-security main non-free-firmware" >> /etc/apt/sources.list && \ +RUN echo "deb http://deb.debian.org/debian trixie main non-free-firmware" > /etc/apt/sources.list && \ + echo "deb http://deb.debian.org/debian trixie-updates main non-free-firmware" >> /etc/apt/sources.list && \ + echo "deb http://deb.debian.org/debian-security trixie-security main non-free-firmware" >> /etc/apt/sources.list && \ rm -f /etc/apt/sources.list.d/debian.sources # Install all packages we need including nginx, podman, tor, and openssl (for self-signed certs) @@ -318,8 +318,8 @@ RUN find /usr/share/doc -depth -type f ! -name copyright -delete 2>/dev/null || find /usr/share/locale -maxdepth 1 -mindepth 1 ! -name 'en_US' ! -name 'locale.alias' -exec rm -rf {} + 2>/dev/null || true # Install Tailscale from official repo -RUN curl -fsSL https://pkgs.tailscale.com/stable/debian/bookworm.noarmor.gpg | tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null && \ - curl -fsSL https://pkgs.tailscale.com/stable/debian/bookworm.tailscale-keyring.list | tee /etc/apt/sources.list.d/tailscale.list && \ +RUN curl -fsSL https://pkgs.tailscale.com/stable/debian/trixie.noarmor.gpg | tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null && \ + curl -fsSL https://pkgs.tailscale.com/stable/debian/trixie.tailscale-keyring.list | tee /etc/apt/sources.list.d/tailscale.list && \ apt-get update && apt-get install -y --no-install-recommends tailscale && \ apt-get clean && rm -rf /var/lib/apt/lists/* @@ -582,7 +582,7 @@ $CONTAINER_CMD run --rm --privileged --platform $CONTAINER_PLATFORM \ -v "$WORK_DIR:/output" \ -e DEB_ARCH="$DEB_ARCH" \ -e LIB_DIR="$LIB_DIR" \ - debian:bookworm bash -c ' + debian:trixie bash -c ' set -e apt-get update -qq @@ -596,7 +596,7 @@ kmod,procps,iproute2,ca-certificates,gdisk,\ cryptsetup,cryptsetup-initramfs,parted,dosfstools,e2fsprogs,\ linux-image-${DEB_ARCH},grub-efi-${DEB_ARCH},grub-pc-bin,\ pciutils,usbutils,less,nano \ - bookworm /installer http://deb.debian.org/debian + trixie /installer http://deb.debian.org/debian # Install live-boot via chroot — debootstrap minbase resolver cannot handle it. # The chroot approach works (confirmed in CI run 90) — just needs proc/sys/dev mounts. @@ -948,7 +948,7 @@ if [ "$BACKEND_CAPTURED" = "0" ]; then fi BACKEND_DOCKERFILE="$WORK_DIR/Dockerfile.backend" cat > "$BACKEND_DOCKERFILE" <<'BACKENDFILE' -FROM rust:1.93-bookworm as builder +FROM rust:1.93-trixie as builder WORKDIR /build COPY core ./core RUN cd core && cargo build --release --bin archipelago @@ -967,17 +967,35 @@ BACKENDFILE fi # Extract NostrVPN binary from container image (native system service, not a container app) +# NOTE: The container image must be built against Debian 12's GLIBC (2.36). +# If built against a newer GLIBC (e.g. 2.39 from Ubuntu 24.10), the binary will fail +# at runtime with "GLIBC_2.39 not found". Rebuild with: FROM debian:12 AS builder echo " Extracting NostrVPN binary..." -NVPN_IMAGE="$($CONTAINER_CMD images -q 80.71.235.15:3000/archipelago/nostr-vpn:v0.3.7 2>/dev/null)" -if [ -z "$NVPN_IMAGE" ]; then - $CONTAINER_CMD pull 80.71.235.15:3000/archipelago/nostr-vpn:v0.3.7 2>/dev/null || true +_NVPN_IMG="${NOSTR_VPN_IMAGE:-80.71.235.15:3000/archipelago/nostr-vpn:v0.3.7}" +NVPN_IMAGE_ID="$($CONTAINER_CMD images -q "$_NVPN_IMG" 2>/dev/null)" +if [ -z "$NVPN_IMAGE_ID" ]; then + $CONTAINER_CMD pull "$_NVPN_IMG" 2>/dev/null || true fi -NVPN_CONTAINER=$($CONTAINER_CMD create 80.71.235.15:3000/archipelago/nostr-vpn:v0.3.7 2>/dev/null) || true +NVPN_CONTAINER=$($CONTAINER_CMD create "$_NVPN_IMG" 2>/dev/null) || true if [ -n "$NVPN_CONTAINER" ]; then $CONTAINER_CMD cp "$NVPN_CONTAINER:/usr/local/bin/nvpn" "$ARCH_DIR/bin/nvpn" 2>/dev/null && \ chmod +x "$ARCH_DIR/bin/nvpn" && \ echo " ✅ NostrVPN binary extracted ($(du -h "$ARCH_DIR/bin/nvpn" | cut -f1))" $CONTAINER_CMD rm "$NVPN_CONTAINER" 2>/dev/null || true + # Check GLIBC compatibility — Debian 12 has GLIBC 2.36 + if [ -f "$ARCH_DIR/bin/nvpn" ]; then + NVPN_GLIBC=$(objdump -T "$ARCH_DIR/bin/nvpn" 2>/dev/null | grep -oP 'GLIBC_\K[0-9.]+' | sort -V | tail -1) + if [ -n "$NVPN_GLIBC" ]; then + # Compare: if required GLIBC > 2.36, warn + if printf '%s\n' "2.36" "$NVPN_GLIBC" | sort -V | tail -1 | grep -qv "^2\.36$"; then + echo " ⚠ WARNING: nvpn binary requires GLIBC $NVPN_GLIBC but Debian 12 has 2.36" + echo " ⚠ The nvpn daemon will fail at runtime. Rebuild the container against Debian 12." + echo " ⚠ VPN invite/status will still work via Rust backend config.toml fallback." + else + echo " ✅ nvpn GLIBC compatibility OK (requires $NVPN_GLIBC, target has 2.36)" + fi + fi + fi else echo " ⚠ NostrVPN image not available — nvpn binary will be missing" fi diff --git a/image-recipe/configs/archipelago.service b/image-recipe/configs/archipelago.service index 9fdc9e60..dcebe306 100644 --- a/image-recipe/configs/archipelago.service +++ b/image-recipe/configs/archipelago.service @@ -34,15 +34,12 @@ NoNewPrivileges=no PrivateDevices=no SupplementaryGroups=dialout debian-tor -# Network restriction (allow IPv4/IPv6 + Unix sockets + netlink for WireGuard/VPN management) -RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK - -# Restrict what the process can do -# RestrictNamespaces disabled: rootless podman creates user namespaces -RestrictRealtime=yes - -# SystemCallFilter disabled: rootless podman needs clone/unshare for user namespaces -SystemCallArchitectures=native +# Network, syscall, and realtime restrictions DISABLED on Debian 12: +# RestrictAddressFamilies, SystemCallArchitectures, and RestrictRealtime all use +# seccomp filters that force no_new_privs=1 in the kernel (systemd 252). +# This blocks sudo, which is required for archipelago-wg (WireGuard peer management). +# Debian 13+ (systemd 256) respects NoNewPrivileges=no as an override, but Debian 12 does not. +# Re-enable these when dropping Debian 12 support. # MemoryDenyWriteExecute removed: ring (rustls) and secp256k1 (bitcoin/nostr) # use assembly code that requires executable memory mappings on some platforms diff --git a/image-recipe/configs/nginx-archipelago.conf b/image-recipe/configs/nginx-archipelago.conf index b5669a47..bb6d9cc8 100644 --- a/image-recipe/configs/nginx-archipelago.conf +++ b/image-recipe/configs/nginx-archipelago.conf @@ -21,8 +21,6 @@ server { # AIUI SPA (Chat mode iframe) — SPA fallback for client-side routing location /aiui/ { - alias /opt/archipelago/web-ui/aiui/; - index index.html; try_files $uri $uri/ /aiui/index.html; add_header Cache-Control "no-cache, no-store, must-revalidate"; } @@ -794,8 +792,6 @@ server { # AIUI SPA (Chat mode iframe) — SPA fallback for client-side routing location /aiui/ { - alias /opt/archipelago/web-ui/aiui/; - index index.html; try_files $uri $uri/ /aiui/index.html; add_header Cache-Control "no-cache, no-store, must-revalidate"; } diff --git a/image-recipe/configs/nostr-vpn.service b/image-recipe/configs/nostr-vpn.service index 235e1b85..19437a57 100644 --- a/image-recipe/configs/nostr-vpn.service +++ b/image-recipe/configs/nostr-vpn.service @@ -2,6 +2,8 @@ Description=Nostr VPN - Mesh VPN with Nostr identity After=network-online.target tor.service archipelago.service Wants=network-online.target +StartLimitIntervalSec=300 +StartLimitBurst=10 [Service] Type=simple @@ -13,8 +15,6 @@ ExecStartPre=/bin/bash -c 'test -f /var/lib/archipelago/nostr-vpn/env || { echo ExecStart=/usr/local/bin/nvpn daemon Restart=on-failure RestartSec=30 -StartLimitIntervalSec=300 -StartLimitBurst=10 TimeoutStartSec=30 TimeoutStopSec=10 diff --git a/scripts/first-boot-containers.sh b/scripts/first-boot-containers.sh index d3a8b7d3..e727360f 100644 --- a/scripts/first-boot-containers.sh +++ b/scripts/first-boot-containers.sh @@ -126,67 +126,96 @@ else fi # ── NostrVPN: configure native system service with node identity ────── -if command -v nvpn >/dev/null 2>&1; then - NOSTR_SECRET=$(cat /var/lib/archipelago/identity/nostr_secret 2>/dev/null) - NOSTR_PUBKEY=$(cat /var/lib/archipelago/identity/nostr_pubkey 2>/dev/null) - if [ -n "$NOSTR_SECRET" ]; then - # Initialize nvpn config if not already done - NVPN_CONFIG_DIR="/home/archipelago/.config/nvpn" - mkdir -p "$NVPN_CONFIG_DIR" +# The nvpn binary may have GLIBC mismatch (built for newer glibc than Debian 12). +# Write config.toml directly as fallback — the Rust backend reads it for vpn.invite/status. +NOSTR_SECRET=$(cat /var/lib/archipelago/identity/nostr_secret 2>/dev/null) +NOSTR_PUBKEY=$(cat /var/lib/archipelago/identity/nostr_pubkey 2>/dev/null) +if [ -n "$NOSTR_SECRET" ]; then + NVPN_CONFIG_DIR="/home/archipelago/.config/nvpn" + DAEMON_CONFIG_DIR="/var/lib/archipelago/nostr-vpn/.config/nvpn" + mkdir -p "$NVPN_CONFIG_DIR" "$DAEMON_CONFIG_DIR" + + # Try nvpn CLI first (may fail with GLIBC mismatch) + NVPN_CLI_OK=false + if command -v nvpn >/dev/null 2>&1; then if [ ! -f "$NVPN_CONFIG_DIR/config.toml" ]; then - # Run nvpn init as archipelago user to generate default config - su -l archipelago -c "nvpn init" 2>/dev/null || true + if su -l archipelago -c "nvpn init" 2>/dev/null; then + NVPN_CLI_OK=true + su -l archipelago -c "nvpn set --config '$NVPN_CONFIG_DIR/config.toml'" 2>/dev/null || true + else + log "NostrVPN: nvpn init failed (likely GLIBC mismatch) — using direct config" + fi + else + NVPN_CLI_OK=true fi - # Set the node's Nostr identity from onboarding seed phrase - su -l archipelago -c "nvpn set --config '$NVPN_CONFIG_DIR/config.toml'" 2>/dev/null || true + fi - # Get server's public IP for WireGuard endpoint - HOST_IP=$(cat /var/lib/archipelago/host-ip.env 2>/dev/null | grep ARCHIPELAGO_HOST_IP | cut -d= -f2) - [ -z "$HOST_IP" ] && HOST_IP=$(curl -s --connect-timeout 5 https://api.ipify.org 2>/dev/null || hostname -I | awk '{print $1}') + # Get server's public IP for WireGuard endpoint + HOST_IP=$(cat /var/lib/archipelago/host-ip.env 2>/dev/null | grep ARCHIPELAGO_HOST_IP | cut -d= -f2) + [ -z "$HOST_IP" ] && HOST_IP=$(curl -s --connect-timeout 5 https://api.ipify.org 2>/dev/null || hostname -I | awk '{print $1}') - # Configure nvpn with node identity and endpoint - if [ -f "$NVPN_CONFIG_DIR/config.toml" ]; then - su -l archipelago -c "nvpn set --endpoint '${HOST_IP}:51821'" 2>/dev/null || true - fi - - # Add this node's own relay as a signaling relay + if $NVPN_CLI_OK && [ -f "$NVPN_CONFIG_DIR/config.toml" ]; then + # nvpn CLI works — use it to configure + su -l archipelago -c "nvpn set --endpoint '${HOST_IP}:51821'" 2>/dev/null || true # Direct relay (public IP) — only if not behind NAT if [ -n "$HOST_IP" ] && ! echo "$HOST_IP" | grep -qE '^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.)'; then su -l archipelago -c "nvpn relay add 'ws://${HOST_IP}:7777'" 2>/dev/null || true fi - # Tor relay (works behind NAT) RELAY_ONION=$(cat /var/lib/archipelago/tor-hostnames/relay 2>/dev/null) if [ -n "$RELAY_ONION" ]; then su -l archipelago -c "nvpn relay add 'ws://${RELAY_ONION}:7777'" 2>/dev/null || true fi + fi - # Sync config to daemon HOME so the service finds it - # (service runs with HOME=/var/lib/archipelago/nostr-vpn) - # Owned by archipelago so the backend can update participants without sudo - DAEMON_CONFIG_DIR="/var/lib/archipelago/nostr-vpn/.config/nvpn" - mkdir -p "$DAEMON_CONFIG_DIR" - if [ -f "$NVPN_CONFIG_DIR/config.toml" ]; then - cp "$NVPN_CONFIG_DIR/config.toml" "$DAEMON_CONFIG_DIR/config.toml" + # Fallback: write config.toml directly if it doesn't exist yet. + # Uses hex keys — the Rust backend converts hex to npub1/nsec1 at read time. + if [ ! -f "$DAEMON_CONFIG_DIR/config.toml" ] && [ ! -f "$NVPN_CONFIG_DIR/config.toml" ]; then + # Build relay list + RELAYS="" + RELAY_ONION=$(cat /var/lib/archipelago/tor-hostnames/relay 2>/dev/null) + if [ -n "$RELAY_ONION" ]; then + RELAYS="\"ws://${RELAY_ONION}:7777\"" fi - chown -R archipelago:archipelago /var/lib/archipelago/nostr-vpn + if [ -n "$HOST_IP" ] && ! echo "$HOST_IP" | grep -qE '^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.)'; then + [ -n "$RELAYS" ] && RELAYS="$RELAYS, " + RELAYS="${RELAYS}\"ws://${HOST_IP}:7777\"" + fi + [ -z "$RELAYS" ] && RELAYS='"wss://relay.damus.io", "wss://relay.primal.net"' - # Ensure env file exists for the service - mkdir -p /var/lib/archipelago/nostr-vpn - cat > /var/lib/archipelago/nostr-vpn/env < "$DAEMON_CONFIG_DIR/config.toml" < /var/lib/archipelago/nostr-vpn/env </dev/null || true - systemctl enable --now nostr-vpn 2>/dev/null || true - log "NostrVPN configured with node identity and started" - else - log "NostrVPN: no Nostr identity yet — will configure after onboarding" - fi + # Start NostrVPN mesh service (standalone WG already started above) + systemctl reset-failed nostr-vpn 2>/dev/null || true + systemctl enable --now nostr-vpn 2>/dev/null || true + log "NostrVPN configured with node identity and started" else - log "NostrVPN binary not found — skipping VPN setup" + log "NostrVPN: no Nostr identity yet — will configure after onboarding" fi # Wait for a container to be healthy (accepting connections)