Compare commits
34 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 | |||
| 750830d593 | |||
| 3c0f1a1d2f | |||
| 4253b0ed29 |
@@ -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_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_BURROW_URL=
|
||||||
VITE_PLATFORM_URL=https://flotilla.social
|
VITE_PLATFORM_URL=https://flotilla.social
|
||||||
VITE_PLATFORM_TERMS=https://flotilla.social/terms
|
VITE_PLATFORM_TERMS=https://flotilla.social/terms
|
||||||
@@ -10,7 +11,7 @@ VITE_PLATFORM_ACCENT="#7161FF"
|
|||||||
VITE_PLATFORM_SECONDARY="#EB5E28"
|
VITE_PLATFORM_SECONDARY="#EB5E28"
|
||||||
VITE_PLATFORM_DESCRIPTION="Flotilla is nostr — for communities."
|
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_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_PUBKEY=27b7c2ed89ef78322114225ea3ebf5f72c7767c2528d4d0c1854d039c00085df
|
||||||
VITE_NOTIFIER_RELAY=wss://anchor.coracle.social/
|
VITE_NOTIFIER_RELAY=wss://anchor.coracle.social/
|
||||||
VITE_VAPID_PUBLIC_KEY=BIt2D4BdgdbCowD_0d3Np6GbrIGHxd7aIEUeZNe3hQuRlHz02OhzvDaai0XSFoJYVzSzdMjdyW-QhvW9_yq8j4Y
|
VITE_VAPID_PUBLIC_KEY=BIt2D4BdgdbCowD_0d3Np6GbrIGHxd7aIEUeZNe3hQuRlHz02OhzvDaai0XSFoJYVzSzdMjdyW-QhvW9_yq8j4Y
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
# Changelog
|
# 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
|
||||||
|
|
||||||
# 1.2.4
|
# 1.2.4
|
||||||
|
|
||||||
* Add direct message alerts
|
* Add direct message alerts
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ android {
|
|||||||
applicationId "social.flotilla"
|
applicationId "social.flotilla"
|
||||||
minSdk rootProject.ext.minSdkVersion
|
minSdk rootProject.ext.minSdkVersion
|
||||||
targetSdk rootProject.ext.targetSdkVersion
|
targetSdk rootProject.ext.targetSdkVersion
|
||||||
versionCode 25
|
versionCode 27
|
||||||
versionName "1.2.4"
|
versionName "1.3.0"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
aaptOptions {
|
aaptOptions {
|
||||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
// 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 {
|
dependencies {
|
||||||
implementation project(':capacitor-community-safe-area')
|
implementation project(':capacitor-community-safe-area')
|
||||||
implementation project(':capacitor-app')
|
implementation project(':capacitor-app')
|
||||||
|
implementation project(':capacitor-filesystem')
|
||||||
implementation project(':capacitor-keyboard')
|
implementation project(':capacitor-keyboard')
|
||||||
implementation project(':capacitor-preferences')
|
implementation project(':capacitor-preferences')
|
||||||
implementation project(':capacitor-push-notifications')
|
implementation project(':capacitor-push-notifications')
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ project(':capacitor-community-safe-area').projectDir = new File('../node_modules
|
|||||||
include ':capacitor-app'
|
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')
|
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'
|
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')
|
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 */
|
/* Begin PBXBuildFile section */
|
||||||
2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; };
|
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 */; };
|
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
|
||||||
504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
|
504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
|
||||||
504EC30D1FED79650016851F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30B1FED79650016851F /* Main.storyboard */; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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; };
|
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>"; };
|
504EC3071FED79650016851F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
@@ -58,6 +60,7 @@
|
|||||||
504EC2FB1FED79650016851F = {
|
504EC2FB1FED79650016851F = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
3478F0322E846FEB002431E0 /* PrivacyInfo.xcprivacy */,
|
||||||
051414282E0CC28400BE0BC8 /* Flotilla Chat.entitlements */,
|
051414282E0CC28400BE0BC8 /* Flotilla Chat.entitlements */,
|
||||||
504EC3061FED79650016851F /* App */,
|
504EC3061FED79650016851F /* App */,
|
||||||
504EC3051FED79650016851F /* Products */,
|
504EC3051FED79650016851F /* Products */,
|
||||||
@@ -162,6 +165,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */,
|
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */,
|
||||||
|
3478F0332E846FEB002431E0 /* PrivacyInfo.xcprivacy in Resources */,
|
||||||
50B271D11FEDC1A000F3C39B /* public in Resources */,
|
50B271D11FEDC1A000F3C39B /* public in Resources */,
|
||||||
504EC30F1FED79650016851F /* Assets.xcassets in Resources */,
|
504EC30F1FED79650016851F /* Assets.xcassets in Resources */,
|
||||||
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
|
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
|
||||||
@@ -354,14 +358,14 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = "Flotilla Chat.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "Flotilla Chat.entitlements";
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 17;
|
CURRENT_PROJECT_VERSION = 19;
|
||||||
DEVELOPMENT_TEAM = S26U9DYW3A;
|
DEVELOPMENT_TEAM = S26U9DYW3A;
|
||||||
INFOPLIST_FILE = App/Info.plist;
|
INFOPLIST_FILE = App/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "Flotilla Chat";
|
INFOPLIST_KEY_CFBundleDisplayName = "Flotilla Chat";
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
MARKETING_VERSION = 1.2.4;
|
MARKETING_VERSION = 1.3.0;
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = social.flotilla;
|
PRODUCT_BUNDLE_IDENTIFIER = social.flotilla;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
@@ -380,14 +384,14 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = "Flotilla Chat.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "Flotilla Chat.entitlements";
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 17;
|
CURRENT_PROJECT_VERSION = 19;
|
||||||
DEVELOPMENT_TEAM = S26U9DYW3A;
|
DEVELOPMENT_TEAM = S26U9DYW3A;
|
||||||
INFOPLIST_FILE = App/Info.plist;
|
INFOPLIST_FILE = App/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "Flotilla Chat";
|
INFOPLIST_KEY_CFBundleDisplayName = "Flotilla Chat";
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
MARKETING_VERSION = 1.2.4;
|
MARKETING_VERSION = 1.3.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = social.flotilla;
|
PRODUCT_BUNDLE_IDENTIFIER = social.flotilla;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
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 '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 '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 '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 '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 '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'
|
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>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "flotilla",
|
"name": "flotilla",
|
||||||
"version": "1.2.4",
|
"version": "1.3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
@@ -43,6 +43,7 @@
|
|||||||
"@capacitor/app": "^7.0.0",
|
"@capacitor/app": "^7.0.0",
|
||||||
"@capacitor/cli": "^7.0.0",
|
"@capacitor/cli": "^7.0.0",
|
||||||
"@capacitor/core": "^7.0.1",
|
"@capacitor/core": "^7.0.1",
|
||||||
|
"@capacitor/filesystem": "^7.0.0",
|
||||||
"@capacitor/ios": "^7.0.0",
|
"@capacitor/ios": "^7.0.0",
|
||||||
"@capacitor/keyboard": "^7.0.0",
|
"@capacitor/keyboard": "^7.0.0",
|
||||||
"@capacitor/preferences": "^7.0.2",
|
"@capacitor/preferences": "^7.0.2",
|
||||||
@@ -58,17 +59,17 @@
|
|||||||
"@types/throttle-debounce": "^5.0.2",
|
"@types/throttle-debounce": "^5.0.2",
|
||||||
"@vite-pwa/assets-generator": "^0.2.6",
|
"@vite-pwa/assets-generator": "^0.2.6",
|
||||||
"@vite-pwa/sveltekit": "^0.6.6",
|
"@vite-pwa/sveltekit": "^0.6.6",
|
||||||
"@welshman/app": "^0.4.7",
|
"@welshman/app": "^0.5.1",
|
||||||
"@welshman/content": "^0.4.7",
|
"@welshman/content": "^0.5.1",
|
||||||
"@welshman/editor": "^0.4.7",
|
"@welshman/editor": "^0.5.1",
|
||||||
"@welshman/feeds": "^0.4.7",
|
"@welshman/feeds": "^0.5.1",
|
||||||
"@welshman/lib": "^0.4.7",
|
"@welshman/lib": "^0.5.1",
|
||||||
"@welshman/net": "^0.4.7",
|
"@welshman/net": "^0.5.1",
|
||||||
"@welshman/relay": "^0.4.7",
|
"@welshman/relay": "^0.5.1",
|
||||||
"@welshman/router": "^0.4.7",
|
"@welshman/router": "^0.5.1",
|
||||||
"@welshman/signer": "^0.4.7",
|
"@welshman/signer": "^0.5.1",
|
||||||
"@welshman/store": "^0.4.7",
|
"@welshman/store": "^0.5.1",
|
||||||
"@welshman/util": "^0.4.7",
|
"@welshman/util": "^0.5.1",
|
||||||
"compressorjs": "^1.2.1",
|
"compressorjs": "^1.2.1",
|
||||||
"daisyui": "^4.12.10",
|
"daisyui": "^4.12.10",
|
||||||
"date-picker-svelte": "^2.13.0",
|
"date-picker-svelte": "^2.13.0",
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ importers:
|
|||||||
'@capacitor/core':
|
'@capacitor/core':
|
||||||
specifier: ^7.0.1
|
specifier: ^7.0.1
|
||||||
version: 7.2.0
|
version: 7.2.0
|
||||||
|
'@capacitor/filesystem':
|
||||||
|
specifier: ^7.0.0
|
||||||
|
version: 7.1.4(@capacitor/core@7.2.0)
|
||||||
'@capacitor/ios':
|
'@capacitor/ios':
|
||||||
specifier: ^7.0.0
|
specifier: ^7.0.0
|
||||||
version: 7.2.0(@capacitor/core@7.2.0)
|
version: 7.2.0(@capacitor/core@7.2.0)
|
||||||
@@ -69,38 +72,38 @@ importers:
|
|||||||
specifier: ^0.6.6
|
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))
|
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':
|
'@welshman/app':
|
||||||
specifier: ^0.4.7
|
specifier: ^0.5.1
|
||||||
version: 0.4.7(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)
|
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':
|
'@welshman/content':
|
||||||
specifier: ^0.4.7
|
specifier: ^0.5.1
|
||||||
version: 0.4.7(typescript@5.8.3)
|
version: 0.5.1(typescript@5.8.3)
|
||||||
'@welshman/editor':
|
'@welshman/editor':
|
||||||
specifier: ^0.4.7
|
specifier: ^0.5.1
|
||||||
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)
|
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':
|
'@welshman/feeds':
|
||||||
specifier: ^0.4.7
|
specifier: ^0.5.1
|
||||||
version: 0.4.7(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)
|
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':
|
'@welshman/lib':
|
||||||
specifier: ^0.4.7
|
specifier: ^0.5.1
|
||||||
version: 0.4.7
|
version: 0.5.1
|
||||||
'@welshman/net':
|
'@welshman/net':
|
||||||
specifier: ^0.4.7
|
specifier: ^0.5.1
|
||||||
version: 0.4.7(typescript@5.8.3)(ws@8.18.3)
|
version: 0.5.1(typescript@5.8.3)(ws@8.18.3)
|
||||||
'@welshman/relay':
|
'@welshman/relay':
|
||||||
specifier: ^0.4.7
|
specifier: ^0.5.1
|
||||||
version: 0.4.7(typescript@5.8.3)
|
version: 0.5.1(typescript@5.8.3)
|
||||||
'@welshman/router':
|
'@welshman/router':
|
||||||
specifier: ^0.4.7
|
specifier: ^0.5.1
|
||||||
version: 0.4.7(typescript@5.8.3)
|
version: 0.5.1(typescript@5.8.3)
|
||||||
'@welshman/signer':
|
'@welshman/signer':
|
||||||
specifier: ^0.4.7
|
specifier: ^0.5.1
|
||||||
version: 0.4.7(nostr-signer-capacitor-plugin@0.0.4(@capacitor/core@7.2.0))(typescript@5.8.3)(ws@8.18.3)
|
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':
|
'@welshman/store':
|
||||||
specifier: ^0.4.7
|
specifier: ^0.5.1
|
||||||
version: 0.4.7(typescript@5.8.3)
|
version: 0.5.1(typescript@5.8.3)
|
||||||
'@welshman/util':
|
'@welshman/util':
|
||||||
specifier: ^0.4.7
|
specifier: ^0.5.1
|
||||||
version: 0.4.7(typescript@5.8.3)
|
version: 0.5.1(typescript@5.8.3)
|
||||||
compressorjs:
|
compressorjs:
|
||||||
specifier: ^1.2.1
|
specifier: ^1.2.1
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
@@ -754,6 +757,11 @@ packages:
|
|||||||
'@capacitor/core@7.2.0':
|
'@capacitor/core@7.2.0':
|
||||||
resolution: {integrity: sha512-2zCnA6RJeZ9ec4470o8QMZEQTWpekw9FNoqm5TLc10jeCrhvHVI8MPgxdZVc3mOdFlyieYu4AS1fNxSqbS57Pw==}
|
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':
|
'@capacitor/ios@7.2.0':
|
||||||
resolution: {integrity: sha512-MQgRZcXZpbpjN83bjkGrzQd7s3XeHBZplmWf38/msF/siMGJKLrXNmNzmmPIWA5Xpi/aH6UoJFk1wXuU2U+zMg==}
|
resolution: {integrity: sha512-MQgRZcXZpbpjN83bjkGrzQd7s3XeHBZplmWf38/msF/siMGJKLrXNmNzmmPIWA5Xpi/aH6UoJFk1wXuU2U+zMg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -774,6 +782,9 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@capacitor/core': '>=7.0.0'
|
'@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':
|
'@capawesome/capacitor-android-dark-mode-support@7.0.0':
|
||||||
resolution: {integrity: sha512-xLa988v9MEnFZj7Aje3v2vvYbs5U3zk8vaO24OioXUV1ZPjGy4R2VkdoKG8fTsSYRdF6s4/8DpCuos8JLJqpjw==}
|
resolution: {integrity: sha512-xLa988v9MEnFZj7Aje3v2vvYbs5U3zk8vaO24OioXUV1ZPjGy4R2VkdoKG8fTsSYRdF6s4/8DpCuos8JLJqpjw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1089,8 +1100,8 @@ packages:
|
|||||||
'@noble/curves@1.2.0':
|
'@noble/curves@1.2.0':
|
||||||
resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==}
|
resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==}
|
||||||
|
|
||||||
'@noble/curves@1.9.2':
|
'@noble/curves@1.9.7':
|
||||||
resolution: {integrity: sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==}
|
resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==}
|
||||||
engines: {node: ^14.21.3 || >=16}
|
engines: {node: ^14.21.3 || >=16}
|
||||||
|
|
||||||
'@noble/hashes@1.3.1':
|
'@noble/hashes@1.3.1':
|
||||||
@@ -1419,77 +1430,77 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/pm': ^2.7.0
|
'@tiptap/pm': ^2.7.0
|
||||||
|
|
||||||
'@tiptap/extension-code-block@2.26.1':
|
'@tiptap/extension-code-block@2.26.2':
|
||||||
resolution: {integrity: sha512-/TDDOwONl0qEUc4+B6V9NnWtSjz95eg7/8uCb8Y8iRbGvI9vT4/znRKofFxstvKmW4URu/H74/g0ywV57h0B+A==}
|
resolution: {integrity: sha512-MJZ4QtziIWJ1zuSW2ogAHv+UHGk3DvGbVi+Dfmo0ybonXX7vRVHE+3qT7OcdTRBF+pC2oCnsjzqwFcGBP3BbZw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
'@tiptap/pm': ^2.7.0
|
'@tiptap/pm': ^2.7.0
|
||||||
|
|
||||||
'@tiptap/extension-code@2.26.1':
|
'@tiptap/extension-code@2.26.2':
|
||||||
resolution: {integrity: sha512-GU9deB1A/Tr4FMPu71CvlcjGKwRhGYz60wQ8m4aM+ELZcVIcZRa1ebR8bExRIEWnvRztQuyRiCQzw2N0xQJ1QQ==}
|
resolution: {integrity: sha512-xnKJvzlAp75dheyaK5tLKAksHf9PtSr8a7OuPjf2IXS5K+QMtnwxx7KAHHijmecfWjLR0wyu9AvT/FWFfKi5LQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
|
|
||||||
'@tiptap/extension-document@2.26.1':
|
'@tiptap/extension-document@2.26.2':
|
||||||
resolution: {integrity: sha512-2P2IZp1NRAE+21mRuFBiP3X2WKfZ6kUC23NJKpn8bcOamY3obYqCt0ltGPhE4eR8n8QAl2fI/3jIgjR07dC8ow==}
|
resolution: {integrity: sha512-s0/P3A8zxWL/h3e20xWMTT/rcwD0+57I6mT9JgNBPtvhPePy8d698G6/qFK+x+GdIyjJylfsq2BrSE9H+QhIBg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
|
|
||||||
'@tiptap/extension-dropcursor@2.26.1':
|
'@tiptap/extension-dropcursor@2.26.2':
|
||||||
resolution: {integrity: sha512-JkDQU2ZYFOuT5mNYb8OiWGwD1HcjbtmX8tLNugQbToECmz9WvVPqJmn7V/q8VGpP81iEECz/IsyRmuf2kSD4uA==}
|
resolution: {integrity: sha512-o5j4Gkurb/WBu1wP2tihYnZ8dENzmlxFWWMx++g6abEpn9xdud7VxHT5Ny7mBSBptI8uMwKT53weYC0on38n3g==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
'@tiptap/pm': ^2.7.0
|
'@tiptap/pm': ^2.7.0
|
||||||
|
|
||||||
'@tiptap/extension-gapcursor@2.26.1':
|
'@tiptap/extension-gapcursor@2.26.2':
|
||||||
resolution: {integrity: sha512-KOiMZc3PwJS3hR0nSq5d0TJi2jkNZkLZElcT6pCEnhRHzPH6dRMu9GM5Jj798ZRUy0T9UFcKJalFZaDxnmRnpg==}
|
resolution: {integrity: sha512-a68mi8V0mh058UrBIk23f50K5JGVeRZnF6ViptIleAD/Ny1K6VLjGCz6k190de+Tb9tnQLPEwwwDcy+ZnvCmYQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
'@tiptap/pm': ^2.7.0
|
'@tiptap/pm': ^2.7.0
|
||||||
|
|
||||||
'@tiptap/extension-hard-break@2.26.1':
|
'@tiptap/extension-hard-break@2.26.2':
|
||||||
resolution: {integrity: sha512-d6uStdNKi8kjPlHAyO59M6KGWATNwhLCD7dng0NXfwGndc22fthzIk/6j9F6ltQx30huy5qQram6j3JXwNACoA==}
|
resolution: {integrity: sha512-OLpeTey7p3ChyEsABLPvNv7rD/8E4k1JTt+H+MUjyL0dnrZuIWluckUJCJKnV8PhR9Mifngk1MTFUilpooiv1g==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
|
|
||||||
'@tiptap/extension-history@2.26.1':
|
'@tiptap/extension-history@2.26.2':
|
||||||
resolution: {integrity: sha512-m6YR1gkkauIDo3PRl0gP+7Oc4n5OqDzcjVh6LvWREmZP8nmi94hfseYbqOXUb6RPHIc0JKF02eiRifT4MSd2nw==}
|
resolution: {integrity: sha512-X/cu79AV5D2Z1QtuvKo/4/Rgl/Uti/n5V3QgCxFLQRCKTxHOCis+RlBCjBfOPztJX4T9QUE6lq20KqB47rsNwQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
'@tiptap/pm': ^2.7.0
|
'@tiptap/pm': ^2.7.0
|
||||||
|
|
||||||
'@tiptap/extension-image@2.26.1':
|
'@tiptap/extension-image@2.26.2':
|
||||||
resolution: {integrity: sha512-96+MaYBJebQlR/ik5W72GLUfXdEoxFs+6jsoERxbM5qEdhb7TEnodBFtWZOwgDO27kFd6rSNZuW9r5KJNtljEg==}
|
resolution: {integrity: sha512-3gK+ETLiWGAUdyPDXDheNJ38OgQabSzZJ+1nQo9KWjI7P3LQ7/ctxLtT+hAFpxX0qMK4bnu5vZaItSXxE3ZtpQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
|
|
||||||
'@tiptap/extension-link@2.26.1':
|
'@tiptap/extension-link@2.26.2':
|
||||||
resolution: {integrity: sha512-7yfum5Jymkue/uOSTQPt2SmkZIdZx7t3QhZLqBU7R9ettkdSCBgEGok6N+scJM1R1Zes+maSckLm0JZw5BKYNA==}
|
resolution: {integrity: sha512-rzYxx5wI1551ubPfW2pJ3V957cX/WAmbUI3q8Un+LlOsSmbddl+5BjlF5t/vl/pwaOv7FJAz9e29n877zkGOVQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
'@tiptap/pm': ^2.7.0
|
'@tiptap/pm': ^2.7.0
|
||||||
|
|
||||||
'@tiptap/extension-paragraph@2.26.1':
|
'@tiptap/extension-paragraph@2.26.2':
|
||||||
resolution: {integrity: sha512-UezvM9VDRAVJlX1tykgHWSD1g3MKfVMWWZ+Tg+PE4+kizOwoYkRWznVPgCAxjmyHajxpCKRXgqTZkOxjJ9Kjzg==}
|
resolution: {integrity: sha512-dccyffm95nNT9arjxGOyv4/cOPF4XS5Osylccp9KYLrmiSTXEuzVIYtMXhXbc0UUdABGvbFQWi88tRxgeDTkgA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
|
|
||||||
'@tiptap/extension-placeholder@2.26.1':
|
'@tiptap/extension-placeholder@2.26.2':
|
||||||
resolution: {integrity: sha512-MBlqbkd+63btY7Qu+SqrXvWjPwooGZDsLTtl7jp52BczBl61cq9yygglt9XpM11TFMBdySgdLHBrLtQ0B7fBlw==}
|
resolution: {integrity: sha512-XBTDcpEo7Zo/1+RhGnRxA2TF0elQW7EayUcV+lJ3f7HQ5lrb5NTnakYc1ydeZ8Ih6vUqbK2CQUsESe3UWHHgHg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
'@tiptap/pm': ^2.7.0
|
'@tiptap/pm': ^2.7.0
|
||||||
|
|
||||||
'@tiptap/extension-text@2.26.1':
|
'@tiptap/extension-text@2.26.2':
|
||||||
resolution: {integrity: sha512-p2n8WVMd/2vckdJlol24acaTDIZAhI7qle5cM75bn01sOEZoFlSw6SwINOULrUCzNJsYb43qrLEibZb4j2LeQw==}
|
resolution: {integrity: sha512-Rb8Le/Li+EixQNc/pGkEJpLjozTjWYP9glaYfnjPtRVw4tHcd7khVm5mer0TQjonbBUjVC1zSuXv9gifXOv6DQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
|
|
||||||
'@tiptap/pm@2.12.0':
|
'@tiptap/pm@2.12.0':
|
||||||
resolution: {integrity: sha512-TNzVwpeNzFfHAcYTOKqX9iU4fRxliyoZrCnERR+RRzeg7gWrXrCLubQt1WEx0sojMAfznshSL3M5HGsYjEbYwA==}
|
resolution: {integrity: sha512-TNzVwpeNzFfHAcYTOKqX9iU4fRxliyoZrCnERR+RRzeg7gWrXrCLubQt1WEx0sojMAfznshSL3M5HGsYjEbYwA==}
|
||||||
|
|
||||||
'@tiptap/suggestion@2.26.1':
|
'@tiptap/suggestion@2.26.2':
|
||||||
resolution: {integrity: sha512-iNWJdQN7h01keNoVwyCsdI7ZX11YkrexZjCnutWK17Dd72s3NYVTmQXu7saftwddT4nDdlczNxAFosrt0zMhcg==}
|
resolution: {integrity: sha512-BtigI3xOJQbdNh2OeKN5wQDI/EPGN4GXdpoMHhENZeXKrX6PvWNaqjyLVsV3QiLgv6P352nZWcgo51wPXY2JgQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
'@tiptap/pm': ^2.7.0
|
'@tiptap/pm': ^2.7.0
|
||||||
@@ -1648,41 +1659,41 @@ packages:
|
|||||||
'@vite-pwa/assets-generator':
|
'@vite-pwa/assets-generator':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@welshman/app@0.4.7':
|
'@welshman/app@0.5.1':
|
||||||
resolution: {integrity: sha512-JEgr3NhzDLeOoTSZ4+AESKhW+kwqYClLbLd6ccHV+Wa7hjoPJy2FlY3rDuppw9QSeTNCDEOvqCsjeWYz83lUBA==}
|
resolution: {integrity: sha512-/7xRGdBQyCDh+av1yDSMEHeyQQy61IZATBUxaGT/0tjFObsBoiYtLSg6iWFr9b5eo9LYVi54EJOo1PX2PdzvTg==}
|
||||||
|
|
||||||
'@welshman/content@0.4.7':
|
'@welshman/content@0.5.1':
|
||||||
resolution: {integrity: sha512-PF2FqiE3QUybl0CwwaEI2aGCZIis2rbdvBgeafgPiHW7fRYROxUZdtcMy+MyiRfiV40uoBcYwu/N6hHCRU7Pag==}
|
resolution: {integrity: sha512-Ft41yd5fdNgn+ZGO21zV2SSuwBGaKUw1l9HfpPvFbf+Ef+PYtRclOCIkZ3uo4OSASJu06lbumnBChgfkGn6AxA==}
|
||||||
|
|
||||||
'@welshman/editor@0.4.7':
|
'@welshman/editor@0.5.1':
|
||||||
resolution: {integrity: sha512-K6XCLG+vVvVeEYPx+m/+Lfx/JO+NtvvIemCds6gFjY7ac+WaQuEQDP3kFGYQu69XiFXp/UZrIa+t7SezEpnU8A==}
|
resolution: {integrity: sha512-JuM2Sb9XaXLDNxEnmMVGzPZfkYXl8BicHXua4dETmhPuZV23UPTuv2m7y0K+yW56AStRnBtjgSzVanK/pJW5Xg==}
|
||||||
|
|
||||||
'@welshman/feeds@0.4.7':
|
'@welshman/feeds@0.5.1':
|
||||||
resolution: {integrity: sha512-aZQuTUD4aSkL0s2BkjwEpo5KTd9BKf/XiOssQrltLdc8NIsz8RIO0XLgCpFb0/dmqHRoJEqU/plIBy7AlleRCQ==}
|
resolution: {integrity: sha512-9QOJERYlkmlQsiQH0OHA0CvoaE1r8lC2GsWn5cXv1XoskyR5q3HghKRC9MUtyx/vnO45irmy9SdBkVHz7WqXjg==}
|
||||||
|
|
||||||
'@welshman/lib@0.4.7':
|
'@welshman/lib@0.5.1':
|
||||||
resolution: {integrity: sha512-VP3WO2ROo5pf2vHwnrdt6lQVTc8Eo52Ie+1/9ZzfTrSxtLrreSSxW3H+1oPDbHl3FXbDnQWdFWbxys6OxzKZWw==}
|
resolution: {integrity: sha512-XPttF23jzwwgdmd83d+AZPCxZbkoQfJhn6p+w3hr5gdvunmDp3xdBf+fegnQYv/HIDBMQOHzyM/XxUYmqNDheA==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
'@welshman/net@0.4.7':
|
'@welshman/net@0.5.1':
|
||||||
resolution: {integrity: sha512-S0dGVqNAfo5cvBxIuaI2oEX0JUs2FuzkOcYXkMNB1plWzi1mBcskNCBWfFf/zHJYaqUoYjZ/tDARy64lge9m/w==}
|
resolution: {integrity: sha512-NSgAgiJhJvme9ov2/JP+ehuao/WMpjcQNFkshGaoe+PtzpwMsBSz9rEiwuPpZwsz3/edPdv8DgJwOzL6rQM+bw==}
|
||||||
|
|
||||||
'@welshman/relay@0.4.7':
|
'@welshman/relay@0.5.1':
|
||||||
resolution: {integrity: sha512-FkqYswNA3uT1NeJVHdEZ7p9jEPGCFMx4ci2y+h9o25rCDdxg3WUhqDSdc5d85sGTO0qG2pNnvNMfS/Du/nFlOA==}
|
resolution: {integrity: sha512-yyKvJt/3Vf2at7bqrGKPawHnuOVS1BKrMN8zyFLa49ntNi394+foWDkmMBEUZMdJBVVK5YVk/SQ0rJ2RkRj/gA==}
|
||||||
|
|
||||||
'@welshman/router@0.4.7':
|
'@welshman/router@0.5.1':
|
||||||
resolution: {integrity: sha512-HnB1qrKGNxL8HtC6p47yHUnaDHevi+IKtqWEVCIFMRf17GwINBc3wp3+d3pu9KBBXItFZz1awABvZK+pNKQcgg==}
|
resolution: {integrity: sha512-jH9pNSc8C1yYhEjN3Y0b8SMPg7V3Pqa0QNEKplk/TqdXoMCRQhM1aez+DXXwp7lA1q7GAqfViQ//0DMYrvAS6A==}
|
||||||
|
|
||||||
'@welshman/signer@0.4.7':
|
'@welshman/signer@0.5.1':
|
||||||
resolution: {integrity: sha512-V5Jdmblb2kPO5bAv1CzVrodZiwKpYYotmS6MFXfWmyrKKp+9B5KoMWzXt6yfd4HWYbEKEjLhbm1gzbckupW8Nw==}
|
resolution: {integrity: sha512-Ok8qUD7Mp7fHYXUxDnw0k0/fkiBxNomPXlt7EQ16RZ8ND9QayhP4U+MCXUGfIqzh89cPtwBnhZYofKsqaSWD0Q==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
nostr-signer-capacitor-plugin: ~0.0.4
|
nostr-signer-capacitor-plugin: ~0.0.4
|
||||||
|
|
||||||
'@welshman/store@0.4.7':
|
'@welshman/store@0.5.1':
|
||||||
resolution: {integrity: sha512-8PniW1AOOYFtLRYMuay62taumW7zgwtBmouwoMh08fBQjLb+c90V4g2cEGVWoyvKXSLzQkQppPlaqYzdSDqgwg==}
|
resolution: {integrity: sha512-wuQt/RGMk1dkOfImGfnCm+dDMI0+6mFIRXC17nC3v8TT/k0HUY8+JXPgYo9PP5E98YK3zFpmdeqFmxj4Q4puGA==}
|
||||||
|
|
||||||
'@welshman/util@0.4.7':
|
'@welshman/util@0.5.1':
|
||||||
resolution: {integrity: sha512-FlmBiZeKlAEAAwyhu7cWtlfAxU3CWX7WQGn0NkCZaAjgGV3n8LIDjT1u9m1PmXirBT0+qFNGLWas3p72IQMLgg==}
|
resolution: {integrity: sha512-8Hn0ONx2yc3l3D/7DMFkqIPlMU1b7CeMmEz+np43f5+X5y7iWJ3LGau2nJ6lSbIyM1WaxFl3++W691+bFPNz3Q==}
|
||||||
|
|
||||||
'@xml-tools/parser@1.0.11':
|
'@xml-tools/parser@1.0.11':
|
||||||
resolution: {integrity: sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==}
|
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==}
|
resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
js-base64@3.7.7:
|
js-base64@3.7.8:
|
||||||
resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==}
|
resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==}
|
||||||
|
|
||||||
js-tokens@4.0.0:
|
js-tokens@4.0.0:
|
||||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||||
@@ -3185,8 +3196,8 @@ packages:
|
|||||||
linkify-it@5.0.0:
|
linkify-it@5.0.0:
|
||||||
resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
|
resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
|
||||||
|
|
||||||
linkifyjs@4.3.1:
|
linkifyjs@4.3.2:
|
||||||
resolution: {integrity: sha512-DRSlB9DKVW04c4SUdGvKK5FR6be45lTU9M76JnngqPeeGDqPwYc0zdUErtsNVMtxPXgUWV4HbXbnC4sNyBxkYg==}
|
resolution: {integrity: sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==}
|
||||||
|
|
||||||
load-json-file@4.0.0:
|
load-json-file@4.0.0:
|
||||||
resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==}
|
resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==}
|
||||||
@@ -3430,8 +3441,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
|
resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
nostr-editor@1.0.0:
|
nostr-editor@1.0.1:
|
||||||
resolution: {integrity: sha512-+TL3G0m7WsXeEAitxzQhun7hyARxqRANjGIS2z9CBbniCGvT/Wz6YLgUnUysnBg3tmSgMZg5FWhaDPwfvdvbSw==}
|
resolution: {integrity: sha512-HXqXjxtIN0CcC7sLV5xYjEsQF0bFYLmNKxS75ya2yZGQ/z16U+uK6bb2Hd72QyqXlHXyWN0m24E5Gcws8/NhRQ==}
|
||||||
engines: {node: '>=18.16.1'}
|
engines: {node: '>=18.16.1'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.6.6
|
'@tiptap/core': ^2.6.6
|
||||||
@@ -5601,6 +5612,11 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
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)':
|
'@capacitor/ios@7.2.0(@capacitor/core@7.2.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@capacitor/core': 7.2.0
|
'@capacitor/core': 7.2.0
|
||||||
@@ -5617,6 +5633,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@capacitor/core': 7.2.0
|
'@capacitor/core': 7.2.0
|
||||||
|
|
||||||
|
'@capacitor/synapse@1.0.4': {}
|
||||||
|
|
||||||
'@capawesome/capacitor-android-dark-mode-support@7.0.0(@capacitor/core@7.2.0)':
|
'@capawesome/capacitor-android-dark-mode-support@7.0.0(@capacitor/core@7.2.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@capacitor/core': 7.2.0
|
'@capacitor/core': 7.2.0
|
||||||
@@ -5939,7 +5957,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@noble/hashes': 1.3.2
|
'@noble/hashes': 1.3.2
|
||||||
|
|
||||||
'@noble/curves@1.9.2':
|
'@noble/curves@1.9.7':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@noble/hashes': 1.8.0
|
'@noble/hashes': 1.8.0
|
||||||
|
|
||||||
@@ -6237,58 +6255,58 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@tiptap/pm': 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-code-block@2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
'@tiptap/core': 2.12.0(@tiptap/pm@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:
|
dependencies:
|
||||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
'@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:
|
dependencies:
|
||||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
'@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:
|
dependencies:
|
||||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
'@tiptap/core': 2.12.0(@tiptap/pm@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:
|
dependencies:
|
||||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
'@tiptap/core': 2.12.0(@tiptap/pm@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:
|
dependencies:
|
||||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
'@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:
|
dependencies:
|
||||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
'@tiptap/core': 2.12.0(@tiptap/pm@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:
|
dependencies:
|
||||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
'@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:
|
dependencies:
|
||||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
'@tiptap/core': 2.12.0(@tiptap/pm@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:
|
dependencies:
|
||||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
'@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:
|
dependencies:
|
||||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
'@tiptap/core': 2.12.0(@tiptap/pm@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:
|
dependencies:
|
||||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||||
|
|
||||||
@@ -6313,7 +6331,7 @@ snapshots:
|
|||||||
prosemirror-transform: 1.10.4
|
prosemirror-transform: 1.10.4
|
||||||
prosemirror-view: 1.39.3
|
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:
|
dependencies:
|
||||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
||||||
'@tiptap/pm': 2.12.0
|
'@tiptap/pm': 2.12.0
|
||||||
@@ -6524,19 +6542,18 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@vite-pwa/assets-generator': 0.2.6
|
'@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:
|
dependencies:
|
||||||
'@types/throttle-debounce': 5.0.2
|
'@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/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.4.7
|
'@welshman/lib': 0.5.1
|
||||||
'@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)
|
||||||
'@welshman/relay': 0.4.7(typescript@5.8.3)
|
'@welshman/relay': 0.5.1(typescript@5.8.3)
|
||||||
'@welshman/router': 0.4.7(typescript@5.8.3)
|
'@welshman/router': 0.5.1(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/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.4.7(typescript@5.8.3)
|
'@welshman/store': 0.5.1(typescript@5.8.3)
|
||||||
'@welshman/util': 0.4.7(typescript@5.8.3)
|
'@welshman/util': 0.5.1(typescript@5.8.3)
|
||||||
fuse.js: 7.1.0
|
fuse.js: 7.1.0
|
||||||
idb: 8.0.2
|
|
||||||
svelte: 4.2.20
|
svelte: 4.2.20
|
||||||
throttle-debounce: 5.0.2
|
throttle-debounce: 5.0.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -6544,31 +6561,31 @@ snapshots:
|
|||||||
- typescript
|
- typescript
|
||||||
- ws
|
- ws
|
||||||
|
|
||||||
'@welshman/content@0.4.7(typescript@5.8.3)':
|
'@welshman/content@0.5.1(typescript@5.8.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@braintree/sanitize-url': 7.1.1
|
'@braintree/sanitize-url': 7.1.1
|
||||||
nostr-tools: 2.14.2(typescript@5.8.3)
|
nostr-tools: 2.14.2(typescript@5.8.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- typescript
|
- 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:
|
dependencies:
|
||||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.0)
|
'@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': 2.26.2(@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-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.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))
|
||||||
'@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)
|
||||||
'@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)
|
||||||
'@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))
|
||||||
'@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)
|
||||||
'@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))
|
||||||
'@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)
|
||||||
'@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))
|
||||||
'@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)
|
'@tiptap/suggestion': 2.26.2(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
|
||||||
'@welshman/lib': 0.4.7
|
'@welshman/lib': 0.5.1
|
||||||
'@welshman/util': 0.4.7(typescript@5.8.3)
|
'@welshman/util': 0.5.1(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)))
|
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)
|
nostr-tools: 2.14.2(typescript@5.8.3)
|
||||||
tippy.js: 6.3.7
|
tippy.js: 6.3.7
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -6582,79 +6599,79 @@ snapshots:
|
|||||||
- tiptap-markdown
|
- tiptap-markdown
|
||||||
- typescript
|
- 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:
|
dependencies:
|
||||||
'@welshman/lib': 0.4.7
|
'@welshman/lib': 0.5.1
|
||||||
'@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)
|
||||||
'@welshman/relay': 0.4.7(typescript@5.8.3)
|
'@welshman/relay': 0.5.1(typescript@5.8.3)
|
||||||
'@welshman/router': 0.4.7(typescript@5.8.3)
|
'@welshman/router': 0.5.1(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/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.4.7(typescript@5.8.3)
|
'@welshman/util': 0.5.1(typescript@5.8.3)
|
||||||
trava: 1.2.1
|
trava: 1.2.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- nostr-signer-capacitor-plugin
|
- nostr-signer-capacitor-plugin
|
||||||
- typescript
|
- typescript
|
||||||
- ws
|
- ws
|
||||||
|
|
||||||
'@welshman/lib@0.4.7':
|
'@welshman/lib@0.5.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@scure/base': 1.2.6
|
'@scure/base': 1.2.6
|
||||||
'@types/events': 3.0.3
|
'@types/events': 3.0.3
|
||||||
events: 3.3.0
|
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:
|
dependencies:
|
||||||
'@welshman/lib': 0.4.7
|
'@welshman/lib': 0.5.1
|
||||||
'@welshman/relay': 0.4.7(typescript@5.8.3)
|
'@welshman/relay': 0.5.1(typescript@5.8.3)
|
||||||
'@welshman/util': 0.4.7(typescript@5.8.3)
|
'@welshman/util': 0.5.1(typescript@5.8.3)
|
||||||
events: 3.3.0
|
events: 3.3.0
|
||||||
isomorphic-ws: 5.0.0(ws@8.18.3)
|
isomorphic-ws: 5.0.0(ws@8.18.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- typescript
|
- typescript
|
||||||
- ws
|
- ws
|
||||||
|
|
||||||
'@welshman/relay@0.4.7(typescript@5.8.3)':
|
'@welshman/relay@0.5.1(typescript@5.8.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@welshman/lib': 0.4.7
|
'@welshman/lib': 0.5.1
|
||||||
'@welshman/util': 0.4.7(typescript@5.8.3)
|
'@welshman/util': 0.5.1(typescript@5.8.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
'@welshman/router@0.4.7(typescript@5.8.3)':
|
'@welshman/router@0.5.1(typescript@5.8.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@welshman/lib': 0.4.7
|
'@welshman/lib': 0.5.1
|
||||||
'@welshman/relay': 0.4.7(typescript@5.8.3)
|
'@welshman/relay': 0.5.1(typescript@5.8.3)
|
||||||
'@welshman/util': 0.4.7(typescript@5.8.3)
|
'@welshman/util': 0.5.1(typescript@5.8.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- typescript
|
- 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:
|
dependencies:
|
||||||
'@noble/curves': 1.9.2
|
'@noble/curves': 1.9.7
|
||||||
'@noble/hashes': 1.8.0
|
'@noble/hashes': 1.8.0
|
||||||
'@welshman/lib': 0.4.7
|
'@welshman/lib': 0.5.1
|
||||||
'@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)
|
||||||
'@welshman/util': 0.4.7(typescript@5.8.3)
|
'@welshman/util': 0.5.1(typescript@5.8.3)
|
||||||
nostr-signer-capacitor-plugin: 0.0.4(@capacitor/core@7.2.0)
|
nostr-signer-capacitor-plugin: 0.0.4(@capacitor/core@7.2.0)
|
||||||
nostr-tools: 2.14.2(typescript@5.8.3)
|
nostr-tools: 2.14.2(typescript@5.8.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- typescript
|
- typescript
|
||||||
- ws
|
- ws
|
||||||
|
|
||||||
'@welshman/store@0.4.7(typescript@5.8.3)':
|
'@welshman/store@0.5.1(typescript@5.8.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@welshman/lib': 0.4.7
|
'@welshman/lib': 0.5.1
|
||||||
'@welshman/relay': 0.4.7(typescript@5.8.3)
|
'@welshman/relay': 0.5.1(typescript@5.8.3)
|
||||||
'@welshman/util': 0.4.7(typescript@5.8.3)
|
'@welshman/util': 0.5.1(typescript@5.8.3)
|
||||||
svelte: 4.2.20
|
svelte: 4.2.20
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
'@welshman/util@0.4.7(typescript@5.8.3)':
|
'@welshman/util@0.5.1(typescript@5.8.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/ws': 8.18.1
|
'@types/ws': 8.18.1
|
||||||
'@welshman/lib': 0.4.7
|
'@welshman/lib': 0.5.1
|
||||||
js-base64: 3.7.7
|
js-base64: 3.7.8
|
||||||
nostr-tools: 2.14.2(typescript@5.8.3)
|
nostr-tools: 2.14.2(typescript@5.8.3)
|
||||||
nostr-wasm: 0.1.0
|
nostr-wasm: 0.1.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -8174,7 +8191,7 @@ snapshots:
|
|||||||
|
|
||||||
jiti@1.21.7: {}
|
jiti@1.21.7: {}
|
||||||
|
|
||||||
js-base64@3.7.7: {}
|
js-base64@3.7.8: {}
|
||||||
|
|
||||||
js-tokens@4.0.0: {}
|
js-tokens@4.0.0: {}
|
||||||
|
|
||||||
@@ -8249,7 +8266,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
uc.micro: 2.1.0
|
uc.micro: 2.1.0
|
||||||
|
|
||||||
linkifyjs@4.3.1: {}
|
linkifyjs@4.3.2: {}
|
||||||
|
|
||||||
load-json-file@4.0.0:
|
load-json-file@4.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -8485,15 +8502,15 @@ snapshots:
|
|||||||
|
|
||||||
normalize-range@0.1.2: {}
|
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:
|
dependencies:
|
||||||
'@tiptap/core': 2.12.0(@tiptap/pm@2.12.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-image': 2.26.2(@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)
|
||||||
'@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
|
light-bolt11-decoder: 3.2.0
|
||||||
linkifyjs: 4.3.1
|
linkifyjs: 4.3.2
|
||||||
nostr-tools: 2.14.2(typescript@5.8.3)
|
nostr-tools: 2.14.2(typescript@5.8.3)
|
||||||
prosemirror-markdown: 1.13.2
|
prosemirror-markdown: 1.13.2
|
||||||
prosemirror-model: 1.25.1
|
prosemirror-model: 1.25.1
|
||||||
|
|||||||
@@ -62,6 +62,8 @@
|
|||||||
--primary-content: oklch(var(--pc));
|
--primary-content: oklch(var(--pc));
|
||||||
--secondary: oklch(var(--s));
|
--secondary: oklch(var(--s));
|
||||||
--secondary-content: oklch(var(--sc));
|
--secondary-content: oklch(var(--sc));
|
||||||
|
--neutral: oklch(var(--n));
|
||||||
|
--neutral-content: oklch(var(--nc));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* safe area insets */
|
/* safe area insets */
|
||||||
@@ -215,12 +217,6 @@
|
|||||||
@apply ellipsize;
|
@apply ellipsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 639px) {
|
|
||||||
[data-tip]::before {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-padding-x {
|
.content-padding-x {
|
||||||
@apply px-4 sm:px-8 md:px-12;
|
@apply px-4 sm:px-8 md:px-12;
|
||||||
}
|
}
|
||||||
@@ -278,8 +274,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tiptap {
|
.tiptap {
|
||||||
--tiptap-object-bg: var(--base-100);
|
--tiptap-object-bg: var(--neutral);
|
||||||
--tiptap-object-fg: var(--base-content);
|
--tiptap-object-fg: var(--neutral-content);
|
||||||
--tiptap-active-bg: var(--primary);
|
--tiptap-active-bg: var(--primary);
|
||||||
--tiptap-active-fg: var(--primary-content);
|
--tiptap-active-fg: var(--primary-content);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import {getTagValue, getAddress} from "@welshman/util"
|
import {getTagValue, getAddress} from "@welshman/util"
|
||||||
import {isRelayFeed, findFeed} from "@welshman/feeds"
|
import {isRelayFeed, findFeed} from "@welshman/feeds"
|
||||||
import Inbox from "@assets/icons/inbox.svg?dataurl"
|
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 AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
@@ -10,8 +11,16 @@
|
|||||||
import AlertItem from "@app/components/AlertItem.svelte"
|
import AlertItem from "@app/components/AlertItem.svelte"
|
||||||
import {pushModal} from "@app/util/modal"
|
import {pushModal} from "@app/util/modal"
|
||||||
import {pushToast} from "@app/util/toast"
|
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 {deleteAlert, createDmAlert} from "@app/core/commands"
|
||||||
|
import {clearBadges} from "../util/notifications"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
url?: string
|
url?: string
|
||||||
@@ -42,11 +51,11 @@
|
|||||||
const uncheckDmAlert = async (message: string) => {
|
const uncheckDmAlert = async (message: string) => {
|
||||||
await sleep(100)
|
await sleep(100)
|
||||||
|
|
||||||
toggle.checked = false
|
directMessagesNotificationToggle.checked = false
|
||||||
pushToast({theme: "error", message})
|
pushToast({theme: "error", message})
|
||||||
}
|
}
|
||||||
|
|
||||||
const onToggle = async () => {
|
const onDirectMessagesNotificationToggle = async () => {
|
||||||
if ($dmAlert) {
|
if ($dmAlert) {
|
||||||
deleteAlert($dmAlert)
|
deleteAlert($dmAlert)
|
||||||
} else {
|
} 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>
|
</script>
|
||||||
|
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
@@ -88,14 +109,36 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card2 bg-alt flex flex-col gap-4 shadow-xl">
|
<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">
|
<div class="flex justify-between">
|
||||||
<p>Notify me about new direct messages</p>
|
<p>Notify me about new direct messages</p>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="toggle toggle-primary"
|
class="toggle toggle-primary"
|
||||||
bind:this={toggle}
|
bind:this={directMessagesNotificationToggle}
|
||||||
checked={Boolean($dmAlert)}
|
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>
|
</div>
|
||||||
{#if $dmStatus}
|
{#if $dmStatus}
|
||||||
{@const status = getTagValue("status", $dmStatus.tags) || "error"}
|
{@const status = getTagValue("status", $dmStatus.tags) || "error"}
|
||||||
|
|||||||
@@ -10,11 +10,10 @@
|
|||||||
import {makeEditor} from "@app/editor"
|
import {makeEditor} from "@app/editor"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
url?: string
|
|
||||||
onSubmit: (event: EventContent) => void
|
onSubmit: (event: EventContent) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const {onSubmit, url}: Props = $props()
|
const {onSubmit}: Props = $props()
|
||||||
|
|
||||||
const autofocus = !isMobile
|
const autofocus = !isMobile
|
||||||
|
|
||||||
@@ -39,11 +38,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const editor = makeEditor({
|
const editor = makeEditor({
|
||||||
url,
|
|
||||||
autofocus,
|
autofocus,
|
||||||
submit,
|
submit,
|
||||||
uploading,
|
uploading,
|
||||||
aggressive: true,
|
aggressive: true,
|
||||||
|
encryptFiles: true,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -69,11 +69,11 @@
|
|||||||
|
|
||||||
if (!parsed || hideMediaAtDepth <= depth) return false
|
if (!parsed || hideMediaAtDepth <= depth) return false
|
||||||
|
|
||||||
if (isLink(parsed) && $userSettingsValues.show_media && isStartOrEnd(i)) {
|
if (isLink(parsed) && $userSettingsValues.show_media && isStartAndEnd(i)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((isEvent(parsed) || isAddress(parsed)) && isStartOrEnd(i)) {
|
if ((isEvent(parsed) || isAddress(parsed)) && isStartAndEnd(i)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,8 +95,6 @@
|
|||||||
|
|
||||||
const isStartAndEnd = (i: number) => isStart(i) && isEnd(i)
|
const isStartAndEnd = (i: number) => isStart(i) && isEnd(i)
|
||||||
|
|
||||||
const isStartOrEnd = (i: number) => isStart(i) || isEnd(i)
|
|
||||||
|
|
||||||
const ignoreWarning = () => {
|
const ignoreWarning = () => {
|
||||||
warning = null
|
warning = null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type {ParsedEmojiValue} from "@welshman/content"
|
import type {ParsedEmojiValue} from "@welshman/content"
|
||||||
import {imgproxy} from "@app/core/state"
|
|
||||||
|
|
||||||
export let value: ParsedEmojiValue
|
export let value: ParsedEmojiValue
|
||||||
|
|
||||||
@@ -8,10 +7,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if value.url}
|
{#if value.url}
|
||||||
<img
|
<img {alt} src={value.url} class="-mt-0.5 inline h-[1em] min-w-[1em] align-middle" />
|
||||||
{alt}
|
|
||||||
src={imgproxy(value.url, {w: 24, h: 24})}
|
|
||||||
class="-mt-0.5 inline h-[1em] min-w-[1em] align-middle" />
|
|
||||||
{:else}
|
{:else}
|
||||||
{alt}
|
{alt}
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {ellipsize, displayUrl, postJson} from "@welshman/lib"
|
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 {preventDefault, stopPropagation} from "@lib/html"
|
||||||
import Link from "@lib/components/Link.svelte"
|
import Link from "@lib/components/Link.svelte"
|
||||||
import ContentLinkDetail from "@app/components/ContentLinkDetail.svelte"
|
import ContentLinkDetail from "@app/components/ContentLinkDetail.svelte"
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
<img
|
<img
|
||||||
alt="Link preview"
|
alt="Link preview"
|
||||||
onerror={onError}
|
onerror={onError}
|
||||||
src={imgproxy(preview.image)}
|
src={preview.image}
|
||||||
class="bg-alt max-h-72 rounded-t-box object-contain object-center" />
|
class="bg-alt max-h-72 rounded-t-box object-contain object-center" />
|
||||||
{/if}
|
{/if}
|
||||||
<div class="flex flex-col gap-2 p-4">
|
<div class="flex flex-col gap-2 p-4">
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {onMount, onDestroy} from "svelte"
|
import {onMount, onDestroy} from "svelte"
|
||||||
import {displayUrl} from "@welshman/lib"
|
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 LinkRound from "@assets/icons/link-round.svg?dataurl"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import {imgproxy} from "@app/core/state"
|
|
||||||
|
|
||||||
const {value, event, ...props} = $props()
|
const {value, event, ...props} = $props()
|
||||||
|
|
||||||
@@ -14,18 +21,34 @@
|
|||||||
.map(tagsFromIMeta)
|
.map(tagsFromIMeta)
|
||||||
.find(meta => getTagValue("url", meta) === url) || event.tags
|
.find(meta => getTagValue("url", meta) === url) || event.tags
|
||||||
|
|
||||||
|
const hash = getTagValue("x", meta)
|
||||||
const key = getTagValue("decryption-key", meta)
|
const key = getTagValue("decryption-key", meta)
|
||||||
const nonce = getTagValue("decryption-nonce", meta)
|
const nonce = getTagValue("decryption-nonce", meta)
|
||||||
const algorithm = getTagValue("encryption-algorithm", meta)
|
const algorithm = getTagValue("encryption-algorithm", meta)
|
||||||
|
|
||||||
const onError = () => {
|
const onError = async () => {
|
||||||
hasError = true
|
// 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 hasError = $state(false)
|
||||||
let src = $state(imgproxy(url))
|
let src = $state("")
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
|
// If we have an encryption algorithm, fetch and decrypt
|
||||||
if (algorithm === "aes-gcm" && key && nonce) {
|
if (algorithm === "aes-gcm" && key && nonce) {
|
||||||
const response = await fetch(url)
|
const response = await fetch(url)
|
||||||
|
|
||||||
@@ -35,6 +58,8 @@
|
|||||||
|
|
||||||
src = URL.createObjectURL(new Blob([decryptedData]))
|
src = URL.createObjectURL(new Blob([decryptedData]))
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
src = url
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -48,6 +73,6 @@
|
|||||||
<Icon icon={LinkRound} size={3} class="inline-block" />
|
<Icon icon={LinkRound} size={3} class="inline-block" />
|
||||||
{displayUrl(url)}
|
{displayUrl(url)}
|
||||||
</a>
|
</a>
|
||||||
{:else}
|
{:else if src}
|
||||||
<img alt="" {src} onerror={onError} {...props} />
|
<img alt="" {src} onerror={onError} {...props} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
{/snippet}
|
{/snippet}
|
||||||
</CardButton>
|
</CardButton>
|
||||||
</Button>
|
</Button>
|
||||||
<Button onclick={signUp} class="dark:btn-neutral">
|
<Button onclick={signUp} class="btn-neutral">
|
||||||
<CardButton>
|
<CardButton>
|
||||||
{#snippet icon()}
|
{#snippet icon()}
|
||||||
<div><Icon icon={AddCircle} size={7} /></div>
|
<div><Icon icon={AddCircle} size={7} /></div>
|
||||||
|
|||||||
@@ -32,9 +32,10 @@
|
|||||||
onNostrConnect: async (response: Nip46ResponseWithResult) => {
|
onNostrConnect: async (response: Nip46ResponseWithResult) => {
|
||||||
const pubkey = await controller.broker.getPublicKey()
|
const pubkey = await controller.broker.getPublicKey()
|
||||||
|
|
||||||
|
loginWithNip46(pubkey, controller.clientSecret, response.event.pubkey, SIGNER_RELAYS)
|
||||||
|
|
||||||
await loadUserData(pubkey)
|
await loadUserData(pubkey)
|
||||||
|
|
||||||
loginWithNip46(pubkey, controller.clientSecret, response.event.pubkey, SIGNER_RELAYS)
|
|
||||||
setChecked("*")
|
setChecked("*")
|
||||||
clearModals()
|
clearModals()
|
||||||
},
|
},
|
||||||
@@ -48,13 +49,20 @@
|
|||||||
try {
|
try {
|
||||||
const {signerPubkey, connectSecret, relays} = Nip46Broker.parseBunkerUrl($bunker)
|
const {signerPubkey, connectSecret, relays} = Nip46Broker.parseBunkerUrl($bunker)
|
||||||
|
|
||||||
if (!signerPubkey || relays.length === 0) {
|
if (!signerPubkey) {
|
||||||
return pushToast({
|
return pushToast({
|
||||||
theme: "error",
|
theme: "error",
|
||||||
message: "Sorry, it looks like that's an invalid bunker link.",
|
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)
|
controller.loading.set(true)
|
||||||
|
|
||||||
const {clientSecret} = controller
|
const {clientSecret} = controller
|
||||||
@@ -91,6 +99,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const selectConnect = () => {
|
const selectConnect = () => {
|
||||||
|
controller.loading.set(false)
|
||||||
mode = "connect"
|
mode = "connect"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import UserRounded from "@assets/icons/user-rounded.svg?dataurl"
|
import UserRounded from "@assets/icons/user-rounded.svg?dataurl"
|
||||||
import Server from "@assets/icons/server.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 Settings from "@assets/icons/settings-minimalistic.svg?dataurl"
|
||||||
import Code2 from "@assets/icons/code-2.svg?dataurl"
|
import Code2 from "@assets/icons/code-2.svg?dataurl"
|
||||||
import Exit from "@assets/icons/logout-3.svg?dataurl"
|
import Exit from "@assets/icons/logout-3.svg?dataurl"
|
||||||
@@ -13,13 +14,16 @@
|
|||||||
import LogOut from "@app/components/LogOut.svelte"
|
import LogOut from "@app/components/LogOut.svelte"
|
||||||
import {PLATFORM_NAME} from "@app/core/state"
|
import {PLATFORM_NAME} from "@app/core/state"
|
||||||
import {pushModal} from "@app/util/modal"
|
import {pushModal} from "@app/util/modal"
|
||||||
|
import {theme} from "@app/util/theme"
|
||||||
|
|
||||||
const logout = () => pushModal(LogOut)
|
const logout = () => pushModal(LogOut)
|
||||||
|
|
||||||
|
const toggleTheme = () => theme.set($theme === "dark" ? "light" : "dark")
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="column menu gap-2">
|
<div class="column menu gap-2">
|
||||||
<Link replaceState href="/settings/profile">
|
<Link replaceState href="/settings/profile">
|
||||||
<CardButton class="dark:btn-neutral">
|
<CardButton class="btn-neutral">
|
||||||
{#snippet icon()}
|
{#snippet icon()}
|
||||||
<div><Icon icon={UserRounded} size={7} /></div>
|
<div><Icon icon={UserRounded} size={7} /></div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
@@ -32,7 +36,7 @@
|
|||||||
</CardButton>
|
</CardButton>
|
||||||
</Link>
|
</Link>
|
||||||
<Link replaceState href="/settings/alerts">
|
<Link replaceState href="/settings/alerts">
|
||||||
<CardButton class="dark:btn-neutral">
|
<CardButton class="btn-neutral">
|
||||||
{#snippet icon()}
|
{#snippet icon()}
|
||||||
<div><Icon icon={Bell} size={7} /></div>
|
<div><Icon icon={Bell} size={7} /></div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
@@ -45,7 +49,7 @@
|
|||||||
</CardButton>
|
</CardButton>
|
||||||
</Link>
|
</Link>
|
||||||
<Link replaceState href="/settings/wallet">
|
<Link replaceState href="/settings/wallet">
|
||||||
<CardButton class="dark:btn-neutral">
|
<CardButton class="btn-neutral">
|
||||||
{#snippet icon()}
|
{#snippet icon()}
|
||||||
<div><Icon icon={Wallet} size={7} /></div>
|
<div><Icon icon={Wallet} size={7} /></div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
@@ -58,7 +62,7 @@
|
|||||||
</CardButton>
|
</CardButton>
|
||||||
</Link>
|
</Link>
|
||||||
<Link replaceState href="/settings/relays">
|
<Link replaceState href="/settings/relays">
|
||||||
<CardButton class="dark:btn-neutral">
|
<CardButton class="btn-neutral">
|
||||||
{#snippet icon()}
|
{#snippet icon()}
|
||||||
<div><Icon icon={Server} size={7} /></div>
|
<div><Icon icon={Server} size={7} /></div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
@@ -71,7 +75,7 @@
|
|||||||
</CardButton>
|
</CardButton>
|
||||||
</Link>
|
</Link>
|
||||||
<Link replaceState href="/settings/content">
|
<Link replaceState href="/settings/content">
|
||||||
<CardButton class="dark:btn-neutral">
|
<CardButton class="btn-neutral">
|
||||||
{#snippet icon()}
|
{#snippet icon()}
|
||||||
<div><Icon icon={Settings} size={7} /></div>
|
<div><Icon icon={Settings} size={7} /></div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
@@ -83,8 +87,21 @@
|
|||||||
{/snippet}
|
{/snippet}
|
||||||
</CardButton>
|
</CardButton>
|
||||||
</Link>
|
</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">
|
<Link replaceState href="/settings/about">
|
||||||
<CardButton class="dark:btn-neutral">
|
<CardButton class="btn-neutral">
|
||||||
{#snippet icon()}
|
{#snippet icon()}
|
||||||
<div><Icon icon={Code2} size={7} /></div>
|
<div><Icon icon={Code2} size={7} /></div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
<script lang="ts">
|
<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 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 Divider from "@lib/components/Divider.svelte"
|
||||||
import CardButton from "@lib/components/CardButton.svelte"
|
import CardButton from "@lib/components/CardButton.svelte"
|
||||||
import MenuSpacesItem from "@app/components/MenuSpacesItem.svelte"
|
import MenuSpacesItem from "@app/components/MenuSpacesItem.svelte"
|
||||||
import SpaceAdd from "@app/components/SpaceAdd.svelte"
|
|
||||||
import {userRoomsByUrl, PLATFORM_RELAYS} from "@app/core/state"
|
import {userRoomsByUrl, PLATFORM_RELAYS} from "@app/core/state"
|
||||||
import {pushModal} from "@app/util/modal"
|
|
||||||
|
|
||||||
const addSpace = () => pushModal(SpaceAdd)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="column menu gap-2">
|
<div class="column menu gap-2">
|
||||||
@@ -22,18 +18,18 @@
|
|||||||
{/each}
|
{/each}
|
||||||
<Divider />
|
<Divider />
|
||||||
{/if}
|
{/if}
|
||||||
<Button onclick={addSpace}>
|
<Link href="/discover">
|
||||||
<CardButton class="dark:btn-neutral">
|
<CardButton class="btn-neutral">
|
||||||
{#snippet icon()}
|
{#snippet icon()}
|
||||||
<div><Icon icon={Login} size={7} /></div>
|
<div><Icon icon={Compass} size={7} /></div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
{#snippet title()}
|
{#snippet title()}
|
||||||
<div>Add a space</div>
|
<div>Explore Spaces</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
{#snippet info()}
|
{#snippet info()}
|
||||||
<div>Join or create a new space</div>
|
<div>Join create, or browse spaces</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</CardButton>
|
</CardButton>
|
||||||
</Button>
|
</Link>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Link replaceState href={path}>
|
<Link replaceState href={path}>
|
||||||
<CardButton class="dark:btn-neutral">
|
<CardButton class="btn-neutral">
|
||||||
{#snippet icon()}
|
{#snippet icon()}
|
||||||
<div><SpaceAvatar {url} /></div>
|
<div><SpaceAvatar {url} /></div>
|
||||||
{/snippet}
|
{/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 {makeSpacePath} from "@app/util/routes"
|
||||||
import {notifications} from "@app/util/notifications"
|
import {notifications} from "@app/util/notifications"
|
||||||
import Widget from "@assets/icons/widget.svg?dataurl"
|
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 Letter from "@assets/icons/letter.svg?dataurl"
|
||||||
import Magnifier from "@assets/icons/magnifier.svg?dataurl"
|
import Magnifier from "@assets/icons/magnifier.svg?dataurl"
|
||||||
import HomeSmile from "@assets/icons/home-smile.svg?dataurl"
|
import HomeSmile from "@assets/icons/home-smile.svg?dataurl"
|
||||||
@@ -31,8 +31,6 @@
|
|||||||
|
|
||||||
const {children}: Props = $props()
|
const {children}: Props = $props()
|
||||||
|
|
||||||
const addSpace = () => pushModal(SpaceAdd)
|
|
||||||
|
|
||||||
const showSpacesMenu = () => (spaceUrls.length > 0 ? pushModal(MenuSpaces) : pushModal(SpaceAdd))
|
const showSpacesMenu = () => (spaceUrls.length > 0 ? pushModal(MenuSpaces) : pushModal(SpaceAdd))
|
||||||
|
|
||||||
const showOtherSpacesMenu = () => pushModal(MenuOtherSpaces, {urls: secondarySpaceUrls})
|
const showOtherSpacesMenu = () => pushModal(MenuOtherSpaces, {urls: secondarySpaceUrls})
|
||||||
@@ -83,8 +81,8 @@
|
|||||||
<Avatar icon={Widget} class="!h-10 !w-10" />
|
<Avatar icon={Widget} class="!h-10 !w-10" />
|
||||||
</PrimaryNavItem>
|
</PrimaryNavItem>
|
||||||
{/if}
|
{/if}
|
||||||
<PrimaryNavItem title="Add Space" onclick={addSpace} class="tooltip-right">
|
<PrimaryNavItem title="Add a Space" href="/discover" class="tooltip-right">
|
||||||
<Avatar icon={AddSquare} class="!h-10 !w-10" />
|
<Avatar icon={Compass} class="!h-10 !w-10" />
|
||||||
</PrimaryNavItem>
|
</PrimaryNavItem>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,22 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {nthNe} from "@welshman/lib"
|
|
||||||
import type {Profile} from "@welshman/util"
|
import type {Profile} from "@welshman/util"
|
||||||
import {
|
import {getTag, makeProfile} from "@welshman/util"
|
||||||
getTag,
|
import {pubkey, profilesByPubkey} from "@welshman/app"
|
||||||
makeEvent,
|
|
||||||
makeProfile,
|
|
||||||
editProfile,
|
|
||||||
createProfile,
|
|
||||||
isPublishedProfile,
|
|
||||||
uniqTags,
|
|
||||||
} from "@welshman/util"
|
|
||||||
import {Router} from "@welshman/router"
|
|
||||||
import {pubkey, profilesByPubkey, publishThunk} from "@welshman/app"
|
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import ProfileEditForm from "@app/components/ProfileEditForm.svelte"
|
import ProfileEditForm from "@app/components/ProfileEditForm.svelte"
|
||||||
import {clearModals} from "@app/util/modal"
|
import {clearModals} from "@app/util/modal"
|
||||||
import {pushToast} from "@app/util/toast"
|
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 profile = $profilesByPubkey.get($pubkey!) || makeProfile()
|
||||||
const shouldBroadcast = !getTag(PROTECTED, profile.event?.tags || [])
|
const shouldBroadcast = !getTag(PROTECTED, profile.event?.tags || [])
|
||||||
@@ -25,21 +16,7 @@
|
|||||||
const back = () => history.back()
|
const back = () => history.back()
|
||||||
|
|
||||||
const onsubmit = ({profile, shouldBroadcast}: {profile: Profile; shouldBroadcast: boolean}) => {
|
const onsubmit = ({profile, shouldBroadcast}: {profile: Profile; shouldBroadcast: boolean}) => {
|
||||||
const router = Router.get()
|
updateProfile({profile, shouldBroadcast})
|
||||||
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})
|
|
||||||
pushToast({message: "Your profile has been updated!"})
|
pushToast({message: "Your profile has been updated!"})
|
||||||
clearModals()
|
clearModals()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,8 @@
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Button class="max-w-full {props.class}" onclick={copy}>
|
<Button class="flex w-full justify-center {props.class}" onclick={copy}>
|
||||||
<div bind:this={wrapper} style={`height: ${height}px`}>
|
<div bind:this={wrapper} class="w-md" style={`height: ${height}px`}>
|
||||||
<canvas
|
<canvas
|
||||||
class="rounded-box"
|
class="rounded-box"
|
||||||
bind:this={canvas}
|
bind:this={canvas}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {spec, prop, avg} from "@welshman/lib"
|
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 CloseCircle from "@assets/icons/close-circle.svg?dataurl"
|
||||||
import Danger from "@assets/icons/danger-triangle.svg?dataurl"
|
import Danger from "@assets/icons/danger-triangle.svg?dataurl"
|
||||||
import ClockCircle from "@assets/icons/clock-circle.svg?dataurl"
|
import ClockCircle from "@assets/icons/clock-circle.svg?dataurl"
|
||||||
@@ -26,27 +26,45 @@
|
|||||||
const logout = () => pushModal(LogOut)
|
const logout = () => pushModal(LogOut)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card2 bg-alt flex flex-col gap-4">
|
{#if $session && $session.method !== SessionMethod.Anonymous}
|
||||||
<div class="flex flex-col gap-2">
|
<div class="card2 bg-alt flex flex-col gap-4">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-col gap-2">
|
||||||
<span class="text-xl font-bold">Signer Status</span>
|
<div class="flex items-center justify-between">
|
||||||
<span class="flex items-center gap-2">
|
<span class="text-xl font-bold">Signer Status</span>
|
||||||
{#if isDisconnected}
|
<span class="flex items-center gap-2">
|
||||||
<Icon icon={CloseCircle} class="text-error" size={4} /> Disconnected
|
{#if isDisconnected}
|
||||||
{:else if recentFailure > 3}
|
<Icon icon={CloseCircle} class="text-error" size={4} /> Disconnected
|
||||||
<Icon icon={Danger} class="text-warning" size={4} /> Partial Failure
|
{:else if recentFailure > 3}
|
||||||
{:else if recentAvg > 1000 || recentPending > 3}
|
<Icon icon={Danger} class="text-warning" size={4} /> Partial Failure
|
||||||
<Icon icon={ClockCircle} class="text-warning" size={4} /> Slow connection
|
{:else if recentAvg > 1000 || recentPending > 3}
|
||||||
{:else if recentSuccess === 0 && recentFailure > 0}{:else}
|
<Icon icon={ClockCircle} class="text-warning" size={4} /> Slow connection
|
||||||
<Icon icon={CheckCircle} class="text-success" size={4} /> Ok
|
{:else if recentSuccess === 0 && recentFailure > 0}{:else}
|
||||||
{/if}
|
<Icon icon={CheckCircle} class="text-success" size={4} /> Ok
|
||||||
</span>
|
{/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>
|
</div>
|
||||||
<p class="text-sm opacity-75">
|
{#if isDisconnected}
|
||||||
{success} requests succeeded, {failure} failed, {pending} pending
|
<Button class="btn btn-outline btn-error" onclick={logout}>Logout to Reconnect</Button>
|
||||||
</p>
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if isDisconnected}
|
{/if}
|
||||||
<Button class="btn btn-outline btn-error" onclick={logout}>Logout to Reconnect</Button>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {displayUrl} from "@welshman/lib"
|
import {displayUrl} from "@welshman/lib"
|
||||||
import {AuthStatus} from "@welshman/net"
|
import {AuthStatus} from "@welshman/net"
|
||||||
import {waitForThunkError} from "@welshman/app"
|
|
||||||
import {preventDefault} from "@lib/html"
|
import {preventDefault} from "@lib/html"
|
||||||
import Spinner from "@lib/components/Spinner.svelte"
|
import Spinner from "@lib/components/Spinner.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
@@ -15,7 +14,7 @@
|
|||||||
import SpaceJoinConfirm, {confirmSpaceJoin} from "@app/components/SpaceJoinConfirm.svelte"
|
import SpaceJoinConfirm, {confirmSpaceJoin} from "@app/components/SpaceJoinConfirm.svelte"
|
||||||
import {pushToast} from "@app/util/toast"
|
import {pushToast} from "@app/util/toast"
|
||||||
import {pushModal} from "@app/util/modal"
|
import {pushModal} from "@app/util/modal"
|
||||||
import {publishJoinRequest} from "@app/core/commands"
|
import {checkRelayAccess} from "@app/core/commands"
|
||||||
import {deriveSocket} from "@app/core/state"
|
import {deriveSocket} from "@app/core/state"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -32,11 +31,10 @@
|
|||||||
loading = true
|
loading = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const thunk = publishJoinRequest({url, claim})
|
const message = await checkRelayAccess(url, claim)
|
||||||
const error = await waitForThunkError(thunk)
|
|
||||||
|
|
||||||
if (error) {
|
if (message) {
|
||||||
return pushToast({theme: "error", message: error, timeout: 30_000})
|
return pushToast({theme: "error", message, timeout: 30_000})
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($socket.auth.status === AuthStatus.None) {
|
if ($socket.auth.status === AuthStatus.None) {
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Compass from "@assets/icons/compass-big.svg?dataurl"
|
|
||||||
import Login from "@assets/icons/login-3.svg?dataurl"
|
import Login from "@assets/icons/login-3.svg?dataurl"
|
||||||
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Link from "@lib/components/Link.svelte"
|
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import CardButton from "@lib/components/CardButton.svelte"
|
import CardButton from "@lib/components/CardButton.svelte"
|
||||||
import ModalHeader from "@lib/components/ModalHeader.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>
|
<div>Spaces are places where communities come together to work, play, and hang out.</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</ModalHeader>
|
</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}>
|
<Button onclick={startJoin}>
|
||||||
<CardButton class="dark:btn-neutral">
|
<CardButton class="btn-primary">
|
||||||
{#snippet icon()}
|
{#snippet icon()}
|
||||||
<div><Icon icon={Login} size={7} /></div>
|
<div><Icon icon={Login} size={7} /></div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
@@ -47,12 +32,12 @@
|
|||||||
<div>Join a space</div>
|
<div>Join a space</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
{#snippet info()}
|
{#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}
|
{/snippet}
|
||||||
</CardButton>
|
</CardButton>
|
||||||
</Button>
|
</Button>
|
||||||
<Button onclick={startCreate}>
|
<Button onclick={startCreate}>
|
||||||
<CardButton class="dark:btn-neutral">
|
<CardButton class="btn-neutral">
|
||||||
{#snippet icon()}
|
{#snippet icon()}
|
||||||
<div><Icon icon={AddCircle} size={7} /></div>
|
<div><Icon icon={AddCircle} size={7} /></div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|||||||
@@ -3,15 +3,15 @@
|
|||||||
import {sleep, nthEq} from "@welshman/lib"
|
import {sleep, nthEq} from "@welshman/lib"
|
||||||
import {request} from "@welshman/net"
|
import {request} from "@welshman/net"
|
||||||
import {displayRelayUrl, AUTH_INVITE} from "@welshman/util"
|
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 Spinner from "@lib/components/Spinner.svelte"
|
||||||
import Field from "@lib/components/Field.svelte"
|
import Field from "@lib/components/Field.svelte"
|
||||||
import Button from "@lib/components/Button.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 Icon from "@lib/components/Icon.svelte"
|
||||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||||
|
import QRCode from "@app/components/QRCode.svelte"
|
||||||
import {clip} from "@app/util/toast"
|
import {clip} from "@app/util/toast"
|
||||||
import {PLATFORM_URL} from "@app/core/state"
|
import {PLATFORM_URL} from "@app/core/state"
|
||||||
|
|
||||||
@@ -62,11 +62,12 @@
|
|||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
<div>
|
<div>
|
||||||
{#if loading}
|
{#if loading}
|
||||||
<p class="center" out:slide>
|
<p class="center">
|
||||||
<Spinner {loading}>Requesting an invite link...</Spinner>
|
<Spinner {loading}>Requesting an invite link...</Spinner>
|
||||||
</p>
|
</p>
|
||||||
{:else}
|
{:else}
|
||||||
<div in:slide>
|
<div class="flex flex-col items-center gap-6">
|
||||||
|
<QRCode code={invite} />
|
||||||
<Field>
|
<Field>
|
||||||
{#snippet input()}
|
{#snippet input()}
|
||||||
<label class="input input-bordered flex w-full items-center gap-2">
|
<label class="input input-bordered flex w-full items-center gap-2">
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import {fade} from "@lib/transition"
|
import {fade} from "@lib/transition"
|
||||||
import CompassBig from "@assets/icons/compass-big.svg?dataurl"
|
import CompassBig from "@assets/icons/compass-big.svg?dataurl"
|
||||||
import NotesMinimalistic from "@assets/icons/notes-minimalistic.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 CalendarMinimalistic from "@assets/icons/calendar-minimalistic.svg?dataurl"
|
||||||
import Magnifier from "@assets/icons/magnifier.svg?dataurl"
|
import Magnifier from "@assets/icons/magnifier.svg?dataurl"
|
||||||
import Lock from "@assets/icons/lock-keyhole.svg?dataurl"
|
import Lock from "@assets/icons/lock-keyhole.svg?dataurl"
|
||||||
@@ -14,7 +15,7 @@
|
|||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import RoomCreate from "@app/components/RoomCreate.svelte"
|
import RoomCreate from "@app/components/RoomCreate.svelte"
|
||||||
import ChannelName from "@app/components/ChannelName.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 {
|
import {
|
||||||
hasNip29,
|
hasNip29,
|
||||||
deriveUserRooms,
|
deriveUserRooms,
|
||||||
@@ -34,8 +35,9 @@
|
|||||||
const userRooms = deriveUserRooms(url)
|
const userRooms = deriveUserRooms(url)
|
||||||
const otherRooms = deriveOtherRooms(url)
|
const otherRooms = deriveOtherRooms(url)
|
||||||
const chatPath = makeSpacePath(url, "chat")
|
const chatPath = makeSpacePath(url, "chat")
|
||||||
const threadsPath = makeThreadPath(url)
|
const goalsPath = makeSpacePath(url, "goals")
|
||||||
const calendarPath = makeCalendarPath(url)
|
const threadsPath = makeSpacePath(url, "threads")
|
||||||
|
const calendarPath = makeSpacePath(url, "calendar")
|
||||||
|
|
||||||
const addRoom = () => pushModal(RoomCreate, {url})
|
const addRoom = () => pushModal(RoomCreate, {url})
|
||||||
|
|
||||||
@@ -61,25 +63,37 @@
|
|||||||
Quick Links
|
Quick Links
|
||||||
</h3>
|
</h3>
|
||||||
<div class="flex flex-col gap-2">
|
<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">
|
<div class="relative flex items-center gap-2">
|
||||||
<Icon icon={NotesMinimalistic} />
|
<Icon icon={StarFallMinimalistic} />
|
||||||
Threads
|
Goals
|
||||||
{#if $notifications.has(threadsPath)}
|
{#if $notifications.has(goalsPath)}
|
||||||
<div
|
<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>
|
transition:fade>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</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">
|
<div class="relative flex items-center gap-2">
|
||||||
<Icon icon={CalendarMinimalistic} />
|
<Icon icon={CalendarMinimalistic} />
|
||||||
Calendar
|
Calendar
|
||||||
{#if $notifications.has(calendarPath)}
|
{#if $notifications.has(calendarPath)}
|
||||||
<div
|
<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>
|
transition:fade>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -46,8 +46,7 @@
|
|||||||
|
|
||||||
{#if showFailure}
|
{#if showFailure}
|
||||||
{@const url = failedUrls[0]}
|
{@const url = failedUrls[0]}
|
||||||
{@const status = $thunk.status[url]}
|
{@const {status, detail: message} = $thunk.results[url]}
|
||||||
{@const message = $thunk.details[url]}
|
|
||||||
<button
|
<button
|
||||||
class="flex w-full justify-end px-1 text-xs {restProps.class}"
|
class="flex w-full justify-end px-1 text-xs {restProps.class}"
|
||||||
onclick={stopPropagation(noop)}>
|
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 {nwc} from "@getalby/sdk"
|
||||||
import {sleep, assoc} from "@welshman/lib"
|
import {sleep, assoc} from "@welshman/lib"
|
||||||
import type {NWCInfo} from "@welshman/util"
|
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 Link from "@lib/components/Link.svelte"
|
||||||
import Cpu from "@assets/icons/cpu-bolt.svg?dataurl"
|
import Cpu from "@assets/icons/cpu-bolt.svg?dataurl"
|
||||||
import Lock from "@assets/icons/lock-keyhole.svg?dataurl"
|
import Lock from "@assets/icons/lock-keyhole.svg?dataurl"
|
||||||
@@ -15,11 +15,13 @@
|
|||||||
import Scanner from "@lib/components/Scanner.svelte"
|
import Scanner from "@lib/components/Scanner.svelte"
|
||||||
import Spinner from "@lib/components/Spinner.svelte"
|
import Spinner from "@lib/components/Spinner.svelte"
|
||||||
import Field from "@lib/components/Field.svelte"
|
import Field from "@lib/components/Field.svelte"
|
||||||
import Divider from "@lib/components/Divider.svelte"
|
|
||||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||||
import {getWebLn} from "@app/core/commands"
|
import {getWebLn} from "@app/core/commands"
|
||||||
import {pushToast} from "@app/util/toast"
|
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()
|
const back = () => history.back()
|
||||||
|
|
||||||
@@ -76,6 +78,10 @@
|
|||||||
await sleep(400)
|
await sleep(400)
|
||||||
|
|
||||||
back()
|
back()
|
||||||
|
|
||||||
|
if (info.lud16 && info.lud16 !== $userProfile?.lud16) {
|
||||||
|
pushModal(WalletAsReceivingAddress)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
@@ -109,7 +115,7 @@
|
|||||||
<div>Connect a Wallet</div>
|
<div>Connect a Wallet</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
{#snippet info()}
|
{#snippet info()}
|
||||||
Use Nostr Wallet Connect to send Bitcoin payments over Bolt.
|
Use Nostr Wallet Connect to send Bitcoin payments over lightning.
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
{#if getWebLn()}
|
{#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>
|
||||||
@@ -3,6 +3,7 @@ import * as nip19 from "nostr-tools/nip19"
|
|||||||
import {get} from "svelte/store"
|
import {get} from "svelte/store"
|
||||||
import type {Override, MakeOptional} from "@welshman/lib"
|
import type {Override, MakeOptional} from "@welshman/lib"
|
||||||
import {
|
import {
|
||||||
|
first,
|
||||||
sha256,
|
sha256,
|
||||||
randomId,
|
randomId,
|
||||||
append,
|
append,
|
||||||
@@ -16,12 +17,15 @@ import {
|
|||||||
parseJson,
|
parseJson,
|
||||||
fromPairs,
|
fromPairs,
|
||||||
last,
|
last,
|
||||||
|
simpleCache,
|
||||||
|
normalizeUrl,
|
||||||
|
nthNe,
|
||||||
} from "@welshman/lib"
|
} from "@welshman/lib"
|
||||||
import {decrypt, Nip01Signer} from "@welshman/signer"
|
import {decrypt, Nip01Signer} from "@welshman/signer"
|
||||||
import type {UploadTask} from "@welshman/editor"
|
import type {UploadTask} from "@welshman/editor"
|
||||||
import type {Feed} from "@welshman/feeds"
|
import type {Feed} from "@welshman/feeds"
|
||||||
import {makeIntersectionFeed, feedFromFilters, makeRelayFeed} 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 {
|
import {
|
||||||
WRAP,
|
WRAP,
|
||||||
DELETE,
|
DELETE,
|
||||||
@@ -57,8 +61,13 @@ import {
|
|||||||
getTagValue,
|
getTagValue,
|
||||||
getTagValues,
|
getTagValues,
|
||||||
uploadBlob,
|
uploadBlob,
|
||||||
|
canUploadBlob,
|
||||||
encryptFile,
|
encryptFile,
|
||||||
makeBlossomAuthEvent,
|
makeBlossomAuthEvent,
|
||||||
|
isPublishedProfile,
|
||||||
|
editProfile,
|
||||||
|
createProfile,
|
||||||
|
uniqTags,
|
||||||
} from "@welshman/util"
|
} from "@welshman/util"
|
||||||
import {Pool, AuthStatus, SocketStatus} from "@welshman/net"
|
import {Pool, AuthStatus, SocketStatus} from "@welshman/net"
|
||||||
import {Router} from "@welshman/router"
|
import {Router} from "@welshman/router"
|
||||||
@@ -75,7 +84,6 @@ import {
|
|||||||
userInboxRelaySelections,
|
userInboxRelaySelections,
|
||||||
nip44EncryptToSelf,
|
nip44EncryptToSelf,
|
||||||
loadRelay,
|
loadRelay,
|
||||||
clearStorage,
|
|
||||||
dropSession,
|
dropSession,
|
||||||
tagEventForComment,
|
tagEventForComment,
|
||||||
tagEventForQuote,
|
tagEventForQuote,
|
||||||
@@ -92,15 +100,17 @@ import {
|
|||||||
INDEXER_RELAYS,
|
INDEXER_RELAYS,
|
||||||
NOTIFIER_PUBKEY,
|
NOTIFIER_PUBKEY,
|
||||||
NOTIFIER_RELAY,
|
NOTIFIER_RELAY,
|
||||||
|
DEFAULT_BLOSSOM_SERVERS,
|
||||||
userRoomsByUrl,
|
userRoomsByUrl,
|
||||||
userSettingsValues,
|
userSettingsValues,
|
||||||
canDecrypt,
|
canDecrypt,
|
||||||
ensureUnwrapped,
|
ensureUnwrapped,
|
||||||
userInboxRelays,
|
userInboxRelays,
|
||||||
|
getMembershipUrls,
|
||||||
} from "@app/core/state"
|
} from "@app/core/state"
|
||||||
import {loadAlertStatuses} from "@app/core/requests"
|
import {loadAlertStatuses} from "@app/core/requests"
|
||||||
import {platform, platformName, getPushInfo} from "@app/util/push"
|
import {platform, platformName, getPushInfo} from "@app/util/push"
|
||||||
import {preferencesStorageProvider} from "@src/lib/storage"
|
import {preferencesStorageProvider, collectionStorageProvider} from "@src/lib/storage"
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
|
|
||||||
@@ -143,10 +153,10 @@ export const logout = async () => {
|
|||||||
dropSession($pubkey)
|
dropSession($pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
await clearStorage()
|
|
||||||
|
|
||||||
localStorage.clear()
|
localStorage.clear()
|
||||||
|
|
||||||
await preferencesStorageProvider.clear()
|
await preferencesStorageProvider.clear()
|
||||||
|
await collectionStorageProvider.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Synchronization
|
// Synchronization
|
||||||
@@ -158,7 +168,7 @@ export const broadcastUserData = async (relays: string[]) => {
|
|||||||
|
|
||||||
for (const event of events) {
|
for (const event of events) {
|
||||||
if (isSignedEvent(event)) {
|
if (isSignedEvent(event)) {
|
||||||
await publishThunk({event, relays}).result
|
await publishThunk({event, relays}).complete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -660,17 +670,53 @@ export const enableGiftWraps = () => {
|
|||||||
|
|
||||||
// File upload
|
// 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()))
|
const userUrls = getTagValues("server", getListTags(userBlossomServers.get()))
|
||||||
|
|
||||||
for (const url of userUrls) {
|
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 = {
|
export type UploadFileOptions = {
|
||||||
|
url?: string
|
||||||
encrypt?: boolean
|
encrypt?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -680,35 +726,35 @@ export type UploadFileResult = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const uploadFile = async (file: File, options: UploadFileOptions = {}) => {
|
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 {
|
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 res = await uploadBlob(server, file, {authEvent})
|
||||||
const text = await res.text()
|
const text = await res.text()
|
||||||
|
|
||||||
@@ -718,16 +764,45 @@ export const uploadFile = async (file: File, options: UploadFileOptions = {}) =>
|
|||||||
return {error: text}
|
return {error: text}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always append file extension if missing
|
// Always append correct file extension if we encrypted the file, or if it's missing
|
||||||
if (new URL(url).pathname.split(".").length === 1) {
|
if (options.encrypt) {
|
||||||
url += "." + type.split("/")[1]
|
url = url.replace(/\.\w+$/, "") + ext
|
||||||
|
} else if (new URL(url).pathname.split(".").length === 1) {
|
||||||
|
url += ext
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = {...task, tags, url}
|
const result = {...task, tags, url}
|
||||||
|
|
||||||
return {result}
|
return {result}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error(e)
|
console.error("Error caught when uploading file:", e)
|
||||||
|
|
||||||
return {error: e.toString()}
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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 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 BURROW_URL = import.meta.env.VITE_BURROW_URL
|
||||||
|
|
||||||
export const DEFAULT_PUBKEYS = import.meta.env.VITE_DEFAULT_PUBKEYS
|
export const DEFAULT_PUBKEYS = import.meta.env.VITE_DEFAULT_PUBKEYS
|
||||||
|
|
||||||
export const DUFFLEPUD_URL = "https://dufflepud.onrender.com"
|
export const DUFFLEPUD_URL = "https://dufflepud.onrender.com"
|
||||||
|
|
||||||
export const IMGPROXY_URL = "https://imgproxy.coracle.social"
|
|
||||||
|
|
||||||
export const NIP46_PERMS =
|
export const NIP46_PERMS =
|
||||||
"nip44_encrypt,nip44_decrypt," +
|
"nip44_encrypt,nip44_decrypt," +
|
||||||
[CLIENT_AUTH, AUTH_JOIN, MESSAGE, THREAD, COMMENT, ROOMS, WRAP, REACTION, ZAP_REQUEST]
|
[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 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 entityLink = (entity: string) => `https://coracle.social/${entity}`
|
||||||
|
|
||||||
export const pubkeyLink = (pubkey: string, relays = Router.get().FromPubkeys([pubkey]).getUrls()) =>
|
export const pubkeyLink = (pubkey: string, relays = Router.get().FromPubkeys([pubkey]).getUrls()) =>
|
||||||
@@ -336,6 +322,8 @@ export type SettingsValues = {
|
|||||||
report_errors: boolean
|
report_errors: boolean
|
||||||
send_delay: number
|
send_delay: number
|
||||||
font_size: number
|
font_size: number
|
||||||
|
play_notification_sound: boolean
|
||||||
|
show_notifications_badge: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Settings = {
|
export type Settings = {
|
||||||
@@ -349,8 +337,10 @@ export const defaultSettings = {
|
|||||||
trusted_relays: [],
|
trusted_relays: [],
|
||||||
report_usage: true,
|
report_usage: true,
|
||||||
report_errors: true,
|
report_errors: true,
|
||||||
send_delay: 3000,
|
send_delay: 0,
|
||||||
font_size: 1,
|
font_size: 1,
|
||||||
|
play_notification_sound: true,
|
||||||
|
show_notifications_badge: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const settings = deriveEventsMapped<Settings>(repository, {
|
export const settings = deriveEventsMapped<Settings>(repository, {
|
||||||
@@ -405,9 +395,13 @@ export const alerts = withGetter(
|
|||||||
filters: [{kinds: [ALERT_EMAIL, ALERT_WEB, ALERT_IOS, ALERT_ANDROID]}],
|
filters: [{kinds: [ALERT_EMAIL, ALERT_WEB, ALERT_IOS, ALERT_ANDROID]}],
|
||||||
itemToEvent: item => item.event,
|
itemToEvent: item => item.event,
|
||||||
eventToItem: async 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]}],
|
filters: [{kinds: [ALERT_STATUS]}],
|
||||||
itemToEvent: item => item.event,
|
itemToEvent: item => item.event,
|
||||||
eventToItem: async 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[]>()
|
const messagesByChatId = new Map<string, TrustedEvent[]>()
|
||||||
|
|
||||||
for (const message of $messages) {
|
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))
|
const chatId = makeChatId(getPubkeyTagValues(message.tags).concat(message.pubkey))
|
||||||
|
|
||||||
pushToMapKey(messagesByChatId, chatId, message)
|
pushToMapKey(messagesByChatId, chatId, message)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {uploadFile} from "@app/core/commands"
|
|||||||
import {pushToast} from "@app/util/toast"
|
import {pushToast} from "@app/util/toast"
|
||||||
|
|
||||||
export const makeEditor = async ({
|
export const makeEditor = async ({
|
||||||
|
encryptFiles = false,
|
||||||
aggressive = false,
|
aggressive = false,
|
||||||
autofocus = false,
|
autofocus = false,
|
||||||
charCount,
|
charCount,
|
||||||
@@ -21,6 +22,7 @@ export const makeEditor = async ({
|
|||||||
uploading,
|
uploading,
|
||||||
wordCount,
|
wordCount,
|
||||||
}: {
|
}: {
|
||||||
|
encryptFiles?: boolean
|
||||||
aggressive?: boolean
|
aggressive?: boolean
|
||||||
autofocus?: boolean
|
autofocus?: boolean
|
||||||
charCount?: Writable<number>
|
charCount?: Writable<number>
|
||||||
@@ -51,7 +53,8 @@ export const makeEditor = async ({
|
|||||||
},
|
},
|
||||||
fileUpload: {
|
fileUpload: {
|
||||||
config: {
|
config: {
|
||||||
upload: (attrs: FileAttributes) => uploadFile(attrs.file, {encrypt: true}),
|
upload: (attrs: FileAttributes) =>
|
||||||
|
uploadFile(attrs.file, {url, encrypt: encryptFiles}),
|
||||||
onDrop: () => uploading?.set(true),
|
onDrop: () => uploading?.set(true),
|
||||||
onComplete: () => uploading?.set(false),
|
onComplete: () => uploading?.set(false),
|
||||||
onUploadError(currentEditor, task) {
|
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 {synced, throttled} from "@welshman/store"
|
||||||
import {pubkey, relaysByUrl} from "@welshman/app"
|
import {pubkey, relaysByUrl} from "@welshman/app"
|
||||||
import {prop, spec, identity, now, groupBy} from "@welshman/lib"
|
import {prop, spec, identity, now, groupBy} from "@welshman/lib"
|
||||||
@@ -12,8 +12,16 @@ import {
|
|||||||
makeSpaceChatPath,
|
makeSpaceChatPath,
|
||||||
makeRoomPath,
|
makeRoomPath,
|
||||||
} from "@app/util/routes"
|
} 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 {preferencesStorageProvider} from "@src/lib/storage"
|
||||||
|
import {Badge} from "@capawesome/capacitor-badge"
|
||||||
|
|
||||||
// Checked state
|
// Checked state
|
||||||
|
|
||||||
@@ -150,3 +158,23 @@ export const notifications = derived(
|
|||||||
return paths
|
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(),
|
||||||
|
])
|
||||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 723 B After Width: | Height: | Size: 723 B |
|
Before Width: | Height: | Size: 919 B After Width: | Height: | Size: 919 B |
|
Before Width: | Height: | Size: 826 B After Width: | Height: | Size: 826 B |
|
Before Width: | Height: | Size: 630 B After Width: | Height: | Size: 630 B |
|
Before Width: | Height: | Size: 805 B After Width: | Height: | Size: 805 B |
|
Before Width: | Height: | Size: 597 B After Width: | Height: | Size: 597 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 826 B After Width: | Height: | Size: 826 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 780 B After Width: | Height: | Size: 780 B |
|
Before Width: | Height: | Size: 814 B After Width: | Height: | Size: 814 B |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 787 B After Width: | Height: | Size: 787 B |
|
Before Width: | Height: | Size: 556 B After Width: | Height: | Size: 556 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 992 B After Width: | Height: | Size: 992 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 687 B After Width: | Height: | Size: 687 B |
|
Before Width: | Height: | Size: 659 B After Width: | Height: | Size: 659 B |
|
Before Width: | Height: | Size: 773 B After Width: | Height: | Size: 773 B |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 527 B After Width: | Height: | Size: 527 B |
|
Before Width: | Height: | Size: 959 B After Width: | Height: | Size: 959 B |
|
Before Width: | Height: | Size: 268 B After Width: | Height: | Size: 268 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 906 B After Width: | Height: | Size: 906 B |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -49,7 +49,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex flex-col gap-2" role="list">
|
<div class="flex flex-col gap-2" role="list">
|
||||||
{#each value as item, index (item)}
|
{#each value as item, index}
|
||||||
<div
|
<div
|
||||||
class="flex items-center gap-2"
|
class="flex items-center gap-2"
|
||||||
draggable="true"
|
draggable="true"
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import {type StorageProvider} from "@welshman/store"
|
import {type StorageProvider} from "@welshman/store"
|
||||||
import {Preferences} from "@capacitor/preferences"
|
import {Preferences} from "@capacitor/preferences"
|
||||||
|
import {Encoding, Filesystem, Directory} from "@capacitor/filesystem"
|
||||||
|
|
||||||
export class PreferencesStorageProvider implements StorageProvider {
|
export class PreferencesStorageProvider implements StorageProvider {
|
||||||
|
p = Promise.resolve()
|
||||||
|
|
||||||
get = async <T>(key: string): Promise<T | undefined> => {
|
get = async <T>(key: string): Promise<T | undefined> => {
|
||||||
const result = await Preferences.get({key})
|
const result = await Preferences.get({key})
|
||||||
if (!result.value) return undefined
|
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> => {
|
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
|
await this.p
|
||||||
}
|
}
|
||||||
|
|
||||||
clear = async (): Promise<void> => {
|
clear = async (): Promise<void> => {
|
||||||
await Preferences.clear()
|
this.p = this.p.then(async () => {
|
||||||
this.p = Promise.resolve()
|
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 collectionStorageProvider = new CollectionStorageProvider()
|
||||||
export const preferencesStorageProvider = new PreferencesStorageProvider()
|
|
||||||
|
|||||||
@@ -24,27 +24,7 @@
|
|||||||
WEEK,
|
WEEK,
|
||||||
} from "@welshman/lib"
|
} from "@welshman/lib"
|
||||||
import type {TrustedEvent, StampedEvent} from "@welshman/util"
|
import type {TrustedEvent, StampedEvent} from "@welshman/util"
|
||||||
import {
|
import {WRAP} from "@welshman/util"
|
||||||
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 {Nip46Broker, makeSecret} from "@welshman/signer"
|
import {Nip46Broker, makeSecret} from "@welshman/signer"
|
||||||
import type {Socket, RelayMessage, ClientMessage} from "@welshman/net"
|
import type {Socket, RelayMessage, ClientMessage} from "@welshman/net"
|
||||||
import {
|
import {
|
||||||
@@ -61,8 +41,6 @@
|
|||||||
} from "@welshman/net"
|
} from "@welshman/net"
|
||||||
import {
|
import {
|
||||||
loadRelay,
|
loadRelay,
|
||||||
db,
|
|
||||||
initStorage,
|
|
||||||
repository,
|
repository,
|
||||||
pubkey,
|
pubkey,
|
||||||
session,
|
session,
|
||||||
@@ -70,10 +48,8 @@
|
|||||||
signer,
|
signer,
|
||||||
signerLog,
|
signerLog,
|
||||||
dropSession,
|
dropSession,
|
||||||
defaultStorageAdapters,
|
|
||||||
loginWithNip01,
|
loginWithNip01,
|
||||||
loginWithNip46,
|
loginWithNip46,
|
||||||
EventsStorageAdapter,
|
|
||||||
loadRelaySelections,
|
loadRelaySelections,
|
||||||
SignerLogEntryStatus,
|
SignerLogEntryStatus,
|
||||||
} from "@welshman/app"
|
} from "@welshman/app"
|
||||||
@@ -107,8 +83,13 @@
|
|||||||
import {initializePushNotifications} from "@app/util/push"
|
import {initializePushNotifications} from "@app/util/push"
|
||||||
import * as commands from "@app/core/commands"
|
import * as commands from "@app/core/commands"
|
||||||
import * as requests from "@app/core/requests"
|
import * as requests from "@app/core/requests"
|
||||||
import * as notifications from "@app/util/notifications"
|
|
||||||
import * as appState from "@app/core/state"
|
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
|
// Migration: old nostrtalk instance used different sessions
|
||||||
if ($session && !$signer) {
|
if ($session && !$signer) {
|
||||||
@@ -122,6 +103,8 @@
|
|||||||
|
|
||||||
const ready = $state(defer<void>())
|
const ready = $state(defer<void>())
|
||||||
|
|
||||||
|
let initialized = false
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
Object.assign(window, {
|
Object.assign(window, {
|
||||||
get,
|
get,
|
||||||
@@ -239,7 +222,8 @@
|
|||||||
document.documentElement.style["font-size"] = `${$userSettingsValues.font_size}rem`
|
document.documentElement.style["font-size"] = `${$userSettingsValues.font_size}rem`
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!db) {
|
if (!initialized) {
|
||||||
|
initialized = true
|
||||||
setupTracking()
|
setupTracking()
|
||||||
setupAnalytics()
|
setupAnalytics()
|
||||||
|
|
||||||
@@ -278,44 +262,10 @@
|
|||||||
storage: preferencesStorageProvider,
|
storage: preferencesStorageProvider,
|
||||||
})
|
})
|
||||||
|
|
||||||
await initStorage("flotilla", 8, {
|
// Sync application data (relay, events, etc)
|
||||||
...defaultStorageAdapters,
|
await storage.syncDataStores()
|
||||||
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
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
|
// Wait 300 ms for any throttled stores to finish
|
||||||
sleep(300).then(() => ready.resolve())
|
sleep(300).then(() => ready.resolve())
|
||||||
|
|
||||||
defaultSocketPolicies.push(
|
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
|
// Listen for signer errors, report to user via toast
|
||||||
signerLog.subscribe(
|
signerLog.subscribe(
|
||||||
throttle(10_000, $log => {
|
throttle(10_000, $log => {
|
||||||
@@ -504,5 +457,6 @@
|
|||||||
</AppContainer>
|
</AppContainer>
|
||||||
<ModalContainer />
|
<ModalContainer />
|
||||||
<div class="tippy-target"></div>
|
<div class="tippy-target"></div>
|
||||||
|
<NewNotificationSound />
|
||||||
</div>
|
</div>
|
||||||
{/await}
|
{/await}
|
||||||
|
|||||||
@@ -1,24 +1,44 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {onMount} from "svelte"
|
import {onMount} from "svelte"
|
||||||
import {dec} from "@welshman/lib"
|
import {debounce} from "throttle-debounce"
|
||||||
import {ROOMS} from "@welshman/util"
|
import {dec, tryCatch} from "@welshman/lib"
|
||||||
|
import {ROOMS, normalizeRelayUrl, isRelayUrl} from "@welshman/util"
|
||||||
import {Router} from "@welshman/router"
|
import {Router} from "@welshman/router"
|
||||||
import {load} from "@welshman/net"
|
import {load} from "@welshman/net"
|
||||||
import type {Relay} from "@welshman/app"
|
import type {Relay} from "@welshman/app"
|
||||||
import {relays, createSearch, loadRelay, loadRelaySelections} from "@welshman/app"
|
import {relays, createSearch, loadRelay, loadRelaySelections} from "@welshman/app"
|
||||||
import {createScroller} from "@lib/html"
|
import {createScroller} from "@lib/html"
|
||||||
import {fly} from "@lib/transition"
|
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 Magnifier from "@assets/icons/magnifier.svg?dataurl"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Page from "@lib/components/Page.svelte"
|
import Page from "@lib/components/Page.svelte"
|
||||||
|
import Scanner from "@lib/components/Scanner.svelte"
|
||||||
import Spinner from "@lib/components/Spinner.svelte"
|
import Spinner from "@lib/components/Spinner.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import PageHeader from "@lib/components/PageHeader.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 RelaySummary from "@app/components/RelaySummary.svelte"
|
||||||
import SpaceCheck from "@app/components/SpaceCheck.svelte"
|
import SpaceCheck from "@app/components/SpaceCheck.svelte"
|
||||||
import {getMembershipUrls, loadMembership, defaultPubkeys, membersByUrl} from "@app/core/state"
|
import {getMembershipUrls, loadMembership, defaultPubkeys, membersByUrl} from "@app/core/state"
|
||||||
import {pushModal} from "@app/util/modal"
|
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 = () =>
|
const discoverRelays = () =>
|
||||||
Promise.all([
|
Promise.all([
|
||||||
load({
|
load({
|
||||||
@@ -37,7 +57,7 @@
|
|||||||
|
|
||||||
const relaySearch = $derived(
|
const relaySearch = $derived(
|
||||||
createSearch(
|
createSearch(
|
||||||
$relays.filter(r => $membersByUrl.has(r.url)),
|
$relays.filter(r => $membersByUrl.has(r.url) && r.url !== termUrl),
|
||||||
{
|
{
|
||||||
getValue: (relay: Relay) => relay.url,
|
getValue: (relay: Relay) => relay.url,
|
||||||
sortFn: ({score, item}) => {
|
sortFn: ({score, item}) => {
|
||||||
@@ -59,6 +79,7 @@
|
|||||||
|
|
||||||
let term = $state("")
|
let term = $state("")
|
||||||
let limit = $state(20)
|
let limit = $state(20)
|
||||||
|
let showScanner = $state(false)
|
||||||
let element: Element
|
let element: Element
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@@ -76,30 +97,58 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Page class="cw-full">
|
<Page class="cw-full">
|
||||||
<div class="content column gap-4" bind:this={element}>
|
<ContentSearch>
|
||||||
<PageHeader>
|
{#snippet input()}
|
||||||
{#snippet title()}
|
<div class="flex flex-col gap-2">
|
||||||
Discover Spaces
|
<PageHeader>
|
||||||
{/snippet}
|
{#snippet title()}
|
||||||
{#snippet info()}
|
Discover Spaces
|
||||||
Find communities all across the nostr network
|
{/snippet}
|
||||||
{/snippet}
|
{#snippet info()}
|
||||||
</PageHeader>
|
Find communities all across the nostr network
|
||||||
<label class="input input-bordered flex w-full items-center gap-2">
|
{/snippet}
|
||||||
<Icon icon={Magnifier} />
|
</PageHeader>
|
||||||
<input bind:value={term} class="grow" type="text" placeholder="Search for spaces..." />
|
<div class="row-2 min-w-0 flex-grow items-center">
|
||||||
</label>
|
<label class="input input-bordered flex flex-grow items-center gap-2">
|
||||||
{#each relaySearch.searchOptions(term).slice(0, limit) as relay (relay.url)}
|
<Icon icon={Magnifier} />
|
||||||
<Button
|
<input bind:value={term} class="grow" type="text" placeholder="Search for spaces..." />
|
||||||
class="card2 bg-alt shadow-xl transition-all hover:shadow-2xl hover:dark:brightness-[1.1]"
|
<Button onclick={toggleScanner} class="center">
|
||||||
onclick={() => openSpace(relay.url)}>
|
<Icon icon={QrCode} />
|
||||||
<RelaySummary url={relay.url} />
|
</Button>
|
||||||
</Button>
|
</label>
|
||||||
{/each}
|
<Button class="btn btn-primary" onclick={openMenu}>
|
||||||
{#await discoverRelays()}
|
<Icon icon={AddCircle} />
|
||||||
<div class="flex justify-center py-20" out:fly>
|
</Button>
|
||||||
<Spinner loading>Looking for spaces...</Spinner>
|
</div>
|
||||||
|
{#if showScanner}
|
||||||
|
<Scanner onscan={onScan} />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/await}
|
{/snippet}
|
||||||
</div>
|
{#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>
|
</Page>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
<h1 class="mb-4 text-center text-5xl font-bold uppercase">{PLATFORM_NAME}</h1>
|
<h1 class="mb-4 text-center text-5xl font-bold uppercase">{PLATFORM_NAME}</h1>
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<Button onclick={addSpace}>
|
<Button onclick={addSpace}>
|
||||||
<CardButton class="dark:btn-neutral">
|
<CardButton class="btn-neutral">
|
||||||
{#snippet icon()}
|
{#snippet icon()}
|
||||||
<div><Icon icon={AddCircle} size={7} /></div>
|
<div><Icon icon={AddCircle} size={7} /></div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
</CardButton>
|
</CardButton>
|
||||||
</Button>
|
</Button>
|
||||||
<Link href="/discover">
|
<Link href="/discover">
|
||||||
<CardButton class="dark:btn-neutral">
|
<CardButton class="btn-neutral">
|
||||||
{#snippet icon()}
|
{#snippet icon()}
|
||||||
<div><Icon icon={Compass} size={7} /></div>
|
<div><Icon icon={Compass} size={7} /></div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
</CardButton>
|
</CardButton>
|
||||||
</Link>
|
</Link>
|
||||||
<Button onclick={openChat}>
|
<Button onclick={openChat}>
|
||||||
<CardButton class="dark:btn-neutral">
|
<CardButton class="btn-neutral">
|
||||||
{#snippet icon()}
|
{#snippet icon()}
|
||||||
<div><Icon icon={ChatRound} size={7} /></div>
|
<div><Icon icon={ChatRound} size={7} /></div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|||||||
@@ -61,9 +61,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button class="center btn btn-circle btn-neutral -mr-4 -mt-4 h-12 w-12" onclick={startEdit}>
|
||||||
class="center btn btn-circle -mr-4 -mt-4 h-12 w-12 dark:btn-neutral"
|
|
||||||
onclick={startEdit}>
|
|
||||||
<Icon icon={PenNewSquare} />
|
<Icon icon={PenNewSquare} />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="content column gap-4">
|
<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()}
|
{#snippet title()}
|
||||||
<h2 class="flex items-center gap-3 text-xl">
|
<h2 class="flex items-center gap-3 text-xl">
|
||||||
<Icon icon={Globus} />
|
<Icon icon={Globus} />
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
<Collapse class="card2 bg-alt column gap-4">
|
<Collapse class="card2 bg-alt column gap-4 shadow-xl">
|
||||||
{#snippet title()}
|
{#snippet title()}
|
||||||
<h2 class="flex items-center gap-3 text-xl">
|
<h2 class="flex items-center gap-3 text-xl">
|
||||||
<Icon icon={Inbox} />
|
<Icon icon={Inbox} />
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
<Collapse class="card2 bg-alt column gap-4">
|
<Collapse class="card2 bg-alt column gap-4 shadow-xl">
|
||||||
{#snippet title()}
|
{#snippet title()}
|
||||||
<h2 class="flex items-center gap-3 text-xl">
|
<h2 class="flex items-center gap-3 text-xl">
|
||||||
<Icon icon={Mailbox} />
|
<Icon icon={Mailbox} />
|
||||||
|
|||||||
@@ -1,22 +1,32 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {nwc} from "@getalby/sdk"
|
import {nwc} from "@getalby/sdk"
|
||||||
import {LOCALE} from "@welshman/lib"
|
import {LOCALE} from "@welshman/lib"
|
||||||
import {displayRelayUrl, fromMsats} from "@welshman/util"
|
import {displayRelayUrl, isNWCWallet, fromMsats} from "@welshman/util"
|
||||||
import {session} from "@welshman/app"
|
import {session, pubkey, profilesByPubkey} from "@welshman/app"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import WalletConnect from "@app/components/WalletConnect.svelte"
|
import WalletConnect from "@app/components/WalletConnect.svelte"
|
||||||
import WalletDisconnect from "@app/components/WalletDisconnect.svelte"
|
import WalletDisconnect from "@app/components/WalletDisconnect.svelte"
|
||||||
|
import WalletUpdateReceivingAddress from "@app/components/WalletUpdateReceivingAddress.svelte"
|
||||||
import {pushModal} from "@app/util/modal"
|
import {pushModal} from "@app/util/modal"
|
||||||
import {getWebLn} from "@app/core/commands"
|
import {getWebLn} from "@app/core/commands"
|
||||||
import Wallet2 from "@assets/icons/wallet.svg?dataurl"
|
import Wallet2 from "@assets/icons/wallet.svg?dataurl"
|
||||||
import CheckCircle from "@assets/icons/check-circle.svg?dataurl"
|
import CheckCircle from "@assets/icons/check-circle.svg?dataurl"
|
||||||
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
||||||
import CloseCircle from "@assets/icons/close-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 connect = () => pushModal(WalletConnect)
|
||||||
|
|
||||||
const disconnect = () => pushModal(WalletDisconnect)
|
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>
|
</script>
|
||||||
|
|
||||||
<div class="content column gap-4">
|
<div class="content column gap-4">
|
||||||
@@ -89,4 +99,23 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
userRoomsByUrl,
|
userRoomsByUrl,
|
||||||
} from "@app/core/state"
|
} from "@app/core/state"
|
||||||
import {pullConservatively} from "@app/core/requests"
|
import {pullConservatively} from "@app/core/requests"
|
||||||
|
import {hasBlossomSupport} from "@app/core/commands"
|
||||||
import {notifications} from "@app/util/notifications"
|
import {notifications} from "@app/util/notifications"
|
||||||
|
|
||||||
type Props = {
|
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
|
// Load group meta, threads, calendar events, comments, and recent messages
|
||||||
// for user rooms to help with a quick page transition
|
// for user rooms to help with a quick page transition
|
||||||
pullConservatively({
|
pullConservatively({
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ export default {
|
|||||||
},
|
},
|
||||||
light: {
|
light: {
|
||||||
...themes["winter"],
|
...themes["winter"],
|
||||||
|
neutral: '#F2F7FF',
|
||||||
|
warning: '#FD8D0B',
|
||||||
primary: process.env.VITE_PLATFORM_ACCENT,
|
primary: process.env.VITE_PLATFORM_ACCENT,
|
||||||
"primary-content": process.env.VITE_PLATFORM_ACCENT_CONTENT || "#EAE7FF",
|
"primary-content": process.env.VITE_PLATFORM_ACCENT_CONTENT || "#EAE7FF",
|
||||||
secondary: process.env.VITE_PLATFORM_SECONDARY,
|
secondary: process.env.VITE_PLATFORM_SECONDARY,
|
||||||
|
|||||||