Compare commits

...

93 Commits

Author SHA1 Message Date
e74b510d59 remove statusbar and keyboard plugin errors 2023-06-06 20:41:31 +02:00
f4a952c76f remove firebaseapp global 2023-06-06 20:40:01 +02:00
fdb1543ffa bug fixes 2023-06-06 20:29:42 +02:00
69255d0734 complete capacitor firebase integration 2023-06-06 20:19:50 +02:00
73a1a61d23 configure Firebase Android 2023-06-06 19:47:48 +02:00
d793a4260c capacitor firebase auth 2023-06-06 19:33:43 +02:00
5e1ff59880 small ui fixes 2023-06-03 23:04:57 +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
151 changed files with 21311 additions and 1009 deletions

8
.env Normal file
View File

@@ -0,0 +1,8 @@
VITE_FIREBASE_API_KEY=AIzaSyBxt-j-9yVwt-3iPLp1Px-a038ZXwAiHOs
VITE_FIREBASE_AUTH_DOMAIN=contexted.app
VITE_FIREBASE_DATABASE_URL=https://contexted-f8b4e.firebaseio.com
VITE_FIREBASE_PROJECT_ID=contexted-f8b4e
VITE_FIREBASE_STORAGE_BUCKET=contexted-f8b4e.appspot.com
VITE_FIREBASE_MESSAGING_SENDER_ID=1048273547256
VITE_FIREBASE_APP_ID=1:1048273547256:web:c5516617eeeabd470f700d
VITE_FIREBASE_MEASUREMENT_ID=G-ZMQXB5HFNV

View File

@@ -1,9 +0,0 @@
VITE_FIREBASE_API_KEY=
VITE_FIREBASE_AUTH_DOMAIN=
VITE_FIREBASE_DATABASE_URL=
VITE_FIREBASE_PROJECT_ID=
VITE_FIREBASE_STORAGE_BUCKET=
VITE_FIREBASE_MESSAGE_SENDER_ID=
VITE_FIREBASE_APP_ID=
VITE_FIREBASE_MEASUREMENT_ID=

18
.eslintrc.cjs Normal file
View File

@@ -0,0 +1,18 @@
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier/skip-formatting'
],
parserOptions: {
ecmaVersion: 'latest'
},
rules: {
'vue/multi-word-component-names': 'off'
}
}

15
.firebaserc Normal file
View File

@@ -0,0 +1,15 @@
{
"projects": {
"default": "contexted-f8b4e"
},
"targets": {
"contexted-f8b4e": {
"hosting": {
"contexted-v3": [
"contexted-v3"
]
}
}
},
"etags": {}
}

3
.gitignore vendored
View File

@@ -22,5 +22,4 @@ dist-ssr
*.njsproj
*.sln
*.sw?
.env
.firebase

View File

@@ -1,9 +1,10 @@
{
"tabWidth": 2,
"useTabs": false,
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 88,
"printWidth": 100,
"trailingComma": "none",
"htmlWhitespaceSensitivity": "ignore",
"plugins": [
"prettier-plugin-tailwindcss"

101
android/.gitignore vendored Normal file
View File

@@ -0,0 +1,101 @@
# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore
# Built application files
*.apk
*.aar
*.ap_
*.aab
# Files for the ART/Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Uncomment the following line in case you need and you don't have the release build type files in your app
# release/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
# IntelliJ
*.iml
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/assetWizardSettings.xml
.idea/dictionaries
.idea/libraries
# Android Studio 3 in .gitignore file.
.idea/caches
.idea/modules.xml
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
.idea/navEditor.xml
# Keystore files
# Uncomment the following lines if you do not want to check your keystore files in.
#*.jks
#*.keystore
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
.cxx/
# Google Services (e.g. APIs or Firebase)
# google-services.json
# Freeline
freeline.py
freeline/
freeline_project_description.json
# fastlane
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
fastlane/readme.md
# Version control
vcs.xml
# lint
lint/intermediates/
lint/generated/
lint/outputs/
lint/tmp/
# lint/reports/
# Android Profiling
*.hprof
# Cordova plugins for Capacitor
capacitor-cordova-android-plugins
# Copied web assets
app/src/main/assets/public
# Generated Config files
app/src/main/assets/capacitor.config.json
app/src/main/assets/capacitor.plugins.json
app/src/main/res/xml/config.xml

2
android/app/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/build/*
!/build/.npmkeep

54
android/app/build.gradle Normal file
View File

@@ -0,0 +1,54 @@
apply plugin: 'com.android.application'
android {
namespace "com.contexted.app"
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {
applicationId "com.contexted.app"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
repositories {
flatDir{
dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
implementation project(':capacitor-android')
testImplementation "junit:junit:$junitVersion"
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
implementation project(':capacitor-cordova-android-plugins')
}
apply from: 'capacitor.build.gradle'
try {
def servicesJSON = file('google-services.json')
if (servicesJSON.text) {
apply plugin: 'com.google.gms.google-services'
}
} catch(Exception e) {
logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
}

View File

@@ -0,0 +1,23 @@
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
}
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-status-bar')
}
if (hasProperty('postBuildExtras')) {
postBuildExtras()
}

View File

@@ -0,0 +1,40 @@
{
"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"
}

21
android/app/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,26 @@
package com.getcapacitor.myapp;
import static org.junit.Assert.*;
import android.content.Context;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.getcapacitor.app", appContext.getPackageName());
}
}

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:name=".MainActivity"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBarLaunch"
android:launchMode="singleTask"
android:exported="true">
<tools:validation testUrl="https://contexted.app" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="contexted.app" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"></meta-data>
</provider>
</application>
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

View File

@@ -0,0 +1,5 @@
package com.contexted.app;
import com.getcapacitor.BridgeActivity;
public class MainActivity extends BridgeActivity {}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#26A69A"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<WebView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

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

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="app_name">Contexted</string>
<string name="title_activity_main">Contexted</string>
<string name="package_name">com.contexted.app</string>
<string name="custom_url_scheme">com.contexted.app</string>
</resources>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:background">@null</item>
</style>
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
<item name="android:background">@drawable/splash</item>
</style>
</resources>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="." />
<cache-path name="my_cache_images" path="." />
</paths>

View File

@@ -0,0 +1,18 @@
package com.getcapacitor.myapp;
import static org.junit.Assert.*;
import org.junit.Test;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}

29
android/build.gradle Normal file
View File

@@ -0,0 +1,29 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.0.0'
classpath 'com.google.gms:google-services:4.3.15'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
apply from: "variables.gradle"
allprojects {
repositories {
google()
mavenCentral()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@@ -0,0 +1,18 @@
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
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')
include ':capacitor-haptics'
project(':capacitor-haptics').projectDir = new File('../node_modules/@capacitor/haptics/android')
include ':capacitor-keyboard'
project(':capacitor-keyboard').projectDir = new File('../node_modules/@capacitor/keyboard/android')
include ':capacitor-status-bar'
project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android')

22
android/gradle.properties Normal file
View File

@@ -0,0 +1,22 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true

Binary file not shown.

View File

@@ -0,0 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-all.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

244
android/gradlew vendored Executable file
View File

@@ -0,0 +1,244 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

92
android/gradlew.bat vendored Normal file
View File

@@ -0,0 +1,92 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

5
android/settings.gradle Normal file
View File

@@ -0,0 +1,5 @@
include ':app'
include ':capacitor-cordova-android-plugins'
project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/')
apply from: 'capacitor.settings.gradle'

17
android/variables.gradle Normal file
View File

@@ -0,0 +1,17 @@
ext {
minSdkVersion = 22
compileSdkVersion = 33
targetSdkVersion = 33
androidxActivityVersion = '1.7.0'
androidxAppCompatVersion = '1.6.1'
androidxCoordinatorLayoutVersion = '1.2.0'
androidxCoreVersion = '1.10.0'
androidxFragmentVersion = '1.5.6'
coreSplashScreenVersion = '1.0.0'
androidxWebkitVersion = '1.6.1'
junitVersion = '4.13.2'
androidxJunitVersion = '1.1.5'
androidxEspressoCoreVersion = '3.5.1'
cordovaAndroidVersion = '10.1.1'
rgcfaIncludeGoogle = true
}

21
capacitor.config.ts Normal file
View File

@@ -0,0 +1,21 @@
import { CapacitorConfig } from '@capacitor/cli'
const config: CapacitorConfig = {
appId: 'com.contexted.app',
appName: 'Contexted',
webDir: 'dist',
server: {
androidScheme: 'https'
},
plugins: {
Keyboard: {
resize: 'native'
},
FirebaseAuthentication: {
skipNativeAuth: false,
providers: ['google.com']
}
}
}
export default config

34
components.d.ts vendored
View File

@@ -9,19 +9,43 @@ export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
Autocomplete: typeof import('./src/components/Autocomplete.vue')['default']
Hamburger: typeof import('./src/components/Hamburger.vue')['default']
Logo: typeof import('./src/components/Logo.vue')['default']
Modal: typeof import('./src/components/Modal.vue')['default']
Note: typeof import('./src/components/Note.vue')['default']
AccountSettings: typeof import('./src/components/TopBar/Settings/AccountSettings.vue')['default']
Auth: typeof import('./src/components/Auth.vue')['default']
Autocomplete: typeof import('./src/components/Note/Autocomplete.vue')['default']
Hamburger: typeof import('./src/components/TopBar/Hamburger.vue')['default']
ListView: typeof import('./src/components/ViewModes/ListView.vue')['default']
Logo: typeof import('./src/components/TopBar/Logo.vue')['default']
Mindmap: typeof import('./src/components/ViewModes/Mindmap.vue')['default']
Note: typeof import('./src/components/ViewModes/Note.vue')['default']
NoteEditor: typeof import('./src/components/Note/NoteEditor.vue')['default']
NoteReferences: typeof import('./src/components/Note/NoteReferences.vue')['default']
NotesSourceSwitcher: typeof import('./src/components/TopBar/Settings/NotesSourceSwitcher.vue')['default']
NoteToolbar: typeof import('./src/components/Note/NoteToolbar.vue')['default']
SearchBar: typeof import('./src/components/Search/SearchBar.vue')['default']
SearchResult: typeof import('./src/components/Search/SearchResult.vue')['default']
Settings: typeof import('./src/components/TopBar/Settings.vue')['default']
SideBar: typeof import('./src/components/SideBar.vue')['default']
SideBarMenu: typeof import('./src/components/SideBar/SideBarMenu.vue')['default']
SideBarMenuItem: typeof import('./src/components/SideBar/SideBarMenuItem.vue')['default']
SignOut: typeof import('./src/components/TopBar/Settings/SignOut.vue')['default']
SkeletonNote: typeof import('./src/components/Skeleton/SkeletonNote.vue')['default']
SkeletonSidebarItem: typeof import('./src/components/Skeleton/SkeletonSidebarItem.vue')['default']
SkeletonTopBar: typeof import('./src/components/Skeleton/SkeletonTopBar.vue')['default']
TopBar: typeof import('./src/components/TopBar.vue')['default']
UIAlert: typeof import('./src/components/ui/UIAlert.vue')['default']
UIBadge: typeof import('./src/components/ui/UIBadge.vue')['default']
UIButton: typeof import('./src/components/ui/UIButton.vue')['default']
UIButtonGroup: typeof import('./src/components/ui/UIButtonGroup.vue')['default']
UICard: typeof import('./src/components/ui/UICard.vue')['default']
UIDropdown: typeof import('./src/components/ui/UIDropdown.vue')['default']
UIDropdownItem: typeof import('./src/components/ui/UIDropdownItem.vue')['default']
UIInputCheckbox: typeof import('./src/components/ui/UIInputCheckbox.vue')['default']
UIInputText: typeof import('./src/components/ui/UIInputText.vue')['default']
UIMenu: typeof import('./src/components/ui/UIMenu.vue')['default']
UIMenuItem: typeof import('./src/components/ui/UIMenuItem.vue')['default']
UIModal: typeof import('./src/components/ui/UIModal.vue')['default']
UITab: typeof import('./src/components/ui/UITab.vue')['default']
UITable: typeof import('./src/components/ui/UITable.vue')['default']
UITabs: typeof import('./src/components/ui/UITabs.vue')['default']
}
}

17
firebase.json Normal file
View File

@@ -0,0 +1,17 @@
{
"hosting": {
"target": "contexted-v3",
"public": "dist",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}

View File

@@ -2,12 +2,12 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/x-icon" href="/favicon-dark.ico" />
<meta name="viewport" content="width=device-width,initial-scale=1.0,viewport-fit=cover,maximum-scale=1.0,user-scalable=no" />
<title>Contexted</title>
</head>
<body>
<div id="app" class="bg-gray-100"></div>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

13
ios/.gitignore vendored Normal file
View File

@@ -0,0 +1,13 @@
App/build
App/Pods
App/output
App/App/public
DerivedData
xcuserdata
# Cordova plugins for Capacitor
capacitor-cordova-ios-plugins
# Generated Config files
App/App/capacitor.config.json
App/App/config.xml

View File

@@ -0,0 +1,406 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 48;
objects = {
/* Begin PBXBuildFile section */
2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; };
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
504EC30D1FED79650016851F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30B1FED79650016851F /* Main.storyboard */; };
504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; };
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 */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; };
504EC3041FED79650016851F /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; };
504EC3071FED79650016851F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
504EC30C1FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
504EC30E1FED79650016851F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; 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>"; };
50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; 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>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
504EC3011FED79650016851F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */ = {
isa = PBXGroup;
children = (
AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
504EC2FB1FED79650016851F = {
isa = PBXGroup;
children = (
504EC3061FED79650016851F /* App */,
504EC3051FED79650016851F /* Products */,
7F8756D8B27F46E3366F6CEA /* Pods */,
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */,
);
sourceTree = "<group>";
};
504EC3051FED79650016851F /* Products */ = {
isa = PBXGroup;
children = (
504EC3041FED79650016851F /* App.app */,
);
name = Products;
sourceTree = "<group>";
};
504EC3061FED79650016851F /* App */ = {
isa = PBXGroup;
children = (
50379B222058CBB4000EE86E /* capacitor.config.json */,
504EC3071FED79650016851F /* AppDelegate.swift */,
504EC30B1FED79650016851F /* Main.storyboard */,
504EC30E1FED79650016851F /* Assets.xcassets */,
504EC3101FED79650016851F /* LaunchScreen.storyboard */,
504EC3131FED79650016851F /* Info.plist */,
2FAD9762203C412B000D30F8 /* config.xml */,
50B271D01FEDC1A000F3C39B /* public */,
);
path = App;
sourceTree = "<group>";
};
7F8756D8B27F46E3366F6CEA /* Pods */ = {
isa = PBXGroup;
children = (
FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */,
AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
504EC3031FED79650016851F /* App */ = {
isa = PBXNativeTarget;
buildConfigurationList = 504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */;
buildPhases = (
6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */,
504EC3001FED79650016851F /* Sources */,
504EC3011FED79650016851F /* Frameworks */,
504EC3021FED79650016851F /* Resources */,
9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = App;
productName = App;
productReference = 504EC3041FED79650016851F /* App.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
504EC2FC1FED79650016851F /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 0920;
TargetAttributes = {
504EC3031FED79650016851F = {
CreatedOnToolsVersion = 9.2;
LastSwiftMigration = 1100;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */;
compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 504EC2FB1FED79650016851F;
productRefGroup = 504EC3051FED79650016851F /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
504EC3031FED79650016851F /* App */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
504EC3021FED79650016851F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */,
50B271D11FEDC1A000F3C39B /* public in Resources */,
504EC30F1FED79650016851F /* Assets.xcassets in Resources */,
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
504EC30D1FED79650016851F /* Main.storyboard in Resources */,
2FAD9763203C412B000D30F8 /* config.xml in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-App-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App/Pods-App-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
504EC3001FED79650016851F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
504EC3081FED79650016851F /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
504EC30B1FED79650016851F /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
504EC30C1FED79650016851F /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
504EC3101FED79650016851F /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
504EC3111FED79650016851F /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
504EC3141FED79650016851F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
504EC3151FED79650016851F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
504EC3171FED79650016851F /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = com.contexted.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
504EC3181FED79650016851F /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.contexted.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */ = {
isa = XCConfigurationList;
buildConfigurations = (
504EC3141FED79650016851F /* Debug */,
504EC3151FED79650016851F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */ = {
isa = XCConfigurationList;
buildConfigurations = (
504EC3171FED79650016851F /* Debug */,
504EC3181FED79650016851F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 504EC2FC1FED79650016851F /* Project object */;
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:App.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:App.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,8 @@
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,49 @@
import UIKit
import Capacitor
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
// Called when the app was launched with a url. Feel free to add additional processing here,
// but if you want the App API to support tracking app url opens, make sure to keep this call
return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
// Called when the app was launched with an activity, including Universal Links.
// Feel free to add additional processing here, but if you want the App API to support
// tracking app url opens, make sure to keep this call
return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

View File

@@ -0,0 +1,14 @@
{
"images" : [
{
"filename" : "AppIcon-512@2x.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "splash-2732x2732-2.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "splash-2732x2732-1.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "splash-2732x2732.png",
"scale" : "3x"
}
],
"info" : {
"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

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17132" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17105"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<imageView key="view" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Splash" id="snD-IY-ifK">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</imageView>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="Splash" width="1366" height="1366"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14111" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
</dependencies>
<scenes>
<!--Bridge View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="CAPBridgeViewController" customModule="Capacitor" sceneMemberID="viewController"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

49
ios/App/App/Info.plist Normal file
View File

@@ -0,0 +1,49 @@
<?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>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>Contexted</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
</dict>
</plist>

41
ios/App/Podfile Normal file
View File

@@ -0,0 +1,41 @@
require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
platform :ios, '13.0'
use_frameworks!
# workaround to avoid Xcode caching of Pods that requires
# Product -> Clean Build Folder after new Cordova plugins installed
# Requires CocoaPods 1.6 or newer
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 '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)
end
post_install do |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

46
ios/App/Podfile.lock Normal file
View File

@@ -0,0 +1,46 @@
PODS:
- Capacitor (5.0.4):
- CapacitorCordova
- CapacitorCordova (5.0.4)
- CapacitorDialog (5.0.2):
- Capacitor
- CapacitorHaptics (5.0.2):
- Capacitor
- CapacitorKeyboard (5.0.2):
- Capacitor
- CapacitorStatusBar (5.0.2):
- Capacitor
DEPENDENCIES:
- "Capacitor (from `../../node_modules/@capacitor/ios`)"
- "CapacitorCordova (from `../../node_modules/@capacitor/ios`)"
- "CapacitorDialog (from `../../node_modules/@capacitor/dialog`)"
- "CapacitorHaptics (from `../../node_modules/@capacitor/haptics`)"
- "CapacitorKeyboard (from `../../node_modules/@capacitor/keyboard`)"
- "CapacitorStatusBar (from `../../node_modules/@capacitor/status-bar`)"
EXTERNAL SOURCES:
Capacitor:
:path: "../../node_modules/@capacitor/ios"
CapacitorCordova:
:path: "../../node_modules/@capacitor/ios"
CapacitorDialog:
:path: "../../node_modules/@capacitor/dialog"
CapacitorHaptics:
:path: "../../node_modules/@capacitor/haptics"
CapacitorKeyboard:
:path: "../../node_modules/@capacitor/keyboard"
CapacitorStatusBar:
:path: "../../node_modules/@capacitor/status-bar"
SPEC CHECKSUMS:
Capacitor: d3d4463573438b9fa65326d1f3549da6f4c21634
CapacitorCordova: b1fe6bf1f36974a8e4a9044b342d22d49c0996d6
CapacitorDialog: 01c49f7f4b37e7ad59e38fd317a6e5f006f23cdc
CapacitorHaptics: 864585542a435bd41eaabf7f30d9ff5ec03024d3
CapacitorKeyboard: e628d4e66d621c69e449945ebabded17c5b9c2e8
CapacitorStatusBar: 48f2899f6846cc7d8431b251ebfc58e1c10e3d58
PODFILE CHECKSUM: b469cdc64593e190968b9aa15066224f10938107
COCOAPODS: 1.12.1

17163
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,28 @@
{
"name": "contexted-v3",
"private": true,
"version": "0.0.0",
"version": "0.1.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview"
"build": "run-p type-check build-only",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false",
"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/status-bar": "^5.0.2",
"@ckeditor/ckeditor5-autoformat": "^37.1.0",
"@ckeditor/ckeditor5-basic-styles": "^37.1.0",
"@ckeditor/ckeditor5-editor-balloon": "^37.1.0",
@@ -21,27 +35,48 @@
"@ckeditor/vite-plugin-ckeditor5": "^0.1.1",
"@fontsource/source-sans-pro": "^4.5.11",
"@fortawesome/fontawesome-free": "^6.4.0",
"@types/cytoscape": "^3.19.9",
"@types/marked": "^4.0.8",
"@vueuse/components": "^10.1.0",
"@vueuse/core": "^10.1.2",
"daisyui": "^2.51.6",
"crypto-js": "^4.1.1",
"cytoscape": "^3.25.0",
"daisyui": "^3.0.3",
"date-fns": "^2.29.3",
"dompurify": "^3.0.2",
"firebase": "^9.20.0",
"file-saver": "^2.0.5",
"firebase": "^9.22.0",
"firebaseui": "^6.0.2",
"hamburgers": "^1.2.1",
"jszip": "^3.10.1",
"lodash-es": "^4.17.21",
"marked": "^4.3.0",
"shortid": "^2.2.16",
"turndown": "^7.1.2",
"vue": "^3.3.1"
"vue": "^3.3.4",
"vue-virtual-scroller": "^2.0.0-beta.8"
},
"devDependencies": {
"@capacitor/cli": "^5.0.4",
"@rushstack/eslint-patch": "^1.2.0",
"@tailwindcss/typography": "^0.5.9",
"@tsconfig/node18": "^2.0.1",
"@types/crypto-js": "^4.1.1",
"@types/dompurify": "^3.0.2",
"@types/file-saver": "^2.0.5",
"@types/lodash-es": "^4.17.7",
"@types/node": "^20.2.1",
"@types/shortid": "^0.0.29",
"@types/turndown": "^5.0.1",
"@vitejs/plugin-vue": "^4.2.2",
"@vitejs/plugin-vue": "^4.2.3",
"@vue/eslint-config-prettier": "^7.1.0",
"@vue/eslint-config-typescript": "^11.0.3",
"@vue/tsconfig": "^0.4.0",
"autoprefixer": "^10.4.14",
"eslint": "^8.40.0",
"eslint-plugin-vue": "^9.13.0",
"firebase-tools": "^12.1.0",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.23",
"prettier": "^2.8.8",
"prettier-plugin-tailwindcss": "^0.2.8",
@@ -50,7 +85,7 @@
"typescript": "^5.0.2",
"unplugin-auto-import": "^0.15.3",
"unplugin-vue-components": "^0.24.1",
"vite": "^4.3.5",
"vite": "^4.3.8",
"vue-tsc": "^1.6.4"
}
}

View File

@@ -1,4 +1,5 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},

View File

@@ -0,0 +1,9 @@
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.contexted.app",
"sha256_cert_fingerprints":
["42:56:8A:D7:2C:F0:BE:28:E4:C2:CB:A7:C0:D1:4B:00:88:70:95:C7:C6:BF:7D:AA:61:D8:A0:59:94:25:63:1A"]
}
}]

BIN
public/contexted-black.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/contexted-blue.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/contexted-white.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,32 +1,148 @@
<script setup lang="ts">
import { activeNote, updateNote } from '@/composables/useNotes'
import { activeNote, updateNote, notes, activeNotesSource, getNotes } from '@/composables/useNotes'
import { viewModes, activeViewMode } from '@/composables/useViewMode'
const sideBarCollapsed = ref(false)
import {
getClientKey,
getEncryptionKey,
encryptionKey,
setClientKey,
passphraseRequired
} from '@/composables/useEncryption'
import { initializeSettings } from '@/composables/useSettings'
import { windowIsMobile } from '@/utils/helpers'
import SideBar from '@/components/SideBar.vue'
import { useWindowSize } from '@vueuse/core'
initializeSettings()
const sideBarCollapsed = ref<boolean>(windowIsMobile())
const { width } = useWindowSize()
watch(width, () => (sideBarCollapsed.value = windowIsMobile()))
// const Note = defineAsyncComponent(() => import('@/components/ViewModes/Note.vue'))
// 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)
watch(
[activeNotesSource, encryptionKey],
() => {
if (activeNotesSource.value === 'firebase') {
getClientKey()
getEncryptionKey()
}
getNotes()
},
{ immediate: true }
)
const passphrase = ref('')
const passphraseValid = ref<boolean>()
const submitPassphrase = (close: () => void) => {
const setClientKeyResult = setClientKey(passphrase.value)
passphraseValid.value = setClientKeyResult
if (passphraseValid.value) close()
}
const loading = computed(
() => notes.value.length === 0 || passphraseRequired.value || !activeNotesSource.value
)
provide('loading', loading)
const topBarHeight = 52
const topBarHeightWithSafeArea = computed(() => `calc(${topBarHeight}px + var(--safe-area-top))`)
</script>
<template>
<TopBar
:side-bar-collapsed="sideBarCollapsed"
:height="topBarHeight"
:style="{ height: topBarHeightWithSafeArea }"
@toggle-side-bar="sideBarCollapsed = !sideBarCollapsed"
class="pe-[var(--safe-area-right)] ps-[var(--safe-area-left)]"
/>
<div class="relative mx-auto flex h-full max-w-app">
<SideBar
:view-modes="viewModes"
:active-view-mode="activeViewMode"
@set-view-mode="(viewMode) => (activeViewMode = viewMode)"
class="mt-[50px] px-3 py-6"
/>
<main
class="transition[margin-left] absolute bottom-0 left-0 right-0 top-[50px] flex overflow-hidden border-x-[1px] bg-white px-10 py-6 duration-200 ease-out"
:class="sideBarCollapsed ? 'ml-0' : 'ml-sidebar'"
>
<Note
v-if="activeNote"
:key="activeNote.id"
:note="activeNote"
class="w-full"
@update="(note) => updateNote(note.id, note)"
<!-- <div class="absolute bottom-0 left-0 right-0 top-[50px] mx-auto flex flex-grow"> -->
<div
class="mx-auto flex w-full max-w-app flex-grow pe-[var(--safe-area-right)] ps-[var(--safe-area-left)]"
>
<Transition name="sidebar">
<SideBar
:view-modes="viewModes"
:active-view-mode="activeViewMode"
@set-view-mode="(viewMode) => (activeViewMode = viewMode)"
@collapse="(collapse) => (sideBarCollapsed = collapse)"
class="bg-gray-100 px-3 py-6 transition-[width] delay-200 duration-0 max-sm:z-50 max-sm:border-x-[1px] max-sm:py-3 max-sm:transition-transform max-sm:delay-0 max-sm:duration-200"
:style="{ 'margin-top': topBarHeightWithSafeArea }"
v-if="!sideBarCollapsed"
/>
</Transition>
<Transition name="overlay">
<div
class="absolute bottom-0 left-0 right-0 top-0 z-40 cursor-pointer bg-neutral-800 bg-opacity-60 transition-opacity duration-200 sm:hidden"
@click="sideBarCollapsed = true"
v-if="!sideBarCollapsed"
/>
</Transition>
<main
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 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"
:key="activeNote.id"
:note="activeNote"
class=""
@update="(note) => updateNote(note.id, note)"
/>
<ListView v-else-if="activeViewMode.name === 'List'" />
<Mindmap v-else-if="activeViewMode.name === 'Mindmap'" />
</template>
<SkeletonNote v-else />
</div>
</main>
</div>
<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.
</div>
<form @submit.prevent="submitPassphrase(close)">
<UIInputText
type="password"
class="w-full !max-w-full"
:color="passphraseValid === false ? 'error' : 'regular'"
v-model="passphrase"
></UIInputText>
</form>
<UIAlert color="error" class="mt-4" v-if="passphraseValid === false">
<i class="fa-solid fa-triangle-exclamation"></i>
The passphrase you entered is incorrect.
</UIAlert>
</template>
<template #actions="{ close }">
<UIButton color="primary" size="sm" @click="submitPassphrase(close)">Submit</UIButton>
</template>
</UIModal>
</template>
<style scoped>
.sidebar-enter-from,
.sidebar-leave-to {
@apply max-sm:-translate-x-full;
}
.overlay-enter-from,
.overlay-leave-to {
@apply opacity-0;
}
main {
contain: size layout style;
}
</style>

View File

@@ -24,7 +24,7 @@ export default defineComponent({
model: {
prop: 'modelValue',
event: 'update:modelValue',
event: 'update:modelValue'
},
props: {
@@ -32,28 +32,28 @@ export default defineComponent({
type: Function as unknown as PropType<{
create(...args: any): Promise<Editor>
}>,
required: true,
required: true
},
config: {
type: Object as PropType<EditorConfig>,
default: () => ({}),
default: () => ({})
},
modelValue: {
type: String,
default: '',
default: ''
},
tagName: {
type: String,
default: 'div',
default: 'div'
},
disabled: {
type: Boolean,
default: false,
default: false
},
disableTwoWayDataBinding: {
type: Boolean,
default: false,
},
default: false
}
},
emits: [
@@ -66,7 +66,7 @@ export default defineComponent({
'click',
'editorReady',
'contextedLinkAutocomplete',
'contextedKeypress',
'contextedKeypress'
],
data(): CKEditorComponentData {
@@ -74,7 +74,7 @@ export default defineComponent({
// Don't define it in #props because it produces a warning.
// https://v3.vuejs.org/guide/component-props.html#one-way-data-flow
instance: null,
lastEditorData: null,
lastEditorData: null
}
},
@@ -114,7 +114,7 @@ export default defineComponent({
} else {
this.instance!.disableReadOnlyMode(SAMPLE_READ_ONLY_LOCK_ID)
}
},
}
},
created() {
@@ -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.')
@@ -233,10 +231,10 @@ export default defineComponent({
editor.model.document.on('contextedKeypress', (_, eventData) => {
this.$emit('contextedKeypress', eventData)
})
},
}
},
render() {
return h(this.tagName)
},
}
})

View File

@@ -13,10 +13,7 @@ export default class ContextedLinkEditing extends Plugin {
const twoStepCaretMovementPlugin = this.editor.plugins.get(TwoStepCaretMovement)
twoStepCaretMovementPlugin.registerAttribute('contextedLink')
inlineHighlight(this.editor, 'contextedLink', 'a', HIGHLIGHT_CLASS)
this.editor.commands.add(
'autocomplete',
new AttributeCommand(this.editor, 'autocomplete')
)
this.editor.commands.add('autocomplete', new AttributeCommand(this.editor, 'autocomplete'))
}
afterInit() {
this._addAutocomplete()
@@ -27,7 +24,7 @@ export default class ContextedLinkEditing extends Plugin {
// Extend the text node's schema to accept the abbreviation attribute.
schema.extend('$text', {
allowAttributes: ['contextedLink', 'autocomplete'],
allowAttributes: ['contextedLink', 'autocomplete']
})
}
_defineConverters() {
@@ -43,19 +40,19 @@ export default class ContextedLinkEditing extends Plugin {
const { writer } = conversionApi
return writer.createAttributeElement('a', {
'data-contexted-link': modelAttributeValue,
'data-contexted-link': modelAttributeValue
})
},
}
})
conversion.for('upcast').elementToAttribute({
view: {
name: 'a',
key: 'data-contexted-link',
key: 'data-contexted-link'
},
model: {
key: 'contextedLink',
key: 'contextedLink'
},
converterPriority: 'high',
converterPriority: 'high'
})
}
_addAutocomplete() {
@@ -83,17 +80,15 @@ export default class ContextedLinkEditing extends Plugin {
const focus = selection.focus
const block = focus?.parent
if (!block || !focus) return
const { text } = getTextAfterCode(
const { text, range } = getTextAfterCode(
model.createRange(model.createPositionAt(block, 0), focus),
model
)
const inputText = (text as string).split(']]').at(-1)
const inputText = (text as string).split(']]').slice(-1)[0]
const autocompleteText = (inputText as string).match(/(?<=\[\[).*/g)
const cursorNodes = [focus.textNode, focus.nodeBefore, focus.nodeAfter]
const autocompleteNode: any = cursorNodes.find((node) =>
['contextedLink', 'autocomplete'].some((attribute) =>
node?.hasAttribute(attribute)
)
['contextedLink', 'autocomplete'].some((attribute) => node?.hasAttribute(attribute))
)
if (Boolean(autocompleteText) !== Boolean(autocompleteNode)) {
@@ -104,6 +99,35 @@ export default class ContextedLinkEditing extends Plugin {
})
showAutocomplete = autocompleteActive
fireAutocompleteEvent(editor, showAutocomplete, autocompleteNode)
const regexFormat = /(\[\[)([^[]+?)(\]\])$/g
let result
const format: Array<number>[] = []
while ((result = regexFormat.exec(text as string)) !== null) {
if (result && result.length < 4) {
break
}
let index = result.index
const { '1': leftDel, '2': content, '3': rightDel } = result
// Real matched string - there might be some non-capturing groups so we need to recalculate starting index.
const found = leftDel + content + rightDel
index += result[0].length - found.length
format.push([index + leftDel.length, index + leftDel.length + content.length])
}
model.enqueueChange((writer) => {
const rangesToFormat = format.map((array) =>
model.createRange(range.start.getShiftedBy(array[0]), range.start.getShiftedBy(array[1]))
)
const validRanges = editor.model.schema.getValidRanges(rangesToFormat, 'contextedLink')
for (const range of validRanges) {
for (const item of range.getItems()) {
if ((item as any).data) {
writer.setAttribute('contextedLink', true, range)
}
}
}
})
})
}
_addContextedKeyHandler() {
@@ -121,15 +145,15 @@ 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')) {
const autocompleteNode = [
selection.focus?.nodeBefore,
selection.focus?.textNode,
selection.focus?.nodeAfter,
selection.focus?.nodeAfter
].find((node) => Boolean(node))
fireAutocompleteEvent(editor, true, autocompleteNode)
}
@@ -149,9 +173,7 @@ function getNodePosition(editor: any, modelPosition: any) {
const viewPosition = mapper.toViewPosition(modelPosition)
const viewRange = editor.editing.view.createRange(viewPosition)
const domConverter = editor.editing.view.domConverter
const rangeRects = Rect.getDomRangeRects(
domConverter.viewRangeToDom(viewRange)
).pop()
const rangeRects = Rect.getDomRangeRects(domConverter.viewRangeToDom(viewRange)).pop()
return rangeRects
} catch (e) {
console.log(e)
@@ -194,18 +216,15 @@ 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,
show: true,
show: true
}
} else {
event = {
show: false,
show: false
}
}
editor.model.document.fire('contextedLinkAutocomplete', event)

137
src/components/Auth.vue Normal file
View File

@@ -0,0 +1,137 @@
<script setup lang="ts">
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,
OAuthProvider,
signInWithCredential,
} from 'firebase/auth'
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 uiConfig = {
signInOptions: [
firebase.auth.EmailAuthProvider.PROVIDER_ID
// firebase.auth.GoogleAuthProvider.PROVIDER_ID
],
// signInFlow: 'popup',
signInFlow: 'redirect',
callbacks: {
signInSuccessWithAuthResult(authResult: any) {
// var user = authResult.user
// var credential = authResult.credential
// var isNewUser = authResult.additionalUserInfo.isNewUser
// var providerId = authResult.additionalUserInfo.providerId
// var operationType = authResult.operationType
// Do something with the returned AuthResult.
// Return type determines whether we continue the redirect
// automatically or whether we leave that to developer to handle.
emit('signedIn', authResult)
return false
},
signInFailure(error: any) {
console.error('Error signing in', error)
}
}
// Other config options...
}
// onMounted(() => ui.start('#auth', uiConfig))
interface Provider {
name: 'google' | 'microsoft' | 'github'
icon: string
signin: () => Promise<void>
// (options?: SignInOptions) => Promise<SignInResult>
}
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 signingInWithEmail = ref(false)
const signInWithEmail = () => {
firebaseAuthUI.start('#auth', uiConfig)
signingInWithEmail.value = true
}
</script>
<template>
<div class="space-y-2">
<template v-if="!signingInWithEmail">
<UIButton
class="mx-auto block w-[225px]"
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 class="mx-auto block w-[225px]" size="sm" @click="signInWithEmail">
<i class="fa-fw fa-regular fa-envelope mr-2"></i>
Sign in with email
</UIButton>
</template>
<div id="auth"></div>
<!-- <progress
v-show="props.authenticating"
class="dui-progress dui-progress-primary w-full"
></progress> -->
</div>
</template>

View File

@@ -1,120 +0,0 @@
<script setup lang="ts">
const props = defineProps<{
sideBarCollapsed: boolean
}>()
const emit = defineEmits<{
toggleSideBar: []
}>()
</script>
<template>
<label class="swap-rotate swap btn-ghost btn-sm btn-circle btn">
<input
type="checkbox"
@click="emit('toggleSideBar')"
:checked="!props.sideBarCollapsed"
/>
<svg
class="swap-off fill-current"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 512 512"
>
<path d="M64,384H448V341.33H64Zm0-106.67H448V234.67H64ZM64,128v42.67H448V128Z" />
</svg>
<svg
class="swap-on fill-current"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 512 512"
>
<polygon
points="400 145.49 366.51 112 256 222.51 145.49 112 112 145.49 222.51 256 112 366.51 145.49 400 256 289.49 366.51 400 400 366.51 289.49 256 400 145.49"
/>
</svg>
</label>
</template>
<style scoped lang="scss">
.swap > * {
transition-duration: 0.2s;
}
</style>
<!--
$hamburger-layer-color: white;
$hamburger-layer-width: 25px;
$hamburger-layer-height: 3px;
$hamburger-layer-spacing: 3px;
$hamburger-padding-x: 0px;
$hamburger-padding-y: 0px;
$hamburger-scale-speed: calc(200ms / 0.22s);
@import 'hamburgers/_sass/hamburgers/hamburgers.scss';
@if index($hamburger-types, spin-r) {
/*
* Spin Reverse
*/
.hamburger--spin-r {
.hamburger-inner {
transition-duration: ($hamburger-scale-speed * 0.22s);
transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
&::before {
transition: top
($hamburger-scale-speed * 0.1s)
($hamburger-scale-speed * 0.25s)
ease-in,
opacity ($hamburger-scale-speed * 0.1s) ease-in;
}
&::after {
transition: bottom
($hamburger-scale-speed * 0.1s)
($hamburger-scale-speed * 0.25s)
ease-in,
transform
($hamburger-scale-speed * 0.22s)
cubic-bezier(0.55, 0.055, 0.675, 0.19);
}
}
&.is-active {
.hamburger-inner {
transform: rotate(-225deg);
transition-delay: ($hamburger-scale-speed * 0.12s);
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
&::before {
top: 0;
opacity: 0;
transition: top ($hamburger-scale-speed * 0.1s) ease-out,
opacity
($hamburger-scale-speed * 0.1s)
($hamburger-scale-speed * 0.12s)
ease-out;
}
&::after {
bottom: 0;
transform: rotate(90deg);
transition: bottom ($hamburger-scale-speed * 0.1s) ease-out,
transform
($hamburger-scale-speed * 0.22s)
($hamburger-scale-speed * 0.12s)
cubic-bezier(0.215, 0.61, 0.355, 1);
}
}
}
}
}
button.hamburger {
outline: none !important;
line-height: 1;
opacity: 0.9;
border-radius: 2rem;
}
.hamburger-box {
display: block;
}
</style> -->

View File

@@ -1,55 +0,0 @@
<script setup lang="ts">
import { onClickOutside } from '@vueuse/core'
const modal = ref<HTMLElement | null>(null)
const modalBox = ref(null)
const show = ref(false)
const open = () => (show.value = true)
const close = async () => {
return new Promise((resolve) => {
modal.value?.addEventListener('transitionend', () => resolve(true))
show.value = false
// nextTick(() => {
// console.log('done!')
// resolve(true)
// })
})
}
const slotProps = { open, close }
onClickOutside(modalBox, () => close())
const onEnter = (el: Element, done: () => void): void => {
setTimeout(() => {
el.classList.add('modal-open')
done()
})
}
const onLeave = (el: Element, done: () => void): void => {
el.classList.remove('modal-open')
el.addEventListener('transitionend', () => done())
}
</script>
<template>
<slot name="activator" v-bind="slotProps"></slot>
<Teleport to="body">
<Transition @enter="onEnter" @leave="onLeave">
<div class="modal bg-neutral-800 bg-opacity-60" v-if="show" ref="modal">
<div class="modal-box" ref="modalBox">
<h3 class="text-lg font-bold" v-if="$slots.title"><slot name="title" /></h3>
<p class="py-4">
<slot />
</p>
<div class="modal-action">
<slot name="actions" v-bind="slotProps">
<button class="btn-sm btn" @click="close">Close</button>
</slot>
</div>
</div>
</div>
</Transition>
</Teleport>
</template>

View File

@@ -10,9 +10,9 @@ const emit = defineEmits<{
}>()
const results = computed<Note[]>(() => {
return (
props.autocompleteText ? findNotesByByTitle(props.autocompleteText) : notes.value
).filter((note) => note.id !== activeNote.value?.id)
return (props.autocompleteText ? findNotesByByTitle(props.autocompleteText) : notes.value)
.filter((note) => note.id !== activeNote.value?.id)
.slice(0, 10)
})
const activeResult = ref<Note>()
@@ -32,35 +32,30 @@ const handleKeypress = (event: { [key: string]: number }) => {
const keyCode = event.keyCode
const keyCodes = {
cycle: [38, 40],
confirm: [13],
confirm: [13]
}
if (keyCodes.cycle.includes(keyCode)) {
const direction = keyCode === 38 ? -1 : 1
changeActiveResult(direction)
} else if (keyCodes.confirm.includes(keyCode)) {
const contextedLink = activeResult.value
? activeResult.value.title
: props.autocompleteText
const contextedLink = activeResult.value ? activeResult.value.title : props.autocompleteText
emit('createLink', contextedLink)
}
}
defineExpose({ handleKeypress })
</script>
<template>
<ul
tabindex="0"
class="menu rounded-md border-[1px] bg-base-100 p-2 text-[0.875rem] text-black shadow-md"
>
<li class="flex flex-row">
<a class="flex-1 px-2 py-1" :class="!activeResult && 'active'">
<span class="flex-1">{{ props.autocompleteText }}</span>
<i class="fas fa-plus-circle ml-auto text-white" />
</a>
</li>
<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" />
</UIMenuItem>
<SearchResult
v-for="result in results"
:key="result.id"
:result="result"
:active-result="activeResult"
@go-to-note="emit('createLink', result.title)"
/>
</ul>
</UIMenu>
</template>

View File

@@ -13,8 +13,9 @@ import ListPlugin from '@ckeditor/ckeditor5-list/src/list'
import AutoformatPlugin from '@ckeditor/ckeditor5-autoformat/src/autoformat'
import ContextedPlugin from '@/ckeditor/ContextedPlugin'
import { mdToHtml, htmlToMd } from '@/utils/markdown'
import { getNoteByTitle, setActiveNote } from '@/composables/useNotes'
import Autocomplete from '@/components/Autocomplete.vue'
import { getNoteByTitle, setActiveNote, addNote } from '@/composables/useNotes'
import Autocomplete from '@/components/Note/Autocomplete.vue'
import { Haptics, ImpactStyle } from '@capacitor/haptics'
const props = defineProps<{ note: Note }>()
@@ -38,7 +39,7 @@ const editorConfig = {
ParagraphPlugin,
ListPlugin,
AutoformatPlugin,
ContextedPlugin,
ContextedPlugin
],
toolbar: {
items: [
@@ -51,27 +52,30 @@ const editorConfig = {
'redo',
'heading',
'bulletedList',
'numberedList',
],
'numberedList'
]
},
placeholder: 'Click here to start typing...',
placeholder: 'Click here to start typing...'
}
const editorElement = ref<HTMLInputElement | null>(null)
watch(editorData, () => emit('update', htmlToMd(editorData.value)))
let editorInstance: any
const handleClick = ({ data }: { data: any }) => {
const handleClick = async ({ data }: { data: any }) => {
if (!data.domTarget.hasAttribute('data-contexted-link')) return
const noteTitle = data.domTarget.textContent as string
const note = getNoteByTitle(noteTitle)
if (note) setActiveNote(note.id)
let note: BaseNote | Note | undefined = getNoteByTitle(noteTitle)
if (!note) note = addNote(noteTitle, '')
setActiveNote(note.id)
await Haptics.impact({ style: ImpactStyle.Light })
}
const autocompleteRef = ref<InstanceType<typeof Autocomplete> | null>(null)
const showAutocomplete = ref(false)
const autocompleteStyle = ref({})
const autocompleteText = ref('')
const autocompleteReverse = ref(false)
const showAutocomplete = ref<boolean>(false)
const autocompleteStyle = ref<{ [key: string]: any }>({})
const autocompleteText = ref<string>('')
const autocompleteReverse = ref<boolean>(false)
const handleAutocomplete = async (event: AutocompleteEvent) => {
const position = event.position
@@ -82,7 +86,7 @@ const handleAutocomplete = async (event: AutocompleteEvent) => {
)
autocompleteStyle.value = {
top: `${position.top - rect.top + lineHeight}px`,
left: `${position.left - rect.left}px`,
left: `${position.left - rect.left}px`
}
}
autocompleteText.value = event.autocompleteText || ''
@@ -97,12 +101,10 @@ const handleAutocomplete = async (event: AutocompleteEvent) => {
editorRect &&
autocompleteRect.bottom > editorRect.bottom
) {
const autocompleteHeight = parseFloat(
window.getComputedStyle(autocompleteElem).height
)
const autocompleteHeight = parseFloat(window.getComputedStyle(autocompleteElem).height)
autocompleteStyle.value = {
...autocompleteStyle.value,
top: `${position.top - editorRect.top - autocompleteHeight}px`,
top: `${position.top - editorRect.top - autocompleteHeight}px`
}
autocompleteReverse.value = true
} else {
@@ -117,54 +119,51 @@ const handleContextedKeypress = (event: any) => {
const createLink = (link: string) => {
if (!editor) return
const model = editorInstance.model
model.change((writer: any) => {
const currentPosition = model.document.selection.getFirstPosition()
// const node = [currentPosition.textNode, currentPosition.nodeBefore, currentPosition.nodeAfter]
// console.log(currentPosition, node)
// writer.insertText(link, currentPosition)
console.log(model.document.selection.getFirstPosition())
writer.insertText(
link,
{ contextedLink: true },
currentPosition.nodeBefore,
'after'
)
model.enqueueChange((writer: any) => {
// const { nextSibling } = contextedLinkTextNode
// if (!nextSibling || !nextSibling.data || !nextSibling.data.startsWith(']]'))
writer.insertText(']]', model.document.selection.getFirstPosition())
})
writer.remove(currentPosition.nodeBefore)
showAutocomplete.value = false
const getPosition = () => model.document.selection.anchor
// const getNodes = () => {
// const nodes = [
// getPosition().nodeBefore,
// getPosition().nodeAfter,
// getPosition().textNnode,
// ]
// return nodes.map((node) => ({
// data: node?.data,
// attrs: Array.from(node?.getAttributes() || []),
// }))
// }
// console.log(getNodes())
let nodeToRemove: any
if (getPosition().nodeBefore?.hasAttribute('autocomplete')) {
// Insert new link
nodeToRemove = getPosition().nodeBefore
} else if (getPosition().nodeBefore?.hasAttribute('contextedLink')) {
// Update existing link from end of existing link (backspace)
nodeToRemove = getPosition().nodeBefore
} else if (getPosition().textNode?.hasAttribute('contextedLink')) {
// Update existing link from middle of existing link
nodeToRemove = getPosition().textNode
} else if (getPosition().nodeAfter?.hasAttribute('contextedLink')) {
// Update existing link from beginning (delete)
nodeToRemove = getPosition().nodeAfter
}
// const node = [
// currentPosition.textNode,
// currentPosition.nodeBefore,
// currentPosition.nodeAfter,
// ].find(
// (node) =>
// node &&
// (node.hasAttribute('contextedLinkAutocomplete') ||
// node.hasAttribute('contextedLink'))
// )
// const contextedLinkTextNode = writer.createText(title, { contextedLink: true })
// writer.insert(contextedLinkTextNode, node, 'after')
// model.enqueueChange((writer) => {
// const { nextSibling } = contextedLinkTextNode
// if (!nextSibling || !nextSibling.data || !nextSibling.data.startsWith(']]'))
// writer.insertText(']]', model.document.selection.getFirstPosition())
// })
// if (node) writer.remove(node)
// writer.removeSelectionAttribute('contextedLink')
// writer.removeSelectionAttribute('contextedLinkAutocomplete')
// this.autocompleteText = null
model.change((writer: any) => {
if (nodeToRemove) writer.remove(nodeToRemove)
writer.insertText(link, { contextedLink: true }, getPosition(), 'after')
model.enqueueChange((writer: any) => {
const nodeAfter = getPosition().nodeAfter
if (!nodeAfter || (nodeAfter && !nodeAfter.data.startsWith(']]'))) {
writer.insertText(']]', model.document.selection.getFirstPosition())
}
})
showAutocomplete.value = false
})
}
</script>
<template>
<div class="relative" ref="editorElement">
<CKEditor
class="h-full text-[110%] font-light"
class="w-full flex-grow text-[110%] font-light"
:editor="editor"
v-model="editorData"
:config="editorConfig"
@@ -179,19 +178,8 @@ const createLink = (link: string) => {
:autocomplete-text="autocompleteText"
:style="autocompleteStyle"
@create-link="createLink"
class="absolute w-[250px]"
class="absolute w-[300px]"
:class="autocompleteReverse && 'flex-col-reverse'"
/>
</div>
</template>
<style>
.ck-content {
padding: 0 !important;
border: 0 !important;
outline: none !important;
box-shadow: none !important;
}
.ck-content a[data-contexted-link='true'] {
@apply cursor-pointer font-semibold text-primary hover:bg-gray-200;
}
</style>

View File

@@ -5,22 +5,18 @@ const props = defineProps<{
}>()
</script>
<template>
<div class="card mt-3 border-[1px]" v-if="props.references.length > 0">
<div class="card-body px-3 py-3">
<ul class="menu rounded-md">
<li class="menu-title !opacity-100">
<span class="card-title text-secondary">
References
<div class="badge-outline badge">{{ props.references.length }}</div>
</span>
</li>
<li v-for="reference in props.references">
<a class="rounded-md" @click="setActiveNote(reference.id)">
<i class="far fa-file-alt fa-fw" />
{{ reference.title }}
</a>
</li>
</ul>
</div>
</div>
<UIMenu class="mt-3 rounded-xl border-[1px] px-3 py-3" v-if="props.references.length > 0">
<UIMenuItem :title="true">
<span>References</span>
<UIBadge variant="outline" class="ml-2">{{ props.references.length }}</UIBadge>
</UIMenuItem>
<UIMenuItem
v-for="reference in props.references"
:key="reference.id"
@click="setActiveNote(reference.id)"
>
<i class="far fa-file-alt fa-fw" />
{{ reference.title }}
</UIMenuItem>
</UIMenu>
</template>

View File

@@ -1,50 +1,78 @@
<script setup lang="ts">
import { Capacitor } from '@capacitor/core'
import { Dialog } from '@capacitor/dialog'
import type { ConfirmOptions } from '@capacitor/dialog'
const props = defineProps<{
note: Note
}>()
type ActionKey = 'delete' | 'setRoot'
interface ModalOptions {
key: ActionKey
icon: string
confirmOptions: ConfirmOptions
}
const confirmModals: ModalOptions[] = [
{
key: 'delete',
icon: 'fas fa-fw fa-trash',
confirmOptions: {
title: 'Delete note',
message: 'Are you sure you want to delete this note?',
okButtonTitle: 'Delete note'
}
},
{
key: 'setRoot',
icon: 'fas fa-fw fa-sitemap',
confirmOptions: {
title: 'Set root note',
message: 'Are you sure you want to set this note as root note?',
okButtonTitle: 'Set note as root note'
}
}
]
const emit = defineEmits<{
delete: [close: () => void]
setRoot: [close: () => void]
execute: [actionType: ActionKey, close?: () => void]
}>()
const openModal = async (open: () => void, modal: ModalOptions) => {
if (['android', 'ios'].includes(Capacitor.getPlatform())) {
const { value: confirmed } = await Dialog.confirm(modal.confirmOptions)
if (confirmed) emit('execute', modal.key)
} else {
open()
}
}
</script>
<template>
<div class="mb-2 flex items-center">
<h1
class="mr-2 flex flex-1 items-center rounded-md pr-2 text-3xl font-semibold hover:bg-gray-200"
>
<div class="mb-2 flex items-center space-x-2">
<h1 class="flex flex-grow items-center rounded-md text-3xl font-semibold hover:bg-gray-200">
<slot name="title"></slot>
</h1>
<div class="btn-group flex items-center" v-if="!props.note.isRoot">
<Modal>
<UIButtonGroup class="flex items-center" v-if="!props.note.isRoot">
<UIModal v-for="confirmModal in confirmModals" :key="confirmModal.key">
<template #activator="{ open }">
<button class="btn-toolbar btn-sm btn" @click="open">
<i class="fas fa-fw fa-trash" />
</button>
<UIButton size="sm" @click="openModal(open, confirmModal)" :join="true">
<i :class="confirmModal.icon" />
</UIButton>
</template>
<template #default>Are you sure you want to delete this note?</template>
<template #title>
<i class="mr-2" :class="confirmModal.icon" />
{{ confirmModal.confirmOptions.title }}
</template>
<template #default>{{ confirmModal.confirmOptions.message }}</template>
<template #actions="{ close }">
<button class="btn-primary btn-sm btn mr-1" @click="emit('delete', close)">
Delete note
</button>
<button class="btn-sm btn" @click="close">Close</button>
<UIButton size="sm" @click="close">Cancel</UIButton>
<UIButton size="sm" color="primary" @click="emit('execute', confirmModal.key, close)">
{{ confirmModal.confirmOptions.okButtonTitle }}
</UIButton>
</template>
</Modal>
<Modal>
<template #activator="{ open }">
<button class="btn-toolbar btn-sm btn" @click="open">
<i class="fas fa-fw fa-sitemap" />
</button>
</template>
<template #default>
Are you sure you want to set this note as root note?
</template>
<template #actions="{ close }">
<button class="btn-primary btn-sm btn mr-1" @click="emit('setRoot', close)">
Set current note as root
</button>
<button class="btn-sm btn" @click="close">Close</button>
</template>
</Modal>
</div>
</UIModal>
</UIButtonGroup>
</div>
</template>

Some files were not shown because too many files have changed in this diff Show More