forked from Mirrors/elk
Compare commits
146 commits
renovate/d
...
main
Author | SHA1 | Date | |
---|---|---|---|
b217b4dc25 | |||
f2edec194f | |||
087f8cc992 | |||
6efbf8768b | |||
cd934fcd55 | |||
7f1e97a37c | |||
58c84b2f9b | |||
322ffeef12 | |||
4a8110a52e | |||
d481c0ae7a | |||
68ffb627e7 | |||
b221687139 | |||
7b10620cca | |||
498face3cf | |||
672ff46072 | |||
81b5f8b8e7 | |||
721e55be06 | |||
eba4cc0757 | |||
80818ed52d | |||
|
25fb7c1c97 | ||
|
839aa52e86 | ||
|
9ff55289ea | ||
|
73293fbcd3 | ||
|
a27c218802 | ||
|
f8fc0efadc | ||
|
618a5b2df3 | ||
|
1146dca5f6 | ||
|
f86e856ee6 | ||
|
6d13d61227 | ||
|
0de9825bf2 | ||
|
3f0b234cc4 | ||
|
8f04ea8eee | ||
|
7dcafa3fe0 | ||
|
bead2183b2 | ||
|
59dda09cd4 | ||
|
d0b115751f | ||
|
c6787aae3f | ||
|
9025416ab3 | ||
|
aa28257754 | ||
|
d807e06fa0 | ||
|
611d556936 | ||
|
4313002950 | ||
|
de11a60b17 | ||
|
5064b269e7 | ||
|
d8d9975756 | ||
|
eee671cdc3 | ||
|
587c063aba | ||
|
28514e956d | ||
|
42aeb8fa35 | ||
|
f6f50a582e | ||
|
f86818867b | ||
|
82d962a54b | ||
|
1b189043e4 | ||
|
a4867566d9 | ||
|
0757db69b2 | ||
|
f0de25c992 | ||
|
660549b08b | ||
|
7807730118 | ||
|
b526db0860 | ||
|
0133324ded | ||
|
e9ab0cd40b | ||
|
9251ec496b | ||
|
bd4cd02b2b | ||
|
74ccfece5d | ||
35b4c80311 | |||
f6a081d199 | |||
5e419045ed | |||
cfdbb66b96 | |||
c717aace86 | |||
6713329a5e | |||
7470468077 | |||
9044b3bcad | |||
5bd9dce91e | |||
12e14cfc05 | |||
1ea4399765 | |||
991cb812da | |||
|
c89e499f96 | ||
|
89e3582dd7 | ||
|
48c013709a | ||
|
f90f0a2e61 | ||
|
c58b585855 | ||
|
ded2e0f3d7 | ||
9b77efe1d7 | |||
aec670a903 | |||
1218f92133 | |||
7c0986a005 | |||
ac01207283 | |||
ef169d682f | |||
|
21d5633233 | ||
|
7703565c75 | ||
|
5a9546ec0a | ||
|
bc30a8bd82 | ||
|
c432c2bd0d | ||
|
364fbd350b | ||
|
c64580f782 | ||
|
e7dfdafd59 | ||
|
b06ec9356d | ||
|
3b1a66c93c | ||
|
ed8a1811cc | ||
|
dfbe2e080d | ||
|
0fd9374e8c | ||
|
1c8e48bee4 | ||
|
3448335356 | ||
|
4954473f50 | ||
|
efa17caf5e | ||
|
df165f0023 | ||
|
0f583ece28 | ||
|
d579977790 | ||
|
8786c83db7 | ||
|
1ce913e69d | ||
|
48a8b74e7c | ||
|
1ff13952b0 | ||
|
02f7c4b291 | ||
|
9da77637b2 | ||
|
62f70250d5 | ||
|
873c62e9ef | ||
|
b1ff1e6277 | ||
|
f644148844 | ||
|
3120bbb77f | ||
|
6cbe65c9d8 | ||
|
1c908363cb | ||
|
c01a15c930 | ||
|
0c15aa55d8 | ||
|
9f04e17e57 | ||
|
308b50cbad | ||
|
e44833b18a | ||
|
0fa87f71a4 | ||
|
edfbe2c3ed | ||
|
70c7e93919 | ||
|
95e466146d | ||
|
efec212a9f | ||
|
1844af0a41 | ||
|
72b80d4984 | ||
|
6dc5a68c80 | ||
|
310b32c123 | ||
|
748dd5e19f | ||
|
c00d6f7bf8 | ||
|
fc5d248094 | ||
|
6f20ce5bba | ||
|
edcc8741bf | ||
|
3584151fab | ||
|
efb6967e6a | ||
|
eddbb1eee9 | ||
|
6b40319723 | ||
|
913e2892f7 | ||
|
a3c5272e07 |
156 changed files with 7121 additions and 3621 deletions
|
@ -1,15 +0,0 @@
|
||||||
*.css
|
|
||||||
*.png
|
|
||||||
*.ico
|
|
||||||
*.toml
|
|
||||||
*.patch
|
|
||||||
*.txt
|
|
||||||
Dockerfile
|
|
||||||
public/
|
|
||||||
public-dev/
|
|
||||||
public-staging/
|
|
||||||
https-dev-config/localhost.crt
|
|
||||||
https-dev-config/localhost.key
|
|
||||||
Dockerfile
|
|
||||||
elk-translation-status.json
|
|
||||||
docs/translation-status.json
|
|
19
.eslintrc
19
.eslintrc
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "@antfu",
|
|
||||||
"ignorePatterns": ["!pages/public"],
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": ["locales/**.json"],
|
|
||||||
"rules": {
|
|
||||||
"jsonc/sort-keys": "error"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"vue/no-restricted-syntax":["error", {
|
|
||||||
"selector": "VElement[name='a']",
|
|
||||||
"message": "Use NuxtLink instead."
|
|
||||||
}],
|
|
||||||
"n/prefer-global/process": "off"
|
|
||||||
}
|
|
||||||
}
|
|
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
||||||
- run: corepack enable
|
- run: corepack enable
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 20
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: 📦 Install dependencies
|
- name: 📦 Install dependencies
|
||||||
|
@ -32,6 +32,7 @@ jobs:
|
||||||
|
|
||||||
- name: 🧪 Test project
|
- name: 🧪 Test project
|
||||||
run: pnpm test:ci
|
run: pnpm test:ci
|
||||||
|
timeout-minutes: 10
|
||||||
|
|
||||||
- name: 📝 Lint
|
- name: 📝 Lint
|
||||||
run: pnpm lint
|
run: pnpm lint
|
||||||
|
|
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
|
@ -38,7 +38,7 @@ jobs:
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
tags: ${{ steps.metal.outputs.tags }}
|
tags: ${{ steps.metal.outputs.tags }}
|
||||||
labels: ${{ steps.metal.outputs.labels }}
|
labels: ${{ steps.metal.outputs.labels }}
|
||||||
|
|
45
.vscode/settings.json
vendored
45
.vscode/settings.json
vendored
|
@ -5,10 +5,6 @@
|
||||||
"unmute",
|
"unmute",
|
||||||
"unstorage"
|
"unstorage"
|
||||||
],
|
],
|
||||||
"editor.codeActionsOnSave": {
|
|
||||||
"source.fixAll.eslint": true
|
|
||||||
},
|
|
||||||
"editor.formatOnSave": false,
|
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"*.css": "postcss"
|
"*.css": "postcss"
|
||||||
},
|
},
|
||||||
|
@ -23,7 +19,44 @@
|
||||||
"i18n-ally.preferredDelimiter": "_",
|
"i18n-ally.preferredDelimiter": "_",
|
||||||
"i18n-ally.sortKeys": true,
|
"i18n-ally.sortKeys": true,
|
||||||
"i18n-ally.sourceLanguage": "en",
|
"i18n-ally.sourceLanguage": "en",
|
||||||
|
|
||||||
|
// Enable the ESlint flat config support
|
||||||
|
"eslint.experimental.useFlatConfig": true,
|
||||||
|
|
||||||
|
// Disable the default formatter, use eslint instead
|
||||||
"prettier.enable": false,
|
"prettier.enable": false,
|
||||||
"volar.completion.preferredTagNameCase": "pascal",
|
"editor.formatOnSave": false,
|
||||||
"volar.completion.preferredAttrNameCase": "kebab"
|
|
||||||
|
// Auto fix
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll": "explicit",
|
||||||
|
"source.organizeImports": "never"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Silent the stylistic rules in you IDE, but still auto fix them
|
||||||
|
"eslint.rules.customizations": [
|
||||||
|
{ "rule": "style/*", "severity": "off" },
|
||||||
|
{ "rule": "*-indent", "severity": "off" },
|
||||||
|
{ "rule": "*-spacing", "severity": "off" },
|
||||||
|
{ "rule": "*-spaces", "severity": "off" },
|
||||||
|
{ "rule": "*-order", "severity": "off" },
|
||||||
|
{ "rule": "*-dangle", "severity": "off" },
|
||||||
|
{ "rule": "*-newline", "severity": "off" },
|
||||||
|
{ "rule": "*quotes", "severity": "off" },
|
||||||
|
{ "rule": "*semi", "severity": "off" }
|
||||||
|
],
|
||||||
|
|
||||||
|
// Enable eslint for all supported languages
|
||||||
|
"eslint.validate": [
|
||||||
|
"javascript",
|
||||||
|
"javascriptreact",
|
||||||
|
"typescript",
|
||||||
|
"typescriptreact",
|
||||||
|
"vue",
|
||||||
|
"html",
|
||||||
|
"markdown",
|
||||||
|
"json",
|
||||||
|
"jsonc",
|
||||||
|
"yaml"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
22
.woodpecker.yml
Normal file
22
.woodpecker.yml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
steps:
|
||||||
|
- name: build docker
|
||||||
|
image: docker:25-cli
|
||||||
|
secrets: [user, pass]
|
||||||
|
commands:
|
||||||
|
- apk add git
|
||||||
|
- REPO=$(echo "$CI_REPO" | tr '[:upper:]' '[:lower:]')
|
||||||
|
- REGISTRY="dev.cat-enby.club"
|
||||||
|
- MAJOR=$(echo ${CI_COMMIT_TAG} | cut -d '.' -f 1 | tr -d 'v')
|
||||||
|
- MINOR=$(echo ${CI_COMMIT_TAG} | cut -d '.' -f 2)
|
||||||
|
- PATCH=$(echo ${CI_COMMIT_TAG} | cut -d '.' -f 3 | cut -d '-' -f 1)
|
||||||
|
- docker buildx build -t $${REGISTRY}/$${REPO}:v$${MAJOR:-0}.$${MINOR:-0}.$${PATCH-0} -t $${REGISTRY}/$${REPO}:v$${MAJOR:-0}.$${MINOR} -t $${REGISTRY}/$$REPO:v$${MAJOR:-0} -t $${REGISTRY}/$$REPO:latest .
|
||||||
|
- docker login --username $USER --password $PASS $${REGISTRY}
|
||||||
|
- docker push $${REGISTRY}/$${REPO}:v$${MAJOR:-0}.$${MINOR:-0}.$${PATCH-0}
|
||||||
|
- docker push $${REGISTRY}/$${REPO}:v$${MAJOR:-0}.$${MINOR}
|
||||||
|
- docker push $${REGISTRY}/$${REPO}:v$${MAJOR:-0}
|
||||||
|
- docker push $${REGISTRY}/$${REPO}:latest
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
when:
|
||||||
|
- repo: nikurasu:elk-test-ci
|
||||||
|
- event: tag
|
|
@ -21,7 +21,6 @@ To develop and test the Elk package:
|
||||||
2. Ensure using the latest Node.js (16.x).
|
2. Ensure using the latest Node.js (16.x).
|
||||||
If you have [nvm](https://github.com/nvm-sh/nvm), you can run `nvm i` to install the required version.
|
If you have [nvm](https://github.com/nvm-sh/nvm), you can run `nvm i` to install the required version.
|
||||||
|
|
||||||
|
|
||||||
3. The package manager used to install and link dependencies must be [pnpm](https://pnpm.io/) v7. To use it you must first enable [Corepack](https://github.com/nodejs/corepack) by running `corepack enable`. (Note: on Linux in a standard Node 16+ environment, you should follow the instructions to install via Node's `corepack` rather than using the `curl` command)
|
3. The package manager used to install and link dependencies must be [pnpm](https://pnpm.io/) v7. To use it you must first enable [Corepack](https://github.com/nodejs/corepack) by running `corepack enable`. (Note: on Linux in a standard Node 16+ environment, you should follow the instructions to install via Node's `corepack` rather than using the `curl` command)
|
||||||
|
|
||||||
4. Check out a branch where you can work and commit your changes:
|
4. Check out a branch where you can work and commit your changes:
|
||||||
|
@ -84,7 +83,7 @@ Simple approach used by most websites of relying on direction set in HTML elemen
|
||||||
We've added some `UnoCSS` utilities styles to help you with that:
|
We've added some `UnoCSS` utilities styles to help you with that:
|
||||||
- Do not use `left/right` padding and margin: for example `pl-1`. Use `padding-inline-start/end` instead. So `pl-1` should be `ps-1`, `pr-1` should be `pe-1`. The same rules apply to margin.
|
- Do not use `left/right` padding and margin: for example `pl-1`. Use `padding-inline-start/end` instead. So `pl-1` should be `ps-1`, `pr-1` should be `pe-1`. The same rules apply to margin.
|
||||||
- Do not use `rtl-` classes, such as `rtl-left-0`.
|
- Do not use `rtl-` classes, such as `rtl-left-0`.
|
||||||
- For icons that should be rotated for RTL, add `class="rtl-flip"`. This can only be used for icons outside of elements with `dir="auto"`, such as timeline, and is the only exception from the rule above. For icons inside the timeline, it might not work as expected.
|
- For icons that should be rotated for RTL, add `class="rtl-flip"`. This can only be used for icons outside of elements with `dir="auto"`, such as timeline, and is the only exception to the rule above. For icons inside the timeline, it might not work as expected.
|
||||||
- For absolute positioned elements, don't use `left/right`: for example `left-0`. Use `inset-inline-start/end` instead. `UnoCSS` shortcuts are `inset-is` for `inset-inline-start` and `inset-ie` for `inset-inline-end`. Example: `left-0` should be replaced with `inset-is-0`.
|
- For absolute positioned elements, don't use `left/right`: for example `left-0`. Use `inset-inline-start/end` instead. `UnoCSS` shortcuts are `inset-is` for `inset-inline-start` and `inset-ie` for `inset-inline-end`. Example: `left-0` should be replaced with `inset-is-0`.
|
||||||
- If you need to change the border radius for an entire left or right side, use `border-inline-start/end`. `UnoCSS` shortcuts are `rounded-is` for left side, `rounded-ie` for right side. Example: `rounded-l-5` should be replaced with `rounded-ie-5`.
|
- If you need to change the border radius for an entire left or right side, use `border-inline-start/end`. `UnoCSS` shortcuts are `rounded-is` for left side, `rounded-ie` for right side. Example: `rounded-l-5` should be replaced with `rounded-ie-5`.
|
||||||
- If you need to change the border radius for one corner, use `border-start-end-radius` and similar rules. `UnoCSS` shortcuts are `rounded` + top/bottom as either `-bs` (top) or `-be` (bottom) + left/right as either `-is` (left) or `-ie` (right). Example: `rounded-tl-0` should be replaced with `rounded-bs-is-0`.
|
- If you need to change the border radius for one corner, use `border-start-end-radius` and similar rules. `UnoCSS` shortcuts are `rounded` + top/bottom as either `-bs` (top) or `-be` (bottom) + left/right as either `-is` (left) or `-ie` (right). Example: `rounded-tl-0` should be replaced with `rounded-bs-is-0`.
|
||||||
|
|
|
@ -52,7 +52,6 @@ One could put Elk behind popular reverse proxies with SSL Handling like Traefik,
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> The provided Dockerfile creates a container which will eventually run Elk as non-root user and create a persistent named Docker volume upon first start (if that volume does not yet exist). This volume is always created with root permission. Failing to change the permissions of ```/elk/data``` inside this volume to UID:GID 911 (as specified for Elk in the Dockerfile) will prevent Elk from storing it's config for user accounts. You either have to fix the permission in the created named volume, or mount a directory with the correct permission to ```/elk/data``` into the container.
|
> The provided Dockerfile creates a container which will eventually run Elk as non-root user and create a persistent named Docker volume upon first start (if that volume does not yet exist). This volume is always created with root permission. Failing to change the permissions of ```/elk/data``` inside this volume to UID:GID 911 (as specified for Elk in the Dockerfile) will prevent Elk from storing it's config for user accounts. You either have to fix the permission in the created named volume, or mount a directory with the correct permission to ```/elk/data``` into the container.
|
||||||
|
|
||||||
|
|
||||||
### Ecosystem
|
### Ecosystem
|
||||||
|
|
||||||
These are known deployments using Elk as an alternative Web client for Mastodon servers or as a base for other projects in the fediverse:
|
These are known deployments using Elk as an alternative Web client for Mastodon servers or as a base for other projects in the fediverse:
|
||||||
|
|
|
@ -13,6 +13,7 @@ const { t } = useI18n()
|
||||||
const isSelf = useSelfAccount(() => account)
|
const isSelf = useSelfAccount(() => account)
|
||||||
const enable = computed(() => !isSelf.value && currentUser.value)
|
const enable = computed(() => !isSelf.value && currentUser.value)
|
||||||
const relationship = computed(() => props.relationship || useRelationship(account).value)
|
const relationship = computed(() => props.relationship || useRelationship(account).value)
|
||||||
|
const isLoading = computed(() => relationship.value === undefined)
|
||||||
|
|
||||||
const { client } = useMasto()
|
const { client } = useMasto()
|
||||||
|
|
||||||
|
@ -62,6 +63,10 @@ const buttonStyle = computed(() => {
|
||||||
if (relationship.value ? relationship.value.following : context === 'following')
|
if (relationship.value ? relationship.value.following : context === 'following')
|
||||||
return `text-base ${relationship.value?.followedBy ? 'border-strong' : 'border-base'}`
|
return `text-base ${relationship.value?.followedBy ? 'border-strong' : 'border-base'}`
|
||||||
|
|
||||||
|
// If loading, use a plain style
|
||||||
|
if (isLoading.value)
|
||||||
|
return 'text-base border-base'
|
||||||
|
|
||||||
// If not following, use a button style
|
// If not following, use a button style
|
||||||
return 'text-inverted bg-primary border-primary'
|
return 'text-inverted bg-primary border-primary'
|
||||||
})
|
})
|
||||||
|
@ -77,28 +82,33 @@ const buttonStyle = computed(() => {
|
||||||
:hover="!relationship?.blocking && !relationship?.muting && relationship?.following ? 'border-red text-red' : 'bg-base border-primary text-primary'"
|
:hover="!relationship?.blocking && !relationship?.muting && relationship?.following ? 'border-red text-red' : 'bg-base border-primary text-primary'"
|
||||||
@click="relationship?.blocking ? unblock() : relationship?.muting ? unmute() : toggleFollowAccount(relationship!, account)"
|
@click="relationship?.blocking ? unblock() : relationship?.muting ? unmute() : toggleFollowAccount(relationship!, account)"
|
||||||
>
|
>
|
||||||
<template v-if="relationship?.blocking">
|
<template v-if="isLoading">
|
||||||
<span elk-group-hover="hidden">{{ $t('account.blocking') }}</span>
|
<span i-svg-spinners-180-ring-with-bg />
|
||||||
<span hidden elk-group-hover="inline">{{ $t('account.unblock') }}</span>
|
|
||||||
</template>
|
|
||||||
<template v-if="relationship?.muting">
|
|
||||||
<span elk-group-hover="hidden">{{ $t('account.muting') }}</span>
|
|
||||||
<span hidden elk-group-hover="inline">{{ $t('account.unmute') }}</span>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="relationship ? relationship.following : context === 'following'">
|
|
||||||
<span elk-group-hover="hidden">{{ relationship?.followedBy ? $t('account.mutuals') : $t('account.following') }}</span>
|
|
||||||
<span hidden elk-group-hover="inline">{{ $t('account.unfollow') }}</span>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="relationship?.requested">
|
|
||||||
<span elk-group-hover="hidden">{{ $t('account.follow_requested') }}</span>
|
|
||||||
<span hidden elk-group-hover="inline">{{ $t('account.withdraw_follow_request') }}</span>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="relationship ? relationship.followedBy : context === 'followedBy'">
|
|
||||||
<span elk-group-hover="hidden">{{ $t('account.follows_you') }}</span>
|
|
||||||
<span hidden elk-group-hover="inline">{{ account.locked ? $t('account.request_follow') : $t('account.follow_back') }}</span>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<span>{{ account.locked ? $t('account.request_follow') : $t('account.follow') }}</span>
|
<template v-if="relationship?.blocking">
|
||||||
|
<span elk-group-hover="hidden">{{ $t('account.blocking') }}</span>
|
||||||
|
<span hidden elk-group-hover="inline">{{ $t('account.unblock') }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-if="relationship?.muting">
|
||||||
|
<span elk-group-hover="hidden">{{ $t('account.muting') }}</span>
|
||||||
|
<span hidden elk-group-hover="inline">{{ $t('account.unmute') }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="relationship ? relationship.following : context === 'following'">
|
||||||
|
<span elk-group-hover="hidden">{{ relationship?.followedBy ? $t('account.mutuals') : $t('account.following') }}</span>
|
||||||
|
<span hidden elk-group-hover="inline">{{ $t('account.unfollow') }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="relationship?.requested">
|
||||||
|
<span elk-group-hover="hidden">{{ $t('account.follow_requested') }}</span>
|
||||||
|
<span hidden elk-group-hover="inline">{{ $t('account.withdraw_follow_request') }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="relationship ? relationship.followedBy : context === 'followedBy'">
|
||||||
|
<span elk-group-hover="hidden">{{ $t('account.follows_you') }}</span>
|
||||||
|
<span hidden elk-group-hover="inline">{{ account.locked ? $t('account.request_follow') : $t('account.follow_back') }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<span>{{ account.locked ? $t('account.request_follow') : $t('account.follow') }}</span>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -2,39 +2,33 @@
|
||||||
import type { mastodon } from 'masto'
|
import type { mastodon } from 'masto'
|
||||||
import { fetchAccountByHandle } from '~/composables/cache'
|
import { fetchAccountByHandle } from '~/composables/cache'
|
||||||
|
|
||||||
type WatcherType = [acc?: mastodon.v1.Account, h?: string, v?: boolean]
|
type WatcherType = [acc?: mastodon.v1.Account | null, h?: string, v?: boolean]
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
account?: mastodon.v1.Account
|
account?: mastodon.v1.Account | null
|
||||||
handle?: string
|
handle?: string
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const hoverCard = ref()
|
const accountHover = ref()
|
||||||
const targetIsVisible = ref(false)
|
const hovered = useElementHover(accountHover)
|
||||||
const account = ref<mastodon.v1.Account | null | undefined>(props.account)
|
const account = ref<mastodon.v1.Account | null | undefined>(props.account)
|
||||||
|
|
||||||
useIntersectionObserver(
|
|
||||||
hoverCard,
|
|
||||||
([{ intersectionRatio }]) => {
|
|
||||||
targetIsVisible.value = intersectionRatio <= 0.75
|
|
||||||
},
|
|
||||||
)
|
|
||||||
watch(
|
watch(
|
||||||
() => [props.account, props.handle, targetIsVisible.value] satisfies WatcherType,
|
() => [props.account, props.handle, hovered.value] satisfies WatcherType,
|
||||||
([newAccount, newHandle, newVisible], oldProps) => {
|
([newAccount, newHandle, newVisible], oldProps) => {
|
||||||
|
if (!newVisible || process.test)
|
||||||
|
return
|
||||||
|
|
||||||
if (newAccount) {
|
if (newAccount) {
|
||||||
account.value = newAccount
|
account.value = newAccount
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newVisible)
|
|
||||||
return
|
|
||||||
|
|
||||||
if (newHandle) {
|
if (newHandle) {
|
||||||
const [_oldAccount, oldHandle, _oldVisible] = oldProps ?? [undefined, undefined, false]
|
const [_oldAccount, oldHandle, _oldVisible] = oldProps ?? [undefined, undefined, false]
|
||||||
if (!oldHandle || newHandle !== oldHandle || !account.value) {
|
if (!oldHandle || newHandle !== oldHandle || !account.value) {
|
||||||
|
@ -49,15 +43,22 @@ watch(
|
||||||
}
|
}
|
||||||
|
|
||||||
account.value = undefined
|
account.value = undefined
|
||||||
}, { immediate: true, flush: 'post' },
|
},
|
||||||
|
{ immediate: true, flush: 'post' },
|
||||||
)
|
)
|
||||||
|
|
||||||
const userSettings = useUserSettings()
|
const userSettings = useUserSettings()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<span ref="hoverCard">
|
<span ref="accountHover">
|
||||||
<VMenu v-if="!disabled && account && !getPreferences(userSettings, 'hideAccountHoverCard')" placement="bottom-start" :delay="{ show: 500, hide: 100 }" v-bind="$attrs" :close-on-content-click="false">
|
<VMenu
|
||||||
|
v-if="!disabled && account && !getPreferences(userSettings, 'hideAccountHoverCard')"
|
||||||
|
placement="bottom-start"
|
||||||
|
:delay="{ show: 500, hide: 100 }"
|
||||||
|
v-bind="$attrs"
|
||||||
|
:close-on-content-click="false"
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
<template #popper>
|
<template #popper>
|
||||||
<AccountHoverCard v-if="account" :account="account" />
|
<AccountHoverCard v-if="account" :account="account" />
|
||||||
|
|
|
@ -25,13 +25,16 @@ function shareAccount() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toggleReblogs() {
|
async function toggleReblogs() {
|
||||||
if (!relationship.value!.showingReblogs && await openConfirmDialog({
|
if (!relationship.value!.showingReblogs) {
|
||||||
title: t('confirm.show_reblogs.title'),
|
const dialogChoice = await openConfirmDialog({
|
||||||
description: t('confirm.show_reblogs.description', [account.acct]),
|
title: t('confirm.show_reblogs.title'),
|
||||||
confirm: t('confirm.show_reblogs.confirm'),
|
description: t('confirm.show_reblogs.description', [account.acct]),
|
||||||
cancel: t('confirm.show_reblogs.cancel'),
|
confirm: t('confirm.show_reblogs.confirm'),
|
||||||
}) !== 'confirm')
|
cancel: t('confirm.show_reblogs.cancel'),
|
||||||
return
|
})
|
||||||
|
if (dialogChoice.choice !== 'confirm')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const showingReblogs = !relationship.value?.showingReblogs
|
const showingReblogs = !relationship.value?.showingReblogs
|
||||||
relationship.value = await client.value.v1.accounts.$select(account.id).follow({ reblogs: showingReblogs })
|
relationship.value = await client.value.v1.accounts.$select(account.id).follow({ reblogs: showingReblogs })
|
||||||
|
|
45
components/account/TagHoverWrapper.vue
Normal file
45
components/account/TagHoverWrapper.vue
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { mastodon } from 'masto'
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
inheritAttrs: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
const { tagName, disabled } = defineProps<{
|
||||||
|
tagName?: string
|
||||||
|
disabled?: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const tag = ref<mastodon.v1.Tag>()
|
||||||
|
const tagHover = ref()
|
||||||
|
const hovered = useElementHover(tagHover)
|
||||||
|
|
||||||
|
watch(hovered, (newHovered) => {
|
||||||
|
if (newHovered && tagName) {
|
||||||
|
fetchTag(tagName).then((t) => {
|
||||||
|
tag.value = t
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const userSettings = useUserSettings()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<span ref="tagHover">
|
||||||
|
<VMenu
|
||||||
|
v-if="!disabled && !getPreferences(userSettings, 'hideTagHoverCard')"
|
||||||
|
placement="bottom-start"
|
||||||
|
:delay="{ show: 500, hide: 100 }"
|
||||||
|
v-bind="$attrs"
|
||||||
|
:close-on-content-click="false"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
<template #popper>
|
||||||
|
<TagCardSkeleton v-if="!tag" />
|
||||||
|
<TagCard v-else :tag="tag" />
|
||||||
|
</template>
|
||||||
|
</VMenu>
|
||||||
|
<slot v-else />
|
||||||
|
</span>
|
||||||
|
</template>
|
|
@ -22,7 +22,7 @@ onMounted(() => {
|
||||||
|
|
||||||
const commandMode = computed(() => input.value.startsWith('>'))
|
const commandMode = computed(() => input.value.startsWith('>'))
|
||||||
|
|
||||||
const query = computed(() => commandMode ? '' : input.value.trim())
|
const query = computed(() => commandMode.value ? '' : input.value.trim())
|
||||||
|
|
||||||
const { accounts, hashtags, loading } = useSearch(query)
|
const { accounts, hashtags, loading } = useSearch(query)
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ const searchResult = computed<QueryResult>(() => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = computed<QueryResult>(() => commandMode
|
const result = computed<QueryResult>(() => commandMode.value
|
||||||
? registry.query(scopes.value.map(s => s.id).join('.'), input.value.slice(1).trim())
|
? registry.query(scopes.value.map(s => s.id).join('.'), input.value.slice(1).trim())
|
||||||
: searchResult.value,
|
: searchResult.value,
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,6 +4,8 @@ defineProps<{
|
||||||
hover?: boolean
|
hover?: boolean
|
||||||
iconChecked?: string
|
iconChecked?: string
|
||||||
iconUnchecked?: string
|
iconUnchecked?: string
|
||||||
|
checkedIconColor?: string
|
||||||
|
prependCheckbox?: boolean
|
||||||
}>()
|
}>()
|
||||||
const modelValue = defineModel<boolean | null>()
|
const modelValue = defineModel<boolean | null>()
|
||||||
</script>
|
</script>
|
||||||
|
@ -15,9 +17,12 @@ const modelValue = defineModel<boolean | null>()
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
@click.prevent="modelValue = !modelValue"
|
@click.prevent="modelValue = !modelValue"
|
||||||
>
|
>
|
||||||
<span v-if="label" flex-1 ms-2 pointer-events-none>{{ label }}</span>
|
<span v-if="label && !prependCheckbox" flex-1 ms-2 pointer-events-none>{{ label }}</span>
|
||||||
<span
|
<span
|
||||||
:class="modelValue ? (iconChecked ?? 'i-ri:checkbox-line') : (iconUnchecked ?? 'i-ri:checkbox-blank-line')"
|
:class="[
|
||||||
|
modelValue ? (iconChecked ?? 'i-ri:checkbox-line') : (iconUnchecked ?? 'i-ri:checkbox-blank-line'),
|
||||||
|
modelValue && checkedIconColor,
|
||||||
|
]"
|
||||||
text-lg
|
text-lg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
|
@ -26,6 +31,7 @@ const modelValue = defineModel<boolean | null>()
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
sr-only
|
sr-only
|
||||||
>
|
>
|
||||||
|
<span v-if="label && prependCheckbox" flex-1 ms-2 pointer-events-none>{{ label }}</span>
|
||||||
</label>
|
</label>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import type { UnwrapRef } from 'vue'
|
||||||
const {
|
const {
|
||||||
paginator,
|
paginator,
|
||||||
stream,
|
stream,
|
||||||
|
eventType,
|
||||||
keyProp = 'id',
|
keyProp = 'id',
|
||||||
virtualScroller = false,
|
virtualScroller = false,
|
||||||
preprocess,
|
preprocess,
|
||||||
|
@ -17,6 +18,7 @@ const {
|
||||||
keyProp?: keyof T
|
keyProp?: keyof T
|
||||||
virtualScroller?: boolean
|
virtualScroller?: boolean
|
||||||
stream?: mastodon.streaming.Subscription
|
stream?: mastodon.streaming.Subscription
|
||||||
|
eventType?: 'update' | 'notification'
|
||||||
preprocess?: (items: (U | T)[]) => U[]
|
preprocess?: (items: (U | T)[]) => U[]
|
||||||
endMessage?: boolean | string
|
endMessage?: boolean | string
|
||||||
}>()
|
}>()
|
||||||
|
@ -44,7 +46,7 @@ defineSlots<{
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const nuxtApp = useNuxtApp()
|
const nuxtApp = useNuxtApp()
|
||||||
|
|
||||||
const { items, prevItems, update, state, endAnchor, error } = usePaginator(paginator, toRef(() => stream), preprocess)
|
const { items, prevItems, update, state, endAnchor, error } = usePaginator(paginator, toRef(() => stream), eventType, preprocess)
|
||||||
|
|
||||||
nuxtApp.hook('elk-logo:click', () => {
|
nuxtApp.hook('elk-logo:click', () => {
|
||||||
update()
|
update()
|
||||||
|
|
|
@ -33,7 +33,7 @@ useCommands(() => command
|
||||||
:to="option.to"
|
:to="option.to"
|
||||||
:replace="replace"
|
:replace="replace"
|
||||||
relative flex flex-auto cursor-pointer sm:px6 px2 rounded transition-all
|
relative flex flex-auto cursor-pointer sm:px6 px2 rounded transition-all
|
||||||
tabindex="1"
|
tabindex="0"
|
||||||
hover:bg-active transition-100
|
hover:bg-active transition-100
|
||||||
exact-active-class="children:(text-secondary !border-primary !op100 !text-base)"
|
exact-active-class="children:(text-secondary !border-primary !op100 !text-base)"
|
||||||
@click="!preventScrollTop && $scrollToTop()"
|
@click="!preventScrollTop && $scrollToTop()"
|
||||||
|
@ -46,7 +46,7 @@ useCommands(() => command
|
||||||
</template>
|
</template>
|
||||||
<template v-if="isHydrated && moreOptions?.options?.length">
|
<template v-if="isHydrated && moreOptions?.options?.length">
|
||||||
<CommonDropdown placement="bottom" flex cursor-pointer mx-1.25rem>
|
<CommonDropdown placement="bottom" flex cursor-pointer mx-1.25rem>
|
||||||
<CommonTooltip placement="top" :content="moreOptions.tooltip || t('action.more')">
|
<CommonTooltip placement="top" no-auto-focus :content="moreOptions.tooltip || t('action.more')">
|
||||||
<button
|
<button
|
||||||
cursor-pointer
|
cursor-pointer
|
||||||
flex
|
flex
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { as = 'div', active } = defineProps<{ as: any; active: boolean }>()
|
const { as = 'div', active } = defineProps<{
|
||||||
|
as: any
|
||||||
|
active: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
const el = ref()
|
const el = ref()
|
||||||
|
|
||||||
watch(() => active, (active) => {
|
watch(() => active, (active) => {
|
||||||
|
|
|
@ -19,8 +19,8 @@ const tabs = computed(() => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
function toValidName(otpion: string) {
|
function toValidName(option: string) {
|
||||||
return otpion.toLowerCase().replace(/[^a-zA-Z0-9]/g, '-')
|
return option.toLowerCase().replace(/[^a-zA-Z0-9]/g, '-')
|
||||||
}
|
}
|
||||||
|
|
||||||
useCommands(() => command
|
useCommands(() => command
|
||||||
|
@ -49,7 +49,7 @@ useCommands(() => command
|
||||||
><label
|
><label
|
||||||
flex flex-auto cursor-pointer px3 m1 rounded transition-all
|
flex flex-auto cursor-pointer px3 m1 rounded transition-all
|
||||||
:for="`tab-${toValidName(option.name)}`"
|
:for="`tab-${toValidName(option.name)}`"
|
||||||
tabindex="1"
|
tabindex="0"
|
||||||
hover:bg-active transition-100
|
hover:bg-active transition-100
|
||||||
@keypress.enter="modelValue = option.name"
|
@keypress.enter="modelValue = option.name"
|
||||||
><span
|
><span
|
||||||
|
|
|
@ -2,12 +2,14 @@
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(event: 'close'): void
|
(event: 'close'): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const vAutoFocus = (el: HTMLElement) => el.focus()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div my-8 px-3 sm:px-8 md:max-w-200 flex="~ col gap-4" relative>
|
<div my-8 px-3 sm:px-8 md:max-w-200 flex="~ col gap-4" relative>
|
||||||
<button btn-action-icon absolute top--8 right-0 m1 aria-label="Close" @click="emit('close')">
|
<button v-auto-focus type="button" btn-action-icon absolute top--8 right-0 m1 aria-label="Close" @click="emit('close')">
|
||||||
<div i-ri:close-line />
|
<span i-ri:close-line />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<img :alt="$t('app_logo')" :src="`/${''}logo.svg`" w-20 h-20 height="80" width="80" mxa class="rtl-flip">
|
<img :alt="$t('app_logo')" :src="`/${''}logo.svg`" w-20 h-20 height="80" width="80" mxa class="rtl-flip">
|
||||||
|
@ -28,10 +30,12 @@ const emit = defineEmits<{
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
{{ $t('help.desc_para6') }}
|
{{ $t('help.desc_para6') }}
|
||||||
</p>
|
</p>
|
||||||
{{ $t('help.desc_para3') }}
|
<NuxtLink hover:text-primary href="https://github.com/sponsors/elk-zone" target="_blank">
|
||||||
<p flex="~ gap-2 wrap" mxa>
|
{{ $t('help.desc_para3') }}
|
||||||
|
</NuxtLink>
|
||||||
|
<p flex="~ gap-2 wrap justify-center" mxa>
|
||||||
<template v-for="team of elkTeamMembers" :key="team.github">
|
<template v-for="team of elkTeamMembers" :key="team.github">
|
||||||
<NuxtLink :href="`https://github.com/sponsors/${team.github}`" target="_blank" external rounded-full transition duration-300 border="~ transparent" hover="scale-105 border-primary">
|
<NuxtLink :href="team.link" target="_blank" external rounded-full transition duration-300 border="~ transparent" hover="scale-105 border-primary">
|
||||||
<img :src="`/avatars/${team.github}-100x100.png`" :alt="team.display" rounded-full w-15 h-15 height="60" width="60">
|
<img :src="`/avatars/${team.github}-100x100.png`" :alt="team.display" rounded-full w-15 h-15 height="60" width="60">
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</template>
|
</template>
|
||||||
|
@ -42,7 +46,7 @@ const emit = defineEmits<{
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<button btn-solid mxa tabindex="2" @click="emit('close')">
|
<button type="button" btn-solid mxa @click="emit('close')">
|
||||||
{{ $t('action.enter_app') }}
|
{{ $t('action.enter_app') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -68,7 +68,7 @@ async function removeList() {
|
||||||
actionError.value = undefined
|
actionError.value = undefined
|
||||||
await nextTick()
|
await nextTick()
|
||||||
|
|
||||||
if (confirmDelete === 'confirm') {
|
if (confirmDelete.choice === 'confirm') {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
try {
|
try {
|
||||||
await client.v1.lists.$select(list.value.id).remove()
|
await client.v1.lists.$select(list.value.id).remove()
|
||||||
|
@ -92,7 +92,7 @@ async function removeList() {
|
||||||
async function clearError() {
|
async function clearError() {
|
||||||
actionError.value = undefined
|
actionError.value = undefined
|
||||||
await nextTick()
|
await nextTick()
|
||||||
if (isEditing)
|
if (isEditing.value)
|
||||||
input.value?.focus()
|
input.value?.focus()
|
||||||
else
|
else
|
||||||
deleteBtn.value?.focus()
|
deleteBtn.value?.focus()
|
||||||
|
|
|
@ -40,6 +40,10 @@ const shortcutItemGroups = computed<ShortcutItemGroup[]>(() => [
|
||||||
// description: t('magic_keys.groups.navigation.previous_status'),
|
// description: t('magic_keys.groups.navigation.previous_status'),
|
||||||
// shortcut: { keys: ['k'], isSequence: false },
|
// shortcut: { keys: ['k'], isSequence: false },
|
||||||
// },
|
// },
|
||||||
|
{
|
||||||
|
description: t('magic_keys.groups.navigation.go_to_search'),
|
||||||
|
shortcut: { keys: ['/'], isSequence: false },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: t('magic_keys.groups.navigation.go_to_home'),
|
description: t('magic_keys.groups.navigation.go_to_home'),
|
||||||
shortcut: { keys: ['g', 'h'], isSequence: true },
|
shortcut: { keys: ['g', 'h'], isSequence: true },
|
||||||
|
@ -48,6 +52,42 @@ const shortcutItemGroups = computed<ShortcutItemGroup[]>(() => [
|
||||||
description: t('magic_keys.groups.navigation.go_to_notifications'),
|
description: t('magic_keys.groups.navigation.go_to_notifications'),
|
||||||
shortcut: { keys: ['g', 'n'], isSequence: true },
|
shortcut: { keys: ['g', 'n'], isSequence: true },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: t('magic_keys.groups.navigation.go_to_conversations'),
|
||||||
|
shortcut: { keys: ['g', 'c'], isSequence: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: t('magic_keys.groups.navigation.go_to_favourites'),
|
||||||
|
shortcut: { keys: ['g', 'f'], isSequence: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: t('magic_keys.groups.navigation.go_to_bookmarks'),
|
||||||
|
shortcut: { keys: ['g', 'b'], isSequence: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: t('magic_keys.groups.navigation.go_to_explore'),
|
||||||
|
shortcut: { keys: ['g', 'e'], isSequence: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: t('magic_keys.groups.navigation.go_to_local'),
|
||||||
|
shortcut: { keys: ['g', 'l'], isSequence: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: t('magic_keys.groups.navigation.go_to_federated'),
|
||||||
|
shortcut: { keys: ['g', 't'], isSequence: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: t('magic_keys.groups.navigation.go_to_lists'),
|
||||||
|
shortcut: { keys: ['g', 'i'], isSequence: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: t('magic_keys.groups.navigation.go_to_settings'),
|
||||||
|
shortcut: { keys: ['g', 's'], isSequence: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: t('magic_keys.groups.navigation.go_to_profile'),
|
||||||
|
shortcut: { keys: ['g', 'p'], isSequence: true },
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
45
components/modal/DurationPicker.vue
Normal file
45
components/modal/DurationPicker.vue
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
const model = defineModel<number>()
|
||||||
|
const isValid = defineModel<boolean>('isValid')
|
||||||
|
|
||||||
|
const days = ref<number | ''>(0)
|
||||||
|
const hours = ref<number | ''>(1)
|
||||||
|
const minutes = ref<number | ''>(0)
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
if (days.value === '' || hours.value === '' || minutes.value === '') {
|
||||||
|
isValid.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const duration
|
||||||
|
= days.value * 24 * 60 * 60
|
||||||
|
+ hours.value * 60 * 60
|
||||||
|
+ minutes.value * 60
|
||||||
|
|
||||||
|
if (duration <= 0) {
|
||||||
|
isValid.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid.value = true
|
||||||
|
model.value = duration
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div flex flex-grow-0 gap-2>
|
||||||
|
<label flex items-center gap-2>
|
||||||
|
<input v-model="days" type="number" min="0" max="1999" input-base :class="!isValid ? 'input-error' : null">
|
||||||
|
{{ $t('confirm.mute_account.days', days === '' ? 0 : days) }}
|
||||||
|
</label>
|
||||||
|
<label flex items-center gap-2>
|
||||||
|
<input v-model="hours" type="number" min="0" max="24" input-base :class="!isValid ? 'input-error' : null">
|
||||||
|
{{ $t('confirm.mute_account.hours', hours === '' ? 0 : hours) }}
|
||||||
|
</label>
|
||||||
|
<label flex items-center gap-2>
|
||||||
|
<input v-model="minutes" type="number" min="0" max="59" step="5" input-base :class="!isValid ? 'input-error' : null">
|
||||||
|
{{ $t('confirm.mute_account.minute', minutes === '' ? 0 : minutes) }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -1,11 +1,34 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ConfirmDialogChoice, ConfirmDialogLabel } from '~/types'
|
import type { ConfirmDialogChoice, ConfirmDialogOptions } from '~/types'
|
||||||
|
import DurationPicker from '~/components/modal/DurationPicker.vue'
|
||||||
|
|
||||||
defineProps<ConfirmDialogLabel>()
|
const props = defineProps<ConfirmDialogOptions>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(evt: 'choice', choice: ConfirmDialogChoice): void
|
(evt: 'choice', choice: ConfirmDialogChoice): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const hasDuration = ref(false)
|
||||||
|
const isValidDuration = ref(true)
|
||||||
|
const duration = ref(60 * 60) // default to 1 hour
|
||||||
|
const shouldMuteNotifications = ref(true)
|
||||||
|
const isMute = computed(() => props.extraOptionType === 'mute')
|
||||||
|
|
||||||
|
function handleChoice(choice: ConfirmDialogChoice['choice']) {
|
||||||
|
const dialogChoice = {
|
||||||
|
choice,
|
||||||
|
...isMute.value && {
|
||||||
|
extraOptions: {
|
||||||
|
mute: {
|
||||||
|
duration: hasDuration.value ? duration.value : 0,
|
||||||
|
notifications: shouldMuteNotifications.value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
emit('choice', dialogChoice)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -16,11 +39,17 @@ const emit = defineEmits<{
|
||||||
<div v-if="description">
|
<div v-if="description">
|
||||||
{{ description }}
|
{{ description }}
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="isMute" flex-col flex gap-4>
|
||||||
|
<CommonCheckbox v-model="hasDuration" :label="$t('confirm.mute_account.specify_duration')" prepend-checkbox checked-icon-color="text-primary" />
|
||||||
|
<DurationPicker v-if="hasDuration" v-model="duration" v-model:is-valid="isValidDuration" />
|
||||||
|
<CommonCheckbox v-model="shouldMuteNotifications" :label="$t('confirm.mute_account.notifications')" prepend-checkbox checked-icon-color="text-primary" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div flex justify-end gap-2>
|
<div flex justify-end gap-2>
|
||||||
<button btn-text @click="emit('choice', 'cancel')">
|
<button btn-text @click="handleChoice('cancel')">
|
||||||
{{ cancel || $t('confirm.common.cancel') }}
|
{{ cancel || $t('confirm.common.cancel') }}
|
||||||
</button>
|
</button>
|
||||||
<button btn-solid @click="emit('choice', 'confirm')">
|
<button btn-solid :disabled="!isValidDuration" @click="handleChoice('confirm')">
|
||||||
{{ confirm || $t('confirm.common.confirm') }}
|
{{ confirm || $t('confirm.common.confirm') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -37,7 +37,7 @@ onUnmounted(() => locked.value = false)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div relative h-full w-full flex pt-12 w-100vh @click="onClick">
|
<div relative h-full w-full flex pt-12 @click="onClick">
|
||||||
<button
|
<button
|
||||||
v-if="hasNext" pointer-events-auto btn-action-icon bg="black/20" :aria-label="$t('action.previous')"
|
v-if="hasNext" pointer-events-auto btn-action-icon bg="black/20" :aria-label="$t('action.previous')"
|
||||||
hover:bg="black/40" dark:bg="white/30" dark-hover:bg="white/20" absolute top="1/2" right-1 z5
|
hover:bg="black/40" dark:bg="white/30" dark-hover:bg="white/20" absolute top="1/2" right-1 z5
|
||||||
|
|
|
@ -15,7 +15,7 @@ const emit = defineEmits<{
|
||||||
const modelValue = defineModel<number>({ required: true })
|
const modelValue = defineModel<number>({ required: true })
|
||||||
|
|
||||||
const slideGap = 20
|
const slideGap = 20
|
||||||
const doubleTapTreshold = 250
|
const doubleTapThreshold = 250
|
||||||
|
|
||||||
const view = ref()
|
const view = ref()
|
||||||
const slider = ref()
|
const slider = ref()
|
||||||
|
@ -36,6 +36,8 @@ const isPinching = ref(false)
|
||||||
const maxZoomOut = ref(1)
|
const maxZoomOut = ref(1)
|
||||||
const isZoomedIn = computed(() => scale.value > 1)
|
const isZoomedIn = computed(() => scale.value > 1)
|
||||||
|
|
||||||
|
const enableAutoplay = usePreferences('enableAutoplay')
|
||||||
|
|
||||||
function goToFocusedSlide() {
|
function goToFocusedSlide() {
|
||||||
scale.value = 1
|
scale.value = 1
|
||||||
x.value = slide.value[modelValue.value].offsetLeft * scale.value
|
x.value = slide.value[modelValue.value].offsetLeft * scale.value
|
||||||
|
@ -147,7 +149,7 @@ function handleLastDrag(tap: boolean, swipe: Vector2, movement: Vector2, positio
|
||||||
let lastTapAt = 0
|
let lastTapAt = 0
|
||||||
function handleTap([positionX, positionY]: Vector2) {
|
function handleTap([positionX, positionY]: Vector2) {
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
const isDoubleTap = now - lastTapAt < doubleTapTreshold
|
const isDoubleTap = now - lastTapAt < doubleTapThreshold
|
||||||
lastTapAt = now
|
lastTapAt = now
|
||||||
|
|
||||||
if (!isDoubleTap)
|
if (!isDoubleTap)
|
||||||
|
@ -218,7 +220,7 @@ function handleZoomDrag([deltaX, deltaY]: Vector2) {
|
||||||
function handleSlideDrag([movementX, movementY]: Vector2) {
|
function handleSlideDrag([movementX, movementY]: Vector2) {
|
||||||
goToFocusedSlide()
|
goToFocusedSlide()
|
||||||
|
|
||||||
if (Math.abs(movementY) > Math.abs(movementX)) // vertical movement is more then horizontal
|
if (Math.abs(movementY) > Math.abs(movementX)) // vertical movement is more than horizontal
|
||||||
y.value -= movementY / scale.value
|
y.value -= movementY / scale.value
|
||||||
else
|
else
|
||||||
x.value -= movementX / scale.value
|
x.value -= movementX / scale.value
|
||||||
|
@ -264,8 +266,12 @@ const imageStyle = computed(() => ({
|
||||||
items-center
|
items-center
|
||||||
justify-center
|
justify-center
|
||||||
>
|
>
|
||||||
<img
|
<component
|
||||||
|
:is="item.type === 'gifv' ? 'video' : 'img'"
|
||||||
ref="image"
|
ref="image"
|
||||||
|
:autoplay="enableAutoplay"
|
||||||
|
controls
|
||||||
|
loop
|
||||||
select-none
|
select-none
|
||||||
max-w-full
|
max-w-full
|
||||||
max-h-full
|
max-h-full
|
||||||
|
@ -273,7 +279,7 @@ const imageStyle = computed(() => ({
|
||||||
:draggable="false"
|
:draggable="false"
|
||||||
:src="item.url || item.previewUrl"
|
:src="item.url || item.previewUrl"
|
||||||
:alt="item.description || ''"
|
:alt="item.description || ''"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// only one icon can be lit up at the same time
|
// only one icon can be lit up at the same time
|
||||||
|
import { STORAGE_KEY_LAST_ACCESSED_EXPLORE_ROUTE, STORAGE_KEY_LAST_ACCESSED_NOTIFICATION_ROUTE } from '~/constants'
|
||||||
|
|
||||||
const moreMenuVisible = ref(false)
|
const moreMenuVisible = ref(false)
|
||||||
|
|
||||||
const { notifications } = useNotifications()
|
const { notifications } = useNotifications()
|
||||||
|
const lastAccessedNotificationRoute = useLocalStorage(STORAGE_KEY_LAST_ACCESSED_NOTIFICATION_ROUTE, '')
|
||||||
|
const lastAccessedExploreRoute = useLocalStorage(STORAGE_KEY_LAST_ACCESSED_EXPLORE_ROUTE, '')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -19,7 +23,7 @@ const { notifications } = useNotifications()
|
||||||
<NuxtLink to="/search" :aria-label="$t('nav.search')" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 class="coarse-pointer:select-none" @click="$scrollToTop">
|
<NuxtLink to="/search" :aria-label="$t('nav.search')" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 class="coarse-pointer:select-none" @click="$scrollToTop">
|
||||||
<div i-ri:search-line />
|
<div i-ri:search-line />
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
<NuxtLink to="/notifications" :aria-label="$t('nav.notifications')" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 class="coarse-pointer:select-none" @click="$scrollToTop">
|
<NuxtLink :to="`/notifications/${lastAccessedNotificationRoute}`" :aria-label="$t('nav.notifications')" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 class="coarse-pointer:select-none" @click="$scrollToTop">
|
||||||
<div flex relative>
|
<div flex relative>
|
||||||
<div class="i-ri:notification-4-line" text-xl />
|
<div class="i-ri:notification-4-line" text-xl />
|
||||||
<div v-if="notifications" class="top-[-0.3rem] right-[-0.3rem]" absolute font-bold rounded-full h-4 w-4 text-xs bg-primary text-inverted flex items-center justify-center>
|
<div v-if="notifications" class="top-[-0.3rem] right-[-0.3rem]" absolute font-bold rounded-full h-4 w-4 text-xs bg-primary text-inverted flex items-center justify-center>
|
||||||
|
@ -32,8 +36,8 @@ const { notifications } = useNotifications()
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<NuxtLink :to="`/${currentServer}/explore`" :aria-label="$t('nav.explore')" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 class="coarse-pointer:select-none" @click="$scrollToTop">
|
<NuxtLink :to="`/${currentServer}/explore/${lastAccessedExploreRoute}`" :aria-label="$t('nav.explore')" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 class="coarse-pointer:select-none" @click="$scrollToTop">
|
||||||
<div i-ri:hashtag />
|
<div i-ri:compass-3-line />
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
<NuxtLink group :to="`/${currentServer}/public/local`" :aria-label="$t('nav.local')" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 class="coarse-pointer:select-none" @click="$scrollToTop">
|
<NuxtLink group :to="`/${currentServer}/public/local`" :aria-label="$t('nav.local')" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 class="coarse-pointer:select-none" @click="$scrollToTop">
|
||||||
<div i-ri:group-2-line />
|
<div i-ri:group-2-line />
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { STORAGE_KEY_LAST_ACCESSED_EXPLORE_ROUTE, STORAGE_KEY_LAST_ACCESSED_NOTIFICATION_ROUTE } from '~/constants'
|
||||||
|
|
||||||
const { command } = defineProps<{
|
const { command } = defineProps<{
|
||||||
command?: boolean
|
command?: boolean
|
||||||
}>()
|
}>()
|
||||||
const { notifications } = useNotifications()
|
const { notifications } = useNotifications()
|
||||||
const useStarFavoriteIcon = usePreferences('useStarFavoriteIcon')
|
const useStarFavoriteIcon = usePreferences('useStarFavoriteIcon')
|
||||||
|
const lastAccessedNotificationRoute = useLocalStorage(STORAGE_KEY_LAST_ACCESSED_NOTIFICATION_ROUTE, '')
|
||||||
|
const lastAccessedExploreRoute = useLocalStorage(STORAGE_KEY_LAST_ACCESSED_EXPLORE_ROUTE, '')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -12,7 +16,7 @@ const useStarFavoriteIcon = usePreferences('useStarFavoriteIcon')
|
||||||
|
|
||||||
<div class="spacer" shrink xl:hidden />
|
<div class="spacer" shrink xl:hidden />
|
||||||
<NavSideItem :text="$t('nav.home')" to="/home" icon="i-ri:home-5-line" user-only :command="command" />
|
<NavSideItem :text="$t('nav.home')" to="/home" icon="i-ri:home-5-line" user-only :command="command" />
|
||||||
<NavSideItem :text="$t('nav.notifications')" to="/notifications" icon="i-ri:notification-4-line" user-only :command="command">
|
<NavSideItem :text="$t('nav.notifications')" :to="`/notifications/${lastAccessedNotificationRoute}`" icon="i-ri:notification-4-line" user-only :command="command">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<div flex relative>
|
<div flex relative>
|
||||||
<div class="i-ri:notification-4-line" text-xl />
|
<div class="i-ri:notification-4-line" text-xl />
|
||||||
|
@ -30,10 +34,11 @@ const useStarFavoriteIcon = usePreferences('useStarFavoriteIcon')
|
||||||
<NavSideItem :text="$t('action.compose')" to="/compose" icon="i-ri:quill-pen-line" user-only :command="command" />
|
<NavSideItem :text="$t('action.compose')" to="/compose" icon="i-ri:quill-pen-line" user-only :command="command" />
|
||||||
|
|
||||||
<div class="spacer" shrink hidden sm:block />
|
<div class="spacer" shrink hidden sm:block />
|
||||||
<NavSideItem :text="$t('nav.explore')" :to="isHydrated ? `/${currentServer}/explore` : '/explore'" icon="i-ri:hashtag" :command="command" />
|
<NavSideItem :text="$t('nav.explore')" :to="isHydrated ? `/${currentServer}/explore/${lastAccessedExploreRoute}` : `/explore/${lastAccessedExploreRoute}`" icon="i-ri:compass-3-line" :command="command" />
|
||||||
<NavSideItem :text="$t('nav.local')" :to="isHydrated ? `/${currentServer}/public/local` : '/public/local'" icon="i-ri:group-2-line " :command="command" />
|
<NavSideItem :text="$t('nav.local')" :to="isHydrated ? `/${currentServer}/public/local` : '/public/local'" icon="i-ri:group-2-line " :command="command" />
|
||||||
<NavSideItem :text="$t('nav.federated')" :to="isHydrated ? `/${currentServer}/public` : '/public'" icon="i-ri:earth-line" :command="command" />
|
<NavSideItem :text="$t('nav.federated')" :to="isHydrated ? `/${currentServer}/public` : '/public'" icon="i-ri:earth-line" :command="command" />
|
||||||
<NavSideItem :text="$t('nav.lists')" :to="isHydrated ? `/${currentServer}/lists` : '/lists'" icon="i-ri:list-check" user-only :command="command" />
|
<NavSideItem :text="$t('nav.lists')" :to="isHydrated ? `/${currentServer}/lists` : '/lists'" icon="i-ri:list-check" user-only :command="command" />
|
||||||
|
<NavSideItem :text="$t('nav.hashtags')" to="/hashtags" icon="i-ri:hashtag" user-only :command="command" />
|
||||||
|
|
||||||
<div class="spacer" shrink hidden sm:block />
|
<div class="spacer" shrink hidden sm:block />
|
||||||
<NavSideItem :text="$t('nav.settings')" to="/settings" icon="i-ri:settings-3-line" :command="command" />
|
<NavSideItem :text="$t('nav.settings')" to="/settings" icon="i-ri:settings-3-line" :command="command" />
|
||||||
|
|
|
@ -57,11 +57,21 @@ const noUserVisual = computed(() => isHydrated.value && props.userOnly && !curre
|
||||||
<div
|
<div
|
||||||
class="item"
|
class="item"
|
||||||
flex items-center gap4
|
flex items-center gap4
|
||||||
w-fit rounded-3
|
|
||||||
px2 mx3 sm:mxa
|
|
||||||
xl="ml0 mr5 px5 w-auto"
|
xl="ml0 mr5 px5 w-auto"
|
||||||
transition-100
|
:class="isSmallScreen
|
||||||
elk-group-hover="bg-active" group-focus-visible:ring="2 current"
|
? `
|
||||||
|
w-full
|
||||||
|
px5 sm:mxa
|
||||||
|
transition-colors duration-200 transform
|
||||||
|
hover-bg-gray-100 hover-dark:(bg-gray-700 text-white)
|
||||||
|
` : `
|
||||||
|
w-fit rounded-3
|
||||||
|
px2 mx3 sm:mxa
|
||||||
|
transition-100
|
||||||
|
elk-group-hover-bg-active
|
||||||
|
group-focus-visible:ring-2
|
||||||
|
group-focus-visible:ring-current
|
||||||
|
`"
|
||||||
>
|
>
|
||||||
<slot name="icon">
|
<slot name="icon">
|
||||||
<div :class="icon" text-xl />
|
<div :class="icon" text-xl />
|
||||||
|
|
|
@ -34,7 +34,13 @@ const { busy, oauth, singleInstanceServer } = useSignIn()
|
||||||
<strong>{{ currentServer }}</strong>
|
<strong>{{ currentServer }}</strong>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
</button>
|
</button>
|
||||||
<button v-else btn-solid text-sm px-2 py-1 text-center xl:hidden @click="openSigninDialog()">
|
<button
|
||||||
|
v-else
|
||||||
|
flex="~ row"
|
||||||
|
gap-x-1 items-center justify-center btn-solid text-sm px-2 py-1 xl:hidden
|
||||||
|
@click="openSigninDialog()"
|
||||||
|
>
|
||||||
|
<span aria-hidden="true" block i-ri:login-circle-line class="rtl-flip" />
|
||||||
{{ $t('action.sign_in') }}
|
{{ $t('action.sign_in') }}
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -4,6 +4,13 @@ import type { mastodon } from 'masto'
|
||||||
const { notification } = defineProps<{
|
const { notification } = defineProps<{
|
||||||
notification: mastodon.v1.Notification
|
notification: mastodon.v1.Notification
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
// well-known emoji reactions types Elk does not support yet
|
||||||
|
const unsupportedEmojiReactionTypes = ['pleroma:emoji_reaction', 'reaction']
|
||||||
|
if (unsupportedEmojiReactionTypes.includes(notification.type))
|
||||||
|
console.warn(`[DEV] ${t('notification.missing_type')} '${notification.type}' (notification.id: ${notification.id})`)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -88,7 +95,8 @@ const { notification } = defineProps<{
|
||||||
<template v-else-if="notification.type === 'mention' || notification.type === 'poll' || notification.type === 'status'">
|
<template v-else-if="notification.type === 'mention' || notification.type === 'poll' || notification.type === 'status'">
|
||||||
<StatusCard :status="notification.status!" />
|
<StatusCard :status="notification.status!" />
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else-if="!unsupportedEmojiReactionTypes.includes(notification.type)">
|
||||||
|
<!-- prevent showing errors for dev for known emoji reaction types -->
|
||||||
<!-- type 'favourite' and 'reblog' should always rendered by NotificationGroupedLikes -->
|
<!-- type 'favourite' and 'reblog' should always rendered by NotificationGroupedLikes -->
|
||||||
<div text-red font-bold>
|
<div text-red font-bold>
|
||||||
[DEV] {{ $t('notification.missing_type') }} '{{ notification.type }}'
|
[DEV] {{ $t('notification.missing_type') }} '{{ notification.type }}'
|
||||||
|
|
|
@ -25,7 +25,7 @@ function includeNotificationsForStatusCard({ type, status }: mastodon.v1.Notific
|
||||||
|
|
||||||
// Group by type (and status when applicable)
|
// Group by type (and status when applicable)
|
||||||
function groupId(item: mastodon.v1.Notification): string {
|
function groupId(item: mastodon.v1.Notification): string {
|
||||||
// If the update is related to an status, group notifications from the same account (boost + favorite the same status)
|
// If the update is related to a status, group notifications from the same account (boost + favorite the same status)
|
||||||
const id = item.status
|
const id = item.status
|
||||||
? {
|
? {
|
||||||
status: item.status?.id,
|
status: item.status?.id,
|
||||||
|
@ -171,6 +171,7 @@ const { formatNumber } = useHumanReadableNumber()
|
||||||
:paginator="paginator"
|
:paginator="paginator"
|
||||||
:preprocess="preprocess"
|
:preprocess="preprocess"
|
||||||
:stream="stream"
|
:stream="stream"
|
||||||
|
eventType="notification"
|
||||||
:virtualScroller="virtualScroller"
|
:virtualScroller="virtualScroller"
|
||||||
>
|
>
|
||||||
<template #updater="{ number, update }">
|
<template #updater="{ number, update }">
|
||||||
|
|
|
@ -35,8 +35,8 @@ const showWarning = computed(() => {
|
||||||
return false
|
return false
|
||||||
|
|
||||||
return isSupported
|
return isSupported
|
||||||
&& (!isSubscribed.value || !notificationPermission.value || notificationPermission.value === 'prompt')
|
&& (!isSubscribed.value || !notificationPermission.value || notificationPermission.value === 'prompt')
|
||||||
&& !(hiddenNotification.value[currentUser.value?.account?.acct ?? ''] === true)
|
&& !(hiddenNotification.value[currentUser.value?.account?.acct ?? ''])
|
||||||
})
|
})
|
||||||
|
|
||||||
async function saveSettings() {
|
async function saveSettings() {
|
||||||
|
|
|
@ -19,7 +19,8 @@ const emit = defineEmits<{
|
||||||
const maxDescriptionLength = 1500
|
const maxDescriptionLength = 1500
|
||||||
|
|
||||||
const isEditDialogOpen = ref(false)
|
const isEditDialogOpen = ref(false)
|
||||||
const description = computed(() => props.attachment.description ?? '')
|
const description = ref(props.attachment.description ?? '')
|
||||||
|
|
||||||
function toggleApply() {
|
function toggleApply() {
|
||||||
isEditDialogOpen.value = false
|
isEditDialogOpen.value = false
|
||||||
emit('setDescription', description.value)
|
emit('setDescription', description.value)
|
||||||
|
|
|
@ -30,8 +30,14 @@ const draftState = useDraft(draftKey, initial)
|
||||||
const { draft } = draftState
|
const { draft } = draftState
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isExceedingAttachmentLimit, isUploading, failedAttachments, isOverDropZone,
|
isExceedingAttachmentLimit,
|
||||||
uploadAttachments, pickAttachments, setDescription, removeAttachment,
|
isUploading,
|
||||||
|
failedAttachments,
|
||||||
|
isOverDropZone,
|
||||||
|
uploadAttachments,
|
||||||
|
pickAttachments,
|
||||||
|
setDescription,
|
||||||
|
removeAttachment,
|
||||||
dropZoneRef,
|
dropZoneRef,
|
||||||
} = useUploadMediaAttachment(draft)
|
} = useUploadMediaAttachment(draft)
|
||||||
|
|
||||||
|
@ -68,7 +74,7 @@ function trimPollOptions() {
|
||||||
const trimmedOptions = draft.value.params.poll!.options.slice(0, indexLastNonEmpty + 1)
|
const trimmedOptions = draft.value.params.poll!.options.slice(0, indexLastNonEmpty + 1)
|
||||||
|
|
||||||
if (currentInstance.value?.configuration
|
if (currentInstance.value?.configuration
|
||||||
&& trimmedOptions.length >= currentInstance.value?.configuration?.polls.maxOptions)
|
&& trimmedOptions.length >= currentInstance.value?.configuration?.polls.maxOptions)
|
||||||
draft.value.params.poll!.options = trimmedOptions
|
draft.value.params.poll!.options = trimmedOptions
|
||||||
else
|
else
|
||||||
draft.value.params.poll!.options = [...trimmedOptions, '']
|
draft.value.params.poll!.options = [...trimmedOptions, '']
|
||||||
|
@ -81,30 +87,32 @@ function editPollOptionDraft(event: Event, index: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function deletePollOption(index: number) {
|
function deletePollOption(index: number) {
|
||||||
draft.value.params.poll!.options = draft.value.params.poll!.options.slice().splice(index, 1)
|
const newPollOptions = draft.value.params.poll!.options.slice()
|
||||||
|
newPollOptions.splice(index, 1)
|
||||||
|
draft.value.params.poll!.options = newPollOptions
|
||||||
trimPollOptions()
|
trimPollOptions()
|
||||||
}
|
}
|
||||||
|
|
||||||
const expiresInOptions = computed(() => [
|
const expiresInOptions = computed(() => [
|
||||||
{
|
{
|
||||||
seconds: 1 * 60 * 60,
|
seconds: 1 * 60 * 60,
|
||||||
label: isHydrated.value ? t('time_ago_options.hour_future', 1) : '',
|
label: t('time_ago_options.hour_future', 1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
seconds: 2 * 60 * 60,
|
seconds: 2 * 60 * 60,
|
||||||
label: isHydrated.value ? t('time_ago_options.hour_future', 2) : '',
|
label: t('time_ago_options.hour_future', 2),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
seconds: 1 * 24 * 60 * 60,
|
seconds: 1 * 24 * 60 * 60,
|
||||||
label: isHydrated.value ? t('time_ago_options.day_future', 1) : '',
|
label: t('time_ago_options.day_future', 1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
seconds: 2 * 24 * 60 * 60,
|
seconds: 2 * 24 * 60 * 60,
|
||||||
label: isHydrated.value ? t('time_ago_options.day_future', 2) : '',
|
label: t('time_ago_options.day_future', 2),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
seconds: 7 * 24 * 60 * 60,
|
seconds: 7 * 24 * 60 * 60,
|
||||||
label: isHydrated.value ? t('time_ago_options.day_future', 7) : '',
|
label: t('time_ago_options.day_future', 7),
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -132,7 +140,7 @@ const characterCount = computed(() => {
|
||||||
length -= fullMatch.length - (before + username).length - 1 // - 1 for the @
|
length -= fullMatch.length - (before + username).length - 1 // - 1 for the @
|
||||||
|
|
||||||
if (draft.value.mentions) {
|
if (draft.value.mentions) {
|
||||||
// + 1 is needed as mentions always need a space seperator at the end
|
// + 1 is needed as mentions always need a space separator at the end
|
||||||
length += draft.value.mentions.map((mention) => {
|
length += draft.value.mentions.map((mention) => {
|
||||||
const [handle] = mention.split('@')
|
const [handle] = mention.split('@')
|
||||||
return `@${handle}`
|
return `@${handle}`
|
||||||
|
@ -150,6 +158,8 @@ const isExceedingCharacterLimit = computed(() => {
|
||||||
|
|
||||||
const postLanguageDisplay = computed(() => languagesNameList.find(i => i.code === (draft.value.params.language || preferredLanguage))?.nativeName)
|
const postLanguageDisplay = computed(() => languagesNameList.find(i => i.code === (draft.value.params.language || preferredLanguage))?.nativeName)
|
||||||
|
|
||||||
|
const isDM = computed(() => draft.value.params.visibility === 'direct')
|
||||||
|
|
||||||
async function handlePaste(evt: ClipboardEvent) {
|
async function handlePaste(evt: ClipboardEvent) {
|
||||||
const files = evt.clipboardData?.files
|
const files = evt.clipboardData?.files
|
||||||
if (!files || files.length === 0)
|
if (!files || files.length === 0)
|
||||||
|
@ -269,12 +279,16 @@ onDeactivated(() => {
|
||||||
</ol>
|
</ol>
|
||||||
</CommonErrorMessage>
|
</CommonErrorMessage>
|
||||||
|
|
||||||
<div relative flex-1 flex flex-col>
|
<div relative flex-1 flex flex-col min-h-30>
|
||||||
<EditorContent
|
<EditorContent
|
||||||
:editor="editor"
|
:editor="editor"
|
||||||
flex max-w-full
|
flex max-w-full
|
||||||
:class="shouldExpanded ? 'min-h-30 md:max-h-[calc(100vh-200px)] sm:max-h-[calc(100vh-400px)] max-h-35 of-y-auto overscroll-contain' : ''"
|
:class="{
|
||||||
|
'md:max-h-[calc(100vh-200px)] sm:max-h-[calc(100vh-400px)] max-h-35 of-y-auto overscroll-contain': shouldExpanded,
|
||||||
|
'py2 px3.5 bg-dm rounded-4 me--1 ms--1 mt--1': isDM,
|
||||||
|
}"
|
||||||
@keydown="stopQuestionMarkPropagation"
|
@keydown="stopQuestionMarkPropagation"
|
||||||
|
@keydown.esc.prevent="editor?.commands.blur()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -77,11 +77,12 @@ function activate() {
|
||||||
ps-3
|
ps-3
|
||||||
pe-1
|
pe-1
|
||||||
ml-1
|
ml-1
|
||||||
:placeholder="isHydrated ? t('nav.search') : ''"
|
:placeholder="t('nav.search')"
|
||||||
pb="1px"
|
pb="1px"
|
||||||
placeholder-text-secondary
|
placeholder-text-secondary
|
||||||
@keydown.down.prevent="shift(1)"
|
@keydown.down.prevent="shift(1)"
|
||||||
@keydown.up.prevent="shift(-1)"
|
@keydown.up.prevent="shift(-1)"
|
||||||
|
@keydown.esc.prevent="input?.blur()"
|
||||||
@keypress.enter="activate"
|
@keypress.enter="activate"
|
||||||
>
|
>
|
||||||
<button v-if="query.length" btn-action-icon text-secondary @click="query = ''; input?.focus()">
|
<button v-if="query.length" btn-action-icon text-secondary @click="query = ''; input?.focus()">
|
||||||
|
|
|
@ -10,20 +10,22 @@ const props = defineProps<{
|
||||||
external?: true
|
external?: true
|
||||||
large?: true
|
large?: true
|
||||||
match?: boolean
|
match?: boolean
|
||||||
|
target?: string
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const scrollOnClick = computed(() => props.to && !(props.target === '_blank' || props.external))
|
||||||
|
|
||||||
useCommand({
|
useCommand({
|
||||||
scope: 'Settings',
|
scope: 'Settings',
|
||||||
|
|
||||||
name: () => props.text
|
name: () => props.text
|
||||||
?? (props.to
|
?? (props.to
|
||||||
? typeof props.to === 'string'
|
? typeof props.to === 'string'
|
||||||
? props.to
|
? props.to
|
||||||
: props.to.name
|
: props.to.name
|
||||||
: ''
|
: ''
|
||||||
),
|
),
|
||||||
description: () => props.description,
|
description: () => props.description,
|
||||||
icon: () => props.icon || '',
|
icon: () => props.icon || '',
|
||||||
visible: () => props.command && props.to,
|
visible: () => props.command && props.to,
|
||||||
|
@ -39,11 +41,12 @@ useCommand({
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:to="to"
|
:to="to"
|
||||||
:external="external"
|
:external="external"
|
||||||
|
:target="target"
|
||||||
exact-active-class="text-primary"
|
exact-active-class="text-primary"
|
||||||
:class="disabled ? 'op25 pointer-events-none ' : match ? 'text-primary' : ''"
|
:class="disabled ? 'op25 pointer-events-none ' : match ? 'text-primary' : ''"
|
||||||
block w-full group focus:outline-none
|
block w-full group focus:outline-none
|
||||||
:tabindex="disabled ? -1 : null"
|
:tabindex="disabled ? -1 : null"
|
||||||
@click="to ? $scrollToTop() : undefined"
|
@click="scrollOnClick ? $scrollToTop() : undefined"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
w-full flex px5 py3 md:gap2 gap4 items-center
|
w-full flex px5 py3 md:gap2 gap4 items-center
|
||||||
|
|
|
@ -8,8 +8,7 @@ const dropdown = ref<any>()
|
||||||
|
|
||||||
const fieldIcons = computed(() =>
|
const fieldIcons = computed(() =>
|
||||||
Array.from({ length: maxAccountFieldCount.value }, (_, i) =>
|
Array.from({ length: maxAccountFieldCount.value }, (_, i) =>
|
||||||
getAccountFieldIcon(form.value.fieldsAttributes[i].name),
|
getAccountFieldIcon(form.value.fieldsAttributes[i].name)),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const fieldCount = computed(() => {
|
const fieldCount = computed(() => {
|
||||||
|
|
|
@ -16,7 +16,7 @@ const { disabled = false } = defineProps<{
|
||||||
:class="disabled ? 'opacity-50 cursor-not-allowed' : ''"
|
:class="disabled ? 'opacity-50 cursor-not-allowed' : ''"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
w-full flex w-fit px5 py3 md:gap2 gap4 items-center
|
w-full flex px5 py3 md:gap2 gap4 items-center
|
||||||
transition-250
|
transition-250
|
||||||
:class="disabled ? '' : 'group-hover:bg-active'"
|
:class="disabled ? '' : 'group-hover:bg-active'"
|
||||||
group-focus-visible:ring="2 current"
|
group-focus-visible:ring="2 current"
|
||||||
|
|
|
@ -55,7 +55,7 @@ function reply() {
|
||||||
|
|
||||||
<div flex-1>
|
<div flex-1>
|
||||||
<StatusActionButton
|
<StatusActionButton
|
||||||
:content="$t('action.boost')"
|
:content="$t(status.reblogged ? 'action.boosted' : 'action.boost')"
|
||||||
:text="!getPreferences(userSettings, 'hideBoostCount') && status.reblogsCount ? status.reblogsCount : ''"
|
:text="!getPreferences(userSettings, 'hideBoostCount') && status.reblogsCount ? status.reblogsCount : ''"
|
||||||
color="text-green" hover="text-green" elk-group-hover="bg-green/10"
|
color="text-green" hover="text-green" elk-group-hover="bg-green/10"
|
||||||
icon="i-ri:repeat-line"
|
icon="i-ri:repeat-line"
|
||||||
|
@ -77,7 +77,7 @@ function reply() {
|
||||||
|
|
||||||
<div flex-1>
|
<div flex-1>
|
||||||
<StatusActionButton
|
<StatusActionButton
|
||||||
:content="$t('action.favourite')"
|
:content="$t(status.favourited ? 'action.favourited' : 'action.favourite')"
|
||||||
:text="!getPreferences(userSettings, 'hideFavoriteCount') && status.favouritesCount ? status.favouritesCount : ''"
|
:text="!getPreferences(userSettings, 'hideFavoriteCount') && status.favouritesCount ? status.favouritesCount : ''"
|
||||||
:color="useStarFavoriteIcon ? 'text-yellow' : 'text-rose'"
|
:color="useStarFavoriteIcon ? 'text-yellow' : 'text-rose'"
|
||||||
:hover="useStarFavoriteIcon ? 'text-yellow' : 'text-rose'"
|
:hover="useStarFavoriteIcon ? 'text-yellow' : 'text-rose'"
|
||||||
|
@ -100,7 +100,7 @@ function reply() {
|
||||||
|
|
||||||
<div flex-none>
|
<div flex-none>
|
||||||
<StatusActionButton
|
<StatusActionButton
|
||||||
:content="$t('action.bookmark')"
|
:content="$t(status.bookmarked ? 'action.bookmarked' : 'action.bookmark')"
|
||||||
:color="useStarFavoriteIcon ? 'text-rose' : 'text-yellow'"
|
:color="useStarFavoriteIcon ? 'text-rose' : 'text-yellow'"
|
||||||
:hover="useStarFavoriteIcon ? 'text-rose' : 'text-yellow'"
|
:hover="useStarFavoriteIcon ? 'text-rose' : 'text-yellow'"
|
||||||
:elk-group-hover="useStarFavoriteIcon ? 'bg-rose/10' : 'bg-yellow/10' "
|
:elk-group-hover="useStarFavoriteIcon ? 'bg-rose/10' : 'bg-yellow/10' "
|
||||||
|
|
|
@ -62,12 +62,13 @@ async function shareLink(status: mastodon.v1.Status) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteStatus() {
|
async function deleteStatus() {
|
||||||
if (await openConfirmDialog({
|
const confirmDelete = await openConfirmDialog({
|
||||||
title: t('confirm.delete_posts.title'),
|
title: t('confirm.delete_posts.title'),
|
||||||
description: t('confirm.delete_posts.description'),
|
description: t('confirm.delete_posts.description'),
|
||||||
confirm: t('confirm.delete_posts.confirm'),
|
confirm: t('confirm.delete_posts.confirm'),
|
||||||
cancel: t('confirm.delete_posts.cancel'),
|
cancel: t('confirm.delete_posts.cancel'),
|
||||||
}) !== 'confirm')
|
})
|
||||||
|
if (confirmDelete.choice !== 'confirm')
|
||||||
return
|
return
|
||||||
|
|
||||||
removeCachedStatus(status.value.id)
|
removeCachedStatus(status.value.id)
|
||||||
|
@ -80,12 +81,13 @@ async function deleteStatus() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteAndRedraft() {
|
async function deleteAndRedraft() {
|
||||||
if (await openConfirmDialog({
|
const confirmDelete = await openConfirmDialog({
|
||||||
title: t('confirm.delete_posts.title'),
|
title: t('confirm.delete_posts.title'),
|
||||||
description: t('confirm.delete_posts.description'),
|
description: t('confirm.delete_posts.description'),
|
||||||
confirm: t('confirm.delete_posts.confirm'),
|
confirm: t('confirm.delete_posts.confirm'),
|
||||||
cancel: t('confirm.delete_posts.cancel'),
|
cancel: t('confirm.delete_posts.cancel'),
|
||||||
}) !== 'confirm')
|
})
|
||||||
|
if (confirmDelete.choice !== 'confirm')
|
||||||
return
|
return
|
||||||
|
|
||||||
if (import.meta.dev) {
|
if (import.meta.dev) {
|
||||||
|
@ -142,7 +144,7 @@ function showFavoritedAndBoostedBy() {
|
||||||
|
|
||||||
<template #popper>
|
<template #popper>
|
||||||
<div flex="~ col">
|
<div flex="~ col">
|
||||||
<template v-if="getPreferences(userSettings, 'zenMode')">
|
<template v-if="getPreferences(userSettings, 'zenMode') && !details">
|
||||||
<CommonDropdownItem
|
<CommonDropdownItem
|
||||||
:text="$t('action.reply')"
|
:text="$t('action.reply')"
|
||||||
icon="i-ri:chat-1-line"
|
icon="i-ri:chat-1-line"
|
||||||
|
|
|
@ -68,6 +68,7 @@ const video = ref<HTMLVideoElement | undefined>()
|
||||||
const prefersReducedMotion = usePreferredReducedMotion()
|
const prefersReducedMotion = usePreferredReducedMotion()
|
||||||
const isAudio = computed(() => attachment.type === 'audio')
|
const isAudio = computed(() => attachment.type === 'audio')
|
||||||
const isVideo = computed(() => attachment.type === 'video')
|
const isVideo = computed(() => attachment.type === 'video')
|
||||||
|
const isGif = computed(() => attachment.type === 'gifv')
|
||||||
|
|
||||||
const enableAutoplay = usePreferences('enableAutoplay')
|
const enableAutoplay = usePreferences('enableAutoplay')
|
||||||
|
|
||||||
|
@ -164,7 +165,7 @@ watch(shouldLoadAttachment, () => {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
relative
|
relative
|
||||||
@click="!shouldLoadAttachment ? loadAttachment() : null"
|
@click="!shouldLoadAttachment ? loadAttachment() : openMediaPreview(attachments ? attachments : [attachment], attachments?.indexOf(attachment) || 0)"
|
||||||
>
|
>
|
||||||
<video
|
<video
|
||||||
ref="video"
|
ref="video"
|
||||||
|
@ -248,12 +249,13 @@ watch(shouldLoadAttachment, () => {
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<div
|
<div
|
||||||
v-if="attachment.description && !getPreferences(userSettings, 'hideAltIndicatorOnPosts')" :class="isAudio ? [] : [
|
:class="isAudio ? [] : [
|
||||||
'absolute left-2',
|
'absolute left-2',
|
||||||
isVideo ? 'top-2' : 'bottom-2',
|
isVideo ? 'top-2' : 'bottom-2',
|
||||||
]"
|
]"
|
||||||
|
flex gap-col-2
|
||||||
>
|
>
|
||||||
<VDropdown :distance="6" placement="bottom-start">
|
<VDropdown v-if="attachment.description && !getPreferences(userSettings, 'hideAltIndicatorOnPosts')" :distance="6" placement="bottom-start">
|
||||||
<button
|
<button
|
||||||
font-bold text-sm
|
font-bold text-sm
|
||||||
:class="isAudio
|
:class="isAudio
|
||||||
|
@ -281,6 +283,14 @@ watch(shouldLoadAttachment, () => {
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</VDropdown>
|
</VDropdown>
|
||||||
|
<div v-if="isGif && !getPreferences(userSettings, 'hideGifIndicatorOnPosts')">
|
||||||
|
<button
|
||||||
|
aria-hidden font-bold text-sm
|
||||||
|
rounded-1 bg-black:65 text-white px1.2 py0.2 pointer-events-none
|
||||||
|
>
|
||||||
|
{{ $t('status.gif') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -63,8 +63,8 @@ const isSelfReply = computed(() => status.value.inReplyToAccountId === status.va
|
||||||
const collapseRebloggedBy = computed(() => rebloggedBy.value?.id === status.value.account.id)
|
const collapseRebloggedBy = computed(() => rebloggedBy.value?.id === status.value.account.id)
|
||||||
const isDM = computed(() => status.value.visibility === 'direct')
|
const isDM = computed(() => status.value.visibility === 'direct')
|
||||||
|
|
||||||
const showUpperBorder = computed(() => props.newer && !directReply)
|
const showUpperBorder = computed(() => props.newer && !directReply.value)
|
||||||
const showReplyTo = computed(() => !replyToMain && !directReply)
|
const showReplyTo = computed(() => !replyToMain.value && !directReply.value)
|
||||||
|
|
||||||
const forceShow = ref(false)
|
const forceShow = ref(false)
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -30,14 +30,14 @@ const hideAllMedia = computed(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
const embeddedMediaPreference = usePreferences('experimentalEmbeddedMedia')
|
const embeddedMediaPreference = usePreferences('experimentalEmbeddedMedia')
|
||||||
const allowEmbeddedMedia = computed(() => status.card?.html && embeddedMediaPreference)
|
const allowEmbeddedMedia = computed(() => status.card?.html && embeddedMediaPreference.value)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
space-y-3
|
space-y-3
|
||||||
:class="{
|
:class="{
|
||||||
'pt2 pb0.5 px3.5 bg-dm rounded-4 me--1': isDM,
|
'py2 px3.5 bg-dm rounded-4 me--1': isDM,
|
||||||
'ms--3.5 mt--1 ms--1': isDM && context !== 'details',
|
'ms--3.5 mt--1 ms--1': isDM && context !== 'details',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
|
@ -68,7 +68,6 @@ const allowEmbeddedMedia = computed(() => status.card?.html && embeddedMediaPref
|
||||||
:status="status.reblog" border="~ rounded"
|
:status="status.reblog" border="~ rounded"
|
||||||
:actions="false"
|
:actions="false"
|
||||||
/>
|
/>
|
||||||
<div v-if="isDM" />
|
|
||||||
</StatusSpoiler>
|
</StatusSpoiler>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -31,7 +31,7 @@ useHydratedHead({
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :id="`status-${status.id}`" flex flex-col gap-2 pt2 pb1 ps-3 pe-4 relative :lang="status.language ?? undefined" aria-roledescription="status-details">
|
<div :id="`status-${status.id}`" flex flex-col gap-2 pt2 pb1 ps-3 pe-4 relative :lang="status.language ?? undefined" aria-roledescription="status-details">
|
||||||
<StatusActionsMore :status="status" absolute inset-ie-2 top-2 @after-edit="$emit('refetchStatus')" />
|
<StatusActionsMore :status="status" :details="true" absolute inset-ie-2 top-2 @after-edit="$emit('refetchStatus')" />
|
||||||
<NuxtLink :to="getAccountRoute(status.account)" rounded-full hover:bg-active transition-100 pe5 me-a>
|
<NuxtLink :to="getAccountRoute(status.account)" rounded-full hover:bg-active transition-100 pe5 me-a>
|
||||||
<AccountHoverWrapper :account="status.account">
|
<AccountHoverWrapper :account="status.account">
|
||||||
<AccountInfo :account="status.account" />
|
<AccountInfo :account="status.account" />
|
||||||
|
|
|
@ -42,7 +42,7 @@ const tabs = [
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
relative flex flex-auto cursor-pointer sm:px6 px2 rounded transition-all
|
relative flex flex-auto cursor-pointer sm:px6 px2 rounded transition-all
|
||||||
tabindex="1"
|
tabindex="0"
|
||||||
hover:bg-active transition-100
|
hover:bg-active transition-100
|
||||||
@click="option.onClick"
|
@click="option.onClick"
|
||||||
>
|
>
|
||||||
|
|
|
@ -14,7 +14,8 @@ function onclick(evt: MouseEvent | KeyboardEvent) {
|
||||||
const path = evt.composedPath() as HTMLElement[]
|
const path = evt.composedPath() as HTMLElement[]
|
||||||
const el = path.find(el => ['A', 'BUTTON', 'IMG', 'VIDEO'].includes(el.tagName?.toUpperCase()))
|
const el = path.find(el => ['A', 'BUTTON', 'IMG', 'VIDEO'].includes(el.tagName?.toUpperCase()))
|
||||||
const text = window.getSelection()?.toString()
|
const text = window.getSelection()?.toString()
|
||||||
if (!el && !text)
|
const isCustomEmoji = el?.parentElement?.classList.contains('custom-emoji')
|
||||||
|
if ((!el && !text) || isCustomEmoji)
|
||||||
go(evt)
|
go(evt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,56 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { mastodon } from 'masto'
|
import type { mastodon } from 'masto'
|
||||||
|
import { fetchAccountById } from '~/composables/cache'
|
||||||
|
|
||||||
const {
|
type WatcherType = [status?: mastodon.v1.Status, v?: boolean]
|
||||||
status,
|
|
||||||
isSelfReply = false,
|
const props = defineProps<{
|
||||||
} = defineProps<{
|
|
||||||
status: mastodon.v1.Status
|
status: mastodon.v1.Status
|
||||||
isSelfReply: boolean
|
isSelfReply: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const isSelf = computed(() => status.inReplyToAccountId === status.account.id)
|
const link = ref()
|
||||||
const account = isSelf ? computed(() => status.account) : useAccountById(status.inReplyToAccountId)
|
const targetIsVisible = ref(false)
|
||||||
|
const isSelf = computed(() => props.status.inReplyToAccountId === props.status.account.id)
|
||||||
|
const account = ref<mastodon.v1.Account | null | undefined>(isSelf.value ? props.status.account : undefined)
|
||||||
|
|
||||||
|
useIntersectionObserver(
|
||||||
|
link,
|
||||||
|
([{ intersectionRatio }]) => {
|
||||||
|
targetIsVisible.value = intersectionRatio > 0.1
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => [props.status, targetIsVisible.value] satisfies WatcherType,
|
||||||
|
([newStatus, newVisible]) => {
|
||||||
|
if (newStatus.account && newStatus.inReplyToAccountId === newStatus.account.id) {
|
||||||
|
account.value = newStatus.account
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newVisible)
|
||||||
|
return
|
||||||
|
|
||||||
|
const newId = newStatus.inReplyToAccountId
|
||||||
|
|
||||||
|
if (newId) {
|
||||||
|
fetchAccountById(newStatus.inReplyToAccountId).then((acc) => {
|
||||||
|
if (newId === props.status.inReplyToAccountId)
|
||||||
|
account.value = acc
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
account.value = undefined
|
||||||
|
},
|
||||||
|
{ immediate: true, flush: 'post' },
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
v-if="status.inReplyToId"
|
v-if="status.inReplyToId"
|
||||||
|
ref="link"
|
||||||
flex="~ gap2" items-center h-auto text-sm text-secondary
|
flex="~ gap2" items-center h-auto text-sm text-secondary
|
||||||
:to="getStatusInReplyToRoute(status)"
|
:to="getStatusInReplyToRoute(status)"
|
||||||
:title="$t('status.replying_to', [account ? getDisplayName(account) : $t('status.someone')])"
|
:title="$t('status.replying_to', [account ? getDisplayName(account) : $t('status.someone')])"
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const props = defineProps<{ enabled?: boolean; filter?: boolean; isDM?: boolean; sensitiveNonSpoiler?: boolean }>()
|
const props = defineProps<{
|
||||||
|
enabled?: boolean
|
||||||
|
filter?: boolean
|
||||||
|
isDM?: boolean
|
||||||
|
sensitiveNonSpoiler?: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
const expandSpoilers = computed(() => {
|
const expandSpoilers = computed(() => {
|
||||||
const expandCW = currentUser.value ? getExpandSpoilersByDefault(currentUser.value.account) : false
|
const expandCW = currentUser.value ? getExpandSpoilersByDefault(currentUser.value.account) : false
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
<script lang="ts" setup>
|
<script setup lang="ts">
|
||||||
import type { mastodon } from 'masto'
|
import type { mastodon } from 'masto'
|
||||||
|
|
||||||
const {
|
const { tag } = defineProps<{
|
||||||
tag,
|
|
||||||
} = defineProps<{
|
|
||||||
tag: mastodon.v1.Tag
|
tag: mastodon.v1.Tag
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
@ -32,19 +30,21 @@ function go(evt: MouseEvent | KeyboardEvent) {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
block p4 hover:bg-active flex justify-between cursor-pointer
|
block p4 hover:bg-active flex justify-between cursor-pointer flex-gap-2
|
||||||
@click="onclick"
|
@click="onclick"
|
||||||
@keydown.enter="onclick"
|
@keydown.enter="onclick"
|
||||||
>
|
>
|
||||||
<div>
|
<div flex flex-gap-2>
|
||||||
<h4 flex items-center text-size-base leading-normal font-medium line-clamp-1 break-all ws-pre-wrap>
|
<TagActionButton :tag="tag" />
|
||||||
<TagActionButton :tag="tag" />
|
<div>
|
||||||
<bdi>
|
<h4 flex items-center text-size-base leading-normal font-medium line-clamp-1 break-all ws-pre-wrap>
|
||||||
<span>#</span>
|
<bdi>
|
||||||
<span hover:underline>{{ tag.name }}</span>
|
<span>#</span>
|
||||||
</bdi>
|
<span hover:underline>{{ tag.name }}</span>
|
||||||
</h4>
|
</bdi>
|
||||||
<CommonTrending v-if="tag.history" :history="tag.history" text-sm text-secondary line-clamp-1 ws-pre-wrap break-all />
|
</h4>
|
||||||
|
<CommonTrending v-if="tag.history" :history="tag.history" text-sm text-secondary line-clamp-1 ws-pre-wrap break-all />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="tag.history" flex items-center>
|
<div v-if="tag.history" flex items-center>
|
||||||
<CommonTrendingCharts :history="tag.history" />
|
<CommonTrendingCharts :history="tag.history" />
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div p4 flex justify-between>
|
<div p4 flex justify-between gap-4>
|
||||||
<div flex="~ col 1 gap-2">
|
<div flex="~ col 1 gap-2">
|
||||||
<div flex class="skeleton-loading-bg" h-5 w-30 rounded />
|
<div flex class="skeleton-loading-bg" h-5 w-30 rounded />
|
||||||
<div flex class="skeleton-loading-bg" h-4 w-45 rounded />
|
<div flex class="skeleton-loading-bg" h-4 w-45 rounded />
|
||||||
|
|
|
@ -1,18 +1,27 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { mastodon } from 'masto'
|
import type { mastodon } from 'masto'
|
||||||
|
import { STORAGE_KEY_LAST_ACCESSED_NOTIFICATION_ROUTE } from '~/constants'
|
||||||
|
|
||||||
const { filter } = defineProps<{
|
const { filter } = defineProps<{
|
||||||
filter?: mastodon.v1.NotificationType
|
filter?: mastodon.v1.NotificationType
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const lastAccessedNotificationRoute = useLocalStorage(STORAGE_KEY_LAST_ACCESSED_NOTIFICATION_ROUTE, '')
|
||||||
|
|
||||||
const options = { limit: 30, types: filter ? [filter] : [] }
|
const options = { limit: 30, types: filter ? [filter] : [] }
|
||||||
|
|
||||||
// Default limit is 20 notifications, and servers are normally caped to 30
|
// Default limit is 20 notifications, and servers are normally caped to 30
|
||||||
const paginator = useMastoClient().v1.notifications.list(options)
|
const paginator = useMastoClient().v1.notifications.list(options)
|
||||||
const stream = useStreaming(client => client.user.notification.subscribe())
|
const stream = useStreaming(client => client.user.notification.subscribe())
|
||||||
|
|
||||||
|
lastAccessedNotificationRoute.value = route.path.replace(/\/notifications\/?/, '')
|
||||||
|
|
||||||
const { clearNotifications } = useNotifications()
|
const { clearNotifications } = useNotifications()
|
||||||
onActivated(clearNotifications)
|
onActivated(() => {
|
||||||
|
clearNotifications()
|
||||||
|
lastAccessedNotificationRoute.value = route.path.replace(/\/notifications\/?/, '')
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const paginator = useMastoClient().v1.timelines.public.list({ limit: 30, local: true })
|
const paginator = useMastoClient().v1.timelines.public.list({ limit: 30, local: true })
|
||||||
const stream = useStreaming(client => client.direct.subscribe())
|
const stream = useStreaming(client => client.public.local.subscribe())
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -72,7 +72,7 @@ function onEnter(e: KeyboardEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeAutocomplete(evt: KeyboardEvent) {
|
function escapeAutocomplete(evt: KeyboardEvent) {
|
||||||
if (!autocompleteShow)
|
if (!autocompleteShow.value)
|
||||||
return
|
return
|
||||||
autocompleteShow.value = false
|
autocompleteShow.value = false
|
||||||
evt.stopPropagation()
|
evt.stopPropagation()
|
||||||
|
|
|
@ -3,8 +3,10 @@ import type { BuildInfo } from '~~/types'
|
||||||
export interface Team {
|
export interface Team {
|
||||||
github: string
|
github: string
|
||||||
display: string
|
display: string
|
||||||
twitter: string
|
twitter?: string
|
||||||
mastodon: string
|
mastodon: string
|
||||||
|
link: string
|
||||||
|
sponsors?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const elkTeamMembers: Team[] = [
|
export const elkTeamMembers: Team[] = [
|
||||||
|
@ -13,24 +15,43 @@ export const elkTeamMembers: Team[] = [
|
||||||
display: 'Anthony Fu',
|
display: 'Anthony Fu',
|
||||||
twitter: 'antfu7',
|
twitter: 'antfu7',
|
||||||
mastodon: 'antfu@webtoo.ls',
|
mastodon: 'antfu@webtoo.ls',
|
||||||
|
link: '/m.webtoo.ls/@antfu',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
github: 'patak-dev',
|
github: 'patak-dev',
|
||||||
display: 'Patak',
|
display: 'Patak',
|
||||||
twitter: 'patak_dev',
|
twitter: 'patak_dev',
|
||||||
mastodon: 'patak@webtoo.ls',
|
mastodon: 'patak@webtoo.ls',
|
||||||
|
link: '/m.webtoo.ls/@patak',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
github: 'danielroe',
|
github: 'danielroe',
|
||||||
display: 'Daniel Roe',
|
display: 'Daniel Roe',
|
||||||
twitter: 'danielcroe',
|
twitter: 'danielcroe',
|
||||||
mastodon: 'daniel@roe.dev',
|
mastodon: 'daniel@roe.dev',
|
||||||
|
link: '/mastodon.roe.dev/@daniel',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
github: 'sxzz',
|
github: 'sxzz',
|
||||||
display: '三咲智子 Kevin Deng',
|
display: '三咲智子 Kevin Deng',
|
||||||
twitter: 'sanxiaozhizi',
|
twitter: 'sanxiaozhizi',
|
||||||
mastodon: 'sxzz@webtoo.ls',
|
mastodon: 'sxzz@webtoo.ls',
|
||||||
|
link: '/m.webtoo.ls/@sxzz',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
github: 'userquin',
|
||||||
|
display: 'Joaquín Sánchez',
|
||||||
|
twitter: 'userquin',
|
||||||
|
mastodon: 'userquin@webtoo.ls',
|
||||||
|
link: '/m.webtoo.ls/@userquin',
|
||||||
|
sponsors: 'elk-zone', // sponsors/userquin isn't enabled
|
||||||
|
},
|
||||||
|
{
|
||||||
|
github: 'shuuji3',
|
||||||
|
display: 'TAKAHASHI Shuuji',
|
||||||
|
mastodon: 'shuuji3@webtoo.ls',
|
||||||
|
link: '/m.webtoo.ls/@shuuji3',
|
||||||
|
sponsors: 'elk-zone', // sponsors/shuuji3 isn't enabled
|
||||||
},
|
},
|
||||||
].sort(() => Math.random() - 0.5)
|
].sort(() => Math.random() - 0.5)
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,8 @@ export function fetchStatus(id: string, force = false): Promise<mastodon.v1.Stat
|
||||||
const key = `${server}:${userId}:status:${id}`
|
const key = `${server}:${userId}:status:${id}`
|
||||||
const cached = cache.get(key)
|
const cached = cache.get(key)
|
||||||
if (cached && !force)
|
if (cached && !force)
|
||||||
return cached
|
return Promise.resolve(cached)
|
||||||
|
|
||||||
const promise = useMastoClient().v1.statuses.$select(id).fetch()
|
const promise = useMastoClient().v1.statuses.$select(id).fetch()
|
||||||
.then((status) => {
|
.then((status) => {
|
||||||
cacheStatus(status)
|
cacheStatus(status)
|
||||||
|
@ -42,7 +43,8 @@ export function fetchAccountById(id?: string | null): Promise<mastodon.v1.Accoun
|
||||||
const key = `${server}:${userId}:account:${id}`
|
const key = `${server}:${userId}:account:${id}`
|
||||||
const cached = cache.get(key)
|
const cached = cache.get(key)
|
||||||
if (cached)
|
if (cached)
|
||||||
return cached
|
return Promise.resolve(cached)
|
||||||
|
|
||||||
const domain = getInstanceDomainFromServer(server)
|
const domain = getInstanceDomainFromServer(server)
|
||||||
const promise = useMastoClient().v1.accounts.$select(id).fetch()
|
const promise = useMastoClient().v1.accounts.$select(id).fetch()
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
|
@ -64,7 +66,7 @@ export async function fetchAccountByHandle(acct: string): Promise<mastodon.v1.Ac
|
||||||
const key = `${server}:${userId}:account:${userAcct}`
|
const key = `${server}:${userId}:account:${userAcct}`
|
||||||
const cached = cache.get(key)
|
const cached = cache.get(key)
|
||||||
if (cached)
|
if (cached)
|
||||||
return cached
|
return Promise.resolve(cached)
|
||||||
|
|
||||||
async function lookupAccount() {
|
async function lookupAccount() {
|
||||||
const client = useMastoClient()
|
const client = useMastoClient()
|
||||||
|
@ -82,13 +84,30 @@ export async function fetchAccountByHandle(acct: string): Promise<mastodon.v1.Ac
|
||||||
return account
|
return account
|
||||||
}
|
}
|
||||||
|
|
||||||
const account = lookupAccount()
|
const promise = lookupAccount()
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
cacheAccount(r, server, true)
|
cacheAccount(r, server, true)
|
||||||
return r
|
return r
|
||||||
})
|
})
|
||||||
cache.set(key, account)
|
cache.set(key, promise)
|
||||||
return account
|
return promise
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchTag(tagName: string, force = false): Promise<mastodon.v1.Tag> {
|
||||||
|
const server = currentServer.value
|
||||||
|
const userId = currentUser.value?.account.id
|
||||||
|
const key = `${server}:${userId}:tag:${tagName}`
|
||||||
|
const cached = cache.get(key)
|
||||||
|
if (cached && !force)
|
||||||
|
return Promise.resolve(cached)
|
||||||
|
|
||||||
|
const promise = useMastoClient().v1.tags.$select(tagName).fetch()
|
||||||
|
.then((tag) => {
|
||||||
|
cacheTag(tag)
|
||||||
|
return tag
|
||||||
|
})
|
||||||
|
cache.set(key, promise)
|
||||||
|
return promise
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useAccountById(id?: string | null) {
|
export function useAccountById(id?: string | null) {
|
||||||
|
@ -111,3 +130,8 @@ export function cacheAccount(account: mastodon.v1.Account, server = currentServe
|
||||||
setCached(`${server}:${userId}:account:${account.id}`, account, override)
|
setCached(`${server}:${userId}:account:${account.id}`, account, override)
|
||||||
setCached(`${server}:${userId}:account:${userAcct}`, account, override)
|
setCached(`${server}:${userId}:account:${userAcct}`, account, override)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function cacheTag(tag: mastodon.v1.Tag, server = currentServer.value, override?: boolean) {
|
||||||
|
const userId = currentUser.value?.account.id
|
||||||
|
setCached(`${server}:${userId}:tag:${tag.name}`, tag, override)
|
||||||
|
}
|
||||||
|
|
|
@ -170,7 +170,8 @@ export const useCommandRegistry = defineStore('command', () => {
|
||||||
const indexed = cmds.map((cmd, index) => ({ ...cmd, index }))
|
const indexed = cmds.map((cmd, index) => ({ ...cmd, index }))
|
||||||
|
|
||||||
const grouped = new Map<CommandScopeNames, CommandQueryResultItem[]>(
|
const grouped = new Map<CommandScopeNames, CommandQueryResultItem[]>(
|
||||||
scopes.map(scope => [scope, []]))
|
scopes.map(scope => [scope, []]),
|
||||||
|
)
|
||||||
for (const cmd of indexed) {
|
for (const cmd of indexed) {
|
||||||
const scope = cmd.scope ?? ''
|
const scope = cmd.scope ?? ''
|
||||||
grouped.get(scope)!.push({
|
grouped.get(scope)!.push({
|
||||||
|
@ -244,24 +245,12 @@ export function useCommands(cmds: () => CommandProvider[]) {
|
||||||
export function provideGlobalCommands() {
|
export function provideGlobalCommands() {
|
||||||
const { locale, t } = useI18n()
|
const { locale, t } = useI18n()
|
||||||
const { locales } = useI18n() as { locales: ComputedRef<LocaleObject[]> }
|
const { locales } = useI18n() as { locales: ComputedRef<LocaleObject[]> }
|
||||||
const router = useRouter()
|
|
||||||
const users = useUsers()
|
const users = useUsers()
|
||||||
const masto = useMasto()
|
const masto = useMasto()
|
||||||
const colorMode = useColorMode()
|
const colorMode = useColorMode()
|
||||||
const userSettings = useUserSettings()
|
const userSettings = useUserSettings()
|
||||||
const { singleInstanceServer, oauth } = useSignIn()
|
const { singleInstanceServer, oauth } = useSignIn()
|
||||||
|
|
||||||
useCommand({
|
|
||||||
scope: 'Navigation',
|
|
||||||
|
|
||||||
name: () => t('nav.settings'),
|
|
||||||
icon: 'i-ri:settings-3-line',
|
|
||||||
|
|
||||||
onActivate() {
|
|
||||||
router.push('/settings')
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
useCommand({
|
useCommand({
|
||||||
scope: 'Preferences',
|
scope: 'Preferences',
|
||||||
|
|
||||||
|
|
|
@ -494,7 +494,10 @@ function _markdownProcess(value: string) {
|
||||||
|
|
||||||
let start = 0
|
let start = 0
|
||||||
while (true) {
|
while (true) {
|
||||||
let found: { match: RegExpMatchArray; replacer: (c: (string | Node)[]) => Node } | undefined
|
let found: {
|
||||||
|
match: RegExpMatchArray
|
||||||
|
replacer: (c: (string | Node)[]) => Node
|
||||||
|
} | undefined
|
||||||
|
|
||||||
for (const [re, replacer] of _markdownReplacements) {
|
for (const [re, replacer] of _markdownReplacements) {
|
||||||
re.lastIndex = start
|
re.lastIndex = start
|
||||||
|
@ -524,10 +527,21 @@ function transformMarkdown(node: Node) {
|
||||||
return _markdownProcess(node.value)
|
return _markdownProcess(node.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addBdiParagraphs(node: Node) {
|
||||||
|
if (node.name === 'p' && !('dir' in node.attributes) && node.children?.length && node.children.length > 1)
|
||||||
|
node.attributes.dir = 'auto'
|
||||||
|
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
function transformParagraphs(node: Node): Node | Node[] {
|
function transformParagraphs(node: Node): Node | Node[] {
|
||||||
|
// Add bdi to paragraphs
|
||||||
|
addBdiParagraphs(node)
|
||||||
|
|
||||||
// For top level paragraphs, inject an empty <p> to preserve status paragraphs in our editor (except for the last one)
|
// For top level paragraphs, inject an empty <p> to preserve status paragraphs in our editor (except for the last one)
|
||||||
if (node.parent?.type === DOCUMENT_NODE && node.name === 'p' && node.parent.children.at(-1) !== node)
|
if (node.parent?.type === DOCUMENT_NODE && node.name === 'p' && node.parent.children.at(-1) !== node)
|
||||||
return [node, h('p')]
|
return [node, h('p')]
|
||||||
|
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,7 +623,7 @@ function transformCollapseMentions(status?: mastodon.v1.Status, inReplyToStatus?
|
||||||
|
|
||||||
// We have a special case for single mentions that are part of a reply.
|
// We have a special case for single mentions that are part of a reply.
|
||||||
// We already have the replying to badge in this case or the status is connected to the previous one.
|
// We already have the replying to badge in this case or the status is connected to the previous one.
|
||||||
// This is needed because the status doesn't included the in Reply to handle, only the account id.
|
// This is needed because the status doesn't include the in Reply to handle, only the account id.
|
||||||
// But this covers the majority of cases.
|
// But this covers the majority of cases.
|
||||||
const showMentions = !(contextualMentionsCount === 0 || (mentionsCount === 1 && status?.inReplyToAccountId))
|
const showMentions = !(contextualMentionsCount === 0 || (mentionsCount === 1 && status?.inReplyToAccountId))
|
||||||
const grouped = contextualMentionsCount > 2
|
const grouped = contextualMentionsCount > 2
|
||||||
|
|
|
@ -10,6 +10,7 @@ import Emoji from '~/components/emoji/Emoji.vue'
|
||||||
import ContentCode from '~/components/content/ContentCode.vue'
|
import ContentCode from '~/components/content/ContentCode.vue'
|
||||||
import ContentMentionGroup from '~/components/content/ContentMentionGroup.vue'
|
import ContentMentionGroup from '~/components/content/ContentMentionGroup.vue'
|
||||||
import AccountHoverWrapper from '~/components/account/AccountHoverWrapper.vue'
|
import AccountHoverWrapper from '~/components/account/AccountHoverWrapper.vue'
|
||||||
|
import TagHoverWrapper from '~/components/account/TagHoverWrapper.vue'
|
||||||
|
|
||||||
function getTextualAstComponents(astChildren: Node[]): string {
|
function getTextualAstComponents(astChildren: Node[]): string {
|
||||||
return astChildren
|
return astChildren
|
||||||
|
@ -128,11 +129,13 @@ function handleMention(el: Node) {
|
||||||
addBdiNode(el)
|
addBdiNode(el)
|
||||||
return h(AccountHoverWrapper, { handle, class: 'inline-block' }, () => nodeToVNode(el))
|
return h(AccountHoverWrapper, { handle, class: 'inline-block' }, () => nodeToVNode(el))
|
||||||
}
|
}
|
||||||
|
|
||||||
const matchTag = href.match(TagLinkRE)
|
const matchTag = href.match(TagLinkRE)
|
||||||
if (matchTag) {
|
if (matchTag) {
|
||||||
const [, , name] = matchTag
|
const [, , tagName] = matchTag
|
||||||
addBdiNode(el)
|
addBdiNode(el)
|
||||||
el.attributes.href = `/${currentServer.value}/tags/${name}`
|
el.attributes.href = `/${currentServer.value}/tags/${tagName}`
|
||||||
|
return h(TagHoverWrapper, { tagName, class: 'inline-block' }, () => nodeToVNode(el))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import type { mastodon } from 'masto'
|
import type { mastodon } from 'masto'
|
||||||
import type { ConfirmDialogChoice, ConfirmDialogLabel, Draft, ErrorDialogData } from '~/types'
|
import type { ConfirmDialogChoice, ConfirmDialogOptions, Draft, ErrorDialogData } from '~/types'
|
||||||
import { STORAGE_KEY_FIRST_VISIT } from '~/constants'
|
import { STORAGE_KEY_FIRST_VISIT } from '~/constants'
|
||||||
|
|
||||||
export const confirmDialogChoice = ref<ConfirmDialogChoice>()
|
export const confirmDialogChoice = ref<ConfirmDialogChoice>()
|
||||||
export const confirmDialogLabel = ref<ConfirmDialogLabel>()
|
export const confirmDialogLabel = ref<ConfirmDialogOptions>()
|
||||||
export const errorDialogData = ref<ErrorDialogData>()
|
export const errorDialogData = ref<ErrorDialogData>()
|
||||||
|
|
||||||
export const mediaPreviewList = ref<mastodon.v1.MediaAttachment[]>([])
|
export const mediaPreviewList = ref<mastodon.v1.MediaAttachment[]>([])
|
||||||
|
@ -39,7 +39,7 @@ export function openSigninDialog() {
|
||||||
isSigninDialogOpen.value = true
|
isSigninDialogOpen.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function openConfirmDialog(label: ConfirmDialogLabel | string): Promise<ConfirmDialogChoice> {
|
export async function openConfirmDialog(label: ConfirmDialogOptions | string): Promise<ConfirmDialogChoice> {
|
||||||
confirmDialogLabel.value = typeof label === 'string' ? { title: label } : label
|
confirmDialogLabel.value = typeof label === 'string' ? { title: label } : label
|
||||||
confirmDialogChoice.value = undefined
|
confirmDialogChoice.value = undefined
|
||||||
isConfirmDialogOpen.value = true
|
isConfirmDialogOpen.value = true
|
||||||
|
|
|
@ -29,8 +29,10 @@ export function useHumanReadableNumber() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useFormattedDateTime(value: MaybeRefOrGetter<string | number | Date | undefined | null>,
|
export function useFormattedDateTime(
|
||||||
options: Intl.DateTimeFormatOptions = { dateStyle: 'long', timeStyle: 'medium' }) {
|
value: MaybeRefOrGetter<string | number | Date | undefined | null>,
|
||||||
|
options: Intl.DateTimeFormatOptions = { dateStyle: 'long', timeStyle: 'medium' },
|
||||||
|
) {
|
||||||
const { locale } = useI18n()
|
const { locale } = useI18n()
|
||||||
const formatter = computed(() => Intl.DateTimeFormat(locale.value, options))
|
const formatter = computed(() => Intl.DateTimeFormat(locale.value, options))
|
||||||
return computed(() => {
|
return computed(() => {
|
||||||
|
@ -75,3 +77,32 @@ export function useTimeAgoOptions(short = false): UseTimeAgoOptions<false> {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useFileSizeFormatter() {
|
||||||
|
const { locale } = useI18n()
|
||||||
|
|
||||||
|
const formatters = computed(() => ([
|
||||||
|
Intl.NumberFormat(locale.value, {
|
||||||
|
style: 'unit',
|
||||||
|
unit: 'megabyte',
|
||||||
|
unitDisplay: 'narrow',
|
||||||
|
maximumFractionDigits: 0,
|
||||||
|
}),
|
||||||
|
Intl.NumberFormat(locale.value, {
|
||||||
|
style: 'unit',
|
||||||
|
unit: 'kilobyte',
|
||||||
|
unitDisplay: 'narrow',
|
||||||
|
maximumFractionDigits: 0,
|
||||||
|
}),
|
||||||
|
]))
|
||||||
|
|
||||||
|
const megaByte = 1024 * 1024
|
||||||
|
|
||||||
|
function formatFileSize(size: number) {
|
||||||
|
return size >= megaByte
|
||||||
|
? formatters.value[0].format(size / megaByte)
|
||||||
|
: formatters.value[1].format(size / 1024)
|
||||||
|
}
|
||||||
|
|
||||||
|
return { formatFileSize }
|
||||||
|
}
|
||||||
|
|
|
@ -36,9 +36,11 @@ export function useMagicSequence(keys: string[]): ComputedRef<boolean> {
|
||||||
down = false
|
down = false
|
||||||
success.value = true
|
success.value = true
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
deep: true,
|
deep: true,
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
return computed(() => success.value)
|
return computed(() => success.value)
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,26 +36,25 @@ export function usePublish(options: {
|
||||||
const { params, attachments } = draft.value
|
const { params, attachments } = draft.value
|
||||||
const firstEmptyInputIndex = params.poll?.options.findIndex(option => option.trim().length === 0)
|
const firstEmptyInputIndex = params.poll?.options.findIndex(option => option.trim().length === 0)
|
||||||
return isEmpty.value
|
return isEmpty.value
|
||||||
|| options.isUploading.value
|
|| options.isUploading.value
|
||||||
|| isSending.value
|
|| isSending.value
|
||||||
|| (attachments.length === 0 && !params.status)
|
|| (attachments.length === 0 && !params.status)
|
||||||
|| failedMessages.value.length > 0
|
|| failedMessages.value.length > 0
|
||||||
|| (attachments.length > 0 && params.poll !== null && params.poll !== undefined)
|
|| (attachments.length > 0 && params.poll !== null && params.poll !== undefined)
|
||||||
|| ((params.poll !== null && params.poll !== undefined)
|
|| ((params.poll !== null && params.poll !== undefined)
|
||||||
&& (
|
&& (
|
||||||
(firstEmptyInputIndex !== -1
|
(firstEmptyInputIndex !== -1
|
||||||
&& firstEmptyInputIndex !== params.poll.options.length - 1
|
&& firstEmptyInputIndex !== params.poll.options.length - 1
|
||||||
)
|
)
|
||||||
|| params.poll.options.findLastIndex(option => option.trim().length > 0) + 1 < 2
|
|| params.poll.options.findLastIndex(option => option.trim().length > 0) + 1 < 2
|
||||||
|| (new Set(params.poll.options).size !== params.poll.options.length)
|
|| (new Set(params.poll.options).size !== params.poll.options.length)
|
||||||
|| (currentInstance.value?.configuration?.polls.maxCharactersPerOption !== undefined
|
|| (currentInstance.value?.configuration?.polls.maxCharactersPerOption !== undefined
|
||||||
&& params.poll.options.find(option => option.length > currentInstance.value!.configuration!.polls.maxCharactersPerOption) !== undefined
|
&& params.poll.options.find(option => option.length > currentInstance.value!.configuration!.polls.maxCharactersPerOption) !== undefined
|
||||||
)
|
)
|
||||||
)
|
))
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(() => draft, () => {
|
watch(draft, () => {
|
||||||
if (failedMessages.value.length > 0)
|
if (failedMessages.value.length > 0)
|
||||||
failedMessages.value.length = 0
|
failedMessages.value.length = 0
|
||||||
}, { deep: true })
|
}, { deep: true })
|
||||||
|
@ -156,6 +155,7 @@ export type MediaAttachmentUploadError = [filename: string, message: string]
|
||||||
export function useUploadMediaAttachment(draft: Ref<Draft>) {
|
export function useUploadMediaAttachment(draft: Ref<Draft>) {
|
||||||
const { client } = useMasto()
|
const { client } = useMasto()
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
const { formatFileSize } = useFileSizeFormatter()
|
||||||
|
|
||||||
const isUploading = ref<boolean>(false)
|
const isUploading = ref<boolean>(false)
|
||||||
const isExceedingAttachmentLimit = ref<boolean>(false)
|
const isExceedingAttachmentLimit = ref<boolean>(false)
|
||||||
|
@ -164,7 +164,7 @@ export function useUploadMediaAttachment(draft: Ref<Draft>) {
|
||||||
|
|
||||||
const maxPixels = computed(() => {
|
const maxPixels = computed(() => {
|
||||||
return currentInstance.value?.configuration?.mediaAttachments?.imageMatrixLimit
|
return currentInstance.value?.configuration?.mediaAttachments?.imageMatrixLimit
|
||||||
?? 4096 ** 2
|
?? 4096 ** 2
|
||||||
})
|
})
|
||||||
|
|
||||||
const loadImage = (inputFile: Blob) => new Promise<HTMLImageElement>((resolve, reject) => {
|
const loadImage = (inputFile: Blob) => new Promise<HTMLImageElement>((resolve, reject) => {
|
||||||
|
@ -225,8 +225,32 @@ export function useUploadMediaAttachment(draft: Ref<Draft>) {
|
||||||
// TODO: display some kind of message if too many media are selected
|
// TODO: display some kind of message if too many media are selected
|
||||||
// DONE
|
// DONE
|
||||||
const limit = currentInstance.value!.configuration?.statuses.maxMediaAttachments || 4
|
const limit = currentInstance.value!.configuration?.statuses.maxMediaAttachments || 4
|
||||||
|
const maxVideoSize = currentInstance.value!.configuration?.mediaAttachments.videoSizeLimit || 0
|
||||||
|
const maxImageSize = currentInstance.value!.configuration?.mediaAttachments.imageSizeLimit || 0
|
||||||
for (const file of files.slice(0, limit)) {
|
for (const file of files.slice(0, limit)) {
|
||||||
if (draft.value.attachments.length < limit) {
|
if (draft.value.attachments.length < limit) {
|
||||||
|
if (file.type.startsWith('image/')) {
|
||||||
|
if (maxImageSize > 0 && file.size > maxImageSize) {
|
||||||
|
failedAttachments.value = [...failedAttachments.value, [file.name, t('state.attachments_limit_image_error', [formatFileSize(maxImageSize)])]]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (maxVideoSize > 0 && file.size > maxVideoSize) {
|
||||||
|
const key
|
||||||
|
= file.type.startsWith('audio/')
|
||||||
|
? 'state.attachments_limit_audio_error'
|
||||||
|
: file.type.startsWith('video/')
|
||||||
|
? 'state.attachments_limit_video_error'
|
||||||
|
: 'state.attachments_limit_unknown_error'
|
||||||
|
const errorMessage = t(key, [formatFileSize(maxVideoSize)])
|
||||||
|
failedAttachments.value = [
|
||||||
|
...failedAttachments.value,
|
||||||
|
[file.name, errorMessage],
|
||||||
|
]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
isExceedingAttachmentLimit.value = false
|
isExceedingAttachmentLimit.value = false
|
||||||
try {
|
try {
|
||||||
const attachment = await client.value.v1.media.create({
|
const attachment = await client.value.v1.media.create({
|
||||||
|
|
|
@ -11,9 +11,12 @@ let timeoutHandle: NodeJS.Timeout | undefined
|
||||||
export function useRelationship(account: mastodon.v1.Account): Ref<mastodon.v1.Relationship | undefined> {
|
export function useRelationship(account: mastodon.v1.Account): Ref<mastodon.v1.Relationship | undefined> {
|
||||||
if (!currentUser.value)
|
if (!currentUser.value)
|
||||||
return ref()
|
return ref()
|
||||||
|
|
||||||
let relationship = requestedRelationships.get(account.id)
|
let relationship = requestedRelationships.get(account.id)
|
||||||
if (relationship)
|
if (relationship)
|
||||||
return relationship
|
return relationship
|
||||||
|
|
||||||
|
// allow batch relationship requests
|
||||||
relationship = ref<mastodon.v1.Relationship | undefined>()
|
relationship = ref<mastodon.v1.Relationship | undefined>()
|
||||||
requestedRelationships.set(account.id, relationship)
|
requestedRelationships.set(account.id, relationship)
|
||||||
if (timeoutHandle)
|
if (timeoutHandle)
|
||||||
|
@ -22,14 +25,19 @@ export function useRelationship(account: mastodon.v1.Account): Ref<mastodon.v1.R
|
||||||
timeoutHandle = undefined
|
timeoutHandle = undefined
|
||||||
fetchRelationships()
|
fetchRelationships()
|
||||||
}, 100)
|
}, 100)
|
||||||
|
|
||||||
return relationship
|
return relationship
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchRelationships() {
|
async function fetchRelationships() {
|
||||||
const requested = Array.from(requestedRelationships.entries()).filter(([, r]) => !r.value)
|
const requested = Array.from(requestedRelationships.entries()).filter(([, r]) => !r.value)
|
||||||
const relationships = await useMastoClient().v1.accounts.relationships.fetch({ id: requested.map(([id]) => id) })
|
const relationships = await useMastoClient().v1.accounts.relationships.fetch({ id: requested.map(([id]) => id) })
|
||||||
for (let i = 0; i < requested.length; i++)
|
for (const relationship of relationships) {
|
||||||
requested[i][1].value = relationships[i]
|
const requestedToUpdate = requested.find(([id]) => id === relationship.id)
|
||||||
|
if (!requestedToUpdate)
|
||||||
|
continue
|
||||||
|
requestedToUpdate[1].value = relationship
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function toggleFollowAccount(relationship: mastodon.v1.Relationship, account: mastodon.v1.Account) {
|
export async function toggleFollowAccount(relationship: mastodon.v1.Relationship, account: mastodon.v1.Account) {
|
||||||
|
@ -39,12 +47,13 @@ export async function toggleFollowAccount(relationship: mastodon.v1.Relationship
|
||||||
const unfollow = relationship!.following || relationship!.requested
|
const unfollow = relationship!.following || relationship!.requested
|
||||||
|
|
||||||
if (unfollow) {
|
if (unfollow) {
|
||||||
if (await openConfirmDialog({
|
const confirmUnfollow = await openConfirmDialog({
|
||||||
title: i18n.t('confirm.unfollow.title'),
|
title: i18n.t('confirm.unfollow.title'),
|
||||||
description: i18n.t('confirm.unfollow.description', [`@${account.acct}`]),
|
description: i18n.t('confirm.unfollow.description', [`@${account.acct}`]),
|
||||||
confirm: i18n.t('confirm.unfollow.confirm'),
|
confirm: i18n.t('confirm.unfollow.confirm'),
|
||||||
cancel: i18n.t('confirm.unfollow.cancel'),
|
cancel: i18n.t('confirm.unfollow.cancel'),
|
||||||
}) !== 'confirm')
|
})
|
||||||
|
if (confirmUnfollow.choice !== 'confirm')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,18 +75,28 @@ export async function toggleMuteAccount(relationship: mastodon.v1.Relationship,
|
||||||
const { client } = useMasto()
|
const { client } = useMasto()
|
||||||
const i18n = useNuxtApp().$i18n
|
const i18n = useNuxtApp().$i18n
|
||||||
|
|
||||||
if (!relationship!.muting && await openConfirmDialog({
|
let duration = 0 // default 0 == indefinite
|
||||||
title: i18n.t('confirm.mute_account.title'),
|
let notifications = true // default true = mute notifications
|
||||||
description: i18n.t('confirm.mute_account.description', [account.acct]),
|
if (!relationship!.muting) {
|
||||||
confirm: i18n.t('confirm.mute_account.confirm'),
|
const confirmMute = await openConfirmDialog({
|
||||||
cancel: i18n.t('confirm.mute_account.cancel'),
|
title: i18n.t('confirm.mute_account.title'),
|
||||||
}) !== 'confirm')
|
description: i18n.t('confirm.mute_account.description', [account.acct]),
|
||||||
return
|
confirm: i18n.t('confirm.mute_account.confirm'),
|
||||||
|
cancel: i18n.t('confirm.mute_account.cancel'),
|
||||||
|
extraOptionType: 'mute',
|
||||||
|
})
|
||||||
|
if (confirmMute.choice !== 'confirm')
|
||||||
|
return
|
||||||
|
|
||||||
|
duration = confirmMute.extraOptions!.mute.duration
|
||||||
|
notifications = confirmMute.extraOptions!.mute.notifications
|
||||||
|
}
|
||||||
|
|
||||||
relationship!.muting = !relationship!.muting
|
relationship!.muting = !relationship!.muting
|
||||||
relationship = relationship!.muting
|
relationship = relationship!.muting
|
||||||
? await client.value.v1.accounts.$select(account.id).mute({
|
? await client.value.v1.accounts.$select(account.id).mute({
|
||||||
// TODO support more options
|
duration,
|
||||||
|
notifications,
|
||||||
})
|
})
|
||||||
: await client.value.v1.accounts.$select(account.id).unmute()
|
: await client.value.v1.accounts.$select(account.id).unmute()
|
||||||
}
|
}
|
||||||
|
@ -86,13 +105,16 @@ export async function toggleBlockAccount(relationship: mastodon.v1.Relationship,
|
||||||
const { client } = useMasto()
|
const { client } = useMasto()
|
||||||
const i18n = useNuxtApp().$i18n
|
const i18n = useNuxtApp().$i18n
|
||||||
|
|
||||||
if (!relationship!.blocking && await openConfirmDialog({
|
if (!relationship!.blocking) {
|
||||||
title: i18n.t('confirm.block_account.title'),
|
const confirmBlock = await openConfirmDialog({
|
||||||
description: i18n.t('confirm.block_account.description', [account.acct]),
|
title: i18n.t('confirm.block_account.title'),
|
||||||
confirm: i18n.t('confirm.block_account.confirm'),
|
description: i18n.t('confirm.block_account.description', [account.acct]),
|
||||||
cancel: i18n.t('confirm.block_account.cancel'),
|
confirm: i18n.t('confirm.block_account.confirm'),
|
||||||
}) !== 'confirm')
|
cancel: i18n.t('confirm.block_account.cancel'),
|
||||||
return
|
})
|
||||||
|
if (confirmBlock.choice !== 'confirm')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
relationship!.blocking = !relationship!.blocking
|
relationship!.blocking = !relationship!.blocking
|
||||||
relationship = await client.value.v1.accounts.$select(account.id)[relationship!.blocking ? 'block' : 'unblock']()
|
relationship = await client.value.v1.accounts.$select(account.id)[relationship!.blocking ? 'block' : 'unblock']()
|
||||||
|
@ -102,13 +124,16 @@ export async function toggleBlockDomain(relationship: mastodon.v1.Relationship,
|
||||||
const { client } = useMasto()
|
const { client } = useMasto()
|
||||||
const i18n = useNuxtApp().$i18n
|
const i18n = useNuxtApp().$i18n
|
||||||
|
|
||||||
if (!relationship!.domainBlocking && await openConfirmDialog({
|
if (!relationship!.domainBlocking) {
|
||||||
title: i18n.t('confirm.block_domain.title'),
|
const confirmDomainBlock = await openConfirmDialog({
|
||||||
description: i18n.t('confirm.block_domain.description', [getServerName(account)]),
|
title: i18n.t('confirm.block_domain.title'),
|
||||||
confirm: i18n.t('confirm.block_domain.confirm'),
|
description: i18n.t('confirm.block_domain.description', [getServerName(account)]),
|
||||||
cancel: i18n.t('confirm.block_domain.cancel'),
|
confirm: i18n.t('confirm.block_domain.confirm'),
|
||||||
}) !== 'confirm')
|
cancel: i18n.t('confirm.block_domain.cancel'),
|
||||||
return
|
})
|
||||||
|
if (confirmDomainBlock.choice !== 'confirm')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
relationship!.domainBlocking = !relationship!.domainBlocking
|
relationship!.domainBlocking = !relationship!.domainBlocking
|
||||||
await client.value.v1.domainBlocks[relationship!.domainBlocking ? 'create' : 'remove']({ domain: getServerName(account) })
|
await client.value.v1.domainBlocks[relationship!.domainBlocking ? 'create' : 'remove']({ domain: getServerName(account) })
|
||||||
|
|
|
@ -59,11 +59,11 @@ export function useSearch(query: MaybeRefOrGetter<string>, options: UseSearchOpt
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => resolveUnref(query), () => {
|
watch(() => resolveUnref(query), () => {
|
||||||
loading.value = !!(q && isHydrated.value)
|
loading.value = !!(q.value && isHydrated.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
debouncedWatch(() => resolveUnref(query), async () => {
|
debouncedWatch(() => resolveUnref(query), async () => {
|
||||||
if (!q || !isHydrated.value)
|
if (!q.value || !isHydrated.value)
|
||||||
return
|
return
|
||||||
|
|
||||||
loading.value = true
|
loading.value = true
|
||||||
|
@ -87,7 +87,7 @@ export function useSearch(query: MaybeRefOrGetter<string>, options: UseSearchOpt
|
||||||
}, { debounce: 300 })
|
}, { debounce: 300 })
|
||||||
|
|
||||||
const next = async () => {
|
const next = async () => {
|
||||||
if (!q || !isHydrated.value || !paginator)
|
if (!q.value || !isHydrated.value || !paginator)
|
||||||
return
|
return
|
||||||
|
|
||||||
loading.value = true
|
loading.value = true
|
||||||
|
|
|
@ -20,7 +20,7 @@ function getDefaultVisibility(currentVisibility: mastodon.v1.StatusVisibility) {
|
||||||
// the post more private than the replying to post
|
// the post more private than the replying to post
|
||||||
const preferredVisibility = currentUser.value?.account.source.privacy || 'public'
|
const preferredVisibility = currentUser.value?.account.source.privacy || 'public'
|
||||||
return ALL_VISIBILITY.indexOf(currentVisibility)
|
return ALL_VISIBILITY.indexOf(currentVisibility)
|
||||||
> ALL_VISIBILITY.indexOf(preferredVisibility)
|
> ALL_VISIBILITY.indexOf(preferredVisibility)
|
||||||
? currentVisibility
|
? currentVisibility
|
||||||
: preferredVisibility
|
: preferredVisibility
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,12 @@ export async function translateText(text: string, from: string | null | undefine
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
const translations = new WeakMap<mastodon.v1.Status | mastodon.v1.StatusEdit, { visible: boolean; text: string; success: boolean; error: string }>()
|
const translations = new WeakMap<mastodon.v1.Status | mastodon.v1.StatusEdit, {
|
||||||
|
visible: boolean
|
||||||
|
text: string
|
||||||
|
success: boolean
|
||||||
|
error: string
|
||||||
|
}>()
|
||||||
|
|
||||||
export function useTranslation(status: mastodon.v1.Status | mastodon.v1.StatusEdit, to: string) {
|
export function useTranslation(status: mastodon.v1.Status | mastodon.v1.StatusEdit, to: string) {
|
||||||
if (!translations.has(status))
|
if (!translations.has(status))
|
||||||
|
|
|
@ -5,6 +5,7 @@ import type { PaginatorState } from '~/types'
|
||||||
export function usePaginator<T, P, U = T>(
|
export function usePaginator<T, P, U = T>(
|
||||||
_paginator: mastodon.Paginator<T[], P>,
|
_paginator: mastodon.Paginator<T[], P>,
|
||||||
stream: Ref<mastodon.streaming.Subscription | undefined>,
|
stream: Ref<mastodon.streaming.Subscription | undefined>,
|
||||||
|
eventType: 'update' | 'notification' = 'update',
|
||||||
preprocess: (items: (T | U)[]) => U[] = items => items as unknown as U[],
|
preprocess: (items: (T | U)[]) => U[] = items => items as unknown as U[],
|
||||||
buffer = 10,
|
buffer = 10,
|
||||||
) {
|
) {
|
||||||
|
@ -34,10 +35,10 @@ export function usePaginator<T, P, U = T>(
|
||||||
return
|
return
|
||||||
|
|
||||||
for await (const entry of stream) {
|
for await (const entry of stream) {
|
||||||
if (entry.event === 'update') {
|
if (entry.event === eventType) {
|
||||||
const status = entry.payload
|
const status = entry.payload
|
||||||
|
|
||||||
if ('uri' in entry)
|
if ('uri' in status)
|
||||||
cacheStatus(status, undefined, true)
|
cacheStatus(status, undefined, true)
|
||||||
|
|
||||||
const index = prevItems.value.findIndex((i: any) => i.id === status.id)
|
const index = prevItems.value.findIndex((i: any) => i.id === status.id)
|
||||||
|
|
|
@ -6,10 +6,12 @@ import type {
|
||||||
} from '~/composables/push-notifications/types'
|
} from '~/composables/push-notifications/types'
|
||||||
import { PushSubscriptionError } from '~/composables/push-notifications/types'
|
import { PushSubscriptionError } from '~/composables/push-notifications/types'
|
||||||
|
|
||||||
export async function createPushSubscription(user: RequiredUserLogin,
|
export async function createPushSubscription(
|
||||||
|
user: RequiredUserLogin,
|
||||||
notificationData: CreatePushNotification,
|
notificationData: CreatePushNotification,
|
||||||
policy: mastodon.v1.WebPushSubscriptionPolicy = 'all',
|
policy: mastodon.v1.WebPushSubscriptionPolicy = 'all',
|
||||||
force = false): Promise<mastodon.v1.WebPushSubscription | undefined> {
|
force = false,
|
||||||
|
): Promise<mastodon.v1.WebPushSubscription | undefined> {
|
||||||
const { server: serverEndpoint, vapidKey } = user
|
const { server: serverEndpoint, vapidKey } = user
|
||||||
|
|
||||||
return await getRegistration()
|
return await getRegistration()
|
||||||
|
|
|
@ -64,7 +64,7 @@ export function usePushManager() {
|
||||||
policy?: mastodon.v1.WebPushSubscriptionPolicy,
|
policy?: mastodon.v1.WebPushSubscriptionPolicy,
|
||||||
force?: boolean,
|
force?: boolean,
|
||||||
): Promise<SubscriptionResult> => {
|
): Promise<SubscriptionResult> => {
|
||||||
if (!isSupported)
|
if (!isSupported.value)
|
||||||
return 'not-supported'
|
return 'not-supported'
|
||||||
|
|
||||||
if (!currentUser.value)
|
if (!currentUser.value)
|
||||||
|
@ -87,7 +87,10 @@ export function usePushManager() {
|
||||||
|
|
||||||
currentUser.value.pushSubscription = await createPushSubscription(
|
currentUser.value.pushSubscription = await createPushSubscription(
|
||||||
{
|
{
|
||||||
pushSubscription, server, token, vapidKey,
|
pushSubscription,
|
||||||
|
server,
|
||||||
|
token,
|
||||||
|
vapidKey,
|
||||||
},
|
},
|
||||||
notificationData ?? {
|
notificationData ?? {
|
||||||
alerts: {
|
alerts: {
|
||||||
|
@ -109,7 +112,7 @@ export function usePushManager() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsubscribe = async () => {
|
const unsubscribe = async () => {
|
||||||
if (!isSupported || !isSubscribed || !currentUser.value)
|
if (!isSupported.value || !isSubscribed.value || !currentUser.value)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
await removePushNotifications(currentUser.value)
|
await removePushNotifications(currentUser.value)
|
||||||
|
|
|
@ -2,5 +2,6 @@ import { breakpointsTailwind } from '@vueuse/core'
|
||||||
|
|
||||||
export const breakpoints = useBreakpoints(breakpointsTailwind)
|
export const breakpoints = useBreakpoints(breakpointsTailwind)
|
||||||
|
|
||||||
|
export const isSmallScreen = breakpoints.smallerOrEqual('sm')
|
||||||
export const isMediumOrLargeScreen = breakpoints.between('sm', 'xl')
|
export const isMediumOrLargeScreen = breakpoints.between('sm', 'xl')
|
||||||
export const isExtraLargeScreen = breakpoints.smallerOrEqual('xl')
|
export const isExtraLargeScreen = breakpoints.smallerOrEqual('xl')
|
||||||
|
|
|
@ -9,6 +9,7 @@ export type ColorMode = 'light' | 'dark' | 'system'
|
||||||
|
|
||||||
export interface PreferencesSettings {
|
export interface PreferencesSettings {
|
||||||
hideAltIndicatorOnPosts: boolean
|
hideAltIndicatorOnPosts: boolean
|
||||||
|
hideGifIndicatorOnPosts: boolean
|
||||||
hideBoostCount: boolean
|
hideBoostCount: boolean
|
||||||
hideReplyCount: boolean
|
hideReplyCount: boolean
|
||||||
hideFavoriteCount: boolean
|
hideFavoriteCount: boolean
|
||||||
|
@ -16,6 +17,7 @@ export interface PreferencesSettings {
|
||||||
hideTranslation: boolean
|
hideTranslation: boolean
|
||||||
hideUsernameEmojis: boolean
|
hideUsernameEmojis: boolean
|
||||||
hideAccountHoverCard: boolean
|
hideAccountHoverCard: boolean
|
||||||
|
hideTagHoverCard: boolean
|
||||||
hideNews: boolean
|
hideNews: boolean
|
||||||
grayscaleMode: boolean
|
grayscaleMode: boolean
|
||||||
enableAutoplay: boolean
|
enableAutoplay: boolean
|
||||||
|
@ -63,6 +65,7 @@ export function getDefaultLanguage(languages: string[]) {
|
||||||
|
|
||||||
export const DEFAULT__PREFERENCES_SETTINGS: PreferencesSettings = {
|
export const DEFAULT__PREFERENCES_SETTINGS: PreferencesSettings = {
|
||||||
hideAltIndicatorOnPosts: false,
|
hideAltIndicatorOnPosts: false,
|
||||||
|
hideGifIndicatorOnPosts: false,
|
||||||
hideBoostCount: false,
|
hideBoostCount: false,
|
||||||
hideReplyCount: false,
|
hideReplyCount: false,
|
||||||
hideFavoriteCount: false,
|
hideFavoriteCount: false,
|
||||||
|
@ -70,6 +73,7 @@ export const DEFAULT__PREFERENCES_SETTINGS: PreferencesSettings = {
|
||||||
hideTranslation: false,
|
hideTranslation: false,
|
||||||
hideUsernameEmojis: false,
|
hideUsernameEmojis: false,
|
||||||
hideAccountHoverCard: false,
|
hideAccountHoverCard: false,
|
||||||
|
hideTagHoverCard: false,
|
||||||
hideNews: false,
|
hideNews: false,
|
||||||
grayscaleMode: false,
|
grayscaleMode: false,
|
||||||
enableAutoplay: true,
|
enableAutoplay: true,
|
||||||
|
|
|
@ -5,7 +5,10 @@ const highlighter = ref<Highlighter>()
|
||||||
const registeredLang = ref(new Map<string, boolean>())
|
const registeredLang = ref(new Map<string, boolean>())
|
||||||
let shikiImport: Promise<void> | undefined
|
let shikiImport: Promise<void> | undefined
|
||||||
|
|
||||||
export function useHighlighter(lang: Lang): { promise?: Promise<void>; highlighter?: Highlighter } {
|
export function useHighlighter(lang: Lang): {
|
||||||
|
promise?: Promise<void>
|
||||||
|
highlighter?: Highlighter
|
||||||
|
} {
|
||||||
if (!shikiImport) {
|
if (!shikiImport) {
|
||||||
shikiImport = import('shiki')
|
shikiImport = import('shiki')
|
||||||
.then(async ({ getHighlighter }) => {
|
.then(async ({ getHighlighter }) => {
|
||||||
|
|
|
@ -55,11 +55,17 @@ export function useTiptap(options: UseTiptapOptions) {
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
Mention.configure({
|
Mention.configure({
|
||||||
|
renderHTML({ options, node }) {
|
||||||
|
return ['span', { 'data-type': 'mention', 'data-id': node.attrs.id }, `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`]
|
||||||
|
},
|
||||||
suggestion: TiptapMentionSuggestion,
|
suggestion: TiptapMentionSuggestion,
|
||||||
}),
|
}),
|
||||||
Mention
|
Mention
|
||||||
.extend({ name: 'hashtag' })
|
.extend({ name: 'hashtag' })
|
||||||
.configure({
|
.configure({
|
||||||
|
renderHTML({ options, node }) {
|
||||||
|
return ['span', { 'data-type': 'hashtag', 'data-id': node.attrs.id }, `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`]
|
||||||
|
},
|
||||||
suggestion: TiptapHashtagSuggestion,
|
suggestion: TiptapHashtagSuggestion,
|
||||||
}),
|
}),
|
||||||
Mention
|
Mention
|
||||||
|
|
|
@ -16,7 +16,11 @@ declare module '@tiptap/core' {
|
||||||
/**
|
/**
|
||||||
* Insert a custom emoji.
|
* Insert a custom emoji.
|
||||||
*/
|
*/
|
||||||
insertCustomEmoji: (options: { src: string; alt?: string; title?: string }) => ReturnType
|
insertCustomEmoji: (options: {
|
||||||
|
src: string
|
||||||
|
alt?: string
|
||||||
|
title?: string
|
||||||
|
}) => ReturnType
|
||||||
/**
|
/**
|
||||||
* Insert a emoji.
|
* Insert a emoji.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,36 +1,42 @@
|
||||||
|
import type { ExtendedRegExpMatchArray, InputRuleFinder, nodeInputRule } from '@tiptap/core'
|
||||||
|
import type { NodeType } from '@tiptap/pm/model'
|
||||||
import {
|
import {
|
||||||
|
InputRule,
|
||||||
Node,
|
Node,
|
||||||
|
callOrReturn,
|
||||||
mergeAttributes,
|
mergeAttributes,
|
||||||
nodeInputRule,
|
|
||||||
nodePasteRule,
|
nodePasteRule,
|
||||||
} from '@tiptap/core'
|
} from '@tiptap/core'
|
||||||
import { emojiRegEx, getEmojiAttributes } from '~/config/emojis'
|
import { emojiRegEx, getEmojiAttributes } from '~/config/emojis'
|
||||||
|
|
||||||
function createEmojiRule<NR extends typeof nodeInputRule | typeof nodePasteRule>(nodeRule: NR,
|
function wrapHandler<T extends (...args: any[]) => any>(handler: T): T {
|
||||||
type: Parameters<NR>[0]['type']): ReturnType<NR>[] {
|
return <T>((...args: any[]) => {
|
||||||
const rule = nodeRule({
|
|
||||||
find: emojiRegEx as RegExp,
|
|
||||||
type,
|
|
||||||
getAttributes: (match) => {
|
|
||||||
const [native] = match
|
|
||||||
return getEmojiAttributes(native)
|
|
||||||
},
|
|
||||||
}) as ReturnType<NR>
|
|
||||||
|
|
||||||
// Error catch for unsupported emoji
|
|
||||||
const handler = rule.handler.bind(rule)
|
|
||||||
rule.handler = (...args) => {
|
|
||||||
try {
|
try {
|
||||||
return handler(...args)
|
return handler(...args)
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
function createEmojiRule<NR extends typeof nodeInputRule | typeof nodePasteRule>(
|
||||||
rule,
|
nodeRule: NR,
|
||||||
]
|
type: Parameters<NR>[0]['type'],
|
||||||
|
): ReturnType<NR>[] {
|
||||||
|
const rule = nodeRule({
|
||||||
|
find: emojiRegEx as RegExp,
|
||||||
|
type,
|
||||||
|
getAttributes: (match: ExtendedRegExpMatchArray) => {
|
||||||
|
const [native] = match
|
||||||
|
return getEmojiAttributes(native)
|
||||||
|
},
|
||||||
|
}) as ReturnType<NR>
|
||||||
|
|
||||||
|
// Error catch for unsupported emoji
|
||||||
|
rule.handler = wrapHandler(rule.handler.bind(rule))
|
||||||
|
|
||||||
|
return [rule]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TiptapPluginEmoji = Node.create({
|
export const TiptapPluginEmoji = Node.create({
|
||||||
|
@ -78,7 +84,34 @@ export const TiptapPluginEmoji = Node.create({
|
||||||
},
|
},
|
||||||
|
|
||||||
addInputRules() {
|
addInputRules() {
|
||||||
return createEmojiRule(nodeInputRule, this.type)
|
function emojiInputRule(config: {
|
||||||
|
find: InputRuleFinder
|
||||||
|
type: NodeType
|
||||||
|
getAttributes?:
|
||||||
|
| Record<string, any>
|
||||||
|
| ((match: ExtendedRegExpMatchArray) => Record<string, any>)
|
||||||
|
| false
|
||||||
|
| null
|
||||||
|
}) {
|
||||||
|
return new InputRule({
|
||||||
|
find: config.find,
|
||||||
|
handler: ({ state, range, match }) => {
|
||||||
|
const attributes = callOrReturn(config.getAttributes, undefined, match) || {}
|
||||||
|
const { tr } = state
|
||||||
|
const start = range.from
|
||||||
|
const end = range.to
|
||||||
|
|
||||||
|
tr.insert(start, config.type.create(attributes)).delete(
|
||||||
|
tr.mapping.map(start),
|
||||||
|
tr.mapping.map(end),
|
||||||
|
)
|
||||||
|
|
||||||
|
tr.scrollIntoView()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return createEmojiRule(emojiInputRule, this.type)
|
||||||
},
|
},
|
||||||
|
|
||||||
addPasteRules() {
|
addPasteRules() {
|
||||||
|
|
|
@ -14,7 +14,6 @@ export default defineI18nConfig(() => {
|
||||||
missingWarn: true,
|
missingWarn: true,
|
||||||
datetimeFormats,
|
datetimeFormats,
|
||||||
numberFormats,
|
numberFormats,
|
||||||
// eslint-disable-next-line @typescript-eslint/comma-dangle
|
pluralRules,
|
||||||
pluralRules
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -88,6 +88,26 @@ const locales: LocaleObjectData[] = [
|
||||||
return { zero: 0, one: 1, two: 2, few: 3, many: 4, other: 5 }[name]
|
return { zero: 0, one: 1, two: 2, few: 3, many: 4, other: 5 }[name]
|
||||||
},
|
},
|
||||||
} satisfies LocaleObjectData),
|
} satisfies LocaleObjectData),
|
||||||
|
({
|
||||||
|
code: 'ckb',
|
||||||
|
file: 'ckb.json',
|
||||||
|
name: 'کوردیی ناوەندی',
|
||||||
|
dir: 'rtl',
|
||||||
|
pluralRule: (choice: number) => {
|
||||||
|
const name = new Intl.PluralRules('ckb').select(choice)
|
||||||
|
return { zero: 0, one: 1, two: 2, few: 3, many: 4, other: 5 }[name]
|
||||||
|
},
|
||||||
|
} satisfies LocaleObjectData),
|
||||||
|
({
|
||||||
|
code: 'fa-IR',
|
||||||
|
file: 'fa-IR.json',
|
||||||
|
name: 'فارسی',
|
||||||
|
dir: 'rtl',
|
||||||
|
pluralRule: (choice: number) => {
|
||||||
|
const name = new Intl.PluralRules('fa-IR').select(choice)
|
||||||
|
return { zero: 0, one: 1, two: 2, few: 3, many: 4, other: 5 }[name]
|
||||||
|
},
|
||||||
|
} satisfies LocaleObjectData),
|
||||||
{
|
{
|
||||||
code: 'ca',
|
code: 'ca',
|
||||||
file: 'ca.json',
|
file: 'ca.json',
|
||||||
|
|
|
@ -22,7 +22,16 @@ export const STORAGE_KEY_HIDE_EXPLORE_TAGS_TIPS = 'elk-hide-explore-tags-tips'
|
||||||
export const STORAGE_KEY_NOTIFICATION = 'elk-notification'
|
export const STORAGE_KEY_NOTIFICATION = 'elk-notification'
|
||||||
export const STORAGE_KEY_NOTIFICATION_POLICY = 'elk-notification-policy'
|
export const STORAGE_KEY_NOTIFICATION_POLICY = 'elk-notification-policy'
|
||||||
export const STORAGE_KEY_PWA_HIDE_INSTALL = 'elk-pwa-hide-install'
|
export const STORAGE_KEY_PWA_HIDE_INSTALL = 'elk-pwa-hide-install'
|
||||||
|
export const STORAGE_KEY_LAST_ACCESSED_NOTIFICATION_ROUTE = 'elk-last-accessed-notification-route'
|
||||||
|
export const STORAGE_KEY_LAST_ACCESSED_EXPLORE_ROUTE = 'elk-last-accessed-explore-route'
|
||||||
|
|
||||||
export const HANDLED_MASTO_URLS = /^(https?:\/\/)?([\w\d-]+\.)+\w+\/(@[@\w\d-\.]+)(\/objects)?(\/\d+)?$/
|
export const HANDLED_MASTO_URLS = /^(https?:\/\/)?([\w\d-]+\.)+\w+\/(@[@\w\d-\.]+)(\/objects)?(\/\d+)?$/
|
||||||
|
|
||||||
export const NOTIFICATION_FILTER_TYPES: mastodon.v1.NotificationType[] = ['status', 'reblog', 'follow', 'follow_request', 'favourite', 'poll', 'update', 'admin.sign_up', 'admin.report']
|
export const NOTIFICATION_FILTER_TYPES: mastodon.v1.NotificationType[] = ['status', 'reblog', 'follow', 'follow_request', 'favourite', 'poll', 'update', 'admin.sign_up', 'admin.report']
|
||||||
|
|
||||||
|
export const THEME_COLORS = {
|
||||||
|
themeDark: '#111111',
|
||||||
|
themeLight: '#fafafa',
|
||||||
|
backgroundDark: '#fafafa',
|
||||||
|
backgroundLight: '#111111',
|
||||||
|
} as const
|
||||||
|
|
|
@ -44,7 +44,7 @@ When you are ready to submit work back to the main Elk repo, create a PR.
|
||||||
- base branch should be **main**
|
- base branch should be **main**
|
||||||
- Head repository should be your fork
|
- Head repository should be your fork
|
||||||
- Compare branch should be your working branch you want to submit
|
- Compare branch should be your working branch you want to submit
|
||||||
If you don't see four drop downs, be sure you are comparing across forks.
|
If you don't see four drop-downs, be sure you are comparing across forks.
|
||||||
10. Add a description of the changes your request makes
|
10. Add a description of the changes your request makes
|
||||||
11. Select **Add Pull Request**
|
11. Select **Add Pull Request**
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ Avoid screenshots until Elk reaches a stable release.
|
||||||
|
|
||||||
### Standards
|
### Standards
|
||||||
|
|
||||||
Write in **American English** using spelling as found in [Merriam Webster](https://www.merriam-webster.com).
|
Write in **American English** using spelling as found in [Merriam-Webster](https://www.merriam-webster.com).
|
||||||
Translation and localization will be handled separately as/when availability or necessity allow.
|
Translation and localization will be handled separately as/when availability or necessity allow.
|
||||||
|
|
||||||
Use [**semantic linefeeds**](https://rhodesmill.org/brandon/2012/one-sentence-per-line/) with no more than one sentence per line.
|
Use [**semantic linefeeds**](https://rhodesmill.org/brandon/2012/one-sentence-per-line/) with no more than one sentence per line.
|
||||||
|
|
|
@ -14,10 +14,10 @@ css({
|
||||||
gap: '0.5rem',
|
gap: '0.5rem',
|
||||||
fontSize: '1.5rem',
|
fontSize: '1.5rem',
|
||||||
},
|
},
|
||||||
img: {
|
'img': {
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
aspectRatio: '1/1',
|
aspectRatio: '1/1',
|
||||||
height: '2.5rem'
|
height: '2.5rem',
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'ToogleIcon',
|
name: 'ToggleIcon',
|
||||||
props: { up: Boolean },
|
props: { up: Boolean },
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
|
@ -61,8 +61,8 @@ async function copyToClipboard() {
|
||||||
try {
|
try {
|
||||||
await navigator.clipboard.writeText([
|
await navigator.clipboard.writeText([
|
||||||
`# ${localeTitle.value}`,
|
`# ${localeTitle.value}`,
|
||||||
(localeTab.value === 'missing' ? missingEntries.value : outdatedEntries.value).join('\n')].join('\n'),
|
(localeTab.value === 'missing' ? missingEntries.value : outdatedEntries.value).join('\n'),
|
||||||
)
|
].join('\n'))
|
||||||
copied.value = true
|
copied.value = true
|
||||||
setTimeout(() => copied.value = false, 750)
|
setTimeout(() => copied.value = false, 750)
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ async function copyToClipboard() {
|
||||||
>
|
>
|
||||||
<td :class="[{ expandable: !isSource }]">
|
<td :class="[{ expandable: !isSource }]">
|
||||||
<div>
|
<div>
|
||||||
<ToogleIcon v-if="!isSource" :up="hidden || key !== locale" />
|
<ToggleIcon v-if="!isSource" :up="hidden || key !== locale" />
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -35,7 +35,6 @@ You can think of the service as something similar to Twitter, but with some key
|
||||||
|
|
||||||
For more details about Mastodon, see their [website](https://joinmastodon.org/), [blog](https://blog.joinmastodon.org), [docs](https://docs.joinmastodon.org), and [GitHub Repository](https://github.com/mastodon/mastodon).
|
For more details about Mastodon, see their [website](https://joinmastodon.org/), [blog](https://blog.joinmastodon.org), [docs](https://docs.joinmastodon.org), and [GitHub Repository](https://github.com/mastodon/mastodon).
|
||||||
|
|
||||||
|
|
||||||
## What is a Mastodon Client?
|
## What is a Mastodon Client?
|
||||||
|
|
||||||
A Mastodon Client is software that serves up the posts and activities from a Mastodon server using the [Mastodon API](https://docs.joinmastodon.org/api/).
|
A Mastodon Client is software that serves up the posts and activities from a Mastodon server using the [Mastodon API](https://docs.joinmastodon.org/api/).
|
||||||
|
@ -80,7 +79,6 @@ Desktop
|
||||||
[TheDesk](https://thedesk.top/en/), [Whalebird](https://whalebird.social/en), or [Sengi](https://nicolasconstant.github.io/sengi/)
|
[TheDesk](https://thedesk.top/en/), [Whalebird](https://whalebird.social/en), or [Sengi](https://nicolasconstant.github.io/sengi/)
|
||||||
::
|
::
|
||||||
|
|
||||||
|
|
||||||
All of these apps provide some combination of the features a typical Mastodon user expects for their account.
|
All of these apps provide some combination of the features a typical Mastodon user expects for their account.
|
||||||
|
|
||||||
### Browser-based Mastodon Clients
|
### Browser-based Mastodon Clients
|
||||||
|
|
|
@ -67,7 +67,6 @@ Options include:
|
||||||
Elk reorders timeline posts that are connected to each other to display them in a connected thread in the timelines.
|
Elk reorders timeline posts that are connected to each other to display them in a connected thread in the timelines.
|
||||||
This helps keep the conversation context for a post and its replies.
|
This helps keep the conversation context for a post and its replies.
|
||||||
|
|
||||||
|
|
||||||
## Improved notifications
|
## Improved notifications
|
||||||
|
|
||||||
Elk groups boosts and likes to the same post when they occur together in the notification history.
|
Elk groups boosts and likes to the same post when they occur together in the notification history.
|
||||||
|
@ -76,7 +75,6 @@ This greatly simplifies your notification history.
|
||||||
|
|
||||||
<!-- ## GitHub HTML cards -->
|
<!-- ## GitHub HTML cards -->
|
||||||
|
|
||||||
|
|
||||||
<!-- - markdown support
|
<!-- - markdown support
|
||||||
- GitHub HTML cards
|
- GitHub HTML cards
|
||||||
- and so on... -->
|
- and so on... -->
|
||||||
|
|
|
@ -56,6 +56,6 @@ On your project page open the Deploys tab, click on "Trigger deploy" and "Deploy
|
||||||
## Use a custom domain
|
## Use a custom domain
|
||||||
If you want to use a custom domain, go to "Domain settings" on your Netlify project page, and press "Add custom domain". If your domain is not bought from Netlify, it will ask you to add a CNAME record. Do that.
|
If you want to use a custom domain, go to "Domain settings" on your Netlify project page, and press "Add custom domain". If your domain is not bought from Netlify, it will ask you to add a CNAME record. Do that.
|
||||||
|
|
||||||
Once the custom domain is added, you'll need to add an SSL/TLS certificate. At the bottom of the page press "Verify DNS configuration" and if it succeeds, press "Provision certificate". If that fails, you may need to wait some time until your DNS propagetes.
|
Once the custom domain is added, you'll need to add an SSL/TLS certificate. At the bottom of the page press "Verify DNS configuration" and if it succeeds, press "Provision certificate". If that fails, you may need to wait some time until your DNS propagates.
|
||||||
|
|
||||||
And that's it! Enjoy your instance's Elk!
|
And that's it! Enjoy your instance's Elk!
|
||||||
|
|
|
@ -35,4 +35,3 @@ When we update this privacy notice, the updated version will be indicated by a n
|
||||||
## Contact
|
## Contact
|
||||||
|
|
||||||
If you have questions or comments about this notice, you may raise an issue at https://github.com/elk-zone/elk.
|
If you have questions or comments about this notice, you may raise an issue at https://github.com/elk-zone/elk.
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
[build]
|
[build]
|
||||||
publish = "dist"
|
publish = "dist"
|
||||||
command = "pnpm generate"
|
command = "pnpm generate"
|
||||||
|
|
||||||
# Allow previewing docs
|
# Allow previewing docs
|
||||||
[[redirects]]
|
[[redirects]]
|
||||||
from = "/docs/*"
|
from = "/docs/*"
|
||||||
to = "/:splat"
|
to = "/:splat"
|
||||||
status = 200
|
status = 200
|
||||||
force = true
|
force = true
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
extends: '@nuxt-themes/docus',
|
extends: '@nuxt-themes/docus',
|
||||||
|
vite: {
|
||||||
|
optimizeDeps: {
|
||||||
|
include: ['scule'],
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -13,6 +13,6 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxt-themes/docus": "^1.15.0",
|
"@nuxt-themes/docus": "^1.15.0",
|
||||||
"nuxt": "^3.10.3"
|
"nuxt": "^3.11.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
37
eslint.config.js
Normal file
37
eslint.config.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// @ts-check
|
||||||
|
import antfu from '@antfu/eslint-config'
|
||||||
|
|
||||||
|
export default await antfu(
|
||||||
|
{
|
||||||
|
unocss: false,
|
||||||
|
vue: {
|
||||||
|
overrides: {
|
||||||
|
'vue/no-restricted-syntax': ['error', {
|
||||||
|
selector: 'VElement[name=\'a\']',
|
||||||
|
message: 'Use NuxtLink instead.',
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ignores: [
|
||||||
|
'public/**',
|
||||||
|
'public-dev/**',
|
||||||
|
'public-staging/**',
|
||||||
|
'https-dev-config/**',
|
||||||
|
'elk-translation-status.json',
|
||||||
|
'docs/translation-status.json',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rules: {
|
||||||
|
// TODO: migrate all process reference to `import.meta.env` and remove this rule
|
||||||
|
'node/prefer-global/process': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Sort local files
|
||||||
|
{
|
||||||
|
files: ['locales/**.json'],
|
||||||
|
rules: {
|
||||||
|
'jsonc/sort-keys': 'error',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
687
locales/ckb.json
Normal file
687
locales/ckb.json
Normal file
|
@ -0,0 +1,687 @@
|
||||||
|
{
|
||||||
|
"a11y": {
|
||||||
|
"loading_page": "خرمەخرمی لاپەڕە، تکایە چاوەڕوان بن",
|
||||||
|
"loading_titled_page": "خرمەی لاپەڕەی {0}، تکایە چاوەڕوان بن",
|
||||||
|
"locale_changed": "زمان گۆڕدرا بۆ {0}",
|
||||||
|
"locale_changing": "گۆڕینی زمان، تکایە چاوەڕوان بن",
|
||||||
|
"route_loaded": "لاپەڕەی {0} بارکراوە"
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"avatar_description": "{0}بە ئاڤاتاری",
|
||||||
|
"blocked_by": "تۆ لەلایەن ئەم بەکارهێنەرەوە بلۆک کراویت.",
|
||||||
|
"blocked_domains": "دۆمەینەکانی بلۆککراو",
|
||||||
|
"blocked_users": "بەکارهێنەرانی بلۆککراو",
|
||||||
|
"blocking": "بلۆک کراوە",
|
||||||
|
"bot": "بۆت",
|
||||||
|
"favourites": "دڵخواز",
|
||||||
|
"follow": "بەدواداچوون",
|
||||||
|
"follow_back": "دوا بکەوە",
|
||||||
|
"follow_requested": "داواکراوە",
|
||||||
|
"followers": "هۆگران",
|
||||||
|
"followers_count": "هۆگر {0}|هۆگر {0}|{0} هۆگر",
|
||||||
|
"following": "شوێنکەوتوو",
|
||||||
|
"following_count": "{0} شوێنکەوتوو",
|
||||||
|
"follows_you": "شوێنت دەکەوێت",
|
||||||
|
"go_to_profile": "بڕۆ بۆ پڕۆفایلی",
|
||||||
|
"joined": "بەشداری کردووە",
|
||||||
|
"moved_title": "ئاماژەی بەوە کردووە، لە ئێستادا هەژمارە نوێیەکەیان بەم شێوەیەیە:",
|
||||||
|
"muted_users": "بەکارهێنەرە بێدەنگەکان",
|
||||||
|
"muting": "بێدەنگ",
|
||||||
|
"mutuals": "دوولایەنە",
|
||||||
|
"notifications_on_post_disable": "واز لە ئاگادارکردنەوەم بێنە کاتێک {username} پۆست دەکات",
|
||||||
|
"notifications_on_post_enable": "کاتێک {username} پۆست دەکات ئاگادارم بکەرەوە",
|
||||||
|
"pinned": "سەنجاق کراوە",
|
||||||
|
"posts": "بابەت",
|
||||||
|
"posts_count": "{0} بابەت|{0} بابەت|{0} بابەت",
|
||||||
|
"profile_description": "سەردێڕی پڕۆفایلی {0}",
|
||||||
|
"profile_personal_note": "تێبینی کەسی",
|
||||||
|
"profile_unavailable": "پڕۆفایلی بەردەست نییە",
|
||||||
|
"request_follow": "داواکاری بۆ بەدواداچوون",
|
||||||
|
"unblock": "بلۆک بکەرەوە",
|
||||||
|
"unfollow": "بەدوایدا مەچۆ",
|
||||||
|
"unmute": "بێدەنگی لابەرە",
|
||||||
|
"view_other_followers": "لەوانەیە شوێنکەوتووانی حاڵەتەکانی تر نیشان نەدرێن.",
|
||||||
|
"view_other_following": "لە حاڵەتەکانی تر ناتوانرێت ئاشکرا بکرێت."
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"apply": "بهکاربردن",
|
||||||
|
"bookmark": "نیشانەکردن",
|
||||||
|
"bookmarked": "نیشانە کراوە",
|
||||||
|
"boost": "هاوبەشکردن",
|
||||||
|
"boost_count": "{0}",
|
||||||
|
"boosted": "هاوبەشکرا",
|
||||||
|
"clear_publish_failed": "هەڵەکانی بڵاوکردنەوە پاک بکەرەوە",
|
||||||
|
"clear_save_failed": "پاککردنی هەڵەی پاشکەوتکراوە",
|
||||||
|
"clear_upload_failed": "هەڵەکانی بارکردنی پەڕگە پاک بکەرەوە",
|
||||||
|
"close": "داخستن",
|
||||||
|
"compose": "نووسین",
|
||||||
|
"confirm": "دڵنیاکردنەوە",
|
||||||
|
"done": "تەواو",
|
||||||
|
"edit": "دەستکاری",
|
||||||
|
"enter_app": "چوونەناو ئەپ",
|
||||||
|
"favourite": "پهسند",
|
||||||
|
"favourite_count": "{0}",
|
||||||
|
"favourited": "پەسەندکراوە",
|
||||||
|
"more": "زیاتر",
|
||||||
|
"next": "دواتر",
|
||||||
|
"prev": "پێشتر",
|
||||||
|
"publish": "بڵاوكردنهوه",
|
||||||
|
"reply": "وەڵامدانەوە",
|
||||||
|
"reply_count": "{0}",
|
||||||
|
"reset": "ڕێکخستنهوه",
|
||||||
|
"save": "پاشهکهوت",
|
||||||
|
"save_changes": "پاشکەوتی گۆرانکاری",
|
||||||
|
"sign_in": "چوونەژوورەوە",
|
||||||
|
"sign_in_to": "چوونە ژوورەوە بۆ {0}",
|
||||||
|
"switch_account": "گۆڕینی هەژمارە",
|
||||||
|
"vote": "دەنگدان"
|
||||||
|
},
|
||||||
|
"app_desc_short": "ڕاژەخوازێکی وێبی ماستۆدۆن",
|
||||||
|
"app_logo": "Elk لۆگۆی",
|
||||||
|
"app_name": "Elk",
|
||||||
|
"attachment": {
|
||||||
|
"edit_title": "وەسف",
|
||||||
|
"remove_label": "لابردنی لکێندراو"
|
||||||
|
},
|
||||||
|
"command": {
|
||||||
|
"activate": "چالاککردن",
|
||||||
|
"complete": "تەواو",
|
||||||
|
"compose_desc": "نووسینی بابەتێکی نوێ",
|
||||||
|
"select_lang": "زمان هەڵبژێرە",
|
||||||
|
"sign_in_desc": "هەژمارەیێکی ئامادە زیاد بکە",
|
||||||
|
"switch_account": "بیگۆڕە بۆ {0}",
|
||||||
|
"switch_account_desc": "بیگۆڕە بۆ ئەژمێرێکی تر",
|
||||||
|
"toggle_dark_mode": "گۆڕینی دۆخی تاریک",
|
||||||
|
"toggle_zen_mode": "دۆخی zen بگۆڕە"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"end_of_list": "کۆتایی لیستەکە",
|
||||||
|
"error": "هەڵە",
|
||||||
|
"fetching": "هێنانی ...",
|
||||||
|
"in": "لە",
|
||||||
|
"no_bookmarks": "هێشتا هیچ بابەتێک نیشانە نەکراوە",
|
||||||
|
"no_favourites": "هێشتا هیچ بابەتێک پەسەند نەکراوە",
|
||||||
|
"not_found": "هەڵەی ٤٠٤، نەدۆزرایهوه",
|
||||||
|
"offline_desc": "وا دیارە تۆ لە دەرەوەی هێڵ بیت. تکایە پەیوەندی تۆڕەکەت بپشکنە."
|
||||||
|
},
|
||||||
|
"compose": {
|
||||||
|
"draft_title": "ڕەشنووس {0}",
|
||||||
|
"drafts": "ڕەشنووسەکان ({v})"
|
||||||
|
},
|
||||||
|
"confirm": {
|
||||||
|
"block_account": {
|
||||||
|
"cancel": "ههڵوهشاندنهوه",
|
||||||
|
"confirm": "بلۆک",
|
||||||
|
"title": "ئایا دڵنیای کە دەتەوێت {0} بلۆک بکەیت؟"
|
||||||
|
},
|
||||||
|
"block_domain": {
|
||||||
|
"cancel": "ههڵوهشاندنهوه",
|
||||||
|
"confirm": "بلۆک",
|
||||||
|
"title": "ئایا دڵنیای کە دەتەوێت {0} بلۆک بکەیت؟"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"cancel": "نەخێر",
|
||||||
|
"confirm": "بەڵێ"
|
||||||
|
},
|
||||||
|
"delete_list": {
|
||||||
|
"cancel": "ههڵوهشاندنهوه",
|
||||||
|
"confirm": "سڕینەوە",
|
||||||
|
"title": "ئایا دڵنیای کە دەتەوێت لیستی \"{0}\" بسڕیتەوە؟"
|
||||||
|
},
|
||||||
|
"delete_posts": {
|
||||||
|
"cancel": "ههڵوهشاندنهوه",
|
||||||
|
"confirm": "سڕینەوە",
|
||||||
|
"title": "دڵنیای دەتەوێت ئەم بابەتە بسڕیتەوە؟"
|
||||||
|
},
|
||||||
|
"mute_account": {
|
||||||
|
"cancel": "ههڵوهشاندنهوه",
|
||||||
|
"confirm": "بێدەنگ",
|
||||||
|
"title": "ئایا دڵنیای کە دەتەوێت {0} بێدەنگ بکەیت؟"
|
||||||
|
},
|
||||||
|
"show_reblogs": {
|
||||||
|
"cancel": "ههڵوهشاندنهوه",
|
||||||
|
"confirm": "پیشاندان",
|
||||||
|
"title": "ئایا دڵنیای کە دەتەوێت هاوبەشیەکان لە {0}ەوە پیشان بدەیت؟"
|
||||||
|
},
|
||||||
|
"unfollow": {
|
||||||
|
"cancel": "ههڵوهشاندنهوه",
|
||||||
|
"confirm": "شوێن نەکەوتن",
|
||||||
|
"title": "دڵنیای کە دەتەوێت شوێنی نەکەویتەوە؟"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"conversation": {
|
||||||
|
"with": "لەگەڵ"
|
||||||
|
},
|
||||||
|
"custom_cards": {
|
||||||
|
"stackblitz": {
|
||||||
|
"lines": "هێڵەکان {0}",
|
||||||
|
"open": "کراوە",
|
||||||
|
"snippet_from": "پارچەیەک لە {0}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"account_not_found": "هەژمار {0} نەدۆزرایەوە",
|
||||||
|
"file_size_cannot_exceed_n_mb": "قەبارەی پەڕگە ناتوانرێت لە {0} مێگابایت تێپەڕێت",
|
||||||
|
"sign_in_error": "ناتوانیت پەیوەندی بکەیت بە ڕاژەکار.",
|
||||||
|
"status_not_found": "بابەت نەدۆزرایەوە",
|
||||||
|
"unsupported_file_format": "پەڕەگە پشتگیری نەکراو"
|
||||||
|
},
|
||||||
|
"help": {
|
||||||
|
"build_preview": {
|
||||||
|
"desc1": "لە ئێستادا ئێوە وشانی پێشوەختەی Elk لە کۆمەڵگەوە دەبینن - {0}.",
|
||||||
|
"desc2": "لەوانەیە گۆڕانکاری بێ پێداچوونەوە یان تەنانەت زیانبەخشی تێدابێت.",
|
||||||
|
"desc3": "بە هەژمارە ڕاستەقینەکەتەوە مەچۆژوور",
|
||||||
|
"title": "پێشبینینی بڵاوکردنەوە"
|
||||||
|
},
|
||||||
|
"desc_highlight": "چاوەڕوانی هەندێک هەڵە و تایبەتمەندی ونبوو لێرە و لەوێ بن.",
|
||||||
|
"desc_para1": "سوپاس بۆ ئارەزووی ئێوە بۆ تاقیکردنەوەی Elk، ڕاژەخوازی ماستۆدۆنەکەمان لە پێشکەوتندایە!",
|
||||||
|
"desc_para2": "ئێمە زۆر کار لەسەر گەشەپێدانەکە دەکەین و بە تێپەڕبوونی کات باشتری دەکەین.",
|
||||||
|
"desc_para3": "بۆ بەرزکردنەوەی گەشەپێدان، دەتوانیت لە ڕێگەی پاڵپشتیەکانی گیتهاب پشتیوانی تاقمەکەمان بکەیت. هیوادارین چێژ لە Elk وەربگرن!",
|
||||||
|
"desc_para4": "Elk سەرچاوە کراوەیە. ئەگەر دەتەوێت یارمەتی بدەیت لە تاقیکەرەوە، فیدباک بنێرە، یان بەشداری بکە،",
|
||||||
|
"desc_para5": "لە گیتهاب نزیکمان بکەرەوە",
|
||||||
|
"desc_para6": "و بەشداری بکەن.",
|
||||||
|
"footer_team": "گەشەپێدارانی Elk",
|
||||||
|
"title": "ئێلک(Elk) لە پێشبینیدایە!"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"search": "گەڕان"
|
||||||
|
},
|
||||||
|
"list": {
|
||||||
|
"add_account": "هەژمارە زیاد بکە بۆ لیستەکە",
|
||||||
|
"cancel_edit": "هەڵوەشاندنەوەی دەستکاریکردن",
|
||||||
|
"clear_error": "هەڵە پاک بکەرەوە",
|
||||||
|
"create": "دروستکردن",
|
||||||
|
"delete": "ئەم لیستە بسڕەوە",
|
||||||
|
"delete_error": "لە کاتی سڕینەوەی لیستەکەدا هەڵەیەک ڕوویدا",
|
||||||
|
"edit": "دەستکاری ئەم لیستە بکە",
|
||||||
|
"edit_error": "لە کاتی نوێکردنەوەی لیستەکەدا هەڵەیەک ڕوویدا",
|
||||||
|
"error": "لە کاتی دروستکردنی لیستەکەدا هەڵەیەک ڕوویدا",
|
||||||
|
"error_prefix": "هەڵە:",
|
||||||
|
"list_title_placeholder": "ناونیشانی لیستەکە",
|
||||||
|
"modify_account": "دەستکاری لیستەکان بکە بە هەژمارە",
|
||||||
|
"remove_account": "هەژمارە لە لیستەکە دەربهێنە",
|
||||||
|
"save": "پاشکەوتی گۆڕانکاری"
|
||||||
|
},
|
||||||
|
"magic_keys": {
|
||||||
|
"dialog_header": "قەدبڕی تەختەکلیل",
|
||||||
|
"groups": {
|
||||||
|
"actions": {
|
||||||
|
"boost": "هابەشیکردن",
|
||||||
|
"command_mode": "دۆخی فەرمان",
|
||||||
|
"compose": "نووسین",
|
||||||
|
"favourite": "دڵخواز",
|
||||||
|
"title": "کردارەکان"
|
||||||
|
},
|
||||||
|
"media": {
|
||||||
|
"title": "ڕاگهیاندن"
|
||||||
|
},
|
||||||
|
"navigation": {
|
||||||
|
"go_to_home": "سەرەتا",
|
||||||
|
"go_to_notifications": "ئاگاداری",
|
||||||
|
"next_status": "دۆخی داهاتوو",
|
||||||
|
"previous_status": "دۆخی پێشوو",
|
||||||
|
"shortcut_help": "یارمەتی کورتەڕێ",
|
||||||
|
"title": "ڕێدۆز"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sequence_then": "ئیتر"
|
||||||
|
},
|
||||||
|
"menu": {
|
||||||
|
"add_personal_note": "زیادکردنی تێبینی کەسی بۆ {0}",
|
||||||
|
"block_account": "بلۆک {0}",
|
||||||
|
"block_domain": " بلۆککردنی دۆمەینی {0}",
|
||||||
|
"copy_link_to_post": "بەستەری ئەم بابەتە ڕوونووس بکە",
|
||||||
|
"copy_original_link_to_post": "بەستەری ئەسڵی ڕوونووس بکە بۆ ئەم بابەتە",
|
||||||
|
"delete": "سڕینەوە",
|
||||||
|
"delete_and_redraft": "سڕینەوە یا دەستکاری",
|
||||||
|
"direct_message_account": "پەیامی ڕاستەوخۆ {0}",
|
||||||
|
"edit": "دەستکاری",
|
||||||
|
"hide_reblogs": "شاردنەوەی هاوبەشیەکان لە {0}",
|
||||||
|
"mention_account": "ئاماژە بە {0}",
|
||||||
|
"mute_account": "بێدەنگکردنی {0}",
|
||||||
|
"mute_conversation": "ئەم بابەتە بێدەنگ بکەن",
|
||||||
|
"open_in_original_site": "کردنەوە لە ماڵپەڕی سەرەکی",
|
||||||
|
"pin_on_profile": "سنجاقکردن لەسەر پرۆفایل",
|
||||||
|
"remove_personal_note": "لابردنی تێبینی کەسی لە {0}",
|
||||||
|
"report_account": "{0} گوزارشی",
|
||||||
|
"share_post": "ئەم بابەتە هاوبەش بکە",
|
||||||
|
"show_favourited_and_boosted_by": "نیشانی بدە کێ حەزی لێیەتی و هابەشیکردووە",
|
||||||
|
"show_reblogs": "هاوبەشیەکان نیشان بدە لە {0}",
|
||||||
|
"show_untranslated": "پیشاندانی ڕێکنەخراو",
|
||||||
|
"toggle_theme": {
|
||||||
|
"dark": "گۆڕینی شێوازی تاریک",
|
||||||
|
"light": "گۆڕینی شێوازی ڕۆژ"
|
||||||
|
},
|
||||||
|
"translate_post": "بابەت وەربگێڕە",
|
||||||
|
"unblock_account": "{0} بلۆکەکە لاببە",
|
||||||
|
"unblock_domain": "ئازادکردنی {0} دۆمەین",
|
||||||
|
"unfollow_account": "وازهێنان لە شوێنکەوتووان {0}",
|
||||||
|
"unmute_account": "بێدەنگی {0} لابەرە",
|
||||||
|
"unmute_conversation": "بێدەنگی لەم بابەتە لابەرە",
|
||||||
|
"unpin_on_profile": "سنجاقکردن لابەرە لە پرۆفایل"
|
||||||
|
},
|
||||||
|
"modals": {
|
||||||
|
"aria_label_close": "داخستن"
|
||||||
|
},
|
||||||
|
"nav": {
|
||||||
|
"back": "بگەڕێوە",
|
||||||
|
"blocked_domains": "دۆمەینە بلۆککراوەکان",
|
||||||
|
"blocked_users": "بەکارهێنەرە بلۆککراوەکان",
|
||||||
|
"bookmarks": "نیشانکراوەکان",
|
||||||
|
"built_at": "{0} دروستکراو",
|
||||||
|
"compose": "نووسین",
|
||||||
|
"conversations": "گفتوگۆکان",
|
||||||
|
"explore": "گەڕان",
|
||||||
|
"favourites": "دڵخوازەکان",
|
||||||
|
"federated": "یەکگرتن",
|
||||||
|
"home": "سەرەتا",
|
||||||
|
"list": "لیست",
|
||||||
|
"lists": "لیستەکان",
|
||||||
|
"local": "خۆماڵی",
|
||||||
|
"muted_users": "بەکارهێنەرە بێدەنگەکان",
|
||||||
|
"notifications": "ئاگادارییەکان",
|
||||||
|
"privacy": "تایبەتێتی",
|
||||||
|
"profile": "پرۆفایل",
|
||||||
|
"search": "گەڕان",
|
||||||
|
"select_feature_flags": "گۆڕینی تایبەتمەندی ئاڵاکان",
|
||||||
|
"select_font_size": "ئەندازەی پێنووس",
|
||||||
|
"select_language": "پیشاندانی زمان",
|
||||||
|
"settings": "ڕێکخستنهکان",
|
||||||
|
"show_intro": "پیشاندانی پێشەکی",
|
||||||
|
"toggle_theme": "گۆڕینی ڕووکار",
|
||||||
|
"zen_mode": "شێوەی Zen"
|
||||||
|
},
|
||||||
|
"notification": {
|
||||||
|
"favourited_post": "بابەتەکەتی پەسەند کرد",
|
||||||
|
"followed_you": "دوای تۆ کەوت",
|
||||||
|
"followed_you_count": "{0} بەکارهێنەر دوای تۆ کەوتن{0} کەبەکارهێنەر بەدوات کەوتن|{0} بەکارهێنەر دوای تۆ کەوتن",
|
||||||
|
"missing_type": "MISSING notification.type:",
|
||||||
|
"reblogged_post": "هاوبەشیکردنی بابەتی تۆ",
|
||||||
|
"reported": "{0} گوزارشی {1}",
|
||||||
|
"request_to_follow": "داوای کردووە کە شوێنتان بکەوێت ",
|
||||||
|
"signed_up": "بوو به ئه ندام",
|
||||||
|
"update_status": "بابەتەکەیان نوێکردەوە"
|
||||||
|
},
|
||||||
|
"placeholder": {
|
||||||
|
"content_warning": "لێرەدا هۆشدارییەکەت بنووسە",
|
||||||
|
"default_1": "چی لە مێشکتدایە؟",
|
||||||
|
"reply_to_account": "وەڵامی {0}",
|
||||||
|
"replying": "وەڵامدانەوە"
|
||||||
|
},
|
||||||
|
"polls": {
|
||||||
|
"allow_multiple": "ڕێگە بە چەندین هەڵبژاردن بدە",
|
||||||
|
"cancel": "ههڵوهشاندنهوه",
|
||||||
|
"create": "دروستکردنی ڕاپرسی",
|
||||||
|
"disallow_multiple": "ڕێگەنەدان بە هەڵبژاردنی فرە",
|
||||||
|
"expiration": "بەسەرچوونی ماوەی ڕاپرسی",
|
||||||
|
"hide_votes": "Hide vote totals until the end",
|
||||||
|
"option_placeholder": "هەڵبژاردنی ڕاپرسی {current}/{max}",
|
||||||
|
"remove_option": "هەڵبژاردن لاببە",
|
||||||
|
"settings": "بژاردەکانی ڕاپرسی",
|
||||||
|
"show_votes": "هەمیشە کۆی دەنگەکان پیشان بدە"
|
||||||
|
},
|
||||||
|
"pwa": {
|
||||||
|
"dismiss": " ڕێپێنەدان",
|
||||||
|
"install": "دامەزراندن",
|
||||||
|
"install_title": "دامەزراندنی Elk",
|
||||||
|
"screenshots": {
|
||||||
|
"dark": "وێنەی ڕوومێزی Elk کە لە دۆخی تاریکدا کاردەکات",
|
||||||
|
"light": "وێنەی ڕوومێزی Elk کە لە دۆخی ڕووناکیدا کاردەکات"
|
||||||
|
},
|
||||||
|
"title": "نوێکردنەوەی نوێی Elk بەردەستە!",
|
||||||
|
"update": "نوێکردنەوە",
|
||||||
|
"update_available_short": "نوێکردنەوەی Elk",
|
||||||
|
"webmanifest": {
|
||||||
|
"canary": {
|
||||||
|
"description": "ڕاژەخوازێکی ماستۆدۆن (کاناری)",
|
||||||
|
"name": "Elk (کاناری)",
|
||||||
|
"short_name": "Elk (کاناری)"
|
||||||
|
},
|
||||||
|
"dev": {
|
||||||
|
"description": "ڕاژەخوازێکی وێبی ماستۆدۆن (پەرەپێدەر)",
|
||||||
|
"name": "Elk (پەرەپێدەر)",
|
||||||
|
"short_name": "Elk (پەرەپێدەر)"
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"description": "ڕاژەخوازێکی وێبی ماستۆدۆن (پێشبینین)",
|
||||||
|
"name": "Elk (پێشبینین)",
|
||||||
|
"short_name": "Elk (پێشبینین)"
|
||||||
|
},
|
||||||
|
"release": {
|
||||||
|
"description": "ڕاژەخوازێکی وێبی ماستۆدۆن",
|
||||||
|
"name": "Elk",
|
||||||
|
"short_name": "Elk"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"report": {
|
||||||
|
"additional_comments": "سەرنجی زیادە",
|
||||||
|
"another_server": "ئەو بەکارهێنەرەی کە تۆ ڕاپۆرتی دەکەیت لە ڕاژەیێکی ترەوەیە",
|
||||||
|
"anything_else": "ئایا شتێکی تر هەیە کە پێت وایە پێویستە بزانین؟",
|
||||||
|
"block_desc": "چیتر هیچ بابەتێک لەم بەکارهێنەرەوە نابینیت. ئەوان ناتوانن پۆستەکانت ببینن و شوێنتکەون بکەن. ئەوان دەتوانن بزانن کە بلۆک کراون.",
|
||||||
|
"dontlike": "حەزم لێ نیە",
|
||||||
|
"dontlike_desc": "شتێک نییە کە تۆ بتەوێت بیبینیت",
|
||||||
|
"forward": "بەڵێ، ئەم گوزارشە بنێرە بۆ {0}",
|
||||||
|
"forward_question": "ئایا دەتەوێت ڕوونووسێکی بێناو لەم گوزارشە بنێری بۆ ئەو ڕاژەکارەش",
|
||||||
|
"further_actions": {
|
||||||
|
"limit": {
|
||||||
|
"description": "ئەمەی خوارەوە هەڵبژاردنەکانتە بۆ کۆنترۆڵکردنی ئەوەی دەیبینیت:",
|
||||||
|
"title": "ناتەوێت ئەمە ببینیت؟"
|
||||||
|
},
|
||||||
|
"report": {
|
||||||
|
"description": "لە کاتێکدا ئێمە پێداچوونەوە بۆ ئەمە دەکەین، ئەمە ئەو کردارانەن کە دەتوانیت ئەنجامی بدەیت:",
|
||||||
|
"title": "سوپاس بۆ گوزارشەکەت ئێمە سەیری ئەمە دەکەین."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"limiting": "سنووردارکردنی {0}",
|
||||||
|
"mute_desc": "چیتر هیچ بابەتێکی ئەم بەکارهێنەرە نابینیت. ئەوان هێشتا دەتوانن شوێنت بکەون و بابەتەکانت ببینن. ئه وان نازانن که ئه وان هه ر ده بن.",
|
||||||
|
"other": "شتێکی ترە",
|
||||||
|
"other_desc": "کێشەکە ناگونجێت بۆ پۆلەکانی تر",
|
||||||
|
"reporting": "{0} گوزارش",
|
||||||
|
"select_many": "هەموو ئەو شتانە دیاریبکە کە جێبەجێ دەکرێن:",
|
||||||
|
"select_one": "باشترین هاورێ هەڵبژێرە",
|
||||||
|
"select_posts": "ئایا هیچ بابەتێک هەیە کە پشتگیری ئەم گوزارشە بکات؟",
|
||||||
|
"select_posts_other": "ئایا هیچ بابەتێکی دیکە هەیە کە پشتگیری ئەم گوزارشە بکات؟",
|
||||||
|
"spam": "ئەوە سپام",
|
||||||
|
"spam_desc": "بەستەرە زیانبەخشەکان، پەیوەندی ساختە، یان وەڵامی دووبارەبوونەوە",
|
||||||
|
"submit": "گوزارش بنێرە",
|
||||||
|
"unfollow_desc": "چیتر بابەتەکانی ئەم بەکارهێنەرە لە پەڕەی ماڵەکەتدا نابینیت. هێشتا دەتوانیت بابەتەکانیان لە شوێنێکی تر ببینیت.",
|
||||||
|
"violation": "یەکێک یان زیاتر لە یاساکانی ڕاژەکار پێشێل دەکات",
|
||||||
|
"whats_wrong_account": "پێمان بڵێ کێشەی ئەم هەژمارە چییە",
|
||||||
|
"whats_wrong_post": "پێمان بڵێ کێشەی ئەم بابەتە چییە"
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"search_desc": "گەڕان بۆ بەکارهێنەران و هاشتاگەکان",
|
||||||
|
"search_empty": "نەیتوانی هیچ شتێک بدۆزێتەوە بۆ ئەم مەرجە گەڕانە"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"about": {
|
||||||
|
"built_at": "بنیات نان",
|
||||||
|
"label": "دەربارە",
|
||||||
|
"meet_the_team": "تاقمەکە بناسە",
|
||||||
|
"sponsor_action": "پشتیوانمان بە",
|
||||||
|
"sponsor_action_desc": "بۆ پشتگیری کردنی تیمی گەشەپێدانی Elk",
|
||||||
|
"sponsors": "پشتیوانەکان",
|
||||||
|
"sponsors_body_1": "Elk بە هۆی پشتیوانە بەخشەندە و یارمەتییەکانی، پێزانینی هەیە بۆ :",
|
||||||
|
"sponsors_body_2": "وە هەموو ئەو کۆمپانیا و کەسانەی کە پشتیوانی دەستەکەی Elk و ئەندامەکان دەکەن.",
|
||||||
|
"sponsors_body_3": "ئەگەر چێژ لە ئەپەکە وەردەگریت، بیر لەوە بکەرەوە کە پشتیوانیمان بکەیت:",
|
||||||
|
"version": "وشان"
|
||||||
|
},
|
||||||
|
"account_settings": {
|
||||||
|
"description": "دەستکاری ڕێکخستنەکانی هەژمارەکەت بکە لە ڕوخساری ماستۆدۆن",
|
||||||
|
"label": "ڕێکخستنەکانی هەژمارە"
|
||||||
|
},
|
||||||
|
"interface": {
|
||||||
|
"color_mode": "شێوەی ڕەنگ",
|
||||||
|
"dark_mode": "تاریک",
|
||||||
|
"default": " (بنەڕەت)",
|
||||||
|
"font_size": "ئەندازەی پێنووس",
|
||||||
|
"label": "ڕووکار",
|
||||||
|
"light_mode": "ڕۆشن",
|
||||||
|
"system_mode": "سیستەم",
|
||||||
|
"theme_color": "ڕەنگی ڕووکار"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"display_language": "زمانی پیشاندان",
|
||||||
|
"label": "زمان",
|
||||||
|
"post_language": "زمانی بڵاوکردنەوە",
|
||||||
|
"status": "دۆخی وەرگێڕان: {0}/{1} ({2}٪)",
|
||||||
|
"translations": {
|
||||||
|
"add": "زیادکردن",
|
||||||
|
"choose_language": "زمانێک هەڵبژێرە",
|
||||||
|
"heading": "وەرگێڕان",
|
||||||
|
"hide_specific": "وەرگێڕانی دیاریکراو بشارەوە",
|
||||||
|
"remove": "لابردن"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"label": "ئاگادارییەکان",
|
||||||
|
"notifications": {
|
||||||
|
"label": "ڕێکخستنەکانی ئاگادارکردنەوەکان"
|
||||||
|
},
|
||||||
|
"push_notifications": {
|
||||||
|
"alerts": {
|
||||||
|
"favourite": "دڵخوازەکان",
|
||||||
|
"follow": "شوێنکەوتووی نوێ",
|
||||||
|
"mention": "ئاماژە",
|
||||||
|
"poll": "دەنگ",
|
||||||
|
"reblog": "بابەتەکەت دووبارە بنووسەوە",
|
||||||
|
"title": "چ ئاگادارکردنەوەیەک وەربگرین؟"
|
||||||
|
},
|
||||||
|
"description": "تەنانەت کاتێک کە Elk بەکارناهێنیت ئاگادارکردنەوەکان وەربگرە.",
|
||||||
|
"instructions": "لەبیرت نەچێت گۆڕانکارییەکانت بە بەکارهێنانی دوگمەی @:settings.notifications.push_notifications.save_settings پاشەکەوت بکەیت!",
|
||||||
|
"label": "ڕێکخستنەکانی ئاگادارکردنەوەکانی پاڵدان",
|
||||||
|
"policy": {
|
||||||
|
"all": "لە هەر کەسێکەوە",
|
||||||
|
"followed": "لە کەسانێک کە شوێنیان دەکەوم",
|
||||||
|
"follower": "لە کەسانێک کە شوێنم دەکەون",
|
||||||
|
"none": "لە هیچ کەس",
|
||||||
|
"title": "لە کێ دەتوانم ئاگادارکردنەوە وەرگرم؟"
|
||||||
|
},
|
||||||
|
"save_settings": "ڕێکخستنەکان پاشەکەوت بکە",
|
||||||
|
"subscription_error": {
|
||||||
|
"clear_error": "هەڵە بسڕەوە",
|
||||||
|
"error_hint": "دەتوانیت ڕاوێژ بە لیستی پرسیارە زۆرەکان بکەیت بۆ ئەوەی هەوڵی چارەسەرکردنی کێشەکە بدەیت: {0}.",
|
||||||
|
"invalid_vapid_key": "پێدەچێت کلیلی گشتی VAPID نادروست بێت.",
|
||||||
|
"permission_denied": "مۆڵەت ڕەتکرایەوە: ئاگادارکردنەوەکان لە وێبگەڕەکەتدا چالاک بکە.",
|
||||||
|
"repo_link": "کۆگای Elk لە گیتهاب",
|
||||||
|
"request_error": "هەڵەیەک لە کاتی داوای بەشداریکردندا ڕوویدا، دووبارە هەوڵبدەرەوە و ئەگەر هەڵەکە بەردەوام بوو، تکایە کێشەکە گوزارش بدە بە کۆگای Elk.",
|
||||||
|
"title": "نەتوانرا بەشداری بکات بۆ ئاگادارکردنەوەکانی پاڵدان",
|
||||||
|
"too_many_registrations": "بەهۆی سنووردارکردنی وێبگەڕەوە، Elk ناتوانێت خزمەتگوزاری ئاگادارکردنەوەی پاڵنەر بەکاربهێنێت بۆ چەندین هەژمار لەسەر ڕاژەکارە جیاوازەکان. پێویستە بەشداری بکەیت لە پاڵنانی ئاگانامەکان لەسەر هەژمارێکی تر و دووبارە هەوڵ بدە.",
|
||||||
|
"vapid_not_supported": "وێبگەڕەکەت پشتگیری لە ئاگادارییەکانی Web Push دەکات، بەڵام پێناچێت پرۆتۆکۆڵی VAPID جێبەجێ بکات."
|
||||||
|
},
|
||||||
|
"title": "ڕێکخستنەکانی ئاگادارکردنەوەکانی پاڵدان",
|
||||||
|
"undo_settings": "گۆڕانکارییەکان بگەڕێنەوە",
|
||||||
|
"unsubscribe": "ئاگادارکردنەوەکانی پاڵدان لەکاربخە",
|
||||||
|
"unsupported": "وێبگەڕەکەت پشتگیری لە ئاگادارکردنەوەکانی پاڵدان ناکات.",
|
||||||
|
"warning": {
|
||||||
|
"enable_close": "داخستن",
|
||||||
|
"enable_description": "بۆ وەرگرتنی ئاگادارکردنەوەکان کاتێک Elk کراوە نییە، ئاگادارکردنەوەکانی پاڵدان چالاک بکە. دەتوانیت بە وردی کۆنتڕۆڵی ئەوە بکەیت کە چ جۆرە کارلێکێک ئاگادارییەکانی پاڵنەر دروست دەکات لە ڕێگەی دوگمەی \"@:settings.notifications.show_btn{'\"'}ی سەرەوە کاتێک چالاک کرا.",
|
||||||
|
"enable_description_desktop": "بۆ وەرگرتنی ئاگادارکردنەوە کاتێک Elk کراوە نییە، ئاگادارکردنەوەکانی پاڵدان چالاک بکە. دەتوانیت بە وردی کۆنتڕۆڵی ئەوە بکەیت کە چ جۆرە کارلێکێک ئاگادارکردنەوەی پاڵدان دروست دەکات لە \"ڕێکخستنەکان > ئاگادارکردنەوەکان > ڕێکخستنەکانی ئاگادارکردنەوەکانی پاڵدان\" کاتێک چالاک کرا.",
|
||||||
|
"enable_description_mobile": "هەروەها دەتوانیت بە بەکارهێنانی مینیوی گەشتکردن \"ڕێکخستنەکان > ئاگادارکردنەوەکان > ڕێکخستنەکانی ئاگادارکردنەوە پاڵدان\"، دەستت بگات بە ڕێکخستنەکان.",
|
||||||
|
"enable_description_settings": "بۆ وەرگرتنی ئاگادارکردنەوەکان کاتێک Elk کراوە نییە، ئاگادارکردنەوەکانی پاڵدان چالاک بکە. دەتوانیت بە وردی کۆنتڕۆڵی ئەوە بکەیت کە چ جۆرە کارلێکێک ئاگادارکردنەوەی پاڵنەر لەسەر هەمان ئەم شاشەیە دروست دەکات کاتێک چالاکیان دەکەیت.",
|
||||||
|
"enable_desktop": "ئاگادارکردنەوەکانی پاڵدان چالاک بکە",
|
||||||
|
"enable_title": "هەرگیز هیچ شتێک لەدەست مەدە",
|
||||||
|
"re_auth": "وا دیارە ڕاژەکارەکەت پشتگیری لە ئاگادارکردنەوەکانی پاڵدان ناکات. هەوڵبدە بچیتە دەرەوە و دووبارە بچۆرەوە ژوورەوە، ئەگەر ئەم پەیامە هێشتا دەرکەوت پەیوەندی بە بەڕێوەبەری سێرڤەرەکەتەوە بکە."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"show_btn": "بڕۆ بۆ ڕێکخستنەکانی ئاگادارکردنەوەکان",
|
||||||
|
"under_construction": "لەژێر دروستکردنەوەدایە"
|
||||||
|
},
|
||||||
|
"notifications_settings": "ئاگاداریەکان",
|
||||||
|
"preferences": {
|
||||||
|
"enable_autoplay": "چالاککردنی لێدانی خۆکار",
|
||||||
|
"enable_data_saving": "چالاککردنی پاشەکەوتکردنی زانیاری",
|
||||||
|
"enable_data_saving_description": "زانیاری پاشەکەوت بکە بە ڕێگریکردن لە لکێندراوەکان لە بارکردنی خۆکارانە.",
|
||||||
|
"enable_pinch_to_zoom": "چالاککردنی پینچ بۆ گەورەنوێیی",
|
||||||
|
"github_cards": "کاردەکانی گیتهاب",
|
||||||
|
"github_cards_description": "کاتێک بەستەری گیتهاب بڵاودەکرێتەوە، کارتێکی HTML بە بەکارهێنانی مێتای گرافی کۆمەڵایەتی لە جیاتی وێنەی کۆمەڵایەتی پیشان دەدرێت.",
|
||||||
|
"grayscale_mode": "دۆخی خۆڵەمێشی",
|
||||||
|
"hide_account_hover_card": "شاردنەوەی کارتی هۆڤەری ئەکاونت",
|
||||||
|
"hide_alt_indi_on_posts": "شاردنەوەی نیشاندەری سەردێر لەسەر بابەتەکان",
|
||||||
|
"hide_boost_count": "شاردنەوەی ژمارەی هابەشکردنەوە",
|
||||||
|
"hide_favorite_count": "ژمارەی دڵخوازەکان بشارەوە",
|
||||||
|
"hide_follower_count": "ژمارەی شوێنکەوتوو/شوێنکەوتووان بشارەوە",
|
||||||
|
"hide_news": "شاردنەوەی هەواڵەکان",
|
||||||
|
"hide_reply_count": "ژمارەی وەڵامەکان بشارەوە",
|
||||||
|
"hide_translation": "وەرگێڕان بشارەوە",
|
||||||
|
"hide_username_emojis": "شاردنەوەی ئیمۆجیەکانی ناوی بەکارهێنەر",
|
||||||
|
"hide_username_emojis_description": "شاردنەوەی ئیمۆجیەکان لە ناوی بەکارهێنەر لە هێڵی کات. ئیمۆجییەکان هێشتا لە پرۆفایلەکانیاندا دەبینرێن.",
|
||||||
|
"label": "هەڵبژاردن",
|
||||||
|
"title": "تایبەتمەندییە تاقیکارییەکان",
|
||||||
|
"use_star_favorite_icon": "ئایکۆنی دڵخوازی ئەستێرە بەکاربهێنە",
|
||||||
|
"user_picker": "هەڵبژێرەری بەکارهێنەر",
|
||||||
|
"user_picker_description": "هەموو وێنۆچکەکانی هەژمارەکانی تۆمارکراوەکان لە خوارەوەی چەپ پیشان دەدات بۆ ئەوەی بتوانیت بە خێرایی لە نێوانیاندا بگۆڕیت.",
|
||||||
|
"virtual_scroll": "سکڕۆڵکردنی مەجازی",
|
||||||
|
"virtual_scroll_description": "لیستی مەجازی لە هێڵە کاتییەکاندا بەکاربهێنە، بۆ ئەوەی ژمارەیەکی زیاتر لە بابەتە بە شێوەیەکی کارا ڕەندەر بکرێت.",
|
||||||
|
"wellbeing": "خۆشگوزەرانی",
|
||||||
|
"zen_mode": "شێوەی Zen",
|
||||||
|
"zen_mode_description": "لایەک بشارەوە مەگەر ئاماژەدەری ماوسەکە لەسەریان نەبێت. هەروەها هەندێک توخم لە هێڵی کاتی بشارەوە."
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"appearance": {
|
||||||
|
"bio": "ژیاننامە",
|
||||||
|
"description": "دەستکاری وێنۆچکە، ناوی بەکارهێنەر، پڕۆفایل و هتد.",
|
||||||
|
"display_name": "ناوی پیشاندراو",
|
||||||
|
"label": "پیشاندان",
|
||||||
|
"profile_metadata": "مێتاداتای پڕۆفایلی",
|
||||||
|
"profile_metadata_desc": "دەتوانیت تا {0} شت وەک خشتەیەک لە پڕۆفایلی خۆتدا پیشان بدەیت",
|
||||||
|
"profile_metadata_label": "نیشانە",
|
||||||
|
"profile_metadata_value": "ناوەڕۆک",
|
||||||
|
"title": "دەستکاریکردنی پرۆفایل"
|
||||||
|
},
|
||||||
|
"featured_tags": {
|
||||||
|
"description": "خەڵک دەتوانن لە ژێر ئەم هاشتاگانەدا لە بابەتە گشتیەکانتاندا بگەڕێن.",
|
||||||
|
"label": "هاشتاگی تایبەت"
|
||||||
|
},
|
||||||
|
"label": "پرۆفایل"
|
||||||
|
},
|
||||||
|
"select_a_settings": "ڕێکخستنێک هەڵبژێرە",
|
||||||
|
"users": {
|
||||||
|
"export": "هەناردەکردنی تۆکنەکانی بەکارهێنەر",
|
||||||
|
"import": "هاوردەکردنی تۆکنەکانی بەکارهێنەر",
|
||||||
|
"label": "بەکارهێنەرانی چوونەژوورەوە"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"attachments_exceed_server_limit": "ژمارەی هاوپێچەکان سنووری بۆ هەر بابەتێک تێپەڕاند.",
|
||||||
|
"attachments_limit_error": "سنوور بۆ هەر بابەتێک تێپەڕی",
|
||||||
|
"edited": "(دەستکاری کراوە)",
|
||||||
|
"editing": "دەستکاریکردن",
|
||||||
|
"loading": "خرمەخرم ...",
|
||||||
|
"publish_failed": "بڵاوکردنەوە سەرکەوتوو نەبوو",
|
||||||
|
"publishing": "بڵاوکردنەوە",
|
||||||
|
"save_failed": "هەڵگرتن سەرکەوتوو نەبوو",
|
||||||
|
"upload_failed": "بارکردن سەرکەوتوو نەبوو",
|
||||||
|
"uploading": "بارکردنەوە..."
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"account": {
|
||||||
|
"suspended_message": "هەژمارکردنی ئەم دۆخە ڕاگیراوە.",
|
||||||
|
"suspended_show": "بەهەرحاڵ ناوەڕۆک نیشان بدە؟"
|
||||||
|
},
|
||||||
|
"boosted_by": "هاوبەشکردن لە لایەن",
|
||||||
|
"edited": "{0} دەستکاریکراو",
|
||||||
|
"favourited_by": "پەسەندکراوە لەلایەن",
|
||||||
|
"filter_hidden_phrase": "پاڵێوراوە لەلایەن",
|
||||||
|
"filter_show_anyway": "بەهەر حاڵ پیشان بدە",
|
||||||
|
"img_alt": {
|
||||||
|
"ALT": "ALT",
|
||||||
|
"desc": "وەسف",
|
||||||
|
"dismiss": "ڕێپێنەدان",
|
||||||
|
"read": "وەسفی {0} بخوێنەوە"
|
||||||
|
},
|
||||||
|
"poll": {
|
||||||
|
"count": "{0} دەنگ|{0} دەنگ|{0} دەنگ",
|
||||||
|
"ends": "کۆتایی بە {0} دێت",
|
||||||
|
"finished": "تەواو بوو {0}"
|
||||||
|
},
|
||||||
|
"replying_to": "وەڵامدانەوەی {0}",
|
||||||
|
"show_full_thread": "تەوەرەی تەواو پیشان بدە",
|
||||||
|
"someone": "کەسێک",
|
||||||
|
"spoiler_media_hidden": "میدیای شاراوە",
|
||||||
|
"spoiler_show_less": "کەمتر پیشان بدە",
|
||||||
|
"spoiler_show_more": "زیاتر نیشان دە",
|
||||||
|
"thread": "Thread",
|
||||||
|
"try_original_site": "سایتی ئەسڵی تاقی بکەرەوە"
|
||||||
|
},
|
||||||
|
"status_history": {
|
||||||
|
"created": "دروستکراوە {0}",
|
||||||
|
"edited": "دەستکاری کراوە {0}"
|
||||||
|
},
|
||||||
|
"tab": {
|
||||||
|
"accounts": "هەژمارەکان",
|
||||||
|
"for_you": "بۆ تۆ",
|
||||||
|
"hashtags": "هاشتاگەکان",
|
||||||
|
"list": "لیست",
|
||||||
|
"media": "مێدیا",
|
||||||
|
"news": "هەواڵ",
|
||||||
|
"notifications_all": "هەموو",
|
||||||
|
"notifications_mention": "باسکردن",
|
||||||
|
"posts": "بابەتەکان",
|
||||||
|
"posts_with_replies": "بابەت و وەڵام"
|
||||||
|
},
|
||||||
|
"tag": {
|
||||||
|
"follow": "بەدواداچوون",
|
||||||
|
"follow_label": "شوێنکەوتنی تاگی {0} بکە",
|
||||||
|
"unfollow": "شوێن نەکەوتن",
|
||||||
|
"unfollow_label": "شوێنکەوتنی تاگی {0} مەکە"
|
||||||
|
},
|
||||||
|
"time_ago_options": {
|
||||||
|
"day_future": "لە 0 ڕۆژدا|سبەی|لە {n} ڕۆژدا",
|
||||||
|
"day_past": "0 ڕۆژ پێش ئێستا|دوێنێ|{n} ڕۆژ پێش ئێستا",
|
||||||
|
"hour_future": "لە 0 کاتژمێردا|لە 1 کاتژمێردا|لە {n} کاتژمێردا",
|
||||||
|
"hour_past": "0 کاتژمێر پێش ئێستا|1 کاتژمێر پێش ئێستا|{n} کاتژمێر پێش ئێستا",
|
||||||
|
"just_now": "هەر ئێستا",
|
||||||
|
"minute_future": "لە 0 خولەکدا|لە 1 خولەکدا|لە {n} خولەکدا",
|
||||||
|
"minute_past": "0 خولەک پێش ئێستا|1 خولەک پێش ئێستا|{n} خولەک پێش ئێستا",
|
||||||
|
"month_future": "لە 0 مانگ|مانگی داهاتوو|لە {n} مانگ",
|
||||||
|
"month_past": "0 مانگ پێش ئێستا|مانگی ڕابردوو|{n} مانگ پێش ئێستا",
|
||||||
|
"second_future": "تەنها ئێستا|لە {n} چرکە|لە {n} چرکە",
|
||||||
|
"second_past": "تەنها ئێستا|{n} چرکە پێش ئێستا|{n} چرکە پێش ئێستا",
|
||||||
|
"short_day_future": "لە {n}ڕۆژ",
|
||||||
|
"short_day_past": "{n}ڕۆژ",
|
||||||
|
"short_hour_future": "لە {n}کاژێر",
|
||||||
|
"short_hour_past": "{n}کاژێر",
|
||||||
|
"short_minute_future": "لە {n}خولەک",
|
||||||
|
"short_minute_past": "{n}خولەک",
|
||||||
|
"short_month_future": "لە {n}مانگ",
|
||||||
|
"short_month_past": "{n}مانگ",
|
||||||
|
"short_second_future": "لە {n}چرکه",
|
||||||
|
"short_second_past": "{n}چرکه",
|
||||||
|
"short_week_future": "لامەرکەزیدا {n}هەفتە",
|
||||||
|
"short_week_past": "{n}هەفتە",
|
||||||
|
"short_year_future": "لە {n}ساڵ",
|
||||||
|
"short_year_past": "{n}ساڵ",
|
||||||
|
"week_future": "لە 0 هەفتە|هەفتەی داهاتوو|لە {n} هەفتە",
|
||||||
|
"week_past": "0 هەفتە پێش ئێستا|هەفتەی ڕابردوو|{n} هەفتە پێش ئێستا",
|
||||||
|
"year_future": "لە 0 ساڵ|ساڵی داهاتوو|لە {n} ساڵ",
|
||||||
|
"year_past": "0 ساڵ لەمەوبەر|ساڵی ڕابردوو|{n} ساڵ لەمەوبەر"
|
||||||
|
},
|
||||||
|
"timeline": {
|
||||||
|
"show_new_items": "{v} بابەتی نوێ پیشان بدە|{v} بابەتی نوێ پیشان بدە|{v} بابەتی نوێ پیشان بدە",
|
||||||
|
"view_older_posts": "ڕەنگە بابەتە کۆنەکانی نموونەکانی تر پیشان نەدرێت."
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"federated_timeline": "هێڵی کاتی فێدرێرکراو",
|
||||||
|
"local_timeline": "هێڵی کاتی ناوخۆیی"
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"add_content_warning": "ئاگادارکردنەوەی ناوەڕۆک زیاد بکە",
|
||||||
|
"add_emojis": "ئیمۆجی زیاد بکە",
|
||||||
|
"add_media": "زیادکردنی وێنە، ڤیدیۆ یان پەڕگەیێکی دەنگی",
|
||||||
|
"add_publishable_content": "ناوەڕۆک زیاد بکە بۆ بڵاوکردنەوە",
|
||||||
|
"change_content_visibility": "گۆڕینی بینینی ناوەڕۆک",
|
||||||
|
"change_language": "گۆڕینی زمان",
|
||||||
|
"emoji": "ئیمۆجی",
|
||||||
|
"explore_links_intro": "ئەم هەواڵانە لەلایەن ئەندامان و ڕاژەکارەکانی دیکەی تۆڕی کۆمەڵایەتییەوە باس دەکرێن.",
|
||||||
|
"explore_posts_intro": "ئەم بابەتانە لەم ڕاژەکارە و ڕاژەکارەکانی تر لە تۆڕی لامەرکەزی ئێستا لەسەر ئەم ڕاژەکارە ڕاکێشن.",
|
||||||
|
"explore_tags_intro": "ئەم هاشتاگانە لە ئێستادا لە نێو ئەندامانی سەر ئەم ڕاژەکارە و ڕاژەکارەکانی تری تۆڕی لامەرکەزیدا جێگەی خۆیان دەگرن.",
|
||||||
|
"open_editor_tools": "ئامرازەکانی سەرنوسەر",
|
||||||
|
"pick_an_icon": "ئایکۆنێک هەڵبژێرە",
|
||||||
|
"publish_failed": "نامە شکستخواردووەکان لە سەرەوەی سەرنوسەر دابخە بۆ دووبارە بڵاوکردنەوەی پۆستەکان",
|
||||||
|
"toggle_bold": "قەڵەو کردن",
|
||||||
|
"toggle_code_block": "بلۆکی کۆد",
|
||||||
|
"toggle_italic": "لار کردن"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"add_existing": "هەژمارەیەکی بەردەست زیاد بکە",
|
||||||
|
"server_address_label": "ناونیشانی ڕاژەکاری ماستۆدۆن",
|
||||||
|
"sign_in_desc": "چوونەژوورەوە بۆ شوێنکەوتنی پڕۆفایل یان هاشتاگەکان، دڵخوازەکان، هاوبەشکردن و وەڵامدانەوەی بابەتەکان، یان کارلێککردن لە هەژمارەکەتەوە لەسەر ڕاژەکارێکی جیاواز.",
|
||||||
|
"sign_in_notice_title": "بینینی {0} داتا گشتیەکان",
|
||||||
|
"sign_out_account": "چوونە دەرەوە {0}",
|
||||||
|
"single_instance_sign_in_desc": "چوونەژوورەوە بۆ شوێنکەوتنی پڕۆفایل یان هاشتاگەکان، دڵخوازەکان، هاوبەشکردن و وەڵامدانەوەی بابەتەکان،.",
|
||||||
|
"tip_no_account": "ئەگەر هێشتا هەژمارەیێکی ماستۆدۆنت نییە، {0}.",
|
||||||
|
"tip_register_account": "ڕاژەکارەکەت هەڵبژێرە و یەکێکیان تۆمار بکە"
|
||||||
|
},
|
||||||
|
"visibility": {
|
||||||
|
"direct": "ڕاستەوخۆ",
|
||||||
|
"direct_desc": "بینراو تەنها بۆ بەکارهێنەرە ئاماژەپێکراو",
|
||||||
|
"private": "تەنها شوێنکەوتووان",
|
||||||
|
"private_desc": "بینراو تەنها بۆ شوێنکەوتووان",
|
||||||
|
"public": "گشتی",
|
||||||
|
"public_desc": "بینراو بۆ هەمووان",
|
||||||
|
"unlisted": "لیست نەکراوە",
|
||||||
|
"unlisted_desc": "بینراو بۆ هەمووان، بەڵام هەڵبژێردراو لە تایبەتمەندییەکانی دۆزینەوە"
|
||||||
|
}
|
||||||
|
}
|
|
@ -218,8 +218,18 @@
|
||||||
"title": "Medien"
|
"title": "Medien"
|
||||||
},
|
},
|
||||||
"navigation": {
|
"navigation": {
|
||||||
|
"go_to_bookmarks": "Favoriten",
|
||||||
|
"go_to_conversations": "Direktnachrichten",
|
||||||
|
"go_to_explore": "Entdecken",
|
||||||
|
"go_to_favourites": "Favoriten",
|
||||||
|
"go_to_federated": "Föderiert",
|
||||||
"go_to_home": "Startseite",
|
"go_to_home": "Startseite",
|
||||||
|
"go_to_lists": "Listen",
|
||||||
|
"go_to_local": "Lokal",
|
||||||
"go_to_notifications": "Benachrichtigungen",
|
"go_to_notifications": "Benachrichtigungen",
|
||||||
|
"go_to_profile": "Profil",
|
||||||
|
"go_to_search": "Suche",
|
||||||
|
"go_to_settings": "Einstellungen",
|
||||||
"next_status": "Nächster Status",
|
"next_status": "Nächster Status",
|
||||||
"previous_status": "Vorheriger Status",
|
"previous_status": "Vorheriger Status",
|
||||||
"shortcut_help": "Tastaturkürzel-Hilfe",
|
"shortcut_help": "Tastaturkürzel-Hilfe",
|
||||||
|
|
|
@ -149,7 +149,12 @@
|
||||||
"mute_account": {
|
"mute_account": {
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"confirm": "Mute",
|
"confirm": "Mute",
|
||||||
|
"days": "days|day|days",
|
||||||
"description": "Are you sure you want to mute {0}?",
|
"description": "Are you sure you want to mute {0}?",
|
||||||
|
"hours": "hours|hour|hours",
|
||||||
|
"minute": "minutes|minute|minutes",
|
||||||
|
"notifications": "Mute notifications",
|
||||||
|
"specify_duration": "Specify mute duration",
|
||||||
"title": "Mute account"
|
"title": "Mute account"
|
||||||
},
|
},
|
||||||
"show_reblogs": {
|
"show_reblogs": {
|
||||||
|
@ -191,14 +196,14 @@
|
||||||
"title": "Preview deploy"
|
"title": "Preview deploy"
|
||||||
},
|
},
|
||||||
"desc_highlight": "Expect some bugs and missing features here and there.",
|
"desc_highlight": "Expect some bugs and missing features here and there.",
|
||||||
"desc_para1": "Thanks for your interest in trying out Elk, our work-in-progress Mastodon web client!",
|
"desc_para1": "Elk is a nimble Mastodon web client. You can login to your Mastodon account and use it to interact with the fediverse.",
|
||||||
"desc_para2": "we are working hard on the development and improving it over time.",
|
"desc_para2": "Elk is Open Source and we're actively improving it as a community project. Join us and let's build it together!",
|
||||||
"desc_para3": "To boost development, you can sponsor the Team through GitHub Sponsors. We hope you enjoy Elk!",
|
"desc_para3": "To boost development, you can sponsor the Team through GitHub Sponsors. We hope you enjoy Elk!",
|
||||||
"desc_para4": "Elk is Open Source. If you'd like to help with testing, giving feedback, or contributing,",
|
"desc_para4": "If you'd like to report a bug, help us testing, give feedback, or contribute,",
|
||||||
"desc_para5": "reach out to us on GitHub",
|
"desc_para5": "reach out to us on GitHub",
|
||||||
"desc_para6": "and get involved.",
|
"desc_para6": "and get involved.",
|
||||||
"footer_team": "The Elk Team",
|
"footer_team": "The Elk Team",
|
||||||
"title": "Elk is in Preview!"
|
"title": "Welcome to Elk!"
|
||||||
},
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"search": "Search"
|
"search": "Search"
|
||||||
|
@ -226,7 +231,7 @@
|
||||||
"boost": "Boost",
|
"boost": "Boost",
|
||||||
"command_mode": "Command mode",
|
"command_mode": "Command mode",
|
||||||
"compose": "Compose",
|
"compose": "Compose",
|
||||||
"favourite": "Favourite",
|
"favourite": "Favorite",
|
||||||
"search": "Search",
|
"search": "Search",
|
||||||
"show_new_items": "Show new items",
|
"show_new_items": "Show new items",
|
||||||
"title": "Actions"
|
"title": "Actions"
|
||||||
|
@ -235,8 +240,18 @@
|
||||||
"title": "Media"
|
"title": "Media"
|
||||||
},
|
},
|
||||||
"navigation": {
|
"navigation": {
|
||||||
|
"go_to_bookmarks": "Bookmarks",
|
||||||
|
"go_to_conversations": "Conversations",
|
||||||
|
"go_to_explore": "Explore",
|
||||||
|
"go_to_favourites": "Favorites",
|
||||||
|
"go_to_federated": "Federated",
|
||||||
"go_to_home": "Home",
|
"go_to_home": "Home",
|
||||||
|
"go_to_lists": "Lists",
|
||||||
|
"go_to_local": "Local",
|
||||||
"go_to_notifications": "Notifications",
|
"go_to_notifications": "Notifications",
|
||||||
|
"go_to_profile": "Profile",
|
||||||
|
"go_to_search": "Search",
|
||||||
|
"go_to_settings": "Settings",
|
||||||
"next_status": "Next post",
|
"next_status": "Next post",
|
||||||
"previous_status": "Previous post",
|
"previous_status": "Previous post",
|
||||||
"shortcut_help": "Shortcut help",
|
"shortcut_help": "Shortcut help",
|
||||||
|
@ -291,9 +306,11 @@
|
||||||
"built_at": "Built {0}",
|
"built_at": "Built {0}",
|
||||||
"compose": "Compose",
|
"compose": "Compose",
|
||||||
"conversations": "Conversations",
|
"conversations": "Conversations",
|
||||||
|
"docs": "Documentation",
|
||||||
"explore": "Explore",
|
"explore": "Explore",
|
||||||
"favourites": "Favorites",
|
"favourites": "Favorites",
|
||||||
"federated": "Federated",
|
"federated": "Federated",
|
||||||
|
"hashtags": "Hashtags",
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
"list": "List",
|
"list": "List",
|
||||||
"lists": "Lists",
|
"lists": "Lists",
|
||||||
|
@ -443,6 +460,7 @@
|
||||||
},
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"display_language": "Display Language",
|
"display_language": "Display Language",
|
||||||
|
"how_to_contribute": "How to contribute?",
|
||||||
"label": "Language",
|
"label": "Language",
|
||||||
"post_language": "Posting Language",
|
"post_language": "Posting Language",
|
||||||
"status": "Translation status: {0}/{1} ({2}%)",
|
"status": "Translation status: {0}/{1} ({2}%)",
|
||||||
|
@ -524,8 +542,10 @@
|
||||||
"hide_boost_count": "Hide boost count",
|
"hide_boost_count": "Hide boost count",
|
||||||
"hide_favorite_count": "Hide favorite count",
|
"hide_favorite_count": "Hide favorite count",
|
||||||
"hide_follower_count": "Hide following/follower count",
|
"hide_follower_count": "Hide following/follower count",
|
||||||
|
"hide_gif_indi_on_posts": "Hide gif indicator on posts",
|
||||||
"hide_news": "Hide news",
|
"hide_news": "Hide news",
|
||||||
"hide_reply_count": "Hide reply count",
|
"hide_reply_count": "Hide reply count",
|
||||||
|
"hide_tag_hover_card": "Hide tag hover card",
|
||||||
"hide_translation": "Hide translation",
|
"hide_translation": "Hide translation",
|
||||||
"hide_username_emojis": "Hide username emojis",
|
"hide_username_emojis": "Hide username emojis",
|
||||||
"hide_username_emojis_description": "Hides emojis from usernames in timelines. Emojis will still be visible in their profiles.",
|
"hide_username_emojis_description": "Hides emojis from usernames in timelines. Emojis will still be visible in their profiles.",
|
||||||
|
@ -574,7 +594,11 @@
|
||||||
},
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"attachments_exceed_server_limit": "The number of attachments exceeded the limit per post.",
|
"attachments_exceed_server_limit": "The number of attachments exceeded the limit per post.",
|
||||||
|
"attachments_limit_audio_error": "Maximum audio size exceeded: {0}",
|
||||||
"attachments_limit_error": "Limit per post exceeded",
|
"attachments_limit_error": "Limit per post exceeded",
|
||||||
|
"attachments_limit_image_error": "Maximum image size exceeded: {0}",
|
||||||
|
"attachments_limit_unknown_error": "Maximum file size exceeded: {0}",
|
||||||
|
"attachments_limit_video_error": "Maximum video size exceeded: {0}",
|
||||||
"edited": "(Edited)",
|
"edited": "(Edited)",
|
||||||
"editing": "Editing",
|
"editing": "Editing",
|
||||||
"loading": "Loading...",
|
"loading": "Loading...",
|
||||||
|
@ -595,6 +619,7 @@
|
||||||
"favourited_by": "Favorited By",
|
"favourited_by": "Favorited By",
|
||||||
"filter_hidden_phrase": "Filtered by",
|
"filter_hidden_phrase": "Filtered by",
|
||||||
"filter_show_anyway": "Show anyway",
|
"filter_show_anyway": "Show anyway",
|
||||||
|
"gif": "GIF",
|
||||||
"img_alt": {
|
"img_alt": {
|
||||||
"ALT": "ALT",
|
"ALT": "ALT",
|
||||||
"desc": "Description",
|
"desc": "Description",
|
||||||
|
|
|
@ -84,6 +84,16 @@
|
||||||
"add_account": "Añadir cuenta a la lista",
|
"add_account": "Añadir cuenta a la lista",
|
||||||
"remove_account": "Quitar cuenta de la lista"
|
"remove_account": "Quitar cuenta de la lista"
|
||||||
},
|
},
|
||||||
|
"magic_keys": {
|
||||||
|
"groups": {
|
||||||
|
"navigation": {
|
||||||
|
"go_to_conversations": "Mensajes directos",
|
||||||
|
"go_to_federated": "Historia federada",
|
||||||
|
"go_to_local": "Historia local",
|
||||||
|
"go_to_settings": "Preferencias"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"block_domain": "Ocultar dominio {0}",
|
"block_domain": "Ocultar dominio {0}",
|
||||||
"delete_and_redraft": "Eliminar y volver a borrador",
|
"delete_and_redraft": "Eliminar y volver a borrador",
|
||||||
|
@ -174,6 +184,9 @@
|
||||||
"label": "Usuarios en línea"
|
"label": "Usuarios en línea"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"state": {
|
||||||
|
"attachments_limit_video_error": "Tamaño máximo de video excedido: {0}"
|
||||||
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"spoiler_show_less": "Menos"
|
"spoiler_show_less": "Menos"
|
||||||
},
|
},
|
||||||
|
|
|
@ -149,7 +149,12 @@
|
||||||
"mute_account": {
|
"mute_account": {
|
||||||
"cancel": "Cancelar",
|
"cancel": "Cancelar",
|
||||||
"confirm": "Silenciar",
|
"confirm": "Silenciar",
|
||||||
|
"days": "días|día|días",
|
||||||
"description": "¿Estás seguro que quieres silenciar a {0}?",
|
"description": "¿Estás seguro que quieres silenciar a {0}?",
|
||||||
|
"hours": "horas|hora|horas",
|
||||||
|
"minute": "minutos|minuto|minutos",
|
||||||
|
"notifications": "Silenciar notificaciones",
|
||||||
|
"specify_duration": "Especificar la duración del silenciado",
|
||||||
"title": "Silenciar cuenta"
|
"title": "Silenciar cuenta"
|
||||||
},
|
},
|
||||||
"show_reblogs": {
|
"show_reblogs": {
|
||||||
|
@ -235,8 +240,18 @@
|
||||||
"title": "Multimedia"
|
"title": "Multimedia"
|
||||||
},
|
},
|
||||||
"navigation": {
|
"navigation": {
|
||||||
|
"go_to_bookmarks": "Marcadores",
|
||||||
|
"go_to_conversations": "Conversaciones",
|
||||||
|
"go_to_explore": "Explorar",
|
||||||
|
"go_to_favourites": "Favoritas",
|
||||||
|
"go_to_federated": "Federados",
|
||||||
"go_to_home": "Inicio",
|
"go_to_home": "Inicio",
|
||||||
|
"go_to_lists": "Listas",
|
||||||
|
"go_to_local": "Local",
|
||||||
"go_to_notifications": "Notificaciones",
|
"go_to_notifications": "Notificaciones",
|
||||||
|
"go_to_profile": "Perfil",
|
||||||
|
"go_to_search": "Buscar",
|
||||||
|
"go_to_settings": "Ajustes",
|
||||||
"next_status": "Siguiente estado",
|
"next_status": "Siguiente estado",
|
||||||
"previous_status": "Anterior estado",
|
"previous_status": "Anterior estado",
|
||||||
"shortcut_help": "Atajo de ayuda",
|
"shortcut_help": "Atajo de ayuda",
|
||||||
|
@ -291,9 +306,11 @@
|
||||||
"built_at": "Compilado {0}",
|
"built_at": "Compilado {0}",
|
||||||
"compose": "Redactar",
|
"compose": "Redactar",
|
||||||
"conversations": "Conversaciones",
|
"conversations": "Conversaciones",
|
||||||
|
"docs": "Documentación",
|
||||||
"explore": "Explorar",
|
"explore": "Explorar",
|
||||||
"favourites": "Favoritas",
|
"favourites": "Favoritas",
|
||||||
"federated": "Federados",
|
"federated": "Federados",
|
||||||
|
"hashtags": "Etiquetas",
|
||||||
"home": "Inicio",
|
"home": "Inicio",
|
||||||
"list": "Lista",
|
"list": "Lista",
|
||||||
"lists": "Listas",
|
"lists": "Listas",
|
||||||
|
@ -443,6 +460,7 @@
|
||||||
},
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"display_language": "Idioma de pantalla",
|
"display_language": "Idioma de pantalla",
|
||||||
|
"how_to_contribute": "¿Cómo contribuir?",
|
||||||
"label": "Idioma",
|
"label": "Idioma",
|
||||||
"post_language": "Idioma de publicación",
|
"post_language": "Idioma de publicación",
|
||||||
"status": "Estado traducción: {0}/{1} ({2}%)",
|
"status": "Estado traducción: {0}/{1} ({2}%)",
|
||||||
|
@ -524,8 +542,10 @@
|
||||||
"hide_boost_count": "Ocultar contador de retoots",
|
"hide_boost_count": "Ocultar contador de retoots",
|
||||||
"hide_favorite_count": "Ocultar número de publicaciones favoritas",
|
"hide_favorite_count": "Ocultar número de publicaciones favoritas",
|
||||||
"hide_follower_count": "Ocultar número de seguidores",
|
"hide_follower_count": "Ocultar número de seguidores",
|
||||||
|
"hide_gif_indi_on_posts": "Ocultar indicador de gif en publicaciones",
|
||||||
"hide_news": "Ocultar noticias",
|
"hide_news": "Ocultar noticias",
|
||||||
"hide_reply_count": "Ocultar número de respuestas",
|
"hide_reply_count": "Ocultar número de respuestas",
|
||||||
|
"hide_tag_hover_card": "Ocultar tarjeta flotante de etiqueta",
|
||||||
"hide_translation": "Ocultar traducción",
|
"hide_translation": "Ocultar traducción",
|
||||||
"hide_username_emojis": "Ocultar emojis en el nombre de usuario",
|
"hide_username_emojis": "Ocultar emojis en el nombre de usuario",
|
||||||
"hide_username_emojis_description": "Oculta los emojis de los nombres de usuarios en la línea de tiempo. Los emojis permanecerán visibles en sus perfiles.",
|
"hide_username_emojis_description": "Oculta los emojis de los nombres de usuarios en la línea de tiempo. Los emojis permanecerán visibles en sus perfiles.",
|
||||||
|
@ -574,7 +594,11 @@
|
||||||
},
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"attachments_exceed_server_limit": "Número máximo de archivos adjuntos por publicación excedido.",
|
"attachments_exceed_server_limit": "Número máximo de archivos adjuntos por publicación excedido.",
|
||||||
|
"attachments_limit_audio_error": "Tamaño máximo de audio excedido: {0}",
|
||||||
"attachments_limit_error": "Límite por publicación excedido",
|
"attachments_limit_error": "Límite por publicación excedido",
|
||||||
|
"attachments_limit_image_error": "Tamaño máximo de imagen excedido: {0}",
|
||||||
|
"attachments_limit_unknown_error": "Tamaño máximo de archivo excedido: {0}",
|
||||||
|
"attachments_limit_video_error": "Tamaño máximo de vídeo excedido: {0}",
|
||||||
"edited": "(Editado)",
|
"edited": "(Editado)",
|
||||||
"editing": "Editando",
|
"editing": "Editando",
|
||||||
"loading": "Cargando...",
|
"loading": "Cargando...",
|
||||||
|
@ -595,6 +619,7 @@
|
||||||
"favourited_by": "Marcado como favorita por",
|
"favourited_by": "Marcado como favorita por",
|
||||||
"filter_hidden_phrase": "Filtrado por",
|
"filter_hidden_phrase": "Filtrado por",
|
||||||
"filter_show_anyway": "Mostrar de todas formas",
|
"filter_show_anyway": "Mostrar de todas formas",
|
||||||
|
"gif": "GIF",
|
||||||
"img_alt": {
|
"img_alt": {
|
||||||
"ALT": "ALT",
|
"ALT": "ALT",
|
||||||
"desc": "Descripción",
|
"desc": "Descripción",
|
||||||
|
@ -691,7 +716,7 @@
|
||||||
"tooltip": {
|
"tooltip": {
|
||||||
"add_content_warning": "Añadir advertencia de contenido",
|
"add_content_warning": "Añadir advertencia de contenido",
|
||||||
"add_emojis": "Agregar emojis",
|
"add_emojis": "Agregar emojis",
|
||||||
"add_media": "Añadir imágenes, video o audio",
|
"add_media": "Añadir imágenes, vídeo o audio",
|
||||||
"add_publishable_content": "Publicar contenido",
|
"add_publishable_content": "Publicar contenido",
|
||||||
"change_content_visibility": "Cambiar visibilidad de contenido",
|
"change_content_visibility": "Cambiar visibilidad de contenido",
|
||||||
"change_language": "Cambiar idioma",
|
"change_language": "Cambiar idioma",
|
||||||
|
|
|
@ -149,7 +149,12 @@
|
||||||
"mute_account": {
|
"mute_account": {
|
||||||
"cancel": "Utzi",
|
"cancel": "Utzi",
|
||||||
"confirm": "Mututu",
|
"confirm": "Mututu",
|
||||||
|
"days": "egun|egun|egun",
|
||||||
"description": "Ziur {0} mututu nahi duzula?",
|
"description": "Ziur {0} mututu nahi duzula?",
|
||||||
|
"hours": "ordu|ordu|ordu",
|
||||||
|
"minute": "minutu|minutu|minutu",
|
||||||
|
"notifications": "Mututu jakinarazpenak",
|
||||||
|
"specify_duration": "Zehaztu mututzearen iraupena",
|
||||||
"title": "Mututu kontua"
|
"title": "Mututu kontua"
|
||||||
},
|
},
|
||||||
"show_reblogs": {
|
"show_reblogs": {
|
||||||
|
@ -228,16 +233,27 @@
|
||||||
"compose": "Idatzi",
|
"compose": "Idatzi",
|
||||||
"favourite": "Egin gogoko",
|
"favourite": "Egin gogoko",
|
||||||
"search": "Bilatu",
|
"search": "Bilatu",
|
||||||
|
"show_new_items": "Erakutsi elementu berriak",
|
||||||
"title": "Ekintzak"
|
"title": "Ekintzak"
|
||||||
},
|
},
|
||||||
"media": {
|
"media": {
|
||||||
"title": "Multimedia"
|
"title": "Multimedia"
|
||||||
},
|
},
|
||||||
"navigation": {
|
"navigation": {
|
||||||
|
"go_to_bookmarks": "Laster-markak",
|
||||||
|
"go_to_conversations": "Elkarrizketak",
|
||||||
|
"go_to_explore": "Arakatu",
|
||||||
|
"go_to_favourites": "Gogokoak",
|
||||||
|
"go_to_federated": "Federatua",
|
||||||
"go_to_home": "Hasiera",
|
"go_to_home": "Hasiera",
|
||||||
|
"go_to_lists": "Zerrendak",
|
||||||
|
"go_to_local": "Lokala",
|
||||||
"go_to_notifications": "Jakinarazpenak",
|
"go_to_notifications": "Jakinarazpenak",
|
||||||
"next_status": "Hurrengo egoera",
|
"go_to_profile": "Profila",
|
||||||
"previous_status": "Aurreko egoera",
|
"go_to_search": "Bilatu",
|
||||||
|
"go_to_settings": "Ezarpenak",
|
||||||
|
"next_status": "Hurrengo bidalketa",
|
||||||
|
"previous_status": "Aurreko bidalketa",
|
||||||
"shortcut_help": "Laster-teklak",
|
"shortcut_help": "Laster-teklak",
|
||||||
"title": "Nabigazioa"
|
"title": "Nabigazioa"
|
||||||
}
|
}
|
||||||
|
@ -293,6 +309,7 @@
|
||||||
"explore": "Arakatu",
|
"explore": "Arakatu",
|
||||||
"favourites": "Gogokoak",
|
"favourites": "Gogokoak",
|
||||||
"federated": "Federatua",
|
"federated": "Federatua",
|
||||||
|
"hashtags": "Traolak",
|
||||||
"home": "Hasiera",
|
"home": "Hasiera",
|
||||||
"list": "Zerrenda",
|
"list": "Zerrenda",
|
||||||
"lists": "Zerrendak",
|
"lists": "Zerrendak",
|
||||||
|
@ -304,22 +321,22 @@
|
||||||
"search": "Bilaketa",
|
"search": "Bilaketa",
|
||||||
"select_feature_flags": "Aldatu ezaugarrien adierazleak (Toggle Feature Flags)",
|
"select_feature_flags": "Aldatu ezaugarrien adierazleak (Toggle Feature Flags)",
|
||||||
"select_font_size": "Letra-tipoaren tamaina",
|
"select_font_size": "Letra-tipoaren tamaina",
|
||||||
"select_language": "Hizkuntza",
|
"select_language": "Interfazearen hizkuntza",
|
||||||
"settings": "Ezarpenak",
|
"settings": "Ezarpenak",
|
||||||
"show_intro": "Erakutsi aurkezpena",
|
"show_intro": "Erakutsi aurkezpena",
|
||||||
"toggle_theme": "Gai argia/iluna",
|
"toggle_theme": "Gai argia/iluna",
|
||||||
"zen_mode": "ZEN modua"
|
"zen_mode": "ZEN modua"
|
||||||
},
|
},
|
||||||
"notification": {
|
"notification": {
|
||||||
"favourited_post": "zure bidalketa gogoko egin du",
|
"favourited_post": "(e)k zure bidalketa gogoko egin du",
|
||||||
"followed_you": "(e)k jarraitu dizu",
|
"followed_you": "(e)k jarraitu dizu",
|
||||||
"followed_you_count": "{0} pertsonak jarraitu dizute|pertsona {0}ek jarraitu dizu|{0} pertsonak jarraitu dizute",
|
"followed_you_count": "{0} pertsonak jarraitu dizute|pertsona {0}ek jarraitu dizu|{0} pertsonak jarraitu dizute",
|
||||||
"missing_type": "MISSING notification.type:",
|
"missing_type": "MISSING notification.type:",
|
||||||
"reblogged_post": "zure bidalketari bultzada eman dio",
|
"reblogged_post": "(e)k zure bidalketari bultzada eman dio",
|
||||||
"reported": "{0}(e)k {1} salatu du",
|
"reported": "{0}(e)k {1} salatu du",
|
||||||
"request_to_follow": "jarraipen-eskaera bidali dizu",
|
"request_to_follow": "(e)k jarraipen-eskaera bidali dizu",
|
||||||
"signed_up": "izena eman du",
|
"signed_up": "(e)k izena eman du",
|
||||||
"update_status": "bidalketa eguneratu du"
|
"update_status": "(e)k bidalketa eguneratu du"
|
||||||
},
|
},
|
||||||
"placeholder": {
|
"placeholder": {
|
||||||
"content_warning": "Idatzi oharra hemen",
|
"content_warning": "Idatzi oharra hemen",
|
||||||
|
@ -374,7 +391,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"report": {
|
"report": {
|
||||||
"additional_comments": "Ohar gehigarriak",
|
"additional_comments": "Iruzkin gehigarriak",
|
||||||
"another_server": "Salatzen ari zaren erabiltzailea beste zerbitzari batekoa da",
|
"another_server": "Salatzen ari zaren erabiltzailea beste zerbitzari batekoa da",
|
||||||
"anything_else": "Ba al dago jakin beharko genukeen beste ezer?",
|
"anything_else": "Ba al dago jakin beharko genukeen beste ezer?",
|
||||||
"block_desc": "Ez duzu erabiltzaile honen bidalketarik ikusiko. Ezin izango ditu zure bidalketak ikusi edo zuri jarraitu. Blokeatu duzula jakingo du.",
|
"block_desc": "Ez duzu erabiltzaile honen bidalketarik ikusiko. Ezin izango ditu zure bidalketak ikusi edo zuri jarraitu. Blokeatu duzula jakingo du.",
|
||||||
|
@ -395,10 +412,10 @@
|
||||||
"limiting": "Mugatu {0}",
|
"limiting": "Mugatu {0}",
|
||||||
"mute_desc": "Ez duzu erabiltzaile honen bidalketarik ikusiko. Zure bidalketak ikusi eta zuri jarraitu diezazuke. Ez du jakingo mututu duzunik.",
|
"mute_desc": "Ez duzu erabiltzaile honen bidalketarik ikusiko. Zure bidalketak ikusi eta zuri jarraitu diezazuke. Ez du jakingo mututu duzunik.",
|
||||||
"other": "Beste zerbait da",
|
"other": "Beste zerbait da",
|
||||||
"other_desc": "Arazoa ez da beste kategorietan sartzen",
|
"other_desc": "Arazoa ez dator bat beste kategoriekin",
|
||||||
"reporting": "{0} salatzen",
|
"reporting": "{0} salatzen",
|
||||||
"select_many": "Hautatu bat datozen guztiak:",
|
"select_many": "Hautatu dagozkion guztiak:",
|
||||||
"select_one": "Aukeratu hobekien datorrena:",
|
"select_one": "Aukeratu hobekien doakiona:",
|
||||||
"select_posts": "Salaketa hau sostengatzen duen bidalketarik al dago?",
|
"select_posts": "Salaketa hau sostengatzen duen bidalketarik al dago?",
|
||||||
"select_posts_other": "Ba al dago salaketa sostengatzen duen beste bidalketarik?",
|
"select_posts_other": "Ba al dago salaketa sostengatzen duen beste bidalketarik?",
|
||||||
"spam": "Spama da",
|
"spam": "Spama da",
|
||||||
|
@ -441,9 +458,10 @@
|
||||||
"theme_color": "Gaiaren kolorea"
|
"theme_color": "Gaiaren kolorea"
|
||||||
},
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"display_language": "Hizkuntza",
|
"display_language": "Interfazearen hizkuntza",
|
||||||
|
"how_to_contribute": "Nola lagun dezaket?",
|
||||||
"label": "Hizkuntza",
|
"label": "Hizkuntza",
|
||||||
"post_language": "Argitalpenaren hizkuntza",
|
"post_language": "Bidalketen hizkuntza",
|
||||||
"status": "Itzulpenaren egoera: {1} kateetatik {0} itzulita (%{2}a)",
|
"status": "Itzulpenaren egoera: {1} kateetatik {0} itzulita (%{2}a)",
|
||||||
"translations": {
|
"translations": {
|
||||||
"add": "Gehitu",
|
"add": "Gehitu",
|
||||||
|
@ -518,13 +536,14 @@
|
||||||
"github_cards": "GitHub txartelak",
|
"github_cards": "GitHub txartelak",
|
||||||
"github_cards_description": "GitHub-eko esteka argitaratzean, HTML txartel irisgarri bat erakusten du gizarte-grafikoaren metadatuak erabiliz, irudi sozialaren ordez.",
|
"github_cards_description": "GitHub-eko esteka argitaratzean, HTML txartel irisgarri bat erakusten du gizarte-grafikoaren metadatuak erabiliz, irudi sozialaren ordez.",
|
||||||
"grayscale_mode": "Gris modua",
|
"grayscale_mode": "Gris modua",
|
||||||
"hide_account_hover_card": "Ezkutatu kontuaren geruza (Hide account hover card)",
|
"hide_account_hover_card": "Ezkutatu kontuen aurrebista-txartelak sagua gainetik pasatzean",
|
||||||
"hide_alt_indi_on_posts": "Ezkutatu ALT adierazlea bidalketetan",
|
"hide_alt_indi_on_posts": "Ezkutatu ALT adierazlea bidalketetan",
|
||||||
"hide_boost_count": "Ezkutatu bultzaden kopurua",
|
"hide_boost_count": "Ezkutatu bultzaden kopurua",
|
||||||
"hide_favorite_count": "Ezkutatu gogokoen kopurua",
|
"hide_favorite_count": "Ezkutatu gogokoen kopurua",
|
||||||
"hide_follower_count": "Ezkutatu jarraitzaile kopurua",
|
"hide_follower_count": "Ezkutatu jarraitzaile kopurua",
|
||||||
"hide_news": "Ezkutatu berriak",
|
"hide_news": "Ezkutatu berriak",
|
||||||
"hide_reply_count": "Ezkutatu erantzunen kopurua",
|
"hide_reply_count": "Ezkutatu erantzunen kopurua",
|
||||||
|
"hide_tag_hover_card": "Ezkutatu traolen aurrebista-txartelak sagua gainetik pasatzean",
|
||||||
"hide_translation": "Ezkutatu itzulpenak",
|
"hide_translation": "Ezkutatu itzulpenak",
|
||||||
"hide_username_emojis": "Ezkutatu emojiak erabiltzaile izenetan",
|
"hide_username_emojis": "Ezkutatu emojiak erabiltzaile izenetan",
|
||||||
"hide_username_emojis_description": "Denbora-lerroetan erabiltzaile izenetako emojiak ezkutatzen ditu. Emojiak ikusgai egoten jarraituko dute euren profiletan.",
|
"hide_username_emojis_description": "Denbora-lerroetan erabiltzaile izenetako emojiak ezkutatzen ditu. Emojiak ikusgai egoten jarraituko dute euren profiletan.",
|
||||||
|
@ -537,7 +556,7 @@
|
||||||
"virtual_scroll": "Korritze birtuala",
|
"virtual_scroll": "Korritze birtuala",
|
||||||
"virtual_scroll_description": "Zerrenda birtual bat erabiltzen du denbora-lerroetan, item kopuru handiagoa modu eraginkorrean erakutsi ahal izateko.",
|
"virtual_scroll_description": "Zerrenda birtual bat erabiltzen du denbora-lerroetan, item kopuru handiagoa modu eraginkorrean erakutsi ahal izateko.",
|
||||||
"wellbeing": "Ongizatea",
|
"wellbeing": "Ongizatea",
|
||||||
"zen_mode": "Zen modua",
|
"zen_mode": "ZEN modua",
|
||||||
"zen_mode_description": "Aldamenetako elementuak ezkutatzen ditu xagua gainean jarri arte. Denbora-lerroko elementu batzuk ere ezkutatzen ditu."
|
"zen_mode_description": "Aldamenetako elementuak ezkutatzen ditu xagua gainean jarri arte. Denbora-lerroko elementu batzuk ere ezkutatzen ditu."
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
|
@ -585,7 +604,7 @@
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"account": {
|
"account": {
|
||||||
"suspended_message": "Argitalpen honen egileari zigorra jarri zaio.",
|
"suspended_message": "Bidalketa honen egileari zigorra jarri zaio.",
|
||||||
"suspended_show": "Erakutsi edukia hala ere?"
|
"suspended_show": "Erakutsi edukia hala ere?"
|
||||||
},
|
},
|
||||||
"boosted_by": "Bultzatu dute:",
|
"boosted_by": "Bultzatu dute:",
|
||||||
|
|
715
locales/fa-IR.json
Normal file
715
locales/fa-IR.json
Normal file
|
@ -0,0 +1,715 @@
|
||||||
|
{
|
||||||
|
"a11y": {
|
||||||
|
"loading_page": "در حال بارگذاری صفحه، لطفا صبر کنید",
|
||||||
|
"loading_titled_page": "در حال بارگذاری صفحه {0}، لطفا صبر کنید",
|
||||||
|
"locale_changed": "زبان به {0} تغییر کرد",
|
||||||
|
"locale_changing": "در حال تغییر زبان، لطفا صبر کنید",
|
||||||
|
"route_loaded": "صفحه {0} بارگذاری شد"
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"authorize": "اجازه دنبال کردن بدهید",
|
||||||
|
"authorized": "شما درخواست را تأیید کردید",
|
||||||
|
"avatar_description": "آواتار {0}",
|
||||||
|
"blocked_by": "شما توسط این کاربر مسدود شدهاید.",
|
||||||
|
"blocked_domains": "دامنههای مسدود شده",
|
||||||
|
"blocked_users": "کاربران مسدود شده",
|
||||||
|
"blocking": "مسدود شده",
|
||||||
|
"bot": "ربات",
|
||||||
|
"copy_account_name": "رونوشت از نام حساب",
|
||||||
|
"favourites": "موارد مورد علاقه",
|
||||||
|
"follow": "دنبال کنید",
|
||||||
|
"follow_back": "دنبال کردن متقابل",
|
||||||
|
"follow_requested": "درخواست شده",
|
||||||
|
"followers": "دنبالکنندگان",
|
||||||
|
"followers_count": "{0} دنبالکننده",
|
||||||
|
"following": "دنبالشده",
|
||||||
|
"following_count": "{0} در حال دنبال کردن",
|
||||||
|
"follows_you": "شما را دنبال میکند",
|
||||||
|
"go_to_profile": "به نمایه بروید",
|
||||||
|
"joined": "پیوسته",
|
||||||
|
"moved_title": "اعلام کرده که این حساب کاربری جدید ایشان است:",
|
||||||
|
"muted_users": "کاربران بیصدا شده",
|
||||||
|
"muting": "بی صدا",
|
||||||
|
"mutuals": "مشترکات",
|
||||||
|
"notifications_on_post_disable": "دیگر هنگامی که {username} فرسته ای ارسال میکند مرا با خبر نکن",
|
||||||
|
"notifications_on_post_enable": "هنگامی که {username} فرسته ای را ارسال میکند مرا با خبر کن",
|
||||||
|
"pinned": "سنجاق شده",
|
||||||
|
"posts": "فرستهها",
|
||||||
|
"posts_count": "{0} فرسته|{0} فرسته|{0} فرسته",
|
||||||
|
"profile_description": "توضیحات بالای صفحه نمایه {0}",
|
||||||
|
"profile_personal_note": "یادداشت شخصی",
|
||||||
|
"profile_unavailable": "نمایه در دسترس نیست",
|
||||||
|
"reject": "رد درخواست",
|
||||||
|
"rejected": "درخواست را رد کردید",
|
||||||
|
"request_follow": "درخواست برای دنبال کردن",
|
||||||
|
"requested": "{0} درخواست دنبال کردن شما را دارد",
|
||||||
|
"unblock": "رفع مسدودیت",
|
||||||
|
"unfollow": "دنبال نکردن",
|
||||||
|
"unmute": "باصدا",
|
||||||
|
"view_other_followers": "دنبالکنندگان از نمونههای دیگر ممکن است نمایش داده نشوند.",
|
||||||
|
"view_other_following": "دنبال شوندگان از نمونههای دیگر ممکن است نمایش داده نشوند.",
|
||||||
|
"withdraw_follow_request": "درخواست دنبالکردن را پس بگیرید"
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"apply": "اعمال",
|
||||||
|
"bookmark": "نشانک",
|
||||||
|
"bookmarked": "نشانک زده شده",
|
||||||
|
"boost": "تقویت",
|
||||||
|
"boost_count": "{0}",
|
||||||
|
"boosted": "تقویت شده",
|
||||||
|
"clear_publish_failed": "پاک کردن خطاهای انتشار",
|
||||||
|
"clear_save_failed": "پاک کردن خطاهای ذخیرهسازی",
|
||||||
|
"clear_upload_failed": "پاک کردن خطاهای بارگذاری فایل",
|
||||||
|
"close": "بستن",
|
||||||
|
"compose": "نوشتن",
|
||||||
|
"confirm": "تایید",
|
||||||
|
"done": "انجام شد",
|
||||||
|
"edit": "ویرایش",
|
||||||
|
"enter_app": "ورود به برنامه",
|
||||||
|
"favourite": "مورد علاقه",
|
||||||
|
"favourite_count": "{0}",
|
||||||
|
"favourited": "به علاقهمندیها افزوده شد",
|
||||||
|
"more": "بیشتر",
|
||||||
|
"next": "بعدی",
|
||||||
|
"prev": "قبلی",
|
||||||
|
"publish": "انتشار",
|
||||||
|
"reply": "پاسخ",
|
||||||
|
"reply_count": "{0}",
|
||||||
|
"reset": "بازنشانی",
|
||||||
|
"save": "ذخیره",
|
||||||
|
"save_changes": "ذخیره تغییرات",
|
||||||
|
"sign_in": "ورود",
|
||||||
|
"sign_in_to": "ورود به {0}",
|
||||||
|
"switch_account": "تغییر حساب کاربری",
|
||||||
|
"vote": "رای"
|
||||||
|
},
|
||||||
|
"app_desc_short": "یک کارخواه وب چابک برای ماستودون",
|
||||||
|
"app_logo": "لوگوی نرمافزار",
|
||||||
|
"app_name": "Elk",
|
||||||
|
"attachment": {
|
||||||
|
"edit_title": "توضیحات",
|
||||||
|
"remove_label": "حذف پیوست"
|
||||||
|
},
|
||||||
|
"command": {
|
||||||
|
"activate": "فعالسازی",
|
||||||
|
"complete": "کامل کردن",
|
||||||
|
"compose_desc": "نوشتن فرسته جدید",
|
||||||
|
"n_people_in_the_past_n_days": "{0} نفر در {1} روز گذشته",
|
||||||
|
"select_lang": "انتخاب زبان",
|
||||||
|
"sign_in_desc": "افزودن حساب کاربری موجود",
|
||||||
|
"switch_account": "تغییر به {0}",
|
||||||
|
"switch_account_desc": "تغییر حساب به حساب دیگری",
|
||||||
|
"toggle_dark_mode": "تغییر حالت تاریک",
|
||||||
|
"toggle_zen_mode": "تغییر حالت آرام"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"end_of_list": "پایان لیست",
|
||||||
|
"error": "خطا",
|
||||||
|
"fetching": "در حال بارگیری...",
|
||||||
|
"in": "در",
|
||||||
|
"no_bookmarks": "هنوز هیچ فرسته نشانه گذاری شده ای وجود ندارد",
|
||||||
|
"no_favourites": "فرسته پسندیده شده ای هنوز وجود ندارد",
|
||||||
|
"not_found": "۴۰۴ پیدا نشد",
|
||||||
|
"offline_desc": "به نظر میرسد شما آفلاین هستید. لطفا اتصال شبکه خود را بررسی کنید."
|
||||||
|
},
|
||||||
|
"confirm": {
|
||||||
|
"block_account": {
|
||||||
|
"cancel": "لغو",
|
||||||
|
"confirm": "مسدود کردن",
|
||||||
|
"title": "آیا از مسدود کردن {0} اطمینان دارید؟"
|
||||||
|
},
|
||||||
|
"block_domain": {
|
||||||
|
"cancel": "لغو",
|
||||||
|
"confirm": "مسدود کردن",
|
||||||
|
"title": "آیا از مسدود کردن دامنه {0} اطمینان دارید؟"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"cancel": "خیر",
|
||||||
|
"confirm": "بله"
|
||||||
|
},
|
||||||
|
"delete_list": {
|
||||||
|
"cancel": "لغو",
|
||||||
|
"confirm": "حذف",
|
||||||
|
"title": "آیا از حذف لیست {0} اطمینان دارید؟"
|
||||||
|
},
|
||||||
|
"delete_posts": {
|
||||||
|
"cancel": "لغو",
|
||||||
|
"confirm": "حذف",
|
||||||
|
"title": "آیا از حذف این فرسته اطمینان دارید؟"
|
||||||
|
},
|
||||||
|
"mute_account": {
|
||||||
|
"cancel": "لغو",
|
||||||
|
"confirm": "بیصدا کردن",
|
||||||
|
"title": "آیا از بیصدا کردن {0} اطمینان دارید؟"
|
||||||
|
},
|
||||||
|
"show_reblogs": {
|
||||||
|
"cancel": "لغو",
|
||||||
|
"confirm": "نمایش",
|
||||||
|
"title": "آیا میخواهید بازنشرها از {0} را نمایش دهید؟"
|
||||||
|
},
|
||||||
|
"unfollow": {
|
||||||
|
"cancel": "لغو",
|
||||||
|
"confirm": "دنبال نکردن",
|
||||||
|
"title": "آیا از دنبال نکردن اطمینان دارید؟"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"conversation": {
|
||||||
|
"with": "با"
|
||||||
|
},
|
||||||
|
"custom_cards": {
|
||||||
|
"stackblitz": {
|
||||||
|
"lines": "خطوط {0}",
|
||||||
|
"open": "باز کردن",
|
||||||
|
"snippet_from": "تکه کد از {0}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"account_not_found": "حساب {0} یافت نشد",
|
||||||
|
"explore_list_empty": "هیچ چیز تازهای وجود ندارد. بعداً بررسی کنید!",
|
||||||
|
"file_size_cannot_exceed_n_mb": "حجم فایل نمیتواند از {0}MB بیشتر باشد",
|
||||||
|
"sign_in_error": "امکان برقراری ارتباط با سرور وجود ندارد.",
|
||||||
|
"status_not_found": "فرسته یافت نشد",
|
||||||
|
"unsupported_file_format": "قالب فایل پشتیبانی نمیشود"
|
||||||
|
},
|
||||||
|
"help": {
|
||||||
|
"build_preview": {
|
||||||
|
"desc1": "شما در حال مشاهده نسخه پیشنمایش جامعه نرمافزار هستید - {0}.",
|
||||||
|
"desc2": "ممکن است شامل تغییرات بررسی نشده یا حتی مخرب باشد.",
|
||||||
|
"desc3": "با حساب کاربری واقعی خود وارد نشوید.",
|
||||||
|
"title": "استقرار پیشنمایش"
|
||||||
|
},
|
||||||
|
"desc_highlight": "انتظار برخی اشکالات و ویژگیهای ناقص را داشته باشید.",
|
||||||
|
"desc_para1": "از علاقه شما به امتحان کردن نرمافزار، کارخواه وب در دست توسعه ماستودون تشکر میکنیم!",
|
||||||
|
"desc_para2": "ما به سختی در حال کار بر روی توسعه و بهبود آن با گذر زمان هستیم.",
|
||||||
|
"desc_para3": "برای تقویت توسعه، میتوانید از طریق GitHub Sponsors از تیم حمایت کنید. امیدواریم از نرمافزار لذت ببرید!",
|
||||||
|
"desc_para4": "نرمافزار یک منبع باز است. اگر دوست دارید در تستکردن، ارائه بازخورد، یا مشارکت کمک کنید،",
|
||||||
|
"desc_para5": "از طریق GitHub با ما تماس بگیرید",
|
||||||
|
"desc_para6": "و مشارکت کنید.",
|
||||||
|
"footer_team": "تیم نرمافزار",
|
||||||
|
"title": "نرمافزار در حالت پیش نمایش است!"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"search": "جستجو"
|
||||||
|
},
|
||||||
|
"list": {
|
||||||
|
"add_account": "اضافه کردن حساب به لیست",
|
||||||
|
"cancel_edit": "لغو ویرایش",
|
||||||
|
"clear_error": "پاک کردن خطا",
|
||||||
|
"create": "ایجاد کردن",
|
||||||
|
"delete": "حذف این لیست",
|
||||||
|
"delete_error": "خطایی هنگام حذف لیست رخ داد",
|
||||||
|
"edit": "ویرایش این لیست",
|
||||||
|
"edit_error": "خطایی هنگام بهروزرسانی لیست رخ داد",
|
||||||
|
"error": "خطایی هنگام ایجاد لیست رخ داد",
|
||||||
|
"error_prefix": "خطا: ",
|
||||||
|
"list_title_placeholder": "عنوان لیست",
|
||||||
|
"modify_account": "تغییر دادن لیستها با حساب کاربری",
|
||||||
|
"remove_account": "حذف حساب از لیست",
|
||||||
|
"save": "ذخیره تغییرات"
|
||||||
|
},
|
||||||
|
"magic_keys": {
|
||||||
|
"dialog_header": "میانبرهای صفحهکلید",
|
||||||
|
"groups": {
|
||||||
|
"actions": {
|
||||||
|
"boost": "تقویت",
|
||||||
|
"command_mode": "حالت فرمان",
|
||||||
|
"compose": "تهیه فرسته",
|
||||||
|
"favourite": "مورد علاقه",
|
||||||
|
"search": "جستجو",
|
||||||
|
"title": "اقدامات"
|
||||||
|
},
|
||||||
|
"media": {
|
||||||
|
"title": "رسانه"
|
||||||
|
},
|
||||||
|
"navigation": {
|
||||||
|
"go_to_home": "خانه",
|
||||||
|
"go_to_notifications": "اعلانها",
|
||||||
|
"next_status": "فرسته بعدی",
|
||||||
|
"previous_status": "فرسته قبلی",
|
||||||
|
"shortcut_help": "راهنمای میانبرها",
|
||||||
|
"title": "ناوبری"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sequence_then": "در ادامه دنباله"
|
||||||
|
},
|
||||||
|
"menu": {
|
||||||
|
"add_personal_note": "افزودن یادداشت شخصی به {0}",
|
||||||
|
"block_account": "مسدود کردن {0}",
|
||||||
|
"block_domain": "مسدود کردن دامنه {0}",
|
||||||
|
"copy_link_to_post": "کپی لینک این فرسته",
|
||||||
|
"copy_original_link_to_post": "کپی لینک اصلی این فرسته",
|
||||||
|
"delete": "حذف",
|
||||||
|
"delete_and_redraft": "حذف و بازنویسی",
|
||||||
|
"direct_message_account": "پیام خصوصی {0}",
|
||||||
|
"edit": "ویرایش",
|
||||||
|
"hide_reblogs": "پنهان کردن بوستها از {0}",
|
||||||
|
"mention_account": "ذکر {0}",
|
||||||
|
"mute_account": "ساکت کردن {0}",
|
||||||
|
"mute_conversation": "ساکت کردن این فرسته",
|
||||||
|
"open_in_original_site": "باز کردن در سایت اصلی",
|
||||||
|
"pin_on_profile": "به نمایه سنجاق کنید",
|
||||||
|
"remove_personal_note": "یادداشت شخصی را از {0} حذف کنید",
|
||||||
|
"report_account": "گزارش {0}",
|
||||||
|
"share_account": "اشتراکگذاری {0}",
|
||||||
|
"share_post": "اشتراکگذاری این فرسته",
|
||||||
|
"show_favourited_and_boosted_by": "نمایش کسانی که پسند و به اشتراک گذاشتهاند",
|
||||||
|
"show_reblogs": "نمایش به اشتراکگذاریها از {0}",
|
||||||
|
"show_untranslated": "نمایش بدون ترجمه",
|
||||||
|
"toggle_theme": {
|
||||||
|
"dark": "حالت تاریک را تغییر دهید",
|
||||||
|
"light": "حالت روشن را تغییر دهید"
|
||||||
|
},
|
||||||
|
"translate_post": "ترجمه فرسته",
|
||||||
|
"unblock_account": "رفع انسداد {0}",
|
||||||
|
"unblock_domain": "رفع انسداد دامنه {0}",
|
||||||
|
"unfollow_account": "دنبال نکردن {0}",
|
||||||
|
"unmute_account": "بیصدا نکردن {0}",
|
||||||
|
"unmute_conversation": "بیصدا نکردن این فرسته",
|
||||||
|
"unpin_on_profile": "از سنجاق خارج کردن در نمایه"
|
||||||
|
},
|
||||||
|
"modals": {
|
||||||
|
"aria_label_close": "بستن"
|
||||||
|
},
|
||||||
|
"nav": {
|
||||||
|
"back": "بازگشت",
|
||||||
|
"blocked_domains": "دامنههای مسدود شده",
|
||||||
|
"blocked_users": "کاربران مسدود شده",
|
||||||
|
"bookmarks": "نشانها",
|
||||||
|
"built_at": "ساخته شده {0}",
|
||||||
|
"compose": "نوشتن",
|
||||||
|
"conversations": "گفتگوها",
|
||||||
|
"explore": "کاوش کنید",
|
||||||
|
"favourites": "موارد مورد علاقه",
|
||||||
|
"federated": "عمومی",
|
||||||
|
"home": "خانه",
|
||||||
|
"list": "لیست",
|
||||||
|
"lists": "لیستها",
|
||||||
|
"local": "محلی",
|
||||||
|
"muted_users": "کاربران با صدای خاموش",
|
||||||
|
"notifications": "اعلانات",
|
||||||
|
"privacy": "حریم خصوصی",
|
||||||
|
"profile": "نمایه",
|
||||||
|
"search": "جستجو",
|
||||||
|
"select_feature_flags": "تغییر ویژگیهای پرچم",
|
||||||
|
"select_font_size": "اندازه قلم",
|
||||||
|
"select_language": "زبان نمایش",
|
||||||
|
"settings": "تنظیمات",
|
||||||
|
"show_intro": "نمایش مقدمه",
|
||||||
|
"toggle_theme": "تغییر تم",
|
||||||
|
"zen_mode": "حالت آرام"
|
||||||
|
},
|
||||||
|
"notification": {
|
||||||
|
"favourited_post": "فرسته شما را پسندید",
|
||||||
|
"followed_you": "شما را دنبال کرد",
|
||||||
|
"followed_you_count": "{0} نفر شما را دنبال کردند|{0} نفر شما را دنبال کرد|{0} نفر شما را دنبال کردند",
|
||||||
|
"missing_type": "اعلان از نوع ناقص:",
|
||||||
|
"reblogged_post": "فرسته شما را باز نشر کرد",
|
||||||
|
"reported": "{0} گزارش داد {1}",
|
||||||
|
"request_to_follow": "درخواست دنبال کردن شما را داد",
|
||||||
|
"signed_up": "ثبت نام کرد",
|
||||||
|
"update_status": "فرسته خود را بهروزرسانی کرد"
|
||||||
|
},
|
||||||
|
"placeholder": {
|
||||||
|
"content_warning": "اخطار خود را اینجا بنویسید",
|
||||||
|
"default_1": "چه فکری میکنید؟",
|
||||||
|
"reply_to_account": "پاسخ به {0}",
|
||||||
|
"replying": "در حال پاسخ دادن"
|
||||||
|
},
|
||||||
|
"polls": {
|
||||||
|
"allow_multiple": "امکان انتخاب چندگزینهای",
|
||||||
|
"cancel": "لغو",
|
||||||
|
"create": "ایجاد نظرسنجی",
|
||||||
|
"disallow_multiple": "عدم امکان انتخاب چندگزینهای",
|
||||||
|
"expiration": "انقضای نظرسنجی",
|
||||||
|
"hide_votes": "مخفی کردن تعداد آرا تا پایان",
|
||||||
|
"option_placeholder": "گزینه نظرسنجی {current}/{max}",
|
||||||
|
"remove_option": "حذف گزینه",
|
||||||
|
"settings": "تنظیمات نظرسنجی",
|
||||||
|
"show_votes": "نمایش دائمی تعداد آرا"
|
||||||
|
},
|
||||||
|
"pwa": {
|
||||||
|
"dismiss": "رد کردن",
|
||||||
|
"install": "نصب کردن",
|
||||||
|
"install_title": "نصب Elk",
|
||||||
|
"screenshots": {
|
||||||
|
"dark": "تصویری از Elk در حالت تیره",
|
||||||
|
"light": "تصویری از Elk در حالت روشن"
|
||||||
|
},
|
||||||
|
"title": "بهروزرسانی جدید Elk موجود است!",
|
||||||
|
"update": "بهروزرسانی",
|
||||||
|
"update_available_short": "بهروزرسانی Elk",
|
||||||
|
"webmanifest": {
|
||||||
|
"canary": {
|
||||||
|
"description": "یک مشتری وب سبک و پیشرفته مستودون (canary)",
|
||||||
|
"name": "Elk (پیشانتشار)",
|
||||||
|
"short_name": "Elk (پیشانتشار)"
|
||||||
|
},
|
||||||
|
"dev": {
|
||||||
|
"description": "یک کارخواه سبک و پیشرفته ماستودون (پیشنمایش)",
|
||||||
|
"name": "Elk (dev)",
|
||||||
|
"short_name": "Elk (dev)"
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"description": "یک کارخواه وب چابک برای ماستودون (پیش نمایش)",
|
||||||
|
"name": "نرمافزار (پیش نمایش)",
|
||||||
|
"short_name": "نرمافزار (پیش نمایش)"
|
||||||
|
},
|
||||||
|
"release": {
|
||||||
|
"description": "یک کارخواه وب چابک برای ماستودون",
|
||||||
|
"name": "نرمافزار",
|
||||||
|
"short_name": "نرمافزار"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"report": {
|
||||||
|
"additional_comments": "نظرات اضافی",
|
||||||
|
"another_server": "کاربری که در حال گزارش آن هستید از سرور دیگری است",
|
||||||
|
"anything_else": "آیا چیز دیگری هست که فکر میکنید ما باید بدانیم؟",
|
||||||
|
"block_desc": "دیگر فرستههای این کاربر را مشاهده نخواهید کرد. آنها نمیتوانند فرستههای شما را ببینند و یا شما را دنبال کنند. آنها قادر خواهند بود درک کنند که مسدود شدهاند.",
|
||||||
|
"dontlike": "من دوست ندارم",
|
||||||
|
"dontlike_desc": "چیزی نیست که مایل به دیدن آن باشید",
|
||||||
|
"forward": "بله، این گزارش را برای {0} ارسال کنید",
|
||||||
|
"forward_question": "آیا میخواهید یک نسخه ناشناس از این گزارش را نیز برای آن سرور ارسال کنید؟",
|
||||||
|
"further_actions": {
|
||||||
|
"limit": {
|
||||||
|
"description": "در اینجا گزینههای شما برای کنترل آنچه میبینید موجود است:",
|
||||||
|
"title": "نمیخواهید این را ببینید؟"
|
||||||
|
},
|
||||||
|
"report": {
|
||||||
|
"description": "در حالی که ما این موضوع را بررسی میکنیم، در اینجا اقداماتی هست که میتوانید انجام دهید:",
|
||||||
|
"title": "از گزارش شما متشکریم، ما به آن رسیدگی خواهیم کرد."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"limiting": "محدود کردن {0}",
|
||||||
|
"mute_desc": "دیگر هیچ فرستهی از این کاربر را نخواهید دید. آنها همچنان میتوانند شما را دنبال کنند و فرستههای شما را ببینند. آنها متوجه بیصدا شدن نخواهند شد.",
|
||||||
|
"other": "مورد دیگری است",
|
||||||
|
"other_desc": "مشکلی که مطرح شده در دستهبندیهای دیگر نمیگنجد",
|
||||||
|
"reporting": "گزارش {0}",
|
||||||
|
"select_many": "تمام موارد مرتبط را انتخاب کنید:",
|
||||||
|
"select_one": "بهترین تطابق را انتخاب کنید:",
|
||||||
|
"select_posts": "آیا فرستههایی وجود دارد که این گزارش را پشتیبانی میکند؟",
|
||||||
|
"select_posts_other": "آیا فرستههای دیگری وجود دارد که این گزارش را پشتیبانی میکند؟",
|
||||||
|
"spam": "هرزنامه است",
|
||||||
|
"spam_desc": "پیوندهای مخرب، تعاملات تقلبی، یا پاسخهای تکراری",
|
||||||
|
"submit": "ارسال گزارش",
|
||||||
|
"unfollow_desc": "دیگر فرستههای این کاربر را در فید خانگی خود نخواهید دید. ممکن است در جاهای دیگر فرستههای آنها را ببینید.",
|
||||||
|
"violation": "یک یا چند قوانین سرور را نقض میکند",
|
||||||
|
"whats_wrong_account": "بگویید چه مشکلی با این حساب کاربری وجود دارد",
|
||||||
|
"whats_wrong_post": "بگویید چه مشکلی با این فرسته وجود دارد"
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"search_desc": "جستجوی افراد و برچسبها",
|
||||||
|
"search_empty": "هیچ موردی برای اصطلاحات جستجو شده پیدا نشد"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"about": {
|
||||||
|
"built_at": "ساخته شده در",
|
||||||
|
"label": "درباره",
|
||||||
|
"meet_the_team": "آشنایی با تیم",
|
||||||
|
"sponsor_action": "حمایت از ما",
|
||||||
|
"sponsor_action_desc": "برای حمایت از تیم توسعهدهنده Elk,",
|
||||||
|
"sponsors": "حامیان",
|
||||||
|
"sponsors_body_1": "Elk با حمایت سخاوتمندانه و کمک های:",
|
||||||
|
"sponsors_body_2": "و تمام شرکتها و افرادی که از تیم Elk و اعضاء آن حمایت میکنند، امکانپذیر شده است.",
|
||||||
|
"sponsors_body_3": "اگر از برنامه لذت میبرید، لطفا از ما حمایت کنید:",
|
||||||
|
"version": "نسخه"
|
||||||
|
},
|
||||||
|
"account_settings": {
|
||||||
|
"description": "تنظیمات حساب کاربری خود را در رابط کاربری ماستودون ویرایش کنید",
|
||||||
|
"label": "تنظیمات حساب کاربری"
|
||||||
|
},
|
||||||
|
"interface": {
|
||||||
|
"color_mode": "حالت رنگ",
|
||||||
|
"dark_mode": "تاریک",
|
||||||
|
"default": " (پیشفرض)",
|
||||||
|
"font_size": "اندازه فونت",
|
||||||
|
"label": "رابط کاربری",
|
||||||
|
"light_mode": "روشن",
|
||||||
|
"system_mode": "سیستم",
|
||||||
|
"theme_color": "رنگ تم"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"display_language": "زبان نمایش",
|
||||||
|
"label": "زبان",
|
||||||
|
"post_language": "زبان ارسال",
|
||||||
|
"status": "وضعیت ترجمه: {0}/{1} ({2}٪)",
|
||||||
|
"translations": {
|
||||||
|
"add": "اضافه کردن",
|
||||||
|
"choose_language": "انتخاب زبان",
|
||||||
|
"heading": "ترجمهها",
|
||||||
|
"hide_specific": "پنهان کردن ترجمههای خاص",
|
||||||
|
"remove": "حذف کردن"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"label": "اعلانها",
|
||||||
|
"notifications": {
|
||||||
|
"label": "تنظیمات اعلانها"
|
||||||
|
},
|
||||||
|
"push_notifications": {
|
||||||
|
"alerts": {
|
||||||
|
"favourite": "مورد علاقهها",
|
||||||
|
"follow": "دنبالکنندگان جدید",
|
||||||
|
"mention": "اشارهها",
|
||||||
|
"poll": "نظرسنجیها",
|
||||||
|
"reblog": "انتشارات",
|
||||||
|
"title": "کدام اعلانها را دریافت کنیم؟"
|
||||||
|
},
|
||||||
|
"description": "اعلانها را حتی زمانی که از Elk استفاده نمیکنید دریافت کنید.",
|
||||||
|
"instructions": "فراموش نکنید که تغییرات خود را با استفاده از دکمه ذخیره تنظیمات اعلانهای سریع بالا ذخیره کنید!",
|
||||||
|
"label": "تنظیمات اعلانهای سریع",
|
||||||
|
"policy": {
|
||||||
|
"all": "از همه",
|
||||||
|
"followed": "از افرادی که دنبال میکنم",
|
||||||
|
"follower": "از افرادی که من را دنبال میکنند",
|
||||||
|
"none": "از هیچکس",
|
||||||
|
"title": "از چه کسی میتوانم اعلانها را دریافت کنم؟"
|
||||||
|
},
|
||||||
|
"save_settings": "ذخیره تنظیمات",
|
||||||
|
"subscription_error": {
|
||||||
|
"clear_error": "پاک کردن خطا",
|
||||||
|
"error_hint": "میتوانید به لیست سوالات متداول مراجعه کنید تا مشکل را حل کنید: {0}.",
|
||||||
|
"invalid_vapid_key": "کلید عمومی VAPID به نظر نامعتبر است.",
|
||||||
|
"permission_denied": "اجازه دسترسی رد شد: اعلانها را در مرورگر خود فعال کنید.",
|
||||||
|
"repo_link": "مخزن Elk در گیتهاب",
|
||||||
|
"request_error": "هنگام درخواست اشتراکگذاری خطایی رخ داد، دوباره تلاش کنید و اگر مشکل ادامه یافت، لطفاً موضوع را در مخزن Elk گزارش دهید.",
|
||||||
|
"title": "توانایی اشتراکگذاری در اعلانهای سریع وجود ندارد",
|
||||||
|
"too_many_registrations": "به دلیل محدودیتهای مرورگر، Elk نمیتواند از سرویس اعلانهای سریع برای حسابهای متعدد در سرورهای مختلف استفاده کند. باید از اعلانهای سریع در یک حساب دیگر لغو اشتراک کنید و دوباره تلاش کنید.",
|
||||||
|
"vapid_not_supported": "مرورگر شما از اعلانهای وب پشتیبانی میکند، اما به نظر میرسد پروتکل VAPID را پیادهسازی نمیکند."
|
||||||
|
},
|
||||||
|
"title": "تنظیمات اعلانهای سریع",
|
||||||
|
"undo_settings": "لغو تغییرات",
|
||||||
|
"unsubscribe": "غیرفعال کردن اعلانهای سریع",
|
||||||
|
"unsupported": "مرورگر شما از اعلانهای سریع پشتیبانی نمیکند.",
|
||||||
|
"warning": {
|
||||||
|
"enable_close": "بستن",
|
||||||
|
"enable_description": "برای دریافت اعلانها وقتی Elk باز نیست، اعلانهای سریع را فعال کنید. شما میتوانید دقیقاً کنترل کنید که چه نوع تعاملاتی اعلانهای سریع ایجاد کند از طریق دکمه فوق که بعد از فعالسازی نشان داده میشود.",
|
||||||
|
"enable_description_desktop": "برای دریافت اعلانها وقتی Elk باز نیست، اعلانهای سریع را فعال کنید. شما میتوانید دقیقاً کنترل کنید که چه نوع تعاملاتی اعلانهای سریع ایجاد کند در تنظیمات > اعلانها > تنظیمات اعلانهای سریع پس از فعالسازی.",
|
||||||
|
"enable_description_mobile": "همچنین میتوانید از منوی ناوبری به تنظیمات > اعلانها > تنظیمات اعلانهای سریع دسترسی پیدا کنید.",
|
||||||
|
"enable_description_settings": "برای دریافت اعلانها وقتی Elk باز نیست، اعلانهای سریع را فعال کنید. شما خواهید توانست دقیقاً کنترل کنید که چه نوع تعاملاتی اعلانهای سریع ایجاد کند در همین صفحه پس از فعالسازی آنها.",
|
||||||
|
"enable_desktop": "فعالسازی اعلانهای سریع",
|
||||||
|
"enable_title": "هیچچیزی را از دست ندهید",
|
||||||
|
"re_auth": "به نظر میرسد سرور شما از اعلانهای سریع پشتیبانی نمیکند. خروج و ورود مجدد را امتحان کنید، اگر این پیام همچنان ظاهر شد با مدیر سرور خود تماس بگیرید."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"show_btn": "رفتن به تنظیمات اعلانها",
|
||||||
|
"under_construction": "در دست ساخت"
|
||||||
|
},
|
||||||
|
"notifications_settings": "اعلانها",
|
||||||
|
"preferences": {
|
||||||
|
"embedded_media": "پخشکننده رسانه توکار",
|
||||||
|
"embedded_media_description": "نمایش یک پخشکننده توکار به جای کارت پیشنمایش معمولی هنگام گسترش پیوندهای رسانهای به اشتراک گذاشته شده.",
|
||||||
|
"enable_autoplay": "فعالسازی خودکارپخش",
|
||||||
|
"enable_data_saving": "فعالسازی صرفهجویی در مصرف داده",
|
||||||
|
"enable_data_saving_description": "صرفهجویی در دادهها با جلوگیری از بارگذاری خودکار پیوستها.",
|
||||||
|
"enable_pinch_to_zoom": "فعالسازی بزرگنمایی با دو انگشت",
|
||||||
|
"github_cards": "کارتهای گیتهاب",
|
||||||
|
"github_cards_description": "هنگام ارسال پیوند گیتهاب، یک کارت HTML قابل دسترس با استفاده از نمایش شبکههای اجتماعی به نمایش درمیآید به جای تصویر اجتماعی.",
|
||||||
|
"grayscale_mode": "حالت خاکستری",
|
||||||
|
"hide_account_hover_card": "پنهان کردن کارت شناور حساب",
|
||||||
|
"hide_alt_indi_on_posts": "پنهان کردن نشانگر جایگزین در فرستهها",
|
||||||
|
"hide_boost_count": "پنهان کردن شمارش انتشارات",
|
||||||
|
"hide_favorite_count": "پنهان کردن شمارش موردهای علاقهمندی",
|
||||||
|
"hide_follower_count": "پنهان کردن شمارش دنبالکنندگان و دنبالشوندگان",
|
||||||
|
"hide_news": "پنهان کردن خبرها",
|
||||||
|
"hide_reply_count": "پنهان کردن شمارش پاسخها",
|
||||||
|
"hide_translation": "پنهان کردن ترجمه",
|
||||||
|
"hide_username_emojis": "پنهان کردن اموجیهای نام کاربری",
|
||||||
|
"hide_username_emojis_description": "پنهان کردن اموجیها از نامهای کاربری در زمان خطوط. اموجیها هنوز در نمایههای آنها قابل مشاهده خواهند بود.",
|
||||||
|
"label": "ترجیحات",
|
||||||
|
"title": "ویژگیهای تجربی",
|
||||||
|
"use_star_favorite_icon": "استفاده از نماد ستاره موردهای علاقهمندی",
|
||||||
|
"user_picker": "انتخابکننده کاربر",
|
||||||
|
"user_picker_description": "نمایش تمام آواتارهای حسابهای ورود شده در پایین-چپ تا شما بتوانید به سرعت بین آنها تعویض کنید.",
|
||||||
|
"virtual_scroll": "پیمایش مجازی",
|
||||||
|
"virtual_scroll_description": "استفاده از لیست مجازی در خطوط زمانی، برای نمایش تعداد بیشتری آیتم با عملکرد بهتر.",
|
||||||
|
"wellbeing": "سلامتی",
|
||||||
|
"zen_mode": "حالت آرامش",
|
||||||
|
"zen_mode_description": "پنهان سازی حواشی مگر آنکه نشانگر موس روی آنها باشد. همچنین پنهانسازی بعضی المانها از خط زمانی."
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"appearance": {
|
||||||
|
"bio": "بیوگرافی",
|
||||||
|
"description": "ویرایش آواتار، نام کاربری، نمایه و غیره.",
|
||||||
|
"display_name": "نام نمایشی",
|
||||||
|
"label": "ظاهر",
|
||||||
|
"profile_metadata": "توضیحات نمایه",
|
||||||
|
"profile_metadata_desc": "شما میتوانید تا {0} مورد را به صورت جدول در نمایه خود نمایش دهید",
|
||||||
|
"profile_metadata_label": "برچسب",
|
||||||
|
"profile_metadata_value": "محتوا",
|
||||||
|
"title": "ویرایش نمایه"
|
||||||
|
},
|
||||||
|
"featured_tags": {
|
||||||
|
"description": "افراد میتوانند فرستههای عمومی شما را زیر این برچسبها مرور کنند.",
|
||||||
|
"label": "برچسبهای برجسته",
|
||||||
|
"under_construction": "در دست ساخت"
|
||||||
|
},
|
||||||
|
"label": "نمایه"
|
||||||
|
},
|
||||||
|
"select_a_settings": "یک تنظیم را انتخاب کنید",
|
||||||
|
"users": {
|
||||||
|
"export": "صادر کردن توکنهای کاربر",
|
||||||
|
"import": "وارد کردن توکنهای کاربر",
|
||||||
|
"label": "کاربران وارد شده"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"share_target": {
|
||||||
|
"description": "نرمافزار را میتوانید طوری پیکربندی کنید که از سایر برنامهها محتوا را به اشتراک بگذارید، تنها کافیست نرمافزار را روی دستگاه یا کامپیوتر خود نصب کرده و وارد شوید.",
|
||||||
|
"hint": "برای به اشتراک گذاشتن محتوا با نرمافزار، باید نرمافزار نصب شده باشد و شما وارد حساب کاربری خود شده باشید.",
|
||||||
|
"title": "به اشتراک گذاشتن با نرمافزار"
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"attachments_exceed_server_limit": "تعداد پیوستها از حد مجاز هر فرسته تجاوز کرده است.",
|
||||||
|
"attachments_limit_error": "حد مجاز فرسته تجاوز شده",
|
||||||
|
"edited": "(ویرایش شده)",
|
||||||
|
"editing": "در حال ویرایش",
|
||||||
|
"loading": "در حال بارگذاری...",
|
||||||
|
"publish_failed": "انتشار ناموفق بود",
|
||||||
|
"publishing": "در حال انتشار",
|
||||||
|
"save_failed": "ذخیره ناموفق بود",
|
||||||
|
"upload_failed": "بارگذاری ناموفق بود",
|
||||||
|
"uploading": "در حال بارگذاری..."
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"account": {
|
||||||
|
"suspended_message": "حساب کاربری این فرسته تعلیق شده است.",
|
||||||
|
"suspended_show": "با این حال محتوا را نشان دهم؟"
|
||||||
|
},
|
||||||
|
"boosted_by": "تقویت شده توسط",
|
||||||
|
"edited": "ویرایش شده {0}",
|
||||||
|
"embedded_warning": "پخش این ممکن است آدرس IP شما را برای دیگران آشکار کند.",
|
||||||
|
"favourited_by": "مورد علاقه توسط",
|
||||||
|
"filter_hidden_phrase": "مخفی شده توسط فیلتر",
|
||||||
|
"filter_show_anyway": "با این حال نشان بده",
|
||||||
|
"img_alt": {
|
||||||
|
"ALT": "ALT",
|
||||||
|
"desc": "توصیف",
|
||||||
|
"dismiss": "رد کردن",
|
||||||
|
"read": "خواندن توصیف {0}"
|
||||||
|
},
|
||||||
|
"poll": {
|
||||||
|
"count": "{0} رای|{0} رای|{0} رای",
|
||||||
|
"ends": "پایان {0}",
|
||||||
|
"finished": "به پایان رسید {0}"
|
||||||
|
},
|
||||||
|
"replying_to": "در پاسخ به {0}",
|
||||||
|
"show_full_thread": "نمایش کامل رشته",
|
||||||
|
"someone": "یک نفر",
|
||||||
|
"spoiler_media_hidden": "رسانه مخفی شده",
|
||||||
|
"spoiler_show_less": "نمایش کمتر",
|
||||||
|
"spoiler_show_more": "نمایش بیشتر",
|
||||||
|
"thread": "رشته",
|
||||||
|
"try_original_site": "سایت اصلی را امتحان کنید"
|
||||||
|
},
|
||||||
|
"status_history": {
|
||||||
|
"created": "ایجاد شده {0}",
|
||||||
|
"edited": "ویرایش شده {0}"
|
||||||
|
},
|
||||||
|
"tab": {
|
||||||
|
"accounts": "حسابها",
|
||||||
|
"for_you": "برای شما",
|
||||||
|
"hashtags": "برچسبها",
|
||||||
|
"list": "لیست",
|
||||||
|
"media": "رسانه",
|
||||||
|
"news": "اخبار",
|
||||||
|
"notifications_admin": {
|
||||||
|
"report": "گزارش",
|
||||||
|
"sign_up": "ثبت نام"
|
||||||
|
},
|
||||||
|
"notifications_all": "همه",
|
||||||
|
"notifications_favourite": "مورد علاقه",
|
||||||
|
"notifications_follow": "دنبال کردن",
|
||||||
|
"notifications_follow_request": "درخواست دنبال کردن",
|
||||||
|
"notifications_mention": "اشاره",
|
||||||
|
"notifications_more_tooltip": "نوع اعلانها را بر اساس نوع فیلتر کنید",
|
||||||
|
"notifications_poll": "نظرسنجی",
|
||||||
|
"notifications_reblog": "بازنشر",
|
||||||
|
"notifications_status": "وضعیت",
|
||||||
|
"notifications_update": "بروزرسانی",
|
||||||
|
"posts": "فرستهها",
|
||||||
|
"posts_with_replies": "فرستهها و پاسخها"
|
||||||
|
},
|
||||||
|
"tag": {
|
||||||
|
"follow": "دنبال کردن",
|
||||||
|
"follow_label": "دنبال کردن برچسب {0}",
|
||||||
|
"unfollow": "انصراف از دنبال کردن",
|
||||||
|
"unfollow_label": "انصراف از دنبال کردن برچسب {0}"
|
||||||
|
},
|
||||||
|
"time_ago_options": {
|
||||||
|
"day_future": "در 0 روز|فردا|در {n} روز",
|
||||||
|
"day_past": "0 روز پیش|دیروز|{n} روز پیش",
|
||||||
|
"hour_future": "در 0 ساعت|در 1 ساعت|در {n} ساعت",
|
||||||
|
"hour_past": "0 ساعت پیش|1 ساعت پیش|{n} ساعت پیش",
|
||||||
|
"just_now": "همین الان",
|
||||||
|
"minute_future": "در 0 دقیقه|در 1 دقیقه|در {n} دقیقه",
|
||||||
|
"minute_past": "0 دقیقه پیش|1 دقیقه پیش|{n} دقیقه پیش",
|
||||||
|
"month_future": "در 0 ماه|ماه بعد|در {n} ماه",
|
||||||
|
"month_past": "0 ماه پیش|ماه گذشته|{n} ماه پیش",
|
||||||
|
"second_future": "همین الان|در {n} ثانیه|در {n} ثانیه",
|
||||||
|
"second_past": "همین الان|{n} ثانیه پیش|{n} ثانیه پیش",
|
||||||
|
"short_day_future": "در {n}روز",
|
||||||
|
"short_day_past": "{n}روز",
|
||||||
|
"short_hour_future": "در {n}س",
|
||||||
|
"short_hour_past": "{n}س",
|
||||||
|
"short_minute_future": "در {n}دقیقه",
|
||||||
|
"short_minute_past": "{n}دقیقه",
|
||||||
|
"short_month_future": "در {n}م",
|
||||||
|
"short_month_past": "{n}م",
|
||||||
|
"short_second_future": "در {n}ث",
|
||||||
|
"short_second_past": "{n}ث",
|
||||||
|
"short_week_future": "در {n}هفته",
|
||||||
|
"short_week_past": "{n}هفته",
|
||||||
|
"short_year_future": "در {n}سال",
|
||||||
|
"short_year_past": "{n}سال",
|
||||||
|
"week_future": "در 0 هفته|هفته بعد|در {n} هفته",
|
||||||
|
"week_past": "0 هفته پیش|هفته گذشته|{n} هفته پیش",
|
||||||
|
"year_future": "در 0 سال|سال بعد|در {n} سال",
|
||||||
|
"year_past": "0 سال پیش|سال گذشته|{n} سال پیش"
|
||||||
|
},
|
||||||
|
"timeline": {
|
||||||
|
"show_new_items": "نمایش {v} مورد جدید|نمایش {v} مورد جدید|نمایش {v} مورد جدید",
|
||||||
|
"view_older_posts": "فرستههای قدیمیتر از دیگر موارد ممکن است نمایش داده نشوند."
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"federated_timeline": "جریان اتحادی",
|
||||||
|
"local_timeline": "جریان محلی"
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"add_content_warning": "اضافه کردن هشدار محتوا",
|
||||||
|
"add_emojis": "اضافه کردن شکلکها",
|
||||||
|
"add_media": "اضافه کردن تصاویر، ویدیو یا فایل صوتی",
|
||||||
|
"add_publishable_content": "اضافه کردن محتوای قابل انتشار",
|
||||||
|
"change_content_visibility": "تغییر دیدهبانی محتوا",
|
||||||
|
"change_language": "تغییر زبان",
|
||||||
|
"emoji": "شکلک",
|
||||||
|
"explore_links_intro": "این داستانهای خبری، در حال حاضر توسط افراد در این و دیگر نمونههای شبکه غیرمتمرکز مورد بحث قرار میگیرد.",
|
||||||
|
"explore_posts_intro": "این فرستهها از این و دیگر نمونههای در شبکه غیرمتمرکز هم اکنون در این سرور محبوبیت دارند.",
|
||||||
|
"explore_tags_intro": "این برچسبها در حال حاضر میان افراد در این و دیگر سرورهای شبکه غیرمتمرکز مشهور شدهاند.",
|
||||||
|
"open_editor_tools": "ابزار ویراستار",
|
||||||
|
"pick_an_icon": "انتخاب یک آیکون",
|
||||||
|
"publish_failed": "پیامهای ناموفق را در بالای ویرایشگر ببندید تا مجدد فرستهها را انتشار دهید",
|
||||||
|
"toggle_bold": "تغییر به حالت توپر",
|
||||||
|
"toggle_code_block": "تغییر به بلوک کد",
|
||||||
|
"toggle_italic": "تغییر به حالت کج"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"add_existing": "اضافه کردن حساب کاربری موجود",
|
||||||
|
"server_address_label": "آدرس سرور ماستودون",
|
||||||
|
"sign_in_desc": "برای دنبال کردن نمایهها یا برچسبها، پسندیدن، به اشتراکگذاری و پاسخ دادن به فرستهها وارد شوید، یا از حساب کاربری خود در سرور دیگر ارتباط برقرار کنید.",
|
||||||
|
"sign_in_notice_title": "مشاهده دادههای عمومی {0}",
|
||||||
|
"sign_out_account": "خروج از حساب کاربری {0}",
|
||||||
|
"single_instance_sign_in_desc": "برای دنبال کردن نمایهها یا برچسبها، پسندیدن، به اشتراکگذاری و پاسخ دادن به فرستهها وارد شوید.",
|
||||||
|
"tip_no_account": "اگر هنوز حساب کاربری ماستودون ندارید، {0}.",
|
||||||
|
"tip_register_account": "سرور خود را انتخاب کرده و یکی بسازید"
|
||||||
|
},
|
||||||
|
"visibility": {
|
||||||
|
"direct": "مستقیم",
|
||||||
|
"direct_desc": "فقط برای کاربران منشنشده قابل مشاهده",
|
||||||
|
"private": "فقط دنبالکنندگان",
|
||||||
|
"private_desc": "فقط برای دنبالکنندگان قابل مشاهده",
|
||||||
|
"public": "عمومی",
|
||||||
|
"public_desc": "برای همه قابل مشاهده",
|
||||||
|
"unlisted": "فهرست نشده",
|
||||||
|
"unlisted_desc": "برای همه قابل مشاهده اما از ویژگیهای کشف خارج شدهاست"
|
||||||
|
}
|
||||||
|
}
|
|
@ -214,8 +214,7 @@
|
||||||
"command_mode": "Mode commande",
|
"command_mode": "Mode commande",
|
||||||
"compose": "Composer",
|
"compose": "Composer",
|
||||||
"favourite": "J'aime",
|
"favourite": "J'aime",
|
||||||
"title": "Actions",
|
"title": "Actions"
|
||||||
"zen_mode": "Mode Zen"
|
|
||||||
},
|
},
|
||||||
"media": {
|
"media": {
|
||||||
"title": "Média"
|
"title": "Média"
|
||||||
|
@ -550,9 +549,6 @@
|
||||||
"label": "Comptes connectés"
|
"label": "Comptes connectés"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"share-target": {
|
|
||||||
"title": ""
|
|
||||||
},
|
|
||||||
"share_target": {
|
"share_target": {
|
||||||
"description": "Elk peut être configuré pour que vous puissiez partager du contenu à partir d'autres applications, installez simplement Elk sur votre appareil ou ordinateur et connectez-vous.",
|
"description": "Elk peut être configuré pour que vous puissiez partager du contenu à partir d'autres applications, installez simplement Elk sur votre appareil ou ordinateur et connectez-vous.",
|
||||||
"hint": "Pour partager du contenu avec Elk, Elk doit être installé et vous devez être connecté.",
|
"hint": "Pour partager du contenu avec Elk, Elk doit être installé et vous devez être connecté.",
|
||||||
|
@ -605,7 +601,6 @@
|
||||||
"edited": "a édité {0}"
|
"edited": "a édité {0}"
|
||||||
},
|
},
|
||||||
"tab": {
|
"tab": {
|
||||||
"account": "Compte",
|
|
||||||
"accounts": "Comptes",
|
"accounts": "Comptes",
|
||||||
"for_you": "Pour vous",
|
"for_you": "Pour vous",
|
||||||
"hashtags": "Hashtags",
|
"hashtags": "Hashtags",
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
"follows_you": "Követ téged",
|
"follows_you": "Követ téged",
|
||||||
"go_to_profile": "Ugrás a profilhoz",
|
"go_to_profile": "Ugrás a profilhoz",
|
||||||
"joined": "Csatlakozott",
|
"joined": "Csatlakozott",
|
||||||
|
"lock": "Zárolt",
|
||||||
"moved_title": "jelezte, hogy az új fiók mostantól:",
|
"moved_title": "jelezte, hogy az új fiók mostantól:",
|
||||||
"muted_users": "Némított felhasználók",
|
"muted_users": "Némított felhasználók",
|
||||||
"muting": "Némított",
|
"muting": "Némított",
|
||||||
|
@ -79,7 +80,7 @@
|
||||||
"save": "Ment",
|
"save": "Ment",
|
||||||
"save_changes": "Változások mentése",
|
"save_changes": "Változások mentése",
|
||||||
"sign_in": "Bejelentkezés",
|
"sign_in": "Bejelentkezés",
|
||||||
"sign_in_to": "Bejelentkezés: {0}",
|
"sign_in_to": "Bejelentkezve: {0}",
|
||||||
"switch_account": "Fiók váltás",
|
"switch_account": "Fiók váltás",
|
||||||
"vote": "Szavazás"
|
"vote": "Szavazás"
|
||||||
},
|
},
|
||||||
|
@ -94,7 +95,7 @@
|
||||||
"activate": "Aktivál",
|
"activate": "Aktivál",
|
||||||
"complete": "Befejez",
|
"complete": "Befejez",
|
||||||
"compose_desc": "Új bejegyzés írása",
|
"compose_desc": "Új bejegyzés írása",
|
||||||
"n-people-in-the-past-n-days": "{0} felhasználó az elmúlt {1} napban",
|
"n_people_in_the_past_n_days": "{0} ember az elmúlt {1} napban",
|
||||||
"select_lang": "Nyelv kiválasztása",
|
"select_lang": "Nyelv kiválasztása",
|
||||||
"sign_in_desc": "Létező fiók hozzáadása",
|
"sign_in_desc": "Létező fiók hozzáadása",
|
||||||
"switch_account": "Váltás: {0}",
|
"switch_account": "Váltás: {0}",
|
||||||
|
@ -120,12 +121,14 @@
|
||||||
"block_account": {
|
"block_account": {
|
||||||
"cancel": "Mégsem",
|
"cancel": "Mégsem",
|
||||||
"confirm": "Blokkol",
|
"confirm": "Blokkol",
|
||||||
"description": "Biztosan blokkolja? {0}"
|
"description": "Biztosan blokkolja? {0}",
|
||||||
|
"title": "Hozzáférés blokkolása"
|
||||||
},
|
},
|
||||||
"block_domain": {
|
"block_domain": {
|
||||||
"cancel": "Mégsem",
|
"cancel": "Mégsem",
|
||||||
"confirm": "Blokkol",
|
"confirm": "Blokkol",
|
||||||
"description": "Biztosan blokkolja? {0}"
|
"description": "Biztosan blokkolja? {0}",
|
||||||
|
"title": "Domain blokkolása"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"cancel": "Mégsem",
|
"cancel": "Mégsem",
|
||||||
|
@ -134,27 +137,37 @@
|
||||||
"delete_list": {
|
"delete_list": {
|
||||||
"cancel": "Mégsem",
|
"cancel": "Mégsem",
|
||||||
"confirm": "Töröl",
|
"confirm": "Töröl",
|
||||||
"description": "Biztosan törli a listát? \"{0}\""
|
"description": "Biztosan törli a listát? \"{0}\"",
|
||||||
|
"title": "Lista törlése"
|
||||||
},
|
},
|
||||||
"delete_posts": {
|
"delete_posts": {
|
||||||
"cancel": "Mégsem",
|
"cancel": "Mégsem",
|
||||||
"confirm": "Töröl",
|
"confirm": "Töröl",
|
||||||
"description": "Biztosan törli a bejegyzést?"
|
"description": "Biztosan törli a bejegyzést?",
|
||||||
|
"title": "Bejegyzés törlése"
|
||||||
},
|
},
|
||||||
"mute_account": {
|
"mute_account": {
|
||||||
"cancel": "Mégsem",
|
"cancel": "Mégsem",
|
||||||
"confirm": "Némít",
|
"confirm": "Némít",
|
||||||
"description": "Biztosan némítja? {0}"
|
"days": "napok|nap|napok",
|
||||||
|
"description": "Biztosan némítja? {0}",
|
||||||
|
"hours": "órák|óra|órák",
|
||||||
|
"minute": "perc|perc|perc",
|
||||||
|
"notifications": "Értesítések némítása",
|
||||||
|
"specify_duration": "Határozzon meg némítási időtartamot",
|
||||||
|
"title": "Hozzáférés némítása"
|
||||||
},
|
},
|
||||||
"show_reblogs": {
|
"show_reblogs": {
|
||||||
"cancel": "Mégsem",
|
"cancel": "Mégsem",
|
||||||
"confirm": "Mutat",
|
"confirm": "Mutat",
|
||||||
"description": "Biztosan megjeleníti a Turbót tőle? {0}"
|
"description": "Biztosan megjeleníti a Kiemelést tőle? {0}",
|
||||||
|
"title": "Kiemelés megjenítése"
|
||||||
},
|
},
|
||||||
"unfollow": {
|
"unfollow": {
|
||||||
"cancel": "Mégsem",
|
"cancel": "Mégsem",
|
||||||
"confirm": "Követés leállítása",
|
"confirm": "Követés leállítása",
|
||||||
"description": "Biztosan leállítja a követését?"
|
"description": "Biztosan leállítja a követését?",
|
||||||
|
"title": "Követés elállítása"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"conversation": {
|
"conversation": {
|
||||||
|
@ -169,7 +182,7 @@
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"account_not_found": "Fiók {0} nem található",
|
"account_not_found": "Fiók {0} nem található",
|
||||||
"explore_list-empty": "Nincs most itt semmi... Nézz vissza később!",
|
"explore_list_empty": "Nincs most semmi érdekes. Térj vissza később!",
|
||||||
"file_size_cannot_exceed_n_mb": "A fájl mérete nem haladhatja meg a {0}MB-ot",
|
"file_size_cannot_exceed_n_mb": "A fájl mérete nem haladhatja meg a {0}MB-ot",
|
||||||
"sign_in_error": "Nem lehetséges a csatlakozás.",
|
"sign_in_error": "Nem lehetséges a csatlakozás.",
|
||||||
"status_not_found": "A bejegyzés nem található",
|
"status_not_found": "A bejegyzés nem található",
|
||||||
|
@ -220,14 +233,25 @@
|
||||||
"compose": "Közzétesz",
|
"compose": "Közzétesz",
|
||||||
"favourite": "Kedvenc",
|
"favourite": "Kedvenc",
|
||||||
"search": "Keresés",
|
"search": "Keresés",
|
||||||
|
"show_new_items": "Új elemek mutatása",
|
||||||
"title": "Műveletek"
|
"title": "Műveletek"
|
||||||
},
|
},
|
||||||
"media": {
|
"media": {
|
||||||
"title": "Média"
|
"title": "Média"
|
||||||
},
|
},
|
||||||
"navigation": {
|
"navigation": {
|
||||||
|
"go_to_bookmarks": "Könyvjelzők",
|
||||||
|
"go_to_conversations": "Párbeszédek",
|
||||||
|
"go_to_explore": "Felfedez",
|
||||||
|
"go_to_favourites": "Kedvencek",
|
||||||
|
"go_to_federated": "Összesített",
|
||||||
"go_to_home": "Otthon",
|
"go_to_home": "Otthon",
|
||||||
|
"go_to_lists": "Listák",
|
||||||
|
"go_to_local": "Helyi",
|
||||||
"go_to_notifications": "Értesítések",
|
"go_to_notifications": "Értesítések",
|
||||||
|
"go_to_profile": "Profil",
|
||||||
|
"go_to_search": "Keresés",
|
||||||
|
"go_to_settings": "Beállítások",
|
||||||
"next_status": "Következő bejegyzés",
|
"next_status": "Következő bejegyzés",
|
||||||
"previous_status": "Előző bejegyzés",
|
"previous_status": "Előző bejegyzés",
|
||||||
"shortcut_help": "Gyors segítség",
|
"shortcut_help": "Gyors segítség",
|
||||||
|
@ -285,6 +309,7 @@
|
||||||
"explore": "Felfedezés",
|
"explore": "Felfedezés",
|
||||||
"favourites": "Kedvencek",
|
"favourites": "Kedvencek",
|
||||||
"federated": "Összesített",
|
"federated": "Összesített",
|
||||||
|
"hashtags": "Címkék",
|
||||||
"home": "Otthon",
|
"home": "Otthon",
|
||||||
"list": "Lista",
|
"list": "Lista",
|
||||||
"lists": "Listák",
|
"lists": "Listák",
|
||||||
|
@ -316,7 +341,7 @@
|
||||||
"placeholder": {
|
"placeholder": {
|
||||||
"content_warning": "Írja ide figyelmeztetését",
|
"content_warning": "Írja ide figyelmeztetését",
|
||||||
"default_1": "Mi jár a fejedben?",
|
"default_1": "Mi jár a fejedben?",
|
||||||
"reply_to_account": "Válasz: {0}",
|
"reply_to_account": "Válasz erre: {0}",
|
||||||
"replying": "Válaszol"
|
"replying": "Válaszol"
|
||||||
},
|
},
|
||||||
"polls": {
|
"polls": {
|
||||||
|
@ -517,10 +542,12 @@
|
||||||
"hide_follower_count": "Követők/Követések számláló elrejtése",
|
"hide_follower_count": "Követők/Követések számláló elrejtése",
|
||||||
"hide_news": "Hírek elrejtése",
|
"hide_news": "Hírek elrejtése",
|
||||||
"hide_reply_count": "Visszajelzések számláló elrejtése",
|
"hide_reply_count": "Visszajelzések számláló elrejtése",
|
||||||
|
"hide_tag_hover_card": "Lebegő kártya elrejtése",
|
||||||
"hide_translation": "Fordítás elrejtése",
|
"hide_translation": "Fordítás elrejtése",
|
||||||
"hide_username_emojis": "Felhasználói emoji elrejtése",
|
"hide_username_emojis": "Felhasználói emoji elrejtése",
|
||||||
"hide_username_emojis_description": "Elrejti a hangulatjeleket a felhasználónevek elől az idővonalakban. A hangulatjelek továbbra is láthatók lesznek a profiljukban.",
|
"hide_username_emojis_description": "Elrejti a hangulatjeleket a felhasználónevek elől az idővonalakban. A hangulatjelek továbbra is láthatók lesznek a profiljukban.",
|
||||||
"label": "Preferenciák",
|
"label": "Preferenciák",
|
||||||
|
"optimize_for_low_performance_device": "Alacsony teljesítményre optimalizálás",
|
||||||
"title": "Kísérleti képességek",
|
"title": "Kísérleti képességek",
|
||||||
"use_star_favorite_icon": "Használja a csillag favikont",
|
"use_star_favorite_icon": "Használja a csillag favikont",
|
||||||
"user_picker": "Felhasználók váltása",
|
"user_picker": "Felhasználók váltása",
|
||||||
|
@ -557,10 +584,10 @@
|
||||||
"label": "Bejelentkezett felhasználók"
|
"label": "Bejelentkezett felhasználók"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"share-target": {
|
"share_target": {
|
||||||
"description": "Az Elk konfigurálható úgy, hogy más alkalmazásokból is megoszthasson tartalmat, egyszerűen telepítse az Elket eszközére vagy számítógépére, és jelentkezzen be.",
|
"description": "Az Elk konfigurálható úgy, hogy más alkalmazásokból is megoszthasson tartalmat, egyszerűen telepítse az Elket eszközére vagy számítógépére, és jelentkezzen be.",
|
||||||
"hint": "A tartalom Elkkel való megosztásához telepíteni kell az Elket, és be kell jelentkeznie.",
|
"hint": "A tartalom megosztásához telepíteni kell az Elket, és be kell jelentkeznie.",
|
||||||
"title": "Megosztás Elkkel"
|
"title": "Oszd meg Elkkel"
|
||||||
},
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"attachments_exceed_server_limit": "A mellékletek száma meghaladta a bejegyzésenkénti korlátot.",
|
"attachments_exceed_server_limit": "A mellékletek száma meghaladta a bejegyzésenkénti korlátot.",
|
||||||
|
|
|
@ -121,13 +121,13 @@
|
||||||
"block_account": {
|
"block_account": {
|
||||||
"cancel": "Annulla",
|
"cancel": "Annulla",
|
||||||
"confirm": "Blocca",
|
"confirm": "Blocca",
|
||||||
"description": "Confermi di voler bloccare {0}?",
|
"description": "Bloccare {0}?",
|
||||||
"title": "Blocca account"
|
"title": "Blocca account"
|
||||||
},
|
},
|
||||||
"block_domain": {
|
"block_domain": {
|
||||||
"cancel": "Annulla",
|
"cancel": "Annulla",
|
||||||
"confirm": "Blocca",
|
"confirm": "Blocca",
|
||||||
"description": "Confermi di voler bloccare {0}?",
|
"description": "Bloccare {0}?",
|
||||||
"title": "Blocca dominio"
|
"title": "Blocca dominio"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
@ -137,31 +137,36 @@
|
||||||
"delete_list": {
|
"delete_list": {
|
||||||
"cancel": "Annulla",
|
"cancel": "Annulla",
|
||||||
"confirm": "Elimina",
|
"confirm": "Elimina",
|
||||||
"description": "Confermi di voler eliminare la lista \"{0}\"?",
|
"description": "Eliminare la lista \"{0}\"?",
|
||||||
"title": "Elimina lista"
|
"title": "Elimina lista"
|
||||||
},
|
},
|
||||||
"delete_posts": {
|
"delete_posts": {
|
||||||
"cancel": "Annulla",
|
"cancel": "Annulla",
|
||||||
"confirm": "Elimina",
|
"confirm": "Elimina",
|
||||||
"description": "Confermi di voler eliminare questo post?",
|
"description": "Eliminare questo post?",
|
||||||
"title": "Elimina post"
|
"title": "Elimina post"
|
||||||
},
|
},
|
||||||
"mute_account": {
|
"mute_account": {
|
||||||
"cancel": "Annulla",
|
"cancel": "Annulla",
|
||||||
"confirm": "Silenzia",
|
"confirm": "Silenzia",
|
||||||
"description": "Confermi di voler silenziare {0}?",
|
"days": "giorni|giorno|giorni",
|
||||||
|
"description": "Silenziare {0}?",
|
||||||
|
"hours": "ore|ora|ore",
|
||||||
|
"minute": "minuti|minuto|minuti",
|
||||||
|
"notifications": "Silenzia notifiche",
|
||||||
|
"specify_duration": "Specifica durata silenziamento",
|
||||||
"title": "Silenzia account"
|
"title": "Silenzia account"
|
||||||
},
|
},
|
||||||
"show_reblogs": {
|
"show_reblogs": {
|
||||||
"cancel": "Annulla",
|
"cancel": "Annulla",
|
||||||
"confirm": "Mostra",
|
"confirm": "Mostra",
|
||||||
"description": "Confermi di voler mostrare i post potenziati da {0}?",
|
"description": "Mostrare i post potenziati da {0}?",
|
||||||
"title": "Mostra potenziamenti"
|
"title": "Mostra potenziamenti"
|
||||||
},
|
},
|
||||||
"unfollow": {
|
"unfollow": {
|
||||||
"cancel": "Annulla",
|
"cancel": "Annulla",
|
||||||
"confirm": "Smetti di seguire",
|
"confirm": "Smetti di seguire",
|
||||||
"description": "Confermi di voler smettere di seguire?",
|
"description": "Smettere di seguire?",
|
||||||
"title": "Smetti di seguire"
|
"title": "Smetti di seguire"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -228,14 +233,25 @@
|
||||||
"compose": "Componi",
|
"compose": "Componi",
|
||||||
"favourite": "Apprezza",
|
"favourite": "Apprezza",
|
||||||
"search": "Cerca",
|
"search": "Cerca",
|
||||||
|
"show_new_items": "Mostra nuovi elementi",
|
||||||
"title": "Azioni"
|
"title": "Azioni"
|
||||||
},
|
},
|
||||||
"media": {
|
"media": {
|
||||||
"title": "Media"
|
"title": "Media"
|
||||||
},
|
},
|
||||||
"navigation": {
|
"navigation": {
|
||||||
|
"go_to_bookmarks": "Segnalibri",
|
||||||
|
"go_to_conversations": "Conversazioni",
|
||||||
|
"go_to_explore": "Esplora",
|
||||||
|
"go_to_favourites": "Preferiti",
|
||||||
|
"go_to_federated": "Federata",
|
||||||
"go_to_home": "Home",
|
"go_to_home": "Home",
|
||||||
|
"go_to_lists": "Liste",
|
||||||
|
"go_to_local": "Locale",
|
||||||
"go_to_notifications": "Notifiche",
|
"go_to_notifications": "Notifiche",
|
||||||
|
"go_to_profile": "Profilo",
|
||||||
|
"go_to_search": "Cerca",
|
||||||
|
"go_to_settings": "Impostazioni",
|
||||||
"next_status": "Post successivo",
|
"next_status": "Post successivo",
|
||||||
"previous_status": "Post precedente",
|
"previous_status": "Post precedente",
|
||||||
"shortcut_help": "Aiuto scorciatoie",
|
"shortcut_help": "Aiuto scorciatoie",
|
||||||
|
@ -290,9 +306,11 @@
|
||||||
"built_at": "Sviluppato {0}",
|
"built_at": "Sviluppato {0}",
|
||||||
"compose": "Componi",
|
"compose": "Componi",
|
||||||
"conversations": "Conversazioni",
|
"conversations": "Conversazioni",
|
||||||
|
"docs": "Documentazione",
|
||||||
"explore": "Esplora",
|
"explore": "Esplora",
|
||||||
"favourites": "Preferiti",
|
"favourites": "Preferiti",
|
||||||
"federated": "Federata",
|
"federated": "Federata",
|
||||||
|
"hashtags": "Hashtag",
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
"list": "Lista",
|
"list": "Lista",
|
||||||
"lists": "Liste",
|
"lists": "Liste",
|
||||||
|
@ -442,6 +460,7 @@
|
||||||
},
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"display_language": "Lingua interfaccia",
|
"display_language": "Lingua interfaccia",
|
||||||
|
"how_to_contribute": "Come posso contribuire?",
|
||||||
"label": "Lingua",
|
"label": "Lingua",
|
||||||
"post_language": "Lingua di pubblicazione",
|
"post_language": "Lingua di pubblicazione",
|
||||||
"status": "Stato traduzione: {0}/{1} ({2}%)",
|
"status": "Stato traduzione: {0}/{1} ({2}%)",
|
||||||
|
@ -525,6 +544,7 @@
|
||||||
"hide_follower_count": "Nascondi contatore seguaci/seguiti",
|
"hide_follower_count": "Nascondi contatore seguaci/seguiti",
|
||||||
"hide_news": "Nascondi notizie",
|
"hide_news": "Nascondi notizie",
|
||||||
"hide_reply_count": "Nascondi contatore risposte",
|
"hide_reply_count": "Nascondi contatore risposte",
|
||||||
|
"hide_tag_hover_card": "Nascondi anteprima tag al passaggio del mouse",
|
||||||
"hide_translation": "Nascondi traduzione",
|
"hide_translation": "Nascondi traduzione",
|
||||||
"hide_username_emojis": "Nascondi emoji dai nomi utente",
|
"hide_username_emojis": "Nascondi emoji dai nomi utente",
|
||||||
"hide_username_emojis_description": "Nasconde le emoji all'interno dei nomi utente nella cronologia. Le emoji saranno comunque visibili nelle pagine dei profili.",
|
"hide_username_emojis_description": "Nasconde le emoji all'interno dei nomi utente nella cronologia. Le emoji saranno comunque visibili nelle pagine dei profili.",
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue