Compare commits

..

87 Commits
master ... auth

Author SHA1 Message Date
Marco Crapts
cfa1987c3a custom auth 2023-06-02 16:00:39 +02:00
33737167b4 run prettier 2023-06-02 00:04:18 +02:00
c21538c09f fix keyboard and haptics 2023-06-01 23:17:41 +02:00
1f3a79bc99 fix statusbar 2023-06-01 22:08:55 +02:00
d6c55da727 fix table layout 2023-06-01 22:02:54 +02:00
6e725ec966 fix iphone padding 2023-06-01 21:32:25 +02:00
Marco Crapts
ccb3c98fe8 fix iphone padding 2023-06-01 21:31:18 +02:00
Marco Crapts
fb07da9599 update ios project 2023-06-01 17:41:41 +02:00
Marco Crapts
75a87378ee daisyUI 3.0 2023-06-01 13:42:35 +02:00
b17ce32b4d add Android app link 2023-06-01 00:21:14 +02:00
a837305f2a fix list view 2023-05-31 21:26:59 +02:00
bbc8010da3 redirect signin 2023-05-31 21:14:59 +02:00
99bc820a71 haptics 2023-05-31 20:14:46 +02:00
af41c3533f native dialog on android & ios 2023-05-31 00:29:10 +02:00
5f5987bf5e create ios and android targets 2023-05-30 23:06:11 +02:00
2b15178184 Merge branch 'master' into capacitor 2023-05-30 22:54:27 +02:00
c3459f689a persistent local cache 2023-05-30 22:54:14 +02:00
65465f79e6 update .env 2023-05-30 00:56:29 +02:00
f1ddb2d736 add Capacitor 2023-05-30 00:45:45 +02:00
a5ef1c5333 public Firebase keys 2023-05-30 00:19:34 +02:00
c21effa5fa small update 2023-05-29 22:10:27 +02:00
e3f11f2b35 ui improvements 2023-05-29 01:54:59 +02:00
2959fbd811 delete account 2023-05-29 01:48:46 +02:00
7708f25caa delete account ui functionality 2023-05-28 23:29:42 +02:00
8e9af01147 delete account ui functionality 2023-05-28 23:21:59 +02:00
bcb956ae6e slight refactoring 2023-05-28 22:23:41 +02:00
13d6364ffe enable/disable e2e encryption 2023-05-28 21:45:47 +02:00
37e677ec6a settings modal 2023-05-28 18:35:27 +02:00
28f2f9a9ca refactor to UI components 2023-05-26 01:44:20 +02:00
c76bf3f6d8 refactor to UI components 2023-05-26 00:50:19 +02:00
Marco Crapts
0f48494469 fix tailwind css 2023-05-26 19:29:52 +02:00
Marco Crapts
41390233c1 more ui components 2023-05-26 19:21:27 +02:00
Marco Crapts
7c1e74ff39 more ui components 2023-05-26 17:32:43 +02:00
Marco Crapts
3e6b9414f4 refactor to ui components 2023-05-26 16:43:12 +02:00
906121882b collapse sidebar on resize 2023-05-25 22:56:56 +02:00
f6e5d5ca4f delete notes & sync to firebase 2023-05-25 22:29:40 +02:00
5a4bba2dcd passphrase validation 2023-05-25 20:29:24 +02:00
Marco Crapts
1ab3db6cce fix overlay 2023-05-25 17:10:57 +02:00
Marco Crapts
ee8afdf2a7 fix layout 2023-05-25 16:41:05 +02:00
Marco Crapts
f059cc0291 fix layout 2023-05-25 10:50:40 +02:00
4becbf41a9 fix click outside 2023-05-25 00:11:18 +02:00
cf8d965e64 store settings in localstorage 2023-05-24 23:30:28 +02:00
79f81cb83f improve sidebar mobile 2023-05-23 23:01:02 +02:00
117fff9b02 click outside sidebar collapse on mobile 2023-05-23 22:49:36 +02:00
32bdacda88 less recent items 2023-05-23 22:13:25 +02:00
b2c1f7d11d tabs 2023-05-23 22:12:23 +02:00
fc9d8d1023 update search results 2023-05-23 21:53:55 +02:00
f82b28b896 update search results 2023-05-23 21:16:48 +02:00
Marco Crapts
3a40c95496 refactor colors 2023-05-23 13:29:00 +02:00
Marco Crapts
f102dd1ff0 better animated sidebar 2023-05-23 13:18:43 +02:00
6f19ee94d1 passphrase prompt 2023-05-23 00:44:51 +02:00
6a53d9fd58 improve loading 2023-05-22 20:56:54 +02:00
b7e5da2354 decrypt notes 2023-05-22 20:48:53 +02:00
Marco Crapts
d45ceb9b41 cleanup css 2023-05-22 10:58:29 +02:00
Marco Crapts
24dc9482da fix stretch + default notes 2023-05-22 10:02:52 +02:00
dd2a3d91ca try catch json parse 2023-05-22 09:08:06 +02:00
4d4938a0ad add word count to note list 2023-05-22 00:27:06 +02:00
021e0f3eb4 update signout dialog 2023-05-22 00:23:25 +02:00
16c92ed33f sync with local storage 2023-05-22 00:19:46 +02:00
87c3ff52ef default sidebar collapse mobile 2023-05-21 13:56:42 +02:00
704c955278 fix jumpy safari 2023-05-21 13:28:02 +02:00
e2386ef681 fix note title too wide 2023-05-21 12:00:20 +02:00
ba0b6b5042 single firebaseui import 2023-05-21 11:28:19 +02:00
07eb24006d rename close to cancel 2023-05-21 01:52:08 +02:00
65b641866e add modal titles 2023-05-20 15:41:37 +02:00
16c93b2d10 signout icon 2023-05-20 15:33:51 +02:00
c3cfc11f5f dropdown menu 2023-05-20 15:26:15 +02:00
cf00a57a7d skeleton loader 2023-05-20 15:00:55 +02:00
f61be632a0 skeleton loader 2023-05-20 14:54:41 +02:00
7e7bb41a27 show auth modal in case of redirect 2023-05-20 12:38:55 +02:00
f9cbc88303 fix auth 2023-05-20 12:14:48 +02:00
1f38d6a1ac auth loader 2023-05-20 07:13:06 +02:00
b0224826ec working auth 2023-05-20 06:53:47 +02:00
aa02e66245 add auth modal 2023-05-20 04:05:36 +02:00
b52ae59817 create link without autocomplete 2023-05-20 02:35:11 +02:00
0ac2e00399 add firebase 2023-05-19 23:38:43 +02:00
14018e7606 mindmap 2023-05-19 22:07:58 +02:00
e802ad289c listview 2023-05-19 19:12:55 +02:00
Marco Crapts
35b016449a update project config to match official create vue recommendations 2023-05-19 14:16:44 +02:00
Marco Crapts
0619707054 update list view 2023-05-19 11:00:18 +02:00
d45045d63f listview component 2023-05-17 07:43:53 +02:00
22017f3e8b improve scrolling / layout 2023-05-17 07:24:26 +02:00
6c52785597 flex-grow instead of flex-1 2023-05-17 05:27:59 +02:00
9765806dca add favicons 2023-05-17 04:20:08 +02:00
15147a547d create note on click if does not exist 2023-05-17 03:47:48 +02:00
54af4cdc7e improved autocomplete 2023-05-17 03:42:10 +02:00
Marco Crapts
4a47f6d0a4 rename types to types.d.ts & fix Contexted logo 2023-05-17 15:27:12 +02:00
99 changed files with 2615 additions and 3080 deletions

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "https://json.schemastore.org/prettierrc", "$schema": "https://json.schemastore.org/prettierrc",
"semi": false, "semi": false,
"tabWidth": 4, "tabWidth": 2,
"singleQuote": true, "singleQuote": true,
"printWidth": 100, "printWidth": 100,
"trailingComma": "none", "trailingComma": "none",

View File

@@ -1,11 +1,2 @@
pretty: pretty:
npx prettier --write "./src/**/*.(ts|vue)" npx prettier --write "./src/**/*.(ts|vue)"
check:
npm run type-check && npm run lint
local: check
npm run local
deploy: check
npm run deploy

View File

@@ -9,11 +9,9 @@ android {
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies { dependencies {
implementation project(':capacitor-firebase-authentication')
implementation project(':capacitor-dialog') implementation project(':capacitor-dialog')
implementation project(':capacitor-haptics') implementation project(':capacitor-haptics')
implementation project(':capacitor-keyboard') implementation project(':capacitor-keyboard')
implementation project(':capacitor-splash-screen')
implementation project(':capacitor-status-bar') implementation project(':capacitor-status-bar')
} }

View File

@@ -1,40 +0,0 @@
{
"project_info": {
"project_number": "1048273547256",
"firebase_url": "https://contexted-f8b4e.firebaseio.com",
"project_id": "contexted-f8b4e",
"storage_bucket": "contexted-f8b4e.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:1048273547256:android:878e44df2e5f0b200f700d",
"android_client_info": {
"package_name": "com.contexted.app"
}
},
"oauth_client": [
{
"client_id": "1048273547256-mq8b1irdiovpblrdcuf8bb30is29rfm9.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCJ-A3ziDw_2qMWnP2uXFDoY2O8DrUlXp8"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "1048273547256-mq8b1irdiovpblrdcuf8bb30is29rfm9.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="ic_launcher_background">#1E4BC4</color> <color name="ic_launcher_background">#FFFFFF</color>
</resources> </resources>

View File

@@ -2,9 +2,6 @@
include ':capacitor-android' include ':capacitor-android'
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
include ':capacitor-firebase-authentication'
project(':capacitor-firebase-authentication').projectDir = new File('../node_modules/@capacitor-firebase/authentication/android')
include ':capacitor-dialog' include ':capacitor-dialog'
project(':capacitor-dialog').projectDir = new File('../node_modules/@capacitor/dialog/android') project(':capacitor-dialog').projectDir = new File('../node_modules/@capacitor/dialog/android')
@@ -14,8 +11,5 @@ project(':capacitor-haptics').projectDir = new File('../node_modules/@capacitor/
include ':capacitor-keyboard' include ':capacitor-keyboard'
project(':capacitor-keyboard').projectDir = new File('../node_modules/@capacitor/keyboard/android') project(':capacitor-keyboard').projectDir = new File('../node_modules/@capacitor/keyboard/android')
include ':capacitor-splash-screen'
project(':capacitor-splash-screen').projectDir = new File('../node_modules/@capacitor/splash-screen/android')
include ':capacitor-status-bar' include ':capacitor-status-bar'
project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android') project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android')

View File

@@ -13,5 +13,4 @@ ext {
androidxJunitVersion = '1.1.5' androidxJunitVersion = '1.1.5'
androidxEspressoCoreVersion = '3.5.1' androidxEspressoCoreVersion = '3.5.1'
cordovaAndroidVersion = '10.1.1' cordovaAndroidVersion = '10.1.1'
rgcfaIncludeGoogle = true
} }

View File

@@ -8,15 +8,8 @@ const config: CapacitorConfig = {
androidScheme: 'https' androidScheme: 'https'
}, },
plugins: { plugins: {
SplashScreen: {
backgroundColor: '#1E4BC4'
},
Keyboard: { Keyboard: {
resize: 'native' resize: 'native'
},
FirebaseAuthentication: {
skipNativeAuth: false,
providers: ['google.com', 'microsoft.com', 'github.com']
} }
} }
} }

View File

@@ -15,7 +15,6 @@
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; }; 504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; };
50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; }; 50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; };
A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; }; A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; };
A9A186E62A2FB826009CBA16 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = A9A186E52A2FB826009CBA16 /* GoogleService-Info.plist */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@@ -28,7 +27,6 @@
504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; 504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = "<group>"; }; 50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = "<group>"; };
A9A186E52A2FB826009CBA16 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; }; AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; };
AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = "<group>"; }; AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = "<group>"; };
FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = "<group>"; }; FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = "<group>"; };
@@ -76,7 +74,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
50379B222058CBB4000EE86E /* capacitor.config.json */, 50379B222058CBB4000EE86E /* capacitor.config.json */,
A9A186E52A2FB826009CBA16 /* GoogleService-Info.plist */,
504EC3071FED79650016851F /* AppDelegate.swift */, 504EC3071FED79650016851F /* AppDelegate.swift */,
504EC30B1FED79650016851F /* Main.storyboard */, 504EC30B1FED79650016851F /* Main.storyboard */,
504EC30E1FED79650016851F /* Assets.xcassets */, 504EC30E1FED79650016851F /* Assets.xcassets */,
@@ -164,7 +161,6 @@
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */, 50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
504EC30D1FED79650016851F /* Main.storyboard in Resources */, 504EC30D1FED79650016851F /* Main.storyboard in Resources */,
2FAD9763203C412B000D30F8 /* config.xml in Resources */, 2FAD9763203C412B000D30F8 /* config.xml in Resources */,
A9A186E62A2FB826009CBA16 /* GoogleService-Info.plist in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -351,7 +347,6 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 5XQS3G6YV7;
INFOPLIST_FILE = App/Info.plist; INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0; IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@@ -372,7 +367,6 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 5XQS3G6YV7;
INFOPLIST_FILE = App/Info.plist; INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0; IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

View File

@@ -1,7 +1,7 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "AppIcon-1024@2x.png", "filename" : "AppIcon-512@2x.png",
"idiom" : "universal", "idiom" : "universal",
"platform" : "ios", "platform" : "ios",
"size" : "1024x1024" "size" : "1024x1024"

View File

@@ -1,23 +1,23 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "splash-landscape@1x.png",
"idiom" : "universal", "idiom" : "universal",
"filename" : "splash-2732x2732-2.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"filename" : "splash-landscape@2x.png",
"idiom" : "universal", "idiom" : "universal",
"filename" : "splash-2732x2732-1.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"filename" : "splash-landscape@3x.png",
"idiom" : "universal", "idiom" : "universal",
"filename" : "splash-2732x2732.png",
"scale" : "3x" "scale" : "3x"
} }
], ],
"info" : { "info" : {
"author" : "xcode", "version" : 1,
"version" : 1 "author" : "xcode"
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

View File

@@ -1,38 +0,0 @@
<?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>CLIENT_ID</key>
<string>1048273547256-fes4qqj6po81ki21doggnst5ptjsa940.apps.googleusercontent.com</string>
<key>REVERSED_CLIENT_ID</key>
<string>com.googleusercontent.apps.1048273547256-fes4qqj6po81ki21doggnst5ptjsa940</string>
<key>ANDROID_CLIENT_ID</key>
<string>1048273547256-qq9j4hcvni377p8cva7v10u9us1pjrc9.apps.googleusercontent.com</string>
<key>API_KEY</key>
<string>AIzaSyCkN_Fm0wGcDZJJ6ltz5NHDvs9zPgKiSTQ</string>
<key>GCM_SENDER_ID</key>
<string>1048273547256</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.contexted.app</string>
<key>PROJECT_ID</key>
<string>contexted-f8b4e</string>
<key>STORAGE_BUCKET</key>
<string>contexted-f8b4e.appspot.com</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<true></true>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:1048273547256:ios:e57d78bd483100900f700d</string>
<key>DATABASE_URL</key>
<string>https://contexted-f8b4e.firebaseio.com</string>
</dict>
</plist>

View File

@@ -18,19 +18,6 @@
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string> <string>$(MARKETING_VERSION)</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>Firebase</string>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.1048273547256-fes4qqj6po81ki21doggnst5ptjsa940</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string> <string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>

View File

@@ -11,29 +11,17 @@ install! 'cocoapods', :disable_input_output_paths => true
def capacitor_pods def capacitor_pods
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios' pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios' pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorFirebaseAuthentication', :path => '../../node_modules/@capacitor-firebase/authentication'
pod 'CapacitorDialog', :path => '../../node_modules/@capacitor/dialog' pod 'CapacitorDialog', :path => '../../node_modules/@capacitor/dialog'
pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics' pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard' pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'
pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen'
pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar' pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
end end
target 'App' do target 'App' do
capacitor_pods capacitor_pods
# Add your Pods here # Add your Pods here
pod 'CapacitorFirebaseAuthentication/Google', :path => '../../node_modules/@capacitor-firebase/authentication'
end end
post_install do |installer| post_install do |installer|
assertDeploymentTarget(installer) assertDeploymentTarget(installer)
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
if target.respond_to?(:product_type) and target.product_type == "com.apple.product-type.bundle"
target.build_configurations.each do |config|
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
end
end
end
end
end end

View File

@@ -1,96 +1,24 @@
PODS: PODS:
- AppAuth (1.6.2):
- AppAuth/Core (= 1.6.2)
- AppAuth/ExternalUserAgent (= 1.6.2)
- AppAuth/Core (1.6.2)
- AppAuth/ExternalUserAgent (1.6.2):
- AppAuth/Core
- Capacitor (5.0.4): - Capacitor (5.0.4):
- CapacitorCordova - CapacitorCordova
- CapacitorCordova (5.0.4) - CapacitorCordova (5.0.4)
- CapacitorDialog (5.0.2): - CapacitorDialog (5.0.2):
- Capacitor - Capacitor
- CapacitorFirebaseAuthentication (5.0.0):
- Capacitor
- CapacitorFirebaseAuthentication/Lite (= 5.0.0)
- FirebaseAuth (= 10.8.0)
- CapacitorFirebaseAuthentication/Google (5.0.0):
- Capacitor
- FirebaseAuth (= 10.8.0)
- GoogleSignIn (= 7.0.0)
- CapacitorFirebaseAuthentication/Lite (5.0.0):
- Capacitor
- FirebaseAuth (= 10.8.0)
- CapacitorHaptics (5.0.2): - CapacitorHaptics (5.0.2):
- Capacitor - Capacitor
- CapacitorKeyboard (5.0.2): - CapacitorKeyboard (5.0.2):
- Capacitor - Capacitor
- CapacitorSplashScreen (5.0.2):
- Capacitor
- CapacitorStatusBar (5.0.2): - CapacitorStatusBar (5.0.2):
- Capacitor - Capacitor
- FirebaseAppCheckInterop (10.10.0)
- FirebaseAuth (10.8.0):
- FirebaseAppCheckInterop (~> 10.0)
- FirebaseCore (~> 10.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.8)
- GoogleUtilities/Environment (~> 7.8)
- GTMSessionFetcher/Core (< 4.0, >= 2.1)
- FirebaseCore (10.10.0):
- FirebaseCoreInternal (~> 10.0)
- GoogleUtilities/Environment (~> 7.8)
- GoogleUtilities/Logger (~> 7.8)
- FirebaseCoreInternal (10.10.0):
- "GoogleUtilities/NSData+zlib (~> 7.8)"
- GoogleSignIn (7.0.0):
- AppAuth (~> 1.5)
- GTMAppAuth (< 3.0, >= 1.3)
- GTMSessionFetcher/Core (< 4.0, >= 1.1)
- GoogleUtilities/AppDelegateSwizzler (7.11.1):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- GoogleUtilities/Environment (7.11.1):
- PromisesObjC (< 3.0, >= 1.2)
- GoogleUtilities/Logger (7.11.1):
- GoogleUtilities/Environment
- GoogleUtilities/Network (7.11.1):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (7.11.1)"
- GoogleUtilities/Reachability (7.11.1):
- GoogleUtilities/Logger
- GTMAppAuth (2.0.0):
- AppAuth/Core (~> 1.6)
- GTMSessionFetcher/Core (< 4.0, >= 1.5)
- GTMSessionFetcher/Core (3.1.1)
- PromisesObjC (2.2.0)
DEPENDENCIES: DEPENDENCIES:
- "Capacitor (from `../../node_modules/@capacitor/ios`)" - "Capacitor (from `../../node_modules/@capacitor/ios`)"
- "CapacitorCordova (from `../../node_modules/@capacitor/ios`)" - "CapacitorCordova (from `../../node_modules/@capacitor/ios`)"
- "CapacitorDialog (from `../../node_modules/@capacitor/dialog`)" - "CapacitorDialog (from `../../node_modules/@capacitor/dialog`)"
- "CapacitorFirebaseAuthentication (from `../../node_modules/@capacitor-firebase/authentication`)"
- "CapacitorFirebaseAuthentication/Google (from `../../node_modules/@capacitor-firebase/authentication`)"
- "CapacitorHaptics (from `../../node_modules/@capacitor/haptics`)" - "CapacitorHaptics (from `../../node_modules/@capacitor/haptics`)"
- "CapacitorKeyboard (from `../../node_modules/@capacitor/keyboard`)" - "CapacitorKeyboard (from `../../node_modules/@capacitor/keyboard`)"
- "CapacitorSplashScreen (from `../../node_modules/@capacitor/splash-screen`)"
- "CapacitorStatusBar (from `../../node_modules/@capacitor/status-bar`)" - "CapacitorStatusBar (from `../../node_modules/@capacitor/status-bar`)"
SPEC REPOS:
trunk:
- AppAuth
- FirebaseAppCheckInterop
- FirebaseAuth
- FirebaseCore
- FirebaseCoreInternal
- GoogleSignIn
- GoogleUtilities
- GTMAppAuth
- GTMSessionFetcher
- PromisesObjC
EXTERNAL SOURCES: EXTERNAL SOURCES:
Capacitor: Capacitor:
:path: "../../node_modules/@capacitor/ios" :path: "../../node_modules/@capacitor/ios"
@@ -98,37 +26,21 @@ EXTERNAL SOURCES:
:path: "../../node_modules/@capacitor/ios" :path: "../../node_modules/@capacitor/ios"
CapacitorDialog: CapacitorDialog:
:path: "../../node_modules/@capacitor/dialog" :path: "../../node_modules/@capacitor/dialog"
CapacitorFirebaseAuthentication:
:path: "../../node_modules/@capacitor-firebase/authentication"
CapacitorHaptics: CapacitorHaptics:
:path: "../../node_modules/@capacitor/haptics" :path: "../../node_modules/@capacitor/haptics"
CapacitorKeyboard: CapacitorKeyboard:
:path: "../../node_modules/@capacitor/keyboard" :path: "../../node_modules/@capacitor/keyboard"
CapacitorSplashScreen:
:path: "../../node_modules/@capacitor/splash-screen"
CapacitorStatusBar: CapacitorStatusBar:
:path: "../../node_modules/@capacitor/status-bar" :path: "../../node_modules/@capacitor/status-bar"
SPEC CHECKSUMS: SPEC CHECKSUMS:
AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570
Capacitor: d3d4463573438b9fa65326d1f3549da6f4c21634 Capacitor: d3d4463573438b9fa65326d1f3549da6f4c21634
CapacitorCordova: b1fe6bf1f36974a8e4a9044b342d22d49c0996d6 CapacitorCordova: b1fe6bf1f36974a8e4a9044b342d22d49c0996d6
CapacitorDialog: 01c49f7f4b37e7ad59e38fd317a6e5f006f23cdc CapacitorDialog: 01c49f7f4b37e7ad59e38fd317a6e5f006f23cdc
CapacitorFirebaseAuthentication: f2e3c2a7488b87078025855588670840f93a721e
CapacitorHaptics: 864585542a435bd41eaabf7f30d9ff5ec03024d3 CapacitorHaptics: 864585542a435bd41eaabf7f30d9ff5ec03024d3
CapacitorKeyboard: e628d4e66d621c69e449945ebabded17c5b9c2e8 CapacitorKeyboard: e628d4e66d621c69e449945ebabded17c5b9c2e8
CapacitorSplashScreen: bd2a056394ba0b8807e7bb3e746424f67c426e03
CapacitorStatusBar: 48f2899f6846cc7d8431b251ebfc58e1c10e3d58 CapacitorStatusBar: 48f2899f6846cc7d8431b251ebfc58e1c10e3d58
FirebaseAppCheckInterop: 7d3521f56872cf74a01792c0a095a30e054ff6ae
FirebaseAuth: 28e6fff787467cd15ab51c8c7aa904003b2f57aa
FirebaseCore: d027ff503d37edb78db98429b11f580a24a7df2a
FirebaseCoreInternal: 971029061d326000d65bfdc21f5502c75c8b0893
GoogleSignIn: b232380cf495a429b8095d3178a8d5855b42e842
GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749
GTMAppAuth: 99fb010047ba3973b7026e45393f51f27ab965ae
GTMSessionFetcher: e8647203b65cee28c5f73d0f473d096653945e72
PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef
PODFILE CHECKSUM: 9a19ff50409d024bca91266c62454036ebb27258 PODFILE CHECKSUM: b469cdc64593e190968b9aa15066224f10938107
COCOAPODS: 1.12.1 COCOAPODS: 1.12.1

337
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,20 +9,18 @@
"preview": "vite preview", "preview": "vite preview",
"build-only": "vite build", "build-only": "vite build",
"type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false", "type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false",
"lint": "eslint ./src --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/", "format": "prettier --write src/",
"local": "npm run build && firebase serve --only hosting", "local": "npm run build && firebase serve --only hosting",
"deploy": "npm run build && firebase deploy --only hosting:contexted-v3" "deploy": "npm run build && firebase deploy --only hosting:contexted-v3"
}, },
"dependencies": { "dependencies": {
"@capacitor-firebase/authentication": "^5.0.0",
"@capacitor/android": "^5.0.4", "@capacitor/android": "^5.0.4",
"@capacitor/core": "^5.0.4", "@capacitor/core": "^5.0.4",
"@capacitor/dialog": "^5.0.2", "@capacitor/dialog": "^5.0.2",
"@capacitor/haptics": "^5.0.2", "@capacitor/haptics": "^5.0.2",
"@capacitor/ios": "^5.0.4", "@capacitor/ios": "^5.0.4",
"@capacitor/keyboard": "^5.0.2", "@capacitor/keyboard": "^5.0.2",
"@capacitor/splash-screen": "^5.0.2",
"@capacitor/status-bar": "^5.0.2", "@capacitor/status-bar": "^5.0.2",
"@ckeditor/ckeditor5-autoformat": "^37.1.0", "@ckeditor/ckeditor5-autoformat": "^37.1.0",
"@ckeditor/ckeditor5-basic-styles": "^37.1.0", "@ckeditor/ckeditor5-basic-styles": "^37.1.0",
@@ -42,6 +40,7 @@
"@vueuse/core": "^10.1.2", "@vueuse/core": "^10.1.2",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"cytoscape": "^3.25.0", "cytoscape": "^3.25.0",
"daisyui": "^3.0.0",
"date-fns": "^2.29.3", "date-fns": "^2.29.3",
"dompurify": "^3.0.2", "dompurify": "^3.0.2",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
@@ -53,7 +52,8 @@
"marked": "^4.3.0", "marked": "^4.3.0",
"shortid": "^2.2.16", "shortid": "^2.2.16",
"turndown": "^7.1.2", "turndown": "^7.1.2",
"vue": "^3.3.4" "vue": "^3.3.4",
"vue-virtual-scroller": "^2.0.0-beta.8"
}, },
"devDependencies": { "devDependencies": {
"@capacitor/cli": "^5.0.4", "@capacitor/cli": "^5.0.4",
@@ -72,7 +72,6 @@
"@vue/eslint-config-typescript": "^11.0.3", "@vue/eslint-config-typescript": "^11.0.3",
"@vue/tsconfig": "^0.4.0", "@vue/tsconfig": "^0.4.0",
"autoprefixer": "^10.4.14", "autoprefixer": "^10.4.14",
"daisyui": "^4.4.19",
"eslint": "^8.40.0", "eslint": "^8.40.0",
"eslint-plugin-vue": "^9.13.0", "eslint-plugin-vue": "^9.13.0",
"firebase-tools": "^12.1.0", "firebase-tools": "^12.1.0",

View File

@@ -11,13 +11,12 @@ import {
import { initializeSettings } from '@/composables/useSettings' import { initializeSettings } from '@/composables/useSettings'
import { windowIsMobile } from '@/utils/helpers' import { windowIsMobile } from '@/utils/helpers'
import SideBar from '@/components/SideBar.vue' import SideBar from '@/components/SideBar.vue'
import firebase from 'firebase/compat/app'
import * as firebaseui from 'firebaseui'
import { useWindowSize } from '@vueuse/core' import { useWindowSize } from '@vueuse/core'
import { SplashScreen } from '@capacitor/splash-screen'
initializeSettings() initializeSettings()
onMounted(() => SplashScreen.hide())
const sideBarCollapsed = ref<boolean>(windowIsMobile()) const sideBarCollapsed = ref<boolean>(windowIsMobile())
const { width } = useWindowSize() const { width } = useWindowSize()
@@ -27,9 +26,9 @@ watch(width, () => (sideBarCollapsed.value = windowIsMobile()))
// const ListView = defineAsyncComponent(() => import('@/components/ViewModes/ListView.vue')) // const ListView = defineAsyncComponent(() => import('@/components/ViewModes/ListView.vue'))
// const Mindmap = defineAsyncComponent(() => import('@/components/ViewModes/Mindmap.vue')) // const Mindmap = defineAsyncComponent(() => import('@/components/ViewModes/Mindmap.vue'))
// const firebaseAuthUI = const firebaseAuthUI =
// firebaseui.auth.AuthUI.getInstance() || new firebaseui.auth.AuthUI(firebase.auth()) firebaseui.auth.AuthUI.getInstance() || new firebaseui.auth.AuthUI(firebase.auth())
// provide('firebaseAuthUI', firebaseAuthUI) provide('firebaseAuthUI', firebaseAuthUI)
watch( watch(
[activeNotesSource, encryptionKey], [activeNotesSource, encryptionKey],
@@ -92,10 +91,10 @@ const topBarHeightWithSafeArea = computed(() => `calc(${topBarHeight}px + var(--
/> />
</Transition> </Transition>
<main <main
class="transition[margin-left] z-10 mx-auto flex h-full w-full max-w-app flex-col overflow-y-auto bg-white pb-[var(--safe-area-bottom)] duration-200 ease-out sm:border-x-[1px]" class="transition[margin-left] z-10 mx-auto flex h-full w-full max-w-app flex-col overflow-y-auto border-x-[1px] bg-white pb-[var(--safe-area-bottom)] duration-200 ease-out"
:class="sideBarCollapsed ? 'ml-0' : 'sm:ml-sidebar'" :class="sideBarCollapsed ? 'ml-0' : 'sm:ml-sidebar'"
> >
<div class="flex w-full flex-grow px-10 py-6 max-sm:px-4 max-sm:py-3"> <div class="flex h-full w-full px-10 py-6 max-sm:px-4 max-sm:py-3">
<template v-if="!loading"> <template v-if="!loading">
<Note <Note
v-if="activeViewMode.name === 'Note' && activeNote" v-if="activeViewMode.name === 'Note' && activeNote"
@@ -111,12 +110,12 @@ const topBarHeightWithSafeArea = computed(() => `calc(${topBarHeight}px + var(--
</div> </div>
</main> </main>
</div> </div>
<UIModal :open="passphraseRequired" persistent> <UIModal :open="passphraseRequired" :persistent="true">
<template #title>Enter your passphrase</template> <template #title>Enter your passphrase</template>
<template #default="{ close }"> <template #default="{ close }">
<div> <div>
Your notes are encrypted. Please enter your encryption key passphrase to decrypt Your notes are encrypted. Please enter your encryption key passphrase to decrypt your cloud
your cloud notes. notes.
</div> </div>
<form @submit.prevent="submitPassphrase(close)"> <form @submit.prevent="submitPassphrase(close)">
<UIInputText <UIInputText

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -124,9 +124,7 @@ export default defineComponent({
const [major] = CKEDITOR_VERSION.split('.').map(Number) const [major] = CKEDITOR_VERSION.split('.').map(Number)
if (major < 37) { if (major < 37) {
console.warn( console.warn('The <CKEditor> component requires using CKEditor 5 in version 37 or higher.')
'The <CKEditor> component requires using CKEditor 5 in version 37 or higher.'
)
} }
} else { } else {
console.warn('Cannot find the "CKEDITOR_VERSION" in the "window" scope.') console.warn('Cannot find the "CKEDITOR_VERSION" in the "window" scope.')

View File

@@ -116,16 +116,10 @@ export default class ContextedLinkEditing extends Plugin {
} }
model.enqueueChange((writer) => { model.enqueueChange((writer) => {
const rangesToFormat = format.map((array) => const rangesToFormat = format.map((array) =>
model.createRange( model.createRange(range.start.getShiftedBy(array[0]), range.start.getShiftedBy(array[1]))
range.start.getShiftedBy(array[0]),
range.start.getShiftedBy(array[1])
)
) )
const validRanges = editor.model.schema.getValidRanges( const validRanges = editor.model.schema.getValidRanges(rangesToFormat, 'contextedLink')
rangesToFormat,
'contextedLink'
)
for (const range of validRanges) { for (const range of validRanges) {
for (const item of range.getItems()) { for (const item of range.getItems()) {
if ((item as any).data) { if ((item as any).data) {
@@ -151,8 +145,8 @@ export default class ContextedLinkEditing extends Plugin {
} }
const keyCodes = [...keyCodesConfirm, ...keyCodesCycle] const keyCodes = [...keyCodesConfirm, ...keyCodesCycle]
const selection = editor.model.document.selection const selection = editor.model.document.selection
const selectionInContextedLink = ['contextedLink', 'autocomplete'].some( const selectionInContextedLink = ['contextedLink', 'autocomplete'].some((attribute) =>
(attribute) => selection.hasAttribute(attribute) selection.hasAttribute(attribute)
) )
if (selectionInContextedLink && keyCodes.includes(keyCode)) { if (selectionInContextedLink && keyCodes.includes(keyCode)) {
if (selection.hasAttribute('contextedLink')) { if (selection.hasAttribute('contextedLink')) {
@@ -222,10 +216,7 @@ function fireAutocompleteEvent(editor: any, show: boolean, autocompleteNode?: an
event = { event = {
position: getNodePosition( position: getNodePosition(
editor, editor,
editor.model.createPositionFromPath( editor.model.createPositionFromPath(autocompleteNode.root, autocompleteNode.getPath())
autocompleteNode.root,
autocompleteNode.getPath()
)
), ),
autocompleteText: autocompleteNode.data, autocompleteText: autocompleteNode.data,
domElement, domElement,

View File

@@ -2,17 +2,23 @@
import firebase from 'firebase/compat/app' import firebase from 'firebase/compat/app'
import 'firebase/compat/auth' import 'firebase/compat/auth'
import 'firebaseui/dist/firebaseui.css' import 'firebaseui/dist/firebaseui.css'
import * as firebaseui from 'firebaseui' import {
import { FirebaseAuthentication } from '@capacitor-firebase/authentication' getAuth,
import { getAuth, GoogleAuthProvider, signInWithCredential } from 'firebase/auth' signInWithRedirect,
GoogleAuthProvider,
GithubAuthProvider,
OAuthProvider
} from 'firebase/auth'
// const props = defineProps<{
// authenticating?: boolean
// }>()
const emit = defineEmits<{ const emit = defineEmits<{
signedIn: [authResult: any] signedIn: [authResult: any]
}>() }>()
// const ui: any = inject('firebaseAuthUI') const ui: any = inject('firebaseAuthUI')
const auth = getAuth()
const firebaseAuthUI = firebaseui.auth.AuthUI.getInstance() || new firebaseui.auth.AuthUI(auth)
const uiConfig = { const uiConfig = {
signInOptions: [ signInOptions: [
@@ -42,93 +48,50 @@ const uiConfig = {
} }
// onMounted(() => ui.start('#auth', uiConfig)) // onMounted(() => ui.start('#auth', uiConfig))
interface Provider { type AuthProvider = 'google' | 'github' | 'microsoft'
name: 'google' | 'microsoft' | 'github' const providers: { [key in AuthProvider]: any | (() => any) } = {
icon: string google: new GoogleAuthProvider(),
signin: () => Promise<void> github: () => {
// (options?: SignInOptions) => Promise<SignInResult> const provider = new GithubAuthProvider()
provider.addScope('user:email')
return provider
},
microsoft: new OAuthProvider('microsoft.com')
} }
const providers: Provider[] = [ const signIn = (providerName: AuthProvider) => {
{ const auth = getAuth()
name: 'google', const provider =
icon: 'fa-brands fa-google', typeof providers[providerName] === 'function'
signin: async () => { ? providers[providerName]()
const result = await FirebaseAuthentication.signInWithGoogle({ : providers[providerName]
mode: 'redirect' signInWithRedirect(auth, provider)
})
const credential = GoogleAuthProvider.credential(result.credential?.idToken)
await signInWithCredential(auth, credential)
}
}
// {
// name: 'microsoft',
// icon: 'fa-brands fa-microsoft',
// signin: async () => {
// const result = await FirebaseAuthentication.signInWithMicrosoft({
// mode: 'redirect'
// })
// const provider = new OAuthProvider('microsoft.com')
// const credential = provider.credential({
// idToken: result.credential?.idToken,
// rawNonce: result.credential?.nonce
// })
// await signInWithCredential(auth, credential)
// }
// },
// {
// name: 'github',
// icon: 'fa-brands fa-github',
// signin: async () => {
// const result = await FirebaseAuthentication.signInWithGithub({
// mode: 'redirect'
// })
// const provider = new OAuthProvider('github.com')
// const credential = provider.credential({
// idToken: result.credential?.idToken,
// rawNonce: result.credential?.nonce
// })
// await signInWithCredential(auth, credential)
// }
// }
]
// type Provider = (typeof providers)[number]
const signInWithProvider = async (provider: Provider) => {
provider.signin()
} }
const signingInWithEmail = ref(false) const authenticatingWithEmail = ref(false)
const signInWithEmail = () => { const signInWithEmail = () => {
firebaseAuthUI.start('#auth', uiConfig) authenticatingWithEmail.value = true
signingInWithEmail.value = true ui.start('#auth', uiConfig)
} }
</script> </script>
<template> <template>
<div class="space-y-2"> <div class="flex flex-col items-center" v-if="!authenticatingWithEmail">
<template v-if="!signingInWithEmail"> <UIButton class="mx-auto w-[200px] bg-red-500 text-center" @click="signIn('google')">
<UIButton Sign in with Google
class="mx-auto !block w-[225px] max-sm:w-full"
size="sm"
@click="signInWithProvider(provider)"
v-for="provider in providers"
:key="provider.name"
>
<i class="fa-fw mr-2" :class="provider.icon"></i>
Sign in with {{ provider.name }}
</UIButton> </UIButton>
<UIButton <UIButton class="mx-auto w-[200px] bg-blue-300 text-center" @click="signIn('github')">
class="mx-auto !block w-[225px] max-sm:w-full" Sign in with Github
size="sm"
@click="signInWithEmail"
>
<i class="fa-fw fa-regular fa-envelope mr-2"></i>
Sign in with email
</UIButton> </UIButton>
</template> <UIButton class="mx-auto w-[200px] bg-blue-300 text-center" @click="signIn('microsoft')">
Sign in with Microsoft
</UIButton>
<UIButton class="mx-auto w-[200px] bg-blue-300 text-center" @click="signInWithEmail">
Sign in with e-mail
</UIButton>
</div>
<div id="auth"></div> <div id="auth"></div>
<!-- <progress <!-- <progress
v-show="props.authenticating" v-show="props.authenticating"
class="dui-progress dui-progress-primary w-full" class="dui-progress dui-progress-primary w-full"
></progress> --> ></progress> -->
</div>
</template> </template>

View File

@@ -45,7 +45,7 @@ const handleKeypress = (event: { [key: string]: number }) => {
defineExpose({ handleKeypress }) defineExpose({ handleKeypress })
</script> </script>
<template> <template>
<UIMenu class="border-[1px] p-2 text-[0.875rem] text-black shadow-md" compact> <UIMenu class="border-[1px] p-2 text-[0.875rem] text-black shadow-md" :compact="true">
<UIMenuItem :active="!activeResult" @click="emit('createLink', props.autocompleteText)"> <UIMenuItem :active="!activeResult" @click="emit('createLink', props.autocompleteText)">
<span class="flex-grow">{{ props.autocompleteText }}</span> <span class="flex-grow">{{ props.autocompleteText }}</span>
<i class="fas fa-plus-circle ml-auto text-white" /> <i class="fas fa-plus-circle ml-auto text-white" />

View File

@@ -15,7 +15,8 @@ import ContextedPlugin from '@/ckeditor/ContextedPlugin'
import { mdToHtml, htmlToMd } from '@/utils/markdown' import { mdToHtml, htmlToMd } from '@/utils/markdown'
import { getNoteByTitle, setActiveNote, addNote } from '@/composables/useNotes' import { getNoteByTitle, setActiveNote, addNote } from '@/composables/useNotes'
import Autocomplete from '@/components/Note/Autocomplete.vue' import Autocomplete from '@/components/Note/Autocomplete.vue'
import { vibrate } from '@/composables/useHaptics' import { Haptics, ImpactStyle } from '@capacitor/haptics'
const props = defineProps<{ note: Note }>() const props = defineProps<{ note: Note }>()
const emit = defineEmits<{ const emit = defineEmits<{
@@ -67,7 +68,7 @@ const handleClick = async ({ data }: { data: any }) => {
let note: BaseNote | Note | undefined = getNoteByTitle(noteTitle) let note: BaseNote | Note | undefined = getNoteByTitle(noteTitle)
if (!note) note = addNote(noteTitle, '') if (!note) note = addNote(noteTitle, '')
setActiveNote(note.id) setActiveNote(note.id)
await vibrate() await Haptics.impact({ style: ImpactStyle.Light })
} }
const autocompleteRef = ref<InstanceType<typeof Autocomplete> | null>(null) const autocompleteRef = ref<InstanceType<typeof Autocomplete> | null>(null)

View File

@@ -6,7 +6,7 @@ const props = defineProps<{
</script> </script>
<template> <template>
<UIMenu class="mt-3 rounded-xl border-[1px] px-3 py-3" v-if="props.references.length > 0"> <UIMenu class="mt-3 rounded-xl border-[1px] px-3 py-3" v-if="props.references.length > 0">
<UIMenuItem title> <UIMenuItem :title="true">
<span>References</span> <span>References</span>
<UIBadge variant="outline" class="ml-2">{{ props.references.length }}</UIBadge> <UIBadge variant="outline" class="ml-2">{{ props.references.length }}</UIBadge>
</UIMenuItem> </UIMenuItem>

View File

@@ -2,7 +2,6 @@
import { Capacitor } from '@capacitor/core' import { Capacitor } from '@capacitor/core'
import { Dialog } from '@capacitor/dialog' import { Dialog } from '@capacitor/dialog'
import type { ConfirmOptions } from '@capacitor/dialog' import type { ConfirmOptions } from '@capacitor/dialog'
import { vibrate } from '@/composables/useHaptics'
const props = defineProps<{ const props = defineProps<{
note: Note note: Note
@@ -38,7 +37,7 @@ const confirmModals: ModalOptions[] = [
] ]
const emit = defineEmits<{ const emit = defineEmits<{
execute: [actionType: ActionKey, close?: () => Promise<void>] execute: [actionType: ActionKey, close?: () => void]
}>() }>()
const openModal = async (open: () => void, modal: ModalOptions) => { const openModal = async (open: () => void, modal: ModalOptions) => {
@@ -58,12 +57,7 @@ const openModal = async (open: () => void, modal: ModalOptions) => {
<UIButtonGroup class="flex items-center" v-if="!props.note.isRoot"> <UIButtonGroup class="flex items-center" v-if="!props.note.isRoot">
<UIModal v-for="confirmModal in confirmModals" :key="confirmModal.key"> <UIModal v-for="confirmModal in confirmModals" :key="confirmModal.key">
<template #activator="{ open }"> <template #activator="{ open }">
<UIButton <UIButton size="sm" @click="openModal(open, confirmModal)" :join="true">
size="sm"
@click="openModal(open, confirmModal)"
@mousedown="vibrate"
join
>
<i :class="confirmModal.icon" /> <i :class="confirmModal.icon" />
</UIButton> </UIButton>
</template> </template>
@@ -74,11 +68,7 @@ const openModal = async (open: () => void, modal: ModalOptions) => {
<template #default>{{ confirmModal.confirmOptions.message }}</template> <template #default>{{ confirmModal.confirmOptions.message }}</template>
<template #actions="{ close }"> <template #actions="{ close }">
<UIButton size="sm" @click="close">Cancel</UIButton> <UIButton size="sm" @click="close">Cancel</UIButton>
<UIButton <UIButton size="sm" color="primary" @click="emit('execute', confirmModal.key, close)">
size="sm"
color="primary"
@click="emit('execute', confirmModal.key, close)"
>
{{ confirmModal.confirmOptions.okButtonTitle }} {{ confirmModal.confirmOptions.okButtonTitle }}
</UIButton> </UIButton>
</template> </template>

View File

@@ -42,8 +42,7 @@ const handleKeydown = (event: KeyboardEvent) => {
if (index < 0) index = results.value.length - 1 if (index < 0) index = results.value.length - 1
activeResult.value = results.value[index] activeResult.value = results.value[index]
const element = resultsRefs.value[index].$el const element = resultsRefs.value[index].$el
if (['ArrowUp', 'ArrowDown', 'Tab'].includes(code)) if (['ArrowUp', 'ArrowDown', 'Tab'].includes(code)) element.scrollIntoView({ block: 'nearest' })
element.scrollIntoView({ block: 'nearest' })
} else if (code === 'Enter' && activeResult.value) { } else if (code === 'Enter' && activeResult.value) {
goToNote(activeResult.value) goToNote(activeResult.value)
} else if (code === 'Escape' && queryElem.value) { } else if (code === 'Escape' && queryElem.value) {
@@ -67,7 +66,7 @@ const resultsRefs = ref<InstanceType<typeof SearchResult>[]>([])
@keydown="handleKeydown" @keydown="handleKeydown"
/> />
<div class="z-1000 absolute left-0 right-0 top-[100%]" v-if="active"> <div class="z-1000 absolute left-0 right-0 top-[100%]" v-if="active">
<UIMenu compact class="mt-1 w-full rounded-md bg-base-100 p-2 text-black shadow"> <UIMenu :compact="true" class="mt-1 w-full rounded-md bg-base-100 p-2 text-black shadow">
<div class="max-h-[320px] w-full overflow-y-auto"> <div class="max-h-[320px] w-full overflow-y-auto">
<template v-if="results.length > 0"> <template v-if="results.length > 0">
<SearchResult <SearchResult

View File

@@ -8,11 +8,7 @@ const props = withDefaults(
</script> </script>
<template> <template>
<div class="flex w-full animate-pulse flex-col"> <div class="flex w-full animate-pulse flex-col">
<div <div class="mt-1 h-[1.35rem] w-full rounded bg-secondary" v-for="i in props.n" :key="i"></div>
class="mt-1 h-[1.35rem] w-full rounded bg-secondary"
v-for="i in props.n"
:key="i"
></div>
</div> </div>
</template> </template>
<style scoped> <style scoped>

View File

@@ -23,8 +23,9 @@ const searchActive = ref<boolean>(false)
// const authUI: any = inject('firebaseAuthUI') // const authUI: any = inject('firebaseAuthUI')
// const authPending = ref<boolean>(authUI.isPendingRedirect()) // const authPending = ref<boolean>(authUI.isPendingRedirect())
// const authPending = ref(false)
const handleSignIn = async (close: () => Promise<void>) => { const handleSignIn = async (close: () => Promise<boolean>) => {
await close() await close()
// authPending.value = false // authPending.value = false
} }
@@ -60,7 +61,7 @@ const handleSignIn = async (close: () => Promise<void>) => {
> >
<i class="fa-fw fa-solid fa-plus-circle scale-[115%]" /> <i class="fa-fw fa-solid fa-plus-circle scale-[115%]" />
</UIButton> </UIButton>
<UIModal v-if="initialized && !user"> <UIModal v-if="(initialized && !user)">
<template #activator="{ open }"> <template #activator="{ open }">
<UIButton <UIButton
size="sm" size="sm"
@@ -71,7 +72,7 @@ const handleSignIn = async (close: () => Promise<void>) => {
Sign in Sign in
</UIButton> </UIButton>
</template> </template>
<template #title>Sign in</template> <template #title>{{ 'Sign in' }}</template>
<template #default="{ close }"> <template #default="{ close }">
<Auth @signedIn="handleSignIn(close)" /> <Auth @signedIn="handleSignIn(close)" />
</template> </template>
@@ -86,23 +87,19 @@ const handleSignIn = async (close: () => Promise<void>) => {
</div> </div>
</div> </div>
</template> </template>
<style lang="scss" scoped> <style lang="scss">
#logo { #logo {
@apply cursor-pointer transition-all duration-200 active:text-primary; @apply cursor-pointer transition-all duration-200 hover:text-primary;
} }
@media (hover: hover) and (pointer: fine) { @media (hover: hover) and (pointer: fine) {
#logo:hover { #logo:hover {
text-shadow: 0 0 5px white, 0 0 10px white, 0 0 15px white; text-shadow: 0 0 5px white, 0 0 10px white, 0 0 15px white;
@apply text-primary;
} }
} }
#logo:active { #logo:active {
text-shadow: 0 0 5px white, 0 0 10px white, 0 0 15px white; text-shadow: 0 0 5px white, 0 0 10px white, 0 0 15px white;
} }
.topbar-button { .topbar-button {
&:active {
@apply border-white bg-white text-primary;
}
@apply hover:border-white hover:bg-white hover:text-primary focus-visible:outline-white; @apply hover:border-white hover:bg-white hover:text-primary focus-visible:outline-white;
} }

View File

@@ -9,7 +9,7 @@ const emit = defineEmits<{
</script> </script>
<template> <template>
<label <label
class="dui-btn-ghost dui-btn dui-btn-sm dui-btn-circle relative inline-grid cursor-pointer select-none place-content-center" class="dui-btn-ghost dui-btn-sm dui-btn-circle dui-btn relative inline-grid cursor-pointer select-none place-content-center"
> >
<input type="checkbox" @click="emit('toggleSideBar')" :checked="!props.sideBarCollapsed" /> <input type="checkbox" @click="emit('toggleSideBar')" :checked="!props.sideBarCollapsed" />
<svg <svg

View File

@@ -1,18 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { OnClickOutside } from '@vueuse/components' import { OnClickOutside } from '@vueuse/components'
import { vibrate } from '@/composables/useHaptics'
</script> </script>
<template> <template>
<OnClickOutside> <OnClickOutside>
<UIDropdown class="search-active-hide"> <UIDropdown class="search-active-hide">
<template #activator> <template #activator>
<UIButton <UIButton :dropdown="true" size="sm" variant="outline" class="topbar-button text-white">
dropdown
size="sm"
variant="outline"
class="topbar-button text-white"
@mousedown="vibrate"
>
<i class="fa-fw fa-solid fa-user-gear" /> <i class="fa-fw fa-solid fa-user-gear" />
</UIButton> </UIButton>
</template> </template>
@@ -24,11 +17,3 @@ import { vibrate } from '@/composables/useHaptics'
</UIDropdown> </UIDropdown>
</OnClickOutside> </OnClickOutside>
</template> </template>
<style scoped lang="scss">
.topbar-button {
&:focus-within {
@apply border-white bg-white text-primary;
}
@apply hover:border-white hover:bg-white hover:text-primary focus-visible:outline-white;
}
</style>

View File

@@ -1,5 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import { sendEmailVerification } from 'firebase/auth'
import { user } from '@/composables/useFirebase' import { user } from '@/composables/useFirebase'
import { encryptionKey, enableEncryption, disableEncryption } from '@/composables/useEncryption' import { encryptionKey, enableEncryption, disableEncryption } from '@/composables/useEncryption'
import { notes } from '@/composables/useNotes' import { notes } from '@/composables/useNotes'
@@ -10,10 +9,12 @@ import FileSaver from 'file-saver'
const verificationEmailSent = ref(false) const verificationEmailSent = ref(false)
const sendVerificationMail = () => { const sendVerificationMail = () => {
if (!user.value) throw Error("User doesn't exist, can't send verification email") if (!user.value) throw Error("User doesn't exist, can't send verification email")
sendEmailVerification(user.value) user.value.sendEmailVerification()
verificationEmailSent.value = true verificationEmailSent.value = true
} }
console.log(user.value)
const exportNotes = async () => { const exportNotes = async () => {
const zip = new JSZip() const zip = new JSZip()
notes.value.forEach((note) => { notes.value.forEach((note) => {
@@ -67,22 +68,21 @@ const toggleEncryption = async () => {
<UICard> <UICard>
<template #title>Account</template> <template #title>Account</template>
<template #default> <template #default>
<template v-if="user?.email"> <div class="w-full flex-row sm:flex" v-if="user?.email">
<div class="w-full flex-row sm:flex">
<div class="font-bold sm:w-4/12">E-mail address</div> <div class="font-bold sm:w-4/12">E-mail address</div>
<div>{{ user.email }}</div> <div>{{ user?.email }}</div>
</div> </div>
<div class="w-full flex-row sm:flex"> <div class="w-full flex-row sm:flex" v-if="user?.email">
<div class="font-bold sm:w-4/12">Account status</div> <div class="font-bold sm:w-4/12">Account status</div>
<div class="col-auto"> <div class="col-auto">
<UIBadge :color="user.emailVerified ? 'success' : 'warning'"> <UIBadge :color="user?.emailVerified ? 'success' : 'warning'">
{{ user.emailVerified ? 'Verified' : 'Not yet verified' }} {{ user?.emailVerified ? 'Verified' : 'Not yet verified' }}
</UIBadge> </UIBadge>
<UIButton <UIButton
size="sm" size="sm"
class="ml-2" class="ml-2"
@click="sendVerificationMail" @click="sendVerificationMail"
v-if="!user.emailVerified" v-if="!user?.emailVerified"
:disabled="verificationEmailSent" :disabled="verificationEmailSent"
> >
{{ {{
@@ -93,16 +93,10 @@ const toggleEncryption = async () => {
</UIButton> </UIButton>
</div> </div>
</div> </div>
</template>
<div class="w-full flex-row sm:flex"> <div class="w-full flex-row sm:flex">
<div class="font-bold sm:w-4/12">Account creation date</div> <div class="font-bold sm:w-4/12">Account creation date</div>
<div> <div>
{{ {{ format(Date.parse(user?.metadata?.creationTime || ''), 'dd/MM/yyyy') }}
format(
Date.parse(user?.metadata?.creationTime || ''),
'dd/MM/yyyy'
)
}}
</div> </div>
</div> </div>
</template> </template>
@@ -113,19 +107,15 @@ const toggleEncryption = async () => {
<div class="items-top w-full flex-row sm:flex"> <div class="items-top w-full flex-row sm:flex">
<div class="font-bold sm:w-4/12">Export notes</div> <div class="font-bold sm:w-4/12">Export notes</div>
<UIButton size="sm" @click="exportNotes"> <UIButton size="sm" @click="exportNotes">
<i class="fa-fw fa-solid fa-file-export mr-2"></i> <i class="fa-fw fa-solid fa-file-export"></i>
Export notes Export notes
</UIButton> </UIButton>
</div> </div>
<div class="items-top w-full flex-row sm:flex sm:flex-grow"> <div class="items-top w-full flex-row sm:flex sm:flex-grow">
<div class="flex-shrink-0 font-bold sm:w-4/12">Delete account</div> <div class="flex-shrink-0 font-bold sm:w-4/12">Delete account</div>
<div> <div>
<UIButton <UIButton size="sm" color="error" @click="showDeleteAccountDialog = true">
size="sm" <i class="fa-fw fa-solid fa-trash"></i>
color="error"
@click="showDeleteAccountDialog = true"
>
<i class="fa-fw fa-solid fa-trash mr-2"></i>
Delete account Delete account
</UIButton> </UIButton>
<UIAlert <UIAlert
@@ -135,23 +125,14 @@ const toggleEncryption = async () => {
v-if="showDeleteAccountDialog" v-if="showDeleteAccountDialog"
> >
<div> <div>
Are you sure you want to delete your Contexted account? This Are you sure you want to delete your Contexted account? This action cannot be
action cannot be undone! undone!
</div> </div>
<div class="flex flex-wrap gap-2"> <div class="flex flex-wrap gap-2">
<UIButton <UIButton size="sm" variant="outline" color="primary" @click="deleteAccount">
size="sm"
variant="outline"
color="primary"
@click="deleteAccount"
>
Delete account Delete account
</UIButton> </UIButton>
<UIButton <UIButton size="sm" variant="outline" @click="showDeleteAccountDialog = false">
size="sm"
variant="outline"
@click="showDeleteAccountDialog = false"
>
Cancel Cancel
</UIButton> </UIButton>
</div> </div>
@@ -159,9 +140,7 @@ const toggleEncryption = async () => {
</div> </div>
</div> </div>
<div class="items-top w-full flex-row sm:flex"> <div class="items-top w-full flex-row sm:flex">
<div class="flex-shrink-0 font-bold sm:w-4/12"> <div class="flex-shrink-0 font-bold sm:w-4/12">End-to-end encryption</div>
End-to-end encryption
</div>
<div class="w-full"> <div class="w-full">
<template v-if="!encryptionEnabled"> <template v-if="!encryptionEnabled">
<UIButton <UIButton
@@ -179,16 +158,11 @@ const toggleEncryption = async () => {
@click="showEncryptionDialog = true" @click="showEncryptionDialog = true"
v-if="showEncryptionDialog === false" v-if="showEncryptionDialog === false"
> >
<i class="fa-fw fa-solid fa-key mr-2"></i> <i class="fa-fw fa-solid fa-key"></i>
Disable end-to-end encryption Disable end-to-end encryption
</UIButton> </UIButton>
</template> </template>
<UIAlert <UIAlert color="info" density="compact" class="text-sm" v-if="showEncryptionDialog">
color="info"
density="compact"
class="text-sm"
v-if="showEncryptionDialog"
>
<div class="w-full space-y-2"> <div class="w-full space-y-2">
<div> <div>
Enter your passphrase to Enter your passphrase to
@@ -202,11 +176,7 @@ const toggleEncryption = async () => {
v-model="passphrase" v-model="passphrase"
class="w-full !max-w-full" class="w-full !max-w-full"
/> />
<UIAlert <UIAlert density="compact" color="error" v-if="toggleEncryptionError">
density="compact"
color="error"
v-if="toggleEncryptionError"
>
<i class="fa-solid fa-triangle-exclamation"></i> <i class="fa-solid fa-triangle-exclamation"></i>
{{ toggleEncryptionError }} {{ toggleEncryptionError }}
</UIAlert> </UIAlert>
@@ -218,16 +188,9 @@ const toggleEncryption = async () => {
color="primary" color="primary"
@click="toggleEncryption" @click="toggleEncryption"
> >
{{ {{ encryptionEnabled ? 'Disable' : 'Enable' }} encryption
encryptionEnabled ? 'Disable' : 'Enable'
}}
encryption
</UIButton> </UIButton>
<UIButton <UIButton size="sm" variant="outline" @click="showEncryptionDialog = false">
size="sm"
variant="outline"
@click="showEncryptionDialog = false"
>
Cancel Cancel
</UIButton> </UIButton>
</div> </div>

View File

@@ -3,7 +3,7 @@ import { preferredNotesSource } from '@/composables/useSettings'
import { signOut as firebaseSignOut } from '@/composables/useFirebase' import { signOut as firebaseSignOut } from '@/composables/useFirebase'
import { clearEncryptionKeys } from '@/composables/useEncryption' import { clearEncryptionKeys } from '@/composables/useEncryption'
const signOut = async (close: () => Promise<void>) => { const signOut = async (close: () => Promise<boolean>) => {
await close() await close()
await firebaseSignOut() await firebaseSignOut()
preferredNotesSource.value = null preferredNotesSource.value = null

View File

@@ -34,14 +34,11 @@ const deleteSelectedNotes = (closeModal: () => void) => {
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<div class="flex items-center"> <div class="flex items-center">
<span class="whitespace-nowrap"> <span class="whitespace-nowrap">
{{ notesWithReferences.length }} {{ notesWithReferences.length }} {{ notesWithReferences.length === 1 ? 'note' : 'notes' }}
{{ notesWithReferences.length === 1 ? 'note' : 'notes' }}
</span> </span>
<template v-if="countSelectedNotes > 0"> <template v-if="countSelectedNotes > 0">
<span class="mx-1">|</span> <span class="mx-1">|</span>
<div class="whitespace-nowrap font-semibold"> <div class="whitespace-nowrap font-semibold">{{ countSelectedNotes }} selected</div>
{{ countSelectedNotes }} selected
</div>
</template> </template>
</div> </div>
<UIModal v-if="countSelectedNotes > 0"> <UIModal v-if="countSelectedNotes > 0">

View File

@@ -27,9 +27,7 @@ const renderMindmap = () => {
const elements = { const elements = {
nodes: nodes.value, nodes: nodes.value,
edges: [ edges: [
...links.value.map((link) => ({ ...links.value.map((link) => ({ data: { id: `${link.source}-${link.target}`, ...link } }))
data: { id: `${link.source}-${link.target}`, ...link }
}))
] ]
} }
const cy = cytoscape({ const cy = cytoscape({
@@ -197,13 +195,11 @@ interface Mindmap {
} }
const selectedMindmap = ref<Mindmap>() const selectedMindmap = ref<Mindmap>()
const mindmaps = computed<Mindmap[]>(() => { const mindmaps = computed<Mindmap[]>(() => {
const mindmaps = Object.entries(notesRelations.value).reduce( const mindmaps = Object.entries(notesRelations.value).reduce((mindmaps, [noteId, relations]) => {
(mindmaps, [noteId, relations]) => {
const atomicMindmap = [noteId, ...relations.to, ...relations.from] const atomicMindmap = [noteId, ...relations.to, ...relations.from]
const indices = mindmaps const indices = mindmaps
.filter( .filter(
(mindmap) => (mindmap) => [...mindmap].filter((noteId) => atomicMindmap.includes(noteId)).length > 0
[...mindmap].filter((noteId) => atomicMindmap.includes(noteId)).length > 0
) )
.map((mindmap) => mindmaps.indexOf(mindmap)) .map((mindmap) => mindmaps.indexOf(mindmap))
if (indices.length > 0) { if (indices.length > 0) {
@@ -222,16 +218,13 @@ const mindmaps = computed<Mindmap[]>(() => {
mindmaps.push(atomicMindmap) mindmaps.push(atomicMindmap)
} }
return mindmaps return mindmaps
}, }, [] as string[][])
[] as string[][]
)
return mindmaps return mindmaps
.filter((mindmap) => mindmap.length > 1) .filter((mindmap) => mindmap.length > 1)
.sort((a, b) => b.length - a.length) .sort((a, b) => b.length - a.length)
.sort((a, b) => { .sort((a, b) => {
return ( return (
Number(b.includes(rootNote.value?.id || '')) - Number(b.includes(rootNote.value?.id || '')) - Number(a.includes(rootNote.value?.id || ''))
Number(a.includes(rootNote.value?.id || ''))
) )
}) })
.slice(0, 5) .slice(0, 5)
@@ -280,7 +273,6 @@ const links = computed(() => {
</script> </script>
<template> <template>
<div class="flex h-full flex-grow flex-col"> <div class="flex h-full flex-grow flex-col">
<div class="flex">
<UITabs> <UITabs>
<UITab <UITab
v-for="mindmap in mindmaps" v-for="mindmap in mindmaps"
@@ -292,7 +284,6 @@ const links = computed(() => {
{{ mindmap.notes.length }} notes {{ mindmap.notes.length }} notes
</UITab> </UITab>
</UITabs> </UITabs>
</div>
<div id="mindmap" ref="mindmapElement" class="h-full"></div> <div id="mindmap" ref="mindmapElement" class="h-full"></div>
</div> </div>
</template> </template>

View File

@@ -30,14 +30,13 @@ const updateNoteContent = (content: string) => {
const references = computed<Note[]>(() => getNoteReferences(props.note)) const references = computed<Note[]>(() => getNoteReferences(props.note))
const handleAction = async (action: 'delete' | 'setRoot', closeModal?: () => Promise<void>) => { const handleAction = async (action: string, closeModal: () => Promise<Boolean>) => {
switch (action) { if (action === 'delete') {
case 'delete':
if (closeModal) await closeModal() if (closeModal) await closeModal()
setActiveNote(rootNote.value?.id) setActiveNote(rootNote.value?.id)
deleteNote(props.note.id) deleteNote(props.note.id)
break }
case 'setRoot': if (action === 'setRoot') {
setRootNote(props.note.id) setRootNote(props.note.id)
if (closeModal) closeModal() if (closeModal) closeModal()
} }
@@ -51,11 +50,7 @@ const handleAction = async (action: 'delete' | 'setRoot', closeModal?: () => Pro
class="fas fa-fw fa-home mr-2 text-base text-secondary opacity-40" class="fas fa-fw fa-home mr-2 text-base text-secondary opacity-40"
v-if="props.note.isRoot" v-if="props.note.isRoot"
></i> ></i>
<input <input type="text" class="w-full bg-transparent pb-1 outline-none" v-model="noteTitle" />
type="text"
class="w-full bg-transparent pb-1 outline-none"
v-model="noteTitle"
/>
</template> </template>
</NoteToolbar> </NoteToolbar>
<NoteEditor <NoteEditor

View File

@@ -51,12 +51,7 @@ const styleClass = computed(() => {
> >
<slot></slot> <slot></slot>
</label> </label>
<button <button type="button" class="dui-btn h-auto px-3 py-2 duration-0" :class="styleClass" v-else>
type="button"
class="dui-btn inline-block h-auto max-w-full truncate px-3 py-2 duration-0"
:class="styleClass"
v-else
>
<slot></slot> <slot></slot>
</button> </button>
</template> </template>

View File

@@ -3,7 +3,7 @@
<slot name="activator" tabindex="0"></slot> <slot name="activator" tabindex="0"></slot>
<ul <ul
tabindex="0" tabindex="0"
class="dui-menu-compact dui-dropdown-content dui-menu mt-1 w-52 rounded-box bg-base-100 p-2 text-base-content shadow" class="dui-menu-compact dui-dropdown-content dui-menu rounded-box mt-1 w-52 bg-base-100 p-2 text-base-content shadow"
> >
<slot name="items"></slot> <slot name="items"></slot>
</ul> </ul>

View File

@@ -28,7 +28,7 @@ const styleClass = computed(() => {
type="checkbox" type="checkbox"
class="dui-checkbox dui-checkbox-sm border-secondary" class="dui-checkbox dui-checkbox-sm border-secondary"
:class="styleClass" :class="styleClass"
:checked="props.modelValue || props.checked" :checked="props.modelValue"
@change="emit('update:modelValue', ($event.target as HTMLInputElement).checked)" @change="emit('update:modelValue', ($event.target as HTMLInputElement).checked)"
:disabled="props.disabled" :disabled="props.disabled"
/> />

View File

@@ -16,9 +16,7 @@ const styleClass = computed(() => {
</script> </script>
<template> <template>
<li :class="styleClass"> <li :class="styleClass">
<span class="flex items-center" v-if="props.title"> <span class="flex items-center" v-if="props.title"><slot></slot></span>
<slot></slot>
</span>
<a <a
class="flex w-full rounded-md" class="flex w-full rounded-md"
:class="{ 'dui-disabled': props.disabled, 'dui-active': props.active }" :class="{ 'dui-disabled': props.disabled, 'dui-active': props.active }"
@@ -28,8 +26,3 @@ const styleClass = computed(() => {
</a> </a>
</li> </li>
</template> </template>
<style scoped>
.dui-active {
@apply bg-primary;
}
</style>

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { onClickOutside } from '@vueuse/core' import { onClickOutside } from '@vueuse/core'
import { vibrate } from '@/composables/useHaptics' import { Haptics, ImpactStyle } from '@capacitor/haptics'
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@@ -20,8 +20,9 @@ const show = ref<boolean>(false)
watch( watch(
() => props.open, () => props.open,
() => { () => {
if (show.value) vibrate() if (show.value) {
Haptics.impact({ style: ImpactStyle.Light })
}
show.value = props.open show.value = props.open
}, },
{ immediate: true } { immediate: true }
@@ -31,9 +32,9 @@ const modal = ref<HTMLElement | null>(null)
const modalBox = ref(null) const modalBox = ref(null)
const open = () => (show.value = true) const open = () => (show.value = true)
const close = (): Promise<void> => { const close = (): Promise<boolean> => {
return new Promise((resolve) => { return new Promise((resolve) => {
modal.value?.addEventListener('transitionend', () => resolve()) modal.value?.addEventListener('transitionend', () => resolve(true))
show.value = false show.value = false
}) })
} }

View File

@@ -6,12 +6,12 @@ interface Props {
const props = defineProps<Props>() const props = defineProps<Props>()
const styleClass = computed(() => { const styleClass = computed(() => {
const activeClass = props.active && 'dui-tab-active font-bold !border-primary text-primary' const activeClass = props.active && 'dui-tab-active !border-primary text-primary'
return [activeClass] return [activeClass]
}) })
</script> </script>
<template> <template>
<a class="dui-tab-bordered dui-tab hover:font-bold hover:text-primary" :class="styleClass"> <a class="dui-tab-bordered dui-tab-lifted dui-tab dui-tab-md" :class="styleClass">
<slot></slot> <slot></slot>
</a> </a>
</template> </template>

View File

@@ -1,3 +1,3 @@
<template> <template>
<div class="dui-tabs dui-tabs-boxed dui-tabs-md"><slot></slot></div> <div class="dui-tabs"><slot></slot></div>
</template> </template>

View File

@@ -97,10 +97,7 @@ const decryptNote = (note: BaseNote, key: EncryptionKey) => {
export const decryptNotes = (notes: BaseNotes, encryptionKey: EncryptionKey) => { export const decryptNotes = (notes: BaseNotes, encryptionKey: EncryptionKey) => {
const decryptedNotes = Object.fromEntries( const decryptedNotes = Object.fromEntries(
Object.entries(notes).map(([noteId, note]) => [ Object.entries(notes).map(([noteId, note]) => [noteId, { ...decryptNote(note, encryptionKey) }])
noteId,
{ ...decryptNote(note, encryptionKey) }
])
) )
return decryptedNotes return decryptedNotes
} }
@@ -115,10 +112,7 @@ const encryptNote = (note: BaseNote, key: EncryptionKey) => {
export const encryptNotes = (notes: BaseNotes, encryptionKey: EncryptionKey) => { export const encryptNotes = (notes: BaseNotes, encryptionKey: EncryptionKey) => {
const encryptedNotes = Object.fromEntries( const encryptedNotes = Object.fromEntries(
Object.entries(notes).map(([noteId, note]) => [ Object.entries(notes).map(([noteId, note]) => [noteId, { ...encryptNote(note, encryptionKey) }])
noteId,
{ ...encryptNote(note, encryptionKey) }
])
) )
return encryptedNotes return encryptedNotes
} }

View File

@@ -1,24 +1,13 @@
// import { initializeApp } from 'firebase/app' // import { initializeApp } from 'firebase/app'
import { Capacitor } from '@capacitor/core' import firebase from 'firebase/compat/app'
// import firebase from 'firebase/compat/app' import type { User } from '@firebase/auth-types'
// import type { User } from '@firebase/auth-types'
import { initializeApp } from 'firebase/app'
import { import {
initializeFirestore, initializeFirestore,
persistentLocalCache, persistentLocalCache,
persistentMultipleTabManager persistentMultipleTabManager
} from 'firebase/firestore' } from 'firebase/firestore'
import {
getAuth,
indexedDBLocalPersistence,
initializeAuth,
onAuthStateChanged,
signOut as firebaseSignOut
} from 'firebase/auth'
import { type FirebaseApp } from 'firebase/app'
import { type User } from '@firebase/auth'
import type { Firestore } from 'firebase/firestore' import type { Firestore } from 'firebase/firestore'
import { getAuth, getRedirectResult } from 'firebase/auth'
// import { getAnalytics } from "firebase/analytics"; // import { getAnalytics } from "firebase/analytics";
// TODO: Add SDKs for Firebase products that you want to use // TODO: Add SDKs for Firebase products that you want to use
@@ -41,26 +30,43 @@ export const user = ref<User | null>()
export const initialized = computed<boolean>(() => user.value !== undefined) export const initialized = computed<boolean>(() => user.value !== undefined)
export const signOut = async () => firebaseSignOut(getAuth()) export const signOut = () => firebase.auth().signOut()
export const db = ref<Firestore>() export const db = ref<Firestore>()
const getFirebaseAuth = async (app: FirebaseApp) => {
if (Capacitor.isNativePlatform()) {
return initializeAuth(app, {
persistence: indexedDBLocalPersistence
})
} else {
return getAuth()
}
}
// Initialize Firebase // Initialize Firebase
export const initializeFirebase = async () => { export const initializeFirebase = async () => {
const app = initializeApp(firebaseConfig) const app = firebase.initializeApp(firebaseConfig)
const auth = await getFirebaseAuth(app) const auth = getAuth()
onAuthStateChanged(auth, (firebaseUser) => { try {
console.log('auth state changed', firebaseUser) const authRedirectResult = await getRedirectResult(auth)
console.log(authRedirectResult)
// user.value = result
// This gives you a Google Access Token. You can use it to access Google APIs.
// const credential = GoogleAuthProvider.credentialFromResult(result)
// const token = credential.accessToken
// The signed-in user info.
// const user = result.user
// IdP data available using getAdditionalUserInfo(result)
// ...
} catch (error: any) {
console.error(error)
// const errorCode = error.code
// // const errorMessage = error.message
// const email = error.customData.email
// Handle Errors here.
// const errorCode = error.code
// const errorMessage = error.message
// The email of the user's account used.
// const email = error.customData.email
// The AuthCredential type that was used.
// const credential = GoogleAuthProvider.credentialFromError(error)
// ...
}
firebase.auth().onAuthStateChanged((firebaseUser) => {
user.value = firebaseUser user.value = firebaseUser
}) })
db.value = markRaw( db.value = markRaw(

View File

@@ -1,3 +0,0 @@
import { Haptics, ImpactStyle } from '@capacitor/haptics'
export const vibrate = () => Haptics.impact({ style: ImpactStyle.Light })

View File

@@ -8,7 +8,7 @@ import { defaultNotes } from '@/utils/defaultNotes'
import { mdToHtml } from '@/utils/markdown' import { mdToHtml } from '@/utils/markdown'
import { getAllMatches } from '@/utils/helpers' import { getAllMatches } from '@/utils/helpers'
import { preferredNotesSource } from '@/composables/useSettings' import { preferredNotesSource } from '@/composables/useSettings'
import { vibrate } from '@/composables/useHaptics' import { Haptics, ImpactStyle } from '@capacitor/haptics'
export const notesSources = computed(() => ({ export const notesSources = computed(() => ({
local: true, local: true,
@@ -104,7 +104,7 @@ export const setActiveNote = (noteId: string | undefined, haptic: boolean = true
if (noteId) { if (noteId) {
activeNoteId.value = noteId activeNoteId.value = noteId
activeViewMode.value = viewModes.find((mode) => mode.name === 'Note') || viewModes[0] activeViewMode.value = viewModes.find((mode) => mode.name === 'Note') || viewModes[0]
if (haptic) vibrate() if (haptic) Haptics.impact({ style: ImpactStyle.Light })
} }
} }
@@ -151,9 +151,7 @@ export const findNotes = (query: string): Note[] => {
} }
return notes.value.filter((note) => { return notes.value.filter((note) => {
const matchTitle = note.title.toLowerCase().includes(query.toLowerCase()) const matchTitle = note.title.toLowerCase().includes(query.toLowerCase())
const matchContent = removeMdFromText(note.content) const matchContent = removeMdFromText(note.content).toLowerCase().includes(query.toLowerCase())
.toLowerCase()
.includes(query.toLowerCase())
return matchTitle || matchContent return matchTitle || matchContent
}) })
} }
@@ -207,9 +205,7 @@ export const notesRelations = computed(() => {
.map((noteRelations, _, notesRelations): NoteRelations => { .map((noteRelations, _, notesRelations): NoteRelations => {
const from = [...notesRelations] const from = [...notesRelations]
.map((noteRelation) => .map((noteRelation) =>
noteRelation.to noteRelation.to.filter((toId) => toId === noteRelations.id).map(() => noteRelation.id)
.filter((toId) => toId === noteRelations.id)
.map(() => noteRelation.id)
) )
.reduce((arr, elem) => arr.concat(elem), []) .reduce((arr, elem) => arr.concat(elem), [])
.filter((value, index, self) => self.indexOf(value) === index) .filter((value, index, self) => self.indexOf(value) === index)
@@ -266,9 +262,7 @@ export const getNotes = async () => {
} }
} else if (activeNotesSource.value === 'firebase') { } else if (activeNotesSource.value === 'firebase') {
if (encryptionKey.value === undefined || !user.value || !db.value) return if (encryptionKey.value === undefined || !user.value || !db.value) return
const firebaseNotes = ( const firebaseNotes = (await getDoc(doc(db.value, 'pages', user.value.uid))).data() as BaseNotes
await getDoc(doc(db.value, 'pages', user.value.uid))
).data() as BaseNotes
notes = encryptionKey.value notes = encryptionKey.value
? decryptNotes(firebaseNotes, encryptionKey.value) ? decryptNotes(firebaseNotes, encryptionKey.value)
: firebaseNotes || {} : firebaseNotes || {}

View File

@@ -1,4 +1,3 @@
import { Capacitor } from '@capacitor/core'
import { createApp } from 'vue' import { createApp } from 'vue'
import '@/style.scss' import '@/style.scss'
import '@fortawesome/fontawesome-free/css/all.min.css' import '@fortawesome/fontawesome-free/css/all.min.css'
@@ -8,10 +7,9 @@ import { initializeFirebase } from '@/composables/useFirebase'
import { StatusBar, Style } from '@capacitor/status-bar' import { StatusBar, Style } from '@capacitor/status-bar'
import { Keyboard } from '@capacitor/keyboard' import { Keyboard } from '@capacitor/keyboard'
if (Capacitor.isNativePlatform()) {
StatusBar.setStyle({ style: Style.Dark }) StatusBar.setStyle({ style: Style.Dark })
Keyboard.setAccessoryBarVisible({ isVisible: true }) Keyboard.setAccessoryBarVisible({ isVisible: true })
}
initializeFirebase() initializeFirebase()
const isDark = usePreferredDark() const isDark = usePreferredDark()

View File

@@ -38,12 +38,12 @@ export default {
themes: [ themes: [
{ {
contexted: { contexted: {
...require('daisyui/src/theming/themes')['light'], ...require('daisyui/src/theming/themes')['[data-theme=light]'],
primary, primary,
secondary, secondary,
'--btn-text-case': 'uppercase', // set default text transform for buttons '--btn-text-case': 'uppercase' // set default text transform for buttons
// accent: '#37CDBE', // accent: '#37CDBE',
neutral: primary, // neutral: '#F7F7F7',
// 'base-100': '#FFFFFF', // 'base-100': '#FFFFFF',
// info: '#3ABFF8', // info: '#3ABFF8',
// success: '#36D399', // success: '#36D399',