diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 00000000..6555c986
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,49 @@
+module.exports = {
+ root: true,
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ ecmaVersion: 2020,
+ sourceType: 'module',
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+ settings: {
+ react: {
+ version: 'detect',
+ },
+ 'import/resolver': {
+ node: {
+ paths: ['src'],
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
+ },
+ },
+ },
+ env: {
+ browser: true,
+ amd: true,
+ node: true,
+ },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:react/recommended',
+ 'plugin:jsx-a11y/recommended',
+ 'prettier'
+ ],
+ plugins: [],
+ rules: {
+ 'react/react-in-jsx-scope': 'off',
+ 'jsx-a11y/accessible-emoji': 'off',
+ 'react/prop-types': 'off',
+ '@typescript-eslint/explicit-function-return-type': 'off',
+ 'jsx-a11y/anchor-is-valid': [
+ 'error',
+ {
+ components: ['Link'],
+ specialLink: ['hrefLeft', 'hrefRight'],
+ aspects: ['invalidHref', 'preferButton'],
+ },
+ ],
+ },
+};
\ No newline at end of file
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 00000000..abd9724d
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,9 @@
+.tmp
+.cache/
+coverage/
+.nyc_output/
+**/.yarn/**
+**/.pnp.*
+/dist*/
+node_modules/
+src-tauri/
\ No newline at end of file
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 00000000..66a5b92c
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,22 @@
+{
+ "semi": true,
+ "trailingComma": "es5",
+ "singleQuote": true,
+ "tabWidth": 2,
+ "printWidth": 90,
+ "useTabs": false,
+ "bracketSpacing": true,
+ "bracketSameLine": false,
+ "importOrder": [
+ "^@app/(.*)$",
+ "^@libs/(.*)$",
+ "^@shared/(.*)$",
+ "^@stores/(.*)$",
+ "^@utils/(.*)$",
+ "^[./]"
+ ],
+ "importOrderSeparation": true,
+ "importOrderSortSpecifiers": true,
+ "plugins": ["@trivago/prettier-plugin-sort-imports", "prettier-plugin-tailwindcss"],
+ "pluginSearchDirs": false
+}
diff --git a/package.json b/package.json
index c7ee95a9..9a1b9bc3 100644
--- a/package.json
+++ b/package.json
@@ -1,71 +1,83 @@
{
- "name": "lume",
- "private": true,
- "version": "1.0.0",
- "scripts": {
- "dev": "vite",
- "build": "vite build",
- "tauri": "tauri",
- "add-migrate": "cd src-tauri/ && sqlx migrate add",
- "prepare": "husky install"
- },
- "lint-staged": {
- "**/*.{js,ts,jsx,tsx}": "rome check --apply"
- },
- "dependencies": {
- "@floating-ui/react": "^0.23.1",
- "@headlessui/react": "^1.7.15",
- "@nostr-dev-kit/ndk": "0.6.0",
- "@radix-ui/react-popover": "^1.0.6",
- "@radix-ui/react-tooltip": "^1.0.6",
- "@tanstack/react-query": "^4.29.19",
- "@tanstack/react-virtual": "3.0.0-beta.54",
- "@tauri-apps/api": "^1.4.0",
- "cheerio": "1.0.0-rc.12",
- "dayjs": "^1.11.8",
- "destr": "^1.2.2",
- "framer-motion": "^10.12.17",
- "get-urls": "^11.0.0",
- "immer": "^10.0.2",
- "light-bolt11-decoder": "^3.0.0",
- "nostr-tools": "^1.12.1",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
- "react-hook-form": "^7.45.1",
- "react-hotkeys-hook": "^4.4.0",
- "react-player": "^2.12.0",
- "react-router-dom": "^6.14.0",
- "react-string-replace": "^1.1.1",
- "react-virtuoso": "^4.3.11",
- "slate": "^0.94.1",
- "slate-history": "^0.93.0",
- "slate-react": "^0.94.2",
- "tailwind-merge": "^1.13.2",
- "tauri-plugin-autostart-api": "github:tauri-apps/tauri-plugin-autostart#v1",
- "tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql",
- "zustand": "^4.3.8"
- },
- "devDependencies": {
- "@tailwindcss/typography": "^0.5.9",
- "@tauri-apps/cli": "^1.4.0",
- "@types/node": "^18.16.18",
- "@types/react": "^18.2.14",
- "@types/react-dom": "^18.2.6",
- "@types/youtube-player": "^5.5.7",
- "@vitejs/plugin-react-swc": "^3.3.2",
- "autoprefixer": "^10.4.14",
- "cross-env": "^7.0.3",
- "csstype": "^3.1.2",
- "encoding": "^0.1.13",
- "husky": "^8.0.3",
- "lint-staged": "^13.2.3",
- "postcss": "^8.4.24",
- "prop-types": "^15.8.1",
- "rome": "12.1.0",
- "tailwindcss": "^3.3.2",
- "typescript": "^4.9.5",
- "vite": "^4.3.9",
- "vite-plugin-top-level-await": "^1.3.1",
- "vite-tsconfig-paths": "^4.2.0"
- }
+ "name": "lume",
+ "private": true,
+ "version": "1.0.0",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "tauri": "tauri",
+ "add-migrate": "cd src-tauri/ && sqlx migrate add",
+ "prepare": "husky install",
+ "lint": "eslint ./src --fix",
+ "format": "prettier ./src --write"
+ },
+ "lint-staged": {
+ "src/*.{ts, tsx}": "eslint --fix",
+ "src/*.{ts, tsx, css, md, html, json}": "prettier --cache --write"
+ },
+ "dependencies": {
+ "@floating-ui/react": "^0.23.1",
+ "@headlessui/react": "^1.7.15",
+ "@nostr-dev-kit/ndk": "0.6.0",
+ "@radix-ui/react-popover": "^1.0.6",
+ "@radix-ui/react-tooltip": "^1.0.6",
+ "@tanstack/react-query": "^4.29.19",
+ "@tanstack/react-virtual": "3.0.0-beta.54",
+ "@tauri-apps/api": "^1.4.0",
+ "cheerio": "1.0.0-rc.12",
+ "dayjs": "^1.11.8",
+ "destr": "^1.2.2",
+ "framer-motion": "^10.12.17",
+ "get-urls": "^11.0.0",
+ "immer": "^10.0.2",
+ "light-bolt11-decoder": "^3.0.0",
+ "nostr-tools": "^1.12.1",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-hook-form": "^7.45.1",
+ "react-hotkeys-hook": "^4.4.0",
+ "react-player": "^2.12.0",
+ "react-router-dom": "^6.14.0",
+ "react-string-replace": "^1.1.1",
+ "react-virtuoso": "^4.3.11",
+ "slate": "^0.94.1",
+ "slate-history": "^0.93.0",
+ "slate-react": "^0.94.2",
+ "tailwind-merge": "^1.13.2",
+ "tauri-plugin-autostart-api": "github:tauri-apps/tauri-plugin-autostart#v1",
+ "tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql",
+ "zustand": "^4.3.8"
+ },
+ "devDependencies": {
+ "@tailwindcss/typography": "^0.5.9",
+ "@tauri-apps/cli": "^1.4.0",
+ "@trivago/prettier-plugin-sort-imports": "^4.1.1",
+ "@types/node": "^18.16.18",
+ "@types/react": "^18.2.14",
+ "@types/react-dom": "^18.2.6",
+ "@types/youtube-player": "^5.5.7",
+ "@typescript-eslint/eslint-plugin": "^5.61.0",
+ "@typescript-eslint/parser": "^5.61.0",
+ "@vitejs/plugin-react-swc": "^3.3.2",
+ "autoprefixer": "^10.4.14",
+ "cross-env": "^7.0.3",
+ "csstype": "^3.1.2",
+ "encoding": "^0.1.13",
+ "eslint": "^8.44.0",
+ "eslint-config-prettier": "^8.8.0",
+ "eslint-plugin-jsx-a11y": "^6.7.1",
+ "eslint-plugin-react": "^7.32.2",
+ "eslint-plugin-simple-import-sort": "^10.0.0",
+ "husky": "^8.0.3",
+ "lint-staged": "^13.2.3",
+ "postcss": "^8.4.24",
+ "prettier": "^2.8.8",
+ "prettier-plugin-tailwindcss": "^0.3.0",
+ "prop-types": "^15.8.1",
+ "tailwindcss": "^3.3.2",
+ "typescript": "^4.9.5",
+ "vite": "^4.3.9",
+ "vite-plugin-top-level-await": "^1.3.1",
+ "vite-tsconfig-paths": "^4.2.0"
+ }
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ac73454d..bcfa00c2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -102,6 +102,9 @@ devDependencies:
'@tauri-apps/cli':
specifier: ^1.4.0
version: 1.4.0
+ '@trivago/prettier-plugin-sort-imports':
+ specifier: ^4.1.1
+ version: 4.1.1(prettier@2.8.8)
'@types/node':
specifier: ^18.16.18
version: 18.16.18
@@ -114,6 +117,12 @@ devDependencies:
'@types/youtube-player':
specifier: ^5.5.7
version: 5.5.7
+ '@typescript-eslint/eslint-plugin':
+ specifier: ^5.61.0
+ version: 5.61.0(@typescript-eslint/parser@5.61.0)(eslint@8.44.0)(typescript@4.9.5)
+ '@typescript-eslint/parser':
+ specifier: ^5.61.0
+ version: 5.61.0(eslint@8.44.0)(typescript@4.9.5)
'@vitejs/plugin-react-swc':
specifier: ^3.3.2
version: 3.3.2(vite@4.3.9)
@@ -129,6 +138,21 @@ devDependencies:
encoding:
specifier: ^0.1.13
version: 0.1.13
+ eslint:
+ specifier: ^8.44.0
+ version: 8.44.0
+ eslint-config-prettier:
+ specifier: ^8.8.0
+ version: 8.8.0(eslint@8.44.0)
+ eslint-plugin-jsx-a11y:
+ specifier: ^6.7.1
+ version: 6.7.1(eslint@8.44.0)
+ eslint-plugin-react:
+ specifier: ^7.32.2
+ version: 7.32.2(eslint@8.44.0)
+ eslint-plugin-simple-import-sort:
+ specifier: ^10.0.0
+ version: 10.0.0(eslint@8.44.0)
husky:
specifier: ^8.0.3
version: 8.0.3
@@ -138,12 +162,15 @@ devDependencies:
postcss:
specifier: ^8.4.24
version: 8.4.24
+ prettier:
+ specifier: ^2.8.8
+ version: 2.8.8
+ prettier-plugin-tailwindcss:
+ specifier: ^0.3.0
+ version: 0.3.0(@trivago/prettier-plugin-sort-imports@4.1.1)(prettier@2.8.8)
prop-types:
specifier: ^15.8.1
version: 15.8.1
- rome:
- specifier: 12.1.0
- version: 12.1.0
tailwindcss:
specifier: ^3.3.2
version: 3.3.2
@@ -165,7 +192,6 @@ packages:
/@aashutoshrathi/word-wrap@1.2.6:
resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
engines: {node: '>=0.10.0'}
- dev: false
/@alloc/quick-lru@5.2.0:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
@@ -177,12 +203,51 @@ packages:
engines: {node: '>=6.9.0'}
dependencies:
'@babel/highlight': 7.22.5
- dev: false
+
+ /@babel/generator@7.17.7:
+ resolution: {integrity: sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.17.0
+ jsesc: 2.5.2
+ source-map: 0.5.7
+ dev: true
+
+ /@babel/helper-environment-visitor@7.22.5:
+ resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/helper-function-name@7.22.5:
+ resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/template': 7.22.5
+ '@babel/types': 7.22.5
+ dev: true
+
+ /@babel/helper-hoist-variables@7.22.5:
+ resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.22.5
+ dev: true
+
+ /@babel/helper-split-export-declaration@7.22.5:
+ resolution: {integrity: sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.22.5
+ dev: true
+
+ /@babel/helper-string-parser@7.22.5:
+ resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==}
+ engines: {node: '>=6.9.0'}
+ dev: true
/@babel/helper-validator-identifier@7.22.5:
resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==}
engines: {node: '>=6.9.0'}
- dev: false
/@babel/highlight@7.22.5:
resolution: {integrity: sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==}
@@ -191,14 +256,64 @@ packages:
'@babel/helper-validator-identifier': 7.22.5
chalk: 2.4.2
js-tokens: 4.0.0
- dev: false
+
+ /@babel/parser@7.22.5:
+ resolution: {integrity: sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+ dependencies:
+ '@babel/types': 7.17.0
+ dev: true
/@babel/runtime@7.22.5:
resolution: {integrity: sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==}
engines: {node: '>=6.9.0'}
dependencies:
regenerator-runtime: 0.13.11
- dev: false
+
+ /@babel/template@7.22.5:
+ resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/code-frame': 7.22.5
+ '@babel/parser': 7.22.5
+ '@babel/types': 7.22.5
+ dev: true
+
+ /@babel/traverse@7.17.3:
+ resolution: {integrity: sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/code-frame': 7.22.5
+ '@babel/generator': 7.17.7
+ '@babel/helper-environment-visitor': 7.22.5
+ '@babel/helper-function-name': 7.22.5
+ '@babel/helper-hoist-variables': 7.22.5
+ '@babel/helper-split-export-declaration': 7.22.5
+ '@babel/parser': 7.22.5
+ '@babel/types': 7.17.0
+ debug: 4.3.4
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/types@7.17.0:
+ resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-validator-identifier': 7.22.5
+ to-fast-properties: 2.0.0
+ dev: true
+
+ /@babel/types@7.22.5:
+ resolution: {integrity: sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-string-parser': 7.22.5
+ '@babel/helper-validator-identifier': 7.22.5
+ to-fast-properties: 2.0.0
+ dev: true
/@emotion/is-prop-valid@0.8.8:
resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==}
@@ -397,12 +512,10 @@ packages:
dependencies:
eslint: 8.44.0
eslint-visitor-keys: 3.4.1
- dev: false
/@eslint-community/regexpp@4.5.1:
resolution: {integrity: sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
- dev: false
/@eslint/eslintrc@2.1.0:
resolution: {integrity: sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==}
@@ -419,12 +532,10 @@ packages:
strip-json-comments: 3.1.1
transitivePeerDependencies:
- supports-color
- dev: false
/@eslint/js@8.44.0:
resolution: {integrity: sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- dev: false
/@floating-ui/core@1.3.1:
resolution: {integrity: sha512-Bu+AMaXNjrpjh41znzHqaz3r2Nr8hHuHZT6V2LBKMhyMl0FgKA62PNYbqnfgmzOhoWZj70Zecisbo4H1rotP5g==}
@@ -492,16 +603,13 @@ packages:
minimatch: 3.1.2
transitivePeerDependencies:
- supports-color
- dev: false
/@humanwhocodes/module-importer@1.0.1:
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
engines: {node: '>=12.22'}
- dev: false
/@humanwhocodes/object-schema@1.2.1:
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
- dev: false
/@isaacs/cliui@8.0.2:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
@@ -603,14 +711,14 @@ packages:
'@noble/hashes': 1.3.1
'@noble/secp256k1': 2.0.0
'@scure/base': 1.1.1
- '@typescript-eslint/eslint-plugin': 5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.44.0)(typescript@4.9.5)
- '@typescript-eslint/parser': 5.60.1(eslint@8.44.0)(typescript@4.9.5)
+ '@typescript-eslint/eslint-plugin': 5.61.0(@typescript-eslint/parser@5.61.0)(eslint@8.44.0)(typescript@4.9.5)
+ '@typescript-eslint/parser': 5.61.0(eslint@8.44.0)(typescript@4.9.5)
debug: 4.3.4
esbuild: 0.17.19
esbuild-plugin-alias: 0.2.1
eslint: 8.44.0
eslint-config-prettier: 8.8.0(eslint@8.44.0)
- eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.60.1)(eslint@8.44.0)
+ eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.61.0)(eslint@8.44.0)
esm-loader-typescript: 1.0.5
eventemitter3: 5.0.1
light-bolt11-decoder: 3.0.0
@@ -1078,54 +1186,6 @@ packages:
optional: true
dev: true
- /@rometools/cli-darwin-arm64@12.1.0:
- resolution: {integrity: sha512-U9trIXqE+WVsPUQRE8vooh97jNcyC1cvhNO91Q31FfWgccfbiJbfiQzPewpQ1+UseyJIdpWFAYLs8VFykhAl3g==}
- cpu: [arm64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rometools/cli-darwin-x64@12.1.0:
- resolution: {integrity: sha512-ePyRJwprT+POsGue1gdqPYOHojXfDz/OJI18renU0NI2CHeeeMhnquu+MZJaiBGyBd1ezIgWZWiQ4DhLFOaCUg==}
- cpu: [x64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rometools/cli-linux-arm64@12.1.0:
- resolution: {integrity: sha512-j/pF6pF+lKihw7CIvwQZqQG9gpaUy2FyO9+nu5dvCChblXNEaA2zMnpLnDlCue0B7xY0jZkk1EZdF49ztEZZFA==}
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rometools/cli-linux-x64@12.1.0:
- resolution: {integrity: sha512-zh6tW0JumP/rQkFDdsg6FEDBv0ZPvPLFirfHqzJA8VDNRBHkOTq27oVCbTJIGyUCGm9VvIzG8sJFVKkYpxkl2g==}
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rometools/cli-win32-arm64@12.1.0:
- resolution: {integrity: sha512-ggug6gUWFnO2QK0KC5XsYRhuZ22jeLksebdHMnkaHzZBtxXnKMC7yXnYwU/Lg2fGAwmMsluIbaqFYgen4+c8RA==}
- cpu: [arm64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rometools/cli-win32-x64@12.1.0:
- resolution: {integrity: sha512-TnurdnlzBwcvRSsgmNz9Gorffnjr5cS8TdHo9w+3pT4GdSsrLZqvd1IV2tj4uRKkNn6OJtSqW3tZ5SiTrf0LuA==}
- cpu: [x64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
/@scure/base@1.1.1:
resolution: {integrity: sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==}
dev: false
@@ -1425,6 +1485,26 @@ packages:
engines: {node: '>= 10'}
dev: false
+ /@trivago/prettier-plugin-sort-imports@4.1.1(prettier@2.8.8):
+ resolution: {integrity: sha512-dQ2r2uzNr1x6pJsuh/8x0IRA3CBUB+pWEW3J/7N98axqt7SQSm+2fy0FLNXvXGg77xEDC7KHxJlHfLYyi7PDcw==}
+ peerDependencies:
+ '@vue/compiler-sfc': 3.x
+ prettier: 2.x
+ peerDependenciesMeta:
+ '@vue/compiler-sfc':
+ optional: true
+ dependencies:
+ '@babel/generator': 7.17.7
+ '@babel/parser': 7.22.5
+ '@babel/traverse': 7.17.3
+ '@babel/types': 7.17.0
+ javascript-natural-sort: 0.7.1
+ lodash: 4.17.21
+ prettier: 2.8.8
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
/@tsd/typescript@5.0.4:
resolution: {integrity: sha512-YQi2lvZSI+xidKeUjlbv6b6Zw7qB3aXHw5oGJLs5OOGAEqKIOvz5UIAkWyg0bJbkSUWPBEtaOHpVxU4EYBO1Jg==}
dev: false
@@ -1446,7 +1526,6 @@ packages:
/@types/json-schema@7.0.12:
resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==}
- dev: false
/@types/json5@0.0.29:
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
@@ -1488,14 +1567,13 @@ packages:
/@types/semver@7.5.0:
resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==}
- dev: false
/@types/youtube-player@5.5.7:
resolution: {integrity: sha512-W8F4eoTIvzXeNrT3JroQPimZLXnlJA8smYygHZUKFPVoYwgs/OhJkA1VBhL3iSs57OQkuINqHlY4SmMT5wtnJg==}
dev: true
- /@typescript-eslint/eslint-plugin@5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.44.0)(typescript@4.9.5):
- resolution: {integrity: sha512-KSWsVvsJsLJv3c4e73y/Bzt7OpqMCADUO846bHcuWYSYM19bldbAeDv7dYyV0jwkbMfJ2XdlzwjhXtuD7OY6bw==}
+ /@typescript-eslint/eslint-plugin@5.61.0(@typescript-eslint/parser@5.61.0)(eslint@8.44.0)(typescript@4.9.5):
+ resolution: {integrity: sha512-A5l/eUAug103qtkwccSCxn8ZRwT+7RXWkFECdA4Cvl1dOlDUgTpAOfSEElZn2uSUxhdDpnCdetrf0jvU4qrL+g==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
'@typescript-eslint/parser': ^5.0.0
@@ -1506,13 +1584,13 @@ packages:
optional: true
dependencies:
'@eslint-community/regexpp': 4.5.1
- '@typescript-eslint/parser': 5.60.1(eslint@8.44.0)(typescript@4.9.5)
- '@typescript-eslint/scope-manager': 5.60.1
- '@typescript-eslint/type-utils': 5.60.1(eslint@8.44.0)(typescript@4.9.5)
- '@typescript-eslint/utils': 5.60.1(eslint@8.44.0)(typescript@4.9.5)
+ '@typescript-eslint/parser': 5.61.0(eslint@8.44.0)(typescript@4.9.5)
+ '@typescript-eslint/scope-manager': 5.61.0
+ '@typescript-eslint/type-utils': 5.61.0(eslint@8.44.0)(typescript@4.9.5)
+ '@typescript-eslint/utils': 5.61.0(eslint@8.44.0)(typescript@4.9.5)
debug: 4.3.4
eslint: 8.44.0
- grapheme-splitter: 1.0.4
+ graphemer: 1.4.0
ignore: 5.2.4
natural-compare-lite: 1.4.0
semver: 7.5.3
@@ -1520,10 +1598,9 @@ packages:
typescript: 4.9.5
transitivePeerDependencies:
- supports-color
- dev: false
- /@typescript-eslint/parser@5.60.1(eslint@8.44.0)(typescript@4.9.5):
- resolution: {integrity: sha512-pHWlc3alg2oSMGwsU/Is8hbm3XFbcrb6P5wIxcQW9NsYBfnrubl/GhVVD/Jm/t8HXhA2WncoIRfBtnCgRGV96Q==}
+ /@typescript-eslint/parser@5.61.0(eslint@8.44.0)(typescript@4.9.5):
+ resolution: {integrity: sha512-yGr4Sgyh8uO6fSi9hw3jAFXNBHbCtKKFMdX2IkT3ZqpKmtAq3lHS4ixB/COFuAIJpwl9/AqF7j72ZDWYKmIfvg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
@@ -1532,26 +1609,24 @@ packages:
typescript:
optional: true
dependencies:
- '@typescript-eslint/scope-manager': 5.60.1
- '@typescript-eslint/types': 5.60.1
- '@typescript-eslint/typescript-estree': 5.60.1(typescript@4.9.5)
+ '@typescript-eslint/scope-manager': 5.61.0
+ '@typescript-eslint/types': 5.61.0
+ '@typescript-eslint/typescript-estree': 5.61.0(typescript@4.9.5)
debug: 4.3.4
eslint: 8.44.0
typescript: 4.9.5
transitivePeerDependencies:
- supports-color
- dev: false
- /@typescript-eslint/scope-manager@5.60.1:
- resolution: {integrity: sha512-Dn/LnN7fEoRD+KspEOV0xDMynEmR3iSHdgNsarlXNLGGtcUok8L4N71dxUgt3YvlO8si7E+BJ5Fe3wb5yUw7DQ==}
+ /@typescript-eslint/scope-manager@5.61.0:
+ resolution: {integrity: sha512-W8VoMjoSg7f7nqAROEmTt6LoBpn81AegP7uKhhW5KzYlehs8VV0ZW0fIDVbcZRcaP3aPSW+JZFua+ysQN+m/Nw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
- '@typescript-eslint/types': 5.60.1
- '@typescript-eslint/visitor-keys': 5.60.1
- dev: false
+ '@typescript-eslint/types': 5.61.0
+ '@typescript-eslint/visitor-keys': 5.61.0
- /@typescript-eslint/type-utils@5.60.1(eslint@8.44.0)(typescript@4.9.5):
- resolution: {integrity: sha512-vN6UztYqIu05nu7JqwQGzQKUJctzs3/Hg7E2Yx8rz9J+4LgtIDFWjjl1gm3pycH0P3mHAcEUBd23LVgfrsTR8A==}
+ /@typescript-eslint/type-utils@5.61.0(eslint@8.44.0)(typescript@4.9.5):
+ resolution: {integrity: sha512-kk8u//r+oVK2Aj3ph/26XdH0pbAkC2RiSjUYhKD+PExemG4XSjpGFeyZ/QM8lBOa7O8aGOU+/yEbMJgQv/DnCg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: '*'
@@ -1560,23 +1635,21 @@ packages:
typescript:
optional: true
dependencies:
- '@typescript-eslint/typescript-estree': 5.60.1(typescript@4.9.5)
- '@typescript-eslint/utils': 5.60.1(eslint@8.44.0)(typescript@4.9.5)
+ '@typescript-eslint/typescript-estree': 5.61.0(typescript@4.9.5)
+ '@typescript-eslint/utils': 5.61.0(eslint@8.44.0)(typescript@4.9.5)
debug: 4.3.4
eslint: 8.44.0
tsutils: 3.21.0(typescript@4.9.5)
typescript: 4.9.5
transitivePeerDependencies:
- supports-color
- dev: false
- /@typescript-eslint/types@5.60.1:
- resolution: {integrity: sha512-zDcDx5fccU8BA0IDZc71bAtYIcG9PowaOwaD8rjYbqwK7dpe/UMQl3inJ4UtUK42nOCT41jTSCwg76E62JpMcg==}
+ /@typescript-eslint/types@5.61.0:
+ resolution: {integrity: sha512-ldyueo58KjngXpzloHUog/h9REmHl59G1b3a5Sng1GfBo14BkS3ZbMEb3693gnP1k//97lh7bKsp6/V/0v1veQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- dev: false
- /@typescript-eslint/typescript-estree@5.60.1(typescript@4.9.5):
- resolution: {integrity: sha512-hkX70J9+2M2ZT6fhti5Q2FoU9zb+GeZK2SLP1WZlvUDqdMbEKhexZODD1WodNRyO8eS+4nScvT0dts8IdaBzfw==}
+ /@typescript-eslint/typescript-estree@5.61.0(typescript@4.9.5):
+ resolution: {integrity: sha512-Fud90PxONnnLZ36oR5ClJBLTLfU4pIWBmnvGwTbEa2cXIqj70AEDEmOmpkFComjBZ/037ueKrOdHuYmSFVD7Rw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
typescript: '*'
@@ -1584,8 +1657,8 @@ packages:
typescript:
optional: true
dependencies:
- '@typescript-eslint/types': 5.60.1
- '@typescript-eslint/visitor-keys': 5.60.1
+ '@typescript-eslint/types': 5.61.0
+ '@typescript-eslint/visitor-keys': 5.61.0
debug: 4.3.4
globby: 11.1.0
is-glob: 4.0.3
@@ -1594,10 +1667,9 @@ packages:
typescript: 4.9.5
transitivePeerDependencies:
- supports-color
- dev: false
- /@typescript-eslint/utils@5.60.1(eslint@8.44.0)(typescript@4.9.5):
- resolution: {integrity: sha512-tiJ7FFdFQOWssFa3gqb94Ilexyw0JVxj6vBzaSpfN/8IhoKkDuSAenUKvsSHw2A/TMpJb26izIszTXaqygkvpQ==}
+ /@typescript-eslint/utils@5.61.0(eslint@8.44.0)(typescript@4.9.5):
+ resolution: {integrity: sha512-mV6O+6VgQmVE6+xzlA91xifndPW9ElFW8vbSF0xCT/czPXVhwDewKila1jOyRwa9AE19zKnrr7Cg5S3pJVrTWQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
@@ -1605,24 +1677,22 @@ packages:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.44.0)
'@types/json-schema': 7.0.12
'@types/semver': 7.5.0
- '@typescript-eslint/scope-manager': 5.60.1
- '@typescript-eslint/types': 5.60.1
- '@typescript-eslint/typescript-estree': 5.60.1(typescript@4.9.5)
+ '@typescript-eslint/scope-manager': 5.61.0
+ '@typescript-eslint/types': 5.61.0
+ '@typescript-eslint/typescript-estree': 5.61.0(typescript@4.9.5)
eslint: 8.44.0
eslint-scope: 5.1.1
semver: 7.5.3
transitivePeerDependencies:
- supports-color
- typescript
- dev: false
- /@typescript-eslint/visitor-keys@5.60.1:
- resolution: {integrity: sha512-xEYIxKcultP6E/RMKqube11pGjXH1DCo60mQoWhVYyKfLkwbIVVjYxmOenNMxILx0TjCujPTjjnTIVzm09TXIw==}
+ /@typescript-eslint/visitor-keys@5.61.0:
+ resolution: {integrity: sha512-50XQ5VdbWrX06mQXhy93WywSFZZGsv3EOjq+lqp6WC2t+j3mb6A9xYVdrRxafvK88vg9k9u+CT4l6D8PEatjKg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
- '@typescript-eslint/types': 5.60.1
+ '@typescript-eslint/types': 5.61.0
eslint-visitor-keys: 3.4.1
- dev: false
/@vitejs/plugin-react-swc@3.3.2(vite@4.3.9):
resolution: {integrity: sha512-VJFWY5sfoZerQRvJrh518h3AcQt6f/yTuWn4/TRB+dqmYU0NX1qz7qM5Wfd+gOQqUzQW4gxKqKN3KpE/P3+zrA==}
@@ -1645,13 +1715,11 @@ packages:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
acorn: 8.9.0
- dev: false
/acorn@8.9.0:
resolution: {integrity: sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==}
engines: {node: '>=0.4.0'}
hasBin: true
- dev: false
/agent-base@6.0.2:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
@@ -1687,7 +1755,6 @@ packages:
fast-json-stable-stringify: 2.1.0
json-schema-traverse: 0.4.1
uri-js: 4.4.1
- dev: false
/ansi-escapes@4.3.2:
resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
@@ -1708,7 +1775,6 @@ packages:
engines: {node: '>=4'}
dependencies:
color-convert: 1.9.3
- dev: false
/ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
@@ -1755,7 +1821,6 @@ packages:
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
- dev: false
/aria-hidden@1.2.3:
resolution: {integrity: sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==}
@@ -1764,12 +1829,17 @@ packages:
tslib: 2.6.0
dev: false
+ /aria-query@5.3.0:
+ resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
+ dependencies:
+ dequal: 2.0.3
+ dev: true
+
/array-buffer-byte-length@1.0.0:
resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==}
dependencies:
call-bind: 1.0.2
is-array-buffer: 3.0.2
- dev: false
/array-includes@3.1.6:
resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==}
@@ -1780,12 +1850,10 @@ packages:
es-abstract: 1.21.2
get-intrinsic: 1.2.1
is-string: 1.0.7
- dev: false
/array-union@2.1.0:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
- dev: false
/array.prototype.flat@1.3.1:
resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==}
@@ -1795,7 +1863,6 @@ packages:
define-properties: 1.2.0
es-abstract: 1.21.2
es-shim-unscopables: 1.0.0
- dev: false
/array.prototype.flatmap@1.3.1:
resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==}
@@ -1805,13 +1872,26 @@ packages:
define-properties: 1.2.0
es-abstract: 1.21.2
es-shim-unscopables: 1.0.0
- dev: false
+
+ /array.prototype.tosorted@1.1.1:
+ resolution: {integrity: sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ es-shim-unscopables: 1.0.0
+ get-intrinsic: 1.2.1
+ dev: true
/arrify@1.0.1:
resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==}
engines: {node: '>=0.10.0'}
dev: false
+ /ast-types-flow@0.0.7:
+ resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==}
+ dev: true
+
/astral-regex@2.0.0:
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
engines: {node: '>=8'}
@@ -1836,7 +1916,17 @@ packages:
/available-typed-arrays@1.0.5:
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
engines: {node: '>= 0.4'}
- dev: false
+
+ /axe-core@4.7.2:
+ resolution: {integrity: sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /axobject-query@3.2.1:
+ resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==}
+ dependencies:
+ dequal: 2.0.3
+ dev: true
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@@ -1910,12 +2000,10 @@ packages:
dependencies:
function-bind: 1.1.1
get-intrinsic: 1.2.1
- dev: false
/callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
- dev: false
/camelcase-css@2.0.1:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
@@ -1947,7 +2035,6 @@ packages:
ansi-styles: 3.2.1
escape-string-regexp: 1.0.5
supports-color: 5.5.0
- dev: false
/chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
@@ -1955,7 +2042,6 @@ packages:
dependencies:
ansi-styles: 4.3.0
supports-color: 7.2.0
- dev: false
/chalk@5.2.0:
resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==}
@@ -2041,7 +2127,6 @@ packages:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies:
color-name: 1.1.3
- dev: false
/color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
@@ -2051,7 +2136,6 @@ packages:
/color-name@1.1.3:
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
- dev: false
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
@@ -2151,6 +2235,10 @@ packages:
type: 1.2.0
dev: false
+ /damerau-levenshtein@1.0.8:
+ resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
+ dev: true
+
/data-uri-to-buffer@4.0.1:
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
engines: {node: '>= 12'}
@@ -2208,7 +2296,6 @@ packages:
/deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
- dev: false
/deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
@@ -2221,7 +2308,6 @@ packages:
dependencies:
has-property-descriptors: 1.0.0
object-keys: 1.1.1
- dev: false
/delegates@1.0.0:
resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
@@ -2232,6 +2318,11 @@ packages:
engines: {node: '>= 0.8'}
dev: false
+ /dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+ dev: true
+
/destr@1.2.2:
resolution: {integrity: sha512-lrbCJwD9saUQrqUfXvl6qoM+QN3W7tLV5pAOs+OqOmopCCz/JkE05MHedJR1xfk4IAnZuJXPVuN5+7jNA2ZCiA==}
dev: false
@@ -2254,7 +2345,6 @@ packages:
engines: {node: '>=8'}
dependencies:
path-type: 4.0.0
- dev: false
/direction@1.0.4:
resolution: {integrity: sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==}
@@ -2270,14 +2360,12 @@ packages:
engines: {node: '>=0.10.0'}
dependencies:
esutils: 2.0.3
- dev: false
/doctrine@3.0.0:
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
engines: {node: '>=6.0.0'}
dependencies:
esutils: 2.0.3
- dev: false
/dom-serializer@2.0.0:
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
@@ -2382,7 +2470,6 @@ packages:
typed-array-length: 1.0.4
unbox-primitive: 1.0.2
which-typed-array: 1.1.9
- dev: false
/es-set-tostringtag@2.0.1:
resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==}
@@ -2391,13 +2478,11 @@ packages:
get-intrinsic: 1.2.1
has: 1.0.3
has-tostringtag: 1.0.0
- dev: false
/es-shim-unscopables@1.0.0:
resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==}
dependencies:
has: 1.0.3
- dev: false
/es-to-primitive@1.2.1:
resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
@@ -2406,7 +2491,6 @@ packages:
is-callable: 1.2.7
is-date-object: 1.0.5
is-symbol: 1.0.4
- dev: false
/es5-ext@0.10.62:
resolution: {integrity: sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==}
@@ -2474,12 +2558,10 @@ packages:
/escape-string-regexp@1.0.5:
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
engines: {node: '>=0.8.0'}
- dev: false
/escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
- dev: false
/eslint-config-prettier@8.8.0(eslint@8.44.0):
resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==}
@@ -2488,7 +2570,6 @@ packages:
eslint: '>=7.0.0'
dependencies:
eslint: 8.44.0
- dev: false
/eslint-formatter-pretty@4.1.0:
resolution: {integrity: sha512-IsUTtGxF1hrH6lMWiSl1WbGaiP01eT6kzywdY1U+zLc0MP+nwEnUiS9UI8IaOTUhTeQJLlCEWIbXINBH4YJbBQ==}
@@ -2514,7 +2595,7 @@ packages:
- supports-color
dev: false
- /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.60.1)(eslint-import-resolver-node@0.3.7)(eslint@8.44.0):
+ /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.61.0)(eslint-import-resolver-node@0.3.7)(eslint@8.44.0):
resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
engines: {node: '>=4'}
peerDependencies:
@@ -2535,7 +2616,7 @@ packages:
eslint-import-resolver-webpack:
optional: true
dependencies:
- '@typescript-eslint/parser': 5.60.1(eslint@8.44.0)(typescript@4.9.5)
+ '@typescript-eslint/parser': 5.61.0(eslint@8.44.0)(typescript@4.9.5)
debug: 3.2.7
eslint: 8.44.0
eslint-import-resolver-node: 0.3.7
@@ -2543,7 +2624,7 @@ packages:
- supports-color
dev: false
- /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.60.1)(eslint@8.44.0):
+ /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.61.0)(eslint@8.44.0):
resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==}
engines: {node: '>=4'}
peerDependencies:
@@ -2553,7 +2634,7 @@ packages:
'@typescript-eslint/parser':
optional: true
dependencies:
- '@typescript-eslint/parser': 5.60.1(eslint@8.44.0)(typescript@4.9.5)
+ '@typescript-eslint/parser': 5.61.0(eslint@8.44.0)(typescript@4.9.5)
array-includes: 3.1.6
array.prototype.flat: 1.3.1
array.prototype.flatmap: 1.3.1
@@ -2561,7 +2642,7 @@ packages:
doctrine: 2.1.0
eslint: 8.44.0
eslint-import-resolver-node: 0.3.7
- eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.60.1)(eslint-import-resolver-node@0.3.7)(eslint@8.44.0)
+ eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.61.0)(eslint-import-resolver-node@0.3.7)(eslint@8.44.0)
has: 1.0.3
is-core-module: 2.12.1
is-glob: 4.0.3
@@ -2576,6 +2657,63 @@ packages:
- supports-color
dev: false
+ /eslint-plugin-jsx-a11y@6.7.1(eslint@8.44.0):
+ resolution: {integrity: sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
+ dependencies:
+ '@babel/runtime': 7.22.5
+ aria-query: 5.3.0
+ array-includes: 3.1.6
+ array.prototype.flatmap: 1.3.1
+ ast-types-flow: 0.0.7
+ axe-core: 4.7.2
+ axobject-query: 3.2.1
+ damerau-levenshtein: 1.0.8
+ emoji-regex: 9.2.2
+ eslint: 8.44.0
+ has: 1.0.3
+ jsx-ast-utils: 3.3.4
+ language-tags: 1.0.5
+ minimatch: 3.1.2
+ object.entries: 1.1.6
+ object.fromentries: 2.0.6
+ semver: 6.3.0
+ dev: true
+
+ /eslint-plugin-react@7.32.2(eslint@8.44.0):
+ resolution: {integrity: sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
+ dependencies:
+ array-includes: 3.1.6
+ array.prototype.flatmap: 1.3.1
+ array.prototype.tosorted: 1.1.1
+ doctrine: 2.1.0
+ eslint: 8.44.0
+ estraverse: 5.3.0
+ jsx-ast-utils: 3.3.4
+ minimatch: 3.1.2
+ object.entries: 1.1.6
+ object.fromentries: 2.0.6
+ object.hasown: 1.1.2
+ object.values: 1.1.6
+ prop-types: 15.8.1
+ resolve: 2.0.0-next.4
+ semver: 6.3.0
+ string.prototype.matchall: 4.0.8
+ dev: true
+
+ /eslint-plugin-simple-import-sort@10.0.0(eslint@8.44.0):
+ resolution: {integrity: sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==}
+ peerDependencies:
+ eslint: '>=5.0.0'
+ dependencies:
+ eslint: 8.44.0
+ dev: true
+
/eslint-rule-docs@1.1.235:
resolution: {integrity: sha512-+TQ+x4JdTnDoFEXXb3fDvfGOwnyNV7duH8fXWTPD1ieaBmB8omj7Gw/pMBBu4uI2uJCCU8APDaQJzWuXnTsH4A==}
dev: false
@@ -2586,7 +2724,6 @@ packages:
dependencies:
esrecurse: 4.3.0
estraverse: 4.3.0
- dev: false
/eslint-scope@7.2.0:
resolution: {integrity: sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==}
@@ -2594,12 +2731,10 @@ packages:
dependencies:
esrecurse: 4.3.0
estraverse: 5.3.0
- dev: false
/eslint-visitor-keys@3.4.1:
resolution: {integrity: sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- dev: false
/eslint@8.44.0:
resolution: {integrity: sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==}
@@ -2647,7 +2782,6 @@ packages:
text-table: 0.2.0
transitivePeerDependencies:
- supports-color
- dev: false
/esm-loader-typescript@1.0.5:
resolution: {integrity: sha512-BeHp2TrYbRL9fUttlyzPQJPTvLDBXXUli09UNoAr87WKi8jedcULlMteNZgl7DtFZ3ZE1Mmv74SwRgwJDWyc0A==}
@@ -2665,36 +2799,30 @@ packages:
acorn: 8.9.0
acorn-jsx: 5.3.2(acorn@8.9.0)
eslint-visitor-keys: 3.4.1
- dev: false
/esquery@1.5.0:
resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
engines: {node: '>=0.10'}
dependencies:
estraverse: 5.3.0
- dev: false
/esrecurse@4.3.0:
resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
engines: {node: '>=4.0'}
dependencies:
estraverse: 5.3.0
- dev: false
/estraverse@4.3.0:
resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==}
engines: {node: '>=4.0'}
- dev: false
/estraverse@5.3.0:
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
engines: {node: '>=4.0'}
- dev: false
/esutils@2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
- dev: false
/eventemitter3@5.0.1:
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
@@ -2727,7 +2855,6 @@ packages:
/fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
- dev: false
/fast-glob@3.2.12:
resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==}
@@ -2741,11 +2868,9 @@ packages:
/fast-json-stable-stringify@2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
- dev: false
/fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
- dev: false
/fastq@1.15.0:
resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
@@ -2765,7 +2890,6 @@ packages:
engines: {node: ^10.12.0 || >=12.0.0}
dependencies:
flat-cache: 3.0.4
- dev: false
/fill-range@7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
@@ -2787,7 +2911,6 @@ packages:
dependencies:
locate-path: 6.0.0
path-exists: 4.0.0
- dev: false
/flat-cache@3.0.4:
resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==}
@@ -2795,17 +2918,14 @@ packages:
dependencies:
flatted: 3.2.7
rimraf: 3.0.2
- dev: false
/flatted@3.2.7:
resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
- dev: false
/for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
dependencies:
is-callable: 1.2.7
- dev: false
/foreground-child@3.1.1:
resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
@@ -2880,11 +3000,9 @@ packages:
define-properties: 1.2.0
es-abstract: 1.21.2
functions-have-names: 1.2.3
- dev: false
/functions-have-names@1.2.3:
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
- dev: false
/gauge@4.0.4:
resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==}
@@ -2907,7 +3025,6 @@ packages:
has: 1.0.3
has-proto: 1.0.1
has-symbols: 1.0.3
- dev: false
/get-nonce@1.0.1:
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
@@ -2925,7 +3042,6 @@ packages:
dependencies:
call-bind: 1.0.2
get-intrinsic: 1.2.1
- dev: false
/get-urls@11.0.0:
resolution: {integrity: sha512-rxTvv9HszwTtPfN7oRGVTVn7aPmvLKGqY41SFpMyKan65un/nZHWhqmD+URmnCG7w/B+IFqKw1lWzYfxgfFLEw==}
@@ -2982,21 +3098,23 @@ packages:
minimatch: 3.1.2
once: 1.4.0
path-is-absolute: 1.0.1
- dev: false
+
+ /globals@11.12.0:
+ resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+ engines: {node: '>=4'}
+ dev: true
/globals@13.20.0:
resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==}
engines: {node: '>=8'}
dependencies:
type-fest: 0.20.2
- dev: false
/globalthis@1.0.3:
resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
engines: {node: '>= 0.4'}
dependencies:
define-properties: 1.2.0
- dev: false
/globby@11.1.0:
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
@@ -3008,7 +3126,6 @@ packages:
ignore: 5.2.4
merge2: 1.4.1
slash: 3.0.0
- dev: false
/globrex@0.1.2:
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
@@ -3018,19 +3135,13 @@ packages:
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
dependencies:
get-intrinsic: 1.2.1
- dev: false
/graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
dev: false
- /grapheme-splitter@1.0.4:
- resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==}
- dev: false
-
/graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
- dev: false
/hard-rejection@2.1.0:
resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==}
@@ -3039,40 +3150,33 @@ packages:
/has-bigints@1.0.2:
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
- dev: false
/has-flag@3.0.0:
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'}
- dev: false
/has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
- dev: false
/has-property-descriptors@1.0.0:
resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
dependencies:
get-intrinsic: 1.2.1
- dev: false
/has-proto@1.0.1:
resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
engines: {node: '>= 0.4'}
- dev: false
/has-symbols@1.0.3:
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
engines: {node: '>= 0.4'}
- dev: false
/has-tostringtag@1.0.0:
resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==}
engines: {node: '>= 0.4'}
dependencies:
has-symbols: 1.0.3
- dev: false
/has-unicode@2.0.1:
resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
@@ -3155,7 +3259,6 @@ packages:
/ignore@5.2.4:
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
engines: {node: '>= 4'}
- dev: false
/immer@10.0.2:
resolution: {integrity: sha512-Rx3CqeqQ19sxUtYV9CU911Vhy8/721wRFnJv3REVGWUmoAcIwzifTsdmJte/MV+0/XpM35LZdQMBGkRIoLPwQA==}
@@ -3171,12 +3274,10 @@ packages:
dependencies:
parent-module: 1.0.1
resolve-from: 4.0.0
- dev: false
/imurmurhash@0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
- dev: false
/indent-string@4.0.0:
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
@@ -3203,7 +3304,6 @@ packages:
get-intrinsic: 1.2.1
has: 1.0.3
side-channel: 1.0.4
- dev: false
/invariant@2.2.4:
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
@@ -3231,7 +3331,6 @@ packages:
call-bind: 1.0.2
get-intrinsic: 1.2.1
is-typed-array: 1.1.10
- dev: false
/is-arrayish@0.2.1:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
@@ -3241,7 +3340,6 @@ packages:
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
dependencies:
has-bigints: 1.0.2
- dev: false
/is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
@@ -3256,12 +3354,10 @@ packages:
dependencies:
call-bind: 1.0.2
has-tostringtag: 1.0.0
- dev: false
/is-callable@1.2.7:
resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
engines: {node: '>= 0.4'}
- dev: false
/is-core-module@2.12.1:
resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==}
@@ -3273,7 +3369,6 @@ packages:
engines: {node: '>= 0.4'}
dependencies:
has-tostringtag: 1.0.0
- dev: false
/is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
@@ -3305,14 +3400,12 @@ packages:
/is-negative-zero@2.0.2:
resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
engines: {node: '>= 0.4'}
- dev: false
/is-number-object@1.0.7:
resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
engines: {node: '>= 0.4'}
dependencies:
has-tostringtag: 1.0.0
- dev: false
/is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
@@ -3321,7 +3414,6 @@ packages:
/is-path-inside@3.0.3:
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
engines: {node: '>=8'}
- dev: false
/is-plain-obj@1.1.0:
resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==}
@@ -3339,13 +3431,11 @@ packages:
dependencies:
call-bind: 1.0.2
has-tostringtag: 1.0.0
- dev: false
/is-shared-array-buffer@1.0.2:
resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==}
dependencies:
call-bind: 1.0.2
- dev: false
/is-stream@3.0.0:
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
@@ -3357,14 +3447,12 @@ packages:
engines: {node: '>= 0.4'}
dependencies:
has-tostringtag: 1.0.0
- dev: false
/is-symbol@1.0.4:
resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
engines: {node: '>= 0.4'}
dependencies:
has-symbols: 1.0.3
- dev: false
/is-typed-array@1.1.10:
resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==}
@@ -3375,7 +3463,6 @@ packages:
for-each: 0.3.3
gopd: 1.0.1
has-tostringtag: 1.0.0
- dev: false
/is-typedarray@1.0.0:
resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
@@ -3390,7 +3477,6 @@ packages:
resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
dependencies:
call-bind: 1.0.2
- dev: false
/isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
@@ -3404,6 +3490,10 @@ packages:
'@pkgjs/parseargs': 0.11.0
dev: false
+ /javascript-natural-sort@0.7.1:
+ resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==}
+ dev: true
+
/jest-diff@29.5.0:
resolution: {integrity: sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -3432,7 +3522,12 @@ packages:
hasBin: true
dependencies:
argparse: 2.0.1
- dev: false
+
+ /jsesc@2.5.2:
+ resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: true
/json-parse-better-errors@1.0.2:
resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==}
@@ -3444,11 +3539,9 @@ packages:
/json-schema-traverse@0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
- dev: false
/json-stable-stringify-without-jsonify@1.0.1:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
- dev: false
/json5@1.0.2:
resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
@@ -3457,18 +3550,37 @@ packages:
minimist: 1.2.8
dev: false
+ /jsx-ast-utils@3.3.4:
+ resolution: {integrity: sha512-fX2TVdCViod6HwKEtSWGHs57oFhVfCMwieb9PuRDgjDPh5XeqJiHFFFJCHxU5cnTc3Bu/GRL+kPiFmw8XWOfKw==}
+ engines: {node: '>=4.0'}
+ dependencies:
+ array-includes: 3.1.6
+ array.prototype.flat: 1.3.1
+ object.assign: 4.1.4
+ object.values: 1.1.6
+ dev: true
+
/kind-of@6.0.3:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
engines: {node: '>=0.10.0'}
dev: false
+ /language-subtag-registry@0.3.22:
+ resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==}
+ dev: true
+
+ /language-tags@1.0.5:
+ resolution: {integrity: sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==}
+ dependencies:
+ language-subtag-registry: 0.3.22
+ dev: true
+
/levn@0.4.1:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
dependencies:
prelude-ls: 1.2.1
type-check: 0.4.0
- dev: false
/light-bolt11-decoder@3.0.0:
resolution: {integrity: sha512-AKvOigD2pmC8ktnn2TIqdJu0K0qk6ukUmTvHwF3JNkm8uWCqt18Ijn33A/a7gaRZ4PghJ59X+8+MXrzLKdBTmQ==}
@@ -3552,7 +3664,6 @@ packages:
engines: {node: '>=10'}
dependencies:
p-locate: 5.0.0
- dev: false
/lodash.castarray@4.4.0:
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
@@ -3567,7 +3678,6 @@ packages:
/lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
- dev: false
/log-symbols@4.1.0:
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
@@ -3603,7 +3713,6 @@ packages:
engines: {node: '>=10'}
dependencies:
yallist: 4.0.0
- dev: false
/lru-cache@7.18.3:
resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
@@ -3821,11 +3930,9 @@ packages:
/natural-compare-lite@1.4.0:
resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
- dev: false
/natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
- dev: false
/negotiator@0.6.3:
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
@@ -3989,7 +4096,6 @@ packages:
/object-keys@1.1.1:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
engines: {node: '>= 0.4'}
- dev: false
/object.assign@4.1.4:
resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==}
@@ -3999,7 +4105,31 @@ packages:
define-properties: 1.2.0
has-symbols: 1.0.3
object-keys: 1.1.1
- dev: false
+
+ /object.entries@1.1.6:
+ resolution: {integrity: sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ dev: true
+
+ /object.fromentries@2.0.6:
+ resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ dev: true
+
+ /object.hasown@1.1.2:
+ resolution: {integrity: sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==}
+ dependencies:
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ dev: true
/object.values@1.1.6:
resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==}
@@ -4008,7 +4138,6 @@ packages:
call-bind: 1.0.2
define-properties: 1.2.0
es-abstract: 1.21.2
- dev: false
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
@@ -4039,7 +4168,6 @@ packages:
levn: 0.4.1
prelude-ls: 1.2.1
type-check: 0.4.0
- dev: false
/p-limit@2.3.0:
resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
@@ -4053,7 +4181,6 @@ packages:
engines: {node: '>=10'}
dependencies:
yocto-queue: 0.1.0
- dev: false
/p-locate@4.1.0:
resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
@@ -4067,7 +4194,6 @@ packages:
engines: {node: '>=10'}
dependencies:
p-limit: 3.1.0
- dev: false
/p-map@4.0.0:
resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
@@ -4085,7 +4211,6 @@ packages:
engines: {node: '>=6'}
dependencies:
callsites: 3.1.0
- dev: false
/parse-json@4.0.0:
resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==}
@@ -4121,7 +4246,6 @@ packages:
/path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
- dev: false
/path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
@@ -4162,7 +4286,6 @@ packages:
/path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
- dev: false
/picocolors@1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
@@ -4287,7 +4410,68 @@ packages:
/prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
- dev: false
+
+ /prettier-plugin-tailwindcss@0.3.0(@trivago/prettier-plugin-sort-imports@4.1.1)(prettier@2.8.8):
+ resolution: {integrity: sha512-009/Xqdy7UmkcTBpwlq7jsViDqXAYSOMLDrHAdTMlVZOrKfM2o9Ci7EMWTMZ7SkKBFTG04UM9F9iM2+4i6boDA==}
+ engines: {node: '>=12.17.0'}
+ peerDependencies:
+ '@ianvs/prettier-plugin-sort-imports': '*'
+ '@prettier/plugin-pug': '*'
+ '@shopify/prettier-plugin-liquid': '*'
+ '@shufo/prettier-plugin-blade': '*'
+ '@trivago/prettier-plugin-sort-imports': '*'
+ prettier: '>=2.2.0'
+ prettier-plugin-astro: '*'
+ prettier-plugin-css-order: '*'
+ prettier-plugin-import-sort: '*'
+ prettier-plugin-jsdoc: '*'
+ prettier-plugin-marko: '*'
+ prettier-plugin-organize-attributes: '*'
+ prettier-plugin-organize-imports: '*'
+ prettier-plugin-style-order: '*'
+ prettier-plugin-svelte: '*'
+ prettier-plugin-twig-melody: '*'
+ peerDependenciesMeta:
+ '@ianvs/prettier-plugin-sort-imports':
+ optional: true
+ '@prettier/plugin-pug':
+ optional: true
+ '@shopify/prettier-plugin-liquid':
+ optional: true
+ '@shufo/prettier-plugin-blade':
+ optional: true
+ '@trivago/prettier-plugin-sort-imports':
+ optional: true
+ prettier-plugin-astro:
+ optional: true
+ prettier-plugin-css-order:
+ optional: true
+ prettier-plugin-import-sort:
+ optional: true
+ prettier-plugin-jsdoc:
+ optional: true
+ prettier-plugin-marko:
+ optional: true
+ prettier-plugin-organize-attributes:
+ optional: true
+ prettier-plugin-organize-imports:
+ optional: true
+ prettier-plugin-style-order:
+ optional: true
+ prettier-plugin-svelte:
+ optional: true
+ prettier-plugin-twig-melody:
+ optional: true
+ dependencies:
+ '@trivago/prettier-plugin-sort-imports': 4.1.1(prettier@2.8.8)
+ prettier: 2.8.8
+ dev: true
+
+ /prettier@2.8.8:
+ resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
+ engines: {node: '>=10.13.0'}
+ hasBin: true
+ dev: true
/pretty-format@29.5.0:
resolution: {integrity: sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==}
@@ -4316,7 +4500,6 @@ packages:
/punycode@2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
- dev: false
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -4548,7 +4731,6 @@ packages:
/regenerator-runtime@0.13.11:
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
- dev: false
/regexp.prototype.flags@1.5.0:
resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==}
@@ -4557,12 +4739,10 @@ packages:
call-bind: 1.0.2
define-properties: 1.2.0
functions-have-names: 1.2.3
- dev: false
/resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
- dev: false
/resolve@1.22.2:
resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==}
@@ -4572,6 +4752,15 @@ packages:
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
+ /resolve@2.0.0-next.4:
+ resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==}
+ hasBin: true
+ dependencies:
+ is-core-module: 2.12.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+ dev: true
+
/restore-cursor@3.1.0:
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
engines: {node: '>=8'}
@@ -4598,7 +4787,6 @@ packages:
hasBin: true
dependencies:
glob: 7.2.3
- dev: false
/rollup@3.26.0:
resolution: {integrity: sha512-YzJH0eunH2hr3knvF3i6IkLO/jTjAEwU4HoMUbQl4//Tnl3ou0e7P5SjxdDr8HQJdeUJShlbEHXrrnEHy1l7Yg==}
@@ -4608,20 +4796,6 @@ packages:
fsevents: 2.3.2
dev: true
- /rome@12.1.0:
- resolution: {integrity: sha512-inIBYc2/Das6LDXcw8IQp7yeXth6Rhmj9y8sS/Y/0g5/29Lyzr785SjCmKyiN2No4MNsaP3YJNm2QZAs2UpR2w==}
- engines: {node: '>=14.*'}
- hasBin: true
- requiresBuild: true
- optionalDependencies:
- '@rometools/cli-darwin-arm64': 12.1.0
- '@rometools/cli-darwin-x64': 12.1.0
- '@rometools/cli-linux-arm64': 12.1.0
- '@rometools/cli-linux-x64': 12.1.0
- '@rometools/cli-win32-arm64': 12.1.0
- '@rometools/cli-win32-x64': 12.1.0
- dev: true
-
/run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
@@ -4643,7 +4817,6 @@ packages:
call-bind: 1.0.2
get-intrinsic: 1.2.1
is-regex: 1.1.4
- dev: false
/safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
@@ -4668,7 +4841,6 @@ packages:
/semver@6.3.0:
resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
hasBin: true
- dev: false
/semver@7.5.3:
resolution: {integrity: sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==}
@@ -4676,7 +4848,6 @@ packages:
hasBin: true
dependencies:
lru-cache: 6.0.0
- dev: false
/set-blocking@2.0.0:
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
@@ -4714,7 +4885,6 @@ packages:
call-bind: 1.0.2
get-intrinsic: 1.2.1
object-inspect: 1.12.3
- dev: false
/signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
@@ -4727,7 +4897,6 @@ packages:
/slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
- dev: false
/slate-history@0.93.0(slate@0.94.1):
resolution: {integrity: sha512-Gr1GMGPipRuxIz41jD2/rbvzPj8eyar56TVMyJBvBeIpQSSjNISssvGNDYfJlSWM8eaRqf6DAcxMKzsLCYeX6g==}
@@ -4822,6 +4991,11 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
+ /source-map@0.5.7:
+ resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
/spdx-correct@3.2.0:
resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==}
dependencies:
@@ -4872,6 +5046,19 @@ packages:
emoji-regex: 9.2.2
strip-ansi: 7.1.0
+ /string.prototype.matchall@4.0.8:
+ resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ get-intrinsic: 1.2.1
+ has-symbols: 1.0.3
+ internal-slot: 1.0.5
+ regexp.prototype.flags: 1.5.0
+ side-channel: 1.0.4
+ dev: true
+
/string.prototype.padend@3.1.4:
resolution: {integrity: sha512-67otBXoksdjsnXXRUq+KMVTdlVRZ2af422Y0aTyTjVaoQkGr3mxl2Bc5emi7dOQ3OGVVQQskmLEWwFXwommpNw==}
engines: {node: '>= 0.4'}
@@ -4888,7 +5075,6 @@ packages:
call-bind: 1.0.2
define-properties: 1.2.0
es-abstract: 1.21.2
- dev: false
/string.prototype.trimend@1.0.6:
resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==}
@@ -4896,7 +5082,6 @@ packages:
call-bind: 1.0.2
define-properties: 1.2.0
es-abstract: 1.21.2
- dev: false
/string.prototype.trimstart@1.0.6:
resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==}
@@ -4904,7 +5089,6 @@ packages:
call-bind: 1.0.2
define-properties: 1.2.0
es-abstract: 1.21.2
- dev: false
/string_decoder@1.3.0:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
@@ -4944,7 +5128,6 @@ packages:
/strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
- dev: false
/sucrase@3.32.0:
resolution: {integrity: sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==}
@@ -4965,14 +5148,12 @@ packages:
engines: {node: '>=4'}
dependencies:
has-flag: 3.0.0
- dev: false
/supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
dependencies:
has-flag: 4.0.0
- dev: false
/supports-hyperlinks@2.3.0:
resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==}
@@ -5040,7 +5221,6 @@ packages:
/text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
- dev: false
/thenify-all@1.6.0:
resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
@@ -5072,6 +5252,11 @@ packages:
hasBin: true
dev: false
+ /to-fast-properties@2.0.0:
+ resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
+ engines: {node: '>=4'}
+ dev: true
+
/to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@@ -5125,7 +5310,6 @@ packages:
/tslib@1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
- dev: false
/tslib@2.6.0:
resolution: {integrity: sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==}
@@ -5142,14 +5326,12 @@ packages:
dependencies:
tslib: 1.14.1
typescript: 4.9.5
- dev: false
/type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
dependencies:
prelude-ls: 1.2.1
- dev: false
/type-fest@0.18.1:
resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==}
@@ -5159,7 +5341,6 @@ packages:
/type-fest@0.20.2:
resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
engines: {node: '>=10'}
- dev: false
/type-fest@0.21.3:
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
@@ -5189,7 +5370,6 @@ packages:
call-bind: 1.0.2
for-each: 0.3.3
is-typed-array: 1.1.10
- dev: false
/typedarray-to-buffer@3.1.5:
resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==}
@@ -5215,7 +5395,6 @@ packages:
has-bigints: 1.0.2
has-symbols: 1.0.3
which-boxed-primitive: 1.0.2
- dev: false
/unique-filename@3.0.0:
resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==}
@@ -5246,7 +5425,6 @@ packages:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
dependencies:
punycode: 2.3.0
- dev: false
/url-regex-safe@3.0.0(re2@1.19.1):
resolution: {integrity: sha512-+2U40NrcmtWFVjuxXVt9bGRw6c7/MgkGKN9xIfPrT/2RX0LTkkae6CCEDp93xqUN0UKm/rr821QnHd2dHQmN3A==}
@@ -5429,7 +5607,6 @@ packages:
is-number-object: 1.0.7
is-string: 1.0.7
is-symbol: 1.0.4
- dev: false
/which-typed-array@1.1.9:
resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==}
@@ -5441,7 +5618,6 @@ packages:
gopd: 1.0.1
has-tostringtag: 1.0.0
is-typed-array: 1.1.10
- dev: false
/which@1.3.1:
resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
@@ -5499,7 +5675,6 @@ packages:
/yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
- dev: false
/yaml@2.3.1:
resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==}
@@ -5514,7 +5689,6 @@ packages:
/yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
- dev: false
/zustand@4.3.8(immer@10.0.2)(react@18.2.0):
resolution: {integrity: sha512-4h28KCkHg5ii/wcFFJ5Fp+k1J3gJoasaIbppdgZFO4BPJnsNxL0mQXBSFgOgAdCdBj35aDTPvdAJReTMntFPGg==}
diff --git a/rome.json b/rome.json
deleted file mode 100644
index 85e749ff..00000000
--- a/rome.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "$schema": "https://docs.rome.tools/schemas/12.1.0/schema.json",
- "organizeImports": {
- "enabled": true
- },
- "linter": {
- "enabled": true,
- "rules": {
- "recommended": true,
- "a11y": {
- "noSvgWithoutTitle": "off"
- },
- "suspicious": {
- "noExplicitAny": "off"
- }
- }
- }
-}
diff --git a/src/app.tsx b/src/app.tsx
index bfa4f797..6fdd7e0c 100644
--- a/src/app.tsx
+++ b/src/app.tsx
@@ -1,102 +1,105 @@
-import "./index.css";
-import { AuthCreateScreen } from "@app/auth/create";
-import { CreateStep1Screen } from "@app/auth/create/step-1";
-import { CreateStep2Screen } from "@app/auth/create/step-2";
-import { CreateStep3Screen } from "@app/auth/create/step-3";
-import { CreateStep4Screen } from "@app/auth/create/step-4";
-import { AuthImportScreen } from "@app/auth/import";
-import { ImportStep1Screen } from "@app/auth/import/step-1";
-import { ImportStep2Screen } from "@app/auth/import/step-2";
-import { OnboardingScreen } from "@app/auth/onboarding";
-import { WelcomeScreen } from "@app/auth/welcome";
-import { ChannelScreen } from "@app/channel";
-import { ChatScreen } from "@app/chat";
-import { ErrorScreen } from "@app/error";
-import { Root } from "@app/root";
-import { AccountSettingsScreen } from "@app/settings/account";
-import { GeneralSettingsScreen } from "@app/settings/general";
-import { ShortcutsSettingsScreen } from "@app/settings/shortcuts";
-import { SpaceScreen } from "@app/space";
-import { TrendingScreen } from "@app/trending";
-import { UserScreen } from "@app/user";
-import { AppLayout } from "@shared/appLayout";
-import { AuthLayout } from "@shared/authLayout";
-import { Protected } from "@shared/protected";
-import { SettingsLayout } from "@shared/settingsLayout";
-import { RouterProvider, createBrowserRouter } from "react-router-dom";
+import { RouterProvider, createBrowserRouter } from 'react-router-dom';
+
+import { AuthCreateScreen } from '@app/auth/create';
+import { CreateStep1Screen } from '@app/auth/create/step-1';
+import { CreateStep2Screen } from '@app/auth/create/step-2';
+import { CreateStep3Screen } from '@app/auth/create/step-3';
+import { CreateStep4Screen } from '@app/auth/create/step-4';
+import { AuthImportScreen } from '@app/auth/import';
+import { ImportStep1Screen } from '@app/auth/import/step-1';
+import { ImportStep2Screen } from '@app/auth/import/step-2';
+import { OnboardingScreen } from '@app/auth/onboarding';
+import { WelcomeScreen } from '@app/auth/welcome';
+import { ChannelScreen } from '@app/channel';
+import { ChatScreen } from '@app/chat';
+import { ErrorScreen } from '@app/error';
+import { Root } from '@app/root';
+import { AccountSettingsScreen } from '@app/settings/account';
+import { GeneralSettingsScreen } from '@app/settings/general';
+import { ShortcutsSettingsScreen } from '@app/settings/shortcuts';
+import { SpaceScreen } from '@app/space';
+import { TrendingScreen } from '@app/trending';
+import { UserScreen } from '@app/user';
+
+import { AppLayout } from '@shared/appLayout';
+import { AuthLayout } from '@shared/authLayout';
+import { Protected } from '@shared/protected';
+import { SettingsLayout } from '@shared/settingsLayout';
+
+import './index.css';
const router = createBrowserRouter([
- {
- path: "/",
- element: (
-
-
-
- ),
- errorElement: ,
- },
- {
- path: "/auth",
- element: ,
- children: [
- { path: "welcome", element: },
- { path: "onboarding", element: },
- {
- path: "import",
- element: ,
- children: [
- { path: "", element: },
- { path: "step-2", element: },
- ],
- },
- {
- path: "create",
- element: ,
- children: [
- { path: "", element: },
- { path: "step-2", element: },
- { path: "step-3", element: },
- { path: "step-4", element: },
- ],
- },
- ],
- },
- {
- path: "/app",
- element: (
-
-
-
- ),
- children: [
- { path: "space", element: },
- { path: "trending", element: },
- { path: "user/:pubkey", element: },
- { path: "chat/:pubkey", element: },
- { path: "channel/:id", element: },
- ],
- },
- {
- path: "/settings",
- element: (
-
-
-
- ),
- children: [
- { path: "general", element: },
- { path: "shortcuts", element: },
- { path: "account", element: },
- ],
- },
+ {
+ path: '/',
+ element: (
+
+
+
+ ),
+ errorElement: ,
+ },
+ {
+ path: '/auth',
+ element: ,
+ children: [
+ { path: 'welcome', element: },
+ { path: 'onboarding', element: },
+ {
+ path: 'import',
+ element: ,
+ children: [
+ { path: '', element: },
+ { path: 'step-2', element: },
+ ],
+ },
+ {
+ path: 'create',
+ element: ,
+ children: [
+ { path: '', element: },
+ { path: 'step-2', element: },
+ { path: 'step-3', element: },
+ { path: 'step-4', element: },
+ ],
+ },
+ ],
+ },
+ {
+ path: '/app',
+ element: (
+
+
+
+ ),
+ children: [
+ { path: 'space', element: },
+ { path: 'trending', element: },
+ { path: 'user/:pubkey', element: },
+ { path: 'chat/:pubkey', element: },
+ { path: 'channel/:id', element: },
+ ],
+ },
+ {
+ path: '/settings',
+ element: (
+
+
+
+ ),
+ children: [
+ { path: 'general', element: },
+ { path: 'shortcuts', element: },
+ { path: 'account', element: },
+ ],
+ },
]);
export default function App() {
- return (
- Loading..
}
- future={{ v7_startTransition: true }}
- />
- );
+ return (
+ Loading..}
+ future={{ v7_startTransition: true }}
+ />
+ );
}
diff --git a/src/app/auth/components/user.tsx b/src/app/auth/components/user.tsx
index 629e290a..eaf81702 100644
--- a/src/app/auth/components/user.tsx
+++ b/src/app/auth/components/user.tsx
@@ -1,44 +1,43 @@
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useProfile } from "@utils/hooks/useProfile";
-import { shortenKey } from "@utils/shortenKey";
+import { Image } from '@shared/image';
-export function User({
- pubkey,
- fallback,
-}: { pubkey: string; fallback?: string }) {
- const { status, user } = useProfile(pubkey, fallback);
+import { DEFAULT_AVATAR } from '@stores/constants';
- if (status === "loading") {
- return (
-
- );
- }
+import { useProfile } from '@utils/hooks/useProfile';
+import { shortenKey } from '@utils/shortenKey';
- return (
-
-
-
-
-
-
- {user.name || user.displayName || user.display_name}
-
-
- {user.nip05?.toLowerCase() || shortenKey(pubkey)}
-
-
-
- );
+export function User({ pubkey, fallback }: { pubkey: string; fallback?: string }) {
+ const { status, user } = useProfile(pubkey, fallback);
+
+ if (status === 'loading') {
+ return (
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+ {user.name || user.displayName || user.display_name}
+
+
+ {user.nip05?.toLowerCase() || shortenKey(pubkey)}
+
+
+
+ );
}
diff --git a/src/app/auth/create/index.tsx b/src/app/auth/create/index.tsx
index 3436c46d..15be94d7 100644
--- a/src/app/auth/create/index.tsx
+++ b/src/app/auth/create/index.tsx
@@ -1,9 +1,9 @@
-import { Outlet } from "react-router-dom";
+import { Outlet } from 'react-router-dom';
export function AuthCreateScreen() {
- return (
-
-
-
- );
+ return (
+
+
+
+ );
}
diff --git a/src/app/auth/create/step-1.tsx b/src/app/auth/create/step-1.tsx
index a8732ac7..de1dd4ef 100644
--- a/src/app/auth/create/step-1.tsx
+++ b/src/app/auth/create/step-1.tsx
@@ -1,114 +1,118 @@
-import { createAccount, createBlock } from "@libs/storage";
-import { Button } from "@shared/button";
-import { EyeOffIcon, EyeOnIcon, LoaderIcon } from "@shared/icons";
-import { useMutation, useQueryClient } from "@tanstack/react-query";
-import { generatePrivateKey, getPublicKey, nip19 } from "nostr-tools";
-import { useMemo, useState } from "react";
-import { useNavigate } from "react-router-dom";
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { generatePrivateKey, getPublicKey, nip19 } from 'nostr-tools';
+import { useMemo, useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+
+import { createAccount } from '@libs/storage';
+
+import { Button } from '@shared/button';
+import { EyeOffIcon, EyeOnIcon, LoaderIcon } from '@shared/icons';
export function CreateStep1Screen() {
- const navigate = useNavigate();
- const queryClient = useQueryClient();
+ const navigate = useNavigate();
+ const queryClient = useQueryClient();
- const [type, setType] = useState("password");
- const [loading, setLoading] = useState(false);
+ const [type, setType] = useState('password');
+ const [loading, setLoading] = useState(false);
- const privkey = useMemo(() => generatePrivateKey(), []);
- const pubkey = getPublicKey(privkey);
- const npub = nip19.npubEncode(pubkey);
- const nsec = nip19.nsecEncode(privkey);
+ const privkey = useMemo(() => generatePrivateKey(), []);
+ const pubkey = getPublicKey(privkey);
+ const npub = nip19.npubEncode(pubkey);
+ const nsec = nip19.nsecEncode(privkey);
- // toggle private key
- const showPrivateKey = () => {
- if (type === "password") {
- setType("text");
- } else {
- setType("password");
- }
- };
+ // toggle private key
+ const showPrivateKey = () => {
+ if (type === 'password') {
+ setType('text');
+ } else {
+ setType('password');
+ }
+ };
- const account = useMutation({
- mutationFn: (data: any) => {
- return createAccount(data.npub, data.pubkey, data.privkey, null, 1);
- },
- onSuccess: (data: any) => {
- queryClient.setQueryData(["currentAccount"], data);
- },
- });
+ const account = useMutation({
+ mutationFn: (data: {
+ npub: string;
+ pubkey: string;
+ privkey: string;
+ follows: null | string[][];
+ is_active: number;
+ }) => {
+ return createAccount(data.npub, data.pubkey, data.privkey, null, 1);
+ },
+ onSuccess: (data) => {
+ queryClient.setQueryData(['currentAccount'], data);
+ },
+ });
- const submit = () => {
- setLoading(true);
+ const submit = () => {
+ setLoading(true);
- account.mutate({
- npub,
- pubkey,
- privkey,
- follows: null,
- is_active: 1,
- });
+ account.mutate({
+ npub,
+ pubkey,
+ privkey,
+ follows: null,
+ is_active: 1,
+ });
- // redirect to next step
- setTimeout(() => navigate("/auth/create/step-2", { replace: true }), 1200);
- };
+ // redirect to next step
+ setTimeout(() => navigate('/auth/create/step-2', { replace: true }), 1200);
+ };
- return (
-
-
-
- Lume is auto-generated key for you
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+ Lume is auto-generated key for you
+
+
+
+
+ Public Key
+
+
+
+
Private Key
+
+
+
+
+
+
+
+
+ );
}
diff --git a/src/app/auth/create/step-2.tsx b/src/app/auth/create/step-2.tsx
index 993d23ef..100f8b1f 100644
--- a/src/app/auth/create/step-2.tsx
+++ b/src/app/auth/create/step-2.tsx
@@ -1,146 +1,152 @@
-import { AvatarUploader } from "@shared/avatarUploader";
-import { BannerUploader } from "@shared/bannerUploader";
-import { LoaderIcon } from "@shared/icons";
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useOnboarding } from "@stores/onboarding";
-import { useState } from "react";
-import { useForm } from "react-hook-form";
-import { useNavigate } from "react-router-dom";
+import { useState } from 'react';
+import { useForm } from 'react-hook-form';
+import { useNavigate } from 'react-router-dom';
+
+import { AvatarUploader } from '@shared/avatarUploader';
+import { BannerUploader } from '@shared/bannerUploader';
+import { LoaderIcon } from '@shared/icons';
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+import { useOnboarding } from '@stores/onboarding';
export function CreateStep2Screen() {
- const navigate = useNavigate();
- const createProfile = useOnboarding((state: any) => state.createProfile);
+ const navigate = useNavigate();
+ const createProfile = useOnboarding((state: any) => state.createProfile);
- const [picture, setPicture] = useState(DEFAULT_AVATAR);
- const [banner, setBanner] = useState("");
- const [loading, setLoading] = useState(false);
+ const [picture, setPicture] = useState(DEFAULT_AVATAR);
+ const [banner, setBanner] = useState('');
+ const [loading, setLoading] = useState(false);
- const {
- register,
- handleSubmit,
- formState: { isDirty, isValid },
- } = useForm();
+ const {
+ register,
+ handleSubmit,
+ formState: { isDirty, isValid },
+ } = useForm();
- const onSubmit = (data: any) => {
- setLoading(true);
- try {
- const profile = {
- ...data,
- username: data.name,
- display_name: data.name,
- bio: data.about,
- };
- createProfile(profile);
- // redirect to next step
- setTimeout(
- () => navigate("/auth/create/step-3", { replace: true }),
- 1200,
- );
- } catch {
- console.log("error");
- }
- };
+ const onSubmit = (data: any) => {
+ setLoading(true);
+ try {
+ const profile = {
+ ...data,
+ username: data.name,
+ display_name: data.name,
+ bio: data.about,
+ };
+ createProfile(profile);
+ // redirect to next step
+ setTimeout(() => navigate('/auth/create/step-3', { replace: true }), 1200);
+ } catch {
+ console.log('error');
+ }
+ };
- return (
-
-
-
- Create your profile
-
-
-
-
- );
+ return (
+
+
+
Create your profile
+
+
+
+ );
}
diff --git a/src/app/auth/create/step-3.tsx b/src/app/auth/create/step-3.tsx
index e811f879..9b7940a6 100644
--- a/src/app/auth/create/step-3.tsx
+++ b/src/app/auth/create/step-3.tsx
@@ -1,99 +1,98 @@
-import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
-import { Button } from "@shared/button";
-import { LoaderIcon } from "@shared/icons";
-import { RelayContext } from "@shared/relayProvider";
-import { useOnboarding } from "@stores/onboarding";
-import { Body, fetch } from "@tauri-apps/api/http";
-import { useAccount } from "@utils/hooks/useAccount";
-import { useContext, useState } from "react";
-import { useNavigate } from "react-router-dom";
+import { NDKEvent, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
+import { Body, fetch } from '@tauri-apps/api/http';
+import { useContext, useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+
+import { Button } from '@shared/button';
+import { LoaderIcon } from '@shared/icons';
+import { RelayContext } from '@shared/relayProvider';
+
+import { useOnboarding } from '@stores/onboarding';
+
+import { useAccount } from '@utils/hooks/useAccount';
export function CreateStep3Screen() {
- const ndk = useContext(RelayContext);
- const profile = useOnboarding((state: any) => state.profile);
- const navigate = useNavigate();
+ const ndk = useContext(RelayContext);
+ const profile = useOnboarding((state: any) => state.profile);
+ const navigate = useNavigate();
- const { account } = useAccount();
+ const { account } = useAccount();
- const [username, setUsername] = useState("");
- const [loading, setLoading] = useState(false);
+ const [username, setUsername] = useState('');
+ const [loading, setLoading] = useState(false);
- const createNIP05 = async () => {
- try {
- setLoading(true);
+ const createNIP05 = async () => {
+ try {
+ setLoading(true);
- const response = await fetch("https://lume.nu/api/user-create", {
- method: "POST",
- timeout: 30,
- headers: {
- "Content-Type": "application/json; charset=utf-8",
- },
- body: Body.json({
- username: username,
- pubkey: account.pubkey,
- lightningAddress: "",
- }),
- });
+ const response = await fetch('https://lume.nu/api/user-create', {
+ method: 'POST',
+ timeout: 30,
+ headers: {
+ 'Content-Type': 'application/json; charset=utf-8',
+ },
+ body: Body.json({
+ username: username,
+ pubkey: account.pubkey,
+ lightningAddress: '',
+ }),
+ });
- if (response.ok) {
- const data = { ...profile, nip05: `${username}@lume.nu` };
+ if (response.ok) {
+ const data = { ...profile, nip05: `${username}@lume.nu` };
- const signer = new NDKPrivateKeySigner(account.privkey);
- ndk.signer = signer;
+ const signer = new NDKPrivateKeySigner(account.privkey);
+ ndk.signer = signer;
- const event = new NDKEvent(ndk);
- // build event
- event.content = JSON.stringify(data);
- event.kind = 0;
- event.pubkey = account.pubkey;
- event.tags = [];
- // publish event
- event.publish();
+ const event = new NDKEvent(ndk);
+ // build event
+ event.content = JSON.stringify(data);
+ event.kind = 0;
+ event.pubkey = account.pubkey;
+ event.tags = [];
+ // publish event
+ event.publish();
- // redirect to step 4
- navigate("/auth/create/step-4", { replace: true });
- }
- } catch (error) {
- setLoading(false);
- console.error("Error:", error);
- }
- };
+ // redirect to step 4
+ navigate('/auth/create/step-4', { replace: true });
+ }
+ } catch (error) {
+ setLoading(false);
+ console.error('Error:', error);
+ }
+ };
- return (
-
-
-
- Create your Lume ID
-
-
-
-
- setUsername(e.target.value)}
- autoCapitalize="false"
- autoCorrect="none"
- spellCheck="false"
- placeholder="satoshi"
- className="relative w-full py-3 pl-3.5 !outline-none placeholder:text-zinc-500 bg-transparent text-zinc-100"
- />
-
- @lume.nu
-
-
-
-
-
- );
+ return (
+
+
+
Create your Lume ID
+
+
+
+ setUsername(e.target.value)}
+ autoCapitalize="false"
+ autoCorrect="none"
+ spellCheck="false"
+ placeholder="satoshi"
+ className="relative w-full bg-transparent py-3 pl-3.5 text-zinc-100 !outline-none placeholder:text-zinc-500"
+ />
+ @lume.nu
+
+
+
+
+ );
}
diff --git a/src/app/auth/create/step-4.tsx b/src/app/auth/create/step-4.tsx
index d327a30b..748104a6 100644
--- a/src/app/auth/create/step-4.tsx
+++ b/src/app/auth/create/step-4.tsx
@@ -1,236 +1,235 @@
-import { User } from "@app/auth/components/user";
-import { updateAccount } from "@libs/storage";
-import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
-import { CheckCircleIcon, LoaderIcon } from "@shared/icons";
-import { RelayContext } from "@shared/relayProvider";
-import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
-import { useAccount } from "@utils/hooks/useAccount";
-import { arrayToNIP02 } from "@utils/transform";
-import { useContext, useState } from "react";
-import { useNavigate } from "react-router-dom";
+import { NDKEvent, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
+import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
+import { useContext, useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+
+import { User } from '@app/auth/components/user';
+
+import { updateAccount } from '@libs/storage';
+
+import { CheckCircleIcon, LoaderIcon } from '@shared/icons';
+import { RelayContext } from '@shared/relayProvider';
+
+import { useAccount } from '@utils/hooks/useAccount';
+import { arrayToNIP02 } from '@utils/transform';
const INITIAL_LIST = [
- {
- pubkey: "82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2",
- },
- {
- pubkey: "a341f45ff9758f570a21b000c17d4e53a3a497c8397f26c0e6d61e5acffc7a98",
- },
- {
- pubkey: "04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9",
- },
- {
- pubkey: "c4eabae1be3cf657bc1855ee05e69de9f059cb7a059227168b80b89761cbc4e0",
- },
- {
- pubkey: "6e468422dfb74a5738702a8823b9b28168abab8655faacb6853cd0ee15deee93",
- },
- {
- pubkey: "e88a691e98d9987c964521dff60025f60700378a4879180dcbbb4a5027850411",
- },
- {
- pubkey: "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d",
- },
- {
- pubkey: "c49d52a573366792b9a6e4851587c28042fb24fa5625c6d67b8c95c8751aca15",
- },
- {
- pubkey: "e33fe65f1fde44c6dc17eeb38fdad0fceaf1cae8722084332ed1e32496291d42",
- },
- {
- pubkey: "84dee6e676e5bb67b4ad4e042cf70cbd8681155db535942fcc6a0533858a7240",
- },
- {
- pubkey: "703e26b4f8bc0fa57f99d815dbb75b086012acc24fc557befa310f5aa08d1898",
- },
- {
- pubkey: "bf2376e17ba4ec269d10fcc996a4746b451152be9031fa48e74553dde5526bce",
- },
- {
- pubkey: "4523be58d395b1b196a9b8c82b038b6895cb02b683d0c253a955068dba1facd0",
- },
- {
- pubkey: "c9b19ffcd43e6a5f23b3d27106ce19e4ad2df89ba1031dd4617f1b591e108965",
- },
- {
- pubkey: "c7dccba4fe4426a7b1ea239a5637ba40fab9862c8c86b3330fe65e9f667435f6",
- },
- {
- pubkey: "6e1534f56fc9e937e06237c8ba4b5662bcacc4e1a3cfab9c16d89390bec4fca3",
- },
- {
- pubkey: "50d94fc2d8580c682b071a542f8b1e31a200b0508bab95a33bef0855df281d63",
- },
- {
- pubkey: "3d2e51508699f98f0f2bdbe7a45b673c687fe6420f466dc296d90b908d51d594",
- },
- {
- pubkey: "6e3f51664e19e082df5217fd4492bb96907405a0b27028671dd7f297b688608c",
- },
- {
- pubkey: "2edbcea694d164629854a52583458fd6d965b161e3c48b57d3aff01940558884",
- },
- {
- pubkey: "3f770d65d3a764a9c5cb503ae123e62ec7598ad035d836e2a810f3877a745b24",
- },
- {
- pubkey: "eab0e756d32b80bcd464f3d844b8040303075a13eabc3599a762c9ac7ab91f4f",
- },
- {
- pubkey: "be1d89794bf92de5dd64c1e60f6a2c70c140abac9932418fee30c5c637fe9479",
- },
- {
- pubkey: "a5e93aef8e820cbc7ab7b6205f854b87aed4b48c5f6b30fbbeba5c99e40dcf3f",
- },
- {
- pubkey: "1989034e56b8f606c724f45a12ce84a11841621aaf7182a1f6564380b9c4276b",
- },
- {
- pubkey: "c48b5cced5ada74db078df6b00fa53fc1139d73bf0ed16de325d52220211dbd5",
- },
- {
- pubkey: "460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c",
- },
- {
- pubkey: "7f3b464b9ff3623630485060cbda3a7790131c5339a7803bde8feb79a5e1b06a",
- },
- {
- pubkey: "b99dbca0184a32ce55904cb267b22e434823c97f418f36daf5d2dff0dd7b5c27",
- },
- {
- pubkey: "e9e4276490374a0daf7759fd5f475deff6ffb9b0fc5fa98c902b5f4b2fe3bba2",
- },
- {
- pubkey: "ea2e3c814d08a378f8a5b8faecb2884d05855975c5ca4b5c25e2d6f936286f14",
- },
- {
- pubkey: "ff04a0e6cd80c141b0b55825fed127d4532a6eecdb7e743a38a3c28bf9f44609",
- },
+ {
+ pubkey: '82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2',
+ },
+ {
+ pubkey: 'a341f45ff9758f570a21b000c17d4e53a3a497c8397f26c0e6d61e5acffc7a98',
+ },
+ {
+ pubkey: '04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9',
+ },
+ {
+ pubkey: 'c4eabae1be3cf657bc1855ee05e69de9f059cb7a059227168b80b89761cbc4e0',
+ },
+ {
+ pubkey: '6e468422dfb74a5738702a8823b9b28168abab8655faacb6853cd0ee15deee93',
+ },
+ {
+ pubkey: 'e88a691e98d9987c964521dff60025f60700378a4879180dcbbb4a5027850411',
+ },
+ {
+ pubkey: '3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d',
+ },
+ {
+ pubkey: 'c49d52a573366792b9a6e4851587c28042fb24fa5625c6d67b8c95c8751aca15',
+ },
+ {
+ pubkey: 'e33fe65f1fde44c6dc17eeb38fdad0fceaf1cae8722084332ed1e32496291d42',
+ },
+ {
+ pubkey: '84dee6e676e5bb67b4ad4e042cf70cbd8681155db535942fcc6a0533858a7240',
+ },
+ {
+ pubkey: '703e26b4f8bc0fa57f99d815dbb75b086012acc24fc557befa310f5aa08d1898',
+ },
+ {
+ pubkey: 'bf2376e17ba4ec269d10fcc996a4746b451152be9031fa48e74553dde5526bce',
+ },
+ {
+ pubkey: '4523be58d395b1b196a9b8c82b038b6895cb02b683d0c253a955068dba1facd0',
+ },
+ {
+ pubkey: 'c9b19ffcd43e6a5f23b3d27106ce19e4ad2df89ba1031dd4617f1b591e108965',
+ },
+ {
+ pubkey: 'c7dccba4fe4426a7b1ea239a5637ba40fab9862c8c86b3330fe65e9f667435f6',
+ },
+ {
+ pubkey: '6e1534f56fc9e937e06237c8ba4b5662bcacc4e1a3cfab9c16d89390bec4fca3',
+ },
+ {
+ pubkey: '50d94fc2d8580c682b071a542f8b1e31a200b0508bab95a33bef0855df281d63',
+ },
+ {
+ pubkey: '3d2e51508699f98f0f2bdbe7a45b673c687fe6420f466dc296d90b908d51d594',
+ },
+ {
+ pubkey: '6e3f51664e19e082df5217fd4492bb96907405a0b27028671dd7f297b688608c',
+ },
+ {
+ pubkey: '2edbcea694d164629854a52583458fd6d965b161e3c48b57d3aff01940558884',
+ },
+ {
+ pubkey: '3f770d65d3a764a9c5cb503ae123e62ec7598ad035d836e2a810f3877a745b24',
+ },
+ {
+ pubkey: 'eab0e756d32b80bcd464f3d844b8040303075a13eabc3599a762c9ac7ab91f4f',
+ },
+ {
+ pubkey: 'be1d89794bf92de5dd64c1e60f6a2c70c140abac9932418fee30c5c637fe9479',
+ },
+ {
+ pubkey: 'a5e93aef8e820cbc7ab7b6205f854b87aed4b48c5f6b30fbbeba5c99e40dcf3f',
+ },
+ {
+ pubkey: '1989034e56b8f606c724f45a12ce84a11841621aaf7182a1f6564380b9c4276b',
+ },
+ {
+ pubkey: 'c48b5cced5ada74db078df6b00fa53fc1139d73bf0ed16de325d52220211dbd5',
+ },
+ {
+ pubkey: '460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c',
+ },
+ {
+ pubkey: '7f3b464b9ff3623630485060cbda3a7790131c5339a7803bde8feb79a5e1b06a',
+ },
+ {
+ pubkey: 'b99dbca0184a32ce55904cb267b22e434823c97f418f36daf5d2dff0dd7b5c27',
+ },
+ {
+ pubkey: 'e9e4276490374a0daf7759fd5f475deff6ffb9b0fc5fa98c902b5f4b2fe3bba2',
+ },
+ {
+ pubkey: 'ea2e3c814d08a378f8a5b8faecb2884d05855975c5ca4b5c25e2d6f936286f14',
+ },
+ {
+ pubkey: 'ff04a0e6cd80c141b0b55825fed127d4532a6eecdb7e743a38a3c28bf9f44609',
+ },
];
export function CreateStep4Screen() {
- const ndk = useContext(RelayContext);
- const queryClient = useQueryClient();
- const navigate = useNavigate();
+ const ndk = useContext(RelayContext);
+ const queryClient = useQueryClient();
+ const navigate = useNavigate();
- const [loading, setLoading] = useState(false);
- const [follows, setFollows] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [follows, setFollows] = useState([]);
- const { account } = useAccount();
- const { status, data } = useQuery(["trending-profiles"], async () => {
- const res = await fetch("https://api.nostr.band/v0/trending/profiles");
- if (!res.ok) {
- throw new Error("Error");
- }
- return res.json();
- });
+ const { account } = useAccount();
+ const { status, data } = useQuery(['trending-profiles'], async () => {
+ const res = await fetch('https://api.nostr.band/v0/trending/profiles');
+ if (!res.ok) {
+ throw new Error('Error');
+ }
+ return res.json();
+ });
- // toggle follow state
- const toggleFollow = (pubkey: string) => {
- const arr = follows.includes(pubkey)
- ? follows.filter((i) => i !== pubkey)
- : [...follows, pubkey];
- setFollows(arr);
- };
+ // toggle follow state
+ const toggleFollow = (pubkey: string) => {
+ const arr = follows.includes(pubkey)
+ ? follows.filter((i) => i !== pubkey)
+ : [...follows, pubkey];
+ setFollows(arr);
+ };
- const update = useMutation({
- mutationFn: (follows: any) => {
- return updateAccount("follows", follows, account.pubkey);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["currentAccount"] });
- },
- });
+ const update = useMutation({
+ mutationFn: (follows: any) => {
+ return updateAccount('follows', follows, account.pubkey);
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['currentAccount'] });
+ },
+ });
- // save follows to database then broadcast
- const submit = async () => {
- try {
- setLoading(true);
+ // save follows to database then broadcast
+ const submit = async () => {
+ try {
+ setLoading(true);
- const tags = arrayToNIP02([...follows, account.pubkey]);
- const signer = new NDKPrivateKeySigner(account.privkey);
- ndk.signer = signer;
+ const tags = arrayToNIP02([...follows, account.pubkey]);
+ const signer = new NDKPrivateKeySigner(account.privkey);
+ ndk.signer = signer;
- const event = new NDKEvent(ndk);
- // build event
- event.content = "";
- event.kind = 3;
- event.pubkey = account.pubkey;
- event.tags = tags;
- // publish event
- event.publish();
+ const event = new NDKEvent(ndk);
+ // build event
+ event.content = '';
+ event.kind = 3;
+ event.pubkey = account.pubkey;
+ event.tags = tags;
+ // publish event
+ event.publish();
- // update
- update.mutate([...follows, account.pubkey]);
+ // update
+ update.mutate([...follows, account.pubkey]);
- // redirect to next step
- setTimeout(() => navigate("/auth/onboarding", { replace: true }), 1200);
- } catch {
- console.log("error");
- }
- };
+ // redirect to next step
+ setTimeout(() => navigate('/auth/onboarding', { replace: true }), 1200);
+ } catch {
+ console.log('error');
+ }
+ };
- const list = data ? data.profiles.concat(INITIAL_LIST) : [];
+ const list = data ? data.profiles.concat(INITIAL_LIST) : [];
- return (
-
-
-
- Personalized your newsfeed
-
-
-
-
-
- Follow at least
-
- {follows.length}/10
- {" "}
- plebs
-
- {status === "loading" ? (
-
-
-
- ) : (
-
- {list.map(
- (item: { pubkey: string; profile: { content: string } }) => (
-
- ),
- )}
-
- )}
-
- {follows.length >= 10 && (
-
- )}
-
-
- );
+ return (
+
+
+
+ Personalized your newsfeed
+
+
+
+
+
+ Follow at least
+
+ {follows.length}/10
+ {' '}
+ plebs
+
+ {status === 'loading' ? (
+
+
+
+ ) : (
+
+ {list.map((item: { pubkey: string; profile: { content: string } }) => (
+
+ ))}
+
+ )}
+
+ {follows.length >= 10 && (
+
+ )}
+
+
+ );
}
diff --git a/src/app/auth/import/index.tsx b/src/app/auth/import/index.tsx
index a45ba6c1..bf8983ff 100644
--- a/src/app/auth/import/index.tsx
+++ b/src/app/auth/import/index.tsx
@@ -1,9 +1,9 @@
-import { Outlet } from "react-router-dom";
+import { Outlet } from 'react-router-dom';
export function AuthImportScreen() {
- return (
-
-
-
- );
+ return (
+
+
+
+ );
}
diff --git a/src/app/auth/import/step-1.tsx b/src/app/auth/import/step-1.tsx
index a104ee9e..e7aa6875 100644
--- a/src/app/auth/import/step-1.tsx
+++ b/src/app/auth/import/step-1.tsx
@@ -1,120 +1,119 @@
-import { createAccount, createBlock } from "@libs/storage";
-import { LoaderIcon } from "@shared/icons";
-import { useMutation, useQueryClient } from "@tanstack/react-query";
-import { getPublicKey, nip19 } from "nostr-tools";
-import { useState } from "react";
-import { Resolver, useForm } from "react-hook-form";
-import { useNavigate } from "react-router-dom";
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { getPublicKey, nip19 } from 'nostr-tools';
+import { useState } from 'react';
+import { Resolver, useForm } from 'react-hook-form';
+import { useNavigate } from 'react-router-dom';
+
+import { createAccount } from '@libs/storage';
+
+import { LoaderIcon } from '@shared/icons';
type FormValues = {
- key: string;
+ key: string;
};
const resolver: Resolver = async (values) => {
- return {
- values: values.key ? values : {},
- errors: !values.key
- ? {
- key: {
- type: "required",
- message: "This is required.",
- },
- }
- : {},
- };
+ return {
+ values: values.key ? values : {},
+ errors: !values.key
+ ? {
+ key: {
+ type: 'required',
+ message: 'This is required.',
+ },
+ }
+ : {},
+ };
};
export function ImportStep1Screen() {
- const navigate = useNavigate();
- const queryClient = useQueryClient();
+ const navigate = useNavigate();
+ const queryClient = useQueryClient();
- const [loading, setLoading] = useState(false);
+ const [loading, setLoading] = useState(false);
- const account = useMutation({
- mutationFn: (data: any) => {
- return createAccount(data.npub, data.pubkey, data.privkey, null, 1);
- },
- onSuccess: (data: any) => {
- queryClient.setQueryData(["currentAccount"], data);
- },
- });
+ const account = useMutation({
+ mutationFn: (data: any) => {
+ return createAccount(data.npub, data.pubkey, data.privkey, null, 1);
+ },
+ onSuccess: (data: any) => {
+ queryClient.setQueryData(['currentAccount'], data);
+ },
+ });
- const {
- register,
- setError,
- handleSubmit,
- formState: { errors, isDirty, isValid },
- } = useForm({ resolver });
+ const {
+ register,
+ setError,
+ handleSubmit,
+ formState: { errors, isDirty, isValid },
+ } = useForm({ resolver });
- const onSubmit = async (data: any) => {
- try {
- setLoading(true);
+ const onSubmit = async (data: any) => {
+ try {
+ setLoading(true);
- let privkey = data["key"];
- if (privkey.substring(0, 4) === "nsec") {
- privkey = nip19.decode(privkey).data;
- }
+ let privkey = data['key'];
+ if (privkey.substring(0, 4) === 'nsec') {
+ privkey = nip19.decode(privkey).data;
+ }
- if (typeof getPublicKey(privkey) === "string") {
- const pubkey = getPublicKey(privkey);
- const npub = nip19.npubEncode(pubkey);
+ if (typeof getPublicKey(privkey) === 'string') {
+ const pubkey = getPublicKey(privkey);
+ const npub = nip19.npubEncode(pubkey);
- // update
- account.mutate({
- npub,
- pubkey,
- privkey,
- follows: null,
- is_active: 1,
- });
+ // update
+ account.mutate({
+ npub,
+ pubkey,
+ privkey,
+ follows: null,
+ is_active: 1,
+ });
- // redirect to step 2
- setTimeout(
- () => navigate("/auth/import/step-2", { replace: true }),
- 1200,
- );
- }
- } catch (error) {
- setError("key", {
- type: "custom",
- message: "Private Key is invalid, please check again",
- });
- }
- };
+ // redirect to step 2
+ setTimeout(() => navigate('/auth/import/step-2', { replace: true }), 1200);
+ }
+ } catch (error) {
+ setError('key', {
+ type: 'custom',
+ message: 'Private Key is invalid, please check again',
+ });
+ }
+ };
- return (
-
-
-
Import your key
-
-
-
-
-
- );
+ return (
+
+
+
Import your key
+
+
+
+
+
+ );
}
diff --git a/src/app/auth/import/step-2.tsx b/src/app/auth/import/step-2.tsx
index e4324545..33ac556c 100644
--- a/src/app/auth/import/step-2.tsx
+++ b/src/app/auth/import/step-2.tsx
@@ -1,83 +1,87 @@
-import { User } from "@app/auth/components/user";
-import { updateAccount } from "@libs/storage";
-import { Button } from "@shared/button";
-import { LoaderIcon } from "@shared/icons";
-import { RelayContext } from "@shared/relayProvider";
-import { useMutation, useQueryClient } from "@tanstack/react-query";
-import { useAccount } from "@utils/hooks/useAccount";
-import { setToArray } from "@utils/transform";
-import { useContext, useState } from "react";
-import { useNavigate } from "react-router-dom";
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { useContext, useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+
+import { User } from '@app/auth/components/user';
+
+import { updateAccount } from '@libs/storage';
+
+import { Button } from '@shared/button';
+import { LoaderIcon } from '@shared/icons';
+import { RelayContext } from '@shared/relayProvider';
+
+import { useAccount } from '@utils/hooks/useAccount';
+import { setToArray } from '@utils/transform';
export function ImportStep2Screen() {
- const ndk = useContext(RelayContext);
- const queryClient = useQueryClient();
- const navigate = useNavigate();
+ const ndk = useContext(RelayContext);
+ const queryClient = useQueryClient();
+ const navigate = useNavigate();
- const [loading, setLoading] = useState(false);
- const { status, account } = useAccount();
+ const [loading, setLoading] = useState(false);
+ const { status, account } = useAccount();
- const update = useMutation({
- mutationFn: (follows: any) => {
- return updateAccount("follows", follows, account.pubkey);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["currentAccount"] });
- },
- });
+ const update = useMutation({
+ mutationFn: (follows: any) => {
+ return updateAccount('follows', follows, account.pubkey);
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['currentAccount'] });
+ },
+ });
- const submit = async () => {
- try {
- // show loading indicator
- setLoading(true);
+ const submit = async () => {
+ try {
+ // show loading indicator
+ setLoading(true);
- const user = ndk.getUser({ hexpubkey: account.pubkey });
- const follows = await user.follows();
+ const user = ndk.getUser({ hexpubkey: account.pubkey });
+ const follows = await user.follows();
- // follows as list
- const followsList = setToArray(follows);
+ // follows as list
+ const followsList = setToArray(follows);
- // update
- update.mutate([...followsList, account.pubkey]);
+ // update
+ update.mutate([...followsList, account.pubkey]);
- // redirect to next step
- setTimeout(() => navigate("/auth/onboarding", { replace: true }), 1200);
- } catch {
- console.log("error");
- }
- };
+ // redirect to next step
+ setTimeout(() => navigate('/auth/onboarding', { replace: true }), 1200);
+ } catch {
+ console.log('error');
+ }
+ };
- return (
-
-
-
- {loading ? "Creating..." : "Continue with"}
-
-
-
- {status === "loading" ? (
-
- ) : (
-
-
-
-
- )}
-
-
- );
+ return (
+
+
+
+ {loading ? 'Creating...' : 'Continue with'}
+
+
+
+ {status === 'loading' ? (
+
+ ) : (
+
+
+
+
+ )}
+
+
+ );
}
diff --git a/src/app/auth/onboarding.tsx b/src/app/auth/onboarding.tsx
index f1324ac6..aefe54ed 100644
--- a/src/app/auth/onboarding.tsx
+++ b/src/app/auth/onboarding.tsx
@@ -1,103 +1,103 @@
-import { usePublish } from "@libs/ndk";
-import { LoaderIcon } from "@shared/icons";
-import { ArrowRightCircleIcon } from "@shared/icons/arrowRightCircle";
-import { User } from "@shared/user";
-import { useAccount } from "@utils/hooks/useAccount";
-import { useState } from "react";
-import { Link, useNavigate } from "react-router-dom";
+import { useState } from 'react';
+import { Link, useNavigate } from 'react-router-dom';
+
+import { usePublish } from '@libs/ndk';
+
+import { LoaderIcon } from '@shared/icons';
+import { ArrowRightCircleIcon } from '@shared/icons/arrowRightCircle';
+import { User } from '@shared/user';
+
+import { useAccount } from '@utils/hooks/useAccount';
export function OnboardingScreen() {
- const publish = usePublish();
- const navigate = useNavigate();
+ const publish = usePublish();
+ const navigate = useNavigate();
- const { status, account } = useAccount();
- const [loading, setLoading] = useState(false);
+ const { status, account } = useAccount();
+ const [loading, setLoading] = useState(false);
- const submit = async () => {
- try {
- setLoading(true);
+ const submit = async () => {
+ try {
+ setLoading(true);
- // publish event
- publish({
- content:
- "Running Lume, fighting for better future, join us here: https://lume.nu",
- kind: 1,
- tags: [],
- });
+ // publish event
+ publish({
+ content:
+ 'Running Lume, fighting for better future, join us here: https://lume.nu',
+ kind: 1,
+ tags: [],
+ });
- // redirect to home
- setTimeout(() => navigate("/", { replace: true }), 1200);
- } catch (error) {
- console.log(error);
- }
- };
+ // redirect to home
+ setTimeout(() => navigate('/', { replace: true }), 1200);
+ } catch (error) {
+ console.log(error);
+ }
+ };
- return (
-
-
-
-
- 👋 Hello, welcome you to Lume
-
-
- You're a part of better future that we're fighting
-
-
- If Lume gets your attention, please help us spread via button below
-
-
-
-
- {status === "success" && (
-
- )}
-
-
-
-
-
-
- Skip for now
-
-
-
-
- );
+ return (
+
+
+
+
+ 👋 Hello, welcome you to Lume
+
+
+ You're a part of better future that we're fighting
+
+
+ If Lume gets your attention, please help us spread via button below
+
+
+
+
+ {status === 'success' && (
+
+ )}
+
+
+
+
+
+
+ Skip for now
+
+
+
+
+ );
}
diff --git a/src/app/auth/welcome.tsx b/src/app/auth/welcome.tsx
index b5f8e0b5..cfbf9fa6 100644
--- a/src/app/auth/welcome.tsx
+++ b/src/app/auth/welcome.tsx
@@ -1,53 +1,54 @@
-import { ArrowRightCircleIcon } from "@shared/icons/arrowRightCircle";
-import { Link } from "react-router-dom";
+import { Link } from 'react-router-dom';
+
+import { ArrowRightCircleIcon } from '@shared/icons/arrowRightCircle';
export function WelcomeScreen() {
- return (
-
-
-
-
- Preserve your freedom
-
-
- Protect your future
-
-
- Stack bitcoin
-
-
- Use nostr
-
-
-
-
-
-
Login with private key
-
-
-
- Create new key
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+ Preserve your freedom
+
+
+ Protect your future
+
+
+ Stack bitcoin
+
+
+ Use nostr
+
+
+
+
+
+
Login with private key
+
+
+
+ Create new key
+
+
+
+
+
+
+ );
}
diff --git a/src/app/channel/components/blacklist.tsx b/src/app/channel/components/blacklist.tsx
index 00301708..c53a539d 100644
--- a/src/app/channel/components/blacklist.tsx
+++ b/src/app/channel/components/blacklist.tsx
@@ -1,58 +1,58 @@
-import { MutedItem } from "@app/channel/components/mutedItem";
-import { Popover, Transition } from "@headlessui/react";
-import { MuteIcon } from "@shared/icons";
-import { Fragment } from "react";
+import { Popover, Transition } from '@headlessui/react';
+import { Fragment } from 'react';
+
+import { MutedItem } from '@app/channel/components/mutedItem';
+
+import { MuteIcon } from '@shared/icons';
export function ChannelBlackList({ blacklist }: { blacklist: any }) {
- return (
-
- {({ open }) => (
- <>
-
-
-
-
-
-
-
-
-
- Your muted list
-
-
- Currently, unmute only affect locally, when you move to
- new client, muted list will loaded again
-
-
-
-
- {blacklist.map((item: any) => (
-
- ))}
-
-
-
-
- >
- )}
-
- );
+ return (
+
+ {({ open }) => (
+ <>
+
+
+
+
+
+
+
+
+
+ Your muted list
+
+
+ Currently, unmute only affect locally, when you move to new client,
+ muted list will loaded again
+
+
+
+
+ {blacklist.map((item: any) => (
+
+ ))}
+
+
+
+
+ >
+ )}
+
+ );
}
diff --git a/src/app/channel/components/createModal.tsx b/src/app/channel/components/createModal.tsx
index 65b7be92..f9f02118 100644
--- a/src/app/channel/components/createModal.tsx
+++ b/src/app/channel/components/createModal.tsx
@@ -1,263 +1,269 @@
-import { Dialog, Transition } from "@headlessui/react";
-import { createChannel } from "@libs/storage";
-import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
-import { AvatarUploader } from "@shared/avatarUploader";
-import { CancelIcon, LoaderIcon, PlusIcon } from "@shared/icons";
-import { Image } from "@shared/image";
-import { RelayContext } from "@shared/relayProvider";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useMutation, useQueryClient } from "@tanstack/react-query";
-import { dateToUnix } from "@utils/date";
-import { useAccount } from "@utils/hooks/useAccount";
-import { Fragment, useContext, useEffect, useState } from "react";
-import { useForm } from "react-hook-form";
-import { useNavigate } from "react-router-dom";
+import { Dialog, Transition } from '@headlessui/react';
+import { NDKEvent, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { Fragment, useContext, useEffect, useState } from 'react';
+import { useForm } from 'react-hook-form';
+import { useNavigate } from 'react-router-dom';
+
+import { createChannel } from '@libs/storage';
+
+import { AvatarUploader } from '@shared/avatarUploader';
+import { CancelIcon, LoaderIcon, PlusIcon } from '@shared/icons';
+import { Image } from '@shared/image';
+import { RelayContext } from '@shared/relayProvider';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+
+import { dateToUnix } from '@utils/date';
+import { useAccount } from '@utils/hooks/useAccount';
export function ChannelCreateModal() {
- const ndk = useContext(RelayContext);
- const queryClient = useQueryClient();
- const navigate = useNavigate();
+ const ndk = useContext(RelayContext);
+ const queryClient = useQueryClient();
+ const navigate = useNavigate();
- const [isOpen, setIsOpen] = useState(false);
- const [loading, setLoading] = useState(false);
- const [image, setImage] = useState(DEFAULT_AVATAR);
+ const [isOpen, setIsOpen] = useState(false);
+ const [loading, setLoading] = useState(false);
+ const [image, setImage] = useState(DEFAULT_AVATAR);
- const { account } = useAccount();
+ const { account } = useAccount();
- const closeModal = () => {
- setIsOpen(false);
- };
+ const closeModal = () => {
+ setIsOpen(false);
+ };
- const openModal = () => {
- setIsOpen(true);
- };
+ const openModal = () => {
+ setIsOpen(true);
+ };
- const {
- register,
- handleSubmit,
- reset,
- setValue,
- formState: { isDirty, isValid },
- } = useForm();
+ const {
+ register,
+ handleSubmit,
+ reset,
+ setValue,
+ formState: { isDirty, isValid },
+ } = useForm();
- const addChannel = useMutation({
- mutationFn: (event: any) => {
- return createChannel(
- event.id,
- event.pubkey,
- event.name,
- event.picture,
- event.about,
- event.created_at,
- );
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["channels"] });
- },
- });
+ const addChannel = useMutation({
+ mutationFn: (event: any) => {
+ return createChannel(
+ event.id,
+ event.pubkey,
+ event.name,
+ event.picture,
+ event.about,
+ event.created_at
+ );
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['channels'] });
+ },
+ });
- const onSubmit = (data: any) => {
- setLoading(true);
+ const onSubmit = (data: any) => {
+ setLoading(true);
- try {
- const signer = new NDKPrivateKeySigner(account.privkey);
- ndk.signer = signer;
+ try {
+ const signer = new NDKPrivateKeySigner(account.privkey);
+ ndk.signer = signer;
- const event = new NDKEvent(ndk);
- // build event
- event.content = JSON.stringify(data);
- event.kind = 40;
- event.created_at = dateToUnix();
- event.pubkey = account.pubkey;
- event.tags = [];
+ const event = new NDKEvent(ndk);
+ // build event
+ event.content = JSON.stringify(data);
+ event.kind = 40;
+ event.created_at = dateToUnix();
+ event.pubkey = account.pubkey;
+ event.tags = [];
- // publish event
- event.publish();
+ // publish event
+ event.publish();
- // insert to database
- addChannel.mutate({
- ...event,
- name: data.name,
- picture: data.picture,
- about: data.about,
- });
+ // insert to database
+ addChannel.mutate({
+ ...event,
+ name: data.name,
+ picture: data.picture,
+ about: data.about,
+ });
- // reset form
- reset();
+ // reset form
+ reset();
- setTimeout(() => {
- // close modal
- setIsOpen(false);
- // redirect to channel page
- navigate(`/app/channel/${event.id}`);
- }, 1000);
- } catch (e) {
- console.log("error: ", e);
- }
- };
+ setTimeout(() => {
+ // close modal
+ setIsOpen(false);
+ // redirect to channel page
+ navigate(`/app/channel/${event.id}`);
+ }, 1000);
+ } catch (e) {
+ console.log('error: ', e);
+ }
+ };
- useEffect(() => {
- setValue("picture", image);
- }, [setValue, image]);
+ useEffect(() => {
+ setValue('picture', image);
+ }, [setValue, image]);
- return (
- <>
-
-
-
-
- >
- );
+ return (
+ <>
+
+
+
+
+ >
+ );
}
diff --git a/src/app/channel/components/item.tsx b/src/app/channel/components/item.tsx
index 748106f6..71c7c416 100644
--- a/src/app/channel/components/item.tsx
+++ b/src/app/channel/components/item.tsx
@@ -1,33 +1,34 @@
-import { useChannelProfile } from "@app/channel/hooks/useChannelProfile";
-import { NavLink } from "react-router-dom";
-import { twMerge } from "tailwind-merge";
+import { NavLink } from 'react-router-dom';
+import { twMerge } from 'tailwind-merge';
+
+import { useChannelProfile } from '@app/channel/hooks/useChannelProfile';
export function ChannelsListItem({ data }: { data: any }) {
- const channel = useChannelProfile(data.event_id);
- return (
-
- twMerge(
- "inline-flex h-9 items-center gap-2.5 rounded-md px-2.5",
- isActive ? "bg-zinc-900/50 text-zinc-100" : "",
- )
- }
- >
-
- #
-
-
-
{channel?.name}
-
- {data.new_messages && (
-
- {data.new_messages}
-
- )}
-
-
-
- );
+ const channel = useChannelProfile(data.event_id);
+ return (
+
+ twMerge(
+ 'inline-flex h-9 items-center gap-2.5 rounded-md px-2.5',
+ isActive ? 'bg-zinc-900/50 text-zinc-100' : ''
+ )
+ }
+ >
+
+ #
+
+
+
{channel?.name}
+
+ {data.new_messages && (
+
+ {data.new_messages}
+
+ )}
+
+
+
+ );
}
diff --git a/src/app/channel/components/list.tsx b/src/app/channel/components/list.tsx
index 7282df48..d3f9246a 100644
--- a/src/app/channel/components/list.tsx
+++ b/src/app/channel/components/list.tsx
@@ -1,50 +1,52 @@
-import { ChannelCreateModal } from "@app/channel/components/createModal";
-import { ChannelsListItem } from "@app/channel/components/item";
-import { getChannels } from "@libs/storage";
-import { useQuery } from "@tanstack/react-query";
+import { useQuery } from '@tanstack/react-query';
+
+import { ChannelCreateModal } from '@app/channel/components/createModal';
+import { ChannelsListItem } from '@app/channel/components/item';
+
+import { getChannels } from '@libs/storage';
export function ChannelsList() {
- const {
- status,
- data: channels,
- isFetching,
- } = useQuery(
- ["channels"],
- async () => {
- return await getChannels();
- },
- {
- refetchOnMount: false,
- refetchOnReconnect: false,
- refetchOnWindowFocus: false,
- },
- );
+ const {
+ status,
+ data: channels,
+ isFetching,
+ } = useQuery(
+ ['channels'],
+ async () => {
+ return await getChannels();
+ },
+ {
+ refetchOnMount: false,
+ refetchOnReconnect: false,
+ refetchOnWindowFocus: false,
+ }
+ );
- return (
-
- {status === "loading" ? (
- <>
-
-
- >
- ) : (
- channels.map((item: { event_id: string }) => (
-
- ))
- )}
- {isFetching && (
-
- )}
-
-
- );
+ return (
+
+ {status === 'loading' ? (
+ <>
+
+
+ >
+ ) : (
+ channels.map((item: { event_id: string }) => (
+
+ ))
+ )}
+ {isFetching && (
+
+ )}
+
+
+ );
}
diff --git a/src/app/channel/components/member.tsx b/src/app/channel/components/member.tsx
index e58aeebe..22fa6ba8 100644
--- a/src/app/channel/components/member.tsx
+++ b/src/app/channel/components/member.tsx
@@ -1,22 +1,24 @@
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useProfile } from "@utils/hooks/useProfile";
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+
+import { useProfile } from '@utils/hooks/useProfile';
export function Member({ pubkey }: { pubkey: string }) {
- const { user, isError, isLoading } = useProfile(pubkey);
+ const { user, isError, isLoading } = useProfile(pubkey);
- return (
- <>
- {isError || isLoading ? (
-
- ) : (
-
- )}
- >
- );
+ return (
+ <>
+ {isError || isLoading ? (
+
+ ) : (
+
+ )}
+ >
+ );
}
diff --git a/src/app/channel/components/members.tsx b/src/app/channel/components/members.tsx
index 931bb779..b1fdf40f 100644
--- a/src/app/channel/components/members.tsx
+++ b/src/app/channel/components/members.tsx
@@ -1,29 +1,28 @@
-import { Member } from "@app/channel/components/member";
-import { getChannelUsers } from "@libs/storage";
-import { useQuery } from "@tanstack/react-query";
+import { useQuery } from '@tanstack/react-query';
+
+import { Member } from '@app/channel/components/member';
+
+import { getChannelUsers } from '@libs/storage';
export function ChannelMembers({ id }: { id: string }) {
- const { status, data, isFetching } = useQuery(
- ["channel-members", id],
- async () => {
- return await getChannelUsers(id);
- },
- );
+ const { status, data, isFetching } = useQuery(['channel-members', id], async () => {
+ return await getChannelUsers(id);
+ });
- return (
-
-
- Members
-
-
- {status === "loading" || isFetching ? (
-
Loading...
- ) : (
- data.map((member: { pubkey: string }) => (
-
- ))
- )}
-
-
- );
+ return (
+
+
+ Members
+
+
+ {status === 'loading' || isFetching ? (
+
Loading...
+ ) : (
+ data.map((member: { pubkey: string }) => (
+
+ ))
+ )}
+
+
+ );
}
diff --git a/src/app/channel/components/messages/form.tsx b/src/app/channel/components/messages/form.tsx
index b6a3edae..a9ec5cda 100644
--- a/src/app/channel/components/messages/form.tsx
+++ b/src/app/channel/components/messages/form.tsx
@@ -1,110 +1,114 @@
-import { UserReply } from "@app/channel/components/messages/userReply";
-import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
-import { CancelIcon, EnterIcon } from "@shared/icons";
-import { MediaUploader } from "@shared/mediaUploader";
-import { RelayContext } from "@shared/relayProvider";
-import { useChannelMessages } from "@stores/channels";
-import { dateToUnix } from "@utils/date";
-import { useAccount } from "@utils/hooks/useAccount";
-import { useContext, useState } from "react";
+import { NDKEvent, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
+import { useContext, useState } from 'react';
+
+import { UserReply } from '@app/channel/components/messages/userReply';
+
+import { CancelIcon, EnterIcon } from '@shared/icons';
+import { MediaUploader } from '@shared/mediaUploader';
+import { RelayContext } from '@shared/relayProvider';
+
+import { useChannelMessages } from '@stores/channels';
+
+import { dateToUnix } from '@utils/date';
+import { useAccount } from '@utils/hooks/useAccount';
export function ChannelMessageForm({ channelID }: { channelID: string }) {
- const ndk = useContext(RelayContext);
+ const ndk = useContext(RelayContext);
- const [value, setValue] = useState("");
- const [replyTo, closeReply] = useChannelMessages((state: any) => [
- state.replyTo,
- state.closeReply,
- ]);
+ const [value, setValue] = useState('');
+ const [replyTo, closeReply] = useChannelMessages((state: any) => [
+ state.replyTo,
+ state.closeReply,
+ ]);
- const { account } = useAccount();
+ const { account } = useAccount();
- const submit = () => {
- let tags: string[][];
+ const submit = () => {
+ let tags: string[][];
- if (replyTo.id !== null) {
- tags = [
- ["e", channelID, "", "root"],
- ["e", replyTo.id, "", "reply"],
- ["p", replyTo.pubkey, ""],
- ];
- } else {
- tags = [["e", channelID, "", "root"]];
- }
+ if (replyTo.id !== null) {
+ tags = [
+ ['e', channelID, '', 'root'],
+ ['e', replyTo.id, '', 'reply'],
+ ['p', replyTo.pubkey, ''],
+ ];
+ } else {
+ tags = [['e', channelID, '', 'root']];
+ }
- const signer = new NDKPrivateKeySigner(account.privkey);
- ndk.signer = signer;
+ const signer = new NDKPrivateKeySigner(account.privkey);
+ ndk.signer = signer;
- const event = new NDKEvent(ndk);
- // build event
- event.content = value;
- event.kind = 42;
- event.created_at = dateToUnix();
- event.pubkey = account.pubkey;
- event.tags = tags;
+ const event = new NDKEvent(ndk);
+ // build event
+ event.content = value;
+ event.kind = 42;
+ event.created_at = dateToUnix();
+ event.pubkey = account.pubkey;
+ event.tags = tags;
- // publish event
- event.publish();
+ // publish event
+ event.publish();
- // reset state
- setValue("");
- };
+ // reset state
+ setValue('');
+ };
- const handleEnterPress = (e) => {
- if (e.key === "Enter" && !e.shiftKey) {
- e.preventDefault();
- submit();
- }
- };
+ const handleEnterPress = (e) => {
+ if (e.key === 'Enter' && !e.shiftKey) {
+ e.preventDefault();
+ submit();
+ }
+ };
- const stopReply = () => {
- closeReply();
- };
+ const stopReply = () => {
+ closeReply();
+ };
- return (
-
- {replyTo.id && (
-
-
-
-
-
-
- )}
-
- );
+ return (
+
+ {replyTo.id && (
+
+
+
+
+
+
+ )}
+
+ );
}
diff --git a/src/app/channel/components/messages/hideButton.tsx b/src/app/channel/components/messages/hideButton.tsx
index 158b6450..f763a42f 100644
--- a/src/app/channel/components/messages/hideButton.tsx
+++ b/src/app/channel/components/messages/hideButton.tsx
@@ -1,135 +1,134 @@
-import { Dialog, Transition } from "@headlessui/react";
-import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
-import { CancelIcon, HideIcon } from "@shared/icons";
-import { RelayContext } from "@shared/relayProvider";
-import { Tooltip } from "@shared/tooltip_dep";
-import { useChannelMessages } from "@stores/channels";
-import { dateToUnix } from "@utils/date";
-import { useAccount } from "@utils/hooks/useAccount";
-import { Fragment, useContext, useState } from "react";
+import { Dialog, Transition } from '@headlessui/react';
+import { NDKEvent, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
+import { Fragment, useContext, useState } from 'react';
+
+import { CancelIcon, HideIcon } from '@shared/icons';
+import { RelayContext } from '@shared/relayProvider';
+import { Tooltip } from '@shared/tooltip_dep';
+
+import { useChannelMessages } from '@stores/channels';
+
+import { dateToUnix } from '@utils/date';
+import { useAccount } from '@utils/hooks/useAccount';
export function MessageHideButton({ id }: { id: string }) {
- const ndk = useContext(RelayContext);
- const hide = useChannelMessages((state: any) => state.hideMessage);
+ const ndk = useContext(RelayContext);
+ const hide = useChannelMessages((state: any) => state.hideMessage);
- const [isOpen, setIsOpen] = useState(false);
+ const [isOpen, setIsOpen] = useState(false);
- const { account } = useAccount();
+ const { account } = useAccount();
- const closeModal = () => {
- setIsOpen(false);
- };
+ const closeModal = () => {
+ setIsOpen(false);
+ };
- const openModal = () => {
- setIsOpen(true);
- };
+ const openModal = () => {
+ setIsOpen(true);
+ };
- const hideMessage = () => {
- const signer = new NDKPrivateKeySigner(account.privkey);
- ndk.signer = signer;
+ const hideMessage = () => {
+ const signer = new NDKPrivateKeySigner(account.privkey);
+ ndk.signer = signer;
- const event = new NDKEvent(ndk);
- // build event
- event.content = "";
- event.kind = 43;
- event.created_at = dateToUnix();
- event.pubkey = account.pubkey;
- event.tags = [["e", id]];
+ const event = new NDKEvent(ndk);
+ // build event
+ event.content = '';
+ event.kind = 43;
+ event.created_at = dateToUnix();
+ event.pubkey = account.pubkey;
+ event.tags = [['e', id]];
- // publish event
- event.publish();
+ // publish event
+ event.publish();
- // update state
- hide(id);
+ // update state
+ hide(id);
- // close modal
- closeModal();
- };
+ // close modal
+ closeModal();
+ };
- return (
- <>
-
-
-
-
-
-
- >
- );
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
}
diff --git a/src/app/channel/components/messages/item.tsx b/src/app/channel/components/messages/item.tsx
index 0d1c321c..cecac4f5 100644
--- a/src/app/channel/components/messages/item.tsx
+++ b/src/app/channel/components/messages/item.tsx
@@ -1,60 +1,56 @@
-import { MessageHideButton } from "@app/channel/components/messages/hideButton";
-import { MessageMuteButton } from "@app/channel/components/messages/muteButton";
-import { MessageReplyButton } from "@app/channel/components/messages/replyButton";
-import { MentionNote } from "@shared/notes/mentions/note";
-import { ImagePreview } from "@shared/notes/preview/image";
-import { LinkPreview } from "@shared/notes/preview/link";
-import { VideoPreview } from "@shared/notes/preview/video";
-import { User } from "@shared/user";
-import { parser } from "@utils/parser";
-import { LumeEvent } from "@utils/types";
+import { MessageHideButton } from '@app/channel/components/messages/hideButton';
+import { MessageMuteButton } from '@app/channel/components/messages/muteButton';
+import { MessageReplyButton } from '@app/channel/components/messages/replyButton';
+
+import { MentionNote } from '@shared/notes/mentions/note';
+import { ImagePreview } from '@shared/notes/preview/image';
+import { LinkPreview } from '@shared/notes/preview/link';
+import { VideoPreview } from '@shared/notes/preview/video';
+import { User } from '@shared/user';
+
+import { parser } from '@utils/parser';
+import { LumeEvent } from '@utils/types';
export function ChannelMessageItem({ data }: { data: LumeEvent }) {
- const content = parser(data);
+ const content = parser(data);
- return (
-
-
-
-
-
- {content.parsed}
-
- {Array.isArray(content.images) && content.images.length ? (
-
- ) : (
- <>>
- )}
- {Array.isArray(content.videos) && content.videos.length ? (
-
- ) : (
- <>>
- )}
- {Array.isArray(content.links) && content.links.length ? (
-
- ) : (
- <>>
- )}
- {Array.isArray(content.notes) && content.notes.length ? (
- content.notes.map((note: string) => (
-
- ))
- ) : (
- <>>
- )}
-
-
-
-
- );
+ return (
+
+
+
+
+
+ {content.parsed}
+
+ {Array.isArray(content.images) && content.images.length ? (
+
+ ) : (
+ <>>
+ )}
+ {Array.isArray(content.videos) && content.videos.length ? (
+
+ ) : (
+ <>>
+ )}
+ {Array.isArray(content.links) && content.links.length ? (
+
+ ) : (
+ <>>
+ )}
+ {Array.isArray(content.notes) && content.notes.length ? (
+ content.notes.map((note: string) =>
)
+ ) : (
+ <>>
+ )}
+
+
+
+
+ );
}
diff --git a/src/app/channel/components/messages/muteButton.tsx b/src/app/channel/components/messages/muteButton.tsx
index 9c638a7d..5a9c1381 100644
--- a/src/app/channel/components/messages/muteButton.tsx
+++ b/src/app/channel/components/messages/muteButton.tsx
@@ -1,135 +1,134 @@
-import { Dialog, Transition } from "@headlessui/react";
-import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
-import { CancelIcon, MuteIcon } from "@shared/icons";
-import { RelayContext } from "@shared/relayProvider";
-import { Tooltip } from "@shared/tooltip_dep";
-import { useChannelMessages } from "@stores/channels";
-import { dateToUnix } from "@utils/date";
-import { useAccount } from "@utils/hooks/useAccount";
-import { Fragment, useContext, useState } from "react";
+import { Dialog, Transition } from '@headlessui/react';
+import { NDKEvent, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
+import { Fragment, useContext, useState } from 'react';
+
+import { CancelIcon, MuteIcon } from '@shared/icons';
+import { RelayContext } from '@shared/relayProvider';
+import { Tooltip } from '@shared/tooltip_dep';
+
+import { useChannelMessages } from '@stores/channels';
+
+import { dateToUnix } from '@utils/date';
+import { useAccount } from '@utils/hooks/useAccount';
export function MessageMuteButton({ pubkey }: { pubkey: string }) {
- const ndk = useContext(RelayContext);
- const mute = useChannelMessages((state: any) => state.muteUser);
+ const ndk = useContext(RelayContext);
+ const mute = useChannelMessages((state: any) => state.muteUser);
- const [isOpen, setIsOpen] = useState(false);
+ const [isOpen, setIsOpen] = useState(false);
- const { account } = useAccount();
+ const { account } = useAccount();
- const closeModal = () => {
- setIsOpen(false);
- };
+ const closeModal = () => {
+ setIsOpen(false);
+ };
- const openModal = () => {
- setIsOpen(true);
- };
+ const openModal = () => {
+ setIsOpen(true);
+ };
- const muteUser = () => {
- const signer = new NDKPrivateKeySigner(account.privkey);
- ndk.signer = signer;
+ const muteUser = () => {
+ const signer = new NDKPrivateKeySigner(account.privkey);
+ ndk.signer = signer;
- const event = new NDKEvent(ndk);
- // build event
- event.content = "";
- event.kind = 44;
- event.created_at = dateToUnix();
- event.pubkey = account.pubkey;
- event.tags = [["p", pubkey]];
+ const event = new NDKEvent(ndk);
+ // build event
+ event.content = '';
+ event.kind = 44;
+ event.created_at = dateToUnix();
+ event.pubkey = account.pubkey;
+ event.tags = [['p', pubkey]];
- // publish event
- event.publish();
+ // publish event
+ event.publish();
- // update state
- mute(pubkey);
+ // update state
+ mute(pubkey);
- // close modal
- closeModal();
- };
+ // close modal
+ closeModal();
+ };
- return (
- <>
-
-
-
-
-
-
- >
- );
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
}
diff --git a/src/app/channel/components/messages/replyButton.tsx b/src/app/channel/components/messages/replyButton.tsx
index 7d5d8828..f7baf316 100644
--- a/src/app/channel/components/messages/replyButton.tsx
+++ b/src/app/channel/components/messages/replyButton.tsx
@@ -1,27 +1,32 @@
-import { ReplyMessageIcon } from "@shared/icons";
-import { Tooltip } from "@shared/tooltip_dep";
-import { useChannelMessages } from "@stores/channels";
+import { ReplyMessageIcon } from '@shared/icons';
+import { Tooltip } from '@shared/tooltip_dep';
+
+import { useChannelMessages } from '@stores/channels';
export function MessageReplyButton({
- id,
- pubkey,
- content,
-}: { id: string; pubkey: string; content: string }) {
- const openReply = useChannelMessages((state: any) => state.openReply);
+ id,
+ pubkey,
+ content,
+}: {
+ id: string;
+ pubkey: string;
+ content: string;
+}) {
+ const openReply = useChannelMessages((state: any) => state.openReply);
- const createReply = () => {
- openReply(id, pubkey, content);
- };
+ const createReply = () => {
+ openReply(id, pubkey, content);
+ };
- return (
-
-
-
- );
+ return (
+
+
+
+ );
}
diff --git a/src/app/channel/components/messages/userMute.tsx b/src/app/channel/components/messages/userMute.tsx
index 5e60b7ce..08147b04 100644
--- a/src/app/channel/components/messages/userMute.tsx
+++ b/src/app/channel/components/messages/userMute.tsx
@@ -1,42 +1,40 @@
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useProfile } from "@utils/hooks/useProfile";
+import { Image } from '@shared/image';
-export function ChannelMessageUserMute({
- pubkey,
-}: {
- pubkey: string;
-}) {
- const { user, isError, isLoading } = useProfile(pubkey);
+import { DEFAULT_AVATAR } from '@stores/constants';
- return (
-
- {isError || isLoading ? (
- <>
-
-
- >
- ) : (
- <>
-
-
-
-
-
- You has been muted this user
-
-
- >
- )}
-
- );
+import { useProfile } from '@utils/hooks/useProfile';
+
+export function ChannelMessageUserMute({ pubkey }: { pubkey: string }) {
+ const { user, isError, isLoading } = useProfile(pubkey);
+
+ return (
+
+ {isError || isLoading ? (
+ <>
+
+
+ >
+ ) : (
+ <>
+
+
+
+
+
+ You has been muted this user
+
+
+ >
+ )}
+
+ );
}
diff --git a/src/app/channel/components/messages/userReply.tsx b/src/app/channel/components/messages/userReply.tsx
index 23017818..3488e0c7 100644
--- a/src/app/channel/components/messages/userReply.tsx
+++ b/src/app/channel/components/messages/userReply.tsx
@@ -1,33 +1,35 @@
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useProfile } from "@utils/hooks/useProfile";
-import { shortenKey } from "@utils/shortenKey";
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+
+import { useProfile } from '@utils/hooks/useProfile';
+import { shortenKey } from '@utils/shortenKey';
export function UserReply({ pubkey }: { pubkey: string }) {
- const { user, isError, isLoading } = useProfile(pubkey);
+ const { user, isError, isLoading } = useProfile(pubkey);
- return (
-
- {isError || isLoading ? (
- <>
-
-
- >
- ) : (
- <>
-
-
-
-
- Replying to {user?.name || shortenKey(pubkey)}
-
- >
- )}
-
- );
+ return (
+
+ {isError || isLoading ? (
+ <>
+
+
+ >
+ ) : (
+ <>
+
+
+
+
+ Replying to {user?.name || shortenKey(pubkey)}
+
+ >
+ )}
+
+ );
}
diff --git a/src/app/channel/components/metadata.tsx b/src/app/channel/components/metadata.tsx
index 19bc4915..16fd591a 100644
--- a/src/app/channel/components/metadata.tsx
+++ b/src/app/channel/components/metadata.tsx
@@ -1,43 +1,44 @@
-import { useChannelProfile } from "@app/channel/hooks/useChannelProfile";
-import { CopyIcon } from "@shared/icons";
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { nip19 } from "nostr-tools";
+import { nip19 } from 'nostr-tools';
+
+import { useChannelProfile } from '@app/channel/hooks/useChannelProfile';
+
+import { CopyIcon } from '@shared/icons';
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
export function ChannelMetadata({ id }: { id: string }) {
- const metadata = useChannelProfile(id);
- const noteID = id ? nip19.noteEncode(id) : null;
+ const metadata = useChannelProfile(id);
+ const noteID = id ? nip19.noteEncode(id) : null;
- const copyNoteID = async () => {
- const { writeText } = await import("@tauri-apps/api/clipboard");
- if (noteID) {
- await writeText(noteID);
- }
- };
+ const copyNoteID = async () => {
+ const { writeText } = await import('@tauri-apps/api/clipboard');
+ if (noteID) {
+ await writeText(noteID);
+ }
+ };
- return (
-
-
-
-
-
-
-
- {metadata?.name}
-
-
-
-
- {metadata?.about || (noteID && `${noteID.substring(0, 24)}...`)}
-
-
-
- );
+ return (
+
+
+
+
+
+
+
{metadata?.name}
+
+
+
+ {metadata?.about || (noteID && `${noteID.substring(0, 24)}...`)}
+
+
+
+ );
}
diff --git a/src/app/channel/components/mutedItem.tsx b/src/app/channel/components/mutedItem.tsx
index 2fc9d574..0662e7d1 100644
--- a/src/app/channel/components/mutedItem.tsx
+++ b/src/app/channel/components/mutedItem.tsx
@@ -1,82 +1,85 @@
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useProfile } from "@utils/hooks/useProfile";
-import { shortenKey } from "@utils/shortenKey";
-import { useState } from "react";
+import { useState } from 'react';
+
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+
+import { useProfile } from '@utils/hooks/useProfile';
+import { shortenKey } from '@utils/shortenKey';
export function MutedItem({ data }: { data: any }) {
- const { user, isError, isLoading } = useProfile(data.content);
- const [status, setStatus] = useState(data.status);
+ const { user, isError, isLoading } = useProfile(data.content);
+ const [status, setStatus] = useState(data.status);
- const unmute = async () => {
- const { updateItemInBlacklist } = await import("@libs/storage");
- const res = await updateItemInBlacklist(data.content, 0);
- if (res) {
- setStatus(0);
- }
- };
+ const unmute = async () => {
+ const { updateItemInBlacklist } = await import('@libs/storage');
+ const res = await updateItemInBlacklist(data.content, 0);
+ if (res) {
+ setStatus(0);
+ }
+ };
- const mute = async () => {
- const { updateItemInBlacklist } = await import("@libs/storage");
- const res = await updateItemInBlacklist(data.content, 1);
- if (res) {
- setStatus(1);
- }
- };
+ const mute = async () => {
+ const { updateItemInBlacklist } = await import('@libs/storage');
+ const res = await updateItemInBlacklist(data.content, 1);
+ if (res) {
+ setStatus(1);
+ }
+ };
- return (
-
- {isError || isLoading ? (
- <>
-
- >
- ) : (
- <>
-
-
-
-
-
-
- {user?.displayName || user?.name || "Pleb"}
-
-
- {shortenKey(data.content)}
-
-
-
-
- {status === 1 ? (
-
- ) : (
-
- )}
-
- >
- )}
-
- );
+ return (
+
+ {isError || isLoading ? (
+ <>
+
+ >
+ ) : (
+ <>
+
+
+
+
+
+
+ {user?.displayName || user?.name || 'Pleb'}
+
+
+ {shortenKey(data.content)}
+
+
+
+
+ {status === 1 ? (
+
+ ) : (
+
+ )}
+
+ >
+ )}
+
+ );
}
diff --git a/src/app/channel/hooks/useChannelProfile.tsx b/src/app/channel/hooks/useChannelProfile.tsx
index 3aab45d8..4d1c9577 100644
--- a/src/app/channel/hooks/useChannelProfile.tsx
+++ b/src/app/channel/hooks/useChannelProfile.tsx
@@ -1,35 +1,37 @@
-import { getChannel, updateChannelMetadata } from "@libs/storage";
-import { RelayContext } from "@shared/relayProvider";
-import { useQuery } from "@tanstack/react-query";
-import { useContext, useEffect } from "react";
+import { useQuery } from '@tanstack/react-query';
+import { useContext, useEffect } from 'react';
+
+import { getChannel, updateChannelMetadata } from '@libs/storage';
+
+import { RelayContext } from '@shared/relayProvider';
export function useChannelProfile(id: string) {
- const ndk = useContext(RelayContext);
- const { data } = useQuery(["channel-metadata", id], async () => {
- return await getChannel(id);
- });
+ const ndk = useContext(RelayContext);
+ const { data } = useQuery(['channel-metadata', id], async () => {
+ return await getChannel(id);
+ });
- useEffect(() => {
- // subscribe to channel
- const sub = ndk.subscribe(
- {
- "#e": [id],
- kinds: [41],
- },
- {
- closeOnEose: true,
- },
- );
+ useEffect(() => {
+ // subscribe to channel
+ const sub = ndk.subscribe(
+ {
+ '#e': [id],
+ kinds: [41],
+ },
+ {
+ closeOnEose: true,
+ }
+ );
- sub.addListener("event", (event: { content: string }) => {
- // update in local database
- updateChannelMetadata(id, event.content);
- });
+ sub.addListener('event', (event: { content: string }) => {
+ // update in local database
+ updateChannelMetadata(id, event.content);
+ });
- return () => {
- sub.stop();
- };
- }, []);
+ return () => {
+ sub.stop();
+ };
+ }, []);
- return data;
+ return data;
}
diff --git a/src/app/channel/index.tsx b/src/app/channel/index.tsx
index 85d5e598..e9905b62 100644
--- a/src/app/channel/index.tsx
+++ b/src/app/channel/index.tsx
@@ -1,154 +1,149 @@
-import { ChannelMessageItem } from "./components/messages/item";
-import { ChannelMembers } from "@app/channel/components/members";
-import { ChannelMessageForm } from "@app/channel/components/messages/form";
-import { ChannelMetadata } from "@app/channel/components/metadata";
-import { RelayContext } from "@shared/relayProvider";
-import { useChannelMessages } from "@stores/channels";
-import { dateToUnix, getHourAgo } from "@utils/date";
-import { LumeEvent } from "@utils/types";
-import {
- useCallback,
- useContext,
- useEffect,
- useLayoutEffect,
- useRef,
-} from "react";
-import { useParams } from "react-router-dom";
-import { Virtuoso } from "react-virtuoso";
+import { useCallback, useContext, useEffect, useLayoutEffect, useRef } from 'react';
+import { useParams } from 'react-router-dom';
+import { Virtuoso } from 'react-virtuoso';
+
+import { ChannelMembers } from '@app/channel/components/members';
+import { ChannelMessageForm } from '@app/channel/components/messages/form';
+import { ChannelMetadata } from '@app/channel/components/metadata';
+
+import { RelayContext } from '@shared/relayProvider';
+
+import { useChannelMessages } from '@stores/channels';
+
+import { dateToUnix, getHourAgo } from '@utils/date';
+import { LumeEvent } from '@utils/types';
+
+import { ChannelMessageItem } from './components/messages/item';
const now = new Date();
const Header = (
-
-
-
-
- {getHourAgo(24, now).toLocaleDateString("en-US", {
- weekday: "long",
- year: "numeric",
- month: "long",
- day: "numeric",
- })}
-
-
-
+
+
+
+
+ {getHourAgo(24, now).toLocaleDateString('en-US', {
+ weekday: 'long',
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ })}
+
+
+
);
const Empty = (
-
-
- Nothing to see here yet
-
-
- Be the first to share a message in this channel.
-
-
+
+
+ Nothing to see here yet
+
+
+ Be the first to share a message in this channel.
+
+
);
export function ChannelScreen() {
- const ndk = useContext(RelayContext);
- const virtuosoRef = useRef(null);
+ const ndk = useContext(RelayContext);
+ const virtuosoRef = useRef(null);
- const { id } = useParams();
+ const { id } = useParams();
- const [messages, fetchMessages, addMessage, clearMessages] =
- useChannelMessages((state: any) => [
- state.messages,
- state.fetch,
- state.add,
- state.clear,
- ]);
+ const [messages, fetchMessages, addMessage, clearMessages] = useChannelMessages(
+ (state: any) => [state.messages, state.fetch, state.add, state.clear]
+ );
- useLayoutEffect(() => {
- fetchMessages(id);
- }, [fetchMessages]);
+ useLayoutEffect(() => {
+ fetchMessages(id);
+ }, [fetchMessages]);
- useEffect(() => {
- // subscribe to channel
- const sub = ndk.subscribe(
- {
- "#e": [id],
- kinds: [42],
- since: dateToUnix(),
- },
- { closeOnEose: false },
- );
+ useEffect(() => {
+ // subscribe to channel
+ const sub = ndk.subscribe(
+ {
+ '#e': [id],
+ kinds: [42],
+ since: dateToUnix(),
+ },
+ { closeOnEose: false }
+ );
- sub.addListener("event", (event: LumeEvent) => {
- addMessage(id, event);
- });
+ sub.addListener('event', (event: LumeEvent) => {
+ addMessage(id, event);
+ });
- return () => {
- clearMessages();
- sub.stop();
- };
- }, []);
+ return () => {
+ clearMessages();
+ sub.stop();
+ };
+ }, []);
- const itemContent: any = useCallback(
- (index: string | number) => {
- return ;
- },
- [messages],
- );
+ const itemContent: any = useCallback(
+ (index: string | number) => {
+ return ;
+ },
+ [messages]
+ );
- const computeItemKey = useCallback(
- (index: string | number) => {
- return messages[index].event_id;
- },
- [messages],
- );
+ const computeItemKey = useCallback(
+ (index: string | number) => {
+ return messages[index].event_id;
+ },
+ [messages]
+ );
- return (
-
-
-
-
Public Channel
-
-
-
-
- {!messages ? (
-
Loading...
- ) : (
-
Header,
- EmptyPlaceholder: () => Empty,
- }}
- />
- )}
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
Public Channel
+
+
+
+
+ {!messages ? (
+
Loading...
+ ) : (
+
Header,
+ EmptyPlaceholder: () => Empty,
+ }}
+ />
+ )}
+
+
+
+
+
+
+
+
+
+ );
}
diff --git a/src/app/chat/components/item.tsx b/src/app/chat/components/item.tsx
index d95f379c..71d0e9e6 100644
--- a/src/app/chat/components/item.tsx
+++ b/src/app/chat/components/item.tsx
@@ -1,58 +1,61 @@
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useProfile } from "@utils/hooks/useProfile";
-import { shortenKey } from "@utils/shortenKey";
-import { NavLink } from "react-router-dom";
-import { twMerge } from "tailwind-merge";
+import { NavLink } from 'react-router-dom';
+import { twMerge } from 'tailwind-merge';
+
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+
+import { useProfile } from '@utils/hooks/useProfile';
+import { shortenKey } from '@utils/shortenKey';
export function ChatsListItem({ data }: { data: any }) {
- const { status, user } = useProfile(data.sender_pubkey);
+ const { status, user } = useProfile(data.sender_pubkey);
- if (status === "loading") {
- return (
-
- );
- }
+ if (status === 'loading') {
+ return (
+
+ );
+ }
- return (
-
- twMerge(
- "inline-flex h-9 items-center gap-2.5 rounded-md px-2.5",
- isActive ? "bg-zinc-900/50 text-zinc-100" : "",
- )
- }
- >
-
-
-
-
-
-
- {user?.nip05 ||
- user?.name ||
- user?.displayName ||
- shortenKey(data.sender_pubkey)}
-
-
-
- {data.new_messages > 0 && (
-
- {data.new_messages}
-
- )}
-
-
-
- );
+ return (
+
+ twMerge(
+ 'inline-flex h-9 items-center gap-2.5 rounded-md px-2.5',
+ isActive ? 'bg-zinc-900/50 text-zinc-100' : ''
+ )
+ }
+ >
+
+
+
+
+
+
+ {user?.nip05 ||
+ user?.name ||
+ user?.displayName ||
+ shortenKey(data.sender_pubkey)}
+
+
+
+ {data.new_messages > 0 && (
+
+ {data.new_messages}
+
+ )}
+
+
+
+ );
}
diff --git a/src/app/chat/components/list.tsx b/src/app/chat/components/list.tsx
index 536df6d8..4d7f236d 100644
--- a/src/app/chat/components/list.tsx
+++ b/src/app/chat/components/list.tsx
@@ -1,68 +1,71 @@
-import { ChatsListItem } from "@app/chat/components/item";
-import { NewMessageModal } from "@app/chat/components/modal";
-import { ChatsListSelfItem } from "@app/chat/components/self";
-import { getChatsByPubkey } from "@libs/storage";
-import { useQuery } from "@tanstack/react-query";
-import { useAccount } from "@utils/hooks/useAccount";
+import { useQuery } from '@tanstack/react-query';
+
+import { ChatsListItem } from '@app/chat/components/item';
+import { NewMessageModal } from '@app/chat/components/modal';
+import { ChatsListSelfItem } from '@app/chat/components/self';
+
+import { getChatsByPubkey } from '@libs/storage';
+
+import { useAccount } from '@utils/hooks/useAccount';
export function ChatsList() {
- const { account } = useAccount();
+ const { account } = useAccount();
- const {
- status,
- data: chats,
- isFetching,
- } = useQuery(
- ["chats"],
- async () => {
- const chats = await getChatsByPubkey(account.pubkey);
- const sorted = chats.sort(
- (a, b) => parseInt(a.new_messages) - parseInt(b.new_messages),
- );
- return sorted;
- },
- {
- enabled: account ? true : false,
- },
- );
+ const {
+ status,
+ data: chats,
+ isFetching,
+ } = useQuery(
+ ['chats'],
+ async () => {
+ const chats = await getChatsByPubkey(account.pubkey);
+ const sorted = chats.sort(
+ (a, b) => parseInt(a.new_messages) - parseInt(b.new_messages)
+ );
+ return sorted;
+ },
+ {
+ enabled: account ? true : false,
+ }
+ );
- if (status === "loading") {
- return (
-
- );
- }
+ if (status === 'loading') {
+ return (
+
+ );
+ }
- return (
-
-
- {account ? (
-
- ) : (
-
- )}
- {chats.map((item) => {
- if (account.pubkey !== item.sender_pubkey) {
- return
;
- }
- })}
- {isFetching && (
-
- )}
-
- );
+ return (
+
+
+ {account ? (
+
+ ) : (
+
+ )}
+ {chats.map((item) => {
+ if (account.pubkey !== item.sender_pubkey) {
+ return
;
+ }
+ })}
+ {isFetching && (
+
+ )}
+
+ );
}
diff --git a/src/app/chat/components/messages/form.tsx b/src/app/chat/components/messages/form.tsx
index 2549e5a9..68c17625 100644
--- a/src/app/chat/components/messages/form.tsx
+++ b/src/app/chat/components/messages/form.tsx
@@ -1,65 +1,71 @@
-import { usePublish } from "@libs/ndk";
-import { EnterIcon } from "@shared/icons";
-import { MediaUploader } from "@shared/mediaUploader";
-import { nip04 } from "nostr-tools";
-import { useCallback, useState } from "react";
+import { nip04 } from 'nostr-tools';
+import { useCallback, useState } from 'react';
+
+import { usePublish } from '@libs/ndk';
+
+import { EnterIcon } from '@shared/icons';
+import { MediaUploader } from '@shared/mediaUploader';
export function ChatMessageForm({
- receiverPubkey,
- userPrivkey,
-}: { receiverPubkey: string; userPubkey: string; userPrivkey: string }) {
- const publish = usePublish();
- const [value, setValue] = useState("");
+ receiverPubkey,
+ userPrivkey,
+}: {
+ receiverPubkey: string;
+ userPubkey: string;
+ userPrivkey: string;
+}) {
+ const publish = usePublish();
+ const [value, setValue] = useState('');
- const encryptMessage = useCallback(async () => {
- return await nip04.encrypt(userPrivkey, receiverPubkey, value);
- }, [receiverPubkey, value]);
+ const encryptMessage = useCallback(async () => {
+ return await nip04.encrypt(userPrivkey, receiverPubkey, value);
+ }, [receiverPubkey, value]);
- const submit = async () => {
- const message = await encryptMessage();
- const tags = [["p", receiverPubkey]];
+ const submit = async () => {
+ const message = await encryptMessage();
+ const tags = [['p', receiverPubkey]];
- // publish message
- await publish({ content: message, kind: 4, tags });
+ // publish message
+ await publish({ content: message, kind: 4, tags });
- // reset state
- setValue("");
- };
+ // reset state
+ setValue('');
+ };
- const handleEnterPress = (e: {
- key: string;
- shiftKey: any;
- preventDefault: () => void;
- }) => {
- if (e.key === "Enter" && !e.shiftKey) {
- e.preventDefault();
- submit();
- }
- };
+ const handleEnterPress = (e: {
+ key: string;
+ shiftKey: any;
+ preventDefault: () => void;
+ }) => {
+ if (e.key === 'Enter' && !e.shiftKey) {
+ e.preventDefault();
+ submit();
+ }
+ };
- return (
-
-
setValue(e.target.value)}
- onKeyDown={handleEnterPress}
- spellCheck={false}
- placeholder="Message"
- className="relative h-11 w-full resize-none rounded-md px-5 !outline-none bg-zinc-800 placeholder:text-zinc-500"
- />
-
-
- );
+ return (
+
+
setValue(e.target.value)}
+ onKeyDown={handleEnterPress}
+ spellCheck={false}
+ placeholder="Message"
+ className="relative h-11 w-full resize-none rounded-md bg-zinc-800 px-5 !outline-none placeholder:text-zinc-500"
+ />
+
+
+ );
}
diff --git a/src/app/chat/components/messages/item.tsx b/src/app/chat/components/messages/item.tsx
index e4eed145..29aa1115 100644
--- a/src/app/chat/components/messages/item.tsx
+++ b/src/app/chat/components/messages/item.tsx
@@ -1,49 +1,45 @@
-import { useDecryptMessage } from "@app/chat/hooks/useDecryptMessage";
-import { MentionNote } from "@shared/notes/mentions/note";
-import { ImagePreview } from "@shared/notes/preview/image";
-import { LinkPreview } from "@shared/notes/preview/link";
-import { VideoPreview } from "@shared/notes/preview/video";
-import { User } from "@shared/user";
-import { parser } from "@utils/parser";
+import { useDecryptMessage } from '@app/chat/hooks/useDecryptMessage';
+
+import { MentionNote } from '@shared/notes/mentions/note';
+import { ImagePreview } from '@shared/notes/preview/image';
+import { LinkPreview } from '@shared/notes/preview/link';
+import { VideoPreview } from '@shared/notes/preview/video';
+import { User } from '@shared/user';
+
+import { parser } from '@utils/parser';
export function ChatMessageItem({
- data,
- userPubkey,
- userPrivkey,
+ data,
+ userPubkey,
+ userPrivkey,
}: {
- data: any;
- userPubkey: string;
- userPrivkey: string;
+ data: any;
+ userPubkey: string;
+ userPrivkey: string;
}) {
- const decryptedContent = useDecryptMessage(data, userPubkey, userPrivkey);
- // if we have decrypted content, use it instead of the encrypted content
- if (decryptedContent) {
- data["content"] = decryptedContent;
- }
- // parse the note content
- const content = parser(data);
+ const decryptedContent = useDecryptMessage(data, userPubkey, userPrivkey);
+ // if we have decrypted content, use it instead of the encrypted content
+ if (decryptedContent) {
+ data['content'] = decryptedContent;
+ }
+ // parse the note content
+ const content = parser(data);
- return (
-
-
-
-
-
- {content.parsed}
-
- {content.images.length > 0 &&
}
- {content.videos.length > 0 &&
}
- {content.links.length > 0 &&
}
- {content.notes.length > 0 &&
- content.notes.map((note: string) => (
-
- ))}
-
-
-
- );
+ return (
+
+
+
+
+
+ {content.parsed}
+
+ {content.images.length > 0 &&
}
+ {content.videos.length > 0 &&
}
+ {content.links.length > 0 &&
}
+ {content.notes.length > 0 &&
+ content.notes.map((note: string) =>
)}
+
+
+
+ );
}
diff --git a/src/app/chat/components/modal.tsx b/src/app/chat/components/modal.tsx
index f671e13e..ced45948 100644
--- a/src/app/chat/components/modal.tsx
+++ b/src/app/chat/components/modal.tsx
@@ -1,125 +1,123 @@
-import { User } from "@app/auth/components/user";
-import { Dialog, Transition } from "@headlessui/react";
-import { CancelIcon, LoaderIcon, PlusIcon } from "@shared/icons";
-import { useAccount } from "@utils/hooks/useAccount";
-import { Fragment, useState } from "react";
-import { useNavigate } from "react-router-dom";
+import { Dialog, Transition } from '@headlessui/react';
+import { Fragment, useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+
+import { User } from '@app/auth/components/user';
+
+import { CancelIcon, LoaderIcon, PlusIcon } from '@shared/icons';
+
+import { useAccount } from '@utils/hooks/useAccount';
export function NewMessageModal() {
- const navigate = useNavigate();
- const [isOpen, setIsOpen] = useState(false);
+ const navigate = useNavigate();
+ const [isOpen, setIsOpen] = useState(false);
- const { status, account } = useAccount();
- const follows = account ? JSON.parse(account.follows) : [];
+ const { status, account } = useAccount();
+ const follows = account ? JSON.parse(account.follows) : [];
- const closeModal = () => {
- setIsOpen(false);
- };
+ const closeModal = () => {
+ setIsOpen(false);
+ };
- const openModal = () => {
- setIsOpen(true);
- };
+ const openModal = () => {
+ setIsOpen(true);
+ };
- const openChat = (pubkey: string) => {
- closeModal();
- navigate(`/app/chat/${pubkey}`);
- };
+ const openChat = (pubkey: string) => {
+ closeModal();
+ navigate(`/app/chat/${pubkey}`);
+ };
- return (
- <>
-
-
-
-
- >
- );
+ return (
+ <>
+
+
+
+
+ >
+ );
}
diff --git a/src/app/chat/components/self.tsx b/src/app/chat/components/self.tsx
index fa3ad60a..1cd03707 100644
--- a/src/app/chat/components/self.tsx
+++ b/src/app/chat/components/self.tsx
@@ -1,49 +1,52 @@
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useProfile } from "@utils/hooks/useProfile";
-import { shortenKey } from "@utils/shortenKey";
-import { NavLink } from "react-router-dom";
-import { twMerge } from "tailwind-merge";
+import { NavLink } from 'react-router-dom';
+import { twMerge } from 'tailwind-merge';
+
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+
+import { useProfile } from '@utils/hooks/useProfile';
+import { shortenKey } from '@utils/shortenKey';
export function ChatsListSelfItem({ data }: { data: any }) {
- const { status, user } = useProfile(data.pubkey);
+ const { status, user } = useProfile(data.pubkey);
- if (status === "loading") {
- return (
-
- );
- }
+ if (status === 'loading') {
+ return (
+
+ );
+ }
- return (
-
- twMerge(
- "inline-flex h-9 items-center gap-2.5 rounded-md px-2.5",
- isActive ? "bg-zinc-900/50 text-zinc-100" : "",
- )
- }
- >
-
-
-
-
-
- {user?.nip05 || user?.name || shortenKey(data.pubkey)}
-
- (you)
-
-
- );
+ return (
+
+ twMerge(
+ 'inline-flex h-9 items-center gap-2.5 rounded-md px-2.5',
+ isActive ? 'bg-zinc-900/50 text-zinc-100' : ''
+ )
+ }
+ >
+
+
+
+
+
+ {user?.nip05 || user?.name || shortenKey(data.pubkey)}
+
+ (you)
+
+
+ );
}
diff --git a/src/app/chat/components/sidebar.tsx b/src/app/chat/components/sidebar.tsx
index eed4df51..0f14b440 100644
--- a/src/app/chat/components/sidebar.tsx
+++ b/src/app/chat/components/sidebar.tsx
@@ -1,43 +1,46 @@
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useProfile } from "@utils/hooks/useProfile";
-import { shortenKey } from "@utils/shortenKey";
-import { Link } from "react-router-dom";
+import { Link } from 'react-router-dom';
+
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+
+import { useProfile } from '@utils/hooks/useProfile';
+import { shortenKey } from '@utils/shortenKey';
export function ChatSidebar({ pubkey }: { pubkey: string }) {
- const { user } = useProfile(pubkey);
+ const { user } = useProfile(pubkey);
- return (
-
-
-
-
-
-
-
-
- {user?.displayName || user?.name}
-
-
- {user?.nip05 || shortenKey(pubkey)}
-
-
-
-
{user?.bio || user?.about}
-
- View full profile
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+ {user?.displayName || user?.name}
+
+
+ {user?.nip05 || shortenKey(pubkey)}
+
+
+
+
{user?.bio || user?.about}
+
+ View full profile
+
+
+
+
+
+ );
}
diff --git a/src/app/chat/hooks/useDecryptMessage.tsx b/src/app/chat/hooks/useDecryptMessage.tsx
index 8e4a3715..7036b975 100644
--- a/src/app/chat/hooks/useDecryptMessage.tsx
+++ b/src/app/chat/hooks/useDecryptMessage.tsx
@@ -1,25 +1,19 @@
-import { nip04 } from "nostr-tools";
-import { useEffect, useState } from "react";
+import { nip04 } from 'nostr-tools';
+import { useEffect, useState } from 'react';
-export function useDecryptMessage(
- data: any,
- userPubkey: string,
- userPriv: string,
-) {
- const [content, setContent] = useState(data.content);
+export function useDecryptMessage(data: any, userPubkey: string, userPriv: string) {
+ const [content, setContent] = useState(data.content);
- useEffect(() => {
- async function decrypt() {
- const pubkey =
- userPubkey === data.sender_pubkey
- ? data.receiver_pubkey
- : data.sender_pubkey;
- const result = await nip04.decrypt(userPriv, pubkey, data.content);
- setContent(result);
- }
+ useEffect(() => {
+ async function decrypt() {
+ const pubkey =
+ userPubkey === data.sender_pubkey ? data.receiver_pubkey : data.sender_pubkey;
+ const result = await nip04.decrypt(userPriv, pubkey, data.content);
+ setContent(result);
+ }
- decrypt().catch(console.error);
- }, []);
+ decrypt().catch(console.error);
+ }, []);
- return content;
+ return content;
}
diff --git a/src/app/chat/index.tsx b/src/app/chat/index.tsx
index 82088b84..159eb852 100644
--- a/src/app/chat/index.tsx
+++ b/src/app/chat/index.tsx
@@ -1,155 +1,159 @@
-import { ChatMessageForm } from "@app/chat/components/messages/form";
-import { ChatMessageItem } from "@app/chat/components/messages/item";
-import { ChatSidebar } from "@app/chat/components/sidebar";
-import { createChat, getChatMessages } from "@libs/storage";
-import { NDKSubscription } from "@nostr-dev-kit/ndk";
-import { RelayContext } from "@shared/relayProvider";
-import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
-import { useAccount } from "@utils/hooks/useAccount";
-import { useCallback, useContext, useEffect, useRef } from "react";
-import { useParams } from "react-router-dom";
-import { Virtuoso } from "react-virtuoso";
+import { NDKSubscription } from '@nostr-dev-kit/ndk';
+import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
+import { useCallback, useContext, useEffect, useRef } from 'react';
+import { useParams } from 'react-router-dom';
+import { Virtuoso } from 'react-virtuoso';
+
+import { ChatMessageForm } from '@app/chat/components/messages/form';
+import { ChatMessageItem } from '@app/chat/components/messages/item';
+import { ChatSidebar } from '@app/chat/components/sidebar';
+
+import { createChat, getChatMessages } from '@libs/storage';
+
+import { RelayContext } from '@shared/relayProvider';
+
+import { useAccount } from '@utils/hooks/useAccount';
export function ChatScreen() {
- const ndk = useContext(RelayContext);
- const queryClient = useQueryClient();
- const virtuosoRef = useRef(null);
+ const ndk = useContext(RelayContext);
+ const queryClient = useQueryClient();
+ const virtuosoRef = useRef(null);
- const { pubkey } = useParams();
- const { account } = useAccount();
- const { status, data } = useQuery(
- ["chat", pubkey],
- async () => {
- return await getChatMessages(account.pubkey, pubkey);
- },
- {
- enabled: account ? true : false,
- },
- );
+ const { pubkey } = useParams();
+ const { account } = useAccount();
+ const { status, data } = useQuery(
+ ['chat', pubkey],
+ async () => {
+ return await getChatMessages(account.pubkey, pubkey);
+ },
+ {
+ enabled: account ? true : false,
+ }
+ );
- const itemContent: any = useCallback(
- (index: string | number) => {
- return (
-
- );
- },
- [data],
- );
+ const itemContent: any = useCallback(
+ (index: string | number) => {
+ return (
+
+ );
+ },
+ [data]
+ );
- const computeItemKey = useCallback(
- (index: string | number) => {
- return data[index].id;
- },
- [data],
- );
+ const computeItemKey = useCallback(
+ (index: string | number) => {
+ return data[index].id;
+ },
+ [data]
+ );
- const chat = useMutation({
- mutationFn: (data: any) => {
- return createChat(
- data.id,
- data.receiver_pubkey,
- data.sender_pubkey,
- data.content,
- data.tags,
- data.created_at,
- );
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["chat", pubkey] });
- },
- });
+ const chat = useMutation({
+ mutationFn: (data: any) => {
+ return createChat(
+ data.id,
+ data.receiver_pubkey,
+ data.sender_pubkey,
+ data.content,
+ data.tags,
+ data.created_at
+ );
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['chat', pubkey] });
+ },
+ });
- useEffect(() => {
- const sub: NDKSubscription = ndk.subscribe(
- {
- kinds: [4],
- authors: [account.pubkey],
- "#p": [pubkey],
- since: Math.floor(Date.now() / 1000),
- },
- {
- closeOnEose: false,
- },
- );
+ useEffect(() => {
+ const sub: NDKSubscription = ndk.subscribe(
+ {
+ kinds: [4],
+ authors: [account.pubkey],
+ '#p': [pubkey],
+ since: Math.floor(Date.now() / 1000),
+ },
+ {
+ closeOnEose: false,
+ }
+ );
- sub.addListener("event", (event) => {
- chat.mutate({
- id: event.id,
- receiver_pubkey: pubkey,
- sender_pubkey: event.pubkey,
- content: event.content,
- tags: event.tags,
- created_at: event.created_at,
- });
- });
+ sub.addListener('event', (event) => {
+ chat.mutate({
+ id: event.id,
+ receiver_pubkey: pubkey,
+ sender_pubkey: event.pubkey,
+ content: event.content,
+ tags: event.tags,
+ created_at: event.created_at,
+ });
+ });
- return () => {
- sub.stop();
- };
- }, [pubkey]);
+ return () => {
+ sub.stop();
+ };
+ }, [pubkey]);
- return (
-
-
-
-
Encrypted Chat
-
-
-
-
- {status === "loading" ? (
-
Loading...
- ) : (
-
Empty,
- }}
- />
- )}
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
Encrypted Chat
+
+
+
+
+ {status === 'loading' ? (
+
Loading...
+ ) : (
+
Empty,
+ }}
+ />
+ )}
+
+
+
+
+
+
+
+
+
+ );
}
const Empty = (
-
-
🙌
-
- You two didn't talk yet, let's send first message
-
-
+
+
🙌
+
+ You two didn't talk yet, let's send first message
+
+
);
diff --git a/src/app/error.tsx b/src/app/error.tsx
index bd71c61e..a70b40da 100644
--- a/src/app/error.tsx
+++ b/src/app/error.tsx
@@ -1,17 +1,17 @@
-import { useRouteError } from "react-router-dom";
+import { useRouteError } from 'react-router-dom';
export function ErrorScreen() {
- const error: any = useRouteError();
+ const error: any = useRouteError();
- return (
-
-
-
Oops!
-
Sorry, an unexpected error has occurred.
-
- {error.statusText || error.message}
-
-
-
- );
+ return (
+
+
+
Oops!
+
Sorry, an unexpected error has occurred.
+
+ {error.statusText || error.message}
+
+
+
+ );
}
diff --git a/src/app/root.tsx b/src/app/root.tsx
index 0e13ed37..88347449 100644
--- a/src/app/root.tsx
+++ b/src/app/root.tsx
@@ -1,185 +1,187 @@
-import { prefetchEvents } from "@libs/ndk";
+import { NDKFilter } from '@nostr-dev-kit/ndk';
+import { useContext, useEffect, useRef } from 'react';
+import { useNavigate } from 'react-router-dom';
+
+import { prefetchEvents } from '@libs/ndk';
import {
- countTotalNotes,
- createChannelMessage,
- createChat,
- createNote,
- getChannels,
- getLastLogin,
- updateLastLogin,
-} from "@libs/storage";
-import { NDKFilter } from "@nostr-dev-kit/ndk";
-import { LoaderIcon, LumeIcon } from "@shared/icons";
-import { RelayContext } from "@shared/relayProvider";
-import { dateToUnix, getHourAgo } from "@utils/date";
-import { useAccount } from "@utils/hooks/useAccount";
-import { useContext, useEffect, useRef } from "react";
-import { useNavigate } from "react-router-dom";
+ countTotalNotes,
+ createChannelMessage,
+ createChat,
+ createNote,
+ getChannels,
+ getLastLogin,
+ updateLastLogin,
+} from '@libs/storage';
+
+import { LoaderIcon, LumeIcon } from '@shared/icons';
+import { RelayContext } from '@shared/relayProvider';
+
+import { dateToUnix, getHourAgo } from '@utils/date';
+import { useAccount } from '@utils/hooks/useAccount';
const totalNotes = await countTotalNotes();
const lastLogin = await getLastLogin();
export function Root() {
- const ndk = useContext(RelayContext);
- const now = useRef(new Date());
- const navigate = useNavigate();
+ const ndk = useContext(RelayContext);
+ const now = useRef(new Date());
+ const navigate = useNavigate();
- const { status, account } = useAccount();
+ const { status, account } = useAccount();
- async function fetchNotes() {
- try {
- const follows = JSON.parse(account.follows);
- let since: number;
+ async function fetchNotes() {
+ try {
+ const follows = JSON.parse(account.follows);
+ let since: number;
- if (totalNotes === 0 || lastLogin === 0) {
- since = dateToUnix(getHourAgo(48, now.current));
- } else {
- since = lastLogin;
- }
+ if (totalNotes === 0 || lastLogin === 0) {
+ since = dateToUnix(getHourAgo(48, now.current));
+ } else {
+ since = lastLogin;
+ }
- const filter: NDKFilter = {
- kinds: [1, 6],
- authors: follows,
- since: since,
- };
+ const filter: NDKFilter = {
+ kinds: [1, 6],
+ authors: follows,
+ since: since,
+ };
- const events = await prefetchEvents(ndk, filter);
- events.forEach((event) => {
- createNote(
- event.id,
- event.pubkey,
- event.kind,
- event.tags,
- event.content,
- event.created_at,
- );
- });
+ const events = await prefetchEvents(ndk, filter);
+ events.forEach((event) => {
+ createNote(
+ event.id,
+ event.pubkey,
+ event.kind,
+ event.tags,
+ event.content,
+ event.created_at
+ );
+ });
- return true;
- } catch (e) {
- console.log("error: ", e);
- }
- }
+ return true;
+ } catch (e) {
+ console.log('error: ', e);
+ }
+ }
- async function fetchChats() {
- try {
- const sendFilter: NDKFilter = {
- kinds: [4],
- authors: [account.pubkey],
- since: lastLogin,
- };
- const receiveFilter: NDKFilter = {
- kinds: [4],
- "#p": [account.pubkey],
- since: lastLogin,
- };
+ async function fetchChats() {
+ try {
+ const sendFilter: NDKFilter = {
+ kinds: [4],
+ authors: [account.pubkey],
+ since: lastLogin,
+ };
+ const receiveFilter: NDKFilter = {
+ kinds: [4],
+ '#p': [account.pubkey],
+ since: lastLogin,
+ };
- const sendMessages = await prefetchEvents(ndk, sendFilter);
- const receiveMessages = await prefetchEvents(ndk, receiveFilter);
- const events = [...sendMessages, ...receiveMessages];
+ const sendMessages = await prefetchEvents(ndk, sendFilter);
+ const receiveMessages = await prefetchEvents(ndk, receiveFilter);
+ const events = [...sendMessages, ...receiveMessages];
- events.forEach((event) => {
- const receiverPubkey =
- event.tags.find((t) => t[0] === "p")[1] || account.pubkey;
- createChat(
- event.id,
- receiverPubkey,
- event.pubkey,
- event.content,
- event.tags,
- event.created_at,
- );
- });
+ events.forEach((event) => {
+ const receiverPubkey = event.tags.find((t) => t[0] === 'p')[1] || account.pubkey;
+ createChat(
+ event.id,
+ receiverPubkey,
+ event.pubkey,
+ event.content,
+ event.tags,
+ event.created_at
+ );
+ });
- return true;
- } catch (e) {
- console.log("error: ", e);
- }
- }
+ return true;
+ } catch (e) {
+ console.log('error: ', e);
+ }
+ }
- async function fetchChannelMessages() {
- try {
- const ids = [];
- const channels: any = await getChannels();
- channels.forEach((channel) => {
- ids.push(channel.event_id);
- });
+ /*
+ async function fetchChannelMessages() {
+ try {
+ const ids = [];
+ const channels: any = await getChannels();
+ channels.forEach((channel) => {
+ ids.push(channel.event_id);
+ });
- const since =
- lastLogin === 0 ? dateToUnix(getHourAgo(48, now.current)) : lastLogin;
+ const since = lastLogin === 0 ? dateToUnix(getHourAgo(48, now.current)) : lastLogin;
- const filter: NDKFilter = {
- "#e": ids,
- kinds: [42],
- since: since,
- };
+ const filter: NDKFilter = {
+ '#e': ids,
+ kinds: [42],
+ since: since,
+ };
- const events = await prefetchEvents(ndk, filter);
- events.forEach((event) => {
- const channel_id = event.tags[0][1];
- if (channel_id) {
- createChannelMessage(
- channel_id,
- event.id,
- event.pubkey,
- event.kind,
- event.content,
- event.tags,
- event.created_at,
- );
- }
- });
+ const events = await prefetchEvents(ndk, filter);
+ events.forEach((event) => {
+ const channel_id = event.tags[0][1];
+ if (channel_id) {
+ createChannelMessage(
+ channel_id,
+ event.id,
+ event.pubkey,
+ event.kind,
+ event.content,
+ event.tags,
+ event.created_at
+ );
+ }
+ });
- return true;
- } catch (e) {
- console.log("error: ", e);
- }
- }
+ return true;
+ } catch (e) {
+ console.log('error: ', e);
+ }
+ }
+ */
- useEffect(() => {
- async function prefetch() {
- const notes = await fetchNotes();
- if (notes) {
- const chats = await fetchChats();
- // const channels = await fetchChannelMessages();
- if (chats) {
- const now = Math.floor(Date.now() / 1000);
- await updateLastLogin(now);
- navigate("/app/space", { replace: true });
- }
- }
- }
+ useEffect(() => {
+ async function prefetch() {
+ const notes = await fetchNotes();
+ if (notes) {
+ const chats = await fetchChats();
+ // const channels = await fetchChannelMessages();
+ if (chats) {
+ const now = Math.floor(Date.now() / 1000);
+ await updateLastLogin(now);
+ navigate('/app/space', { replace: true });
+ }
+ }
+ }
- if (status === "success" && account) {
- prefetch();
- }
- }, [status]);
+ if (status === 'success' && account) {
+ prefetch();
+ }
+ }, [status]);
- return (
-
-
-
-
-
-
-
-
- Here's an interesting fact:
-
-
- Bitcoin and Nostr can be used by anyone, and no one can stop
- you!
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+ Here's an interesting fact:
+
+
+ Bitcoin and Nostr can be used by anyone, and no one can stop you!
+
+
+
+
+
+
+
+
+
+ );
}
diff --git a/src/app/settings/account.tsx b/src/app/settings/account.tsx
index 0224c89e..c06663a5 100644
--- a/src/app/settings/account.tsx
+++ b/src/app/settings/account.tsx
@@ -1,84 +1,89 @@
-import { EyeOffIcon, EyeOnIcon } from "@shared/icons";
-import { useAccount } from "@utils/hooks/useAccount";
-import { useState } from "react";
+import { useState } from 'react';
+
+import { EyeOffIcon, EyeOnIcon } from '@shared/icons';
+
+import { useAccount } from '@utils/hooks/useAccount';
export function AccountSettingsScreen() {
- const { status, account } = useAccount();
- const [type, setType] = useState("password");
+ const { status, account } = useAccount();
+ const [type, setType] = useState('password');
- const showPrivateKey = () => {
- if (type === "password") {
- setType("text");
- } else {
- setType("password");
- }
- };
+ const showPrivateKey = () => {
+ if (type === 'password') {
+ setType('text');
+ } else {
+ setType('password');
+ }
+ };
- return (
-
-
-
Account
-
- {status === "loading" ? (
-
Loading...
- ) : (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )}
-
-
-
- );
+ return (
+
+
+
Account
+
+ {status === 'loading' ? (
+
Loading...
+ ) : (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+
+
+ );
}
diff --git a/src/app/settings/components/autoStart.tsx b/src/app/settings/components/autoStart.tsx
index 0dff7c88..da370111 100644
--- a/src/app/settings/components/autoStart.tsx
+++ b/src/app/settings/components/autoStart.tsx
@@ -1,61 +1,58 @@
-import { Switch } from "@headlessui/react";
-import { getSetting, updateSetting } from "@libs/storage";
-import { useEffect, useState } from "react";
-import { twMerge } from "tailwind-merge";
-import { disable, enable, isEnabled } from "tauri-plugin-autostart-api";
+import { Switch } from '@headlessui/react';
+import { useEffect, useState } from 'react';
+import { twMerge } from 'tailwind-merge';
+import { disable, enable, isEnabled } from 'tauri-plugin-autostart-api';
+
+import { getSetting, updateSetting } from '@libs/storage';
export function AutoStartSetting() {
- const [enabled, setEnabled] = useState(false);
+ const [enabled, setEnabled] = useState(false);
- const toggle = async () => {
- if (!enabled) {
- await enable();
- await updateSetting("auto_start", 1);
- console.log(`registered for autostart? ${await isEnabled()}`);
- } else {
- await disable();
- await updateSetting("auto_start", 0);
- }
- setEnabled(!enabled);
- };
+ const toggle = async () => {
+ if (!enabled) {
+ await enable();
+ await updateSetting('auto_start', 1);
+ console.log(`registered for autostart? ${await isEnabled()}`);
+ } else {
+ await disable();
+ await updateSetting('auto_start', 0);
+ }
+ setEnabled(!enabled);
+ };
- useEffect(() => {
- async function getAppSetting() {
- const setting = await getSetting("auto_start");
- if (parseInt(setting) === 0) {
- setEnabled(false);
- } else {
- setEnabled(true);
- }
- }
- getAppSetting();
- }, []);
+ useEffect(() => {
+ async function getAppSetting() {
+ const setting = await getSetting('auto_start');
+ if (parseInt(setting) === 0) {
+ setEnabled(false);
+ } else {
+ setEnabled(true);
+ }
+ }
+ getAppSetting();
+ }, []);
- return (
-
-
-
- Auto start
-
-
- Auto start at login
-
-
-
-
-
-
- );
+ return (
+
+
+ Auto start
+ Auto start at login
+
+
+
+
+
+ );
}
diff --git a/src/app/settings/components/cacheTime.tsx b/src/app/settings/components/cacheTime.tsx
index 2cacac5d..2c62cd52 100644
--- a/src/app/settings/components/cacheTime.tsx
+++ b/src/app/settings/components/cacheTime.tsx
@@ -1,43 +1,43 @@
-import { getSetting, updateSetting } from "@libs/storage";
-import { CheckCircleIcon } from "@shared/icons";
-import { useState } from "react";
+import { useState } from 'react';
-const setting = await getSetting("cache_time");
+import { getSetting, updateSetting } from '@libs/storage';
+
+import { CheckCircleIcon } from '@shared/icons';
+
+const setting = await getSetting('cache_time');
const cacheTime = setting;
export function CacheTimeSetting() {
- const [time, setTime] = useState(cacheTime);
+ const [time, setTime] = useState(cacheTime);
- const update = async () => {
- await updateSetting("cache_time", time);
- };
+ const update = async () => {
+ await updateSetting('cache_time', time);
+ };
- return (
-
-
-
- Cache time
-
-
- The length of time before inactive data gets removed from the cache
-
-
-
- setTime(e.currentTarget.value)}
- autoCapitalize="none"
- autoCorrect="none"
- className="w-24 h-8 rounded-md px-2 bg-zinc-800 text-zinc-300 text-right font-medium focus:outline-none"
- />
-
-
-
- );
+ return (
+
+
+ Cache time
+
+ The length of time before inactive data gets removed from the cache
+
+
+
+ setTime(e.currentTarget.value)}
+ autoCapitalize="none"
+ autoCorrect="none"
+ className="h-8 w-24 rounded-md bg-zinc-800 px-2 text-right font-medium text-zinc-300 focus:outline-none"
+ />
+
+
+
+ );
}
diff --git a/src/app/settings/components/version.tsx b/src/app/settings/components/version.tsx
index dfe9905e..ee0c0a20 100644
--- a/src/app/settings/components/version.tsx
+++ b/src/app/settings/components/version.tsx
@@ -1,26 +1,27 @@
-import { RefreshIcon } from "@shared/icons";
-import { getVersion } from "@tauri-apps/api/app";
+import { getVersion } from '@tauri-apps/api/app';
+
+import { RefreshIcon } from '@shared/icons';
const appVersion = await getVersion();
export function VersionSetting() {
- return (
-
-
- Version
-
- You're using latest version
-
-
-
- {appVersion}
-
-
-
- );
+ return (
+
+
+ Version
+
+ You're using latest version
+
+
+
+ {appVersion}
+
+
+
+ );
}
diff --git a/src/app/settings/general.tsx b/src/app/settings/general.tsx
index 45939715..e535679e 100644
--- a/src/app/settings/general.tsx
+++ b/src/app/settings/general.tsx
@@ -1,20 +1,20 @@
-import { AutoStartSetting } from "@app/settings/components/autoStart";
-import { CacheTimeSetting } from "@app/settings/components/cacheTime";
-import { VersionSetting } from "@app/settings/components/version";
+import { AutoStartSetting } from '@app/settings/components/autoStart';
+import { CacheTimeSetting } from '@app/settings/components/cacheTime';
+import { VersionSetting } from '@app/settings/components/version';
export function GeneralSettingsScreen() {
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/app/settings/shortcuts.tsx b/src/app/settings/shortcuts.tsx
index b05ff9b3..f7d5daa7 100644
--- a/src/app/settings/shortcuts.tsx
+++ b/src/app/settings/shortcuts.tsx
@@ -1,110 +1,90 @@
-import { CommandIcon } from "@shared/icons";
+import { CommandIcon } from '@shared/icons';
export function ShortcutsSettingsScreen() {
- return (
-
-
-
Shortcuts
-
-
-
-
-
- Open composer
-
-
-
-
-
-
-
- Add image block
-
-
-
-
-
-
-
- Add newsfeed block
-
-
-
-
-
-
-
- Open personal page
-
-
-
-
-
-
-
- Open notification
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
Shortcuts
+
+
+
+
+
+ Open composer
+
+
+
+
+
+
+
+ Add image block
+
+
+
+
+
+
+
+ Add newsfeed block
+
+
+
+
+
+
+
+ Open personal page
+
+
+
+
+
+
+
+ Open notification
+
+
+
+
+
+
+
+
+ );
}
diff --git a/src/app/space/components/add.tsx b/src/app/space/components/add.tsx
index dfce2e1a..861bbc78 100644
--- a/src/app/space/components/add.tsx
+++ b/src/app/space/components/add.tsx
@@ -1,11 +1,11 @@
-import { AddFeedBlock } from "@app/space/components/addFeed";
-import { AddImageBlock } from "@app/space/components/addImage";
+import { AddFeedBlock } from '@app/space/components/addFeed';
+import { AddImageBlock } from '@app/space/components/addImage';
export function AddBlock() {
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/app/space/components/addFeed.tsx b/src/app/space/components/addFeed.tsx
index 178a7466..33ced7ad 100644
--- a/src/app/space/components/addFeed.tsx
+++ b/src/app/space/components/addFeed.tsx
@@ -1,274 +1,252 @@
-import { User } from "@app/auth/components/user";
-import { Dialog, Transition } from "@headlessui/react";
-import { Combobox } from "@headlessui/react";
-import { createBlock } from "@libs/storage";
-import { CancelIcon, CheckCircleIcon, CommandIcon } from "@shared/icons";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { ADD_FEEDBLOCK_SHORTCUT } from "@stores/shortcuts";
-import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
-import { useAccount } from "@utils/hooks/useAccount";
-import { nip19 } from "nostr-tools";
-import { Fragment, useEffect, useState } from "react";
-import { useForm } from "react-hook-form";
-import { useHotkeys } from "react-hotkeys-hook";
+import { Dialog, Transition } from '@headlessui/react';
+import { Combobox } from '@headlessui/react';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { nip19 } from 'nostr-tools';
+import { Fragment, useState } from 'react';
+import { useForm } from 'react-hook-form';
+import { useHotkeys } from 'react-hotkeys-hook';
+
+import { User } from '@app/auth/components/user';
+
+import { createBlock } from '@libs/storage';
+
+import { CancelIcon, CheckCircleIcon, CommandIcon, LoaderIcon } from '@shared/icons';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+import { ADD_FEEDBLOCK_SHORTCUT } from '@stores/shortcuts';
+
+import { useAccount } from '@utils/hooks/useAccount';
export function AddFeedBlock() {
- const queryClient = useQueryClient();
+ const queryClient = useQueryClient();
- const [loading, setLoading] = useState(false);
- const [isOpen, setIsOpen] = useState(false);
- const [selected, setSelected] = useState([]);
- const [query, setQuery] = useState("");
+ const [loading, setLoading] = useState(false);
+ const [isOpen, setIsOpen] = useState(false);
+ const [selected, setSelected] = useState([]);
+ const [query, setQuery] = useState('');
- const { status, account } = useAccount();
+ const { status, account } = useAccount();
- const openModal = () => {
- setIsOpen(true);
- };
+ const openModal = () => {
+ setIsOpen(true);
+ };
- const closeModal = () => {
- setIsOpen(false);
- };
+ const closeModal = () => {
+ setIsOpen(false);
+ };
- useHotkeys(ADD_FEEDBLOCK_SHORTCUT, () => openModal());
+ useHotkeys(ADD_FEEDBLOCK_SHORTCUT, () => openModal());
- const block = useMutation({
- mutationFn: (data: any) => {
- return createBlock(data.kind, data.title, data.content);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["blocks"] });
- },
- });
+ const block = useMutation({
+ mutationFn: (data: any) => {
+ return createBlock(data.kind, data.title, data.content);
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['blocks'] });
+ },
+ });
- const {
- register,
- handleSubmit,
- reset,
- formState: { isDirty, isValid },
- } = useForm();
+ const {
+ register,
+ handleSubmit,
+ reset,
+ formState: { isDirty, isValid },
+ } = useForm();
- const onSubmit = (data: any) => {
- setLoading(true);
+ const onSubmit = (data: any) => {
+ setLoading(true);
- selected.forEach((item, index) => {
- if (item.substring(0, 4) === "npub") {
- selected[index] = nip19.decode(item).data;
- }
- });
+ selected.forEach((item, index) => {
+ if (item.substring(0, 4) === 'npub') {
+ selected[index] = nip19.decode(item).data;
+ }
+ });
- // insert to database
- block.mutate({
- kind: 1,
- title: data.title,
- content: JSON.stringify(selected),
- });
+ // insert to database
+ block.mutate({
+ kind: 1,
+ title: data.title,
+ content: JSON.stringify(selected),
+ });
- setLoading(false);
- // reset form
- reset();
- // close modal
- closeModal();
- };
+ setLoading(false);
+ // reset form
+ reset();
+ // close modal
+ closeModal();
+ };
- return (
- <>
-
-
-
-
- >
- );
+ return (
+ <>
+
+
+
+
+ >
+ );
}
diff --git a/src/app/space/components/addImage.tsx b/src/app/space/components/addImage.tsx
index 9625e39c..40777f25 100644
--- a/src/app/space/components/addImage.tsx
+++ b/src/app/space/components/addImage.tsx
@@ -1,298 +1,303 @@
-import { Dialog, Transition } from "@headlessui/react";
-import { createBlock } from "@libs/storage";
-import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
-import { CancelIcon, CommandIcon } from "@shared/icons";
-import { Image } from "@shared/image";
-import { RelayContext } from "@shared/relayProvider";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { ADD_IMAGEBLOCK_SHORTCUT } from "@stores/shortcuts";
-import { useMutation, useQueryClient } from "@tanstack/react-query";
-import { open } from "@tauri-apps/api/dialog";
-import { Body, fetch } from "@tauri-apps/api/http";
-import { createBlobFromFile } from "@utils/createBlobFromFile";
-import { dateToUnix } from "@utils/date";
-import { useAccount } from "@utils/hooks/useAccount";
-import { Fragment, useContext, useEffect, useRef, useState } from "react";
-import { useForm } from "react-hook-form";
-import { useHotkeys } from "react-hotkeys-hook";
+import { Dialog, Transition } from '@headlessui/react';
+import { NDKEvent, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { open } from '@tauri-apps/api/dialog';
+import { Body, fetch } from '@tauri-apps/api/http';
+import { Fragment, useContext, useEffect, useRef, useState } from 'react';
+import { useForm } from 'react-hook-form';
+import { useHotkeys } from 'react-hotkeys-hook';
+
+import { createBlock } from '@libs/storage';
+
+import { CancelIcon, CommandIcon } from '@shared/icons';
+import { Image } from '@shared/image';
+import { RelayContext } from '@shared/relayProvider';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+import { ADD_IMAGEBLOCK_SHORTCUT } from '@stores/shortcuts';
+
+import { createBlobFromFile } from '@utils/createBlobFromFile';
+import { dateToUnix } from '@utils/date';
+import { useAccount } from '@utils/hooks/useAccount';
export function AddImageBlock() {
- const ndk = useContext(RelayContext);
- const queryClient = useQueryClient();
+ const ndk = useContext(RelayContext);
+ const queryClient = useQueryClient();
- const [loading, setLoading] = useState(false);
- const [isOpen, setIsOpen] = useState(false);
- const [image, setImage] = useState("");
+ const [loading, setLoading] = useState(false);
+ const [isOpen, setIsOpen] = useState(false);
+ const [image, setImage] = useState('');
- const { account } = useAccount();
+ const { account } = useAccount();
- const tags = useRef(null);
+ const tags = useRef(null);
- const openModal = () => {
- setIsOpen(true);
- };
+ const openModal = () => {
+ setIsOpen(true);
+ };
- const closeModal = () => {
- setIsOpen(false);
- };
+ const closeModal = () => {
+ setIsOpen(false);
+ };
- useHotkeys(ADD_IMAGEBLOCK_SHORTCUT, () => openModal());
+ useHotkeys(ADD_IMAGEBLOCK_SHORTCUT, () => openModal());
- const {
- register,
- handleSubmit,
- reset,
- setValue,
- formState: { isDirty, isValid },
- } = useForm();
+ const {
+ register,
+ handleSubmit,
+ reset,
+ setValue,
+ formState: { isDirty, isValid },
+ } = useForm();
- const openFileDialog = async () => {
- const selected: any = await open({
- multiple: false,
- filters: [
- {
- name: "Image",
- extensions: ["png", "jpeg", "jpg"],
- },
- ],
- });
+ const openFileDialog = async () => {
+ const selected: any = await open({
+ multiple: false,
+ filters: [
+ {
+ name: 'Image',
+ extensions: ['png', 'jpeg', 'jpg'],
+ },
+ ],
+ });
- if (Array.isArray(selected)) {
- // user selected multiple files
- } else if (selected === null) {
- // user cancelled the selection
- } else {
- const filename = selected.split("/").pop();
- const file = await createBlobFromFile(selected);
- const buf = await file.arrayBuffer();
+ if (Array.isArray(selected)) {
+ // user selected multiple files
+ } else if (selected === null) {
+ // user cancelled the selection
+ } else {
+ const filename = selected.split('/').pop();
+ const file = await createBlobFromFile(selected);
+ const buf = await file.arrayBuffer();
- const res: any = await fetch("https://void.cat/upload?cli=false", {
- method: "POST",
- timeout: 5,
- headers: {
- accept: "*/*",
- "Content-Type": "application/octet-stream",
- "V-Filename": filename,
- "V-Description": "Upload from https://lume.nu",
- "V-Strip-Metadata": "true",
- },
- body: Body.bytes(buf),
- });
+ const res: any = await fetch('https://void.cat/upload?cli=false', {
+ method: 'POST',
+ timeout: 5,
+ headers: {
+ accept: '*/*',
+ 'Content-Type': 'application/octet-stream',
+ 'V-Filename': filename,
+ 'V-Description': 'Upload from https://lume.nu',
+ 'V-Strip-Metadata': 'true',
+ },
+ body: Body.bytes(buf),
+ });
- if (res.ok) {
- const imageURL = `https://void.cat/d/${res.data.file.id}.webp`;
- tags.current = [
- ["url", imageURL],
- ["m", res.data.file.metadata.mimeType],
- ["x", res.data.file.metadata.digest],
- ["size", res.data.file.metadata.size],
- ["magnet", res.data.file.metadata.magnetLink],
- ];
+ if (res.ok) {
+ const imageURL = `https://void.cat/d/${res.data.file.id}.webp`;
+ tags.current = [
+ ['url', imageURL],
+ ['m', res.data.file.metadata.mimeType],
+ ['x', res.data.file.metadata.digest],
+ ['size', res.data.file.metadata.size],
+ ['magnet', res.data.file.metadata.magnetLink],
+ ];
- setImage(imageURL);
- }
- }
- };
+ setImage(imageURL);
+ }
+ }
+ };
- const block = useMutation({
- mutationFn: (data: any) => {
- return createBlock(data.kind, data.title, data.content);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["blocks"] });
- },
- });
+ const block = useMutation({
+ mutationFn: (data: any) => {
+ return createBlock(data.kind, data.title, data.content);
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['blocks'] });
+ },
+ });
- const onSubmit = (data: any) => {
- setLoading(true);
+ const onSubmit = (data: any) => {
+ setLoading(true);
- const signer = new NDKPrivateKeySigner(account.privkey);
- ndk.signer = signer;
+ const signer = new NDKPrivateKeySigner(account.privkey);
+ ndk.signer = signer;
- const event = new NDKEvent(ndk);
- // build event
- event.content = data.title;
- event.kind = 1063;
- event.created_at = dateToUnix();
- event.pubkey = account.pubkey;
- event.tags = tags.current;
+ const event = new NDKEvent(ndk);
+ // build event
+ event.content = data.title;
+ event.kind = 1063;
+ event.created_at = dateToUnix();
+ event.pubkey = account.pubkey;
+ event.tags = tags.current;
- // publish event
- event.publish();
+ // publish event
+ event.publish();
- // mutate
- block.mutate({ kind: 0, title: data.title, content: data.content });
+ // mutate
+ block.mutate({ kind: 0, title: data.title, content: data.content });
- setLoading(false);
- // reset form
- reset();
- // close modal
- closeModal();
- };
+ setLoading(false);
+ // reset form
+ reset();
+ // close modal
+ closeModal();
+ };
- useEffect(() => {
- setValue("content", image);
- }, [setValue, image]);
+ useEffect(() => {
+ setValue('content', image);
+ }, [setValue, image]);
- return (
- <>
-
-
-
-
- >
- );
+ return (
+ <>
+
+
+
+
+ >
+ );
}
diff --git a/src/app/space/components/blocks/feed.tsx b/src/app/space/components/blocks/feed.tsx
index 2d835c0f..c666d4af 100644
--- a/src/app/space/components/blocks/feed.tsx
+++ b/src/app/space/components/blocks/feed.tsx
@@ -1,124 +1,113 @@
-import { getNotesByAuthors, removeBlock } from "@libs/storage";
-import { Note } from "@shared/notes/note";
-import { NoteSkeleton } from "@shared/notes/skeleton";
-import { TitleBar } from "@shared/titleBar";
-import {
- useInfiniteQuery,
- useMutation,
- useQueryClient,
-} from "@tanstack/react-query";
-import { useVirtualizer } from "@tanstack/react-virtual";
-import { useEffect, useRef } from "react";
+import { useInfiniteQuery, useMutation, useQueryClient } from '@tanstack/react-query';
+import { useVirtualizer } from '@tanstack/react-virtual';
+import { useEffect, useRef } from 'react';
+
+import { getNotesByAuthors, removeBlock } from '@libs/storage';
+
+import { Note } from '@shared/notes/note';
+import { NoteSkeleton } from '@shared/notes/skeleton';
+import { TitleBar } from '@shared/titleBar';
const ITEM_PER_PAGE = 10;
export function FeedBlock({ params }: { params: any }) {
- const queryClient = useQueryClient();
- const { status, data, fetchNextPage, hasNextPage, isFetchingNextPage }: any =
- useInfiniteQuery({
- queryKey: ["newsfeed", params.content],
- queryFn: async ({ pageParam = 0 }) => {
- return await getNotesByAuthors(
- params.content,
- ITEM_PER_PAGE,
- pageParam,
- );
- },
- getNextPageParam: (lastPage) => lastPage.nextCursor,
- });
+ const queryClient = useQueryClient();
+ const { status, data, fetchNextPage, hasNextPage, isFetchingNextPage }: any =
+ useInfiniteQuery({
+ queryKey: ['newsfeed', params.content],
+ queryFn: async ({ pageParam = 0 }) => {
+ return await getNotesByAuthors(params.content, ITEM_PER_PAGE, pageParam);
+ },
+ getNextPageParam: (lastPage) => lastPage.nextCursor,
+ });
- const notes = data ? data.pages.flatMap((d: { data: any }) => d.data) : [];
- const parentRef = useRef();
+ const notes = data ? data.pages.flatMap((d: { data: any }) => d.data) : [];
+ const parentRef = useRef();
- const rowVirtualizer = useVirtualizer({
- count: hasNextPage ? notes.length + 1 : notes.length,
- getScrollElement: () => parentRef.current,
- estimateSize: () => 500,
- overscan: 2,
- });
+ const rowVirtualizer = useVirtualizer({
+ count: hasNextPage ? notes.length + 1 : notes.length,
+ getScrollElement: () => parentRef.current,
+ estimateSize: () => 500,
+ overscan: 2,
+ });
- const itemsVirtualizer = rowVirtualizer.getVirtualItems();
+ const itemsVirtualizer = rowVirtualizer.getVirtualItems();
- useEffect(() => {
- const [lastItem] = [...rowVirtualizer.getVirtualItems()].reverse();
+ useEffect(() => {
+ const [lastItem] = [...rowVirtualizer.getVirtualItems()].reverse();
- if (!lastItem) {
- return;
- }
+ if (!lastItem) {
+ return;
+ }
- if (
- lastItem.index >= notes.length - 1 &&
- hasNextPage &&
- !isFetchingNextPage
- ) {
- fetchNextPage();
- }
- }, [notes.length, fetchNextPage, rowVirtualizer.getVirtualItems()]);
+ if (lastItem.index >= notes.length - 1 && hasNextPage && !isFetchingNextPage) {
+ fetchNextPage();
+ }
+ }, [notes.length, fetchNextPage, rowVirtualizer.getVirtualItems()]);
- const block = useMutation({
- mutationFn: (id: string) => {
- return removeBlock(id);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["blocks"] });
- },
- });
+ const block = useMutation({
+ mutationFn: (id: string) => {
+ return removeBlock(id);
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['blocks'] });
+ },
+ });
- const renderItem = (index: string | number) => {
- const note = notes[index];
+ const renderItem = (index: string | number) => {
+ const note = notes[index];
- if (!note) return;
- return (
-
-
-
- );
- };
+ if (!note) return;
+ return (
+
+
+
+ );
+ };
- return (
-
-
block.mutate(params.id)} />
-
- {status === "loading" ? (
-
- ) : (
-
-
- {rowVirtualizer
- .getVirtualItems()
- .map((virtualRow) => renderItem(virtualRow.index))}
-
-
- )}
- {isFetchingNextPage && (
-
- )}
-
-
- );
+ return (
+
+
block.mutate(params.id)} />
+
+ {status === 'loading' ? (
+
+ ) : (
+
+
+ {rowVirtualizer
+ .getVirtualItems()
+ .map((virtualRow) => renderItem(virtualRow.index))}
+
+
+ )}
+ {isFetchingNextPage && (
+
+ )}
+
+
+ );
}
diff --git a/src/app/space/components/blocks/following.tsx b/src/app/space/components/blocks/following.tsx
index 1e81d4c4..0c6270ae 100644
--- a/src/app/space/components/blocks/following.tsx
+++ b/src/app/space/components/blocks/following.tsx
@@ -1,140 +1,133 @@
-import { useNewsfeed } from "@app/space/hooks/useNewsfeed";
-import { getNotes } from "@libs/storage";
-import { Note } from "@shared/notes/note";
-import { NoteSkeleton } from "@shared/notes/skeleton";
-import { TitleBar } from "@shared/titleBar";
-import { useNote } from "@stores/note";
-import { useInfiniteQuery } from "@tanstack/react-query";
-import { useVirtualizer } from "@tanstack/react-virtual";
-import { useEffect, useRef } from "react";
+import { useInfiniteQuery } from '@tanstack/react-query';
+import { useVirtualizer } from '@tanstack/react-virtual';
+import { useEffect, useRef } from 'react';
+
+import { useNewsfeed } from '@app/space/hooks/useNewsfeed';
+
+import { getNotes } from '@libs/storage';
+
+import { Note } from '@shared/notes/note';
+import { NoteSkeleton } from '@shared/notes/skeleton';
+import { TitleBar } from '@shared/titleBar';
+
+import { useNote } from '@stores/note';
const ITEM_PER_PAGE = 10;
export function FollowingBlock({ block }: { block: number }) {
- // subscribe for live update
- useNewsfeed();
- const [hasNewNote, toggleHasNewNote] = useNote((state) => [
- state.hasNewNote,
- state.toggleHasNewNote,
- ]);
+ // subscribe for live update
+ useNewsfeed();
+ const [hasNewNote, toggleHasNewNote] = useNote((state) => [
+ state.hasNewNote,
+ state.toggleHasNewNote,
+ ]);
- const {
- status,
- data,
- fetchNextPage,
- hasNextPage,
- isFetchingNextPage,
- refetch,
- }: any = useInfiniteQuery({
- queryKey: ["newsfeed-circle"],
- queryFn: async ({ pageParam = 0 }) => {
- return await getNotes(ITEM_PER_PAGE, pageParam);
- },
- getNextPageParam: (lastPage) => lastPage.nextCursor,
- });
+ const { status, data, fetchNextPage, hasNextPage, isFetchingNextPage, refetch }: any =
+ useInfiniteQuery({
+ queryKey: ['newsfeed-circle'],
+ queryFn: async ({ pageParam = 0 }) => {
+ return await getNotes(ITEM_PER_PAGE, pageParam);
+ },
+ getNextPageParam: (lastPage) => lastPage.nextCursor,
+ });
- const notes = data ? data.pages.flatMap((d: { data: any }) => d.data) : [];
- const parentRef = useRef();
+ const notes = data ? data.pages.flatMap((d: { data: any }) => d.data) : [];
+ const parentRef = useRef();
- const rowVirtualizer = useVirtualizer({
- count: hasNextPage ? notes.length + 1 : notes.length,
- getScrollElement: () => parentRef.current,
- estimateSize: () => 500,
- overscan: 2,
- });
+ const rowVirtualizer = useVirtualizer({
+ count: hasNextPage ? notes.length + 1 : notes.length,
+ getScrollElement: () => parentRef.current,
+ estimateSize: () => 500,
+ overscan: 2,
+ });
- const itemsVirtualizer = rowVirtualizer.getVirtualItems();
+ const itemsVirtualizer = rowVirtualizer.getVirtualItems();
- useEffect(() => {
- const [lastItem] = [...rowVirtualizer.getVirtualItems()].reverse();
+ useEffect(() => {
+ const [lastItem] = [...rowVirtualizer.getVirtualItems()].reverse();
- if (!lastItem) {
- return;
- }
+ if (!lastItem) {
+ return;
+ }
- if (
- lastItem.index >= notes.length - 1 &&
- hasNextPage &&
- !isFetchingNextPage
- ) {
- fetchNextPage();
- }
- }, [notes.length, fetchNextPage, rowVirtualizer.getVirtualItems()]);
+ if (lastItem.index >= notes.length - 1 && hasNextPage && !isFetchingNextPage) {
+ fetchNextPage();
+ }
+ }, [notes.length, fetchNextPage, rowVirtualizer.getVirtualItems()]);
- const refreshFirstPage = () => {
- // refetch
- refetch({ refetchPage: (_, index: number) => index === 0 });
- // scroll to top
- rowVirtualizer.scrollToIndex(1);
- // stop notify
- toggleHasNewNote(false);
- };
+ const refreshFirstPage = () => {
+ // refetch
+ refetch({ refetchPage: (_, index: number) => index === 0 });
+ // scroll to top
+ rowVirtualizer.scrollToIndex(1);
+ // stop notify
+ toggleHasNewNote(false);
+ };
- const renderItem = (index: string | number) => {
- const note = notes[index];
- if (!note) return;
- return (
-
-
-
- );
- };
+ const renderItem = (index: string | number) => {
+ const note = notes[index];
+ if (!note) return;
+ return (
+
+
+
+ );
+ };
- return (
-
-
- {hasNewNote && (
-
-
-
- )}
-
- {status === "loading" ? (
-
- ) : (
-
-
- {rowVirtualizer
- .getVirtualItems()
- .map((virtualRow) => renderItem(virtualRow.index))}
-
-
- )}
- {isFetchingNextPage && (
-
- )}
-
-
- );
+ return (
+
+
+ {hasNewNote && (
+
+
+
+ )}
+
+ {status === 'loading' ? (
+
+ ) : (
+
+
+ {rowVirtualizer
+ .getVirtualItems()
+ .map((virtualRow) => renderItem(virtualRow.index))}
+
+
+ )}
+ {isFetchingNextPage && (
+
+ )}
+
+
+ );
}
diff --git a/src/app/space/components/blocks/image.tsx b/src/app/space/components/blocks/image.tsx
index 4a688d67..05202221 100644
--- a/src/app/space/components/blocks/image.tsx
+++ b/src/app/space/components/blocks/image.tsx
@@ -1,45 +1,46 @@
-import { removeBlock } from "@libs/storage";
-import { CancelIcon } from "@shared/icons";
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useMutation, useQueryClient } from "@tanstack/react-query";
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+
+import { removeBlock } from '@libs/storage';
+
+import { CancelIcon } from '@shared/icons';
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
export function ImageBlock({ params }: { params: any }) {
- const queryClient = useQueryClient();
+ const queryClient = useQueryClient();
- const block = useMutation({
- mutationFn: (id: string) => {
- return removeBlock(id);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["blocks"] });
- },
- });
+ const block = useMutation({
+ mutationFn: (id: string) => {
+ return removeBlock(id);
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['blocks'] });
+ },
+ });
- return (
-
-
-
-
-
- {params.title}
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
{params.title}
+
+
+
+
+
+
+ );
}
diff --git a/src/app/space/components/blocks/thread.tsx b/src/app/space/components/blocks/thread.tsx
index a7cf18c4..f5440db2 100644
--- a/src/app/space/components/blocks/thread.tsx
+++ b/src/app/space/components/blocks/thread.tsx
@@ -1,75 +1,76 @@
-import { useLiveThread } from "@app/space/hooks/useLiveThread";
-import { getNoteByID, removeBlock } from "@libs/storage";
-import { Kind1 } from "@shared/notes/contents/kind1";
-import { Kind1063 } from "@shared/notes/contents/kind1063";
-import { NoteMetadata } from "@shared/notes/metadata";
-import { NoteReplyForm } from "@shared/notes/replies/form";
-import { RepliesList } from "@shared/notes/replies/list";
-import { NoteSkeleton } from "@shared/notes/skeleton";
-import { TitleBar } from "@shared/titleBar";
-import { User } from "@shared/user";
-import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
-import { useAccount } from "@utils/hooks/useAccount";
-import { parser } from "@utils/parser";
+import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
+
+import { useLiveThread } from '@app/space/hooks/useLiveThread';
+
+import { getNoteByID, removeBlock } from '@libs/storage';
+
+import { Kind1 } from '@shared/notes/contents/kind1';
+import { Kind1063 } from '@shared/notes/contents/kind1063';
+import { NoteMetadata } from '@shared/notes/metadata';
+import { NoteReplyForm } from '@shared/notes/replies/form';
+import { RepliesList } from '@shared/notes/replies/list';
+import { NoteSkeleton } from '@shared/notes/skeleton';
+import { TitleBar } from '@shared/titleBar';
+import { User } from '@shared/user';
+
+import { useAccount } from '@utils/hooks/useAccount';
+import { parser } from '@utils/parser';
export function ThreadBlock({ params }: { params: any }) {
- useLiveThread(params.content);
+ useLiveThread(params.content);
- const queryClient = useQueryClient();
+ const queryClient = useQueryClient();
- const { account } = useAccount();
- const { status, data } = useQuery(["thread", params.content], async () => {
- const res = await getNoteByID(params.content);
- res["content"] = parser(res);
- return res;
- });
+ const { account } = useAccount();
+ const { status, data } = useQuery(['thread', params.content], async () => {
+ const res = await getNoteByID(params.content);
+ res['content'] = parser(res);
+ return res;
+ });
- const block = useMutation({
- mutationFn: (id: string) => {
- return removeBlock(id);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["blocks"] });
- },
- });
+ const block = useMutation({
+ mutationFn: (id: string) => {
+ return removeBlock(id);
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['blocks'] });
+ },
+ });
- return (
-
-
block.mutate(params.id)} />
-
- {status === "loading" ? (
-
- ) : (
-
-
-
-
- {data.kind === 1 && }
- {data.kind === 1063 && }
-
-
-
-
- {account && (
-
- )}
-
-
- )}
-
-
-
-
-
- );
+ return (
+
+
block.mutate(params.id)} />
+
+ {status === 'loading' ? (
+
+ ) : (
+
+
+
+
+ {data.kind === 1 && }
+ {data.kind === 1063 && }
+
+
+
+
+ {account && (
+
+ )}
+
+
+ )}
+
+
+
+
+
+ );
}
diff --git a/src/app/space/hooks/useLiveThread.tsx b/src/app/space/hooks/useLiveThread.tsx
index 9374cf1e..fbdd7f18 100644
--- a/src/app/space/hooks/useLiveThread.tsx
+++ b/src/app/space/hooks/useLiveThread.tsx
@@ -1,46 +1,48 @@
-import { createReplyNote } from "@libs/storage";
-import { NDKEvent, NDKFilter } from "@nostr-dev-kit/ndk";
-import { RelayContext } from "@shared/relayProvider";
-import { useMutation, useQueryClient } from "@tanstack/react-query";
-import { useContext, useEffect, useRef } from "react";
+import { NDKEvent, NDKFilter } from '@nostr-dev-kit/ndk';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { useContext, useEffect, useRef } from 'react';
+
+import { createReplyNote } from '@libs/storage';
+
+import { RelayContext } from '@shared/relayProvider';
export function useLiveThread(id: string) {
- const ndk = useContext(RelayContext);
- const queryClient = useQueryClient();
- const now = useRef(Math.floor(Date.now() / 1000));
+ const ndk = useContext(RelayContext);
+ const queryClient = useQueryClient();
+ const now = useRef(Math.floor(Date.now() / 1000));
- const thread = useMutation({
- mutationFn: (data: NDKEvent) => {
- return createReplyNote(
- id,
- data.id,
- data.pubkey,
- data.kind,
- data.tags,
- data.content,
- data.created_at,
- );
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["replies", id] });
- },
- });
+ const thread = useMutation({
+ mutationFn: (data: NDKEvent) => {
+ return createReplyNote(
+ id,
+ data.id,
+ data.pubkey,
+ data.kind,
+ data.tags,
+ data.content,
+ data.created_at
+ );
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['replies', id] });
+ },
+ });
- useEffect(() => {
- const filter: NDKFilter = {
- kinds: [1],
- "#e": [id],
- since: now.current,
- };
+ useEffect(() => {
+ const filter: NDKFilter = {
+ kinds: [1],
+ '#e': [id],
+ since: now.current,
+ };
- const sub = ndk.subscribe(filter, { closeOnEose: false });
+ const sub = ndk.subscribe(filter, { closeOnEose: false });
- sub.addListener("event", (event: NDKEvent) => {
- thread.mutate(event);
- });
+ sub.addListener('event', (event: NDKEvent) => {
+ thread.mutate(event);
+ });
- return () => {
- sub.stop();
- };
- }, []);
+ return () => {
+ sub.stop();
+ };
+ }, []);
}
diff --git a/src/app/space/hooks/useNewsfeed.tsx b/src/app/space/hooks/useNewsfeed.tsx
index 2aa97bc6..fc2b3606 100644
--- a/src/app/space/hooks/useNewsfeed.tsx
+++ b/src/app/space/hooks/useNewsfeed.tsx
@@ -1,48 +1,52 @@
-import { createNote } from "@libs/storage";
-import { NDKEvent, NDKFilter } from "@nostr-dev-kit/ndk";
-import { RelayContext } from "@shared/relayProvider";
-import { useNote } from "@stores/note";
-import { useAccount } from "@utils/hooks/useAccount";
-import { useContext, useEffect, useRef } from "react";
+import { NDKEvent, NDKFilter } from '@nostr-dev-kit/ndk';
+import { useContext, useEffect, useRef } from 'react';
+
+import { createNote } from '@libs/storage';
+
+import { RelayContext } from '@shared/relayProvider';
+
+import { useNote } from '@stores/note';
+
+import { useAccount } from '@utils/hooks/useAccount';
export function useNewsfeed() {
- const ndk = useContext(RelayContext);
- const sub = useRef(null);
- const now = useRef(Math.floor(Date.now() / 1000));
- const toggleHasNewNote = useNote((state) => state.toggleHasNewNote);
+ const ndk = useContext(RelayContext);
+ const sub = useRef(null);
+ const now = useRef(Math.floor(Date.now() / 1000));
+ const toggleHasNewNote = useNote((state) => state.toggleHasNewNote);
- const { status, account } = useAccount();
+ const { status, account } = useAccount();
- useEffect(() => {
- if (status === "success" && account) {
- const follows = account ? JSON.parse(account.follows) : [];
+ useEffect(() => {
+ if (status === 'success' && account) {
+ const follows = account ? JSON.parse(account.follows) : [];
- const filter: NDKFilter = {
- kinds: [1, 6],
- authors: follows,
- since: now.current,
- };
+ const filter: NDKFilter = {
+ kinds: [1, 6],
+ authors: follows,
+ since: now.current,
+ };
- sub.current = ndk.subscribe(filter, { closeOnEose: false });
+ sub.current = ndk.subscribe(filter, { closeOnEose: false });
- sub.current.addListener("event", (event: NDKEvent) => {
- console.log("new note: ", event);
- // add to db
- createNote(
- event.id,
- event.pubkey,
- event.kind,
- event.tags,
- event.content,
- event.created_at,
- );
- // notify user about created note
- toggleHasNewNote(true);
- });
- }
+ sub.current.addListener('event', (event: NDKEvent) => {
+ console.log('new note: ', event);
+ // add to db
+ createNote(
+ event.id,
+ event.pubkey,
+ event.kind,
+ event.tags,
+ event.content,
+ event.created_at
+ );
+ // notify user about created note
+ toggleHasNewNote(true);
+ });
+ }
- return () => {
- sub.current.stop();
- };
- }, [status]);
+ return () => {
+ sub.current.stop();
+ };
+ }, [status]);
}
diff --git a/src/app/space/index.tsx b/src/app/space/index.tsx
index 6f60c46d..519513ca 100644
--- a/src/app/space/index.tsx
+++ b/src/app/space/index.tsx
@@ -1,76 +1,79 @@
-import { AddBlock } from "@app/space/components/add";
-import { FeedBlock } from "@app/space/components/blocks/feed";
-import { FollowingBlock } from "@app/space/components/blocks/following";
-import { ImageBlock } from "@app/space/components/blocks/image";
-import { ThreadBlock } from "@app/space/components/blocks/thread";
-import { getBlocks } from "@libs/storage";
-import { LoaderIcon } from "@shared/icons";
-import { useQuery } from "@tanstack/react-query";
+import { useQuery } from '@tanstack/react-query';
+
+import { AddBlock } from '@app/space/components/add';
+import { FeedBlock } from '@app/space/components/blocks/feed';
+import { FollowingBlock } from '@app/space/components/blocks/following';
+import { ImageBlock } from '@app/space/components/blocks/image';
+import { ThreadBlock } from '@app/space/components/blocks/thread';
+
+import { getBlocks } from '@libs/storage';
+
+import { LoaderIcon } from '@shared/icons';
export function SpaceScreen() {
- const {
- status,
- data: blocks,
- isFetching,
- } = useQuery(
- ["blocks"],
- async () => {
- return await getBlocks();
- },
- {
- staleTime: Infinity,
- refetchOnMount: false,
- refetchOnReconnect: false,
- refetchOnWindowFocus: false,
- },
- );
+ const {
+ status,
+ data: blocks,
+ isFetching,
+ } = useQuery(
+ ['blocks'],
+ async () => {
+ return await getBlocks();
+ },
+ {
+ staleTime: Infinity,
+ refetchOnMount: false,
+ refetchOnReconnect: false,
+ refetchOnWindowFocus: false,
+ }
+ );
- return (
-
-
- {status === "loading" ? (
-
-
+ return (
+
+
+ {status === 'loading' ? (
+
- ) : (
- blocks.map((block: any) => {
- switch (block.kind) {
- case 0:
- return
;
- case 1:
- return
;
- case 2:
- return
;
- default:
- break;
- }
- })
- )}
- {isFetching && (
-
+ ) : (
+ blocks.map((block: any) => {
+ switch (block.kind) {
+ case 0:
+ return
;
+ case 1:
+ return
;
+ case 2:
+ return
;
+ default:
+ break;
+ }
+ })
+ )}
+ {isFetching && (
+
- )}
-
-
-
- );
+
+
+
+
+ )}
+
+
+
+ );
}
diff --git a/src/app/trending/components/profile.tsx b/src/app/trending/components/profile.tsx
index 69f89de6..d5f9da25 100644
--- a/src/app/trending/components/profile.tsx
+++ b/src/app/trending/components/profile.tsx
@@ -1,152 +1,144 @@
-import { FollowIcon, LoaderIcon, UnfollowIcon } from "@shared/icons";
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useQuery } from "@tanstack/react-query";
-import { useSocial } from "@utils/hooks/useSocial";
-import { compactNumber } from "@utils/number";
-import { shortenKey } from "@utils/shortenKey";
-import { useEffect, useState } from "react";
+import { useQuery } from '@tanstack/react-query';
+import { useEffect, useState } from 'react';
+
+import { FollowIcon, LoaderIcon, UnfollowIcon } from '@shared/icons';
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+
+import { useSocial } from '@utils/hooks/useSocial';
+import { compactNumber } from '@utils/number';
+import { shortenKey } from '@utils/shortenKey';
export function Profile({ data }: { data: any }) {
- const { status, data: userStats } = useQuery(
- ["user-stats", data.pubkey],
- async () => {
- const res = await fetch(
- `https://api.nostr.band/v0/stats/profile/${data.pubkey}`,
- );
- return res.json();
- },
- );
+ const { status, data: userStats } = useQuery(['user-stats', data.pubkey], async () => {
+ const res = await fetch(`https://api.nostr.band/v0/stats/profile/${data.pubkey}`);
+ return res.json();
+ });
- const embedProfile = data.profile ? JSON.parse(data.profile.content) : null;
- const profile = embedProfile;
- const { status: socialStatus, userFollows, follow, unfollow } = useSocial();
+ const embedProfile = data.profile ? JSON.parse(data.profile.content) : null;
+ const profile = embedProfile;
+ const { status: socialStatus, userFollows, follow, unfollow } = useSocial();
- const [followed, setFollowed] = useState(false);
+ const [followed, setFollowed] = useState(false);
- const followUser = (pubkey: string) => {
- try {
- follow(pubkey);
- // update state
- setFollowed(true);
- } catch (error) {
- console.log(error);
- }
- };
+ const followUser = (pubkey: string) => {
+ try {
+ follow(pubkey);
+ // update state
+ setFollowed(true);
+ } catch (error) {
+ console.log(error);
+ }
+ };
- const unfollowUser = (pubkey: string) => {
- try {
- unfollow(pubkey);
- // update state
- setFollowed(false);
- } catch (error) {
- console.log(error);
- }
- };
+ const unfollowUser = (pubkey: string) => {
+ try {
+ unfollow(pubkey);
+ // update state
+ setFollowed(false);
+ } catch (error) {
+ console.log(error);
+ }
+ };
- useEffect(() => {
- if (status === "success" && userFollows) {
- if (userFollows.includes(data.pubkey)) {
- setFollowed(true);
- }
- }
- }, [status]);
+ useEffect(() => {
+ if (status === 'success' && userFollows) {
+ if (userFollows.includes(data.pubkey)) {
+ setFollowed(true);
+ }
+ }
+ }, [status]);
- if (!profile)
- return (
-
- );
+ if (!profile)
+ return (
+
+ );
- return (
-
-
-
-
-
-
-
-
- {profile.display_name || profile.name}
-
-
- {profile.nip05 || shortenKey(data.pubkey)}
-
-
-
-
- {socialStatus === "loading" ? (
-
- ) : followed ? (
-
- ) : (
-
- )}
-
-
-
-
- {profile.about || profile.bio}
-
-
-
- {status === "loading" ? (
-
Loading...
- ) : (
-
-
-
- {userStats.stats[data.pubkey].followers_pubkey_count ?? 0}
-
-
- Followers
-
-
-
-
- {userStats.stats[data.pubkey].pub_following_pubkey_count ?? 0}
-
-
- Following
-
-
-
-
- {userStats.stats[data.pubkey].zaps_received
- ? compactNumber.format(
- userStats.stats[data.pubkey].zaps_received.msats / 1000,
- )
- : 0}
-
-
- Zaps received
-
-
-
- )}
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+ {profile.display_name || profile.name}
+
+
+ {profile.nip05 || shortenKey(data.pubkey)}
+
+
+
+
+ {socialStatus === 'loading' ? (
+
+ ) : followed ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ {profile.about || profile.bio}
+
+
+
+ {status === 'loading' ? (
+
Loading...
+ ) : (
+
+
+
+ {userStats.stats[data.pubkey].followers_pubkey_count ?? 0}
+
+ Followers
+
+
+
+ {userStats.stats[data.pubkey].pub_following_pubkey_count ?? 0}
+
+ Following
+
+
+
+ {userStats.stats[data.pubkey].zaps_received
+ ? compactNumber.format(
+ userStats.stats[data.pubkey].zaps_received.msats / 1000
+ )
+ : 0}
+
+ Zaps received
+
+
+ )}
+
+
+ );
}
diff --git a/src/app/trending/components/trendingNotes.tsx b/src/app/trending/components/trendingNotes.tsx
index 2f31c7fe..89345bec 100644
--- a/src/app/trending/components/trendingNotes.tsx
+++ b/src/app/trending/components/trendingNotes.tsx
@@ -1,36 +1,37 @@
-import { Note } from "@shared/notes/note";
-import { NoteSkeleton } from "@shared/notes/skeleton";
-import { TitleBar } from "@shared/titleBar";
-import { useQuery } from "@tanstack/react-query";
+import { useQuery } from '@tanstack/react-query';
+
+import { Note } from '@shared/notes/note';
+import { NoteSkeleton } from '@shared/notes/skeleton';
+import { TitleBar } from '@shared/titleBar';
export function TrendingNotes() {
- const { status, data, error } = useQuery(["trending-notes"], async () => {
- const res = await fetch("https://api.nostr.band/v0/trending/notes");
- if (!res.ok) {
- throw new Error("Error");
- }
- return res.json();
- });
+ const { status, data, error } = useQuery(['trending-notes'], async () => {
+ const res = await fetch('https://api.nostr.band/v0/trending/notes');
+ if (!res.ok) {
+ throw new Error('Error');
+ }
+ return res.json();
+ });
- return (
-
-
-
- {error &&
Failed to fetch
}
- {status === "loading" ? (
-
- ) : (
-
- {data.notes.map((item) => (
-
- ))}
-
- )}
-
-
- );
+ return (
+
+
+
+ {error &&
Failed to fetch
}
+ {status === 'loading' ? (
+
+ ) : (
+
+ {data.notes.map((item) => (
+
+ ))}
+
+ )}
+
+
+ );
}
diff --git a/src/app/trending/components/trendingProfiles.tsx b/src/app/trending/components/trendingProfiles.tsx
index 50365513..f66f8307 100644
--- a/src/app/trending/components/trendingProfiles.tsx
+++ b/src/app/trending/components/trendingProfiles.tsx
@@ -1,36 +1,38 @@
-import { Profile } from "@app/trending/components/profile";
-import { NoteSkeleton } from "@shared/notes/skeleton";
-import { TitleBar } from "@shared/titleBar";
-import { useQuery } from "@tanstack/react-query";
+import { useQuery } from '@tanstack/react-query';
+
+import { Profile } from '@app/trending/components/profile';
+
+import { NoteSkeleton } from '@shared/notes/skeleton';
+import { TitleBar } from '@shared/titleBar';
export function TrendingProfiles() {
- const { status, data, error } = useQuery(["trending-profiles"], async () => {
- const res = await fetch("https://api.nostr.band/v0/trending/profiles");
- if (!res.ok) {
- throw new Error("Error");
- }
- return res.json();
- });
+ const { status, data, error } = useQuery(['trending-profiles'], async () => {
+ const res = await fetch('https://api.nostr.band/v0/trending/profiles');
+ if (!res.ok) {
+ throw new Error('Error');
+ }
+ return res.json();
+ });
- return (
-
-
-
- {error &&
Failed to fetch
}
- {status === "loading" ? (
-
- ) : (
-
- {data.profiles.map((item) => (
-
- ))}
-
- )}
-
-
- );
+ return (
+
+
+
+ {error &&
Failed to fetch
}
+ {status === 'loading' ? (
+
+ ) : (
+
+ {data.profiles.map((item) => (
+
+ ))}
+
+ )}
+
+
+ );
}
diff --git a/src/app/trending/index.tsx b/src/app/trending/index.tsx
index 2fb43f8e..284e9ea6 100644
--- a/src/app/trending/index.tsx
+++ b/src/app/trending/index.tsx
@@ -1,11 +1,11 @@
-import { TrendingNotes } from "@app/trending/components/trendingNotes";
-import { TrendingProfiles } from "@app/trending/components/trendingProfiles";
+import { TrendingNotes } from '@app/trending/components/trendingNotes';
+import { TrendingProfiles } from '@app/trending/components/trendingProfiles';
export function TrendingScreen() {
- return (
-
-
-
-
- );
+ return (
+
+
+
+
+ );
}
diff --git a/src/app/user/components/feed.tsx b/src/app/user/components/feed.tsx
index 16b2e30f..38ab6696 100644
--- a/src/app/user/components/feed.tsx
+++ b/src/app/user/components/feed.tsx
@@ -1,33 +1,35 @@
-import { NDKFilter } from "@nostr-dev-kit/ndk";
-import { Note } from "@shared/notes/note";
-import { RelayContext } from "@shared/relayProvider";
-import { useQuery } from "@tanstack/react-query";
-import { dateToUnix, getHourAgo } from "@utils/date";
-import { LumeEvent } from "@utils/types";
-import { useContext } from "react";
+import { NDKFilter } from '@nostr-dev-kit/ndk';
+import { useQuery } from '@tanstack/react-query';
+import { useContext } from 'react';
+
+import { Note } from '@shared/notes/note';
+import { RelayContext } from '@shared/relayProvider';
+
+import { dateToUnix, getHourAgo } from '@utils/date';
+import { LumeEvent } from '@utils/types';
export function UserFeed({ pubkey }: { pubkey: string }) {
- const ndk = useContext(RelayContext);
- const { status, data } = useQuery(["user-feed", pubkey], async () => {
- const now = new Date();
- const filter: NDKFilter = {
- kinds: [1],
- authors: [pubkey],
- since: dateToUnix(getHourAgo(48, now)),
- };
- const events = await ndk.fetchEvents(filter);
- return [...events];
- });
+ const ndk = useContext(RelayContext);
+ const { status, data } = useQuery(['user-feed', pubkey], async () => {
+ const now = new Date();
+ const filter: NDKFilter = {
+ kinds: [1],
+ authors: [pubkey],
+ since: dateToUnix(getHourAgo(48, now)),
+ };
+ const events = await ndk.fetchEvents(filter);
+ return [...events];
+ });
- return (
-
- {status === "loading" ? (
-
- ) : (
- data.map((note: LumeEvent) =>
)
- )}
-
- );
+ return (
+
+ {status === 'loading' ? (
+
+ ) : (
+ data.map((note: LumeEvent) =>
)
+ )}
+
+ );
}
diff --git a/src/app/user/components/metadata.tsx b/src/app/user/components/metadata.tsx
index e737fc8c..25e0a435 100644
--- a/src/app/user/components/metadata.tsx
+++ b/src/app/user/components/metadata.tsx
@@ -1,55 +1,50 @@
-import { useQuery } from "@tanstack/react-query";
-import { compactNumber } from "@utils/number";
+import { useQuery } from '@tanstack/react-query';
+
+import { compactNumber } from '@utils/number';
export function UserMetadata({ pubkey }: { pubkey: string }) {
- const { status, data } = useQuery(["user-metadata", pubkey], async () => {
- const res = await fetch(
- `https://api.nostr.band/v0/stats/profile/${pubkey}`,
- );
- if (!res.ok) {
- throw new Error("Error");
- }
- return await res.json();
- });
+ const { status, data } = useQuery(['user-metadata', pubkey], async () => {
+ const res = await fetch(`https://api.nostr.band/v0/stats/profile/${pubkey}`);
+ if (!res.ok) {
+ throw new Error('Error');
+ }
+ return await res.json();
+ });
- if (status === "loading") {
- return Loading...
;
- }
+ if (status === 'loading') {
+ return Loading...
;
+ }
- return (
-
-
-
- {data.stats[pubkey].followers_pubkey_count ?? 0}
-
- Followers
-
-
-
- {data.stats[pubkey].pub_following_pubkey_count ?? 0}
-
- Following
-
-
-
- {data.stats[pubkey].zaps_received
- ? compactNumber.format(
- data.stats[pubkey].zaps_received.msats / 1000,
- )
- : 0}
-
-
- Zaps received
-
-
-
-
- {data.stats[pubkey].zaps_sent
- ? compactNumber.format(data.stats[pubkey].zaps_sent.msats / 1000)
- : 0}
-
- Zaps sent
-
-
- );
+ return (
+
+
+
+ {data.stats[pubkey].followers_pubkey_count ?? 0}
+
+ Followers
+
+
+
+ {data.stats[pubkey].pub_following_pubkey_count ?? 0}
+
+ Following
+
+
+
+ {data.stats[pubkey].zaps_received
+ ? compactNumber.format(data.stats[pubkey].zaps_received.msats / 1000)
+ : 0}
+
+ Zaps received
+
+
+
+ {data.stats[pubkey].zaps_sent
+ ? compactNumber.format(data.stats[pubkey].zaps_sent.msats / 1000)
+ : 0}
+
+ Zaps sent
+
+
+ );
}
diff --git a/src/app/user/index.tsx b/src/app/user/index.tsx
index 66fdb1b1..0548a719 100644
--- a/src/app/user/index.tsx
+++ b/src/app/user/index.tsx
@@ -1,163 +1,167 @@
-import { UserFeed } from "@app/user/components/feed";
-import { UserMetadata } from "@app/user/components/metadata";
-import { Tab } from "@headlessui/react";
-import { EditProfileModal } from "@shared/editProfileModal";
-import { ThreadsIcon, ZapIcon } from "@shared/icons";
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useAccount } from "@utils/hooks/useAccount";
-import { useProfile } from "@utils/hooks/useProfile";
-import { useSocial } from "@utils/hooks/useSocial";
-import { shortenKey } from "@utils/shortenKey";
-import { Fragment, useEffect, useState } from "react";
-import { Link, useParams } from "react-router-dom";
+import { Tab } from '@headlessui/react';
+import { Fragment, useEffect, useState } from 'react';
+import { Link, useParams } from 'react-router-dom';
+
+import { UserFeed } from '@app/user/components/feed';
+import { UserMetadata } from '@app/user/components/metadata';
+
+import { EditProfileModal } from '@shared/editProfileModal';
+import { ThreadsIcon, ZapIcon } from '@shared/icons';
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+
+import { useAccount } from '@utils/hooks/useAccount';
+import { useProfile } from '@utils/hooks/useProfile';
+import { useSocial } from '@utils/hooks/useSocial';
+import { shortenKey } from '@utils/shortenKey';
export function UserScreen() {
- const { pubkey } = useParams();
- const { user } = useProfile(pubkey);
- const { account } = useAccount();
- const { status, userFollows, follow, unfollow } = useSocial();
+ const { pubkey } = useParams();
+ const { user } = useProfile(pubkey);
+ const { account } = useAccount();
+ const { status, userFollows, follow, unfollow } = useSocial();
- const [followed, setFollowed] = useState(false);
+ const [followed, setFollowed] = useState(false);
- const followUser = (pubkey: string) => {
- try {
- follow(pubkey);
+ const followUser = (pubkey: string) => {
+ try {
+ follow(pubkey);
- // update state
- setFollowed(true);
- } catch (error) {
- console.log(error);
- }
- };
+ // update state
+ setFollowed(true);
+ } catch (error) {
+ console.log(error);
+ }
+ };
- const unfollowUser = (pubkey: string) => {
- try {
- unfollow(pubkey);
+ const unfollowUser = (pubkey: string) => {
+ try {
+ unfollow(pubkey);
- // update state
- setFollowed(false);
- } catch (error) {
- console.log(error);
- }
- };
+ // update state
+ setFollowed(false);
+ } catch (error) {
+ console.log(error);
+ }
+ };
- useEffect(() => {
- if (status === "success" && userFollows) {
- if (userFollows.includes(pubkey)) {
- setFollowed(true);
- }
- }
- }, [status]);
+ useEffect(() => {
+ if (status === 'success' && userFollows) {
+ if (userFollows.includes(pubkey)) {
+ setFollowed(true);
+ }
+ }
+ }, [status]);
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- {user?.displayName || user?.name || "No name"}
-
-
- {user?.nip05 || shortenKey(pubkey)}
-
-
-
- {status === "loading" ? (
-
- ) : followed ? (
-
- ) : (
-
- )}
-
- Message
-
-
-
- {account && account.pubkey === pubkey && }
-
-
-
-
-
-
-
-
-
- {({ selected }) => (
-
- )}
-
-
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ {user?.displayName || user?.name || 'No name'}
+
+
+ {user?.nip05 || shortenKey(pubkey)}
+
+
+
+ {status === 'loading' ? (
+
+ ) : followed ? (
+
+ ) : (
+
+ )}
+
+ Message
+
+
+
+ {account && account.pubkey === pubkey && }
+
+
+
+
+
+
+
+
+
+ {({ selected }) => (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+ );
}
diff --git a/src/index.css b/src/index.css
index 16e574e0..72148ca3 100644
--- a/src/index.css
+++ b/src/index.css
@@ -15,7 +15,7 @@ button {
}
.markdown {
- @apply prose prose-zinc max-w-none select-text break-words dark:prose-invert prose-p:mt-0 prose-p:mb-2 prose-p:last:mb-0 prose-p:leading-tight prose-a:font-normal prose-a:leading-tight prose-a:text-fuchsia-500 hover:prose-a:text-fuchsia-600 prose-ol:mb-1 prose-ul:mb-1 prose-li:leading-tight prose-blockquote:m-0 prose-ol:m-0 prose-hr:mx-0 prose-hr:my-2;
+ @apply prose prose-zinc max-w-none select-text break-words dark:prose-invert prose-p:mb-2 prose-p:mt-0 prose-p:leading-tight prose-p:last:mb-0 prose-a:font-normal prose-a:leading-tight prose-a:text-fuchsia-500 hover:prose-a:text-fuchsia-600 prose-blockquote:m-0 prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-li:leading-tight prose-hr:mx-0 prose-hr:my-2;
}
/* For Webkit-based browsers (Chrome, Safari and Opera) */
diff --git a/src/libs/ndk.tsx b/src/libs/ndk.tsx
index 5eed4ac6..2a272f08 100644
--- a/src/libs/ndk.tsx
+++ b/src/libs/ndk.tsx
@@ -1,76 +1,79 @@
import NDK, {
- NDKConstructorParams,
- NDKEvent,
- NDKFilter,
- NDKKind,
- NDKPrivateKeySigner,
-} from "@nostr-dev-kit/ndk";
-import { RelayContext } from "@shared/relayProvider";
-import { FULL_RELAYS } from "@stores/constants";
-import { useAccount } from "@utils/hooks/useAccount";
-import { useContext } from "react";
+ NDKConstructorParams,
+ NDKEvent,
+ NDKFilter,
+ NDKKind,
+ NDKPrivateKeySigner,
+} from '@nostr-dev-kit/ndk';
+import { useContext } from 'react';
+
+import { RelayContext } from '@shared/relayProvider';
+
+import { FULL_RELAYS } from '@stores/constants';
+
+import { useAccount } from '@utils/hooks/useAccount';
export async function initNDK(relays?: string[]): Promise {
- const opts: NDKConstructorParams = {};
- const defaultRelays = new Set(relays || FULL_RELAYS);
+ const opts: NDKConstructorParams = {};
+ const defaultRelays = new Set(relays || FULL_RELAYS);
- opts.explicitRelayUrls = [...defaultRelays];
+ opts.explicitRelayUrls = [...defaultRelays];
- const ndk = new NDK(opts);
- await ndk.connect(500);
+ const ndk = new NDK(opts);
+ await ndk.connect(500);
- return ndk;
+ return ndk;
}
export async function prefetchEvents(
- ndk: NDK,
- filter: NDKFilter,
+ ndk: NDK,
+ filter: NDKFilter
): Promise> {
- return new Promise((resolve) => {
- const events: Map = new Map();
+ return new Promise((resolve) => {
+ const events: Map = new Map();
- const relaySetSubscription = ndk.subscribe(filter, {
- closeOnEose: true,
- });
+ const relaySetSubscription = ndk.subscribe(filter, {
+ closeOnEose: true,
+ });
- relaySetSubscription.on("event", (event: NDKEvent) => {
- event.ndk = ndk;
- events.set(event.tagId(), event);
- });
+ relaySetSubscription.on('event', (event: NDKEvent) => {
+ event.ndk = ndk;
+ events.set(event.tagId(), event);
+ });
- relaySetSubscription.on("eose", () => {
- setTimeout(() => resolve(new Set(events.values())), 3000);
- });
- });
+ relaySetSubscription.on('eose', () => {
+ setTimeout(() => resolve(new Set(events.values())), 3000);
+ });
+ });
}
export function usePublish() {
- const ndk = useContext(RelayContext);
- const { account } = useAccount();
+ const ndk = useContext(RelayContext);
+ const { account } = useAccount();
- const publish = async ({
- content,
- kind,
- tags,
- }: {
- content: string;
- kind: NDKKind;
- tags: string[][];
- }): Promise => {
- const event = new NDKEvent(ndk);
- const signer = new NDKPrivateKeySigner(account.privkey);
+ const publish = async ({
+ content,
+ kind,
+ tags,
+ }: {
+ content: string;
+ kind: NDKKind;
+ tags: string[][];
+ }): Promise => {
+ const event = new NDKEvent(ndk);
+ const signer = new NDKPrivateKeySigner(account.privkey);
- event.content = content;
- event.kind = kind;
- event.created_at = Math.floor(Date.now() / 1000);
- event.pubkey = account.pubkey;
- event.tags = tags;
+ event.content = content;
+ event.kind = kind;
+ event.created_at = Math.floor(Date.now() / 1000);
+ event.pubkey = account.pubkey;
+ event.tags = tags;
- await event.sign(signer);
- await event.publish();
+ await event.sign(signer);
+ await event.publish();
- return event;
- };
+ return event;
+ };
- return publish;
+ return publish;
}
diff --git a/src/libs/openGraph.tsx b/src/libs/openGraph.tsx
index 83c9b3f4..528db73e 100644
--- a/src/libs/openGraph.tsx
+++ b/src/libs/openGraph.tsx
@@ -1,360 +1,349 @@
-import { OPENGRAPH } from "@stores/constants";
-import { FetchOptions, ResponseType, fetch } from "@tauri-apps/api/http";
-import * as cheerio from "cheerio";
+import { FetchOptions, ResponseType, fetch } from '@tauri-apps/api/http';
+import * as cheerio from 'cheerio';
+
+import { OPENGRAPH } from '@stores/constants';
interface ILinkPreviewOptions {
- headers?: Record;
- imagesPropertyType?: string;
- proxyUrl?: string;
- timeout?: number;
- followRedirects?: `follow` | `error` | `manual`;
- resolveDNSHost?: (url: string) => Promise;
- handleRedirects?: (baseURL: string, forwardedURL: string) => boolean;
+ headers?: Record;
+ imagesPropertyType?: string;
+ proxyUrl?: string;
+ timeout?: number;
+ followRedirects?: `follow` | `error` | `manual`;
+ resolveDNSHost?: (url: string) => Promise;
+ handleRedirects?: (baseURL: string, forwardedURL: string) => boolean;
}
interface IPreFetchedResource {
- headers: Record;
- status?: number;
- imagesPropertyType?: string;
- proxyUrl?: string;
- url: string;
- data: any;
+ headers: Record;
+ status?: number;
+ imagesPropertyType?: string;
+ proxyUrl?: string;
+ url: string;
+ data: any;
}
function metaTag(doc: cheerio.CheerioAPI, type: string, attr: string) {
- const nodes = doc(`meta[${attr}='${type}']`);
- return nodes.length ? nodes : null;
+ const nodes = doc(`meta[${attr}='${type}']`);
+ return nodes.length ? nodes : null;
}
function metaTagContent(doc: cheerio.CheerioAPI, type: string, attr: string) {
- return doc(`meta[${attr}='${type}']`).attr("content");
+ return doc(`meta[${attr}='${type}']`).attr('content');
}
function getTitle(doc: cheerio.CheerioAPI) {
- let title =
- metaTagContent(doc, "og:title", "property") ||
- metaTagContent(doc, "og:title", "name");
- if (!title) {
- title = doc("title").text();
- }
- return title;
+ let title =
+ metaTagContent(doc, 'og:title', 'property') ||
+ metaTagContent(doc, 'og:title', 'name');
+ if (!title) {
+ title = doc('title').text();
+ }
+ return title;
}
function getSiteName(doc: cheerio.CheerioAPI) {
- const siteName =
- metaTagContent(doc, "og:site_name", "property") ||
- metaTagContent(doc, "og:site_name", "name");
- return siteName;
+ const siteName =
+ metaTagContent(doc, 'og:site_name', 'property') ||
+ metaTagContent(doc, 'og:site_name', 'name');
+ return siteName;
}
function getDescription(doc: cheerio.CheerioAPI) {
- const description =
- metaTagContent(doc, "description", "name") ||
- metaTagContent(doc, "Description", "name") ||
- metaTagContent(doc, "og:description", "property");
- return description;
+ const description =
+ metaTagContent(doc, 'description', 'name') ||
+ metaTagContent(doc, 'Description', 'name') ||
+ metaTagContent(doc, 'og:description', 'property');
+ return description;
}
function getMediaType(doc: cheerio.CheerioAPI) {
- const node = metaTag(doc, "medium", "name");
- if (node) {
- const content = node.attr("content");
- return content === "image" ? "photo" : content;
- }
- return (
- metaTagContent(doc, "og:type", "property") ||
- metaTagContent(doc, "og:type", "name")
- );
+ const node = metaTag(doc, 'medium', 'name');
+ if (node) {
+ const content = node.attr('content');
+ return content === 'image' ? 'photo' : content;
+ }
+ return (
+ metaTagContent(doc, 'og:type', 'property') || metaTagContent(doc, 'og:type', 'name')
+ );
}
function getImages(
- doc: cheerio.CheerioAPI,
- rootUrl: string,
- imagesPropertyType?: string,
+ doc: cheerio.CheerioAPI,
+ rootUrl: string,
+ imagesPropertyType?: string
) {
- let images: string[] = [];
- let nodes: cheerio.Cheerio | null;
- let src: string | undefined;
- let dic: Record = {};
+ let images: string[] = [];
+ let nodes: cheerio.Cheerio | null;
+ let src: string | undefined;
+ let dic: Record = {};
- const imagePropertyType = imagesPropertyType ?? "og";
- nodes =
- metaTag(doc, `${imagePropertyType}:image`, "property") ||
- metaTag(doc, `${imagePropertyType}:image`, "name");
+ const imagePropertyType = imagesPropertyType ?? 'og';
+ nodes =
+ metaTag(doc, `${imagePropertyType}:image`, 'property') ||
+ metaTag(doc, `${imagePropertyType}:image`, 'name');
- if (nodes) {
- nodes.each((_: number, node: cheerio.Element) => {
- if (node.type === "tag") {
- src = node.attribs.content;
- if (src) {
- src = new URL(src, rootUrl).href;
- images.push(src);
- }
- }
- });
- }
+ if (nodes) {
+ nodes.each((_: number, node: cheerio.Element) => {
+ if (node.type === 'tag') {
+ src = node.attribs.content;
+ if (src) {
+ src = new URL(src, rootUrl).href;
+ images.push(src);
+ }
+ }
+ });
+ }
- if (images.length <= 0 && !imagesPropertyType) {
- src = doc("link[rel=image_src]").attr("href");
- if (src) {
- src = new URL(src, rootUrl).href;
- images = [src];
- } else {
- nodes = doc("img");
+ if (images.length <= 0 && !imagesPropertyType) {
+ src = doc('link[rel=image_src]').attr('href');
+ if (src) {
+ src = new URL(src, rootUrl).href;
+ images = [src];
+ } else {
+ nodes = doc('img');
- if (nodes?.length) {
- dic = {};
- images = [];
- nodes.each((_: number, node: cheerio.Element) => {
- if (node.type === "tag") src = node.attribs.src;
- if (src && !dic[src]) {
- dic[src] = true;
- // width = node.attribs.width;
- // height = node.attribs.height;
- images.push(new URL(src, rootUrl).href);
- }
- });
- }
- }
- }
+ if (nodes?.length) {
+ dic = {};
+ images = [];
+ nodes.each((_: number, node: cheerio.Element) => {
+ if (node.type === 'tag') src = node.attribs.src;
+ if (src && !dic[src]) {
+ dic[src] = true;
+ // width = node.attribs.width;
+ // height = node.attribs.height;
+ images.push(new URL(src, rootUrl).href);
+ }
+ });
+ }
+ }
+ }
- return images;
+ return images;
}
function getVideos(doc: cheerio.CheerioAPI) {
- const videos = [];
- let nodeTypes;
- let nodeSecureUrls;
- let nodeType;
- let nodeSecureUrl;
- let video;
- let videoType;
- let videoSecureUrl;
- let width;
- let height;
- let videoObj;
- let index;
+ const videos = [];
+ let nodeTypes;
+ let nodeSecureUrls;
+ let nodeType;
+ let nodeSecureUrl;
+ let video;
+ let videoType;
+ let videoSecureUrl;
+ let width;
+ let height;
+ let videoObj;
+ let index;
- const nodes =
- metaTag(doc, "og:video", "property") || metaTag(doc, "og:video", "name");
+ const nodes = metaTag(doc, 'og:video', 'property') || metaTag(doc, 'og:video', 'name');
- if (nodes?.length) {
- nodeTypes =
- metaTag(doc, "og:video:type", "property") ||
- metaTag(doc, "og:video:type", "name");
- nodeSecureUrls =
- metaTag(doc, "og:video:secure_url", "property") ||
- metaTag(doc, "og:video:secure_url", "name");
- width =
- metaTagContent(doc, "og:video:width", "property") ||
- metaTagContent(doc, "og:video:width", "name");
- height =
- metaTagContent(doc, "og:video:height", "property") ||
- metaTagContent(doc, "og:video:height", "name");
+ if (nodes?.length) {
+ nodeTypes =
+ metaTag(doc, 'og:video:type', 'property') || metaTag(doc, 'og:video:type', 'name');
+ nodeSecureUrls =
+ metaTag(doc, 'og:video:secure_url', 'property') ||
+ metaTag(doc, 'og:video:secure_url', 'name');
+ width =
+ metaTagContent(doc, 'og:video:width', 'property') ||
+ metaTagContent(doc, 'og:video:width', 'name');
+ height =
+ metaTagContent(doc, 'og:video:height', 'property') ||
+ metaTagContent(doc, 'og:video:height', 'name');
- for (index = 0; index < nodes.length; index += 1) {
- const node = nodes[index];
- if (node.type === "tag") video = node.attribs.content;
+ for (index = 0; index < nodes.length; index += 1) {
+ const node = nodes[index];
+ if (node.type === 'tag') video = node.attribs.content;
- nodeType = nodeTypes?.[index];
- if (nodeType?.type === "tag") {
- videoType = nodeType ? nodeType.attribs.content : null;
- }
+ nodeType = nodeTypes?.[index];
+ if (nodeType?.type === 'tag') {
+ videoType = nodeType ? nodeType.attribs.content : null;
+ }
- nodeSecureUrl = nodeSecureUrls?.[index];
- if (nodeSecureUrl?.type === "tag") {
- videoSecureUrl = nodeSecureUrl ? nodeSecureUrl.attribs.content : null;
- }
+ nodeSecureUrl = nodeSecureUrls?.[index];
+ if (nodeSecureUrl?.type === 'tag') {
+ videoSecureUrl = nodeSecureUrl ? nodeSecureUrl.attribs.content : null;
+ }
- videoObj = {
- url: video,
- secureUrl: videoSecureUrl,
- type: videoType,
- width,
- height,
- };
- if (videoType && videoType.indexOf("video/") === 0) {
- videos.splice(0, 0, videoObj);
- } else {
- videos.push(videoObj);
- }
- }
- }
+ videoObj = {
+ url: video,
+ secureUrl: videoSecureUrl,
+ type: videoType,
+ width,
+ height,
+ };
+ if (videoType && videoType.indexOf('video/') === 0) {
+ videos.splice(0, 0, videoObj);
+ } else {
+ videos.push(videoObj);
+ }
+ }
+ }
- return videos;
+ return videos;
}
// returns default favicon (//hostname/favicon.ico) for a url
function getDefaultFavicon(rootUrl: string) {
- return `${new URL(rootUrl).origin}/favicon.ico`;
+ return `${new URL(rootUrl).origin}/favicon.ico`;
}
// returns an array of URLs to favicon images
function getFavicons(doc: cheerio.CheerioAPI, rootUrl: string) {
- const images = [];
- let nodes: cheerio.Cheerio | never[] = [];
- let src: string | undefined;
+ const images = [];
+ let nodes: cheerio.Cheerio | never[] = [];
+ let src: string | undefined;
- const relSelectors = [
- "rel=icon",
- `rel="shortcut icon"`,
- "rel=apple-touch-icon",
- ];
+ const relSelectors = ['rel=icon', `rel="shortcut icon"`, 'rel=apple-touch-icon'];
- relSelectors.forEach((relSelector) => {
- // look for all icon tags
- nodes = doc(`link[${relSelector}]`);
+ relSelectors.forEach((relSelector) => {
+ // look for all icon tags
+ nodes = doc(`link[${relSelector}]`);
- // collect all images from icon tags
- if (nodes.length) {
- nodes.each((_: number, node: cheerio.Element) => {
- if (node.type === "tag") src = node.attribs.href;
- if (src) {
- src = new URL(rootUrl).href;
- images.push(src);
- }
- });
- }
- });
+ // collect all images from icon tags
+ if (nodes.length) {
+ nodes.each((_: number, node: cheerio.Element) => {
+ if (node.type === 'tag') src = node.attribs.href;
+ if (src) {
+ src = new URL(rootUrl).href;
+ images.push(src);
+ }
+ });
+ }
+ });
- // if no icon images, use default favicon location
- if (images.length <= 0) {
- images.push(getDefaultFavicon(rootUrl));
- }
+ // if no icon images, use default favicon location
+ if (images.length <= 0) {
+ images.push(getDefaultFavicon(rootUrl));
+ }
- return images;
+ return images;
}
function parseImageResponse(url: string, contentType: string) {
- return {
- url,
- mediaType: "image",
- contentType,
- favicons: [getDefaultFavicon(url)],
- };
+ return {
+ url,
+ mediaType: 'image',
+ contentType,
+ favicons: [getDefaultFavicon(url)],
+ };
}
function parseAudioResponse(url: string, contentType: string) {
- return {
- url,
- mediaType: "audio",
- contentType,
- favicons: [getDefaultFavicon(url)],
- };
+ return {
+ url,
+ mediaType: 'audio',
+ contentType,
+ favicons: [getDefaultFavicon(url)],
+ };
}
function parseVideoResponse(url: string, contentType: string) {
- return {
- url,
- mediaType: "video",
- contentType,
- favicons: [getDefaultFavicon(url)],
- };
+ return {
+ url,
+ mediaType: 'video',
+ contentType,
+ favicons: [getDefaultFavicon(url)],
+ };
}
function parseApplicationResponse(url: string, contentType: string) {
- return {
- url,
- mediaType: "application",
- contentType,
- favicons: [getDefaultFavicon(url)],
- };
+ return {
+ url,
+ mediaType: 'application',
+ contentType,
+ favicons: [getDefaultFavicon(url)],
+ };
}
function parseTextResponse(
- body: string,
- url: string,
- options: ILinkPreviewOptions = {},
- contentType?: string,
+ body: string,
+ url: string,
+ options: ILinkPreviewOptions = {},
+ contentType?: string
) {
- const doc = cheerio.load(body);
+ const doc = cheerio.load(body);
- return {
- url,
- title: getTitle(doc),
- siteName: getSiteName(doc),
- description: getDescription(doc),
- mediaType: getMediaType(doc) || "website",
- contentType,
- images: getImages(doc, url, options.imagesPropertyType),
- videos: getVideos(doc),
- favicons: getFavicons(doc, url),
- };
+ return {
+ url,
+ title: getTitle(doc),
+ siteName: getSiteName(doc),
+ description: getDescription(doc),
+ mediaType: getMediaType(doc) || 'website',
+ contentType,
+ images: getImages(doc, url, options.imagesPropertyType),
+ videos: getVideos(doc),
+ favicons: getFavicons(doc, url),
+ };
}
function parseUnknownResponse(
- body: string,
- url: string,
- options: ILinkPreviewOptions = {},
- contentType?: string,
+ body: string,
+ url: string,
+ options: ILinkPreviewOptions = {},
+ contentType?: string
) {
- return parseTextResponse(body, url, options, contentType);
+ return parseTextResponse(body, url, options, contentType);
}
-function parseResponse(
- response: IPreFetchedResource,
- options?: ILinkPreviewOptions,
-) {
- try {
- let contentType = response.headers["content-type"];
- // console.warn(`original content type`, contentType);
- if (contentType?.indexOf(";")) {
- // eslint-disable-next-line prefer-destructuring
- contentType = contentType.split(";")[0];
- // console.warn(`splitting content type`, contentType);
- }
+function parseResponse(response: IPreFetchedResource, options?: ILinkPreviewOptions) {
+ try {
+ let contentType = response.headers['content-type'];
+ // console.warn(`original content type`, contentType);
+ if (contentType?.indexOf(';')) {
+ // eslint-disable-next-line prefer-destructuring
+ contentType = contentType.split(';')[0];
+ // console.warn(`splitting content type`, contentType);
+ }
- if (!contentType) {
- return parseUnknownResponse(response.data, response.url, options);
- }
+ if (!contentType) {
+ return parseUnknownResponse(response.data, response.url, options);
+ }
- if ((contentType as any) instanceof Array) {
- // eslint-disable-next-line no-param-reassign, prefer-destructuring
- contentType = contentType[0];
- }
+ if ((contentType as any) instanceof Array) {
+ // eslint-disable-next-line no-param-reassign, prefer-destructuring
+ contentType = contentType[0];
+ }
- // parse response depending on content type
- if (OPENGRAPH.REGEX_CONTENT_TYPE_IMAGE.test(contentType)) {
- return parseImageResponse(response.url, contentType);
- }
- if (OPENGRAPH.REGEX_CONTENT_TYPE_AUDIO.test(contentType)) {
- return parseAudioResponse(response.url, contentType);
- }
- if (OPENGRAPH.REGEX_CONTENT_TYPE_VIDEO.test(contentType)) {
- return parseVideoResponse(response.url, contentType);
- }
- if (OPENGRAPH.REGEX_CONTENT_TYPE_TEXT.test(contentType)) {
- const htmlString = response.data;
- return parseTextResponse(htmlString, response.url, options, contentType);
- }
- if (OPENGRAPH.REGEX_CONTENT_TYPE_APPLICATION.test(contentType)) {
- return parseApplicationResponse(response.url, contentType);
- }
- const htmlString = response.data;
- return parseUnknownResponse(htmlString, response.url, options);
- } catch (e) {
- throw new Error(
- `link-preview-js could not fetch link information ${(
- e as any
- ).toString()}`,
- );
- }
+ // parse response depending on content type
+ if (OPENGRAPH.REGEX_CONTENT_TYPE_IMAGE.test(contentType)) {
+ return parseImageResponse(response.url, contentType);
+ }
+ if (OPENGRAPH.REGEX_CONTENT_TYPE_AUDIO.test(contentType)) {
+ return parseAudioResponse(response.url, contentType);
+ }
+ if (OPENGRAPH.REGEX_CONTENT_TYPE_VIDEO.test(contentType)) {
+ return parseVideoResponse(response.url, contentType);
+ }
+ if (OPENGRAPH.REGEX_CONTENT_TYPE_TEXT.test(contentType)) {
+ const htmlString = response.data;
+ return parseTextResponse(htmlString, response.url, options, contentType);
+ }
+ if (OPENGRAPH.REGEX_CONTENT_TYPE_APPLICATION.test(contentType)) {
+ return parseApplicationResponse(response.url, contentType);
+ }
+ const htmlString = response.data;
+ return parseUnknownResponse(htmlString, response.url, options);
+ } catch (e) {
+ throw new Error(
+ `link-preview-js could not fetch link information ${(e as any).toString()}`
+ );
+ }
}
export async function getLinkPreview(text: string) {
- const fetchUrl = text;
- const options: FetchOptions = {
- method: "GET",
- timeout: 5,
- responseType: ResponseType.Text,
- };
+ const fetchUrl = text;
+ const options: FetchOptions = {
+ method: 'GET',
+ timeout: 5,
+ responseType: ResponseType.Text,
+ };
- let response = await fetch(fetchUrl, options);
+ let response = await fetch(fetchUrl, options);
- if (response.status > 300 && response.status < 309) {
- const forwardedUrl = response.headers.location || "";
- response = await fetch(forwardedUrl, options);
- }
+ if (response.status > 300 && response.status < 309) {
+ const forwardedUrl = response.headers.location || '';
+ response = await fetch(forwardedUrl, options);
+ }
- return parseResponse(response);
+ return parseResponse(response);
}
diff --git a/src/libs/storage.tsx b/src/libs/storage.tsx
index 32c754dd..b6bcfff6 100644
--- a/src/libs/storage.tsx
+++ b/src/libs/storage.tsx
@@ -1,441 +1,418 @@
-import { getParentID } from "@utils/transform";
-import Database from "tauri-plugin-sql-api";
+import Database from 'tauri-plugin-sql-api';
+
+import { getParentID } from '@utils/transform';
let db: null | Database = null;
// connect database (sqlite)
// path: tauri::api::path::BaseDirectory::App
export async function connect(): Promise {
- if (db) {
- return db;
- }
- db = await Database.load("sqlite:lume.db");
- return db;
+ if (db) {
+ return db;
+ }
+ db = await Database.load('sqlite:lume.db');
+ return db;
}
// get active account
export async function getActiveAccount() {
- const db = await connect();
- const result: any = await db.select(
- "SELECT * FROM accounts WHERE is_active = 1;",
- );
- if (result.length > 0) {
- return result[0];
- } else {
- return null;
- }
+ const db = await connect();
+ const result: any = await db.select('SELECT * FROM accounts WHERE is_active = 1;');
+ if (result.length > 0) {
+ return result[0];
+ } else {
+ return null;
+ }
}
// get all accounts
export async function getAccounts() {
- const db = await connect();
- return await db.select(
- "SELECT * FROM accounts WHERE is_active = 0 ORDER BY created_at DESC;",
- );
+ const db = await connect();
+ return await db.select(
+ 'SELECT * FROM accounts WHERE is_active = 0 ORDER BY created_at DESC;'
+ );
}
// create account
export async function createAccount(
- npub: string,
- pubkey: string,
- privkey: string,
- follows?: string[][],
- is_active?: number,
+ npub: string,
+ pubkey: string,
+ privkey: string,
+ follows?: string[][],
+ is_active?: number
) {
- const db = await connect();
- const res = await db.execute(
- "INSERT OR IGNORE INTO accounts (npub, pubkey, privkey, follows, is_active) VALUES (?, ?, ?, ?, ?);",
- [npub, pubkey, privkey, follows || "", is_active || 0],
- );
- if (res) {
- await createBlock(
- 0,
- "Preserve your freedom",
- "https://void.cat/d/949GNg7ZjSLHm2eTR3jZqv",
- );
- }
- const getAccount = await getActiveAccount();
- return getAccount;
+ const db = await connect();
+ const res = await db.execute(
+ 'INSERT OR IGNORE INTO accounts (npub, pubkey, privkey, follows, is_active) VALUES (?, ?, ?, ?, ?);',
+ [npub, pubkey, privkey, follows || '', is_active || 0]
+ );
+ if (res) {
+ await createBlock(
+ 0,
+ 'Preserve your freedom',
+ 'https://void.cat/d/949GNg7ZjSLHm2eTR3jZqv'
+ );
+ }
+ const getAccount = await getActiveAccount();
+ return getAccount;
}
// update account
export async function updateAccount(
- column: string,
- value: string | string[],
- pubkey: string,
+ column: string,
+ value: string | string[],
+ pubkey: string
) {
- const db = await connect();
- return await db.execute(
- `UPDATE accounts SET ${column} = ? WHERE pubkey = ?;`,
- [value, pubkey],
- );
+ const db = await connect();
+ return await db.execute(`UPDATE accounts SET ${column} = ? WHERE pubkey = ?;`, [
+ value,
+ pubkey,
+ ]);
}
// count total notes
export async function countTotalChannels() {
- const db = await connect();
- const result = await db.select('SELECT COUNT(*) AS "total" FROM channels;');
- return result[0];
+ const db = await connect();
+ const result = await db.select('SELECT COUNT(*) AS "total" FROM channels;');
+ return result[0];
}
// count total notes
export async function countTotalNotes() {
- const db = await connect();
- const result = await db.select(
- 'SELECT COUNT(*) AS "total" FROM notes WHERE kind IN (1, 6);',
- );
- return parseInt(result[0].total);
+ const db = await connect();
+ const result = await db.select(
+ 'SELECT COUNT(*) AS "total" FROM notes WHERE kind IN (1, 6);'
+ );
+ return parseInt(result[0].total);
}
// get all notes
export async function getNotes(limit: number, offset: number) {
- const db = await connect();
- const totalNotes = await countTotalNotes();
- const nextCursor = offset + limit;
+ const db = await connect();
+ const totalNotes = await countTotalNotes();
+ const nextCursor = offset + limit;
- const notes: any = { data: null, nextCursor: 0 };
- const query: any = await db.select(
- `SELECT * FROM notes WHERE kind IN (1, 6, 1063) GROUP BY parent_id ORDER BY created_at DESC LIMIT "${limit}" OFFSET "${offset}";`,
- );
+ const notes: any = { data: null, nextCursor: 0 };
+ const query: any = await db.select(
+ `SELECT * FROM notes WHERE kind IN (1, 6, 1063) GROUP BY parent_id ORDER BY created_at DESC LIMIT "${limit}" OFFSET "${offset}";`
+ );
- notes["data"] = query;
- notes["nextCursor"] =
- Math.round(totalNotes / nextCursor) > 1 ? nextCursor : undefined;
+ notes['data'] = query;
+ notes['nextCursor'] = Math.round(totalNotes / nextCursor) > 1 ? nextCursor : undefined;
- return notes;
+ return notes;
}
// get all notes by pubkey
export async function getNotesByPubkey(pubkey: string) {
- const db = await connect();
- const res: any = await db.select(
- `SELECT * FROM notes WHERE pubkey == "${pubkey}" AND kind IN (1, 6, 1063) GROUP BY parent_id ORDER BY created_at DESC;`,
- );
+ const db = await connect();
+ const res: any = await db.select(
+ `SELECT * FROM notes WHERE pubkey == "${pubkey}" AND kind IN (1, 6, 1063) GROUP BY parent_id ORDER BY created_at DESC;`
+ );
- return res;
+ return res;
}
// get all notes by authors
-export async function getNotesByAuthors(
- authors: string,
- limit: number,
- offset: number,
-) {
- const db = await connect();
- const totalNotes = await countTotalNotes();
- const nextCursor = offset + limit;
- const array = JSON.parse(authors);
- const finalArray = `'${array.join("','")}'`;
+export async function getNotesByAuthors(authors: string, limit: number, offset: number) {
+ const db = await connect();
+ const totalNotes = await countTotalNotes();
+ const nextCursor = offset + limit;
+ const array = JSON.parse(authors);
+ const finalArray = `'${array.join("','")}'`;
- const notes: any = { data: null, nextCursor: 0 };
- const query: any = await db.select(
- `SELECT * FROM notes WHERE pubkey IN (${finalArray}) AND kind IN (1, 6, 1063) GROUP BY parent_id ORDER BY created_at DESC LIMIT "${limit}" OFFSET "${offset}";`,
- );
+ const notes: any = { data: null, nextCursor: 0 };
+ const query: any = await db.select(
+ `SELECT * FROM notes WHERE pubkey IN (${finalArray}) AND kind IN (1, 6, 1063) GROUP BY parent_id ORDER BY created_at DESC LIMIT "${limit}" OFFSET "${offset}";`
+ );
- notes["data"] = query;
- notes["nextCursor"] =
- Math.round(totalNotes / nextCursor) > 1 ? nextCursor : undefined;
+ notes['data'] = query;
+ notes['nextCursor'] = Math.round(totalNotes / nextCursor) > 1 ? nextCursor : undefined;
- return notes;
+ return notes;
}
// get note by id
export async function getNoteByID(event_id: string) {
- const db = await connect();
- const result = await db.select(
- `SELECT * FROM notes WHERE event_id = "${event_id}";`,
- );
- return result[0];
+ const db = await connect();
+ const result = await db.select(`SELECT * FROM notes WHERE event_id = "${event_id}";`);
+ return result[0];
}
// create note
export async function createNote(
- event_id: string,
- pubkey: string,
- kind: number,
- tags: any,
- content: string,
- created_at: number,
+ event_id: string,
+ pubkey: string,
+ kind: number,
+ tags: any,
+ content: string,
+ created_at: number
) {
- const db = await connect();
- const account = await getActiveAccount();
- const parentID = getParentID(tags, event_id);
+ const db = await connect();
+ const account = await getActiveAccount();
+ const parentID = getParentID(tags, event_id);
- return await db.execute(
- "INSERT OR IGNORE INTO notes (event_id, account_id, pubkey, kind, tags, content, created_at, parent_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?);",
- [event_id, account.id, pubkey, kind, tags, content, created_at, parentID],
- );
+ return await db.execute(
+ 'INSERT OR IGNORE INTO notes (event_id, account_id, pubkey, kind, tags, content, created_at, parent_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?);',
+ [event_id, account.id, pubkey, kind, tags, content, created_at, parentID]
+ );
}
// get note replies
export async function getReplies(parent_id: string) {
- const db = await connect();
- const result: any = await db.select(
- `SELECT * FROM replies WHERE parent_id = "${parent_id}" ORDER BY created_at DESC;`,
- );
- return result;
+ const db = await connect();
+ const result: any = await db.select(
+ `SELECT * FROM replies WHERE parent_id = "${parent_id}" ORDER BY created_at DESC;`
+ );
+ return result;
}
// create reply note
export async function createReplyNote(
- parent_id: string,
- event_id: string,
- pubkey: string,
- kind: number,
- tags: any,
- content: string,
- created_at: number,
+ parent_id: string,
+ event_id: string,
+ pubkey: string,
+ kind: number,
+ tags: any,
+ content: string,
+ created_at: number
) {
- const db = await connect();
- return await db.execute(
- "INSERT OR IGNORE INTO replies (event_id, parent_id, pubkey, kind, tags, content, created_at) VALUES (?, ?, ?, ?, ?, ?, ?);",
- [event_id, parent_id, pubkey, kind, tags, content, created_at],
- );
+ const db = await connect();
+ return await db.execute(
+ 'INSERT OR IGNORE INTO replies (event_id, parent_id, pubkey, kind, tags, content, created_at) VALUES (?, ?, ?, ?, ?, ?, ?);',
+ [event_id, parent_id, pubkey, kind, tags, content, created_at]
+ );
}
// get all channels
export async function getChannels() {
- const db = await connect();
- const result: any = await db.select(
- "SELECT * FROM channels ORDER BY created_at DESC;",
- );
- return result;
+ const db = await connect();
+ const result: any = await db.select('SELECT * FROM channels ORDER BY created_at DESC;');
+ return result;
}
// get channel by id
export async function getChannel(id: string) {
- const db = await connect();
- const result = await db.select(
- `SELECT * FROM channels WHERE event_id = "${id}";`,
- );
- return result[0];
+ const db = await connect();
+ const result = await db.select(`SELECT * FROM channels WHERE event_id = "${id}";`);
+ return result[0];
}
// create channel
export async function createChannel(
- event_id: string,
- pubkey: string,
- name: string,
- picture: string,
- about: string,
- created_at: number,
+ event_id: string,
+ pubkey: string,
+ name: string,
+ picture: string,
+ about: string,
+ created_at: number
) {
- const db = await connect();
- return await db.execute(
- "INSERT OR IGNORE INTO channels (event_id, pubkey, name, picture, about, created_at) VALUES (?, ?, ?, ?, ?, ?);",
- [event_id, pubkey, name, picture, about, created_at],
- );
+ const db = await connect();
+ return await db.execute(
+ 'INSERT OR IGNORE INTO channels (event_id, pubkey, name, picture, about, created_at) VALUES (?, ?, ?, ?, ?, ?);',
+ [event_id, pubkey, name, picture, about, created_at]
+ );
}
// update channel metadata
export async function updateChannelMetadata(event_id: string, value: string) {
- const db = await connect();
- const data = JSON.parse(value);
+ const db = await connect();
+ const data = JSON.parse(value);
- return await db.execute(
- "UPDATE channels SET name = ?, picture = ?, about = ? WHERE event_id = ?;",
- [data.name, data.picture, data.about, event_id],
- );
+ return await db.execute(
+ 'UPDATE channels SET name = ?, picture = ?, about = ? WHERE event_id = ?;',
+ [data.name, data.picture, data.about, event_id]
+ );
}
// create channel messages
export async function createChannelMessage(
- channel_id: string,
- event_id: string,
- pubkey: string,
- kind: number,
- content: string,
- tags: string[][],
- created_at: number,
+ channel_id: string,
+ event_id: string,
+ pubkey: string,
+ kind: number,
+ content: string,
+ tags: string[][],
+ created_at: number
) {
- const db = await connect();
- return await db.execute(
- "INSERT OR IGNORE INTO channel_messages (channel_id, event_id, pubkey, kind, content, tags, created_at) VALUES (?, ?, ?, ?, ?, ?, ?);",
- [channel_id, event_id, pubkey, kind, content, tags, created_at],
- );
+ const db = await connect();
+ return await db.execute(
+ 'INSERT OR IGNORE INTO channel_messages (channel_id, event_id, pubkey, kind, content, tags, created_at) VALUES (?, ?, ?, ?, ?, ?, ?);',
+ [channel_id, event_id, pubkey, kind, content, tags, created_at]
+ );
}
// get channel messages by channel id
export async function getChannelMessages(channel_id: string) {
- const db = await connect();
- return await db.select(
- `SELECT * FROM channel_messages WHERE channel_id = "${channel_id}" ORDER BY created_at ASC;`,
- );
+ const db = await connect();
+ return await db.select(
+ `SELECT * FROM channel_messages WHERE channel_id = "${channel_id}" ORDER BY created_at ASC;`
+ );
}
// get channel users
export async function getChannelUsers(channel_id: string) {
- const db = await connect();
- const result: any = await db.select(
- `SELECT DISTINCT pubkey FROM channel_messages WHERE channel_id = "${channel_id}";`,
- );
- return result;
+ const db = await connect();
+ const result: any = await db.select(
+ `SELECT DISTINCT pubkey FROM channel_messages WHERE channel_id = "${channel_id}";`
+ );
+ return result;
}
// get all chats by pubkey
export async function getChatsByPubkey(pubkey: string) {
- const db = await connect();
- const result: any = await db.select(
- `SELECT DISTINCT sender_pubkey FROM chats WHERE receiver_pubkey = "${pubkey}" ORDER BY created_at DESC;`,
- );
- const newArr: any = result.map((v) => ({ ...v, new_messages: 0 }));
- return newArr;
+ const db = await connect();
+ const result: any = await db.select(
+ `SELECT DISTINCT sender_pubkey FROM chats WHERE receiver_pubkey = "${pubkey}" ORDER BY created_at DESC;`
+ );
+ const newArr: any = result.map((v) => ({ ...v, new_messages: 0 }));
+ return newArr;
}
// get chat messages
-export async function getChatMessages(
- receiver_pubkey: string,
- sender_pubkey: string,
-) {
- const db = await connect();
- let receiver = [];
+export async function getChatMessages(receiver_pubkey: string, sender_pubkey: string) {
+ const db = await connect();
+ let receiver = [];
- const sender: any = await db.select(
- `SELECT * FROM chats WHERE sender_pubkey = "${sender_pubkey}" AND receiver_pubkey = "${receiver_pubkey}";`,
- );
+ const sender: any = await db.select(
+ `SELECT * FROM chats WHERE sender_pubkey = "${sender_pubkey}" AND receiver_pubkey = "${receiver_pubkey}";`
+ );
- if (receiver_pubkey !== sender_pubkey) {
- receiver = await db.select(
- `SELECT * FROM chats WHERE sender_pubkey = "${receiver_pubkey}" AND receiver_pubkey = "${sender_pubkey}";`,
- );
- }
+ if (receiver_pubkey !== sender_pubkey) {
+ receiver = await db.select(
+ `SELECT * FROM chats WHERE sender_pubkey = "${receiver_pubkey}" AND receiver_pubkey = "${sender_pubkey}";`
+ );
+ }
- const result = [...sender, ...receiver].sort(
- (x: { created_at: number }, y: { created_at: number }) =>
- x.created_at - y.created_at,
- );
+ const result = [...sender, ...receiver].sort(
+ (x: { created_at: number }, y: { created_at: number }) => x.created_at - y.created_at
+ );
- return result;
+ return result;
}
// create chat
export async function createChat(
- event_id: string,
- receiver_pubkey: string,
- sender_pubkey: string,
- content: string,
- tags: string[][],
- created_at: number,
+ event_id: string,
+ receiver_pubkey: string,
+ sender_pubkey: string,
+ content: string,
+ tags: string[][],
+ created_at: number
) {
- const db = await connect();
- await db.execute(
- "INSERT OR IGNORE INTO chats (event_id, receiver_pubkey, sender_pubkey, content, tags, created_at) VALUES (?, ?, ?, ?, ?, ?);",
- [event_id, receiver_pubkey, sender_pubkey, content, tags, created_at],
- );
- return sender_pubkey;
+ const db = await connect();
+ await db.execute(
+ 'INSERT OR IGNORE INTO chats (event_id, receiver_pubkey, sender_pubkey, content, tags, created_at) VALUES (?, ?, ?, ?, ?, ?);',
+ [event_id, receiver_pubkey, sender_pubkey, content, tags, created_at]
+ );
+ return sender_pubkey;
}
// get setting
export async function getSetting(key: string) {
- const db = await connect();
- const result = await db.select(
- `SELECT value FROM settings WHERE key = "${key}";`,
- );
- return result[0]?.value;
+ const db = await connect();
+ const result = await db.select(`SELECT value FROM settings WHERE key = "${key}";`);
+ return result[0]?.value;
}
// update setting
export async function updateSetting(key: string, value: string | number) {
- const db = await connect();
- return await db.execute(
- `UPDATE settings SET value = "${value}" WHERE key = "${key}";`,
- );
+ const db = await connect();
+ return await db.execute(`UPDATE settings SET value = "${value}" WHERE key = "${key}";`);
}
// get last login
export async function getLastLogin() {
- const db = await connect();
- const result = await db.select(
- `SELECT value FROM settings WHERE key = "last_login";`,
- );
- if (result[0]) {
- return parseInt(result[0].value);
- } else {
- return 0;
- }
+ const db = await connect();
+ const result = await db.select(`SELECT value FROM settings WHERE key = "last_login";`);
+ if (result[0]) {
+ return parseInt(result[0].value);
+ } else {
+ return 0;
+ }
}
// update last login
export async function updateLastLogin(value: number) {
- const db = await connect();
- return await db.execute(
- `UPDATE settings SET value = ${value} WHERE key = "last_login";`,
- );
+ const db = await connect();
+ return await db.execute(
+ `UPDATE settings SET value = ${value} WHERE key = "last_login";`
+ );
}
// get blacklist by kind and account id
export async function getBlacklist(account_id: number, kind: number) {
- const db = await connect();
- return await db.select(
- `SELECT * FROM blacklist WHERE account_id = "${account_id}" AND kind = "${kind}";`,
- );
+ const db = await connect();
+ return await db.select(
+ `SELECT * FROM blacklist WHERE account_id = "${account_id}" AND kind = "${kind}";`
+ );
}
// get active blacklist by kind and account id
export async function getActiveBlacklist(account_id: number, kind: number) {
- const db = await connect();
- return await db.select(
- `SELECT content FROM blacklist WHERE account_id = "${account_id}" AND kind = "${kind}" AND status = 1;`,
- );
+ const db = await connect();
+ return await db.select(
+ `SELECT content FROM blacklist WHERE account_id = "${account_id}" AND kind = "${kind}" AND status = 1;`
+ );
}
// add to blacklist
export async function addToBlacklist(
- account_id: number,
- content: string,
- kind: number,
- status?: number,
+ account_id: number,
+ content: string,
+ kind: number,
+ status?: number
) {
- const db = await connect();
- return await db.execute(
- "INSERT OR IGNORE INTO blacklist (account_id, content, kind, status) VALUES (?, ?, ?, ?);",
- [account_id, content, kind, status || 1],
- );
+ const db = await connect();
+ return await db.execute(
+ 'INSERT OR IGNORE INTO blacklist (account_id, content, kind, status) VALUES (?, ?, ?, ?);',
+ [account_id, content, kind, status || 1]
+ );
}
// update item in blacklist
export async function updateItemInBlacklist(content: string, status: number) {
- const db = await connect();
- return await db.execute(
- `UPDATE blacklist SET status = "${status}" WHERE content = "${content}";`,
- );
+ const db = await connect();
+ return await db.execute(
+ `UPDATE blacklist SET status = "${status}" WHERE content = "${content}";`
+ );
}
// get all blocks
export async function getBlocks() {
- const db = await connect();
- const activeAccount = await getActiveAccount();
- const result: any = await db.select(
- `SELECT * FROM blocks WHERE account_id = "${activeAccount.id}" ORDER BY created_at DESC;`,
- );
- return result;
+ const db = await connect();
+ const activeAccount = await getActiveAccount();
+ const result: any = await db.select(
+ `SELECT * FROM blocks WHERE account_id = "${activeAccount.id}" ORDER BY created_at DESC;`
+ );
+ return result;
}
// create block
export async function createBlock(kind: number, title: string, content: any) {
- const db = await connect();
- const activeAccount = await getActiveAccount();
- return await db.execute(
- "INSERT OR IGNORE INTO blocks (account_id, kind, title, content) VALUES (?, ?, ?, ?);",
- [activeAccount.id, kind, title, content],
- );
+ const db = await connect();
+ const activeAccount = await getActiveAccount();
+ return await db.execute(
+ 'INSERT OR IGNORE INTO blocks (account_id, kind, title, content) VALUES (?, ?, ?, ?);',
+ [activeAccount.id, kind, title, content]
+ );
}
// remove block
export async function removeBlock(id: string) {
- const db = await connect();
- return await db.execute(`DELETE FROM blocks WHERE id = "${id}";`);
+ const db = await connect();
+ return await db.execute(`DELETE FROM blocks WHERE id = "${id}";`);
}
// logout
export async function removeAll() {
- const db = await connect();
- await db.execute(`UPDATE settings SET value = "0" WHERE key = "last_login";`);
- await db.execute("DELETE FROM replies;");
- await db.execute("DELETE FROM notes;");
- await db.execute("DELETE FROM blacklist;");
- await db.execute("DELETE FROM blocks;");
- await db.execute("DELETE FROM chats;");
- await db.execute("DELETE FROM accounts;");
- return true;
+ const db = await connect();
+ await db.execute(`UPDATE settings SET value = "0" WHERE key = "last_login";`);
+ await db.execute('DELETE FROM replies;');
+ await db.execute('DELETE FROM notes;');
+ await db.execute('DELETE FROM blacklist;');
+ await db.execute('DELETE FROM blocks;');
+ await db.execute('DELETE FROM chats;');
+ await db.execute('DELETE FROM accounts;');
+ return true;
}
diff --git a/src/main.tsx b/src/main.tsx
index e979c738..91d7bc2b 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,26 +1,29 @@
-import App from "./app";
-import { getSetting } from "@libs/storage";
-import { RelayProvider } from "@shared/relayProvider";
-import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
-import { createRoot } from "react-dom/client";
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import { createRoot } from 'react-dom/client';
-const cacheTime = await getSetting("cache_time");
+import { getSetting } from '@libs/storage';
+
+import { RelayProvider } from '@shared/relayProvider';
+
+import App from './app';
+
+const cacheTime = await getSetting('cache_time');
const queryClient = new QueryClient({
- defaultOptions: {
- queries: {
- cacheTime: parseInt(cacheTime),
- },
- },
+ defaultOptions: {
+ queries: {
+ cacheTime: parseInt(cacheTime),
+ },
+ },
});
-const container = document.getElementById("root");
+const container = document.getElementById('root');
const root = createRoot(container);
root.render(
-
-
-
-
- ,
+
+
+
+
+
);
diff --git a/src/shared/accounts/active.tsx b/src/shared/accounts/active.tsx
index 282778ca..32f4c9a8 100644
--- a/src/shared/accounts/active.tsx
+++ b/src/shared/accounts/active.tsx
@@ -1,105 +1,105 @@
-import { createChat, getLastLogin } from "@libs/storage";
-import { Image } from "@shared/image";
-import { NetworkStatusIndicator } from "@shared/networkStatusIndicator";
-import { RelayContext } from "@shared/relayProvider";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useMutation, useQueryClient } from "@tanstack/react-query";
-import { useProfile } from "@utils/hooks/useProfile";
-import { sendNativeNotification } from "@utils/notification";
-import { produce } from "immer";
-import { useContext, useEffect } from "react";
-import { Link } from "react-router-dom";
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { produce } from 'immer';
+import { useContext, useEffect } from 'react';
+import { Link } from 'react-router-dom';
+
+import { createChat, getLastLogin } from '@libs/storage';
+
+import { Image } from '@shared/image';
+import { NetworkStatusIndicator } from '@shared/networkStatusIndicator';
+import { RelayContext } from '@shared/relayProvider';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+
+import { useProfile } from '@utils/hooks/useProfile';
+import { sendNativeNotification } from '@utils/notification';
const lastLogin = await getLastLogin();
export function ActiveAccount({ data }: { data: any }) {
- const ndk = useContext(RelayContext);
- const queryClient = useQueryClient();
+ const ndk = useContext(RelayContext);
+ const queryClient = useQueryClient();
- const { status, user } = useProfile(data.pubkey);
+ const { status, user } = useProfile(data.pubkey);
- const chat = useMutation({
- mutationFn: (data: any) => {
- return createChat(
- data.id,
- data.receiver_pubkey,
- data.sender_pubkey,
- data.content,
- data.tags,
- data.created_at,
- );
- },
- onSuccess: (data: any) => {
- const prev = queryClient.getQueryData(["chats"]);
- const next = produce(prev, (draft: any) => {
- const target = draft.findIndex(
- (m: { sender_pubkey: string }) => m.sender_pubkey === data,
- );
- if (target !== -1) {
- draft[target]["new_messages"] =
- draft[target]["new_messages"] + 1 || 1;
- } else {
- draft.push({ sender_pubkey: data, new_messages: 1 });
- }
- });
- queryClient.setQueryData(["chats"], next);
- },
- });
+ const chat = useMutation({
+ mutationFn: (data: any) => {
+ return createChat(
+ data.id,
+ data.receiver_pubkey,
+ data.sender_pubkey,
+ data.content,
+ data.tags,
+ data.created_at
+ );
+ },
+ onSuccess: (data: any) => {
+ const prev = queryClient.getQueryData(['chats']);
+ const next = produce(prev, (draft: any) => {
+ const target = draft.findIndex(
+ (m: { sender_pubkey: string }) => m.sender_pubkey === data
+ );
+ if (target !== -1) {
+ draft[target]['new_messages'] = draft[target]['new_messages'] + 1 || 1;
+ } else {
+ draft.push({ sender_pubkey: data, new_messages: 1 });
+ }
+ });
+ queryClient.setQueryData(['chats'], next);
+ },
+ });
- useEffect(() => {
- const since = lastLogin > 0 ? lastLogin : Math.floor(Date.now() / 1000);
- const sub = ndk.subscribe(
- {
- kinds: [4],
- "#p": [data.pubkey],
- since: since,
- },
- {
- closeOnEose: false,
- },
- );
+ useEffect(() => {
+ const since = lastLogin > 0 ? lastLogin : Math.floor(Date.now() / 1000);
+ const sub = ndk.subscribe(
+ {
+ kinds: [4],
+ '#p': [data.pubkey],
+ since: since,
+ },
+ {
+ closeOnEose: false,
+ }
+ );
- sub.addListener("event", (event) => {
- switch (event.kind) {
- case 4:
- // update state
- chat.mutate({
- id: event.id,
- receiver_pubkey: data.pubkey,
- sender_pubkey: event.pubkey,
- content: event.content,
- tags: event.tags,
- created_at: event.created_at,
- });
- // send native notifiation
- sendNativeNotification("You've received new message");
- break;
- default:
- break;
- }
- });
+ sub.addListener('event', (event) => {
+ switch (event.kind) {
+ case 4:
+ // update state
+ chat.mutate({
+ id: event.id,
+ receiver_pubkey: data.pubkey,
+ sender_pubkey: event.pubkey,
+ content: event.content,
+ tags: event.tags,
+ created_at: event.created_at,
+ });
+ // send native notifiation
+ sendNativeNotification("You've received new message");
+ break;
+ default:
+ break;
+ }
+ });
- return () => {
- sub.stop();
- };
- }, []);
+ return () => {
+ sub.stop();
+ };
+ }, []);
- if (status === "loading") {
- return ;
- }
+ if (status === 'loading') {
+ return ;
+ }
- return (
-
-
-
-
- );
+ return (
+
+
+
+
+ );
}
diff --git a/src/shared/accounts/inactive.tsx b/src/shared/accounts/inactive.tsx
index 0fa7abe1..700a10c8 100644
--- a/src/shared/accounts/inactive.tsx
+++ b/src/shared/accounts/inactive.tsx
@@ -1,18 +1,20 @@
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useProfile } from "@utils/hooks/useProfile";
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+
+import { useProfile } from '@utils/hooks/useProfile';
export function InactiveAccount({ data }: { data: any }) {
- const { user } = useProfile(data.npub);
+ const { user } = useProfile(data.npub);
- return (
-
-
-
- );
+ return (
+
+
+
+ );
}
diff --git a/src/shared/appHeader.tsx b/src/shared/appHeader.tsx
index 69d6f0d7..5240479d 100644
--- a/src/shared/appHeader.tsx
+++ b/src/shared/appHeader.tsx
@@ -1,48 +1,49 @@
-import { ArrowLeftIcon, ArrowRightIcon } from "@shared/icons";
-import { useNavigate } from "react-router-dom";
+import { useNavigate } from 'react-router-dom';
+
+import { ArrowLeftIcon, ArrowRightIcon } from '@shared/icons';
export function AppHeader({ reverse }: { reverse?: boolean }) {
- const navigate = useNavigate();
+ const navigate = useNavigate();
- const goBack = () => {
- navigate(-1);
- };
+ const goBack = () => {
+ navigate(-1);
+ };
- const goForward = () => {
- navigate(1);
- };
+ const goForward = () => {
+ navigate(1);
+ };
- return (
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+ );
}
diff --git a/src/shared/appLayout.tsx b/src/shared/appLayout.tsx
index 5c8d83ee..535686ba 100644
--- a/src/shared/appLayout.tsx
+++ b/src/shared/appLayout.tsx
@@ -1,16 +1,17 @@
-import { Navigation } from "@shared/navigation";
-import { Outlet, ScrollRestoration } from "react-router-dom";
+import { Outlet, ScrollRestoration } from 'react-router-dom';
+
+import { Navigation } from '@shared/navigation';
export function AppLayout() {
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/authLayout.tsx b/src/shared/authLayout.tsx
index 28fb5142..b217de1b 100644
--- a/src/shared/authLayout.tsx
+++ b/src/shared/authLayout.tsx
@@ -1,65 +1,66 @@
-import { ArrowLeftIcon, ArrowRightIcon } from "@shared/icons";
-import { platform } from "@tauri-apps/api/os";
-import { Outlet, useNavigate } from "react-router-dom";
+import { platform } from '@tauri-apps/api/os';
+import { Outlet, useNavigate } from 'react-router-dom';
+
+import { ArrowLeftIcon, ArrowRightIcon } from '@shared/icons';
const platformName = await platform();
export function AuthLayout() {
- const navigate = useNavigate();
+ const navigate = useNavigate();
- const goBack = () => {
- navigate(-1);
- };
+ const goBack = () => {
+ navigate(-1);
+ };
- const goForward = () => {
- navigate(1);
- };
+ const goForward = () => {
+ navigate(1);
+ };
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
}
diff --git a/src/shared/avatarUploader.tsx b/src/shared/avatarUploader.tsx
index 74a05882..c54ef84b 100644
--- a/src/shared/avatarUploader.tsx
+++ b/src/shared/avatarUploader.tsx
@@ -1,69 +1,71 @@
-import { LoaderIcon, PlusIcon } from "@shared/icons";
-import { open } from "@tauri-apps/api/dialog";
-import { Body, fetch } from "@tauri-apps/api/http";
-import { createBlobFromFile } from "@utils/createBlobFromFile";
-import { useState } from "react";
+import { open } from '@tauri-apps/api/dialog';
+import { Body, fetch } from '@tauri-apps/api/http';
+import { useState } from 'react';
+
+import { LoaderIcon, PlusIcon } from '@shared/icons';
+
+import { createBlobFromFile } from '@utils/createBlobFromFile';
export function AvatarUploader({ setPicture }: { setPicture: any }) {
- const [loading, setLoading] = useState(false);
+ const [loading, setLoading] = useState(false);
- const openFileDialog = async () => {
- const selected: any = await open({
- multiple: false,
- filters: [
- {
- name: "Image",
- extensions: ["png", "jpeg", "jpg", "gif"],
- },
- ],
- });
- if (Array.isArray(selected)) {
- // user selected multiple files
- } else if (selected === null) {
- // user cancelled the selection
- } else {
- setLoading(true);
+ const openFileDialog = async () => {
+ const selected: any = await open({
+ multiple: false,
+ filters: [
+ {
+ name: 'Image',
+ extensions: ['png', 'jpeg', 'jpg', 'gif'],
+ },
+ ],
+ });
+ if (Array.isArray(selected)) {
+ // user selected multiple files
+ } else if (selected === null) {
+ // user cancelled the selection
+ } else {
+ setLoading(true);
- const filename = selected.split("/").pop();
- const file = await createBlobFromFile(selected);
- const buf = await file.arrayBuffer();
+ const filename = selected.split('/').pop();
+ const file = await createBlobFromFile(selected);
+ const buf = await file.arrayBuffer();
- const res: { data: { file: { id: string } } } = await fetch(
- "https://void.cat/upload?cli=false",
- {
- method: "POST",
- timeout: 5,
- headers: {
- accept: "*/*",
- "Content-Type": "application/octet-stream",
- "V-Filename": filename,
- "V-Description": "Upload from https://lume.nu",
- "V-Strip-Metadata": "true",
- },
- body: Body.bytes(buf),
- },
- );
- const image = `https://void.cat/d/${res.data.file.id}.jpg`;
+ const res: { data: { file: { id: string } } } = await fetch(
+ 'https://void.cat/upload?cli=false',
+ {
+ method: 'POST',
+ timeout: 5,
+ headers: {
+ accept: '*/*',
+ 'Content-Type': 'application/octet-stream',
+ 'V-Filename': filename,
+ 'V-Description': 'Upload from https://lume.nu',
+ 'V-Strip-Metadata': 'true',
+ },
+ body: Body.bytes(buf),
+ }
+ );
+ const image = `https://void.cat/d/${res.data.file.id}.jpg`;
- // update parent state
- setPicture(image);
+ // update parent state
+ setPicture(image);
- // disable loader
- setLoading(false);
- }
- };
+ // disable loader
+ setLoading(false);
+ }
+ };
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/bannerUploader.tsx b/src/shared/bannerUploader.tsx
index 8e1215d5..3bee2b88 100644
--- a/src/shared/bannerUploader.tsx
+++ b/src/shared/bannerUploader.tsx
@@ -1,69 +1,71 @@
-import { LoaderIcon, PlusIcon } from "@shared/icons";
-import { open } from "@tauri-apps/api/dialog";
-import { Body, fetch } from "@tauri-apps/api/http";
-import { createBlobFromFile } from "@utils/createBlobFromFile";
-import { useState } from "react";
+import { open } from '@tauri-apps/api/dialog';
+import { Body, fetch } from '@tauri-apps/api/http';
+import { useState } from 'react';
+
+import { LoaderIcon, PlusIcon } from '@shared/icons';
+
+import { createBlobFromFile } from '@utils/createBlobFromFile';
export function BannerUploader({ setBanner }: { setBanner: any }) {
- const [loading, setLoading] = useState(false);
+ const [loading, setLoading] = useState(false);
- const openFileDialog = async () => {
- const selected: any = await open({
- multiple: false,
- filters: [
- {
- name: "Image",
- extensions: ["png", "jpeg", "jpg", "gif"],
- },
- ],
- });
- if (Array.isArray(selected)) {
- // user selected multiple files
- } else if (selected === null) {
- // user cancelled the selection
- } else {
- setLoading(true);
+ const openFileDialog = async () => {
+ const selected: any = await open({
+ multiple: false,
+ filters: [
+ {
+ name: 'Image',
+ extensions: ['png', 'jpeg', 'jpg', 'gif'],
+ },
+ ],
+ });
+ if (Array.isArray(selected)) {
+ // user selected multiple files
+ } else if (selected === null) {
+ // user cancelled the selection
+ } else {
+ setLoading(true);
- const filename = selected.split("/").pop();
- const file = await createBlobFromFile(selected);
- const buf = await file.arrayBuffer();
+ const filename = selected.split('/').pop();
+ const file = await createBlobFromFile(selected);
+ const buf = await file.arrayBuffer();
- const res: { data: { file: { id: string } } } = await fetch(
- "https://void.cat/upload?cli=false",
- {
- method: "POST",
- timeout: 5,
- headers: {
- accept: "*/*",
- "Content-Type": "application/octet-stream",
- "V-Filename": filename,
- "V-Description": "Upload from https://lume.nu",
- "V-Strip-Metadata": "true",
- },
- body: Body.bytes(buf),
- },
- );
- const image = `https://void.cat/d/${res.data.file.id}.jpg`;
+ const res: { data: { file: { id: string } } } = await fetch(
+ 'https://void.cat/upload?cli=false',
+ {
+ method: 'POST',
+ timeout: 5,
+ headers: {
+ accept: '*/*',
+ 'Content-Type': 'application/octet-stream',
+ 'V-Filename': filename,
+ 'V-Description': 'Upload from https://lume.nu',
+ 'V-Strip-Metadata': 'true',
+ },
+ body: Body.bytes(buf),
+ }
+ );
+ const image = `https://void.cat/d/${res.data.file.id}.jpg`;
- // update parent state
- setBanner(image);
+ // update parent state
+ setBanner(image);
- // disable loader
- setLoading(false);
- }
- };
+ // disable loader
+ setLoading(false);
+ }
+ };
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/button.tsx b/src/shared/button.tsx
index 80afa8d3..a7ff78c8 100644
--- a/src/shared/button.tsx
+++ b/src/shared/button.tsx
@@ -1,46 +1,46 @@
-import { ReactNode } from "react";
-import { twMerge } from "tailwind-merge";
+import { ReactNode } from 'react';
+import { twMerge } from 'tailwind-merge';
export function Button({
- preset,
- children,
- disabled = false,
- onClick = undefined,
+ preset,
+ children,
+ disabled = false,
+ onClick = undefined,
}: {
- preset: "small" | "publish" | "large";
- children: ReactNode;
- disabled?: boolean;
- onClick?: () => void;
+ preset: 'small' | 'publish' | 'large';
+ children: ReactNode;
+ disabled?: boolean;
+ onClick?: () => void;
}) {
- let preClass: string;
- switch (preset) {
- case "small":
- preClass =
- "w-min h-9 px-4 bg-fuchsia-500 rounded-md text-sm font-medium text-zinc-100 hover:bg-fuchsia-600";
- break;
- case "publish":
- preClass =
- "w-min h-9 px-4 bg-fuchsia-500 rounded-md text-sm font-medium text-zinc-100 hover:bg-fuchsia-600";
- break;
- case "large":
- preClass =
- "h-11 w-full bg-fuchsia-500 rounded-md font-medium text-zinc-100 hover:bg-fuchsia-600";
- break;
- default:
- break;
- }
+ let preClass: string;
+ switch (preset) {
+ case 'small':
+ preClass =
+ 'w-min h-9 px-4 bg-fuchsia-500 rounded-md text-sm font-medium text-zinc-100 hover:bg-fuchsia-600';
+ break;
+ case 'publish':
+ preClass =
+ 'w-min h-9 px-4 bg-fuchsia-500 rounded-md text-sm font-medium text-zinc-100 hover:bg-fuchsia-600';
+ break;
+ case 'large':
+ preClass =
+ 'h-11 w-full bg-fuchsia-500 rounded-md font-medium text-zinc-100 hover:bg-fuchsia-600';
+ break;
+ default:
+ break;
+ }
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/composer/imageUploader.tsx b/src/shared/composer/imageUploader.tsx
index f896e250..ca966546 100644
--- a/src/shared/composer/imageUploader.tsx
+++ b/src/shared/composer/imageUploader.tsx
@@ -1,132 +1,134 @@
-import { PlusCircleIcon } from "@shared/icons";
-import { open } from "@tauri-apps/api/dialog";
-import { listen } from "@tauri-apps/api/event";
-import { Body, fetch } from "@tauri-apps/api/http";
-import { createBlobFromFile } from "@utils/createBlobFromFile";
-import { useCallback, useEffect, useState } from "react";
-import { Transforms } from "slate";
-import { useSlateStatic } from "slate-react";
+import { open } from '@tauri-apps/api/dialog';
+import { listen } from '@tauri-apps/api/event';
+import { Body, fetch } from '@tauri-apps/api/http';
+import { useCallback, useEffect, useState } from 'react';
+import { Transforms } from 'slate';
+import { useSlateStatic } from 'slate-react';
+
+import { PlusCircleIcon } from '@shared/icons';
+
+import { createBlobFromFile } from '@utils/createBlobFromFile';
export function ImageUploader() {
- const editor = useSlateStatic();
- const [loading, setLoading] = useState(false);
+ const editor = useSlateStatic();
+ const [loading, setLoading] = useState(false);
- const insertImage = (editor, url) => {
- const image = { type: "image", url, children: [{ text: url }] };
- Transforms.insertNodes(editor, image);
- };
+ const insertImage = (editor, url) => {
+ const image = { type: 'image', url, children: [{ text: url }] };
+ Transforms.insertNodes(editor, image);
+ };
- const uploadToVoidCat = useCallback(
- async (filepath) => {
- const filename = filepath.split("/").pop();
- const file = await createBlobFromFile(filepath);
- const buf = await file.arrayBuffer();
+ const uploadToVoidCat = useCallback(
+ async (filepath) => {
+ const filename = filepath.split('/').pop();
+ const file = await createBlobFromFile(filepath);
+ const buf = await file.arrayBuffer();
- try {
- const res: { data: { file: { id: string } } } = await fetch(
- "https://void.cat/upload?cli=false",
- {
- method: "POST",
- timeout: 5,
- headers: {
- accept: "*/*",
- "Content-Type": "application/octet-stream",
- "V-Filename": filename,
- "V-Description": "Uploaded from https://lume.nu",
- "V-Strip-Metadata": "true",
- },
- body: Body.bytes(buf),
- },
- );
- const image = `https://void.cat/d/${res.data.file.id}.webp`;
- // update parent state
- insertImage(editor, image);
- // reset loading state
- setLoading(false);
- } catch (error) {
- // reset loading state
- setLoading(false);
- // handle error
- if (error instanceof SyntaxError) {
- // Unexpected token < in JSON
- console.log("There was a SyntaxError", error);
- } else {
- console.log("There was an error", error);
- }
- }
- },
- [editor],
- );
+ try {
+ const res: { data: { file: { id: string } } } = await fetch(
+ 'https://void.cat/upload?cli=false',
+ {
+ method: 'POST',
+ timeout: 5,
+ headers: {
+ accept: '*/*',
+ 'Content-Type': 'application/octet-stream',
+ 'V-Filename': filename,
+ 'V-Description': 'Uploaded from https://lume.nu',
+ 'V-Strip-Metadata': 'true',
+ },
+ body: Body.bytes(buf),
+ }
+ );
+ const image = `https://void.cat/d/${res.data.file.id}.webp`;
+ // update parent state
+ insertImage(editor, image);
+ // reset loading state
+ setLoading(false);
+ } catch (error) {
+ // reset loading state
+ setLoading(false);
+ // handle error
+ if (error instanceof SyntaxError) {
+ // Unexpected token < in JSON
+ console.log('There was a SyntaxError', error);
+ } else {
+ console.log('There was an error', error);
+ }
+ }
+ },
+ [editor]
+ );
- const openFileDialog = async () => {
- const selected: any = await open({
- multiple: false,
- filters: [
- {
- name: "Image",
- extensions: ["png", "jpeg", "jpg", "gif"],
- },
- ],
- });
- if (Array.isArray(selected)) {
- // user selected multiple files
- } else if (selected === null) {
- // user cancelled the selection
- } else {
- setLoading(true);
- // upload file
- uploadToVoidCat(selected);
- }
- };
+ const openFileDialog = async () => {
+ const selected: any = await open({
+ multiple: false,
+ filters: [
+ {
+ name: 'Image',
+ extensions: ['png', 'jpeg', 'jpg', 'gif'],
+ },
+ ],
+ });
+ if (Array.isArray(selected)) {
+ // user selected multiple files
+ } else if (selected === null) {
+ // user cancelled the selection
+ } else {
+ setLoading(true);
+ // upload file
+ uploadToVoidCat(selected);
+ }
+ };
- useEffect(() => {
- async function initFileDrop() {
- const unlisten = await listen("tauri://file-drop", (event) => {
- // set loading state
- setLoading(true);
- // upload file
- uploadToVoidCat(event.payload[0]);
- });
+ useEffect(() => {
+ async function initFileDrop() {
+ const unlisten = await listen('tauri://file-drop', (event) => {
+ // set loading state
+ setLoading(true);
+ // upload file
+ uploadToVoidCat(event.payload[0]);
+ });
- return () => {
- unlisten();
- };
- }
+ return () => {
+ unlisten();
+ };
+ }
- initFileDrop();
- }, [uploadToVoidCat]);
+ initFileDrop();
+ }, [uploadToVoidCat]);
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/composer/modal.tsx b/src/shared/composer/modal.tsx
index 1a030e65..4060710f 100644
--- a/src/shared/composer/modal.tsx
+++ b/src/shared/composer/modal.tsx
@@ -1,96 +1,94 @@
-import { Dialog, Transition } from "@headlessui/react";
-import { Button } from "@shared/button";
-import { Post } from "@shared/composer/types/post";
-import { User } from "@shared/composer/user";
+import { Dialog, Transition } from '@headlessui/react';
+import { Fragment } from 'react';
+import { useHotkeys } from 'react-hotkeys-hook';
+
+import { Button } from '@shared/button';
+import { Post } from '@shared/composer/types/post';
+import { User } from '@shared/composer/user';
import {
- CancelIcon,
- ChevronDownIcon,
- ChevronRightIcon,
- ComposeIcon,
-} from "@shared/icons";
-import { useComposer } from "@stores/composer";
-import { COMPOSE_SHORTCUT } from "@stores/shortcuts";
-import { useAccount } from "@utils/hooks/useAccount";
-import { Fragment } from "react";
-import { useHotkeys } from "react-hotkeys-hook";
+ CancelIcon,
+ ChevronDownIcon,
+ ChevronRightIcon,
+ ComposeIcon,
+} from '@shared/icons';
+
+import { useComposer } from '@stores/composer';
+import { COMPOSE_SHORTCUT } from '@stores/shortcuts';
+
+import { useAccount } from '@utils/hooks/useAccount';
export function Composer() {
- const { account } = useAccount();
+ const { account } = useAccount();
- const [toggle, open] = useComposer((state) => [
- state.toggleModal,
- state.open,
- ]);
+ const [toggle, open] = useComposer((state) => [state.toggleModal, state.open]);
- const closeModal = () => {
- toggle(false);
- };
+ const closeModal = () => {
+ toggle(false);
+ };
- useHotkeys(COMPOSE_SHORTCUT, () => toggle(true));
+ useHotkeys(COMPOSE_SHORTCUT, () => toggle(true));
- return (
- <>
-
-
-
-
- >
- );
+ return (
+ <>
+
+
+
+
+ >
+ );
}
diff --git a/src/shared/composer/types/post.tsx b/src/shared/composer/types/post.tsx
index 53af1c96..f9edffa1 100644
--- a/src/shared/composer/types/post.tsx
+++ b/src/shared/composer/types/post.tsx
@@ -1,179 +1,171 @@
-import { usePublish } from "@libs/ndk";
-import { Button } from "@shared/button";
-import { ImageUploader } from "@shared/composer/imageUploader";
-import { TrashIcon } from "@shared/icons";
-import { MentionNote } from "@shared/notes/mentions/note";
-import { useComposer } from "@stores/composer";
-import { FULL_RELAYS } from "@stores/constants";
-import { useCallback, useMemo, useState } from "react";
-import { Node, Transforms, createEditor } from "slate";
-import { withHistory } from "slate-history";
-import {
- Editable,
- ReactEditor,
- Slate,
- useSlateStatic,
- withReact,
-} from "slate-react";
+import { useCallback, useMemo, useState } from 'react';
+import { Node, Transforms, createEditor } from 'slate';
+import { withHistory } from 'slate-history';
+import { Editable, ReactEditor, Slate, useSlateStatic, withReact } from 'slate-react';
+
+import { usePublish } from '@libs/ndk';
+
+import { Button } from '@shared/button';
+import { ImageUploader } from '@shared/composer/imageUploader';
+import { TrashIcon } from '@shared/icons';
+import { MentionNote } from '@shared/notes/mentions/note';
+
+import { useComposer } from '@stores/composer';
+import { FULL_RELAYS } from '@stores/constants';
const withImages = (editor) => {
- const { isVoid } = editor;
+ const { isVoid } = editor;
- editor.isVoid = (element) => {
- return element.type === "image" ? true : isVoid(element);
- };
+ editor.isVoid = (element) => {
+ return element.type === 'image' ? true : isVoid(element);
+ };
- return editor;
+ return editor;
};
const ImagePreview = ({
- attributes,
- children,
- element,
+ attributes,
+ children,
+ element,
}: {
- attributes: any;
- children: any;
- element: any;
+ attributes: any;
+ children: any;
+ element: any;
}) => {
- const editor: any = useSlateStatic();
- const path = ReactEditor.findPath(editor, element);
+ const editor: any = useSlateStatic();
+ const path = ReactEditor.findPath(editor, element);
- return (
-
- {children}
-
-

-
-
-
- );
+ return (
+
+ {children}
+
+

+
+
+
+ );
};
export function Post() {
- const publish = usePublish();
- const editor = useMemo(
- () => withReact(withImages(withHistory(createEditor()))),
- [],
- );
+ const publish = usePublish();
+ const editor = useMemo(() => withReact(withImages(withHistory(createEditor()))), []);
- const [repost, reply, toggle] = useComposer((state) => [
- state.repost,
- state.reply,
- state.toggleModal,
- ]);
- const [content, setContent] = useState([
- {
- children: [
- {
- text: "",
- },
- ],
- },
- ]);
+ const [repost, reply, toggle] = useComposer((state) => [
+ state.repost,
+ state.reply,
+ state.toggleModal,
+ ]);
+ const [content, setContent] = useState([
+ {
+ children: [
+ {
+ text: '',
+ },
+ ],
+ },
+ ]);
- const serialize = useCallback((nodes: Node[]) => {
- return nodes.map((n) => Node.string(n)).join("\n");
- }, []);
+ const serialize = useCallback((nodes: Node[]) => {
+ return nodes.map((n) => Node.string(n)).join('\n');
+ }, []);
- const getRef = () => {
- if (repost.id) {
- return repost.id;
- } else if (reply.id) {
- return reply.id;
- } else {
- return null;
- }
- };
+ const getRef = () => {
+ if (repost.id) {
+ return repost.id;
+ } else if (reply.id) {
+ return reply.id;
+ } else {
+ return null;
+ }
+ };
- const refID = getRef();
+ const refID = getRef();
- const submit = async () => {
- let tags: string[][] = [];
- let kind: number;
+ const submit = async () => {
+ let tags: string[][] = [];
+ let kind: number;
- if (repost.id && repost.pubkey) {
- kind = 6;
- tags = [
- ["e", repost.id, FULL_RELAYS[0], "root"],
- ["p", repost.pubkey],
- ];
- } else if (reply.id && reply.pubkey) {
- kind = 1;
- if (reply.root && reply.root !== reply.id) {
- tags = [
- ["e", reply.id, FULL_RELAYS[0], "root"],
- ["e", reply.root, FULL_RELAYS[0], "reply"],
- ["p", reply.pubkey],
- ];
- } else {
- tags = [
- ["e", reply.id, FULL_RELAYS[0], "root"],
- ["p", reply.pubkey],
- ];
- }
- } else {
- kind = 1;
- tags = [];
- }
+ if (repost.id && repost.pubkey) {
+ kind = 6;
+ tags = [
+ ['e', repost.id, FULL_RELAYS[0], 'root'],
+ ['p', repost.pubkey],
+ ];
+ } else if (reply.id && reply.pubkey) {
+ kind = 1;
+ if (reply.root && reply.root !== reply.id) {
+ tags = [
+ ['e', reply.id, FULL_RELAYS[0], 'root'],
+ ['e', reply.root, FULL_RELAYS[0], 'reply'],
+ ['p', reply.pubkey],
+ ];
+ } else {
+ tags = [
+ ['e', reply.id, FULL_RELAYS[0], 'root'],
+ ['p', reply.pubkey],
+ ];
+ }
+ } else {
+ kind = 1;
+ tags = [];
+ }
- // serialize content
- const serializedContent = serialize(content);
+ // serialize content
+ const serializedContent = serialize(content);
- // publish message
- await publish({ content: serializedContent, kind, tags });
+ // publish message
+ await publish({ content: serializedContent, kind, tags });
- // close modal
- toggle(false);
- };
+ // close modal
+ toggle(false);
+ };
- const renderElement = useCallback((props: any) => {
- switch (props.element.type) {
- case "image":
- if (props.element.url) {
- return ;
- }
- default:
- return {props.children}
;
- }
- }, []);
+ const renderElement = useCallback((props: any) => {
+ switch (props.element.type) {
+ case 'image':
+ if (props.element.url) {
+ return ;
+ }
+ break;
+ default:
+ return {props.children}
;
+ }
+ }, []);
- return (
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+
+ );
}
diff --git a/src/shared/composer/user.tsx b/src/shared/composer/user.tsx
index a0416743..efc86814 100644
--- a/src/shared/composer/user.tsx
+++ b/src/shared/composer/user.tsx
@@ -1,25 +1,27 @@
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useProfile } from "@utils/hooks/useProfile";
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+
+import { useProfile } from '@utils/hooks/useProfile';
export function User({ pubkey }: { pubkey: string }) {
- const { user } = useProfile(pubkey);
+ const { user } = useProfile(pubkey);
- return (
-
-
-
-
-
- {user?.nip05 || user?.name || (
-
- )}
-
-
- );
+ return (
+
+
+
+
+
+ {user?.nip05 || user?.name || (
+
+ )}
+
+
+ );
}
diff --git a/src/shared/editProfileModal.tsx b/src/shared/editProfileModal.tsx
index 11b4dc06..5ab1a84f 100644
--- a/src/shared/editProfileModal.tsx
+++ b/src/shared/editProfileModal.tsx
@@ -1,328 +1,339 @@
-import { Dialog, Transition } from "@headlessui/react";
-import { usePublish } from "@libs/ndk";
-import { NDKEvent } from "@nostr-dev-kit/ndk";
-import { AvatarUploader } from "@shared/avatarUploader";
-import { BannerUploader } from "@shared/bannerUploader";
-import {
- CancelIcon,
- CheckCircleIcon,
- LoaderIcon,
- UnverifiedIcon,
-} from "@shared/icons";
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useQueryClient } from "@tanstack/react-query";
-import { fetch } from "@tauri-apps/api/http";
-import { useAccount } from "@utils/hooks/useAccount";
-import { Fragment, useEffect, useState } from "react";
-import { useForm } from "react-hook-form";
+import { Dialog, Transition } from '@headlessui/react';
+import { NDKEvent } from '@nostr-dev-kit/ndk';
+import { useQueryClient } from '@tanstack/react-query';
+import { fetch } from '@tauri-apps/api/http';
+import { Fragment, useEffect, useState } from 'react';
+import { useForm } from 'react-hook-form';
+
+import { usePublish } from '@libs/ndk';
+
+import { AvatarUploader } from '@shared/avatarUploader';
+import { BannerUploader } from '@shared/bannerUploader';
+import { CancelIcon, CheckCircleIcon, LoaderIcon, UnverifiedIcon } from '@shared/icons';
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+
+import { useAccount } from '@utils/hooks/useAccount';
export function EditProfileModal() {
- const queryClient = useQueryClient();
- const publish = usePublish();
+ const queryClient = useQueryClient();
+ const publish = usePublish();
- const [isOpen, setIsOpen] = useState(false);
- const [loading, setLoading] = useState(false);
- const [picture, setPicture] = useState(DEFAULT_AVATAR);
- const [banner, setBanner] = useState("");
- const [nip05, setNIP05] = useState({ verified: false, text: "" });
+ const [isOpen, setIsOpen] = useState(false);
+ const [loading, setLoading] = useState(false);
+ const [picture, setPicture] = useState(DEFAULT_AVATAR);
+ const [banner, setBanner] = useState('');
+ const [nip05, setNIP05] = useState({ verified: false, text: '' });
- const { account } = useAccount();
- const {
- register,
- handleSubmit,
- reset,
- setError,
- formState: { isValid, errors },
- } = useForm({
- defaultValues: async () => {
- const res: any = queryClient.getQueryData(["user", account.pubkey]);
- if (res.image) {
- setPicture(res.image);
- }
- if (res.banner) {
- setBanner(res.banner);
- }
- if (res.nip05) {
- setNIP05((prev) => ({ ...prev, text: res.nip05 }));
- }
- return res;
- },
- });
+ const { account } = useAccount();
+ const {
+ register,
+ handleSubmit,
+ reset,
+ setError,
+ formState: { isValid, errors },
+ } = useForm({
+ defaultValues: async () => {
+ const res: any = queryClient.getQueryData(['user', account.pubkey]);
+ if (res.image) {
+ setPicture(res.image);
+ }
+ if (res.banner) {
+ setBanner(res.banner);
+ }
+ if (res.nip05) {
+ setNIP05((prev) => ({ ...prev, text: res.nip05 }));
+ }
+ return res;
+ },
+ });
- const closeModal = () => {
- setIsOpen(false);
- };
+ const closeModal = () => {
+ setIsOpen(false);
+ };
- const openModal = () => {
- setIsOpen(true);
- };
+ const openModal = () => {
+ setIsOpen(true);
+ };
- const verifyNIP05 = async (data: string) => {
- if (data) {
- const url = data.split("@");
- const username = url[0];
- const service = url[1];
- const verifyURL = `https://${service}/.well-known/nostr.json?name=${username}`;
+ const verifyNIP05 = async (data: string) => {
+ if (data) {
+ const url = data.split('@');
+ const username = url[0];
+ const service = url[1];
+ const verifyURL = `https://${service}/.well-known/nostr.json?name=${username}`;
- const res: any = await fetch(verifyURL, {
- method: "GET",
- timeout: 30,
- headers: {
- "Content-Type": "application/json; charset=utf-8",
- },
- });
+ const res: any = await fetch(verifyURL, {
+ method: 'GET',
+ timeout: 30,
+ headers: {
+ 'Content-Type': 'application/json; charset=utf-8',
+ },
+ });
- if (!res.ok) return false;
- if (res.data.names[username] === account.pubkey) {
- setNIP05((prev) => ({ ...prev, verified: true }));
- return true;
- } else {
- return false;
- }
- }
- };
+ if (!res.ok) return false;
+ if (res.data.names[username] === account.pubkey) {
+ setNIP05((prev) => ({ ...prev, verified: true }));
+ return true;
+ } else {
+ return false;
+ }
+ }
+ };
- const onSubmit = async (data: any) => {
- // start loading
- setLoading(true);
+ const onSubmit = async (data: any) => {
+ // start loading
+ setLoading(true);
- let event: NDKEvent;
+ let event: NDKEvent;
- const content = {
- ...data,
- username: data.name,
- display_name: data.name,
- bio: data.about,
- image: data.picture,
- };
+ const content = {
+ ...data,
+ username: data.name,
+ display_name: data.name,
+ bio: data.about,
+ image: data.picture,
+ };
- if (data.nip05) {
- const verify = await verifyNIP05(data.nip05);
- if (verify) {
- event = await publish({
- content: JSON.stringify({ ...content, nip05: data.nip05 }),
- kind: 0,
- tags: [],
- });
- } else {
- setNIP05((prev) => ({ ...prev, verified: false }));
- setError("nip05", {
- type: "manual",
- message: "Can't verify your Lume ID / NIP-05, please check again",
- });
- }
- } else {
- event = await publish({
- content: JSON.stringify(content),
- kind: 0,
- tags: [],
- });
- }
+ if (data.nip05) {
+ const verify = await verifyNIP05(data.nip05);
+ if (verify) {
+ event = await publish({
+ content: JSON.stringify({ ...content, nip05: data.nip05 }),
+ kind: 0,
+ tags: [],
+ });
+ } else {
+ setNIP05((prev) => ({ ...prev, verified: false }));
+ setError('nip05', {
+ type: 'manual',
+ message: "Can't verify your Lume ID / NIP-05, please check again",
+ });
+ }
+ } else {
+ event = await publish({
+ content: JSON.stringify(content),
+ kind: 0,
+ tags: [],
+ });
+ }
- if (event.id) {
- setTimeout(() => {
- // invalid cache
- queryClient.invalidateQueries(["user", account.pubkey]);
- // reset form
- reset();
- // reset state
- setLoading(false);
- setIsOpen(false);
- setPicture(DEFAULT_AVATAR);
- setBanner(null);
- }, 1200);
- } else {
- setLoading(false);
- }
- };
+ if (event.id) {
+ setTimeout(() => {
+ // invalid cache
+ queryClient.invalidateQueries(['user', account.pubkey]);
+ // reset form
+ reset();
+ // reset state
+ setLoading(false);
+ setIsOpen(false);
+ setPicture(DEFAULT_AVATAR);
+ setBanner(null);
+ }, 1200);
+ } else {
+ setLoading(false);
+ }
+ };
- useEffect(() => {
- if (!nip05.verified && /\S+@\S+\.\S+/.test(nip05.text)) {
- verifyNIP05(nip05.text);
- }
- }, [nip05.text]);
+ useEffect(() => {
+ if (!nip05.verified && /\S+@\S+\.\S+/.test(nip05.text)) {
+ verifyNIP05(nip05.text);
+ }
+ }, [nip05.text]);
- return (
- <>
-
-
-
-
- >
- );
+ return (
+ <>
+
+
+
+
+ >
+ );
}
diff --git a/src/shared/icons/arrowLeft.tsx b/src/shared/icons/arrowLeft.tsx
index ebe02c0d..73c78f9c 100644
--- a/src/shared/icons/arrowLeft.tsx
+++ b/src/shared/icons/arrowLeft.tsx
@@ -1,22 +1,15 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function ArrowLeftIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function ArrowLeftIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/arrowRight.tsx b/src/shared/icons/arrowRight.tsx
index cd71c563..2089fc14 100644
--- a/src/shared/icons/arrowRight.tsx
+++ b/src/shared/icons/arrowRight.tsx
@@ -1,22 +1,15 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function ArrowRightIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function ArrowRightIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/arrowRightCircle.tsx b/src/shared/icons/arrowRightCircle.tsx
index fbd3d4f4..52f1f59d 100644
--- a/src/shared/icons/arrowRightCircle.tsx
+++ b/src/shared/icons/arrowRightCircle.tsx
@@ -1,24 +1,24 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
export function ArrowRightCircleIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
+ props: JSX.IntrinsicAttributes & SVGProps
) {
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/icons/bell.tsx b/src/shared/icons/bell.tsx
index 4614ca9a..7b02ef20 100644
--- a/src/shared/icons/bell.tsx
+++ b/src/shared/icons/bell.tsx
@@ -1,22 +1,20 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function BellIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function BellIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/cancel.tsx b/src/shared/icons/cancel.tsx
index 063e8cb4..445cccd9 100644
--- a/src/shared/icons/cancel.tsx
+++ b/src/shared/icons/cancel.tsx
@@ -1,21 +1,14 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function CancelIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function CancelIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/checkCircle.tsx b/src/shared/icons/checkCircle.tsx
index 442a4d08..62d5b59f 100644
--- a/src/shared/icons/checkCircle.tsx
+++ b/src/shared/icons/checkCircle.tsx
@@ -1,23 +1,23 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
export function CheckCircleIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
+ props: JSX.IntrinsicAttributes & SVGProps
) {
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/icons/chevronDown.tsx b/src/shared/icons/chevronDown.tsx
index c72ccf1b..42597fe4 100644
--- a/src/shared/icons/chevronDown.tsx
+++ b/src/shared/icons/chevronDown.tsx
@@ -1,24 +1,24 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
export function ChevronDownIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
+ props: JSX.IntrinsicAttributes & SVGProps
) {
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/icons/chevronRight.tsx b/src/shared/icons/chevronRight.tsx
index 06a4cdac..f5661669 100644
--- a/src/shared/icons/chevronRight.tsx
+++ b/src/shared/icons/chevronRight.tsx
@@ -1,24 +1,24 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
export function ChevronRightIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
+ props: JSX.IntrinsicAttributes & SVGProps
) {
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/icons/cmd.tsx b/src/shared/icons/cmd.tsx
index 71f7d967..3c1be54d 100644
--- a/src/shared/icons/cmd.tsx
+++ b/src/shared/icons/cmd.tsx
@@ -1,23 +1,21 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function CommandIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function CommandIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/compose.tsx b/src/shared/icons/compose.tsx
index 47a90044..8857e371 100644
--- a/src/shared/icons/compose.tsx
+++ b/src/shared/icons/compose.tsx
@@ -1,21 +1,19 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function ComposeIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function ComposeIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/copy.tsx b/src/shared/icons/copy.tsx
index c8b1a171..147195ad 100644
--- a/src/shared/icons/copy.tsx
+++ b/src/shared/icons/copy.tsx
@@ -1,24 +1,22 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function CopyIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function CopyIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/edit.tsx b/src/shared/icons/edit.tsx
index 46317299..e50f9d75 100644
--- a/src/shared/icons/edit.tsx
+++ b/src/shared/icons/edit.tsx
@@ -1,24 +1,22 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function EditIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function EditIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/empty.tsx b/src/shared/icons/empty.tsx
index cdae3e6e..0af77487 100644
--- a/src/shared/icons/empty.tsx
+++ b/src/shared/icons/empty.tsx
@@ -1,66 +1,61 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function EmptyIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function EmptyIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/enter.tsx b/src/shared/icons/enter.tsx
index cf9acf7b..8531ff7e 100644
--- a/src/shared/icons/enter.tsx
+++ b/src/shared/icons/enter.tsx
@@ -1,24 +1,22 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function EnterIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function EnterIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/eyeOff.tsx b/src/shared/icons/eyeOff.tsx
index 64431a26..a6b32e7e 100644
--- a/src/shared/icons/eyeOff.tsx
+++ b/src/shared/icons/eyeOff.tsx
@@ -1,21 +1,19 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function EyeOffIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function EyeOffIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/eyeOn.tsx b/src/shared/icons/eyeOn.tsx
index 403bfe45..d6d108fb 100644
--- a/src/shared/icons/eyeOn.tsx
+++ b/src/shared/icons/eyeOn.tsx
@@ -1,21 +1,19 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function EyeOnIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function EyeOnIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/feed.tsx b/src/shared/icons/feed.tsx
index 728a54d7..0385a276 100644
--- a/src/shared/icons/feed.tsx
+++ b/src/shared/icons/feed.tsx
@@ -1,24 +1,22 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function FeedIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function FeedIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/follow.tsx b/src/shared/icons/follow.tsx
index 660c48f6..77d1f56c 100644
--- a/src/shared/icons/follow.tsx
+++ b/src/shared/icons/follow.tsx
@@ -1,24 +1,22 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function FollowIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function FollowIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/heartbeat.tsx b/src/shared/icons/heartbeat.tsx
index bc9bf980..ad8a38fe 100644
--- a/src/shared/icons/heartbeat.tsx
+++ b/src/shared/icons/heartbeat.tsx
@@ -1,24 +1,22 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function HeartBeatIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function HeartBeatIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/hide.tsx b/src/shared/icons/hide.tsx
index 8cc479b1..2a5062de 100644
--- a/src/shared/icons/hide.tsx
+++ b/src/shared/icons/hide.tsx
@@ -1,21 +1,19 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function HideIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function HideIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/image.tsx b/src/shared/icons/image.tsx
index 35b20b2a..ebf01cbd 100644
--- a/src/shared/icons/image.tsx
+++ b/src/shared/icons/image.tsx
@@ -1,21 +1,19 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function ImageIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function ImageIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/index.tsx b/src/shared/icons/index.tsx
index 83d100ac..549e6b93 100644
--- a/src/shared/icons/index.tsx
+++ b/src/shared/icons/index.tsx
@@ -1,46 +1,46 @@
// @index('./*.tsx', f => `export * from '${f.path}'`)
-export * from "./arrowLeft";
-export * from "./arrowRight";
-export * from "./bell";
-export * from "./cancel";
-export * from "./checkCircle";
-export * from "./chevronDown";
-export * from "./chevronRight";
-export * from "./compose";
-export * from "./copy";
-export * from "./edit";
-export * from "./enter";
-export * from "./eyeOff";
-export * from "./eyeOn";
-export * from "./feed";
-export * from "./heartbeat";
-export * from "./hide";
-export * from "./image";
-export * from "./like";
-export * from "./lume";
-export * from "./media";
-export * from "./mute";
-export * from "./space";
-export * from "./navArrowDown";
-export * from "./plus";
-export * from "./plusCircle";
-export * from "./refresh";
-export * from "./reply";
-export * from "./replyMessage";
-export * from "./repost";
-export * from "./threads";
-export * from "./trash";
-export * from "./world";
-export * from "./zap";
-export * from "./loader";
-export * from "./trending";
-export * from "./empty";
-export * from "./cmd";
-export * from "./verticalDots";
-export * from "./signal";
-export * from "./unverified";
-export * from "./settings";
-export * from "./logout";
-export * from "./follow";
-export * from "./unfollow";
+export * from './arrowLeft';
+export * from './arrowRight';
+export * from './bell';
+export * from './cancel';
+export * from './checkCircle';
+export * from './chevronDown';
+export * from './chevronRight';
+export * from './compose';
+export * from './copy';
+export * from './edit';
+export * from './enter';
+export * from './eyeOff';
+export * from './eyeOn';
+export * from './feed';
+export * from './heartbeat';
+export * from './hide';
+export * from './image';
+export * from './like';
+export * from './lume';
+export * from './media';
+export * from './mute';
+export * from './space';
+export * from './navArrowDown';
+export * from './plus';
+export * from './plusCircle';
+export * from './refresh';
+export * from './reply';
+export * from './replyMessage';
+export * from './repost';
+export * from './threads';
+export * from './trash';
+export * from './world';
+export * from './zap';
+export * from './loader';
+export * from './trending';
+export * from './empty';
+export * from './cmd';
+export * from './verticalDots';
+export * from './signal';
+export * from './unverified';
+export * from './settings';
+export * from './logout';
+export * from './follow';
+export * from './unfollow';
// @endindex
diff --git a/src/shared/icons/like.tsx b/src/shared/icons/like.tsx
index ef6378bd..6567ff1b 100644
--- a/src/shared/icons/like.tsx
+++ b/src/shared/icons/like.tsx
@@ -1,21 +1,14 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function LikeIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function LikeIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/loader.tsx b/src/shared/icons/loader.tsx
index e03fc33d..25e780c7 100644
--- a/src/shared/icons/loader.tsx
+++ b/src/shared/icons/loader.tsx
@@ -1,29 +1,22 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function LoaderIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function LoaderIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/logout.tsx b/src/shared/icons/logout.tsx
index aa31d985..61f8bdac 100644
--- a/src/shared/icons/logout.tsx
+++ b/src/shared/icons/logout.tsx
@@ -1,24 +1,22 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function LogoutIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function LogoutIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/lume.tsx b/src/shared/icons/lume.tsx
index d37bce44..22c46ea1 100644
--- a/src/shared/icons/lume.tsx
+++ b/src/shared/icons/lume.tsx
@@ -1,14 +1,10 @@
export function LumeIcon({ className }: { className: string }) {
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/icons/media.tsx b/src/shared/icons/media.tsx
index cf4a57fb..5c8b2044 100644
--- a/src/shared/icons/media.tsx
+++ b/src/shared/icons/media.tsx
@@ -1,27 +1,25 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function MediaIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function MediaIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/mute.tsx b/src/shared/icons/mute.tsx
index 4bdcdb30..22eae1ca 100644
--- a/src/shared/icons/mute.tsx
+++ b/src/shared/icons/mute.tsx
@@ -1,27 +1,25 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function MuteIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function MuteIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/navArrowDown.tsx b/src/shared/icons/navArrowDown.tsx
index 339ccd51..358ff53e 100644
--- a/src/shared/icons/navArrowDown.tsx
+++ b/src/shared/icons/navArrowDown.tsx
@@ -1,20 +1,15 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
export function NavArrowDownIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
+ props: JSX.IntrinsicAttributes & SVGProps
) {
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/icons/plus.tsx b/src/shared/icons/plus.tsx
index 54397626..38f9b857 100644
--- a/src/shared/icons/plus.tsx
+++ b/src/shared/icons/plus.tsx
@@ -1,22 +1,15 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function PlusIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function PlusIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/plusCircle.tsx b/src/shared/icons/plusCircle.tsx
index f81bfac6..ff43631d 100644
--- a/src/shared/icons/plusCircle.tsx
+++ b/src/shared/icons/plusCircle.tsx
@@ -1,24 +1,22 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function PlusCircleIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function PlusCircleIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/refresh.tsx b/src/shared/icons/refresh.tsx
index e59f0ed6..5faeb6e3 100644
--- a/src/shared/icons/refresh.tsx
+++ b/src/shared/icons/refresh.tsx
@@ -1,21 +1,14 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function RefreshIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function RefreshIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/reply.tsx b/src/shared/icons/reply.tsx
index 7550d663..86b135dc 100644
--- a/src/shared/icons/reply.tsx
+++ b/src/shared/icons/reply.tsx
@@ -1,22 +1,15 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function ReplyIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function ReplyIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/replyMessage.tsx b/src/shared/icons/replyMessage.tsx
index 58292467..03a245db 100644
--- a/src/shared/icons/replyMessage.tsx
+++ b/src/shared/icons/replyMessage.tsx
@@ -1,23 +1,23 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
export function ReplyMessageIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
+ props: JSX.IntrinsicAttributes & SVGProps
) {
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/icons/repost.tsx b/src/shared/icons/repost.tsx
index 434a33c8..cb605aa6 100644
--- a/src/shared/icons/repost.tsx
+++ b/src/shared/icons/repost.tsx
@@ -1,22 +1,15 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function RepostIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function RepostIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/settings.tsx b/src/shared/icons/settings.tsx
index f7a59720..5267f06e 100644
--- a/src/shared/icons/settings.tsx
+++ b/src/shared/icons/settings.tsx
@@ -1,29 +1,27 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function SettingsIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function SettingsIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/signal.tsx b/src/shared/icons/signal.tsx
index fef86186..b3f5c254 100644
--- a/src/shared/icons/signal.tsx
+++ b/src/shared/icons/signal.tsx
@@ -1,24 +1,22 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function SignalIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function SignalIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/space.tsx b/src/shared/icons/space.tsx
index 270a707c..af9a67a7 100644
--- a/src/shared/icons/space.tsx
+++ b/src/shared/icons/space.tsx
@@ -1,22 +1,20 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function SpaceIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function SpaceIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/thread.tsx b/src/shared/icons/thread.tsx
index 4f9689fd..95d8af55 100644
--- a/src/shared/icons/thread.tsx
+++ b/src/shared/icons/thread.tsx
@@ -1,24 +1,22 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function ThreadIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function ThreadIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/threads.tsx b/src/shared/icons/threads.tsx
index c0407239..986fb706 100644
--- a/src/shared/icons/threads.tsx
+++ b/src/shared/icons/threads.tsx
@@ -1,21 +1,19 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function ThreadsIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function ThreadsIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/trash.tsx b/src/shared/icons/trash.tsx
index 22eb01de..610bd16c 100644
--- a/src/shared/icons/trash.tsx
+++ b/src/shared/icons/trash.tsx
@@ -1,21 +1,19 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function TrashIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function TrashIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/trending.tsx b/src/shared/icons/trending.tsx
index 3bb2eeda..f581addf 100644
--- a/src/shared/icons/trending.tsx
+++ b/src/shared/icons/trending.tsx
@@ -1,24 +1,22 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function TrendingIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function TrendingIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/unfollow.tsx b/src/shared/icons/unfollow.tsx
index f3f6c790..8662d04a 100644
--- a/src/shared/icons/unfollow.tsx
+++ b/src/shared/icons/unfollow.tsx
@@ -1,24 +1,22 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function UnfollowIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function UnfollowIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/unverified.tsx b/src/shared/icons/unverified.tsx
index 83ba9a28..5594b6f1 100644
--- a/src/shared/icons/unverified.tsx
+++ b/src/shared/icons/unverified.tsx
@@ -1,23 +1,21 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function UnverifiedIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function UnverifiedIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/verticalDots.tsx b/src/shared/icons/verticalDots.tsx
index dfb1f7df..28d25484 100644
--- a/src/shared/icons/verticalDots.tsx
+++ b/src/shared/icons/verticalDots.tsx
@@ -1,28 +1,28 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
export function VerticalDotsIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
+ props: JSX.IntrinsicAttributes & SVGProps
) {
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/icons/world.tsx b/src/shared/icons/world.tsx
index 00889484..737144f5 100644
--- a/src/shared/icons/world.tsx
+++ b/src/shared/icons/world.tsx
@@ -1,24 +1,22 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function WorldIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function WorldIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/icons/zap.tsx b/src/shared/icons/zap.tsx
index f6a511e6..77b601b8 100644
--- a/src/shared/icons/zap.tsx
+++ b/src/shared/icons/zap.tsx
@@ -1,24 +1,22 @@
-import { SVGProps } from "react";
+import { SVGProps } from 'react';
-export function ZapIcon(
- props: JSX.IntrinsicAttributes & SVGProps,
-) {
- return (
-
- );
+export function ZapIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
}
diff --git a/src/shared/image.tsx b/src/shared/image.tsx
index 82d2ac8e..7e3a82c4 100644
--- a/src/shared/image.tsx
+++ b/src/shared/image.tsx
@@ -1,21 +1,21 @@
-import { ImgHTMLAttributes } from "react";
+import { ImgHTMLAttributes } from 'react';
interface Props extends ImgHTMLAttributes {
- fallback: string;
+ fallback: string;
}
export function Image({ src, fallback, ...props }: Props) {
- return (
-
{
- currentTarget.onerror = null;
- currentTarget.src = fallback;
- }}
- decoding="async"
- alt="lume default img"
- style={{ contentVisibility: "auto" }}
- />
- );
+ return (
+
{
+ currentTarget.onerror = null;
+ currentTarget.src = fallback;
+ }}
+ decoding="async"
+ alt="lume default img"
+ style={{ contentVisibility: 'auto' }}
+ />
+ );
}
diff --git a/src/shared/logout.tsx b/src/shared/logout.tsx
index 86aeb4cb..28471c24 100644
--- a/src/shared/logout.tsx
+++ b/src/shared/logout.tsx
@@ -1,123 +1,119 @@
-import { Dialog, Transition } from "@headlessui/react";
-import { removeAll } from "@libs/storage";
-import { CancelIcon, LogoutIcon } from "@shared/icons";
-import { useQueryClient } from "@tanstack/react-query";
-import { relaunch } from "@tauri-apps/api/process";
-import { Fragment, useState } from "react";
+import { Dialog, Transition } from '@headlessui/react';
+import { useQueryClient } from '@tanstack/react-query';
+import { relaunch } from '@tauri-apps/api/process';
+import { Fragment, useState } from 'react';
+
+import { removeAll } from '@libs/storage';
+
+import { CancelIcon, LogoutIcon } from '@shared/icons';
export function Logout() {
- const queryClient = useQueryClient();
- const [isOpen, setIsOpen] = useState(false);
+ const queryClient = useQueryClient();
+ const [isOpen, setIsOpen] = useState(false);
- const closeModal = () => {
- setIsOpen(false);
- };
+ const closeModal = () => {
+ setIsOpen(false);
+ };
- const openModal = () => {
- setIsOpen(true);
- };
+ const openModal = () => {
+ setIsOpen(true);
+ };
- const logout = async () => {
- // reset database
- await removeAll();
- // reset react query
- queryClient.clear();
- // navigate
- await relaunch();
- };
+ const logout = async () => {
+ // reset database
+ await removeAll();
+ // reset react query
+ queryClient.clear();
+ // navigate
+ await relaunch();
+ };
- return (
- <>
-
-
-
-
- >
- );
+ return (
+ <>
+
+
+
+
+ >
+ );
}
diff --git a/src/shared/lumeBar.tsx b/src/shared/lumeBar.tsx
index 47d409b3..ff14d2ed 100644
--- a/src/shared/lumeBar.tsx
+++ b/src/shared/lumeBar.tsx
@@ -1,35 +1,37 @@
-import { ActiveAccount } from "@shared/accounts/active";
-import { SettingsIcon } from "@shared/icons";
-import { Logout } from "@shared/logout";
-import { NotificationModal } from "@shared/notification/modal";
-import { useAccount } from "@utils/hooks/useAccount";
-import { Link } from "react-router-dom";
+import { Link } from 'react-router-dom';
+
+import { ActiveAccount } from '@shared/accounts/active';
+import { SettingsIcon } from '@shared/icons';
+import { Logout } from '@shared/logout';
+import { NotificationModal } from '@shared/notification/modal';
+
+import { useAccount } from '@utils/hooks/useAccount';
export function LumeBar() {
- const { status, account } = useAccount();
+ const { status, account } = useAccount();
- return (
-
-
- {status === "loading" ? (
- <>
-
-
- >
- ) : (
- <>
-
-
- >
- )}
-
-
-
-
-
-
- );
+ return (
+
+
+ {status === 'loading' ? (
+ <>
+
+
+ >
+ ) : (
+ <>
+
+
+ >
+ )}
+
+
+
+
+
+
+ );
}
diff --git a/src/shared/mediaUploader.tsx b/src/shared/mediaUploader.tsx
index 6ae4ebec..2c8bc1a3 100644
--- a/src/shared/mediaUploader.tsx
+++ b/src/shared/mediaUploader.tsx
@@ -1,90 +1,92 @@
-import * as Tooltip from "@radix-ui/react-tooltip";
-import { LoaderIcon, MediaIcon } from "@shared/icons";
-import { open } from "@tauri-apps/api/dialog";
-import { Body, fetch } from "@tauri-apps/api/http";
-import { createBlobFromFile } from "@utils/createBlobFromFile";
-import { useState } from "react";
+import * as Tooltip from '@radix-ui/react-tooltip';
+import { open } from '@tauri-apps/api/dialog';
+import { Body, fetch } from '@tauri-apps/api/http';
+import { useState } from 'react';
+
+import { LoaderIcon, MediaIcon } from '@shared/icons';
+
+import { createBlobFromFile } from '@utils/createBlobFromFile';
export function MediaUploader({ setState }: { setState: any }) {
- const [loading, setLoading] = useState(false);
+ const [loading, setLoading] = useState(false);
- const openFileDialog = async () => {
- const selected: any = await open({
- multiple: false,
- filters: [
- {
- name: "Image & Video",
- extensions: ["png", "jpeg", "jpg", "gif", "mp4", "mov"],
- },
- ],
- });
- if (Array.isArray(selected)) {
- // user selected multiple files
- } else if (selected === null) {
- // user cancelled the selection
- } else {
- // start loading
- setLoading(true);
+ const openFileDialog = async () => {
+ const selected: any = await open({
+ multiple: false,
+ filters: [
+ {
+ name: 'Image & Video',
+ extensions: ['png', 'jpeg', 'jpg', 'gif', 'mp4', 'mov'],
+ },
+ ],
+ });
+ if (Array.isArray(selected)) {
+ // user selected multiple files
+ } else if (selected === null) {
+ // user cancelled the selection
+ } else {
+ // start loading
+ setLoading(true);
- const filename = selected.split("/").pop();
- const file = await createBlobFromFile(selected);
- const buf = await file.arrayBuffer();
+ const filename = selected.split('/').pop();
+ const file = await createBlobFromFile(selected);
+ const buf = await file.arrayBuffer();
- const res: { data: { file: { id: string } } } = await fetch(
- "https://void.cat/upload?cli=false",
- {
- method: "POST",
- timeout: 5,
- headers: {
- accept: "*/*",
- "Content-Type": "application/octet-stream",
- "V-Filename": filename,
- "V-Description": "Upload from https://lume.nu",
- "V-Strip-Metadata": "true",
- },
- body: Body.bytes(buf),
- },
- );
+ const res: { data: { file: { id: string } } } = await fetch(
+ 'https://void.cat/upload?cli=false',
+ {
+ method: 'POST',
+ timeout: 5,
+ headers: {
+ accept: '*/*',
+ 'Content-Type': 'application/octet-stream',
+ 'V-Filename': filename,
+ 'V-Description': 'Upload from https://lume.nu',
+ 'V-Strip-Metadata': 'true',
+ },
+ body: Body.bytes(buf),
+ }
+ );
- const image = `https://void.cat/d/${res.data.file.id}.webp`;
+ const image = `https://void.cat/d/${res.data.file.id}.webp`;
- // update state
- setState((prev: string) => `${prev}\n${image}`);
- // stop loading
- setLoading(false);
- }
- };
+ // update state
+ setState((prev: string) => `${prev}\n${image}`);
+ // stop loading
+ setLoading(false);
+ }
+ };
- return (
-
-
-
-
-
-
-
- Upload media
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+ Upload media
+
+
+
+
+
+ );
}
diff --git a/src/shared/navigation.tsx b/src/shared/navigation.tsx
index 68a9325f..c015e8fa 100644
--- a/src/shared/navigation.tsx
+++ b/src/shared/navigation.tsx
@@ -1,65 +1,63 @@
-import { ChatsList } from "@app/chat/components/list";
-import { Disclosure } from "@headlessui/react";
-import { AppHeader } from "@shared/appHeader";
-import { Composer } from "@shared/composer/modal";
-import { NavArrowDownIcon, SpaceIcon, TrendingIcon } from "@shared/icons";
-import { LumeBar } from "@shared/lumeBar";
-import { NavLink } from "react-router-dom";
-import { twMerge } from "tailwind-merge";
+import { Disclosure } from '@headlessui/react';
+import { NavLink } from 'react-router-dom';
+import { twMerge } from 'tailwind-merge';
+
+import { ChatsList } from '@app/chat/components/list';
+
+import { AppHeader } from '@shared/appHeader';
+import { Composer } from '@shared/composer/modal';
+import { NavArrowDownIcon, SpaceIcon, TrendingIcon } from '@shared/icons';
+import { LumeBar } from '@shared/lumeBar';
export function Navigation() {
- return (
-
-
-
-
-
-
- {/* Newsfeed */}
-
-
-
- Feeds
-
-
-
-
- twMerge(
- "flex h-9 items-center gap-2.5 rounded-md px-2.5 text-zinc-200",
- isActive ? "bg-zinc-900/50" : "",
- )
- }
- >
-
-
-
- Spaces
-
-
- twMerge(
- "flex h-9 items-center gap-2.5 rounded-md px-2.5 text-zinc-200",
- isActive ? "bg-zinc-900/50" : "",
- )
- }
- >
-
-
-
- Trending
-
-
-
- {/* Channels
+ return (
+
+
+
+
+
+
+ {/* Newsfeed */}
+
+
+
+ Feeds
+
+
+
+
+ twMerge(
+ 'flex h-9 items-center gap-2.5 rounded-md px-2.5 text-zinc-200',
+ isActive ? 'bg-zinc-900/50' : ''
+ )
+ }
+ >
+
+
+
+ Spaces
+
+
+ twMerge(
+ 'flex h-9 items-center gap-2.5 rounded-md px-2.5 text-zinc-200',
+ isActive ? 'bg-zinc-900/50' : ''
+ )
+ }
+ >
+
+
+
+ Trending
+
+
+
+ {/* Channels
{({ open }) => (
@@ -86,36 +84,32 @@ export function Navigation() {
)}
*/}
- {/* Chats */}
-
- {({ open }) => (
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
- )}
-
-
-
-
-
-
- );
+ {/* Chats */}
+
+ {({ open }) => (
+
+
+
+
+
+
+ Chats
+
+
+
+
+
+
+ )}
+
+
+
+
+
+
+ );
}
diff --git a/src/shared/networkStatusIndicator.tsx b/src/shared/networkStatusIndicator.tsx
index 2b538bd2..e5e3fb46 100644
--- a/src/shared/networkStatusIndicator.tsx
+++ b/src/shared/networkStatusIndicator.tsx
@@ -1,13 +1,13 @@
-import { useNetworkStatus } from "@utils/hooks/useNetworkStatus";
+import { useNetworkStatus } from '@utils/hooks/useNetworkStatus';
export function NetworkStatusIndicator() {
- const isOnline = useNetworkStatus();
+ const isOnline = useNetworkStatus();
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/notes/contents/kind1.tsx b/src/shared/notes/contents/kind1.tsx
index ab9a1abe..53d94191 100644
--- a/src/shared/notes/contents/kind1.tsx
+++ b/src/shared/notes/contents/kind1.tsx
@@ -1,41 +1,40 @@
-import { MentionNote } from "@shared/notes/mentions/note";
-import { ImagePreview } from "@shared/notes/preview/image";
-import { LinkPreview } from "@shared/notes/preview/link";
-import { VideoPreview } from "@shared/notes/preview/video";
-import { ReactNode } from "react";
+import { ReactNode } from 'react';
+
+import { MentionNote } from '@shared/notes/mentions/note';
+import { ImagePreview } from '@shared/notes/preview/image';
+import { LinkPreview } from '@shared/notes/preview/link';
+import { VideoPreview } from '@shared/notes/preview/video';
export function Kind1({
- content,
- truncate = false,
+ content,
+ truncate = false,
}: {
- content: {
- original: string;
- parsed: ReactNode[];
- notes: string[];
- images: string[];
- videos: string[];
- links: string[];
- };
- truncate?: boolean;
+ content: {
+ original: string;
+ parsed: ReactNode[];
+ notes: string[];
+ images: string[];
+ videos: string[];
+ links: string[];
+ };
+ truncate?: boolean;
}) {
- return (
- <>
-
- {content.parsed}
-
- {content.images.length > 0 && (
-
- )}
- {content.videos.length > 0 &&
}
- {content.links.length > 0 &&
}
- {content.notes.length > 0 &&
- content.notes.map((note: string) => (
-
- ))}
- >
- );
+ return (
+ <>
+
+ {content.parsed}
+
+ {content.images.length > 0 && (
+
+ )}
+ {content.videos.length > 0 &&
}
+ {content.links.length > 0 &&
}
+ {content.notes.length > 0 &&
+ content.notes.map((note: string) =>
)}
+ >
+ );
}
diff --git a/src/shared/notes/contents/kind1063.tsx b/src/shared/notes/contents/kind1063.tsx
index 08e4a1d4..ea5d7f82 100644
--- a/src/shared/notes/contents/kind1063.tsx
+++ b/src/shared/notes/contents/kind1063.tsx
@@ -1,23 +1,24 @@
-import { NDKTag } from "@nostr-dev-kit/ndk";
-import { Image } from "@shared/image";
+import { NDKTag } from '@nostr-dev-kit/ndk';
+
+import { Image } from '@shared/image';
function isImage(url: string) {
- return /\.(jpg|jpeg|gif|png|webp|avif)$/.test(url);
+ return /\.(jpg|jpeg|gif|png|webp|avif)$/.test(url);
}
export function Kind1063({ metadata }: { metadata: NDKTag[] }) {
- const url = metadata[0][1];
+ const url = metadata[0][1];
- return (
-
- {isImage(url) && (
-
- )}
-
- );
+ return (
+
+ {isImage(url) && (
+
+ )}
+
+ );
}
diff --git a/src/shared/notes/mentions/note.tsx b/src/shared/notes/mentions/note.tsx
index 32d177a7..dc58eaae 100644
--- a/src/shared/notes/mentions/note.tsx
+++ b/src/shared/notes/mentions/note.tsx
@@ -1,70 +1,73 @@
-import { createBlock } from "@libs/storage";
-import { Kind1 } from "@shared/notes/contents/kind1";
-import { Kind1063 } from "@shared/notes/contents/kind1063";
-import { NoteSkeleton } from "@shared/notes/skeleton";
-import { User } from "@shared/user";
-import { useMutation, useQueryClient } from "@tanstack/react-query";
-import { useEvent } from "@utils/hooks/useEvent";
-import { memo } from "react";
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { memo } from 'react';
+
+import { createBlock } from '@libs/storage';
+
+import { Kind1 } from '@shared/notes/contents/kind1';
+import { Kind1063 } from '@shared/notes/contents/kind1063';
+import { NoteSkeleton } from '@shared/notes/skeleton';
+import { User } from '@shared/user';
+
+import { useEvent } from '@utils/hooks/useEvent';
export const MentionNote = memo(function MentionNote({ id }: { id: string }) {
- const queryClient = useQueryClient();
- const { status, data } = useEvent(id);
+ const queryClient = useQueryClient();
+ const { status, data } = useEvent(id);
- const block = useMutation({
- mutationFn: (data: any) => {
- return createBlock(data.kind, data.title, data.content);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["blocks"] });
- },
- });
+ const block = useMutation({
+ mutationFn: (data: any) => {
+ return createBlock(data.kind, data.title, data.content);
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['blocks'] });
+ },
+ });
- const openThread = (event: any, thread: string) => {
- const selection = window.getSelection();
- if (selection.toString().length === 0) {
- block.mutate({ kind: 2, title: "Thread", content: thread });
- } else {
- event.stopPropagation();
- }
- };
+ const openThread = (event: any, thread: string) => {
+ const selection = window.getSelection();
+ if (selection.toString().length === 0) {
+ block.mutate({ kind: 2, title: 'Thread', content: thread });
+ } else {
+ event.stopPropagation();
+ }
+ };
- return (
-
openThread(e, id)}
- onKeyDown={(e) => openThread(e, id)}
- className="mt-3 rounded-lg bg-zinc-800/50 border-t border-zinc-700/50 px-3 py-3"
- >
- {status === "loading" ? (
-
- ) : status === "success" ? (
- <>
-
-
- {data.kind === 1 && (
-
- )}
- {data.kind === 1063 &&
}
- {data.kind !== 1 && data.kind !== 1063 && (
-
-
-
- Kind: {data.kind}
-
-
- Lume isn't fully support this kind in newsfeed
-
-
-
-
- )}
-
- >
- ) : (
-
Failed to fetch event
- )}
-
- );
+ return (
+
openThread(e, id)}
+ onKeyDown={(e) => openThread(e, id)}
+ role="button"
+ tabIndex={0}
+ className="mt-3 rounded-lg border-t border-zinc-700/50 bg-zinc-800/50 px-3 py-3"
+ >
+ {status === 'loading' ? (
+
+ ) : status === 'success' ? (
+ <>
+
+
+ {data.kind === 1 &&
}
+ {data.kind === 1063 &&
}
+ {data.kind !== 1 && data.kind !== 1063 && (
+
+
+
+ Kind: {data.kind}
+
+
+ Lume isn't fully support this kind in newsfeed
+
+
+
+
+ )}
+
+ >
+ ) : (
+
Failed to fetch event
+ )}
+
+ );
});
diff --git a/src/shared/notes/mentions/user.tsx b/src/shared/notes/mentions/user.tsx
index 3e39edcc..0ca6109b 100644
--- a/src/shared/notes/mentions/user.tsx
+++ b/src/shared/notes/mentions/user.tsx
@@ -1,16 +1,17 @@
-import { useProfile } from "@utils/hooks/useProfile";
-import { shortenKey } from "@utils/shortenKey";
-import { Link } from "react-router-dom";
+import { Link } from 'react-router-dom';
+
+import { useProfile } from '@utils/hooks/useProfile';
+import { shortenKey } from '@utils/shortenKey';
export function MentionUser({ pubkey }: { pubkey: string }) {
- const { user } = useProfile(pubkey);
+ const { user } = useProfile(pubkey);
- return (
-
- @{user?.name || user?.displayName || shortenKey(pubkey)}
-
- );
+ return (
+
+ @{user?.name || user?.displayName || shortenKey(pubkey)}
+
+ );
}
diff --git a/src/shared/notes/metadata.tsx b/src/shared/notes/metadata.tsx
index faf5fe93..cdff9d85 100644
--- a/src/shared/notes/metadata.tsx
+++ b/src/shared/notes/metadata.tsx
@@ -1,171 +1,171 @@
-import { createBlock, createReplyNote } from "@libs/storage";
-import { NDKEvent, NDKFilter } from "@nostr-dev-kit/ndk";
-import * as Tooltip from "@radix-ui/react-tooltip";
-import { LoaderIcon, ReplyIcon, RepostIcon, ZapIcon } from "@shared/icons";
-import { ThreadIcon } from "@shared/icons/thread";
-import { NoteReply } from "@shared/notes/metadata/reply";
-import { NoteRepost } from "@shared/notes/metadata/repost";
-import { NoteZap } from "@shared/notes/metadata/zap";
-import { RelayContext } from "@shared/relayProvider";
-import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
-import { decode } from "light-bolt11-decoder";
-import { useContext } from "react";
+import { NDKEvent, NDKFilter } from '@nostr-dev-kit/ndk';
+import * as Tooltip from '@radix-ui/react-tooltip';
+import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
+import { decode } from 'light-bolt11-decoder';
+import { useContext } from 'react';
+
+import { createBlock, createReplyNote } from '@libs/storage';
+
+import { LoaderIcon, ReplyIcon, RepostIcon, ZapIcon } from '@shared/icons';
+import { ThreadIcon } from '@shared/icons/thread';
+import { NoteReply } from '@shared/notes/metadata/reply';
+import { NoteRepost } from '@shared/notes/metadata/repost';
+import { NoteZap } from '@shared/notes/metadata/zap';
+import { RelayContext } from '@shared/relayProvider';
export function NoteMetadata({
- id,
- rootID,
- eventPubkey,
+ id,
+ rootID,
+ eventPubkey,
}: {
- id: string;
- rootID?: string;
- eventPubkey: string;
+ id: string;
+ rootID?: string;
+ eventPubkey: string;
}) {
- const ndk = useContext(RelayContext);
- const queryClient = useQueryClient();
+ const ndk = useContext(RelayContext);
+ const queryClient = useQueryClient();
- const { status, data } = useQuery(["note-metadata", id], async () => {
- let replies = 0;
- let reposts = 0;
- let zap = 0;
+ const { status, data } = useQuery(['note-metadata', id], async () => {
+ let replies = 0;
+ let reposts = 0;
+ let zap = 0;
- const filter: NDKFilter = {
- "#e": [id],
- kinds: [1, 6, 9735],
- };
+ const filter: NDKFilter = {
+ '#e': [id],
+ kinds: [1, 6, 9735],
+ };
- const events = await ndk.fetchEvents(filter);
- events.forEach((event: NDKEvent) => {
- switch (event.kind) {
- case 1:
- replies += 1;
- createReplyNote(
- id,
- event.id,
- event.pubkey,
- event.kind,
- event.tags,
- event.content,
- event.created_at,
- );
- break;
- case 6:
- reposts += 1;
- break;
- case 9735: {
- const bolt11 = event.tags.find((tag) => tag[0] === "bolt11")[1];
- if (bolt11) {
- const decoded = decode(bolt11);
- const amount = decoded.sections.find(
- (item) => item.name === "amount",
- );
- const sats = amount.value / 1000;
- zap += sats;
- }
- break;
- }
- default:
- break;
- }
- });
+ const events = await ndk.fetchEvents(filter);
+ events.forEach((event: NDKEvent) => {
+ switch (event.kind) {
+ case 1:
+ replies += 1;
+ createReplyNote(
+ id,
+ event.id,
+ event.pubkey,
+ event.kind,
+ event.tags,
+ event.content,
+ event.created_at
+ );
+ break;
+ case 6:
+ reposts += 1;
+ break;
+ case 9735: {
+ const bolt11 = event.tags.find((tag) => tag[0] === 'bolt11')[1];
+ if (bolt11) {
+ const decoded = decode(bolt11);
+ const amount = decoded.sections.find((item) => item.name === 'amount');
+ const sats = amount.value / 1000;
+ zap += sats;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ });
- return { replies, reposts, zap };
- });
+ return { replies, reposts, zap };
+ });
- const block = useMutation({
- mutationFn: (data: any) => {
- return createBlock(data.kind, data.title, data.content);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["blocks"] });
- },
- });
+ const block = useMutation({
+ mutationFn: (data: any) => {
+ return createBlock(data.kind, data.title, data.content);
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['blocks'] });
+ },
+ });
- const openThread = (thread: string) => {
- const selection = window.getSelection();
- if (selection.toString().length === 0) {
- block.mutate({ kind: 2, title: "Thread", content: thread });
- } else {
- event.stopPropagation();
- }
- };
+ const openThread = (thread: string) => {
+ const selection = window.getSelection();
+ if (selection.toString().length === 0) {
+ block.mutate({ kind: 2, title: 'Thread', content: thread });
+ } else {
+ event.stopPropagation();
+ }
+ };
- if (status === "loading") {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- }
+ if (status === 'loading') {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
- Open thread
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Open thread
+
+
+
+
+
+
+ );
}
diff --git a/src/shared/notes/metadata/reply.tsx b/src/shared/notes/metadata/reply.tsx
index b515416b..2e552cdc 100644
--- a/src/shared/notes/metadata/reply.tsx
+++ b/src/shared/notes/metadata/reply.tsx
@@ -1,41 +1,49 @@
-import * as Tooltip from "@radix-ui/react-tooltip";
-import { ReplyIcon } from "@shared/icons";
-import { useComposer } from "@stores/composer";
-import { compactNumber } from "@utils/number";
+import * as Tooltip from '@radix-ui/react-tooltip';
+
+import { ReplyIcon } from '@shared/icons';
+
+import { useComposer } from '@stores/composer';
+
+import { compactNumber } from '@utils/number';
export function NoteReply({
- id,
- rootID,
- pubkey,
- replies,
-}: { id: string; rootID?: string; pubkey: string; replies: number }) {
- const setReply = useComposer((state) => state.setReply);
+ id,
+ rootID,
+ pubkey,
+ replies,
+}: {
+ id: string;
+ rootID?: string;
+ pubkey: string;
+ replies: number;
+}) {
+ const setReply = useComposer((state) => state.setReply);
- return (
-
-
-
-
- Quick reply
-
-
-
-
- );
+ return (
+
+
+
+
+ Quick reply
+
+
+
+
+ );
}
diff --git a/src/shared/notes/metadata/repost.tsx b/src/shared/notes/metadata/repost.tsx
index 15669e2c..36d66978 100644
--- a/src/shared/notes/metadata/repost.tsx
+++ b/src/shared/notes/metadata/repost.tsx
@@ -1,40 +1,47 @@
-import * as Tooltip from "@radix-ui/react-tooltip";
-import { RepostIcon } from "@shared/icons";
-import { useComposer } from "@stores/composer";
-import { compactNumber } from "@utils/number";
+import * as Tooltip from '@radix-ui/react-tooltip';
+
+import { RepostIcon } from '@shared/icons';
+
+import { useComposer } from '@stores/composer';
+
+import { compactNumber } from '@utils/number';
export function NoteRepost({
- id,
- pubkey,
- reposts,
-}: { id: string; pubkey: string; reposts: number }) {
- const setRepost = useComposer((state) => state.setRepost);
+ id,
+ pubkey,
+ reposts,
+}: {
+ id: string;
+ pubkey: string;
+ reposts: number;
+}) {
+ const setRepost = useComposer((state) => state.setRepost);
- return (
-
-
-
-
- Repost
-
-
-
-
- );
+ return (
+
+
+
+
+ Repost
+
+
+
+
+ );
}
diff --git a/src/shared/notes/metadata/zap.tsx b/src/shared/notes/metadata/zap.tsx
index 70aafc65..3ae2a0fe 100644
--- a/src/shared/notes/metadata/zap.tsx
+++ b/src/shared/notes/metadata/zap.tsx
@@ -1,32 +1,34 @@
-import * as Tooltip from "@radix-ui/react-tooltip";
-import { ZapIcon } from "@shared/icons";
-import { compactNumber } from "@utils/number";
+import * as Tooltip from '@radix-ui/react-tooltip';
+
+import { ZapIcon } from '@shared/icons';
+
+import { compactNumber } from '@utils/number';
export function NoteZap({ zaps }: { zaps: number }) {
- return (
-
-
-
-
- Coming Soon
-
-
-
-
- );
+ return (
+
+
+
+
+ Coming Soon
+
+
+
+
+ );
}
diff --git a/src/shared/notes/note.tsx b/src/shared/notes/note.tsx
index ddd2ea52..6ae845e2 100644
--- a/src/shared/notes/note.tsx
+++ b/src/shared/notes/note.tsx
@@ -1,89 +1,86 @@
-import { Kind1 } from "@shared/notes/contents/kind1";
-import { Kind1063 } from "@shared/notes/contents/kind1063";
-import { NoteMetadata } from "@shared/notes/metadata";
-import { NoteParent } from "@shared/notes/parent";
-import { Repost } from "@shared/notes/repost";
-import { User } from "@shared/user";
-import { parser } from "@utils/parser";
-import { LumeEvent } from "@utils/types";
-import { useMemo } from "react";
+import { useMemo } from 'react';
+
+import { Kind1 } from '@shared/notes/contents/kind1';
+import { Kind1063 } from '@shared/notes/contents/kind1063';
+import { NoteMetadata } from '@shared/notes/metadata';
+import { NoteParent } from '@shared/notes/parent';
+import { Repost } from '@shared/notes/repost';
+import { User } from '@shared/user';
+
+import { parser } from '@utils/parser';
+import { LumeEvent } from '@utils/types';
interface Note {
- event: LumeEvent;
- block?: number;
+ event: LumeEvent;
}
-export function Note({ event, block }: Note) {
- const isRepost = event.kind === 6;
+export function Note({ event }: Note) {
+ const isRepost = event.kind === 6;
- const renderParent = useMemo(() => {
- if (!isRepost && event.parent_id && event.parent_id !== event.event_id) {
- return
;
- } else {
- return null;
- }
- }, [event.parent_id]);
+ const renderParent = useMemo(() => {
+ if (!isRepost && event.parent_id && event.parent_id !== event.event_id) {
+ return
;
+ } else {
+ return null;
+ }
+ }, [event.parent_id]);
- const renderRepost = useMemo(() => {
- if (isRepost) {
- return
;
- } else {
- return null;
- }
- }, [event.kind]);
+ const renderRepost = useMemo(() => {
+ if (isRepost) {
+ return
;
+ } else {
+ return null;
+ }
+ }, [event.kind]);
- const renderContent = useMemo(() => {
- switch (event.kind) {
- case 1: {
- const content = parser(event);
- return
;
- }
- case 6:
- return null;
- case 1063:
- return
;
- default:
- return (
-
-
-
- Kind: {event.kind}
-
-
- Lume isn't fully support this kind in newsfeed
-
-
-
-
- );
- }
- }, [event.kind]);
+ const renderContent = useMemo(() => {
+ switch (event.kind) {
+ case 1: {
+ const content = parser(event);
+ return
;
+ }
+ case 6:
+ return null;
+ case 1063:
+ return
;
+ default:
+ return (
+
+
+
+ Kind: {event.kind}
+
+
+ Lume isn't fully support this kind in newsfeed
+
+
+
+
+ );
+ }
+ }, [event.kind]);
- return (
-
-
- {renderParent}
-
-
-
- {renderContent}
- {!isRepost && (
-
- )}
-
-
- {renderRepost}
-
-
- );
+ return (
+
+
+ {renderParent}
+
+
+
+ {renderContent}
+ {!isRepost && (
+
+ )}
+
+
+ {renderRepost}
+
+
+ );
}
diff --git a/src/shared/notes/parent.tsx b/src/shared/notes/parent.tsx
index 9d760f7e..ac9eb95b 100644
--- a/src/shared/notes/parent.tsx
+++ b/src/shared/notes/parent.tsx
@@ -1,48 +1,46 @@
-import { Kind1 } from "@shared/notes/contents/kind1";
-import { Kind1063 } from "@shared/notes/contents/kind1063";
-import { NoteMetadata } from "@shared/notes/metadata";
-import { NoteSkeleton } from "@shared/notes/skeleton";
-import { User } from "@shared/user";
-import { useEvent } from "@utils/hooks/useEvent";
+import { Kind1 } from '@shared/notes/contents/kind1';
+import { Kind1063 } from '@shared/notes/contents/kind1063';
+import { NoteMetadata } from '@shared/notes/metadata';
+import { NoteSkeleton } from '@shared/notes/skeleton';
+import { User } from '@shared/user';
+
+import { useEvent } from '@utils/hooks/useEvent';
export function NoteParent({ id }: { id: string }) {
- const { status, data } = useEvent(id);
+ const { status, data } = useEvent(id);
- return (
-
-
- {status === "loading" ? (
-
- ) : status === "success" ? (
- <>
-
-
- {data.kind === 1 &&
}
- {data.kind === 1063 &&
}
- {data.kind !== 1 && data.kind !== 1063 && (
-
-
-
- Kind: {data.kind}
-
-
- Lume isn't fully support this kind in newsfeed
-
-
-
-
{data.content || data.toString()}
-
-
- )}
-
-
- >
- ) : (
-
Failed to fetch event
- )}
-
- );
+ return (
+
+
+ {status === 'loading' ? (
+
+ ) : status === 'success' ? (
+ <>
+
+
+ {data.kind === 1 &&
}
+ {data.kind === 1063 &&
}
+ {data.kind !== 1 && data.kind !== 1063 && (
+
+
+
+ Kind: {data.kind}
+
+
+ Lume isn't fully support this kind in newsfeed
+
+
+
+
{data.content || data.toString()}
+
+
+ )}
+
+
+ >
+ ) : (
+
Failed to fetch event
+ )}
+
+ );
}
diff --git a/src/shared/notes/preview/image.tsx b/src/shared/notes/preview/image.tsx
index 789ccf4a..0b58218e 100644
--- a/src/shared/notes/preview/image.tsx
+++ b/src/shared/notes/preview/image.tsx
@@ -1,25 +1,22 @@
-import { Image } from "@shared/image";
+import { Image } from '@shared/image';
-export function ImagePreview({
- urls,
- truncate,
-}: { urls: string[]; truncate?: boolean }) {
- return (
-
-
- {urls.map((url) => (
-
-
-
- ))}
-
-
- );
+export function ImagePreview({ urls, truncate }: { urls: string[]; truncate?: boolean }) {
+ return (
+
+
+ {urls.map((url) => (
+
+
+
+ ))}
+
+
+ );
}
diff --git a/src/shared/notes/preview/link.tsx b/src/shared/notes/preview/link.tsx
index debb0705..7d43883f 100644
--- a/src/shared/notes/preview/link.tsx
+++ b/src/shared/notes/preview/link.tsx
@@ -1,64 +1,62 @@
-import { Image } from "@shared/image";
-import { useOpenGraph } from "@utils/hooks/useOpenGraph";
+import { Image } from '@shared/image';
+
+import { useOpenGraph } from '@utils/hooks/useOpenGraph';
export function LinkPreview({ urls }: { urls: string[] }) {
- const domain = new URL(urls[0]);
- const { status, data, error } = useOpenGraph(urls[0]);
+ const domain = new URL(urls[0]);
+ const { status, data, error } = useOpenGraph(urls[0]);
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/notes/preview/video.tsx b/src/shared/notes/preview/video.tsx
index 5b6ef340..c5c0ebf1 100644
--- a/src/shared/notes/preview/video.tsx
+++ b/src/shared/notes/preview/video.tsx
@@ -1,19 +1,19 @@
-import ReactPlayer from "react-player/es6";
+import ReactPlayer from 'react-player/es6';
export function VideoPreview({ urls }: { urls: string[] }) {
- return (
-
- {urls.map((url) => (
-
- ))}
-
- );
+ return (
+
+ {urls.map((url) => (
+
+ ))}
+
+ );
}
diff --git a/src/shared/notes/replies/form.tsx b/src/shared/notes/replies/form.tsx
index 10de49b1..dbb870c7 100644
--- a/src/shared/notes/replies/form.tsx
+++ b/src/shared/notes/replies/form.tsx
@@ -1,77 +1,82 @@
-import { usePublish } from "@libs/ndk";
-import { Button } from "@shared/button";
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR, FULL_RELAYS } from "@stores/constants";
-import { useProfile } from "@utils/hooks/useProfile";
-import { shortenKey } from "@utils/shortenKey";
-import { useState } from "react";
+import { useState } from 'react';
+
+import { usePublish } from '@libs/ndk';
+
+import { Button } from '@shared/button';
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR, FULL_RELAYS } from '@stores/constants';
+
+import { useProfile } from '@utils/hooks/useProfile';
+import { shortenKey } from '@utils/shortenKey';
export function NoteReplyForm({
- rootID,
- userPubkey,
-}: { rootID: string; userPubkey: string }) {
- const publish = usePublish();
- const { status, user } = useProfile(userPubkey);
- const [value, setValue] = useState("");
+ rootID,
+ userPubkey,
+}: {
+ rootID: string;
+ userPubkey: string;
+}) {
+ const publish = usePublish();
+ const { status, user } = useProfile(userPubkey);
+ const [value, setValue] = useState('');
- const submit = () => {
- const tags = [["e", rootID, FULL_RELAYS[0], "root"]];
+ const submit = () => {
+ const tags = [['e', rootID, FULL_RELAYS[0], 'root']];
- // publish event
- publish({ content: value, kind: 1, tags });
+ // publish event
+ publish({ content: value, kind: 1, tags });
- // reset form
- setValue("");
- };
+ // reset form
+ setValue('');
+ };
- return (
-
-
-
-
- {status === "loading" ? (
-
- ) : (
-
-
-
-
-
-
-
- Reply as
-
-
- {user.nip05 || user.name || shortenKey(userPubkey)}
-
-
-
-
-
-
-
- )}
-
-
- );
+ return (
+
+
+
+
+ {status === 'loading' ? (
+
+ ) : (
+
+
+
+
+
+
+
Reply as
+
+ {user.nip05 || user.name || shortenKey(userPubkey)}
+
+
+
+
+
+
+
+ )}
+
+
+ );
}
diff --git a/src/shared/notes/replies/item.tsx b/src/shared/notes/replies/item.tsx
index 788dc992..22d12af3 100644
--- a/src/shared/notes/replies/item.tsx
+++ b/src/shared/notes/replies/item.tsx
@@ -1,20 +1,21 @@
-import { Kind1 } from "@shared/notes/contents/kind1";
-import { NoteMetadata } from "@shared/notes/metadata";
-import { User } from "@shared/user";
-import { parser } from "@utils/parser";
+import { Kind1 } from '@shared/notes/contents/kind1';
+import { NoteMetadata } from '@shared/notes/metadata';
+import { User } from '@shared/user';
+
+import { parser } from '@utils/parser';
export function Reply({ data }: { data: any }) {
- const content = parser(data);
+ const content = parser(data);
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/notes/replies/list.tsx b/src/shared/notes/replies/list.tsx
index 25575ec2..d27b6622 100644
--- a/src/shared/notes/replies/list.tsx
+++ b/src/shared/notes/replies/list.tsx
@@ -1,44 +1,44 @@
-import { getReplies } from "@libs/storage";
-import { NDKEvent } from "@nostr-dev-kit/ndk";
-import { Reply } from "@shared/notes/replies/item";
-import { useQuery } from "@tanstack/react-query";
+import { NDKEvent } from '@nostr-dev-kit/ndk';
+import { useQuery } from '@tanstack/react-query';
+
+import { getReplies } from '@libs/storage';
+
+import { Reply } from '@shared/notes/replies/item';
export function RepliesList({ parent_id }: { parent_id: string }) {
- const { status, data } = useQuery(["replies", parent_id], async () => {
- return await getReplies(parent_id);
- });
+ const { status, data } = useQuery(['replies', parent_id], async () => {
+ return await getReplies(parent_id);
+ });
- return (
-
-
-
Replies
-
-
- {status === "loading" ? (
-
- ) : data.length === 0 ? (
-
-
-
-
👋
-
- Share your thought on it...
-
-
-
-
- ) : (
- data.map((event: NDKEvent) =>
)
- )}
-
-
- );
+ return (
+
+
+
Replies
+
+
+ {status === 'loading' ? (
+
+ ) : data.length === 0 ? (
+
+
+
+
👋
+
Share your thought on it...
+
+
+
+ ) : (
+ data.map((event: NDKEvent) =>
)
+ )}
+
+
+ );
}
diff --git a/src/shared/notes/repost.tsx b/src/shared/notes/repost.tsx
index d5b21193..7e0a685e 100644
--- a/src/shared/notes/repost.tsx
+++ b/src/shared/notes/repost.tsx
@@ -1,51 +1,49 @@
-import { Kind1 } from "@shared/notes/contents/kind1";
-import { Kind1063 } from "@shared/notes/contents/kind1063";
-import { NoteMetadata } from "@shared/notes/metadata";
-import { NoteSkeleton } from "@shared/notes/skeleton";
-import { User } from "@shared/user";
-import { useEvent } from "@utils/hooks/useEvent";
-import { getRepostID } from "@utils/transform";
-import { LumeEvent } from "@utils/types";
+import { Kind1 } from '@shared/notes/contents/kind1';
+import { Kind1063 } from '@shared/notes/contents/kind1063';
+import { NoteMetadata } from '@shared/notes/metadata';
+import { NoteSkeleton } from '@shared/notes/skeleton';
+import { User } from '@shared/user';
+
+import { useEvent } from '@utils/hooks/useEvent';
+import { getRepostID } from '@utils/transform';
+import { LumeEvent } from '@utils/types';
export function Repost({ event }: { event: LumeEvent }) {
- const repostID = getRepostID(event.tags);
- const { status, data } = useEvent(repostID);
+ const repostID = getRepostID(event.tags);
+ const { status, data } = useEvent(repostID);
- return (
-
-
- {status === "loading" ? (
-
- ) : status === "success" ? (
- <>
-
-
- {data.kind === 1 &&
}
- {data.kind === 1063 &&
}
- {data.kind !== 1 && data.kind !== 1063 && (
-
-
-
- Kind: {data.kind}
-
-
- Lume isn't fully support this kind in newsfeed
-
-
-
-
{data.content || data.toString()}
-
-
- )}
-
-
- >
- ) : (
-
Failed to fetch event
- )}
-
- );
+ return (
+
+
+ {status === 'loading' ? (
+
+ ) : status === 'success' ? (
+ <>
+
+
+ {data.kind === 1 &&
}
+ {data.kind === 1063 &&
}
+ {data.kind !== 1 && data.kind !== 1063 && (
+
+
+
+ Kind: {data.kind}
+
+
+ Lume isn't fully support this kind in newsfeed
+
+
+
+
{data.content || data.toString()}
+
+
+ )}
+
+
+ >
+ ) : (
+
Failed to fetch event
+ )}
+
+ );
}
diff --git a/src/shared/notes/skeleton.tsx b/src/shared/notes/skeleton.tsx
index 18e836ce..3f417f03 100644
--- a/src/shared/notes/skeleton.tsx
+++ b/src/shared/notes/skeleton.tsx
@@ -1,19 +1,19 @@
export function NoteSkeleton() {
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/shared/notification/modal.tsx b/src/shared/notification/modal.tsx
index 00adf23f..75ab4b75 100644
--- a/src/shared/notification/modal.tsx
+++ b/src/shared/notification/modal.tsx
@@ -1,165 +1,167 @@
-import { NotificationUser } from "./user";
-import { Dialog, Transition } from "@headlessui/react";
-import { NDKEvent, NDKFilter } from "@nostr-dev-kit/ndk";
-import { BellIcon, CancelIcon, LoaderIcon } from "@shared/icons";
-import { RelayContext } from "@shared/relayProvider";
-import { User } from "@shared/user";
-import { useQuery } from "@tanstack/react-query";
-import { dateToUnix, getHourAgo } from "@utils/date";
-import { Fragment, useContext, useRef, useState } from "react";
+import { Dialog, Transition } from '@headlessui/react';
+import { NDKEvent, NDKFilter } from '@nostr-dev-kit/ndk';
+import { useQuery } from '@tanstack/react-query';
+import { Fragment, useContext, useRef, useState } from 'react';
+
+import { BellIcon, CancelIcon, LoaderIcon } from '@shared/icons';
+import { RelayContext } from '@shared/relayProvider';
+import { User } from '@shared/user';
+
+import { dateToUnix, getHourAgo } from '@utils/date';
+
+import { NotificationUser } from './user';
export function NotificationModal({ pubkey }: { pubkey: string }) {
- const ndk = useContext(RelayContext);
- const now = useRef(new Date());
+ const ndk = useContext(RelayContext);
+ const now = useRef(new Date());
- const [isOpen, setIsOpen] = useState(false);
- const [refresh, setRefresh] = useState(false);
+ const [isOpen, setIsOpen] = useState(false);
- const { status, data } = useQuery(
- ["user-notification", pubkey],
- async () => {
- const filter: NDKFilter = {
- "#p": [pubkey],
- kinds: [1, 6, 7, 9735],
- since: dateToUnix(getHourAgo(48, now.current)),
- };
- const events = await ndk.fetchEvents(filter);
- return [...events];
- },
- {
- refetchOnMount: false,
- refetchOnReconnect: false,
- refetchOnWindowFocus: false,
- staleTime: Infinity,
- },
- );
+ const { status, data } = useQuery(
+ ['user-notification', pubkey],
+ async () => {
+ const filter: NDKFilter = {
+ '#p': [pubkey],
+ kinds: [1, 6, 7, 9735],
+ since: dateToUnix(getHourAgo(48, now.current)),
+ };
+ const events = await ndk.fetchEvents(filter);
+ return [...events];
+ },
+ {
+ refetchOnMount: false,
+ refetchOnReconnect: false,
+ refetchOnWindowFocus: false,
+ staleTime: Infinity,
+ }
+ );
- const closeModal = () => {
- setIsOpen(false);
- };
+ const closeModal = () => {
+ setIsOpen(false);
+ };
- const openModal = () => {
- setIsOpen(true);
- };
+ const openModal = () => {
+ setIsOpen(true);
+ };
- const renderItem = (event: NDKEvent) => {
- if (event.kind === 1) {
- return (
-
- );
- }
+ const renderItem = (event: NDKEvent) => {
+ if (event.kind === 1) {
+ return (
+
+ );
+ }
- if (event.kind === 6) {
- return (
-
-
-
- );
- }
+ if (event.kind === 6) {
+ return (
+
+
+
+ );
+ }
- if (event.kind === 7) {
- return (
-
-
-
- );
- }
+ if (event.kind === 7) {
+ return (
+
+
+
+ );
+ }
- if (event.kind === 9735) {
- return (
-
-
-
- );
- }
+ if (event.kind === 9735) {
+ return (
+
+
+
+ );
+ }
- return
{event.content}
;
- };
+ return
{event.content}
;
+ };
- return (
- <>
-
-
-
-
- >
- );
+ return (
+ <>
+
+
+
+
+ >
+ );
}
diff --git a/src/shared/notification/user.tsx b/src/shared/notification/user.tsx
index 39c2550b..38841659 100644
--- a/src/shared/notification/user.tsx
+++ b/src/shared/notification/user.tsx
@@ -1,42 +1,41 @@
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { useProfile } from "@utils/hooks/useProfile";
-import { shortenKey } from "@utils/shortenKey";
+import { Image } from '@shared/image';
-export function NotificationUser({
- pubkey,
- desc,
-}: { pubkey: string; desc: string }) {
- const { status, user } = useProfile(pubkey);
+import { DEFAULT_AVATAR } from '@stores/constants';
- if (status === "loading") {
- return (
-
- );
- }
+import { useProfile } from '@utils/hooks/useProfile';
+import { shortenKey } from '@utils/shortenKey';
- return (
-
-
-
-
-
-
- {user.nip05 || user.name || user.displayName || shortenKey(pubkey)}
-
- {desc}
-
-
- );
+export function NotificationUser({ pubkey, desc }: { pubkey: string; desc: string }) {
+ const { status, user } = useProfile(pubkey);
+
+ if (status === 'loading') {
+ return (
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+ {user.nip05 || user.name || user.displayName || shortenKey(pubkey)}
+
+ {desc}
+
+
+ );
}
diff --git a/src/shared/protected.tsx b/src/shared/protected.tsx
index 79aff269..78943aec 100644
--- a/src/shared/protected.tsx
+++ b/src/shared/protected.tsx
@@ -1,13 +1,14 @@
-import { useAccount } from "@utils/hooks/useAccount";
-import { ReactNode } from "react";
-import { Navigate } from "react-router-dom";
+import { ReactNode } from 'react';
+import { Navigate } from 'react-router-dom';
+
+import { useAccount } from '@utils/hooks/useAccount';
export function Protected({ children }: { children: ReactNode }) {
- const { status, account } = useAccount();
+ const { status, account } = useAccount();
- if (status === "success" && !account) {
- return
;
- }
+ if (status === 'success' && !account) {
+ return
;
+ }
- return children;
+ return children;
}
diff --git a/src/shared/relayProvider.tsx b/src/shared/relayProvider.tsx
index bba6832a..36911705 100644
--- a/src/shared/relayProvider.tsx
+++ b/src/shared/relayProvider.tsx
@@ -1,14 +1,15 @@
-import { initNDK } from "@libs/ndk";
-import { getSetting } from "@libs/storage";
-import NDK from "@nostr-dev-kit/ndk";
-import { createContext } from "react";
+import NDK from '@nostr-dev-kit/ndk';
+import { createContext } from 'react';
+
+import { initNDK } from '@libs/ndk';
+import { getSetting } from '@libs/storage';
export const RelayContext = createContext
(null);
-const relays = await getSetting("relays");
+const relays = await getSetting('relays');
const relaysArray = JSON.parse(relays);
const ndk = await initNDK(relaysArray);
export function RelayProvider({ children }: { children: React.ReactNode }) {
- return {children};
+ return {children};
}
diff --git a/src/shared/settingsLayout.tsx b/src/shared/settingsLayout.tsx
index 74e91199..5e9cca4a 100644
--- a/src/shared/settingsLayout.tsx
+++ b/src/shared/settingsLayout.tsx
@@ -1,63 +1,64 @@
-import { AppHeader } from "@shared/appHeader";
-import { NavLink, Outlet, ScrollRestoration } from "react-router-dom";
-import { twMerge } from "tailwind-merge";
+import { NavLink, Outlet, ScrollRestoration } from 'react-router-dom';
+import { twMerge } from 'tailwind-merge';
+
+import { AppHeader } from '@shared/appHeader';
export function SettingsLayout() {
- return (
-
-
-
-
-
-
-
-
- Settings
-
-
-
-
- twMerge(
- "flex h-9 items-center gap-2.5 rounded-md px-2.5 text-zinc-200",
- isActive ? "bg-zinc-900/50" : "",
- )
- }
- >
- General
-
-
- twMerge(
- "flex h-9 items-center gap-2.5 rounded-md px-2.5 text-zinc-200",
- isActive ? "bg-zinc-900/50" : "",
- )
- }
- >
- Shortcuts
-
-
- twMerge(
- "flex h-9 items-center gap-2.5 rounded-md px-2.5 text-zinc-200",
- isActive ? "bg-zinc-900/50" : "",
- )
- }
- >
- Account
-
-
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+ Settings
+
+
+
+
+ twMerge(
+ 'flex h-9 items-center gap-2.5 rounded-md px-2.5 text-zinc-200',
+ isActive ? 'bg-zinc-900/50' : ''
+ )
+ }
+ >
+ General
+
+
+ twMerge(
+ 'flex h-9 items-center gap-2.5 rounded-md px-2.5 text-zinc-200',
+ isActive ? 'bg-zinc-900/50' : ''
+ )
+ }
+ >
+ Shortcuts
+
+
+ twMerge(
+ 'flex h-9 items-center gap-2.5 rounded-md px-2.5 text-zinc-200',
+ isActive ? 'bg-zinc-900/50' : ''
+ )
+ }
+ >
+ Account
+
+
+
+
+
+
+
+
+
+
+
+ );
}
diff --git a/src/shared/titleBar.tsx b/src/shared/titleBar.tsx
index 6798405e..f1117300 100644
--- a/src/shared/titleBar.tsx
+++ b/src/shared/titleBar.tsx
@@ -1,27 +1,30 @@
-import { CancelIcon } from "@shared/icons";
+import { CancelIcon } from '@shared/icons';
export function TitleBar({
- title,
- onClick = undefined,
-}: { title: string; onClick?: () => void }) {
- return (
-
-
-
{title}
- {onClick ? (
-
- ) : (
-
- )}
-
- );
+ title,
+ onClick = undefined,
+}: {
+ title: string;
+ onClick?: () => void;
+}) {
+ return (
+
+
+
{title}
+ {onClick ? (
+
+ ) : (
+
+ )}
+
+ );
}
diff --git a/src/shared/tooltip_dep.tsx b/src/shared/tooltip_dep.tsx
index b1cdec8d..185695f0 100644
--- a/src/shared/tooltip_dep.tsx
+++ b/src/shared/tooltip_dep.tsx
@@ -1,58 +1,58 @@
import {
- autoUpdate,
- offset,
- shift,
- useFloating,
- useFocus,
- useHover,
- useInteractions,
-} from "@floating-ui/react";
-import { useState } from "react";
+ autoUpdate,
+ offset,
+ shift,
+ useFloating,
+ useFocus,
+ useHover,
+ useInteractions,
+} from '@floating-ui/react';
+import { useState } from 'react';
export function Tooltip({
- children,
- message,
-}: { children: React.ReactNode; message: string }) {
- const [isOpen, setIsOpen] = useState(false);
+ children,
+ message,
+}: {
+ children: React.ReactNode;
+ message: string;
+}) {
+ const [isOpen, setIsOpen] = useState(false);
- const { x, y, strategy, refs, context } = useFloating({
- open: isOpen,
- onOpenChange: setIsOpen,
- placement: "top",
- middleware: [offset(8), shift()],
- whileElementsMounted(...args) {
- const cleanup = autoUpdate(...args, { animationFrame: true });
- return cleanup;
- },
- });
+ const { x, y, strategy, refs, context } = useFloating({
+ open: isOpen,
+ onOpenChange: setIsOpen,
+ placement: 'top',
+ middleware: [offset(8), shift()],
+ whileElementsMounted(...args) {
+ const cleanup = autoUpdate(...args, { animationFrame: true });
+ return cleanup;
+ },
+ });
- const hover = useHover(context);
- const focus = useFocus(context);
+ const hover = useHover(context);
+ const focus = useFocus(context);
- const { getReferenceProps, getFloatingProps } = useInteractions([
- hover,
- focus,
- ]);
+ const { getReferenceProps, getFloatingProps } = useInteractions([hover, focus]);
- return (
- <>
-
- {children}
-
- {isOpen && (
-
- {message}
-
- )}
- >
- );
+ return (
+ <>
+
+ {children}
+
+ {isOpen && (
+
+ {message}
+
+ )}
+ >
+ );
}
diff --git a/src/shared/user.tsx b/src/shared/user.tsx
index c571420b..349cc6c4 100644
--- a/src/shared/user.tsx
+++ b/src/shared/user.tsx
@@ -1,138 +1,138 @@
-import { Popover, Transition } from "@headlessui/react";
-import { Image } from "@shared/image";
-import { DEFAULT_AVATAR } from "@stores/constants";
-import { formatCreatedAt } from "@utils/createdAt";
-import { useProfile } from "@utils/hooks/useProfile";
-import { shortenKey } from "@utils/shortenKey";
-import { Fragment } from "react";
-import { Link } from "react-router-dom";
+import { Popover, Transition } from '@headlessui/react';
+import { Fragment } from 'react';
+import { Link } from 'react-router-dom';
+
+import { Image } from '@shared/image';
+
+import { DEFAULT_AVATAR } from '@stores/constants';
+
+import { formatCreatedAt } from '@utils/createdAt';
+import { useProfile } from '@utils/hooks/useProfile';
+import { shortenKey } from '@utils/shortenKey';
export function User({
- pubkey,
- time,
- size,
- repost,
- isChat = false,
+ pubkey,
+ time,
+ size,
+ repost,
+ isChat = false,
}: {
- pubkey: string;
- time: number;
- size?: string;
- repost?: boolean;
- isChat?: boolean;
+ pubkey: string;
+ time: number;
+ size?: string;
+ repost?: boolean;
+ isChat?: boolean;
}) {
- const { status, user } = useProfile(pubkey);
- const createdAt = formatCreatedAt(time, isChat);
+ const { status, user } = useProfile(pubkey);
+ const createdAt = formatCreatedAt(time, isChat);
- const avatarWidth = size === "small" ? "w-6" : "w-11";
- const avatarHeight = size === "small" ? "h-6" : "h-11";
+ const avatarWidth = size === 'small' ? 'w-6' : 'w-11';
+ const avatarHeight = size === 'small' ? 'h-6' : 'h-11';
- if (status === "loading") {
- return (
-
- );
- }
+ if (status === 'loading') {
+ return (
+
+ );
+ }
- return (
-
-
-
-
-
-
- {user?.nip05 || user?.name || user?.displayName || shortenKey(pubkey)}
-
- {repost && (
-
- {" "}
- reposted
-
- )}
- ·
- {createdAt}
-
-
-
-
-
-
-
-
-
- {user?.displayName || user?.name || (
-
- )}
-
-
- {user?.nip05 || shortenKey(pubkey)}
-
-
-
-
-
-
-
- View profile
-
-
- Message
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+ {user?.nip05 || user?.name || user?.displayName || shortenKey(pubkey)}
+
+ {repost && (
+ reposted
+ )}
+ ·
+ {createdAt}
+
+
+
+
+
+
+
+
+
+ {user?.displayName || user?.name || (
+
+ )}
+
+
+ {user?.nip05 || shortenKey(pubkey)}
+
+
+
+
+
+
+
+ View profile
+
+
+ Message
+
+
+
+
+
+
+ );
}
diff --git a/src/stores/channels.tsx b/src/stores/channels.tsx
index f9704d6f..3a9f0f9c 100644
--- a/src/stores/channels.tsx
+++ b/src/stores/channels.tsx
@@ -1,94 +1,92 @@
-import {
- createChannelMessage,
- getChannelMessages,
- getChannels,
-} from "@libs/storage";
-import { LumeEvent } from "@utils/types";
-import { create } from "zustand";
-import { immer } from "zustand/middleware/immer";
+import { create } from 'zustand';
+import { immer } from 'zustand/middleware/immer';
+
+import { createChannelMessage, getChannelMessages, getChannels } from '@libs/storage';
+
+import { LumeEvent } from '@utils/types';
export const useChannels = create(
- immer((set) => ({
- channels: [],
- fetch: async () => {
- const response = await getChannels();
- set({ channels: response });
- },
- add: (event) => {
- set((state) => {
- const target = state.channels.findIndex(
- (m: { event_id: string }) => m.event_id === event.id,
- );
- if (target !== -1) {
- state.channels[target]["new_messages"] =
- state.channels[target]["new_messages"] + 1 || 1;
- } else {
- state.channels.push({ event_id: event.id, ...event });
- }
- });
- },
- clearBubble: (id: string) => {
- set((state) => {
- const target = state.channels.findIndex(
- (m: { event_id: string }) => m.event_id === id,
- );
- state.channels[target]["new_messages"] = 0;
- });
- },
- })),
+ immer((set) => ({
+ channels: [],
+ fetch: async () => {
+ const response = await getChannels();
+ set({ channels: response });
+ },
+ add: (event) => {
+ set((state) => {
+ const target = state.channels.findIndex(
+ (m: { event_id: string }) => m.event_id === event.id
+ );
+ if (target !== -1) {
+ state.channels[target]['new_messages'] =
+ state.channels[target]['new_messages'] + 1 || 1;
+ } else {
+ state.channels.push({ event_id: event.id, ...event });
+ }
+ });
+ },
+ clearBubble: (id: string) => {
+ set((state) => {
+ const target = state.channels.findIndex(
+ (m: { event_id: string }) => m.event_id === id
+ );
+ state.channels[target]['new_messages'] = 0;
+ });
+ },
+ }))
);
export const useChannelMessages = create(
- immer((set) => ({
- messages: [],
- replyTo: { id: null, pubkey: null, content: null },
- fetch: async (id: string) => {
- const events = await getChannelMessages(id);
- set({ messages: events });
- },
- add: (id, event: LumeEvent) => {
- set((state: any) => {
- createChannelMessage(
- id,
- event.id,
- event.pubkey,
- event.kind,
- event.content,
- event.tags,
- event.created_at,
- );
- state.messages.push({
- event_id: event.id,
- channel_id: id,
- hide: 0,
- mute: 0,
- ...event,
- });
- });
- },
- openReply: (id: string, pubkey: string, content: string) => {
- set(() => ({ replyTo: { id, pubkey, content } }));
- },
- closeReply: () => {
- set(() => ({ replyTo: { id: null, pubkey: null, content: null } }));
- },
- hideMessage: (id: string) => {
- set((state) => {
- const target = state.messages.findIndex((m) => m.id === id);
- state.messages[target]["hide"] = true;
- });
- },
- muteUser: (pubkey: string) => {
- set((state) => {
- const target = state.messages.findIndex((m) => m.pubkey === pubkey);
- state.messages[target]["mute"] = true;
- });
- },
- clear: () => {
- set(() => ({
- messages: [],
- replyTo: { id: null, pubkey: null, content: null },
- }));
- },
- })),
+ immer((set) => ({
+ messages: [],
+ replyTo: { id: null, pubkey: null, content: null },
+ fetch: async (id: string) => {
+ const events = await getChannelMessages(id);
+ set({ messages: events });
+ },
+ add: (id, event: LumeEvent) => {
+ set((state: any) => {
+ createChannelMessage(
+ id,
+ event.id,
+ event.pubkey,
+ event.kind,
+ event.content,
+ event.tags,
+ event.created_at
+ );
+ state.messages.push({
+ event_id: event.id,
+ channel_id: id,
+ hide: 0,
+ mute: 0,
+ ...event,
+ });
+ });
+ },
+ openReply: (id: string, pubkey: string, content: string) => {
+ set(() => ({ replyTo: { id, pubkey, content } }));
+ },
+ closeReply: () => {
+ set(() => ({ replyTo: { id: null, pubkey: null, content: null } }));
+ },
+ hideMessage: (id: string) => {
+ set((state) => {
+ const target = state.messages.findIndex((m) => m.id === id);
+ state.messages[target]['hide'] = true;
+ });
+ },
+ muteUser: (pubkey: string) => {
+ set((state) => {
+ const target = state.messages.findIndex((m) => m.pubkey === pubkey);
+ state.messages[target]['mute'] = true;
+ });
+ },
+ clear: () => {
+ set(() => ({
+ messages: [],
+ replyTo: { id: null, pubkey: null, content: null },
+ }));
+ },
+ }))
);
diff --git a/src/stores/composer.tsx b/src/stores/composer.tsx
index 37b1952b..79659bcc 100644
--- a/src/stores/composer.tsx
+++ b/src/stores/composer.tsx
@@ -1,41 +1,41 @@
-import { create } from "zustand";
+import { create } from 'zustand';
interface ComposerState {
- open: boolean;
- reply: { id: string; root: string; pubkey: string };
- repost: { id: string; pubkey: string };
- toggleModal: (status: boolean) => void;
- setReply: (id: string, root: string, pubkey: string) => void;
- setRepost: (id: string, pubkey: string) => void;
- clearReply: () => void;
- clearRepost: () => void;
+ open: boolean;
+ reply: { id: string; root: string; pubkey: string };
+ repost: { id: string; pubkey: string };
+ toggleModal: (status: boolean) => void;
+ setReply: (id: string, root: string, pubkey: string) => void;
+ setRepost: (id: string, pubkey: string) => void;
+ clearReply: () => void;
+ clearRepost: () => void;
}
export const useComposer = create((set) => ({
- open: false,
- reply: { id: null, root: null, pubkey: null },
- repost: { id: null, pubkey: null },
- toggleModal: (status: boolean) => {
- set({ open: status });
- if (!status) {
- set({ repost: { id: null, pubkey: null } });
- set({ reply: { id: null, root: null, pubkey: null } });
- }
- },
- setReply: (id: string, root: string, pubkey: string) => {
- set({ reply: { id: id, root: root, pubkey: pubkey } });
- set({ repost: { id: null, pubkey: null } });
- set({ open: true });
- },
- setRepost: (id: string, pubkey: string) => {
- set({ repost: { id: id, pubkey: pubkey } });
- set({ reply: { id: null, root: null, pubkey: null } });
- set({ open: true });
- },
- clearReply: () => {
- set({ reply: { id: null, root: null, pubkey: null } });
- },
- clearRepost: () => {
- set({ repost: { id: null, pubkey: null } });
- },
+ open: false,
+ reply: { id: null, root: null, pubkey: null },
+ repost: { id: null, pubkey: null },
+ toggleModal: (status: boolean) => {
+ set({ open: status });
+ if (!status) {
+ set({ repost: { id: null, pubkey: null } });
+ set({ reply: { id: null, root: null, pubkey: null } });
+ }
+ },
+ setReply: (id: string, root: string, pubkey: string) => {
+ set({ reply: { id: id, root: root, pubkey: pubkey } });
+ set({ repost: { id: null, pubkey: null } });
+ set({ open: true });
+ },
+ setRepost: (id: string, pubkey: string) => {
+ set({ repost: { id: id, pubkey: pubkey } });
+ set({ reply: { id: null, root: null, pubkey: null } });
+ set({ open: true });
+ },
+ clearReply: () => {
+ set({ reply: { id: null, root: null, pubkey: null } });
+ },
+ clearRepost: () => {
+ set({ repost: { id: null, pubkey: null } });
+ },
}));
diff --git a/src/stores/constants.tsx b/src/stores/constants.tsx
index 202c6090..7dbcbcb5 100644
--- a/src/stores/constants.tsx
+++ b/src/stores/constants.tsx
@@ -1,72 +1,72 @@
-export const APP_VERSION = "1.0.0";
+export const APP_VERSION = '1.0.0';
-export const DEFAULT_AVATAR = "https://void.cat/d/5VKmKyuHyxrNMf9bWSVPih";
+export const DEFAULT_AVATAR = 'https://void.cat/d/5VKmKyuHyxrNMf9bWSVPih';
export const OPENGRAPH = {
- REGEX_VALID_URL: new RegExp(
- "^" +
- // protocol identifier
- "(?:(?:https?|ftp)://)" +
- // user:pass authentication
- "(?:\\S+(?::\\S*)?@)?" +
- "(?:" +
- // IP address exclusion
- // private & local networks
- "(?!(?:10|127)(?:\\.\\d{1,3}){3})" +
- "(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})" +
- "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" +
- // IP address dotted notation octets
- // excludes loopback network 0.0.0.0
- // excludes reserved space >= 224.0.0.0
- // excludes network & broacast addresses
- // (first & last IP address of each class)
- "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
- "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
- "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
- "|" +
- // host name
- "(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" +
- // domain name
- "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" +
- // TLD identifier
- "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" +
- // TLD may end with dot
- "\\.?" +
- ")" +
- // port number
- "(?::\\d{2,5})?" +
- // resource path
- "(?:[/?#]\\S*)?" +
- "$",
- "i",
- ),
+ REGEX_VALID_URL: new RegExp(
+ '^' +
+ // protocol identifier
+ '(?:(?:https?|ftp)://)' +
+ // user:pass authentication
+ '(?:\\S+(?::\\S*)?@)?' +
+ '(?:' +
+ // IP address exclusion
+ // private & local networks
+ '(?!(?:10|127)(?:\\.\\d{1,3}){3})' +
+ '(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})' +
+ '(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})' +
+ // IP address dotted notation octets
+ // excludes loopback network 0.0.0.0
+ // excludes reserved space >= 224.0.0.0
+ // excludes network & broacast addresses
+ // (first & last IP address of each class)
+ '(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])' +
+ '(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}' +
+ '(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))' +
+ '|' +
+ // host name
+ '(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)' +
+ // domain name
+ '(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*' +
+ // TLD identifier
+ '(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))' +
+ // TLD may end with dot
+ '\\.?' +
+ ')' +
+ // port number
+ '(?::\\d{2,5})?' +
+ // resource path
+ '(?:[/?#]\\S*)?' +
+ '$',
+ 'i'
+ ),
- REGEX_LOOPBACK: new RegExp(
- "^" +
- "(?:(?:10|127)(?:\\.\\d{1,3}){3})" +
- "|" +
- "(?:(?:169\\.254|192\\.168|192\\.0)(?:\\.\\d{1,3}){2})" +
- "|" +
- "(?:172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" +
- "$",
- "i",
- ),
+ REGEX_LOOPBACK: new RegExp(
+ '^' +
+ '(?:(?:10|127)(?:\\.\\d{1,3}){3})' +
+ '|' +
+ '(?:(?:169\\.254|192\\.168|192\\.0)(?:\\.\\d{1,3}){2})' +
+ '|' +
+ '(?:172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})' +
+ '$',
+ 'i'
+ ),
- REGEX_CONTENT_TYPE_IMAGE: new RegExp("image/.*", "i"),
+ REGEX_CONTENT_TYPE_IMAGE: new RegExp('image/.*', 'i'),
- REGEX_CONTENT_TYPE_AUDIO: new RegExp("audio/.*", "i"),
+ REGEX_CONTENT_TYPE_AUDIO: new RegExp('audio/.*', 'i'),
- REGEX_CONTENT_TYPE_VIDEO: new RegExp("video/.*", "i"),
+ REGEX_CONTENT_TYPE_VIDEO: new RegExp('video/.*', 'i'),
- REGEX_CONTENT_TYPE_TEXT: new RegExp("text/.*", "i"),
+ REGEX_CONTENT_TYPE_TEXT: new RegExp('text/.*', 'i'),
- REGEX_CONTENT_TYPE_APPLICATION: new RegExp("application/.*", "i"),
+ REGEX_CONTENT_TYPE_APPLICATION: new RegExp('application/.*', 'i'),
};
export const FULL_RELAYS = [
- "wss://relayable.org",
- "wss://relay.damus.io",
- "wss://relay.nostrgraph.net",
- "wss://relay.nostr.band/all",
- "wss://nostr.mutinywallet.com",
+ 'wss://relayable.org',
+ 'wss://relay.damus.io',
+ 'wss://relay.nostrgraph.net',
+ 'wss://relay.nostr.band/all',
+ 'wss://nostr.mutinywallet.com',
];
diff --git a/src/stores/note.tsx b/src/stores/note.tsx
index 07bab0c8..eff3288f 100644
--- a/src/stores/note.tsx
+++ b/src/stores/note.tsx
@@ -1,13 +1,13 @@
-import { create } from "zustand";
+import { create } from 'zustand';
interface NoteState {
- hasNewNote: boolean;
- toggleHasNewNote: (status: boolean) => void;
+ hasNewNote: boolean;
+ toggleHasNewNote: (status: boolean) => void;
}
export const useNote = create((set) => ({
- hasNewNote: false,
- toggleHasNewNote: (status: boolean) => {
- set({ hasNewNote: status });
- },
+ hasNewNote: false,
+ toggleHasNewNote: (status: boolean) => {
+ set({ hasNewNote: status });
+ },
}));
diff --git a/src/stores/onboarding.tsx b/src/stores/onboarding.tsx
index e5334a34..b93f5d32 100644
--- a/src/stores/onboarding.tsx
+++ b/src/stores/onboarding.tsx
@@ -1,17 +1,17 @@
-import { create } from "zustand";
-import { createJSONStorage, persist } from "zustand/middleware";
+import { create } from 'zustand';
+import { createJSONStorage, persist } from 'zustand/middleware';
export const useOnboarding = create(
- persist(
- (set) => ({
- profile: {},
- createProfile: (data) => {
- set({ profile: data });
- },
- }),
- {
- name: "onboarding",
- storage: createJSONStorage(() => sessionStorage),
- },
- ),
+ persist(
+ (set) => ({
+ profile: {},
+ createProfile: (data) => {
+ set({ profile: data });
+ },
+ }),
+ {
+ name: 'onboarding',
+ storage: createJSONStorage(() => sessionStorage),
+ }
+ )
);
diff --git a/src/stores/shortcuts.tsx b/src/stores/shortcuts.tsx
index 451b83de..bca18047 100644
--- a/src/stores/shortcuts.tsx
+++ b/src/stores/shortcuts.tsx
@@ -1,3 +1,3 @@
-export const COMPOSE_SHORTCUT = "meta+n";
-export const ADD_IMAGEBLOCK_SHORTCUT = "meta+i";
-export const ADD_FEEDBLOCK_SHORTCUT = "meta+f";
+export const COMPOSE_SHORTCUT = 'meta+n';
+export const ADD_IMAGEBLOCK_SHORTCUT = 'meta+i';
+export const ADD_FEEDBLOCK_SHORTCUT = 'meta+f';
diff --git a/src/utils/createBlobFromFile.tsx b/src/utils/createBlobFromFile.tsx
index dc55627e..ada1bff3 100644
--- a/src/utils/createBlobFromFile.tsx
+++ b/src/utils/createBlobFromFile.tsx
@@ -1,6 +1,6 @@
-import { readBinaryFile } from "@tauri-apps/api/fs";
+import { readBinaryFile } from '@tauri-apps/api/fs';
export async function createBlobFromFile(path: string): Promise {
- const file = await readBinaryFile(path);
- return new Blob([file]);
+ const file = await readBinaryFile(path);
+ return new Blob([file]);
}
diff --git a/src/utils/createdAt.tsx b/src/utils/createdAt.tsx
index 5a701d0d..a752ade2 100644
--- a/src/utils/createdAt.tsx
+++ b/src/utils/createdAt.tsx
@@ -1,43 +1,43 @@
-import dayjs from "dayjs";
-import relativeTime from "dayjs/plugin/relativeTime";
-import updateLocale from "dayjs/plugin/updateLocale";
+import dayjs from 'dayjs';
+import relativeTime from 'dayjs/plugin/relativeTime';
+import updateLocale from 'dayjs/plugin/updateLocale';
dayjs.extend(relativeTime);
dayjs.extend(updateLocale);
-dayjs.updateLocale("en", {
- relativeTime: {
- past: "%s ago",
- s: "just now",
- m: "1m",
- mm: "%dm",
- h: "1h",
- hh: "%dh",
- d: "1d",
- dd: "%dd",
- },
+dayjs.updateLocale('en', {
+ relativeTime: {
+ past: '%s ago',
+ s: 'just now',
+ m: '1m',
+ mm: '%dm',
+ h: '1h',
+ hh: '%dh',
+ d: '1d',
+ dd: '%dd',
+ },
});
export function formatCreatedAt(time, message = false) {
- let formated;
+ let formated;
- const now = dayjs();
- const inputTime = dayjs.unix(time);
- const diff = now.diff(inputTime, "hour");
+ const now = dayjs();
+ const inputTime = dayjs.unix(time);
+ const diff = now.diff(inputTime, 'hour');
- if (message) {
- if (diff < 12) {
- formated = inputTime.format("HH:mm A");
- } else {
- formated = inputTime.format("MMM DD");
- }
- } else {
- if (diff < 24) {
- formated = inputTime.from(now, true);
- } else {
- formated = inputTime.format("MMM DD");
- }
- }
+ if (message) {
+ if (diff < 12) {
+ formated = inputTime.format('HH:mm A');
+ } else {
+ formated = inputTime.format('MMM DD');
+ }
+ } else {
+ if (diff < 24) {
+ formated = inputTime.from(now, true);
+ } else {
+ formated = inputTime.format('MMM DD');
+ }
+ }
- return formated;
+ return formated;
}
diff --git a/src/utils/date.tsx b/src/utils/date.tsx
index b7545b7b..6c981663 100644
--- a/src/utils/date.tsx
+++ b/src/utils/date.tsx
@@ -1,22 +1,22 @@
// get X days ago with user provided date
export function getDayAgo(numOfDays, date = new Date()) {
- const days = new Date(date.getTime());
- days.setDate(date.getDate() - numOfDays);
+ const days = new Date(date.getTime());
+ days.setDate(date.getDate() - numOfDays);
- return days;
+ return days;
}
// get X hours ago with user provided date
export function getHourAgo(numOfHours, date = new Date()) {
- const hours = new Date(date.getTime());
- hours.setHours(date.getHours() - numOfHours);
+ const hours = new Date(date.getTime());
+ hours.setHours(date.getHours() - numOfHours);
- return hours;
+ return hours;
}
// convert date to unix timestamp
export function dateToUnix(_date?: Date) {
- const date = _date || new Date();
+ const date = _date || new Date();
- return Math.floor(date.getTime() / 1000);
+ return Math.floor(date.getTime() / 1000);
}
diff --git a/src/utils/hooks/useAccount.tsx b/src/utils/hooks/useAccount.tsx
index 06027f6a..bcc6aca9 100644
--- a/src/utils/hooks/useAccount.tsx
+++ b/src/utils/hooks/useAccount.tsx
@@ -1,17 +1,18 @@
-import { getActiveAccount } from "@libs/storage";
-import { useQuery } from "@tanstack/react-query";
+import { useQuery } from '@tanstack/react-query';
+
+import { getActiveAccount } from '@libs/storage';
export function useAccount() {
- const { status, data: account } = useQuery(
- ["currentAccount"],
- async () => await getActiveAccount(),
- {
- staleTime: Infinity,
- refetchOnMount: true,
- refetchOnWindowFocus: false,
- refetchOnReconnect: true,
- },
- );
+ const { status, data: account } = useQuery(
+ ['currentAccount'],
+ async () => await getActiveAccount(),
+ {
+ staleTime: Infinity,
+ refetchOnMount: true,
+ refetchOnWindowFocus: false,
+ refetchOnReconnect: true,
+ }
+ );
- return { status, account };
+ return { status, account };
}
diff --git a/src/utils/hooks/useEvent.tsx b/src/utils/hooks/useEvent.tsx
index 570f0339..3f57313e 100644
--- a/src/utils/hooks/useEvent.tsx
+++ b/src/utils/hooks/useEvent.tsx
@@ -1,44 +1,48 @@
-import { createNote, getNoteByID } from "@libs/storage";
-import { RelayContext } from "@shared/relayProvider";
-import { useQuery } from "@tanstack/react-query";
-import { parser } from "@utils/parser";
-import { useContext } from "react";
+import { useQuery } from '@tanstack/react-query';
+import { useContext } from 'react';
+
+import { createNote, getNoteByID } from '@libs/storage';
+
+import { RelayContext } from '@shared/relayProvider';
+
+import { parser } from '@utils/parser';
export function useEvent(id: string) {
- const ndk = useContext(RelayContext);
- const { status, data, error, isFetching } = useQuery(
- ["note", id],
- async () => {
- const result = await getNoteByID(id);
- if (result) {
- if (result.kind === 1 || result.kind === 1063) {
- result["content"] = parser(result);
- }
- return result;
- } else {
- const event = await ndk.fetchEvent(id);
- await createNote(
- event.id,
- event.pubkey,
- event.kind,
- event.tags,
- event.content,
- event.created_at,
- );
- event["event_id"] = event.id;
- if (event.kind === 1 || event.kind === 1063) {
- // @ts-ignore
- event["content"] = parser(event);
- }
- return event;
- }
- },
- {
- refetchOnWindowFocus: false,
- refetchOnMount: false,
- refetchOnReconnect: false,
- },
- );
+ const ndk = useContext(RelayContext);
+ const { status, data, error, isFetching } = useQuery(
+ ['note', id],
+ async () => {
+ const result = await getNoteByID(id);
+ if (result) {
+ if (result.kind === 1 || result.kind === 1063) {
+ result['content'] = parser(result);
+ }
+ return result;
+ } else {
+ const event = await ndk.fetchEvent(id);
+ await createNote(
+ event.id,
+ event.pubkey,
+ event.kind,
+ event.tags,
+ event.content,
+ event.created_at
+ );
+ event['event_id'] = event.id;
+ if (event.kind === 1 || event.kind === 1063) {
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ event['content'] = parser(event);
+ }
+ return event;
+ }
+ },
+ {
+ refetchOnWindowFocus: false,
+ refetchOnMount: false,
+ refetchOnReconnect: false,
+ }
+ );
- return { status, data, error, isFetching };
+ return { status, data, error, isFetching };
}
diff --git a/src/utils/hooks/useNetworkStatus.tsx b/src/utils/hooks/useNetworkStatus.tsx
index 55bbfe22..86eda0b3 100644
--- a/src/utils/hooks/useNetworkStatus.tsx
+++ b/src/utils/hooks/useNetworkStatus.tsx
@@ -1,25 +1,25 @@
-import { useEffect, useState } from "react";
+import { useEffect, useState } from 'react';
const getOnLineStatus = () =>
- typeof navigator !== "undefined" && typeof navigator.onLine === "boolean"
- ? navigator.onLine
- : true;
+ typeof navigator !== 'undefined' && typeof navigator.onLine === 'boolean'
+ ? navigator.onLine
+ : true;
export function useNetworkStatus() {
- const [status, setStatus] = useState(getOnLineStatus());
+ const [status, setStatus] = useState(getOnLineStatus());
- const setOnline = () => setStatus(true);
- const setOffline = () => setStatus(false);
+ const setOnline = () => setStatus(true);
+ const setOffline = () => setStatus(false);
- useEffect(() => {
- window.addEventListener("online", setOnline);
- window.addEventListener("offline", setOffline);
+ useEffect(() => {
+ window.addEventListener('online', setOnline);
+ window.addEventListener('offline', setOffline);
- return () => {
- window.removeEventListener("online", setOnline);
- window.removeEventListener("offline", setOffline);
- };
- }, []);
+ return () => {
+ window.removeEventListener('online', setOnline);
+ window.removeEventListener('offline', setOffline);
+ };
+ }, []);
- return status;
+ return status;
}
diff --git a/src/utils/hooks/useOpenGraph.tsx b/src/utils/hooks/useOpenGraph.tsx
index aa493397..ce3b5ed2 100644
--- a/src/utils/hooks/useOpenGraph.tsx
+++ b/src/utils/hooks/useOpenGraph.tsx
@@ -1,28 +1,29 @@
-import { getLinkPreview } from "@libs/openGraph";
-import { useQuery } from "@tanstack/react-query";
+import { useQuery } from '@tanstack/react-query';
+
+import { getLinkPreview } from '@libs/openGraph';
export function useOpenGraph(url: string) {
- const { status, data, error, isFetching } = useQuery(
- ["preview", url],
- async () => {
- const res = await getLinkPreview(url);
- if (!res) {
- throw new Error("Can' fetch");
- }
- return res;
- },
- {
- refetchOnWindowFocus: false,
- refetchOnMount: false,
- refetchOnReconnect: false,
- staleTime: Infinity,
- },
- );
+ const { status, data, error, isFetching } = useQuery(
+ ['preview', url],
+ async () => {
+ const res = await getLinkPreview(url);
+ if (!res) {
+ throw new Error("Can' fetch");
+ }
+ return res;
+ },
+ {
+ refetchOnWindowFocus: false,
+ refetchOnMount: false,
+ refetchOnReconnect: false,
+ staleTime: Infinity,
+ }
+ );
- return {
- status,
- data,
- error,
- isFetching,
- };
+ return {
+ status,
+ data,
+ error,
+ isFetching,
+ };
}
diff --git a/src/utils/hooks/useProfile.tsx b/src/utils/hooks/useProfile.tsx
index 46d75347..fac5bdf1 100644
--- a/src/utils/hooks/useProfile.tsx
+++ b/src/utils/hooks/useProfile.tsx
@@ -1,33 +1,33 @@
-import { NDKUser } from "@nostr-dev-kit/ndk";
-import { RelayContext } from "@shared/relayProvider";
-import { useQuery } from "@tanstack/react-query";
-import { useContext } from "react";
+import { useQuery } from '@tanstack/react-query';
+import { useContext } from 'react';
+
+import { RelayContext } from '@shared/relayProvider';
export function useProfile(pubkey: string, fallback?: string) {
- const ndk = useContext(RelayContext);
- const {
- status,
- data: user,
- error,
- isFetching,
- } = useQuery(
- ["user", pubkey],
- async () => {
- if (fallback) {
- const profile = JSON.parse(fallback);
- return profile;
- } else {
- const user = ndk.getUser({ hexpubkey: pubkey });
- await user.fetchProfile();
+ const ndk = useContext(RelayContext);
+ const {
+ status,
+ data: user,
+ error,
+ isFetching,
+ } = useQuery(
+ ['user', pubkey],
+ async () => {
+ if (fallback) {
+ const profile = JSON.parse(fallback);
+ return profile;
+ } else {
+ const user = ndk.getUser({ hexpubkey: pubkey });
+ await user.fetchProfile();
- return user.profile;
- }
- },
- {
- refetchOnWindowFocus: false,
- refetchOnReconnect: false,
- },
- );
+ return user.profile;
+ }
+ },
+ {
+ refetchOnWindowFocus: false,
+ refetchOnReconnect: false,
+ }
+ );
- return { status, user, error, isFetching };
+ return { status, user, error, isFetching };
}
diff --git a/src/utils/hooks/useSocial.tsx b/src/utils/hooks/useSocial.tsx
index ab4930a3..bdaa004e 100644
--- a/src/utils/hooks/useSocial.tsx
+++ b/src/utils/hooks/useSocial.tsx
@@ -1,89 +1,93 @@
-import { useAccount } from "./useAccount";
-import { usePublish } from "@libs/ndk";
-import { createNote } from "@libs/storage";
-import { NDKEvent, NDKFilter } from "@nostr-dev-kit/ndk";
-import { RelayContext } from "@shared/relayProvider";
-import { useQuery, useQueryClient } from "@tanstack/react-query";
-import { dateToUnix, getHourAgo } from "@utils/date";
-import { nip02ToArray } from "@utils/transform";
-import { useContext } from "react";
+import { NDKEvent, NDKFilter } from '@nostr-dev-kit/ndk';
+import { useQuery, useQueryClient } from '@tanstack/react-query';
+import { useContext } from 'react';
+
+import { usePublish } from '@libs/ndk';
+import { createNote } from '@libs/storage';
+
+import { RelayContext } from '@shared/relayProvider';
+
+import { dateToUnix, getHourAgo } from '@utils/date';
+import { nip02ToArray } from '@utils/transform';
+
+import { useAccount } from './useAccount';
export function useSocial() {
- const ndk = useContext(RelayContext);
- const queryClient = useQueryClient();
- const publish = usePublish();
+ const ndk = useContext(RelayContext);
+ const queryClient = useQueryClient();
+ const publish = usePublish();
- const { account } = useAccount();
- const { status, data: userFollows } = useQuery(
- ["userFollows", account.pubkey],
- async () => {
- const res = await ndk.fetchEvents({
- kinds: [3],
- authors: [account.pubkey],
- });
- const latest = [...res].slice(-1)[0];
- const list = nip02ToArray(latest.tags);
- return list;
- },
- {
- enabled: account ? true : false,
- refetchOnReconnect: false,
- refetchOnMount: false,
- refetchOnWindowFocus: false,
- },
- );
+ const { account } = useAccount();
+ const { status, data: userFollows } = useQuery(
+ ['userFollows', account.pubkey],
+ async () => {
+ const res = await ndk.fetchEvents({
+ kinds: [3],
+ authors: [account.pubkey],
+ });
+ const latest = [...res].slice(-1)[0];
+ const list = nip02ToArray(latest.tags);
+ return list;
+ },
+ {
+ enabled: account ? true : false,
+ refetchOnReconnect: false,
+ refetchOnMount: false,
+ refetchOnWindowFocus: false,
+ }
+ );
- const unfollow = (pubkey: string) => {
- const followsAsSet = new Set(userFollows);
- followsAsSet.delete(pubkey);
+ const unfollow = (pubkey: string) => {
+ const followsAsSet = new Set(userFollows);
+ followsAsSet.delete(pubkey);
- const tags = [];
- followsAsSet.forEach((item) => {
- tags.push(["p", item]);
- });
+ const tags = [];
+ followsAsSet.forEach((item) => {
+ tags.push(['p', item]);
+ });
- // publish event
- publish({ content: "", kind: 3, tags: tags });
- // invalid cache
- queryClient.invalidateQueries({
- queryKey: ["userFollows", account.pubkey],
- });
- };
+ // publish event
+ publish({ content: '', kind: 3, tags: tags });
+ // invalid cache
+ queryClient.invalidateQueries({
+ queryKey: ['userFollows', account.pubkey],
+ });
+ };
- const follow = async (pubkey: string) => {
- const followsAsSet = new Set(userFollows);
- followsAsSet.add(pubkey);
+ const follow = async (pubkey: string) => {
+ const followsAsSet = new Set(userFollows);
+ followsAsSet.add(pubkey);
- const tags = [];
- followsAsSet.forEach((item) => {
- tags.push(["p", item]);
- });
+ const tags = [];
+ followsAsSet.forEach((item) => {
+ tags.push(['p', item]);
+ });
- // publish event
- publish({ content: "", kind: 3, tags: tags });
- // invalid cache
- queryClient.invalidateQueries({
- queryKey: ["userFollows", account.pubkey],
- });
+ // publish event
+ publish({ content: '', kind: 3, tags: tags });
+ // invalid cache
+ queryClient.invalidateQueries({
+ queryKey: ['userFollows', account.pubkey],
+ });
- // fetch events
- const filter: NDKFilter = {
- authors: [pubkey],
- kinds: [1, 6],
- since: dateToUnix(getHourAgo(48, new Date())),
- };
- const events = await ndk.fetchEvents(filter);
- events.forEach((event: NDKEvent) => {
- createNote(
- event.id,
- event.pubkey,
- event.kind,
- event.tags,
- event.content,
- event.created_at,
- );
- });
- };
+ // fetch events
+ const filter: NDKFilter = {
+ authors: [pubkey],
+ kinds: [1, 6],
+ since: dateToUnix(getHourAgo(48, new Date())),
+ };
+ const events = await ndk.fetchEvents(filter);
+ events.forEach((event: NDKEvent) => {
+ createNote(
+ event.id,
+ event.pubkey,
+ event.kind,
+ event.tags,
+ event.content,
+ event.created_at
+ );
+ });
+ };
- return { status, userFollows, follow, unfollow };
+ return { status, userFollows, follow, unfollow };
}
diff --git a/src/utils/notification.tsx b/src/utils/notification.tsx
index 2fc3906b..8d1fc266 100644
--- a/src/utils/notification.tsx
+++ b/src/utils/notification.tsx
@@ -1,16 +1,16 @@
import {
- isPermissionGranted,
- requestPermission,
- sendNotification,
-} from "@tauri-apps/api/notification";
+ isPermissionGranted,
+ requestPermission,
+ sendNotification,
+} from '@tauri-apps/api/notification';
export async function sendNativeNotification(content: string) {
- let permissionGranted = await isPermissionGranted();
- if (!permissionGranted) {
- const permission = await requestPermission();
- permissionGranted = permission === "granted";
- }
- if (permissionGranted) {
- sendNotification({ title: "Lume", body: content });
- }
+ let permissionGranted = await isPermissionGranted();
+ if (!permissionGranted) {
+ const permission = await requestPermission();
+ permissionGranted = permission === 'granted';
+ }
+ if (permissionGranted) {
+ sendNotification({ title: 'Lume', body: content });
+ }
}
diff --git a/src/utils/number.tsx b/src/utils/number.tsx
index 877ebc9a..32994d2f 100644
--- a/src/utils/number.tsx
+++ b/src/utils/number.tsx
@@ -1,2 +1,2 @@
// convert number to K, M, B, T, etc.
-export const compactNumber = Intl.NumberFormat("en", { notation: "compact" });
+export const compactNumber = Intl.NumberFormat('en', { notation: 'compact' });
diff --git a/src/utils/parser.tsx b/src/utils/parser.tsx
index e6ecc736..a57dc83f 100644
--- a/src/utils/parser.tsx
+++ b/src/utils/parser.tsx
@@ -1,122 +1,115 @@
-import { MentionUser } from "@shared/notes/mentions/user";
-import destr from "destr";
-import getUrls from "get-urls";
-import { parseReferences } from "nostr-tools";
-import { ReactNode } from "react";
-import { Link } from "react-router-dom";
-import reactStringReplace from "react-string-replace";
+import destr from 'destr';
+import getUrls from 'get-urls';
+import { parseReferences } from 'nostr-tools';
+import { ReactNode } from 'react';
+import { Link } from 'react-router-dom';
+import reactStringReplace from 'react-string-replace';
+
+import { MentionUser } from '@shared/notes/mentions/user';
function isJsonString(str: string) {
- try {
- JSON.parse(str);
- } catch (e) {
- return false;
- }
- return true;
+ try {
+ JSON.parse(str);
+ } catch (e) {
+ return false;
+ }
+ return true;
}
export function parser(event: any) {
- if (isJsonString(event.tags)) {
- event["tags"] = destr(event.tags);
- }
+ if (isJsonString(event.tags)) {
+ event['tags'] = destr(event.tags);
+ }
- const references = parseReferences(event);
- const urls = getUrls(event.content);
+ const references = parseReferences(event);
+ const urls = getUrls(event.content);
- const content: {
- original: string;
- parsed: ReactNode[];
- notes: string[];
- images: string[];
- videos: string[];
- links: string[];
- } = {
- original: event.content,
- parsed: event.content,
- notes: [],
- images: [],
- videos: [],
- links: [],
- };
+ const content: {
+ original: string;
+ parsed: ReactNode[];
+ notes: string[];
+ images: string[];
+ videos: string[];
+ links: string[];
+ } = {
+ original: event.content,
+ parsed: event.content,
+ notes: [],
+ images: [],
+ videos: [],
+ links: [],
+ };
- // remove unnecessary whitespaces
- // @ts-ignore
- content.parsed = content.parsed.replace(/\s{2,}/g, " ");
+ // remove unnecessary whitespaces
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ content.parsed = content.parsed.replace(/\s{2,}/g, ' ');
- // remove unnecessary linebreak
- // @ts-ignore
- content.parsed = content.parsed.replace(/(\r\n|\r|\n){2,}/g, "$1\n");
+ // remove unnecessary linebreak
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ content.parsed = content.parsed.replace(/(\r\n|\r|\n){2,}/g, '$1\n');
- // parse urls
- urls?.forEach((url: string) => {
- if (url.match(/\.(jpg|jpeg|gif|png|webp|avif)$/)) {
- // image url
- content.images.push(url);
- // remove url from original content
- content.parsed = reactStringReplace(content.parsed, url, () => null);
- } else if (url.match(/\.(mp4|webm|mov|ogv|avi|mp3)$/)) {
- // video
- content.videos.push(url);
- // remove url from original content
- content.parsed = reactStringReplace(content.parsed, url, () => null);
- } else {
- if (content.links.length < 1) {
- // push to store
- content.links.push(url);
- // remove url from original content
- content.parsed = reactStringReplace(content.parsed, url, () => null);
- } else {
- content.parsed = reactStringReplace(
- content.parsed,
- /#(\w+)/g,
- (match, i) => (
-
- {match}
-
- ),
- );
- }
- }
- });
+ // parse urls
+ urls?.forEach((url: string) => {
+ if (url.match(/\.(jpg|jpeg|gif|png|webp|avif)$/)) {
+ // image url
+ content.images.push(url);
+ // remove url from original content
+ content.parsed = reactStringReplace(content.parsed, url, () => null);
+ } else if (url.match(/\.(mp4|webm|mov|ogv|avi|mp3)$/)) {
+ // video
+ content.videos.push(url);
+ // remove url from original content
+ content.parsed = reactStringReplace(content.parsed, url, () => null);
+ } else {
+ if (content.links.length < 1) {
+ // push to store
+ content.links.push(url);
+ // remove url from original content
+ content.parsed = reactStringReplace(content.parsed, url, () => null);
+ } else {
+ content.parsed = reactStringReplace(content.parsed, /#(\w+)/g, (match, i) => (
+
+ {match}
+
+ ));
+ }
+ }
+ });
- // parse nostr
- references?.forEach((item) => {
- const profile = item.profile;
- const event = item.event;
- if (event) {
- content.notes.push(event.id);
- content.parsed = reactStringReplace(
- content.parsed,
- item.text,
- () => null,
- );
- }
- if (profile) {
- content.parsed = reactStringReplace(
- content.parsed,
- item.text,
- (match, i) => ,
- );
- }
- });
+ // parse nostr
+ references?.forEach((item) => {
+ const profile = item.profile;
+ const event = item.event;
+ if (event) {
+ content.notes.push(event.id);
+ content.parsed = reactStringReplace(content.parsed, item.text, () => null);
+ }
+ if (profile) {
+ content.parsed = reactStringReplace(content.parsed, item.text, (match, i) => (
+
+ ));
+ }
+ });
- // parse hashtag
- content.parsed = reactStringReplace(content.parsed, /#(\w+)/g, (match, i) => (
-
- #{match}
-
- ));
+ // parse hashtag
+ content.parsed = reactStringReplace(content.parsed, /#(\w+)/g, (match, i) => (
+
+ #{match}
+
+ ));
- // clean array
- content.parsed = content.parsed.filter((el) => el !== "\n");
+ // clean array
+ content.parsed = content.parsed.filter((el) => el !== '\n');
- return content;
+ return content;
}
diff --git a/src/utils/shortenKey.tsx b/src/utils/shortenKey.tsx
index b34befbc..4e90b4f5 100644
--- a/src/utils/shortenKey.tsx
+++ b/src/utils/shortenKey.tsx
@@ -1,6 +1,6 @@
-import { nip19 } from "nostr-tools";
+import { nip19 } from 'nostr-tools';
export function shortenKey(pubkey: string) {
- const npub = nip19.npubEncode(pubkey);
- return npub.substring(0, 16).concat("...");
+ const npub = nip19.npubEncode(pubkey);
+ return npub.substring(0, 16).concat('...');
}
diff --git a/src/utils/transform.tsx b/src/utils/transform.tsx
index 9273d9b4..e4f771a6 100644
--- a/src/utils/transform.tsx
+++ b/src/utils/transform.tsx
@@ -1,105 +1,105 @@
-import { NDKTag } from "@nostr-dev-kit/ndk";
-import destr from "destr";
-import { nip19 } from "nostr-tools";
+import { NDKTag } from '@nostr-dev-kit/ndk';
+import destr from 'destr';
+import { nip19 } from 'nostr-tools';
export function truncateContent(str, n) {
- return str.length > n ? `${str.slice(0, n - 1)}...` : str;
+ return str.length > n ? `${str.slice(0, n - 1)}...` : str;
}
export function setToArray(tags: any) {
- const newArray = [];
- tags.forEach((item) => {
- const hexpubkey = nip19.decode(item.npub).data;
- newArray.push(hexpubkey);
- });
+ const newArray = [];
+ tags.forEach((item) => {
+ const hexpubkey = nip19.decode(item.npub).data;
+ newArray.push(hexpubkey);
+ });
- return newArray;
+ return newArray;
}
// convert NIP-02 to array of pubkey
export function nip02ToArray(tags: any) {
- const arr = [];
- tags.forEach((item) => {
- arr.push(item[1]);
- });
+ const arr = [];
+ tags.forEach((item) => {
+ arr.push(item[1]);
+ });
- return arr;
+ return arr;
}
// convert array to NIP-02 tag list
export function arrayToNIP02(arr: string[]) {
- const nip02_arr = [];
- arr.forEach((item) => {
- nip02_arr.push(["p", item]);
- });
+ const nip02_arr = [];
+ arr.forEach((item) => {
+ nip02_arr.push(['p', item]);
+ });
- return nip02_arr;
+ return nip02_arr;
}
// convert array object to pure array
export function arrayObjToPureArr(arr: any) {
- const pure_arr = [];
- arr.forEach((item) => {
- pure_arr.push(item.content);
- });
+ const pure_arr = [];
+ arr.forEach((item) => {
+ pure_arr.push(item.content);
+ });
- return pure_arr;
+ return pure_arr;
}
// get parent id from event tags
export function getParentID(arr: string[], fallback: string) {
- const tags = destr(arr);
- let parentID = fallback;
+ const tags = destr(arr);
+ let parentID = fallback;
- if (tags.length > 0) {
- if (tags[0][0] === "e") {
- parentID = tags[0][1];
- } else {
- tags.forEach((tag) => {
- if (tag[0] === "e" && (tag[2] === "root" || tag[3] === "root")) {
- parentID = tag[1];
- }
- });
- }
- }
+ if (tags.length > 0) {
+ if (tags[0][0] === 'e') {
+ parentID = tags[0][1];
+ } else {
+ tags.forEach((tag) => {
+ if (tag[0] === 'e' && (tag[2] === 'root' || tag[3] === 'root')) {
+ parentID = tag[1];
+ }
+ });
+ }
+ }
- return parentID;
+ return parentID;
}
// check id present in event tags
export function isTagsIncludeID(id: string, arr: NDKTag[]) {
- const tags = destr(arr);
+ const tags = destr(arr);
- if (tags.length > 0) {
- if (tags[0][1] === id) {
- return true;
- }
- } else {
- return false;
- }
+ if (tags.length > 0) {
+ if (tags[0][1] === id) {
+ return true;
+ }
+ } else {
+ return false;
+ }
}
// get parent id from event tags
export function getRepostID(arr: NDKTag[]) {
- const tags = destr(arr);
- let quoteID = null;
+ const tags = destr(arr);
+ let quoteID = null;
- if (tags.length > 0) {
- if (tags[0][0] === "e") {
- quoteID = tags[0][1];
- } else {
- quoteID = tags.find((t) => t[0] === "e")?.[1];
- }
- }
+ if (tags.length > 0) {
+ if (tags[0][0] === 'e') {
+ quoteID = tags[0][1];
+ } else {
+ quoteID = tags.find((t) => t[0] === 'e')?.[1];
+ }
+ }
- return quoteID;
+ return quoteID;
}
// sort events by timestamp
export function sortEvents(arr: any) {
- arr.sort((a, b) => {
- return a.created_at - b.created_at;
- });
+ arr.sort((a, b) => {
+ return a.created_at - b.created_at;
+ });
- return arr;
+ return arr;
}
diff --git a/src/utils/types.ts b/src/utils/types.ts
index 315cfc38..49def25d 100644
--- a/src/utils/types.ts
+++ b/src/utils/types.ts
@@ -1,6 +1,6 @@
-import { NDKEvent } from "@nostr-dev-kit/ndk";
+import { NDKEvent } from '@nostr-dev-kit/ndk';
export interface LumeEvent extends NDKEvent {
- event_id: string;
- parent_id: string;
+ event_id: string;
+ parent_id: string;
}