Merge branch 'develop' into feature/asset-qortalrequests

This commit is contained in:
PhilReact 2025-05-01 12:31:21 +03:00
commit f1d9fc9539
312 changed files with 38734 additions and 35336 deletions

View File

@ -2,17 +2,17 @@ module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
ignorePatterns: ["dist", ".eslintrc.cjs"],
parser: "@typescript-eslint/parser",
plugins: ["react-refresh"],
rules: {
'react-refresh/only-export-components': [
'off',
"react-refresh/only-export-components": [
"off",
{ allowConstantExport: true },
],
},
}
};

1
.gitignore vendored
View File

@ -9,6 +9,7 @@ lerna-debug.log*
node_modules
dist
dist.zip
dist-ssr
*.local

3
.prettierignore Normal file
View File

@ -0,0 +1,3 @@
node_modules
build
dist

23
.prettierrc Normal file
View File

@ -0,0 +1,23 @@
{
"arrowParens": "always",
"bracketSameLine": false,
"bracketSpacing": true,
"embeddedLanguageFormatting": "auto",
"endOfLine": "lf",
"experimentalTernaries": false,
"htmlWhitespaceSensitivity": "css",
"insertPragma": false,
"jsxBracketSameLine": false,
"jsxSingleQuote": false,
"printWidth": 80,
"proseWrap": "preserve",
"quoteProps": "as-needed",
"requirePragma": false,
"semi": true,
"singleAttributePerLine": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"useTabs": false,
"vueIndentScriptAndStyle": false
}

View File

@ -1,6 +1,6 @@
# Qortal Hub - Desktop Interface for Qortal
Qortal Hub is the newest interface for Qortal, part of the 'Qortal Trifecta' series of new User Interfaces for the platform/network.
Qortal Hub is the newest interface for Qortal, part of the 'Qortal Trifecta' series of new User Interfaces for the platform/network.
It is likely that Qortal Hub will become the new 'primary interface' for Qortal, and that the primary development focus surrounding Qortal Interface development, will be focused here instead of the previous 'qortal-ui' repo.
@ -8,14 +8,20 @@ It is likely that Qortal Hub will become the new 'primary interface' for Qortal,
Qortal Hub came along with the new Group Encryption methodologies applied, which provide **encrypted chat in Q-Chat for private groups.** Qortal Hub was the first to implement the new method of group encryption, which allows new users to see previously published data, unlike the previous group encryption methodology of things like 'threads' in Q-Mail.
Allowing new users to view older messages also comes along with a massive boost to the usability of the group encryption, and as such has been leveraged in multiple places inside Qortal Hub, Qortal Extension, and Qortal Go.
Allowing new users to view older messages also comes along with a massive boost to the usability of the group encryption, and as such has been leveraged in multiple places inside Qortal Hub, Qortal Extension, and Qortal Go.
## Ease of Use Expanded
Qortal Hub has a focus on ease of use for new users. Providing both the ability to utlilize Qortal without needing to run a local node (though running a local node is still the recommended method to access Qortal), and multiple built-in (QDN-published) walk-thru videos (by Qortal Justin) that explain the various basics of any given section of the application. This allows new users to 'jump right in' to utilizing Qortal Hub, and Qortal overall, in a much more streamlined fashion than that which was previously required by the 'legacy UI' (qortal-ui).
Qortal Hub has a focus on ease of use for new users. Providing both the ability to utlilize Qortal without needing to run a local node (though running a local node is still the recommended method to access Qortal), and multiple built-in (QDN-published) walk-thru videos (by Qortal Justin) that explain the various basics of any given section of the application. This allows new users to 'jump right in' to utilizing Qortal Hub, and Qortal overall, in a much more streamlined fashion than that which was previously required by the 'legacy UI' (qortal-ui).
Leveraging a redundant set of publicly accessible nodes provided by crowetic, Qortal Hub, Qortal Go, and Qortal Extension, all allow the use of Qortal without running a node, making it very simple to 'install and go' and start making use of the extensive functionality provided within the Qortal Ecosystem.
Leveraging a redundant set of publicly accessible nodes provided by crowetic, Qortal Hub, Qortal Go, and Qortal Extension, all allow the use of Qortal without running a node, making it very simple to 'install and go' and start making use of the extensive functionality provided within the Qortal Ecosystem.
Many additional details and a fully featured wiki will be created over time. Reach out on the chat on https://qortal.dev or in any of the community locations for Qortal, if you have any issues. Thank you!
## Internationalization (i18n)
Qortal-Hub supports internationalization (i18n) using [i18next](https://www.i18next.com/), allowing seamless translation of UI text into multiple languages.
The setup includes modularized translation files, language detection, context and runtime language switching.
Files with translation are in `public/locales/<locale>` folder.
See [guidelines](./docs/i18n_languages.md).

101
android/.gitignore vendored
View File

@ -1,101 +0,0 @@
# 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

View File

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

View File

@ -1,54 +0,0 @@
apply plugin: 'com.android.application'
android {
namespace "com.example.app"
compileSdk rootProject.ext.compileSdkVersion
defaultConfig {
applicationId "com.example.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

@ -1,23 +0,0 @@
// 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-browser')
implementation project(':capacitor-filesystem')
implementation project(':capacitor-local-notifications')
implementation project(':evva-capacitor-secure-storage-plugin')
implementation project(':transistorsoft-capacitor-background-fetch')
implementation "androidx.webkit:webkit:1.4.0"
}
if (hasProperty('postBuildExtras')) {
postBuildExtras()
}

View File

@ -1,21 +0,0 @@
# 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

@ -1,26 +0,0 @@
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

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest 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"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:requestLegacyExternalStorage="true"
android:usesCleartextTraffic="true">
<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">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</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" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
</manifest>

View File

@ -1,31 +0,0 @@
package com.example.app;
import android.content.Context;
import android.util.Log;
import com.transistorsoft.tsbackgroundfetch.BackgroundFetch;
import com.transistorsoft.tsbackgroundfetch.BGTask;
public class BackgroundFetchHeadlessTask{
public void onFetch(Context context, BGTask task) {
// Get a reference to the BackgroundFetch Android API.
BackgroundFetch backgroundFetch = BackgroundFetch.getInstance(context);
// Get the taskId.
String taskId = task.getTaskId();
// Log a message to adb logcat.
Log.d("MyHeadlessTask", "BackgroundFetchHeadlessTask onFetch -- CUSTOM IMPLEMENTATION: " + taskId);
boolean isTimeout = task.getTimedOut();
// Is this a timeout?
if (isTimeout) {
backgroundFetch.finish(taskId);
return;
}
// Do your work here...
//
//
// Signal finish just like the Javascript API.
backgroundFetch.finish(taskId);
}
}

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,34 +0,0 @@
<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

@ -1,170 +0,0 @@
<?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.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

View File

@ -1,12 +0,0 @@
<?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

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

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

View File

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

View File

@ -1,22 +0,0 @@
<?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

@ -1,5 +0,0 @@
<?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

@ -1,18 +0,0 @@
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);
}
}

View File

@ -1,33 +0,0 @@
// 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.2.1'
classpath 'com.google.gms:google-services:4.4.0'
// 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()
maven {
// capacitor-background-fetch
url("${project(':transistorsoft-capacitor-background-fetch').projectDir}/libs")
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@ -1,18 +0,0 @@
// 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-browser'
project(':capacitor-browser').projectDir = new File('../node_modules/@capacitor/browser/android')
include ':capacitor-filesystem'
project(':capacitor-filesystem').projectDir = new File('../node_modules/@capacitor/filesystem/android')
include ':capacitor-local-notifications'
project(':capacitor-local-notifications').projectDir = new File('../node_modules/@capacitor/local-notifications/android')
include ':evva-capacitor-secure-storage-plugin'
project(':evva-capacitor-secure-storage-plugin').projectDir = new File('../node_modules/@evva/capacitor-secure-storage-plugin/android')
include ':transistorsoft-capacitor-background-fetch'
project(':transistorsoft-capacitor-background-fetch').projectDir = new File('../node_modules/@transistorsoft/capacitor-background-fetch/android')

View File

@ -1,22 +0,0 @@
# 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

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

248
android/gradlew vendored
View File

@ -1,248 +0,0 @@
#!/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
# 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
if ! command -v java >/dev/null 2>&1
then
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
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
# 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"'
# 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
View File

@ -1,92 +0,0 @@
@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

View File

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

View File

@ -1,16 +0,0 @@
ext {
minSdkVersion = 22
compileSdkVersion = 34
targetSdkVersion = 34
androidxActivityVersion = '1.8.0'
androidxAppCompatVersion = '1.6.1'
androidxCoordinatorLayoutVersion = '1.2.0'
androidxCoreVersion = '1.12.0'
androidxFragmentVersion = '1.6.2'
coreSplashScreenVersion = '1.0.1'
androidxWebkitVersion = '1.9.0'
junitVersion = '4.13.2'
androidxJunitVersion = '1.1.5'
androidxEspressoCoreVersion = '3.5.1'
cordovaAndroidVersion = '10.1.1'
}

View File

@ -1,15 +1,15 @@
import type { CapacitorConfig } from '@capacitor/cli';
import type { CapacitorConfig } from "@capacitor/cli";
const config: CapacitorConfig = {
appId: 'org.Qortal.Qortal-Hub',
appName: 'Qortal-Hub',
webDir: 'dist',
"plugins": {
"LocalNotifications": {
"smallIcon": "qort",
"iconColor": "#09b6e8"
}
}
appId: "org.Qortal.Qortal-Hub",
appName: "Qortal-Hub",
webDir: "dist",
plugins: {
LocalNotifications: {
smallIcon: "qort",
iconColor: "#09b6e8",
},
},
};
export default config;

BIN
dist.zip

Binary file not shown.

84
docs/contribution.md Normal file
View File

@ -0,0 +1,84 @@
# 🤝 Contributing Guide
Thank you for your interest in contributing! We follow a structured Git workflow to keep the project clean, stable, and production-ready at all times.
---
## 📦 Branch Overview
| Branch | Purpose |
|------------------|----------------------------------------------------------|
| `master` | Stable, production-ready code. All releases are tagged from here. |
| `develop` | Active development branch. All new features go here first. |
| `release/x.y.z` | Pre-release branch for staging, QA, and final polish. |
---
## 🌿 Creating a Feature or Fix
1. **Start from `develop`:**
```bash
git checkout develop
git checkout -b feature/your-feature-name
```
2. **Make your changes and commit them.**
3. **Push your branch:**
```bash
git push origin feature/your-feature-name
```
4. **Open a Pull Request into `develop`.**
---
## 🚀 Releasing Code (Maintainers Only)
A new `release/x.y.z` branch must be created for **every release**.
1. **Create a `release/` branch from `master`:**
```bash
git checkout master
git checkout -b release/1.2.0
```
2. **Merge in `develop` or selected branches if `develop` is not ready:**
```bash
git merge develop
# or
git merge feature/finished-feature
git merge feature/another-complete-feature
```
3. **Polish, test, and fix issues as needed.**
4. **Merge back into `develop`:**
```bash
git checkout develop
git merge release/1.2.0
git push origin develop
```
5. **Finalize the release:**
```bash
git checkout master
git merge release/1.2.0
git tag v1.2.0
git push origin master --tags
```
6. **Delete the release branch:**
```bash
git branch -d release/1.2.0
git push origin --delete release/1.2.0
```

10
docs/i18n_languages.md Normal file
View File

@ -0,0 +1,10 @@
# I18N Guidelines
In JSON file:
- Keep the file sorted
- Always write in lowercase
In GUI:
- If the first letter of the translation must be uppercase, use the postProcess, for example: `{t_auth('advanced_users', { postProcess: 'capitalize' })}`

View File

@ -1,15 +1,15 @@
import type { CapacitorConfig } from '@capacitor/cli';
import type { CapacitorConfig } from "@capacitor/cli";
const config: CapacitorConfig = {
appId: 'org.Qortal.Qortal-Hub',
appName: 'Qortal-Hub',
webDir: 'dist',
"plugins": {
"LocalNotifications": {
"smallIcon": "qort",
"iconColor": "#09b6e8"
}
}
appId: "org.Qortal.Qortal-Hub",
appName: "Qortal-Hub",
webDir: "dist",
plugins: {
LocalNotifications: {
smallIcon: "qort",
iconColor: "#09b6e8",
},
},
};
export default config;

View File

@ -1,6 +1,6 @@
{
"name": "qortal-hub",
"version": "0.5.3",
"version": "0.5.4-pre",
"description": "A desktop app that gives you access to the Qortal network",
"author": {
"name": "",
@ -57,4 +57,4 @@
"capacitor",
"electron"
]
}
}

58
i18n.js Normal file
View File

@ -0,0 +1,58 @@
import { initReactI18next } from 'react-i18next';
import HttpBackend from 'i18next-http-backend';
import LocalStorageBackend from 'i18next-localstorage-backend';
import HttpApi from 'i18next-http-backend';
import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
// Detect environment
const isDev = process.env.NODE_ENV === 'development';
// Register custom postProcessor: it capitalizes the first letter of a translation-
// Usage:
// t('greeting', { postProcess: 'capitalize' })
const capitalize = {
type: 'postProcessor',
name: 'capitalize',
process: (value) => {
return value.charAt(0).toUpperCase() + value.slice(1);
},
};
export const supportedLanguages = {
de: { name: 'Deutsch', flag: '🇩🇪' },
en: { name: 'English', flag: '🇺🇸' },
es: { name: 'Español', flag: '🇪🇸' },
fr: { name: 'Français', flag: '🇫🇷' },
it: { name: 'Italiano', flag: '🇮🇹' },
ru: { name: 'Русский', flag: '🇷🇺' },
};
i18n
.use(HttpApi)
.use(LanguageDetector)
.use(initReactI18next)
.use(capitalize)
.init({
backend: {
backends: [LocalStorageBackend, HttpBackend],
backendOptions: [
{
expirationTime: 7 * 24 * 60 * 60 * 1000, // 7 days
},
{
loadPath: '/locales/{{lng}}/{{ns}}.json',
},
],
},
debug: isDev,
fallbackLng: 'en',
interpolation: {
escapeValue: false,
},
lng: navigator.language,
ns: ['auth', 'core', 'group', 'tutorial'],
supportedLngs: Object.keys(supportedLanguages),
});
export default i18n;

View File

@ -1,12 +1,9 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Qortal Hub</title>
</head>
<body>

2164
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@
"scripts": {
"dev": "vite",
"build": "vite build",
"format": "prettier --write .",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"test": "vitest",
@ -19,32 +20,31 @@
"@capacitor/core": "^6.1.2",
"@capacitor/filesystem": "^6.0.1",
"@capacitor/local-notifications": "^6.1.0",
"@chatscope/chat-ui-kit-react": "^2.0.3",
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
"@dnd-kit/core": "^6.3.0",
"@dnd-kit/sortable": "^10.0.0",
"@electron/packager": "^18.3.6",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.0",
"@evva/capacitor-secure-storage-plugin": "^3.0.1",
"@mui/icons-material": "^5.16.4",
"@mui/lab": "^5.0.0-alpha.173",
"@mui/material": "^5.16.7",
"@reduxjs/toolkit": "^2.2.7",
"@tanstack/react-virtual": "^3.10.8",
"@mui/icons-material": "^7.0.1",
"@mui/lab": "^7.0.0-beta.11",
"@mui/material": "^7.0.1",
"@tanstack/react-virtual": "^3.13.6",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/user-event": "^14.5.2",
"@tiptap/extension-color": "^2.5.9",
"@tiptap/extension-highlight": "^2.6.6",
"@tiptap/extension-image": "^2.6.6",
"@tiptap/extension-mention": "^2.9.1",
"@tiptap/extension-placeholder": "^2.6.2",
"@tiptap/extension-text-style": "^2.5.9",
"@tiptap/extension-underline": "^2.6.6",
"@tiptap/pm": "^2.5.9",
"@tiptap/react": "^2.5.9",
"@tiptap/starter-kit": "^2.5.9",
"@testing-library/user-event": "^14.6.1",
"@tiptap/extension-color": "^2.11.7",
"@tiptap/extension-highlight": "^2.11.7",
"@tiptap/extension-image": "^2.11.7",
"@tiptap/extension-mention": "^2.11.7",
"@tiptap/extension-placeholder": "^2.11.7",
"@tiptap/extension-text-style": "^2.11.7",
"@tiptap/extension-underline": "^2.11.7",
"@tiptap/pm": "^2.11.7",
"@tiptap/react": "^2.11.7",
"@tiptap/starter-kit": "^2.11.7",
"@transistorsoft/capacitor-background-fetch": "^6.0.1",
"@types/chrome": "^0.0.263",
"@uiw/react-color": "^2.5.1",
"adm-zip": "^0.5.16",
"asmcrypto.js": "2.3.2",
"axios": "^1.7.7",
@ -60,29 +60,29 @@
"emoji-picker-react": "^4.12.0",
"file-saver": "^2.0.5",
"html-to-text": "^9.0.5",
"i18next": "^25.0.1",
"i18next-browser-languagedetector": "^8.0.5",
"i18next-http-backend": "^3.0.2",
"i18next-localstorage-backend": "^4.2.0",
"jotai": "^2.12.3",
"jssha": "3.3.1",
"lit": "^3.2.1",
"lodash": "^4.17.21",
"mime": "^4.0.4",
"moment": "^2.30.1",
"npm": "^10.8.3",
"quill-image-resize-module-react": "^3.0.0",
"react": "^18.2.0",
"react-copy-to-clipboard": "^5.1.0",
"react": "^19.1.0",
"react-countdown-circle-timer": "^3.2.1",
"react-dom": "^18.2.0",
"react-dom": "^19.1.0",
"react-dropzone": "^14.2.3",
"react-frame-component": "^5.2.7",
"react-infinite-scroller": "^1.2.6",
"react-intersection-observer": "^9.13.0",
"react-json-view-lite": "^2.0.1",
"react-i18next": "^15.4.1",
"react-intersection-observer": "^9.16.0",
"react-json-view-lite": "^2.4.1",
"react-loader-spinner": "^6.1.6",
"react-qr-code": "^2.0.15",
"react-quill": "^2.0.0",
"react-redux": "^9.1.2",
"react-virtualized": "^9.22.5",
"react-virtualized": "^9.22.6",
"react-virtuoso": "^4.10.4",
"recoil": "^0.7.7",
"short-unique-id": "^5.2.0",
"slate": "^0.103.0",
"slate-react": "^0.109.0",
@ -94,14 +94,12 @@
"vite-plugin-wasm": "^3.3.0"
},
"devDependencies": {
"@testing-library/dom": "^10.3.0",
"@testing-library/react": "^16.0.0",
"@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.3.0",
"@types/dompurify": "^3.0.5",
"@types/lodash": "^4.17.7",
"@types/react": "^18.2.64",
"@types/react-copy-to-clipboard": "^5.0.7",
"@types/react-dom": "^18.2.21",
"@types/react-infinite-scroller": "^1.2.5",
"@types/react": "^19.1.0",
"@types/react-dom": "^19.1.0",
"@types/react-virtualized": "^9.21.30",
"@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1",
@ -110,9 +108,16 @@
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5",
"prettier": "^3.5.3",
"rename-cli": "^6.2.1",
"typescript": "^5.2.2",
"vite": "^5.1.6",
"vitest": "^1.6.0"
"vitest": "^1.6.1"
},
"overrides": {
"react-loader-spinner": {
"react": "^18 || ^19",
"react-dom": "^18 || ^19"
}
}
}

View File

@ -0,0 +1,43 @@
{
"account": {
"your": "ihr Konto",
"account_many": "Konten",
"account_one": "Konto"
},
"advanced_users": "für fortgeschrittene Benutzer",
"apikey": {
"alternative": "Alternative: Datei auswählen",
"change": "API-Schlüssel ändern",
"enter": "API-Schlüssel eingeben",
"import": "API-Schlüssel importieren",
"key": "API-Schlüssel",
"select_valid": "gültigen API-Schlüssel auswählen"
},
"authenticate": "authentifizieren",
"build_version": "Build-Version",
"create_account": "Konto erstellen",
"download_account": "Konto herunterladen",
"keep_secure": "Bewahren Sie Ihre Kontodatei sicher auf",
"node": {
"choose": "benutzerdefinierten Node auswählen",
"custom_many": "benutzerdefinierte Nodes",
"use_custom": "benutzerdefinierten Node verwenden",
"use_local": "lokalen Node verwenden",
"using": "verwende Node",
"using_public": "öffentlichen Node verwenden"
},
"password": "Passwort",
"password_confirmation": "Passwort bestätigen",
"return_to_list": "zurück zur Liste",
"wallet": {
"password_confirmation": "Wallet-Passwort bestätigen",
"password": "Wallet-Passwort",
"keep_password": "aktuelles Passwort beibehalten",
"new_password": "neues Passwort",
"error": {
"missing_new_password": "bitte neues Passwort eingeben",
"missing_password": "bitte Passwort eingeben"
}
},
"welcome": "willkommen bei"
}

View File

@ -0,0 +1,71 @@
{
"add": "hinzufügen",
"cancel": "abbrechen",
"choose": "auswählen",
"close": "schließen",
"continue": "fortfahren",
"core": {
"block_height": "Blockhöhe",
"information": "Kerninformationen",
"peers": "verbundene Peers",
"version": "Kernversion"
},
"description": "Beschreibung",
"edit": "bearbeiten",
"export": "exportieren",
"import": "importieren",
"last_height": "letzte Höhe",
"loading": "Lade...",
"logout": "abmelden",
"minting_status": "Präge-Status",
"payment_notification": "Zahlungsbenachrichtigung",
"price": "Preis",
"q_mail": "Q-Mail",
"result": {
"error": {
"generic": "Ein Fehler ist aufgetreten",
"incorrect_password": "Falsches Passwort",
"save_qdn": "Speichern in QDN nicht möglich"
},
"status": {
"minting": "(Prägung)",
"not_minting": "(keine Prägung)",
"synchronized": "synchronisiert",
"synchronizing": "synchronisiere"
},
"success": {
"publish_qdn": "Erfolgreich in QDN veröffentlicht"
}
},
"save_options": {
"no_pinned_changes": "Derzeit keine Änderungen an Ihren angehefteten Apps",
"overwrite_changes": "Die App konnte Ihre vorhandenen in QDN gespeicherten angehefteten Apps nicht herunterladen. Möchten Sie diese Änderungen überschreiben?",
"overwrite_qdn": "In QDN überschreiben",
"publish_qdn": "Möchten Sie Ihre Einstellungen in QDN (verschlüsselt) veröffentlichen?",
"qdn": "QDN-Speicherung verwenden",
"register_name": "Sie benötigen einen registrierten Qortal-Namen, um Ihre angehefteten Apps in QDN zu speichern.",
"reset_pinned": "Gefällt Ihnen Ihre aktuellen lokalen Änderungen nicht? Möchten Sie zu den Standard-Anheftungen zurückkehren?",
"reset_qdn": "Gefällt Ihnen Ihre aktuellen lokalen Änderungen nicht? Möchten Sie zu Ihren in QDN gespeicherten Anheftungen zurückkehren?",
"revert_default": "Auf Standard zurücksetzen",
"revert_qdn": "Auf QDN zurücksetzen",
"save_qdn": "In QDN speichern",
"save": "speichern",
"settings": "Sie verwenden die Export/Import-Methode zum Speichern von Einstellungen.",
"unsaved_changes": "Sie haben nicht gespeicherte Änderungen an Ihren angehefteten Apps. Speichern Sie sie in QDN."
},
"settings": "Einstellungen",
"supply": "Angebot",
"theme": {
"dark": "Dunkelmodus",
"light": "Hellmodus"
},
"title": "Titel",
"tutorial": "Tutorial",
"user_lookup": "Benutzersuche",
"wallet": {
"backup_wallet": "Wallet sichern",
"wallet": "Wallet",
"wallet_other": "Wallets"
},
"welcome": "Willkommen"
}

View File

@ -0,0 +1,21 @@
{
"1_getting_started": "1. Erste Schritte",
"2_overview": "2. Überblick",
"3_groups": "3. Qortal-Gruppen",
"4_obtain_qort": "4. QORT erhalten",
"account_creation": "Kontoerstellung",
"important_info": "wichtige Informationen!",
"apps": {
"dashboard": "1. App-Dashboard",
"navigation": "2. App-Navigation"
},
"initial": {
"6_qort": "mindestens 6 QORT im Wallet haben",
"explore": "erkunden",
"general_chat": "allgemeiner Chat",
"getting_started": "erste Schritte",
"register_name": "einen Namen registrieren",
"see_apps": "apps ansehen",
"trade_qort": "QORT handeln"
}
}

View File

@ -0,0 +1,48 @@
{
"account": {
"your": "your account",
"account_many": "accounts",
"account_one": "account"
},
"advanced_users": "for advanced users",
"apikey": {
"alternative": "alternative: File select",
"change": "change APIkey",
"enter": "enter APIkey",
"import": "import APIkey",
"key": "API key",
"select_valid": "select a valid apikey"
},
"authenticate": "authenticate",
"build_version": "build version",
"create_account": "create account",
"download_account": "download account",
"keep_secure": "keep your account file secure",
"node": {
"choose": "choose custom node",
"custom_many": "custom nodes",
"use_custom": "use custom node",
"use_local": "use local node",
"using": "using node",
"using_public": "using public node"
},
"password": "password",
"password_confirmation": "confirm password",
"return_to_list": "return to list",
"tips": {
"digital_id": "your wallet is like your digital ID on Qortal, and is how you will login to the Qortal User Interface. It holds your public address and the Qortal name you will eventually choose. Every transaction you make is linked to your ID, and this is where you manage all your QORT and other tradeable cryptocurrencies on Qortal.",
"new_account": "creating an account means creating a new wallet and digital ID to start using Qortal. Once you have made your account, you can start doing things like obtaining some QORT, buying a name and avatar, publishing videos and blogs, and much more.",
"new_users": "new users start here!"
},
"wallet": {
"password_confirmation": "confirm wallet password",
"password": "wallet password",
"keep_password": "keep current password",
"new_password": "new password",
"error": {
"missing_new_password": "please enter a new password",
"missing_password": "please enter your password"
}
},
"welcome": "welcome to"
}

111
public/locales/en/core.json Normal file
View File

@ -0,0 +1,111 @@
{
"action": {
"add": "add",
"accept": "accept",
"backup_account": "backup account",
"backup_wallet": "backup wallet",
"cancel": "cancel",
"change": "change",
"change_language": "change language",
"choose": "choose",
"close": "close",
"continue": "continue",
"continue_logout": "continue to logout",
"decline": "decline",
"edit": "edit",
"export": "export",
"import": "import",
"invite": "invite",
"join": "join",
"logout": "logout",
"notify": "notify"
},
"core": {
"block_height": "block height",
"information": "core information",
"peers": "connected peers",
"version": "core version"
},
"count": {
"none": "none",
"one": "one"
},
"description": "description",
"fee": {
"payment": "payment fee",
"publish": "publish fee"
},
"page": {
"last": "last",
"first": "first",
"next": "next",
"previous": "previous"
},
"downloading_qdn": "downloading from QDN",
"last_height": "last height",
"loading": "loading...",
"loading_posts": "loading posts... please wait.",
"message_us": "please message us on Telegram or Discord if you need 4 QORT to start chatting without any limitations",
"minting_status": "minting status",
"new_user": "are you a new user?",
"payment_notification": "payment notification",
"price": "price",
"q_mail": "q-mail",
"message": {
"error": {
"generic": "an error occurred",
"incorrect_password": "incorrect password",
"save_qdn": "unable to save to QDN"
},
"status": {
"minting": "(minting)",
"not_minting": "(not minting)",
"synchronized": "synchronized",
"synchronizing": "synchronizing"
},
"success": {
"order_submitted": "your buy order was submitted",
"publish_qdn": "successfully published to QDN",
"request_read": "I have read this request",
"transfer": "the transfer was succesful!"
}
},
"save_options": {
"no_pinned_changes": "you currently do not have any changes to your pinned apps",
"overwrite_changes": "the app was unable to download your existing QDN-saved pinned apps. Would you like to overwrite those changes?",
"overwrite_qdn": "overwrite to QDN",
"publish_qdn": "would you like to publish your settings to QDN (encrypted)?",
"qdn": "use QDN saving",
"register_name": "you need a registered Qortal name to save your pinned apps to QDN.",
"reset_pinned": "don't like your current local changes? Would you like to reset to the default pinned apps?",
"reset_qdn": "don't like your current local changes? Would you like to reset to your saved QDN pinned apps?",
"revert_default": "revert to default",
"revert_qdn": "revert to QDN",
"save_qdn": "save to QDN",
"save": "save",
"settings": "you are using the export/import way of saving settings.",
"unsaved_changes": " you have unsaved changes to your pinned apps. Save them to QDN."
},
"settings": "settings",
"supply": "supply",
"theme": {
"dark": "dark mode",
"light": "light mode"
},
"time": {
"day_one": "{{count}} day",
"day_other": "{{count}} days",
"hour_one": "{{count}} hour",
"hour_other": "{{count}} hours",
"minute_one": "{{count}} minute",
"minute_other": "{{count}} minutes"
},
"title": "title",
"tutorial": "tutorial",
"user_lookup": "user lookup",
"wallet": {
"wallet": "wallet",
"wallet_other": "wallets"
},
"welcome": "welcome"
}

View File

@ -0,0 +1,65 @@
{
"action": {
"cancel_ban": "cancel ban",
"create_group": "create group",
"find_group": "find group",
"join_group": "join group",
"invite_member": "invite member",
"refetch_page": "refetch page",
"return_to_thread": "return to threads"
},
"advanced_options": "advanced options",
"approval_threshold": "group Approval Threshold (number / percentage of Admins that must approve a transaction)",
"ban_list": "ban list",
"block_delay": {
"minimum": "minimum Block delay for Group Transaction Approvals",
"maximum": "maximum Block delay for Group Transaction Approvals"
},
"group": {
"closed": "closed (private) - users need permission to join",
"description": "description of group",
"invites": "group invites",
"management": "group management",
"name": "name of group",
"open": "open (public)",
"type": "group type"
},
"invitation_expiry": "invitation Expiry Time",
"join_requests": "join requests",
"question": {
"cancel_ban": "would you like to perform a CANCEL_GROUP_BAN transaction?",
"create_group": "would you like to perform an CREATE_GROUP transaction?",
"group_invite": "would you like to perform a GROUP_INVITE transaction?",
"join_group": "would you like to perform an JOIN_GROUP transaction?",
"provide_thread": "please provide a thread title"
},
"message": {
"generic": {
"encryption_key": "the group's first common encryption key is in the process of creation. Please wait a few minutes for it to be retrieved by the network. Checking every 2 minutes...",
"group_invited_you": "{{group}} has invited you",
"no_display": "nothing to display",
"no_selection": "no group selected",
"not_part_group": "you are not part of the encrypted group of members. Wait until an admin re-encrypts the keys.",
"only_encrypted": "only unencrypted messages will be displayed.",
"setting_group": "setting up group... please wait."
},
"error": {
"access_name": "cannot send a message without a access to your name",
"description_required": "please provide a description",
"group_info": "cannot access group information",
"name_required": "please provide a name",
"notify_admins": "try notifying an admin from the list of admins below:"
},
"success": {
"group_creation": "successfully created group. It may take a couple of minutes for the changes to propagate",
"group_creation_name": "created group {{group_name}}: awaiting confirmation",
"group_creation_label": "created group {{name}}: success!",
"group_invite": "successfully invited {{value}}. It may take a couple of minutes for the changes to propagate",
"join_creation": "successfully requested to join group. It may take a couple of minutes for the changes to propagate",
"group_join_name": "joined group {{group_name}}: awaiting confirmation",
"group_join_label": "joined group {{name}}: success!",
"loading_threads": "loading threads... please wait.",
"unbanned_user": "successfully unbanned user. It may take a couple of minutes for the changes to propagate"
}
}
}

View File

@ -0,0 +1,21 @@
{
"1_getting_started": "1. Getting Started",
"2_overview": "2. Overview",
"3_groups": "3. Qortal Groups",
"4_obtain_qort": "4. Obtaining Qort",
"account_creation": "account creation",
"important_info": "important information!",
"apps": {
"dashboard": "1. Apps Dashboard",
"navigation": "2. Apps Navigation"
},
"initial": {
"6_qort": "have at least 6 QORT in your wallet",
"explore": "explore",
"general_chat": "general chat",
"getting_started": "getting started",
"register_name": "register a name",
"see_apps": "see apps",
"trade_qort": "trade QORT"
}
}

View File

@ -0,0 +1,43 @@
{
"account": {
"your": "tu cuenta",
"account_many": "cuentas",
"account_one": "cuenta"
},
"advanced_users": "para usuarios avanzados",
"apikey": {
"alternative": "alternativa: Seleccionar archivo",
"change": "cambiar clave API",
"enter": "ingresar clave API",
"import": "importar clave API",
"key": "clave API",
"select_valid": "selecciona una clave API válida"
},
"authenticate": "autenticar",
"build_version": "versión de compilación",
"create_account": "crear cuenta",
"download_account": "descargar cuenta",
"keep_secure": "mantén tu archivo de cuenta seguro",
"node": {
"choose": "elegir nodo personalizado",
"custom_many": "nodos personalizados",
"use_custom": "usar nodo personalizado",
"use_local": "usar nodo local",
"using": "usando nodo",
"using_public": "usando nodo público"
},
"password": "contraseña",
"password_confirmation": "confirmar contraseña",
"return_to_list": "volver a la lista",
"wallet": {
"password_confirmation": "confirmar contraseña del monedero",
"password": "contraseña del monedero",
"keep_password": "mantener la contraseña actual",
"new_password": "nueva contraseña",
"error": {
"missing_new_password": "por favor ingresa una nueva contraseña",
"missing_password": "por favor ingresa tu contraseña"
}
},
"welcome": "bienvenido a"
}

View File

@ -0,0 +1,71 @@
{
"add": "agregar",
"cancel": "cancelar",
"choose": "elegir",
"close": "cerrar",
"continue": "continuar",
"core": {
"block_height": "altura de bloque",
"information": "información del núcleo",
"peers": "pares conectados",
"version": "versión del núcleo"
},
"description": "descripción",
"edit": "editar",
"export": "exportar",
"import": "importar",
"last_height": "última altura",
"loading": "cargando...",
"logout": "cerrar sesión",
"minting_status": "estado de acuñación",
"payment_notification": "notificación de pago",
"price": "precio",
"q_mail": "q-mail",
"result": {
"error": {
"generic": "ocurrió un error",
"incorrect_password": "contraseña incorrecta",
"save_qdn": "no se pudo guardar en QDN"
},
"status": {
"minting": "(acuñando)",
"not_minting": "(no acuñando)",
"synchronized": "sincronizado",
"synchronizing": "sincronizando"
},
"success": {
"publish_qdn": "publicado exitosamente en QDN"
}
},
"save_options": {
"no_pinned_changes": "actualmente no tienes cambios en tus aplicaciones fijadas",
"overwrite_changes": "la aplicación no pudo descargar tus aplicaciones fijadas existentes guardadas en QDN. ¿Deseas sobrescribir esos cambios?",
"overwrite_qdn": "sobrescribir en QDN",
"publish_qdn": "¿Deseas publicar tus configuraciones en QDN (cifrado)?",
"qdn": "usar guardado en QDN",
"register_name": "necesitas un nombre Qortal registrado para guardar tus aplicaciones fijadas en QDN.",
"reset_pinned": "¿No te gustan tus cambios locales actuales? ¿Deseas restablecer las aplicaciones fijadas predeterminadas?",
"reset_qdn": "¿No te gustan tus cambios locales actuales? ¿Deseas restablecer tus aplicaciones fijadas guardadas en QDN?",
"revert_default": "restablecer a predeterminado",
"revert_qdn": "restablecer a QDN",
"save_qdn": "guardar en QDN",
"save": "guardar",
"settings": "estás utilizando el método de exportación/importación para guardar configuraciones.",
"unsaved_changes": "tienes cambios no guardados en tus aplicaciones fijadas. Guárdalos en QDN."
},
"settings": "configuraciones",
"supply": "suministro",
"theme": {
"dark": "modo oscuro",
"light": "modo claro"
},
"title": "título",
"tutorial": "tutorial",
"user_lookup": "búsqueda de usuario",
"wallet": {
"backup_wallet": "respaldar billetera",
"wallet": "billetera",
"wallet_other": "billeteras"
},
"welcome": "bienvenido"
}

View File

@ -0,0 +1,21 @@
{
"1_getting_started": "1. Comenzando",
"2_overview": "2. Visión general",
"3_groups": "3. Grupos de Qortal",
"4_obtain_qort": "4. Obtener QORT",
"account_creation": "creación de cuenta",
"important_info": "¡información importante!",
"apps": {
"dashboard": "1. Panel de aplicaciones",
"navigation": "2. Navegación de aplicaciones"
},
"initial": {
"6_qort": "tener al menos 6 QORT en tu monedero",
"explore": "explorar",
"general_chat": "chat general",
"getting_started": "comenzando",
"register_name": "registrar un nombre",
"see_apps": "ver aplicaciones",
"trade_qort": "intercambiar QORT"
}
}

View File

@ -0,0 +1,43 @@
{
"account": {
"your": "ton compte",
"account_many": "comptes",
"account_one": "compte"
},
"advanced_users": "pour les utilisateurs avancés",
"apikey": {
"alternative": "alternative : Sélectionner un fichier",
"change": "changer la clé API",
"enter": "entrer la clé API",
"import": "importer la clé API",
"key": "clé API",
"select_valid": "sélectionnez une clé API valide"
},
"authenticate": "authentifier",
"build_version": "version de build",
"create_account": "créer un compte",
"download_account": "télécharger le compte",
"keep_secure": "Gardez votre fichier de compte en sécurité",
"node": {
"choose": "choisir un nœud personnalisé",
"custom_many": "nœuds personnalisés",
"use_custom": "utiliser un nœud personnalisé",
"use_local": "utiliser un nœud local",
"using": "utilise le nœud",
"using_public": "utilise un nœud public"
},
"password": "mot de passe",
"password_confirmation": "confirmer le mot de passe",
"return_to_list": "retour à la liste",
"wallet": {
"password_confirmation": "confirmer le mot de passe du portefeuille",
"password": "mot de passe du portefeuille",
"keep_password": "garder le mot de passe actuel",
"new_password": "nouveau mot de passe",
"error": {
"missing_new_password": "veuillez entrer un nouveau mot de passe",
"missing_password": "veuillez entrer votre mot de passe"
}
},
"welcome": "bienvenue sur"
}

View File

@ -0,0 +1,71 @@
{
"add": "ajouter",
"cancel": "annuler",
"choose": "choisir",
"close": "fermer",
"continue": "continuer",
"core": {
"block_height": "hauteur de bloc",
"information": "informations du noyau",
"peers": "pairs connectés",
"version": "version du noyau"
},
"description": "description",
"edit": "éditer",
"export": "exporter",
"import": "importer",
"last_height": "dernière hauteur",
"loading": "chargement...",
"logout": "se déconnecter",
"minting_status": "statut de frappe",
"payment_notification": "notification de paiement",
"price": "prix",
"q_mail": "q-mail",
"result": {
"error": {
"generic": "une erreur s'est produite",
"incorrect_password": "mot de passe incorrect",
"save_qdn": "impossible d'enregistrer dans QDN"
},
"status": {
"minting": "(frappe en cours)",
"not_minting": "(pas de frappe)",
"synchronized": "synchronisé",
"synchronizing": "synchronisation en cours"
},
"success": {
"publish_qdn": "publié avec succès dans QDN"
}
},
"save_options": {
"no_pinned_changes": "vous n'avez actuellement aucune modification de vos applications épinglées",
"overwrite_changes": "l'application n'a pas pu télécharger vos applications épinglées existantes enregistrées dans QDN. Voulez-vous écraser ces modifications ?",
"overwrite_qdn": "écraser dans QDN",
"publish_qdn": "souhaitez-vous publier vos paramètres dans QDN (chiffré) ?",
"qdn": "utiliser l'enregistrement QDN",
"register_name": "vous devez avoir un nom Qortal enregistré pour enregistrer vos applications épinglées dans QDN.",
"reset_pinned": "vous n'aimez pas vos modifications locales actuelles ? Voulez-vous réinitialiser les applications épinglées par défaut ?",
"reset_qdn": "vous n'aimez pas vos modifications locales actuelles ? Voulez-vous réinitialiser vos applications épinglées enregistrées dans QDN ?",
"revert_default": "revenir aux paramètres par défaut",
"revert_qdn": "revenir à QDN",
"save_qdn": "enregistrer dans QDN",
"save": "enregistrer",
"settings": "vous utilisez la méthode d'exportation/importation pour enregistrer les paramètres.",
"unsaved_changes": "vous avez des modifications non enregistrées de vos applications épinglées. Enregistrez-les dans QDN."
},
"settings": "paramètres",
"supply": "approvisionnement",
"theme": {
"dark": "mode sombre",
"light": "mode clair"
},
"title": "titre",
"tutorial": "tutoriel",
"user_lookup": "recherche d'utilisateur",
"wallet": {
"backup_wallet": "sauvegarder le portefeuille",
"wallet": "portefeuille",
"wallet_other": "portefeuilles"
},
"welcome": "bienvenue"
}

View File

@ -0,0 +1,21 @@
{
"1_getting_started": "1. Démarrer",
"2_overview": "2. Aperçu",
"3_groups": "3. Groupes Qortal",
"4_obtain_qort": "4. Obtenir des QORT",
"account_creation": "création de compte",
"important_info": "informations importantes !",
"apps": {
"dashboard": "1. Tableau de bord des applications",
"navigation": "2. Navigation des applications"
},
"initial": {
"6_qort": "avoir au moins 6 QORT dans votre portefeuille",
"explore": "explorer",
"general_chat": "chat général",
"getting_started": "démarrer",
"register_name": "enregistrer un nom",
"see_apps": "voir les applications",
"trade_qort": "échanger des QORT"
}
}

View File

@ -0,0 +1,48 @@
{
"account": {
"your": "il tuo account",
"account_many": "account",
"account_one": "account"
},
"advanced_users": "per utenti avanzati",
"apikey": {
"alternative": "alternativa: selezione file",
"change": "cambia APIkey",
"enter": "inserisci APIkey",
"import": "importa APIkey",
"key": "chiave API",
"select_valid": "seleziona una APIkey valida"
},
"authenticate": "autentica",
"build_version": "versione build",
"create_account": "crea account",
"download_account": "scarica account",
"keep_secure": "mantieni sicuro il file del tuo account",
"node": {
"choose": "scegli nodo personalizzato",
"custom_many": "nodi personalizzati",
"use_custom": "usa nodo personalizzato",
"use_local": "usa nodo locale",
"using": "utilizzo nodo",
"using_public": "utilizzo nodo pubblico"
},
"password": "password",
"password_confirmation": "conferma password",
"return_to_list": "torna alla lista",
"tips": {
"digital_id": "il tuo wallet è come la tua identità digitale su Qortal ed è il modo in cui accederai all'interfaccia utente di Qortal. Contiene il tuo indirizzo pubblico e il nome Qortal che sceglierai. Ogni transazione che esegui è collegata alla tua identità ed è qui che gestisci tutti i tuoi QORT e altre criptovalute scambiabili su Qortal.",
"new_account": "creare un account significa creare un nuovo wallet e un'identità digitale per iniziare a usare Qortal. Una volta creato l'account, potrai iniziare a ottenere QORT, acquistare un nome e un avatar, pubblicare video e blog, e molto altro.",
"new_users": "i nuovi utenti iniziano qui!"
},
"wallet": {
"password_confirmation": "conferma password del wallet",
"password": "password del wallet",
"keep_password": "mantieni password corrente",
"new_password": "nuova password",
"error": {
"missing_new_password": "per favore inserisci una nuova password",
"missing_password": "per favore inserisci la tua password"
}
},
"welcome": "benvenuto in"
}

111
public/locales/it/core.json Normal file
View File

@ -0,0 +1,111 @@
{
"action": {
"add": "aggiungi",
"accept": "accetta",
"backup_account": "backup account",
"backup_wallet": "backup wallet",
"cancel": "annulla",
"change": "cambia",
"change_language": "cambia lingua",
"choose": "scegli",
"close": "chiudi",
"continue": "continua",
"continue_logout": "continua con il logout",
"decline": "rifiuta",
"edit": "modifica",
"export": "esporta",
"import": "importa",
"invite": "invita",
"join": "unisciti",
"logout": "esci",
"notify": "notifica"
},
"core": {
"block_height": "altezza blocco",
"information": "informazioni core",
"peers": "peer connessi",
"version": "versione core"
},
"count": {
"none": "nessuno",
"one": "uno"
},
"description": "descrizione",
"fee": {
"payment": "commissione di pagamento",
"publish": "commissione di pubblicazione"
},
"page": {
"last": "ultimo",
"first": "primo",
"next": "successivo",
"previous": "precedente"
},
"downloading_qdn": "scaricamento da QDN",
"last_height": "ultima altezza",
"loading": "caricamento...",
"loading_posts": "caricamento post... attendere prego.",
"message_us": "per favore scrivici su Telegram o Discord se hai bisogno di 4 QORT per iniziare a chattare senza limitazioni",
"minting_status": "stato minting",
"new_user": "sei un nuovo utente?",
"payment_notification": "notifica di pagamento",
"price": "prezzo",
"q_mail": "q-mail",
"message": {
"error": {
"generic": "si è verificato un errore",
"incorrect_password": "password errata",
"save_qdn": "impossibile salvare su QDN"
},
"status": {
"minting": "(minting)",
"not_minting": "(non minting)",
"synchronized": "sincronizzato",
"synchronizing": "sincronizzazione in corso"
},
"success": {
"order_submitted": "il tuo ordine di acquisto è stato inviato",
"publish_qdn": "pubblicato su QDN con successo",
"request_read": "ho letto questa richiesta",
"transfer": "il trasferimento è stato effettuato con successo!"
}
},
"save_options": {
"no_pinned_changes": "attualmente non hai modifiche alle tue app appuntate",
"overwrite_changes": "l'app non è riuscita a scaricare le tue app appuntate salvate su QDN. Vuoi sovrascrivere le modifiche?",
"overwrite_qdn": "sovrascrivi su QDN",
"publish_qdn": "vuoi pubblicare le tue impostazioni su QDN (crittografato)?",
"qdn": "usa il salvataggio su QDN",
"register_name": "devi avere un nome Qortal registrato per salvare le tue app appuntate su QDN.",
"reset_pinned": "non ti piacciono le modifiche locali attuali? Vuoi ripristinare le app appuntate predefinite?",
"reset_qdn": "non ti piacciono le modifiche locali attuali? Vuoi ripristinare le app appuntate salvate su QDN?",
"revert_default": "ripristina predefinito",
"revert_qdn": "ripristina da QDN",
"save_qdn": "salva su QDN",
"save": "salva",
"settings": "stai usando il metodo di esportazione/importazione per salvare le impostazioni.",
"unsaved_changes": "hai modifiche non salvate alle tue app appuntate. Salvale su QDN."
},
"settings": "impostazioni",
"supply": "disponibilità",
"theme": {
"dark": "modalità scura",
"light": "modalità chiara"
},
"time": {
"day_one": "{{count}} giorno",
"day_other": "{{count}} giorni",
"hour_one": "{{count}} ora",
"hour_other": "{{count}} ore",
"minute_one": "{{count}} minuto",
"minute_other": "{{count}} minuti"
},
"title": "titolo",
"tutorial": "tutorial",
"user_lookup": "ricerca utente",
"wallet": {
"wallet": "wallet",
"wallet_other": "wallet"
},
"welcome": "benvenuto"
}

View File

@ -0,0 +1,65 @@
{
"action": {
"cancel_ban": "annulla ban",
"create_group": "crea gruppo",
"find_group": "trova gruppo",
"join_group": "unisciti al gruppo",
"invite_member": "invita membro",
"refetch_page": "ricarica pagina",
"return_to_thread": "torna ai thread"
},
"advanced_options": "opzioni avanzate",
"approval_threshold": "soglia di Approvazione del gruppo (numero/percentuale di Admin che devono approvare una transazione)",
"ban_list": "lista ban",
"block_delay": {
"minimum": "ritardo minimo dei blocchi per Approvazione di Transazioni di Gruppo",
"maximum": "ritardo massimo dei blocchi per Approvazione di Transazioni di Gruppo"
},
"group": {
"closed": "chiuso (privato) - gli utenti necessitano di permesso per unirsi",
"description": "descrizione del gruppo",
"invites": "inviti del gruppo",
"management": "gestione del gruppo",
"name": "nome del gruppo",
"open": "aperto (pubblico)",
"type": "tipo di gruppo"
},
"invitation_expiry": "tempo di scadenza dell'invito",
"join_requests": "richieste di adesione",
"question": {
"cancel_ban": "vuoi eseguire una transazione CANCEL_GROUP_BAN?",
"create_group": "vuoi eseguire una transazione CREATE_GROUP?",
"group_invite": "vuoi eseguire una transazione GROUP_INVITE?",
"join_group": "vuoi eseguire una transazione JOIN_GROUP?",
"provide_thread": "per favore fornisci un titolo per il thread"
},
"message": {
"generic": {
"encryption_key": "la prima chiave di cifratura comune del gruppo è in fase di creazione. Attendere alcuni minuti affinché venga recuperata dalla rete. Controllo ogni 2 minuti...",
"group_invited_you": "{{group}} ti ha invitato",
"no_display": "niente da visualizzare",
"no_selection": "nessun gruppo selezionato",
"not_part_group": "non fai parte del gruppo cifrato dei membri. Attendi che un amministratore ri-codifichi le chiavi.",
"only_encrypted": "verranno visualizzati solo i messaggi non cifrati.",
"setting_group": "configurazione del gruppo... attendere prego."
},
"error": {
"access_name": "impossibile inviare un messaggio senza accesso al tuo nome",
"description_required": "per favore fornisci una descrizione",
"group_info": "impossibile accedere alle informazioni del gruppo",
"name_required": "per favore fornisci un nome",
"notify_admins": "prova a notificare un admin dalla lista di amministratori qui sotto:"
},
"success": {
"group_creation": "gruppo creato con successo. Potrebbero volerci alcuni minuti affinché le modifiche si propaghino",
"group_creation_name": "gruppo {{group_name}} creato: in attesa di conferma",
"group_creation_label": "gruppo {{name}} creato: successo!",
"group_invite": "invito inviato con successo a {{value}}. Potrebbero volerci alcuni minuti affinché le modifiche si propaghino",
"join_creation": "richiesta di adesione al gruppo inviata con successo. Potrebbero volerci alcuni minuti affinché le modifiche si propaghino",
"group_join_name": "entrato nel gruppo {{group_name}}: in attesa di conferma",
"group_join_label": "entrato nel gruppo {{name}}: successo!",
"loading_threads": "caricamento thread... attendere prego.",
"unbanned_user": "utente sbannato con successo. Potrebbero volerci alcuni minuti affinché le modifiche si propaghino"
}
}
}

View File

@ -0,0 +1,21 @@
{
"1_getting_started": "1. Come iniziare",
"2_overview": "2. Overview",
"3_groups": "3. I gruppi in Qortal",
"4_obtain_qort": "4. Ottenere Qort",
"account_creation": "creazione account",
"important_info": "important information!",
"apps": {
"dashboard": "1. Dashboard delle app",
"navigation": "2. Navigation tra le app"
},
"initial": {
"6_qort": "avere almeno 6 QORT nel proprio wallet",
"explore": "esplora",
"general_chat": "chat generale",
"getting_started": "come iniziare",
"register_name": "registra un nome",
"see_apps": "vedi le apps",
"trade_qort": "scambia i QORT"
}
}

View File

@ -0,0 +1,43 @@
{
"account": {
"your": "Ваш аккаунт",
"account_many": "аккаунты",
"account_one": "аккаунт"
},
"advanced_users": "для продвинутых пользователей",
"apikey": {
"alternative": "альтернатива: выбрать файл",
"change": "изменить API-ключ",
"enter": "введите API-ключ",
"import": "импортировать API-ключ",
"key": "API-ключ",
"select_valid": "выберите действительный API-ключ"
},
"authenticate": "аутентификация",
"build_version": "версия сборки",
"create_account": "создать аккаунт",
"download_account": "скачать аккаунт",
"keep_secure": "Храните файл аккаунта в безопасности",
"node": {
"choose": "выбрать пользовательский узел",
"custom_many": "пользовательские узлы",
"use_custom": "использовать пользовательский узел",
"use_local": "использовать локальный узел",
"using": "используется узел",
"using_public": "используется публичный узел"
},
"password": "пароль",
"password_confirmation": "подтвердите пароль",
"return_to_list": "вернуться к списку",
"wallet": {
"password_confirmation": "подтвердите пароль кошелька",
"password": "пароль кошелька",
"keep_password": "сохранить текущий пароль",
"new_password": "новый пароль",
"error": {
"missing_new_password": "пожалуйста, введите новый пароль",
"missing_password": "пожалуйста, введите ваш пароль"
}
},
"welcome": "добро пожаловать в"
}

View File

@ -0,0 +1,71 @@
{
"add": "добавить",
"cancel": "отмена",
"choose": "выбрать",
"close": "закрыть",
"continue": "продолжить",
"core": {
"block_height": "высота блока",
"information": "информация ядра",
"peers": "подключенные узлы",
"version": "версия ядра"
},
"description": "описание",
"edit": "редактировать",
"export": "экспорт",
"import": "импорт",
"last_height": "последняя высота",
"loading": "загрузка...",
"logout": "выйти",
"minting_status": "статус чеканки",
"payment_notification": "уведомление о платеже",
"price": "цена",
"q_mail": "q-mail",
"result": {
"error": {
"generic": "произошла ошибка",
"incorrect_password": "неверный пароль",
"save_qdn": "не удалось сохранить в QDN"
},
"status": {
"minting": "(чеканка)",
"not_minting": "(не чеканится)",
"synchronized": "синхронизировано",
"synchronizing": "синхронизация"
},
"success": {
"publish_qdn": "успешно опубликовано в QDN"
}
},
"save_options": {
"no_pinned_changes": "у вас нет изменений в закреплённых приложениях",
"overwrite_changes": "приложению не удалось загрузить ваши закреплённые приложения, сохранённые в QDN. Хотите перезаписать эти изменения?",
"overwrite_qdn": "перезаписать в QDN",
"publish_qdn": "хотите опубликовать свои настройки в QDN (зашифровано)?",
"qdn": "использовать сохранение в QDN",
"register_name": "вам необходимо зарегистрированное имя Qortal для сохранения закреплённых приложений в QDN.",
"reset_pinned": "не устраивают текущие локальные изменения? Хотите сбросить до приложений по умолчанию?",
"reset_qdn": "не устраивают текущие локальные изменения? Хотите сбросить до сохранённых в QDN приложений?",
"revert_default": "сбросить до стандартных",
"revert_qdn": "сбросить до QDN",
"save_qdn": "сохранить в QDN",
"save": "сохранить",
"settings": "вы используете метод экспорта/импорта для сохранения настроек.",
"unsaved_changes": "у вас есть несохранённые изменения в закреплённых приложениях. Сохраните их в QDN."
},
"settings": "настройки",
"supply": "предложение",
"theme": {
"dark": "тёмная тема",
"light": "светлая тема"
},
"title": "заголовок",
"tutorial": "учебник",
"user_lookup": "поиск пользователя",
"wallet": {
"backup_wallet": "резервная копия кошелька",
"wallet": "кошелёк",
"wallet_other": "кошельки"
},
"welcome": "добро пожаловать"
}

View File

@ -0,0 +1,21 @@
{
"1_getting_started": "1. Начало работы",
"2_overview": "2. Обзор",
"3_groups": "3. Группы Qortal",
"4_obtain_qort": "4. Получение QORT",
"account_creation": "создание аккаунта",
"important_info": "важная информация!",
"apps": {
"dashboard": "1. Панель приложений",
"navigation": "2. Навигация по приложениям"
},
"initial": {
"6_qort": "иметь не менее 6 QORT в кошельке",
"explore": "исследовать",
"general_chat": "общий чат",
"getting_started": "начало работы",
"register_name": "зарегистрировать имя",
"see_apps": "посмотреть приложения",
"trade_qort": "обмен QORT"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,229 +0,0 @@
import {
AppBar,
Button,
Toolbar,
Typography,
Box,
TextField,
InputLabel,
} from "@mui/material";
import { styled } from "@mui/system";
export const AppContainer = styled(Box)(({ theme }) => ({
display: "flex",
alignItems: "center",
flexDirection: 'column',
width: "100vw",
background: "rgba(39, 40, 44, 1)",
height: "100vh",
radius: "15px",
overflow: 'hidden'
}));
export const AuthenticatedContainer = styled(Box)(({ theme }) => ({
display: "flex",
width: "100%",
height: "100%",
justifyContent: "space-between"
}));
export const AuthenticatedContainerInnerLeft = styled(Box)(({ theme }) => ({
display: "flex",
alignItems: "center",
flexDirection: 'column',
height: "100%",
width: "100%"
}));
export const AuthenticatedContainerInnerRight = styled(Box)(({ theme }) => ({
display: "flex",
alignItems: "center",
flexDirection: 'column',
width: "60px",
height: "100%",
background: "rgba(0, 0, 0, 0.1)"
}));
export const AuthenticatedContainerInnerTop = styled(Box)(({ theme }) => ({
display: "flex",
alignItems: "center",
justifyContent: "flex-start",
width: "100%px",
height: "60px",
background: "rgba(0, 0, 0, 0.1)",
padding: '20px'
}));
export const TextP = styled(Typography)(({ theme }) => ({
fontSize: "13px",
fontWeight: 600,
fontFamily: "Inter",
color: "white"
}));
export const TextItalic = styled("span")(({ theme }) => ({
fontSize: "13px",
fontWeight: 600,
fontFamily: "Inter",
color: "white",
fontStyle: "italic"
}));
export const TextSpan = styled("span")(({ theme }) => ({
fontSize: "13px",
fontFamily: "Inter",
fontWeight: 800,
color: "white"
}));
export const AddressBox = styled(Box)`
display: flex;
border: 1px solid var(--50-white, rgba(255, 255, 255, 0.5));
justify-content: space-between;
align-items: center;
width: auto;
height: 25px;
padding: 5px 15px 5px 15px;
gap: 5px;
border-radius: 100px;
font-family: Inter;
font-size: 12px;
font-weight: 600;
line-height: 14.52px;
text-align: left;
color: var(--50-white, rgba(255, 255, 255, 0.5));
cursor: pointer;
transition: all 0.2s;
&:hover {
background-color: rgba(41, 41, 43, 1);
color: white;
svg path {
fill: white; // Fill color changes to white on hover
}
}
`
export const CustomButton = styled(Box)`
/* Authenticate */
box-sizing: border-box;
padding: 15px 20px;
gap: 10px;
border: 0.5px solid rgba(255, 255, 255, 0.5);
filter: drop-shadow(1px 4px 10.5px rgba(0, 0, 0, 0.3));
border-radius: 5px;
display: inline-flex;
justify-content: center;
align-items: center;
width: fit-content;
transition: all 0.2s;
color: black;
min-width: 160px;
cursor: pointer;
font-weight: 600;
font-family: Inter;
color: white;
text-align: center;
&:hover {
background-color: rgba(41, 41, 43, 1);
color: white;
svg path {
fill: white; // Fill color changes to white on hover
}
}
`;
interface CustomButtonProps {
bgColor?: string;
color?: string;
}
export const CustomButtonAccept = styled(Box)<CustomButtonProps>(
({ bgColor, color }) => ({
boxSizing: "border-box",
padding: "15px 20px",
gap: "10px",
border: "0.5px solid rgba(255, 255, 255, 0.5)",
filter: "drop-shadow(1px 4px 10.5px rgba(0,0,0,0.3))",
borderRadius: 5,
display: "inline-flex",
justifyContent: "center",
alignItems: "center",
width: "fit-content",
transition: "all 0.2s",
minWidth: 160,
cursor: "pointer",
fontWeight: 600,
fontFamily: "Inter",
textAlign: "center",
opacity: 0.7,
// Use the passed-in props or fallback defaults
backgroundColor: bgColor || "transparent",
color: color || "white",
"&:hover": {
opacity: 1,
backgroundColor: bgColor
? bgColor
: "rgba(41, 41, 43, 1)", // fallback hover bg
color: color || "white",
svg: {
path: {
fill: color || "white",
},
},
},
})
);
export const CustomInput = styled(TextField)({
width: "183px", // Adjust the width as needed
borderRadius: "5px",
// backgroundColor: "rgba(30, 30, 32, 1)",
outline: "none",
input: {
fontSize: 10,
fontFamily: "Inter",
fontWeight: 400,
color: "white",
"&::placeholder": {
fontSize: 16,
color: "rgba(255, 255, 255, 0.2)",
},
outline: "none",
padding: "10px",
},
"& .MuiOutlinedInput-root": {
"& fieldset": {
border: '0.5px solid rgba(255, 255, 255, 0.5)',
},
"&:hover fieldset": {
border: '0.5px solid rgba(255, 255, 255, 0.5)',
},
"&.Mui-focused fieldset": {
border: '0.5px solid rgba(255, 255, 255, 0.5)',
},
},
"& .MuiInput-underline:before": {
borderBottom: "none",
},
"& .MuiInput-underline:hover:not(.Mui-disabled):before": {
borderBottom: "none",
},
"& .MuiInput-underline:after": {
borderBottom: "none",
},
});
export const CustomLabel = styled(InputLabel)`
font-weight: 400;
font-family: Inter;
font-size: 10px;
line-height: 12px;
color: rgba(255, 255, 255, 0.5);
`

View File

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,48 +1,59 @@
import React, { useContext, useEffect, useRef, useState } from "react";
import List from "@mui/material/List";
import ListItem from "@mui/material/ListItem";
import Divider from "@mui/material/Divider";
import ListItemText from "@mui/material/ListItemText";
import ListItemAvatar from "@mui/material/ListItemAvatar";
import Avatar from "@mui/material/Avatar";
import Typography from "@mui/material/Typography";
import { Box, Button, ButtonBase, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, Input } from "@mui/material";
import { CustomButton } from "./App-styles";
import { useDropzone } from "react-dropzone";
import EditIcon from "@mui/icons-material/Edit";
import { Label } from "./components/Group/AddGroup";
import { Spacer } from "./common/Spacer";
import { getWallets, storeWallets, walletVersion } from "./background";
import { useModal } from "./common/useModal";
import PhraseWallet from "./utils/generateWallet/phrase-wallet";
import { decryptStoredWalletFromSeedPhrase } from "./utils/decryptWallet";
import { crypto } from "./constants/decryptWallet";
import { LoadingButton } from "@mui/lab";
import { PasswordField } from "./components";
import { HtmlTooltip } from "./ExtStates/NotAuthenticated";
import { GlobalContext } from "./App";
import React, { useContext, useEffect, useState } from 'react';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import Divider from '@mui/material/Divider';
import ListItemText from '@mui/material/ListItemText';
import ListItemAvatar from '@mui/material/ListItemAvatar';
import Avatar from '@mui/material/Avatar';
import Typography from '@mui/material/Typography';
import {
Box,
Button,
ButtonBase,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
IconButton,
Input,
useTheme,
} from '@mui/material';
import { CustomButton } from './styles/App-styles';
import { useDropzone } from 'react-dropzone';
import EditIcon from '@mui/icons-material/Edit';
import { Label } from './components/Group/AddGroup';
import { Spacer } from './common/Spacer';
import { getWallets, storeWallets, walletVersion } from './background';
import { useModal } from './common/useModal';
import PhraseWallet from './utils/generateWallet/phrase-wallet';
import { decryptStoredWalletFromSeedPhrase } from './utils/decryptWallet';
import { crypto } from './constants/decryptWallet';
import { LoadingButton } from '@mui/lab';
import { PasswordField } from './components';
import { HtmlTooltip } from './ExtStates/NotAuthenticated';
import { MyContext } from './App';
const parsefilenameQortal = (filename)=> {
return filename.startsWith("qortal_backup_") ? filename.slice(14) : filename;
}
const parsefilenameQortal = (filename) => {
return filename.startsWith('qortal_backup_') ? filename.slice(14) : filename;
};
export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
const [wallets, setWallets] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [seedValue, setSeedValue] = useState("");
const [seedName, setSeedName] = useState("");
const [seedError, setSeedError] = useState("");
const { hasSeenGettingStarted } = useContext(GlobalContext);
const [seedValue, setSeedValue] = useState('');
const [seedName, setSeedName] = useState('');
const [seedError, setSeedError] = useState('');
const { hasSeenGettingStarted } = useContext(MyContext);
const [password, setPassword] = useState("");
const [password, setPassword] = useState('');
const [isOpenSeedModal, setIsOpenSeedModal] = useState(false);
const [isLoadingEncryptSeed, setIsLoadingEncryptSeed] = useState(false);
const { isShow, onCancel, onOk, show, } = useModal();
const theme = useTheme();
const { isShow, onCancel, onOk, show } = useModal();
const { getRootProps, getInputProps } = useDropzone({
accept: {
"application/json": [".json"], // Only accept JSON files
'application/json': ['.json'], // Only accept JSON files
},
onDrop: async (acceptedFiles) => {
const files: any = acceptedFiles;
@ -53,8 +64,8 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
const fileContents = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onabort = () => reject("File reading was aborted");
reader.onerror = () => reject("File reading has failed");
reader.onabort = () => reject('File reading was aborted');
reader.onerror = () => reject('File reading has failed');
reader.onload = () => {
// Resolve the promise with the reader result when reading completes
resolve(reader.result);
@ -63,9 +74,9 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
// Read the file as text
reader.readAsText(file);
});
if (typeof fileContents !== "string") continue;
const parsedData = JSON.parse(fileContents)
importedWallets.push({...parsedData, filename: file?.name});
if (typeof fileContents !== 'string') continue;
const parsedData = JSON.parse(fileContents);
importedWallets.push({ ...parsedData, filename: file?.name });
} catch (error) {
console.error(error);
}
@ -108,83 +119,85 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
});
};
const handleSetSeedValue = async ()=> {
const handleSetSeedValue = async () => {
try {
setIsOpenSeedModal(true)
const {seedValue, seedName, password} = await show({
message: "",
publishFee: "",
setIsOpenSeedModal(true);
const { seedValue, seedName, password } = await show({
message: '',
publishFee: '',
});
setIsLoadingEncryptSeed(true)
const res = await decryptStoredWalletFromSeedPhrase(seedValue)
setIsLoadingEncryptSeed(true);
const res = await decryptStoredWalletFromSeedPhrase(seedValue);
const wallet2 = new PhraseWallet(res, walletVersion);
const wallet = await wallet2.generateSaveWalletData(
password,
crypto.kdfThreads,
() => {}
);
if(wallet?.address0){
setWallets([...wallets, {
...wallet,
name: seedName
}]);
setIsOpenSeedModal(false)
setSeedValue('')
setSeedName('')
setPassword('')
setSeedError('')
if (wallet?.address0) {
setWallets([
...wallets,
{
...wallet,
name: seedName,
},
]);
setIsOpenSeedModal(false);
setSeedValue('');
setSeedName('');
setPassword('');
setSeedError('');
} else {
setSeedError('Could not create account.')
setSeedError('Could not create account.');
}
} catch (error) {
setSeedError(error?.message || 'Could not create account.')
setSeedError(error?.message || 'Could not create account.');
} finally {
setIsLoadingEncryptSeed(false)
setIsLoadingEncryptSeed(false);
}
}
};
const selectedWalletFunc = (wallet) => {
setRawWallet(wallet);
setExtState("wallet-dropped");
setExtState('wallet-dropped');
};
useEffect(()=> {
setIsLoading(true)
getWallets().then((res)=> {
if(res && Array.isArray(res)){
setWallets(res)
useEffect(() => {
setIsLoading(true);
getWallets()
.then((res) => {
if (res && Array.isArray(res)) {
setWallets(res);
}
setIsLoading(false)
}).catch((error)=> {
console.error(error)
setIsLoading(false)
})
}, [])
setIsLoading(false);
})
.catch((error) => {
console.error(error);
setIsLoading(false);
});
}, []);
useEffect(()=> {
if(!isLoading && wallets && Array.isArray(wallets)){
storeWallets(wallets)
useEffect(() => {
if (!isLoading && wallets && Array.isArray(wallets)) {
storeWallets(wallets);
}
}, [wallets, isLoading])
}, [wallets, isLoading]);
if(isLoading) return null
if (isLoading) return null;
return (
<div>
{(wallets?.length === 0 ||
!wallets) ? (
<>
<Typography>No accounts saved</Typography>
<Spacer height="75px" />
</>
): (
<>
<Typography>Your saved accounts</Typography>
<Spacer height="30px" />
</>
)}
{wallets?.length === 0 || !wallets ? (
<>
<Typography>No accounts saved</Typography>
<Spacer height="75px" />
</>
) : (
<>
<Typography>Your saved accounts</Typography>
<Spacer height="30px" />
</>
)}
{rawWallet && (
<Box>
@ -196,175 +209,201 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
</Box>
)}
{wallets?.length > 0 && (
<List
sx={{
width: "100%",
maxWidth: "500px",
maxHeight: "60vh",
overflowY: "auto",
overflowX: "hidden",
backgroundColor: "rgb(30 30 32 / 70%)",
}}
>
{wallets?.map((wallet, idx) => {
return (
<>
<WalletItem
setSelectedWallet={selectedWalletFunc}
key={wallet?.address0}
wallet={wallet}
idx={idx}
updateWalletItem={updateWalletItem}
/>
<Divider variant="inset" component="li" />
</>
);
})}
</List>
<List
sx={{
width: '100%',
maxWidth: '500px',
maxHeight: '60vh',
overflowY: 'auto',
overflowX: 'hidden',
backgroundColor: theme.palette.background.paper,
}}
>
{wallets?.map((wallet, idx) => {
return (
<>
<WalletItem
setSelectedWallet={selectedWalletFunc}
key={wallet?.address0}
wallet={wallet}
idx={idx}
updateWalletItem={updateWalletItem}
/>
<Divider variant="inset" component="li" />
</>
);
})}
</List>
)}
<Box
sx={{
display: "flex",
gap: "10px",
alignItems: "center",
display: 'flex',
gap: '10px',
alignItems: 'center',
position: wallets?.length === 0 ? 'relative' : 'fixed',
bottom: wallets?.length === 0 ? 'unset' : '20px',
right: wallets?.length === 0 ? 'unset' : '20px'
bottom: wallets?.length === 0 ? 'unset' : '20px',
right: wallets?.length === 0 ? 'unset' : '20px',
}}
>
<HtmlTooltip
disableHoverListener={hasSeenGettingStarted === true}
title={
<React.Fragment>
<Typography color="inherit" sx={{
fontSize: '16px'
}}>Already have a Qortal account? Enter your secret backup phrase here to access it. This phrase is one of the ways to recover your account.</Typography>
</React.Fragment>
}
>
<CustomButton onClick={handleSetSeedValue} sx={{
padding: '10px'
}} >
Add seed-phrase
</CustomButton>
</HtmlTooltip>
<HtmlTooltip
disableHoverListener={hasSeenGettingStarted === true}
title={
<React.Fragment>
<Typography color="inherit" sx={{
fontSize: '16px'
}}>Use this option to connect additional Qortal wallets you've already made, in order to login with them afterwards. You will need access to your backup JSON file in order to do so.</Typography>
</React.Fragment>
}
>
<CustomButton sx={{
padding: '10px'
}} {...getRootProps()}>
<input {...getInputProps()} />
Add account
</CustomButton>
disableHoverListener={hasSeenGettingStarted === true}
title={
<React.Fragment>
<Typography
color="inherit"
sx={{
fontSize: '16px',
}}
>
Already have a Qortal account? Enter your secret backup phrase
here to access it. This phrase is one of the ways to recover
your account.
</Typography>
</React.Fragment>
}
>
<CustomButton
onClick={handleSetSeedValue}
sx={{
padding: '10px',
display: 'inline',
}}
>
Add seed-phrase
</CustomButton>
</HtmlTooltip>
<HtmlTooltip
disableHoverListener={hasSeenGettingStarted === true}
title={
<React.Fragment>
<Typography
color="inherit"
sx={{
fontSize: '16px',
}}
>
Use this option to connect additional Qortal wallets you've
already made, in order to login with them afterwards. You will
need access to your backup JSON file in order to do so.
</Typography>
</React.Fragment>
}
>
<CustomButton
sx={{
padding: '10px',
}}
{...getRootProps()}
>
<input {...getInputProps()} />
Add account
</CustomButton>
</HtmlTooltip>
</Box>
<Dialog
open={isOpenSeedModal}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
onKeyDown={(e) => {
if (e.key === 'Enter' && seedValue && seedName && password) {
onOk({seedValue, seedName, password});
}
}}
>
<DialogTitle id="alert-dialog-title">
Type or paste in your seed-phrase
</DialogTitle>
<DialogContent>
<Box
sx={{
display: "flex",
flexDirection: "column",
}}
>
<Dialog
open={isOpenSeedModal}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
onKeyDown={(e) => {
if (e.key === 'Enter' && seedValue && seedName && password) {
onOk({ seedValue, seedName, password });
}
}}
>
<DialogTitle id="alert-dialog-title">
Type or paste in your seed-phrase
</DialogTitle>
<DialogContent>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
}}
>
<Label>Name</Label>
<Input
placeholder="Name"
value={seedName}
onChange={(e) => setSeedName(e.target.value)}
/>
<Spacer height="7px" />
<Label>Seed-phrase</Label>
<PasswordField
placeholder="Seed-phrase"
<Input
placeholder="Name"
value={seedName}
onChange={(e) => setSeedName(e.target.value)}
/>
<Spacer height="7px" />
<Label>Seed-phrase</Label>
<PasswordField
placeholder="Seed-phrase"
id="standard-adornment-password"
value={seedValue}
onChange={(e) => setSeedValue(e.target.value)}
autoComplete="off"
sx={{
width: '100%'
width: '100%',
}}
/>
<Spacer height="7px" />
<Label>Choose new password</Label>
<PasswordField
<Spacer height="7px" />
<Label>Choose new password</Label>
<PasswordField
id="standard-adornment-password"
value={password}
onChange={(e) => setPassword(e.target.value)}
autoComplete="off"
sx={{
width: '100%'
width: '100%',
}}
/>
</Box>
</DialogContent>
<DialogActions>
<Button disabled={isLoadingEncryptSeed} variant="contained" onClick={()=> {
setIsOpenSeedModal(false)
setSeedValue('')
setSeedName('')
setPassword('')
setSeedError('')
}}>
Close
</Button>
<LoadingButton
</Box>
</DialogContent>
<DialogActions>
<Button
disabled={isLoadingEncryptSeed}
variant="contained"
onClick={() => {
setIsOpenSeedModal(false);
setSeedValue('');
setSeedName('');
setPassword('');
setSeedError('');
}}
>
Close
</Button>
<LoadingButton
loading={isLoadingEncryptSeed}
disabled={!seedValue || !seedName || !password}
variant="contained"
onClick={() => {
if(!seedValue || !seedName || !password) return
onOk({seedValue, seedName, password});
}}
autoFocus
>
Add
</LoadingButton>
<Typography sx={{
fontSize: '14px',
visibility: seedError ? 'visible' : 'hidden'
}}>{seedError}</Typography>
</DialogActions>
</Dialog>
disabled={!seedValue || !seedName || !password}
variant="contained"
onClick={() => {
if (!seedValue || !seedName || !password) return;
onOk({ seedValue, seedName, password });
}}
autoFocus
>
Add
</LoadingButton>
<Typography
sx={{
fontSize: '14px',
visibility: seedError ? 'visible' : 'hidden',
}}
>
{seedError}
</Typography>
</DialogActions>
</Dialog>
</div>
);
};
const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
const [name, setName] = useState("");
const [note, setNote] = useState("");
const [name, setName] = useState('');
const [note, setNote] = useState('');
const [isEdit, setIsEdit] = useState(false);
const theme = useTheme();
useEffect(() => {
if (wallet?.name) {
@ -382,71 +421,78 @@ const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
}}
sx={{
width: '100%',
padding: '10px'
padding: '10px',
}}
>
<ListItem
sx={{
bgcolor: "background.paper",
bgcolor: theme.palette.background.default,
flexGrow: 1,
"&:hover": { backgroundColor: "secondary.main", transform: "scale(1.01)" },
transition: "all 0.1s ease-in-out",
'&:hover': {
backgroundColor: theme.palette.action.hover,
transform: 'scale(1.01)',
},
transition: 'all 0.1s ease-in-out',
}}
alignItems="flex-start"
>
<ListItemAvatar>
<Avatar alt="" src="/static/images/avatar/1.jpg" />
</ListItemAvatar>
<ListItemText
primary={wallet?.name ? wallet.name : wallet?.filename ? parsefilenameQortal(wallet?.filename) : "No name"}
primary={
wallet?.name
? wallet.name
: wallet?.filename
? parsefilenameQortal(wallet?.filename)
: 'No name'
}
secondary={
<Box
sx={{
display: "flex",
flexDirection: "column",
display: 'flex',
flexDirection: 'column',
}}
>
<Typography
component="span"
variant="body2"
sx={{ color: "text.primary", display: "inline" }}
sx={{ color: theme.palette.text.primary, display: 'inline' }}
>
{wallet?.address0}
</Typography>
{wallet?.note}
<Typography sx={{
textAlign: 'end',
marginTop: '5px'
}}>Login</Typography>
<Typography
sx={{
textAlign: 'end',
marginTop: '5px',
}}
>
Login
</Typography>
</Box>
}
/>
</ListItem>
<IconButton
sx={{
alignSelf: 'flex-start'
}}
onClick={(e) => {
e.stopPropagation();
setIsEdit(true);
}}
edge="end"
aria-label="edit"
>
<EditIcon
sx={{
color: "white",
}}
/>
</IconButton>
sx={{
alignSelf: 'flex-start',
}}
onClick={(e) => {
e.stopPropagation();
setIsEdit(true);
}}
edge="end"
aria-label="edit"
>
<EditIcon />
</IconButton>
</ButtonBase>
{isEdit && (
<Box
sx={{
padding: "8px",
padding: '8px',
}}
>
<Label>Name</Label>
@ -455,10 +501,12 @@ const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
value={name}
onChange={(e) => setName(e.target.value)}
sx={{
width: "100%",
width: '100%',
}}
/>
<Spacer height="10px" />
<Label>Note</Label>
<Input
placeholder="Note"
@ -468,48 +516,54 @@ const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
maxLength: 100,
}}
sx={{
width: "100%",
width: '100%',
}}
/>
<Spacer height="10px" />
<Box
sx={{
display: "flex",
gap: "20px",
justifyContent: "flex-end",
width: "100%",
display: 'flex',
gap: '20px',
justifyContent: 'flex-end',
width: '100%',
}}
>
<Button size="small" variant="contained" onClick={() => setIsEdit(false)}>
<Button
size="small"
variant="contained"
onClick={() => setIsEdit(false)}
>
Close
</Button>
<Button
sx={{
backgroundColor: 'var(--danger)',
"&:hover": {
backgroundColor: "var(--danger)",
},
"&:focus": {
backgroundColor: "var(--danger)",
},
}}
size="small"
sx={{
backgroundColor: theme.palette.other.danger,
'&:hover': {
backgroundColor: theme.palette.other.danger,
},
'&:focus': {
backgroundColor: theme.palette.other.danger,
},
}}
size="small"
variant="contained"
onClick={() => updateWalletItem(idx, null)}
>
Remove
</Button>
<Button
sx={{
backgroundColor: "#5EB049",
"&:hover": {
backgroundColor: "#5EB049",
},
"&:focus": {
backgroundColor: "#5EB049",
},
}}
size="small"
sx={{
backgroundColor: '#5EB049',
'&:hover': {
backgroundColor: '#5EB049',
},
'&:focus': {
backgroundColor: '#5EB049',
},
}}
size="small"
variant="contained"
onClick={() => {
updateWalletItem(idx, {
@ -525,9 +579,6 @@ const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
</Box>
</Box>
)}
</>
);
};

View File

@ -1,6 +1,10 @@
import React from "react";
import { useTheme } from '@mui/material';
export const AppsIcon = ({ height = 31, width = 31, color }) => {
const theme = useTheme();
const setColor = color ? color : theme.palette.text.primary;
export const AppsIcon = ({ color, height = 31, width = 31 }) => {
return (
<svg
width={width}
@ -11,39 +15,39 @@ export const AppsIcon = ({ color, height = 31, width = 31 }) => {
>
<path
d="M3.76596 7.53192C5.84584 7.53192 7.53192 5.84584 7.53192 3.76596C7.53192 1.68608 5.84584 0 3.76596 0C1.68608 0 0 1.68608 0 3.76596C0 5.84584 1.68608 7.53192 3.76596 7.53192Z"
fill={color}
fill={setColor}
/>
<path
d="M15 7.53192C17.0799 7.53192 18.766 5.84584 18.766 3.76596C18.766 1.68608 17.0799 0 15 0C12.9201 0 11.2341 1.68608 11.2341 3.76596C11.2341 5.84584 12.9201 7.53192 15 7.53192Z"
fill={color}
fill={setColor}
/>
<path
d="M26.234 7.53192C28.3139 7.53192 30 5.84584 30 3.76596C30 1.68608 28.3139 0 26.234 0C24.1542 0 22.4681 1.68608 22.4681 3.76596C22.4681 5.84584 24.1542 7.53192 26.234 7.53192Z"
fill={color}
fill={setColor}
/>
<path
d="M3.76596 30.0001C5.84584 30.0001 7.53192 28.314 7.53192 26.2341C7.53192 24.1542 5.84584 22.4681 3.76596 22.4681C1.68608 22.4681 0 24.1542 0 26.2341C0 28.314 1.68608 30.0001 3.76596 30.0001Z"
fill={color}
fill={setColor}
/>
<path
d="M15 30.0002C17.0799 30.0002 18.766 28.3141 18.766 26.2342C18.766 24.1543 17.0799 22.4683 15 22.4683C12.9201 22.4683 11.2341 24.1543 11.2341 26.2342C11.2341 28.3141 12.9201 30.0002 15 30.0002Z"
fill={color}
fill={setColor}
/>
<path
d="M26.234 30.0002C28.3139 30.0002 30 28.3141 30 26.2342C30 24.1543 28.3139 22.4683 26.234 22.4683C24.1542 22.4683 22.4681 24.1543 22.4681 26.2342C22.4681 28.3141 24.1542 30.0002 26.234 30.0002Z"
fill={color}
fill={setColor}
/>
<path
d="M3.76596 18.766C5.84584 18.766 7.53192 17.08 7.53192 15.0001C7.53192 12.9202 5.84584 11.2341 3.76596 11.2341C1.68608 11.2341 0 12.9202 0 15.0001C0 17.08 1.68608 18.766 3.76596 18.766Z"
fill={color}
fill={setColor}
/>
<path
d="M15 18.766C17.0799 18.766 18.766 17.08 18.766 15.0001C18.766 12.9202 17.0799 11.2341 15 11.2341C12.9201 11.2341 11.2341 12.9202 11.2341 15.0001C11.2341 17.08 12.9201 18.766 15 18.766Z"
fill={color}
fill={setColor}
/>
<path
d="M26.234 18.766C28.3139 18.766 30 17.08 30 15.0001C30 12.9202 28.3139 11.2341 26.234 11.2341C24.1542 11.2341 22.4681 12.9202 22.4681 15.0001C22.4681 17.08 24.1542 18.766 26.234 18.766Z"
fill={color}
fill={setColor}
/>
</svg>
);

View File

@ -1,12 +1,18 @@
import React from 'react';
export const ChatIcon= ({ color = 'white', height = 15, width = 15 }) => {
return (
<svg width={width} height={height} viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.5 0C3.35915 0 0 3.35915 0 7.5V13.8169C0 14.4718 0.528169 15 1.1831 15H7.5C11.6408 15 15 11.6408 15 7.5C15 3.35915 11.6408 0 7.5 0ZM11.0915 10.669H3.90845C3.67606 10.669 3.48592 10.4789 3.48592 10.2465C3.48592 10.0141 3.67606 9.82394 3.90845 9.82394H11.0915C11.3239 9.82394 11.5141 10.0141 11.5141 10.2465C11.5141 10.4789 11.3239 10.669 11.0915 10.669ZM11.0915 8.34507H3.90845C3.67606 8.34507 3.48592 8.15493 3.48592 7.92254C3.48592 7.69014 3.67606 7.5 3.90845 7.5H11.0915C11.3239 7.5 11.5141 7.69014 11.5141 7.92254C11.5141 8.15493 11.3239 8.34507 11.0915 8.34507ZM11.0915 6.02113H3.90845C3.67606 6.02113 3.48592 5.83099 3.48592 5.59859C3.48592 5.3662 3.67606 5.17606 3.90845 5.17606H11.0915C11.3239 5.17606 11.5141 5.3662 11.5141 5.59859C11.5141 5.83099 11.3239 6.02113 11.0915 6.02113Z" fill={color}/>
</svg>
);
};
export const ChatIcon = ({ color = 'white', height = 15, width = 15 }) => {
return (
<svg
width={width}
height={height}
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.5 0C3.35915 0 0 3.35915 0 7.5V13.8169C0 14.4718 0.528169 15 1.1831 15H7.5C11.6408 15 15 11.6408 15 7.5C15 3.35915 11.6408 0 7.5 0ZM11.0915 10.669H3.90845C3.67606 10.669 3.48592 10.4789 3.48592 10.2465C3.48592 10.0141 3.67606 9.82394 3.90845 9.82394H11.0915C11.3239 9.82394 11.5141 10.0141 11.5141 10.2465C11.5141 10.4789 11.3239 10.669 11.0915 10.669ZM11.0915 8.34507H3.90845C3.67606 8.34507 3.48592 8.15493 3.48592 7.92254C3.48592 7.69014 3.67606 7.5 3.90845 7.5H11.0915C11.3239 7.5 11.5141 7.69014 11.5141 7.92254C11.5141 8.15493 11.3239 8.34507 11.0915 8.34507ZM11.0915 6.02113H3.90845C3.67606 6.02113 3.48592 5.83099 3.48592 5.59859C3.48592 5.3662 3.67606 5.17606 3.90845 5.17606H11.0915C11.3239 5.17606 11.5141 5.3662 11.5141 5.59859C11.5141 5.83099 11.3239 6.02113 11.0915 6.02113Z"
fill={color}
/>
</svg>
);
};

View File

@ -0,0 +1,33 @@
import { useTheme } from '@mui/material';
import { SVGProps } from './interfaces';
export const ComposeIcon: React.FC<SVGProps> = ({
color,
height = 20,
width = 20,
opacity,
...children
}) => {
const theme = useTheme();
const setColor = color ? color : theme.palette.text.primary;
const setOpacity = opacity ? opacity : 1;
return (
<svg
{...children}
width={width}
height={height}
viewBox="0 0 64 64"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M50.3 3c1.5 0 3.9 0.6 5.5 1.4 1.5 0.7 3.3 2.5 4 4 0.6 1.4 1.2 3.7 1.2 5.1 0 1.4-0.6 3.7-1.4 5.3-0.8 1.5-9.9 11.1-39.1 40l-6.7 1.6c-3.8 0.9-7.9 1.6-9.3 1.6-1.8 0-2.5-0.5-2.5-2 0-1.1 0.7-5.3 3.2-16.5l18.1-18.4c10-10 19.6-19.2 21.2-20.2 1.7-1 4.2-1.9 5.8-1.9zm-8.4 11.3c0 0.7 1.5 2.7 3.3 4.4 1.8 1.8 3.9 3.3 4.6 3.3 0.6 0 2.3-1.4 3.7-3 1.4-1.7 2.5-4 2.5-5.3 0.1-1.2-0.7-3-1.7-3.9-1-1-2.8-1.8-4-1.8-1.2 0-3.5 1.2-5.3 2.6-1.7 1.4-3.1 3.1-3.1 3.7z"
fill={setColor}
opacity={setOpacity}
fillRule="evenodd"
/>
</svg>
);
};

View File

@ -0,0 +1,25 @@
import { useTheme } from '@mui/material';
import React from 'react';
export const CopyIcon = ({ color, height = 11, width = 10 }) => {
const theme = useTheme();
const setColor = color ? color : theme.palette.text.primary;
return (
<svg
width={width}
height={height}
viewBox="0 0 10 11"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M3.92857 0.5H8.57143C9.36071 0.5 10 1.13929 10 1.92857V6.57143C10 7.36071 9.36071 8 8.57143 8H8.21429V4.42857C8.21429 3.24643 7.25357 2.28571 6.07143 2.28571H2.5V1.92857C2.5 1.13929 3.13929 0.5 3.92857 0.5ZM1.42857 3H6.07143C6.86041 3 7.5 3.63959 7.5 4.42857V9.07143C7.5 9.86041 6.86041 10.5 6.07143 10.5H1.42857C0.639593 10.5 0 9.86041 0 9.07143V4.42857C0 3.63959 0.639593 3 1.42857 3Z"
fill={setColor}
fill-opacity="0.5"
/>
</svg>
);
};

View File

@ -0,0 +1,31 @@
import React from 'react';
import { styled } from '@mui/system';
import { SVGProps } from './interfaces';
import { useTheme } from '@mui/material';
// Create a styled container with hover effects
const SvgContainer = styled('svg')<{ color?: string }>(({ color }) => ({
'& path': {
fill: color,
},
}));
export const CreateThreadIcon: React.FC<SVGProps> = ({ color }) => {
const theme = useTheme();
const setColor = color || theme.palette.text.primary;
return (
<SvgContainer
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
color={setColor}
>
<path
d="M0 9.80209V9.0205C0.0460138 8.67679 0.080024 8.31425 0.144043 7.98466C0.469856 6.30568 1.25577 4.79934 2.38071 3.6977C4.13924 1.88262 6.22987 0.985679 8.52256 0.674927C9.9086 0.485649 11.3116 0.565177 12.6758 0.910345C14.5124 1.34351 16.1889 2.2075 17.6053 3.67886C18.7276 4.84183 19.5319 6.24257 19.858 7.98466C19.918 8.31189 19.952 8.64383 20 8.97577V9.80209C19.9827 9.8676 19.9693 9.93447 19.96 10.0022C19.8708 11.2186 19.5113 12.3861 18.9177 13.3875C17.961 15.0025 16.6297 16.2594 15.0825 17.0082C12.4657 18.3525 9.75693 18.5667 6.98209 17.8346C6.8589 17.8074 6.73157 17.8264 6.61799 17.8887C5.15955 18.7339 3.70511 19.5908 2.24867 20.4501C2.18866 20.4854 2.12464 20.5183 2.0146 20.5748L3.78714 16.3703C3.37301 16.0148 2.96889 15.7017 2.60078 15.3415C1.42243 14.1879 0.556167 12.7895 0.182055 11.0192C0.0980294 10.6213 0.060018 10.2094 0 9.80209ZM14.0042 10.5931C14.1362 10.5968 14.2676 10.5698 14.3907 10.5135C14.5138 10.4572 14.6262 10.3728 14.7214 10.2651C14.8167 10.1574 14.8928 10.0286 14.9455 9.8861C14.9982 9.7436 15.0264 9.59023 15.0285 9.43484V9.4113C15.0285 9.25517 15.0024 9.10058 14.9516 8.95634C14.9008 8.8121 14.8264 8.68104 14.7326 8.57064C14.6388 8.46025 14.5274 8.37268 14.4048 8.31293C14.2823 8.25319 14.1509 8.22243 14.0182 8.22243C13.8855 8.22243 13.7542 8.25319 13.6316 8.31293C13.509 8.37268 13.3976 8.46025 13.3038 8.57064C13.21 8.68104 13.1356 8.8121 13.0848 8.95634C13.034 9.10058 13.0079 9.25517 13.0079 9.4113C13.0074 9.56588 13.0327 9.71906 13.0825 9.86211C13.1323 10.0052 13.2055 10.1353 13.2981 10.245C13.3906 10.3547 13.5005 10.442 13.6217 10.5017C13.7429 10.5614 13.8728 10.5925 14.0042 10.5931ZM10.003 10.5931C10.203 10.5926 10.3983 10.5225 10.5644 10.3915C10.7306 10.2606 10.86 10.0746 10.9364 9.85719C11.0129 9.63976 11.0329 9.40056 10.9939 9.16977C10.9549 8.93898 10.8588 8.72694 10.7175 8.5604C10.5763 8.39385 10.3962 8.28026 10.2002 8.23396C10.0041 8.18765 9.80084 8.21071 9.61591 8.30022C9.43099 8.38973 9.27273 8.54168 9.1611 8.7369C9.04948 8.93212 8.98949 9.16187 8.9887 9.39717C8.98975 9.71356 9.09688 10.0167 9.28682 10.2406C9.47675 10.4646 9.73413 10.5912 10.003 10.5931ZM4.98349 9.3854C4.9836 9.61979 5.04316 9.8488 5.15456 10.0431C5.26595 10.2374 5.42411 10.3882 5.60876 10.476C5.79341 10.5639 5.99616 10.5849 6.19102 10.5364C6.38588 10.4878 6.56399 10.3719 6.70252 10.2035C6.84105 10.0351 6.93371 9.82183 6.96861 9.59108C7.00352 9.36032 6.97909 9.12255 6.89845 8.90823C6.8178 8.69392 6.68463 8.51281 6.51597 8.38811C6.34732 8.26342 6.15087 8.20081 5.95179 8.20831C5.69208 8.21809 5.44579 8.34641 5.26507 8.56611C5.08434 8.78581 4.98336 9.07963 4.98349 9.3854Z"
fill={color}
/>
</SvgContainer>
);
};

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