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",
"semi": false,
"tabWidth": 4,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "none",

View File

@@ -1,11 +1,2 @@
pretty:
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"
dependencies {
implementation project(':capacitor-firebase-authentication')
implementation project(':capacitor-dialog')
implementation project(':capacitor-haptics')
implementation project(':capacitor-keyboard')
implementation project(':capacitor-splash-screen')
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"?>
<resources>
<color name="ic_launcher_background">#1E4BC4</color>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>

View File

@@ -2,9 +2,6 @@
include ':capacitor-android'
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'
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'
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'
project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android')

View File

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

View File

@@ -8,15 +8,8 @@ const config: CapacitorConfig = {
androidScheme: 'https'
},
plugins: {
SplashScreen: {
backgroundColor: '#1E4BC4'
},
Keyboard: {
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 */; };
50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; };
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 */
/* Begin PBXFileReference section */
@@ -28,7 +27,6 @@
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>"; };
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; };
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>"; };
@@ -76,7 +74,6 @@
isa = PBXGroup;
children = (
50379B222058CBB4000EE86E /* capacitor.config.json */,
A9A186E52A2FB826009CBA16 /* GoogleService-Info.plist */,
504EC3071FED79650016851F /* AppDelegate.swift */,
504EC30B1FED79650016851F /* Main.storyboard */,
504EC30E1FED79650016851F /* Assets.xcassets */,
@@ -164,7 +161,6 @@
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
504EC30D1FED79650016851F /* Main.storyboard in Resources */,
2FAD9763203C412B000D30F8 /* config.xml in Resources */,
A9A186E62A2FB826009CBA16 /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -351,7 +347,6 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 5XQS3G6YV7;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@@ -372,7 +367,6 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 5XQS3G6YV7;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
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" : [
{
"filename" : "AppIcon-1024@2x.png",
"filename" : "AppIcon-512@2x.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"

View File

@@ -1,23 +1,23 @@
{
"images" : [
{
"filename" : "splash-landscape@1x.png",
"idiom" : "universal",
"filename" : "splash-2732x2732-2.png",
"scale" : "1x"
},
{
"filename" : "splash-landscape@2x.png",
"idiom" : "universal",
"filename" : "splash-2732x2732-1.png",
"scale" : "2x"
},
{
"filename" : "splash-landscape@3x.png",
"idiom" : "universal",
"filename" : "splash-2732x2732.png",
"scale" : "3x"
}
],
"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>
<key>CFBundleShortVersionString</key>
<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>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key>

View File

@@ -11,29 +11,17 @@ install! 'cocoapods', :disable_input_output_paths => true
def capacitor_pods
pod 'Capacitor', :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 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'
pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen'
pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
end
target 'App' do
capacitor_pods
# Add your Pods here
pod 'CapacitorFirebaseAuthentication/Google', :path => '../../node_modules/@capacitor-firebase/authentication'
end
post_install do |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

View File

@@ -1,96 +1,24 @@
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):
- CapacitorCordova
- CapacitorCordova (5.0.4)
- CapacitorDialog (5.0.2):
- 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):
- Capacitor
- CapacitorKeyboard (5.0.2):
- Capacitor
- CapacitorSplashScreen (5.0.2):
- Capacitor
- CapacitorStatusBar (5.0.2):
- 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:
- "Capacitor (from `../../node_modules/@capacitor/ios`)"
- "CapacitorCordova (from `../../node_modules/@capacitor/ios`)"
- "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`)"
- "CapacitorKeyboard (from `../../node_modules/@capacitor/keyboard`)"
- "CapacitorSplashScreen (from `../../node_modules/@capacitor/splash-screen`)"
- "CapacitorStatusBar (from `../../node_modules/@capacitor/status-bar`)"
SPEC REPOS:
trunk:
- AppAuth
- FirebaseAppCheckInterop
- FirebaseAuth
- FirebaseCore
- FirebaseCoreInternal
- GoogleSignIn
- GoogleUtilities
- GTMAppAuth
- GTMSessionFetcher
- PromisesObjC
EXTERNAL SOURCES:
Capacitor:
:path: "../../node_modules/@capacitor/ios"
@@ -98,37 +26,21 @@ EXTERNAL SOURCES:
:path: "../../node_modules/@capacitor/ios"
CapacitorDialog:
:path: "../../node_modules/@capacitor/dialog"
CapacitorFirebaseAuthentication:
:path: "../../node_modules/@capacitor-firebase/authentication"
CapacitorHaptics:
:path: "../../node_modules/@capacitor/haptics"
CapacitorKeyboard:
:path: "../../node_modules/@capacitor/keyboard"
CapacitorSplashScreen:
:path: "../../node_modules/@capacitor/splash-screen"
CapacitorStatusBar:
:path: "../../node_modules/@capacitor/status-bar"
SPEC CHECKSUMS:
AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570
Capacitor: d3d4463573438b9fa65326d1f3549da6f4c21634
CapacitorCordova: b1fe6bf1f36974a8e4a9044b342d22d49c0996d6
CapacitorDialog: 01c49f7f4b37e7ad59e38fd317a6e5f006f23cdc
CapacitorFirebaseAuthentication: f2e3c2a7488b87078025855588670840f93a721e
CapacitorHaptics: 864585542a435bd41eaabf7f30d9ff5ec03024d3
CapacitorKeyboard: e628d4e66d621c69e449945ebabded17c5b9c2e8
CapacitorSplashScreen: bd2a056394ba0b8807e7bb3e746424f67c426e03
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

337
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,20 +9,18 @@
"preview": "vite preview",
"build-only": "vite build",
"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/",
"local": "npm run build && firebase serve --only hosting",
"deploy": "npm run build && firebase deploy --only hosting:contexted-v3"
},
"dependencies": {
"@capacitor-firebase/authentication": "^5.0.0",
"@capacitor/android": "^5.0.4",
"@capacitor/core": "^5.0.4",
"@capacitor/dialog": "^5.0.2",
"@capacitor/haptics": "^5.0.2",
"@capacitor/ios": "^5.0.4",
"@capacitor/keyboard": "^5.0.2",
"@capacitor/splash-screen": "^5.0.2",
"@capacitor/status-bar": "^5.0.2",
"@ckeditor/ckeditor5-autoformat": "^37.1.0",
"@ckeditor/ckeditor5-basic-styles": "^37.1.0",
@@ -42,6 +40,7 @@
"@vueuse/core": "^10.1.2",
"crypto-js": "^4.1.1",
"cytoscape": "^3.25.0",
"daisyui": "^3.0.0",
"date-fns": "^2.29.3",
"dompurify": "^3.0.2",
"file-saver": "^2.0.5",
@@ -53,7 +52,8 @@
"marked": "^4.3.0",
"shortid": "^2.2.16",
"turndown": "^7.1.2",
"vue": "^3.3.4"
"vue": "^3.3.4",
"vue-virtual-scroller": "^2.0.0-beta.8"
},
"devDependencies": {
"@capacitor/cli": "^5.0.4",
@@ -72,7 +72,6 @@
"@vue/eslint-config-typescript": "^11.0.3",
"@vue/tsconfig": "^0.4.0",
"autoprefixer": "^10.4.14",
"daisyui": "^4.4.19",
"eslint": "^8.40.0",
"eslint-plugin-vue": "^9.13.0",
"firebase-tools": "^12.1.0",

View File

@@ -11,13 +11,12 @@ import {
import { initializeSettings } from '@/composables/useSettings'
import { windowIsMobile } from '@/utils/helpers'
import SideBar from '@/components/SideBar.vue'
import firebase from 'firebase/compat/app'
import * as firebaseui from 'firebaseui'
import { useWindowSize } from '@vueuse/core'
import { SplashScreen } from '@capacitor/splash-screen'
initializeSettings()
onMounted(() => SplashScreen.hide())
const sideBarCollapsed = ref<boolean>(windowIsMobile())
const { width } = useWindowSize()
@@ -27,9 +26,9 @@ watch(width, () => (sideBarCollapsed.value = windowIsMobile()))
// const ListView = defineAsyncComponent(() => import('@/components/ViewModes/ListView.vue'))
// const Mindmap = defineAsyncComponent(() => import('@/components/ViewModes/Mindmap.vue'))
// const firebaseAuthUI =
// firebaseui.auth.AuthUI.getInstance() || new firebaseui.auth.AuthUI(firebase.auth())
// provide('firebaseAuthUI', firebaseAuthUI)
const firebaseAuthUI =
firebaseui.auth.AuthUI.getInstance() || new firebaseui.auth.AuthUI(firebase.auth())
provide('firebaseAuthUI', firebaseAuthUI)
watch(
[activeNotesSource, encryptionKey],
@@ -92,10 +91,10 @@ const topBarHeightWithSafeArea = computed(() => `calc(${topBarHeight}px + var(--
/>
</Transition>
<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'"
>
<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">
<Note
v-if="activeViewMode.name === 'Note' && activeNote"
@@ -111,12 +110,12 @@ const topBarHeightWithSafeArea = computed(() => `calc(${topBarHeight}px + var(--
</div>
</main>
</div>
<UIModal :open="passphraseRequired" persistent>
<UIModal :open="passphraseRequired" :persistent="true">
<template #title>Enter your passphrase</template>
<template #default="{ close }">
<div>
Your notes are encrypted. Please enter your encryption key passphrase to decrypt
your cloud notes.
Your notes are encrypted. Please enter your encryption key passphrase to decrypt your cloud
notes.
</div>
<form @submit.prevent="submitPassphrase(close)">
<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)
if (major < 37) {
console.warn(
'The <CKEditor> component requires using CKEditor 5 in version 37 or higher.'
)
console.warn('The <CKEditor> component requires using CKEditor 5 in version 37 or higher.')
}
} else {
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) => {
const rangesToFormat = format.map((array) =>
model.createRange(
range.start.getShiftedBy(array[0]),
range.start.getShiftedBy(array[1])
)
model.createRange(range.start.getShiftedBy(array[0]), range.start.getShiftedBy(array[1]))
)
const validRanges = editor.model.schema.getValidRanges(
rangesToFormat,
'contextedLink'
)
const validRanges = editor.model.schema.getValidRanges(rangesToFormat, 'contextedLink')
for (const range of validRanges) {
for (const item of range.getItems()) {
if ((item as any).data) {
@@ -151,8 +145,8 @@ export default class ContextedLinkEditing extends Plugin {
}
const keyCodes = [...keyCodesConfirm, ...keyCodesCycle]
const selection = editor.model.document.selection
const selectionInContextedLink = ['contextedLink', 'autocomplete'].some(
(attribute) => selection.hasAttribute(attribute)
const selectionInContextedLink = ['contextedLink', 'autocomplete'].some((attribute) =>
selection.hasAttribute(attribute)
)
if (selectionInContextedLink && keyCodes.includes(keyCode)) {
if (selection.hasAttribute('contextedLink')) {
@@ -222,10 +216,7 @@ function fireAutocompleteEvent(editor: any, show: boolean, autocompleteNode?: an
event = {
position: getNodePosition(
editor,
editor.model.createPositionFromPath(
autocompleteNode.root,
autocompleteNode.getPath()
)
editor.model.createPositionFromPath(autocompleteNode.root, autocompleteNode.getPath())
),
autocompleteText: autocompleteNode.data,
domElement,

View File

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

View File

@@ -45,7 +45,7 @@ const handleKeypress = (event: { [key: string]: number }) => {
defineExpose({ handleKeypress })
</script>
<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)">
<span class="flex-grow">{{ props.autocompleteText }}</span>
<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 { getNoteByTitle, setActiveNote, addNote } from '@/composables/useNotes'
import Autocomplete from '@/components/Note/Autocomplete.vue'
import { vibrate } from '@/composables/useHaptics'
import { Haptics, ImpactStyle } from '@capacitor/haptics'
const props = defineProps<{ note: Note }>()
const emit = defineEmits<{
@@ -67,7 +68,7 @@ const handleClick = async ({ data }: { data: any }) => {
let note: BaseNote | Note | undefined = getNoteByTitle(noteTitle)
if (!note) note = addNote(noteTitle, '')
setActiveNote(note.id)
await vibrate()
await Haptics.impact({ style: ImpactStyle.Light })
}
const autocompleteRef = ref<InstanceType<typeof Autocomplete> | null>(null)

View File

@@ -6,7 +6,7 @@ const props = defineProps<{
</script>
<template>
<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>
<UIBadge variant="outline" class="ml-2">{{ props.references.length }}</UIBadge>
</UIMenuItem>

View File

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

View File

@@ -42,8 +42,7 @@ const handleKeydown = (event: KeyboardEvent) => {
if (index < 0) index = results.value.length - 1
activeResult.value = results.value[index]
const element = resultsRefs.value[index].$el
if (['ArrowUp', 'ArrowDown', 'Tab'].includes(code))
element.scrollIntoView({ block: 'nearest' })
if (['ArrowUp', 'ArrowDown', 'Tab'].includes(code)) element.scrollIntoView({ block: 'nearest' })
} else if (code === 'Enter' && activeResult.value) {
goToNote(activeResult.value)
} else if (code === 'Escape' && queryElem.value) {
@@ -67,7 +66,7 @@ const resultsRefs = ref<InstanceType<typeof SearchResult>[]>([])
@keydown="handleKeydown"
/>
<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">
<template v-if="results.length > 0">
<SearchResult

View File

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

View File

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

View File

@@ -9,7 +9,7 @@ const emit = defineEmits<{
</script>
<template>
<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" />
<svg

View File

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

View File

@@ -3,7 +3,7 @@ import { preferredNotesSource } from '@/composables/useSettings'
import { signOut as firebaseSignOut } from '@/composables/useFirebase'
import { clearEncryptionKeys } from '@/composables/useEncryption'
const signOut = async (close: () => Promise<void>) => {
const signOut = async (close: () => Promise<boolean>) => {
await close()
await firebaseSignOut()
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">
<span class="whitespace-nowrap">
{{ notesWithReferences.length }}
{{ notesWithReferences.length === 1 ? 'note' : 'notes' }}
{{ notesWithReferences.length }} {{ notesWithReferences.length === 1 ? 'note' : 'notes' }}
</span>
<template v-if="countSelectedNotes > 0">
<span class="mx-1">|</span>
<div class="whitespace-nowrap font-semibold">
{{ countSelectedNotes }} selected
</div>
<div class="whitespace-nowrap font-semibold">{{ countSelectedNotes }} selected</div>
</template>
</div>
<UIModal v-if="countSelectedNotes > 0">

View File

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

View File

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

View File

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

View File

@@ -3,7 +3,7 @@
<slot name="activator" tabindex="0"></slot>
<ul
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>
</ul>

View File

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

View File

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

View File

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

View File

@@ -6,12 +6,12 @@ interface Props {
const props = defineProps<Props>()
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]
})
</script>
<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>
</a>
</template>

View File

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

View File

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

View File

@@ -1,24 +1,13 @@
// import { initializeApp } from 'firebase/app'
import { Capacitor } from '@capacitor/core'
// import firebase from 'firebase/compat/app'
// import type { User } from '@firebase/auth-types'
import { initializeApp } from 'firebase/app'
import firebase from 'firebase/compat/app'
import type { User } from '@firebase/auth-types'
import {
initializeFirestore,
persistentLocalCache,
persistentMultipleTabManager
} 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 { getAuth, getRedirectResult } from 'firebase/auth'
// import { getAnalytics } from "firebase/analytics";
// 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 signOut = async () => firebaseSignOut(getAuth())
export const signOut = () => firebase.auth().signOut()
export const db = ref<Firestore>()
const getFirebaseAuth = async (app: FirebaseApp) => {
if (Capacitor.isNativePlatform()) {
return initializeAuth(app, {
persistence: indexedDBLocalPersistence
})
} else {
return getAuth()
}
}
// Initialize Firebase
export const initializeFirebase = async () => {
const app = initializeApp(firebaseConfig)
const auth = await getFirebaseAuth(app)
onAuthStateChanged(auth, (firebaseUser) => {
console.log('auth state changed', firebaseUser)
const app = firebase.initializeApp(firebaseConfig)
const auth = getAuth()
try {
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
})
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 { getAllMatches } from '@/utils/helpers'
import { preferredNotesSource } from '@/composables/useSettings'
import { vibrate } from '@/composables/useHaptics'
import { Haptics, ImpactStyle } from '@capacitor/haptics'
export const notesSources = computed(() => ({
local: true,
@@ -104,7 +104,7 @@ export const setActiveNote = (noteId: string | undefined, haptic: boolean = true
if (noteId) {
activeNoteId.value = noteId
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) => {
const matchTitle = note.title.toLowerCase().includes(query.toLowerCase())
const matchContent = removeMdFromText(note.content)
.toLowerCase()
.includes(query.toLowerCase())
const matchContent = removeMdFromText(note.content).toLowerCase().includes(query.toLowerCase())
return matchTitle || matchContent
})
}
@@ -207,9 +205,7 @@ export const notesRelations = computed(() => {
.map((noteRelations, _, notesRelations): NoteRelations => {
const from = [...notesRelations]
.map((noteRelation) =>
noteRelation.to
.filter((toId) => toId === noteRelations.id)
.map(() => noteRelation.id)
noteRelation.to.filter((toId) => toId === noteRelations.id).map(() => noteRelation.id)
)
.reduce((arr, elem) => arr.concat(elem), [])
.filter((value, index, self) => self.indexOf(value) === index)
@@ -266,9 +262,7 @@ export const getNotes = async () => {
}
} else if (activeNotesSource.value === 'firebase') {
if (encryptionKey.value === undefined || !user.value || !db.value) return
const firebaseNotes = (
await getDoc(doc(db.value, 'pages', user.value.uid))
).data() as BaseNotes
const firebaseNotes = (await getDoc(doc(db.value, 'pages', user.value.uid))).data() as BaseNotes
notes = encryptionKey.value
? decryptNotes(firebaseNotes, encryptionKey.value)
: firebaseNotes || {}

View File

@@ -1,4 +1,3 @@
import { Capacitor } from '@capacitor/core'
import { createApp } from 'vue'
import '@/style.scss'
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 { Keyboard } from '@capacitor/keyboard'
if (Capacitor.isNativePlatform()) {
StatusBar.setStyle({ style: Style.Dark })
Keyboard.setAccessoryBarVisible({ isVisible: true })
}
initializeFirebase()
const isDark = usePreferredDark()

View File

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