forked from coracle/flotilla
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 71dcfae5ff | |||
| 04155f5b23 | |||
| b4058389ec | |||
| 483fa81b74 | |||
| a8d1c4bbbc | |||
| 0a8c2faa74 | |||
| dd3231e70f | |||
| 7ff9c00032 | |||
| 9ed483abf7 | |||
| b9aeaf29a4 | |||
| 65e3f81f36 | |||
| c6641dba31 | |||
| e48d1e0e59 | |||
| d1e5aee84e | |||
| 5cb22d0bed | |||
| d1c6f53d7c | |||
| 6e238f98c0 | |||
| 290274d6c8 | |||
| e1de0239c9 | |||
| bec77d59e8 | |||
| 84f8794d7c | |||
| 4cddf41bf3 | |||
| 125a7e238e | |||
| 468200b717 | |||
| bdfcb99781 | |||
| 38da650861 | |||
| dd006badfc | |||
| 87e4e3fe5b | |||
| af3e38254f | |||
| 70843f54d3 | |||
| bda75b29b4 |
+2
-1
@@ -1,4 +1,5 @@
|
||||
VITE_DEFAULT_PUBKEYS=06639a386c9c1014217622ccbcf40908c4f1a0c33e23f8d6d68f4abf655f8f71,266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5,391819e2f2f13b90cac7209419eb574ef7c0d1f4e81867fc24c47a3ce5e8a248,3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d,3f770d65d3a764a9c5cb503ae123e62ec7598ad035d836e2a810f3877a745b24,55f04590674f3648f4cdc9dc8ce32da2a282074cd0b020596ee033d12d385185,58c741aa630c2da35a56a77c1d05381908bd10504fdd2d8b43f725efa6d23196,61066504617ee79387021e18c89fb79d1ddbc3e7bff19cf2298f40466f8715e9,6389be6491e7b693e9f368ece88fcd145f07c068d2c1bbae4247b9b5ef439d32,63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed,6e75f7972397ca3295e0f4ca0fbc6eb9cc79be85bafdd56bd378220ca8eee74e,76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa,7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194,82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2,84dee6e676e5bb67b4ad4e042cf70cbd8681155db535942fcc6a0533858a7240,97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322,b676ded7c768d66a757aa3967b1243d90bf57afb09d1044d3219d8d424e4aea0,dace63b00c42e6e017d00dd190a9328386002ff597b841eb5ef91de4f1ce8491,eeb11961b25442b16389fe6c7ebea9adf0ac36dd596816ea7119e521b8821b9e,fe7f6bc6f7338b76bbf80db402ade65953e20b2f23e66e898204b63cc42539a3
|
||||
VITE_DEFAULT_BLOSSOM_SERVERS=https://blossom.primal.net/
|
||||
VITE_BURROW_URL=
|
||||
VITE_PLATFORM_URL=https://flotilla.social
|
||||
VITE_PLATFORM_TERMS=https://flotilla.social/terms
|
||||
@@ -10,7 +11,7 @@ VITE_PLATFORM_ACCENT="#7161FF"
|
||||
VITE_PLATFORM_SECONDARY="#EB5E28"
|
||||
VITE_PLATFORM_DESCRIPTION="Flotilla is nostr — for communities."
|
||||
VITE_INDEXER_RELAYS=wss://purplepag.es/,wss://relay.damus.io/,wss://relay.nostr.band/,wss://indexer.coracle.social/
|
||||
VITE_SIGNER_RELAYS=wss://relay.nsec.app/,wss://bucket.coracle.social/
|
||||
VITE_SIGNER_RELAYS=wss://relay.nsec.app/,wss://offchain.pub/
|
||||
VITE_NOTIFIER_PUBKEY=27b7c2ed89ef78322114225ea3ebf5f72c7767c2528d4d0c1854d039c00085df
|
||||
VITE_NOTIFIER_RELAY=wss://anchor.coracle.social/
|
||||
VITE_VAPID_PUBLIC_KEY=BIt2D4BdgdbCowD_0d3Np6GbrIGHxd7aIEUeZNe3hQuRlHz02OhzvDaai0XSFoJYVzSzdMjdyW-QhvW9_yq8j4Y
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
# 1.3.0
|
||||
|
||||
* Add optional badge and sound for notifications
|
||||
* Improve link rendering
|
||||
* Remove imgproxy
|
||||
* Bring back blossom feature detection for spaces
|
||||
* Improve light theme
|
||||
* Add more info to signer status
|
||||
* Simplify navigation for adding a space
|
||||
* Add ability to scan QR code for invite links
|
||||
* Streamline wallet setup and move receive address setting
|
||||
* Remove indexeddb on mobile, use capacitor file storage API
|
||||
* Fix duplicate DMs showing up
|
||||
|
||||
# 1.2.5
|
||||
|
||||
* Fix icons in build
|
||||
|
||||
@@ -7,8 +7,8 @@ android {
|
||||
applicationId "social.flotilla"
|
||||
minSdk rootProject.ext.minSdkVersion
|
||||
targetSdk rootProject.ext.targetSdkVersion
|
||||
versionCode 26
|
||||
versionName "1.2.5"
|
||||
versionCode 27
|
||||
versionName "1.3.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
aaptOptions {
|
||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||
|
||||
@@ -11,6 +11,7 @@ apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||
dependencies {
|
||||
implementation project(':capacitor-community-safe-area')
|
||||
implementation project(':capacitor-app')
|
||||
implementation project(':capacitor-filesystem')
|
||||
implementation project(':capacitor-keyboard')
|
||||
implementation project(':capacitor-preferences')
|
||||
implementation project(':capacitor-push-notifications')
|
||||
|
||||
@@ -8,6 +8,9 @@ project(':capacitor-community-safe-area').projectDir = new File('../node_modules
|
||||
include ':capacitor-app'
|
||||
project(':capacitor-app').projectDir = new File('../node_modules/.pnpm/@capacitor+app@7.0.1_@capacitor+core@7.2.0/node_modules/@capacitor/app/android')
|
||||
|
||||
include ':capacitor-filesystem'
|
||||
project(':capacitor-filesystem').projectDir = new File('../node_modules/.pnpm/@capacitor+filesystem@7.1.4_@capacitor+core@7.2.0/node_modules/@capacitor/filesystem/android')
|
||||
|
||||
include ':capacitor-keyboard'
|
||||
project(':capacitor-keyboard').projectDir = new File('../node_modules/.pnpm/@capacitor+keyboard@7.0.1_@capacitor+core@7.2.0/node_modules/@capacitor/keyboard/android')
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; };
|
||||
3478F0332E846FEB002431E0 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3478F0322E846FEB002431E0 /* PrivacyInfo.xcprivacy */; };
|
||||
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
|
||||
504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
|
||||
504EC30D1FED79650016851F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30B1FED79650016851F /* Main.storyboard */; };
|
||||
@@ -21,6 +22,7 @@
|
||||
051414282E0CC28400BE0BC8 /* Flotilla Chat.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Flotilla Chat.entitlements"; sourceTree = "<group>"; };
|
||||
1F53EE54954731A2328CBC4B /* Pods-Flotilla Chat.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Flotilla Chat.release.xcconfig"; path = "Pods/Target Support Files/Pods-Flotilla Chat/Pods-Flotilla Chat.release.xcconfig"; sourceTree = "<group>"; };
|
||||
2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
|
||||
3478F0322E846FEB002431E0 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; };
|
||||
504EC3041FED79650016851F /* Flotilla Chat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Flotilla Chat.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
504EC3071FED79650016851F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
@@ -58,6 +60,7 @@
|
||||
504EC2FB1FED79650016851F = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3478F0322E846FEB002431E0 /* PrivacyInfo.xcprivacy */,
|
||||
051414282E0CC28400BE0BC8 /* Flotilla Chat.entitlements */,
|
||||
504EC3061FED79650016851F /* App */,
|
||||
504EC3051FED79650016851F /* Products */,
|
||||
@@ -162,6 +165,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */,
|
||||
3478F0332E846FEB002431E0 /* PrivacyInfo.xcprivacy in Resources */,
|
||||
50B271D11FEDC1A000F3C39B /* public in Resources */,
|
||||
504EC30F1FED79650016851F /* Assets.xcassets in Resources */,
|
||||
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
|
||||
@@ -354,14 +358,14 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "Flotilla Chat.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 18;
|
||||
CURRENT_PROJECT_VERSION = 19;
|
||||
DEVELOPMENT_TEAM = S26U9DYW3A;
|
||||
INFOPLIST_FILE = App/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "Flotilla Chat";
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 1.2.5;
|
||||
MARKETING_VERSION = 1.3.0;
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = social.flotilla;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -380,14 +384,14 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "Flotilla Chat.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 18;
|
||||
CURRENT_PROJECT_VERSION = 19;
|
||||
DEVELOPMENT_TEAM = S26U9DYW3A;
|
||||
INFOPLIST_FILE = App/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "Flotilla Chat";
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 1.2.5;
|
||||
MARKETING_VERSION = 1.3.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = social.flotilla;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
||||
@@ -13,6 +13,7 @@ def capacitor_pods
|
||||
pod 'CapacitorCordova', :path => '../../node_modules/.pnpm/@capacitor+ios@7.2.0_@capacitor+core@7.2.0/node_modules/@capacitor/ios'
|
||||
pod 'CapacitorCommunitySafeArea', :path => '../../node_modules/.pnpm/@capacitor-community+safe-area@7.0.0-alpha.1_@capacitor+core@7.2.0/node_modules/@capacitor-community/safe-area'
|
||||
pod 'CapacitorApp', :path => '../../node_modules/.pnpm/@capacitor+app@7.0.1_@capacitor+core@7.2.0/node_modules/@capacitor/app'
|
||||
pod 'CapacitorFilesystem', :path => '../../node_modules/.pnpm/@capacitor+filesystem@7.1.4_@capacitor+core@7.2.0/node_modules/@capacitor/filesystem'
|
||||
pod 'CapacitorKeyboard', :path => '../../node_modules/.pnpm/@capacitor+keyboard@7.0.1_@capacitor+core@7.2.0/node_modules/@capacitor/keyboard'
|
||||
pod 'CapacitorPreferences', :path => '../../node_modules/.pnpm/@capacitor+preferences@7.0.2_@capacitor+core@7.2.0/node_modules/@capacitor/preferences'
|
||||
pod 'CapacitorPushNotifications', :path => '../../node_modules/.pnpm/@capacitor+push-notifications@7.0.1_@capacitor+core@7.2.0/node_modules/@capacitor/push-notifications'
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>C617.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
+13
-12
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "flotilla",
|
||||
"version": "1.2.5",
|
||||
"version": "1.3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
@@ -43,6 +43,7 @@
|
||||
"@capacitor/app": "^7.0.0",
|
||||
"@capacitor/cli": "^7.0.0",
|
||||
"@capacitor/core": "^7.0.1",
|
||||
"@capacitor/filesystem": "^7.0.0",
|
||||
"@capacitor/ios": "^7.0.0",
|
||||
"@capacitor/keyboard": "^7.0.0",
|
||||
"@capacitor/preferences": "^7.0.2",
|
||||
@@ -58,17 +59,17 @@
|
||||
"@types/throttle-debounce": "^5.0.2",
|
||||
"@vite-pwa/assets-generator": "^0.2.6",
|
||||
"@vite-pwa/sveltekit": "^0.6.6",
|
||||
"@welshman/app": "^0.4.7",
|
||||
"@welshman/content": "^0.4.7",
|
||||
"@welshman/editor": "^0.4.7",
|
||||
"@welshman/feeds": "^0.4.7",
|
||||
"@welshman/lib": "^0.4.7",
|
||||
"@welshman/net": "^0.4.7",
|
||||
"@welshman/relay": "^0.4.7",
|
||||
"@welshman/router": "^0.4.7",
|
||||
"@welshman/signer": "^0.4.7",
|
||||
"@welshman/store": "^0.4.7",
|
||||
"@welshman/util": "^0.4.7",
|
||||
"@welshman/app": "^0.5.1",
|
||||
"@welshman/content": "^0.5.1",
|
||||
"@welshman/editor": "^0.5.1",
|
||||
"@welshman/feeds": "^0.5.1",
|
||||
"@welshman/lib": "^0.5.1",
|
||||
"@welshman/net": "^0.5.1",
|
||||
"@welshman/relay": "^0.5.1",
|
||||
"@welshman/router": "^0.5.1",
|
||||
"@welshman/signer": "^0.5.1",
|
||||
"@welshman/store": "^0.5.1",
|
||||
"@welshman/util": "^0.5.1",
|
||||
"compressorjs": "^1.2.1",
|
||||
"daisyui": "^4.12.10",
|
||||
"date-picker-svelte": "^2.13.0",
|
||||
|
||||
Generated
+174
-157
@@ -23,6 +23,9 @@ importers:
|
||||
'@capacitor/core':
|
||||
specifier: ^7.0.1
|
||||
version: 7.2.0
|
||||
'@capacitor/filesystem':
|
||||
specifier: ^7.0.0
|
||||
version: 7.1.4(@capacitor/core@7.2.0)
|
||||
'@capacitor/ios':
|
||||
specifier: ^7.0.0
|
||||
version: 7.2.0(@capacitor/core@7.2.0)
|
||||
@@ -69,38 +72,38 @@ importers:
|
||||
specifier: ^0.6.6
|
||||
version: 0.6.8(@sveltejs/kit@2.20.5(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.25.10)(vite@5.4.17(@types/node@22.14.0)(terser@5.39.0)))(svelte@5.25.10)(vite@5.4.17(@types/node@22.14.0)(terser@5.39.0)))(@vite-pwa/assets-generator@0.2.6)(vite-plugin-pwa@0.21.2(@vite-pwa/assets-generator@0.2.6)(vite@5.4.17(@types/node@22.14.0)(terser@5.39.0))(workbox-build@7.3.0)(workbox-window@7.3.0))
|
||||
'@welshman/app':
|
||||
specifier: ^0.4.7
|
||||
version: 0.4.7(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/content':
|
||||
specifier: ^0.4.7
|
||||
version: 0.4.7(typescript@5.8.3)
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1(typescript@5.8.3)
|
||||
'@welshman/editor':
|
||||
specifier: ^0.4.7
|
||||
version: 0.4.7(@tiptap/extension-image@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)))(@tiptap/extension-link@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0))(linkifyjs@4.3.1)(prosemirror-markdown@1.13.2)(prosemirror-model@1.25.1)(prosemirror-state@1.4.3)(prosemirror-view@1.39.3)(tiptap-markdown@0.8.10(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)))(typescript@5.8.3)
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1(@tiptap/extension-image@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)))(@tiptap/extension-link@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0))(linkifyjs@4.3.2)(prosemirror-markdown@1.13.2)(prosemirror-model@1.25.1)(prosemirror-state@1.4.3)(prosemirror-view@1.39.3)(tiptap-markdown@0.8.10(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)))(typescript@5.8.3)
|
||||
'@welshman/feeds':
|
||||
specifier: ^0.4.7
|
||||
version: 0.4.7(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/lib':
|
||||
specifier: ^0.4.7
|
||||
version: 0.4.7
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1
|
||||
'@welshman/net':
|
||||
specifier: ^0.4.7
|
||||
version: 0.4.7(typescript@5.8.3)(ws@8.18.3)
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/relay':
|
||||
specifier: ^0.4.7
|
||||
version: 0.4.7(typescript@5.8.3)
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1(typescript@5.8.3)
|
||||
'@welshman/router':
|
||||
specifier: ^0.4.7
|
||||
version: 0.4.7(typescript@5.8.3)
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1(typescript@5.8.3)
|
||||
'@welshman/signer':
|
||||
specifier: ^0.4.7
|
||||
version: 0.4.7(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/store':
|
||||
specifier: ^0.4.7
|
||||
version: 0.4.7(typescript@5.8.3)
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1(typescript@5.8.3)
|
||||
'@welshman/util':
|
||||
specifier: ^0.4.7
|
||||
version: 0.4.7(typescript@5.8.3)
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1(typescript@5.8.3)
|
||||
compressorjs:
|
||||
specifier: ^1.2.1
|
||||
version: 1.2.1
|
||||
@@ -754,6 +757,11 @@ packages:
|
||||
'@capacitor/core@7.2.0':
|
||||
resolution: {integrity: sha512-2zCnA6RJeZ9ec4470o8QMZEQTWpekw9FNoqm5TLc10jeCrhvHVI8MPgxdZVc3mOdFlyieYu4AS1fNxSqbS57Pw==}
|
||||
|
||||
'@capacitor/filesystem@7.1.4':
|
||||
resolution: {integrity: sha512-BdUnOVulHAtruW2GeC9o7e9LO5aFcVYqNn3dLypJSOck/WipUFNfI0QWoUS0FVGeqBbDJgFGi3zjXJx0lzbDkA==}
|
||||
peerDependencies:
|
||||
'@capacitor/core': '>=7.0.0'
|
||||
|
||||
'@capacitor/ios@7.2.0':
|
||||
resolution: {integrity: sha512-MQgRZcXZpbpjN83bjkGrzQd7s3XeHBZplmWf38/msF/siMGJKLrXNmNzmmPIWA5Xpi/aH6UoJFk1wXuU2U+zMg==}
|
||||
peerDependencies:
|
||||
@@ -774,6 +782,9 @@ packages:
|
||||
peerDependencies:
|
||||
'@capacitor/core': '>=7.0.0'
|
||||
|
||||
'@capacitor/synapse@1.0.4':
|
||||
resolution: {integrity: sha512-/C1FUo8/OkKuAT4nCIu/34ny9siNHr9qtFezu4kxm6GY1wNFxrCFWjfYx5C1tUhVGz3fxBABegupkpjXvjCHrw==}
|
||||
|
||||
'@capawesome/capacitor-android-dark-mode-support@7.0.0':
|
||||
resolution: {integrity: sha512-xLa988v9MEnFZj7Aje3v2vvYbs5U3zk8vaO24OioXUV1ZPjGy4R2VkdoKG8fTsSYRdF6s4/8DpCuos8JLJqpjw==}
|
||||
peerDependencies:
|
||||
@@ -1089,8 +1100,8 @@ packages:
|
||||
'@noble/curves@1.2.0':
|
||||
resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==}
|
||||
|
||||
'@noble/curves@1.9.2':
|
||||
resolution: {integrity: sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==}
|
||||
'@noble/curves@1.9.7':
|
||||
resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==}
|
||||
engines: {node: ^14.21.3 || >=16}
|
||||
|
||||
'@noble/hashes@1.3.1':
|
||||
@@ -1419,77 +1430,77 @@ packages:
|
||||
peerDependencies:
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-code-block@2.26.1':
|
||||
resolution: {integrity: sha512-/TDDOwONl0qEUc4+B6V9NnWtSjz95eg7/8uCb8Y8iRbGvI9vT4/znRKofFxstvKmW4URu/H74/g0ywV57h0B+A==}
|
||||
'@tiptap/extension-code-block@2.26.2':
|
||||
resolution: {integrity: sha512-MJZ4QtziIWJ1zuSW2ogAHv+UHGk3DvGbVi+Dfmo0ybonXX7vRVHE+3qT7OcdTRBF+pC2oCnsjzqwFcGBP3BbZw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-code@2.26.1':
|
||||
resolution: {integrity: sha512-GU9deB1A/Tr4FMPu71CvlcjGKwRhGYz60wQ8m4aM+ELZcVIcZRa1ebR8bExRIEWnvRztQuyRiCQzw2N0xQJ1QQ==}
|
||||
'@tiptap/extension-code@2.26.2':
|
||||
resolution: {integrity: sha512-xnKJvzlAp75dheyaK5tLKAksHf9PtSr8a7OuPjf2IXS5K+QMtnwxx7KAHHijmecfWjLR0wyu9AvT/FWFfKi5LQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-document@2.26.1':
|
||||
resolution: {integrity: sha512-2P2IZp1NRAE+21mRuFBiP3X2WKfZ6kUC23NJKpn8bcOamY3obYqCt0ltGPhE4eR8n8QAl2fI/3jIgjR07dC8ow==}
|
||||
'@tiptap/extension-document@2.26.2':
|
||||
resolution: {integrity: sha512-s0/P3A8zxWL/h3e20xWMTT/rcwD0+57I6mT9JgNBPtvhPePy8d698G6/qFK+x+GdIyjJylfsq2BrSE9H+QhIBg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-dropcursor@2.26.1':
|
||||
resolution: {integrity: sha512-JkDQU2ZYFOuT5mNYb8OiWGwD1HcjbtmX8tLNugQbToECmz9WvVPqJmn7V/q8VGpP81iEECz/IsyRmuf2kSD4uA==}
|
||||
'@tiptap/extension-dropcursor@2.26.2':
|
||||
resolution: {integrity: sha512-o5j4Gkurb/WBu1wP2tihYnZ8dENzmlxFWWMx++g6abEpn9xdud7VxHT5Ny7mBSBptI8uMwKT53weYC0on38n3g==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-gapcursor@2.26.1':
|
||||
resolution: {integrity: sha512-KOiMZc3PwJS3hR0nSq5d0TJi2jkNZkLZElcT6pCEnhRHzPH6dRMu9GM5Jj798ZRUy0T9UFcKJalFZaDxnmRnpg==}
|
||||
'@tiptap/extension-gapcursor@2.26.2':
|
||||
resolution: {integrity: sha512-a68mi8V0mh058UrBIk23f50K5JGVeRZnF6ViptIleAD/Ny1K6VLjGCz6k190de+Tb9tnQLPEwwwDcy+ZnvCmYQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-hard-break@2.26.1':
|
||||
resolution: {integrity: sha512-d6uStdNKi8kjPlHAyO59M6KGWATNwhLCD7dng0NXfwGndc22fthzIk/6j9F6ltQx30huy5qQram6j3JXwNACoA==}
|
||||
'@tiptap/extension-hard-break@2.26.2':
|
||||
resolution: {integrity: sha512-OLpeTey7p3ChyEsABLPvNv7rD/8E4k1JTt+H+MUjyL0dnrZuIWluckUJCJKnV8PhR9Mifngk1MTFUilpooiv1g==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-history@2.26.1':
|
||||
resolution: {integrity: sha512-m6YR1gkkauIDo3PRl0gP+7Oc4n5OqDzcjVh6LvWREmZP8nmi94hfseYbqOXUb6RPHIc0JKF02eiRifT4MSd2nw==}
|
||||
'@tiptap/extension-history@2.26.2':
|
||||
resolution: {integrity: sha512-X/cu79AV5D2Z1QtuvKo/4/Rgl/Uti/n5V3QgCxFLQRCKTxHOCis+RlBCjBfOPztJX4T9QUE6lq20KqB47rsNwQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-image@2.26.1':
|
||||
resolution: {integrity: sha512-96+MaYBJebQlR/ik5W72GLUfXdEoxFs+6jsoERxbM5qEdhb7TEnodBFtWZOwgDO27kFd6rSNZuW9r5KJNtljEg==}
|
||||
'@tiptap/extension-image@2.26.2':
|
||||
resolution: {integrity: sha512-3gK+ETLiWGAUdyPDXDheNJ38OgQabSzZJ+1nQo9KWjI7P3LQ7/ctxLtT+hAFpxX0qMK4bnu5vZaItSXxE3ZtpQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-link@2.26.1':
|
||||
resolution: {integrity: sha512-7yfum5Jymkue/uOSTQPt2SmkZIdZx7t3QhZLqBU7R9ettkdSCBgEGok6N+scJM1R1Zes+maSckLm0JZw5BKYNA==}
|
||||
'@tiptap/extension-link@2.26.2':
|
||||
resolution: {integrity: sha512-rzYxx5wI1551ubPfW2pJ3V957cX/WAmbUI3q8Un+LlOsSmbddl+5BjlF5t/vl/pwaOv7FJAz9e29n877zkGOVQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-paragraph@2.26.1':
|
||||
resolution: {integrity: sha512-UezvM9VDRAVJlX1tykgHWSD1g3MKfVMWWZ+Tg+PE4+kizOwoYkRWznVPgCAxjmyHajxpCKRXgqTZkOxjJ9Kjzg==}
|
||||
'@tiptap/extension-paragraph@2.26.2':
|
||||
resolution: {integrity: sha512-dccyffm95nNT9arjxGOyv4/cOPF4XS5Osylccp9KYLrmiSTXEuzVIYtMXhXbc0UUdABGvbFQWi88tRxgeDTkgA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-placeholder@2.26.1':
|
||||
resolution: {integrity: sha512-MBlqbkd+63btY7Qu+SqrXvWjPwooGZDsLTtl7jp52BczBl61cq9yygglt9XpM11TFMBdySgdLHBrLtQ0B7fBlw==}
|
||||
'@tiptap/extension-placeholder@2.26.2':
|
||||
resolution: {integrity: sha512-XBTDcpEo7Zo/1+RhGnRxA2TF0elQW7EayUcV+lJ3f7HQ5lrb5NTnakYc1ydeZ8Ih6vUqbK2CQUsESe3UWHHgHg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-text@2.26.1':
|
||||
resolution: {integrity: sha512-p2n8WVMd/2vckdJlol24acaTDIZAhI7qle5cM75bn01sOEZoFlSw6SwINOULrUCzNJsYb43qrLEibZb4j2LeQw==}
|
||||
'@tiptap/extension-text@2.26.2':
|
||||
resolution: {integrity: sha512-Rb8Le/Li+EixQNc/pGkEJpLjozTjWYP9glaYfnjPtRVw4tHcd7khVm5mer0TQjonbBUjVC1zSuXv9gifXOv6DQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/pm@2.12.0':
|
||||
resolution: {integrity: sha512-TNzVwpeNzFfHAcYTOKqX9iU4fRxliyoZrCnERR+RRzeg7gWrXrCLubQt1WEx0sojMAfznshSL3M5HGsYjEbYwA==}
|
||||
|
||||
'@tiptap/suggestion@2.26.1':
|
||||
resolution: {integrity: sha512-iNWJdQN7h01keNoVwyCsdI7ZX11YkrexZjCnutWK17Dd72s3NYVTmQXu7saftwddT4nDdlczNxAFosrt0zMhcg==}
|
||||
'@tiptap/suggestion@2.26.2':
|
||||
resolution: {integrity: sha512-BtigI3xOJQbdNh2OeKN5wQDI/EPGN4GXdpoMHhENZeXKrX6PvWNaqjyLVsV3QiLgv6P352nZWcgo51wPXY2JgQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
@@ -1648,41 +1659,41 @@ packages:
|
||||
'@vite-pwa/assets-generator':
|
||||
optional: true
|
||||
|
||||
'@welshman/app@0.4.7':
|
||||
resolution: {integrity: sha512-JEgr3NhzDLeOoTSZ4+AESKhW+kwqYClLbLd6ccHV+Wa7hjoPJy2FlY3rDuppw9QSeTNCDEOvqCsjeWYz83lUBA==}
|
||||
'@welshman/app@0.5.1':
|
||||
resolution: {integrity: sha512-/7xRGdBQyCDh+av1yDSMEHeyQQy61IZATBUxaGT/0tjFObsBoiYtLSg6iWFr9b5eo9LYVi54EJOo1PX2PdzvTg==}
|
||||
|
||||
'@welshman/content@0.4.7':
|
||||
resolution: {integrity: sha512-PF2FqiE3QUybl0CwwaEI2aGCZIis2rbdvBgeafgPiHW7fRYROxUZdtcMy+MyiRfiV40uoBcYwu/N6hHCRU7Pag==}
|
||||
'@welshman/content@0.5.1':
|
||||
resolution: {integrity: sha512-Ft41yd5fdNgn+ZGO21zV2SSuwBGaKUw1l9HfpPvFbf+Ef+PYtRclOCIkZ3uo4OSASJu06lbumnBChgfkGn6AxA==}
|
||||
|
||||
'@welshman/editor@0.4.7':
|
||||
resolution: {integrity: sha512-K6XCLG+vVvVeEYPx+m/+Lfx/JO+NtvvIemCds6gFjY7ac+WaQuEQDP3kFGYQu69XiFXp/UZrIa+t7SezEpnU8A==}
|
||||
'@welshman/editor@0.5.1':
|
||||
resolution: {integrity: sha512-JuM2Sb9XaXLDNxEnmMVGzPZfkYXl8BicHXua4dETmhPuZV23UPTuv2m7y0K+yW56AStRnBtjgSzVanK/pJW5Xg==}
|
||||
|
||||
'@welshman/feeds@0.4.7':
|
||||
resolution: {integrity: sha512-aZQuTUD4aSkL0s2BkjwEpo5KTd9BKf/XiOssQrltLdc8NIsz8RIO0XLgCpFb0/dmqHRoJEqU/plIBy7AlleRCQ==}
|
||||
'@welshman/feeds@0.5.1':
|
||||
resolution: {integrity: sha512-9QOJERYlkmlQsiQH0OHA0CvoaE1r8lC2GsWn5cXv1XoskyR5q3HghKRC9MUtyx/vnO45irmy9SdBkVHz7WqXjg==}
|
||||
|
||||
'@welshman/lib@0.4.7':
|
||||
resolution: {integrity: sha512-VP3WO2ROo5pf2vHwnrdt6lQVTc8Eo52Ie+1/9ZzfTrSxtLrreSSxW3H+1oPDbHl3FXbDnQWdFWbxys6OxzKZWw==}
|
||||
'@welshman/lib@0.5.1':
|
||||
resolution: {integrity: sha512-XPttF23jzwwgdmd83d+AZPCxZbkoQfJhn6p+w3hr5gdvunmDp3xdBf+fegnQYv/HIDBMQOHzyM/XxUYmqNDheA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@welshman/net@0.4.7':
|
||||
resolution: {integrity: sha512-S0dGVqNAfo5cvBxIuaI2oEX0JUs2FuzkOcYXkMNB1plWzi1mBcskNCBWfFf/zHJYaqUoYjZ/tDARy64lge9m/w==}
|
||||
'@welshman/net@0.5.1':
|
||||
resolution: {integrity: sha512-NSgAgiJhJvme9ov2/JP+ehuao/WMpjcQNFkshGaoe+PtzpwMsBSz9rEiwuPpZwsz3/edPdv8DgJwOzL6rQM+bw==}
|
||||
|
||||
'@welshman/relay@0.4.7':
|
||||
resolution: {integrity: sha512-FkqYswNA3uT1NeJVHdEZ7p9jEPGCFMx4ci2y+h9o25rCDdxg3WUhqDSdc5d85sGTO0qG2pNnvNMfS/Du/nFlOA==}
|
||||
'@welshman/relay@0.5.1':
|
||||
resolution: {integrity: sha512-yyKvJt/3Vf2at7bqrGKPawHnuOVS1BKrMN8zyFLa49ntNi394+foWDkmMBEUZMdJBVVK5YVk/SQ0rJ2RkRj/gA==}
|
||||
|
||||
'@welshman/router@0.4.7':
|
||||
resolution: {integrity: sha512-HnB1qrKGNxL8HtC6p47yHUnaDHevi+IKtqWEVCIFMRf17GwINBc3wp3+d3pu9KBBXItFZz1awABvZK+pNKQcgg==}
|
||||
'@welshman/router@0.5.1':
|
||||
resolution: {integrity: sha512-jH9pNSc8C1yYhEjN3Y0b8SMPg7V3Pqa0QNEKplk/TqdXoMCRQhM1aez+DXXwp7lA1q7GAqfViQ//0DMYrvAS6A==}
|
||||
|
||||
'@welshman/signer@0.4.7':
|
||||
resolution: {integrity: sha512-V5Jdmblb2kPO5bAv1CzVrodZiwKpYYotmS6MFXfWmyrKKp+9B5KoMWzXt6yfd4HWYbEKEjLhbm1gzbckupW8Nw==}
|
||||
'@welshman/signer@0.5.1':
|
||||
resolution: {integrity: sha512-Ok8qUD7Mp7fHYXUxDnw0k0/fkiBxNomPXlt7EQ16RZ8ND9QayhP4U+MCXUGfIqzh89cPtwBnhZYofKsqaSWD0Q==}
|
||||
peerDependencies:
|
||||
nostr-signer-capacitor-plugin: ~0.0.4
|
||||
|
||||
'@welshman/store@0.4.7':
|
||||
resolution: {integrity: sha512-8PniW1AOOYFtLRYMuay62taumW7zgwtBmouwoMh08fBQjLb+c90V4g2cEGVWoyvKXSLzQkQppPlaqYzdSDqgwg==}
|
||||
'@welshman/store@0.5.1':
|
||||
resolution: {integrity: sha512-wuQt/RGMk1dkOfImGfnCm+dDMI0+6mFIRXC17nC3v8TT/k0HUY8+JXPgYo9PP5E98YK3zFpmdeqFmxj4Q4puGA==}
|
||||
|
||||
'@welshman/util@0.4.7':
|
||||
resolution: {integrity: sha512-FlmBiZeKlAEAAwyhu7cWtlfAxU3CWX7WQGn0NkCZaAjgGV3n8LIDjT1u9m1PmXirBT0+qFNGLWas3p72IQMLgg==}
|
||||
'@welshman/util@0.5.1':
|
||||
resolution: {integrity: sha512-8Hn0ONx2yc3l3D/7DMFkqIPlMU1b7CeMmEz+np43f5+X5y7iWJ3LGau2nJ6lSbIyM1WaxFl3++W691+bFPNz3Q==}
|
||||
|
||||
'@xml-tools/parser@1.0.11':
|
||||
resolution: {integrity: sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==}
|
||||
@@ -3079,8 +3090,8 @@ packages:
|
||||
resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
|
||||
hasBin: true
|
||||
|
||||
js-base64@3.7.7:
|
||||
resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==}
|
||||
js-base64@3.7.8:
|
||||
resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==}
|
||||
|
||||
js-tokens@4.0.0:
|
||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||
@@ -3185,8 +3196,8 @@ packages:
|
||||
linkify-it@5.0.0:
|
||||
resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
|
||||
|
||||
linkifyjs@4.3.1:
|
||||
resolution: {integrity: sha512-DRSlB9DKVW04c4SUdGvKK5FR6be45lTU9M76JnngqPeeGDqPwYc0zdUErtsNVMtxPXgUWV4HbXbnC4sNyBxkYg==}
|
||||
linkifyjs@4.3.2:
|
||||
resolution: {integrity: sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==}
|
||||
|
||||
load-json-file@4.0.0:
|
||||
resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==}
|
||||
@@ -3430,8 +3441,8 @@ packages:
|
||||
resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
nostr-editor@1.0.0:
|
||||
resolution: {integrity: sha512-+TL3G0m7WsXeEAitxzQhun7hyARxqRANjGIS2z9CBbniCGvT/Wz6YLgUnUysnBg3tmSgMZg5FWhaDPwfvdvbSw==}
|
||||
nostr-editor@1.0.1:
|
||||
resolution: {integrity: sha512-HXqXjxtIN0CcC7sLV5xYjEsQF0bFYLmNKxS75ya2yZGQ/z16U+uK6bb2Hd72QyqXlHXyWN0m24E5Gcws8/NhRQ==}
|
||||
engines: {node: '>=18.16.1'}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.6.6
|
||||
@@ -5601,6 +5612,11 @@ snapshots:
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@capacitor/filesystem@7.1.4(@capacitor/core@7.2.0)':
|
||||
dependencies:
|
||||
'@capacitor/core': 7.2.0
|
||||
'@capacitor/synapse': 1.0.4
|
||||
|
||||
'@capacitor/ios@7.2.0(@capacitor/core@7.2.0)':
|
||||
dependencies:
|
||||
'@capacitor/core': 7.2.0
|
||||
@@ -5617,6 +5633,8 @@ snapshots:
|
||||
dependencies:
|
||||
'@capacitor/core': 7.2.0
|
||||
|
||||
'@capacitor/synapse@1.0.4': {}
|
||||
|
||||
'@capawesome/capacitor-android-dark-mode-support@7.0.0(@capacitor/core@7.2.0)':
|
||||
dependencies:
|
||||
'@capacitor/core': 7.2.0
|
||||
@@ -5939,7 +5957,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@noble/hashes': 1.3.2
|
||||
|
||||
'@noble/curves@1.9.2':
|
||||
'@noble/curves@1.9.7':
|
||||
dependencies:
|
||||
'@noble/hashes': 1.8.0
|
||||
|
||||
@@ -6237,58 +6255,58 @@ snapshots:
|
||||
dependencies:
|
||||
'@tiptap/pm': 2.12.0
|
||||
|
||||
'@tiptap/extension-code-block@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)':
|
||||
'@tiptap/extension-code-block@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||
'@tiptap/pm': 2.12.0
|
||||
|
||||
'@tiptap/extension-code@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))':
|
||||
'@tiptap/extension-code@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||
|
||||
'@tiptap/extension-document@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))':
|
||||
'@tiptap/extension-document@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||
|
||||
'@tiptap/extension-dropcursor@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)':
|
||||
'@tiptap/extension-dropcursor@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||
'@tiptap/pm': 2.12.0
|
||||
|
||||
'@tiptap/extension-gapcursor@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)':
|
||||
'@tiptap/extension-gapcursor@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||
'@tiptap/pm': 2.12.0
|
||||
|
||||
'@tiptap/extension-hard-break@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))':
|
||||
'@tiptap/extension-hard-break@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||
|
||||
'@tiptap/extension-history@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)':
|
||||
'@tiptap/extension-history@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||
'@tiptap/pm': 2.12.0
|
||||
|
||||
'@tiptap/extension-image@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))':
|
||||
'@tiptap/extension-image@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||
|
||||
'@tiptap/extension-link@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)':
|
||||
'@tiptap/extension-link@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||
'@tiptap/pm': 2.12.0
|
||||
linkifyjs: 4.3.1
|
||||
linkifyjs: 4.3.2
|
||||
|
||||
'@tiptap/extension-paragraph@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))':
|
||||
'@tiptap/extension-paragraph@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||
|
||||
'@tiptap/extension-placeholder@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)':
|
||||
'@tiptap/extension-placeholder@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||
'@tiptap/pm': 2.12.0
|
||||
|
||||
'@tiptap/extension-text@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))':
|
||||
'@tiptap/extension-text@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||
|
||||
@@ -6313,7 +6331,7 @@ snapshots:
|
||||
prosemirror-transform: 1.10.4
|
||||
prosemirror-view: 1.39.3
|
||||
|
||||
'@tiptap/suggestion@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)':
|
||||
'@tiptap/suggestion@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||
'@tiptap/pm': 2.12.0
|
||||
@@ -6524,19 +6542,18 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@vite-pwa/assets-generator': 0.2.6
|
||||
|
||||
'@welshman/app@0.4.7(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)':
|
||||
'@welshman/app@0.5.1(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)':
|
||||
dependencies:
|
||||
'@types/throttle-debounce': 5.0.2
|
||||
'@welshman/feeds': 0.4.7(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/lib': 0.4.7
|
||||
'@welshman/net': 0.4.7(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/relay': 0.4.7(typescript@5.8.3)
|
||||
'@welshman/router': 0.4.7(typescript@5.8.3)
|
||||
'@welshman/signer': 0.4.7(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/store': 0.4.7(typescript@5.8.3)
|
||||
'@welshman/util': 0.4.7(typescript@5.8.3)
|
||||
'@welshman/feeds': 0.5.1(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/lib': 0.5.1
|
||||
'@welshman/net': 0.5.1(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/relay': 0.5.1(typescript@5.8.3)
|
||||
'@welshman/router': 0.5.1(typescript@5.8.3)
|
||||
'@welshman/signer': 0.5.1(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/store': 0.5.1(typescript@5.8.3)
|
||||
'@welshman/util': 0.5.1(typescript@5.8.3)
|
||||
fuse.js: 7.1.0
|
||||
idb: 8.0.2
|
||||
svelte: 4.2.20
|
||||
throttle-debounce: 5.0.2
|
||||
transitivePeerDependencies:
|
||||
@@ -6544,31 +6561,31 @@ snapshots:
|
||||
- typescript
|
||||
- ws
|
||||
|
||||
'@welshman/content@0.4.7(typescript@5.8.3)':
|
||||
'@welshman/content@0.5.1(typescript@5.8.3)':
|
||||
dependencies:
|
||||
'@braintree/sanitize-url': 7.1.1
|
||||
nostr-tools: 2.14.2(typescript@5.8.3)
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
|
||||
'@welshman/editor@0.4.7(@tiptap/extension-image@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)))(@tiptap/extension-link@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0))(linkifyjs@4.3.1)(prosemirror-markdown@1.13.2)(prosemirror-model@1.25.1)(prosemirror-state@1.4.3)(prosemirror-view@1.39.3)(tiptap-markdown@0.8.10(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)))(typescript@5.8.3)':
|
||||
'@welshman/editor@0.5.1(@tiptap/extension-image@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)))(@tiptap/extension-link@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0))(linkifyjs@4.3.2)(prosemirror-markdown@1.13.2)(prosemirror-model@1.25.1)(prosemirror-state@1.4.3)(prosemirror-view@1.39.3)(tiptap-markdown@0.8.10(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)))(typescript@5.8.3)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||
'@tiptap/extension-code': 2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
|
||||
'@tiptap/extension-code-block': 2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
|
||||
'@tiptap/extension-document': 2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
|
||||
'@tiptap/extension-dropcursor': 2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
|
||||
'@tiptap/extension-gapcursor': 2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
|
||||
'@tiptap/extension-hard-break': 2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
|
||||
'@tiptap/extension-history': 2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
|
||||
'@tiptap/extension-paragraph': 2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
|
||||
'@tiptap/extension-placeholder': 2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
|
||||
'@tiptap/extension-text': 2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
|
||||
'@tiptap/extension-code': 2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
|
||||
'@tiptap/extension-code-block': 2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
|
||||
'@tiptap/extension-document': 2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
|
||||
'@tiptap/extension-dropcursor': 2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
|
||||
'@tiptap/extension-gapcursor': 2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
|
||||
'@tiptap/extension-hard-break': 2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
|
||||
'@tiptap/extension-history': 2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
|
||||
'@tiptap/extension-paragraph': 2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
|
||||
'@tiptap/extension-placeholder': 2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
|
||||
'@tiptap/extension-text': 2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
|
||||
'@tiptap/pm': 2.12.0
|
||||
'@tiptap/suggestion': 2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
|
||||
'@welshman/lib': 0.4.7
|
||||
'@welshman/util': 0.4.7(typescript@5.8.3)
|
||||
nostr-editor: 1.0.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/extension-image@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)))(@tiptap/extension-link@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)(linkifyjs@4.3.1)(nostr-tools@2.14.2(typescript@5.8.3))(prosemirror-markdown@1.13.2)(prosemirror-model@1.25.1)(prosemirror-state@1.4.3)(prosemirror-view@1.39.3)(tiptap-markdown@0.8.10(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)))
|
||||
'@tiptap/suggestion': 2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
|
||||
'@welshman/lib': 0.5.1
|
||||
'@welshman/util': 0.5.1(typescript@5.8.3)
|
||||
nostr-editor: 1.0.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/extension-image@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)))(@tiptap/extension-link@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)(linkifyjs@4.3.2)(nostr-tools@2.14.2(typescript@5.8.3))(prosemirror-markdown@1.13.2)(prosemirror-model@1.25.1)(prosemirror-state@1.4.3)(prosemirror-view@1.39.3)(tiptap-markdown@0.8.10(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)))
|
||||
nostr-tools: 2.14.2(typescript@5.8.3)
|
||||
tippy.js: 6.3.7
|
||||
transitivePeerDependencies:
|
||||
@@ -6582,79 +6599,79 @@ snapshots:
|
||||
- tiptap-markdown
|
||||
- typescript
|
||||
|
||||
'@welshman/feeds@0.4.7(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)':
|
||||
'@welshman/feeds@0.5.1(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)':
|
||||
dependencies:
|
||||
'@welshman/lib': 0.4.7
|
||||
'@welshman/net': 0.4.7(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/relay': 0.4.7(typescript@5.8.3)
|
||||
'@welshman/router': 0.4.7(typescript@5.8.3)
|
||||
'@welshman/signer': 0.4.7(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/util': 0.4.7(typescript@5.8.3)
|
||||
'@welshman/lib': 0.5.1
|
||||
'@welshman/net': 0.5.1(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/relay': 0.5.1(typescript@5.8.3)
|
||||
'@welshman/router': 0.5.1(typescript@5.8.3)
|
||||
'@welshman/signer': 0.5.1(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/util': 0.5.1(typescript@5.8.3)
|
||||
trava: 1.2.1
|
||||
transitivePeerDependencies:
|
||||
- nostr-signer-capacitor-plugin
|
||||
- typescript
|
||||
- ws
|
||||
|
||||
'@welshman/lib@0.4.7':
|
||||
'@welshman/lib@0.5.1':
|
||||
dependencies:
|
||||
'@scure/base': 1.2.6
|
||||
'@types/events': 3.0.3
|
||||
events: 3.3.0
|
||||
|
||||
'@welshman/net@0.4.7(typescript@5.8.3)(ws@8.18.3)':
|
||||
'@welshman/net@0.5.1(typescript@5.8.3)(ws@8.18.3)':
|
||||
dependencies:
|
||||
'@welshman/lib': 0.4.7
|
||||
'@welshman/relay': 0.4.7(typescript@5.8.3)
|
||||
'@welshman/util': 0.4.7(typescript@5.8.3)
|
||||
'@welshman/lib': 0.5.1
|
||||
'@welshman/relay': 0.5.1(typescript@5.8.3)
|
||||
'@welshman/util': 0.5.1(typescript@5.8.3)
|
||||
events: 3.3.0
|
||||
isomorphic-ws: 5.0.0(ws@8.18.3)
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
- ws
|
||||
|
||||
'@welshman/relay@0.4.7(typescript@5.8.3)':
|
||||
'@welshman/relay@0.5.1(typescript@5.8.3)':
|
||||
dependencies:
|
||||
'@welshman/lib': 0.4.7
|
||||
'@welshman/util': 0.4.7(typescript@5.8.3)
|
||||
'@welshman/lib': 0.5.1
|
||||
'@welshman/util': 0.5.1(typescript@5.8.3)
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
|
||||
'@welshman/router@0.4.7(typescript@5.8.3)':
|
||||
'@welshman/router@0.5.1(typescript@5.8.3)':
|
||||
dependencies:
|
||||
'@welshman/lib': 0.4.7
|
||||
'@welshman/relay': 0.4.7(typescript@5.8.3)
|
||||
'@welshman/util': 0.4.7(typescript@5.8.3)
|
||||
'@welshman/lib': 0.5.1
|
||||
'@welshman/relay': 0.5.1(typescript@5.8.3)
|
||||
'@welshman/util': 0.5.1(typescript@5.8.3)
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
|
||||
'@welshman/signer@0.4.7(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)':
|
||||
'@welshman/signer@0.5.1(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)':
|
||||
dependencies:
|
||||
'@noble/curves': 1.9.2
|
||||
'@noble/curves': 1.9.7
|
||||
'@noble/hashes': 1.8.0
|
||||
'@welshman/lib': 0.4.7
|
||||
'@welshman/net': 0.4.7(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/util': 0.4.7(typescript@5.8.3)
|
||||
'@welshman/lib': 0.5.1
|
||||
'@welshman/net': 0.5.1(typescript@5.8.3)(ws@8.18.3)
|
||||
'@welshman/util': 0.5.1(typescript@5.8.3)
|
||||
nostr-signer-capacitor-plugin: 0.0.4(@capacitor/core@7.2.0)
|
||||
nostr-tools: 2.14.2(typescript@5.8.3)
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
- ws
|
||||
|
||||
'@welshman/store@0.4.7(typescript@5.8.3)':
|
||||
'@welshman/store@0.5.1(typescript@5.8.3)':
|
||||
dependencies:
|
||||
'@welshman/lib': 0.4.7
|
||||
'@welshman/relay': 0.4.7(typescript@5.8.3)
|
||||
'@welshman/util': 0.4.7(typescript@5.8.3)
|
||||
'@welshman/lib': 0.5.1
|
||||
'@welshman/relay': 0.5.1(typescript@5.8.3)
|
||||
'@welshman/util': 0.5.1(typescript@5.8.3)
|
||||
svelte: 4.2.20
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
|
||||
'@welshman/util@0.4.7(typescript@5.8.3)':
|
||||
'@welshman/util@0.5.1(typescript@5.8.3)':
|
||||
dependencies:
|
||||
'@types/ws': 8.18.1
|
||||
'@welshman/lib': 0.4.7
|
||||
js-base64: 3.7.7
|
||||
'@welshman/lib': 0.5.1
|
||||
js-base64: 3.7.8
|
||||
nostr-tools: 2.14.2(typescript@5.8.3)
|
||||
nostr-wasm: 0.1.0
|
||||
transitivePeerDependencies:
|
||||
@@ -8174,7 +8191,7 @@ snapshots:
|
||||
|
||||
jiti@1.21.7: {}
|
||||
|
||||
js-base64@3.7.7: {}
|
||||
js-base64@3.7.8: {}
|
||||
|
||||
js-tokens@4.0.0: {}
|
||||
|
||||
@@ -8249,7 +8266,7 @@ snapshots:
|
||||
dependencies:
|
||||
uc.micro: 2.1.0
|
||||
|
||||
linkifyjs@4.3.1: {}
|
||||
linkifyjs@4.3.2: {}
|
||||
|
||||
load-json-file@4.0.0:
|
||||
dependencies:
|
||||
@@ -8485,15 +8502,15 @@ snapshots:
|
||||
|
||||
normalize-range@0.1.2: {}
|
||||
|
||||
nostr-editor@1.0.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/extension-image@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)))(@tiptap/extension-link@2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)(linkifyjs@4.3.1)(nostr-tools@2.14.2(typescript@5.8.3))(prosemirror-markdown@1.13.2)(prosemirror-model@1.25.1)(prosemirror-state@1.4.3)(prosemirror-view@1.39.3)(tiptap-markdown@0.8.10(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))):
|
||||
nostr-editor@1.0.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/extension-image@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)))(@tiptap/extension-link@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)(linkifyjs@4.3.2)(nostr-tools@2.14.2(typescript@5.8.3))(prosemirror-markdown@1.13.2)(prosemirror-model@1.25.1)(prosemirror-state@1.4.3)(prosemirror-view@1.39.3)(tiptap-markdown@0.8.10(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))):
|
||||
dependencies:
|
||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||
'@tiptap/extension-image': 2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
|
||||
'@tiptap/extension-link': 2.26.1(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
|
||||
'@tiptap/extension-image': 2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
|
||||
'@tiptap/extension-link': 2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
|
||||
'@tiptap/pm': 2.12.0
|
||||
js-base64: 3.7.7
|
||||
js-base64: 3.7.8
|
||||
light-bolt11-decoder: 3.2.0
|
||||
linkifyjs: 4.3.1
|
||||
linkifyjs: 4.3.2
|
||||
nostr-tools: 2.14.2(typescript@5.8.3)
|
||||
prosemirror-markdown: 1.13.2
|
||||
prosemirror-model: 1.25.1
|
||||
|
||||
+4
-8
@@ -62,6 +62,8 @@
|
||||
--primary-content: oklch(var(--pc));
|
||||
--secondary: oklch(var(--s));
|
||||
--secondary-content: oklch(var(--sc));
|
||||
--neutral: oklch(var(--n));
|
||||
--neutral-content: oklch(var(--nc));
|
||||
}
|
||||
|
||||
/* safe area insets */
|
||||
@@ -215,12 +217,6 @@
|
||||
@apply ellipsize;
|
||||
}
|
||||
|
||||
@media (max-width: 639px) {
|
||||
[data-tip]::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.content-padding-x {
|
||||
@apply px-4 sm:px-8 md:px-12;
|
||||
}
|
||||
@@ -278,8 +274,8 @@
|
||||
}
|
||||
|
||||
.tiptap {
|
||||
--tiptap-object-bg: var(--base-100);
|
||||
--tiptap-object-fg: var(--base-content);
|
||||
--tiptap-object-bg: var(--neutral);
|
||||
--tiptap-object-fg: var(--neutral-content);
|
||||
--tiptap-active-bg: var(--primary);
|
||||
--tiptap-active-fg: var(--primary-content);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import {getTagValue, getAddress} from "@welshman/util"
|
||||
import {isRelayFeed, findFeed} from "@welshman/feeds"
|
||||
import Inbox from "@assets/icons/inbox.svg?dataurl"
|
||||
import Bell from "@assets/icons/bell.svg?dataurl"
|
||||
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
@@ -10,8 +11,16 @@
|
||||
import AlertItem from "@app/components/AlertItem.svelte"
|
||||
import {pushModal} from "@app/util/modal"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
import {alerts, dmAlert, deriveAlertStatus, userInboxRelays, getAlertFeed} from "@app/core/state"
|
||||
import {
|
||||
alerts,
|
||||
dmAlert,
|
||||
deriveAlertStatus,
|
||||
userInboxRelays,
|
||||
getAlertFeed,
|
||||
userSettingsValues,
|
||||
} from "@app/core/state"
|
||||
import {deleteAlert, createDmAlert} from "@app/core/commands"
|
||||
import {clearBadges} from "../util/notifications"
|
||||
|
||||
type Props = {
|
||||
url?: string
|
||||
@@ -42,11 +51,11 @@
|
||||
const uncheckDmAlert = async (message: string) => {
|
||||
await sleep(100)
|
||||
|
||||
toggle.checked = false
|
||||
directMessagesNotificationToggle.checked = false
|
||||
pushToast({theme: "error", message})
|
||||
}
|
||||
|
||||
const onToggle = async () => {
|
||||
const onDirectMessagesNotificationToggle = async () => {
|
||||
if ($dmAlert) {
|
||||
deleteAlert($dmAlert)
|
||||
} else {
|
||||
@@ -64,7 +73,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
let toggle: HTMLInputElement
|
||||
const onShowBadgeOnUnreadToggle = async () => {
|
||||
$userSettingsValues.show_notifications_badge = !$userSettingsValues.show_notifications_badge
|
||||
|
||||
if (!$userSettingsValues.show_notifications_badge) {
|
||||
await clearBadges()
|
||||
}
|
||||
}
|
||||
|
||||
const onDirectMessagesNotificationSoundToggle = async () => {
|
||||
$userSettingsValues.play_notification_sound = !$userSettingsValues.play_notification_sound
|
||||
}
|
||||
|
||||
let directMessagesNotificationToggle: HTMLInputElement
|
||||
</script>
|
||||
|
||||
<div class="col-4">
|
||||
@@ -88,14 +109,36 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="card2 bg-alt flex flex-col gap-4 shadow-xl">
|
||||
<div class="flex items-center justify-between">
|
||||
<strong class="flex items-center gap-3">
|
||||
<Icon icon={Bell} />
|
||||
Notifications
|
||||
</strong>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<p>Notify me about new direct messages</p>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
bind:this={toggle}
|
||||
bind:this={directMessagesNotificationToggle}
|
||||
checked={Boolean($dmAlert)}
|
||||
oninput={onToggle} />
|
||||
oninput={onDirectMessagesNotificationToggle} />
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<p>Show badge for unread direct messages</p>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
checked={Boolean($userSettingsValues.show_notifications_badge)}
|
||||
oninput={onShowBadgeOnUnreadToggle} />
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<p>Play sound for new direct messages</p>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
checked={Boolean($userSettingsValues.play_notification_sound)}
|
||||
oninput={onDirectMessagesNotificationSoundToggle} />
|
||||
</div>
|
||||
{#if $dmStatus}
|
||||
{@const status = getTagValue("status", $dmStatus.tags) || "error"}
|
||||
|
||||
@@ -10,11 +10,10 @@
|
||||
import {makeEditor} from "@app/editor"
|
||||
|
||||
type Props = {
|
||||
url?: string
|
||||
onSubmit: (event: EventContent) => void
|
||||
}
|
||||
|
||||
const {onSubmit, url}: Props = $props()
|
||||
const {onSubmit}: Props = $props()
|
||||
|
||||
const autofocus = !isMobile
|
||||
|
||||
@@ -39,11 +38,11 @@
|
||||
}
|
||||
|
||||
const editor = makeEditor({
|
||||
url,
|
||||
autofocus,
|
||||
submit,
|
||||
uploading,
|
||||
aggressive: true,
|
||||
encryptFiles: true,
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -69,11 +69,11 @@
|
||||
|
||||
if (!parsed || hideMediaAtDepth <= depth) return false
|
||||
|
||||
if (isLink(parsed) && $userSettingsValues.show_media && isStartOrEnd(i)) {
|
||||
if (isLink(parsed) && $userSettingsValues.show_media && isStartAndEnd(i)) {
|
||||
return true
|
||||
}
|
||||
|
||||
if ((isEvent(parsed) || isAddress(parsed)) && isStartOrEnd(i)) {
|
||||
if ((isEvent(parsed) || isAddress(parsed)) && isStartAndEnd(i)) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -95,8 +95,6 @@
|
||||
|
||||
const isStartAndEnd = (i: number) => isStart(i) && isEnd(i)
|
||||
|
||||
const isStartOrEnd = (i: number) => isStart(i) || isEnd(i)
|
||||
|
||||
const ignoreWarning = () => {
|
||||
warning = null
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import type {ParsedEmojiValue} from "@welshman/content"
|
||||
import {imgproxy} from "@app/core/state"
|
||||
|
||||
export let value: ParsedEmojiValue
|
||||
|
||||
@@ -8,10 +7,7 @@
|
||||
</script>
|
||||
|
||||
{#if value.url}
|
||||
<img
|
||||
{alt}
|
||||
src={imgproxy(value.url, {w: 24, h: 24})}
|
||||
class="-mt-0.5 inline h-[1em] min-w-[1em] align-middle" />
|
||||
<img {alt} src={value.url} class="-mt-0.5 inline h-[1em] min-w-[1em] align-middle" />
|
||||
{:else}
|
||||
{alt}
|
||||
{/if}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import {ellipsize, displayUrl, postJson} from "@welshman/lib"
|
||||
import {dufflepud, imgproxy} from "@app/core/state"
|
||||
import {dufflepud} from "@app/core/state"
|
||||
import {preventDefault, stopPropagation} from "@lib/html"
|
||||
import Link from "@lib/components/Link.svelte"
|
||||
import ContentLinkDetail from "@app/components/ContentLinkDetail.svelte"
|
||||
@@ -51,7 +51,7 @@
|
||||
<img
|
||||
alt="Link preview"
|
||||
onerror={onError}
|
||||
src={imgproxy(preview.image)}
|
||||
src={preview.image}
|
||||
class="bg-alt max-h-72 rounded-t-box object-contain object-center" />
|
||||
{/if}
|
||||
<div class="flex flex-col gap-2 p-4">
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
<script lang="ts">
|
||||
import {onMount, onDestroy} from "svelte"
|
||||
import {displayUrl} from "@welshman/lib"
|
||||
import {getTags, decryptFile, getTagValue, tagsFromIMeta} from "@welshman/util"
|
||||
import {
|
||||
getTags,
|
||||
getBlob,
|
||||
decryptFile,
|
||||
getTagValue,
|
||||
tagsFromIMeta,
|
||||
makeBlossomAuthEvent,
|
||||
} from "@welshman/util"
|
||||
import {signer} from "@welshman/app"
|
||||
import LinkRound from "@assets/icons/link-round.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import {imgproxy} from "@app/core/state"
|
||||
|
||||
const {value, event, ...props} = $props()
|
||||
|
||||
@@ -14,18 +21,34 @@
|
||||
.map(tagsFromIMeta)
|
||||
.find(meta => getTagValue("url", meta) === url) || event.tags
|
||||
|
||||
const hash = getTagValue("x", meta)
|
||||
const key = getTagValue("decryption-key", meta)
|
||||
const nonce = getTagValue("decryption-nonce", meta)
|
||||
const algorithm = getTagValue("encryption-algorithm", meta)
|
||||
|
||||
const onError = () => {
|
||||
hasError = true
|
||||
const onError = async () => {
|
||||
// If the image failed to load, try authenticating
|
||||
if (hash && $signer) {
|
||||
const server = new URL(url).origin
|
||||
const template = makeBlossomAuthEvent({action: "get", server, hashes: [hash]})
|
||||
const authEvent = await $signer.sign(template)
|
||||
const res = await getBlob(server, hash, {authEvent})
|
||||
|
||||
if (res.status === 200) {
|
||||
src = URL.createObjectURL(await res.blob())
|
||||
} else {
|
||||
hasError = true
|
||||
}
|
||||
} else {
|
||||
hasError = true
|
||||
}
|
||||
}
|
||||
|
||||
let hasError = $state(false)
|
||||
let src = $state(imgproxy(url))
|
||||
let src = $state("")
|
||||
|
||||
onMount(async () => {
|
||||
// If we have an encryption algorithm, fetch and decrypt
|
||||
if (algorithm === "aes-gcm" && key && nonce) {
|
||||
const response = await fetch(url)
|
||||
|
||||
@@ -35,6 +58,8 @@
|
||||
|
||||
src = URL.createObjectURL(new Blob([decryptedData]))
|
||||
}
|
||||
} else {
|
||||
src = url
|
||||
}
|
||||
})
|
||||
|
||||
@@ -48,6 +73,6 @@
|
||||
<Icon icon={LinkRound} size={3} class="inline-block" />
|
||||
{displayUrl(url)}
|
||||
</a>
|
||||
{:else}
|
||||
{:else if src}
|
||||
<img alt="" {src} onerror={onError} {...props} />
|
||||
{/if}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
{/snippet}
|
||||
</CardButton>
|
||||
</Button>
|
||||
<Button onclick={signUp} class="dark:btn-neutral">
|
||||
<Button onclick={signUp} class="btn-neutral">
|
||||
<CardButton>
|
||||
{#snippet icon()}
|
||||
<div><Icon icon={AddCircle} size={7} /></div>
|
||||
|
||||
@@ -32,9 +32,10 @@
|
||||
onNostrConnect: async (response: Nip46ResponseWithResult) => {
|
||||
const pubkey = await controller.broker.getPublicKey()
|
||||
|
||||
loginWithNip46(pubkey, controller.clientSecret, response.event.pubkey, SIGNER_RELAYS)
|
||||
|
||||
await loadUserData(pubkey)
|
||||
|
||||
loginWithNip46(pubkey, controller.clientSecret, response.event.pubkey, SIGNER_RELAYS)
|
||||
setChecked("*")
|
||||
clearModals()
|
||||
},
|
||||
@@ -48,13 +49,20 @@
|
||||
try {
|
||||
const {signerPubkey, connectSecret, relays} = Nip46Broker.parseBunkerUrl($bunker)
|
||||
|
||||
if (!signerPubkey || relays.length === 0) {
|
||||
if (!signerPubkey) {
|
||||
return pushToast({
|
||||
theme: "error",
|
||||
message: "Sorry, it looks like that's an invalid bunker link.",
|
||||
})
|
||||
}
|
||||
|
||||
if (relays.length === 0) {
|
||||
return pushToast({
|
||||
theme: "error",
|
||||
message: "That bunker link does not include any relays.",
|
||||
})
|
||||
}
|
||||
|
||||
controller.loading.set(true)
|
||||
|
||||
const {clientSecret} = controller
|
||||
@@ -91,6 +99,7 @@
|
||||
}
|
||||
|
||||
const selectConnect = () => {
|
||||
controller.loading.set(false)
|
||||
mode = "connect"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import UserRounded from "@assets/icons/user-rounded.svg?dataurl"
|
||||
import Server from "@assets/icons/server.svg?dataurl"
|
||||
import Moon from "@assets/icons/moon.svg?dataurl"
|
||||
import Settings from "@assets/icons/settings-minimalistic.svg?dataurl"
|
||||
import Code2 from "@assets/icons/code-2.svg?dataurl"
|
||||
import Exit from "@assets/icons/logout-3.svg?dataurl"
|
||||
@@ -13,13 +14,16 @@
|
||||
import LogOut from "@app/components/LogOut.svelte"
|
||||
import {PLATFORM_NAME} from "@app/core/state"
|
||||
import {pushModal} from "@app/util/modal"
|
||||
import {theme} from "@app/util/theme"
|
||||
|
||||
const logout = () => pushModal(LogOut)
|
||||
|
||||
const toggleTheme = () => theme.set($theme === "dark" ? "light" : "dark")
|
||||
</script>
|
||||
|
||||
<div class="column menu gap-2">
|
||||
<Link replaceState href="/settings/profile">
|
||||
<CardButton class="dark:btn-neutral">
|
||||
<CardButton class="btn-neutral">
|
||||
{#snippet icon()}
|
||||
<div><Icon icon={UserRounded} size={7} /></div>
|
||||
{/snippet}
|
||||
@@ -32,7 +36,7 @@
|
||||
</CardButton>
|
||||
</Link>
|
||||
<Link replaceState href="/settings/alerts">
|
||||
<CardButton class="dark:btn-neutral">
|
||||
<CardButton class="btn-neutral">
|
||||
{#snippet icon()}
|
||||
<div><Icon icon={Bell} size={7} /></div>
|
||||
{/snippet}
|
||||
@@ -45,7 +49,7 @@
|
||||
</CardButton>
|
||||
</Link>
|
||||
<Link replaceState href="/settings/wallet">
|
||||
<CardButton class="dark:btn-neutral">
|
||||
<CardButton class="btn-neutral">
|
||||
{#snippet icon()}
|
||||
<div><Icon icon={Wallet} size={7} /></div>
|
||||
{/snippet}
|
||||
@@ -58,7 +62,7 @@
|
||||
</CardButton>
|
||||
</Link>
|
||||
<Link replaceState href="/settings/relays">
|
||||
<CardButton class="dark:btn-neutral">
|
||||
<CardButton class="btn-neutral">
|
||||
{#snippet icon()}
|
||||
<div><Icon icon={Server} size={7} /></div>
|
||||
{/snippet}
|
||||
@@ -71,7 +75,7 @@
|
||||
</CardButton>
|
||||
</Link>
|
||||
<Link replaceState href="/settings/content">
|
||||
<CardButton class="dark:btn-neutral">
|
||||
<CardButton class="btn-neutral">
|
||||
{#snippet icon()}
|
||||
<div><Icon icon={Settings} size={7} /></div>
|
||||
{/snippet}
|
||||
@@ -83,8 +87,21 @@
|
||||
{/snippet}
|
||||
</CardButton>
|
||||
</Link>
|
||||
<Button onclick={toggleTheme}>
|
||||
<CardButton class="btn-neutral">
|
||||
{#snippet icon()}
|
||||
<div><Icon icon={Moon} size={7} /></div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<div>Theme</div>
|
||||
{/snippet}
|
||||
{#snippet info()}
|
||||
<div>Switch between light and dark mode</div>
|
||||
{/snippet}
|
||||
</CardButton>
|
||||
</Button>
|
||||
<Link replaceState href="/settings/about">
|
||||
<CardButton class="dark:btn-neutral">
|
||||
<CardButton class="btn-neutral">
|
||||
{#snippet icon()}
|
||||
<div><Icon icon={Code2} size={7} /></div>
|
||||
{/snippet}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
<script lang="ts">
|
||||
import Login from "@assets/icons/login-3.svg?dataurl"
|
||||
import Compass from "@assets/icons/compass.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Link from "@lib/components/Link.svelte"
|
||||
import Divider from "@lib/components/Divider.svelte"
|
||||
import CardButton from "@lib/components/CardButton.svelte"
|
||||
import MenuSpacesItem from "@app/components/MenuSpacesItem.svelte"
|
||||
import SpaceAdd from "@app/components/SpaceAdd.svelte"
|
||||
import {userRoomsByUrl, PLATFORM_RELAYS} from "@app/core/state"
|
||||
import {pushModal} from "@app/util/modal"
|
||||
|
||||
const addSpace = () => pushModal(SpaceAdd)
|
||||
</script>
|
||||
|
||||
<div class="column menu gap-2">
|
||||
@@ -22,18 +18,18 @@
|
||||
{/each}
|
||||
<Divider />
|
||||
{/if}
|
||||
<Button onclick={addSpace}>
|
||||
<CardButton class="dark:btn-neutral">
|
||||
<Link href="/discover">
|
||||
<CardButton class="btn-neutral">
|
||||
{#snippet icon()}
|
||||
<div><Icon icon={Login} size={7} /></div>
|
||||
<div><Icon icon={Compass} size={7} /></div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<div>Add a space</div>
|
||||
<div>Explore Spaces</div>
|
||||
{/snippet}
|
||||
{#snippet info()}
|
||||
<div>Join or create a new space</div>
|
||||
<div>Join create, or browse spaces</div>
|
||||
{/snippet}
|
||||
</CardButton>
|
||||
</Button>
|
||||
</Link>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
</script>
|
||||
|
||||
<Link replaceState href={path}>
|
||||
<CardButton class="dark:btn-neutral">
|
||||
<CardButton class="btn-neutral">
|
||||
{#snippet icon()}
|
||||
<div><SpaceAvatar {url} /></div>
|
||||
{/snippet}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<script lang="ts">
|
||||
import {onMount} from "svelte"
|
||||
import {userSettingsValues} from "@app/core/state"
|
||||
import {notifications} from "../util/notifications"
|
||||
|
||||
let audioElement: HTMLAudioElement
|
||||
|
||||
let enabled = $state(false)
|
||||
|
||||
document.addEventListener("visibilitychange", () => {
|
||||
if (document.hidden) {
|
||||
enabled = true
|
||||
} else {
|
||||
enabled = false
|
||||
}
|
||||
})
|
||||
let notificationCount = $state($notifications.size)
|
||||
|
||||
const playSound = () => {
|
||||
if (enabled && $userSettingsValues.play_notification_sound) {
|
||||
audioElement.play()
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
audioElement.load()
|
||||
|
||||
notifications.subscribe(notifications => {
|
||||
if (notifications.size > notificationCount) {
|
||||
playSound()
|
||||
}
|
||||
|
||||
notificationCount = notifications.size
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<audio bind:this={audioElement} src="/new-notification-3-398649.mp3"></audio>
|
||||
@@ -18,7 +18,7 @@
|
||||
import {makeSpacePath} from "@app/util/routes"
|
||||
import {notifications} from "@app/util/notifications"
|
||||
import Widget from "@assets/icons/widget.svg?dataurl"
|
||||
import AddSquare from "@assets/icons/add-square.svg?dataurl"
|
||||
import Compass from "@assets/icons/compass.svg?dataurl"
|
||||
import Letter from "@assets/icons/letter.svg?dataurl"
|
||||
import Magnifier from "@assets/icons/magnifier.svg?dataurl"
|
||||
import HomeSmile from "@assets/icons/home-smile.svg?dataurl"
|
||||
@@ -31,8 +31,6 @@
|
||||
|
||||
const {children}: Props = $props()
|
||||
|
||||
const addSpace = () => pushModal(SpaceAdd)
|
||||
|
||||
const showSpacesMenu = () => (spaceUrls.length > 0 ? pushModal(MenuSpaces) : pushModal(SpaceAdd))
|
||||
|
||||
const showOtherSpacesMenu = () => pushModal(MenuOtherSpaces, {urls: secondarySpaceUrls})
|
||||
@@ -83,8 +81,8 @@
|
||||
<Avatar icon={Widget} class="!h-10 !w-10" />
|
||||
</PrimaryNavItem>
|
||||
{/if}
|
||||
<PrimaryNavItem title="Add Space" onclick={addSpace} class="tooltip-right">
|
||||
<Avatar icon={AddSquare} class="!h-10 !w-10" />
|
||||
<PrimaryNavItem title="Add a Space" href="/discover" class="tooltip-right">
|
||||
<Avatar icon={Compass} class="!h-10 !w-10" />
|
||||
</PrimaryNavItem>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
@@ -1,22 +1,13 @@
|
||||
<script lang="ts">
|
||||
import {nthNe} from "@welshman/lib"
|
||||
import type {Profile} from "@welshman/util"
|
||||
import {
|
||||
getTag,
|
||||
makeEvent,
|
||||
makeProfile,
|
||||
editProfile,
|
||||
createProfile,
|
||||
isPublishedProfile,
|
||||
uniqTags,
|
||||
} from "@welshman/util"
|
||||
import {Router} from "@welshman/router"
|
||||
import {pubkey, profilesByPubkey, publishThunk} from "@welshman/app"
|
||||
import {getTag, makeProfile} from "@welshman/util"
|
||||
import {pubkey, profilesByPubkey} from "@welshman/app"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import ProfileEditForm from "@app/components/ProfileEditForm.svelte"
|
||||
import {clearModals} from "@app/util/modal"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
import {PROTECTED, getMembershipUrls, userMembership} from "@app/core/state"
|
||||
import {PROTECTED} from "@app/core/state"
|
||||
import {updateProfile} from "../core/commands"
|
||||
|
||||
const profile = $profilesByPubkey.get($pubkey!) || makeProfile()
|
||||
const shouldBroadcast = !getTag(PROTECTED, profile.event?.tags || [])
|
||||
@@ -25,21 +16,7 @@
|
||||
const back = () => history.back()
|
||||
|
||||
const onsubmit = ({profile, shouldBroadcast}: {profile: Profile; shouldBroadcast: boolean}) => {
|
||||
const router = Router.get()
|
||||
const template = isPublishedProfile(profile) ? editProfile(profile) : createProfile(profile)
|
||||
const scenarios = [router.FromRelays(getMembershipUrls($userMembership))]
|
||||
|
||||
if (shouldBroadcast) {
|
||||
scenarios.push(router.FromUser(), router.Index())
|
||||
template.tags = template.tags.filter(nthNe(0, "-"))
|
||||
} else {
|
||||
template.tags = uniqTags([...template.tags, PROTECTED])
|
||||
}
|
||||
|
||||
const event = makeEvent(template.kind, template)
|
||||
const relays = router.merge(scenarios).getUrls()
|
||||
|
||||
publishThunk({event, relays})
|
||||
updateProfile({profile, shouldBroadcast})
|
||||
pushToast({message: "Your profile has been updated!"})
|
||||
clearModals()
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<Button class="max-w-full {props.class}" onclick={copy}>
|
||||
<div bind:this={wrapper} style={`height: ${height}px`}>
|
||||
<Button class="flex w-full justify-center {props.class}" onclick={copy}>
|
||||
<div bind:this={wrapper} class="w-md" style={`height: ${height}px`}>
|
||||
<canvas
|
||||
class="rounded-box"
|
||||
bind:this={canvas}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import {spec, prop, avg} from "@welshman/lib"
|
||||
import {signerLog, SignerLogEntryStatus} from "@welshman/app"
|
||||
import {session, SessionMethod, signerLog, SignerLogEntryStatus} from "@welshman/app"
|
||||
import CloseCircle from "@assets/icons/close-circle.svg?dataurl"
|
||||
import Danger from "@assets/icons/danger-triangle.svg?dataurl"
|
||||
import ClockCircle from "@assets/icons/clock-circle.svg?dataurl"
|
||||
@@ -26,27 +26,45 @@
|
||||
const logout = () => pushModal(LogOut)
|
||||
</script>
|
||||
|
||||
<div class="card2 bg-alt flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-xl font-bold">Signer Status</span>
|
||||
<span class="flex items-center gap-2">
|
||||
{#if isDisconnected}
|
||||
<Icon icon={CloseCircle} class="text-error" size={4} /> Disconnected
|
||||
{:else if recentFailure > 3}
|
||||
<Icon icon={Danger} class="text-warning" size={4} /> Partial Failure
|
||||
{:else if recentAvg > 1000 || recentPending > 3}
|
||||
<Icon icon={ClockCircle} class="text-warning" size={4} /> Slow connection
|
||||
{:else if recentSuccess === 0 && recentFailure > 0}{:else}
|
||||
<Icon icon={CheckCircle} class="text-success" size={4} /> Ok
|
||||
{/if}
|
||||
</span>
|
||||
{#if $session && $session.method !== SessionMethod.Anonymous}
|
||||
<div class="card2 bg-alt flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-xl font-bold">Signer Status</span>
|
||||
<span class="flex items-center gap-2">
|
||||
{#if isDisconnected}
|
||||
<Icon icon={CloseCircle} class="text-error" size={4} /> Disconnected
|
||||
{:else if recentFailure > 3}
|
||||
<Icon icon={Danger} class="text-warning" size={4} /> Partial Failure
|
||||
{:else if recentAvg > 1000 || recentPending > 3}
|
||||
<Icon icon={ClockCircle} class="text-warning" size={4} /> Slow connection
|
||||
{:else if recentSuccess === 0 && recentFailure > 0}{:else}
|
||||
<Icon icon={CheckCircle} class="text-success" size={4} /> Ok
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm opacity-75">
|
||||
<p>
|
||||
Logged in with
|
||||
{#if $session.method === SessionMethod.Nip01}
|
||||
private key
|
||||
{:else if $session.method === SessionMethod.Nip07}
|
||||
browser extension
|
||||
{:else if $session.method === SessionMethod.Nip46}
|
||||
remote signer
|
||||
{:else if $session.method === SessionMethod.Nip55}
|
||||
{$session.signer}
|
||||
{:else if $session.method === SessionMethod.Pubkey}
|
||||
public key (readonly)
|
||||
{/if}
|
||||
</p>
|
||||
<p>
|
||||
{success} requests succeeded, {failure} failed, {pending} pending
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm opacity-75">
|
||||
{success} requests succeeded, {failure} failed, {pending} pending
|
||||
</p>
|
||||
{#if isDisconnected}
|
||||
<Button class="btn btn-outline btn-error" onclick={logout}>Logout to Reconnect</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{#if isDisconnected}
|
||||
<Button class="btn btn-outline btn-error" onclick={logout}>Logout to Reconnect</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import {displayUrl} from "@welshman/lib"
|
||||
import {AuthStatus} from "@welshman/net"
|
||||
import {waitForThunkError} from "@welshman/app"
|
||||
import {preventDefault} from "@lib/html"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
@@ -15,7 +14,7 @@
|
||||
import SpaceJoinConfirm, {confirmSpaceJoin} from "@app/components/SpaceJoinConfirm.svelte"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
import {pushModal} from "@app/util/modal"
|
||||
import {publishJoinRequest} from "@app/core/commands"
|
||||
import {checkRelayAccess} from "@app/core/commands"
|
||||
import {deriveSocket} from "@app/core/state"
|
||||
|
||||
type Props = {
|
||||
@@ -32,11 +31,10 @@
|
||||
loading = true
|
||||
|
||||
try {
|
||||
const thunk = publishJoinRequest({url, claim})
|
||||
const error = await waitForThunkError(thunk)
|
||||
const message = await checkRelayAccess(url, claim)
|
||||
|
||||
if (error) {
|
||||
return pushToast({theme: "error", message: error, timeout: 30_000})
|
||||
if (message) {
|
||||
return pushToast({theme: "error", message, timeout: 30_000})
|
||||
}
|
||||
|
||||
if ($socket.auth.status === AuthStatus.None) {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<script lang="ts">
|
||||
import Compass from "@assets/icons/compass-big.svg?dataurl"
|
||||
import Login from "@assets/icons/login-3.svg?dataurl"
|
||||
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Link from "@lib/components/Link.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import CardButton from "@lib/components/CardButton.svelte"
|
||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||
@@ -25,21 +23,8 @@
|
||||
<div>Spaces are places where communities come together to work, play, and hang out.</div>
|
||||
{/snippet}
|
||||
</ModalHeader>
|
||||
<Link href="/discover">
|
||||
<CardButton class="btn-primary">
|
||||
{#snippet icon()}
|
||||
<div><Icon icon={Compass} size={7} /></div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<div>Discover spaces</div>
|
||||
{/snippet}
|
||||
{#snippet info()}
|
||||
<div>Browse spaces on the discover page.</div>
|
||||
{/snippet}
|
||||
</CardButton>
|
||||
</Link>
|
||||
<Button onclick={startJoin}>
|
||||
<CardButton class="dark:btn-neutral">
|
||||
<CardButton class="btn-primary">
|
||||
{#snippet icon()}
|
||||
<div><Icon icon={Login} size={7} /></div>
|
||||
{/snippet}
|
||||
@@ -47,12 +32,12 @@
|
||||
<div>Join a space</div>
|
||||
{/snippet}
|
||||
{#snippet info()}
|
||||
<div>Enter an invite code or url to join an existing space.</div>
|
||||
<div>Enter an invite link to join an existing space.</div>
|
||||
{/snippet}
|
||||
</CardButton>
|
||||
</Button>
|
||||
<Button onclick={startCreate}>
|
||||
<CardButton class="dark:btn-neutral">
|
||||
<CardButton class="btn-neutral">
|
||||
{#snippet icon()}
|
||||
<div><Icon icon={AddCircle} size={7} /></div>
|
||||
{/snippet}
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
import {sleep, nthEq} from "@welshman/lib"
|
||||
import {request} from "@welshman/net"
|
||||
import {displayRelayUrl, AUTH_INVITE} from "@welshman/util"
|
||||
import {slide} from "@lib/transition"
|
||||
import LinkRound from "@assets/icons/link-round.svg?dataurl"
|
||||
import Copy from "@assets/icons/copy.svg?dataurl"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import Field from "@lib/components/Field.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import LinkRound from "@assets/icons/link-round.svg?dataurl"
|
||||
import Copy from "@assets/icons/copy.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||
import QRCode from "@app/components/QRCode.svelte"
|
||||
import {clip} from "@app/util/toast"
|
||||
import {PLATFORM_URL} from "@app/core/state"
|
||||
|
||||
@@ -62,11 +62,12 @@
|
||||
</ModalHeader>
|
||||
<div>
|
||||
{#if loading}
|
||||
<p class="center" out:slide>
|
||||
<p class="center">
|
||||
<Spinner {loading}>Requesting an invite link...</Spinner>
|
||||
</p>
|
||||
{:else}
|
||||
<div in:slide>
|
||||
<div class="flex flex-col items-center gap-6">
|
||||
<QRCode code={invite} />
|
||||
<Field>
|
||||
{#snippet input()}
|
||||
<label class="input input-bordered flex w-full items-center gap-2">
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import {fade} from "@lib/transition"
|
||||
import CompassBig from "@assets/icons/compass-big.svg?dataurl"
|
||||
import NotesMinimalistic from "@assets/icons/notes-minimalistic.svg?dataurl"
|
||||
import StarFallMinimalistic from "@assets/icons/star-fall-minimalistic.svg?dataurl"
|
||||
import CalendarMinimalistic from "@assets/icons/calendar-minimalistic.svg?dataurl"
|
||||
import Magnifier from "@assets/icons/magnifier.svg?dataurl"
|
||||
import Lock from "@assets/icons/lock-keyhole.svg?dataurl"
|
||||
@@ -14,7 +15,7 @@
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import RoomCreate from "@app/components/RoomCreate.svelte"
|
||||
import ChannelName from "@app/components/ChannelName.svelte"
|
||||
import {makeThreadPath, makeCalendarPath, makeRoomPath, makeSpacePath} from "@app/util/routes"
|
||||
import {makeRoomPath, makeSpacePath} from "@app/util/routes"
|
||||
import {
|
||||
hasNip29,
|
||||
deriveUserRooms,
|
||||
@@ -34,8 +35,9 @@
|
||||
const userRooms = deriveUserRooms(url)
|
||||
const otherRooms = deriveOtherRooms(url)
|
||||
const chatPath = makeSpacePath(url, "chat")
|
||||
const threadsPath = makeThreadPath(url)
|
||||
const calendarPath = makeCalendarPath(url)
|
||||
const goalsPath = makeSpacePath(url, "goals")
|
||||
const threadsPath = makeSpacePath(url, "threads")
|
||||
const calendarPath = makeSpacePath(url, "calendar")
|
||||
|
||||
const addRoom = () => pushModal(RoomCreate, {url})
|
||||
|
||||
@@ -61,25 +63,37 @@
|
||||
Quick Links
|
||||
</h3>
|
||||
<div class="flex flex-col gap-2">
|
||||
<Link href={threadsPath} class="btn btn-primary w-full justify-start">
|
||||
<Link href={goalsPath} class="btn btn-neutral w-full justify-start">
|
||||
<div class="relative flex items-center gap-2">
|
||||
<Icon icon={NotesMinimalistic} />
|
||||
Threads
|
||||
{#if $notifications.has(threadsPath)}
|
||||
<Icon icon={StarFallMinimalistic} />
|
||||
Goals
|
||||
{#if $notifications.has(goalsPath)}
|
||||
<div
|
||||
class="absolute -right-3 -top-1 h-2 w-2 rounded-full bg-primary-content"
|
||||
class="absolute -right-3 -top-1 h-2 w-2 rounded-full bg-neutral-content"
|
||||
transition:fade>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Link>
|
||||
<Link href={calendarPath} class="btn btn-secondary w-full justify-start">
|
||||
<Link href={threadsPath} class="btn btn-neutral w-full justify-start">
|
||||
<div class="relative flex items-center gap-2">
|
||||
<Icon icon={NotesMinimalistic} />
|
||||
Threads
|
||||
{#if $notifications.has(threadsPath)}
|
||||
<div
|
||||
class="absolute -right-3 -top-1 h-2 w-2 rounded-full bg-neutral-content"
|
||||
transition:fade>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Link>
|
||||
<Link href={calendarPath} class="btn btn-neutral w-full justify-start">
|
||||
<div class="relative flex items-center gap-2">
|
||||
<Icon icon={CalendarMinimalistic} />
|
||||
Calendar
|
||||
{#if $notifications.has(calendarPath)}
|
||||
<div
|
||||
class="absolute -right-3 -top-1 h-2 w-2 rounded-full bg-primary-content"
|
||||
class="absolute -right-3 -top-1 h-2 w-2 rounded-full bg-neutral-content"
|
||||
transition:fade>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -46,8 +46,7 @@
|
||||
|
||||
{#if showFailure}
|
||||
{@const url = failedUrls[0]}
|
||||
{@const status = $thunk.status[url]}
|
||||
{@const message = $thunk.details[url]}
|
||||
{@const {status, detail: message} = $thunk.results[url]}
|
||||
<button
|
||||
class="flex w-full justify-end px-1 text-xs {restProps.class}"
|
||||
onclick={stopPropagation(noop)}>
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<script lang="ts">
|
||||
import {getWalletAddress} from "@welshman/util"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||
import {updateProfile} from "@app/core/commands"
|
||||
import {clearModals} from "@app/util/modal"
|
||||
import {userProfile, session} from "@welshman/app"
|
||||
import {makeProfile} from "@welshman/util"
|
||||
|
||||
const lud16 = getWalletAddress($session!.wallet!)
|
||||
|
||||
const confirm = async () => {
|
||||
const profile = $userProfile || makeProfile()
|
||||
|
||||
loading = true
|
||||
|
||||
try {
|
||||
await updateProfile({profile: {...profile, lud16}})
|
||||
|
||||
clearModals()
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
|
||||
const cancel = () => {
|
||||
clearModals()
|
||||
}
|
||||
|
||||
let loading = $state(false)
|
||||
</script>
|
||||
|
||||
<div class="column gap-4">
|
||||
<ModalHeader>
|
||||
{#snippet title()}
|
||||
Set as Receiving Address?
|
||||
{/snippet}
|
||||
</ModalHeader>
|
||||
{#if $userProfile?.lud16}
|
||||
<p>
|
||||
Your current receiving address is different from the one provided by your connected wallet.
|
||||
</p>
|
||||
<p>
|
||||
Would you like to update your receiving address to <span class="text-primary">{lud16}</span>?
|
||||
</p>
|
||||
{:else}
|
||||
<p>
|
||||
You don't currently have a receiving address set, which means other people can't send you
|
||||
lightning payments.
|
||||
</p>
|
||||
<p>Would you like to use the one associated with your connected wallet?</p>
|
||||
{/if}
|
||||
<ModalFooter>
|
||||
<Button class="btn btn-neutral" onclick={cancel} disabled={loading}>No, skip this</Button>
|
||||
<Button class="btn btn-primary" onclick={confirm} disabled={loading}>
|
||||
<Spinner {loading}>Yes, set as receiving address</Spinner>
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</div>
|
||||
@@ -3,7 +3,7 @@
|
||||
import {nwc} from "@getalby/sdk"
|
||||
import {sleep, assoc} from "@welshman/lib"
|
||||
import type {NWCInfo} from "@welshman/util"
|
||||
import {pubkey, updateSession} from "@welshman/app"
|
||||
import {pubkey, userProfile, updateSession} from "@welshman/app"
|
||||
import Link from "@lib/components/Link.svelte"
|
||||
import Cpu from "@assets/icons/cpu-bolt.svg?dataurl"
|
||||
import Lock from "@assets/icons/lock-keyhole.svg?dataurl"
|
||||
@@ -15,11 +15,13 @@
|
||||
import Scanner from "@lib/components/Scanner.svelte"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import Field from "@lib/components/Field.svelte"
|
||||
import Divider from "@lib/components/Divider.svelte"
|
||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||
import {getWebLn} from "@app/core/commands"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
import {pushModal} from "@app/util/modal"
|
||||
import WalletAsReceivingAddress from "@app/components/WalletAsReceivingAddress.svelte"
|
||||
import Divider from "@src/lib/components/Divider.svelte"
|
||||
|
||||
const back = () => history.back()
|
||||
|
||||
@@ -76,6 +78,10 @@
|
||||
await sleep(400)
|
||||
|
||||
back()
|
||||
|
||||
if (info.lud16 && info.lud16 !== $userProfile?.lud16) {
|
||||
pushModal(WalletAsReceivingAddress)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
@@ -109,7 +115,7 @@
|
||||
<div>Connect a Wallet</div>
|
||||
{/snippet}
|
||||
{#snippet info()}
|
||||
Use Nostr Wallet Connect to send Bitcoin payments over Bolt.
|
||||
Use Nostr Wallet Connect to send Bitcoin payments over lightning.
|
||||
{/snippet}
|
||||
</ModalHeader>
|
||||
{#if getWebLn()}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
<script lang="ts">
|
||||
import {getWalletAddress} from "@welshman/util"
|
||||
import {session, userProfile} from "@welshman/app"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||
import Wallet from "@assets/icons/wallet.svg?dataurl"
|
||||
import CheckCircle from "@assets/icons/check-circle.svg?dataurl"
|
||||
import {updateProfile} from "@app/core/commands"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
|
||||
const back = () => history.back()
|
||||
|
||||
let address = $state($userProfile?.lud16 || "")
|
||||
let isLoading = $state(false)
|
||||
|
||||
const walletLud16 = $derived($session?.wallet ? getWalletAddress($session.wallet) : undefined)
|
||||
|
||||
const useWalletAddress = () => {
|
||||
if (walletLud16) {
|
||||
address = walletLud16
|
||||
}
|
||||
}
|
||||
|
||||
const save = async () => {
|
||||
isLoading = true
|
||||
try {
|
||||
await updateProfile({
|
||||
profile: {
|
||||
...$userProfile,
|
||||
lud06: undefined,
|
||||
lud16: address.trim() || undefined,
|
||||
},
|
||||
})
|
||||
back()
|
||||
} catch (error) {
|
||||
pushToast({theme: "error", message: "Failed to update profile"})
|
||||
} finally {
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="column gap-4">
|
||||
<ModalHeader>
|
||||
{#snippet title()}
|
||||
Update Lightning Address
|
||||
{/snippet}
|
||||
{#snippet info()}
|
||||
Update your lightning address for receiving payments.
|
||||
{/snippet}
|
||||
</ModalHeader>
|
||||
|
||||
<div class="column gap-4">
|
||||
<div class="column gap-2">
|
||||
<span> Lightning Address </span>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="user@domain.com"
|
||||
bind:value={address}
|
||||
class="input input-bordered flex w-full"
|
||||
disabled={isLoading} />
|
||||
<p class="text-xs opacity-75">
|
||||
You can enter one manually or use your connected wallet's address (if available). Leave
|
||||
empty to remove your lightning address
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{#if walletLud16 && walletLud16 !== address}
|
||||
<div class="card bg-base-200 p-4">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<div class="column gap-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<Icon icon={Wallet} size={4} />
|
||||
<span class="text-sm font-medium">Wallet Address</span>
|
||||
</div>
|
||||
<p class="text-xs opacity-75">{walletLud16}</p>
|
||||
</div>
|
||||
<Button class="btn btn-outline btn-sm" onclick={useWalletAddress} disabled={isLoading}>
|
||||
Use This
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<ModalFooter>
|
||||
<Button class="btn btn-neutral" onclick={back} disabled={isLoading}>Cancel</Button>
|
||||
<Button class="btn btn-primary" onclick={save} disabled={isLoading}>
|
||||
{#if isLoading}
|
||||
<span class="loading loading-spinner loading-sm"></span>
|
||||
{:else}
|
||||
<Icon icon={CheckCircle} />
|
||||
{/if}
|
||||
Save Changes
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</div>
|
||||
+116
-41
@@ -3,6 +3,7 @@ import * as nip19 from "nostr-tools/nip19"
|
||||
import {get} from "svelte/store"
|
||||
import type {Override, MakeOptional} from "@welshman/lib"
|
||||
import {
|
||||
first,
|
||||
sha256,
|
||||
randomId,
|
||||
append,
|
||||
@@ -16,12 +17,15 @@ import {
|
||||
parseJson,
|
||||
fromPairs,
|
||||
last,
|
||||
simpleCache,
|
||||
normalizeUrl,
|
||||
nthNe,
|
||||
} from "@welshman/lib"
|
||||
import {decrypt, Nip01Signer} from "@welshman/signer"
|
||||
import type {UploadTask} from "@welshman/editor"
|
||||
import type {Feed} from "@welshman/feeds"
|
||||
import {makeIntersectionFeed, feedFromFilters, makeRelayFeed} from "@welshman/feeds"
|
||||
import type {TrustedEvent, EventContent} from "@welshman/util"
|
||||
import type {TrustedEvent, EventContent, Profile} from "@welshman/util"
|
||||
import {
|
||||
WRAP,
|
||||
DELETE,
|
||||
@@ -57,8 +61,13 @@ import {
|
||||
getTagValue,
|
||||
getTagValues,
|
||||
uploadBlob,
|
||||
canUploadBlob,
|
||||
encryptFile,
|
||||
makeBlossomAuthEvent,
|
||||
isPublishedProfile,
|
||||
editProfile,
|
||||
createProfile,
|
||||
uniqTags,
|
||||
} from "@welshman/util"
|
||||
import {Pool, AuthStatus, SocketStatus} from "@welshman/net"
|
||||
import {Router} from "@welshman/router"
|
||||
@@ -75,7 +84,6 @@ import {
|
||||
userInboxRelaySelections,
|
||||
nip44EncryptToSelf,
|
||||
loadRelay,
|
||||
clearStorage,
|
||||
dropSession,
|
||||
tagEventForComment,
|
||||
tagEventForQuote,
|
||||
@@ -92,15 +100,17 @@ import {
|
||||
INDEXER_RELAYS,
|
||||
NOTIFIER_PUBKEY,
|
||||
NOTIFIER_RELAY,
|
||||
DEFAULT_BLOSSOM_SERVERS,
|
||||
userRoomsByUrl,
|
||||
userSettingsValues,
|
||||
canDecrypt,
|
||||
ensureUnwrapped,
|
||||
userInboxRelays,
|
||||
getMembershipUrls,
|
||||
} from "@app/core/state"
|
||||
import {loadAlertStatuses} from "@app/core/requests"
|
||||
import {platform, platformName, getPushInfo} from "@app/util/push"
|
||||
import {preferencesStorageProvider} from "@src/lib/storage"
|
||||
import {preferencesStorageProvider, collectionStorageProvider} from "@src/lib/storage"
|
||||
|
||||
// Utils
|
||||
|
||||
@@ -143,10 +153,10 @@ export const logout = async () => {
|
||||
dropSession($pubkey)
|
||||
}
|
||||
|
||||
await clearStorage()
|
||||
|
||||
localStorage.clear()
|
||||
|
||||
await preferencesStorageProvider.clear()
|
||||
await collectionStorageProvider.clear()
|
||||
}
|
||||
|
||||
// Synchronization
|
||||
@@ -158,7 +168,7 @@ export const broadcastUserData = async (relays: string[]) => {
|
||||
|
||||
for (const event of events) {
|
||||
if (isSignedEvent(event)) {
|
||||
await publishThunk({event, relays}).result
|
||||
await publishThunk({event, relays}).complete
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -660,17 +670,53 @@ export const enableGiftWraps = () => {
|
||||
|
||||
// File upload
|
||||
|
||||
export const getBlossomServer = () => {
|
||||
export const normalizeBlossomUrl = (url: string) => normalizeUrl(url.replace(/^ws/, "http"))
|
||||
|
||||
export const hasBlossomSupport = simpleCache(async ([url]: [string]) => {
|
||||
const server = normalizeBlossomUrl(url)
|
||||
const $signer = signer.get() || Nip01Signer.ephemeral()
|
||||
const headers: Record<string, string> = {
|
||||
"X-Content-Type": "text/plain",
|
||||
"X-Content-Length": "1",
|
||||
"X-SHA-256": "73cb3858a687a8494ca3323053016282f3dad39d42cf62ca4e79dda2aac7d9ac",
|
||||
}
|
||||
|
||||
try {
|
||||
const authEvent = await $signer.sign(makeBlossomAuthEvent({action: "upload", server}))
|
||||
const res = await canUploadBlob(server, {authEvent, headers})
|
||||
|
||||
return res.status === 200
|
||||
} catch (e) {
|
||||
if (!String(e).match(/Failed to fetch|NetworkError/)) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
export type GetBlossomServerOptions = {
|
||||
url?: string
|
||||
}
|
||||
|
||||
export const getBlossomServer = async (options: GetBlossomServerOptions = {}) => {
|
||||
if (options.url) {
|
||||
if (await hasBlossomSupport(options.url)) {
|
||||
return normalizeBlossomUrl(options.url)
|
||||
}
|
||||
}
|
||||
|
||||
const userUrls = getTagValues("server", getListTags(userBlossomServers.get()))
|
||||
|
||||
for (const url of userUrls) {
|
||||
return url.replace(/^ws/, "http")
|
||||
return normalizeBlossomUrl(url)
|
||||
}
|
||||
|
||||
return "https://cdn.satellite.earth"
|
||||
return first(DEFAULT_BLOSSOM_SERVERS)!
|
||||
}
|
||||
|
||||
export type UploadFileOptions = {
|
||||
url?: string
|
||||
encrypt?: boolean
|
||||
}
|
||||
|
||||
@@ -680,35 +726,35 @@ export type UploadFileResult = {
|
||||
}
|
||||
|
||||
export const uploadFile = async (file: File, options: UploadFileOptions = {}) => {
|
||||
const {name, type} = file
|
||||
|
||||
if (!type.match("image/(webp|gif)")) {
|
||||
file = await compressFile(file)
|
||||
}
|
||||
|
||||
const tags: string[][] = []
|
||||
|
||||
if (options.encrypt) {
|
||||
const {ciphertext, key, nonce, algorithm} = await encryptFile(file)
|
||||
|
||||
tags.push(
|
||||
["decryption-key", key],
|
||||
["decryption-nonce", nonce],
|
||||
["encryption-algorithm", algorithm],
|
||||
)
|
||||
|
||||
file = new File([new Blob([ciphertext])], name, {
|
||||
type: "application/octet-stream",
|
||||
})
|
||||
}
|
||||
|
||||
const server = getBlossomServer()
|
||||
const hashes = [await sha256(await file.arrayBuffer())]
|
||||
const $signer = signer.get() || Nip01Signer.ephemeral()
|
||||
const authTemplate = makeBlossomAuthEvent({action: "upload", server, hashes})
|
||||
const authEvent = await $signer.sign(authTemplate)
|
||||
|
||||
try {
|
||||
const {name, type} = file
|
||||
|
||||
if (!type.match("image/(webp|gif)")) {
|
||||
file = await compressFile(file)
|
||||
}
|
||||
|
||||
const tags: string[][] = []
|
||||
|
||||
if (options.encrypt) {
|
||||
const {ciphertext, key, nonce, algorithm} = await encryptFile(file)
|
||||
|
||||
tags.push(
|
||||
["decryption-key", key],
|
||||
["decryption-nonce", nonce],
|
||||
["encryption-algorithm", algorithm],
|
||||
)
|
||||
|
||||
file = new File([new Blob([ciphertext])], name, {
|
||||
type: "application/octet-stream",
|
||||
})
|
||||
}
|
||||
|
||||
const ext = "." + type.split("/")[1]
|
||||
const server = await getBlossomServer(options)
|
||||
const hashes = [await sha256(await file.arrayBuffer())]
|
||||
const $signer = signer.get() || Nip01Signer.ephemeral()
|
||||
const authTemplate = makeBlossomAuthEvent({action: "upload", server, hashes})
|
||||
const authEvent = await $signer.sign(authTemplate)
|
||||
const res = await uploadBlob(server, file, {authEvent})
|
||||
const text = await res.text()
|
||||
|
||||
@@ -718,16 +764,45 @@ export const uploadFile = async (file: File, options: UploadFileOptions = {}) =>
|
||||
return {error: text}
|
||||
}
|
||||
|
||||
// Always append file extension if missing
|
||||
if (new URL(url).pathname.split(".").length === 1) {
|
||||
url += "." + type.split("/")[1]
|
||||
// Always append correct file extension if we encrypted the file, or if it's missing
|
||||
if (options.encrypt) {
|
||||
url = url.replace(/\.\w+$/, "") + ext
|
||||
} else if (new URL(url).pathname.split(".").length === 1) {
|
||||
url += ext
|
||||
}
|
||||
|
||||
const result = {...task, tags, url}
|
||||
|
||||
return {result}
|
||||
} catch (e: any) {
|
||||
console.error(e)
|
||||
console.error("Error caught when uploading file:", e)
|
||||
|
||||
return {error: e.toString()}
|
||||
}
|
||||
}
|
||||
|
||||
// Update Profile
|
||||
|
||||
export const updateProfile = async ({
|
||||
profile,
|
||||
shouldBroadcast = !getTag(PROTECTED, profile.event?.tags || []),
|
||||
}: {
|
||||
profile: Profile
|
||||
shouldBroadcast?: boolean
|
||||
}) => {
|
||||
const router = Router.get()
|
||||
const template = isPublishedProfile(profile) ? editProfile(profile) : createProfile(profile)
|
||||
const scenarios = [router.FromRelays(getMembershipUrls(userMembership.get()))]
|
||||
|
||||
if (shouldBroadcast) {
|
||||
scenarios.push(router.FromUser(), router.Index())
|
||||
template.tags = template.tags.filter(nthNe(0, "-"))
|
||||
} else {
|
||||
template.tags = uniqTags([...template.tags, PROTECTED])
|
||||
}
|
||||
|
||||
const event = makeEvent(template.kind, template)
|
||||
const relays = router.merge(scenarios).getUrls()
|
||||
|
||||
await publishThunk({event, relays}).complete
|
||||
}
|
||||
|
||||
+24
-21
@@ -140,14 +140,14 @@ export const PLATFORM_ACCENT = import.meta.env.VITE_PLATFORM_ACCENT
|
||||
|
||||
export const PLATFORM_DESCRIPTION = import.meta.env.VITE_PLATFORM_DESCRIPTION
|
||||
|
||||
export const DEFAULT_BLOSSOM_SERVERS = fromCsv(import.meta.env.VITE_DEFAULT_BLOSSOM_SERVERS)
|
||||
|
||||
export const BURROW_URL = import.meta.env.VITE_BURROW_URL
|
||||
|
||||
export const DEFAULT_PUBKEYS = import.meta.env.VITE_DEFAULT_PUBKEYS
|
||||
|
||||
export const DUFFLEPUD_URL = "https://dufflepud.onrender.com"
|
||||
|
||||
export const IMGPROXY_URL = "https://imgproxy.coracle.social"
|
||||
|
||||
export const NIP46_PERMS =
|
||||
"nip44_encrypt,nip44_decrypt," +
|
||||
[CLIENT_AUTH, AUTH_JOIN, MESSAGE, THREAD, COMMENT, ROOMS, WRAP, REACTION, ZAP_REQUEST]
|
||||
@@ -178,20 +178,6 @@ export const colors = [
|
||||
|
||||
export const dufflepud = (path: string) => DUFFLEPUD_URL + "/" + path
|
||||
|
||||
export const imgproxy = (url: string, {w = 640, h = 1024} = {}) => {
|
||||
if (!url || url.match("gif$")) {
|
||||
return url
|
||||
}
|
||||
|
||||
url = url.split("?")[0]
|
||||
|
||||
try {
|
||||
return url ? `${IMGPROXY_URL}/x/s:${w}:${h}/${btoa(url)}` : url
|
||||
} catch (e) {
|
||||
return url
|
||||
}
|
||||
}
|
||||
|
||||
export const entityLink = (entity: string) => `https://coracle.social/${entity}`
|
||||
|
||||
export const pubkeyLink = (pubkey: string, relays = Router.get().FromPubkeys([pubkey]).getUrls()) =>
|
||||
@@ -336,6 +322,8 @@ export type SettingsValues = {
|
||||
report_errors: boolean
|
||||
send_delay: number
|
||||
font_size: number
|
||||
play_notification_sound: boolean
|
||||
show_notifications_badge: boolean
|
||||
}
|
||||
|
||||
export type Settings = {
|
||||
@@ -349,8 +337,10 @@ export const defaultSettings = {
|
||||
trusted_relays: [],
|
||||
report_usage: true,
|
||||
report_errors: true,
|
||||
send_delay: 3000,
|
||||
send_delay: 0,
|
||||
font_size: 1,
|
||||
play_notification_sound: true,
|
||||
show_notifications_badge: true,
|
||||
}
|
||||
|
||||
export const settings = deriveEventsMapped<Settings>(repository, {
|
||||
@@ -405,9 +395,13 @@ export const alerts = withGetter(
|
||||
filters: [{kinds: [ALERT_EMAIL, ALERT_WEB, ALERT_IOS, ALERT_ANDROID]}],
|
||||
itemToEvent: item => item.event,
|
||||
eventToItem: async event => {
|
||||
const tags = parseJson(await decrypt(signer.get(), NOTIFIER_PUBKEY, event.content))
|
||||
const $signer = signer.get()
|
||||
|
||||
return {event, tags}
|
||||
if ($signer) {
|
||||
const tags = parseJson(await decrypt($signer, NOTIFIER_PUBKEY, event.content))
|
||||
|
||||
return {event, tags}
|
||||
}
|
||||
},
|
||||
}),
|
||||
)
|
||||
@@ -435,9 +429,13 @@ export const alertStatuses = withGetter(
|
||||
filters: [{kinds: [ALERT_STATUS]}],
|
||||
itemToEvent: item => item.event,
|
||||
eventToItem: async event => {
|
||||
const tags = parseJson(await decrypt(signer.get(), NOTIFIER_PUBKEY, event.content))
|
||||
const $signer = signer.get()
|
||||
|
||||
return {event, tags}
|
||||
if ($signer) {
|
||||
const tags = parseJson(await decrypt($signer, NOTIFIER_PUBKEY, event.content))
|
||||
|
||||
return {event, tags}
|
||||
}
|
||||
},
|
||||
}),
|
||||
)
|
||||
@@ -527,6 +525,11 @@ export const chats = derived(
|
||||
const messagesByChatId = new Map<string, TrustedEvent[]>()
|
||||
|
||||
for (const message of $messages) {
|
||||
// Filter out messages we sent but aren't addressed to the user
|
||||
if (!getPubkeyTagValues(message.wrap?.tags || []).includes($pubkey!)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const chatId = makeChatId(getPubkeyTagValues(message.tags).concat(message.pubkey))
|
||||
|
||||
pushToMapKey(messagesByChatId, chatId, message)
|
||||
|
||||
@@ -11,6 +11,7 @@ import {uploadFile} from "@app/core/commands"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
|
||||
export const makeEditor = async ({
|
||||
encryptFiles = false,
|
||||
aggressive = false,
|
||||
autofocus = false,
|
||||
charCount,
|
||||
@@ -21,6 +22,7 @@ export const makeEditor = async ({
|
||||
uploading,
|
||||
wordCount,
|
||||
}: {
|
||||
encryptFiles?: boolean
|
||||
aggressive?: boolean
|
||||
autofocus?: boolean
|
||||
charCount?: Writable<number>
|
||||
@@ -51,7 +53,8 @@ export const makeEditor = async ({
|
||||
},
|
||||
fileUpload: {
|
||||
config: {
|
||||
upload: (attrs: FileAttributes) => uploadFile(attrs.file, {encrypt: true}),
|
||||
upload: (attrs: FileAttributes) =>
|
||||
uploadFile(attrs.file, {url, encrypt: encryptFiles}),
|
||||
onDrop: () => uploading?.set(true),
|
||||
onComplete: () => uploading?.set(false),
|
||||
onUploadError(currentEditor, task) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {derived} from "svelte/store"
|
||||
import {derived, get} from "svelte/store"
|
||||
import {synced, throttled} from "@welshman/store"
|
||||
import {pubkey, relaysByUrl} from "@welshman/app"
|
||||
import {prop, spec, identity, now, groupBy} from "@welshman/lib"
|
||||
@@ -12,8 +12,16 @@ import {
|
||||
makeSpaceChatPath,
|
||||
makeRoomPath,
|
||||
} from "@app/util/routes"
|
||||
import {chats, hasNip29, getUrlsForEvent, userRoomsByUrl, repositoryStore} from "@app/core/state"
|
||||
import {
|
||||
chats,
|
||||
hasNip29,
|
||||
getUrlsForEvent,
|
||||
userRoomsByUrl,
|
||||
repositoryStore,
|
||||
userSettingsValues,
|
||||
} from "@app/core/state"
|
||||
import {preferencesStorageProvider} from "@src/lib/storage"
|
||||
import {Badge} from "@capawesome/capacitor-badge"
|
||||
|
||||
// Checked state
|
||||
|
||||
@@ -150,3 +158,23 @@ export const notifications = derived(
|
||||
return paths
|
||||
},
|
||||
)
|
||||
|
||||
export const badgeCount = derived(notifications, notifications => {
|
||||
return notifications.size
|
||||
})
|
||||
|
||||
export const handleBadgeCountChanges = async (count: number) => {
|
||||
if (get(userSettingsValues).show_notifications_badge) {
|
||||
try {
|
||||
await Badge.set({count})
|
||||
} catch (err) {
|
||||
// failed to set badge
|
||||
}
|
||||
} else {
|
||||
await clearBadges()
|
||||
}
|
||||
}
|
||||
|
||||
export const clearBadges = async () => {
|
||||
await Badge.clear()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
import {on, throttle, fromPairs, batch, sortBy, concat} from "@welshman/lib"
|
||||
import {throttled, freshness} from "@welshman/store"
|
||||
import {
|
||||
PROFILE,
|
||||
FOLLOWS,
|
||||
MUTES,
|
||||
RELAYS,
|
||||
BLOSSOM_SERVERS,
|
||||
INBOX_RELAYS,
|
||||
ROOMS,
|
||||
APP_DATA,
|
||||
ALERT_STATUS,
|
||||
ALERT_EMAIL,
|
||||
ALERT_WEB,
|
||||
ALERT_IOS,
|
||||
ALERT_ANDROID,
|
||||
EVENT_TIME,
|
||||
THREAD,
|
||||
MESSAGE,
|
||||
DIRECT_MESSAGE,
|
||||
DIRECT_MESSAGE_FILE,
|
||||
} from "@welshman/util"
|
||||
import type {Zapper, TrustedEvent} from "@welshman/util"
|
||||
import type {RepositoryUpdate} from "@welshman/relay"
|
||||
import type {Handle, Relay} from "@welshman/app"
|
||||
import {
|
||||
plaintext,
|
||||
tracker,
|
||||
relays,
|
||||
repository,
|
||||
handles,
|
||||
zappers,
|
||||
onZapper,
|
||||
onHandle,
|
||||
} from "@welshman/app"
|
||||
import {collectionStorageProvider} from "@lib/storage"
|
||||
|
||||
const syncEvents = async () => {
|
||||
repository.load(await collectionStorageProvider.get<TrustedEvent>("events"))
|
||||
|
||||
const rankEvent = (event: TrustedEvent) => {
|
||||
switch (event.kind) {
|
||||
case PROFILE:
|
||||
return 1
|
||||
case FOLLOWS:
|
||||
return 1
|
||||
case MUTES:
|
||||
return 1
|
||||
case RELAYS:
|
||||
return 1
|
||||
case BLOSSOM_SERVERS:
|
||||
return 1
|
||||
case INBOX_RELAYS:
|
||||
return 1
|
||||
case ROOMS:
|
||||
return 1
|
||||
case APP_DATA:
|
||||
return 1
|
||||
case ALERT_STATUS:
|
||||
return 1
|
||||
case ALERT_EMAIL:
|
||||
return 1
|
||||
case ALERT_WEB:
|
||||
return 1
|
||||
case ALERT_IOS:
|
||||
return 1
|
||||
case ALERT_ANDROID:
|
||||
return 1
|
||||
case EVENT_TIME:
|
||||
return 0.9
|
||||
case THREAD:
|
||||
return 0.9
|
||||
case MESSAGE:
|
||||
return 0.9
|
||||
case DIRECT_MESSAGE:
|
||||
return 0.9
|
||||
case DIRECT_MESSAGE_FILE:
|
||||
return 0.9
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
return on(
|
||||
repository,
|
||||
"update",
|
||||
batch(3000, async (updates: RepositoryUpdate[]) => {
|
||||
let added: TrustedEvent[] = []
|
||||
const removed = new Set<string>()
|
||||
|
||||
for (const update of updates) {
|
||||
for (const event of update.added) {
|
||||
if (rankEvent(event) > 0) {
|
||||
added.push(event)
|
||||
removed.delete(event.id)
|
||||
}
|
||||
}
|
||||
|
||||
for (const id of update.removed) {
|
||||
added = added.filter(event => !update.removed.has(event.id))
|
||||
removed.add(id)
|
||||
}
|
||||
}
|
||||
|
||||
if (added.length > 0) {
|
||||
let events = concat(await collectionStorageProvider.get<TrustedEvent>("events"), added)
|
||||
|
||||
// If we're well above our retention limit, drop lowest-ranked events
|
||||
if (events.length > 15_000) {
|
||||
events = sortBy(e => -rankEvent(e), events).slice(10_000)
|
||||
}
|
||||
|
||||
await collectionStorageProvider.set("events", events)
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
const syncTracker = async () => {
|
||||
const relaysById = new Map<string, Set<string>>()
|
||||
|
||||
for (const [id, relays] of await collectionStorageProvider.get<[string, string[]]>("tracker")) {
|
||||
relaysById.set(id, new Set(relays))
|
||||
}
|
||||
|
||||
tracker.load(relaysById)
|
||||
|
||||
let p = Promise.resolve()
|
||||
|
||||
const updateOne = batch(3000, (ids: string[]) => {
|
||||
p = p.then(() => {
|
||||
collectionStorageProvider.add(
|
||||
"tracker",
|
||||
ids.map(id => [id, Array.from(tracker.getRelays(id))]),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
const updateAll = throttle(3000, () => {
|
||||
p = p.then(() => {
|
||||
collectionStorageProvider.set(
|
||||
"tracker",
|
||||
Array.from(tracker.relaysById.entries()).map(([id, relays]) => [id, Array.from(relays)]),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
tracker.on("add", updateOne)
|
||||
tracker.on("remove", updateOne)
|
||||
tracker.on("load", updateAll)
|
||||
tracker.on("clear", updateAll)
|
||||
|
||||
return () => {
|
||||
tracker.off("add", updateOne)
|
||||
tracker.off("remove", updateOne)
|
||||
tracker.off("load", updateAll)
|
||||
tracker.off("clear", updateAll)
|
||||
}
|
||||
}
|
||||
|
||||
const syncRelays = async () => {
|
||||
relays.set(await collectionStorageProvider.get<Relay>("relays"))
|
||||
|
||||
return throttled(3000, relays).subscribe($relays => {
|
||||
collectionStorageProvider.set("relays", $relays)
|
||||
})
|
||||
}
|
||||
|
||||
const syncHandles = async () => {
|
||||
handles.set(await collectionStorageProvider.get<Handle>("handles"))
|
||||
|
||||
return onHandle(
|
||||
batch(3000, async $handles => {
|
||||
await collectionStorageProvider.add("handles", $handles)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
const syncZappers = async () => {
|
||||
zappers.set(await collectionStorageProvider.get<Zapper>("zappers"))
|
||||
|
||||
return onZapper(
|
||||
batch(3000, async $zappers => {
|
||||
await collectionStorageProvider.add("zappers", $zappers)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
const syncFreshness = async () => {
|
||||
freshness.set(fromPairs(await collectionStorageProvider.get<[string, number]>("freshness")))
|
||||
|
||||
return throttled(3000, freshness).subscribe($freshness => {
|
||||
collectionStorageProvider.set("freshness", Object.entries($freshness))
|
||||
})
|
||||
}
|
||||
|
||||
const syncPlaintext = async () => {
|
||||
plaintext.set(fromPairs(await collectionStorageProvider.get<[string, string]>("plaintext")))
|
||||
|
||||
return throttled(3000, plaintext).subscribe($plaintext => {
|
||||
collectionStorageProvider.set("plaintext", Object.entries($plaintext))
|
||||
})
|
||||
}
|
||||
|
||||
export const syncDataStores = () =>
|
||||
Promise.all([
|
||||
syncEvents(),
|
||||
syncTracker(),
|
||||
syncRelays(),
|
||||
syncHandles(),
|
||||
syncZappers(),
|
||||
syncFreshness(),
|
||||
syncPlaintext(),
|
||||
])
|
||||
@@ -49,7 +49,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-2" role="list">
|
||||
{#each value as item, index (item)}
|
||||
{#each value as item, index}
|
||||
<div
|
||||
class="flex items-center gap-2"
|
||||
draggable="true"
|
||||
|
||||
+86
-6
@@ -1,7 +1,10 @@
|
||||
import {type StorageProvider} from "@welshman/store"
|
||||
import {Preferences} from "@capacitor/preferences"
|
||||
import {Encoding, Filesystem, Directory} from "@capacitor/filesystem"
|
||||
|
||||
export class PreferencesStorageProvider implements StorageProvider {
|
||||
p = Promise.resolve()
|
||||
|
||||
get = async <T>(key: string): Promise<T | undefined> => {
|
||||
const result = await Preferences.get({key})
|
||||
if (!result.value) return undefined
|
||||
@@ -12,17 +15,94 @@ export class PreferencesStorageProvider implements StorageProvider {
|
||||
}
|
||||
}
|
||||
|
||||
p = Promise.resolve()
|
||||
set = async <T>(key: string, value: T): Promise<void> => {
|
||||
this.p = this.p.then(async () => await Preferences.set({key, value: JSON.stringify(value)}))
|
||||
this.p = this.p.then(() => Preferences.set({key, value: JSON.stringify(value)}))
|
||||
|
||||
await this.p
|
||||
}
|
||||
|
||||
clear = async () => {
|
||||
this.p = this.p.then(() => Preferences.clear())
|
||||
|
||||
await this.p
|
||||
}
|
||||
}
|
||||
|
||||
export const preferencesStorageProvider = new PreferencesStorageProvider()
|
||||
|
||||
export class CollectionStorageProvider implements StorageProvider {
|
||||
p = Promise.resolve()
|
||||
|
||||
get = async <T>(key: string): Promise<T[]> => {
|
||||
try {
|
||||
const file = await Filesystem.readFile({
|
||||
path: key + ".json",
|
||||
directory: Directory.Data,
|
||||
encoding: Encoding.UTF8,
|
||||
})
|
||||
|
||||
const items: T[] = []
|
||||
for (const line of file.data.toString().split("\n")) {
|
||||
try {
|
||||
items.push(JSON.parse(line))
|
||||
} catch (e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
|
||||
return items
|
||||
} catch (err) {
|
||||
// file doesn't exist, or isn't valid json
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
set = async <T>(key: string, value: T[]): Promise<void> => {
|
||||
this.p = this.p.then(async () => {
|
||||
await Filesystem.writeFile({
|
||||
path: key + ".json",
|
||||
directory: Directory.Data,
|
||||
encoding: Encoding.UTF8,
|
||||
data: value.map(v => JSON.stringify(v)).join("\n"),
|
||||
})
|
||||
})
|
||||
|
||||
await this.p
|
||||
}
|
||||
|
||||
add = async <T>(key: string, value: T[]): Promise<void> => {
|
||||
this.p = this.p.then(async () => {
|
||||
await Filesystem.appendFile({
|
||||
path: key + ".json",
|
||||
directory: Directory.Data,
|
||||
encoding: Encoding.UTF8,
|
||||
data: "\n" + value.map(v => JSON.stringify(v)).join("\n"),
|
||||
})
|
||||
})
|
||||
|
||||
await this.p
|
||||
}
|
||||
|
||||
clear = async (): Promise<void> => {
|
||||
await Preferences.clear()
|
||||
this.p = Promise.resolve()
|
||||
this.p = this.p.then(async () => {
|
||||
try {
|
||||
const res = await Filesystem.readdir({path: "./", directory: Directory.Data})
|
||||
|
||||
await Promise.all(
|
||||
res.files.map(file =>
|
||||
Filesystem.deleteFile({
|
||||
path: file.name + ".json",
|
||||
directory: Directory.Data,
|
||||
}),
|
||||
),
|
||||
)
|
||||
} catch (e) {
|
||||
// Directory might not have been created yet
|
||||
}
|
||||
})
|
||||
|
||||
await this.p
|
||||
}
|
||||
}
|
||||
|
||||
// singleton instance of PreferencesStorageProvider
|
||||
export const preferencesStorageProvider = new PreferencesStorageProvider()
|
||||
export const collectionStorageProvider = new CollectionStorageProvider()
|
||||
|
||||
+18
-64
@@ -24,27 +24,7 @@
|
||||
WEEK,
|
||||
} from "@welshman/lib"
|
||||
import type {TrustedEvent, StampedEvent} from "@welshman/util"
|
||||
import {
|
||||
WRAP,
|
||||
ALERT_STATUS,
|
||||
ALERT_EMAIL,
|
||||
ALERT_WEB,
|
||||
ALERT_IOS,
|
||||
ALERT_ANDROID,
|
||||
EVENT_TIME,
|
||||
APP_DATA,
|
||||
THREAD,
|
||||
MESSAGE,
|
||||
INBOX_RELAYS,
|
||||
DIRECT_MESSAGE,
|
||||
DIRECT_MESSAGE_FILE,
|
||||
MUTES,
|
||||
FOLLOWS,
|
||||
PROFILE,
|
||||
RELAYS,
|
||||
BLOSSOM_SERVERS,
|
||||
ROOMS,
|
||||
} from "@welshman/util"
|
||||
import {WRAP} from "@welshman/util"
|
||||
import {Nip46Broker, makeSecret} from "@welshman/signer"
|
||||
import type {Socket, RelayMessage, ClientMessage} from "@welshman/net"
|
||||
import {
|
||||
@@ -61,8 +41,6 @@
|
||||
} from "@welshman/net"
|
||||
import {
|
||||
loadRelay,
|
||||
db,
|
||||
initStorage,
|
||||
repository,
|
||||
pubkey,
|
||||
session,
|
||||
@@ -70,10 +48,8 @@
|
||||
signer,
|
||||
signerLog,
|
||||
dropSession,
|
||||
defaultStorageAdapters,
|
||||
loginWithNip01,
|
||||
loginWithNip46,
|
||||
EventsStorageAdapter,
|
||||
loadRelaySelections,
|
||||
SignerLogEntryStatus,
|
||||
} from "@welshman/app"
|
||||
@@ -107,8 +83,13 @@
|
||||
import {initializePushNotifications} from "@app/util/push"
|
||||
import * as commands from "@app/core/commands"
|
||||
import * as requests from "@app/core/requests"
|
||||
import * as notifications from "@app/util/notifications"
|
||||
import * as appState from "@app/core/state"
|
||||
import * as notifications from "@app/util/notifications"
|
||||
import * as storage from "@app/util/storage"
|
||||
import NewNotificationSound from "@src/app/components/NewNotificationSound.svelte"
|
||||
|
||||
// Migration: delete old indexeddb database
|
||||
indexedDB?.deleteDatabase("flotilla")
|
||||
|
||||
// Migration: old nostrtalk instance used different sessions
|
||||
if ($session && !$signer) {
|
||||
@@ -122,6 +103,8 @@
|
||||
|
||||
const ready = $state(defer<void>())
|
||||
|
||||
let initialized = false
|
||||
|
||||
onMount(async () => {
|
||||
Object.assign(window, {
|
||||
get,
|
||||
@@ -239,7 +222,8 @@
|
||||
document.documentElement.style["font-size"] = `${$userSettingsValues.font_size}rem`
|
||||
})
|
||||
|
||||
if (!db) {
|
||||
if (!initialized) {
|
||||
initialized = true
|
||||
setupTracking()
|
||||
setupAnalytics()
|
||||
|
||||
@@ -278,44 +262,10 @@
|
||||
storage: preferencesStorageProvider,
|
||||
})
|
||||
|
||||
await initStorage("flotilla", 8, {
|
||||
...defaultStorageAdapters,
|
||||
events: new EventsStorageAdapter({
|
||||
name: "events",
|
||||
limit: 10_000,
|
||||
repository,
|
||||
rankEvent: (e: TrustedEvent) => {
|
||||
if (
|
||||
[
|
||||
PROFILE,
|
||||
FOLLOWS,
|
||||
MUTES,
|
||||
RELAYS,
|
||||
BLOSSOM_SERVERS,
|
||||
INBOX_RELAYS,
|
||||
ROOMS,
|
||||
APP_DATA,
|
||||
ALERT_STATUS,
|
||||
ALERT_EMAIL,
|
||||
ALERT_WEB,
|
||||
ALERT_IOS,
|
||||
ALERT_ANDROID,
|
||||
].includes(e.kind)
|
||||
) {
|
||||
return 1
|
||||
}
|
||||
|
||||
if (
|
||||
[EVENT_TIME, THREAD, MESSAGE, DIRECT_MESSAGE, DIRECT_MESSAGE_FILE].includes(e.kind)
|
||||
) {
|
||||
return 0.9
|
||||
}
|
||||
|
||||
return 0
|
||||
},
|
||||
}),
|
||||
})
|
||||
// Sync application data (relay, events, etc)
|
||||
await storage.syncDataStores()
|
||||
|
||||
// Wait 300 ms for any throttled stores to finish
|
||||
sleep(300).then(() => ready.resolve())
|
||||
|
||||
defaultSocketPolicies.push(
|
||||
@@ -465,6 +415,9 @@
|
||||
},
|
||||
)
|
||||
|
||||
// subscribe to badge count for changes
|
||||
notifications.badgeCount.subscribe(notifications.handleBadgeCountChanges)
|
||||
|
||||
// Listen for signer errors, report to user via toast
|
||||
signerLog.subscribe(
|
||||
throttle(10_000, $log => {
|
||||
@@ -504,5 +457,6 @@
|
||||
</AppContainer>
|
||||
<ModalContainer />
|
||||
<div class="tippy-target"></div>
|
||||
<NewNotificationSound />
|
||||
</div>
|
||||
{/await}
|
||||
|
||||
@@ -1,24 +1,44 @@
|
||||
<script lang="ts">
|
||||
import {onMount} from "svelte"
|
||||
import {dec} from "@welshman/lib"
|
||||
import {ROOMS} from "@welshman/util"
|
||||
import {debounce} from "throttle-debounce"
|
||||
import {dec, tryCatch} from "@welshman/lib"
|
||||
import {ROOMS, normalizeRelayUrl, isRelayUrl} from "@welshman/util"
|
||||
import {Router} from "@welshman/router"
|
||||
import {load} from "@welshman/net"
|
||||
import type {Relay} from "@welshman/app"
|
||||
import {relays, createSearch, loadRelay, loadRelaySelections} from "@welshman/app"
|
||||
import {createScroller} from "@lib/html"
|
||||
import {fly} from "@lib/transition"
|
||||
import QrCode from "@assets/icons/qr-code.svg?dataurl"
|
||||
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
||||
import Magnifier from "@assets/icons/magnifier.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Page from "@lib/components/Page.svelte"
|
||||
import Scanner from "@lib/components/Scanner.svelte"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import PageHeader from "@lib/components/PageHeader.svelte"
|
||||
import ContentSearch from "@lib/components/ContentSearch.svelte"
|
||||
import SpaceAdd from "@app/components/SpaceAdd.svelte"
|
||||
import SpaceInviteAccept from "@app/components/SpaceInviteAccept.svelte"
|
||||
import RelaySummary from "@app/components/RelaySummary.svelte"
|
||||
import SpaceCheck from "@app/components/SpaceCheck.svelte"
|
||||
import {getMembershipUrls, loadMembership, defaultPubkeys, membersByUrl} from "@app/core/state"
|
||||
import {pushModal} from "@app/util/modal"
|
||||
|
||||
const openMenu = () => pushModal(SpaceAdd)
|
||||
|
||||
const termUrl = $derived(tryCatch(() => normalizeRelayUrl(term)) || "")
|
||||
|
||||
const toggleScanner = () => {
|
||||
showScanner = !showScanner
|
||||
}
|
||||
|
||||
const onScan = debounce(1000, async (data: string) => {
|
||||
showScanner = false
|
||||
pushModal(SpaceInviteAccept, {invite: data})
|
||||
})
|
||||
|
||||
const discoverRelays = () =>
|
||||
Promise.all([
|
||||
load({
|
||||
@@ -37,7 +57,7 @@
|
||||
|
||||
const relaySearch = $derived(
|
||||
createSearch(
|
||||
$relays.filter(r => $membersByUrl.has(r.url)),
|
||||
$relays.filter(r => $membersByUrl.has(r.url) && r.url !== termUrl),
|
||||
{
|
||||
getValue: (relay: Relay) => relay.url,
|
||||
sortFn: ({score, item}) => {
|
||||
@@ -59,6 +79,7 @@
|
||||
|
||||
let term = $state("")
|
||||
let limit = $state(20)
|
||||
let showScanner = $state(false)
|
||||
let element: Element
|
||||
|
||||
onMount(() => {
|
||||
@@ -76,30 +97,58 @@
|
||||
</script>
|
||||
|
||||
<Page class="cw-full">
|
||||
<div class="content column gap-4" bind:this={element}>
|
||||
<PageHeader>
|
||||
{#snippet title()}
|
||||
Discover Spaces
|
||||
{/snippet}
|
||||
{#snippet info()}
|
||||
Find communities all across the nostr network
|
||||
{/snippet}
|
||||
</PageHeader>
|
||||
<label class="input input-bordered flex w-full items-center gap-2">
|
||||
<Icon icon={Magnifier} />
|
||||
<input bind:value={term} class="grow" type="text" placeholder="Search for spaces..." />
|
||||
</label>
|
||||
{#each relaySearch.searchOptions(term).slice(0, limit) as relay (relay.url)}
|
||||
<Button
|
||||
class="card2 bg-alt shadow-xl transition-all hover:shadow-2xl hover:dark:brightness-[1.1]"
|
||||
onclick={() => openSpace(relay.url)}>
|
||||
<RelaySummary url={relay.url} />
|
||||
</Button>
|
||||
{/each}
|
||||
{#await discoverRelays()}
|
||||
<div class="flex justify-center py-20" out:fly>
|
||||
<Spinner loading>Looking for spaces...</Spinner>
|
||||
<ContentSearch>
|
||||
{#snippet input()}
|
||||
<div class="flex flex-col gap-2">
|
||||
<PageHeader>
|
||||
{#snippet title()}
|
||||
Discover Spaces
|
||||
{/snippet}
|
||||
{#snippet info()}
|
||||
Find communities all across the nostr network
|
||||
{/snippet}
|
||||
</PageHeader>
|
||||
<div class="row-2 min-w-0 flex-grow items-center">
|
||||
<label class="input input-bordered flex flex-grow items-center gap-2">
|
||||
<Icon icon={Magnifier} />
|
||||
<input bind:value={term} class="grow" type="text" placeholder="Search for spaces..." />
|
||||
<Button onclick={toggleScanner} class="center">
|
||||
<Icon icon={QrCode} />
|
||||
</Button>
|
||||
</label>
|
||||
<Button class="btn btn-primary" onclick={openMenu}>
|
||||
<Icon icon={AddCircle} />
|
||||
</Button>
|
||||
</div>
|
||||
{#if showScanner}
|
||||
<Scanner onscan={onScan} />
|
||||
{/if}
|
||||
</div>
|
||||
{/await}
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet content()}
|
||||
<div class="col-2 scroll-container" bind:this={element}>
|
||||
{#key termUrl}
|
||||
{#if isRelayUrl(termUrl)}
|
||||
<Button
|
||||
class="card2 bg-alt shadow-xl transition-all hover:shadow-2xl hover:dark:brightness-[1.1]"
|
||||
onclick={() => openSpace(termUrl)}>
|
||||
<RelaySummary url={termUrl} />
|
||||
</Button>
|
||||
{/if}
|
||||
{/key}
|
||||
{#each relaySearch.searchOptions(term).slice(0, limit) as relay (relay.url)}
|
||||
<Button
|
||||
class="card2 bg-alt shadow-xl transition-all hover:shadow-2xl hover:dark:brightness-[1.1]"
|
||||
onclick={() => openSpace(relay.url)}>
|
||||
<RelaySummary url={relay.url} />
|
||||
</Button>
|
||||
{/each}
|
||||
{#await discoverRelays()}
|
||||
<div class="flex justify-center py-20" out:fly>
|
||||
<Spinner loading>Looking for spaces...</Spinner>
|
||||
</div>
|
||||
{/await}
|
||||
</div>
|
||||
{/snippet}
|
||||
</ContentSearch>
|
||||
</Page>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<h1 class="mb-4 text-center text-5xl font-bold uppercase">{PLATFORM_NAME}</h1>
|
||||
<div class="col-3">
|
||||
<Button onclick={addSpace}>
|
||||
<CardButton class="dark:btn-neutral">
|
||||
<CardButton class="btn-neutral">
|
||||
{#snippet icon()}
|
||||
<div><Icon icon={AddCircle} size={7} /></div>
|
||||
{/snippet}
|
||||
@@ -45,7 +45,7 @@
|
||||
</CardButton>
|
||||
</Button>
|
||||
<Link href="/discover">
|
||||
<CardButton class="dark:btn-neutral">
|
||||
<CardButton class="btn-neutral">
|
||||
{#snippet icon()}
|
||||
<div><Icon icon={Compass} size={7} /></div>
|
||||
{/snippet}
|
||||
@@ -58,7 +58,7 @@
|
||||
</CardButton>
|
||||
</Link>
|
||||
<Button onclick={openChat}>
|
||||
<CardButton class="dark:btn-neutral">
|
||||
<CardButton class="btn-neutral">
|
||||
{#snippet icon()}
|
||||
<div><Icon icon={ChatRound} size={7} /></div>
|
||||
{/snippet}
|
||||
|
||||
@@ -61,9 +61,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
class="center btn btn-circle -mr-4 -mt-4 h-12 w-12 dark:btn-neutral"
|
||||
onclick={startEdit}>
|
||||
<Button class="center btn btn-circle btn-neutral -mr-4 -mt-4 h-12 w-12" onclick={startEdit}>
|
||||
<Icon icon={PenNewSquare} />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
</script>
|
||||
|
||||
<div class="content column gap-4">
|
||||
<Collapse class="card2 bg-alt column gap-4">
|
||||
<Collapse class="card2 bg-alt column gap-4 shadow-xl">
|
||||
{#snippet title()}
|
||||
<h2 class="flex items-center gap-3 text-xl">
|
||||
<Icon icon={Globus} />
|
||||
@@ -83,7 +83,7 @@
|
||||
</Button>
|
||||
</div>
|
||||
</Collapse>
|
||||
<Collapse class="card2 bg-alt column gap-4">
|
||||
<Collapse class="card2 bg-alt column gap-4 shadow-xl">
|
||||
{#snippet title()}
|
||||
<h2 class="flex items-center gap-3 text-xl">
|
||||
<Icon icon={Inbox} />
|
||||
@@ -115,7 +115,7 @@
|
||||
</Button>
|
||||
</div>
|
||||
</Collapse>
|
||||
<Collapse class="card2 bg-alt column gap-4">
|
||||
<Collapse class="card2 bg-alt column gap-4 shadow-xl">
|
||||
{#snippet title()}
|
||||
<h2 class="flex items-center gap-3 text-xl">
|
||||
<Icon icon={Mailbox} />
|
||||
|
||||
@@ -1,22 +1,32 @@
|
||||
<script lang="ts">
|
||||
import {nwc} from "@getalby/sdk"
|
||||
import {LOCALE} from "@welshman/lib"
|
||||
import {displayRelayUrl, fromMsats} from "@welshman/util"
|
||||
import {session} from "@welshman/app"
|
||||
import {displayRelayUrl, isNWCWallet, fromMsats} from "@welshman/util"
|
||||
import {session, pubkey, profilesByPubkey} from "@welshman/app"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import WalletConnect from "@app/components/WalletConnect.svelte"
|
||||
import WalletDisconnect from "@app/components/WalletDisconnect.svelte"
|
||||
import WalletUpdateReceivingAddress from "@app/components/WalletUpdateReceivingAddress.svelte"
|
||||
import {pushModal} from "@app/util/modal"
|
||||
import {getWebLn} from "@app/core/commands"
|
||||
import Wallet2 from "@assets/icons/wallet.svg?dataurl"
|
||||
import CheckCircle from "@assets/icons/check-circle.svg?dataurl"
|
||||
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
||||
import CloseCircle from "@assets/icons/close-circle.svg?dataurl"
|
||||
import InfoCircle from "@assets/icons/info-circle.svg?dataurl"
|
||||
|
||||
const connect = () => pushModal(WalletConnect)
|
||||
|
||||
const disconnect = () => pushModal(WalletDisconnect)
|
||||
|
||||
const updateReceivingAddress = () => pushModal(WalletUpdateReceivingAddress)
|
||||
|
||||
const profile = $derived($profilesByPubkey.get($pubkey || ""))
|
||||
const profileLightningAddress = $derived(profile?.lud16)
|
||||
const walletLud16 = $derived(
|
||||
$session?.wallet && isNWCWallet($session.wallet) ? $session.wallet.info.lud16 : undefined,
|
||||
)
|
||||
</script>
|
||||
|
||||
<div class="content column gap-4">
|
||||
@@ -89,4 +99,23 @@
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="card2 bg-alt flex flex-col shadow-xl"
|
||||
class:gap-6={profileLightningAddress && walletLud16 && profile?.lud16 !== walletLud16}>
|
||||
<div class="flex items-center justify-between">
|
||||
<strong>Lightning Address</strong>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class={profileLightningAddress ? "" : "text-warning"}>
|
||||
{profileLightningAddress ? profileLightningAddress : "Not set"}
|
||||
</span>
|
||||
<Button class="btn btn-neutral btn-xs ml-3" onclick={updateReceivingAddress}>Update</Button>
|
||||
</div>
|
||||
</div>
|
||||
{#if profileLightningAddress && walletLud16 && profile?.lud16 !== walletLud16}
|
||||
<div class="card2 bg-alt flex items-center gap-2 text-xs">
|
||||
<Icon icon={InfoCircle} size={4} />
|
||||
Your profile has a different lightning address than your connected wallet.
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
userRoomsByUrl,
|
||||
} from "@app/core/state"
|
||||
import {pullConservatively} from "@app/core/requests"
|
||||
import {hasBlossomSupport} from "@app/core/commands"
|
||||
import {notifications} from "@app/util/notifications"
|
||||
|
||||
type Props = {
|
||||
@@ -66,6 +67,9 @@
|
||||
}
|
||||
})
|
||||
|
||||
// Prime our cache so we can upload images quicker
|
||||
hasBlossomSupport(url)
|
||||
|
||||
// Load group meta, threads, calendar events, comments, and recent messages
|
||||
// for user rooms to help with a quick page transition
|
||||
pullConservatively({
|
||||
|
||||
Binary file not shown.
@@ -36,6 +36,8 @@ export default {
|
||||
},
|
||||
light: {
|
||||
...themes["winter"],
|
||||
neutral: '#F2F7FF',
|
||||
warning: '#FD8D0B',
|
||||
primary: process.env.VITE_PLATFORM_ACCENT,
|
||||
"primary-content": process.env.VITE_PLATFORM_ACCENT_CONTENT || "#EAE7FF",
|
||||
secondary: process.env.VITE_PLATFORM_SECONDARY,
|
||||
|
||||
Reference in New Issue
Block a user