diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE.md rename to .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/screenshots/correction.png b/.github/screenshots/correction.png new file mode 100644 index 00000000..d86a446c Binary files /dev/null and b/.github/screenshots/correction.png differ diff --git a/.github/screenshots/definition.png b/.github/screenshots/definition.png new file mode 100644 index 00000000..8883f2a0 Binary files /dev/null and b/.github/screenshots/definition.png differ diff --git a/.github/screenshots/fr/correction.png b/.github/screenshots/fr/correction.png new file mode 100644 index 00000000..990a7291 Binary files /dev/null and b/.github/screenshots/fr/correction.png differ diff --git a/.github/screenshots/fr/definition.png b/.github/screenshots/fr/definition.png new file mode 100644 index 00000000..a801507b Binary files /dev/null and b/.github/screenshots/fr/definition.png differ diff --git a/.github/screenshots/fr/header.png b/.github/screenshots/fr/header.png new file mode 100644 index 00000000..1db1bf3c Binary files /dev/null and b/.github/screenshots/fr/header.png differ diff --git a/.github/screenshots/fr/home.png b/.github/screenshots/fr/home.png new file mode 100644 index 00000000..3702411c Binary files /dev/null and b/.github/screenshots/fr/home.png differ diff --git a/.github/screenshots/fr/settings.png b/.github/screenshots/fr/settings.png new file mode 100644 index 00000000..634732e6 Binary files /dev/null and b/.github/screenshots/fr/settings.png differ diff --git a/.github/screenshots/header.png b/.github/screenshots/header.png new file mode 100644 index 00000000..335e3a2a Binary files /dev/null and b/.github/screenshots/header.png differ diff --git a/.github/screenshots/home.png b/.github/screenshots/home.png new file mode 100644 index 00000000..42382af9 Binary files /dev/null and b/.github/screenshots/home.png differ diff --git a/.github/screenshots/settings.png b/.github/screenshots/settings.png new file mode 100644 index 00000000..4f9ff502 Binary files /dev/null and b/.github/screenshots/settings.png differ diff --git a/.github/workflows/build.desktop.yml b/.github/workflows/build.desktop.yml new file mode 100644 index 00000000..c6d7d754 --- /dev/null +++ b/.github/workflows/build.desktop.yml @@ -0,0 +1,127 @@ +name: 'Build Remède desktop applications' + +on: + push: + branches: + - dev + +jobs: + publish-tauri: + permissions: + contents: write + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: + - platform: 'macos-latest' # for Arm based macs (M1 and above). + args: '--target aarch64-apple-darwin' + - platform: 'macos-latest' # for Intel based macs. + args: '--target x86_64-apple-darwin' + - platform: 'ubuntu-22.04' # for Tauri v1 you could replace this with ubuntu-20.04. + args: '' + - platform: 'windows-latest' + args: '' + + runs-on: ${{ matrix.platform }} + steps: + - uses: actions/checkout@v4 + - name: Install dependencies (ubuntu only) + if: matrix.platform == 'ubuntu-22.04' # This must match the platform value defined above. + run: | + sudo apt-get update + sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf + # webkitgtk 4.0 is for Tauri v1 - webkitgtk 4.1 is for Tauri v2. + + # You can remove the one that doesn't apply to your app to speed up the workflow a bit. + + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: 18 + cache: 'npm' # Set this to npm, yarn or pnpm. + cache-dependency-path: app/package-lock.json + + - name: Install Rust stable + uses: dtolnay/rust-toolchain@stable + with: + # Those targets are only used on macos runners so it's in an `if` to slightly speed up windows and linux builds. + targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }} + + - name: Rust cache + uses: swatinem/rust-cache@v2 + with: + workspaces: './src-tauri -> target' + + - name: Install frontend dependencies + # If you don't have `beforeBuildCommand` configured you may want to build your frontend here too. + working-directory: ./app + run: npm install # change this to npm or pnpm depending on which one you use. + + # Additional windows configuration options + - uses: actions/setup-python@v5 + if: matrix.platform == 'windows-latest' + with: + python-version: '3.10' + - name: Make configuration changes for windows + if: matrix.platform == 'windows-latest' + run: | + python app/src-tauri/windows_conf.py + + - uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tagName: __VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version. + releaseName: '__VERSION__' + releaseBody: '## `__VERSION__`: Unknown Codename + Quick description... + ## Associated issues + - [ ] + ' + releaseDraft: true + prerelease: false + projectPath: ./app + args: ${{ matrix.args }} + + - name: Copy DEB binary + if: matrix.platform == 'ubuntu-22.04' + run: cp /home/runner/work/remede/remede/app/src-tauri/target/release/bundle/deb/*.deb /home/runner/work/remede/remede/builds/remede.deb + + - name: Copy x64 DMG binary + if: matrix.platform == 'macos-latest' && matrix.args == '--target x86_64-apple-darwin' + run: | + cp /Users/runner/work/remede/remede/app/src-tauri/target/x86_64-apple-darwin/release/bundle/macos/*.app.tar.gz /Users/runner/work/remede/remede/builds/remede.x64.app.tar.gz + cp /Users/runner/work/remede/remede/app/src-tauri/target/x86_64-apple-darwin/release/bundle/dmg/*.dmg /Users/runner/work/remede/remede/builds/remede.x64.dmg + + - name: Copy aarch64 DMG binary + if: matrix.platform == 'macos-latest' && matrix.args == '--target aarch64-apple-darwin' + run: | + cp /Users/runner/work/remede/remede/app/src-tauri/target/aarch64-apple-darwin/release/bundle/macos/*.app.tar.gz /Users/runner/work/remede/remede/builds/remede.aarch64.app.tar.gz + cp /Users/runner/work/remede/remede/app/src-tauri/target/aarch64-apple-darwin/release/bundle/dmg/*.dmg /Users/runner/work/remede/remede/builds/remede.aarch64.dmg + +# - name: Copy MSI binary +# if: matrix.platform == 'windows-latest' +# run: | +# Copy-Item -Path "D:\a\remede\remede\app\src-tauri\target\release\bundle\nsis\*" -Destination "D:\a\remede\remede\builds" -Include *.msi +# Copy-Item -Path "D:\a\remede\remede\app\src-tauri\target\release\bundle\nsis\*" -Destination "D:\a\remede\remede\builds" -Include *.exe +# git restore app/package.json +# git restore app/src-tauri/Cargo.toml + + - name: Commit changes + if: matrix.platform != 'windows-latest' + run: | + git config --local user.name actions-user + git config --local user.email "actions@github.com" + git config pull.rebase true + git add builds/* + git commit -m "chore(binaries): added latest Remède binaries" + git pull + + - name: Push changes # push the output folder to your repo + if: matrix.platform != 'windows-latest' + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + force: true + branch: 'dev' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index ead2f99f..00000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,28 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# THis workflow checks if the code can build -name: Code builds - -on: - push: - branches: [ "main" ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ "main" ] - -jobs: - build: - name: Build Vue project - runs-on: ubuntu-latest - permissions: - contents: read - security-events: write - actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup Environnement - run: cd app && npm install - - - name: Build code - run: cd app && npm run build diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 00000000..718cee04 --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,64 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +# ESLint is a tool for identifying and reporting on patterns +# found in ECMAScript/JavaScript code. +# More details at https://github.com/eslint/eslint +# and https://eslint.org + +name: Checks + +on: + push: + branches: [ "main" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "main" ] + +jobs: + eslint: + name: Eslint scanning + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Environnement + run: cd app && npm install + + - name: Run ESLint + run: cd app && npm run lint + build: + name: Building Vue project + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Environnement + run: cd app && npm install + + - name: Build code + run: cd app && npm run build + generation: + name: Ressources generation (wordlist, IPA list) + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Run ressources generation + run: python3 scripts/pre_generate_ressources.py diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml deleted file mode 100644 index aace1ad2..00000000 --- a/.github/workflows/eslint.yml +++ /dev/null @@ -1,35 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# ESLint is a tool for identifying and reporting on patterns -# found in ECMAScript/JavaScript code. -# More details at https://github.com/eslint/eslint -# and https://eslint.org - -name: ESLint - -on: - push: - branches: [ "main" ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ "main" ] - -jobs: - eslint: - name: Run eslint scanning - runs-on: ubuntu-latest - permissions: - contents: read - security-events: write - actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup Environnement - run: cd app && npm install - - - name: Run ESLint - run: cd app && npm run lint diff --git a/.github/workflows/ressources.yml b/.github/workflows/ressources.yml deleted file mode 100644 index f6d8a581..00000000 --- a/.github/workflows/ressources.yml +++ /dev/null @@ -1,26 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# This workflow execute a python scripts to check if ressources are correctly formatted ! - -name: Ressources format - -on: - push: - branches: [ "main" ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ "main" ] - -jobs: - generation: - name: Run ressources generation (wordlist, IPA list) - runs-on: ubuntu-latest - permissions: - contents: read - security-events: write - actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Run ressources generation - run: python3 scripts/pre_generate_ressources.py diff --git a/CITATIONS.cff b/CITATIONS.cff index 27bd44da..0c6d01ab 100644 --- a/CITATIONS.cff +++ b/CITATIONS.cff @@ -3,8 +3,8 @@ cff-version: "1.2.0" message: "If you use this software, or part of this one, please cite it using these metadata." identifiers: - - type: doi - - value: '10.5281/zenodo.10546995' + - type: doi + value: 10.5281/zenodo.10546995 title: "Remède - French open source dictionary" authors: - @@ -15,6 +15,6 @@ authors: abstract: "Remède is a french dictionary database, API and mobile application. It's an open source alternative to Antidote." repository-code: "https://github.com/camarm-dev/remede" license: CECILL-2.1 -version: 1.1.5 -date-released: '2024-03-31' +version: 1.3.0 +date-released: '2024-08-01' ... diff --git a/README.md b/README.md index 59a408ba..c215869a 100644 --- a/README.md +++ b/README.md @@ -29,14 +29,13 @@ Remède is a dictionary, which can replace any proprietary dictionary, with thes - [Documentation](#documentation) - [Screenshots](#screenshots) -## Current: 1.2.0-beta — Brown Sheep - -La version `1.2.0`, nom de code `Brown Sheep` inclue les nouvelles fonctionnalités suivantes : -- [x] Dictionnaire de **rimes** -- [x] Nouvelle navigation **encore plus agréable**. -- [x] Actions natives quand **un mot est sélectionné** n'importe où dans votre téléphone ! -- [x] Widget pour un accès **plus rapide**. -- [x] **Base révisée** avec +340 000 mots ! +## Current: 1.3.0-beta — Phenomenal Feather + +La version `1.3.0`, nom de code `Phenomenal Feather` inclue les nouvelles fonctionnalités suivantes : +- [x] Application traduite en anglais +- [ ] Nouvelle structure de données +- [ ] Applications de bureau +- [ ] **Base révisée** avec +900 000 mots ! - [ ] Téléchargeable sur le **Play Store** ! ## Télécharger diff --git a/api-definition b/api-definition index d5065a53..46c0542a 160000 --- a/api-definition +++ b/api-definition @@ -1 +1 @@ -Subproject commit d5065a530850daf9c383322febf6d93220e29bb0 +Subproject commit 46c0542a6cf890f6d4ab2719e2e5e2334c35903b diff --git a/app/android/app/build.gradle b/app/android/app/build.gradle index 5d25cd2c..fc717fab 100644 --- a/app/android/app/build.gradle +++ b/app/android/app/build.gradle @@ -5,14 +5,14 @@ android { buildFeatures { viewBinding true } - namespace "com.camarm.remede" + namespace "dev.camarm.remede" compileSdkVersion rootProject.ext.compileSdkVersion defaultConfig { - applicationId "com.camarm.remede" + applicationId "dev.camarm.remede" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 123 - versionName '1.2.3 — Brown Sheep, revison 3' + versionCode 124 + versionName '1.3.0-beta — Phenomenal Feather, Beta' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/app/android/app/capacitor.build.gradle b/app/android/app/capacitor.build.gradle index 2a713b05..610b33d2 100644 --- a/app/android/app/capacitor.build.gradle +++ b/app/android/app/capacitor.build.gradle @@ -11,6 +11,7 @@ apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" dependencies { implementation project(':capacitor-app') implementation project(':capacitor-clipboard') + implementation project(':capacitor-device') implementation project(':capacitor-filesystem') implementation project(':capacitor-haptics') implementation project(':capacitor-keyboard') diff --git a/app/android/app/release/output-metadata.json b/app/android/app/release/output-metadata.json index 035e4494..78ccf1b0 100644 --- a/app/android/app/release/output-metadata.json +++ b/app/android/app/release/output-metadata.json @@ -4,17 +4,17 @@ "type": "APK", "kind": "Directory" }, - "applicationId": "com.camarm.remede", + "applicationId": "dev.camarm.remede", "variantName": "release", "elements": [ { "type": "SINGLE", "filters": [], "attributes": [], - "versionCode": 122, - "versionName": "1.2.2 — Brown Sheep, revison 2", + "versionCode": 124, + "versionName": "1.3.0-beta — Phenomenal Feather, Beta", "outputFile": "app-release.apk" } ], "elementType": "File" -} \ No newline at end of file +} diff --git a/app/android/app/src/main/AndroidManifest.xml b/app/android/app/src/main/AndroidManifest.xml index 0314b031..d34733f3 100644 --- a/app/android/app/src/main/AndroidManifest.xml +++ b/app/android/app/src/main/AndroidManifest.xml @@ -23,7 +23,7 @@ - + @@ -40,7 +40,7 @@ - + - \ No newline at end of file + diff --git a/app/android/app/src/main/java/com/camarm/remede/ActiveRemedeActivity.java b/app/android/app/src/main/java/dev/camarm/remede/ActiveRemedeActivity.java similarity index 95% rename from app/android/app/src/main/java/com/camarm/remede/ActiveRemedeActivity.java rename to app/android/app/src/main/java/dev/camarm/remede/ActiveRemedeActivity.java index e9cdf90f..b68f57c1 100644 --- a/app/android/app/src/main/java/com/camarm/remede/ActiveRemedeActivity.java +++ b/app/android/app/src/main/java/dev/camarm/remede/ActiveRemedeActivity.java @@ -1,4 +1,4 @@ -package com.camarm.remede; +package dev.camarm.remede; import android.app.Activity; import android.content.Intent; @@ -47,7 +47,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { - String result = data.getStringExtra("com.camarm.remede.ACTIVE_REMEDE_RESULT"); + String result = data.getStringExtra("dev.camarm.remede.ACTIVE_REMEDE_RESULT"); Log.w("Active Remede", result); Intent outgoingIntent = new Intent().putExtra(Intent.EXTRA_PROCESS_TEXT, result); setResult(Activity.RESULT_OK, outgoingIntent); diff --git a/app/android/app/src/main/java/com/camarm/remede/MainActivity.java b/app/android/app/src/main/java/dev/camarm/remede/MainActivity.java similarity index 91% rename from app/android/app/src/main/java/com/camarm/remede/MainActivity.java rename to app/android/app/src/main/java/dev/camarm/remede/MainActivity.java index f06ecc9d..43d1592f 100644 --- a/app/android/app/src/main/java/com/camarm/remede/MainActivity.java +++ b/app/android/app/src/main/java/dev/camarm/remede/MainActivity.java @@ -1,4 +1,4 @@ -package com.camarm.remede; +package dev.camarm.remede; import android.os.Bundle; diff --git a/app/android/app/src/main/java/com/camarm/remede/RemedeSearchbarWidget.java b/app/android/app/src/main/java/dev/camarm/remede/RemedeSearchbarWidget.java similarity index 96% rename from app/android/app/src/main/java/com/camarm/remede/RemedeSearchbarWidget.java rename to app/android/app/src/main/java/dev/camarm/remede/RemedeSearchbarWidget.java index cf38f033..1bab8400 100644 --- a/app/android/app/src/main/java/com/camarm/remede/RemedeSearchbarWidget.java +++ b/app/android/app/src/main/java/dev/camarm/remede/RemedeSearchbarWidget.java @@ -1,4 +1,4 @@ -package com.camarm.remede; +package dev.camarm.remede; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; @@ -13,7 +13,7 @@ */ public class RemedeSearchbarWidget extends AppWidgetProvider { - public static String CLICK_ACTION = "com.camarm.remede.action.OPEN_SEARCHBAR"; + public static String CLICK_ACTION = "dev.camarm.remede.action.OPEN_SEARCHBAR"; static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { @@ -58,4 +58,4 @@ public void onReceive(Context context, Intent intent) { context.startActivity(searchbarIntent); } } -} \ No newline at end of file +} diff --git a/app/android/app/src/main/java/com/camarm/remede/RemedeWordOfDayWidget.java b/app/android/app/src/main/java/dev/camarm/remede/RemedeWordOfDayWidget.java similarity index 98% rename from app/android/app/src/main/java/com/camarm/remede/RemedeWordOfDayWidget.java rename to app/android/app/src/main/java/dev/camarm/remede/RemedeWordOfDayWidget.java index 9a525b49..d909a6c4 100644 --- a/app/android/app/src/main/java/com/camarm/remede/RemedeWordOfDayWidget.java +++ b/app/android/app/src/main/java/dev/camarm/remede/RemedeWordOfDayWidget.java @@ -1,4 +1,4 @@ -package com.camarm.remede; +package dev.camarm.remede; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; @@ -22,7 +22,7 @@ */ public class RemedeWordOfDayWidget extends AppWidgetProvider { - public static String CLICK_ACTION = "com.camarm.remede.action.OPEN_WORD_OF_DAY"; + public static String CLICK_ACTION = "dev.camarm.remede.action.OPEN_WORD_OF_DAY"; public static String DEFAULT_WORD_JSON = "{}"; private static JSONObject getJsonResponse(URL url) throws JSONException, IOException { @@ -141,4 +141,4 @@ public void onReceive(Context context, Intent intent) { context.startActivity(searchbarIntent); } } -} \ No newline at end of file +} diff --git a/app/android/app/src/main/java/com/camarm/remede/SetResult.java b/app/android/app/src/main/java/dev/camarm/remede/SetResult.java similarity index 87% rename from app/android/app/src/main/java/com/camarm/remede/SetResult.java rename to app/android/app/src/main/java/dev/camarm/remede/SetResult.java index d9f206f3..60a584ae 100644 --- a/app/android/app/src/main/java/com/camarm/remede/SetResult.java +++ b/app/android/app/src/main/java/dev/camarm/remede/SetResult.java @@ -1,4 +1,4 @@ -package com.camarm.remede; +package dev.camarm.remede; import android.app.Activity; import android.content.Intent; @@ -15,7 +15,7 @@ public class SetResult extends Plugin { public void sendActiveRemedeResult(PluginCall call) { String value = call.getString("value"); - Intent returnIntent = new Intent().putExtra("com.camarm.remede.ACTIVE_REMEDE_RESULT", value).putExtra(Intent.EXTRA_PROCESS_TEXT, value); + Intent returnIntent = new Intent().putExtra("dev.camarm.remede.ACTIVE_REMEDE_RESULT", value).putExtra(Intent.EXTRA_PROCESS_TEXT, value); getActivity().setResult(Activity.RESULT_OK, returnIntent); getActivity().finish(); } diff --git a/app/android/app/src/main/res/values/strings.xml b/app/android/app/src/main/res/values/strings.xml index e5fcf099..061475d8 100644 --- a/app/android/app/src/main/res/values/strings.xml +++ b/app/android/app/src/main/res/values/strings.xml @@ -2,7 +2,7 @@ Remède Remède - com.camarm.remede + dev.camarm.remede remede Ouvrir Remède Add widget diff --git a/app/android/capacitor.settings.gradle b/app/android/capacitor.settings.gradle index 18bccf70..fe9be89b 100644 --- a/app/android/capacitor.settings.gradle +++ b/app/android/capacitor.settings.gradle @@ -8,6 +8,9 @@ project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/ include ':capacitor-clipboard' project(':capacitor-clipboard').projectDir = new File('../node_modules/@capacitor/clipboard/android') +include ':capacitor-device' +project(':capacitor-device').projectDir = new File('../node_modules/@capacitor/device/android') + include ':capacitor-filesystem' project(':capacitor-filesystem').projectDir = new File('../node_modules/@capacitor/filesystem/android') diff --git a/app/capacitor.config.ts b/app/capacitor.config.ts index d19535bf..f70b8cae 100644 --- a/app/capacitor.config.ts +++ b/app/capacitor.config.ts @@ -1,7 +1,7 @@ import { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { - appId: 'com.camarm.remede', + appId: 'dev.camarm.remede', appName: 'Remède', webDir: 'dist', plugins: { @@ -18,13 +18,6 @@ const config: CapacitorConfig = { }, server: { androidScheme: 'https' - }, - electron: { - deepLinkingEnabled: true, - deepLinkingCustomProtocol: 'remede', - splashScreenImageName: "splash.png", - splashScreenEnabled: true, - customUrlScheme: 'remede' } }; diff --git a/app/electron/.gitignore b/app/electron/.gitignore deleted file mode 100644 index d06f9c20..00000000 --- a/app/electron/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# NPM renames .gitignore to .npmignore -# In order to prevent that, we remove the initial "." -# And the CLI then renames it -app -node_modules -build -dist -logs - -out/ \ No newline at end of file diff --git a/app/electron/README.md b/app/electron/README.md deleted file mode 100644 index 7734df84..00000000 --- a/app/electron/README.md +++ /dev/null @@ -1,50 +0,0 @@ -## Electron - -Ressources generated by `npx cap add @capacitor-community/electron` - -### Updated changes - -```shell -npx cap sync @capacitor-community/electron -``` - -### Run electron app - -```shell -npx cap open @capacitor-community/electron -``` - -### Build - -[Electron documentation](https://www.electronjs.org/docs/latest/tutorial/tutorial-packaging) - -```shell -npm run make -``` - -### Multiplatform build - -**Build EXE, DEB and RPM; on a Linux system** - -- Dependencies -```shell -apt install mono-devel wine -``` - -- _Linux platforms_ -```shell -npm run make -``` - -- _Windows exe_ -```shell -npm run make -- --platform win32 -``` - -**Build DMG; using docker** - -// In development // - -```shell -docker run sickcodes/docker-osx:naked -``` \ No newline at end of file diff --git a/app/electron/assets/appIcon.ico b/app/electron/assets/appIcon.ico deleted file mode 100644 index 8050788f..00000000 Binary files a/app/electron/assets/appIcon.ico and /dev/null differ diff --git a/app/electron/assets/appIcon.png b/app/electron/assets/appIcon.png deleted file mode 100644 index ac7869fa..00000000 Binary files a/app/electron/assets/appIcon.png and /dev/null differ diff --git a/app/electron/assets/icon.icns b/app/electron/assets/icon.icns deleted file mode 100644 index 844357c9..00000000 Binary files a/app/electron/assets/icon.icns and /dev/null differ diff --git a/app/electron/assets/icon.ico b/app/electron/assets/icon.ico deleted file mode 100644 index 8050788f..00000000 Binary files a/app/electron/assets/icon.ico and /dev/null differ diff --git a/app/electron/assets/icon.png b/app/electron/assets/icon.png deleted file mode 100644 index ac7869fa..00000000 Binary files a/app/electron/assets/icon.png and /dev/null differ diff --git a/app/electron/assets/splash.png b/app/electron/assets/splash.png deleted file mode 100644 index ddcc8252..00000000 Binary files a/app/electron/assets/splash.png and /dev/null differ diff --git a/app/electron/build-container.sh b/app/electron/build-container.sh deleted file mode 100644 index dd826dfb..00000000 --- a/app/electron/build-container.sh +++ /dev/null @@ -1,9 +0,0 @@ -docker run --rm -ti \ - --env-file <(env | grep -iE 'DEBUG|NODE_|ELECTRON_|YARN_|NPM_|CI|CIRCLE|TRAVIS_TAG|TRAVIS|TRAVIS_REPO_|TRAVIS_BUILD_|TRAVIS_BRANCH|TRAVIS_PULL_REQUEST_|APPVEYOR_|CSC_|GH_|GITHUB_|BT_|AWS_|STRIP|BUILD_') \ - --env ELECTRON_CACHE="/root/.cache/electron" \ - --env ELECTRON_BUILDER_CACHE="/root/.cache/electron-builder" \ - -v ${PWD}:/project \ - -v ${PWD##*/}-node-modules:/project/node_modules \ - -v ~/.cache/electron:/root/.cache/electron \ - -v ~/.cache/electron-builder:/root/.cache/electron-builder \ - electronuserland/builder:wine /bin/bash -c "yarn && yarn dist" \ No newline at end of file diff --git a/app/electron/capacitor.config.ts b/app/electron/capacitor.config.ts deleted file mode 100644 index d19535bf..00000000 --- a/app/electron/capacitor.config.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { CapacitorConfig } from '@capacitor/cli'; - -const config: CapacitorConfig = { - appId: 'com.camarm.remede', - appName: 'Remède', - webDir: 'dist', - plugins: { - "SplashScreen": { - "launchAutoHide": false, - "androidScaleType": "CENTER_CROP", - "splashFullScreen": true, - "splashImmersive": false, - "backgroundColor": "#ffffff" - }, - CapacitorHttp: { - enabled: false - } - }, - server: { - androidScheme: 'https' - }, - electron: { - deepLinkingEnabled: true, - deepLinkingCustomProtocol: 'remede', - splashScreenImageName: "splash.png", - splashScreenEnabled: true, - customUrlScheme: 'remede' - } -}; - -export default config; diff --git a/app/electron/electron-builder.config.json b/app/electron/electron-builder.config.json deleted file mode 100644 index fd0dbc21..00000000 --- a/app/electron/electron-builder.config.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "appId": "com.camarm.remede", - "productName": "Remède", - "copyright": "Copyright © 2024 Armand CAMPONOVO", - "directories": { - "buildResources": "resources" - }, - "files": [ - "assets/**/*", - "build/**/*", - "capacitor.config.*", - "app/**/*" - ], - "publish": { - "provider": "github" - }, - "nsis": { - "allowElevation": true, - "oneClick": false, - "allowToChangeInstallationDirectory": true - }, - "win": { - "target": "nsis", - "icon": "assets/appIcon.ico" - }, - "mac": { - "category": "your.app.category.type", - "target": "dmg" - } -} \ No newline at end of file diff --git a/app/electron/forge.config.js b/app/electron/forge.config.js deleted file mode 100644 index b43619c5..00000000 --- a/app/electron/forge.config.js +++ /dev/null @@ -1,73 +0,0 @@ -module.exports = { - packagerConfig: { - asar: true, - }, - rebuildConfig: {}, - makers: [ - { - name: '@electron-forge/maker-squirrel', - config: { - title: "Remède", - manufacturer: "Labse Software", - description: "Open source and free French dictionary !", - iconUrl: "https://raw.githubusercontent.com/camarm-dev/remede/main/app/electron/assets/appIcon.ico", - setupIcon: "./assets/appIcon.ico", - authors: "Armand CAMPONOVO (@camarm-dev) and Remède contributors", - owners: "Armand CAMPONOVO (@camarm-dev) and Labse Software", - copyright: "Copyrights 2024 Remède, CeCill V2.1" - }, - }, - { - name: '@electron-forge/maker-dmg', - config: { - name: "Remède", - background: './assets/splash.png', - format: 'ULFO', - icon: "./assets/appIcon.ico" - } - }, - { - name: '@electron-forge/maker-zip', - platforms: ['darwin'], - }, - { - name: '@electron-forge/maker-deb', - config: { - options: { - name: "remede", - description: "Open source and free French dictionary !", - productName: "Remède", - productDescription: "Remède is an open source alternative to Antidote. It's free and open source !", - categories: ["Utility"], - genericName: "Dictionary", - homepage: "https://remede.camarm.fr", - icon: "./assets/appIcon.ico", - maintainer: "Armand CAMPONOVO (@camarm-dev)" - } - }, - }, - { - name: '@electron-forge/maker-rpm', - config: { - options: { - name: "remede", - description: "Open source and free French dictionary !", - productName: "Remède", - productDescription: "Remède is an open source alternative to Antidote. It's free and open source !", - categories: ["Utility"], - genericName: "Dictionary", - homepage: "https://remede.camarm.fr", - icon: "./assets/appIcon.ico", - maintainer: "Armand CAMPONOVO (@camarm-dev)", - license: "CeCill V2.1" - } - }, - }, - ], - plugins: [ - { - name: '@electron-forge/plugin-auto-unpack-natives', - config: {}, - }, - ], -}; diff --git a/app/electron/live-runner.js b/app/electron/live-runner.js deleted file mode 100644 index 84c3ea73..00000000 --- a/app/electron/live-runner.js +++ /dev/null @@ -1,75 +0,0 @@ -/* eslint-disable no-undef */ -/* eslint-disable @typescript-eslint/no-var-requires */ -const cp = require('child_process'); -const chokidar = require('chokidar'); -const electron = require('electron'); - -let child = null; -const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'; -const reloadWatcher = { - debouncer: null, - ready: false, - watcher: null, - restarting: false, -}; - -///* -function runBuild() { - return new Promise((resolve, _reject) => { - let tempChild = cp.spawn(npmCmd, ['run', 'build']); - tempChild.once('exit', () => { - resolve(); - }); - tempChild.stdout.pipe(process.stdout); - }); -} -//*/ - -async function spawnElectron() { - if (child !== null) { - child.stdin.pause(); - child.kill(); - child = null; - await runBuild(); - } - child = cp.spawn(electron, ['--inspect=5858', './']); - child.on('exit', () => { - if (!reloadWatcher.restarting) { - process.exit(0); - } - }); - child.stdout.pipe(process.stdout); -} - -function setupReloadWatcher() { - reloadWatcher.watcher = chokidar - .watch('./src/**/*', { - ignored: /[/\\]\./, - persistent: true, - }) - .on('ready', () => { - reloadWatcher.ready = true; - }) - .on('all', (_event, _path) => { - if (reloadWatcher.ready) { - clearTimeout(reloadWatcher.debouncer); - reloadWatcher.debouncer = setTimeout(async () => { - console.log('Restarting'); - reloadWatcher.restarting = true; - await spawnElectron(); - reloadWatcher.restarting = false; - reloadWatcher.ready = false; - clearTimeout(reloadWatcher.debouncer); - reloadWatcher.debouncer = null; - reloadWatcher.watcher = null; - setupReloadWatcher(); - }, 500); - } - }); -} - -(async () => { - await runBuild(); - await spawnElectron(); - setupReloadWatcher(); -})(); diff --git a/app/electron/package.json b/app/electron/package.json deleted file mode 100644 index 7a81a1c5..00000000 --- a/app/electron/package.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "name": "remede", - "version": "1.1.2", - "description": "A french mobile and offline dictionary.", - "build": { - "appId": "com.camarm.remede", - "productName": "Remède", - "copyright": "Copyright © 2024 Armand CAMPONOVO" - }, - "author": { - "name": "Armand CAMPONOVO (@camarm-dev)", - "email": "software@camarm.dev" - }, - "repository": { - "type": "git", - "url": "https://github.com/camarm-dev/remede" - }, - "license": "CeCill V2.1", - "main": "build/src/index.js", - "scripts": { - "build": "tsc && electron-rebuild", - "electron:start-live": "node ./live-runner.js", - "electron:start": "npm run build && electron --inspect=5858 ./", - "electron:pack": "npm run build && electron-builder build --dir -c ./electron-builder.config.json", - "electron:make": "npm run build && electron-builder build -c ./electron-builder.config.json -p always", - "start": "electron-forge start", - "package": "electron-forge package", - "make": "electron-forge make" - }, - "dependencies": { - "chokidar": "~3.5.3", - "electron-is-dev": "~2.0.0", - "electron-serve": "~1.1.0", - "electron-squirrel-startup": "^1.0.0", - "electron-unhandled": "~4.0.1", - "electron-updater": "^5.3.0", - "electron-window-state": "^5.0.3" - }, - "devDependencies": { - "@capacitor-community/electron": "^5.0.0", - "@electron-forge/maker-dmg": "^7.2.0", - "@electron-forge/maker-wix": "^7.2.0", - "@electron-forge/cli": "^7.2.0", - "@electron-forge/maker-deb": "^7.2.0", - "@electron-forge/maker-rpm": "^7.2.0", - "@electron-forge/maker-squirrel": "^7.2.0", - "@electron-forge/maker-zip": "^7.2.0", - "@electron-forge/plugin-auto-unpack-natives": "^7.2.0", - "electron": "^26.2.2", - "electron-rebuild": "^3.2.9", - "typescript": "^5.0.4" - }, - "keywords": [ - "capacitor", - "electron" - ] -} diff --git a/app/electron/resources/electron-publisher-custom.js b/app/electron/resources/electron-publisher-custom.js deleted file mode 100644 index 6e0821ef..00000000 --- a/app/electron/resources/electron-publisher-custom.js +++ /dev/null @@ -1,10 +0,0 @@ -/* eslint-disable no-undef */ -/* eslint-disable @typescript-eslint/no-var-requires */ -const electronPublish = require('electron-publish'); - -class Publisher extends electronPublish.Publisher { - async upload(task) { - console.log('electron-publisher-custom', task.file); - } -} -module.exports = Publisher; diff --git a/app/electron/src/index.ts b/app/electron/src/index.ts deleted file mode 100644 index e23f2bb3..00000000 --- a/app/electron/src/index.ts +++ /dev/null @@ -1,70 +0,0 @@ -import type { CapacitorElectronConfig } from '@capacitor-community/electron'; -import { getCapacitorElectronConfig, setupElectronDeepLinking } from '@capacitor-community/electron'; -import type { MenuItemConstructorOptions } from 'electron'; -import { app, MenuItem } from 'electron'; -import electronIsDev from 'electron-is-dev'; -import unhandled from 'electron-unhandled'; -import { autoUpdater } from 'electron-updater'; - -import { ElectronCapacitorApp, setupContentSecurityPolicy, setupReloadWatcher } from './setup'; - -// Graceful handling of unhandled errors. -unhandled(); - -// Define our menu templates (these are optional) -const trayMenuTemplate: (MenuItemConstructorOptions | MenuItem)[] = [new MenuItem({ label: 'Quit App', role: 'quit' })]; -const appMenuBarMenuTemplate: (MenuItemConstructorOptions | MenuItem)[] = [ - { role: process.platform === 'darwin' ? 'appMenu' : 'fileMenu' }, - { role: 'viewMenu' }, -]; - -// Get Config options from capacitor.config -const capacitorFileConfig: CapacitorElectronConfig = getCapacitorElectronConfig(); - -// Initialize our app. You can pass menu templates into the app here. -// const myCapacitorApp = new ElectronCapacitorApp(capacitorFileConfig); -const myCapacitorApp = new ElectronCapacitorApp(capacitorFileConfig, trayMenuTemplate, appMenuBarMenuTemplate); - -// If deeplinking is enabled then we will set it up here. -if (capacitorFileConfig.electron?.deepLinkingEnabled) { - setupElectronDeepLinking(myCapacitorApp, { - customProtocol: capacitorFileConfig.electron.deepLinkingCustomProtocol ?? 'mycapacitorapp', - }); -} - -// If we are in Dev mode, use the file watcher components. -if (electronIsDev) { - setupReloadWatcher(myCapacitorApp); -} - -// Run Application -(async () => { - // Wait for electron app to be ready. - await app.whenReady(); - // Security - Set Content-Security-Policy based on whether or not we are in dev mode. - setupContentSecurityPolicy(myCapacitorApp.getCustomURLScheme()); - // Initialize our app, build windows, and load content. - await myCapacitorApp.init(); - // Check for updates if we are in a packaged app. - autoUpdater.checkForUpdatesAndNotify(); -})(); - -// Handle when all of our windows are close (platforms have their own expectations). -app.on('window-all-closed', function () { - // On OS X it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit(); - } -}); - -// When the dock icon is clicked. -app.on('activate', async function () { - // On OS X it's common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (myCapacitorApp.getMainWindow().isDestroyed()) { - await myCapacitorApp.init(); - } -}); - -// Place all ipc or other electron api calls and custom functionality under this line diff --git a/app/electron/src/preload.ts b/app/electron/src/preload.ts deleted file mode 100644 index 6b99aedb..00000000 --- a/app/electron/src/preload.ts +++ /dev/null @@ -1,2 +0,0 @@ -require('./rt/electron-rt'); -////////////////////////////// diff --git a/app/electron/src/rt/electron-plugins.js b/app/electron/src/rt/electron-plugins.js deleted file mode 100644 index b33b2826..00000000 --- a/app/electron/src/rt/electron-plugins.js +++ /dev/null @@ -1,4 +0,0 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ - -module.exports = { -} \ No newline at end of file diff --git a/app/electron/src/rt/electron-rt.ts b/app/electron/src/rt/electron-rt.ts deleted file mode 100644 index 55d67c30..00000000 --- a/app/electron/src/rt/electron-rt.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { randomBytes } from 'crypto'; -import { ipcRenderer, contextBridge } from 'electron'; -import { EventEmitter } from 'events'; - -//////////////////////////////////////////////////////// -// eslint-disable-next-line @typescript-eslint/no-var-requires -const plugins = require('./electron-plugins'); - -const randomId = (length = 5) => randomBytes(length).toString('hex'); - -const contextApi: { - [plugin: string]: { [functionName: string]: () => Promise }; -} = {}; - -Object.keys(plugins).forEach((pluginKey) => { - Object.keys(plugins[pluginKey]) - .filter((className) => className !== 'default') - .forEach((classKey) => { - const functionList = Object.getOwnPropertyNames(plugins[pluginKey][classKey].prototype).filter( - (v) => v !== 'constructor' - ); - - if (!contextApi[classKey]) { - contextApi[classKey] = {}; - } - - functionList.forEach((functionName) => { - if (!contextApi[classKey][functionName]) { - contextApi[classKey][functionName] = (...args) => ipcRenderer.invoke(`${classKey}-${functionName}`, ...args); - } - }); - - // Events - if (plugins[pluginKey][classKey].prototype instanceof EventEmitter) { - const listeners: { [key: string]: { type: string; listener: (...args: any[]) => void } } = {}; - const listenersOfTypeExist = (type) => - !!Object.values(listeners).find((listenerObj) => listenerObj.type === type); - - Object.assign(contextApi[classKey], { - addListener(type: string, callback: (...args) => void) { - const id = randomId(); - - // Deduplicate events - if (!listenersOfTypeExist(type)) { - ipcRenderer.send(`event-add-${classKey}`, type); - } - - const eventHandler = (_, ...args) => callback(...args); - - ipcRenderer.addListener(`event-${classKey}-${type}`, eventHandler); - listeners[id] = { type, listener: eventHandler }; - - return id; - }, - removeListener(id: string) { - if (!listeners[id]) { - throw new Error('Invalid id'); - } - - const { type, listener } = listeners[id]; - - ipcRenderer.removeListener(`event-${classKey}-${type}`, listener); - - delete listeners[id]; - - if (!listenersOfTypeExist(type)) { - ipcRenderer.send(`event-remove-${classKey}-${type}`); - } - }, - removeAllListeners(type: string) { - Object.entries(listeners).forEach(([id, listenerObj]) => { - if (!type || listenerObj.type === type) { - ipcRenderer.removeListener(`event-${classKey}-${listenerObj.type}`, listenerObj.listener); - ipcRenderer.send(`event-remove-${classKey}-${listenerObj.type}`); - delete listeners[id]; - } - }); - }, - }); - } - }); -}); - -contextBridge.exposeInMainWorld('CapacitorCustomPlatform', { - name: 'electron', - plugins: contextApi, -}); -//////////////////////////////////////////////////////// diff --git a/app/electron/src/setup.ts b/app/electron/src/setup.ts deleted file mode 100644 index de99c637..00000000 --- a/app/electron/src/setup.ts +++ /dev/null @@ -1,233 +0,0 @@ -import type { CapacitorElectronConfig } from '@capacitor-community/electron'; -import { - CapElectronEventEmitter, - CapacitorSplashScreen, - setupCapacitorElectronPlugins, -} from '@capacitor-community/electron'; -import chokidar from 'chokidar'; -import type { MenuItemConstructorOptions } from 'electron'; -import { app, BrowserWindow, Menu, MenuItem, nativeImage, Tray, session } from 'electron'; -import electronIsDev from 'electron-is-dev'; -import electronServe from 'electron-serve'; -import windowStateKeeper from 'electron-window-state'; -import { join } from 'path'; - -// Define components for a watcher to detect when the webapp is changed so we can reload in Dev mode. -const reloadWatcher = { - debouncer: null, - ready: false, - watcher: null, -}; -export function setupReloadWatcher(electronCapacitorApp: ElectronCapacitorApp): void { - reloadWatcher.watcher = chokidar - .watch(join(app.getAppPath(), 'app'), { - ignored: /[/\\]\./, - persistent: true, - }) - .on('ready', () => { - reloadWatcher.ready = true; - }) - .on('all', (_event, _path) => { - if (reloadWatcher.ready) { - clearTimeout(reloadWatcher.debouncer); - reloadWatcher.debouncer = setTimeout(async () => { - electronCapacitorApp.getMainWindow().webContents.reload(); - reloadWatcher.ready = false; - clearTimeout(reloadWatcher.debouncer); - reloadWatcher.debouncer = null; - reloadWatcher.watcher = null; - setupReloadWatcher(electronCapacitorApp); - }, 1500); - } - }); -} - -// Define our class to manage our app. -export class ElectronCapacitorApp { - private MainWindow: BrowserWindow | null = null; - private SplashScreen: CapacitorSplashScreen | null = null; - private TrayIcon: Tray | null = null; - private CapacitorFileConfig: CapacitorElectronConfig; - private TrayMenuTemplate: (MenuItem | MenuItemConstructorOptions)[] = [ - new MenuItem({ label: 'Quit App', role: 'quit' }), - ]; - private AppMenuBarMenuTemplate: (MenuItem | MenuItemConstructorOptions)[] = [ - { role: process.platform === 'darwin' ? 'appMenu' : 'fileMenu' }, - { role: 'viewMenu' }, - ]; - private mainWindowState; - private loadWebApp; - private customScheme: string; - - constructor( - capacitorFileConfig: CapacitorElectronConfig, - trayMenuTemplate?: (MenuItemConstructorOptions | MenuItem)[], - appMenuBarMenuTemplate?: (MenuItemConstructorOptions | MenuItem)[] - ) { - this.CapacitorFileConfig = capacitorFileConfig; - - this.customScheme = this.CapacitorFileConfig.electron?.customUrlScheme ?? 'capacitor-electron'; - - if (trayMenuTemplate) { - this.TrayMenuTemplate = trayMenuTemplate; - } - - if (appMenuBarMenuTemplate) { - this.AppMenuBarMenuTemplate = appMenuBarMenuTemplate; - } - - // Setup our web app loader, this lets us load apps like react, vue, and angular without changing their build chains. - this.loadWebApp = electronServe({ - directory: join(app.getAppPath(), 'app'), - scheme: this.customScheme, - }); - } - - // Helper function to load in the app. - private async loadMainWindow(thisRef: any) { - await thisRef.loadWebApp(thisRef.MainWindow); - } - - // Expose the mainWindow ref for use outside of the class. - getMainWindow(): BrowserWindow { - return this.MainWindow; - } - - getCustomURLScheme(): string { - return this.customScheme; - } - - async init(): Promise { - const icon = nativeImage.createFromPath( - join(app.getAppPath(), 'assets', process.platform === 'win32' ? 'appIcon.ico' : 'appIcon.png') - ); - this.mainWindowState = windowStateKeeper({ - defaultWidth: 1000, - defaultHeight: 800, - }); - // Setup preload script path and construct our main window. - const preloadPath = join(app.getAppPath(), 'build', 'src', 'preload.js'); - this.MainWindow = new BrowserWindow({ - icon, - show: false, - x: this.mainWindowState.x, - y: this.mainWindowState.y, - width: this.mainWindowState.width, - height: this.mainWindowState.height, - webPreferences: { - nodeIntegration: true, - contextIsolation: true, - // Use preload to inject the electron varriant overrides for capacitor plugins. - // preload: join(app.getAppPath(), "node_modules", "@capacitor-community", "electron", "dist", "runtime", "electron-rt.js"), - preload: preloadPath, - }, - }); - this.mainWindowState.manage(this.MainWindow); - - if (this.CapacitorFileConfig.backgroundColor) { - this.MainWindow.setBackgroundColor(this.CapacitorFileConfig.electron.backgroundColor); - } - - // If we close the main window with the splashscreen enabled we need to destory the ref. - this.MainWindow.on('closed', () => { - if (this.SplashScreen?.getSplashWindow() && !this.SplashScreen.getSplashWindow().isDestroyed()) { - this.SplashScreen.getSplashWindow().close(); - } - }); - - // When the tray icon is enabled, setup the options. - if (this.CapacitorFileConfig.electron?.trayIconAndMenuEnabled) { - this.TrayIcon = new Tray(icon); - this.TrayIcon.on('double-click', () => { - if (this.MainWindow) { - if (this.MainWindow.isVisible()) { - this.MainWindow.hide(); - } else { - this.MainWindow.show(); - this.MainWindow.focus(); - } - } - }); - this.TrayIcon.on('click', () => { - if (this.MainWindow) { - if (this.MainWindow.isVisible()) { - this.MainWindow.hide(); - } else { - this.MainWindow.show(); - this.MainWindow.focus(); - } - } - }); - this.TrayIcon.setToolTip(app.getName()); - this.TrayIcon.setContextMenu(Menu.buildFromTemplate(this.TrayMenuTemplate)); - } - - // Setup the main manu bar at the top of our window. - Menu.setApplicationMenu(Menu.buildFromTemplate(this.AppMenuBarMenuTemplate)); - - // If the splashscreen is enabled, show it first while the main window loads then switch it out for the main window, or just load the main window from the start. - if (this.CapacitorFileConfig.electron?.splashScreenEnabled) { - this.SplashScreen = new CapacitorSplashScreen({ - imageFilePath: join( - app.getAppPath(), - 'assets', - this.CapacitorFileConfig.electron?.splashScreenImageName ?? 'splash.png' - ), - windowWidth: 400, - windowHeight: 400, - }); - this.SplashScreen.init(this.loadMainWindow, this); - } else { - this.loadMainWindow(this); - } - - // Security - this.MainWindow.webContents.setWindowOpenHandler((details) => { - if (!details.url.includes(this.customScheme)) { - return { action: 'deny' }; - } else { - return { action: 'allow' }; - } - }); - this.MainWindow.webContents.on('will-navigate', (event, _newURL) => { - if (!this.MainWindow.webContents.getURL().includes(this.customScheme)) { - event.preventDefault(); - } - }); - - // Link electron plugins into the system. - setupCapacitorElectronPlugins(); - - // When the web app is loaded we hide the splashscreen if needed and show the mainwindow. - this.MainWindow.webContents.on('dom-ready', () => { - if (this.CapacitorFileConfig.electron?.splashScreenEnabled) { - this.SplashScreen.getSplashWindow().hide(); - } - if (!this.CapacitorFileConfig.electron?.hideMainWindowOnLaunch) { - this.MainWindow.show(); - } - setTimeout(() => { - if (electronIsDev) { - this.MainWindow.webContents.openDevTools(); - } - CapElectronEventEmitter.emit('CAPELECTRON_DeeplinkListenerInitialized', ''); - }, 400); - }); - } -} - -// Set a CSP up for our application based on the custom scheme -export function setupContentSecurityPolicy(customScheme: string): void { - session.defaultSession.webRequest.onHeadersReceived((details, callback) => { - callback({ - responseHeaders: { - ...details.responseHeaders, - 'Content-Security-Policy': [ - electronIsDev - ? `default-src https://* remede://* 'unsafe-inline' devtools://* 'unsafe-eval' data:` - : `default-src https://* remede://* 'unsafe-inline' data:`, - ], - }, - }); - }); -} diff --git a/app/electron/tsconfig.json b/app/electron/tsconfig.json deleted file mode 100644 index ef90ab39..00000000 --- a/app/electron/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compileOnSave": true, - "include": ["./src/**/*", "./capacitor.config.ts", "./capacitor.config.js"], - "compilerOptions": { - "outDir": "./build", - "importHelpers": true, - "target": "ES2017", - "module": "CommonJS", - "moduleResolution": "node", - "esModuleInterop": true, - "typeRoots": ["./node_modules/@types"], - "allowJs": true, - "rootDir": "." - } -} diff --git a/app/icon.png b/app/icon.png new file mode 100644 index 00000000..99dc4183 Binary files /dev/null and b/app/icon.png differ diff --git a/app/package.json b/app/package.json index 7903837d..4ae93771 100644 --- a/app/package.json +++ b/app/package.json @@ -1,9 +1,9 @@ { "name": "remede", "private": true, - "version": "1.2.3", + "version": "1.3.0-beta", "type": "module", - "license": "Cecill V2.1", + "license": "CECILL-2.1", "author": { "name": "Armand CAMPONOVO (@camarm-dev)", "email": "software@camarm.dev" @@ -18,7 +18,8 @@ "preview": "vite preview", "test": "cypress run", "lint": "eslint src", - "lint:fix": "eslint src --fix" + "lint:fix": "eslint src --fix", + "tauri": "tauri" }, "dependencies": { "@capacitor-community/electron": "^5.0.1", @@ -26,6 +27,7 @@ "@capacitor/app": "^5.0.7", "@capacitor/clipboard": "^5.0.6", "@capacitor/core": "5.5.1", + "@capacitor/device": "^5.0.8", "@capacitor/filesystem": "^5.1.4", "@capacitor/haptics": "5.0.6", "@capacitor/keyboard": "^5.0.6", @@ -40,11 +42,13 @@ "sql.js": "^1.8.0", "swiper": "^11.0.5", "vue": "^3.2.45", + "vue-i18n": "^9.13.1", "vue-router": "^4.1.6" }, "devDependencies": { "@capacitor/assets": "^3.0.5", "@capacitor/cli": "5.5.1", + "@tauri-apps/cli": "^1.5.14", "@vitejs/plugin-legacy": "^4.0.2", "@vitejs/plugin-vue": "^4.0.0", "@vue/eslint-config-typescript": "^11.0.2", diff --git a/app/public/logo.png b/app/public/logo.png new file mode 100644 index 00000000..0cd16a17 Binary files /dev/null and b/app/public/logo.png differ diff --git a/app/src-tauri/.gitignore b/app/src-tauri/.gitignore new file mode 100644 index 00000000..aba21e24 --- /dev/null +++ b/app/src-tauri/.gitignore @@ -0,0 +1,3 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ diff --git a/app/src-tauri/Cargo.toml b/app/src-tauri/Cargo.toml new file mode 100644 index 00000000..a529379b --- /dev/null +++ b/app/src-tauri/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "app" +version = "1.3.0-beta" +description = "The french open source dictionary." +authors = ["Armand CAMPONOVO "] +license = "CECILL-2.1" +repository = "https://github.com/camarm-dev/remede" +readme = "https://github.com/camarm-dev/remede" +homepage = "https://remede.camarm.fr" +default-run = "app" +edition = "2021" +rust-version = "1.60" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[build-dependencies] +tauri-build = { version = "1.5.2", features = [] } + +[dependencies] +serde_json = "1.0" +serde = { version = "1.0", features = ["derive"] } +tauri = { version = "1.6.5", features = [] } + +[features] +# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled. +# If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes. +# DO NOT REMOVE!! +custom-protocol = [ "tauri/custom-protocol" ] diff --git a/app/src-tauri/build.rs b/app/src-tauri/build.rs new file mode 100644 index 00000000..795b9b7c --- /dev/null +++ b/app/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build() +} diff --git a/app/src-tauri/icons/128x128.png b/app/src-tauri/icons/128x128.png new file mode 100644 index 00000000..a81a0028 Binary files /dev/null and b/app/src-tauri/icons/128x128.png differ diff --git a/app/src-tauri/icons/128x128@2x.png b/app/src-tauri/icons/128x128@2x.png new file mode 100644 index 00000000..7c1face0 Binary files /dev/null and b/app/src-tauri/icons/128x128@2x.png differ diff --git a/app/src-tauri/icons/32x32.png b/app/src-tauri/icons/32x32.png new file mode 100644 index 00000000..a3e16b11 Binary files /dev/null and b/app/src-tauri/icons/32x32.png differ diff --git a/app/src-tauri/icons/Square107x107Logo.png b/app/src-tauri/icons/Square107x107Logo.png new file mode 100644 index 00000000..cef3b7da Binary files /dev/null and b/app/src-tauri/icons/Square107x107Logo.png differ diff --git a/app/src-tauri/icons/Square142x142Logo.png b/app/src-tauri/icons/Square142x142Logo.png new file mode 100644 index 00000000..2da9c224 Binary files /dev/null and b/app/src-tauri/icons/Square142x142Logo.png differ diff --git a/app/src-tauri/icons/Square150x150Logo.png b/app/src-tauri/icons/Square150x150Logo.png new file mode 100644 index 00000000..6a3d6686 Binary files /dev/null and b/app/src-tauri/icons/Square150x150Logo.png differ diff --git a/app/src-tauri/icons/Square284x284Logo.png b/app/src-tauri/icons/Square284x284Logo.png new file mode 100644 index 00000000..92504307 Binary files /dev/null and b/app/src-tauri/icons/Square284x284Logo.png differ diff --git a/app/src-tauri/icons/Square30x30Logo.png b/app/src-tauri/icons/Square30x30Logo.png new file mode 100644 index 00000000..93a2551e Binary files /dev/null and b/app/src-tauri/icons/Square30x30Logo.png differ diff --git a/app/src-tauri/icons/Square310x310Logo.png b/app/src-tauri/icons/Square310x310Logo.png new file mode 100644 index 00000000..4f239643 Binary files /dev/null and b/app/src-tauri/icons/Square310x310Logo.png differ diff --git a/app/src-tauri/icons/Square44x44Logo.png b/app/src-tauri/icons/Square44x44Logo.png new file mode 100644 index 00000000..614dfca1 Binary files /dev/null and b/app/src-tauri/icons/Square44x44Logo.png differ diff --git a/app/src-tauri/icons/Square71x71Logo.png b/app/src-tauri/icons/Square71x71Logo.png new file mode 100644 index 00000000..527f7aad Binary files /dev/null and b/app/src-tauri/icons/Square71x71Logo.png differ diff --git a/app/src-tauri/icons/Square89x89Logo.png b/app/src-tauri/icons/Square89x89Logo.png new file mode 100644 index 00000000..98413398 Binary files /dev/null and b/app/src-tauri/icons/Square89x89Logo.png differ diff --git a/app/src-tauri/icons/StoreLogo.png b/app/src-tauri/icons/StoreLogo.png new file mode 100644 index 00000000..03741f71 Binary files /dev/null and b/app/src-tauri/icons/StoreLogo.png differ diff --git a/app/src-tauri/icons/icon.icns b/app/src-tauri/icons/icon.icns new file mode 100644 index 00000000..c0607098 Binary files /dev/null and b/app/src-tauri/icons/icon.icns differ diff --git a/app/src-tauri/icons/icon.ico b/app/src-tauri/icons/icon.ico new file mode 100644 index 00000000..9d2eadd6 Binary files /dev/null and b/app/src-tauri/icons/icon.ico differ diff --git a/app/src-tauri/icons/icon.png b/app/src-tauri/icons/icon.png new file mode 100644 index 00000000..d61c8d8f Binary files /dev/null and b/app/src-tauri/icons/icon.png differ diff --git a/app/src-tauri/remede.desktop b/app/src-tauri/remede.desktop new file mode 100644 index 00000000..8d40bfb9 --- /dev/null +++ b/app/src-tauri/remede.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Categories=Office; +Comment=Le dictionnaire libre +Exec=remede +Icon=remede +Name=Remède +Terminal=false +Type=Application diff --git a/app/src-tauri/remede.metainfo.xml b/app/src-tauri/remede.metainfo.xml new file mode 100644 index 00000000..87c92d8c --- /dev/null +++ b/app/src-tauri/remede.metainfo.xml @@ -0,0 +1,107 @@ + + + remede + remede.desktop + Remède + + Armand CAMPONOVO + + + https://github.com/camarm-dev/remede/issues + https://ko-fi.com/camarm + https://remede.camarm.fr + https://github.com/camarm-dev/remede + https://docs.remede.camarm.fr/docs/contributing + GPL-3.0 + CC-BY-4.0 + The free dictionary + Le dictionnaire libre + +

+ Remède is a powerful dictionary developed by its community. It has a large database with over 900 000 french words, synonyms, antonyms, conjugations and rhymes. It also has a corrector and an offline mode. With Remède, never lost your words again. + + Remède is distributed under the CECILL-2.1 license, which is compatible with GPL-3.0 license. +

+

+ Remède est un dictionnaire puissant développé par sa communauté. Il dispose d'une large base de +900 000 mots, avec des synonymes, des antonymes, des conjugaisons et des rimes. Vous y retrouverez aussi un correcteur et un mode hors ligne. Avec Remède, ne perdez plus vos mots. + + Remède est distribué sous la licence CECILL-2.1, qui est compatible avec la licence GPL-3.0. +

+
+ + pointing + keyboard + touch + 360 + + + + https://raw.githubusercontent.com/camarm-dev/remede/.github/screenshots/fr/header.png + Remède + + + https://raw.githubusercontent.com/camarm-dev/remede/.github/screenshots/header.png + Remède + + + https://raw.githubusercontent.com/camarm-dev/remede/.github/screenshots/fr/home.png + Remède page d'accueil + + + https://raw.githubusercontent.com/camarm-dev/remede/.github/screenshots/home.png + Remède homepage + + + https://raw.githubusercontent.com/camarm-dev/remede/.github/screenshots/fr/definition.png + Remède page de définition + + + https://raw.githubusercontent.com/camarm-dev/remede/.github/screenshots/definition.png + Definition page + + + https://raw.githubusercontent.com/camarm-dev/remede/.github/screenshots/fr/correction.png + Correcteur + + + https://raw.githubusercontent.com/camarm-dev/remede/.github/screenshots/correction.png + Corrector + + + https://raw.githubusercontent.com/camarm-dev/remede/.github/screenshots/fr/settings.png + Paramètres + + + https://raw.githubusercontent.com/camarm-dev/remede/.github/screenshots/settings.png + Settings + + + + 360 + + + + +
    +
  • Added desktop application
  • +
  • More than 900 000 french words
  • +
  • Added English support !
  • +
  • New database schema !
  • +
+
+
+
+ software@camarm.dev + + + Dictionary + French + English + Correction + Rhymes + + + 10.5281/zenodo.10546995 + https://raw.githubusercontent.com/camarm-dev/remede/main/CITATIONS.cff + +
diff --git a/app/src-tauri/src/header.bmp b/app/src-tauri/src/header.bmp new file mode 100644 index 00000000..1e61e76e Binary files /dev/null and b/app/src-tauri/src/header.bmp differ diff --git a/app/src-tauri/src/main.rs b/app/src-tauri/src/main.rs new file mode 100644 index 00000000..f5c5be23 --- /dev/null +++ b/app/src-tauri/src/main.rs @@ -0,0 +1,8 @@ +// Prevents additional console window on Windows in release, DO NOT REMOVE!! +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + tauri::Builder::default() + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/app/src-tauri/tauri.conf.json b/app/src-tauri/tauri.conf.json new file mode 100644 index 00000000..1055d7ec --- /dev/null +++ b/app/src-tauri/tauri.conf.json @@ -0,0 +1,84 @@ +{ + "$schema": "../node_modules/@tauri-apps/cli/schema.json", + "build": { + "beforeBuildCommand": "npm run build", + "beforeDevCommand": "npm run dev", + "devPath": "http://localhost:5173", + "distDir": "../dist" + }, + "package": { + "productName": "remede", + "version": "../package.json" + }, + "tauri": { + "allowlist": { + "all": false + }, + "bundle": { + "active": true, + "deb": { + "depends": [], + "desktopTemplate": "./remede.desktop", + "files": { + "/usr/share/README.md": "../../README.md", + "/usr/share/metainfo/remede.metainfo.xml": "./remede.metainfo.xml" + } + }, + "externalBin": [], + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ], + "identifier": "dev.camarm.remede", + "shortDescription": "The free dictionary", + "longDescription": "Remède is a powerful dictionary developed by its community. It has a large database with over 900 000 french words, synonyms, antonyms, conjugations and rhymes. It also has a corrector and an offline mode. With Remède, never lost your words again.", + "copyright": "Remède and its contributors.", + "category": "Productivity", + "macOS": { + "entitlements": null, + "exceptionDomain": "", + "frameworks": [], + "providerShortName": null, + "signingIdentity": null, + "license": "../../LICENSE" + }, + "resources": [], + "targets": ["deb", "nsis", "msi", "dmg", "app", "updater"], + "windows": { + "certificateThumbprint": null, + "digestAlgorithm": "sha256", + "timestampUrl": "", + "webviewInstallMode": { + "type": "offlineInstaller" + }, + "nsis": { + "installerIcon": "icons/icon.ico", + "headerImage": "src/header.bmp", + "license": "../../LICENSE" + } + } + }, + "security": { + "csp": null + }, + "updater": { + "active": false + }, + "windows": [ + { + "fullscreen": false, + "maxHeight": 1000, + "maxWidth": 1800, + "minHeight": 700, + "minWidth": 1100, + "height": 800, + "resizable": true, + "title": "Remède | Dictionnaire", + "width": 1300 + } + ] + } +} diff --git a/app/src-tauri/windows_conf.py b/app/src-tauri/windows_conf.py new file mode 100644 index 00000000..84289723 --- /dev/null +++ b/app/src-tauri/windows_conf.py @@ -0,0 +1,22 @@ +import json + + +def get_package_json(): + with open('app/package.json') as file: + return json.loads(file.read()) + + +def save_package_json(content: dict): + with open('app/package.json', 'w+') as file: + file.write(json.dumps(content)) + + +if __name__ == '__main__': + print("Making changes for Windows MSI build...") + package = get_package_json() + version = package.get('version', '') + valid_version = version.split('-')[0] + print(f"Changing {version} to {valid_version}...") + package['version'] = valid_version + save_package_json(package) + diff --git a/app/src/App.vue b/app/src/App.vue index 66e29756..9d21089a 100644 --- a/app/src/App.vue +++ b/app/src/App.vue @@ -5,60 +5,58 @@ - Remède icon - Remède - Retrouvez vos mots en toute simplicité - + + {{ $t('theDictionary') }} + - @@ -69,38 +67,48 @@ diff --git a/app/src/components/LandingScreen.vue b/app/src/components/LandingScreen.vue index 53f22ea5..55c2a17e 100644 --- a/app/src/components/LandingScreen.vue +++ b/app/src/components/LandingScreen.vue @@ -18,10 +18,10 @@
-

Bienvenue sur Remède !

+

{{ $t('landingScreen.welcomeTo') }} Remède !

- Votre nouveau dictionnaire préféré ! + {{ $t('landingScreen.yourNewFavoriteDictionary') }}
Remède icon
- +
-

Une application, tous vos mots !

+

{{ $t('landingScreen.oneAppAllYour') }} {{ $t('landingScreen.words') }} !

- + 340 000 mots, mais aussi des rimes, des exemples, un correcteur et plus encore... Remède est bien plus qu'un dictionnaire ! + {{ $t('landingScreen.functionalities') }}
-

Mais surtout ... open source !

+

{{ $t('landingScreen.butAboveAll') }} {{ $t('landingScreen.openSource') }} !

- Et oui ! Remède grandi avec sa communauté et est 100% open source ! + {{ $t('landingScreen.openSourceDescription') }}
-

Prêts à entrer dans l'aventure ?

+

{{ $t('landingScreen.readyToStart') }}{{ $t('landingScreen.adventure') }} ?

- Guérir vos maux face au français, c'est possible dès maintenant avec Remède ! + {{ $t('landingScreen.tagline') }}
- C'est parti + {{ $t('letsgo') }} diff --git a/app/src/components/RemedeLogo.vue b/app/src/components/RemedeLogo.vue new file mode 100644 index 00000000..423568dc --- /dev/null +++ b/app/src/components/RemedeLogo.vue @@ -0,0 +1,23 @@ + + diff --git a/app/src/components/TabSection.vue b/app/src/components/TabSection.vue new file mode 100644 index 00000000..3b44804e --- /dev/null +++ b/app/src/components/TabSection.vue @@ -0,0 +1,22 @@ + + diff --git a/app/src/data/translations/en.json b/app/src/data/translations/en.json new file mode 100644 index 00000000..0f054edc --- /dev/null +++ b/app/src/data/translations/en.json @@ -0,0 +1,175 @@ +{ + "dictionary": "Dictionary", + "theDictionary": "The dictionary.", + "rhymes": "Rhymes", + "correction": "Correction", + "corrector": "Corrector", + "sheets": "Sheets", + "bookmarks": "Bookmarks", + "settings": "Settings", + "about": "About", + "back": "Back", + "cancel": "Cancel", + "apply": "Apply", + "confirm": "Confirm", + "continue": "Continue", + "start": "Start", + "letsgo": "Let's go", + "delete": "Delete", + "close": "Close", + "ignore": "Ignore", + "credits": "Credits", + "license": "License", + "remedeData": "Remède data", + "sources": "Sources", + "error": "Error", + "repository": "Github repository", + "filters": "Filters", + "feminineAll": "All", + "errors": { + "cannotReadWord": "Cannot read word: {error}", + "rhymesSearchFailed": "Failed to search in the rhymes dictionary: {error}" + }, + "bookmark": { + "addWordsToBookmarks": "Add words to your bookmarks" + }, + "home": { + "wordOfDay": "Word of day", + "randomWord": "Random word", + "myBookmarks": "My bookmarks", + "forYou": "For you", + "seeAll": "See all", + "askToAddAWord": "Ask to add a word", + "report": "Report", + "searchWord": "Search a word...", + "changelog": "Changelog" + }, + "definition": { + "etymologies": "Etymologies", + "backToApp": "Back to app", + "definition": "Definition", + "synonyms": "Synonyms", + "noSynonyms": "No synonyms referenced", + "antonyms": "Antonyms", + "noAntonyms": "No antonyms referenced", + "conjugation": "Conjugation", + "conjugationMode": "Mode", + "conjugationTense": "Tense", + "wordNotFound": "This word cannot be found in the Remède dictionary...", + "examples": "Examples", + "openConjugation": "Open conjugation", + "openRhymesDictionary": "Open rhymes dictionary" + }, + "share": { + "definitionTitle": "Definition of \"{word}\" on Remède", + "definitionDescription": "The definition of word \"{word}\" is on Remède !", + "definitionDialogTitle": "Share definition", + "sheetTitle": "\"{name}\" on Remède", + "sheetDescription": "the french grammar sheet \"{name}\" is on Remède !", + "sheetDialogTitle": "Share sheet" + }, + "aboutPage": { + "description": "Remède is an open source dictionary built on extern resources.", + "moreInformationCredits": "For more information about our data provenance, or how it is built, please visit the documentation on our", + "contributors": "Contributors", + "donors": "Donors", + "contributorsAndDonors": "Contributors & donors", + "maintainer": "Maintainer" + }, + "correctionPage": { + "corrected": "Corrected text", + "placeholder": "Write your text here, we will correct it.", + "text": "Text", + "edit": "Edit", + "correct": "Correct", + "recorrect": "Recorrect", + "replaceBy": "Replace by", + "ignoredError": "Error ignored.", + "deleteException": "Remove expection", + "copy": "Copy", + "backToApp": "Back to application", + "backToAppDisclaimer": "Back to app will replaced selected text by corrected text.", + "copyAndBackToApp": "Copy and get back to app", + "copyAndBackToAppDisclaimer": "Copy the corrected text and get back to previous application. All you have to do is paste the text !", + "exceptions": "Exceptions", + "noExceptions": "No exceptions added.", + "correctionPoweredBy": "Correction powered by", + "hostedByRemede": "hosted by Remède" + }, + "sheetPage": { + "attributionsTo": "Attributions to", + "sheetNotFound": "The sheet cannot be found !", + "noSheet": "No sheet" + }, + "rhymesPage": { + "rhyme": "Rhyme", + "placeholder": "Enter a word", + "quality": "Rhyme quality", + "qualityPoor": "Poor rhyme", + "qualitySufficient": "Sufficient rhyme", + "qualityRich": "Rich rhyme", + "withElide": "With elide", + "elides": "Elides", + "femininesOnly": "Feminines only", + "feminines": "Feminines", + "femininesElidableLabel": "Feminine / Elidable", + "syllables": "syllable(s)", + "toSyllables": "to", + "fromSyllables": "", + "syllablesNumber": "Syllables nb.", + "addFilter": "Add filter", + "noRhymeFound": "No rhyme found for this word and these filters. Use the searchbar above to retry.", + "searchErrored" : "The search in the rhyme dictionary has failed.", + "syllablesMinimumAbbr": "Syllables min.", + "syllablesMaximumAbbr": "Syllables max.", + "searchRhymesAbove": "Search rhymes above !", + "rhymeNature": "Rhymes nature" + }, + "nature": { + "name": "Name", + "verb": "Verb", + "adverb": "Adverb", + "adjective": "Adjective", + "pronoun": "Pronoun", + "auxiliary": "Auxiliary", + "onomatopoeia": "Onomatopoeia" + }, + "settingsPage": { + "personalization": "Personalization", + "theme": "Theme", + "lightTheme": "Light", + "darkTheme": "Dark", + "tongue": "Tongue", + "offlineDictionary": "Offline dictionary", + "download": "Download", + "downloaded": "downloaded", + "downloading": "Downloading...", + "downloadSuccess": "Download successfully", + "downloadDescription": "The offline dictionary has been downloaded", + "downloadLongDescription": "To finish its installation, please restart the application !", + "downloadFailed": "Failed to download", + "downloadFailedDescription": "The offline dictionary cannot be downloaded: {error}", + "updateTo": "Update to", + "cannotDownload": "You cannot download the dictionary...", + "downloadingDisclaimer": "Please let this page open while the dictionary is downloading.\n\nYou must restart the application after the dictionary has been downloaded.", + "workingNormally": "Everything looks ok ! You can start searching words offline !", + "problemDetected": "A problem has been detected, please reinstall the dictionary or contact the support." + }, + "sheetsPage": { + "placeholder": "Search a sheet", + "onlyWorkWithInternet": "Only works with an internet connection !" + }, + "landingScreen": { + "welcomeTo": "Welcome to", + "yourNewFavoriteDictionary": "Your new favorite dictionary !", + "oneAppAllYour": "One application, all your", + "words": "words", + "functionalities": "+ 900 000 word, but also rhymes, examples, a corrector and more... Remède is much more than a dictionary !", + "butAboveAll": "But above all ...", + "openSource": "open source", + "openSourceDescription": "Yes ! Remède is growing with his community and 100% open source !", + "readyToStart": "Ready to enter the ", + "adventure": "adventure", + "tagline": "Cure your French ills now with Remède !" + } +} diff --git a/app/src/data/translations/fr.json b/app/src/data/translations/fr.json new file mode 100644 index 00000000..1dc4766a --- /dev/null +++ b/app/src/data/translations/fr.json @@ -0,0 +1,175 @@ +{ + "dictionary": "Dictionnaire", + "theDictionary": "Le dictionnaire.", + "rhymes": "Rimes", + "correction": "Correction", + "corrector": "Correcteur", + "sheets": "Fiches", + "bookmarks": "Marques page", + "settings": "Paramètres", + "about": "À propos", + "back": "Retour", + "cancel": "Annuler", + "apply": "Appliquer", + "confirm": "Confirmer", + "continue": "Continuer", + "start": "Commencer", + "letsgo": "C'est parti", + "delete": "Supprimer", + "close": "Fermer", + "ignore": "Ignorer", + "credits": "Crédits", + "license": "Licence", + "remedeData": "Données Remède", + "sources": "Sources", + "error": "Erreur", + "repository": "dépôt Github", + "filters": "Filtres", + "feminineAll": "Toutes", + "errors": { + "cannotReadWord": "Impossible de lire le mot: {error}", + "rhymesSearchFailed": "La recherche dans le dictionnaire des rimes a échouée: {error}" + }, + "bookmark": { + "addWordsToBookmarks": "Ajoutez des mots à vos marques pages" + }, + "home": { + "wordOfDay": "Mot du jour", + "randomWord": "Mot au hasard", + "myBookmarks": "Mes marques page", + "forYou": "Pour vous", + "seeAll": "Tout voir", + "askToAddAWord": "Demander à ajouter un mot", + "report": "Reporter", + "searchWord": "Rechercher un mot...", + "changelog": "Notes de changement" + }, + "definition": { + "etymologies": "Étymologies", + "backToApp": "Retour à l'application", + "definition": "Définition", + "synonyms": "Synonymes", + "noSynonyms": "Pas de synonymes référencés", + "antonyms": "Antonymes", + "noAntonyms": "Pas d'antonymes référencés", + "conjugation": "Conjugaison", + "conjugationMode": "Mode", + "conjugationTense": "Temps", + "wordNotFound": "Ce mot n'a pas été trouvé dans le dictionnaire Remède...", + "examples": "Exemples", + "openConjugation": "Ouvrir la conjugaison", + "openRhymesDictionary": "Ouvrir le dictionnaire des rimes" + }, + "share": { + "definitionTitle": "Définition \"{word}\" sur Remède", + "definitionDescription": "La définition du mot \"{word}\" est sur Remède !", + "definitionDialogTitle": "Partager la définition", + "sheetTitle": "\"{name}\" sur Remède", + "sheetDescription": "La fiche de français \"{name}\" est sur Remède !", + "sheetDialogTitle": "Partager la fiche" + }, + "aboutPage": { + "description": "Remède est un dictionnaire français libre, construit sur plusieurs services tiers.", + "moreInformationCredits": "Pour plus d'informations concernant la provenance des données de nos dictionnaires et leur construction, visitez la documentation sur notre", + "contributors": "Contributeurs", + "donors": "Donateurs", + "contributorsAndDonors": "Contributeurs & donateurs", + "maintainer": "Mainteneur" + }, + "correctionPage": { + "corrected": "Texte corrigé", + "placeholder": "Écrivez votre texte ici, nous le corrigerons.", + "text": "Texte", + "edit": "Éditer", + "correct": "Corriger", + "recorrect": "Recorriger", + "replaceBy": "Remplacer par", + "ignoredError": "Erreur ignorée.", + "deleteException": "Enlever l'exception", + "copy": "Copier", + "backToApp": "Retourner à l'application", + "backToAppDisclaimer": "Retourner à l'application utilisera le texte corrigé.", + "copyAndBackToApp": "Copier et retourner à l'application", + "copyAndBackToAppDisclaimer": "Copie le texte corrigé et retourne à l'application précédente. Vous n'aurez plus qu'a coller le texte !", + "exceptions": "Exceptions", + "noExceptions": "Aucunes exceptions ajoutées.", + "correctionPoweredBy": "Correction grâce à", + "hostedByRemede": "hébergé par Remède" + }, + "sheetPage": { + "attributionsTo": "Attributions à", + "sheetNotFound": "La fiche n'a pas été trouvée !", + "noSheet": "Pas de fiche" + }, + "rhymesPage": { + "rhyme": "Rime", + "placeholder": "Entrez un mot", + "quality": "Qualité des rimes", + "qualityPoor": "Rimes pauvres", + "qualitySufficient": "Rimes suffisantes", + "qualityRich": "Rimes riches", + "withElide": "Avec élide", + "elides": "Élides", + "femininesOnly": "Féminines seulement", + "feminines": "Féminines", + "femininesElidableLabel": "Féminine / Élidable", + "syllables": "syllabe(s)", + "toSyllables": "à", + "fromSyllables": "de", + "syllablesNumber": "Nb. syllabes", + "addFilter": "Ajouter un filtre", + "noRhymeFound": "Aucune rimes trouvées dans notre base avec ce mot. Utilisez la barre de recherche ci-dessus.", + "searchErrored" : "La recherche dans le dictionnaire des rimes a échouée.", + "syllablesMinimumAbbr": "Syllabes min.", + "syllablesMaximumAbbr": "Syllabes max.", + "searchRhymesAbove": "Recherchez des rimes ci-dessus !", + "rhymeNature": "Nature des rimes" + }, + "nature": { + "name": "Nom", + "verb": "Verbe", + "adverb": "Adverbe", + "adjective": "Adjectif", + "pronoun": "Pronom", + "auxiliary": "Auxiliaire", + "onomatopoeia": "Onomatopée" + }, + "settingsPage": { + "personalization": "Personnalisation", + "theme": "Thème", + "lightTheme": "Clair", + "darkTheme": "Sombre", + "tongue": "Langue", + "offlineDictionary": "Dictionnaire hors ligne", + "download": "Télécharger", + "downloaded": "téléchargé", + "downloading": "Téléchargement en cours...", + "downloadSuccess": "Téléchargement réussi", + "downloadDescription": "Le dictionnaire hors-ligne a été téléchargé", + "downloadLongDescription": "Pour finaliser son installation, veuillez relancer l'application !", + "downloadFailed": "Échec de téléchargement", + "downloadFailedDescription": "Le dictionnaire hors-ligne n'a pas pu être téléchargé: {error}", + "updateTo": "Mettre à jour vers", + "cannotDownload": "Vous ne pouvez pas télécharger le dictionnaire...", + "downloadingDisclaimer": "Veuillez ne pas quitter cette page pendant le téléchargement.\n\nIl est conseillé de redémarrer l'application après le téléchargement.", + "workingNormally": "Tout semble fonctionner parfaitement. Vous pouvez commencer à chercher des mots hors-ligne !", + "problemDetected": "Un problème a été détecté, veuillez réinstaller le dictionnaire ou contacter le support." + }, + "sheetsPage": { + "placeholder": "Rechercher une fiche", + "onlyWorkWithInternet": "Fonctionne seulement avec une connexion internet !" + }, + "landingScreen": { + "welcomeTo": "Bienvenue sur", + "yourNewFavoriteDictionary": "Votre nouveau dictionnaire préféré !", + "oneAppAllYour": "Une application, tous vos", + "words": "mots", + "functionalities": "+ 900 000 mots, mais aussi des rimes, des exemples, un correcteur et plus encore... Remède est bien plus qu'un dictionnaire !", + "butAboveAll": "Mais surtout ...", + "openSource": "open source", + "openSourceDescription": "Et oui ! Remède grandi avec sa communauté et est 100% open source !", + "readyToStart": "Prêts à entrer dans l'", + "adventure": "aventure", + "tagline": "Guérir vos maux face au français, c'est possible dès maintenant avec Remède !" + } +} diff --git a/app/src/functions/animations.ts b/app/src/functions/animations.ts new file mode 100644 index 00000000..d2ef893f --- /dev/null +++ b/app/src/functions/animations.ts @@ -0,0 +1,19 @@ +import {createAnimation} from "@ionic/vue" + +export const defaultRemedeMainToolbarAnimation = (element: Element | Element[] | Node | Node[] | NodeList) => createAnimation() + .addElement(element) + .duration(250) + .fromTo("transform", "translateY(0)", "translateY(-100%)") + .fromTo("opacity", "1", "0") + +export const defaultRemedeSearchToolbarAnimation = (element: Element | Element[] | Node | Node[] | NodeList) => createAnimation() + .addElement(element) + .beforeAddClass("mt") + .duration(250) + .fromTo("transform", "translateY(0)", "translateY(-50%)") + .fromTo("scale", "1", "1.01") + +export const defaultRemedeContentAnimation = (element: Element | Element[] | Node | Node[] | NodeList) => createAnimation() + .addElement(element) + .duration(250) + .fromTo("transform", "translateY(0)", "translateY(-10%)") diff --git a/app/src/functions/device.ts b/app/src/functions/device.ts new file mode 100644 index 00000000..be799a97 --- /dev/null +++ b/app/src/functions/device.ts @@ -0,0 +1,6 @@ +import {Device} from "@capacitor/device" + +export async function getDeviceLocale() { + const locale = await Device.getLanguageCode() + return locale.value.includes("-") ? locale.value.split("-")[0]: locale.value +} diff --git a/app/src/functions/dictionnary.ts b/app/src/functions/dictionnary.ts index 25374875..8bd38fd8 100644 --- a/app/src/functions/dictionnary.ts +++ b/app/src/functions/dictionnary.ts @@ -42,7 +42,7 @@ async function getRandomWordFromDatabase() { } async function doesWordExistsWithAPI(word: string) { - return (await fetch(`https://api-remede.camarm.fr/word/${word}`).then(resp => resp.json())).message != "Mot non trouvé" + return (await fetch(`https://api-remede.camarm.fr/word/${word}`).then(resp => resp.json()).catch(() => { return { message: "Mot non trouvé" } })).message != "Mot non trouvé" } async function doesWordExistsWithDatabase(word: string) { diff --git a/app/src/functions/locales.ts b/app/src/functions/locales.ts new file mode 100644 index 00000000..09f3aba2 --- /dev/null +++ b/app/src/functions/locales.ts @@ -0,0 +1,19 @@ +const locales = { + en: "English", + fr: "Français", + dialects: { + en: [ + "en-GB", + "en-US", + "en-CA", + "en-AU", + "en-NZ" + ] + } +} + +export function hasDialect(locale: string) { + return Object.prototype.hasOwnProperty.call(locales.dialects, locale) +} + +export default locales diff --git a/app/src/functions/offline.ts b/app/src/functions/offline.ts index 88b2f5d8..a0fb97c3 100644 --- a/app/src/functions/offline.ts +++ b/app/src/functions/offline.ts @@ -1,4 +1,4 @@ -import {RemedeDictionaryOption} from "@/functions/types/api_responses" +import {RemedeDictionaryOption} from "@/functions/types/apiResponses" import {Directory, Filesystem} from "@capacitor/filesystem" import {Preferences} from "@capacitor/preferences" import {Capacitor} from "@capacitor/core" diff --git a/app/src/functions/sources.ts b/app/src/functions/sources.ts new file mode 100644 index 00000000..95bcfde5 --- /dev/null +++ b/app/src/functions/sources.ts @@ -0,0 +1,24 @@ +const sources = { + antonyme_org: { + label: "definition.antonyms", + url: "http://www.antonyme.org/antonyme/{word}" + }, + synonymo_fr: { + label: "definition.synonyms", + url: "http://synonymo.fr/synonyme/{word}" + }, + conjuguons_fr: { + label: "definition.conjugation", + url: "http://conjuguons.fr/conjugaison/verbe/{word}" + }, + fr_wik: { + label: "Wiktionnaire", + url: "https://fr.wiktionary.org/wiki/{word}" + }, + en_wik: { + label: "Wiktionary", + url: "https://fr.wiktionary.org/wiki/{word}" + } +} + +export default sources diff --git a/app/src/functions/types/api_responses.ts b/app/src/functions/types/apiResponses.ts similarity index 100% rename from app/src/functions/types/api_responses.ts rename to app/src/functions/types/apiResponses.ts diff --git a/app/src/i18n.ts b/app/src/i18n.ts new file mode 100644 index 00000000..9fa4d5ff --- /dev/null +++ b/app/src/i18n.ts @@ -0,0 +1,15 @@ +import { createI18n } from "vue-i18n" +import frenchTranslations from "@/data/translations/fr.json" +import englishTranslations from "@/data/translations/en.json" + +const globalizationList = { + fr: frenchTranslations, + en: englishTranslations +} + +export default createI18n({ + locale: "fr", + fallbackLocale: "en", + messages: globalizationList, + preserveDirectiveContent: true +}) diff --git a/app/src/main.ts b/app/src/main.ts index 45ed959b..69ae10f8 100644 --- a/app/src/main.ts +++ b/app/src/main.ts @@ -23,12 +23,16 @@ import "@ionic/vue/css/display.css" /* Theme variables */ import "./theme/variables.css" +/* For translations */ +import i18n from "./i18n" + const app = createApp(App) .use(IonicVue, { mode: "ios", innerHTMLTemplatesEnabled: true }) .use(router) + .use(i18n) router.isReady().then(() => { app.mount("#app") diff --git a/app/src/router/index.ts b/app/src/router/index.ts index 3dc08583..0f9ecfcb 100644 --- a/app/src/router/index.ts +++ b/app/src/router/index.ts @@ -13,47 +13,51 @@ const routes: Array = [ }, { path: "dictionnaire", - component: () => import ("../views/HomePage.vue"), + name: "dictionnaire", + component: () => import ("../views/HomeView.vue"), }, { path: "dictionnaire/:mot", - component: () => import ("../views/WordModal.vue") + component: () => import ("../views/DefinitionView.vue") }, { path: "search/:mot", - component: () => import ("../components/SearchModal.vue") + component: () => import ("../views/SearchResultsView.vue") }, { path: "a-propos", - component: () => import ("../views/AboutPage.vue") + component: () => import ("../views/AboutView.vue") }, { path: "correction", - component: () => import ("../views/CorrectionPage.vue") + name: "correction", + component: () => import ("../views/CorrectionView.vue") }, { path: "fiches", - component: () => import ("../views/FichesPage.vue") + name: "fiches", + component: () => import ("../views/SheetsView.vue") }, { path: "fiches/:slug", - component: () => import ("../views/FichePage.vue") + component: () => import ("../views/ReadSheetView.vue") }, { path: "rimes", - component: () => import ("../views/RimesPage.vue") + name: "rimes", + component: () => import ("../views/RhymesDictionaryView.vue") }, { path: "rimes/:mot", - component: () => import ("../views/RimesResults.vue") + component: () => import ("../views/RhymesDictionarySearchResultsView.vue") }, { path: "parametres", - component: () => import ("../views/SettingsPage.vue") + component: () => import ("../views/SettingsView.vue") }, { path: "marques-page", - component: () => import ("../views/FavoritesPage.vue") + component: () => import ("../views/BookmarksView.vue") } ] } diff --git a/app/src/theme/variables.css b/app/src/theme/variables.css index b1ec7588..15081a26 100644 --- a/app/src/theme/variables.css +++ b/app/src/theme/variables.css @@ -3,6 +3,74 @@ http://ionicframework.com/docs/theming/ */ /** Ionic CSS Variables **/ +@keyframes spawn { + from { + opacity: 0; + height: 0; + } + to { + height: auto; + opacity: 1; + } +} + +.hidden { + display: none; +} + +@media (max-width: 1000px) { + .hidden-mobile { + display: none; + } +} + +@media (min-width: 1000px) { + .hidden-desktop { + display: none; + } + + .hidden-mobile { + transition: .5s ease-in-out; + animation: .5s ease-in-out spawn; + } + + .radius-0 { + border-radius: 0; + } + + ion-list.list-inset:not(.search-results,.corrector,.fullwidth) { + scale: 1.02; + margin-inline-start: calc(var(--margin-start, 16px) + 1em) !important; + max-width: 60%; + margin: 16px auto; + } + + .corrector ion-textarea, .corrector .correction-content { + min-height: 10em !important; + } + + ion-menu { + width: max-content; + } + + ion-toolbar.hidden-desktop + ion-toolbar { + margin-top: 1em; + } + + .mt { + margin-top: 2.5em !important; + } + + .no-desktop-swiper .swiper-slide { + max-width: 30% !important; + margin-right: 1em; + } + + .no-desktop-swiper .swiper-pagination { + display: none; + } +} + @font-face { font-family: "IMBPlexSerif"; font-weight: normal; @@ -328,3 +396,16 @@ html { https://ionicframework.com/docs/layout/dynamic-font-scaling */ --ion-dynamic-font: var(--ion-default-dynamic-font); } + + +body.dark .new-version { + content: url("@/assets/newVersionDark.png"); +} + +body.dark .new-base { + content: url("@/assets/newBaseDark.png"); +} + +body.dark .changelog { + content: url("@/assets/changelogDark.png"); +} diff --git a/app/src/views/AboutPage.vue b/app/src/views/AboutView.vue similarity index 87% rename from app/src/views/AboutPage.vue rename to app/src/views/AboutView.vue index 23503669..c450a41c 100644 --- a/app/src/views/AboutPage.vue +++ b/app/src/views/AboutView.vue @@ -14,17 +14,17 @@
- À propos + {{ $t('about') }}

- Remède est un dictionnaire français libre, construit sur plusieurs services tiers. + {{ $t('aboutPage.description') }}

- Pour plus d'informations concernant la provenance des données de nos dictionnaires et leur construction, visitez la documentation sur notre - dépôt Github. + {{ $t('aboutPage.moreInformationCredits') }} + {{ $t('repository') }}.

@@ -36,7 +36,7 @@ - Contributeurs & donateurs + {{ $t('aboutPage.contributorsAndDonors') }} @@ -51,7 +51,7 @@
- Contributeurs + {{ $t('aboutPage.contributors') }}
@@ -60,7 +60,7 @@

camarm

-

Fondateur

+

{{ $t('aboutPage.maintainer') }}

@@ -69,7 +69,7 @@

Labse Software

-

Contributeurs

+

{{ $t('aboutPage.contributors') }}

@@ -78,19 +78,19 @@
- Crédits + {{ $t('credits') }}
- Licence + {{ $t('license') }} - Données Remède + {{ $t('remedeData') }} @@ -105,7 +105,7 @@ @@ -115,8 +115,8 @@ import { App } from "@capacitor/app" export default { data() { return { - version: ":unavailable:", - build: ":unavailable:" + version: "1.3.0-beta", + build: "tauri-1" } }, mounted() { diff --git a/app/src/views/FavoritesPage.vue b/app/src/views/BookmarksView.vue similarity index 78% rename from app/src/views/FavoritesPage.vue rename to app/src/views/BookmarksView.vue index ba8e50fb..7696b992 100644 --- a/app/src/views/FavoritesPage.vue +++ b/app/src/views/BookmarksView.vue @@ -11,7 +11,7 @@ - Marques pages + {{ $t('bookmarks') }} @@ -24,7 +24,7 @@
- Ajoutez des mots à vos marques pages + {{ $t('bookmark.addWordsToBookmarks') }}
@@ -69,15 +69,6 @@ export default { this.refresh() }, methods: { - handleThemeChangement(theme: string) { - localStorage.setItem("userTheme", theme) - document.body.classList.remove("dark") - document.body.classList.remove("light") - document.body.classList.add(theme) - }, - getCurrentTheme() { - return localStorage.getItem("userTheme") || "light" - }, refresh() { this.starredWords = getStarredWords() } diff --git a/app/src/views/CorrectionPage.vue b/app/src/views/CorrectionView.vue similarity index 76% rename from app/src/views/CorrectionPage.vue rename to app/src/views/CorrectionView.vue index 00b5903f..11aef6e5 100644 --- a/app/src/views/CorrectionPage.vue +++ b/app/src/views/CorrectionView.vue @@ -16,21 +16,27 @@ - Correcteur + {{ $t('corrector') }} - + -

Texte Corrigé

+

{{ $t('correctionPage.corrected')}}

+

{{ $t('correctionPage.text')}}

+ + + {{ dialect }} + + - Éditer  + {{ $t('correctionPage.edit') }}  - Corriger  + {{ $t('correctionPage.correct') }}  @@ -40,8 +46,8 @@ -
+ :placeholder="$t('correctionPage.placeholder')"> +
{{ segment.text }} @@ -58,18 +64,18 @@
- Remplacer par + {{ $t('correctionPage.replaceBy') }}
- {{ suggested.value == '' ? 'Supprimer': suggested.value }}
- Ignorer + {{ suggested.value == '' ? 'Supprimer': suggested.value }}
+ {{ $t('ignore') }} -

Erreur ignorée.

+

{{ $t('correctionPage.ignoredError') }}


- Enlever l'exception + {{ $t('correctionPage.deleteException') }}
@@ -80,10 +86,10 @@ - Copier  + {{ $t('correctionPage.copy') }}  - Recorriger  + {{ $t('correctionPage.recorrect') }}  @@ -93,42 +99,42 @@
- Copier et retourner à l'application - Retourner à l'application + {{ $t('correctionPage.copyAndBackToApp') }} + {{ $t('correctionPage.backToApp') }}
- Copie le texte corrigé et retourne à l'application précédente. Vous n'aurez plus qu'a coller le texte ! + {{ $t('correctionPage.copyAndBackToAppDisclaimer') }} - Retourner à l'application utilisera le texte corrigé. + {{ $t('correctionPage.backToAppDisclaimer') }}
- Correction grâce à Languagetool, hébergé par Remède. + {{ $t('correctionPage.correctionPoweredBy') }} Languagetool, {{ $t('correctionPage.hostedByRemede') }}.
- Exceptions + {{ $t('correctionPage.exceptions') }} - Fermer + {{ $t('close') }} - Aucunes exceptions ajoutées. + {{ $t('correctionPage.noExceptions') }} - +

"{{ error.text }}"

@@ -162,7 +168,9 @@ import { IonList, IonNote, IonSpinner, - IonModal + IonModal, + IonSelect, + IonSelectOption } from "@ionic/vue" import { chevronForwardOutline, @@ -170,17 +178,24 @@ import { pencilOutline, sparkles, closeOutline, - trashOutline, languageOutline, informationCircleOutline, returnUpBackOutline + trashOutline, + languageOutline, + informationCircleOutline, + returnUpBackOutline } from "ionicons/icons" +import { hasDialect } from "@/functions/locales" - - - diff --git a/app/src/views/HomePage.vue b/app/src/views/HomeView.vue similarity index 81% rename from app/src/views/HomePage.vue rename to app/src/views/HomeView.vue index e1aebf0b..7674e5e7 100644 --- a/app/src/views/HomePage.vue +++ b/app/src/views/HomeView.vue @@ -1,7 +1,7 @@