diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index fea021fa..28ba6a56 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -24,7 +24,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: 1.22.2 + go-version: 1.23.0 - run: make lint-backend lint: runs-on: ubuntu-latest @@ -47,7 +47,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: 1.22.2 + go-version: 1.23.0 - run: make test-backend test: runs-on: ubuntu-latest @@ -66,7 +66,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-go@v5 with: - go-version: 1.22.2 + go-version: 1.23.0 - uses: actions/setup-node@v4 with: node-version: '18' diff --git a/.goreleaser.yml b/.goreleaser.yml index d500f967..2fbdefc6 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,3 +1,5 @@ +version: 2 + project_name: filebrowser env: @@ -189,7 +191,7 @@ brews: repository: owner: filebrowser name: homebrew-tap - folder: Formula + directory: Formula homepage: https://filebrowser.org commit_author: name: FileBrowser Robot diff --git a/.tx/config b/.tx/config index 339e80b4..f7363d04 100644 --- a/.tx/config +++ b/.tx/config @@ -1,6 +1,6 @@ [main] host = https://www.transifex.com -lang_map = pt_BR: pt-br, zh_CN: zh-cn, zh_HK: zh-hk, zh_TW: zh-tw, nl_BE: nl-be, sv_SE: sv-se +lang_map = pt_BR: pt-br, zh_CN: zh-cn, zh_HK: zh-hk, zh_TW: zh-tw, nl_BE: nl-be, sv_SE: sv-se, cz-CS: cz_cs [file-browser.file-browser] file_filter = frontend/src/i18n/.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 886f5df9..d173411e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,50 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [2.31.1](https://github.com/filebrowser/filebrowser/compare/v2.31.0...v2.31.1) (2024-08-30) + + +### Bug Fixes + +* command not found in shell ([#3438](https://github.com/filebrowser/filebrowser/issues/3438)) ([121d9ab](https://github.com/filebrowser/filebrowser/commit/121d9abecdc7d4e923cfc5023519995938a6ccae)) + + +### Build + +* update to alpine 3.20 ([#3447](https://github.com/filebrowser/filebrowser/issues/3447)) ([7de6bc4](https://github.com/filebrowser/filebrowser/commit/7de6bc4a912b5734dd0df02ed8391e78619e2615)) + +## [2.31.0](https://github.com/filebrowser/filebrowser/compare/v2.30.0...v2.31.0) (2024-08-29) + + +### Features + +* add Czech translation ([#3416](https://github.com/filebrowser/filebrowser/issues/3416)) ([8e67a12](https://github.com/filebrowser/filebrowser/commit/8e67a12f260caefcbe419c2281025b9b15f02bf3)) +* Added epub preview. Resolves [#3375](https://github.com/filebrowser/filebrowser/issues/3375) ([#3376](https://github.com/filebrowser/filebrowser/issues/3376)) ([99a6382](https://github.com/filebrowser/filebrowser/commit/99a6382b320874e94f9bd74708f46dd9a7485d3c)) +* implement markdown file preview in Ace editor ([#3431](https://github.com/filebrowser/filebrowser/issues/3431)) ([b0f4604](https://github.com/filebrowser/filebrowser/commit/b0f4604f44e6a35e07df3000f106f523cd942cfc)) +* support mime type for epub extension ([#3425](https://github.com/filebrowser/filebrowser/issues/3425)) ([f6f7e5f](https://github.com/filebrowser/filebrowser/commit/f6f7e5fea3ff7073ee652008a51cb5445a6f3d5d)) + + +### Bug Fixes + +* clipboard copy in safari ([#3261](https://github.com/filebrowser/filebrowser/issues/3261)) ([1fccc5d](https://github.com/filebrowser/filebrowser/commit/1fccc5d649add2a56c55e75cf9dec4851e6d7cbf)) +* CSS selectors for listing icons ([#3277](https://github.com/filebrowser/filebrowser/issues/3277)) ([2a90cdf](https://github.com/filebrowser/filebrowser/commit/2a90cdfdaff8655c7cb1167c01994a0978dece8f)) +* fix catalan i18n file ([090272e](https://github.com/filebrowser/filebrowser/commit/090272e3b7c56a940c4aa2d28f860c574aa17d53)) +* fixing an issue where the upload indicator would "jump" around in the UI ([#3354](https://github.com/filebrowser/filebrowser/issues/3354)) ([7be5644](https://github.com/filebrowser/filebrowser/commit/7be564495226bc6846289a56edb8893511036c6e)) +* **frontend:** N files selected hint use i18n ([#3390](https://github.com/filebrowser/filebrowser/issues/3390)) ([10bf3cf](https://github.com/filebrowser/filebrowser/commit/10bf3cffbf8eb7d95fe4e1cc6acf1012329744b9)) +* pdf preview header ([#3274](https://github.com/filebrowser/filebrowser/issues/3274)) ([a838868](https://github.com/filebrowser/filebrowser/commit/a8388689f3019083f263845900f683ddc13884dc)) +* pull down to refresh within editor ([#3378](https://github.com/filebrowser/filebrowser/issues/3378)) ([21783ed](https://github.com/filebrowser/filebrowser/commit/21783ed91a13ad52afdb411e43faf14fb6ef6e42)) + + +### Build + +* bump go libs ([b596567](https://github.com/filebrowser/filebrowser/commit/b596567c6163d57eaefbf3e30d84cfca65c24cdf)) +* bump go version to 1.23.0 ([364fdaa](https://github.com/filebrowser/filebrowser/commit/364fdaaf0c1eace82ff8637d337cc1b32e5e9972)) +* bump golangci-lint to 1.60.3 ([a6347c8](https://github.com/filebrowser/filebrowser/commit/a6347c88586e584b4565277b0010fa9ff2576b1f)) +* **deps-dev:** bump braces from 3.0.2 to 3.0.3 in /frontend ([#3316](https://github.com/filebrowser/filebrowser/issues/3316)) ([e8589be](https://github.com/filebrowser/filebrowser/commit/e8589be6409a2b29edd44ee2edd3fbf6b2d72724)) +* **deps-dev:** bump ws from 8.16.0 to 8.17.1 in /frontend ([#3321](https://github.com/filebrowser/filebrowser/issues/3321)) ([c3465f9](https://github.com/filebrowser/filebrowser/commit/c3465f99136506d51b813be4f31b289e708da0ce)) +* **deps:** bump golang.org/x/image from 0.15.0 to 0.18.0 ([#3335](https://github.com/filebrowser/filebrowser/issues/3335)) ([30a8ddf](https://github.com/filebrowser/filebrowser/commit/30a8ddf113862e3de2c09547662b7f2af8a30dfe)) +* fix goreleaser file ([056cfa8](https://github.com/filebrowser/filebrowser/commit/056cfa8facdca4c397a6b245028d4c9d3f0ca518)) + ## [2.30.0](https://github.com/filebrowser/filebrowser/compare/v2.29.0...v2.30.0) (2024-05-19) diff --git a/Dockerfile.s6 b/Dockerfile.s6 index 233feb22..63c43018 100644 --- a/Dockerfile.s6 +++ b/Dockerfile.s6 @@ -1,4 +1,4 @@ -FROM ghcr.io/linuxserver/baseimage-alpine:3.17 +FROM ghcr.io/linuxserver/baseimage-alpine:3.20 RUN apk --update add ca-certificates \ mailcap \ diff --git a/Dockerfile.s6.aarch64 b/Dockerfile.s6.aarch64 index d7f3dcee..752e3ed3 100644 --- a/Dockerfile.s6.aarch64 +++ b/Dockerfile.s6.aarch64 @@ -1,4 +1,4 @@ -FROM ghcr.io/linuxserver/baseimage-alpine:arm64v8-3.17 +FROM ghcr.io/linuxserver/baseimage-alpine:arm64v8-3.20 RUN apk --update add ca-certificates \ mailcap \ diff --git a/Dockerfile.s6.armhf b/Dockerfile.s6.armhf deleted file mode 100644 index 17bd1def..00000000 --- a/Dockerfile.s6.armhf +++ /dev/null @@ -1,16 +0,0 @@ -FROM ghcr.io/linuxserver/baseimage-alpine:arm32v7-3.17 - -RUN apk --update add ca-certificates \ - mailcap \ - curl - -HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \ - CMD curl -f http://localhost/health || exit 1 - -# copy local files -COPY docker/root/ / -COPY filebrowser /usr/bin/filebrowser - -# ports and volumes -VOLUME /srv /config /database -EXPOSE 80 \ No newline at end of file diff --git a/docker/root/etc/cont-init.d/20-config b/docker/root/etc/cont-init.d/20-config old mode 100644 new mode 100755 diff --git a/docker/root/etc/services.d/filebrowser/run b/docker/root/etc/services.d/filebrowser/run old mode 100644 new mode 100755 diff --git a/files/mime.go b/files/mime.go index 1f715f5c..1e6d9bef 100644 --- a/files/mime.go +++ b/files/mime.go @@ -597,6 +597,7 @@ var types = map[string]string{ ".m3u8": "application/x-mpegURL", ".mpd": "application/dash+xml", ".webp": "image/webp", + ".epub": "application/epub+zip", } //nolint:gochecknoinits diff --git a/frontend/package-lock.json b/frontend/package-lock.json index dcab386e..6a95d1ab 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -18,6 +18,7 @@ "js-base64": "^3.7.7", "jwt-decode": "^4.0.0", "lodash-es": "^4.17.21", + "marked": "^14.1.0", "material-icons": "^1.13.12", "normalize.css": "^8.0.1", "pinia": "^2.1.7", @@ -32,6 +33,7 @@ "vue-final-modal": "^4.5.4", "vue-i18n": "^9.10.2", "vue-lazyload": "^3.0.0", + "vue-reader": "^1.2.14", "vue-router": "^4.3.0", "vue-toastification": "^2.0.0-rc.5" }, @@ -2762,6 +2764,16 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, + "node_modules/@types/localforage": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@types/localforage/-/localforage-0.0.34.tgz", + "integrity": "sha512-tJxahnjm9dEI1X+hQSC5f2BSd/coZaqbIl1m3TCl0q9SVuC52XcXfV0XmoCU1+PmjyucuVITwoTnN8OlTbEXXA==", + "deprecated": "This is a stub types definition for localforage (https://github.com/localForage/localForage). localforage provides its own type definitions, so you don't need @types/localforage installed!", + "license": "MIT", + "dependencies": { + "localforage": "*" + } + }, "node_modules/@types/lodash": { "version": "4.17.0", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz", @@ -3095,31 +3107,29 @@ } }, "node_modules/@volar/language-core": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.1.6.tgz", - "integrity": "sha512-pAlMCGX/HatBSiDFMdMyqUshkbwWbLxpN/RL7HCQDOo2gYBE+uS+nanosLc1qR6pTQ/U8q00xt8bdrrAFPSC0A==", + "version": "2.4.0-alpha.19", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.0-alpha.19.tgz", + "integrity": "sha512-8H6x3vC0/SbOqy1cU0s7/Hk9nNH61t8qOoghjX7XpguLagEyjF6zkMp6C5F/sBlpr0WpeByc1KDfyBHumB8ZfA==", "dev": true, "dependencies": { - "@volar/source-map": "2.1.6" + "@volar/source-map": "2.4.0-alpha.19" } }, "node_modules/@volar/source-map": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.1.6.tgz", - "integrity": "sha512-TeyH8pHHonRCHYI91J7fWUoxi0zWV8whZTVRlsWHSYfjm58Blalkf9LrZ+pj6OiverPTmrHRkBsG17ScQyWECw==", - "dev": true, - "dependencies": { - "muggle-string": "^0.4.0" - } + "version": "2.4.0-alpha.19", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.0-alpha.19.tgz", + "integrity": "sha512-f86wTDVVjWUtaBcmFYTTLtWpBfooNfZmwvn73f+KXIchYqKgQVzOuGbORuVPwSrAjYLPW0f8Aa5Gb9TbdI17Ug==", + "dev": true }, "node_modules/@volar/typescript": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.1.6.tgz", - "integrity": "sha512-JgPGhORHqXuyC3r6skPmPHIZj4LoMmGlYErFTuPNBq9Nhc9VTv7ctHY7A3jMN3ngKEfRrfnUcwXHztvdSQqNfw==", + "version": "2.4.0-alpha.19", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.0-alpha.19.tgz", + "integrity": "sha512-Q7tfVVL3HmvUlqjcoTEk/6LiwlDF13XP8avAARovK4Qc6Djsckc+COLovr+ZX6kIxxTdM+Ggv9C0nCNFjMeiSQ==", "dev": true, "dependencies": { - "@volar/language-core": "2.1.6", - "path-browserify": "^1.0.1" + "@volar/language-core": "2.4.0-alpha.19", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" } }, "node_modules/@vue/compiler-core": { @@ -3168,6 +3178,16 @@ "@vue/shared": "3.4.21" } }, + "node_modules/@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", + "dev": true, + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, "node_modules/@vue/devtools-api": { "version": "6.6.1", "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.1.tgz", @@ -3212,18 +3232,19 @@ } }, "node_modules/@vue/language-core": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.7.tgz", - "integrity": "sha512-Vh1yZX3XmYjn9yYLkjU8DN6L0ceBtEcapqiyclHne8guG84IaTzqtvizZB1Yfxm3h6m7EIvjerLO5fvOZO6IIQ==", + "version": "2.0.29", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.29.tgz", + "integrity": "sha512-o2qz9JPjhdoVj8D2+9bDXbaI4q2uZTHQA/dbyZT4Bj1FR9viZxDJnLcKVHfxdn6wsOzRgpqIzJEEmSSvgMvDTQ==", "dev": true, "dependencies": { - "@volar/language-core": "~2.1.3", + "@volar/language-core": "~2.4.0-alpha.18", "@vue/compiler-dom": "^3.4.0", + "@vue/compiler-vue2": "^2.7.16", "@vue/shared": "^3.4.0", "computeds": "^0.0.1", "minimatch": "^9.0.3", - "path-browserify": "^1.0.1", - "vue-template-compiler": "^2.7.14" + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1" }, "peerDependencies": { "typescript": "*" @@ -4097,8 +4118,7 @@ "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, "node_modules/cross-spawn": { "version": "7.0.3", @@ -4148,6 +4168,19 @@ "resolved": "https://registry.npmjs.org/custom-error-instance/-/custom-error-instance-2.1.1.tgz", "integrity": "sha512-p6JFxJc3M4OTD2li2qaHkDCw9SfMw82Ldr6OC9Je1aXiGfhx2W8p3GaoeaGrPJTUN9NirTM/KTxHWMUdR1rsUg==" }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/data-urls": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", @@ -4299,6 +4332,72 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/epubjs": { + "version": "0.3.93", + "resolved": "https://registry.npmjs.org/epubjs/-/epubjs-0.3.93.tgz", + "integrity": "sha512-c06pNSdBxcXv3dZSbXAVLE1/pmleRhOT6mXNZo6INKmvuKpYB65MwU/lO7830czCtjIiK9i+KR+3S+p0wtljrw==", + "license": "BSD-2-Clause", + "dependencies": { + "@types/localforage": "0.0.34", + "@xmldom/xmldom": "^0.7.5", + "core-js": "^3.18.3", + "event-emitter": "^0.3.5", + "jszip": "^3.7.1", + "localforage": "^1.10.0", + "lodash": "^4.17.21", + "marks-pane": "^1.0.9", + "path-webpack": "0.0.3" + } + }, + "node_modules/epubjs/node_modules/@xmldom/xmldom": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.13.tgz", + "integrity": "sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/esbuild": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", @@ -4657,6 +4756,21 @@ "node": ">=8" } }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -4734,6 +4848,25 @@ "node": ">=0.10.0" } }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "license": "ISC", + "dependencies": { + "type": "^2.7.2" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5160,6 +5293,12 @@ "node": ">= 4" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -5203,8 +5342,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/is-binary-path": { "version": "2.1.0", @@ -5318,8 +5456,7 @@ "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, "node_modules/isexe": { "version": "2.0.0", @@ -5465,6 +5602,18 @@ "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", "dev": true }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, "node_modules/jwt-decode": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", @@ -5500,6 +5649,33 @@ "node": ">= 0.8.0" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/localforage": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", + "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", + "license": "Apache-2.0", + "dependencies": { + "lie": "3.1.1" + } + }, + "node_modules/localforage/node_modules/lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -5518,8 +5694,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash-es": { "version": "4.17.21", @@ -5636,6 +5811,24 @@ "node": ">=12" } }, + "node_modules/marked": { + "version": "14.1.0", + "resolved": "https://registry.npmmirror.com/marked/-/marked-14.1.0.tgz", + "integrity": "sha512-P93GikH/Pde0hM5TAXEd8I4JAYi8IB03n8qzW8Bh1BIEFpEyBoYxi/XWZA53LSpTeLBiMQOoSMj0u5E/tiVYTA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/marks-pane": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/marks-pane/-/marks-pane-1.0.9.tgz", + "integrity": "sha512-Ahs4oeG90tbdPWwAJkAAoHg2lRR8lAs9mZXETNPO9hYg3AkjUJBKi1NQ4aaIQZVGrig7c/3NUV1jANl8rFTeMg==", + "license": "MIT" + }, "node_modules/material-icons": { "version": "1.13.12", "resolved": "https://registry.npmjs.org/material-icons/-/material-icons-1.13.12.tgz", @@ -5663,12 +5856,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -5796,6 +5989,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "license": "ISC" + }, "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", @@ -5976,6 +6175,12 @@ "node": ">=8" } }, + "node_modules/path-webpack": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/path-webpack/-/path-webpack-0.0.3.tgz", + "integrity": "sha512-AmeDxedoo5svf7aB3FYqSAKqMxys014lVKBzy1o/5vv9CtU7U4wgGWL1dA2o6MOzcD53ScN4Jmiq6VbtLz1vIQ==", + "license": "MIT" + }, "node_modules/pathe": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", @@ -6216,8 +6421,7 @@ "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "node_modules/proper-lockfile": { "version": "4.1.2", @@ -6308,7 +6512,6 @@ "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -6557,8 +6760,7 @@ "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/safe-json-parse": { "version": "4.0.0", @@ -6619,6 +6821,12 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -6719,7 +6927,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -6956,6 +7163,12 @@ "node": ">=18" } }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", + "license": "ISC" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -7134,8 +7347,7 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/video.js": { "version": "8.10.0", @@ -7290,6 +7502,12 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "dev": true + }, "node_modules/vue": { "version": "3.4.21", "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.21.tgz", @@ -7374,6 +7592,55 @@ "resolved": "https://registry.npmjs.org/vue-lazyload/-/vue-lazyload-3.0.0.tgz", "integrity": "sha512-h2keL/Rj550dLgesgOtXJS9qOiSMmuJNeVlfNAYV1/IYwOQYaWk5mFJlwRxmZDK9YC5gECcFLYYj7z1lKSf9ug==" }, + "node_modules/vue-reader": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/vue-reader/-/vue-reader-1.2.14.tgz", + "integrity": "sha512-aGtJsmEdYcWLZmMqOrAzcb8/SYUcaz8zj9GtYFP+1cHs53IBG45/uZkywn/7RjWwFtiixSkLO7w/7qiqcyjwGQ==", + "license": "ISC", + "workspaces": [ + "test/vue2", + "test/vue2.7" + ], + "dependencies": { + "epubjs": "^0.3.93", + "vue-demi": "latest" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^2.0.0 || >=3.0.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/vue-reader/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/vue-router": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.3.0.tgz", @@ -7388,16 +7655,6 @@ "vue": "^3.2.0" } }, - "node_modules/vue-template-compiler": { - "version": "2.7.16", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", - "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", - "dev": true, - "dependencies": { - "de-indent": "^1.0.2", - "he": "^1.2.0" - } - }, "node_modules/vue-toastification": { "version": "2.0.0-rc.5", "resolved": "https://registry.npmjs.org/vue-toastification/-/vue-toastification-2.0.0-rc.5.tgz", @@ -7407,20 +7664,20 @@ } }, "node_modules/vue-tsc": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.7.tgz", - "integrity": "sha512-LYa0nInkfcDBB7y8jQ9FQ4riJTRNTdh98zK/hzt4gEpBZQmf30dPhP+odzCa+cedGz6B/guvJEd0BavZaRptjg==", + "version": "2.0.29", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.29.tgz", + "integrity": "sha512-MHhsfyxO3mYShZCGYNziSbc63x7cQ5g9kvijV7dRe1TTXBRLxXyL0FnXWpUF1xII2mJ86mwYpYsUmMwkmerq7Q==", "dev": true, "dependencies": { - "@volar/typescript": "~2.1.3", - "@vue/language-core": "2.0.7", + "@volar/typescript": "~2.4.0-alpha.18", + "@vue/language-core": "2.0.29", "semver": "^7.5.4" }, "bin": { "vue-tsc": "bin/vue-tsc.js" }, "peerDependencies": { - "typescript": "*" + "typescript": ">=5.0.0" } }, "node_modules/w3c-xmlserializer": { diff --git a/frontend/package.json b/frontend/package.json index a5089c94..a46c6e38 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -29,6 +29,7 @@ "jwt-decode": "^4.0.0", "lodash-es": "^4.17.21", "material-icons": "^1.13.12", + "marked": "^14.1.0", "normalize.css": "^8.0.1", "pinia": "^2.1.7", "pretty-bytes": "^6.1.1", @@ -42,6 +43,7 @@ "vue-final-modal": "^4.5.4", "vue-i18n": "^9.10.2", "vue-lazyload": "^3.0.0", + "vue-reader": "^1.2.14", "vue-router": "^4.3.0", "vue-toastification": "^2.0.0-rc.5" }, diff --git a/frontend/src/api/tus.ts b/frontend/src/api/tus.ts index dd824357..5e4e116b 100644 --- a/frontend/src/api/tus.ts +++ b/frontend/src/api/tus.ts @@ -61,7 +61,7 @@ export async function upload( fileData.hasStarted = true; fileData.lastProgressTimestamp = Date.now(); - fileData.interval = setInterval(() => { + fileData.interval = window.setInterval(() => { calcProgress(filePath); }, SPEED_UPDATE_INTERVAL); } diff --git a/frontend/src/components/settings/Languages.vue b/frontend/src/components/settings/Languages.vue index 992a50c8..14acc4cb 100644 --- a/frontend/src/components/settings/Languages.vue +++ b/frontend/src/components/settings/Languages.vue @@ -18,6 +18,7 @@ export default { he: "עברית", hu: "Magyar", ar: "العربية", + ca: "Català", de: "Deutsch", el: "Ελληνικά", en: "English", diff --git a/frontend/src/css/_shell.css b/frontend/src/css/_shell.css index 1d2813a9..3b4eec0e 100644 --- a/frontend/src/css/_shell.css +++ b/frontend/src/css/_shell.css @@ -14,7 +14,7 @@ width: 100%; } -.shell__divider{ +.shell__divider { background: rgba(127, 127, 127, 0.3); width: 100%; height: 8px; @@ -69,8 +69,6 @@ body.rtl .shell-content { font-size: inherit; } - - .shell__prompt { width: 1.2rem; } @@ -84,5 +82,5 @@ body.rtl .shell-content { font-family: inherit; white-space: pre-wrap; width: 100%; - color:var(--textSecondary); + color: var(--textSecondary); } diff --git a/frontend/src/css/_variables.css b/frontend/src/css/_variables.css index a56285ba..85ad96ec 100644 --- a/frontend/src/css/_variables.css +++ b/frontend/src/css/_variables.css @@ -54,5 +54,5 @@ --borderPrimary: rgba(255, 255, 255, 0.05); --borderSecondary: rgba(255, 255, 255, 0.15); --dividerPrimary: rgba(30, 30, 30, 0.4); - --dividerSecondary:rgba(30, 30, 30, 0.6); + --dividerSecondary: rgba(30, 30, 30, 0.6); } diff --git a/frontend/src/css/epubReader.css b/frontend/src/css/epubReader.css new file mode 100644 index 00000000..a575fb27 --- /dev/null +++ b/frontend/src/css/epubReader.css @@ -0,0 +1,78 @@ +.epub-reader { + display: flex; + align-items: flex-end; + height: 100%; +} + +.epub-reader .container { + width: 100%; + max-width: 100%; + height: calc(100% - 64px); + margin: 0; +} + +.epub-reader .arrow.pre { + left: 0; +} + +.epub-reader .readerArea { + background-color: var(--background) !important; +} + +.epub-reader .titleArea { + color: var(--text); +} + +.epub-reader .tocButtonBar { + background: var(--divider); +} + +.epub-reader .tocButton { + color: var(--text); +} + +.epub-reader .tocButton.tocButtonExpanded { + background-color: var(--background); +} + +.epub-reader .tocAreaButton.active { + color: var(--blue); + border-color: var(--dark-blue); +} + +.epub-reader .tocArea { + background-color: var(--background); +} + +.epub-reader .readerArea .arrow { + color: var(--text); +} + +.epub-reader .readerArea .arrow:hover { + color: var(--hover); +} + +.epub-reader .size { + display: flex; + gap: 5px; + align-items: center; + z-index: 111; + right: 25px; + outline: none; + position: absolute; + top: 78px; +} + +.epub-reader .size span { + color: var(--textSecondary); +} + +.epub-reader .size button { + background: none; + outline: none; + border: none; + width: 25px; + height: 25px; + color: var(--textPrimary); + padding: 0; +} diff --git a/frontend/src/css/mdPreview.css b/frontend/src/css/mdPreview.css new file mode 100644 index 00000000..bf2863f6 --- /dev/null +++ b/frontend/src/css/mdPreview.css @@ -0,0 +1,13 @@ +.md_preview { + overflow-y: auto; + max-height: 80vh; + padding: 1rem; + border: 1px solid #000; + font-size: 20px; + line-height: 1.2; +} + +#preview-container { + overflow: auto; + max-height: 80vh; /* Match the max-height of md_preview for scrolling */ +} diff --git a/frontend/src/css/styles.css b/frontend/src/css/styles.css index f8d4ef9d..19b94b95 100644 --- a/frontend/src/css/styles.css +++ b/frontend/src/css/styles.css @@ -15,6 +15,8 @@ @import "./dashboard.css"; @import "./login.css"; @import "./mobile.css"; +@import "./epubReader.css"; +@import "./mdPreview.css"; /* For testing only :focus { diff --git a/frontend/src/i18n/ca.json b/frontend/src/i18n/ca.json new file mode 100644 index 00000000..bc00fd2a --- /dev/null +++ b/frontend/src/i18n/ca.json @@ -0,0 +1,264 @@ +{ + "buttons": { + "cancel": "Cancel·lar", + "clear": "Netejar", + "close": "Tancar", + "continue": "Continuar", + "copy": "Copiar", + "copyFile": "Copiar fitxer", + "copyToClipboard": "Copiar al porta-retalls", + "copyDownloadLinkToClipboard": "Copiar l'enllaç de descàrrega al portapapers", + "create": "Crear", + "delete": "Esborrar", + "download": "Descarregar", + "file": "Fitxer", + "folder": "Carpeta", + "fullScreen": "Canviar a pantalla completa", + "hideDotfiles": "Ocultar fitxers que comencen per punt", + "info": "Info", + "more": "Més", + "move": "Moure", + "moveFile": "Moure fitxer", + "new": "Nou", + "next": "Següent", + "ok": "D'acord", + "permalink": "Enllaç permanent", + "previous": "Anterior", + "publish": "Publicar", + "rename": "Reanomenar", + "replace": "Substituir", + "reportIssue": "Reportar problema", + "save": "Desar", + "schedule": "Programar", + "search": "Cercar", + "select": "Seleccionar", + "selectMultiple": "Selecció múltiple", + "share": "Compartir", + "shell": "Prem Enter per cercar...", + "submit": "Enviar", + "switchView": "Canviar vista", + "toggleSidebar": "Mostrar/ocultar menú", + "update": "Actualitzar", + "upload": "Pujar", + "openFile": "Obrir fitxer", + "discardChanges": "Descartar" + }, + "download": { + "downloadFile": "Descarregar fitxer", + "downloadFolder": "Descarregar directori", + "downloadSelected": "Descarregar seleccionats" + }, + "upload": { + "abortUpload": "Are you sure you wish to abort?" + }, + "errors": { + "forbidden": "No tens els permisos necessaris per accedir.", + "internal": "La veritat és que alguna cosa ha anat malament.", + "notFound": "No es pot accedir a aquest lloc.", + "connection": "No es pot accedir al servidor." + }, + "files": { + "body": "Cos", + "closePreview": "Tancar vista prèvia", + "files": "Fitxers", + "folders": "Carpetes", + "home": "Inici", + "lastModified": "Última modificació", + "loading": "Carregant...", + "lonely": "Un se sent molt sol aquí...", + "metadata": "Metadades", + "multipleSelectionEnabled": "Selecció múltiple activada", + "name": "Nom", + "size": "Mida", + "sortByLastModified": "Ordenar per última modificació", + "sortByName": "Ordenar per nom", + "sortBySize": "Ordenar per mida", + "noPreview": "La vista prèvia no està disponible per a aquest fitxer." + }, + "help": { + "click": "seleccionar fitxer o carpeta", + "ctrl": { + "click": "seleccionar múltiples fitxers o carpetes", + "f": "obre la cerca", + "s": "desa un fitxer o el descarrega a la carpeta en què estàs" + }, + "del": "elimina els ítems seleccionats", + "doubleClick": "obre un fitxer o carpeta", + "esc": "neteja la selecció i/o tanca la finestra", + "f1": "aquesta informació", + "f2": "reanomenar fitxer", + "help": "Ajuda" + }, + "login": { + "createAnAccount": "Crear un compte", + "loginInstead": "Usuari ja existent", + "password": "Contrasenya", + "passwordConfirm": "Confirmació de contrasenya", + "passwordsDontMatch": "Les contrasenyes no coincideixen", + "signup": "Registra't", + "submit": "Iniciar sessió", + "username": "Usuari", + "usernameTaken": "Nom d'usuari no disponible", + "wrongCredentials": "Usuari i/o contrasenya incorrectes" + }, + "permanent": "Permanent", + "prompts": { + "copy": "Copiar", + "copyMessage": "Tria el lloc on vols copiar els teus fitxers:", + "currentlyNavigating": "Actualment estàs a:", + "deleteMessageMultiple": "Estàs segur que vols eliminar {count} fitxer(s)?", + "deleteMessageSingle": "Estàs segur que vols eliminar aquest fitxer/carpeta?", + "deleteMessageShare": "Estàs segur que vols eliminar aquest recurs compartit ({path})?", + "deleteUser": "Esteu segur que voleu eliminar aquest usuari?", + "deleteTitle": "Esborrar fitxers", + "displayName": "Nom:", + "download": "Descarregar fitxers", + "downloadMessage": "Tria el format de descàrrega.", + "error": "Alguna cosa ha fallat", + "fileInfo": "Informació del fitxer", + "filesSelected": "{count} fitxers seleccionats.", + "lastModified": "Última modificació", + "move": "Moure", + "moveMessage": "Tria una nova casa per als teus fitxers/carpeta(s):", + "newArchetype": "Crea un nou post basat en un arquetip. El teu fitxer serà creat a la carpeta de contingut.", + "newDir": "Nova carpeta", + "newDirMessage": "Escriu el nom de la nova carpeta.", + "newFile": "Nou fitxer", + "newFileMessage": "Escriu el nom del nou fitxer.", + "numberDirs": "Nombre de carpetes", + "numberFiles": "Nombre de fitxers", + "rename": "Reanomenar", + "renameMessage": "Escriu el nou nom per a", + "replace": "Substituir", + "replaceMessage": "Un dels fitxers que intentes pujar està creant conflicte pel seu nom. Vols canviar el nom del ja existent?\n", + "schedule": "Programar", + "scheduleMessage": "Tria una hora i data per programar la publicació d'aquest post.", + "show": "Mostrar", + "size": "Mida", + "upload": "Pujar", + "uploadFiles": "Pujant {files} fitxers...", + "uploadMessage": "Seleccioneu una opció per pujar.", + "optionalPassword": "Contrasenya opcional", + "resolution": "Resolució", + "discardEditorChanges": "Esteu segur que voleu descartar els canvis que heu fet?" + }, + "search": { + "images": "Imatges", + "music": "Música", + "pdf": "PDF", + "pressToSearch": "Prem Enter per cercar...", + "search": "Cercar...", + "typeToSearch": "Escriu per fer una cerca...", + "types": "Tipus", + "video": "Vídeo" + }, + "settings": { + "admin": "Admin", + "administrator": "Administrador", + "allowCommands": "Executar comandes", + "allowEdit": "Editar, reanomenar i esborrar fitxers o carpetes", + "allowNew": "Crear nous fitxers i carpetes", + "allowPublish": "Publicar nous posts i pàgines", + "allowSignup": "Permetre registre d'usuaris", + "avoidChanges": "(deixar en blanc per evitar canvis)", + "branding": "Marca", + "brandingDirectoryPath": "Ruta de la carpeta de personalització de marca", + "brandingHelp": "Pots personalitzar com es veu la teva instància de FileBrowser canviant-li el nom, reemplaçant el logotip, afegint estils personalitzats i fins i tot deshabilitant els enllaços externs que apunten cap a GitHub. \nPer a més informació sobre personalització de marca, si us plau revisa el {0}.", + "changePassword": "Canviar contrasenya", + "commandRunner": "Executor de comandes", + "commandRunnerHelp": "Aquí pots establir les comandes que s'executen en els esdeveniments anomenats. Has d'escriure'n una per línia. Les variables d'entorn {0} i {1} estaran disponibles, sent {0} relativa a {1}. Per a més informació sobre aquesta característica i les variables d'entorn disponibles, si us plau llegeix el {2}.", + "commandsUpdated": "Comandes actualitzades!", + "createUserDir": "Crea automàticament una carpeta d'inici quan s'afegeix un usuari", + "tusUploads": "Càrregues a trossos", + "tusUploadsHelp": "El File Browser suporta càrregues de fitxers a trossos, permetent la creació de càrregues de fitxers eficients, fiables, reanudables i a trossos fins i tot en xarxes poc fiables.", + "tusUploadsChunkSize": "Indica la mida màxima d'una sol·licitud (s'utilitzaran càrregues directes per a càrregues més petites). Podeu introduir un enter pla que indiqui la mida en bytes o una cadena com 10MB, 1GB, etc.", + "tusUploadsRetryCount": "Nombre de reintents a realitzar si una part falla en carregar-se.", + "userHomeBasePath": "Ruta base per als directoris personals dels usuaris", + "userScopeGenerationPlaceholder": "L'àmbit es generarà automàticament", + "createUserHomeDirectory": "Crear el directori principal de l'usuari", + "customStylesheet": "Modificar full d'estils", + "defaultUserDescription": "Aquestes són les configuracions per defecte per a nous usuaris.", + "disableExternalLinks": "Deshabilitar enllaços externs (excepte documentació)", + "disableUsedDiskPercentage": "Desactivar el gràfic de percentatge de disc utilitzat", + "documentation": "documentació", + "examples": "Exemples", + "executeOnShell": "Executar a la shell", + "executeOnShellDescription": "Per defecte, FileBrowser executa les comandes cridant directament els seus binaris. Si vols executar-los en una shell en lloc (com Bash o PowerShell), pots definir-ho aquí amb els arguments i flags necessaris. Si es defineix, la comanda que s'executa s'afegirà com a argument. Això s'aplica tant a les comandes d'usuari com als ganxos d'esdeveniments.", + "globalRules": "Es tracta d'un conjunt global de regles de permís i rebuig. S'apliquen a tots els usuaris. Pots definir regles específiques en la configuració de cada usuari per anul·lar aquestes.", + "globalSettings": "Ajustos globals", + "hideDotfiles": "Ocultar fitxers que comencen per punt", + "insertPath": "Introdueix la ruta", + "insertRegex": "Introduir expressió regular", + "instanceName": "Nom de la instància", + "language": "Idioma", + "lockPassword": "Evitar que l'usuari canviï la contrasenya", + "newPassword": "La teva nova contrasenya", + "newPasswordConfirm": "Confirma la teva contrasenya", + "newUser": "Nou usuari", + "password": "Contrasenya", + "passwordUpdated": "Contrasenya actualitzada!", + "path": "Ruta", + "perm": { + "create": "Crear fitxers i directoris", + "delete": "Eliminar fitxers i directoris", + "download": "Descarregar", + "execute": "Executar comandes", + "modify": "Editar fitxers", + "rename": "Reanomenar o moure fitxers i directoris", + "share": "Compartir fitxers" + }, + "permissions": "Permisos", + "permissionsHelp": "Pots nomenar l'usuari com a administrador o triar els permisos individualment. Si selecciones \"Administrador\", totes les altres opcions s'activaran automàticament. L'administració d'usuaris és un privilegi d'administrador.\n", + "profileSettings": "Ajustos del perfil", + "ruleExample1": "prevé l'accés a una extensió de fitxer (Com .git) en cada carpeta.\n", + "ruleExample2": "bloqueja l'accés al fitxer anomenat Caddyfile a la carpeta arrel.", + "rules": "Regles", + "rulesHelp": "Aquí pots definir un conjunt de regles de permisos per a aquest usuari específic. Els fitxers bloquejats no es mostraran en les llistes i no seran accessibles per l'usuari. Pots utilitzar regex i rutes relatives a l'arrel de l'usuari.\n", + "scope": "Arrel", + "setDateFormat": "Establir el format exacte de la data", + "settingsUpdated": "Ajustos actualitzats!", + "shareDuration": "Compartir Duració", + "shareManagement": "Gestió Compartida", + "shareDeleted": "Recurs compartit eliminat!", + "singleClick": "Utilitza un sol clic per obrir fitxers i directoris", + "themes": { + "default": "Valor per defecte del sistema", + "dark": "Fosc", + "light": "Clar", + "title": "Tema" + }, + "user": "Usuari", + "userCommands": "Comandes", + "userCommandsHelp": "Una llista separada per espais amb les comandes permeses per a aquest usuari. Exemple:\n", + "userCreated": "Usuari creat!", + "userDefaults": "Configuració d'usuari per defecte", + "userDeleted": "Usuari eliminat!", + "userManagement": "Administració d'usuaris", + "userUpdated": "Usuari actualitzat!", + "username": "Usuari", + "users": "Usuaris" + }, + "sidebar": { + "help": "Ajuda", + "hugoNew": "Nou Hugo", + "login": "Iniciar sessió", + "logout": "Tancar sessió", + "myFiles": "Els meus fitxers", + "newFile": "Nou fitxer", + "newFolder": "Nova carpeta", + "preview": "Vista prèvia", + "settings": "Ajustos", + "signup": "Registra't", + "siteSettings": "Ajustos del lloc" + }, + "success": { + "linkCopied": "Enllaç copiat!" + }, + "time": { + "days": "Dies", + "hours": "Hores", + "minutes": "Minuts", + "seconds": "Segons", + "unit": "Unitat" + } +} diff --git a/frontend/src/i18n/cz_cs.json b/frontend/src/i18n/cz_cs.json new file mode 100644 index 00000000..1147f38c --- /dev/null +++ b/frontend/src/i18n/cz_cs.json @@ -0,0 +1,264 @@ +{ + "buttons": { + "cancel": "Zrušit", + "clear": "Vymazat", + "close": "Zavřít", + "continue": "Pokračovat", + "copy": "Kopírovat", + "copyFile": "Kopírovat soubor", + "copyToClipboard": "Kopírovat do schránky", + "copyDownloadLinkToClipboard": "Kopírovat odkaz na stažení do schránky", + "create": "Vytvořit", + "delete": "Smazat", + "download": "Stáhnout", + "file": "Soubor", + "folder": "Složka", + "fullScreen": "Přepnout na celou obrazovku", + "hideDotfiles": "Skrýt skryté soubory", + "info": "Informace", + "more": "Více", + "move": "Přesunout", + "moveFile": "Přesunout soubor", + "new": "Nový", + "next": "Další", + "ok": "OK", + "permalink": "Získat trvalý odkaz", + "previous": "Předchozí", + "publish": "Publikovat", + "rename": "Přejmenovat", + "replace": "Nahradit", + "reportIssue": "Nahlásit problém", + "save": "Uložit", + "schedule": "Naplánovat", + "search": "Hledat", + "select": "Vybrat", + "selectMultiple": "Vybrat více", + "share": "Sdílet", + "shell": "Přepnout shell", + "submit": "Odeslat", + "switchView": "Přepnout zobrazení", + "toggleSidebar": "Přepnout postranní panel", + "update": "Aktualizovat", + "upload": "Nahrát", + "openFile": "Otevřít soubor", + "discardChanges": "Zrušit změny" + }, + "download": { + "downloadFile": "Stáhnout soubor", + "downloadFolder": "Stáhnout složku", + "downloadSelected": "Stáhnout vybrané" + }, + "upload": { + "abortUpload": "Opravdu chcete přerušit nahrávání?" + }, + "errors": { + "forbidden": "Nemáte oprávnění k přístupu.", + "internal": "Nastala vážná chyba.", + "notFound": "Tuto lokaci nelze najít.", + "connection": "Server nelze dosáhnout." + }, + "files": { + "body": "Tělo", + "closePreview": "Zavřít náhled", + "files": "Soubory", + "folders": "Složky", + "home": "Domů", + "lastModified": "Naposledy změněno", + "loading": "Načítání...", + "lonely": "Je tu osaměle...", + "metadata": "Metadata", + "multipleSelectionEnabled": "Vícenásobný výběr povolen", + "name": "Název", + "size": "Velikost", + "sortByLastModified": "Seřadit podle poslední změny", + "sortByName": "Seřadit podle názvu", + "sortBySize": "Seřadit podle velikosti", + "noPreview": "Náhled pro tento soubor není k dispozici." + }, + "help": { + "click": "vyberte soubor nebo adresář", + "ctrl": { + "click": "vybrat více souborů nebo adresářů", + "f": "otevřít vyhledávání", + "s": "uložit soubor nebo stáhnout adresář, kde se nacházíte" + }, + "del": "smazat vybrané položky", + "doubleClick": "otevřít soubor nebo adresář", + "esc": "zrušit výběr a/nebo zavřít výzvu", + "f1": "tato informace", + "f2": "přejmenovat soubor", + "help": "Nápověda" + }, + "login": { + "createAnAccount": "Vytvořit účet", + "loginInstead": "Již máte účet", + "password": "Heslo", + "passwordConfirm": "Potvrzení hesla", + "passwordsDontMatch": "Hesla se neshodují", + "signup": "Registrace", + "submit": "Přihlásit se", + "username": "Uživatelské jméno", + "usernameTaken": "Uživatelské jméno již existuje", + "wrongCredentials": "Nesprávné přihlašovací údaje" + }, + "permanent": "Trvalý", + "prompts": { + "copy": "Kopírovat", + "copyMessage": "Vyberte místo, kam chcete soubory kopírovat:", + "currentlyNavigating": "Aktuálně navigujete v:", + "deleteMessageMultiple": "Opravdu chcete smazat {count} soubor(ů)?", + "deleteMessageSingle": "Opravdu chcete smazat tento soubor/složku?", + "deleteMessageShare": "Opravdu chcete smazat toto sdílení({path})?", + "deleteUser": "Opravdu chcete smazat tohoto uživatele?", + "deleteTitle": "Smazat soubory", + "displayName": "Zobrazované jméno:", + "download": "Stáhnout soubory", + "downloadMessage": "Vyberte formát, který chcete stáhnout.", + "error": "Něco se pokazilo", + "fileInfo": "Informace o souboru", + "filesSelected": "{count} souborů vybráno.", + "lastModified": "Naposledy změněno", + "move": "Přesunout", + "moveMessage": "Vyberte nové umístění pro váš soubor(y)/složku(y):", + "newArchetype": "Vytvořit nový příspěvek na základě archetypu. Váš soubor bude vytvořen ve složce content.", + "newDir": "Nový adresář", + "newDirMessage": "Pojmenujte svůj nový adresář.", + "newFile": "Nový soubor", + "newFileMessage": "Pojmenujte svůj nový soubor.", + "numberDirs": "Počet adresářů", + "numberFiles": "Počet souborů", + "rename": "Přejmenovat", + "renameMessage": "Vložte nový název pro", + "replace": "Nahradit", + "replaceMessage": "Jeden ze souborů, které se snažíte nahrát, má konfliktní název. Chcete tento soubor přeskočit a pokračovat v nahrávání, nebo nahradit stávající?", + "schedule": "Naplánovat", + "scheduleMessage": "Vyberte datum a čas pro naplánování publikace tohoto příspěvku.", + "show": "Zobrazit", + "size": "Velikost", + "upload": "Nahrát", + "uploadFiles": "Nahrávání {files} souborů...", + "uploadMessage": "Vyberte možnost pro nahrání.", + "optionalPassword": "Volitelné heslo", + "resolution": "Rozlišení", + "discardEditorChanges": "Opravdu chcete zrušit provedené změny?" + }, + "search": { + "images": "Obrázky", + "music": "Hudba", + "pdf": "PDF", + "pressToSearch": "Stiskněte enter pro hledání...", + "search": "Hledat...", + "typeToSearch": "Zadejte pro hledání...", + "types": "Typy", + "video": "Video" + }, + "settings": { + "admin": "Admin", + "administrator": "Administrátor", + "allowCommands": "Povolit příkazy", + "allowEdit": "Upravit, přejmenovat a mazat soubory nebo adresáře", + "allowNew": "Vytvářet nové soubory a adresáře", + "allowPublish": "Publikovat nové příspěvky a stránky", + "allowSignup": "Povolit uživatelům registraci", + "avoidChanges": "(ponechte prázdné pro zabránění změnám)", + "branding": "Branding", + "brandingDirectoryPath": "Cesta ke složce s brandingem", + "brandingHelp": "Můžete přizpůsobit vzhled a dojem z vaší instance File Browseru změnou názvu, nahrazením loga, přidáním vlastních stylů a dokonce zakázat externí odkazy na GitHub.\nPro více informací o přizpůsobení brandingu se podívejte na {0}.", + "changePassword": "Změnit heslo", + "commandRunner": "Spouštění příkazů", + "commandRunnerHelp": "Zde můžete nastavit příkazy, které se spustí při určených událostech. Každý příkaz musí být na samostatném řádku. Budou k dispozici proměnné prostředí {0} a {1}, přičemž {0} se vztahuje na {1}. Pro více informací o této funkci a dostupných proměnných prostředí si přečtěte {2}.", + "commandsUpdated": "Příkazy aktualizovány!", + "createUserDir": "Automaticky vytvořit domovskou složku uživatele při přidání nového uživatele", + "tusUploads": "Nahrávání po částech", + "tusUploadsHelp": "File Browser podporuje nahrávání souborů po částech, což umožňuje vytváření efektivních, spolehlivých, obnovitelných a rozdělených nahrávek souborů i na nespolehlivých sítích.", + "tusUploadsChunkSize": "Maximální velikost požadavku (přímé nahrávání bude použito pro menší nahrávky). Můžete zadat prosté číslo označující velikost v bajtech nebo řetězec jako 10MB, 1GB atd.", + "tusUploadsRetryCount": "Počet pokusů o opakování, pokud se nahrání části nezdaří.", + "userHomeBasePath": "Základní cesta pro domovské adresáře uživatelů", + "userScopeGenerationPlaceholder": "Rozsah bude automaticky vygenerován", + "createUserHomeDirectory": "Vytvořit domovský adresář uživatele", + "customStylesheet": "Vlastní stylový soubor", + "defaultUserDescription": "Toto jsou výchozí nastavení pro nové uživatele.", + "disableExternalLinks": "Zakázat externí odkazy (kromě dokumentace)", + "disableUsedDiskPercentage": "Zakázat graf s procentem využitého disku", + "documentation": "dokumentace", + "examples": "Příklady", + "executeOnShell": "Spustit na shellu", + "executeOnShellDescription": "Ve výchozím nastavení File Browser spouští příkazy přímo voláním jejich binárek. Pokud je chcete spouštět na shellu (např. Bash nebo PowerShell), můžete to zde definovat s požadovanými argumenty a příznaky. Pokud je nastaveno, příkaz, který spustíte, bude přidán jako argument. To platí jak pro uživatelské příkazy, tak pro háky událostí.", + "globalRules": "Jedná se o globální sadu povolení a zakázání pravidel. Platí pro každého uživatele. Specifická pravidla můžete definovat v nastaveních každého uživatele, aby přepsala tato pravidla.", + "globalSettings": "Globální nastavení", + "hideDotfiles": "Skrýt skryté soubory", + "insertPath": "Vložte cestu", + "insertRegex": "Vložte regex výraz", + "instanceName": "Název instance", + "language": "Jazyk", + "lockPassword": "Zabránit uživateli ve změně hesla", + "newPassword": "Vaše nové heslo", + "newPasswordConfirm": "Potvrďte své nové heslo", + "newUser": "Nový uživatel", + "password": "Heslo", + "passwordUpdated": "Heslo bylo aktualizováno!", + "path": "Cesta", + "perm": { + "create": "Vytvářet soubory a adresáře", + "delete": "Mazat soubory a adresáře", + "download": "Stahovat", + "execute": "Spouštět příkazy", + "modify": "Upravit soubory", + "rename": "Přejmenovat nebo přesunout soubory a adresáře", + "share": "Sdílet soubory" + }, + "permissions": "Oprávnění", + "permissionsHelp": "Můžete nastavit uživatele jako administrátora nebo zvolit jednotlivá oprávnění. Pokud vyberete \"Administrátor\", všechny ostatní možnosti budou automaticky zaškrtnuty. Správa uživatelů zůstává výsadou administrátora.\n", + "profileSettings": "Nastavení profilu", + "ruleExample1": "zabraňuje přístupu k jakémukoli skrytému souboru (např. .git, .gitignore) v každé složce.\n", + "ruleExample2": "blokuje přístup k souboru s názvem Caddyfile v kořenovém adresáři.", + "rules": "Pravidla", + "rulesHelp": "Zde můžete definovat sadu povolení a zakázání pravidel pro tohoto konkrétního uživatele. Blokované soubory se nebudou zobrazovat v seznamech a uživatel k nim nebude mít přístup. Podporujeme regex a cesty relativní k rozsahu uživatele.\n", + "scope": "Rozsah", + "setDateFormat": "Nastavit přesný formát data", + "settingsUpdated": "Nastavení aktualizována!", + "shareDuration": "Doba sdílení", + "shareManagement": "Správa sdílení", + "shareDeleted": "Sdílení bylo smazáno!", + "singleClick": "Použít jediné kliknutí pro otevření souborů a adresářů", + "themes": { + "default": "Systémové výchozí", + "dark": "Tmavý", + "light": "Světlý", + "title": "Motiv" + }, + "user": "Uživatel", + "userCommands": "Příkazy", + "userCommandsHelp": "Seznam dostupných příkazů pro tohoto uživatele oddělený mezerami. Příklad:\n", + "userCreated": "Uživatel vytvořen!", + "userDefaults": "Výchozí nastavení uživatele", + "userDeleted": "Uživatel smazán!", + "userManagement": "Správa uživatelů", + "userUpdated": "Uživatel aktualizován!", + "username": "Uživatelské jméno", + "users": "Uživatelé" + }, + "sidebar": { + "help": "Nápověda", + "hugoNew": "Hugo Nový", + "login": "Přihlásit se", + "logout": "Odhlásit se", + "myFiles": "Moje soubory", + "newFile": "Nový soubor", + "newFolder": "Nová složka", + "preview": "Náhled", + "settings": "Nastavení", + "signup": "Registrace", + "siteSettings": "Nastavení webu" + }, + "success": { + "linkCopied": "Odkaz zkopírován!" + }, + "time": { + "days": "Dny", + "hours": "Hodiny", + "minutes": "Minuty", + "seconds": "Sekundy", + "unit": "Časová jednotka" + } +} diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index 00d43b9d..1360bbec 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -24,6 +24,7 @@ "ok": "OK", "permalink": "Get Permanent Link", "previous": "Previous", + "preview": "Preview", "publish": "Publish", "rename": "Rename", "replace": "Replace", diff --git a/frontend/src/i18n/uk.json b/frontend/src/i18n/uk.json index b95a99c3..655988a0 100644 --- a/frontend/src/i18n/uk.json +++ b/frontend/src/i18n/uk.json @@ -36,7 +36,7 @@ "switchView": "Вид", "toggleSidebar": "Бічна панель", "update": "Оновити", - "upload": "Завантажити", + "upload": "Вивантажити", "openFile": "Відкрити файл" }, "download": { @@ -102,9 +102,9 @@ "deleteMessageMultiple": "Видалити ці файли ({count})?", "deleteMessageSingle": "Видалити цей файл/каталог?", "deleteMessageShare": "Видалити цей спільний файл/каталог ({path})?", - "deleteTitle": "Видалити файлы", + "deleteTitle": "Видалити файли", "displayName": "Відображене ім'я:", - "download": "Завантажити файлы", + "download": "Завантажити файли", "downloadMessage": "Виберіть формат, в якому хочете завантажити.", "error": "Помилка", "fileInfo": "Інформація про файл", @@ -127,8 +127,8 @@ "scheduleMessage": "Запланувати дату та час публікації.", "show": "Показати", "size": "Розмір", - "upload": "Завантажити", - "uploadMessage": "Виберіть варіант для завантаження.", + "upload": "Вивантажити", + "uploadMessage": "Виберіть варіант для вивантаження.", "optionalPassword": "Необов'язковий пароль" }, "search": { diff --git a/frontend/src/i18n/zh-cn.json b/frontend/src/i18n/zh-cn.json index 1aea4134..376dc029 100644 --- a/frontend/src/i18n/zh-cn.json +++ b/frontend/src/i18n/zh-cn.json @@ -22,6 +22,7 @@ "ok": "确定", "permalink": "获取永久链接", "previous": "上一个", + "preview": "预览", "publish": "发布", "rename": "重命名", "replace": "替换", diff --git a/frontend/src/i18n/zh-tw.json b/frontend/src/i18n/zh-tw.json index fdb2447c..050666f8 100644 --- a/frontend/src/i18n/zh-tw.json +++ b/frontend/src/i18n/zh-tw.json @@ -6,7 +6,7 @@ "copy": "複製", "copyFile": "複製檔案", "copyToClipboard": "複製到剪貼簿", - "copyDownloadLinkToClipboard": "複製到剪貼簿", + "copyDownloadLinkToClipboard": "複製到剪貼簿", "create": "建立", "delete": "刪除", "download": "下載", @@ -228,7 +228,7 @@ "title": "主題" }, "user": "使用者", - "userCommands": "使用者命令(Shell 命令)", + "userCommands": "使用者命令(Shell 命令)", "userCommandsHelp": "指定該使用者可以執行的命令(Shell 命令),用空格分隔。例如:", "userCreated": "使用者已建立!", "userDefaults": "使用者預設選項", diff --git a/frontend/src/stores/upload.ts b/frontend/src/stores/upload.ts index 60dfdb8a..6fef19a0 100644 --- a/frontend/src/stores/upload.ts +++ b/frontend/src/stores/upload.ts @@ -22,7 +22,7 @@ function formatSize(bytes: number): string { const i = Math.floor(Math.log(bytes) / Math.log(k)); // Return the rounded size with two decimal places - return (bytes / k ** i).toFixed(2) + " " + sizes[i]; + return (bytes / k ** i).toFixed(2) + " " + sizes[i]; } export const useUploadStore = defineStore("upload", { diff --git a/frontend/src/views/files/Editor.vue b/frontend/src/views/files/Editor.vue index 214d8d4f..7e4d7a9b 100644 --- a/frontend/src/views/files/Editor.vue +++ b/frontend/src/views/files/Editor.vue @@ -11,11 +11,26 @@ :label="t('buttons.save')" @action="save()" /> + + -
+ +
+ +
@@ -33,10 +48,11 @@ import Breadcrumbs from "@/components/Breadcrumbs.vue"; import { useAuthStore } from "@/stores/auth"; import { useFileStore } from "@/stores/file"; import { useLayoutStore } from "@/stores/layout"; -import { inject, onBeforeUnmount, onMounted, ref } from "vue"; +import { inject, onBeforeUnmount, onMounted, ref, watchEffect } from "vue"; import { useRoute, useRouter } from "vue-router"; import { useI18n } from "vue-i18n"; import { getTheme } from "@/utils/theme"; +import { marked } from "marked"; const $showError = inject("$showError")!; @@ -51,11 +67,37 @@ const router = useRouter(); const editor = ref(null); +const isPreview = ref(false); +const previewContent = ref(""); +const isMarkdownFile = + fileStore.req?.name.endsWith(".md") || + fileStore.req?.name.endsWith(".markdown"); + onMounted(() => { window.addEventListener("keydown", keyEvent); + window.addEventListener("wheel", handleScroll); const fileContent = fileStore.req?.content || ""; + watchEffect(async () => { + if (isMarkdownFile && isPreview.value) { + const new_value = editor.value?.getValue() || ""; + try { + previewContent.value = await marked(new_value); + } catch (error) { + console.error("Failed to convert content to HTML:", error); + previewContent.value = ""; + } + + const previewContainer = document.getElementById("preview-container"); + if (previewContainer) { + previewContainer.addEventListener("wheel", handleScroll, { + capture: true, + }); + } + } + }); + ace.config.set( "basePath", `https://cdn.jsdelivr.net/npm/ace-builds@${ace_version}/src-min-noconflict/` @@ -82,6 +124,7 @@ onMounted(() => { onBeforeUnmount(() => { window.removeEventListener("keydown", keyEvent); + window.removeEventListener("wheel", handleScroll); editor.value?.destroy(); }); @@ -102,6 +145,13 @@ const keyEvent = (event: KeyboardEvent) => { save(); }; +const handleScroll = (event: WheelEvent) => { + const editorContainer = document.getElementById("preview-container"); + if (editorContainer) { + editorContainer.scrollTop += event.deltaY; + } +}; + const save = async () => { const button = "save"; buttons.loading("save"); @@ -126,4 +176,8 @@ const close = () => { let uri = url.removeLastDir(route.path) + "/"; router.push({ path: uri }); }; + +const preview = () => { + isPreview.value = !isPreview.value; +}; diff --git a/frontend/src/views/files/FileListing.vue b/frontend/src/views/files/FileListing.vue index a26ac67e..c1b048a6 100644 --- a/frontend/src/views/files/FileListing.vue +++ b/frontend/src/views/files/FileListing.vue @@ -82,9 +82,9 @@
- {{ fileStore.selectedCount }} selected + + {{ t("prompts.filesSelected", fileStore.selectedCount) }} + - + {{ name }}