From da931debcc34f0bf50ed86934c6fa1c5ab0b5f7d Mon Sep 17 00:00:00 2001 From: blinko Date: Tue, 17 Dec 2024 14:11:41 +0800 Subject: [PATCH 01/55] fix: update logo assets and caching headers - Added caching headers for static assets in `next.config.js` to improve performance. - Replaced old logo files with new versions (`logo-light.png`, `logo-dark.png`) and updated references in the Sidebar and Sign-in components. - Updated the `manifest.json` to include new icon sizes and paths. - Removed deprecated icon files (`icon-192x192.png`, `icon-512x512.png`, `single-logo.svg`). - Enhanced the `logo.svg` and `logo-dark.svg` with new designs for better visual appeal. --- next.config.js | 40 ++++++++++ public/favicon.ico | Bin 4721 -> 20977 bytes public/icon-192x192.png | Bin 10342 -> 0 bytes public/icon-512x512.png | Bin 22677 -> 0 bytes public/icons/icon-128x128.png | Bin 0 -> 20977 bytes public/icons/icon-144x144.png | Bin 0 -> 25375 bytes public/icons/icon-152x152.png | Bin 0 -> 27954 bytes public/icons/icon-192x192.png | Bin 0 -> 42044 bytes public/icons/icon-256x256.png | Bin 0 -> 69648 bytes public/logo-dark.png | Bin 0 -> 13117 bytes public/logo-dark.svg | 113 ++++++++++++++++++++++++++- public/logo-light.png | Bin 0 -> 13466 bytes public/logo-light.svg | 123 ++++++++++++++++++++++++++++++ public/logo.svg | 115 +++++++++++++++++++++++++++- public/manifest.json | 23 +++++- public/single-logo.svg | 1 - src/components/Layout/Sidebar.tsx | 4 +- src/pages/signin.tsx | 2 +- 18 files changed, 411 insertions(+), 10 deletions(-) delete mode 100644 public/icon-192x192.png delete mode 100644 public/icon-512x512.png create mode 100644 public/icons/icon-128x128.png create mode 100644 public/icons/icon-144x144.png create mode 100644 public/icons/icon-152x152.png create mode 100644 public/icons/icon-192x192.png create mode 100644 public/icons/icon-256x256.png create mode 100644 public/logo-dark.png create mode 100644 public/logo-light.png create mode 100644 public/logo-light.svg delete mode 100644 public/single-logo.svg diff --git a/next.config.js b/next.config.js index 424cf983..aae1a535 100644 --- a/next.config.js +++ b/next.config.js @@ -7,6 +7,46 @@ const withPWA = require('next-pwa')({ module.exports = withPWA({ output: 'standalone', transpilePackages: ['react-diff-view','highlight.js','remark-gfm','rehype-raw'], + async headers() { + return [ + { + headers: [ + { + key: 'Cache-Control', + value: 'public, max-age=31536000, immutable', + }, + ], + source: '/icons/(.*).(png|jpe?g|gif|svg|ico|webp)', + }, + { + headers: [ + { + key: 'Cache-Control', + value: 'public, max-age=31536000, immutable', + }, + ], + source: '/favicon.ico', + }, + { + headers: [ + { + key: 'Cache-Control', + value: 'public, max-age=31536000, immutable', + }, + ], + source: '/logo-light.png', + }, + { + headers: [ + { + key: 'Cache-Control', + value: 'public, max-age=31536000, immutable', + }, + ], + source: '/logo-dark.png', + }, + ]; + }, webpack: (config, { isServer }) => { config.experiments = { ...config.experiments, topLevelAwait: true }; if (!isServer) { diff --git a/public/favicon.ico b/public/favicon.ico index a110df443b20334d377ea9e105abdcb43eea359d..32469e9b447e9c155a4fae11577ea019e209bc1a 100644 GIT binary patch literal 20977 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�hurKI*j+hbZ-&mqQU2_)-NR}X&x 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 literal 4721 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 diff --git a/public/icon-512x512.png b/public/icon-512x512.png deleted file mode 100644 index 86cbc8007f8e261c85377627b7ec5804dc0e71b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22677 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 L-R$nzP*46Ji6QR1 diff --git a/public/icons/icon-128x128.png b/public/icons/icon-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..32469e9b447e9c155a4fae11577ea019e209bc1a GIT binary patch literal 20977 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�hurKI*j+hbZ-&mqQU2_)-NR}X&x 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 literal 0 HcmV?d00001 diff --git a/public/icons/icon-144x144.png b/public/icons/icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..ec2a7ca78ca20342868929cc5ca4bd9b14f40dc1 GIT binary patch literal 25375 zcmV({K+?a7P)AIrr9(8p4nWq$(&vP%@ycXp;#WpNJ^DR{Hl8CD8q}acISMeCQ);i~SrB z?QU`8*+PU?(Y6~AK^uWEDN!I0AQ6&ORi?^NbJZQrIeWdm_Zs(itC$4em)tt%e8V2r zUi-iPYwh7f`2XkFKL9+9Qo0-g_GF^V%eme4I{@x3-x13XA|NQA{D1l04g|hNaufew zz9JCcg9))*Cq4!3(ehoA!+JowUJl}1+D+|(9QAxE330Z5x;;}fZ-w+c`I&NE%GiFj z8!QFlGj@NdlP1=m0!fdg#>kR5UcMefOb5%kV;Sh?A*Gx10uP+tJbg3#6CViwG{>Hz zFwZFpb4{uIvx$`jSe{^wp-rjEgXb(=cpAWz0i=OjyEYAz7HKWl8a}iBwRR^A`Ez>h zInN~_-$+%Nuy1+R;QCA|7qXp4&I?>IU6C~L`j9B`mRd=rLY=g?0EW7I&8!Wp{vIrM z-IyW2W4gNfXUEC`pXcNAsz8&;Ynr+J9v58{xx1j}RLLlmp6dSq9sYEm3Y#S9TB~=;F;)l$OGa5n zT$YcNLu6Q#G3DAhSOyW>Za^4rIJtiEM)*7(pAQAvlTx~_$mPZ5`+hmca_cKc0qOlF zDHb=hrKxgf;Q@?Fu3{Ad`a^^eaY*hCCa&g@8DSy)mY@|qa z!pnf#-mF07hFp#)mWoO_C}&6?Me((xMeI?)BRy42FQ-#}B&hX+0}1fwPOP840Y1ma z=URbYQ2u_oRH$$nsiG2(mYXO>%o<~(oA9_-kNJQ|lR^VQKq�kSjp==1PQHdMdyu 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�$~Im+ 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 \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/logo-light.png b/public/logo-light.png new file mode 100644 index 0000000000000000000000000000000000000000..4b2ec521ac357094e0a0126a50df51a591e745d6 GIT binary patch literal 13466 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 IM6N<$f;i?MIRF3v literal 0 HcmV?d00001 diff --git a/public/logo-light.svg b/public/logo-light.svg new file mode 100644 index 00000000..a1d4af99 --- /dev/null +++ b/public/logo-light.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/logo.svg b/public/logo.svg index d1317ed0..11836e3a 100644 --- a/public/logo.svg +++ b/public/logo.svg @@ -1 +1,114 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/manifest.json b/public/manifest.json index 3a1031a8..3d913fbd 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -3,14 +3,29 @@ "short_name": "Blinko", "icons": [ { - "src": "/icon-192x192.png", - "sizes": "192x192", + "src": "/logo/icon-128x128.png", + "sizes": "128x128", "type": "image/png", "purpose": "any maskable" }, { - "src": "/icon-512x512.png", - "sizes": "512x512", + "src": "/logo/icon-144x144.png", + "sizes": "144x144", + "type": "image/png" + }, + { + "src": "/logo/icon-152x152.png", + "sizes": "152x152", + "type": "image/png" + }, + { + "src": "/logo/icon-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/logo/icon-256x256.png", + "sizes": "256x256", "type": "image/png" } ], diff --git a/public/single-logo.svg b/public/single-logo.svg deleted file mode 100644 index 40ba6c13..00000000 --- a/public/single-logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/components/Layout/Sidebar.tsx b/src/components/Layout/Sidebar.tsx index ab460a81..2bcab313 100644 --- a/src/components/Layout/Sidebar.tsx +++ b/src/components/Layout/Sidebar.tsx @@ -39,9 +39,9 @@ export const Sidebar = observer(({ onItemClick }: SidebarProps) => {

{!base.isSidebarCollapsed && ( theme == 'dark' ? ( - + ) : ( - + ) )} { diff --git a/src/pages/signin.tsx b/src/pages/signin.tsx index 1d3c95fc..c3de21cd 100644 --- a/src/pages/signin.tsx +++ b/src/pages/signin.tsx @@ -98,7 +98,7 @@ export default function Component() {

- Login With

+ Login With

e.preventDefault()}> Date: Tue, 17 Dec 2024 14:12:26 +0800 Subject: [PATCH 02/55] chore: update logo reference in README - Replaced the old logo reference from `single-logo.svg` to the new `logo.svg` in the README file to reflect the latest branding changes. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ea14bcd7..870dfa0d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -Blinko +Blinko # Blinko - Open Source, Self-hosted From 3de26b58f4c66dba760daaca6e09fbdb063d9d0e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 17 Dec 2024 06:13:27 +0000 Subject: [PATCH 03/55] chore(release): 0.26.11 [skip ci] ## [0.26.11](https://github.com/blinko-space/blinko/compare/v0.26.10...v0.26.11) (2024-12-17) ### Bug Fixes * update logo assets and caching headers ([da931de](https://github.com/blinko-space/blinko/commit/da931debcc34f0bf50ed86934c6fa1c5ab0b5f7d)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 408805e5..2deeec29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.26.11](https://github.com/blinko-space/blinko/compare/v0.26.10...v0.26.11) (2024-12-17) + + +### Bug Fixes + +* update logo assets and caching headers ([da931de](https://github.com/blinko-space/blinko/commit/da931debcc34f0bf50ed86934c6fa1c5ab0b5f7d)) + ## [0.26.10](https://github.com/blinko-space/blinko/compare/v0.26.9...v0.26.10) (2024-12-16) diff --git a/package.json b/package.json index 76d05552..bd606192 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blinko", - "version": "0.26.10", + "version": "0.26.11", "repository": "https://github.com/blinko-space/blinko.git", "private": true, "browser": { From 17604c28f08e0e3f4ab426e074bbd8c812d6375f Mon Sep 17 00:00:00 2001 From: blinko Date: Tue, 17 Dec 2024 16:56:55 +0800 Subject: [PATCH 04/55] fix: add error logging in FileService writeFileSafe method - Introduced console error logging in the writeFileSafe method of the FileService class to capture and report errors during file write attempts. This enhancement aids in debugging and improves error visibility. --- app/api/file/upload-by-url/route.ts | 2 +- src/components/Common/AttachmentRender/imageRender.tsx | 6 +++--- src/server/plugins/files.ts | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/api/file/upload-by-url/route.ts b/app/api/file/upload-by-url/route.ts index 6f76e2c4..c7a8e7e3 100644 --- a/app/api/file/upload-by-url/route.ts +++ b/app/api/file/upload-by-url/route.ts @@ -32,7 +32,7 @@ export const POST = async (req: NextRequest, res: NextResponse) => { const urlPath = new URL(url).pathname; const originalName = path.basename(urlPath).replaceAll(" ", "_"); const extension = path.extname(originalName); - + console.log({ originalName, extension }) const filePath = await FileService.uploadFile(buffer, originalName); return NextResponse.json({ diff --git a/src/components/Common/AttachmentRender/imageRender.tsx b/src/components/Common/AttachmentRender/imageRender.tsx index 3bdf9cdb..bcc29690 100644 --- a/src/components/Common/AttachmentRender/imageRender.tsx +++ b/src/components/Common/AttachmentRender/imageRender.tsx @@ -17,12 +17,13 @@ type IProps = { const ImageThumbnailRender = ({ file, className }: { file: FileType, className?: string }) => { const [isOriginalError, setIsOriginalError] = useState(false); const [currentSrc, setCurrentSrc] = useState( + file.preview.includes('/api/s3file/') ? file.preview : `${file.preview}?thumbnail=true` ); useEffect(() => { if (isOriginalError) { - setCurrentSrc('/image-fallback.svg') + setCurrentSrc('/image-fallback.svg') } }, [isOriginalError]) @@ -37,7 +38,6 @@ const ImageThumbnailRender = ({ file, className }: { file: FileType, className?: } setCurrentSrc(file.preview) }} - crossOrigin="use-credentials" className={`object-cover w-full ${className}`} /> } @@ -73,7 +73,7 @@ const ImageRender = observer((props: IProps) => { return `max-h-[100px] w-auto` } if (!preview && !isPc) { - return `h-[80px] w-[80px] min-w-[80px]` + return `h-[80px] min-w-[80px]` } if (imageLength == 1) { return `h-[200px] max-h-[200px] md:max-w-[200px]` diff --git a/src/server/plugins/files.ts b/src/server/plugins/files.ts index c441ea25..3ab9fa23 100644 --- a/src/server/plugins/files.ts +++ b/src/server/plugins/files.ts @@ -32,7 +32,7 @@ export class FileService { let filename = attempt === 0 ? `${baseName}${extension}` : - `${baseName}_${attempt}${extension}`; + `${baseName}_${Date.now()}${extension}`; try { const filePath = path.join(process.cwd(), `${UPLOAD_FILE_PATH}/` + filename); @@ -40,6 +40,7 @@ export class FileService { //@ts-ignore return this.writeFileSafe(baseName, extension, buffer, attempt + 1); } catch (error) { + console.error(error) const filePath = path.join(process.cwd(), `${UPLOAD_FILE_PATH}/` + filename); //@ts-ignore await writeFile(filePath, buffer); From bab1eef43ff0a16104f02b29249ee451a9e5f36f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 17 Dec 2024 08:58:25 +0000 Subject: [PATCH 05/55] chore(release): 0.26.12 [skip ci] ## [0.26.12](https://github.com/blinko-space/blinko/compare/v0.26.11...v0.26.12) (2024-12-17) ### Bug Fixes * add error logging in FileService writeFileSafe method ([17604c2](https://github.com/blinko-space/blinko/commit/17604c28f08e0e3f4ab426e074bbd8c812d6375f)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2deeec29..c559680a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.26.12](https://github.com/blinko-space/blinko/compare/v0.26.11...v0.26.12) (2024-12-17) + + +### Bug Fixes + +* add error logging in FileService writeFileSafe method ([17604c2](https://github.com/blinko-space/blinko/commit/17604c28f08e0e3f4ab426e074bbd8c812d6375f)) + ## [0.26.11](https://github.com/blinko-space/blinko/compare/v0.26.10...v0.26.11) (2024-12-17) diff --git a/package.json b/package.json index bd606192..18a2b0cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blinko", - "version": "0.26.11", + "version": "0.26.12", "repository": "https://github.com/blinko-space/blinko.git", "private": true, "browser": { From ef0930618aefbefa461fd98f9d23095d39e3ae34 Mon Sep 17 00:00:00 2001 From: blinko Date: Tue, 17 Dec 2024 17:31:53 +0800 Subject: [PATCH 06/55] feat: add user data deletion confirmation dialog and enhance translation files - Implemented a confirmation dialog for user data deletion in the UserSetting component, ensuring users are aware that all associated data will be permanently cleared. - Updated translation files for multiple languages to include a new message regarding the irretrievability of user data after deletion, enhancing user experience and clarity across the application. --- public/locales/ar/translation.json | 3 +- public/locales/de/translation.json | 3 +- public/locales/en/translation.json | 3 +- public/locales/es/translation.json | 3 +- public/locales/fr/translation.json | 3 +- public/locales/ja/translation.json | 3 +- public/locales/ko/translation.json | 3 +- public/locales/pt/translation.json | 3 +- public/locales/ru/translation.json | 3 +- public/locales/tr/translation.json | 3 +- public/locales/zh-TW/translation.json | 3 +- public/locales/zh/translation.json | 3 +- src/components/BlinkoSettings/UserSetting.tsx | 42 +++++- src/components/Common/TipsDialog/index.tsx | 4 +- src/components/Layout/index.tsx | 36 ++++- src/server/routers/note.ts | 136 ++++++++++-------- src/server/routers/user.ts | 54 +++++++ 17 files changed, 227 insertions(+), 81 deletions(-) diff --git a/public/locales/ar/translation.json b/public/locales/ar/translation.json index 8de0437c..7364d953 100644 --- a/public/locales/ar/translation.json +++ b/public/locales/ar/translation.json @@ -344,5 +344,6 @@ "insert-attachment-or-note": "الإرفاق بملف أو المذكرة؟", "context": "السياق", "paste-to-note-or-attachment": "هل أنت متأكد من لصق النص في السياق أو المرفق؟", - "attachment": "المرفق" + "attachment": "المرفق", + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "بعد الحذف، سيتم مسح جميع بيانات المستخدم ولن يمكن استرجاعها." } diff --git a/public/locales/de/translation.json b/public/locales/de/translation.json index a7b46a8c..90b5d15a 100644 --- a/public/locales/de/translation.json +++ b/public/locales/de/translation.json @@ -331,5 +331,6 @@ "insert-attachment-or-note": "In Anhang oder Notiz einfügen?", "context": "Kontext", "paste-to-note-or-attachment": "Sind Sie sicher, dass Sie in den Kontext oder als Anhang einfügen möchten?", - "attachment": "Anhang" + "attachment": "Anhang", + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Nach dem Löschen werden alle Benutzerdaten gelöscht und können nicht wiederhergestellt werden." } diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 8e87dcd1..f7a5179b 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -342,5 +342,6 @@ "insert-attachment-or-note": "Insert to attachment or note?", "paste-to-note-or-attachment": "Are you sure to paste to context or attachment? ", "context": "Context", - "attachment": "Attachment" + "attachment": "Attachment", + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "After deletion, all user data will be cleared and unrecoverable." } diff --git a/public/locales/es/translation.json b/public/locales/es/translation.json index 18131fcf..53543652 100644 --- a/public/locales/es/translation.json +++ b/public/locales/es/translation.json @@ -322,5 +322,6 @@ "insert-attachment-or-note": "¿Insertar en el archivo adjunto o en la nota?", "context": "Contexto", "paste-to-note-or-attachment": "¿Estás seguro de pegar en el contexto o adjuntar?", - "attachment": "Adjunto" + "attachment": "Adjunto", + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Después de la eliminación, todos los datos de usuario serán borrados y no se podrán recuperar." } diff --git a/public/locales/fr/translation.json b/public/locales/fr/translation.json index 9bae94d6..1316ec0f 100644 --- a/public/locales/fr/translation.json +++ b/public/locales/fr/translation.json @@ -319,5 +319,6 @@ "insert-attachment-or-note": "Insérer dans la pièce jointe ou la note ?", "context": "Contexte", "paste-to-note-or-attachment": "Êtes-vous sûr de coller dans le contexte ou en pièce jointe ?", - "attachment": "Pièce jointe" + "attachment": "Pièce jointe", + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Après la suppression, toutes les données utilisateur seront effacées et définitivement irrécupérables." } diff --git a/public/locales/ja/translation.json b/public/locales/ja/translation.json index 53f7d576..c9346800 100644 --- a/public/locales/ja/translation.json +++ b/public/locales/ja/translation.json @@ -304,5 +304,6 @@ "insert-attachment-or-note": "添付ファイルに挿入しますか、それともメモに書き込みますか?", "context": "コンテクスト", "paste-to-note-or-attachment": "コンテキストや添付ファイルに貼り付けることを確認しますか?", - "attachment": "添付" + "attachment": "添付", + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "削除後、すべてのユーザーデータは消去され、回復不能になります。" } diff --git a/public/locales/ko/translation.json b/public/locales/ko/translation.json index 0bc94a16..769fbd9a 100644 --- a/public/locales/ko/translation.json +++ b/public/locales/ko/translation.json @@ -326,5 +326,6 @@ "insert-attachment-or-note": "첨부 파일이나 메모로 삽입하시겠습니까?", "context": "문맥", "paste-to-note-or-attachment": "컨텍스트나 첨부 파일에 붙여 넣을 확신이 있습니까?", - "attachment": "첨부 파일" + "attachment": "첨부 파일", + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "삭제 후 모든 사용자 데이터가 지워지고 복구할 수 없게 됩니다." } diff --git a/public/locales/pt/translation.json b/public/locales/pt/translation.json index d5788ccb..1fa93d25 100644 --- a/public/locales/pt/translation.json +++ b/public/locales/pt/translation.json @@ -254,5 +254,6 @@ "insert-attachment-or-note": "Inserir em anexo ou nota?", "context": "Contexto", "paste-to-note-or-attachment": "Tem certeza de que deseja colar no contexto ou no anexo?", - "attachment": "Anexo" + "attachment": "Anexo", + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Após a exclusão, todos os dados do usuário serão apagados e não poderão ser recuperados." } diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json index e8205df4..50da1d07 100644 --- a/public/locales/ru/translation.json +++ b/public/locales/ru/translation.json @@ -259,5 +259,6 @@ "insert-attachment-or-note": "Вставить во вложение или заметку?", "context": "Контекст", "paste-to-note-or-attachment": "Вы уверены, что хотите вставить в контекст или прикрепление?", - "attachment": "Прикрепление" + "attachment": "Прикрепление", + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "После удаления все данные пользователей будут очищены и не поддадутся восстановлению." } diff --git a/public/locales/tr/translation.json b/public/locales/tr/translation.json index d6141f25..811ec8c0 100644 --- a/public/locales/tr/translation.json +++ b/public/locales/tr/translation.json @@ -272,5 +272,6 @@ "insert-attachment-or-note": "Eklentiye mi yoksa notlara mı ekleyeceksiniz?", "context": "Bağlam", "paste-to-note-or-attachment": "Metin veya ek dosyaya yapıştırmak istediğinizden emin misiniz?", - "attachment": "Eklenti" + "attachment": "Eklenti", + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Silme işleminden sonra, tüm kullanıcı verileri temizlenecek ve kurtarılamaz hale gelecektir." } diff --git a/public/locales/zh-TW/translation.json b/public/locales/zh-TW/translation.json index e74d5981..bd63d66d 100644 --- a/public/locales/zh-TW/translation.json +++ b/public/locales/zh-TW/translation.json @@ -356,5 +356,6 @@ "insert-attachment-or-note": "插入至附件或備註?", "context": "正文", "paste-to-note-or-attachment": "您確定要貼上到內容或附件嗎?", - "attachment": "附件" + "attachment": "附件", + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "刪除後,所有用戶資料將被清空且無法恢復。" } diff --git a/public/locales/zh/translation.json b/public/locales/zh/translation.json index e5dc47b6..4f649c41 100644 --- a/public/locales/zh/translation.json +++ b/public/locales/zh/translation.json @@ -356,5 +356,6 @@ "insert-attachment-or-note": "插入附件还是笔记中?", "paste-to-note-or-attachment": "您确定要粘贴到上下文或附件吗?", "context": "正文", - "attachment": "附件" + "attachment": "附件", + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "删除后,所有用户数据将被清除且无法恢复。" } diff --git a/src/components/BlinkoSettings/UserSetting.tsx b/src/components/BlinkoSettings/UserSetting.tsx index 96770130..42d21dd0 100644 --- a/src/components/BlinkoSettings/UserSetting.tsx +++ b/src/components/BlinkoSettings/UserSetting.tsx @@ -13,6 +13,9 @@ import { DialogStore } from "@/store/module/Dialog"; import { signOut } from "next-auth/react"; import { PasswordInput } from "../Common/PasswordInput"; import { CollapsibleCard } from "../Common/CollapsibleCard"; +import { showTipsDialog } from "../Common/TipsDialog"; +import { ToastPlugin } from "@/store/module/Toast/Toast"; +import { DialogStandaloneStore } from "@/store/module/DialogStandalone"; const UpdateUserInfo = observer(({ id, name, password }: { id?: number, name: string, password: string }) => { const { t } = useTranslation() @@ -55,7 +58,7 @@ export const UserSetting = observer(() => { useEffect(() => { blinko.userList.call() }, []) - + return ( { content: }) }}>{t('create-user')} - } + } /> { {i.role} - + }) } - : null} + : null + } /> - + ); }); \ No newline at end of file diff --git a/src/components/Common/TipsDialog/index.tsx b/src/components/Common/TipsDialog/index.tsx index 2cf772ae..ee1408ae 100644 --- a/src/components/Common/TipsDialog/index.tsx +++ b/src/components/Common/TipsDialog/index.tsx @@ -29,11 +29,11 @@ const TipsDialog = observer(({ content, onConfirm, onCancel, buttonSlot }: any)
}) -export const showTipsDialog = async (props: { title: string, content: string, onConfirm?, onCancel?: any, buttonSlot?: React.ReactNode }) => { +export const showTipsDialog = async (props: { size?: 'sm' | 'md' | 'lg' | 'xl', title: string, content: string, onConfirm?, onCancel?: any, buttonSlot?: React.ReactNode }) => { RootStore.Get(DialogStandaloneStore).setData({ isOpen: true, onlyContent: false, - size: 'xl', + size: props.size || 'md', title: props.title, content: }) diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx index 547eeb9a..c4551dfb 100644 --- a/src/components/Layout/index.tsx +++ b/src/components/Layout/index.tsx @@ -25,6 +25,10 @@ import { Sidebar } from "./Sidebar"; import { MobileNavBar } from "./MobileNavBar"; import FilterPop from "../Common/PopoverFloat/filterPop"; import { AppProvider } from "@/store/module/AppProvider"; +import { api } from "@/lib/trpc"; +import { showTipsDialog } from "../Common/TipsDialog"; +import { DialogStandaloneStore } from "@/store/module/DialogStandalone"; +import { ToastPlugin } from "@/store/module/Toast/Toast"; export const SideBarItem = "p-2 flex flex-row items-center cursor-pointer gap-2 hover:bg-hover rounded-xl transition-all" @@ -122,9 +126,33 @@ export const CommonLayout = observer(({ }
- {/* @ts-ignore */} -
{t(base.currentTitle)}
- blinkoStore.refreshData()} icon="fluent:arrow-sync-12-filled" width="20" height="20" /> +
+
{t(base.currentTitle)}
+ { + router.pathname != '/trash' + ? blinkoStore.refreshData()} icon="fluent:arrow-sync-12-filled" width="20" height="20" /> + : { + showTipsDialog({ + size: 'sm', + title: t('confirm-to-delete'), + content: t('this-operation-removes-the-associated-label-and-cannot-be-restored-please-confirm'), + onConfirm: async () => { + await RootStore.Get(ToastPlugin).promise( + api.notes.clearRecycleBin.mutate(), + { + loading: t('in-progress'), + success: {t('your-changes-have-been-saved')}, + error: {t('operation-failed')}, + }) + blinkoStore.refreshData() + RootStore.Get(DialogStandaloneStore).close() + } + }) + }} icon="mingcute:delete-2-line" width="20" height="20" /> + } +
{/* backdrop pt-6 -mt-6 to fix the editor tooltip position */} - + { }} className="flex h-[calc(100%_-_70px)] overflow-y-scroll">
{children} diff --git a/src/server/routers/note.ts b/src/server/routers/note.ts index 5e40a43c..a125c248 100644 --- a/src/server/routers/note.ts +++ b/src/server/routers/note.ts @@ -10,6 +10,7 @@ import { getGlobalConfig } from './config'; import { FileService } from '../plugins/files'; import { AiService } from '../plugins/ai'; import { SendWebhook } from './helper'; +import { Context } from '../context'; const extractHashtags = (input: string): string[] => { const withoutCodeBlocks = input.replace(/```[\s\S]*?```/g, ''); @@ -18,6 +19,7 @@ const extractHashtags = (input: string): string[] => { return matches ? matches : []; } + export const noteRouter = router({ list: authProcedure .meta({ openapi: { method: 'POST', path: '/v1/note/list', summary: 'Query notes list', protect: true, tags: ['Note'] } }) @@ -424,66 +426,12 @@ export const noteRouter = router({ }), deleteMany: authProcedure.use(demoAuthMiddleware) .meta({ openapi: { method: 'POST', path: '/v1/note/batch-delete', summary: 'Batch delete note', protect: true, tags: ['Note'] } }) - // .output(z.union([z.null(), notesSchema])) .input(z.object({ ids: z.array(z.number()) })) .output(z.any()) .mutation(async function ({ input, ctx }) { - const { ids } = input - const notes = await prisma.notes.findMany({ - where: { id: { in: ids }, accountId: Number(ctx.id) }, - include: { - tags: { include: { tag: true } }, - attachments: true, - references: true, - referencedBy: true - } - }) - const handleDeleteRelation = async () => { - for (const note of notes) { - SendWebhook({ ...note }, 'delete', ctx) - await prisma.tagsToNote.deleteMany({ where: { noteId: note.id } }) - - await prisma.noteReference.deleteMany({ - where: { - OR: [ - { fromNoteId: note.id }, - { toNoteId: note.id } - ] - } - }) - - const allTagsInThisNote = note.tags || [] - const oldTags = allTagsInThisNote.map(i => i.tag).filter(i => !!i) - const allTagsIds = oldTags?.map(i => i?.id) - const usingTags = (await prisma.tagsToNote.findMany({ - where: { tagId: { in: allTagsIds } }, - include: { tag: true } - })).map(i => i.tag?.id).filter(i => !!i) - const needTobeDeledTags = _.difference(allTagsIds, usingTags); - if (needTobeDeledTags?.length) { - await prisma.tag.deleteMany({ where: { id: { in: needTobeDeledTags }, accountId: Number(ctx.id) } }) - } - - if (note.attachments?.length) { - for (const attachment of note.attachments) { - try { - await FileService.deleteFile(attachment.path) - } catch (error) { - console.log('delete attachment error:', error) - } - } - await prisma.attachments.deleteMany({ - where: { id: { in: note.attachments.map(i => i.id) } } - }) - } - } - } - - await handleDeleteRelation() - await prisma.notes.deleteMany({ where: { id: { in: ids }, accountId: Number(ctx.id) } }) - return { ok: true } + return await deleteNotes(input.ids, ctx); }), addReference: authProcedure .meta({ openapi: { method: 'POST', path: '/v1/note/add-reference', summary: 'Add note reference', protect: true, tags: ['Note'] } }) @@ -560,6 +508,24 @@ export const noteRouter = router({ })); } }), + clearRecycleBin: authProcedure.use(demoAuthMiddleware) + .meta({ openapi: { method: 'POST', path: '/v1/note/clear-recycle-bin', summary: 'Clear recycle bin', protect: true, tags: ['Note'] } }) + .input(z.void()) + .output(z.any()) + .mutation(async function ({ ctx }) { + const recycleBinNotes = await prisma.notes.findMany({ + where: { + accountId: Number(ctx.id), + isRecycle: true + }, + select: { id: true } + }); + + const noteIds = recycleBinNotes.map(note => note.id); + if(noteIds.length === 0) return { ok: true }; + + return await deleteNotes(noteIds, ctx); + }), }) let insertNoteReference = async ({ fromNoteId, toNoteId, accountId }) => { @@ -580,6 +546,60 @@ let insertNoteReference = async ({ fromNoteId, toNoteId, accountId }) => { }); } -// let deleteNoteReference = async ({ fromNoteId, toNoteId, accountId }) => { -// return await prisma.noteReference.deleteMany({ where: { fromNoteId, toNoteId, accountId } }) -// } + +export async function deleteNotes(ids: number[], ctx: Context) { + const notes = await prisma.notes.findMany({ + where: { id: { in: ids }, accountId: Number(ctx.id) }, + include: { + tags: { include: { tag: true } }, + attachments: true, + references: true, + referencedBy: true + } + }); + + const handleDeleteRelation = async () => { + for (const note of notes) { + SendWebhook({ ...note }, 'delete', ctx); + await prisma.tagsToNote.deleteMany({ where: { noteId: note.id } }); + + await prisma.noteReference.deleteMany({ + where: { + OR: [ + { fromNoteId: note.id }, + { toNoteId: note.id } + ] + } + }); + + const allTagsInThisNote = note.tags || []; + const oldTags = allTagsInThisNote.map(i => i.tag).filter(i => !!i); + const allTagsIds = oldTags?.map(i => i?.id); + const usingTags = (await prisma.tagsToNote.findMany({ + where: { tagId: { in: allTagsIds } }, + include: { tag: true } + })).map(i => i.tag?.id).filter(i => !!i); + const needTobeDeledTags = _.difference(allTagsIds, usingTags); + if (needTobeDeledTags?.length) { + await prisma.tag.deleteMany({ where: { id: { in: needTobeDeledTags }, accountId: Number(ctx.id) } }); + } + + if (note.attachments?.length) { + for (const attachment of note.attachments) { + try { + await FileService.deleteFile(attachment.path); + } catch (error) { + console.log('delete attachment error:', error); + } + } + await prisma.attachments.deleteMany({ + where: { id: { in: note.attachments.map(i => i.id) } } + }); + } + } + }; + + await handleDeleteRelation(); + await prisma.notes.deleteMany({ where: { id: { in: ids }, accountId: Number(ctx.id) } }); + return { ok: true }; +} \ No newline at end of file diff --git a/src/server/routers/user.ts b/src/server/routers/user.ts index 63d3cb27..9c81a58c 100644 --- a/src/server/routers/user.ts +++ b/src/server/routers/user.ts @@ -7,6 +7,7 @@ import { Prisma } from '@prisma/client'; import { accountsSchema } from '@/lib/prismaZodType'; import { hashPassword, verifyPassword } from 'prisma/seed'; import { generateTOTP, generateTOTPQRCode, verifyTOTP } from "./helper"; +import { deleteNotes } from './note'; const genToken = async ({ id, name, role }: { id: number, name: string, role: string }) => { return await encode({ @@ -244,4 +245,57 @@ export const userRouter = router({ } return true; }), + deleteUser: authProcedure.use(superAdminAuthMiddleware).use(demoAuthMiddleware) + .meta({ + openapi: { + method: 'DELETE', + path: '/v1/user/delete', + summary: 'Delete user', + description: 'Delete user and all related data, need super admin permission', + tags: ['User'] + } + }) + .input(z.object({ + id: z.number() + })) + .output(z.boolean()) + .mutation(async ({ input, ctx }) => { + return prisma.$transaction(async () => { + const { id } = input + + const userToDelete = await prisma.accounts.findFirst({ + where: { id } + }) + + if (!userToDelete) { + throw new TRPCError({ + code: 'NOT_FOUND', + message: 'User not found' + }) + } + + if (userToDelete.role === 'superadmin') { + throw new TRPCError({ + code: 'FORBIDDEN', + message: 'Cannot delete super admin account' + }) + } + + const userNotes = await prisma.notes.findMany({ + where: { accountId: id } + }) + + await deleteNotes(userNotes.map(note => note.id), ctx) + + await prisma.config.deleteMany({ + where: { userId: id } + }) + + await prisma.accounts.delete({ + where: { id } + }) + + return true + }) + }), }) From 60c4a418164f0cc8e2eae32edad6a667f740a6df Mon Sep 17 00:00:00 2001 From: blinko Date: Tue, 17 Dec 2024 17:34:40 +0800 Subject: [PATCH 07/55] feat: add self-deletion prevention in user deletion logic - Implemented a check to prevent users from deleting their own accounts, throwing a FORBIDDEN error if attempted. This enhances account security and user experience by ensuring users cannot inadvertently remove their own access. --- src/server/routers/user.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/server/routers/user.ts b/src/server/routers/user.ts index 9c81a58c..8dac159b 100644 --- a/src/server/routers/user.ts +++ b/src/server/routers/user.ts @@ -267,6 +267,8 @@ export const userRouter = router({ where: { id } }) + + if (!userToDelete) { throw new TRPCError({ code: 'NOT_FOUND', @@ -281,6 +283,13 @@ export const userRouter = router({ }) } + if (userToDelete.id === Number(ctx.id)) { + throw new TRPCError({ + code: 'FORBIDDEN', + message: 'Cannot delete yourself' + }) + } + const userNotes = await prisma.notes.findMany({ where: { accountId: id } }) From f9d500ce40ebd8a6d2608945e3dbfe8d123c89b6 Mon Sep 17 00:00:00 2001 From: blinko Date: Tue, 17 Dec 2024 17:36:48 +0800 Subject: [PATCH 08/55] fix: enhance sign-in component with theme-based logo and clean up imports - Removed unused imports and added the useTheme hook to dynamically switch the logo based on the current theme (light/dark). - Updated the logo rendering in the sign-in component to reflect the selected theme, improving visual consistency and user experience. --- src/pages/signin.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pages/signin.tsx b/src/pages/signin.tsx index c3de21cd..80272a34 100644 --- a/src/pages/signin.tsx +++ b/src/pages/signin.tsx @@ -1,17 +1,17 @@ -import React, { useCallback, useEffect, useState } from "react"; -import { Button, Input, Checkbox, Link, Image, InputOtp } from "@nextui-org/react"; +import React, { useEffect, useState } from "react"; +import { Button, Input, Checkbox, Link, Image } from "@nextui-org/react"; import { Icon } from "@iconify/react"; import { signIn } from "next-auth/react"; import { RootStore } from "@/store"; import { useRouter } from "next/router"; import { ToastPlugin } from "@/store/module/Toast/Toast"; import { useTranslation } from "react-i18next"; -import { api } from "@/lib/trpc"; import { StorageState } from "@/store/standard/StorageState"; import { UserStore } from "@/store/user"; import { ShowTwoFactorModal } from "@/components/Common/TwoFactorModal"; import { DialogStore } from "@/store/module/Dialog"; import { PromiseState } from "@/store/standard/PromiseState"; +import { useTheme } from "next-themes"; export default function Component() { const router = useRouter() @@ -19,6 +19,7 @@ export default function Component() { const [user, setUser] = React.useState(""); const [password, setPassword] = React.useState(""); const [canRegister, setCanRegister] = useState(false) + const { theme } = useTheme() const { t } = useTranslation() const SignIn = new PromiseState({ function: async () => { @@ -98,7 +99,7 @@ export default function Component() {

- Login With

+ Login With

e.preventDefault()}> Date: Tue, 17 Dec 2024 09:39:20 +0000 Subject: [PATCH 09/55] chore(release): 0.27.0 [skip ci] # [0.27.0](https://github.com/blinko-space/blinko/compare/v0.26.12...v0.27.0) (2024-12-17) ### Bug Fixes * enhance sign-in component with theme-based logo and clean up imports ([f9d500c](https://github.com/blinko-space/blinko/commit/f9d500ce40ebd8a6d2608945e3dbfe8d123c89b6)) ### Features * add self-deletion prevention in user deletion logic ([60c4a41](https://github.com/blinko-space/blinko/commit/60c4a418164f0cc8e2eae32edad6a667f740a6df)) * add user data deletion confirmation dialog and enhance translation files ([ef09306](https://github.com/blinko-space/blinko/commit/ef0930618aefbefa461fd98f9d23095d39e3ae34)) --- CHANGELOG.md | 13 +++++++++++++ package.json | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c559680a..21b763cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +# [0.27.0](https://github.com/blinko-space/blinko/compare/v0.26.12...v0.27.0) (2024-12-17) + + +### Bug Fixes + +* enhance sign-in component with theme-based logo and clean up imports ([f9d500c](https://github.com/blinko-space/blinko/commit/f9d500ce40ebd8a6d2608945e3dbfe8d123c89b6)) + + +### Features + +* add self-deletion prevention in user deletion logic ([60c4a41](https://github.com/blinko-space/blinko/commit/60c4a418164f0cc8e2eae32edad6a667f740a6df)) +* add user data deletion confirmation dialog and enhance translation files ([ef09306](https://github.com/blinko-space/blinko/commit/ef0930618aefbefa461fd98f9d23095d39e3ae34)) + ## [0.26.12](https://github.com/blinko-space/blinko/compare/v0.26.11...v0.26.12) (2024-12-17) diff --git a/package.json b/package.json index 18a2b0cc..2df7c236 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blinko", - "version": "0.26.12", + "version": "0.27.0", "repository": "https://github.com/blinko-space/blinko.git", "private": true, "browser": { From c86cd4e61c66cc5e419510c92ba7fac3ec40df5e Mon Sep 17 00:00:00 2001 From: blinko Date: Tue, 17 Dec 2024 18:54:45 +0800 Subject: [PATCH 10/55] fix: enhance file upload functionality and improve user feedback - Refactored the file upload process to utilize streams, allowing for more efficient handling of large files. - Added error handling for upload failures, providing clearer feedback to users. - Updated translation files to include new messages for upload status (completed, cancelled, failed) across multiple languages. - Enhanced the upload progress indication in the UI, improving user experience during file uploads. --- app/api/file/upload/route.ts | 46 +++++-- public/locales/ar/translation.json | 6 +- public/locales/de/translation.json | 6 +- public/locales/en/translation.json | 6 +- public/locales/es/translation.json | 6 +- public/locales/fr/translation.json | 6 +- public/locales/ja/translation.json | 6 +- public/locales/ko/translation.json | 6 +- public/locales/pt/translation.json | 6 +- public/locales/ru/translation.json | 6 +- public/locales/tr/translation.json | 6 +- public/locales/zh-TW/translation.json | 6 +- public/locales/zh/translation.json | 6 +- .../BlinkoSettings/ImportSetting.tsx | 5 +- .../BlinkoSettings/StorageSetting.tsx | 16 +-- src/components/Common/Editor/editorStore.tsx | 13 +- src/components/Common/UploadFile/index.tsx | 51 ++++++-- src/server/plugins/files.ts | 57 +++++++++ src/store/module/Toast/Toast.tsx | 114 ++++++++++++++++++ 19 files changed, 321 insertions(+), 53 deletions(-) diff --git a/app/api/file/upload/route.ts b/app/api/file/upload/route.ts index 509910d0..918daef2 100644 --- a/app/api/file/upload/route.ts +++ b/app/api/file/upload/route.ts @@ -8,20 +8,40 @@ export const POST = async (req: NextRequest, res: NextResponse) => { if (!token) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } - const formData = await req.formData(); - const file = formData.getAll('file')[0] - if (!file) { - return NextResponse.json({ error: "No files received." }, { status: 400 }); - } + if (process.env.IS_DEMO) { return NextResponse.json({ error: "In Demo App" }, { status: 401 }); } - //@ts-ignore - const buffer = Buffer.from(await file.arrayBuffer()); - //@ts-ignore - const originalName = (file.name).replaceAll(" ", "_"); - const extension = path.extname(originalName); - const filePath = await FileService.uploadFile(buffer, originalName) - //@ts-ignore - return NextResponse.json({ Message: "Success", status: 200, ...filePath, type: file?.type ?? '', size: file?.size ?? 0 }); + + try { + const formData = await req.formData(); + const file = formData.getAll('file')[0] as File; + + if (!file) { + return NextResponse.json({ error: "No files received." }, { status: 400 }); + } + + const originalName = file.name.replaceAll(" ", "_"); + const stream = file.stream(); + + const filePath = await FileService.uploadFileStream(stream, originalName, file.size); + + return NextResponse.json({ + Message: "Success", + status: 200, + ...filePath, + type: file.type, + size: file.size + }); + + } catch (error) { + console.error('Upload error:', error); + return NextResponse.json({ error: "Upload failed" }, { status: 500 }); + } +}; + +export const config = { + api: { + bodyParser: false, + }, }; diff --git a/public/locales/ar/translation.json b/public/locales/ar/translation.json index 7364d953..4f1e51df 100644 --- a/public/locales/ar/translation.json +++ b/public/locales/ar/translation.json @@ -345,5 +345,9 @@ "context": "السياق", "paste-to-note-or-attachment": "هل أنت متأكد من لصق النص في السياق أو المرفق؟", "attachment": "المرفق", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "بعد الحذف، سيتم مسح جميع بيانات المستخدم ولن يمكن استرجاعها." + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "بعد الحذف، سيتم مسح جميع بيانات المستخدم ولن يمكن استرجاعها.", + "upload-completed": "تم الرفع بنجاح", + "upload-cancelled": "تم إلغاء التحميل", + "upload-failed": "فشل التحميل", + "import-from-bko-tip": "تحميل إلى s3 للإسترداد غير مدعوم في الوقت الحالي. يُرجى تعطيل الخيار s3 مؤقتًا عند رغبتك في الاسترداد." } diff --git a/public/locales/de/translation.json b/public/locales/de/translation.json index 90b5d15a..f4cc24f3 100644 --- a/public/locales/de/translation.json +++ b/public/locales/de/translation.json @@ -332,5 +332,9 @@ "context": "Kontext", "paste-to-note-or-attachment": "Sind Sie sicher, dass Sie in den Kontext oder als Anhang einfügen möchten?", "attachment": "Anhang", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Nach dem Löschen werden alle Benutzerdaten gelöscht und können nicht wiederhergestellt werden." + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Nach dem Löschen werden alle Benutzerdaten gelöscht und können nicht wiederhergestellt werden.", + "upload-completed": "Hochladen abgeschlossen", + "upload-cancelled": "Upload abgebrochen", + "upload-failed": "Upload fehlgeschlagen", + "import-from-bko-tip": "Das Hochladen zur Wiederherstellung auf S3 wird derzeit nicht unterstützt. Deaktivieren Sie die S3-Option vorübergehend, wenn Sie eine Wiederherstellung durchführen möchten." } diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index f7a5179b..4fe986a9 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -343,5 +343,9 @@ "paste-to-note-or-attachment": "Are you sure to paste to context or attachment? ", "context": "Context", "attachment": "Attachment", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "After deletion, all user data will be cleared and unrecoverable." + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "After deletion, all user data will be cleared and unrecoverable.", + "upload-completed": "Upload completed", + "upload-cancelled": "Upload cancelled", + "upload-failed": "Upload Failed", + "import-from-bko-tip": "Uploading to s3 for recovery is not supported at this time. Please disable the s3 option temporarily when you want to recover." } diff --git a/public/locales/es/translation.json b/public/locales/es/translation.json index 53543652..aa83d75a 100644 --- a/public/locales/es/translation.json +++ b/public/locales/es/translation.json @@ -323,5 +323,9 @@ "context": "Contexto", "paste-to-note-or-attachment": "¿Estás seguro de pegar en el contexto o adjuntar?", "attachment": "Adjunto", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Después de la eliminación, todos los datos de usuario serán borrados y no se podrán recuperar." + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Después de la eliminación, todos los datos de usuario serán borrados y no se podrán recuperar.", + "upload-completed": "Carga completada", + "upload-cancelled": "Subida cancelada", + "upload-failed": "Error al subir", + "import-from-bko-tip": "La carga a s3 para recuperación no está soportada en este momento. Por favor, deshabilite temporalmente la opción s3 cuando desee recuperar." } diff --git a/public/locales/fr/translation.json b/public/locales/fr/translation.json index 1316ec0f..b103168e 100644 --- a/public/locales/fr/translation.json +++ b/public/locales/fr/translation.json @@ -320,5 +320,9 @@ "context": "Contexte", "paste-to-note-or-attachment": "Êtes-vous sûr de coller dans le contexte ou en pièce jointe ?", "attachment": "Pièce jointe", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Après la suppression, toutes les données utilisateur seront effacées et définitivement irrécupérables." + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Après la suppression, toutes les données utilisateur seront effacées et définitivement irrécupérables.", + "upload-completed": "Téléchargement terminé", + "upload-cancelled": "Téléchargement annulé", + "upload-failed": "Téléchargement échoué", + "import-from-bko-tip": "Le téléversement vers s3 pour la récupération n'est pas pris en charge actuellement. Veuillez désactiver temporairement l'option s3 lorsque vous souhaitez récupérer." } diff --git a/public/locales/ja/translation.json b/public/locales/ja/translation.json index c9346800..f24e5144 100644 --- a/public/locales/ja/translation.json +++ b/public/locales/ja/translation.json @@ -305,5 +305,9 @@ "context": "コンテクスト", "paste-to-note-or-attachment": "コンテキストや添付ファイルに貼り付けることを確認しますか?", "attachment": "添付", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "削除後、すべてのユーザーデータは消去され、回復不能になります。" + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "削除後、すべてのユーザーデータは消去され、回復不能になります。", + "upload-completed": "アップロードが完了しました", + "upload-cancelled": "アップロードがキャンセルされました", + "upload-failed": "アップロードに失敗しました", + "import-from-bko-tip": "この時点では、S3 へのアップロードによるリカバリはサポートされていません。リカバリを行う際には一時的に S3 オプションを無効にしてください。" } diff --git a/public/locales/ko/translation.json b/public/locales/ko/translation.json index 769fbd9a..8139ae95 100644 --- a/public/locales/ko/translation.json +++ b/public/locales/ko/translation.json @@ -327,5 +327,9 @@ "context": "문맥", "paste-to-note-or-attachment": "컨텍스트나 첨부 파일에 붙여 넣을 확신이 있습니까?", "attachment": "첨부 파일", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "삭제 후 모든 사용자 데이터가 지워지고 복구할 수 없게 됩니다." + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "삭제 후 모든 사용자 데이터가 지워지고 복구할 수 없게 됩니다.", + "upload-completed": "업로드가 완료되었습니다.", + "upload-cancelled": "업로드가 취소되었습니다.", + "upload-failed": "업로드 실패", + "import-from-bko-tip": "현재 s3로의 업로드는 복구되지 않습니다. 복구를 원할 경우 s3 옵션을 일시적으로 비활성화하십시오." } diff --git a/public/locales/pt/translation.json b/public/locales/pt/translation.json index 1fa93d25..213713d6 100644 --- a/public/locales/pt/translation.json +++ b/public/locales/pt/translation.json @@ -255,5 +255,9 @@ "context": "Contexto", "paste-to-note-or-attachment": "Tem certeza de que deseja colar no contexto ou no anexo?", "attachment": "Anexo", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Após a exclusão, todos os dados do usuário serão apagados e não poderão ser recuperados." + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Após a exclusão, todos os dados do usuário serão apagados e não poderão ser recuperados.", + "upload-completed": "Carregamento concluído", + "upload-cancelled": "Envio cancelado", + "upload-failed": "Falha ao Carregar", + "import-from-bko-tip": "O envio para o s3 para recuperação não é suportado neste momento. Por favor, desative temporariamente a opção s3 quando desejar recuperar." } diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json index 50da1d07..39ac6515 100644 --- a/public/locales/ru/translation.json +++ b/public/locales/ru/translation.json @@ -260,5 +260,9 @@ "context": "Контекст", "paste-to-note-or-attachment": "Вы уверены, что хотите вставить в контекст или прикрепление?", "attachment": "Прикрепление", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "После удаления все данные пользователей будут очищены и не поддадутся восстановлению." + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "После удаления все данные пользователей будут очищены и не поддадутся восстановлению.", + "upload-completed": "Загрузка завершена", + "upload-cancelled": "Загрузка отменена", + "upload-failed": "Не удалось загрузить", + "import-from-bko-tip": "Загрузка в s3 для восстановления в настоящее время не поддерживается. Пожалуйста, временно отключите опцию s3, когда планируете выполнить восстановление." } diff --git a/public/locales/tr/translation.json b/public/locales/tr/translation.json index 811ec8c0..b54346a5 100644 --- a/public/locales/tr/translation.json +++ b/public/locales/tr/translation.json @@ -273,5 +273,9 @@ "context": "Bağlam", "paste-to-note-or-attachment": "Metin veya ek dosyaya yapıştırmak istediğinizden emin misiniz?", "attachment": "Eklenti", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Silme işleminden sonra, tüm kullanıcı verileri temizlenecek ve kurtarılamaz hale gelecektir." + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Silme işleminden sonra, tüm kullanıcı verileri temizlenecek ve kurtarılamaz hale gelecektir.", + "upload-completed": "Yükleme tamamlandı", + "upload-cancelled": "Yükleme iptal edildi", + "upload-failed": "Yükleme Başarısız oldu", + "import-from-bko-tip": "Bu zamanda s3'e yükleme yapılmamaktadır. Kurtarma işlemi gerçekleştirmek istediğinizde lütfen geçici olarak s3 seçeneğini devre dışı bırakın." } diff --git a/public/locales/zh-TW/translation.json b/public/locales/zh-TW/translation.json index bd63d66d..20cfe4a1 100644 --- a/public/locales/zh-TW/translation.json +++ b/public/locales/zh-TW/translation.json @@ -357,5 +357,9 @@ "context": "正文", "paste-to-note-or-attachment": "您確定要貼上到內容或附件嗎?", "attachment": "附件", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "刪除後,所有用戶資料將被清空且無法恢復。" + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "刪除後,所有用戶資料將被清空且無法恢復。", + "upload-completed": "上傳完成", + "upload-cancelled": "上傳已取消", + "upload-failed": "上傳失敗", + "import-from-bko-tip": "目前不支援上傳至 s3 進行還原。當您想要進行恢復操作時,請暫時停用 s3 選項。" } diff --git a/public/locales/zh/translation.json b/public/locales/zh/translation.json index 4f649c41..78ff27f1 100644 --- a/public/locales/zh/translation.json +++ b/public/locales/zh/translation.json @@ -357,5 +357,9 @@ "paste-to-note-or-attachment": "您确定要粘贴到上下文或附件吗?", "context": "正文", "attachment": "附件", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "删除后,所有用户数据将被清除且无法恢复。" + "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "删除后,所有用户数据将被清除且无法恢复。", + "upload-completed": "上传完成", + "upload-cancelled": "上传已取消", + "upload-failed": "上传失败", + "import-from-bko-tip": "目前不支持将上传到S3进行恢复。当您想要恢复时,请暂时禁用S3选项。" } diff --git a/src/components/BlinkoSettings/ImportSetting.tsx b/src/components/BlinkoSettings/ImportSetting.tsx index 3c5aa12d..e31ace31 100644 --- a/src/components/BlinkoSettings/ImportSetting.tsx +++ b/src/components/BlinkoSettings/ImportSetting.tsx @@ -7,7 +7,7 @@ import { helper } from "@/lib/helper"; import dayjs from "@/lib/dayjs"; import { Icon } from "@iconify/react"; import { api, streamApi } from "@/lib/trpc"; -import { Item } from "./Item"; +import { Item, ItemWithTooltip } from "./Item"; import { useTranslation } from "react-i18next"; import { UploadFileWrapper } from "../Common/UploadFile"; import { ToastPlugin } from "@/store/module/Toast/Toast"; @@ -26,13 +26,12 @@ export const ImportSetting = observer(() => { title={t('import')} > {t('import-from-bko')}} + leftContent={{t('import-from-bko-tip')}
} />} rightContent={<> { if (!fileName.endsWith('.bko')) { return RootStore.Get(ToastPlugin).error(t('not-a-bko-file')) } - // PromiseCall(api.task.restoreDB.query({ fileName })) ShowBlinkoProgressDialog(filePath) }}> diff --git a/src/components/BlinkoSettings/StorageSetting.tsx b/src/components/BlinkoSettings/StorageSetting.tsx index e5f26480..d71d6903 100644 --- a/src/components/BlinkoSettings/StorageSetting.tsx +++ b/src/components/BlinkoSettings/StorageSetting.tsx @@ -1,5 +1,5 @@ import { observer } from "mobx-react-lite"; -import { Button, Card, DropdownItem, DropdownMenu, DropdownTrigger, Dropdown, Input } from "@nextui-org/react"; +import { Button, DropdownItem, DropdownMenu, DropdownTrigger, Dropdown, Input } from "@nextui-org/react"; import { RootStore } from "@/store"; import { BlinkoStore } from "@/store/blinkoStore"; import { PromiseCall } from "@/store/standard/PromiseState"; @@ -10,6 +10,7 @@ import { useTranslation } from "react-i18next"; import { useMediaQuery } from "usehooks-ts"; import { useEffect } from "react"; import { PasswordInput } from "@/components/Common/PasswordInput"; +import { CollapsibleCard } from "@/components/Common/CollapsibleCard"; export const StorageSetting = observer(() => { @@ -35,13 +36,12 @@ export const StorageSetting = observer(() => { }, [blinko.config.value]) - return -
- -
{t('storage')}
-
+ return + leftContent={
{t('object-storage')}
} rightContent={
@@ -129,5 +129,5 @@ export const StorageSetting = observer(() => { }} />} /> } - + }) \ No newline at end of file diff --git a/src/components/Common/Editor/editorStore.tsx b/src/components/Common/Editor/editorStore.tsx index d1a5dce5..b2f00792 100644 --- a/src/components/Common/Editor/editorStore.tsx +++ b/src/components/Common/Editor/editorStore.tsx @@ -17,6 +17,8 @@ import i18n from '@/lib/i18n'; import { DialogStandaloneStore } from '@/store/module/DialogStandalone'; import { handlePaste } from '@/lib/hooks'; import { Button } from '@nextui-org/react'; +import axios from 'axios'; +import { ToastPlugin } from '@/store/module/Toast/Toast'; export class EditorStore { files: FileType[] = [] lastRange: Range | null = null @@ -132,11 +134,14 @@ export class EditorStore { function: async () => { const formData = new FormData(); formData.append('file', file) - const response = await fetch('/api/file/upload', { - method: 'POST', - body: formData, + const { onUploadProgress } = RootStore.Get(ToastPlugin) + .setSizeThreshold(40) + .uploadProgress(file); + + const response = await axios.post('/api/file/upload', formData, { + onUploadProgress }); - const data = await response.json(); + const data = response.data; this.speechToText(data.filePath) if (data.filePath) { return data.filePath diff --git a/src/components/Common/UploadFile/index.tsx b/src/components/Common/UploadFile/index.tsx index 91a8d422..47ebc8d4 100644 --- a/src/components/Common/UploadFile/index.tsx +++ b/src/components/Common/UploadFile/index.tsx @@ -4,12 +4,20 @@ import { Button } from "@nextui-org/react"; import { Icon } from "@iconify/react"; import { useState } from "react"; import { useTranslation } from "react-i18next"; +import axios from "axios"; +import { RootStore } from "@/store"; +import { ToastPlugin } from "@/store/module/Toast/Toast"; +import { BlinkoStore } from "@/store/blinkoStore"; +import { observer } from "mobx-react-lite"; + type IProps = { onUpload?: ({ filePath, fileName }) => void } -export const UploadFileWrapper = ({ onUpload }: IProps) => { + +export const UploadFileWrapper = observer(({ onUpload }: IProps) => { const { t } = useTranslation() const [isLoading, setIsLoading] = useState(false) + const blinko = RootStore.Get(BlinkoStore) const { getRootProps, getInputProps, @@ -19,21 +27,38 @@ export const UploadFileWrapper = ({ onUpload }: IProps) => { noClick: true, onDrop: async acceptedFiles => { setIsLoading(true) - const file = acceptedFiles[0]! - const formData = new FormData(); - formData.append('file', file) - const response = await fetch('/api/file/upload', { - method: 'POST', - body: formData, - }); - const data = await response.json(); - onUpload?.(data) - setIsLoading(false) + try { + const file = acceptedFiles[0]! + const formData = new FormData(); + formData.append('file', file) + + const { onUploadProgress } = RootStore.Get(ToastPlugin) + .setSizeThreshold(40) + .uploadProgress(file); + + const response = await axios.post('/api/file/upload', formData, { + onUploadProgress + }); + + onUpload?.(response.data) + } catch (error) { + console.error('Upload failed:', error); + } finally { + setIsLoading(false) + } } }); return
- +
-} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/server/plugins/files.ts b/src/server/plugins/files.ts index 3ab9fa23..969c8787 100644 --- a/src/server/plugins/files.ts +++ b/src/server/plugins/files.ts @@ -5,6 +5,10 @@ import fs, { unlink, writeFile } from 'fs/promises'; import path from 'path'; import { cache } from "@/lib/cache"; import { prisma } from "../prisma"; +import { Readable } from 'stream'; +import { Upload } from "@aws-sdk/lib-storage"; +import { PassThrough } from 'stream'; +import { createWriteStream } from "fs"; export class FileService { public static async getS3Client() { @@ -135,5 +139,58 @@ export class FileService { return path.join(UPLOAD_FILE_PATH, fileName); } } + + static async uploadFileStream(stream: ReadableStream, originalName: string, fileSize: number) { + const config = await getGlobalConfig({ useAdmin: true }); + const extension = path.extname(originalName); + const baseName = path.basename(originalName, extension); + const timestamp = Date.now(); + const timestampedFileName = `${baseName}_${timestamp}${extension}`; + + if (config.objectStorage === 's3') { + const { s3ClientInstance } = await this.getS3Client(); + + let customPath = config.s3CustomPath || ''; + if (customPath) { + customPath = customPath.startsWith('/') ? customPath : '/' + customPath; + customPath = customPath.endsWith('/') ? customPath : customPath + '/'; + } + + const s3Key = `${customPath}${timestampedFileName}`.replace(/^\//, ''); + + const passThrough = new PassThrough(); + const nodeReadable = Readable.fromWeb(stream as any); + nodeReadable.pipe(passThrough); + + const upload = new Upload({ + client: s3ClientInstance, + params: { + Bucket: config.s3Bucket, + Key: s3Key, + Body: passThrough, + }, + }); + + await upload.done(); + const s3Url = `/api/s3file/${s3Key}`; + return { filePath: s3Url, fileName: timestampedFileName }; + + } else { + const filePath = path.join(process.cwd(), UPLOAD_FILE_PATH, timestampedFileName); + const writeStream = createWriteStream(filePath); + const nodeReadable = Readable.fromWeb(stream as any); + + await new Promise((resolve, reject) => { + nodeReadable.pipe(writeStream) + .on('finish', resolve) + .on('error', reject); + }); + + return { + filePath: `/api/file/${timestampedFileName}`, + fileName: timestampedFileName + }; + } + } } diff --git a/src/store/module/Toast/Toast.tsx b/src/store/module/Toast/Toast.tsx index 372b74ec..575807ee 100644 --- a/src/store/module/Toast/Toast.tsx +++ b/src/store/module/Toast/Toast.tsx @@ -1,9 +1,51 @@ import { Store } from "@/store/standard/base"; import React from "react"; import toast, { Toaster } from "react-hot-toast"; +import { Progress } from "@nextui-org/react"; +import i18n from "@/lib/i18n"; + +interface UploadProgressProps { + progress: number; + fileName: string; + speed: string; + loaded: string; + total: string; +} + +const UploadProgressToast = ({ progress, fileName, speed, loaded, total }: UploadProgressProps) => ( +
+
+
+ {fileName} +
+ +
+ {speed}/s + + {loaded} / {total} + +
+
+
+); export class ToastPlugin implements Store { sid = "ToastPlugin"; + private sizeThreshold = 5; + provider = () => ( {} + }; + } + + let startTime = Date.now(); + let lastLoaded = 0; + let toastId: string; + + const updateProgress = (loaded: number, total: number) => { + const currentTime = Date.now(); + const timeElapsed = (currentTime - startTime) / 1000; + const loadedDiff = loaded - lastLoaded; + const speed = loadedDiff / timeElapsed; + + lastLoaded = loaded; + startTime = currentTime; + + const progress = Math.round((loaded * 100) / total); + + if (!toastId) { + toastId = toast.custom((t) => ( + + ), { duration: Infinity }); + } else { + toast.custom((t) => ( + + ), { id: toastId }); + } + + if (progress === 100) { + setTimeout(() => { + toast.dismiss(toastId); + this.success(i18n.t('upload-completed')); + }, 1000); + } + }; + + return { + onUploadProgress: (progressEvent: any) => { + updateProgress(progressEvent.loaded, progressEvent.total); + } + }; + } + success(str: string) { toast.success(str, { icon: '👏' }) }; From e38501a071ea9c5b952e6cfe6354cf7e170effea Mon Sep 17 00:00:00 2001 From: blinko Date: Tue, 17 Dec 2024 20:31:25 +0800 Subject: [PATCH 11/55] fix: enhance user sign-out process and improve component structure 326 - Integrated event bus for user sign-out functionality, allowing for better state management across components. - Updated the BasicSetting component to utilize the event bus for sign-out, improving code clarity. - Added a key prop to BlinkoCard in the Home component to ensure proper rendering and performance. - Cleaned up unused imports in the SignIn component, enhancing code maintainability. - Introduced a clear method in UserStore to reset user data upon sign-out, improving user experience and security. - Enhanced user preference setup logic to prevent redundant calls, optimizing performance. --- .../BlinkoSettings/BasicSetting.tsx | 5 ++- src/pages/index.tsx | 2 +- src/pages/signin.tsx | 4 +-- src/server/routers/user.ts | 23 +++++++++++-- src/store/blinkoStore.tsx | 1 - src/store/user.ts | 32 +++++++++++++------ 6 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/components/BlinkoSettings/BasicSetting.tsx b/src/components/BlinkoSettings/BasicSetting.tsx index f6bfaaa8..fa9c5f26 100644 --- a/src/components/BlinkoSettings/BasicSetting.tsx +++ b/src/components/BlinkoSettings/BasicSetting.tsx @@ -18,6 +18,7 @@ import React, { useEffect, useState } from "react"; import { motion, AnimatePresence } from "motion/react"; import { ShowGen2FATokenModal } from "../Common/TwoFactorModal/gen2FATokenModal"; import { CollapsibleCard } from "../Common/CollapsibleCard"; +import { eventBus } from "@/lib/event"; export const BasicSetting = observer(() => { const [isCollapsed, setIsCollapsed] = useState(false); @@ -240,9 +241,7 @@ export const BasicSetting = observer(() => { } /> diff --git a/src/pages/index.tsx b/src/pages/index.tsx index e540dde0..6b17a22f 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -63,7 +63,7 @@ const Home = observer(() => { columnClassName="my-masonry-grid_column"> { blinko.noteList?.value?.map(i => { - return + return }) } diff --git a/src/pages/signin.tsx b/src/pages/signin.tsx index 80272a34..4a872a3a 100644 --- a/src/pages/signin.tsx +++ b/src/pages/signin.tsx @@ -12,6 +12,7 @@ import { ShowTwoFactorModal } from "@/components/Common/TwoFactorModal"; import { DialogStore } from "@/store/module/Dialog"; import { PromiseState } from "@/store/standard/PromiseState"; import { useTheme } from "next-themes"; +import { eventBus } from "@/lib/event"; export default function Component() { const router = useRouter() @@ -162,9 +163,6 @@ export default function Component() {

}
- - -
); } diff --git a/src/server/routers/user.ts b/src/server/routers/user.ts index 8dac159b..5553c22e 100644 --- a/src/server/routers/user.ts +++ b/src/server/routers/user.ts @@ -91,8 +91,27 @@ export const userRouter = router({ const passwordHash = await hashPassword(password) const count = await prisma.accounts.count() if (count == 0) { - const res = await prisma.accounts.create({ data: { name, password: passwordHash, nickname: name, role: 'superadmin' } }) - await prisma.accounts.update({ where: { id: res.id }, data: { apiToken: await genToken({ id: res.id, name, role: 'superadmin' }) } }) + const res = await prisma.accounts.create({ + data: { + name, + password: passwordHash, + nickname: name, + role: 'superadmin', + } + }) + await prisma.accounts.update({ + where: { id: res.id }, + data: { + apiToken: await genToken({ id: res.id, name, role: 'superadmin' }) + } + }) + await prisma.config.create({ + data: { + key: 'theme', + config: { value: 'system' }, + userId: res.id + } + }) return true } else { const config = await prisma.config.findFirst({ where: { key: 'isAllowRegister' } }) diff --git a/src/store/blinkoStore.tsx b/src/store/blinkoStore.tsx index 876e4d80..0b6dabd0 100644 --- a/src/store/blinkoStore.tsx +++ b/src/store/blinkoStore.tsx @@ -228,7 +228,6 @@ export class BlinkoStore implements Store { const { tagId, withoutTag, withFile, withLink, searchText } = router.query; useEffect(() => { if (!router.isReady) return - console.log(searchText) this.noteListFilterConfig.type = NoteType.BLINKO this.noteTypeDefault = NoteType.BLINKO this.noteListFilterConfig.tagId = null diff --git a/src/store/user.ts b/src/store/user.ts index 1e406648..7291bd60 100644 --- a/src/store/user.ts +++ b/src/store/user.ts @@ -25,6 +25,7 @@ export class UserStore implements User, Store { token: string = ''; role: string = ''; theme: any = 'light'; + isSetup: boolean = false; wait() { return new Promise((res, rej) => { @@ -75,6 +76,17 @@ export class UserStore implements User, Store { this.setData(args); } + clear() { + console.log('clear') + this.token = '' + this.id = '' + this.name = '' + this.nickname = '' + this.image = '' + this.role = '' + this.isSetup = false + } + updatePWAColor(theme: string) { const themeColor = theme === 'dark' ? '#1C1C1E' : '#F8F8F8'; document.querySelector('meta[name="theme-color"]')?.setAttribute('content', themeColor); @@ -82,13 +94,14 @@ export class UserStore implements User, Store { } async setupUserPreferences(setTheme: (theme: string) => void, i18n: any) { - const config = this.blinko.config.value || await this.blinko.config.getOrCall(); - const newTheme = config?.theme == 'system' - ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') - : (config?.theme ?? 'light'); - + if (this.isSetup) return + await this.blinko.config.call(); + const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; + const config = this.blinko.config.value + const newTheme = config?.theme == 'system' ? systemTheme : (config?.theme ?? systemTheme); setTheme(newTheme); RootStore.Get(BaseStore).changeLanugage(i18n, config?.language ?? 'en'); + this.isSetup = true } use() { @@ -108,20 +121,19 @@ export class UserStore implements User, Store { console.log(session) //@ts-ignore userStore.ready({ ...session.user, token: session.token }); + this.setupUserPreferences(setTheme, i18n); userStore.userInfo.call(Number(this.id)) } }, [session]); - useEffect(() => { - if (!this.isLogin) return - this.setupUserPreferences(setTheme, i18n); - }, [this.isLogin]); - useEffect(() => { eventBus.on('user:signout', () => { if (router.pathname == '/signup' || router.pathname == '/api-doc' || router.pathname.includes('/share')) { return } + localStorage.removeItem('username') + localStorage.removeItem('password') + RootStore.Get(UserStore).clear() router.push('/signin') }) }, []); From cf7b05752a9221291d4f96bf37afffcd02b38015 Mon Sep 17 00:00:00 2001 From: blinko Date: Tue, 17 Dec 2024 20:40:20 +0800 Subject: [PATCH 12/55] fix: adjust button alignment in TipsDialog component - Updated the alignment of the cancel button to use 'ml-auto' for proper spacing. - Ensured consistent button styling by removing unnecessary width classes, enhancing the overall layout and user experience. --- src/components/Common/TipsDialog/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Common/TipsDialog/index.tsx b/src/components/Common/TipsDialog/index.tsx index ee1408ae..334f9292 100644 --- a/src/components/Common/TipsDialog/index.tsx +++ b/src/components/Common/TipsDialog/index.tsx @@ -52,11 +52,11 @@ export const TipsPopover = observer((props: { children: React.ReactNode, content
{props.content}
- -
From 4047c64f68c41bb95b057e7a5a0ff1d8072c7808 Mon Sep 17 00:00:00 2001 From: blinko Date: Tue, 17 Dec 2024 20:43:49 +0800 Subject: [PATCH 13/55] fix: remove bodyParser configuration from file upload route - Eliminated the bodyParser configuration from the file upload route, streamlining the API setup. - This change simplifies the handling of file uploads, aligning with the recent refactor for improved efficiency. --- app/api/file/upload/route.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/api/file/upload/route.ts b/app/api/file/upload/route.ts index 918daef2..21c22020 100644 --- a/app/api/file/upload/route.ts +++ b/app/api/file/upload/route.ts @@ -40,8 +40,3 @@ export const POST = async (req: NextRequest, res: NextResponse) => { } }; -export const config = { - api: { - bodyParser: false, - }, -}; From 66f1cbe38146e2d21de7d828841f3e310cc20dec Mon Sep 17 00:00:00 2001 From: blinko Date: Tue, 17 Dec 2024 20:44:49 +0800 Subject: [PATCH 14/55] fix: update icon paths in manifest.json for consistency - Changed icon source paths in the manifest.json from '/logo/' to '/icons/' to align with the new directory structure. - This update ensures that the application correctly references the updated icon locations, improving asset management. --- public/manifest.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/public/manifest.json b/public/manifest.json index 3d913fbd..829a33be 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -3,28 +3,28 @@ "short_name": "Blinko", "icons": [ { - "src": "/logo/icon-128x128.png", + "src": "/icons/icon-128x128.png", "sizes": "128x128", "type": "image/png", "purpose": "any maskable" }, { - "src": "/logo/icon-144x144.png", + "src": "/icons/icon-144x144.png", "sizes": "144x144", "type": "image/png" }, { - "src": "/logo/icon-152x152.png", + "src": "/icons/icon-152x152.png", "sizes": "152x152", "type": "image/png" }, { - "src": "/logo/icon-192x192.png", + "src": "/icons/icon-192x192.png", "sizes": "192x192", "type": "image/png" }, { - "src": "/logo/icon-256x256.png", + "src": "/icons/icon-256x256.png", "sizes": "256x256", "type": "image/png" } From 0e6ff7ad1a8c11d4b2c20b166c7f6b9edf63b2c5 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 17 Dec 2024 13:09:16 +0000 Subject: [PATCH 15/55] chore(release): 0.27.1 [skip ci] ## [0.27.1](https://github.com/blinko-space/blinko/compare/v0.27.0...v0.27.1) (2024-12-17) ### Bug Fixes * adjust button alignment in TipsDialog component ([cf7b057](https://github.com/blinko-space/blinko/commit/cf7b05752a9221291d4f96bf37afffcd02b38015)) * enhance file upload functionality and improve user feedback ([c86cd4e](https://github.com/blinko-space/blinko/commit/c86cd4e61c66cc5e419510c92ba7fac3ec40df5e)) * enhance user sign-out process and improve component structure 326 ([e38501a](https://github.com/blinko-space/blinko/commit/e38501a071ea9c5b952e6cfe6354cf7e170effea)) * remove bodyParser configuration from file upload route ([4047c64](https://github.com/blinko-space/blinko/commit/4047c64f68c41bb95b057e7a5a0ff1d8072c7808)) * update icon paths in manifest.json for consistency ([66f1cbe](https://github.com/blinko-space/blinko/commit/66f1cbe38146e2d21de7d828841f3e310cc20dec)) --- CHANGELOG.md | 11 +++++++++++ package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21b763cf..72a4b472 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## [0.27.1](https://github.com/blinko-space/blinko/compare/v0.27.0...v0.27.1) (2024-12-17) + + +### Bug Fixes + +* adjust button alignment in TipsDialog component ([cf7b057](https://github.com/blinko-space/blinko/commit/cf7b05752a9221291d4f96bf37afffcd02b38015)) +* enhance file upload functionality and improve user feedback ([c86cd4e](https://github.com/blinko-space/blinko/commit/c86cd4e61c66cc5e419510c92ba7fac3ec40df5e)) +* enhance user sign-out process and improve component structure 326 ([e38501a](https://github.com/blinko-space/blinko/commit/e38501a071ea9c5b952e6cfe6354cf7e170effea)) +* remove bodyParser configuration from file upload route ([4047c64](https://github.com/blinko-space/blinko/commit/4047c64f68c41bb95b057e7a5a0ff1d8072c7808)) +* update icon paths in manifest.json for consistency ([66f1cbe](https://github.com/blinko-space/blinko/commit/66f1cbe38146e2d21de7d828841f3e310cc20dec)) + # [0.27.0](https://github.com/blinko-space/blinko/compare/v0.26.12...v0.27.0) (2024-12-17) diff --git a/package.json b/package.json index 2df7c236..ebf0e1ef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blinko", - "version": "0.27.0", + "version": "0.27.1", "repository": "https://github.com/blinko-space/blinko.git", "private": true, "browser": { From b2edb7620770c4a2315f272df16ed83a4ceba85a Mon Sep 17 00:00:00 2001 From: blinko Date: Wed, 18 Dec 2024 09:25:44 +0800 Subject: [PATCH 16/55] fix: disable dragging for image thumbnails in AttachmentRender component #331 - Updated the ImageThumbnailRender component to set the draggable property to false, preventing users from dragging images unintentionally. - This change enhances the user experience by ensuring that image thumbnails behave as expected within the application. --- src/components/Common/AttachmentRender/imageRender.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Common/AttachmentRender/imageRender.tsx b/src/components/Common/AttachmentRender/imageRender.tsx index bcc29690..a020daba 100644 --- a/src/components/Common/AttachmentRender/imageRender.tsx +++ b/src/components/Common/AttachmentRender/imageRender.tsx @@ -32,6 +32,7 @@ const ImageThumbnailRender = ({ file, className }: { file: FileType, className?: classNames={{ wrapper: '!max-w-full', }} + draggable={false} onError={() => { if (file.preview === currentSrc) { return setIsOriginalError(true) From 4183c9f964c6e851a0c2331c4e78d79eea4421e8 Mon Sep 17 00:00:00 2001 From: blinko Date: Wed, 18 Dec 2024 09:29:55 +0800 Subject: [PATCH 17/55] fix: update dialog store reference in DeleteIcon component #332 - Replaced the DialogStore reference with DialogStandaloneStore in the DeleteIcon component to ensure proper dialog management. - This change improves the functionality of the delete action by correctly closing the standalone dialog after a file deletion. --- src/components/Common/AttachmentRender/icons.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Common/AttachmentRender/icons.tsx b/src/components/Common/AttachmentRender/icons.tsx index ba4248f2..e742970e 100644 --- a/src/components/Common/AttachmentRender/icons.tsx +++ b/src/components/Common/AttachmentRender/icons.tsx @@ -10,6 +10,7 @@ import { PromiseState } from '@/store/standard/PromiseState'; import { BlinkoStore } from '@/store/blinkoStore'; import { helper } from '@/lib/helper'; import { FileType } from '../Editor/type'; +import { DialogStandaloneStore } from '@/store/module/DialogStandalone'; export const DeleteIcon = observer(({ className, file, files, size = 20 }: { className: string, file: FileType, files: FileType[], size?: number }) => { const store = RootStore.Local(() => ({ @@ -21,7 +22,7 @@ export const DeleteIcon = observer(({ className, file, files, size = 20 }: { cla }); const index = files.findIndex(i => i.name == file.name) files.splice(index, 1) - RootStore.Get(DialogStore).close() + RootStore.Get(DialogStandaloneStore).close() RootStore.Get(ToastPlugin).success(t('delete-success')) RootStore.Get(BlinkoStore).updateTicker++ } From dc41a44883e5f4a0913c7b956fc911baa7351415 Mon Sep 17 00:00:00 2001 From: blinko Date: Wed, 18 Dec 2024 10:02:38 +0800 Subject: [PATCH 18/55] fix: pwa refresh language lose --- src/store/user.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/store/user.ts b/src/store/user.ts index 7291bd60..3d375b3d 100644 --- a/src/store/user.ts +++ b/src/store/user.ts @@ -94,10 +94,10 @@ export class UserStore implements User, Store { } async setupUserPreferences(setTheme: (theme: string) => void, i18n: any) { - if (this.isSetup) return - await this.blinko.config.call(); - const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; + await this.blinko.config.getOrCall(); const config = this.blinko.config.value + if (this.isSetup && RootStore.Get(BaseStore).locale.value == config?.language) return + const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; const newTheme = config?.theme == 'system' ? systemTheme : (config?.theme ?? systemTheme); setTheme(newTheme); RootStore.Get(BaseStore).changeLanugage(i18n, config?.language ?? 'en'); From 5b69f2b99f45c69165034c5d8132b9cea5656839 Mon Sep 17 00:00:00 2001 From: blinko Date: Wed, 18 Dec 2024 11:49:50 +0800 Subject: [PATCH 19/55] fix: enhance attachment management and sorting functionality - Added the ability to reorder attachments in the AttachmentRender component, improving user experience by allowing drag-and-drop functionality. - Introduced a new sortOrder field in the attachments model to facilitate ordering. - Updated the Prisma schema and Zod validation to include sortOrder for attachments and tags. - Enhanced the note router to return attachments sorted by sortOrder. - Implemented a new mutation to update the order of attachments in the database. - Refactored the Editor and AttachmentsRender components to support file reordering, ensuring a seamless integration with the existing file management system. --- package.json | 1 + pnpm-lock.yaml | 130 +++++++++++++ .../20241218023101_0_27_0/migration.sql | 5 + prisma/schema.prisma | 54 +++--- .../AttachmentRender/DraggableFileGrid.tsx | 97 ++++++++++ .../Common/AttachmentRender/imageRender.tsx | 84 +++++---- .../Common/AttachmentRender/index.tsx | 175 ++++++++++++------ src/components/Common/Editor/editorStore.tsx | 4 + src/components/Common/Editor/index.tsx | 8 +- src/lib/prismaZodType.ts | 2 + src/server/routers/note.ts | 42 ++++- 11 files changed, 482 insertions(+), 120 deletions(-) create mode 100644 prisma/migrations/20241218023101_0_27_0/migration.sql create mode 100644 src/components/Common/AttachmentRender/DraggableFileGrid.tsx diff --git a/package.json b/package.json index 2df7c236..013877f5 100644 --- a/package.json +++ b/package.json @@ -116,6 +116,7 @@ "react-accessible-treeview": "^2.9.1", "react-audio-visualize": "^1.2.0", "react-audio-voice-recorder": "^2.2.0", + "react-beautiful-dnd-next": "^11.0.5", "react-burger-menu": "^3.0.9", "react-collapsed": "^4.1.2", "react-dev-inspector": "^2.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d70aa3bb..3cf7be8b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -266,6 +266,9 @@ importers: react-audio-voice-recorder: specifier: ^2.2.0 version: 2.2.0(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-beautiful-dnd-next: + specifier: ^11.0.5 + version: 11.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-burger-menu: specifier: ^3.0.9 version: 3.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1219,6 +1222,10 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + '@babel/runtime-corejs2@7.26.0': + resolution: {integrity: sha512-AQKSxUdaM7uTEGFmLZj1LOgX3LaLdt4udjqywaVdN6R5P2KAgqtBkDW4TS2ySRYNqcKmEe8Xv96jegHJNNb7Gg==} + engines: {node: '>=6.9.0'} + '@babel/runtime-corejs3@7.25.7': resolution: {integrity: sha512-gMmIEhg35sXk9Te5qbGp3W9YKrvLt3HV658/d3odWrHSqT0JeG5OzsJWFHRLiOohRyjRsJc/x03DhJm3i8VJxg==} engines: {node: '>=6.9.0'} @@ -4072,6 +4079,9 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/hoist-non-react-statics@3.3.6': + resolution: {integrity: sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -4132,6 +4142,9 @@ packages: '@types/react-reconciler@0.28.8': resolution: {integrity: sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==} + '@types/react-redux@7.1.34': + resolution: {integrity: sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ==} + '@types/react@18.2.8': resolution: {integrity: sha512-lTyWUNrd8ntVkqycEEplasWy2OxNlShj3zqS0LuB1ENUGis5HodmhM7DtCoUGbxj3VW/WsGA0DUhpG6XrM7gPA==} @@ -4843,6 +4856,10 @@ packages: core-js-pure@3.38.1: resolution: {integrity: sha512-BY8Etc1FZqdw1glX0XNOq2FDwfrg/VGqoZOZCdaL+UmdaqDwQwYXkMJT4t6In+zfEfOJDcM9T0KdbBeJg8KKCQ==} + core-js@2.6.12: + resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==} + deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. + core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -4893,6 +4910,9 @@ packages: resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} engines: {node: '>=12'} + css-box-model@1.2.1: + resolution: {integrity: sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==} + css-declaration-sorter@6.4.1: resolution: {integrity: sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==} engines: {node: ^10 || ^12 || >=14} @@ -5986,6 +6006,9 @@ packages: highlightjs-vue@1.0.0: resolution: {integrity: sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==} + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + hook-std@3.0.0: resolution: {integrity: sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6879,6 +6902,9 @@ packages: resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} engines: {node: '>= 4.0.0'} + memoize-one@5.2.1: + resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} + meow@13.2.0: resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} engines: {node: '>=18'} @@ -8189,6 +8215,9 @@ packages: radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + raf-schd@4.0.3: + resolution: {integrity: sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==} + ramda-adjunct@5.1.0: resolution: {integrity: sha512-8qCpl2vZBXEJyNbi4zqcgdfHtcdsWjOGbiNSEnEBrM6Y0OKOT8UxJbIVGm1TIcjaSu2MxaWcgtsNlKlCk7o7qg==} engines: {node: '>=0.10.3'} @@ -8244,6 +8273,11 @@ packages: react: '>=16.2.0' react-dom: '>=16.2.0' + react-beautiful-dnd-next@11.0.5: + resolution: {integrity: sha512-kM5Mob41HkA3ShS9uXqeMkW51L5bVsfttxfrwwHucu7I6SdnRKCyN78t6QiLH/UJQQ8T4ukI6NeQAQQpGwolkg==} + peerDependencies: + react: ^16.8.5 + react-burger-menu@3.0.9: resolution: {integrity: sha512-Qy15hkCxwxNEKfqdAv43F+8ZSl+/c6KkqrBwGP0CesFYJ02onHtiUFUbuhSWCMtBH8/n0HhfekFlp/NyCdKYzQ==} engines: {node: '>=4.0.0'} @@ -8366,6 +8400,9 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-markdown@9.0.1: resolution: {integrity: sha512-186Gw/vF1uRkydbsOIkcGXw7aHq0sZOCRFFjGrr7b9+nVZg4UfA4enXCaxm4fUzecU38sWfrNDitGhshuU7rdg==} peerDependencies: @@ -8392,6 +8429,18 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' + react-redux@7.2.9: + resolution: {integrity: sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==} + peerDependencies: + react: ^16.8.3 || ^17 || ^18 + react-dom: '*' + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + react-redux@9.1.2: resolution: {integrity: sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==} peerDependencies: @@ -8503,6 +8552,9 @@ packages: peerDependencies: immutable: ^3.8.1 || ^4.0.0-rc.1 + redux@4.2.1: + resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} + redux@5.0.1: resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} @@ -9202,6 +9254,9 @@ packages: resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==} engines: {node: '>=12'} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + tiny-warning@1.0.3: resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} @@ -9585,6 +9640,11 @@ packages: '@types/react': optional: true + use-memo-one@1.1.3: + resolution: {integrity: sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + use-sidecar@1.1.2: resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} engines: {node: '>=10'} @@ -11295,6 +11355,11 @@ snapshots: '@babel/types': 7.26.0 esutils: 2.0.3 + '@babel/runtime-corejs2@7.26.0': + dependencies: + core-js: 2.6.12 + regenerator-runtime: 0.14.1 + '@babel/runtime-corejs3@7.25.7': dependencies: core-js-pure: 3.38.1 @@ -15427,6 +15492,11 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/hoist-non-react-statics@3.3.6': + dependencies: + '@types/react': 18.2.8 + hoist-non-react-statics: 3.3.2 + '@types/json-schema@7.0.15': {} '@types/katex@0.16.7': {} @@ -15486,6 +15556,13 @@ snapshots: dependencies: '@types/react': 18.2.8 + '@types/react-redux@7.1.34': + dependencies: + '@types/hoist-non-react-statics': 3.3.6 + '@types/react': 18.2.8 + hoist-non-react-statics: 3.3.2 + redux: 4.2.1 + '@types/react@18.2.8': dependencies: '@types/prop-types': 15.7.13 @@ -16258,6 +16335,8 @@ snapshots: core-js-pure@3.38.1: {} + core-js@2.6.12: {} + core-util-is@1.0.3: {} cors@2.8.5: @@ -16319,6 +16398,10 @@ snapshots: dependencies: type-fest: 1.4.0 + css-box-model@1.2.1: + dependencies: + tiny-invariant: 1.3.3 + css-declaration-sorter@6.4.1(postcss@8.4.47): dependencies: postcss: 8.4.47 @@ -17583,6 +17666,10 @@ snapshots: highlightjs-vue@1.0.0: {} + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + hook-std@3.0.0: {} hosted-git-info@7.0.2: @@ -18604,6 +18691,8 @@ snapshots: dependencies: fs-monkey: 1.0.6 + memoize-one@5.2.1: {} + meow@13.2.0: {} merge-descriptors@1.0.3: {} @@ -19908,6 +19997,8 @@ snapshots: radix3@1.1.2: {} + raf-schd@4.0.3: {} + ramda-adjunct@5.1.0(ramda@0.30.1): dependencies: ramda: 0.30.1 @@ -19971,6 +20062,21 @@ snapshots: transitivePeerDependencies: - encoding + react-beautiful-dnd-next@11.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@babel/runtime-corejs2': 7.26.0 + css-box-model: 1.2.1 + memoize-one: 5.2.1 + raf-schd: 4.0.3 + react: 18.3.1 + react-redux: 7.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + redux: 4.2.1 + tiny-invariant: 1.3.3 + use-memo-one: 1.1.3(react@18.3.1) + transitivePeerDependencies: + - react-dom + - react-native + react-burger-menu@3.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: browserify-optional: 1.0.1 @@ -20141,6 +20247,8 @@ snapshots: react-is@16.13.1: {} + react-is@17.0.2: {} + react-markdown@9.0.1(@types/react@18.2.8)(react@18.3.1): dependencies: '@types/hast': 3.0.4 @@ -20176,6 +20284,18 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + react-redux@7.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@babel/runtime': 7.25.7 + '@types/react-redux': 7.1.34 + hoist-non-react-statics: 3.3.2 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 18.3.1 + react-is: 17.0.2 + optionalDependencies: + react-dom: 18.3.1(react@18.3.1) + react-redux@9.1.2(@types/react@18.2.8)(react@18.3.1)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.3 @@ -20313,6 +20433,10 @@ snapshots: dependencies: immutable: 3.8.2 + redux@4.2.1: + dependencies: + '@babel/runtime': 7.25.7 + redux@5.0.1: {} reflect-metadata@0.2.2: {} @@ -21214,6 +21338,8 @@ snapshots: dependencies: convert-hrtime: 5.0.0 + tiny-invariant@1.3.3: {} + tiny-warning@1.0.3: {} tinyexec@0.3.1: {} @@ -21584,6 +21710,10 @@ snapshots: optionalDependencies: '@types/react': 18.2.8 + use-memo-one@1.1.3(react@18.3.1): + dependencies: + react: 18.3.1 + use-sidecar@1.1.2(@types/react@18.2.8)(react@18.3.1): dependencies: detect-node-es: 1.1.0 diff --git a/prisma/migrations/20241218023101_0_27_0/migration.sql b/prisma/migrations/20241218023101_0_27_0/migration.sql new file mode 100644 index 00000000..5db902fb --- /dev/null +++ b/prisma/migrations/20241218023101_0_27_0/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "attachments" ADD COLUMN "sortOrder" INTEGER NOT NULL DEFAULT 0; + +-- AlterTable +ALTER TABLE "tag" ADD COLUMN "sortOrder" INTEGER NOT NULL DEFAULT 0; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index a708c675..d6a69f30 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -36,6 +36,7 @@ model attachments { size Decimal @default(0) @db.Decimal type String @default("") @db.VarChar noteId Int @default(0) + sortOrder Int @default(0) createdAt DateTime @default(now()) @db.Timestamptz(6) updatedAt DateTime @updatedAt @db.Timestamptz(6) @@ -43,30 +44,30 @@ model attachments { } model config { - id Int @id @default(autoincrement()) - key String @default("") @db.VarChar - config Json? @db.Json - userId Int? + id Int @id @default(autoincrement()) + key String @default("") @db.VarChar + config Json? @db.Json + userId Int? user accounts? @relation(fields: [userId], references: [id]) } model notes { - id Int @id @default(autoincrement()) - type Int @default(0) - content String @default("") @db.VarChar - isArchived Boolean @default(false) - isRecycle Boolean @default(false) - isShare Boolean @default(false) - isTop Boolean @default(false) - isReviewed Boolean @default(false) - sharePassword String @default("") @db.VarChar - metadata Json? @db.Json - accountId Int? - createdAt DateTime @default(now()) @db.Timestamptz(6) - updatedAt DateTime @updatedAt @db.Timestamptz(6) + id Int @id @default(autoincrement()) + type Int @default(0) + content String @default("") @db.VarChar + isArchived Boolean @default(false) + isRecycle Boolean @default(false) + isShare Boolean @default(false) + isTop Boolean @default(false) + isReviewed Boolean @default(false) + sharePassword String @default("") @db.VarChar + metadata Json? @db.Json + accountId Int? + createdAt DateTime @default(now()) @db.Timestamptz(6) + updatedAt DateTime @updatedAt @db.Timestamptz(6) attachments attachments[] tags tagsToNote[] - account accounts? @relation(fields: [accountId], references: [id]) + account accounts? @relation(fields: [accountId], references: [id]) referencedBy noteReference[] @relation("ReferencedNote") references noteReference[] @relation("ReferencingNote") } @@ -76,10 +77,11 @@ model tag { name String @default("") @db.VarChar icon String @default("") @db.VarChar parent Int @default(0) - accountId Int? + accountId Int? createdAt DateTime @default(now()) @db.Timestamptz(6) updatedAt DateTime @updatedAt @db.Timestamptz(6) tagsToNote tagsToNote[] + sortOrder Int @default(0) account accounts? @relation(fields: [accountId], references: [id]) } @@ -104,13 +106,13 @@ model scheduledTask { } model noteReference { - id Int @id @default(autoincrement()) - fromNoteId Int - toNoteId Int - createdAt DateTime @default(now()) @db.Timestamptz(6) - - fromNote notes @relation("ReferencingNote", fields: [fromNoteId], references: [id]) - toNote notes @relation("ReferencedNote", fields: [toNoteId], references: [id]) + id Int @id @default(autoincrement()) + fromNoteId Int + toNoteId Int + createdAt DateTime @default(now()) @db.Timestamptz(6) + + fromNote notes @relation("ReferencingNote", fields: [fromNoteId], references: [id]) + toNote notes @relation("ReferencedNote", fields: [toNoteId], references: [id]) @@unique([fromNoteId, toNoteId]) } diff --git a/src/components/Common/AttachmentRender/DraggableFileGrid.tsx b/src/components/Common/AttachmentRender/DraggableFileGrid.tsx new file mode 100644 index 00000000..b4e79221 --- /dev/null +++ b/src/components/Common/AttachmentRender/DraggableFileGrid.tsx @@ -0,0 +1,97 @@ +import React from 'react'; +import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd-next'; +import { FileType } from '../Editor/type'; +import { FileIcons } from '../FileIcon'; +import { DeleteIcon } from './icons'; +import { helper } from '@/lib/helper'; +import { api } from '@/lib/trpc'; + +type DraggableFileGridProps = { + files: FileType[]; + preview?: boolean; + columns?: number; + onReorder?: (newFiles: FileType[]) => void; + type: 'image' | 'other'; + className?: string; + renderItem?: (file: FileType) => React.ReactNode; +}; + +export const DraggableFileGrid = ({ + files, + preview = false, + onReorder, + type, + className, + renderItem +}: DraggableFileGridProps) => { + const handleDragEnd = async (result: any) => { + if (!result.destination) return; + + const { source, destination } = result; + const filteredFiles = files.filter(i => i.previewType === type); + const allFiles = Array.from(files); + + const [reorderedItem] = filteredFiles.splice(source.index, 1); + if (reorderedItem) { + filteredFiles.splice(destination.index, 0, reorderedItem); + + const newFiles = allFiles.map(file => { + if (file.previewType === type) { + return filteredFiles.shift() || file; + } + return file; + }); + + onReorder?.(newFiles); + + try { + await api.notes.updateAttachmentsOrder.mutate({ + attachments: newFiles.map((file, index) => ({ + name: file.name, + sortOrder: index + })) + }); + } catch (error) { + console.error('Failed to update attachments order:', error); + } + } + }; + + return ( + + + {(provided, snapshot) => ( +
+ {files.filter(i => i.previewType === type).map((file, index) => ( + + {(provided, snapshot) => ( +
+ {renderItem?.(file)} +
+ )} +
+ ))} + {provided.placeholder} +
+ )} +
+
+ ); +}; \ No newline at end of file diff --git a/src/components/Common/AttachmentRender/imageRender.tsx b/src/components/Common/AttachmentRender/imageRender.tsx index a020daba..ab068065 100644 --- a/src/components/Common/AttachmentRender/imageRender.tsx +++ b/src/components/Common/AttachmentRender/imageRender.tsx @@ -1,18 +1,18 @@ import React, { useEffect, useMemo, useState } from 'react'; import { FileType } from '../Editor/type'; -import { Image, Skeleton } from '@nextui-org/react'; +import { Image } from '@nextui-org/react'; import { PhotoProvider, PhotoView } from 'react-photo-view'; import { Icon } from '@iconify/react'; import { DeleteIcon, DownloadIcon } from './icons'; import { observer } from 'mobx-react-lite'; -import { RootStore } from '@/store'; import { useMediaQuery } from 'usehooks-ts'; -import { api } from '@/lib/trpc'; +import { DraggableFileGrid } from './DraggableFileGrid'; type IProps = { files: FileType[] preview?: boolean columns?: number + onReorder?: (newFiles: FileType[]) => void } const ImageThumbnailRender = ({ file, className }: { file: FileType, className?: string }) => { const [isOriginalError, setIsOriginalError] = useState(false); @@ -49,13 +49,14 @@ const ImageRender = observer((props: IProps) => { const images = files?.filter(i => i.previewType == 'image') const imageRenderClassName = useMemo(() => { - const imageLength = files?.filter(i => i.previewType == 'image')?.length + if (!preview) { + return 'flex flex-row gap-2 overflow-x-auto pb-2' + } + + const imageLength = images?.length if (columns) { return `grid grid-cols-${columns} gap-2` } - if (!preview && !isPc) { - return `flex items-center overflow-x-scroll gap-2` - } if (imageLength == 1) { return `grid grid-cols-2 gap-2` } @@ -66,16 +67,17 @@ const ImageRender = observer((props: IProps) => { return `grid grid-cols-3 gap-3` } return '' - }, [images]) + }, [images, preview, columns]) const imageHeight = useMemo(() => { - const imageLength = files?.filter(i => i.previewType == 'image')?.length + if (!preview) { + return 'h-[160px] w-[160px]' + } + + const imageLength = images?.length if (columns) { return `max-h-[100px] w-auto` } - if (!preview && !isPc) { - return `h-[80px] min-w-[80px]` - } if (imageLength == 1) { return `h-[200px] max-h-[200px] md:max-w-[200px]` } @@ -86,31 +88,45 @@ const ImageRender = observer((props: IProps) => { return `lg:h-[160px] md:h-[120px] h-[100px]` } return '' - }, [images]) + }, [images, preview, columns]) - return
- - {images.map((file, index) => ( -
- {file.uploadPromise?.loading?.value &&
- -
} -
- -
- -
-
-
- {!file.uploadPromise?.loading?.value && !preview && - - } - {preview && - } + const renderImage = (file: FileType) => ( +
+ {file.uploadPromise?.loading?.value && ( +
+
- ))} + )} +
+ +
+ +
+
+
+ {!file.uploadPromise?.loading?.value && !preview && + + } + {preview && } +
+ ) + + return ( + + -
+ ) }) export { ImageRender } \ No newline at end of file diff --git a/src/components/Common/AttachmentRender/index.tsx b/src/components/Common/AttachmentRender/index.tsx index baf829cd..67399112 100644 --- a/src/components/Common/AttachmentRender/index.tsx +++ b/src/components/Common/AttachmentRender/index.tsx @@ -8,15 +8,12 @@ import { DeleteIcon, DownloadIcon } from './icons'; import { ImageRender } from './imageRender'; import { HandleFileType } from '../Editor/editorUtils'; import { Icon } from '@iconify/react'; -import { RootStore } from '@/store'; -import { BlinkoStore } from '@/store/blinkoStore'; import { Popover, PopoverContent, PopoverTrigger } from '@nextui-org/popover'; import { BlinkoCard } from '@/components/BlinkoCard'; import { api } from '@/lib/trpc'; -import { PromiseState } from '@/store/standard/PromiseState'; -import { cache } from '@/lib/cache'; -import { reaction } from 'mobx'; import { EditorStore } from '../Editor/editorStore'; +import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd-next'; +import { DraggableFileGrid } from './DraggableFileGrid'; //https://www.npmjs.com/package/browser-thumbnail-generator @@ -24,65 +21,131 @@ type IProps = { files: FileType[] preview?: boolean columns?: number + onReorder?: (newFiles: FileType[]) => void } const AttachmentsRender = observer((props: IProps) => { const { files, preview = false, columns = 3 } = props - return <> - {/* image render */} - - {/* video render todo:improve style*/} -
- {files?.filter(i => i.previewType == 'video').map((file, index) => ( -
-
- ))} -
- {/* audio render todo:improve style*/} -
- {files?.filter(i => i.previewType == 'audio').map((file, index) => ( -
-
- ))} -
- - - {/* other file render */} -
- {files?.filter(i => i.previewType == 'other').map((file, index) => ( -
{ - if (preview) { - helper.download.downloadByLink(file.uploadPromise.value) - } - }} className='relative flex p-2 w-full items-center gap-2 cursor-pointer bg-sencondbackground hover:bg-hover tansition-all rounded-md group'> - -
{file.name}
- {!file.uploadPromise?.loading?.value && !preview && - } -
- ))} -
- + const gridClassName = preview + ? `grid grid-cols-${(columns - 1) < 1 ? 1 : (columns - 1)} md:grid-cols-${columns} gap-2 mt-3` + : 'flex flex-row gap-2 overflow-x-auto pb-2 mt-3'; + + return ( +
+ {/* image render */} + + + {/* video render */} +
+ {files?.filter(i => i.previewType == 'video').map((file, index) => ( +
+
+ ))} +
+ + {/* audio render - */} +
+ {files?.filter(i => i.previewType == 'audio').map((file, index) => ( +
+
+ ))} +
+ + {/* other file render */} + ( +
{ + if (preview) { + helper.download.downloadByLink(file.uploadPromise.value) + } + }} + > + +
{file.name}
+ {!file.uploadPromise?.loading?.value && !preview && + + } +
+ )} + /> +
+ ) }) -const FilesAttachmentRender = observer(({ files, preview, columns }: { files: Attachment[], preview?: boolean, columns?: number }) => { - const [handledFiles, setFiles] = useState([]) +const FilesAttachmentRender = observer(({ + files, + preview, + columns, + onReorder +}: { + files: Attachment[], + preview?: boolean, + columns?: number, + onReorder?: (newFiles: Attachment[]) => void +}) => { + const [handledFiles, setFiles] = useState([]); + useEffect(() => { - setFiles(HandleFileType(files)) - }, [files]) - return -}) + setFiles(HandleFileType(files)); + }, [files]); + + const handleReorder = (newFiles: FileType[]) => { + const newAttachments = files.slice().sort((a, b) => { + const aIndex = newFiles.findIndex(f => f.name === a.name); + const bIndex = newFiles.findIndex(f => f.name === b.name); + return aIndex - bIndex; + }); + onReorder?.(newAttachments); + }; + + return ( + + ); +}); const ReferenceRender = observer(({ store }: { store: EditorStore }) => { diff --git a/src/components/Common/Editor/editorStore.tsx b/src/components/Common/Editor/editorStore.tsx index b2f00792..f5d77b7f 100644 --- a/src/components/Common/Editor/editorStore.tsx +++ b/src/components/Common/Editor/editorStore.tsx @@ -51,6 +51,10 @@ export class EditorStore { } catch (error) { } } + updateFileOrder = (newFiles: FileType[]) => { + this.files = newFiles; + } + insertMarkdown = (text) => { this.vditor?.insertValue(text) this.focus() diff --git a/src/components/Common/Editor/index.tsx b/src/components/Common/Editor/index.tsx index 7bb13676..293d7257 100644 --- a/src/components/Common/Editor/index.tsx +++ b/src/components/Common/Editor/index.tsx @@ -5,7 +5,7 @@ import { useTheme } from 'next-themes'; import React, { ReactElement, useEffect, useRef, useState } from 'react'; import { useDropzone } from 'react-dropzone'; import { observer, useLocalObservable } from 'mobx-react-lite'; -import { OnSendContentType } from './type'; +import { FileType, OnSendContentType } from './type'; import { BlinkoStore } from '@/store/blinkoStore'; import { _ } from '@/lib/lodash'; import { useTranslation } from 'react-i18next'; @@ -72,6 +72,10 @@ const Editor = observer(({ content, onChange, onSend, isSendLoading, originFiles } }); + const handleFileReorder = (newFiles: FileType[]) => { + store.updateFileOrder(newFiles); + }; + return 0 && (
- +
)} diff --git a/src/lib/prismaZodType.ts b/src/lib/prismaZodType.ts index 62252322..9e3e9a34 100644 --- a/src/lib/prismaZodType.ts +++ b/src/lib/prismaZodType.ts @@ -33,6 +33,7 @@ export const attachmentsSchema = z.object({ size: z.instanceof(Prisma.Decimal, { message: "Field 'size' must be a Decimal. Location: ['Models', 'attachments']" }), noteId: z.number().int(), createdAt: z.coerce.date(), + sortOrder: z.number().int(), updatedAt: z.coerce.date(), type: z.string(), }) @@ -82,6 +83,7 @@ export const tagSchema = z.object({ name: z.string(), icon: z.string(), parent: z.number().int(), + sortOrder: z.number().int(), createdAt: z.coerce.date(), updatedAt: z.coerce.date(), }) diff --git a/src/server/routers/note.ts b/src/server/routers/note.ts index a125c248..2174c0d8 100644 --- a/src/server/routers/note.ts +++ b/src/server/routers/note.ts @@ -117,7 +117,12 @@ export const noteRouter = router({ take: size, include: { tags: { include: { tag: true } }, - attachments: true, + attachments: { + orderBy: [ + { sortOrder: 'asc' }, + { id: 'asc' } + ] + }, references: { select: { toNoteId: true @@ -173,7 +178,12 @@ export const noteRouter = router({ where: { id: { in: ids }, accountId: Number(ctx.id) }, include: { tags: { include: { tag: true } }, - attachments: true, + attachments: { + orderBy: [ + { sortOrder: 'asc' }, + { id: 'asc' } + ] + }, references: { select: { toNoteId: true @@ -526,6 +536,34 @@ export const noteRouter = router({ return await deleteNotes(noteIds, ctx); }), + updateAttachmentsOrder: authProcedure + .meta({ openapi: { method: 'POST', path: '/v1/note/update-attachments-order', summary: 'Update attachments order', protect: true, tags: ['Note'] } }) + .input(z.object({ + attachments: z.array(z.object({ + name: z.string(), + sortOrder: z.number() + })) + })) + .output(z.any()) + .mutation(async function ({ input, ctx }) { + const { attachments } = input; + + await Promise.all( + attachments.map(({ name, sortOrder }) => + prisma.attachments.updateMany({ + where: { + name, + note: { + accountId: Number(ctx.id) + } + }, + data: { sortOrder } + }) + ) + ); + + return { success: true }; + }), }) let insertNoteReference = async ({ fromNoteId, toNoteId, accountId }) => { From 91229c6addd1b4ca25547fe831a675f5b188642c Mon Sep 17 00:00:00 2001 From: blinko Date: Wed, 18 Dec 2024 12:57:24 +0800 Subject: [PATCH 20/55] fix: improve BlinkoAiChat responsiveness and enhance file name handling - Added support for iOS-specific styling in the BlinkoAiChat component to improve responsiveness on iOS devices. - Updated the EditorStore to correctly update the file name in the files array after a successful upload. - Refactored Dialog and DialogStandalone components to ensure consistent content rendering and layout adjustments, enhancing user experience. --- src/components/BlinkoAi/index.tsx | 6 +++--- src/components/Common/Editor/editorStore.tsx | 6 ++++++ src/store/module/Dialog/Provider.tsx | 15 ++++++++++----- src/store/module/DialogStandalone/Provider.tsx | 8 ++++++-- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/components/BlinkoAi/index.tsx b/src/components/BlinkoAi/index.tsx index 132a609c..316ee267 100644 --- a/src/components/BlinkoAi/index.tsx +++ b/src/components/BlinkoAi/index.tsx @@ -8,17 +8,16 @@ import { motion } from "motion/react" import { AiStore } from "@/store/aiStore"; import { useEffect, useRef } from "react"; import { useMediaQuery } from "usehooks-ts"; -import { DialogStore } from "@/store/module/Dialog"; import { UserStore } from "@/store/user"; import { useTranslation } from "react-i18next"; import { ScrollArea, ScrollAreaHandles } from "../Common/ScrollArea"; import Link from "next/link"; -import DraggableDiv from "../Common/DragContainer"; import dayjs from "@/lib/dayjs"; import { FilesAttachmentRender } from "../Common/AttachmentRender"; import { ResizableWrapper } from "../Common/ResizableWrapper"; import { useRouter } from "next/router"; import { MarkdownRender } from "../Common/MarkdownRender"; +import { useIsIOS } from "@/lib/hooks"; export const BlinkoAiChat = observer(() => { const ai = RootStore.Get(AiStore) @@ -26,6 +25,7 @@ export const BlinkoAiChat = observer(() => { const router = useRouter() const scrollAreaRef = useRef(null); const { t } = useTranslation() + const isIOS = useIsIOS() useEffect(() => { scrollAreaRef.current?.scrollToBottom() }, [ai.scrollTicker]) @@ -35,7 +35,7 @@ export const BlinkoAiChat = observer(() => { onBottom={() => { }} ref={scrollAreaRef} key='BlinkoAiChat' - className={`mx-1 w-full flex-1`}> + className={`mx-1 w-full flex-1 ${isIOS ? 'max-h-[70vh]' : ''}`}> { ai.chatHistory.list.length == 0 &&
diff --git a/src/components/Common/Editor/editorStore.tsx b/src/components/Common/Editor/editorStore.tsx index f5d77b7f..080c3604 100644 --- a/src/components/Common/Editor/editorStore.tsx +++ b/src/components/Common/Editor/editorStore.tsx @@ -146,6 +146,12 @@ export class EditorStore { onUploadProgress }); const data = response.data; + if (data.fileName) { + const fileIndex = this.files.findIndex(f => f.name === file.name); + if (fileIndex !== -1) { + this.files[fileIndex]!.name = data.fileName; + } + } this.speechToText(data.filePath) if (data.filePath) { return data.filePath diff --git a/src/store/module/Dialog/Provider.tsx b/src/store/module/Dialog/Provider.tsx index 23ed3cc3..4479b490 100644 --- a/src/store/module/Dialog/Provider.tsx +++ b/src/store/module/Dialog/Provider.tsx @@ -8,6 +8,7 @@ import { useMediaQuery } from "usehooks-ts"; import { motion } from "motion/react"; import { Icon } from "@iconify/react"; import { CancelIcon } from "@/components/Common/Icons"; +import { ScrollArea } from "@/components/Common/ScrollArea"; const CloseButton = ({ onClose }: { onClose: () => void }) => (
{ className="w-full bg-background border-sencondbackground p-1 rounded-t-lg shadow-lg pointer-events-auto" {...motionConfig} > -
+
{title ?? ''}
-
- +
+ +
)} @@ -123,12 +126,14 @@ const Dialog = observer(() => { className="w-full pointer-events-auto " {...motionConfig} > -
+
{ showOnlyContentCloseButton && modal.close()} /> } - +
+ +
} diff --git a/src/store/module/DialogStandalone/Provider.tsx b/src/store/module/DialogStandalone/Provider.tsx index 77d0741f..cf5d9325 100644 --- a/src/store/module/DialogStandalone/Provider.tsx +++ b/src/store/module/DialogStandalone/Provider.tsx @@ -115,7 +115,9 @@ const Dialog = observer(() => {
- +
+ +
)} @@ -129,7 +131,9 @@ const Dialog = observer(() => { showOnlyContentCloseButton && modal.close()} /> } - +
+ +
} From 6194067d5de9f8ed95a2b850b747448d188ea539 Mon Sep 17 00:00:00 2001 From: blinko Date: Wed, 18 Dec 2024 13:21:04 +0800 Subject: [PATCH 21/55] fix: refactor sidebar state management and enhance resizing functionality - Introduced StorageState for sidebar width and collapsed state, allowing persistent storage and validation of sidebar dimensions. - Updated Sidebar component to conditionally apply transition effects based on resizing state. - Enhanced resizing functionality with mouse event handlers for better user interaction. - Improved code readability and maintainability by refactoring sidebar-related logic in BaseStore. --- src/components/Layout/Sidebar.tsx | 18 ++++++-- src/store/baseStore.ts | 67 +++++++++++++++++++++++++++--- src/store/standard/StorageState.ts | 6 ++- 3 files changed, 80 insertions(+), 11 deletions(-) diff --git a/src/components/Layout/Sidebar.tsx b/src/components/Layout/Sidebar.tsx index 2bcab313..abd634a3 100644 --- a/src/components/Layout/Sidebar.tsx +++ b/src/components/Layout/Sidebar.tsx @@ -27,15 +27,27 @@ export const Sidebar = observer(({ onItemClick }: SidebarProps) => { useEffect(() => { if (!isPc) { - base.collapseSidebar() + base.collapseSidebar(); } - }, [isPc]) + }, [isPc]); return (
+ {!base.isSidebarCollapsed && ( +
e.stopPropagation()} + style={{ touchAction: 'none' }} + /> + )}
{!base.isSidebarCollapsed && ( theme == 'dark' ? ( diff --git a/src/store/baseStore.ts b/src/store/baseStore.ts index fd634919..db14e8f5 100644 --- a/src/store/baseStore.ts +++ b/src/store/baseStore.ts @@ -106,15 +106,70 @@ export class BaseStore implements Store { }, [this.currentRouter, router.pathname]) } - isSidebarCollapsed: boolean = false; - sideBarWidth = 288 + sidebarWidth = new StorageState({ + key: 'sidebar-width', + default: 288, + validate: (value: number) => { + if (value < 220) return 220; + if (value > 400) return 400; + return value; + } + }); + + sidebarCollapsed = new StorageState({ + key: 'sidebar-collapsed', + default: false + }); + + isResizing = false; + isDragging = false; + + get isSidebarCollapsed() { + return this.sidebarCollapsed.value; + } + + get sideBarWidth() { + return this.isSidebarCollapsed ? 80 : this.sidebarWidth.value; + } + + set sideBarWidth(value: number) { + if (!this.isSidebarCollapsed) { + this.sidebarWidth.save(value); + } + } + + startResizing = (e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + this.isResizing = true; + this.isDragging = true; + document.addEventListener('mousemove', this.handleMouseMove); + document.addEventListener('mouseup', this.stopResizing); + }; + + handleMouseMove = (e: MouseEvent) => { + if (!this.isResizing || this.isSidebarCollapsed) return; + + e.preventDefault(); + const newWidth = Math.max(80, Math.min(400, e.clientX)); + this.sidebarWidth.save(newWidth); + }; + + stopResizing = () => { + this.isResizing = false; + setTimeout(() => { + this.isDragging = false; + }, 50); + document.removeEventListener('mousemove', this.handleMouseMove); + document.removeEventListener('mouseup', this.stopResizing); + }; toggleSidebar = () => { - this.isSidebarCollapsed = !this.isSidebarCollapsed; - this.sideBarWidth = this.isSidebarCollapsed ? 80 : 288 + const newCollapsed = !this.isSidebarCollapsed; + this.sidebarCollapsed.save(newCollapsed); } + collapseSidebar = () => { - this.isSidebarCollapsed = false; - this.sideBarWidth = 288 + this.sidebarCollapsed.save(false); } } diff --git a/src/store/standard/StorageState.ts b/src/store/standard/StorageState.ts index acd9b748..e57f98d4 100644 --- a/src/store/standard/StorageState.ts +++ b/src/store/standard/StorageState.ts @@ -4,6 +4,8 @@ export class StorageState { key: string; value: T | any = null; default: T | any = null; + validate?: (value: T) => T; + constructor(args: Partial>) { Object.assign(this, args); makeAutoObservable(this); @@ -37,9 +39,9 @@ export class StorageState { try { if (typeof window == 'undefined') return if (value !== null || value !== undefined) { - this.value = value; + this.value = this.validate ? this.validate(value!) : value; } - window?.localStorage.setItem(this.key, JSON.stringify(value)); + window?.localStorage.setItem(this.key, JSON.stringify(this.value)); } catch (error) { console.error(error); return null; From 9de5e8e8786d1fec3e6781467af9bb4a565333e4 Mon Sep 17 00:00:00 2001 From: blinko Date: Wed, 18 Dec 2024 14:48:52 +0800 Subject: [PATCH 22/55] fix: enhance layout components and improve user interaction - Refactored FilterPop component to wrap the filter icon in a button for better accessibility and interaction. - Updated CommonLayout to integrate BarSearchInput and improve layout structure, enhancing the overall user experience. - Adjusted MobileNavBar styles for better text visibility and alignment, ensuring a more consistent appearance across devices. - Improved responsiveness and overflow handling in layout components to enhance usability on mobile devices. --- .../Common/PopoverFloat/filterPop.tsx | 4 +- src/components/Layout/BarSearchInput.tsx | 122 ++++++++++++++++ src/components/Layout/MobileNavBar.tsx | 8 +- src/components/Layout/index.tsx | 138 +++++++----------- 4 files changed, 183 insertions(+), 89 deletions(-) create mode 100644 src/components/Layout/BarSearchInput.tsx diff --git a/src/components/Common/PopoverFloat/filterPop.tsx b/src/components/Common/PopoverFloat/filterPop.tsx index 73ab9484..972ae463 100644 --- a/src/components/Common/PopoverFloat/filterPop.tsx +++ b/src/components/Common/PopoverFloat/filterPop.tsx @@ -69,7 +69,9 @@ export default function FilterPop() { return ( - +
diff --git a/src/components/Layout/BarSearchInput.tsx b/src/components/Layout/BarSearchInput.tsx new file mode 100644 index 00000000..5da4fdb2 --- /dev/null +++ b/src/components/Layout/BarSearchInput.tsx @@ -0,0 +1,122 @@ +import React, { useRef, useState } from "react"; +import { Button, Input, Tooltip } from "@nextui-org/react"; +import { Icon } from "@iconify/react"; +import { motion, AnimatePresence } from "framer-motion"; +import { useTranslation } from "react-i18next"; +import { _ } from "@/lib/lodash"; +import { useRouter } from "next/router"; +import { RootStore } from "@/store"; +import { BlinkoStore } from "@/store/blinkoStore"; +import { observer } from "mobx-react-lite"; + +interface BarSearchInputProps { + isPc: boolean; +} + +export const BarSearchInput = observer(({ isPc }: BarSearchInputProps) => { + const { t } = useTranslation(); + const router = useRouter(); + const searchInputRef = useRef(null); + const blinkoStore = RootStore.Get(BlinkoStore); + const [showSearchInput, setShowSearchInput] = useState(false); + + const throttleSearchRef = useRef(_.throttle(() => { + if (router.pathname == '/resources') { + return blinkoStore.resourceList.resetAndCall({ searchText: searchInputRef.current?.value }) + } + blinkoStore.noteList.resetAndCall({}) + }, 1000, { trailing: true, leading: false })); + + const handleClose = () => { + setShowSearchInput(false); + blinkoStore.noteListFilterConfig.searchText = ''; + throttleSearchRef.current(); + } + + return ( + <> + {!isPc && !showSearchInput ? ( + + + + ) : ( + + + { + blinkoStore.noteListFilterConfig.searchText = e.target.value + throttleSearchRef.current() + }} + startContent={ + g]:stroke-[2px] ${!isPc ? 'cursor-pointer' : ''}`} + icon={!isPc && showSearchInput ? "material-symbols:close" : "lets-icons:search"} + width="24" + height="24" + onClick={() => !isPc && handleClose()} + /> + } + endContent={router.pathname != '/resources' && ( + + { + searchInputRef.current?.focus() + blinkoStore.noteListFilterConfig.isUseAiQuery = !blinkoStore.noteListFilterConfig.isUseAiQuery + if (blinkoStore.noteListFilterConfig.searchText != '') { + throttleSearchRef.current() + } + }} + /> + + )} + /> + + + )} + + ); +}); \ No newline at end of file diff --git a/src/components/Layout/MobileNavBar.tsx b/src/components/Layout/MobileNavBar.tsx index a1b5a8eb..3c48099b 100644 --- a/src/components/Layout/MobileNavBar.tsx +++ b/src/components/Layout/MobileNavBar.tsx @@ -24,7 +24,7 @@ export const MobileNavBar = observer(({ onItemClick }: MobileNavBarProps) => { } return ( -
+
{base.routerList.filter(i => !i.hiddenMobile).map(i => ( { >
- -
{t(i.title)}
+ +
{t(i.title)}
))} diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx index c4551dfb..2d3ac7c1 100644 --- a/src/components/Layout/index.tsx +++ b/src/components/Layout/index.tsx @@ -29,6 +29,8 @@ import { api } from "@/lib/trpc"; import { showTipsDialog } from "../Common/TipsDialog"; import { DialogStandaloneStore } from "@/store/module/DialogStandalone"; import { ToastPlugin } from "@/store/module/Toast/Toast"; +import { motion, AnimatePresence } from "framer-motion"; +import { BarSearchInput } from "./BarSearchInput"; export const SideBarItem = "p-2 flex flex-row items-center cursor-pointer gap-2 hover:bg-hover rounded-xl transition-all" @@ -48,14 +50,6 @@ export const CommonLayout = observer(({ const user = RootStore.Get(UserStore) const blinkoStore = RootStore.Get(BlinkoStore) const base = RootStore.Get(BaseStore) - const searchInputRef = useRef(null); - - const throttleSearchRef = useRef(_.throttle(() => { - if (base.currentRouter?.href == '/resources') { - return blinkoStore.resourceList.resetAndCall({ searchText: searchInputRef.current?.value }) - } - blinkoStore.noteList.resetAndCall({}) - }, 1000, { trailing: true, leading: false })); blinkoStore.use() user.use() @@ -84,9 +78,7 @@ export const CommonLayout = observer(({ return (
{blinkoStore.showAi && createPortal(, document.body)} - - setisOpen(false)} @@ -124,88 +116,66 @@ export const CommonLayout = observer(({ width={24} /> } -
-
-
-
{t(base.currentTitle)}
- { - router.pathname != '/trash' - ? blinkoStore.refreshData()} icon="fluent:arrow-sync-12-filled" width="20" height="20" /> - : { - showTipsDialog({ - size: 'sm', - title: t('confirm-to-delete'), - content: t('this-operation-removes-the-associated-label-and-cannot-be-restored-please-confirm'), - onConfirm: async () => { - await RootStore.Get(ToastPlugin).promise( - api.notes.clearRecycleBin.mutate(), - { - loading: t('in-progress'), - success: {t('your-changes-have-been-saved')}, - error: {t('operation-failed')}, - }) - blinkoStore.refreshData() - RootStore.Get(DialogStandaloneStore).close() - } - }) - }} icon="mingcute:delete-2-line" width="20" height="20" /> - } +
+
+
+
+
{t(base.currentTitle)}
+ { + router.pathname != '/trash' + ? blinkoStore.refreshData()} + icon="fluent:arrow-sync-12-filled" + width="20" + height="20" + /> + : { + showTipsDialog({ + size: 'sm', + title: t('confirm-to-delete'), + content: t('this-operation-removes-the-associated-label-and-cannot-be-restored-please-confirm'), + onConfirm: async () => { + await RootStore.Get(ToastPlugin).promise( + api.notes.clearRecycleBin.mutate(), + { + loading: t('in-progress'), + success: {t('your-changes-have-been-saved')}, + error: {t('operation-failed')}, + }) + blinkoStore.refreshData() + RootStore.Get(DialogStandaloneStore).close() + } + }) + }} + icon="mingcute:delete-2-line" + width="20" + height="20" + /> + } +
- { - blinkoStore.noteListFilterConfig.searchText = e.target.value - throttleSearchRef.current() - }} - startContent={ - +
+ + + {blinkoStore.dailyReviewNoteList.value?.length != 0 && + + + + + } - endContent={router.pathname != '/resources' && - { - searchInputRef.current?.focus() - blinkoStore.noteListFilterConfig.isUseAiQuery = !blinkoStore.noteListFilterConfig.isUseAiQuery - if (blinkoStore.noteListFilterConfig.searchText != '') { - throttleSearchRef.current() - } - }} - /> - } - /> - - {blinkoStore.dailyReviewNoteList.value?.length != 0 && - - - - - } +
{header} {/* backdrop pt-6 -mt-6 to fix the editor tooltip position */} - { }} className="flex h-[calc(100%_-_70px)] overflow-y-scroll"> + { }} className="flex h-[calc(100%_-_70px)] overflow-y-scroll overflow-x-hidden">
{children}
From d0b445efd0a3d30f284dc805d7d95facf17c2d8a Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 18 Dec 2024 06:54:43 +0000 Subject: [PATCH 23/55] chore(release): 0.27.2 [skip ci] ## [0.27.2](https://github.com/blinko-space/blinko/compare/v0.27.1...v0.27.2) (2024-12-18) ### Bug Fixes * disable dragging for image thumbnails in AttachmentRender component [#331](https://github.com/blinko-space/blinko/issues/331) ([b2edb76](https://github.com/blinko-space/blinko/commit/b2edb7620770c4a2315f272df16ed83a4ceba85a)) * enhance attachment management and sorting functionality ([5b69f2b](https://github.com/blinko-space/blinko/commit/5b69f2b99f45c69165034c5d8132b9cea5656839)) * enhance layout components and improve user interaction ([9de5e8e](https://github.com/blinko-space/blinko/commit/9de5e8e8786d1fec3e6781467af9bb4a565333e4)) * improve BlinkoAiChat responsiveness and enhance file name handling ([91229c6](https://github.com/blinko-space/blinko/commit/91229c6addd1b4ca25547fe831a675f5b188642c)) * pwa refresh language lose ([dc41a44](https://github.com/blinko-space/blinko/commit/dc41a44883e5f4a0913c7b956fc911baa7351415)) * refactor sidebar state management and enhance resizing functionality ([6194067](https://github.com/blinko-space/blinko/commit/6194067d5de9f8ed95a2b850b747448d188ea539)) * update dialog store reference in DeleteIcon component [#332](https://github.com/blinko-space/blinko/issues/332) ([4183c9f](https://github.com/blinko-space/blinko/commit/4183c9f964c6e851a0c2331c4e78d79eea4421e8)) --- CHANGELOG.md | 13 +++++++++++++ package.json | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72a4b472..77ee22fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## [0.27.2](https://github.com/blinko-space/blinko/compare/v0.27.1...v0.27.2) (2024-12-18) + + +### Bug Fixes + +* disable dragging for image thumbnails in AttachmentRender component [#331](https://github.com/blinko-space/blinko/issues/331) ([b2edb76](https://github.com/blinko-space/blinko/commit/b2edb7620770c4a2315f272df16ed83a4ceba85a)) +* enhance attachment management and sorting functionality ([5b69f2b](https://github.com/blinko-space/blinko/commit/5b69f2b99f45c69165034c5d8132b9cea5656839)) +* enhance layout components and improve user interaction ([9de5e8e](https://github.com/blinko-space/blinko/commit/9de5e8e8786d1fec3e6781467af9bb4a565333e4)) +* improve BlinkoAiChat responsiveness and enhance file name handling ([91229c6](https://github.com/blinko-space/blinko/commit/91229c6addd1b4ca25547fe831a675f5b188642c)) +* pwa refresh language lose ([dc41a44](https://github.com/blinko-space/blinko/commit/dc41a44883e5f4a0913c7b956fc911baa7351415)) +* refactor sidebar state management and enhance resizing functionality ([6194067](https://github.com/blinko-space/blinko/commit/6194067d5de9f8ed95a2b850b747448d188ea539)) +* update dialog store reference in DeleteIcon component [#332](https://github.com/blinko-space/blinko/issues/332) ([4183c9f](https://github.com/blinko-space/blinko/commit/4183c9f964c6e851a0c2331c4e78d79eea4421e8)) + ## [0.27.1](https://github.com/blinko-space/blinko/compare/v0.27.0...v0.27.1) (2024-12-17) diff --git a/package.json b/package.json index cc7bf81d..1568e7b7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blinko", - "version": "0.27.1", + "version": "0.27.2", "repository": "https://github.com/blinko-space/blinko.git", "private": true, "browser": { From 800cc73cee9f5c03b603975e2804964405409eef Mon Sep 17 00:00:00 2001 From: blinko Date: Wed, 18 Dec 2024 23:16:01 +0800 Subject: [PATCH 24/55] feat: add music metadata functionality and Spotify integration - Introduced `music-metadata` package for extracting metadata from audio files. - Implemented new API endpoint to retrieve music metadata, including cover art, track name, album name, and artists. - Added support for Spotify API to fetch cover art using Spotify consumer key and secret. - Updated various components to integrate music settings and player functionality. - Enhanced localization files to include new music-related translations and settings. This update enhances the application's capabilities in handling music files and improves user experience with music-related features. --- package.json | 1 + pnpm-lock.yaml | 108 +++++- public/locales/ar/translation.json | 353 +----------------- public/locales/de/translation.json | 340 +---------------- public/locales/en/translation.json | 9 +- public/locales/es/translation.json | 331 +--------------- public/locales/fr/translation.json | 328 +--------------- public/locales/ja/translation.json | 313 +--------------- public/locales/ko/translation.json | 336 +---------------- public/locales/pt/translation.json | 264 +------------ public/locales/ru/translation.json | 8 +- public/locales/tr/translation.json | 282 +------------- public/locales/zh-TW/translation.json | 8 +- public/locales/zh/translation.json | 15 +- src/components/BlinkoMusicPlayer/index.tsx | 273 ++++++++++++++ src/components/BlinkoSettings/Item.tsx | 2 +- .../BlinkoSettings/MusicSetting.tsx | 58 +++ .../Common/AttachmentRender/audioRender.tsx | 264 +++++++++++++ .../Common/AttachmentRender/index.tsx | 24 +- src/components/Common/Editor/editorStore.tsx | 3 +- src/lib/constant.ts | 1 + src/pages/_app.tsx | 2 + src/pages/api/trpc/[trpc].ts | 20 + src/pages/settings.tsx | 2 + src/server/routers/helper/spotify.ts | 188 ++++++++++ src/server/routers/public.ts | 120 +++++- src/server/types.ts | 7 +- src/store/index.ts | 1 + src/store/musicManagerStore.tsx | 184 +++++++++ 29 files changed, 1277 insertions(+), 2568 deletions(-) create mode 100644 src/components/BlinkoMusicPlayer/index.tsx create mode 100644 src/components/BlinkoSettings/MusicSetting.tsx create mode 100644 src/components/Common/AttachmentRender/audioRender.tsx create mode 100644 src/server/routers/helper/spotify.ts create mode 100644 src/store/musicManagerStore.tsx diff --git a/package.json b/package.json index 1568e7b7..bd0de861 100644 --- a/package.json +++ b/package.json @@ -96,6 +96,7 @@ "mobx": "^6.13.3", "mobx-react-lite": "^4.0.7", "motion": "^11.13.1", + "music-metadata": "^10.6.4", "ncp": "^2.0.0", "next": "14.2.10", "next-auth": "^4.24.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3cf7be8b..376a2b99 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -206,6 +206,9 @@ importers: motion: specifier: ^11.13.1 version: 11.13.1(@emotion/is-prop-valid@1.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + music-metadata: + specifier: ^10.6.4 + version: 10.6.4 ncp: specifier: ^2.0.0 version: 2.0.0 @@ -3914,6 +3917,9 @@ packages: '@tanstack/virtual-core@3.10.9': resolution: {integrity: sha512-kBknKOKzmeR7lN+vSadaKWXaLS0SZZG+oqpQ/k80Q6g9REn6zRHS/ZYdrIzHnpHgy/eWs00SujveUN/GJT2qTw==} + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@tootallnate/once@1.1.2': resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} engines: {node: '>= 6'} @@ -4803,6 +4809,10 @@ packages: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + conventional-changelog-angular@8.0.0: resolution: {integrity: sha512-CLf+zr6St0wIxos4bmaKHRXWAcsCXrJU6F4VdNDrGRK3B8LDLKoX3zuMV5GhtbGkVR/LohZ6MT6im43vZLSjmA==} engines: {node: '>=18'} @@ -5602,6 +5612,10 @@ packages: resolution: {integrity: sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==} engines: {node: '>= 12'} + file-type@19.6.0: + resolution: {integrity: sha512-VZR5I7k5wkD0HgFnMsq5hOsSc710MJMu5Nc5QYsbe38NN5iPV/XTObYLc/cpttRTf6lX538+5uO1ZQRhYibiZQ==} + engines: {node: '>=18'} + file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} @@ -6625,6 +6639,10 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + link@2.1.1: + resolution: {integrity: sha512-NV3AUVYBovJ6eVQcTeRoPnZSxzt2LOijNd+ugEZKRy/XeQlpTRhVRkuDv5kOlXwMAUx30vfUc7asRFb9RT65yg==} + hasBin: true + linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} @@ -6898,6 +6916,10 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + memfs@3.5.3: resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} engines: {node: '>= 4.0.0'} @@ -7172,6 +7194,10 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + music-metadata@10.6.4: + resolution: {integrity: sha512-42ekQ5CRic4Pvw/85FfzMKegeRDHyWBpCjSSI1B9PTGqaevZ17ASA4v4W6MRq1ELC5THn5rD8S+82iPQ6gv6lw==} + engines: {node: '>=16.0.0'} + mustache@4.2.0: resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} hasBin: true @@ -7725,6 +7751,10 @@ packages: resolution: {integrity: sha512-v6ZJ/efsBpGrGGknjtq9J/oC8tZWq0KWL5vQrk2GlzLEQPUDB1ex+13Rmidl1neNN358Jn9EHZw5y07FFtaC7A==} engines: {node: '>=6.8.1'} + peek-readable@5.3.1: + resolution: {integrity: sha512-GVlENSDW6KHaXcd9zkZltB7tCLosKB/4Hg0fqBJkAoBgYG2Tn1xtMgXtSUuMU9AK/gCm/tTdT8mgAeF4YNeeqw==} + engines: {node: '>=14.16'} + pg-cloudflare@1.1.1: resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} @@ -9067,6 +9097,14 @@ packages: strnum@1.0.5: resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + strtok3@10.0.1: + resolution: {integrity: sha512-7OOJepVlvlcgjW/fLNCsIqpNleAoi1y0LTRWGnOpABOSpRmw+65HvnruoOCnjpaQ1efnlYpQ/JwHKuaombnuXQ==} + engines: {node: '>=16'} + + strtok3@9.1.1: + resolution: {integrity: sha512-FhwotcEqjr241ZbjFzjlIYg6c5/L/s4yBGWSMvJ9UoExiSqL+FnFA/CaeZx17WGaZMS/4SOZp8wH18jSS4R4lw==} + engines: {node: '>=16'} + style-inject@0.3.0: resolution: {integrity: sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==} @@ -9278,6 +9316,10 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + token-types@6.0.0: + resolution: {integrity: sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==} + engines: {node: '>=14.16'} + totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} @@ -9477,6 +9519,10 @@ packages: engines: {node: '>=0.8.0'} hasBin: true + uint8array-extras@1.4.0: + resolution: {integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==} + engines: {node: '>=18'} + unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} @@ -11388,7 +11434,7 @@ snapshots: '@babel/parser': 7.25.8 '@babel/template': 7.25.7 '@babel/types': 7.25.8 - debug: 4.3.7 + debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -15318,6 +15364,8 @@ snapshots: '@tanstack/virtual-core@3.10.9': {} + '@tokenizer/token@0.3.0': {} + '@tootallnate/once@1.1.2': optional: true @@ -15714,14 +15762,14 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.3.7 + debug: 4.4.0 transitivePeerDependencies: - supports-color optional: true agent-base@7.1.1: dependencies: - debug: 4.3.7 + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -16289,6 +16337,8 @@ snapshots: dependencies: safe-buffer: 5.2.1 + content-type@1.0.5: {} + conventional-changelog-angular@8.0.0: dependencies: compare-func: 2.0.0 @@ -17177,6 +17227,13 @@ snapshots: dependencies: tslib: 2.8.0 + file-type@19.6.0: + dependencies: + get-stream: 9.0.1 + strtok3: 9.1.1 + token-types: 6.0.0 + uint8array-extras: 1.4.0 + file-uri-to-path@1.0.0: {} filelist@1.0.4: @@ -17727,7 +17784,7 @@ snapshots: dependencies: '@tootallnate/once': 1.1.2 agent-base: 6.0.2 - debug: 4.3.7 + debug: 4.4.0 transitivePeerDependencies: - supports-color optional: true @@ -17751,7 +17808,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.7 + debug: 4.4.0 transitivePeerDependencies: - supports-color optional: true @@ -18271,6 +18328,8 @@ snapshots: lines-and-columns@1.2.4: {} + link@2.1.1: {} + linkify-it@5.0.0: dependencies: uc.micro: 2.1.0 @@ -18687,6 +18746,8 @@ snapshots: media-typer@0.3.0: {} + media-typer@1.1.0: {} + memfs@3.5.3: dependencies: fs-monkey: 1.0.6 @@ -18910,7 +18971,7 @@ snapshots: micromark@4.0.0: dependencies: '@types/debug': 4.1.12 - debug: 4.3.7 + debug: 4.4.0 decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.1 @@ -19058,6 +19119,20 @@ snapshots: ms@2.1.3: {} + music-metadata@10.6.4: + dependencies: + '@tokenizer/token': 0.3.0 + content-type: 1.0.5 + debug: 4.4.0 + file-type: 19.6.0 + link: 2.1.1 + media-typer: 1.1.0 + strtok3: 10.0.1 + token-types: 6.0.0 + uint8array-extras: 1.4.0 + transitivePeerDependencies: + - supports-color + mustache@4.2.0: {} mz@2.7.0: @@ -19544,6 +19619,8 @@ snapshots: transitivePeerDependencies: - supports-color + peek-readable@5.3.1: {} + pg-cloudflare@1.1.1: optional: true @@ -20887,7 +20964,7 @@ snapshots: socks-proxy-agent@6.2.1: dependencies: agent-base: 6.0.2 - debug: 4.3.7 + debug: 4.4.0 socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -21074,6 +21151,16 @@ snapshots: strnum@1.0.5: {} + strtok3@10.0.1: + dependencies: + '@tokenizer/token': 0.3.0 + peek-readable: 5.3.1 + + strtok3@9.1.1: + dependencies: + '@tokenizer/token': 0.3.0 + peek-readable: 5.3.1 + style-inject@0.3.0: {} style-to-object@1.0.8: @@ -21354,6 +21441,11 @@ snapshots: toidentifier@1.0.1: {} + token-types@6.0.0: + dependencies: + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + totalist@3.0.1: {} tough-cookie@4.1.4: @@ -21533,6 +21625,8 @@ snapshots: uglify-js@3.19.3: optional: true + uint8array-extras@1.4.0: {} + unbox-primitive@1.0.2: dependencies: call-bind: 1.0.7 diff --git a/public/locales/ar/translation.json b/public/locales/ar/translation.json index 4f1e51df..f8ddd1f5 100644 --- a/public/locales/ar/translation.json +++ b/public/locales/ar/translation.json @@ -1,353 +1,4 @@ { - "hello": "مرحبًا", - "blinko": "بلينكو", - "notes": "ملاحظات", - "resources": "الموارد", - "archived": "المؤرشفة", - "settings": "الإعدادات", - "total-tags": "إجمالي العلامات", - "search": "بحث...", - "i-have-a-new-idea": "لدي فكرة جديدة...", - "note": "ملاحظة", - "edit": "تعديل", - "multiple-select": "اختيار متعدد", - "convert-to": "تحويل إلى", - "delete": "حذف", - "recovery": "استعادة", - "archive": "أرشفة", - "items": "عناصر", - "your-changes-have-been-saved": "تم حفظ التغييرات!", - "operation-failed": "فشلت العملية.", - "in-progress": "قيد التنفيذ...", - "confirm-to-delete": "تأكيد الحذف!", - "this-operation-removes-the-associated-label-and-cannot-be-restored-please-confirm": "هذه العملية ستزيل التصنيف المرتبط ولن يمكن استعادته. يرجى التأكيد", - "add-tag": "إضافة علامة", - "cancel": "إلغاء", - "confirm": "تأكيد", - "no-data-here-well-then-time-to-write-a-note": "لا توجد بيانات هنا؟ إذن حان الوقت لكتابة ملاحظة!", - "basic-information": "معلومات أساسية", - "name": "الاسم", - "preference": "التفضيل", - "theme": "السمة", - "language": "اللغة", - "change-type": "تغيير النوع", - "insert-hashtag": "إدراج وسم", - "bulleted-list": "قائمة نقطية", - "numbered-list": "قائمة مرقمة", - "check-list": "قائمة التحقق", - "insert-table": "إدراج جدول", - "insert-codeblock": "إدراج كتلة كود", - "insert-sandpack": "إدراج حزمة الرمل", - "upload-file": "رفع ملف", - "delete-confirm": "تأكيد الحذف", - "this-operation-will-be-delete-resource-are-you-sure": "سيتم حذف المورد. هل أنت متأكد؟", - "delete-success": "تم الحذف بنجاح", - "update-successfully": "تم التحديث بنجاح", - "create-successfully": "تم الإنشاء بنجاح", - "total": "الإجمالي", - "all-notes-have-been-loaded": "تم تحميل جميع {{items}} الملاحظات", - "hi-user-name-i-can-search-for-the-notes-for-you-how-can-i-help-you-today": "مرحبًا {{name}}! يمكنني البحث عن الملاحظات لك، كيف يمكنني مساعدتك اليوم؟", - "ask-about-your-notes": "اسأل عن ملاحظاتك", - "use-ai": "استخدام الذكاء الاصطناعي", - "model-provider": "مزود الخدمة", - "api-endpoint": "نقطة نهاية API", - "must-start-with-http-s-or-use-api-openai-as-default": "يجب أن يبدأ بـ ://http(s) أو استخدام /api/openai كإعداد افتراضي", - "user-custom-openai-api-key": "مفتاح واجهة برمجة التطبيقات المخصص للمستخدم من OpenAI", - "user-custom-azureopenai-api-instance": "اسم مثيل Azure OpenAI", - "user-custom-azureopenai-api-deployment": "اسم نشر Azure OpenAI", - "user-custom-azureopenai-api-version": "نسخة API", - "ai-model": "نموذج الذكاء الاصطناعي", - "logout": "تسجيل الخروج", - "user-or-password-error": "خطأ في اسم المستخدم أو كلمة المرور", - "username": "اسم المستخدم", - "enter-your-name": "أدخل اسمك", - "password": "كلمة المرور", - "enter-your-password": "أدخل كلمة المرور", - "need-to-create-an-account": "هل تحتاج إلى إنشاء حساب؟", - "sign-up": "التسجيل", - "sign-in": "تسجيل الدخول", - "nickname": "اللقب", - "change-user-info": "تغيير معلومات المستخدم", - "rest-user-password": "إعادة تعيين كلمة مرور المستخدم", - "confirm-password": "تأكيد كلمة المرور", - "confirm-your-password": "أكد كلمة المرور", - "enter-your-username": "أدخل اسم المستخدم", - "save": "حفظ", - "keep-sign-in": "البقاء مسجلًا", - "recording": "تسجيل", - "required-items-cannot-be-empty": "العناصر المطلوبة لا يمكن أن تكون فارغة", - "the-two-passwords-are-inconsistent": "كلمتا المرور غير متطابقتين", - "create-successfully-is-about-to-jump-to-the-login": "تم الإنشاء بنجاح، سيتم التحويل إلى صفحة تسجيل الدخول", - "already-have-an-account-direct-login": "هل لديك حساب بالفعل؟ تسجيل الدخول مباشرة", - "no-tag-found": "لم يتم العثور على علامة", - "new-version-detected-click-to-get-the-latest-version": "🎉 تم اكتشاف إصدار جديد، اضغط للحصول على أحدث إصدار", - "schedule-task": "جدولة المهام", - "schedule-back-up": "جدولة النسخ الاحتياطي", - "every-day": "كل يوم", - "every-week": "كل أسبوع", - "every-month": "كل شهر", - "every-three-month": "كل ثلاثة أشهر", - "every-half-year": "كل نصف عام", - "import": "استيراد", - "impoort-from-bko": "استيراد من ملف.bko", - "not-a-bko-file": "ليس ملف .bko", - "convert-to-note": "تحويل إلى ملاحظة", - "convert-to-blinko": "تحويل إلى بلينكو", - "reviewed": "تمت المراجعة", - "congratulations-youve-reviewed-everything-today": "تهانينا، لقد راجعت كل شيء اليوم.", - "name-db": "الاسم", - "schedule": "الجدولة", - "last-run": "آخر تشغيل", - "backup-file": "ملف النسخ الاحتياطي", - "status": "الحالة", - "running": "قيد التشغيل", - "stopped": "متوقف", - "show-navigation-bar-on-mobile": "إخفاء شريط التنقل على الجوال", - "schedule-archive-blinko": "جدولة أرشفة بلينكو", - "there-are-no-resources-yet-go-upload-them-now": "لا توجد موارد حتى الآن، قم برفعها الآن", - "confrim": "تأكيد", - "daily-review": "مراجعة يومية", - "detail": "التفاصيل", - "enter-send-shift-enter-for-new-line": "إدخال للإرسال، Shift+Enter لسطر جديد", - "show-less": "عرض أقل", - "show-more": "عرض المزيد", - "top": "أعلى", - "cancel-top": "إلغاء التثبيت", - "created-in": "تم الإنشاء في", - "set-as-public": "تعيين كعام", - "unset-as-public": "إلغاء التعيين كعام", - "with-link": "برابط", - "no-tag": "بدون علامة", - "has-file": "يتضمن ملفًا", - "created-at": "تم الإنشاء في", - "updated-at": "تم التحديث في", - "role": "الدور", - "user-list": "قائمة المستخدمين", - "create-user": "إنشاء مستخدم", - "action": "الإجراء", - "original-password": "كلمة المرور الأصلية", - "edit-user": "تعديل المستخدم", - "import-from-memos-memos_prod-db": "استيراد من قاعدة البيانات(memos_prod.db)", - "when-exporting-memos_prod-db-please-close-the-memos-container-to-avoid-partial-loss-of-data": "عند تصدير memos_prod.db، يرجى إغلاق الحاوية لتجنب فقدان البيانات جزئيًا.", - "allow-register": "السماح بالتسجيل", - "access-token": "رمز الوصول", - "superadmin": "مدير النظام", - "user": "مستخدم", - "select-model-provider": "اختيار مزود النموذج", - "select-model": "اختيار النموذج", - "api-key": "مفتاح API", - "enter-your-api-key": "أدخل مفتاح API الخاص بك", - "delete-only-tag": "حذف العلامة فقط", - "update-name": "تحديث الاسم", - "delete-tag-with-note": "حذف العلامة مع الملاحظة", - "minutes-ago": "منذ {{count}} دقيقة", - "hours-ago": "منذ {{count}} ساعة", - "days-ago": "منذ {{count}} يوم", - "weeks-ago": "منذ {{count}} أسبوع", - "months-ago": "منذ {{count}} شهر", - "years-ago": "منذ {{count}} سنة", - "in-addition-to-the-gpt-model-there-is-a-need-to-ensure-that-it-is-possible-to-invoke-the": "بالإضافة إلى نموذج GPT، هناك حاجة إلى التأكد من إمكانية استدعاء", - "speech-recognition-requires-the-use-of": "يتطلب التعرف على الكلام استخدام", - "ai-expand": "توسيع نطاق الذكاء الاصطناعي", - "ai-polish": "الذكاء الاصطناعي البولندي", - "accept": "قبول", - "reject": "رفض", - "stop": "توقف", - "card-columns": "أعمدة البطاقة", - "select-a-columns": "حدد أعمدة", - "width-less-than-1024px": "العرض أقل من 1024 بكسل", - "width-less-than": "عرض أقل من", - "small-device-card-columns": "أعمدة بطاقة الجهاز الصغيرة", - "medium-device-card-columns": "أعمدة بطاقة الجهاز المتوسطة", - "large-device-card-columns": "أعمدة بطاقة الجهاز الكبيرة", - "device-card-columns": "أعمدة بطاقة الجهاز", - "columns-for-different-devices": "أعمدة للأجهزة المختلفة", - "mobile": "الهاتف المحمول", - "tablet": "جهاز لوحي", - "desktop": "سطح المكتب", - "chars": "الأحرف", - "text-fold-length": "طول طية النص", - "title-first-line-of-the-text": "العنوان (السطر الأول من النص)", - "content-rest-of-the-text-if-the-text-is-longer-than-the-length": "المحتوى(بقية النص، إذا كان النص أطول من الطول)", - "ai-tag": "علامة الذكاء الاصطناعي", - "article": "المادة", - "embedding-model": "نموذج التضمين", - "if-you-have-a-lot-of-notes-you-may-consume-a-certain-number-of-tokens": "إذا كان لديك الكثير من الملاحظات فقد تستهلك عددًا معينًا من الرموز المميزة", - "force-rebuild": "إعادة بناء القوة", - "force-rebuild-embedding-index": "ستؤدي إعادة البناء القسري إلى إعادة بناء جميع البيانات التي تمت فهرستها بالكامل", - "embedding-model-description": "يجب إعادة بناء الفهرس بعد تبديل النماذج المدمجة", - "top-k-description": "الحد الأقصى لعدد المستندات التي تم إرجاعها في النهاية", - "embedding-score-description": "عادة ما تكون عتبة التشابه للاستعلامات هي مجموع المسافة الإقليدية", - "embedding-lambda-description": "معلمة ترجيح تنوع نتائج الاستعلامات", - "update-tag-icon": "أيقونة تحديث العلامة", - "update-tag-name": "تحديث اسم العلامة", - "thinking": "التفكير...", - "select-all": "اختر الكل", - "insert-before": "إدراج قبل", - "insert-after": "إدراج بعد", - "ai-emoji": "الرموز التعبيرية Ai", - "custom-icon": "أيقونة مخصصة", - "ai-enhanced-search": "البحث المحسّن بالذكاء الاصطناعي", - "preview-mode": "وضع المعاينة", - "source-code": "كود المصدر", - "camera": "كاميرا", - "reference": "المرجع", - "reference-note": "مذكرة مرجعية", - "source-code-mode": "وضع شفرة المصدر", - "heading": "العنوان", - "paragraph": "الفقرة", - "quote": "اقتباس", - "bold": "جريئة", - "remove-italic": "إزالة الخط المائل", - "underline": "تسطير", - "italic": "مائل", - "remove-bold": "إزالة الخط العريض", - "remove-underline": "إزالة التسطير", - "select-block-type": "حدد نوع الكتلة", - "block-type-select-placeholder": "نوع المربع", - "trash": "قمامة", - "custom-path": "المسار المخصص", - "page-size": "حجم الصفحة", - "toolbar-visibility": "رؤية شريط الأدوات", - "always-hide-toolbar": "اختبئ دائماً", - "always-show-toolbar": "اعرض دائماً", - "hide-toolbar-on-mobile": "إخفاء على الجوال", - "select-toolbar-visibility": "تحديد رؤية شريط الأدوات", - "select-a-time-format": "حدد تنسيق الوقت", - "enter-code-shown-on-authenticator-app": "أدخل الرمز الظاهر في تطبيق المصادقة", - "open-your-third-party-authentication-app-and-enter-the-codeshown-on-screen": "افتح تطبيق المصادقة التابع لجهة خارجية، وأدخل الرموزالتي تظهر على الشاشة", - "two-factor-authentication": "المصادقة الثنائية", - "scan-this-qr-code-with-your-authenticator-app": "امسح رمز الاستجابة السريعة هذا باستخدام تطبيق المصادقة الخاص بك", - "or-enter-this-code-manually": "أو أدخل هذا الرمز يدوياً:", - "verify": "تحقق", - "about": "نبذة عن", - "upload": "التحميل", - "days": "الأيام", - "bucket": "دلو", - "region": "المنطقة", - "access-key-secret": "مفتاح الوصول السري", - "access-key-id": "معرّف مفتاح الوصول", - "share-and-copy-link": "مشاركة ونسخ الرابط", - "copy-share-link": "نسخ رابط المشاركة", - "endpoint": "نقطة النهاية", - "export-format": "تنسيق التصدير", - "export": "التصدير", - "time-range": "النطاق الزمني", - "all": "الكل", - "exporting": "التصدير...", - "has-image": "لديه صورة", - "has-link": "لديه رابط", - "filter-settings": "إعدادات التصفية", - "tag-status": "حالة العلامة", - "all-notes": "جميع الملاحظات", - "with-tags": "مع العلامات", - "without-tags": "بدون علامات", - "select-tags": "حدد العلامات", - "additional-conditions": "الشروط الإضافية", - "apply-filter": "تطبيق الفلتر", - "to": "إلى", - "start-date": "تاريخ البدء", - "end-date": "تاريخ الانتهاء", - "reset": "إعادة تعيين", - "no-condition": "لا توجد حالة", - "public": "عام", - "ai-model-tooltip": "أدخل اسم الطراز المراد استخدامه، مثل gpt-3.5-turbo، gpt-4، gpt-4o، gpt-4o، gpt-4o-mini", - "user-custom-azureopenai-api-deployment-tooltip": " أدخل اسم النشر المراد استخدامه، مثل gpt-4o", - "ollama-ai-model-tooltip": "أدخل اسم الطراز المراد استخدامه، مثل llama3.2", - "ollama-default-endpoint-is-http-localhost-11434": "نقطة نهاية أولاما الافتراضية هي http://localhost:11434", - "your-azure-openai-instance-name": "اسم مثيل Azure OpenAI الخاص بك", - "ai-generate-emoji": "", - "ai-generating-emoji": "", - "date-range": "", - "2fa-setup-successful": "تم إعداد المصادقة الثنائية بنجاح", - "both": "المحرر والمعاينة", - "code": "كود بلوك", - "copied": "تم النسخ", - "dark-mode": "الوضع الداكن", - "delete-column": "حذف الصف", - "delete-row": "حذف العمود", - "devtools": "أدوات المطورين", - "down": "أسفل", - "download-tip": "لا يدعم المتصفح وظيفة التنزيل", - "edit-mode": "تبديل وضع التحرير", - "emoji": "إيموجي", - "exclude-tag-from-embedding-desc": "حدد علامة لاستبعاد ملاحظاتها المرتبطة من إنشاء النواة التضمينية باستخدام الذكاء الصناعي", - "exclude-tag-from-embedding-tip": "سيتم استبعاد الملاحظات التي تحتوي على هذه العلامة من معالجة تضمين الذكاء الاصطناعي", - "file-type-error": "نوع الملف خاطىء", - "follow-system": "متابعة النظام", - "footnote-ref": "المرجع السفلي", - "fullscreen": "تبديل وضع ملء الشاشة", - "generate": "توليد", - "go-to-share-page": "انتقل إلى صفحة المشاركة", - "heading1": "العنوان ١", - "heading2": "العنوان ٢", - "heading3": "العنوان 3", - "heading4": "العنوان 4", - "heading5": "العنوان 5", - "heading6": "العنوان 6", - "headings": "العناوين", - "help": "مساعدة", - "image-url": "عنوان URL", - "import-done": "تم الاستيراد", - "import-from-bko": "استيراد من .bko", - "indent": "المسافة البادئة", - "info": "معلومات", - "inline-code": "كود مضمن", - "insert-column-left": "ادخل 1 يسار", - "insert-column-right": "أدخل 1 يمين", - "insert-row-above": "أدخل 1 أعلى", - "insert-row-below": "أدخل 1 أسفل", - "instant-rendering": "التقديم الفوري", - "light-mode": "وضع النور", - "line": "خط", - "link": "رابط", - "link-ref": "رابط المرجع", - "list": "قائمة", - "local-file-system": "نظام الملفات المحلي", - "more": "أكثر", - "name-empty": "الاسم فارغ", - "new-version-available": "الإصدار الجديد متاح", - "notes-imported-by-other-means-may-not-have-embedded-vectors": "قد لا تحتوي الملاحظات المستوردة بطرق أخرى على متجهات مضمنة", - "object-storage": "تخزين الكائنات", - "order-by-create-time": "ترتيب حسب وقت الإنشاء", - "ordered-list": "قائمة الطلبات", - "outdent": "نسبة العجز", - "outline": "مخطط/ تفصيلات", - "over": "فوق", - "performance-tip": "المعاينة في الوقت الحقيقي تتطلب ${x} ميلِّ ثانية، يمكنك إغلاقها", - "preview": "معاينة", - "rebuild": "إعادة البناء", - "rebuild-embedding-index": "إعادة بناء فهرس التضمين", - "rebuilding-embedding-progress": "إعادة بناء تقدم التضمين", - "record": "بدء التسجيل / إنهاء التسجيل", - "record-tip": "الجهاز لا يدعم التسجيل", - "redo": "إعادة", - "remove": "إزالة", - "row": "صف", - "spin": "الدوران", - "split-view": "تقسيم العرض", - "storage": "تخزين", - "strike": "ضربة", - "table": "الطاولة", - "text-is-not-empty": "النص (غير فارغ)", - "time-format": "تنسيق الوقت", - "title": "العنوان", - "tooltip-text": "نص التلميح", - "undo": "تراجع", - "up": "فوق", - "update": "تحديث", - "upload-error": "خطأ في التحميل", - "uploading": "جاري التحميل...", - "version": "الإصدار", - "wysiwyg": "ما تراه هو ما تحصل عليه", - "search-tags": "البحث عن العلامات", - "insert-attachment-or-note": "الإرفاق بملف أو المذكرة؟", - "context": "السياق", - "paste-to-note-or-attachment": "هل أنت متأكد من لصق النص في السياق أو المرفق؟", - "attachment": "المرفق", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "بعد الحذف، سيتم مسح جميع بيانات المستخدم ولن يمكن استرجاعها.", - "upload-completed": "تم الرفع بنجاح", - "upload-cancelled": "تم إلغاء التحميل", - "upload-failed": "فشل التحميل", - "import-from-bko-tip": "تحميل إلى s3 للإسترداد غير مدعوم في الوقت الحالي. يُرجى تعطيل الخيار s3 مؤقتًا عند رغبتك في الاسترداد." + "spotify-consumer-key-tip": "كان يُستخدم للحصول على غلاف موسيقى mp3", + "spotify-consumer-key-tip-2": "احصل على مفتاح API من https://developer.spotify.com/" } diff --git a/public/locales/de/translation.json b/public/locales/de/translation.json index f4cc24f3..eaf5a837 100644 --- a/public/locales/de/translation.json +++ b/public/locales/de/translation.json @@ -1,340 +1,4 @@ { - "blinko": "Blinko", - "notes": "Anmerkungen", - "resources": "Ressourcen", - "archived": "Archiviert", - "settings": "Einstellungen", - "total-tags": "TOTAL TAGS", - "search": "Suche...", - "i-have-a-new-idea": "Ich habe eine neue Idee...", - "add-tag": "Tag hinzufügen", - "all-notes-have-been-loaded": "Alle {{Items}} Notizen wurden geladen", - "already-have-an-account-direct-login": "Sie haben bereits ein Konto? Direkt anmelden", - "api-endpoint": "API-Endpunkt", - "archive": "Archiv", - "ask-about-your-notes": "Fragen Sie nach Ihren Notizen", - "backup-file": "SICHERUNGSDATEI", - "basic-information": "Grundlegende Informationen", - "bulleted-list": "Aufzählungsliste", - "cancel": "Abbrechen", - "cancel-top": "Abbrechen oben", - "change-type": "Typ ändern", - "change-user-info": "Benutzerinformationen ändern", - "check-list": "Checkliste", - "confirm": "Bestätigen Sie", - "confirm-password": "Bestätigen Sie Ihr Passwort", - "convert-to": "Umrechnen in", - "convert-to-blinko": "Zu Blinko konvertieren", - "convert-to-note": "In Note umwandeln", - "create-successfully": "Erfolgreich erstellen", - "create-successfully-is-about-to-jump-to-the-login": "Erfolgreich erstellen, springt gleich zum Login", - "daily-review": "Tägliche Überprüfung", - "delete": "Löschen", - "delete-confirm": "Löschen Bestätigen", - "delete-success": "Erfolgreich löschen", - "edit": "bearbeiten", - "enter-your-name": "Geben Sie Ihren Namen ein", - "enter-your-password": "Geben Sie Ihr Passwort ein", - "enter-your-username": "Geben Sie Ihren Benutzernamen ein", - "every-half-year": "Jedes halbe Jahr", - "every-month": "Jeden Monat", - "hello": "hallo", - "hi-user-name-i-can-search-for-the-notes-for-you-how-can-i-help-you-today": "Hallo {{Name}}, ich kann die Notizen für Sie suchen, wie kann ich Ihnen heute helfen?", - "import-from-bko": "Importieren von .bko", - "import": "Importieren", - "insert-hashtag": "Hashtag einfügen", - "items": "Artikel", - "language": "Sprache", - "logout": "Abmeldung", - "multiple-select": "Mehrfachauswahl", - "name": "Name", - "name-db": "NAME", - "need-to-create-an-account": "Möchten Sie ein Konto erstellen?", - "new-version-detected-click-to-get-the-latest-version": "🎉Neue Version entdeckt, klicken Sie, um die neueste Version zu erhalten", - "nickname": "Spitzname", - "no-data-here-well-then-time-to-write-a-note": "Keine Daten hier? Dann wird es Zeit, eine Notiz zu schreiben!", - "no-tag-found": "Kein Tag gefunden", - "not-a-bko-file": "keine bko-Datei", - "note": "Hinweis", - "numbered-list": "Nummerierte Liste", - "operation-failed": "Operation fehlgeschlagen.", - "password": "Passwort", - "preference": "Präferenz", - "recording": "Aufnahme", - "required-items-cannot-be-empty": "Erforderliche Elemente können nicht leer sein", - "rest-user-password": "Restliches Benutzerpasswort", - "running": "Laufen", - "save": "Speichern Sie", - "schedule-archive-blinko": "Zeitplan Archiv Blinko", - "schedule-back-up": "Zeitplan für Back-up", - "schedule-task": "Zeitplan Aufgabe", - "show-less": "Weniger anzeigen", - "show-more": "Mehr anzeigen", - "show-navigation-bar-on-mobile": "Ausgeblendete Navigationsleiste auf dem Handy", - "sign-in": "Eintragen", - "sign-up": "Anmeldung", - "status": "STATUS", - "stopped": "Gestoppt", - "the-two-passwords-are-inconsistent": "Die beiden Kennwörter sind inkonsistent", - "theme": "Thema", - "there-are-no-resources-yet-go-upload-them-now": "Es sind noch keine Ressourcen vorhanden, laden Sie sie jetzt hoch", - "this-operation-removes-the-associated-label-and-cannot-be-restored-please-confirm": "Bei diesem Vorgang wird das zugehörige Etikett entfernt und kann nicht wiederhergestellt werden.", - "this-operation-will-be-delete-resource-are-you-sure": "Sind Sie sicher, dass es sich bei diesem Vorgang um das Löschen von Ressourcen handelt?", - "top": "Top", - "total": "Insgesamt", - "update-successfully": "Erfolgreich aktualisieren", - "upload-file": "Datei hochladen", - "use-ai": "Ai verwenden", - "user-custom-openai-api-key": "Benutzerdefinierter OpenAI Api-Schlüssel", - "user-custom-azureopenai-api-instance": "Azure OpenAI Instanzname", - "user-custom-azureopenai-api-deployment": "Azure OpenAI Bereitstellungsname", - "user-custom-azureopenai-api-version": "API version", - "user-or-password-error": "Benutzer- oder Passwortfehler", - "username": "Nutzername", - "your-changes-have-been-saved": "Ihre Änderungen wurden gespeichert!", - "confirm-your-password": "Bestätigen Sie Ihr Passwort", - "confrim": "Bestätigen Sie", - "every-day": "Jeden Tag", - "every-three-month": "Alle drei Monate", - "every-week": "Jede Woche", - "insert-sandpack": "Sandpäckchen einlegen", - "insert-table": "Tabelle einfügen", - "schedule": "SCHEDULE", - "ai-model": "AI-Modell", - "confirm-to-delete": "Bestätigen Sie die Löschung!", - "congratulations-youve-reviewed-everything-today": "Sie haben heute alles durchgesehen.", - "detail": "Einzelheiten", - "enter-send-shift-enter-for-new-line": "Enter senden, Shift+Enter für neue Zeile", - "in-progress": "In Arbeit...", - "insert-codeblock": "CodeBlock einfügen", - "keep-sign-in": "Anmeldung beibehalten", - "last-run": "LETZTER LAUF", - "model-provider": "Modell-Anbieter", - "must-start-with-http-s-or-use-api-openai-as-default": "Muss mit http(s):// beginnen oder /api/openai als Standard verwenden", - "recovery": "Erholung", - "reviewed": "Überprüft", - "created-in": "Erstellt in", - "set-as-public": "Als öffentlich festlegen", - "unset-as-public": "Nicht als öffentlich gekennzeichnet", - "no-tag": "Keine Markierung", - "with-link": "Mit Link", - "has-file": "Hat Datei", - "created-at": "Erstellen am", - "role": "Rolle", - "create-user": "Benutzer erstellen", - "action": "Aktion", - "original-password": "Original-Passwort", - "import-from-memos-memos_prod-db": "Import aus Memos(memos_prod.db)", - "when-exporting-memos_prod-db-please-close-the-memos-container-to-avoid-partial-loss-of-data": "Wenn Sie memos_prod.db exportieren, schließen Sie bitte den Memos-Container, um einen teilweisen Datenverlust zu vermeiden.", - "go-to-share-page": "Zur Freigabeseite gehen", - "import-done": "Import abgeschlossen", - "rebuilding-embedding-progress": "Wiederaufbau Einbettung des Fortschritts", - "rebuild": "Wiederherstellen", - "notes-imported-by-other-means-may-not-have-embedded-vectors": "Auf anderem Wege importierte Noten haben möglicherweise keine eingebetteten Vektoren", - "if-you-have-a-lot-of-notes-you-may-consume-a-certain-number-of-tokens": "Wenn Sie viele Scheine haben, können Sie eine bestimmte Anzahl von Token verbrauchen.", - "time-format": "Zeitformat", - "version": "Version", - "new-version-available": "Neue Version verfügbar", - "storage": "Lagerung", - "local-file-system": "Lokales Dateisystem", - "object-storage": "Speicherung von Objekten", - "in-addition-to-the-gpt-model-there-is-a-need-to-ensure-that-it-is-possible-to-invoke-the": "Zusätzlich zum GPT-Modell muss sichergestellt werden, dass es möglich ist, die", - "speech-recognition-requires-the-use-of": "Die Spracherkennung erfordert die Verwendung von", - "ai-expand": "AI Erweitern", - "ai-polish": "AI Polnisch", - "accept": "Akzeptieren", - "reject": "Ablehnen", - "stop": "Stopp", - "card-columns": "Kartenspalten", - "select-a-columns": "Wählen Sie eine Spalte", - "width-less-than-1024px": "Breite weniger als 1024px", - "width-less-than": "Breite weniger als", - "small-device-card-columns": "Spalten für kleine Gerätekarten", - "medium-device-card-columns": "Medium-Gerätekarten-Spalten", - "large-device-card-columns": "Große Gerätekartenspalten", - "device-card-columns": "Spalten der Gerätekarte", - "columns-for-different-devices": "Säulen für verschiedene Geräte", - "mobile": "Mobil", - "tablet": "Tablette", - "desktop": "Schreibtisch", - "chars": "Zeichen", - "text-fold-length": "Text Falzlänge", - "title-first-line-of-the-text": "Titel (erste Zeile des Textes)", - "content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Inhalt (Rest des Textes, wenn der Text länger als die Länge ist)", - "ai-tag": "AI-Tag", - "article": "Artikel", - "embedding-model": "Einbettungsmodell", - "force-rebuild": "Force Rebuild", - "force-rebuild-embedding-index": "Erzwungener Neuaufbau stellt alle Daten wieder her, die vollständig indiziert wurden.", - "embedding-model-description": "Der Index muss nach einem Wechsel des eingebetteten Modells neu aufgebaut werden", - "top-k-description": "Maximale Anzahl von Dokumenten, die zurückgegeben werden", - "embedding-score-description": "Die Ähnlichkeitsschwelle für Abfragen ist im Allgemeinen der euklidische Summenabstand", - "embedding-lambda-description": "Abfrageergebnis Diversität Gewichtungsparameter", - "update-tag-icon": "Tag-Symbol aktualisieren", - "delete-only-tag": "Nur Tag löschen", - "delete-tag-with-note": "Tag mit Notiz löschen", - "update-tag-name": "Tag-Name aktualisieren", - "thinking": "Ich denke...", - "select-all": "Alle auswählen", - "insert-before": "Einfügen vor", - "insert-after": "Einfügen nach", - "update-name": "Update Name", - "ai-emoji": "Ai-Emoji", - "custom-icon": "Benutzerdefinierte Ikone", - "ai-enhanced-search": "AI-erweiterte Suche", - "preview-mode": "Vorschau-Modus", - "source-code": "Quellcode", - "camera": "Kamera", - "reference": "Referenz", - "reference-note": "Referenz-Notiz", - "source-code-mode": "Quellcode-Modus", - "heading": "Überschrift", - "paragraph": "Absatz", - "quote": "Zitat", - "bold": "Kühn", - "remove-italic": "Kursivschrift entfernen", - "underline": "Unterstreichen Sie", - "italic": "Kursiv", - "remove-bold": "Fettdruck entfernen", - "remove-underline": "Unterstrich entfernen", - "select-block-type": "Blocktyp auswählen", - "block-type-select-placeholder": "Block Typ", - "trash": "Müll", - "page-size": "Größe der Seite", - "toolbar-visibility": "Sichtbarkeit der Symbolleiste", - "always-hide-toolbar": "Immer verstecken", - "always-show-toolbar": "Immer anzeigen", - "hide-toolbar-on-mobile": "Auf dem Handy ausblenden", - "select-toolbar-visibility": "Sichtbarkeit der Symbolleiste auswählen", - "select-a-time-format": "Wählen Sie ein Zeitformat", - "enter-code-shown-on-authenticator-app": "Code eingeben, der in der Authenticator-App angezeigt wird", - "open-your-third-party-authentication-app-and-enter-the-codeshown-on-screen": "Öffnen Sie die Authentifizierungs-App eines Drittanbieters und geben Sie die auf dem Bildschirm angezeigten Codes ein.", - "two-factor-authentication": "Zwei-Faktoren-Authentifizierung", - "scan-this-qr-code-with-your-authenticator-app": "Scannen Sie diesen QR-Code mit Ihrer Authenticator-App", - "or-enter-this-code-manually": "Oder geben Sie diesen Code manuell ein:", - "verify": "Überprüfen Sie", - "about": "Über", - "upload": "Hochladen", - "days": "Tage", - "select-model-provider": "Modellanbieter auswählen", - "allow-register": "Register zulassen", - "access-token": "Zugangs-Token", - "bucket": "Eimer", - "region": "Region", - "access-key-secret": "Zugangsschlüssel geheim", - "access-key-id": "Zugangsschlüssel id", - "share-and-copy-link": "Link teilen und kopieren", - "copy-share-link": "Link zur Freigabe kopieren", - "endpoint": "Endpunkt", - "export-format": "Format exportieren", - "export": "Exportieren", - "time-range": "Zeitspanne", - "all": "Alle", - "exporting": "Exportieren...", - "has-image": "Hat Image", - "has-link": "Hat Link", - "filter-settings": "Filter-Einstellungen", - "tag-status": "Tag Status", - "all-notes": "Alle Anmerkungen", - "with-tags": "Mit Tags", - "without-tags": "Ohne Tags", - "select-tags": "Tags auswählen", - "additional-conditions": "Zusätzliche Bedingungen", - "apply-filter": "Filter anwenden", - "to": "An", - "start-date": "Datum des Beginns", - "end-date": "Enddatum", - "reset": "Zurücksetzen", - "no-condition": "Keine Bedingung", - "public": "Öffentlich", - "ai-model-tooltip": "Geben Sie den zu verwendenden Modellnamen ein, z. B. gpt-3.5-turbo, gpt-4, gpt-4o, gpt-4o-mini", - "user-custom-azureopenai-api-deployment-tooltip": " Geben Sie den zu verwendenden Einsatznamen ein, z. B. gpt-4o", - "ollama-ai-model-tooltip": "Geben Sie den zu verwendenden Modellnamen ein, z. B. llama3.2", - "ollama-default-endpoint-is-http-localhost-11434": "Der Standard-Endpunkt von Ollama ist http://localhost:11434.", - "your-azure-openai-instance-name": "Der Name Ihrer Azure OpenAI-Instanz", - "ai-generate-emoji": "", - "ai-generating-emoji": "", - "api-key": "", - "date-range": "", - "days-ago": "", - "enter-your-api-key": "", - "hours-ago": "", - "impoort-from-bko": "", - "minutes-ago": "", - "months-ago": "", - "superadmin": "", - "user": "", - "weeks-ago": "", - "years-ago": "", - "both": "Editor & Vorschau", - "code": "Code-Block", - "column": "Spalte", - "content-theme": "Vorschau des Inhaltsdesigns", - "dark-mode": "Dunkelmodus", - "delete-column": "Zeile löschen", - "delete-row": "Spalte löschen", - "down": "Nach unten", - "download-tip": "Der Browser unterstützt die Download-Funktion nicht.", - "edit-mode": "Umschalten in den Bearbeitungsmodus", - "edit-user": "Benutzer bearbeiten", - "emoji": "Emoji\n\nEmoji", - "exclude-tag-from-embedding": "Schließen Sie markierten Inhalt aus.", - "exclude-tag-from-embedding-desc": "Wählen Sie ein Tag aus, um die zugehörigen Notizen von der Generierung des KI-Einbettungsvektors auszuschließen.", - "exclude-tag-from-embedding-tip": "Notizen mit diesem Tag werden von der KI-Einbettungsverarbeitung ausgeschlossen.", - "file-type-error": "Dateityp ist fehlerhaft", - "follow-system": "Folgen Sie dem System.", - "footnote-ref": "Fußnotenverweis", - "fullscreen": "Vollbild umschalten", - "generate": "Generieren", - "heading1": "Überschrift 1", - "heading2": "Überschrift 2", - "heading3": "Überschrift 3", - "heading4": "Überschrift 4", - "heading5": "Überschrift 5", - "heading6": "Überschrift 6", - "headings": "Überschriften", - "help": "Hilfe", - "image-url": "Bild-URL", - "indent": "Einzug", - "info": "Informationen", - "inline-code": "Inline-Code", - "insert-column-left": "Fügen Sie 1 links ein.", - "insert-column-right": "Fügen Sie 1 richtig ein.", - "insert-row-above": "Fügen Sie 1 oben ein", - "insert-row-below": "Fügen Sie unten die 1 ein.", - "instant-rendering": "Echtzeit-Rendering", - "light-mode": "Hellmodus", - "line": "Linie", - "link": "Verbindung", - "link-ref": "Link-Verweis", - "list": "Liste", - "more": "Mehr", - "name-empty": "Der Name ist leer", - "order-by-create-time": "Sortieren nach Erstellungszeit", - "ordered-list": "Bestellliste", - "outdent": "Ausrücken", - "outline": "Gliederung", - "over": "über", - "performance-tip": "Echtzeitvorschau benötigt ${x}ms, du kannst sie schließen.", - "preview": "Vorschau", - "rebuild-embedding-index": "Erstellen Sie den Einbettungsindex neu", - "record": "Startaufnahme/Endaufnahme", - "record-tip": "Das Gerät unterstützt keine Aufzeichnung.", - "redo": "Neu machen", - "remove": "Entfernen", - "row": "Reihe", - "spin": "Drehen", - "split-view": "geteilte Ansicht", - "strike": "Schlag", - "table": "Tisch", - "search-tags": "Suchbegriffe", - "insert-attachment-or-note": "In Anhang oder Notiz einfügen?", - "context": "Kontext", - "paste-to-note-or-attachment": "Sind Sie sicher, dass Sie in den Kontext oder als Anhang einfügen möchten?", - "attachment": "Anhang", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Nach dem Löschen werden alle Benutzerdaten gelöscht und können nicht wiederhergestellt werden.", - "upload-completed": "Hochladen abgeschlossen", - "upload-cancelled": "Upload abgebrochen", - "upload-failed": "Upload fehlgeschlagen", - "import-from-bko-tip": "Das Hochladen zur Wiederherstellung auf S3 wird derzeit nicht unterstützt. Deaktivieren Sie die S3-Option vorübergehend, wenn Sie eine Wiederherstellung durchführen möchten." + "spotify-consumer-key-tip": "Verwendet, um MP3-Musikcover zu erhalten.", + "spotify-consumer-key-tip-2": "Holen Sie sich den API-Schlüssel von https://developer.spotify.com/" } diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 4fe986a9..adf4f899 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -347,5 +347,12 @@ "upload-completed": "Upload completed", "upload-cancelled": "Upload cancelled", "upload-failed": "Upload Failed", - "import-from-bko-tip": "Uploading to s3 for recovery is not supported at this time. Please disable the s3 option temporarily when you want to recover." + "import-from-bko-tip": "Uploading to s3 for recovery is not supported at this time. Please disable the s3 option temporarily when you want to recover.", + "music-settings": "Music Settings", + "spotify-consumer-key": "Spotify API Key", + "spotify-consumer-secret": "Spotify API Secret", + "enter-spotify-consumer-key": "Enter Spotify API Key", + "enter-spotify-consumer-secret": "Enter Spotify Consumer Secret", + "spotify-consumer-key-tip": "Used to get mp3 music cover", + "spotify-consumer-key-tip-2": "Get API Key from https://developer.spotify.com/" } diff --git a/public/locales/es/translation.json b/public/locales/es/translation.json index aa83d75a..714f4431 100644 --- a/public/locales/es/translation.json +++ b/public/locales/es/translation.json @@ -1,331 +1,4 @@ { - "blinko": "Blinko", - "notes": "Notas", - "resources": "Recursos", - "archived": "Archivado", - "settings": "Ajustes", - "total-tags": "TOTAL TAGS", - "search": "Busca...", - "i-have-a-new-idea": "Tengo una nueva idea...", - "add-tag": "Añadir etiqueta", - "ai-model": "Modelo de IA", - "already-have-an-account-direct-login": "¿Ya tiene una cuenta? Acceso directo", - "api-endpoint": "Punto final de la API", - "archive": "Archivo", - "backup-file": "ARCHIVO DE COPIA DE SEGURIDAD", - "change-type": "Tipo de cambio", - "confirm": "Confirme", - "confirm-password": "Confirmar contraseña", - "confirm-to-delete": "¡Confirmar para borrar!", - "confirm-your-password": "Confirme su contraseña", - "confrim": "Confirme", - "create-successfully-is-about-to-jump-to-the-login": "Crear con éxito, está a punto de saltar a la entrada", - "daily-review": "Análisis diario", - "delete": "Borrar", - "delete-confirm": "Borrar Confirmar", - "delete-success": "Borrar con éxito", - "detail": "Detalle", - "edit": "Editar", - "enter-your-name": "Introduzca su nombre", - "enter-your-password": "Introduzca su contraseña", - "enter-your-username": "Introduzca su nombre de usuario", - "every-day": "Todos los días", - "every-half-year": "Cada semestre", - "every-month": "Todos los meses", - "every-three-month": "Cada tres meses", - "every-week": "Cada semana", - "hello": "hola", - "hi-user-name-i-can-search-for-the-notes-for-you-how-can-i-help-you-today": "Hola {{nombre}}, puedo buscarte las notas, ¿en qué puedo ayudarte hoy?", - "import-from-bko": "Importar desde .bko", - "in-progress": "En curso...", - "insert-codeblock": "Insertar codeBlock", - "insert-hashtag": "Insertar hashtag", - "insert-table": "Insertar tabla", - "items": "artículos", - "keep-sign-in": "Mantener registro", - "multiple-select": "Selección múltiple", - "must-start-with-http-s-or-use-api-openai-as-default": "Debe empezar por http(s):// o utilizar /api/openai por defecto", - "need-to-create-an-account": "¿Necesita crear una cuenta?", - "new-version-detected-click-to-get-the-latest-version": "🎉Nueva versión detectada, haga clic para obtener la última versión", - "nickname": "apodo", - "no-data-here-well-then-time-to-write-a-note": "¿No hay datos aquí? Entonces, ¡es hora de escribir una nota!", - "not-a-bko-file": "no es un archivo bko", - "note": "Nota", - "numbered-list": "Lista numerada", - "operation-failed": "Operación fallida.", - "password": "contraseña", - "recovery": "Recuperación", - "required-items-cannot-be-empty": "Los elementos obligatorios no pueden estar vacíos", - "rest-user-password": "Resto de la contraseña de usuario", - "reviewed": "Revisado", - "running": "Ejecutar", - "save": "Guardar", - "schedule": "PROGRAMA", - "schedule-archive-blinko": "Calendario Archivo Blinko", - "schedule-back-up": "Programar copia de seguridad", - "schedule-task": "Programar tarea", - "show-less": "Mostrar menos", - "show-navigation-bar-on-mobile": "Barra de navegación oculta en el móvil", - "sign-in": "Iniciar sesión", - "sign-up": "Inscribirse", - "status": "ESTADO", - "stopped": "Detenido", - "the-two-passwords-are-inconsistent": "Las dos contraseñas son incoherentes", - "theme": "Tema", - "there-are-no-resources-yet-go-upload-them-now": "Todavía no hay recursos, súbelos ahora", - "this-operation-will-be-delete-resource-are-you-sure": "Esta operación será borrar recurso ¿estás seguro?", - "top": "Top", - "total": "Total", - "update-successfully": "Actualizar con éxito", - "upload-file": "Cargar archivo", - "use-ai": "Utilizar ai", - "user-custom-openai-api-key": "Clave Api OpenAI personalizada por el usuario", - "user-custom-azureopenai-api-instance": "Nombre de la instancia de Azure OpenAI", - "user-custom-azureopenai-api-deployment": "Nombre de implementación de Azure OpenAI", - "user-custom-azureopenai-api-version": "Versión API", - "username": "nombre de usuario", - "your-changes-have-been-saved": "Tus cambios se han guardado.", - "all-notes-have-been-loaded": "Todas las notas {{items}} han sido cargadas", - "ask-about-your-notes": "Pregunte por sus notas", - "basic-information": "Información básica", - "bulleted-list": "Lista con viñetas", - "cancel": "Cancelar", - "cancel-top": "Cancelar", - "change-user-info": "Cambiar la información de usuario", - "check-list": "Lista de control", - "congratulations-youve-reviewed-everything-today": "lo has revisado todo hoy.", - "convert-to": "Convertir a", - "convert-to-blinko": "Convertir a Blinko", - "enter-send-shift-enter-for-new-line": "Intro enviar, Mayús+Intro para nueva línea", - "language": "Idioma", - "last-run": "ÚLTIMA CARRERA", - "logout": "Cierre de sesión", - "model-provider": "Modelo de proveedor", - "name": "Nombre", - "name-db": "NOMBRE", - "no-tag-found": "No se ha encontrado ninguna etiqueta", - "preference": "Preferencia", - "recording": "Grabación", - "show-more": "Ver más", - "this-operation-removes-the-associated-label-and-cannot-be-restored-please-confirm": "Esta operación elimina la etiqueta asociada y no se puede restaurar por favor confirme", - "user-or-password-error": "Error de usuario o contraseña", - "convert-to-note": "Convertir en nota", - "import": "Importar", - "create-successfully": "Crear con éxito", - "insert-sandpack": "Insertar saco de arena", - "created-in": "Creado en", - "set-as-public": "Establecer como público", - "unset-as-public": "Desactivado como Público", - "no-tag": "Sin etiqueta", - "with-link": "Con enlace", - "has-file": "Tiene archivo", - "created-at": "Crear en", - "user-list": "Lista de usuarios", - "create-user": "Crear usuario", - "import-from-memos-memos_prod-db": "Importar de Memos(memos_prod.db)", - "when-exporting-memos_prod-db-please-close-the-memos-container-to-avoid-partial-loss-of-data": "Al exportar memos_prod.db, cierre el contenedor de memos para evitar la pérdida parcial de datos.", - "go-to-share-page": "Ir a la página para compartir", - "import-done": "Importación realizada", - "rebuilding-embedding-progress": "Reconstruir Integrar el progreso", - "rebuild-embedding-index": "Reconstruir índice de incrustación", - "rebuild": "Reconstruir", - "notes-imported-by-other-means-may-not-have-embedded-vectors": "Los billetes importados por otros medios pueden no tener vectores incrustados", - "order-by-create-time": "Ordenar por hora de creación", - "time-format": "Formato de hora", - "version": "Versión", - "new-version-available": "Nueva versión disponible", - "storage": "Almacenamiento", - "local-file-system": "Sistema de archivos local", - "object-storage": "Almacenamiento de objetos", - "in-addition-to-the-gpt-model-there-is-a-need-to-ensure-that-it-is-possible-to-invoke-the": "Además del modelo GPT, es necesario garantizar que sea posible invocar el modelo", - "speech-recognition-requires-the-use-of": "El reconocimiento de voz requiere el uso de", - "ai-expand": "AI Ampliar", - "ai-polish": "AI Polaco", - "accept": "Acepte", - "reject": "Rechazar", - "stop": "Stop", - "card-columns": "Columnas de tarjetas", - "select-a-columns": "Seleccione una columna", - "width-less-than-1024px": "Anchura inferior a 1024px", - "width-less-than": "Anchura inferior a", - "small-device-card-columns": "Columnas de la tarjeta de dispositivo pequeño", - "medium-device-card-columns": "Columnas de la tarjeta de dispositivo medio", - "large-device-card-columns": "Columnas grandes de la tarjeta de dispositivo", - "device-card-columns": "Columnas de la tarjeta de dispositivo", - "columns-for-different-devices": "Columnas para distintos dispositivos", - "mobile": "Móvil", - "tablet": "Tableta", - "desktop": "Escritorio", - "chars": "Caracteres", - "text-fold-length": "Longitud del pliegue del texto", - "title-first-line-of-the-text": "Título(primera línea del texto)", - "content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Contenido(resto del texto,si el texto supera la longitud)", - "ai-tag": "Etiqueta AI", - "article": "Artículo", - "embedding-model": "Modelo de incrustación", - "if-you-have-a-lot-of-notes-you-may-consume-a-certain-number-of-tokens": "Si tienes muchos billetes puedes consumir un número determinado de fichas", - "force-rebuild": "Reconstrucción forzosa", - "force-rebuild-embedding-index": "La reconstrucción forzada reconstruirá por completo todos los datos indexados.", - "embedding-model-description": "El índice debe reconstruirse después de cambiar de modelo integrado.", - "top-k-description": "Número máximo de documentos devueltos", - "embedding-score-description": "El umbral de similitud de las consultas suele ser la distancia de la suma euclídea", - "embedding-lambda-description": "Resultado de la consulta Parámetro de ponderación de la diversidad", - "update-tag-icon": "Actualizar icono de etiqueta", - "delete-only-tag": "Borrar sólo etiqueta", - "delete-tag-with-note": "Eliminar etiqueta con nota", - "update-tag-name": "Actualizar nombre de etiqueta", - "thinking": "Pensando...", - "select-all": "Seleccionar todo", - "insert-before": "Insertar antes de", - "insert-after": "Insertar después de", - "update-name": "Actualizar nombre", - "ai-emoji": "Ai Emoji", - "custom-icon": "Icono personalizado", - "ai-enhanced-search": "Búsqueda mejorada por IA", - "preview-mode": "Modo de vista previa", - "source-code": "Código fuente", - "camera": "Cámara", - "reference": "Referencia", - "reference-note": "Nota de referencia", - "source-code-mode": "Modo de código fuente", - "heading": "Rúbrica", - "paragraph": "Párrafo", - "quote": "Cita", - "bold": "Negrita", - "remove-italic": "Eliminar cursiva", - "underline": "Subraye", - "italic": "Cursiva", - "remove-bold": "Eliminar negrita", - "remove-underline": "Eliminar subrayado", - "select-block-type": "Seleccione el tipo de bloque", - "block-type-select-placeholder": "Tipo de bloque", - "trash": "basura", - "custom-path": "Ruta personalizada", - "page-size": "Tamaño de página", - "toolbar-visibility": "Visibilidad de la barra de herramientas", - "always-hide-toolbar": "Esconderse siempre", - "always-show-toolbar": "Mostrar siempre", - "hide-toolbar-on-mobile": "Ocultar en el móvil", - "select-toolbar-visibility": "Seleccionar la visibilidad de la barra de herramientas", - "select-a-time-format": "Seleccione un formato de hora", - "enter-code-shown-on-authenticator-app": "Introduzca el código que aparece en la aplicación de autenticación", - "open-your-third-party-authentication-app-and-enter-the-codeshown-on-screen": "Abra la aplicación de autenticación de terceros e introduzca los códigos que aparecen en pantalla.", - "two-factor-authentication": "Autenticación de dos factores", - "scan-this-qr-code-with-your-authenticator-app": "Escanea este código QR con tu aplicación de autenticación", - "or-enter-this-code-manually": "O introduzca este código manualmente:", - "verify": "Verifique", - "upload": "Cargar", - "days": "Días", - "select-model-provider": "Seleccionar proveedor de modelos", - "allow-register": "Permitir Registro", - "access-token": "Ficha de acceso", - "bucket": "Cubo", - "region": "Región", - "access-key-secret": "Clave de acceso secreta", - "access-key-id": "Identificador de la clave de acceso", - "share-and-copy-link": "Compartir y copiar enlace", - "copy-share-link": "Copiar enlace compartido", - "endpoint": "Punto final", - "export-format": "Formato de exportación", - "export": "Exportar", - "time-range": "Intervalo de tiempo", - "all": "Todos", - "exporting": "Exportar...", - "has-image": "Tiene Imagen", - "has-link": "Tiene enlace", - "filter-settings": "Ajustes de filtro", - "tag-status": "Estado de la etiqueta", - "all-notes": "Todas las notas", - "with-tags": "Con etiquetas", - "without-tags": "Sin etiquetas", - "select-tags": "Seleccionar etiquetas", - "additional-conditions": "Condiciones adicionales", - "apply-filter": "Aplicar filtro", - "to": "A", - "start-date": "Fecha de inicio", - "end-date": "Fecha final", - "reset": "Restablecer", - "no-condition": "Ninguna condición", - "public": "Público", - "ai-model-tooltip": "Introduzca el nombre del modelo a utilizar, como gpt-3.5-turbo, gpt-4, gpt-4o, gpt-4o-mini", - "user-custom-azureopenai-api-deployment-tooltip": " Introduzca el nombre de despliegue que desea utilizar, por ejemplo gpt-4o", - "ollama-ai-model-tooltip": "Introduce el nombre del modelo a utilizar, por ejemplo llama3.2", - "ollama-default-endpoint-is-http-localhost-11434": "El punto final por defecto de Ollama es http://localhost:11434", - "your-azure-openai-instance-name": "Nombre de su instancia de Azure OpenAI", - "ai-generate-emoji": "", - "ai-generating-emoji": "", - "api-key": "", - "date-range": "", - "days-ago": "", - "enter-your-api-key": "", - "hours-ago": "", - "impoort-from-bko": "", - "minutes-ago": "", - "months-ago": "", - "superadmin": "", - "user": "", - "weeks-ago": "", - "years-ago": "", - "about": "Acerca de", - "alternate-text": "Texto alternativo", - "close": "Cerrar", - "code": "Bloque de código", - "code-theme": "Vista previa del tema de bloque de código", - "content-theme": "Vista previa del tema del contenido", - "delete-row": "Eliminar columna", - "devtools": "Herramientas de desarrollo", - "down": "Abajo", - "download-tip": "El navegador no es compatible con la función de descarga", - "edit-mode": "Alternar modo de edición", - "edit-user": "Editar usuario", - "emoji": "Emoji", - "exclude-tag-from-embedding": "Excluir contenido etiquetado", - "exclude-tag-from-embedding-desc": "Seleccione una etiqueta para excluir sus notas asociadas de la generación de vectores de incrustación de IA.", - "exclude-tag-from-embedding-tip": "Las notas con esta etiqueta serán excluidas del procesamiento de incrustación de IA.", - "file-type-error": "El tipo de archivo es error", - "follow-system": "Sistema de seguimiento", - "footnote-ref": "Nota al pie de página", - "fullscreen": "Alternar pantalla completa", - "generate": "Generando", - "heading1": "Título 1", - "heading2": "Encabezado 2", - "heading3": "Título 3", - "heading4": "Encabezado 4", - "heading5": "Encabezado 5", - "heading6": "Encabezado 6", - "headings": "Encabezados", - "help": "Ayuda", - "image-url": "URL de la imagen", - "indent": "Sangría", - "info": "Información", - "inline-code": "Código en línea", - "insert-column-left": "Insertar 1 izquierda", - "insert-column-right": "Inserte 1 a la derecha", - "insert-row-above": "Insertar 1 arriba", - "insert-row-below": "Inserte 1 debajo", - "instant-rendering": "Renderizado instantáneo", - "light-mode": "Modo claro", - "line": "Línea", - "link": "Enlace", - "link-ref": "Enlace de referencia", - "list": "Lista", - "more": "Más", - "name-empty": "El nombre está vacío", - "ordered-list": "Lista de pedidos", - "original-password": "Contraseña original", - "outdent": "Sangrar", - "outline": "Esquema", - "over": "sobre", - "performance-tip": "La vista previa en tiempo real requiere ${x} ms, puedes cerrarla", - "preview": "Vista previa", - "search-tags": "Buscar etiquetas", - "insert-attachment-or-note": "¿Insertar en el archivo adjunto o en la nota?", - "context": "Contexto", - "paste-to-note-or-attachment": "¿Estás seguro de pegar en el contexto o adjuntar?", - "attachment": "Adjunto", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Después de la eliminación, todos los datos de usuario serán borrados y no se podrán recuperar.", - "upload-completed": "Carga completada", - "upload-cancelled": "Subida cancelada", - "upload-failed": "Error al subir", - "import-from-bko-tip": "La carga a s3 para recuperación no está soportada en este momento. Por favor, deshabilite temporalmente la opción s3 cuando desee recuperar." + "spotify-consumer-key-tip": "Solía obtener portadas de música mp3.", + "spotify-consumer-key-tip-2": "Obtén la clave de API en https://developer.spotify.com/" } diff --git a/public/locales/fr/translation.json b/public/locales/fr/translation.json index b103168e..a462c578 100644 --- a/public/locales/fr/translation.json +++ b/public/locales/fr/translation.json @@ -1,328 +1,4 @@ { - "blinko": "Blinko", - "notes": "Notes", - "resources": "Ressources", - "archived": "Archivé", - "settings": "Paramètres", - "total-tags": "TOTAL DES ÉTIQUETTES", - "search": "Recherche...", - "i-have-a-new-idea": "J'ai une nouvelle idée...", - "add-tag": "Ajouter une étiquette", - "ai-model": "Modèle IA", - "already-have-an-account-direct-login": "Vous avez déjà un compte ? Connexion directe", - "api-endpoint": "Point final de l'API", - "archive": "Archives", - "ask-about-your-notes": "Demandez vos notes", - "cancel": "Annuler", - "cancel-top": "Annuler le haut", - "change-user-info": "Modifier les informations sur l'utilisateur", - "confirm-your-password": "Confirmez votre mot de passe", - "convert-to": "Convertir en", - "convert-to-blinko": "Convertir en Blinko", - "convert-to-note": "Convertir en note", - "create-successfully": "Créer avec succès", - "create-successfully-is-about-to-jump-to-the-login": "Créer avec succès, est sur le point de passer à la connexion", - "delete": "Supprimer", - "delete-confirm": "Supprimer Confirmer", - "edit": "Editer", - "every-day": "Tous les jours", - "every-half-year": "Tous les semestres", - "every-month": "Chaque mois", - "every-three-month": "Tous les trois mois", - "every-week": "Chaque semaine", - "hello": "Bonjour", - "hi-user-name-i-can-search-for-the-notes-for-you-how-can-i-help-you-today": "Bonjour {{nom}}, je peux rechercher les notes pour vous, comment puis-je vous aider aujourd'hui ?", - "import-from-bko": "Importation à partir de .bko", - "in-progress": "En cours...", - "insert-codeblock": "Insérer un bloc de code", - "insert-sandpack": "Insérer le sac de sable", - "insert-table": "Insérer un tableau", - "items": "articles", - "last-run": "DERNIÈRE COURSE", - "logout": "Déconnexion", - "multiple-select": "Sélection multiple", - "name": "Nom", - "name-db": "NOM", - "new-version-detected-click-to-get-the-latest-version": "🎉Nouvelle version détectée, cliquer pour obtenir la dernière version", - "nickname": "surnom", - "no-data-here-well-then-time-to-write-a-note": "Pas de données ici ? Dans ce cas, il est temps de rédiger une note !", - "note": "Note", - "numbered-list": "Liste numérotée", - "preference": "Préférence", - "recording": "Enregistrement", - "recovery": "Récupération", - "required-items-cannot-be-empty": "Les éléments requis ne peuvent pas être vides", - "rest-user-password": "Mot de passe de l'utilisateur du repos", - "running": "La course à pied", - "save": "Économiser", - "schedule-archive-blinko": "Archive du calendrier Blinko", - "schedule-back-up": "Planification de la sauvegarde", - "schedule-task": "Tâche de planification", - "show-less": "Montrer moins", - "show-more": "Afficher plus", - "sign-in": "S'inscrire", - "stopped": "Arrêtée", - "theme": "Thème", - "there-are-no-resources-yet-go-upload-them-now": "Il n'y a pas encore de ressources, téléchargez-les maintenant", - "this-operation-removes-the-associated-label-and-cannot-be-restored-please-confirm": "Cette opération supprime l'étiquette associée et ne peut pas être restaurée.", - "this-operation-will-be-delete-resource-are-you-sure": "Cette opération permettra de supprimer des ressources. Êtes-vous sûr ?", - "top": "Haut de page", - "total": "Total", - "update-successfully": "Mise à jour réussie", - "upload-file": "Télécharger le fichier", - "use-ai": "Utiliser l'ai", - "user-custom-openai-api-key": "Clé Api OpenAI personnalisée par l'utilisateur", - "user-custom-azureopenai-api-instance": "Nom de l'instance Azure OpenAI", - "user-custom-azureopenai-api-deployment": "Nom du déploiement Azure OpenAI", - "user-custom-azureopenai-api-version": "Version API", - "user-or-password-error": "Erreur d'utilisateur ou de mot de passe", - "username": "Nom d'utilisateur", - "backup-file": "FICHIER DE SAUVEGARDE", - "basic-information": "Informations de base", - "bulleted-list": "Liste à puces", - "change-type": "Modifier le type", - "confirm": "Confirmer", - "confirm-password": "Confirmer le mot de passe", - "confirm-to-delete": "Confirmer pour supprimer !", - "confrim": "Confirmer", - "congratulations-youve-reviewed-everything-today": "vous avez tout passé en revue aujourd'hui.", - "daily-review": "Revue quotidienne", - "detail": "Détail", - "enter-send-shift-enter-for-new-line": "Entrer envoyer, Shift+Enter pour une nouvelle ligne", - "all-notes-have-been-loaded": "Toutes les notes {{items}} ont été chargées", - "check-list": "Liste de contrôle", - "delete-success": "Supprimer avec succès", - "enter-your-name": "Entrez votre nom", - "enter-your-password": "Entrez votre mot de passe", - "enter-your-username": "Entrez votre nom d'utilisateur", - "import": "Importation", - "language": "Langue", - "must-start-with-http-s-or-use-api-openai-as-default": "Doit commencer par http(s):// ou utiliser /api/openai par défaut.", - "need-to-create-an-account": "Besoin de créer un compte ?", - "insert-hashtag": "Insérer un hashtag", - "model-provider": "Modèle de fournisseur", - "no-tag-found": "Aucune étiquette trouvée", - "not-a-bko-file": "pas un fichier bko", - "password": "mot de passe", - "schedule": "CALENDRIER", - "show-navigation-bar-on-mobile": "Barre de navigation cachée sur mobile", - "sign-up": "S'inscrire", - "status": "STATUT", - "the-two-passwords-are-inconsistent": "Les deux mots de passe sont incohérents", - "your-changes-have-been-saved": "Vos modifications ont été enregistrées !", - "keep-sign-in": "Garder la connexion", - "operation-failed": "L'opération a échoué.", - "reviewed": "Examiné", - "created-in": "Créé en", - "set-as-public": "Définir comme public", - "unset-as-public": "Non défini comme public", - "no-tag": "Pas d'étiquette", - "with-link": "Avec lien", - "has-file": "A le fichier", - "created-at": "Créer à", - "create-user": "Créer un utilisateur", - "action": "Action", - "original-password": "Mot de passe original", - "edit-user": "Modifier l'utilisateur", - "import-from-memos-memos_prod-db": "Importation de Memos(memos_prod.db)", - "when-exporting-memos_prod-db-please-close-the-memos-container-to-avoid-partial-loss-of-data": "Lors de l'exportation de memos_prod.db, veuillez fermer le conteneur memos afin d'éviter une perte partielle des données.", - "go-to-share-page": "Aller à la page de partage", - "import-done": "Importation effectuée", - "rebuilding-embedding-progress": "Reconstruire Intégrer le progrès", - "rebuild-embedding-index": "Reconstruire l'index d'intégration", - "rebuild": "Reconstruction", - "order-by-create-time": "Ordre par temps de création", - "time-format": "Format de l'heure", - "version": "Version", - "new-version-available": "Nouvelle version disponible", - "storage": "Stockage", - "local-file-system": "Système de fichiers local", - "object-storage": "Stockage d'objets", - "in-addition-to-the-gpt-model-there-is-a-need-to-ensure-that-it-is-possible-to-invoke-the": "En plus du modèle GPT, il est nécessaire de s'assurer qu'il est possible d'invoquer le modèle", - "speech-recognition-requires-the-use-of": "La reconnaissance vocale nécessite l'utilisation de", - "ai-expand": "Extension de l'IA", - "ai-polish": "AI Polish", - "accept": "Accepter", - "reject": "Rejeter", - "stop": "Arrêter", - "card-columns": "Colonnes de la carte", - "select-a-columns": "Sélectionner une colonne", - "width-less-than-1024px": "Largeur inférieure à 1024px", - "width-less-than": "Largeur inférieure à", - "small-device-card-columns": "Colonnes de la carte des petits appareils", - "medium-device-card-columns": "Colonnes de la carte de dispositif moyen", - "large-device-card-columns": "Grandes colonnes de la carte d'appareil", - "device-card-columns": "Colonnes de la carte d'appareil", - "columns-for-different-devices": "Colonnes pour différents appareils", - "mobile": "Mobile", - "tablet": "Tablette", - "desktop": "Bureau", - "chars": "Chars", - "text-fold-length": "Longueur du pli du texte", - "title-first-line-of-the-text": "Titre (première ligne du texte)", - "content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Contenu (reste du texte, si le texte est plus long que la longueur)", - "ai-tag": "Étiquette AI", - "article": "Article", - "embedding-model": "Modèle d'intégration", - "if-you-have-a-lot-of-notes-you-may-consume-a-certain-number-of-tokens": "Si vous avez beaucoup de notes, vous pouvez consommer un certain nombre de jetons.", - "force-rebuild": "Reconstruction des forces", - "force-rebuild-embedding-index": "La reconstruction forcée reconstruit toutes les données qui ont été complètement indexées.", - "embedding-model-description": "L'index doit être reconstruit après avoir changé de modèle intégré.", - "top-k-description": "Nombre maximum de documents éventuellement renvoyés", - "embedding-score-description": "Le seuil de similarité pour les requêtes est généralement la distance de la somme euclidienne", - "embedding-lambda-description": "Résultat de la requête Paramètre de pondération de la diversité", - "update-tag-icon": "Mise à jour de l'icône de la balise", - "delete-only-tag": "Supprimer uniquement l'étiquette", - "delete-tag-with-note": "Supprimer une étiquette avec une note", - "update-tag-name": "Mise à jour du nom de l'étiquette", - "thinking": "Réflexion...", - "select-all": "Sélectionner tout", - "insert-before": "Insérer avant", - "insert-after": "Insérer après", - "update-name": "Nom de la mise à jour", - "ai-emoji": "Ai Emoji", - "custom-icon": "Icône personnalisée", - "ai-enhanced-search": "Recherche améliorée par l'IA", - "preview-mode": "Mode de prévisualisation", - "source-code": "Code source", - "camera": "Appareil photo", - "reference": "Référence", - "reference-note": "Note de référence", - "source-code-mode": "Mode code source", - "heading": "Rubrique", - "paragraph": "Paragraphe", - "quote": "Citation", - "bold": "Gras", - "remove-italic": "Supprimer l'italique", - "underline": "Souligner", - "italic": "Italique", - "remove-bold": "Supprimer les caractères gras", - "remove-underline": "Supprimer le soulignement", - "select-block-type": "Sélectionner le type de bloc", - "block-type-select-placeholder": "Type de bloc", - "trash": "poubelle", - "custom-path": "Chemin d'accès personnalisé", - "page-size": "Taille de la page", - "toolbar-visibility": "Visibilité de la barre d'outils", - "always-hide-toolbar": "Toujours cacher", - "always-show-toolbar": "Toujours montrer", - "hide-toolbar-on-mobile": "Cacher sur mobile", - "select-toolbar-visibility": "Sélection de la visibilité de la barre d'outils", - "select-a-time-format": "Sélectionner un format d'heure", - "enter-code-shown-on-authenticator-app": "Saisir le code affiché sur l'application d'authentification", - "open-your-third-party-authentication-app-and-enter-the-codeshown-on-screen": "Ouvrez votre application d'authentification tierce et saisissez les codes affichés à l'écran.", - "two-factor-authentication": "Authentification à deux facteurs", - "scan-this-qr-code-with-your-authenticator-app": "Scannez ce code QR avec votre application d'authentification", - "or-enter-this-code-manually": "Ou saisissez ce code manuellement :", - "verify": "Vérifier", - "about": "A propos de", - "upload": "Télécharger", - "days": "Jours", - "select-model-provider": "Sélectionner le fournisseur du modèle", - "allow-register": "Autoriser le registre", - "access-token": "Jeton d'accès", - "bucket": "Seau", - "region": "Région", - "access-key-secret": "Clé d'accès secret", - "access-key-id": "Clé d'accès", - "share-and-copy-link": "Partager et copier le lien", - "copy-share-link": "Copier le lien de partage", - "endpoint": "Point final", - "export-format": "Format d'exportation", - "export": "Exportation", - "time-range": "Plage de temps", - "all": "Tous", - "exporting": "Exporter...", - "has-image": "A l'image", - "has-link": "A le lien", - "filter-settings": "Paramètres du filtre", - "tag-status": "Statut de l'étiquette", - "all-notes": "Toutes les notes", - "with-tags": "Avec Tags", - "without-tags": "Sans étiquette", - "select-tags": "Sélectionner les étiquettes", - "additional-conditions": "Conditions supplémentaires", - "apply-filter": "Appliquer le filtre", - "to": "Pour", - "start-date": "Date de début", - "end-date": "Date de fin", - "reset": "Remise à zéro", - "no-condition": "Pas de condition", - "public": "Public", - "ai-model-tooltip": "Entrez le nom du modèle à utiliser, par exemple gpt-3.5-turbo, gpt-4, gpt-4o, gpt-4o-mini.", - "user-custom-azureopenai-api-deployment-tooltip": " Saisissez le nom de déploiement à utiliser, par exemple gpt-4o", - "ollama-ai-model-tooltip": "Saisissez le nom du modèle à utiliser, par exemple llama3.2.", - "ollama-default-endpoint-is-http-localhost-11434": "Le point de terminaison par défaut d'Ollama est http://localhost:11434", - "your-azure-openai-instance-name": "Nom de votre instance Azure OpenAI", - "ai-generate-emoji": "", - "ai-generating-emoji": "", - "api-key": "", - "date-range": "", - "days-ago": "", - "enter-your-api-key": "", - "hours-ago": "", - "impoort-from-bko": "", - "minutes-ago": "", - "months-ago": "", - "superadmin": "", - "user": "", - "weeks-ago": "", - "years-ago": "", - "align-center": "Centre", - "both": "éditeur & aperçu", - "check": "Liste de tâches", - "close": "Fermer", - "code-theme": "Aperçu du thème de bloc de code", - "content-theme": "Aperçu du thème de contenu", - "dark-mode": "Mode sombre", - "delete-column": "Supprimer la ligne", - "delete-row": "Supprimer la colonne", - "devtools": "Outils de développement", - "download-tip": "Le navigateur ne prend pas en charge la fonction de téléchargement", - "edit-mode": "Activer/désactiver le mode d'édition", - "emoji": "Emoji", - "exclude-tag-from-embedding": "Exclure le contenu balisé", - "exclude-tag-from-embedding-desc": "Sélectionnez une balise pour exclure ses notes associées de la génération du vecteur d'encastrement de l'IA.", - "exclude-tag-from-embedding-tip": "Les notes avec cette étiquette seront exclues du traitement d'intégration de l'IA.", - "file-type-error": "Le type de fichier est une erreur.", - "follow-system": "Système de suivi", - "footnote-ref": "Référence de bas de page", - "fullscreen": "Activer/désactiver le mode plein écran", - "generate": "Génération", - "heading1": "Titre 1", - "heading2": "Sous-titre 2", - "heading3": "Titre 3", - "heading4": "Titre 4", - "heading5": "Niveau 5", - "heading6": "Niveau 6", - "headings": "Titres", - "help": "Aider", - "image-url": "URL de l'image", - "indent": "Retrait", - "info": "Informations", - "inline-code": "Code en ligne", - "insert-column-left": "Insérez 1 à gauche", - "insert-column-right": "Insérez 1 à droite", - "insert-row-above": "Insérez 1 ci-dessus", - "insert-row-below": "Insérez 1 ci-dessous", - "instant-rendering": "Rendu instantané", - "light-mode": "Mode clair", - "line": "Ligne", - "link": "Lien", - "link-ref": "Lien de référence", - "list": "Liste", - "more": "Plus", - "name-empty": "Le nom est vide", - "preview": "Aperçu", - "select-model": "Sélectionner un modèle", - "search-tags": "Balises de recherche", - "insert-attachment-or-note": "Insérer dans la pièce jointe ou la note ?", - "context": "Contexte", - "paste-to-note-or-attachment": "Êtes-vous sûr de coller dans le contexte ou en pièce jointe ?", - "attachment": "Pièce jointe", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Après la suppression, toutes les données utilisateur seront effacées et définitivement irrécupérables.", - "upload-completed": "Téléchargement terminé", - "upload-cancelled": "Téléchargement annulé", - "upload-failed": "Téléchargement échoué", - "import-from-bko-tip": "Le téléversement vers s3 pour la récupération n'est pas pris en charge actuellement. Veuillez désactiver temporairement l'option s3 lorsque vous souhaitez récupérer." + "spotify-consumer-key-tip": "Utilisé pour obtenir la couverture de musique mp3", + "spotify-consumer-key-tip-2": "Obtenez la clé API à partir de https://developer.spotify.com/" } diff --git a/public/locales/ja/translation.json b/public/locales/ja/translation.json index f24e5144..b3485d21 100644 --- a/public/locales/ja/translation.json +++ b/public/locales/ja/translation.json @@ -1,313 +1,4 @@ { - "blinko": "ブリンコ", - "notes": "備考", - "resources": "リソース", - "archived": "アーカイブ", - "settings": "設定", - "total-tags": "総合タグ", - "search": "検索...", - "i-have-a-new-idea": "新しいアイデアがあるんだ", - "add-tag": "タグを追加", - "ai-model": "AIモデル", - "all-notes-have-been-loaded": "すべての{{items}}ノートがロードされました。", - "already-have-an-account-direct-login": "アカウントをお持ちですか?直接ログイン", - "api-endpoint": "APIエンドポイント", - "archive": "アーカイブ", - "ask-about-your-notes": "ノートについて尋ねる", - "basic-information": "基本情報", - "bulleted-list": "箇条書きリスト", - "confirm": "確認", - "confirm-password": "パスワードの確認", - "confirm-to-delete": "削除を確認する!", - "confrim": "確認", - "convert-to": "に変換する。", - "convert-to-blinko": "ブリンコに変換", - "convert-to-note": "ノートに変換", - "create-successfully": "作成に成功", - "create-successfully-is-about-to-jump-to-the-login": "正常に作成され、ログインにジャンプしようとしている", - "delete": "削除", - "delete-confirm": "削除確認", - "delete-success": "削除成功", - "enter-send-shift-enter-for-new-line": "Enterで送信、Shift+Enterで改行", - "enter-your-name": "名前を入力", - "enter-your-username": "ユーザー名を入力してください", - "every-day": "毎日", - "every-half-year": "半年ごと", - "every-month": "毎月", - "every-three-month": "3ヶ月ごと", - "every-week": "毎週", - "hello": "こんにちわ", - "hi-user-name-i-can-search-for-the-notes-for-you-how-can-i-help-you-today": "こんにちは{{名前}}!あなたのためにノートを検索することができます。", - "import": "輸入", - "insert-codeblock": "codeBlockを挿入する", - "insert-table": "テーブルの挿入", - "keep-sign-in": "サインインを維持する", - "language": "言語", - "last-run": "ラストラン", - "logout": "ログアウト", - "model-provider": "モデル・プロバイダー", - "need-to-create-an-account": "アカウントの作成が必要ですか?", - "new-version-detected-click-to-get-the-latest-version": "新しいバージョンが検出されました。", - "nickname": "ニックネーム", - "no-data-here-well-then-time-to-write-a-note": "データがない?それなら、ノートを書く時間だ!", - "no-tag-found": "タグが見つかりません", - "not-a-bko-file": "bkoファイルではない", - "numbered-list": "番号付きリスト", - "operation-failed": "操作に失敗した。", - "password": "パスワード", - "preference": "プリファレンス", - "recovery": "リカバリー", - "required-items-cannot-be-empty": "必須項目を空にすることはできない", - "rest-user-password": "一休ユーザーのパスワード", - "reviewed": "レビュー", - "running": "ランニング", - "save": "セーブ", - "schedule-archive-blinko": "スケジュール アーカイブ ブリンコ", - "schedule-back-up": "バックアップのスケジュール", - "show-less": "ショー・レス", - "show-more": "もっと見る", - "show-navigation-bar-on-mobile": "モバイルでのナビゲーションバーの非表示", - "sign-in": "ログイン", - "status": "ステータス", - "stopped": "停止", - "theme": "テーマ", - "there-are-no-resources-yet-go-upload-them-now": "リソースはまだありません。", - "this-operation-will-be-delete-resource-are-you-sure": "この操作はリソースを削除することになりますが、よろしいですか?", - "top": "トップ", - "backup-file": "バックアップファイル", - "cancel": "キャンセル", - "cancel-top": "キャンセルトップ", - "change-type": "タイプ変更", - "change-user-info": "ユーザー情報の変更", - "total": "合計", - "upload-file": "ファイルのアップロード", - "use-ai": "aiを使う", - "user-custom-openai-api-key": "ユーザー独自のOpenAI APIキー", - "user-custom-azureopenai-api-instance": "Azure OpenAI インスタンス名", - "user-custom-azureopenai-api-deployment": "Azure OpenAI デプロイ名", - "user-custom-azureopenai-api-version": "APIバージョン", - "edit": "編集", - "enter-your-password": "パスワードを入力してください", - "import-from-bko": ".bkoからのインポート", - "insert-hashtag": "ハッシュタグを入れる", - "items": "項目", - "name-db": "名前", - "note": "注", - "recording": "レコーディング", - "schedule-task": "スケジュール・タスク", - "this-operation-removes-the-associated-label-and-cannot-be-restored-please-confirm": "この操作によって関連ラベルが削除され、元に戻すことはできません。", - "update-successfully": "更新成功", - "user-or-password-error": "ユーザーまたはパスワードのエラー", - "username": "ユーザー名", - "your-changes-have-been-saved": "変更が保存されました!", - "check-list": "チェックリスト", - "confirm-your-password": "パスワードの確認", - "congratulations-youve-reviewed-everything-today": "今日はすべてを見直したね。", - "daily-review": "デイリーレビュー", - "detail": "詳細", - "in-progress": "進行中だ...", - "insert-sandpack": "サンドパックを入れる", - "multiple-select": "複数選択", - "must-start-with-http-s-or-use-api-openai-as-default": "http(s)://で始まるか、デフォルトの/api/openaiを使用する必要があります。", - "name": "名称", - "schedule": "スケジュール", - "sign-up": "会員登録", - "the-two-passwords-are-inconsistent": "2つのパスワードは矛盾している", - "created-in": "で作成された。", - "set-as-public": "公開設定", - "unset-as-public": "公開未設定", - "no-tag": "タグなし", - "with-link": "リンク付き", - "has-file": "ファイル", - "created-at": "で作成する", - "role": "役割", - "create-user": "ユーザー作成", - "edit-user": "編集ユーザー", - "import-from-memos-memos_prod-db": "メモからのインポート(memos_prod.db)", - "when-exporting-memos_prod-db-please-close-the-memos-container-to-avoid-partial-loss-of-data": "memos_prod.dbをエクスポートする際は、データの一部消失を避けるため、メモコンテナを閉じてください。", - "go-to-share-page": "シェアページへ", - "rebuilding-embedding-progress": "再構築 進歩の定着", - "rebuild": "再構築", - "if-you-have-a-lot-of-notes-you-may-consume-a-certain-number-of-tokens": "多くのノートをお持ちの場合、一定数のトークンを消費する可能性があります。", - "order-by-create-time": "作成時間順", - "time-format": "時間形式", - "version": "バージョン", - "new-version-available": "新バージョン", - "storage": "ストレージ", - "local-file-system": "ローカルファイルシステム", - "object-storage": "オブジェクトストレージ", - "in-addition-to-the-gpt-model-there-is-a-need-to-ensure-that-it-is-possible-to-invoke-the": "GPTモデルに加えて、次のようなことが可能であることを保証する必要がある。", - "speech-recognition-requires-the-use-of": "音声認識には", - "ai-expand": "AI拡大", - "ai-polish": "AIポーランド語", - "accept": "受け入れる", - "reject": "却下", - "stop": "ストップ", - "card-columns": "カード・コラム", - "select-a-columns": "列を選択する", - "width-less-than-1024px": "横幅が1024px未満", - "width-less-than": "幅", - "small-device-card-columns": "小型デバイスカードのコラム", - "medium-device-card-columns": "ミディアムデバイスカードのコラム", - "large-device-card-columns": "大型デバイスカードのコラム", - "device-card-columns": "デバイスカードのコラム", - "columns-for-different-devices": "デバイス別コラム", - "mobile": "モバイル", - "tablet": "タブレット", - "desktop": "デスクトップ", - "chars": "文字", - "text-fold-length": "テキストの折りの長さ", - "title-first-line-of-the-text": "タイトル(本文の1行目)", - "content-rest-of-the-text-if-the-text-is-longer-than-the-length": "コンテンツ(テキストが長さを超える場合、残りの部分)", - "ai-tag": "AIタグ", - "article": "記事", - "embedding-model": "埋め込みモデル", - "force-rebuild": "フォース・リビルド", - "force-rebuild-embedding-index": "強制再構築は、インデックスが作成されたすべてのデータを完全に再構築します。", - "embedding-model-description": "組み込みモデルを切り替えた後は、インデックスを再構築する必要があります。", - "top-k-description": "最終的に返される文書の最大数", - "embedding-score-description": "クエリの類似度閾値は一般的にユークリッド和距離である。", - "embedding-lambda-description": "クエリ結果の多様性重み付けパラメータ", - "update-tag-icon": "タグアイコンの更新", - "delete-only-tag": "タグのみ削除", - "delete-tag-with-note": "メモ付きタグの削除", - "update-tag-name": "タグ名の更新", - "thinking": "考える...", - "select-all": "すべて選択", - "insert-before": "前に挿入", - "insert-after": "の後に挿入する。", - "update-name": "更新名", - "ai-emoji": "絵文字", - "custom-icon": "カスタムアイコン", - "ai-enhanced-search": "AIによる検索強化", - "preview-mode": "プレビュー・モード", - "source-code": "ソースコード", - "camera": "カメラ", - "reference": "参考", - "reference-note": "参考資料", - "source-code-mode": "ソースコードモード", - "heading": "見出し", - "paragraph": "パラグラフ", - "quote": "引用", - "bold": "太字", - "remove-italic": "イタリック体の削除", - "underline": "アンダーライン", - "italic": "イタリック", - "remove-bold": "太字を削除", - "remove-underline": "アンダーラインの削除", - "select-block-type": "ブロックタイプを選択", - "block-type-select-placeholder": "ブロックタイプ", - "trash": "ゴミ", - "custom-path": "カスタムパス", - "page-size": "ページサイズ", - "toolbar-visibility": "ツールバーの表示", - "always-hide-toolbar": "常に隠れる", - "always-show-toolbar": "常にショー", - "hide-toolbar-on-mobile": "モバイルで隠す", - "select-toolbar-visibility": "ツールバーの表示を選択", - "select-a-time-format": "時間フォーマットを選択する", - "enter-code-shown-on-authenticator-app": "認証アプリに表示されたコードを入力", - "open-your-third-party-authentication-app-and-enter-the-codeshown-on-screen": "サードパーティ認証アプリを開き、画面に表示されたコードを入力する。", - "two-factor-authentication": "二要素認証", - "scan-this-qr-code-with-your-authenticator-app": "認証アプリでこのQRコードをスキャンしてください。", - "or-enter-this-code-manually": "または、このコードを手動で入力する:", - "verify": "ベリファイ", - "about": "について", - "upload": "アップロード", - "days": "日数", - "select-model-provider": "モデルプロバイダーを選択", - "allow-register": "登録許可", - "access-token": "アクセス・トークン", - "bucket": "バケット", - "region": "地域", - "access-key-secret": "アクセスキーの秘密", - "access-key-id": "アクセスキーID", - "share-and-copy-link": "リンクの共有とコピー", - "copy-share-link": "共有リンクをコピーする", - "endpoint": "エンドポイント", - "export-format": "エクスポート形式", - "export": "輸出", - "time-range": "時間範囲", - "all": "すべて", - "exporting": "輸出...", - "has-image": "イメージ", - "has-link": "リンクあり", - "filter-settings": "フィルター設定", - "tag-status": "タグステータス", - "all-notes": "すべての注意事項", - "with-tags": "タグ付き", - "without-tags": "タグなし", - "select-tags": "タグを選択", - "additional-conditions": "追加条件", - "apply-filter": "フィルタを適用する", - "to": "へ", - "start-date": "開始日", - "end-date": "終了日", - "reset": "リセット", - "no-condition": "コンディションなし", - "public": "パブリック", - "ai-model-tooltip": "gpt-3.5-turbo、gpt-4、gpt-4o、gpt-4o-miniなど、使用するモデル名を入力してください。", - "user-custom-azureopenai-api-deployment-tooltip": "使用するデプロイメント名(gpt-4o など)を入力します。", - "ollama-ai-model-tooltip": "llama3.2のように、使用するモデル名を入力してください。", - "ollama-default-endpoint-is-http-localhost-11434": "Ollama デフォルトのエンドポイントは http://localhost:11434", - "your-azure-openai-instance-name": "Azure OpenAIインスタンス名", - "action": "行動", - "ai-generate-emoji": "", - "ai-generating-emoji": "", - "align-center": "センター", - "align-left": "左", - "align-right": "正しい", - "alternate-text": "代替テキスト", - "api-key": "", - "both": "エディター&プレビュー", - "check": "タスクリスト", - "close": "閉める", - "code": "コードブロック", - "code-theme": "コードブロックテーマプレビュー", - "column": "列", - "comment": "コメント", - "content-theme": "コンテンツテーマのプレビュー", - "copied": "コピーされました", - "copy": "コピー", - "dark-mode": "ダークモード", - "date-range": "", - "days-ago": "", - "delete-column": "行を削除する", - "delete-row": "列を削除します。", - "devtools": "DevTools\n\nデベロッパーツール", - "down": "ダウン", - "download-tip": "ブラウザはダウンロード機能をサポートしていません", - "edit-mode": "編集モードの切り替え", - "emoji": "絵文字", - "enter-your-api-key": "", - "exclude-tag-from-embedding": "タグ付けされたコンテンツを除外します。", - "exclude-tag-from-embedding-desc": "AI埋め込みベクトル生成から関連するノートを排除するためのタグを選択します。", - "exclude-tag-from-embedding-tip": "このタグが付けられたノートは、AIの埋め込み処理から除外されます。", - "follow-system": "システムに従う", - "footnote-ref": "脚注参照", - "fullscreen": "フルスクリーン切り替え", - "generate": "生成します", - "heading1": "見出し1", - "heading2": "見出し2", - "headings": "見出し", - "help": "助けてください", - "hours-ago": "", - "image-url": "画像のURL", - "impoort-from-bko": "", - "import-done": "インポートが完了しました。", - "indent": "インデント", - "info": "情報", - "inline-code": "インラインコード", - "insert-column-left": "1 を挿入左", - "insert-column-right": "1を右に挿入", - "search-tags": "検索タグ", - "insert-attachment-or-note": "添付ファイルに挿入しますか、それともメモに書き込みますか?", - "context": "コンテクスト", - "paste-to-note-or-attachment": "コンテキストや添付ファイルに貼り付けることを確認しますか?", - "attachment": "添付", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "削除後、すべてのユーザーデータは消去され、回復不能になります。", - "upload-completed": "アップロードが完了しました", - "upload-cancelled": "アップロードがキャンセルされました", - "upload-failed": "アップロードに失敗しました", - "import-from-bko-tip": "この時点では、S3 へのアップロードによるリカバリはサポートされていません。リカバリを行う際には一時的に S3 オプションを無効にしてください。" + "spotify-consumer-key-tip": "mp3音楽のカバーを取得するために使用されました", + "spotify-consumer-key-tip-2": "https://developer.spotify.com/ から API キーを取得します。" } diff --git a/public/locales/ko/translation.json b/public/locales/ko/translation.json index 8139ae95..d3089abf 100644 --- a/public/locales/ko/translation.json +++ b/public/locales/ko/translation.json @@ -1,335 +1,5 @@ { - "blinko": "Blinko", - "notes": "참고", - "resources": "리소스", - "archived": "아카이브", - "settings": "설정", - "total-tags": "총 태그", - "search": "검색...", - "i-have-a-new-idea": "새로운 아이디어가 떠올랐어요...", - "add-tag": "태그 추가", - "ai-model": "AI 모델", - "all-notes-have-been-loaded": "모든 {{아이템}} 노트가 로드되었습니다.", - "already-have-an-account-direct-login": "이미 계정이 있으신가요? 직접 로그인", - "archive": "아카이브", - "ask-about-your-notes": "노트에 대해 질문하기", - "basic-information": "기본 정보", - "bulleted-list": "글머리 기호 목록", - "cancel": "취소", - "change-type": "유형 변경", - "change-user-info": "사용자 정보 변경", - "check-list": "확인 목록", - "confirm": "확인", - "confirm-password": "비밀번호 확인", - "confirm-to-delete": "삭제를 확인합니다!", - "confirm-your-password": "비밀번호 확인", - "confrim": "확인", - "convert-to": "다음으로 변환", - "convert-to-blinko": "Blinko로 전환", - "convert-to-note": "노트로 변환", - "create-successfully": "성공적으로 만들기", - "create-successfully-is-about-to-jump-to-the-login": "생성 성공, 로그인으로 이동하려고 합니다.", - "daily-review": "일일 검토", - "delete": "삭제", - "delete-confirm": "삭제 확인", - "detail": "세부 정보", - "edit": "편집", - "enter-send-shift-enter-for-new-line": "보내기 입력, 새 줄을 위한 Shift+Enter 입력", - "enter-your-name": "이름 입력", - "enter-your-password": "비밀번호 입력", - "every-month": "매월", - "every-three-month": "3개월마다", - "every-week": "매주", - "import": "가져오기", - "in-progress": "진행 중...", - "insert-hashtag": "해시태그 삽입", - "insert-sandpack": "샌드팩 삽입", - "insert-table": "표 삽입", - "items": "항목", - "language": "언어", - "last-run": "마지막 실행", - "logout": "로그아웃", - "model-provider": "모델 제공자", - "must-start-with-http-s-or-use-api-openai-as-default": "http(s)://로 시작하거나 기본값으로 /api/openai를 사용해야 합니다.", - "name": "이름", - "name-db": "이름", - "need-to-create-an-account": "계정을 만들어야 하나요?", - "nickname": "닉네임", - "no-tag-found": "태그를 찾을 수 없습니다.", - "not-a-bko-file": "BKO 파일이 아닙니다.", - "numbered-list": "번호가 매겨진 목록", - "operation-failed": "작업이 실패했습니다.", - "password": "비밀번호", - "preference": "기본 설정", - "recording": "녹음", - "required-items-cannot-be-empty": "필수 항목은 비워둘 수 없습니다.", - "rest-user-password": "나머지 사용자 비밀번호", - "reviewed": "검토 완료", - "running": "실행 중", - "save": "저장", - "schedule": "일정", - "schedule-archive-blinko": "일정 아카이브 블링코", - "schedule-back-up": "백업 예약", - "schedule-task": "작업 예약", - "show-less": "덜 보기", - "show-more": "자세히 보기", - "show-navigation-bar-on-mobile": "모바일의 숨겨진 탐색 모음", - "status": "상태", - "the-two-passwords-are-inconsistent": "두 비밀번호가 일치하지 않습니다.", - "theme": "테마", - "there-are-no-resources-yet-go-upload-them-now": "아직 리소스가 없으니 지금 업로드하세요.", - "this-operation-removes-the-associated-label-and-cannot-be-restored-please-confirm": "이 작업은 관련 레이블을 제거하며 복원할 수 없음을 확인하시기 바랍니다.", - "this-operation-will-be-delete-resource-are-you-sure": "이 작업은 리소스 삭제가 확실합니까?", - "total": "합계", - "update-successfully": "업데이트 성공", - "use-ai": "AI 사용", - "user-custom-openai-api-key": "사용자 지정 OpenAI API 키", - "user-custom-azureopenai-api-instance": "Azure OpenAI 인스턴스 이름", - "user-custom-azureopenai-api-deployment": "Azure OpenAI 배포 이름", - "user-custom-azureopenai-api-version": "API 버전", - "user-or-password-error": "사용자 또는 비밀번호 오류", - "username": "사용자 이름", - "api-endpoint": "API 엔드포인트", - "backup-file": "백업 파일", - "congratulations-youve-reviewed-everything-today": "오늘 모든 내용을 검토하셨습니다.", - "delete-success": "삭제 성공", - "every-day": "매일", - "every-half-year": "반기마다", - "import-from-bko": ".bko에서 가져오기", - "insert-codeblock": "코드 블록 삽입", - "multiple-select": "다중 선택", - "new-version-detected-click-to-get-the-latest-version": "🎉새 버전이 감지되었습니다, 최신 버전을 받으려면 클릭하세요.", - "recovery": "복구", - "sign-in": "로그인", - "cancel-top": "상단 취소", - "stopped": "중지됨", - "top": "Top", - "no-data-here-well-then-time-to-write-a-note": "여기에 데이터가 없나요? 그렇다면 메모를 작성할 시간입니다!", - "keep-sign-in": "로그인 유지", - "enter-your-username": "사용자 이름 입력", - "hello": "hello", - "hi-user-name-i-can-search-for-the-notes-for-you-how-can-i-help-you-today": "안녕하세요 {{이름}}!,노트를 검색해 드릴 수 있는데요,오늘은 무엇을 도와드릴까요?", - "note": "참고", - "sign-up": "가입하기", - "upload-file": "파일 업로드", - "your-changes-have-been-saved": "변경 사항이 저장되었습니다!", - "created-in": "에 생성됨", - "unset-as-public": "공개로 설정 해제", - "no-tag": "태그 없음", - "with-link": "링크 사용", - "has-file": "파일 있음", - "created-at": "다음에서 만들기", - "role": "역할", - "create-user": "사용자 만들기", - "action": "액션", - "original-password": "원래 비밀번호", - "edit-user": "사용자 편집", - "import-from-memos-memos_prod-db": "메모(memos_prod.db)에서 가져오기", - "when-exporting-memos_prod-db-please-close-the-memos-container-to-avoid-partial-loss-of-data": "memos_prod.db를 내보낼 때는 데이터의 일부가 손실되지 않도록 메모 컨테이너를 닫아 주세요.", - "go-to-share-page": "공유 페이지로 이동", - "import-done": "가져오기 완료", - "rebuild-embedding-index": "임베딩 인덱스 재구축", - "notes-imported-by-other-means-may-not-have-embedded-vectors": "다른 방법으로 가져온 노트에는 벡터가 내장되어 있지 않을 수 있습니다.", - "if-you-have-a-lot-of-notes-you-may-consume-a-certain-number-of-tokens": "노트가 많으면 특정 수의 토큰을 소모할 수 있습니다.", - "order-by-create-time": "생성 시간별 주문", - "time-format": "시간 형식", - "version": "버전", - "new-version-available": "새 버전 사용 가능", - "storage": "스토리지", - "local-file-system": "로컬 파일 시스템", - "object-storage": "개체 스토리지", - "in-addition-to-the-gpt-model-there-is-a-need-to-ensure-that-it-is-possible-to-invoke-the": "GPT 모델 외에도 다음과 같이", - "speech-recognition-requires-the-use-of": "음성 인식은 다음을 사용해야 합니다.", - "ai-expand": "AI 확장", - "ai-polish": "AI 폴란드어", - "accept": "수락", - "reject": "거부", - "stop": "중지", - "card-columns": "카드 열", - "select-a-columns": "열 선택", - "width-less-than-1024px": "너비 1024px 미만", - "width-less-than": "너비 미만", - "small-device-card-columns": "소형 장치 카드 열", - "medium-device-card-columns": "중간 장치 카드 열", - "large-device-card-columns": "대형 장치 카드 열", - "device-card-columns": "장치 카드 열", - "columns-for-different-devices": "다양한 장치용 열", - "mobile": "모바일", - "tablet": "태블릿", - "desktop": "데스크톱", - "chars": "문자", - "text-fold-length": "텍스트 접기 길이", - "title-first-line-of-the-text": "제목(텍스트의 첫 줄)", - "content-rest-of-the-text-if-the-text-is-longer-than-the-length": "콘텐츠(텍스트가 길이보다 긴 경우 나머지 텍스트)", - "ai-tag": "AI 태그", - "article": "기사", - "embedding-model": "임베딩 모델", - "force-rebuild": "강제 재구축", - "force-rebuild-embedding-index": "강제 재구축은 인덱싱된 모든 데이터를 완전히 재구축합니다.", - "embedding-model-description": "임베디드 모델을 전환한 후 인덱스를 다시 작성해야 합니다.", - "top-k-description": "최종적으로 반환되는 최대 문서 수", - "embedding-score-description": "쿼리의 유사성 임계값은 일반적으로 유클리드 합 거리입니다.", - "embedding-lambda-description": "쿼리 결과 다양성 가중치 매개변수", - "update-tag-icon": "태그 업데이트 아이콘", - "delete-only-tag": "태그만 삭제", - "delete-tag-with-note": "메모와 함께 태그 삭제", - "update-tag-name": "태그 이름 업데이트", - "thinking": "생각...", - "select-all": "모두 선택", - "insert-before": "앞에 삽입", - "insert-after": "다음에 삽입", - "update-name": "업데이트 이름", - "ai-emoji": "Ai 이모티콘", - "custom-icon": "사용자 지정 아이콘", - "ai-enhanced-search": "AI 강화 검색", - "preview-mode": "미리보기 모드", - "source-code": "소스 코드", - "camera": "카메라", - "reference": "참조", - "reference-note": "참고 참고 사항", - "source-code-mode": "소스 코드 모드", - "heading": "제목", - "paragraph": "단락", - "quote": "견적", - "bold": "Bold", - "remove-italic": "이탤릭체 제거", - "underline": "밑줄", - "remove-bold": "굵게 제거", - "italic": "이탤릭체", - "remove-underline": "밑줄 제거", - "select-block-type": "블록 유형 선택", - "block-type-select-placeholder": "블록 유형", - "trash": "쓰레기", - "custom-path": "사용자 지정 경로", - "page-size": "페이지 크기", - "toolbar-visibility": "툴바 가시성", - "always-hide-toolbar": "항상 숨기기", - "always-show-toolbar": "항상 표시", - "hide-toolbar-on-mobile": "모바일에서 숨기기", - "select-toolbar-visibility": "도구 모음 표시 여부 선택", - "select-a-time-format": "시간 형식 선택", - "enter-code-shown-on-authenticator-app": "인증 앱에 표시된 코드를 입력합니다.", - "open-your-third-party-authentication-app-and-enter-the-codeshown-on-screen": "타사 인증 앱을 열고 화면에 표시된 코드를 입력합니다.", - "two-factor-authentication": "2단계 인증", - "scan-this-qr-code-with-your-authenticator-app": "인증 앱으로 이 QR 코드를 스캔하세요.", - "or-enter-this-code-manually": "또는 이 코드를 수동으로 입력하세요:", - "verify": "확인", - "about": "정보", - "upload": "업로드", - "days": "일수", - "select-model-provider": "모델 공급자 선택", - "allow-register": "등록 허용", - "access-token": "액세스 토큰", - "bucket": "버킷", - "region": "지역", - "access-key-secret": "액세스 키 비밀", - "access-key-id": "액세스 키 ID", - "share-and-copy-link": "링크 공유 및 복사", - "copy-share-link": "공유 링크 복사", - "endpoint": "엔드포인트", - "export-format": "내보내기 형식", - "export": "내보내기", - "time-range": "시간 범위", - "all": "모두", - "exporting": "내보내기...", - "has-image": "이미지 있음", - "has-link": "링크 있음", - "filter-settings": "필터 설정", - "tag-status": "태그 상태", - "all-notes": "모든 메모", - "with-tags": "태그 포함", - "without-tags": "태그 없음", - "select-tags": "태그 선택", - "additional-conditions": "추가 조건", - "apply-filter": "필터 적용", - "to": "To", - "start-date": "시작 날짜", - "end-date": "종료 날짜", - "reset": "초기화", - "no-condition": "조건 없음", - "public": "공개", - "ai-model-tooltip": "사용할 모델명(예: gpt-3.5-turbo, gpt-4, gpt-4o, gpt-4o-mini)을 입력합니다.", - "user-custom-azureopenai-api-deployment-tooltip": " 사용할 배포 이름(예: gpt-4o)을 입력합니다.", - "ollama-ai-model-tooltip": "사용할 모델 이름(예: llama3.2)을 입력합니다.", - "ollama-default-endpoint-is-http-localhost-11434": "Ollama 기본 엔드포인트는 http://localhost:11434", - "your-azure-openai-instance-name": "Azure OpenAI 인스턴스 이름", - "2fa-setup-successful": "2단계 인증 설정이 성공적으로 완료되었습니다.", - "ai-generate-emoji": "", - "ai-generating-emoji": "", - "align-center": "중앙", - "align-left": "왼쪽", - "align-right": "옳다", - "alternate-text": "대체 텍스트", - "api-key": "", - "both": "편집기 및 미리 보기", - "check": "작업 목록", - "close": "가까운", - "code": "코드 블록", - "code-theme": "코드 블록 테마 미리보기", - "comment": "의견", - "content-theme": "콘텐츠 테마 미리보기", - "copied": "복사된", - "copy": "복사하기", - "dark-mode": "다크 모드", - "date-range": "", - "days-ago": "", - "delete-column": "행 삭제", - "delete-row": "열 삭제", - "devtools": "개발자 도구", - "down": "아래", - "download-tip": "브라우저는 다운로드 기능을 지원하지 않습니다.", - "edit-mode": "편집 모드 전환", - "emoji": "이모지", - "enter-your-api-key": "", - "exclude-tag-from-embedding": "태그가 지정된 콘텐츠 제외", - "exclude-tag-from-embedding-desc": "AI 임베딩 벡터 생성에서 해당 노트를 제외하려는 태그를 선택하세요.", - "exclude-tag-from-embedding-tip": "이 태그가 있는 노트는 AI 임베딩 처리에서 제외됩니다.", - "file-type-error": "파일 유형이 오류입니다.", - "follow-system": "시스템 따르기", - "footnote-ref": "각주 참조", - "fullscreen": "전체 화면 전환", - "generate": "생성하기", - "heading1": "제목 1", - "heading2": "제목 2", - "heading3": "제목 3", - "heading4": "4단계 제목", - "heading5": "제목 5", - "heading6": "6단계", - "headings": "제목", - "help": "도와주세요", - "hours-ago": "", - "image-url": "이미지 URL", - "impoort-from-bko": "", - "indent": "들여쓰기", - "info": "정보", - "inline-code": "인라인 코드", - "insert-column-left": "1개를 왼쪽에 삽입하세요.", - "insert-column-right": "1을 삽입하십시오.", - "insert-row-above": "위에 1을 삽입하세요.", - "insert-row-below": "아래에 1을 삽입하세요.", - "instant-rendering": "즉각적 렌더링", - "light-mode": "라이트 모드", - "line": "라인", - "link": "링크", - "link-ref": "링크 참조", - "list": "목록", - "minutes-ago": "", - "months-ago": "", - "more": "더 많은", - "name-empty": "이름이 비어 있습니다.", - "ordered-list": "주문 목록", - "outdent": "내어쓰다", - "outline": "개요", - "over": "넘어서다", - "performance-tip": "실시간 미리보기에는 ${x}ms가 필요합니다. 닫을 수 있습니다.", - "search-tags": "검색 태그", - "insert-attachment-or-note": "첨부 파일이나 메모로 삽입하시겠습니까?", - "context": "문맥", - "paste-to-note-or-attachment": "컨텍스트나 첨부 파일에 붙여 넣을 확신이 있습니까?", - "attachment": "첨부 파일", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "삭제 후 모든 사용자 데이터가 지워지고 복구할 수 없게 됩니다.", - "upload-completed": "업로드가 완료되었습니다.", - "upload-cancelled": "업로드가 취소되었습니다.", - "upload-failed": "업로드 실패", - "import-from-bko-tip": "현재 s3로의 업로드는 복구되지 않습니다. 복구를 원할 경우 s3 옵션을 일시적으로 비활성화하십시오." + "enter-spotify-consumer-key": "Spotify 소비자 키를 입력하세요.", + "spotify-consumer-key-tip": "mp3 음악 커버를 얻었던 것", + "spotify-consumer-key-tip-2": "https://developer.spotify.com/에서 API 키를 받으세요." } diff --git a/public/locales/pt/translation.json b/public/locales/pt/translation.json index 213713d6..0182524d 100644 --- a/public/locales/pt/translation.json +++ b/public/locales/pt/translation.json @@ -1,263 +1,5 @@ { - "blinko": "Blinko", - "notes": "Notas", - "resources": "Recursos", - "archived": "Arquivado", - "settings": "Definições", - "total-tags": "TOTAL TAGS", - "search": "Procurar...", - "i-have-a-new-idea": "Tenho uma nova ideia...", - "ai-model": "Modelo de IA", - "all-notes-have-been-loaded": "Todas as notas {{items}} foram carregadas", - "archive": "Arquivo", - "ask-about-your-notes": "Perguntar sobre as suas notas", - "backup-file": "FICHEIRO DE CÓPIA DE SEGURANÇA", - "bulleted-list": "Lista com marcadores", - "cancel": "Cancelar", - "cancel-top": "Cancelar topo", - "change-type": "Tipo de modificação", - "change-user-info": "Alterar informações do utilizador", - "confirm-to-delete": "Confirmar a eliminação!", - "congratulations-youve-reviewed-everything-today": "já reviu tudo hoje.", - "convert-to-note": "Converter em nota", - "create-successfully": "Criar com êxito", - "daily-review": "Revisão diária", - "delete": "Eliminar", - "delete-confirm": "Apagar Confirmar", - "delete-success": "Eliminar com êxito", - "edit": "Editar", - "enter-send-shift-enter-for-new-line": "Introduzir enviar, Shift+Enter para nova linha", - "enter-your-name": "Introduza o seu nome", - "enter-your-password": "Introduza a sua palavra-passe", - "enter-your-username": "Introduza o seu nome de utilizador", - "every-day": "Todos os dias", - "every-half-year": "Todos os semestres", - "every-month": "Todos os meses", - "every-week": "Todas as semanas", - "hello": "Olá", - "hi-user-name-i-can-search-for-the-notes-for-you-how-can-i-help-you-today": "Olá {{nome}}, posso procurar as notas para si, como posso ajudá-lo hoje?", - "import-from-bko": "Importar de .bko", - "import": "Importação", - "in-progress": "Em curso...", - "insert-codeblock": "Inserir codeBlock", - "insert-hashtag": "Inserir hashtag", - "insert-sandpack": "Inserir saco de areia", - "insert-table": "Inserir tabela", - "items": "artigos", - "keep-sign-in": "Manter o registo", - "language": "Língua", - "last-run": "ÚLTIMA CORRIDA", - "logout": "Terminar sessão", - "multiple-select": "Seleção múltipla", - "must-start-with-http-s-or-use-api-openai-as-default": "Deve começar com http(s):// ou utilizar /api/openai como predefinição", - "name": "Nome", - "name-db": "NOME", - "need-to-create-an-account": "Precisa de criar uma conta?", - "new-version-detected-click-to-get-the-latest-version": "Nova versão detectada, clique para obter a versão mais recente", - "nickname": "alcunha", - "no-data-here-well-then-time-to-write-a-note": "Não há dados aqui? Então, é altura de escrever uma nota!", - "no-tag-found": "Nenhuma etiqueta encontrada", - "not-a-bko-file": "não é um ficheiro bko", - "note": "Nota", - "numbered-list": "Lista numerada", - "operation-failed": "A operação falhou.", - "password": "palavra-passe", - "preference": "Preferência", - "recording": "Registo", - "required-items-cannot-be-empty": "Os itens obrigatórios não podem estar vazios", - "rest-user-password": "Palavra-passe do utilizador restante", - "running": "Em curso", - "save": "Guardar", - "schedule": "CALENDÁRIO", - "schedule-archive-blinko": "Arquivo de horários Blinko", - "schedule-back-up": "Programar a cópia de segurança", - "schedule-task": "Programar tarefa", - "show-less": "Mostrar menos", - "show-more": "Mostrar mais", - "show-navigation-bar-on-mobile": "Barra de navegação oculta no telemóvel", - "sign-in": "Iniciar sessão", - "sign-up": "Inscrever-se", - "status": "ESTADO", - "stopped": "Parado", - "the-two-passwords-are-inconsistent": "As duas palavras-passe são inconsistentes", - "theme": "Tema", - "there-are-no-resources-yet-go-upload-them-now": "Ainda não existem recursos, carregue-os agora", - "this-operation-will-be-delete-resource-are-you-sure": "Esta operação será um recurso de eliminação, tem a certeza?", - "top": "Topo", - "total": "Total", - "update-successfully": "Atualizar com êxito", - "upload-file": "Carregar ficheiro", - "use-ai": "Utilizar ai", - "user-custom-openai-api-key": "Chave de Api OpenAI personalizada pelo utilizador", - "user-custom-azureopenai-api-instance": "Nome da instância do Azure OpenAI", - "user-custom-azureopenai-api-deployment": "Nome da implantação do Azure OpenAI", - "user-custom-azureopenai-api-version": "Versão da API", - "user-or-password-error": "Erro de utilizador ou de palavra-passe", - "username": "nome de utilizador", - "your-changes-have-been-saved": "As suas alterações foram guardadas!", - "add-tag": "Adicionar etiqueta", - "already-have-an-account-direct-login": "Já tem uma conta? Início de sessão direto", - "api-endpoint": "Ponto final da API", - "check-list": "Lista de controlo", - "confirm": "Confirmar", - "confirm-password": "Confirmar a palavra-passe", - "confirm-your-password": "Confirmar a sua palavra-passe", - "confrim": "Confirmar", - "convert-to": "Converter para", - "create-successfully-is-about-to-jump-to-the-login": "Criar com êxito, está prestes a passar para o início de sessão", - "every-three-month": "De três em três meses", - "model-provider": "Modelo de fornecedor", - "reviewed": "Revisto", - "basic-information": "Informações básicas", - "convert-to-blinko": "Converter para Blinko", - "recovery": "Recuperação", - "detail": "Detalhes", - "created-in": "Criado em", - "set-as-public": "Definir como público", - "unset-as-public": "Não definido como público", - "no-tag": "Sem etiqueta", - "with-link": "Com ligação", - "has-file": "Tem ficheiro", - "created-at": "Criar em", - "role": "Papel", - "user-list": "Lista de utilizadores", - "create-user": "Criar utilizador", - "action": "Ação", - "original-password": "Palavra-passe original", - "edit-user": "Editar utilizador", - "import-from-memos-memos_prod-db": "Importar de Memos(memos_prod.db)", - "when-exporting-memos_prod-db-please-close-the-memos-container-to-avoid-partial-loss-of-data": "Ao exportar memos_prod.db, feche o contentor de memos para evitar a perda parcial de dados.", - "go-to-share-page": "Ir para a página de partilha", - "rebuild-embedding-index": "Reconstruir o índice de incorporação", - "notes-imported-by-other-means-may-not-have-embedded-vectors": "As notas importadas por outros meios podem não ter vectores incorporados", - "if-you-have-a-lot-of-notes-you-may-consume-a-certain-number-of-tokens": "Se tiver muitas notas, pode consumir um determinado número de fichas", - "time-format": "Formato da hora", - "version": "Versão", - "new-version-available": "Nova versão disponível", - "storage": "Armazenamento", - "local-file-system": "Sistema de ficheiros local", - "object-storage": "Armazenamento de objectos", - "in-addition-to-the-gpt-model-there-is-a-need-to-ensure-that-it-is-possible-to-invoke-the": "Para além do modelo GPT, é necessário garantir que é possível invocar o modelo", - "speech-recognition-requires-the-use-of": "O reconhecimento de voz requer a utilização de", - "ai-expand": "Expandir a IA", - "ai-polish": "Polaco AI", - "accept": "Aceitar", - "reject": "Rejeitar", - "stop": "Parar", - "card-columns": "Colunas de cartões", - "select-a-columns": "Selecionar uma coluna", - "width-less-than-1024px": "Largura inferior a 1024px", - "width-less-than": "Largura inferior a", - "small-device-card-columns": "Colunas do cartão de dispositivo pequeno", - "medium-device-card-columns": "Colunas do cartão de dispositivo médio", - "large-device-card-columns": "Colunas grandes do cartão de dispositivo", - "device-card-columns": "Colunas do cartão de dispositivo", - "columns-for-different-devices": "Colunas para diferentes dispositivos", - "mobile": "Telemóvel", - "tablet": "Tablet", - "desktop": "Ambiente de trabalho", - "chars": "Caracteres", - "text-fold-length": "Comprimento da dobra do texto", - "title-first-line-of-the-text": "Título (primeira linha do texto)", - "content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Conteúdo (resto do texto, se o texto for mais longo do que o comprimento)", - "ai-tag": "Etiqueta AI", - "article": "Artigo", - "embedding-model": "Modelo de incorporação", - "force-rebuild": "Reconstrução da força", - "force-rebuild-embedding-index": "A reconstrução forçada irá reconstruir completamente todos os dados que foram indexados", - "embedding-model-description": "O índice deve ser reconstruído após a mudança de modelos incorporados", - "top-k-description": "Número máximo de documentos eventualmente devolvidos", - "embedding-lambda-description": "Resultado da consulta Parâmetro de ponderação da diversidade", - "update-tag-icon": "Atualizar o ícone da etiqueta", - "delete-only-tag": "Eliminar apenas a etiqueta", - "delete-tag-with-note": "Eliminar etiqueta com nota", - "update-tag-name": "Atualizar o nome da etiqueta", - "thinking": "A pensar...", - "select-all": "Selecionar tudo", - "insert-before": "Inserir antes de", - "insert-after": "Inserir após", - "update-name": "Atualizar nome", - "ai-emoji": "Ai Emoji", - "custom-icon": "Ícone personalizado", - "ai-enhanced-search": "Pesquisa optimizada por IA", - "preview-mode": "Modo de pré-visualização", - "source-code": "Código fonte", - "reference": "Referência", - "reference-note": "Nota de referência", - "source-code-mode": "Modo de código fonte", - "heading": "Título", - "paragraph": "Parágrafo", - "quote": "Citação", - "bold": "Negrito", - "remove-italic": "Remover itálico", - "underline": "Sublinhar", - "remove-bold": "Remover negrito", - "italic": "Itálico", - "remove-underline": "Remover o sublinhado", - "select-block-type": "Selecionar o tipo de bloco", - "block-type-select-placeholder": "Tipo de bloco", - "trash": "lixo", - "page-size": "Tamanho da página", - "toolbar-visibility": "Visibilidade da barra de ferramentas", - "always-hide-toolbar": "Esconder-se sempre", - "always-show-toolbar": "Mostrar sempre", - "hide-toolbar-on-mobile": "Ocultar no telemóvel", - "select-toolbar-visibility": "Selecionar a visibilidade da barra de ferramentas", - "select-a-time-format": "Selecionar um formato de hora", - "enter-code-shown-on-authenticator-app": "Introduzir o código apresentado na aplicação de autenticação", - "open-your-third-party-authentication-app-and-enter-the-codeshown-on-screen": "Abra a sua aplicação de autenticação de terceiros e introduza os códigosmostrados no ecrã", - "two-factor-authentication": "Autenticação de dois factores", - "scan-this-qr-code-with-your-authenticator-app": "Digitalize este código QR com a sua aplicação de autenticação", - "or-enter-this-code-manually": "Ou introduza este código manualmente:", - "verify": "Verificar", - "about": "Sobre", - "upload": "Carregar", - "days": "Dias", - "select-model": "Selecionar modelo", - "select-model-provider": "Selecionar fornecedor de modelos", - "allow-register": "Permitir registo", - "access-token": "Token de acesso", - "bucket": "Balde", - "region": "Região", - "access-key-secret": "Chave de acesso secreta", - "access-key-id": "ID da chave de acesso", - "share-and-copy-link": "Partilhar e copiar a ligação", - "copy-share-link": "Copiar a ligação de partilha", - "endpoint": "Ponto final", - "export-format": "Formato de exportação", - "export": "Exportação", - "time-range": "Intervalo de tempo", - "all": "Todos", - "exporting": "Exportar...", - "has-image": "Tem imagem", - "has-link": "Tem ligação", - "filter-settings": "Definições do filtro", - "tag-status": "Estado da etiqueta", - "all-notes": "Todas as notas", - "with-tags": "Com etiquetas", - "without-tags": "Sem etiquetas", - "select-tags": "Selecionar etiquetas", - "additional-conditions": "Condições adicionais", - "apply-filter": "Aplicar filtro", - "to": "Para", - "start-date": "Data de início", - "end-date": "Data final", - "reset": "Reiniciar", - "no-condition": "Sem condição", - "public": "Público", - "ai-model-tooltip": "Introduza o nome do modelo a utilizar, por exemplo, gpt-3.5-turbo, gpt-4, gpt-4o, gpt-4o-mini", - "user-custom-azureopenai-api-deployment-tooltip": " Introduza o nome da implantação a utilizar, por exemplo, gpt-4o", - "ollama-ai-model-tooltip": "Introduza o nome do modelo a utilizar, por exemplo, llama3.2", - "ollama-default-endpoint-is-http-localhost-11434": "O ponto de extremidade predefinido da Ollama é http://localhost:11434", - "your-azure-openai-instance-name": "O nome da sua instância do Azure OpenAI", - "search-tags": "Tags de pesquisa", - "insert-attachment-or-note": "Inserir em anexo ou nota?", - "context": "Contexto", - "paste-to-note-or-attachment": "Tem certeza de que deseja colar no contexto ou no anexo?", - "attachment": "Anexo", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Após a exclusão, todos os dados do usuário serão apagados e não poderão ser recuperados.", - "upload-completed": "Carregamento concluído", - "upload-cancelled": "Envio cancelado", - "upload-failed": "Falha ao Carregar", - "import-from-bko-tip": "O envio para o s3 para recuperação não é suportado neste momento. Por favor, desative temporariamente a opção s3 quando desejar recuperar." + "enter-spotify-consumer-key": "Insira a Chave do Consumidor do Spotify", + "spotify-consumer-key-tip": "Costumava obter a capa de músicas em mp3.", + "spotify-consumer-key-tip-2": "Obtenha a Chave da API em https://developer.spotify.com/" } diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json index 39ac6515..9385f82a 100644 --- a/public/locales/ru/translation.json +++ b/public/locales/ru/translation.json @@ -264,5 +264,11 @@ "upload-completed": "Загрузка завершена", "upload-cancelled": "Загрузка отменена", "upload-failed": "Не удалось загрузить", - "import-from-bko-tip": "Загрузка в s3 для восстановления в настоящее время не поддерживается. Пожалуйста, временно отключите опцию s3, когда планируете выполнить восстановление." + "import-from-bko-tip": "Загрузка в s3 для восстановления в настоящее время не поддерживается. Пожалуйста, временно отключите опцию s3, когда планируете выполнить восстановление.", + "music-settings": "Настройки музыки", + "enter-spotify-consumer-secret": "Введите секрет потребителя Spotify", + "spotify-consumer-secret": "Spotify Секрет потребителя", + "enter-spotify-consumer-key": "Введите ключ потребителя Spotify", + "spotify-consumer-key-tip": "Использовались для получения обложек музыкальных альбомов в формате mp3.", + "spotify-consumer-key-tip-2": "Получите ключ API на https://developer.spotify.com/" } diff --git a/public/locales/tr/translation.json b/public/locales/tr/translation.json index b54346a5..87f8e952 100644 --- a/public/locales/tr/translation.json +++ b/public/locales/tr/translation.json @@ -1,281 +1,5 @@ { - "blinko": "Blinko", - "notes": "Notlar", - "resources": "Kaynaklar", - "archived": "Arşivlendi", - "settings": "Ayarlar", - "total-tags": "TOPLAM ETİKETLER", - "search": "Arama...", - "i-have-a-new-idea": "Yeni bir fikrim var.", - "add-tag": "Etiket Ekle", - "ai-model": "Yapay Zeka Modeli", - "all-notes-have-been-loaded": "Tüm {{items}} notları yüklendi", - "api-endpoint": "API Uç Noktası", - "archive": "Arşiv", - "ask-about-your-notes": "Notlarınız hakkında soru sorun", - "backup-file": "YEDEK DOSYA", - "basic-information": "Temel Bilgiler", - "bulleted-list": "Madde işaretli liste", - "cancel": "İptal", - "cancel-top": "Üstü İptal Et", - "change-type": "Türü değiştir", - "change-user-info": "Kullanıcı bilgilerini değiştir", - "check-list": "Kontrol listesi", - "confirm": "Onaylayın", - "confirm-password": "Şifreyi Onayla", - "confirm-to-delete": "Silmek için onaylayın!", - "confrim": "Onaylayın", - "congratulations-youve-reviewed-everything-today": "bugün her şeyi gözden geçirdiniz.", - "convert-to": "Dönüştür", - "convert-to-blinko": "Dönüştürme yöntemi Blinko", - "convert-to-note": "Nota Dönüştür", - "create-successfully": "Başarıyla oluşturun", - "create-successfully-is-about-to-jump-to-the-login": "Başarıyla oluşturuldu, girişe atlamak üzere", - "daily-review": "Günlük İnceleme", - "delete": "Silme", - "delete-confirm": "Sil Onayla", - "detail": "Detay", - "edit": "Düzenle", - "enter-send-shift-enter-for-new-line": "Enter gönder, yeni satır için Shift+Enter", - "enter-your-name": "Adınızı girin", - "enter-your-password": "Şifrenizi girin", - "every-three-month": "Her üç ayda bir", - "hi-user-name-i-can-search-for-the-notes-for-you-how-can-i-help-you-today": "Merhaba {{isim}}!,Sizin için notları arayabilirim, bugün size nasıl yardımcı olabilirim?", - "import": "İthalat", - "insert-sandpack": "Kum torbasını yerleştirin", - "items": "öğeler", - "keep-sign-in": "Oturum açmaya devam et", - "language": "Dil", - "last-run": "SON KOŞU", - "logout": "Oturumu Kapat", - "delete-success": "Başarıyla silindi", - "enter-your-username": "Kullanıcı adınızı girin", - "every-day": "Her gün", - "user-custom-azureopenai-api-instance": "Azure OpenAI örnek adı", - "user-custom-azureopenai-api-deployment": "Azure OpenAI dağıtım adı", - "user-custom-azureopenai-api-version": "API sürümü", - "ai-model-tooltip": "Kullanılacak model adını girin, örneğin gpt-3.5-turbo, gpt-4, gpt-4o, gpt-4o-mini", - "user-custom-azureopenai-api-deployment-tooltip": " Kullanılacak dağıtım adını girin, örneğin gpt-4o", - "ollama-ai-model-tooltip": "Kullanılacak model adını girin, örneğin llama3.2", - "ollama-default-endpoint-is-http-localhost-11434": "Ollama varsayılan uç noktası http://localhost:11434", - "your-azure-openai-instance-name": "Azure OpenAI örnek adınız", - "2fa-setup-successful": "2FA kurulumu başarılı", - "about": "Hakkında", - "accept": "Kabul etmek", - "access-key-secret": "Erişim anahtarı gizli", - "action": "Eylem", - "ai-generate-emoji": "", - "ai-generating-emoji": "", - "ai-tag": "Yapay Zeka Etiketi", - "all": "Hepsi", - "allow-register": "Kayıt izni ver", - "already-have-an-account-direct-login": "Zaten bir hesabınız mı var? Doğrudan giriş yapın", - "alternate-text": "Yedek metin", - "always-hide-toolbar": "Her zaman gizle", - "always-show-toolbar": "Her zaman göster", - "api-key": "", - "apply-filter": "Filtre uygula", - "article": "Makale", - "block-type-select-placeholder": "Blog Türü", - "bold": "Koyu", - "both": "düzenleyici ve önizleme", - "bucket": "Kova", - "camera": "Kamera", - "card-columns": "Kart Sütunları", - "chars": "Karakterler", - "check": "Görev Listesi", - "close": "Kapatmak", - "code": "Kod Bloğu", - "code-theme": "Kod Blok Teması Önizlemesi", - "column": "Sütun", - "columns-for-different-devices": "Farklı cihazlar için sütunlar", - "comment": "Yorum", - "confirm-your-password": "Şifrenizi onaylayın", - "content-rest-of-the-text-if-the-text-is-longer-than-the-length": "İçerik (metnin geri kalanı, eğer metin uzunsa)", - "content-theme": "İçerik Tema Önizlemesi", - "copied": "Kopyalandı", - "copy": "Kopyala", - "copy-share-link": "Paylaşım bağlantısını kopyala", - "created-at": "Oluşturun At", - "date-range": "", - "days": "Günler", - "days-ago": "", - "desktop": "Masaüstü", - "enter-your-api-key": "", - "exporting": "İhracat yapılıyor...", - "heading2": "Başlık 2", - "heading3": "Başlık 3", - "heading4": "Başlık 4", - "heading5": "Başlık 5", - "heading6": "Başlık 6", - "headings": "Başlıklar", - "hello": "merhaba", - "help": "Yardım", - "hide-toolbar-on-mobile": "Mobilde Gizle", - "hours-ago": "", - "if-you-have-a-lot-of-notes-you-may-consume-a-certain-number-of-tokens": "Eğer çok fazla notunuz varsa, belirli bir sayıda jeton tüketebilirsiniz.", - "image-url": "görsel URL'ı", - "impoort-from-bko": "", - "import-done": "İthalat yapıldı", - "import-from-bko": ".bko'dan içe aktar", - "import-from-memos-memos_prod-db": "Memos'dan (memos_prod.db) içe aktar", - "in-addition-to-the-gpt-model-there-is-a-need-to-ensure-that-it-is-possible-to-invoke-the": "GPT modelinin yanı sıra, onu çağırmanın mümkün olduğundan emin olmak gerekmektedir.", - "in-progress": "Devam ediyor...", - "indent": "Girinti", - "info": "Bilgi", - "insert-before": "Satır eklemeden önce", - "local-file-system": "Yerel Dosya Sistemi", - "medium-device-card-columns": "Orta Cihaz Kartı Sütunları", - "minutes-ago": "", - "mobile": "Mobil", - "months-ago": "", - "new-version-detected-click-to-get-the-latest-version": "Yeni sürüm tespit edildi, en son sürümü almak için tıklayın 🎉", - "no-data-here-well-then-time-to-write-a-note": "Burada veri yok~", - "no-tag": "Etiket Yok", - "no-tag-found": "Etiket bulunamadı", - "not-a-bko-file": "bko dosyası değil", - "note": "Not", - "notes-imported-by-other-means-may-not-have-embedded-vectors": "Başka yollarla içe aktarılan notlarda gömülü vektörler bulunamaz", - "numbered-list": "Numaralı liste", - "object-storage": "Nesne depolama", - "open-your-third-party-authentication-app-and-enter-the-codeshown-on-screen": "Üçüncü taraf kimlik doğrulama uygulamanızı açın ve ekranda gösterilen kodu girin.", - "operation-failed": "İşlem başarısız oldu.", - "or-enter-this-code-manually": "Ya da bu kodu manuel olarak girin:", - "order-by-create-time": "Oluşturma zamanına göre sırala", - "ordered-list": "Sipariş Listesi", - "original-password": "Orijinal Şifre", - "outdent": "Girinti dışı bırakma", - "outline": "Taslak", - "over": "üzerinde", - "page-size": "Sayfa Boyutu", - "paragraph": "Paragraf", - "password": "şifre", - "performance-tip": "Gerçek zamanlı önizleme ${x} ms gerektiriyor, kapatabilirsiniz.", - "preference": "Tercih", - "preview": "Önizleme", - "preview-mode": "Önizleme Modu", - "public": "Halk", - "quote": "Alıntı", - "rebuild": "Yeniden inşa etmek", - "rebuild-embedding-index": "Gömme Dizini Yeniden Oluştur", - "rebuilding-embedding-progress": "Gömme Yeniden İnşa Etmek İlerlemesi", - "record": "Kaydı Başlat/Kaydı Sonlandır", - "record-tip": "Cihaz kayıt desteklemez", - "recording": "kayıt yapılıyor...", - "recovery": "İyileşmek", - "redo": "Yeniden yapmak", - "reference": "Referans", - "reference-note": "Referans Notu", - "region": "Bölge", - "reject": "Reddetmek", - "remove": "Kaldır", - "remove-bold": "Kalınları kaldır", - "remove-italic": "İtalik Kaldır", - "remove-underline": "Altını çıkar", - "required-items-cannot-be-empty": "Gerekli olan öğeler boş olamaz.", - "reset": "Sıfırla", - "rest-user-password": "Kullanıcı şifresini sıfırla", - "reviewed": "Gözden geçirildi.", - "role": "Rol", - "row": "Sıra", - "running": "Koşu", - "save": "Koruyun", - "scan-this-qr-code-with-your-authenticator-app": "Bu QR kodu kimlik doğrulama uygulamanızla tarayın.", - "schedule": "PROGRAM", - "schedule-archive-blinko": "Program Arşivi Blinko", - "schedule-back-up": "Yedekleme Planı", - "schedule-task": "Görev Zamanlaması", - "select-a-columns": "Bir sütun seçin.", - "select-a-time-format": "Bir zaman formatı seçin", - "select-all": "Tümünü Seç", - "select-block-type": "Blok Türünü Seç", - "select-model": "Model Seçiniz", - "select-model-provider": "Model Sağlayıcısını Seçin", - "select-tags": "Etiketleri Seç", - "select-toolbar-visibility": "Araç çubuğu görünürlüğünü seçin.", - "set-as-public": "Halka Ayarla", - "share-and-copy-link": "Paylaş ve bağlantıyı kopyala", - "show-less": "Daha Az Göster", - "show-more": "Daha Fazla Göster", - "show-navigation-bar-on-mobile": "Mobil cihazlarda gizli gezinti çubuğu", - "sign-in": "Giriş yap", - "sign-up": "Kaydol", - "small-device-card-columns": "Küçük Cihaz Kartı Sütunları", - "source-code": "Kaynak Kodu", - "source-code-mode": "Kaynak Kod Modu", - "speech-recognition-requires-the-use-of": "Konuşma tanıma kullanımını gerektirir.", - "spin": "Döndürmek", - "split-view": "Bölünmüş Görünüm", - "start-date": "Başlangıç Tarihi", - "status": "DURUM", - "stop": "Durdur", - "stopped": "Durduruldu", - "storage": "Depolama", - "strike": "Grev", - "superadmin": "", - "table": "Tablo", - "tablet": "Tablet", - "tag-status": "Etiket Durumu", - "text-fold-length": "Metin Katlama Uzunluğu", - "text-is-not-empty": "metin", - "the-two-passwords-are-inconsistent": "İki şifre uyuşmuyor", - "theme": "Tema", - "there-are-no-resources-yet-go-upload-them-now": "Henüz kaynak yok, şimdi onları yükle.", - "thinking": "Düşünüyorum...", - "this-operation-removes-the-associated-label-and-cannot-be-restored-please-confirm": "Bu işlem ilişkili etiketi kaldırır ve geri alınamaz, lütfen onaylayın.", - "this-operation-will-be-delete-resource-are-you-sure": "Bu işlem kaynağı silecek, emin misiniz?", - "time-format": "Zaman Biçimi", - "time-range": "Zaman Aralığı", - "title": "Başlık", - "title-first-line-of-the-text": "Başlık (metnin ilk satırı)", - "to": "\"Kime\"", - "toolbar-visibility": "Araç Çubuğu Görünürlüğü", - "tooltip-text": "Araç ipucu metni", - "top": "Tepe", - "top-k-description": "Sonunda döndürülecek belgelerin maksimum sayısı", - "total": "Toplam", - "trash": "Geridönüşüm Kutusu", - "two-factor-authentication": "İki Faktörlü Kimlik Doğrulama", - "underline": "Altı çizmek", - "undo": "Geri al", - "unset-as-public": "Genel olmaması.", - "up": "Yukarı", - "update": "Güncelleme", - "update-name": "İsmi Güncelle", - "update-successfully": "Başarıyla güncellendi", - "update-tag-icon": "Güncelleme etiket simgesi", - "update-tag-name": "Etiket Adını Güncelle", - "updated-at": "Güncelleme Saati", - "upload": "Resim veya dosya yükle", - "upload-error": "yükleyici hatası", - "upload-file": "Dosya yükle", - "uploading": "yükleniyor...", - "use-ai": "Yapay zekayı kullanın.", - "user": "", - "user-custom-openai-api-key": "Kullanıcı özel OpenAI Api Anahtarı", - "user-list": "Kullanıcı Listesi", - "user-or-password-error": "Kullanıcı adı veya şifre hatası", - "username": "Kullanıcı adı", - "verify": "Doğrula", - "version": "Sürüm", - "weeks-ago": "", - "when-exporting-memos_prod-db-please-close-the-memos-container-to-avoid-partial-loss-of-data": "memos_prod.db dışa aktarılırken, veri kaybının kısmen önlenmesi için memos konteynerını kapatınız.", - "width-less-than": "Genişlikten daha az", - "width-less-than-1024px": "1024 pikselden küçük genişlik", - "with-link": "Bağlantı ile", - "with-tags": "Etiketlerle", - "without-tags": "Etiketler olmadan", - "wysiwyg": "Ne gördüğün, onu alırsın.", - "years-ago": "", - "your-changes-have-been-saved": "Değişiklikleriniz kaydedildi!", - "search-tags": "Arama Etiketleri", - "insert-attachment-or-note": "Eklentiye mi yoksa notlara mı ekleyeceksiniz?", - "context": "Bağlam", - "paste-to-note-or-attachment": "Metin veya ek dosyaya yapıştırmak istediğinizden emin misiniz?", - "attachment": "Eklenti", - "after-deletion-all-user-data-will-be-cleared-and-unrecoverable": "Silme işleminden sonra, tüm kullanıcı verileri temizlenecek ve kurtarılamaz hale gelecektir.", - "upload-completed": "Yükleme tamamlandı", - "upload-cancelled": "Yükleme iptal edildi", - "upload-failed": "Yükleme Başarısız oldu", - "import-from-bko-tip": "Bu zamanda s3'e yükleme yapılmamaktadır. Kurtarma işlemi gerçekleştirmek istediğinizde lütfen geçici olarak s3 seçeneğini devre dışı bırakın." + "enter-spotify-consumer-key": "Spotify Tüketici Anahtarı Giriniz", + "spotify-consumer-key-tip": "Mp3 müzik kapağı almak için kullanılan.", + "spotify-consumer-key-tip-2": "https://developer.spotify.com/ adresinden API Anahtarı alın." } diff --git a/public/locales/zh-TW/translation.json b/public/locales/zh-TW/translation.json index 20cfe4a1..649726a5 100644 --- a/public/locales/zh-TW/translation.json +++ b/public/locales/zh-TW/translation.json @@ -361,5 +361,11 @@ "upload-completed": "上傳完成", "upload-cancelled": "上傳已取消", "upload-failed": "上傳失敗", - "import-from-bko-tip": "目前不支援上傳至 s3 進行還原。當您想要進行恢復操作時,請暫時停用 s3 選項。" + "import-from-bko-tip": "目前不支援上傳至 s3 進行還原。當您想要進行恢復操作時,請暫時停用 s3 選項。", + "music-settings": "音樂設定", + "enter-spotify-consumer-secret": "輸入 Spotify 用戶秘密", + "spotify-consumer-secret": "Spotify 用戶端秘鑰", + "enter-spotify-consumer-key": "輸入 Spotify 使用者金鑰", + "spotify-consumer-key-tip": "以前用來取得 MP3 音樂封面", + "spotify-consumer-key-tip-2": "從 https://developer.spotify.com/ 取得 API 金鑰" } diff --git a/public/locales/zh/translation.json b/public/locales/zh/translation.json index 78ff27f1..ec295ee4 100644 --- a/public/locales/zh/translation.json +++ b/public/locales/zh/translation.json @@ -53,7 +53,7 @@ "api-endpoint": "接口地址", "must-start-with-http-s-or-use-api-openai-as-default": "必须以 http(s):// 开头,或默认使用 /api/openai", "user-custom-openai-api-key": "用户自定义 OpenAI Api 密钥", - "user-custom-azureopenai-api-instance": "Azure OpenAI 虚拟实例名称", + "user-custom-azureopenai-api-instance": "Azure OpenAI 虚拟实例名��", "user-custom-azureopenai-api-deployment": "Azure OpenAI 部署名称", "user-custom-azureopenai-api-version": "API 版本", "ai-model": "人工智能模型", @@ -165,7 +165,7 @@ "ai-tag": "AI标签", "article": "文章", "embedding-model": "嵌入式模型", - "if-you-have-a-lot-of-notes-you-may-consume-a-certain-number-of-tokens": "如果您有大量笔记,您可能会消耗一定数量的代币", + "if-you-have-a-lot-of-notes-you-may-consume-a-certain-number-of-tokens": "如果您有大量笔记,���可能会消耗一定数量的代币", "force-rebuild": "强制重建", "force-rebuild-embedding-index": "强制重建将完全重建已索引的所有数据", "embedding-model-description": "切换嵌入式模型后必须重建索引", @@ -220,7 +220,7 @@ "verify": "验证", "about": "关于", "upload": "上传", - "days": "天", + "days": "���", "select-model": "选择型号", "select-model-provider": "选择模型提供商", "allow-register": "允许注册", @@ -361,5 +361,12 @@ "upload-completed": "上传完成", "upload-cancelled": "上传已取消", "upload-failed": "上传失败", - "import-from-bko-tip": "目前不支持将上传到S3进行恢复。当您想要恢复时,请暂时禁用S3选项。" + "import-from-bko-tip": "目前不支持将上传到S3进行恢复。当您想要恢复时,请暂时禁用S3选项。", + "music-settings": "音乐设置", + "spotify-consumer-key": "Spotify接口Key", + "spotify-consumer-secret": "Spotify接口密钥", + "enter-spotify-consumer-key": "输入 Spotify 接口 Key", + "enter-spotify-consumer-secret": "输入Spotify接口密钥", + "spotify-consumer-key-tip": "用来获得mp3音乐封面", + "spotify-consumer-key-tip-2": "从https://developer.spotify.com/获取API密钥。" } diff --git a/src/components/BlinkoMusicPlayer/index.tsx b/src/components/BlinkoMusicPlayer/index.tsx new file mode 100644 index 00000000..fbc85f24 --- /dev/null +++ b/src/components/BlinkoMusicPlayer/index.tsx @@ -0,0 +1,273 @@ +import { observer } from 'mobx-react-lite'; +import { RootStore } from '@/store'; +import { MusicManagerStore } from '@/store/musicManagerStore'; +import { Icon } from '@iconify/react'; +import { useEffect, useRef, useState } from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; + +export const BlinkoMusicPlayer = observer(() => { + const musicManager = RootStore.Get(MusicManagerStore); + const progressRef = useRef(null); + const currentTrack = musicManager.currentTrack; + const metadata = currentTrack?.metadata; + const [isCompact, setIsCompact] = useState(false); + + const formatTime = (seconds: number): string => { + const minutes = Math.floor(seconds / 60); + const remainingSeconds = Math.floor(seconds % 60); + return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`; + }; + + const handleProgressBarClick = (e: React.MouseEvent) => { + if (!musicManager.audioElement) return; + const progressBar = e.currentTarget; + const rect = progressBar.getBoundingClientRect(); + const x = e.clientX - rect.left; + const percentage = x / rect.width; + musicManager.seek(musicManager.duration * percentage); + }; + + useEffect(() => { + const updateProgress = () => { + if (!progressRef.current || !musicManager.audioElement) return; + const percentage = (musicManager.currentTime / musicManager.duration) * 100; + progressRef.current.style.width = `${percentage}%`; + }; + + const interval = setInterval(updateProgress, 100); + return () => clearInterval(interval); + }, [musicManager.currentTrack]); + + useEffect(() => { + if (musicManager.showMiniPlayer) { + const timer = setTimeout(() => { + setIsCompact(true); + }, 5000); + return () => clearTimeout(timer); + } else { + setIsCompact(false); + } + }, [musicManager.showMiniPlayer]); + + return ( + + {musicManager.showMiniPlayer && currentTrack && ( + setIsCompact(false)} + onMouseLeave={() => setIsCompact(true)} + > + + {metadata?.coverUrl && ( + <> +
+
+ + )} + +
+ + {metadata?.coverUrl ? ( + Album Cover + ) : ( +
+ +
+ )} +
+ +
+ + + + {metadata?.trackName || currentTrack.file.name} + + + {metadata?.artists && metadata.artists.join(', ')} + + + + + + + + + + + + + + {formatTime(musicManager.currentTime)} + +
+ +
+ + {formatTime(musicManager.duration)} + +
+
+
+ + + )} + + ); +}); diff --git a/src/components/BlinkoSettings/Item.tsx b/src/components/BlinkoSettings/Item.tsx index 53ecb956..ae9414f1 100644 --- a/src/components/BlinkoSettings/Item.tsx +++ b/src/components/BlinkoSettings/Item.tsx @@ -31,7 +31,7 @@ export const Item = observer(({ leftContent, rightContent, type = 'row', hidden export const ItemWithTooltip = observer(({ content, toolTipContent }: { content: any, toolTipContent: any }) => { return
{content} - + {toolTipContent}
}> diff --git a/src/components/BlinkoSettings/MusicSetting.tsx b/src/components/BlinkoSettings/MusicSetting.tsx new file mode 100644 index 00000000..0f9eb604 --- /dev/null +++ b/src/components/BlinkoSettings/MusicSetting.tsx @@ -0,0 +1,58 @@ +import { observer } from "mobx-react-lite"; +import { Input } from "@nextui-org/react"; +import { useTranslation } from "react-i18next"; +import { Item, ItemWithTooltip } from "./Item"; +import { RootStore } from "@/store"; +import { BlinkoStore } from "@/store/blinkoStore"; +import { PromiseCall } from "@/store/standard/PromiseState"; +import { api } from "@/lib/trpc"; +import { CollapsibleCard } from "../Common/CollapsibleCard"; + +export const MusicSetting = observer(() => { + const { t } = useTranslation(); + const blinko = RootStore.Get(BlinkoStore); + + return ( + + + {t('spotify-consumer-key')}} toolTipContent={t('spotify-consumer-key-tip')} /> +
{t('spotify-consumer-key-tip-2')}
+
} + rightContent={ + { + PromiseCall(api.config.update.mutate({ + key: 'spotifyConsumerKey', + value: e.target.value + })); + }} + placeholder={t('enter-spotify-consumer-key')} + /> + } + /> + + {t('spotify-consumer-secret')}} + rightContent={ + { + PromiseCall(api.config.update.mutate({ + key: 'spotifyConsumerSecret', + value: e.target.value + })); + }} + placeholder={t('enter-spotify-consumer-secret')} + /> + } + /> + + ); +}); diff --git a/src/components/Common/AttachmentRender/audioRender.tsx b/src/components/Common/AttachmentRender/audioRender.tsx new file mode 100644 index 00000000..b0d5c34d --- /dev/null +++ b/src/components/Common/AttachmentRender/audioRender.tsx @@ -0,0 +1,264 @@ +import React, { useEffect, useState, useRef } from 'react'; +import { api } from '@/lib/trpc'; +import { FileType } from '../Editor/type'; +import { DeleteIcon, DownloadIcon } from './icons'; +import { Icon } from '@iconify/react'; +import { RootStore, useStore } from '@/store'; +import { MusicManagerStore } from '@/store/musicManagerStore' +import { observer } from 'mobx-react-lite'; + +interface AudioMetadata { + coverUrl?: string; + trackName?: string; + albumName?: string; + artists?: string[]; + previewUrl?: string; +} + +interface Props { + files: FileType[]; + preview?: boolean; +} + +export const AudioRender = observer(({ files, preview = false }: Props) => { + const [audioMetadata, setAudioMetadata] = useState>({}); + const musicManager = RootStore.Get(MusicManagerStore); + const [isPlaying, setIsPlaying] = useState>({}); + const audioRefs = useRef>({}); + const progressRefs = useRef>({}); + const [currentTime, setCurrentTime] = useState>({}); + const [duration, setDuration] = useState>({}); + const audioRef = useRef(null); + + useEffect(() => { + if (audioRef.current) { + musicManager.initAudio(audioRef.current); + } + }, []); + + const getMetadata = async (file: FileType) => { + try { + const metadata = await api.public.musicMetadata.query({ + filePath: file.preview + }); + setAudioMetadata(prev => ({ + ...prev, + [file.name]: metadata + })); + } catch (error) { + console.error('Failed to fetch audio metadata:', error); + } + }; + + useEffect(() => { + files?.filter(i => i.previewType === 'audio').forEach(file => { + getMetadata(file); + }); + }, [files]); + + const isCurrentPlaying = (fileName: string) => { + return musicManager.isPlaying && musicManager.currentTrack?.file.name === fileName; + }; + + const togglePlay = (fileName: string) => { + const audioFiles = files.filter(i => i.previewType === 'audio'); + const index = audioFiles.findIndex(f => f.name === fileName); + + if (index === -1) return; + console.log('togglePlay', fileName); + musicManager.setPlaylist(audioFiles, audioMetadata); + + if (musicManager.currentTrack?.file.name === fileName) { + console.log('togglePlay', 'pause'); + musicManager.togglePlay(); + } else { + console.log('togglePlay', 'play'); + musicManager.playTrack(index); + } + }; + + const formatTime = (seconds: number): string => { + const minutes = Math.floor(seconds / 60); + const remainingSeconds = Math.floor(seconds % 60); + return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`; + }; + + useEffect(() => { + const updateProgress = () => { + if (!musicManager.audioElement) return; + + const fileName = musicManager.currentTrack?.file.name; + if (!fileName) return; + + const progress = progressRefs.current[fileName]; + if (!progress) return; + + const percentage = (musicManager.currentTime / musicManager.duration) * 100; + progress.style.width = `${percentage}%`; + + setCurrentTime(prev => ({ + ...prev, + [fileName]: formatTime(musicManager.currentTime) + })); + }; + + const interval = setInterval(updateProgress, 100); + return () => clearInterval(interval); + }, [musicManager.currentTrack]); + + const handleProgressBarClick = (e: React.MouseEvent, fileName: string) => { + if (!musicManager.audioElement || musicManager.currentTrack?.file.name !== fileName) return; + + const progressBar = e.currentTarget; + const rect = progressBar.getBoundingClientRect(); + const x = e.clientX - rect.left; + const percentage = x / rect.width; + + musicManager.seek(musicManager.duration * percentage); + }; + + const handleLoadedMetadata = (fileName: string) => { + const audio = audioRefs.current[fileName]; + if (!audio) return; + + setDuration(prev => ({ + ...prev, + [fileName]: formatTime(audio.duration) + })); + }; + + const handleEnded = (fileName: string) => { + setIsPlaying(prev => ({ ...prev, [fileName]: false })); + const progress = progressRefs.current[fileName]; + if (progress) { + progress.style.width = '0%'; + } + }; + + const handleProgressBarDrag = (e: React.MouseEvent, fileName: string) => { + if (!musicManager.audioElement || musicManager.currentTrack?.file.name !== fileName) return; + + const progressBar = e.currentTarget; + const updateTimeFromMousePosition = (e: MouseEvent) => { + const rect = progressBar.getBoundingClientRect(); + const x = Math.max(0, Math.min(e.clientX - rect.left, rect.width)); + const percentage = x / rect.width; + musicManager.seek(musicManager.duration * percentage); + }; + + const handleMouseMove = (e: MouseEvent) => { + e.preventDefault(); + updateTimeFromMousePosition(e); + }; + + const handleMouseUp = () => { + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); + }; + + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); + }; + + const getBackgroundStyle = (coverUrl?: string) => { + if (!coverUrl) { + return 'bg-sencondbackground hover:bg-hover'; + } + return 'bg-cover bg-center relative overflow-hidden hover:bg-opacity-90'; + }; + + return ( +
+