Firefish v1.0.5-dev6
This commit is contained in:
parent
f2215e511d
commit
d52e4b3c6a
313 changed files with 5296 additions and 3678 deletions
|
@ -161,6 +161,9 @@ reservedUsernames: [
|
||||||
# deliverJobMaxAttempts: 12
|
# deliverJobMaxAttempts: 12
|
||||||
# inboxJobMaxAttempts: 8
|
# inboxJobMaxAttempts: 8
|
||||||
|
|
||||||
|
# Local address used for outgoing requests
|
||||||
|
#outgoingAddress: 127.0.0.1
|
||||||
|
|
||||||
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
||||||
#outgoingAddressFamily: ipv4
|
#outgoingAddressFamily: ipv4
|
||||||
|
|
||||||
|
|
1
.vscode/extensions.json
vendored
1
.vscode/extensions.json
vendored
|
@ -1,7 +1,6 @@
|
||||||
{
|
{
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
"editorconfig.editorconfig",
|
"editorconfig.editorconfig",
|
||||||
"eg2.vscode-npm-script",
|
|
||||||
"rome.rome",
|
"rome.rome",
|
||||||
"Vue.volar",
|
"Vue.volar",
|
||||||
"Vue.vscode-typescript-vue-plugin",
|
"Vue.vscode-typescript-vue-plugin",
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
pipeline:
|
|
||||||
testCommit:
|
|
||||||
image: node:alpine
|
|
||||||
commands:
|
|
||||||
- apk add --no-cache cargo python3 make g++
|
|
||||||
- cp .config/ci.yml .config/default.yml
|
|
||||||
- corepack enable
|
|
||||||
- corepack prepare pnpm@latest --activate
|
|
||||||
- pnpm i --frozen-lockfile
|
|
||||||
- pnpm run build
|
|
||||||
- pnpm run migrate
|
|
||||||
|
|
||||||
services:
|
|
||||||
database:
|
|
||||||
image: postgres:15
|
|
||||||
environment:
|
|
||||||
- POSTGRES_PASSWORD=test
|
|
||||||
redis:
|
|
||||||
image: redis
|
|
||||||
|
|
||||||
branches:
|
|
||||||
include: [ main, beta, develop, feature/* ]
|
|
|
@ -1,15 +0,0 @@
|
||||||
pipeline:
|
|
||||||
publish-docker-latest:
|
|
||||||
image: plugins/kaniko
|
|
||||||
settings:
|
|
||||||
repo: thatonecalculator/firefish
|
|
||||||
tags: latest
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
username:
|
|
||||||
# Secret 'docker_username' needs to be set in the CI settings
|
|
||||||
from_secret: docker_username
|
|
||||||
password:
|
|
||||||
# Secret 'docker_password' needs to be set in the CI settings
|
|
||||||
from_secret: docker_password
|
|
||||||
|
|
||||||
branches: main
|
|
|
@ -1,14 +0,0 @@
|
||||||
pipeline:
|
|
||||||
publish-docker-latest:
|
|
||||||
image: plugins/kaniko
|
|
||||||
settings:
|
|
||||||
repo: thatonecalculator/firefish
|
|
||||||
tags: rc
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
username:
|
|
||||||
# Secret 'docker_username' needs to be set in the CI settings
|
|
||||||
from_secret: docker_username
|
|
||||||
password:
|
|
||||||
# Secret 'docker_password' needs to be set in the CI settings
|
|
||||||
from_secret: docker_password
|
|
||||||
branches: beta
|
|
|
@ -1,18 +0,0 @@
|
||||||
pipeline:
|
|
||||||
publish-docker-tag:
|
|
||||||
image: plugins/kaniko
|
|
||||||
settings:
|
|
||||||
repo: thatonecalculator/firefish
|
|
||||||
# Uses the tag from git for the container tag
|
|
||||||
tags: ${CI_COMMIT_TAG}
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
username:
|
|
||||||
# Secret 'docker_username' needs to be set in the CI settings
|
|
||||||
from_secret: docker_username
|
|
||||||
password:
|
|
||||||
# Secret 'docker_password' needs to be set in the CI settings
|
|
||||||
from_secret: docker_password
|
|
||||||
when:
|
|
||||||
# Push new version when version tag is created
|
|
||||||
event: tag
|
|
||||||
tag: v*
|
|
|
@ -1,11 +0,0 @@
|
||||||
pipeline:
|
|
||||||
docker-build:
|
|
||||||
image: plugins/kaniko
|
|
||||||
settings:
|
|
||||||
repo: thatonecalculator/firefish
|
|
||||||
tags: test
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
no_push: true
|
|
||||||
|
|
||||||
branches:
|
|
||||||
include: [ main, develop, beta ]
|
|
|
@ -8900,7 +8900,7 @@ Resolve #7540
|
||||||
* truncate user information if it is too long
|
* truncate user information if it is too long
|
||||||
|
|
||||||
Some AP software allows for user names or summaries to be very long.
|
Some AP software allows for user names or summaries to be very long.
|
||||||
Misskey can not handle this and the profile page can not be opened and
|
Misskey cannot handle this and the profile page cannot be opened and
|
||||||
no activities from such users can be seen.
|
no activities from such users can be seen.
|
||||||
|
|
||||||
Instead, the user name and summary are cut off after the maximum length
|
Instead, the user name and summary are cut off after the maximum length
|
||||||
|
@ -9902,7 +9902,7 @@ This duplicated processing can be avoided by querying the database directly.
|
||||||
|
|
||||||
Misskey will only use ActivityPub follow requests for users that are local
|
Misskey will only use ActivityPub follow requests for users that are local
|
||||||
and are requesting to follow a remote user. This check is to ensure that
|
and are requesting to follow a remote user. This check is to ensure that
|
||||||
this endpoint can not be used by other services or instances.
|
this endpoint cannot be used by other services or instances.
|
||||||
|
|
||||||
* fix: missing import
|
* fix: missing import
|
||||||
|
|
||||||
|
@ -14921,7 +14921,7 @@ Defaults for `local` and `withFiles` are based on the behaviour of the endpoint.
|
||||||
|
|
||||||
* fix: define required fields
|
* fix: define required fields
|
||||||
|
|
||||||
- `notes/create`: the default for `text` has been removed because ajv can not handle
|
- `notes/create`: the default for `text` has been removed because ajv cannot handle
|
||||||
`default` inside of `anyOf`, see
|
`default` inside of `anyOf`, see
|
||||||
https://ajv.js.org/guide/modifying-data.html#assigning-defaults
|
https://ajv.js.org/guide/modifying-data.html#assigning-defaults
|
||||||
and the default value cannot be `null` if text is `nullable: false` in the `anyOf`
|
and the default value cannot be `null` if text is `nullable: false` in the `anyOf`
|
||||||
|
@ -15551,7 +15551,7 @@ unnecessarily loaded.
|
||||||
* remove duplicate null check
|
* remove duplicate null check
|
||||||
|
|
||||||
The variable is checked for null in the lines above and the function
|
The variable is checked for null in the lines above and the function
|
||||||
returns if so. Therefore, it can not be null at this point.
|
returns if so. Therefore, it cannot be null at this point.
|
||||||
|
|
||||||
* simplify `getJsonSchema`
|
* simplify `getJsonSchema`
|
||||||
|
|
||||||
|
|
17
Dockerfile
17
Dockerfile
|
@ -1,9 +1,14 @@
|
||||||
## Install dev and compilation dependencies, build files
|
## Install dev and compilation dependencies, build files
|
||||||
FROM alpine:3.18 as build
|
FROM node:latest as build
|
||||||
WORKDIR /firefish
|
WORKDIR /firefish
|
||||||
|
|
||||||
# Install compilation dependencies
|
# Install compilation dependencies
|
||||||
RUN apk add --no-cache --no-progress git alpine-sdk python3 nodejs-current npm rust cargo vips
|
RUN apt-get update && apt-get install -y libvips42 python3 git wget curl build-essential
|
||||||
|
RUN mkdir -m777 /opt/rust /opt/cargo
|
||||||
|
ENV RUSTUP_HOME=/opt/rust CARGO_HOME=/opt/cargo PATH=/opt/cargo/bin:$PATH
|
||||||
|
RUN wget --https-only --secure-protocol=TLSv1_2 -O- https://sh.rustup.rs | sh /dev/stdin -y
|
||||||
|
RUN printf '#!/bin/sh\nexport CARGO_HOME=/opt/cargo\nexec /bin/sh "$@"\n' >/usr/local/bin/sh
|
||||||
|
RUN chmod +x /usr/local/bin/sh
|
||||||
|
|
||||||
# Copy only the cargo dependency-related files first, to cache efficiently
|
# Copy only the cargo dependency-related files first, to cache efficiently
|
||||||
COPY packages/backend/native-utils/Cargo.toml packages/backend/native-utils/Cargo.toml
|
COPY packages/backend/native-utils/Cargo.toml packages/backend/native-utils/Cargo.toml
|
||||||
|
@ -26,7 +31,7 @@ COPY packages/backend/native-utils/package.json packages/backend/native-utils/pa
|
||||||
COPY packages/backend/native-utils/npm/linux-x64-musl/package.json packages/backend/native-utils/npm/linux-x64-musl/package.json
|
COPY packages/backend/native-utils/npm/linux-x64-musl/package.json packages/backend/native-utils/npm/linux-x64-musl/package.json
|
||||||
COPY packages/backend/native-utils/npm/linux-arm64-musl/package.json packages/backend/native-utils/npm/linux-arm64-musl/package.json
|
COPY packages/backend/native-utils/npm/linux-arm64-musl/package.json packages/backend/native-utils/npm/linux-arm64-musl/package.json
|
||||||
|
|
||||||
# Configure corepack and pnpm, and install dev mode dependencies for compilation
|
# Configure pnpm, and install dev mode dependencies for compilation
|
||||||
RUN corepack enable && corepack prepare pnpm@latest --activate && pnpm i --frozen-lockfile
|
RUN corepack enable && corepack prepare pnpm@latest --activate && pnpm i --frozen-lockfile
|
||||||
|
|
||||||
# Copy in the rest of the native-utils rust files
|
# Copy in the rest of the native-utils rust files
|
||||||
|
@ -43,11 +48,11 @@ RUN env NODE_ENV=production sh -c "pnpm run --filter '!native-utils' build && pn
|
||||||
RUN pnpm i --prod --frozen-lockfile
|
RUN pnpm i --prod --frozen-lockfile
|
||||||
|
|
||||||
## Runtime container
|
## Runtime container
|
||||||
FROM alpine:3.18
|
FROM node:latest
|
||||||
WORKDIR /firefish
|
WORKDIR /firefish
|
||||||
|
|
||||||
# Install runtime dependencies
|
# Install runtime dependencies
|
||||||
RUN apk add --no-cache --no-progress tini ffmpeg vips-dev zip unzip nodejs-current
|
RUN apt-get update && apt-get install -y libvips-dev zip unzip tini ffmpeg
|
||||||
|
|
||||||
COPY . ./
|
COPY . ./
|
||||||
|
|
||||||
|
@ -69,5 +74,5 @@ COPY --from=build /firefish/packages/backend/native-utils/built /firefish/packag
|
||||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
VOLUME "/firefish/files"
|
VOLUME "/firefish/files"
|
||||||
ENTRYPOINT [ "/sbin/tini", "--" ]
|
ENTRYPOINT [ "/usr/bin/tini", "--" ]
|
||||||
CMD [ "pnpm", "run", "migrateandstart" ]
|
CMD [ "pnpm", "run", "migrateandstart" ]
|
||||||
|
|
|
@ -103,4 +103,4 @@ NODE_ENV=production pnpm run migrate
|
||||||
|
|
||||||
## Reverse
|
## Reverse
|
||||||
|
|
||||||
You ***cannot*** migrate back to Misskey from Firefish due to re-hashing passwords on signin with argon2. You can migrate from Calckey to FoundKey, although this is not recommended due to FoundKey being end-of-life, and may have some problems with alt-text.
|
You ***cannot*** migrate back to Misskey from Firefish due to re-hashing passwords on signin with argon2. You can migrate from Firefish to FoundKey, although this is not recommended due to FoundKey being end-of-life, and may have some problems with alt-text.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
_lang_: Български
|
_lang_: Български
|
||||||
cancel: Отмяна
|
cancel: Отмени
|
||||||
noNotes: Няма публикации
|
noNotes: Няма публикации
|
||||||
settings: Настройки
|
settings: Настройки
|
||||||
headlineFirefish: Децентрализирана социална медийна платформа с отворен код, която
|
headlineFirefish: Децентрализирана социална медийна платформа с отворен код, която
|
||||||
|
@ -101,6 +101,10 @@ _filters:
|
||||||
followersOnly: Само последователи
|
followersOnly: Само последователи
|
||||||
notesAfter: Публикации след
|
notesAfter: Публикации след
|
||||||
fromDomain: От домейн
|
fromDomain: От домейн
|
||||||
|
fromUser: От потребител
|
||||||
|
withFile: С файл
|
||||||
|
notesBefore: Публикации преди
|
||||||
|
followingOnly: Само последвани
|
||||||
_notification:
|
_notification:
|
||||||
_types:
|
_types:
|
||||||
follow: Нови последователи
|
follow: Нови последователи
|
||||||
|
@ -113,10 +117,10 @@ noLists: Нямаш никакви списъци
|
||||||
markAsReadAllUnreadNotes: Маркирай всички публикации като прочетени
|
markAsReadAllUnreadNotes: Маркирай всички публикации като прочетени
|
||||||
markAsReadAllTalkMessages: Маркирай всички съобщения като прочетени
|
markAsReadAllTalkMessages: Маркирай всички съобщения като прочетени
|
||||||
_time:
|
_time:
|
||||||
second: Секунд(а/и)
|
second: Секунди
|
||||||
hour: Час(а)
|
hour: Часа
|
||||||
day: Дни
|
day: Дни
|
||||||
minute: Минут(а/и)
|
minute: Минути
|
||||||
create: Създай
|
create: Създай
|
||||||
lists: Списъци
|
lists: Списъци
|
||||||
reportAbuseOf: Докладвай {name}
|
reportAbuseOf: Докладвай {name}
|
||||||
|
@ -134,9 +138,9 @@ rename: Преименувай
|
||||||
customEmojis: Персонализирани емоджита
|
customEmojis: Персонализирани емоджита
|
||||||
emoji: Емоджи
|
emoji: Емоджи
|
||||||
_aboutFirefish:
|
_aboutFirefish:
|
||||||
translation: Преведи Calckey
|
translation: Преведи Firefish
|
||||||
translatedFrom: Преведено от {x}
|
translatedFrom: Преведено от {x}
|
||||||
i18nInfo: Calckey се превежда на различни езици от доброволци. Можете да помогнете
|
i18nInfo: Firefish се превежда на различни езици от доброволци. Можете да помогнете
|
||||||
на адрес {link}.
|
на адрес {link}.
|
||||||
image: Изображение
|
image: Изображение
|
||||||
recipient: Получател(и)
|
recipient: Получател(и)
|
||||||
|
@ -222,11 +226,11 @@ _mfm:
|
||||||
_messaging:
|
_messaging:
|
||||||
groups: Групи
|
groups: Групи
|
||||||
apps: Приложения
|
apps: Приложения
|
||||||
introFirefish: Добре дошли! Calckey е децентрализирана социална медийна платформа
|
introFirefish: Добре дошли! Firefish е децентрализирана социална медийна платформа
|
||||||
с отворен код, която е безплатна завинаги! 🚀
|
с отворен код, която е безплатна завинаги! 🚀
|
||||||
monthAndDay: '{day}/{month}'
|
monthAndDay: '{day}/{month}'
|
||||||
search: Търсене
|
search: Търсене
|
||||||
searchPlaceholder: Търсене в Calckey
|
searchPlaceholder: Търсене в Firefish
|
||||||
username: Потребителско име
|
username: Потребителско име
|
||||||
password: Парола
|
password: Парола
|
||||||
fetchingAsApObject: Извличане от федивърса
|
fetchingAsApObject: Извличане от федивърса
|
||||||
|
@ -257,7 +261,7 @@ alreadyFavorited: Вече е добавено в отметки.
|
||||||
cantFavorite: Неуспешно добавяне в отметки.
|
cantFavorite: Неуспешно добавяне в отметки.
|
||||||
copyContent: Копирай съдържанието
|
copyContent: Копирай съдържанието
|
||||||
deleteAndEdit: Изтрий и редактирай
|
deleteAndEdit: Изтрий и редактирай
|
||||||
editNote: Редактирай бележка
|
editNote: Редактирай публикация
|
||||||
edited: Редактирано на {date} {time}
|
edited: Редактирано на {date} {time}
|
||||||
addToList: Добави в списък
|
addToList: Добави в списък
|
||||||
sendMessage: Изпрати съобщение
|
sendMessage: Изпрати съобщение
|
||||||
|
@ -422,3 +426,51 @@ _visibility:
|
||||||
followers: Последователи
|
followers: Последователи
|
||||||
explore: Разглеждане
|
explore: Разглеждане
|
||||||
theme: Теми
|
theme: Теми
|
||||||
|
wallpaper: Тапет
|
||||||
|
setWallpaper: Задай тапет
|
||||||
|
removeWallpaper: Премахни тапет
|
||||||
|
themeForLightMode: Тема за използване в светъл режим
|
||||||
|
themeForDarkMode: Тема за използване в тъмен режим
|
||||||
|
light: Светло
|
||||||
|
dark: Тъмно
|
||||||
|
darkThemes: Тъмни теми
|
||||||
|
invitations: Покани
|
||||||
|
invitationCode: Код на поканата
|
||||||
|
checking: Проверка...
|
||||||
|
available: Свободно
|
||||||
|
unavailable: Не е свободно
|
||||||
|
tooShort: Твърде кратко
|
||||||
|
tooLong: Твърде дълго
|
||||||
|
weakPassword: Слаба парола
|
||||||
|
strongPassword: Силна парола
|
||||||
|
passwordMatched: Съвпада
|
||||||
|
passwordNotMatched: Не съвпада
|
||||||
|
signinWith: Вписване с {x}
|
||||||
|
aboutX: Относно {x}
|
||||||
|
openInNewTab: Отвори в нов раздел
|
||||||
|
_tutorial:
|
||||||
|
step2_1: Първо, моля, попълнете своя профил.
|
||||||
|
step2_2: Предоставянето на известна информация за това кой сте вие ще улесни другите
|
||||||
|
да разберат дали искат да видят вашите публикации или да ви следват.
|
||||||
|
title: Как се използва Firefish
|
||||||
|
step1_1: Добре дошли!
|
||||||
|
step5_1: Инфопотоци, инфопотоци навсякъде!
|
||||||
|
step3_1: Сега е време да последвате няколко хора!
|
||||||
|
step1_2: Нека да ви настроим. Ще бъдете готови за нула време!
|
||||||
|
openImageInNewTab: Отваряй изображенията в нов раздел
|
||||||
|
showOnRemote: Отвори оригиналната страница
|
||||||
|
lightThemes: Светли теми
|
||||||
|
syncDeviceDarkMode: Синхронизиране на тъмния режим с настройките на устройството
|
||||||
|
text: Текст
|
||||||
|
normalPassword: Средна парола
|
||||||
|
usernameInvalidFormat: Можете да използвате главни и малки букви, цифри и долни черти.
|
||||||
|
signinFailed: Неуспешно вписване. Въведените потребителско име или парола са неправилни.
|
||||||
|
signinRequired: Моля, регистрирайте се или се впишете, преди да продължите
|
||||||
|
start: Започни
|
||||||
|
confirm: Потвърди
|
||||||
|
failedToUpload: Неуспешно качване
|
||||||
|
_preferencesBackups:
|
||||||
|
cannotSave: Неуспешно запазване
|
||||||
|
cannotLoad: Неуспешно зареждане
|
||||||
|
editWidgetsExit: Готово
|
||||||
|
done: Готово
|
||||||
|
|
|
@ -2074,7 +2074,7 @@ _relayStatus:
|
||||||
accepted: Acceptat
|
accepted: Acceptat
|
||||||
rejected: Rebutjat
|
rejected: Rebutjat
|
||||||
deleted: Eliminat
|
deleted: Eliminat
|
||||||
editNote: Edita la nota
|
editNote: Edita la publicació
|
||||||
edited: 'Editat a {date} {time}'
|
edited: 'Editat a {date} {time}'
|
||||||
findOtherInstance: Cercar un altre servidor
|
findOtherInstance: Cercar un altre servidor
|
||||||
signupsDisabled: Actualment, les inscripcions en aquest servidor estan desactivades,
|
signupsDisabled: Actualment, les inscripcions en aquest servidor estan desactivades,
|
||||||
|
@ -2182,3 +2182,7 @@ delete2fa: Desactivar 2FA
|
||||||
delete2faConfirm: Això suprimirà irreversiblement 2FA en aquest compte. Procedir?
|
delete2faConfirm: Això suprimirà irreversiblement 2FA en aquest compte. Procedir?
|
||||||
addRe: Afegeix "re:" al començament del comentari quant responguis a un missatge amb
|
addRe: Afegeix "re:" al començament del comentari quant responguis a un missatge amb
|
||||||
avís de contingut
|
avís de contingut
|
||||||
|
confirm: Confirmar
|
||||||
|
importZip: Importar ZIP
|
||||||
|
exportZip: Exportar ZIP
|
||||||
|
emojiPackCreator: Creador de paquets Emoji
|
||||||
|
|
|
@ -77,7 +77,7 @@ lists: "Listen"
|
||||||
noLists: "Du hast keine Listen angelegt"
|
noLists: "Du hast keine Listen angelegt"
|
||||||
note: "Beitrag"
|
note: "Beitrag"
|
||||||
notes: "Beiträge"
|
notes: "Beiträge"
|
||||||
following: "Folge ich"
|
following: "Folgen"
|
||||||
followers: "Folgen mir"
|
followers: "Folgen mir"
|
||||||
followsYou: "Folgt dir"
|
followsYou: "Folgt dir"
|
||||||
createList: "Liste erstellen"
|
createList: "Liste erstellen"
|
||||||
|
@ -474,7 +474,7 @@ invitations: "Einladungen"
|
||||||
invitationCode: "Einladungscode"
|
invitationCode: "Einladungscode"
|
||||||
checking: "Wird überprüft …"
|
checking: "Wird überprüft …"
|
||||||
available: "Verfügbar"
|
available: "Verfügbar"
|
||||||
unavailable: "Unverfügbar"
|
unavailable: "Nicht verfügbar"
|
||||||
usernameInvalidFormat: "Du kannst Klein- und Großbuchstaben, Zahlen sowie Unterstriche
|
usernameInvalidFormat: "Du kannst Klein- und Großbuchstaben, Zahlen sowie Unterstriche
|
||||||
verwenden."
|
verwenden."
|
||||||
tooShort: "Zu kurz"
|
tooShort: "Zu kurz"
|
||||||
|
@ -1945,7 +1945,7 @@ _notification:
|
||||||
renote: "Renote"
|
renote: "Renote"
|
||||||
voted: haben bei deiner Umfrage abgestimmt
|
voted: haben bei deiner Umfrage abgestimmt
|
||||||
reacted: hat auf deinen Beitrag reagiert
|
reacted: hat auf deinen Beitrag reagiert
|
||||||
renoted: hat Ihren Beitrag geteilt
|
renoted: hat deinen Beitrag geteilt
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "Hauptspalte immer zeigen"
|
alwaysShowMainColumn: "Hauptspalte immer zeigen"
|
||||||
columnAlign: "Spaltenausrichtung"
|
columnAlign: "Spaltenausrichtung"
|
||||||
|
@ -2099,7 +2099,7 @@ customKaTeXMacro: Individuelle KaTeX Makros
|
||||||
enableCustomKaTeXMacro: Individuelle KaTeX-Makros aktivieren
|
enableCustomKaTeXMacro: Individuelle KaTeX-Makros aktivieren
|
||||||
replayTutorial: Wiederhole die Benutzeranleitung
|
replayTutorial: Wiederhole die Benutzeranleitung
|
||||||
apps: Apps
|
apps: Apps
|
||||||
caption: Automatische Untertitelung
|
caption: Automatische Beschreibung
|
||||||
pwa: PWA installieren
|
pwa: PWA installieren
|
||||||
cw: Inhaltswarnung
|
cw: Inhaltswarnung
|
||||||
older: älter
|
older: älter
|
||||||
|
@ -2204,3 +2204,7 @@ deletePasskeysConfirm: Alle Passkeys und Security-Keys werden unwiderruflich von
|
||||||
inputNotMatch: Eingabe stimmt nicht überein
|
inputNotMatch: Eingabe stimmt nicht überein
|
||||||
addRe: Ein "re:" am Anfang des Kommentars hinzufügen, um einem Beitrag mit einer Inhaltswarnung
|
addRe: Ein "re:" am Anfang des Kommentars hinzufügen, um einem Beitrag mit einer Inhaltswarnung
|
||||||
zu antworten
|
zu antworten
|
||||||
|
confirm: Bestätigen
|
||||||
|
importZip: ZIP Importieren
|
||||||
|
emojiPackCreator: Emoji-Pack Ersteller
|
||||||
|
exportZip: ZIP Exportieren
|
||||||
|
|
|
@ -51,7 +51,7 @@ deleted: "Deleted"
|
||||||
deleteAndEdit: "Delete and edit"
|
deleteAndEdit: "Delete and edit"
|
||||||
deleteAndEditConfirm: "Are you sure you want to delete this post and edit it? You
|
deleteAndEditConfirm: "Are you sure you want to delete this post and edit it? You
|
||||||
will lose all reactions, boosts and replies to it."
|
will lose all reactions, boosts and replies to it."
|
||||||
editNote: "Edit note"
|
editNote: "Edit post"
|
||||||
edited: "Edited at {date} {time}"
|
edited: "Edited at {date} {time}"
|
||||||
addToList: "Add to list"
|
addToList: "Add to list"
|
||||||
sendMessage: "Send a message"
|
sendMessage: "Send a message"
|
||||||
|
@ -337,11 +337,11 @@ emptyDrive: "Your Drive is empty"
|
||||||
emptyFolder: "This folder is empty"
|
emptyFolder: "This folder is empty"
|
||||||
unableToDelete: "Unable to delete"
|
unableToDelete: "Unable to delete"
|
||||||
inputNewFileName: "Enter a new filename"
|
inputNewFileName: "Enter a new filename"
|
||||||
inputNewDescription: "Enter new caption"
|
inputNewDescription: "Enter new description"
|
||||||
inputNewFolderName: "Enter a new folder name"
|
inputNewFolderName: "Enter a new folder name"
|
||||||
circularReferenceFolder: "The destination folder is a subfolder of the folder you
|
circularReferenceFolder: "The destination folder is a subfolder of the folder you
|
||||||
wish to move."
|
wish to move."
|
||||||
hasChildFilesOrFolders: "Since this folder is not empty, it can not be deleted."
|
hasChildFilesOrFolders: "Since this folder is not empty, it cannot be deleted."
|
||||||
copyUrl: "Copy URL"
|
copyUrl: "Copy URL"
|
||||||
rename: "Rename"
|
rename: "Rename"
|
||||||
avatar: "Avatar"
|
avatar: "Avatar"
|
||||||
|
@ -634,8 +634,8 @@ disablePlayer: "Close video player"
|
||||||
expandTweet: "Expand tweet"
|
expandTweet: "Expand tweet"
|
||||||
themeEditor: "Theme editor"
|
themeEditor: "Theme editor"
|
||||||
description: "Description"
|
description: "Description"
|
||||||
describeFile: "Add caption"
|
describeFile: "Add description"
|
||||||
enterFileDescription: "Enter caption"
|
enterFileDescription: "Enter description"
|
||||||
author: "Author"
|
author: "Author"
|
||||||
leaveConfirm: "There are unsaved changes. Do you want to discard them?"
|
leaveConfirm: "There are unsaved changes. Do you want to discard them?"
|
||||||
manage: "Management"
|
manage: "Management"
|
||||||
|
@ -1054,7 +1054,7 @@ showUpdates: "Show a popup when Firefish updates"
|
||||||
recommendedInstances: "Recommended servers"
|
recommendedInstances: "Recommended servers"
|
||||||
recommendedInstancesDescription: "Recommended servers separated by line breaks to
|
recommendedInstancesDescription: "Recommended servers separated by line breaks to
|
||||||
appear in the recommended timeline."
|
appear in the recommended timeline."
|
||||||
caption: "Auto Caption"
|
caption: "Auto description"
|
||||||
splash: "Splash Screen"
|
splash: "Splash Screen"
|
||||||
updateAvailable: "There might be an update available!"
|
updateAvailable: "There might be an update available!"
|
||||||
swipeOnMobile: "Allow swiping between pages"
|
swipeOnMobile: "Allow swiping between pages"
|
||||||
|
@ -1147,6 +1147,9 @@ addRe: "Add \"re:\" at the beginning of comment in reply to a post with a conten
|
||||||
showBigPostButton: "Show a bigger post button in the posting form"
|
showBigPostButton: "Show a bigger post button in the posting form"
|
||||||
confirm: "Confirm"
|
confirm: "Confirm"
|
||||||
emphasizeFollowed: "Highlight the \"Follows you\" sign on your follower info"
|
emphasizeFollowed: "Highlight the \"Follows you\" sign on your follower info"
|
||||||
|
importZip: "Import ZIP"
|
||||||
|
exportZip: "Export ZIP"
|
||||||
|
emojiPackCreator: "Emoji pack creator"
|
||||||
|
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Reduces the effort of server moderation through automatically recognizing
|
description: "Reduces the effort of server moderation through automatically recognizing
|
||||||
|
|
|
@ -572,8 +572,8 @@ updateRemoteUser: "Actualizar información de usuario remoto"
|
||||||
deleteAllFiles: "Borrar todos los archivos"
|
deleteAllFiles: "Borrar todos los archivos"
|
||||||
deleteAllFilesConfirm: "¿Desea borrar todos los archivos?"
|
deleteAllFilesConfirm: "¿Desea borrar todos los archivos?"
|
||||||
removeAllFollowing: "Retener todos los siguientes"
|
removeAllFollowing: "Retener todos los siguientes"
|
||||||
removeAllFollowingDescription: "Cancelar todos los siguientes del servidor {host}.
|
removeAllFollowingDescription: "Al ejecutar esto todas las cuentas de {host} dejarán
|
||||||
Ejecutar en caso de que esta instancia haya dejado de existir."
|
de seguirse. Por favor, ejecuta esto si el servidor ya no existe."
|
||||||
userSuspended: "Este usuario ha sido suspendido."
|
userSuspended: "Este usuario ha sido suspendido."
|
||||||
userSilenced: "Este usuario ha sido silenciado."
|
userSilenced: "Este usuario ha sido silenciado."
|
||||||
yourAccountSuspendedTitle: "Esta cuenta ha sido suspendida"
|
yourAccountSuspendedTitle: "Esta cuenta ha sido suspendida"
|
||||||
|
@ -838,7 +838,7 @@ gallery: "Galería"
|
||||||
recentPosts: "Posts recientes"
|
recentPosts: "Posts recientes"
|
||||||
popularPosts: "Más vistos"
|
popularPosts: "Más vistos"
|
||||||
shareWithNote: "Compartir con una publicación"
|
shareWithNote: "Compartir con una publicación"
|
||||||
ads: "Banners"
|
ads: "Banners de la comunidad"
|
||||||
expiration: "Termina el"
|
expiration: "Termina el"
|
||||||
memo: "Notas"
|
memo: "Notas"
|
||||||
priority: "Prioridad"
|
priority: "Prioridad"
|
||||||
|
@ -892,7 +892,7 @@ unmuteThread: "Mostrar hilo"
|
||||||
ffVisibility: "Visibilidad de seguidores y seguidos"
|
ffVisibility: "Visibilidad de seguidores y seguidos"
|
||||||
ffVisibilityDescription: "Puedes configurar quien puede ver a quienes sigues y quienes
|
ffVisibilityDescription: "Puedes configurar quien puede ver a quienes sigues y quienes
|
||||||
te siguen"
|
te siguen"
|
||||||
continueThread: "Ver la continuación del hilo"
|
continueThread: "Continuar hilo"
|
||||||
deleteAccountConfirm: "La cuenta será borrada irreversiblemente. ¿Está seguro?"
|
deleteAccountConfirm: "La cuenta será borrada irreversiblemente. ¿Está seguro?"
|
||||||
incorrectPassword: "La contraseña es incorrecta"
|
incorrectPassword: "La contraseña es incorrecta"
|
||||||
voteConfirm: "¿Confirma su voto a {choice}?"
|
voteConfirm: "¿Confirma su voto a {choice}?"
|
||||||
|
@ -906,12 +906,12 @@ overridedDeviceKind: "Tipo de dispositivo"
|
||||||
smartphone: "Teléfono smartphone"
|
smartphone: "Teléfono smartphone"
|
||||||
tablet: "Tablet"
|
tablet: "Tablet"
|
||||||
auto: "Automático"
|
auto: "Automático"
|
||||||
themeColor: "Color del tema"
|
themeColor: "Color de la marquesina del servidor"
|
||||||
size: "Tamaño"
|
size: "Tamaño"
|
||||||
numberOfColumn: "Cantidad de columnas"
|
numberOfColumn: "Cantidad de columnas"
|
||||||
searchByGoogle: "Buscar"
|
searchByGoogle: "Buscar"
|
||||||
instanceDefaultLightTheme: "Tema claro por defecto de la instancia"
|
instanceDefaultLightTheme: "Tema claro por defecto del servidor"
|
||||||
instanceDefaultDarkTheme: "Tema oscuro por defecto de la instancia"
|
instanceDefaultDarkTheme: "Tema oscuro por defecto del servidor"
|
||||||
instanceDefaultThemeDescription: "Ingrese el código del tema en formato objeto"
|
instanceDefaultThemeDescription: "Ingrese el código del tema en formato objeto"
|
||||||
mutePeriod: "Período de silenciamiento"
|
mutePeriod: "Período de silenciamiento"
|
||||||
indefinitely: "Sin límite de tiempo"
|
indefinitely: "Sin límite de tiempo"
|
||||||
|
@ -968,7 +968,7 @@ beta: "Beta"
|
||||||
enableAutoSensitive: "Marcar automáticamente contenido NSFW"
|
enableAutoSensitive: "Marcar automáticamente contenido NSFW"
|
||||||
enableAutoSensitiveDescription: "Permite la detección y marcado automático de contenido
|
enableAutoSensitiveDescription: "Permite la detección y marcado automático de contenido
|
||||||
NSFW usando 'Machine Learning' cuando sea posible. Incluso si esta opción está desactivada,
|
NSFW usando 'Machine Learning' cuando sea posible. Incluso si esta opción está desactivada,
|
||||||
puede ser activado para toda la instancia."
|
puede ser activado para todo el servidor."
|
||||||
activeEmailValidationDescription: "Habilita la validación estricta de direcciones
|
activeEmailValidationDescription: "Habilita la validación estricta de direcciones
|
||||||
de correo electrónico, lo cual incluye la revisión de direcciones desechables y
|
de correo electrónico, lo cual incluye la revisión de direcciones desechables y
|
||||||
si se puede comunicar con éstas. Cuando está deshabilitado, sólo el formato de la
|
si se puede comunicar con éstas. Cuando está deshabilitado, sólo el formato de la
|
||||||
|
@ -1085,6 +1085,7 @@ _aboutFirefish:
|
||||||
pleaseDonateToHost: También considera donar a tu propio servidor , {host}, para
|
pleaseDonateToHost: También considera donar a tu propio servidor , {host}, para
|
||||||
ayudar con los costos de operación.
|
ayudar con los costos de operación.
|
||||||
sponsors: Patrocinadores de Firefish
|
sponsors: Patrocinadores de Firefish
|
||||||
|
misskeyContributors: Contribuidores de Misskey
|
||||||
_nsfw:
|
_nsfw:
|
||||||
respect: "Ocultar medios NSFW"
|
respect: "Ocultar medios NSFW"
|
||||||
ignore: "No esconder medios NSFW "
|
ignore: "No esconder medios NSFW "
|
||||||
|
@ -1177,8 +1178,10 @@ _mfm:
|
||||||
fade: Fundido
|
fade: Fundido
|
||||||
advanced: MFM avanzado
|
advanced: MFM avanzado
|
||||||
play: Reproducir MFM
|
play: Reproducir MFM
|
||||||
foregroundDescription: Cambiar el color en primer plano del texto.
|
foregroundDescription: Cambiar el color del texto en primer plano.
|
||||||
background: Color de fondo
|
background: Color de fondo
|
||||||
|
positionDescription: Mueve el contenido en una cantidad especificada.
|
||||||
|
fadeDescription: Funde el contenido dentro y fuera.
|
||||||
_instanceTicker:
|
_instanceTicker:
|
||||||
none: "No mostrar"
|
none: "No mostrar"
|
||||||
remote: "Mostrar a usuarios remotos"
|
remote: "Mostrar a usuarios remotos"
|
||||||
|
@ -1197,7 +1200,7 @@ _channel:
|
||||||
owned: "Dueño"
|
owned: "Dueño"
|
||||||
following: "Siguiendo"
|
following: "Siguiendo"
|
||||||
usersCount: "{n} participantes"
|
usersCount: "{n} participantes"
|
||||||
notesCount: "{n} publicaciones"
|
notesCount: "{n} Publicaciones"
|
||||||
nameOnly: Nombre solamente
|
nameOnly: Nombre solamente
|
||||||
nameAndDescription: Nombre y descripción
|
nameAndDescription: Nombre y descripción
|
||||||
_menuDisplay:
|
_menuDisplay:
|
||||||
|
@ -1301,7 +1304,7 @@ _theme:
|
||||||
fgHighlighted: "Texto resaltado"
|
fgHighlighted: "Texto resaltado"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Nueva publicación"
|
note: "Nueva publicación"
|
||||||
noteMy: "Nota (a mí mismo)"
|
noteMy: "Publicación propia"
|
||||||
notification: "Notificaciones"
|
notification: "Notificaciones"
|
||||||
chat: "Chat"
|
chat: "Chat"
|
||||||
chatBg: "Chat (Fondo)"
|
chatBg: "Chat (Fondo)"
|
||||||
|
@ -1310,11 +1313,11 @@ _sfx:
|
||||||
_ago:
|
_ago:
|
||||||
future: "Futuro"
|
future: "Futuro"
|
||||||
justNow: "Recién ahora"
|
justNow: "Recién ahora"
|
||||||
secondsAgo: "Hace {n} segundo(s)"
|
secondsAgo: "Hace {n} s"
|
||||||
minutesAgo: "Hace {n} minuto(s)"
|
minutesAgo: "Hace {n} m"
|
||||||
hoursAgo: "Hace {n} hora(s)"
|
hoursAgo: "Hace {n} hora(s)"
|
||||||
daysAgo: "Hace {n} día(s)"
|
daysAgo: "Hace {n} d"
|
||||||
weeksAgo: "Hace {n} semana(s)"
|
weeksAgo: "Hace {n} sem"
|
||||||
monthsAgo: "Hace {n} mes(es)"
|
monthsAgo: "Hace {n} mes(es)"
|
||||||
yearsAgo: "Hace {n} año(s)"
|
yearsAgo: "Hace {n} año(s)"
|
||||||
_time:
|
_time:
|
||||||
|
@ -1339,15 +1342,15 @@ _tutorial:
|
||||||
step5_1: "¡Líneas de tiempo, líneas de tiempo por todas partes!"
|
step5_1: "¡Líneas de tiempo, líneas de tiempo por todas partes!"
|
||||||
step5_2: "Tu servidor tiene {timelines} diferentes líneas de tiempo habilitadas."
|
step5_2: "Tu servidor tiene {timelines} diferentes líneas de tiempo habilitadas."
|
||||||
step5_3: "La línea de tiempo Inicio {icon} es donde puedes ver las publicaciones
|
step5_3: "La línea de tiempo Inicio {icon} es donde puedes ver las publicaciones
|
||||||
de tus seguidores."
|
de personas que sigues."
|
||||||
step5_4: "La línea de tiempo Local {icon} es donde puedes ver las publicaciones
|
step5_4: "La línea de tiempo Local {icon} es donde puedes ver las publicaciones
|
||||||
de todos los demás en esta instancia."
|
de todos los demás en este servidor."
|
||||||
step5_5: "La línea de tiempo {icon} recomendada es donde puedes ver las publicaciones
|
step5_5: "La línea de tiempo {icon} social es una combinación de las líneas de tiempo
|
||||||
de las instancias que los administradores recomiendan."
|
Inicio y Local."
|
||||||
step5_6: "La línea de tiempo Social {icon} es donde puedes ver las publicaciones
|
step5_6: "La línea de tiempo {icon} recomendada es donde puedes ver las publicaciones
|
||||||
de los amigos de tus seguidores."
|
de los servidores que los administradores recomiendan."
|
||||||
step5_7: "La línea de tiempo Global {icon} es donde puedes ver las publicaciones
|
step5_7: "La línea de tiempo {icon} global es donde puedes ver las publicaciones
|
||||||
de todas las demás instancias conectadas."
|
de todos los demás servidores a los cuales este servidor conecta."
|
||||||
step6_1: "Entonces, ¿qué es este lugar?"
|
step6_1: "Entonces, ¿qué es este lugar?"
|
||||||
step6_2: "Bueno, no sólo te has unido a Firefish. Te has unido a un portal del Fediverso,
|
step6_2: "Bueno, no sólo te has unido a Firefish. Te has unido a un portal del Fediverso,
|
||||||
una red interconectada de miles de servidores, llamada \"instancias\""
|
una red interconectada de miles de servidores, llamada \"instancias\""
|
||||||
|
@ -1368,6 +1371,26 @@ _2fa:
|
||||||
securityKeyInfo: "Se puede configurar el inicio de sesión usando una clave de seguridad
|
securityKeyInfo: "Se puede configurar el inicio de sesión usando una clave de seguridad
|
||||||
de hardware que soporte FIDO2 o con un certificado de huella digital o con un
|
de hardware que soporte FIDO2 o con un certificado de huella digital o con un
|
||||||
PIN"
|
PIN"
|
||||||
|
chromePasskeyNotSupported: Contraseñas de Chrome no están soportadas.
|
||||||
|
removeKeyConfirm: ¿Realmente deseas borrar la clave {name}?
|
||||||
|
step3Title: Ingresa un código de autorización
|
||||||
|
renewTOTP: Reconfigurar la aplicación autorizadora
|
||||||
|
whyTOTPOnlyRenew: La aplicación autorizadora no puede ser quitada mientras la clave
|
||||||
|
de seguridad siga registrada.
|
||||||
|
renewTOTPConfirm: Esto causará que los códigos de verificación de la aplicación
|
||||||
|
anterior dejen de funcionar
|
||||||
|
renewTOTPOk: Reconfigurar
|
||||||
|
securityKeyNotSupported: Tu navegador no soporta claves de seguridad.
|
||||||
|
step2Click: Presionar este código QR te permitirá registrar la autorización 2FA
|
||||||
|
a tu clave de seguridad o aplicación autorizadora.
|
||||||
|
registerTOTPBeforeKey: Por favor configura una aplicación autorizadora para registrar
|
||||||
|
una clave de seguridad o de paso.
|
||||||
|
securityKeyName: Ingresa el nombre de la clave
|
||||||
|
tapSecurityKey: Por favor, espera al navegador para registrar la clave de seguridad
|
||||||
|
o de paso
|
||||||
|
renewTOTPCancel: Cancelar
|
||||||
|
token: Token 2FA
|
||||||
|
removeKey: Quitar clave de seguridad
|
||||||
_permissions:
|
_permissions:
|
||||||
"read:account": "Ver información de la cuenta"
|
"read:account": "Ver información de la cuenta"
|
||||||
"write:account": "Editar información de la cuenta"
|
"write:account": "Editar información de la cuenta"
|
||||||
|
@ -1383,7 +1406,7 @@ _permissions:
|
||||||
"write:messaging": "Administrar chat"
|
"write:messaging": "Administrar chat"
|
||||||
"read:mutes": "Ver usuarios silenciados"
|
"read:mutes": "Ver usuarios silenciados"
|
||||||
"write:mutes": "Administrar usuarios silenciados"
|
"write:mutes": "Administrar usuarios silenciados"
|
||||||
"write:notes": "Crear/borrar notas"
|
"write:notes": "Crear o borrar publicaciones"
|
||||||
"read:notifications": "Ver notificaciones"
|
"read:notifications": "Ver notificaciones"
|
||||||
"write:notifications": "Administrar notificaciones"
|
"write:notifications": "Administrar notificaciones"
|
||||||
"read:reactions": "Ver reacciones"
|
"read:reactions": "Ver reacciones"
|
||||||
|
@ -1405,16 +1428,19 @@ _auth:
|
||||||
shareAccess: "¿Desea permitir el acceso a la cuenta \"{name}\"?"
|
shareAccess: "¿Desea permitir el acceso a la cuenta \"{name}\"?"
|
||||||
shareAccessAsk: "¿Está seguro de que desea autorizar esta aplicación para acceder
|
shareAccessAsk: "¿Está seguro de que desea autorizar esta aplicación para acceder
|
||||||
a su cuenta?"
|
a su cuenta?"
|
||||||
permissionAsk: "Esta aplicación requiere los siguientes permisos"
|
permissionAsk: "Esta aplicación requiere los siguientes permisos:"
|
||||||
pleaseGoBack: "Por favor, vuelve a la aplicación"
|
pleaseGoBack: "Por favor, vuelve a la aplicación"
|
||||||
callback: "Volviendo a la aplicación"
|
callback: "Volviendo a la aplicación"
|
||||||
denied: "Acceso denegado"
|
denied: "Acceso denegado"
|
||||||
|
copyAsk: 'Por favor, pega el siguiente código de autorización en la aplicación:'
|
||||||
|
allPermissions: Acceso completo
|
||||||
_antennaSources:
|
_antennaSources:
|
||||||
all: "Todas las notas"
|
all: "Todas las publicaciones"
|
||||||
homeTimeline: "Notas de los usuarios que sigues"
|
homeTimeline: "Publicaciones de los usuarios que sigues"
|
||||||
users: "Notas de un usuario o varios"
|
users: "Publicaciones de usuarios específicos"
|
||||||
userList: "Notas de los usuarios de una lista"
|
userList: "Publicaciones de una lista de usuarios específica"
|
||||||
userGroup: "Notas de los usuarios de una grupo"
|
userGroup: "Publicaciones de usuarios de un grupo"
|
||||||
|
instances: Publicaciones de todos los usuarios en un servidor
|
||||||
_weekday:
|
_weekday:
|
||||||
sunday: "Domingo"
|
sunday: "Domingo"
|
||||||
monday: "Lunes"
|
monday: "Lunes"
|
||||||
|
@ -1431,24 +1457,28 @@ _widgets:
|
||||||
trends: "Tendencias"
|
trends: "Tendencias"
|
||||||
clock: "Reloj"
|
clock: "Reloj"
|
||||||
rss: "Lector RSS"
|
rss: "Lector RSS"
|
||||||
rssTicker: "Ticker-RSS"
|
rssTicker: "Marquesina RSS"
|
||||||
activity: "Actividad"
|
activity: "Actividad"
|
||||||
photos: "Fotos"
|
photos: "Fotos"
|
||||||
digitalClock: "Reloj digital"
|
digitalClock: "Reloj digital"
|
||||||
unixClock: "Reloj UNIX"
|
unixClock: "Reloj UNIX"
|
||||||
federation: "Federación"
|
federation: "Federación"
|
||||||
instanceCloud: "Nube de palabras de la instancia"
|
instanceCloud: "Nube de servidores"
|
||||||
postForm: "Formulario"
|
postForm: "Formulario"
|
||||||
slideshow: "Diapositivas"
|
slideshow: "Diapositivas"
|
||||||
button: "Botón"
|
button: "Botón"
|
||||||
onlineUsers: "Usuarios en linea"
|
onlineUsers: "Usuarios en línea"
|
||||||
jobQueue: "Cola de trabajos"
|
jobQueue: "Cola de trabajos"
|
||||||
serverMetric: "Estadísticas del servidor"
|
serverMetric: "Estadísticas del servidor"
|
||||||
aiscript: "Consola de AiScript"
|
aiscript: "Consola de AiScript"
|
||||||
aichan: "indigo"
|
aichan: "indigo"
|
||||||
userList: Lista Usuarios
|
userList: Lista de usuarios
|
||||||
_userList:
|
_userList:
|
||||||
chooseList: Seleccione una lista
|
chooseList: Seleccione una lista
|
||||||
|
serverInfo: Información del servidor
|
||||||
|
meiliStatus: Estado del servidor
|
||||||
|
meiliSize: Tamaño del índice
|
||||||
|
meiliIndexCount: Publicaciones indizadas
|
||||||
_cw:
|
_cw:
|
||||||
hide: "Ocultar"
|
hide: "Ocultar"
|
||||||
show: "Ver más"
|
show: "Ver más"
|
||||||
|
@ -1478,18 +1508,18 @@ _poll:
|
||||||
remainingSeconds: "Quedan {s} segundos para que finalice"
|
remainingSeconds: "Quedan {s} segundos para que finalice"
|
||||||
_visibility:
|
_visibility:
|
||||||
public: "Público"
|
public: "Público"
|
||||||
publicDescription: "Visible para todos los usuarios"
|
publicDescription: "Tu publicación será visible en todas las líneas de tiempo"
|
||||||
home: "Inicio"
|
home: "Sin listar (Inicio)"
|
||||||
homeDescription: "Visible sólo en la linea de tiempo de inicio"
|
homeDescription: "Visible sólo en la linea de tiempo de inicio"
|
||||||
followers: "Seguidores"
|
followers: "Seguidores"
|
||||||
followersDescription: "Visible sólo para tus seguidores"
|
followersDescription: "Hacer sólo visible sólo para tus seguidores y usuarios mencionados"
|
||||||
specified: "Mensaje directo"
|
specified: "Mensaje directo"
|
||||||
specifiedDescription: "Visible sólo para los usuarios elegidos"
|
specifiedDescription: "Visible sólo para los usuarios elegidos"
|
||||||
localOnly: "Solo local"
|
localOnly: "Solo local"
|
||||||
localOnlyDescription: "Oculto para usuarios remotos"
|
localOnlyDescription: "Oculto para usuarios remotos"
|
||||||
_postForm:
|
_postForm:
|
||||||
replyPlaceholder: "Responder a esta nota"
|
replyPlaceholder: "Responder a esta publicación..."
|
||||||
quotePlaceholder: "Citar esta nota"
|
quotePlaceholder: "Citar esta publicación..."
|
||||||
channelPlaceholder: "Postear en el canal"
|
channelPlaceholder: "Postear en el canal"
|
||||||
_placeholders:
|
_placeholders:
|
||||||
a: "¿Qué haces?"
|
a: "¿Qué haces?"
|
||||||
|
@ -1514,7 +1544,7 @@ _profile:
|
||||||
locationDescription: Si ingresas tu ciudad primero, el tiempo local tuyo será visible
|
locationDescription: Si ingresas tu ciudad primero, el tiempo local tuyo será visible
|
||||||
para otros usuarios.
|
para otros usuarios.
|
||||||
_exportOrImport:
|
_exportOrImport:
|
||||||
allNotes: "Todas las notas"
|
allNotes: "Todas las publicaciones"
|
||||||
followingList: "Siguiendo"
|
followingList: "Siguiendo"
|
||||||
muteList: "Silenciados"
|
muteList: "Silenciados"
|
||||||
blockingList: "Bloqueados"
|
blockingList: "Bloqueados"
|
||||||
|
@ -1527,10 +1557,10 @@ _charts:
|
||||||
usersIncDec: "Variación de usuarios"
|
usersIncDec: "Variación de usuarios"
|
||||||
usersTotal: "Total de usuarios"
|
usersTotal: "Total de usuarios"
|
||||||
activeUsers: "Cantidad de usuarios activos"
|
activeUsers: "Cantidad de usuarios activos"
|
||||||
notesIncDec: "Variación de la cantidad de notas"
|
notesIncDec: "Diferencia en la cantidad de publicaciones"
|
||||||
localNotesIncDec: "Variación de la cantidad de notas locales"
|
localNotesIncDec: "Diferencia en la cantidad de publicaciones locales"
|
||||||
remoteNotesIncDec: "Variación de la cantidad de notas remotas"
|
remoteNotesIncDec: "Diferencia en el número de publicaciones remotas"
|
||||||
notesTotal: "Total de notas"
|
notesTotal: "Total de publicaciones"
|
||||||
filesIncDec: "Variación de cantidad de archivos"
|
filesIncDec: "Variación de cantidad de archivos"
|
||||||
filesTotal: "Total de archivos"
|
filesTotal: "Total de archivos"
|
||||||
storageUsageIncDec: "Variación de uso del almacenamiento"
|
storageUsageIncDec: "Variación de uso del almacenamiento"
|
||||||
|
@ -1539,8 +1569,8 @@ _instanceCharts:
|
||||||
requests: "Pedidos"
|
requests: "Pedidos"
|
||||||
users: "Variación de usuarios"
|
users: "Variación de usuarios"
|
||||||
usersTotal: "Total acumulado de usuarios"
|
usersTotal: "Total acumulado de usuarios"
|
||||||
notes: "Variación de la cantidad de notas"
|
notes: "Diferencia en el número de publicaciones"
|
||||||
notesTotal: "Total acumulado de la cantidad de notas"
|
notesTotal: "Total acumulado de publicaciones"
|
||||||
ff: "Variación de cantidad de seguidos/seguidores"
|
ff: "Variación de cantidad de seguidos/seguidores"
|
||||||
ffTotal: "Total acumulado de cantidad de seguidos/seguidores"
|
ffTotal: "Total acumulado de cantidad de seguidos/seguidores"
|
||||||
cacheSize: "Variación del tamaño de la caché"
|
cacheSize: "Variación del tamaño de la caché"
|
||||||
|
@ -1627,10 +1657,10 @@ _pages:
|
||||||
id: "Lienzo ID"
|
id: "Lienzo ID"
|
||||||
width: "Ancho"
|
width: "Ancho"
|
||||||
height: "Altura"
|
height: "Altura"
|
||||||
note: "Nota embebida"
|
note: "Publicación incrustada"
|
||||||
_note:
|
_note:
|
||||||
id: "Id de la nota"
|
id: "ID de la publicación"
|
||||||
idDescription: "Pega la URL de la nota para configurarla"
|
idDescription: "Puedes también pegar la URL de la publicación aquí."
|
||||||
detailed: "Ver Detalles"
|
detailed: "Ver Detalles"
|
||||||
switch: "Interruptor"
|
switch: "Interruptor"
|
||||||
_switch:
|
_switch:
|
||||||
|
@ -1853,7 +1883,7 @@ _notification:
|
||||||
youGotMention: "Mención de {name}"
|
youGotMention: "Mención de {name}"
|
||||||
youGotReply: "Respuesta de {name}"
|
youGotReply: "Respuesta de {name}"
|
||||||
youGotQuote: "Citado por {name}"
|
youGotQuote: "Citado por {name}"
|
||||||
youRenoted: "Renotado por {name}"
|
youRenoted: "Impulsado por {name}"
|
||||||
youGotPoll: "Encuestado por {name}"
|
youGotPoll: "Encuestado por {name}"
|
||||||
youGotMessagingMessageFromUser: "{name} comenzó un chat contigo"
|
youGotMessagingMessageFromUser: "{name} comenzó un chat contigo"
|
||||||
youGotMessagingMessageFromGroup: "Tienes un chat de {name}"
|
youGotMessagingMessageFromGroup: "Tienes un chat de {name}"
|
||||||
|
@ -1868,7 +1898,7 @@ _notification:
|
||||||
follow: "Siguiendo"
|
follow: "Siguiendo"
|
||||||
mention: "Menciones"
|
mention: "Menciones"
|
||||||
reply: "Respuestas"
|
reply: "Respuestas"
|
||||||
renote: "Renotar"
|
renote: "Impulsos"
|
||||||
quote: "Citar"
|
quote: "Citar"
|
||||||
reaction: "Reacción"
|
reaction: "Reacción"
|
||||||
pollVote: "Votado en la encuesta"
|
pollVote: "Votado en la encuesta"
|
||||||
|
@ -1880,7 +1910,10 @@ _notification:
|
||||||
_actions:
|
_actions:
|
||||||
followBack: "Te sigue de vuelta"
|
followBack: "Te sigue de vuelta"
|
||||||
reply: "Responder"
|
reply: "Responder"
|
||||||
renote: "Renotar"
|
renote: "Impulsos"
|
||||||
|
renoted: impulsó tu publicación
|
||||||
|
reacted: reaccionó a tu publicación
|
||||||
|
voted: votó en tu encuesta
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "Siempre mostrar la columna principal"
|
alwaysShowMainColumn: "Siempre mostrar la columna principal"
|
||||||
columnAlign: "Alinear columnas"
|
columnAlign: "Alinear columnas"
|
||||||
|
@ -1892,9 +1925,9 @@ _deck:
|
||||||
swapDown: "Mover abajo"
|
swapDown: "Mover abajo"
|
||||||
stackLeft: "Apilar a la izquierda"
|
stackLeft: "Apilar a la izquierda"
|
||||||
popRight: "Sacar a la derecha"
|
popRight: "Sacar a la derecha"
|
||||||
profile: "Perfil"
|
profile: "Espacio de trabajo"
|
||||||
newProfile: "Nuevo perfil"
|
newProfile: "Nuevo espacio de trabajo"
|
||||||
deleteProfile: "Eliminar perfil"
|
deleteProfile: "Eliminar espacio de trabajo"
|
||||||
introduction: "¡Crea la interfaz perfecta para tí organizando las columnas libremente!"
|
introduction: "¡Crea la interfaz perfecta para tí organizando las columnas libremente!"
|
||||||
introduction2: "Presiona en la + de la derecha de la pantalla para añadir nuevas
|
introduction2: "Presiona en la + de la derecha de la pantalla para añadir nuevas
|
||||||
columnas donde quieras."
|
columnas donde quieras."
|
||||||
|
@ -1905,10 +1938,13 @@ _deck:
|
||||||
widgets: "Widgets"
|
widgets: "Widgets"
|
||||||
notifications: "Notificaciones"
|
notifications: "Notificaciones"
|
||||||
tl: "Linea de tiempo"
|
tl: "Linea de tiempo"
|
||||||
antenna: "Antenas"
|
antenna: "Antena"
|
||||||
list: "Listas"
|
list: "Listas"
|
||||||
mentions: "Menciones"
|
mentions: "Menciones"
|
||||||
direct: "Mensaje directo"
|
direct: "Mensajes directos"
|
||||||
|
channel: Canal
|
||||||
|
renameProfile: Renombrar espacio de trabajo
|
||||||
|
nameAlreadyExists: Este nombre de espacio de trabajo ya existe.
|
||||||
manageGroups: Administrar grupos
|
manageGroups: Administrar grupos
|
||||||
replayTutorial: Repetir Tutorial
|
replayTutorial: Repetir Tutorial
|
||||||
privateMode: Modo privado
|
privateMode: Modo privado
|
||||||
|
@ -1923,11 +1959,13 @@ breakFollowConfirm: ¿Estás seguro de que quieres eliminar el seguidor?
|
||||||
subscribePushNotification: Habilitar notificaciones
|
subscribePushNotification: Habilitar notificaciones
|
||||||
unsubscribePushNotification: Desactivar notificaciones
|
unsubscribePushNotification: Desactivar notificaciones
|
||||||
pushNotificationAlreadySubscribed: Las notificaciones ya están activados
|
pushNotificationAlreadySubscribed: Las notificaciones ya están activados
|
||||||
pushNotificationNotSupported: Su navegador o instancia no admite notificaciones
|
pushNotificationNotSupported: Su navegador o servidor no admite notificaciones
|
||||||
moveAccount: ¡Mover cuenta!
|
moveAccount: ¡Mover cuenta!
|
||||||
moveFrom: Mueve a esta cuenta de una cuenta antigua
|
moveFrom: Mueve a esta cuenta de una cuenta antigua
|
||||||
moveFromLabel: 'La cuenta que estás moviendo de:'
|
moveFromLabel: 'La cuenta que estás moviendo de:'
|
||||||
moveAccountDescription: ''
|
moveAccountDescription: 'Este proceso es irreversible. Asegúrate de configurar un
|
||||||
|
alias para ésta cuenta en tu cuenta nueva antes de comenzar. Por favor, ingresa
|
||||||
|
la etiqueta de la cuenta en el formato siguiente: @persona@servidor.tld'
|
||||||
license: Licencia
|
license: Licencia
|
||||||
noThankYou: No gracias
|
noThankYou: No gracias
|
||||||
userSaysSomethingReason: '{name} dijo {reason}'
|
userSaysSomethingReason: '{name} dijo {reason}'
|
||||||
|
@ -1938,7 +1976,7 @@ caption: Auto Subtítulos
|
||||||
showAds: Mostrar banners
|
showAds: Mostrar banners
|
||||||
enterSendsMessage: Presione "RETORNO" en los mensajes para enviar el mensaje (para
|
enterSendsMessage: Presione "RETORNO" en los mensajes para enviar el mensaje (para
|
||||||
apagarlo es Ctrl + RETORNO)
|
apagarlo es Ctrl + RETORNO)
|
||||||
recommendedInstances: Instancias Recomendadas
|
recommendedInstances: Servidores recomendados
|
||||||
instanceSecurity: Seguridad del servidor
|
instanceSecurity: Seguridad del servidor
|
||||||
seperateRenoteQuote: Separar botones de Impulsar y Citar
|
seperateRenoteQuote: Separar botones de Impulsar y Citar
|
||||||
_messaging:
|
_messaging:
|
||||||
|
@ -1995,6 +2033,10 @@ _filters:
|
||||||
fromUser: Del usuario
|
fromUser: Del usuario
|
||||||
fromDomain: Desde el dominio
|
fromDomain: Desde el dominio
|
||||||
notesAfter: Publicaciones posteriores
|
notesAfter: Publicaciones posteriores
|
||||||
|
followingOnly: Sólo seguidos
|
||||||
|
withFile: Con archivo
|
||||||
|
followersOnly: Sólo seguidores
|
||||||
|
notesBefore: Publicaciones anteriores
|
||||||
userSaysSomethingReasonReply: '{name} respondió a una publicación que contiene {reason}'
|
userSaysSomethingReasonReply: '{name} respondió a una publicación que contiene {reason}'
|
||||||
userSaysSomethingReasonQuote: '{name} citó una publicación que contiene {reason}'
|
userSaysSomethingReasonQuote: '{name} citó una publicación que contiene {reason}'
|
||||||
privateModeInfo: Al activar, solo servidores autorizados podrán federar con tu servidor.
|
privateModeInfo: Al activar, solo servidores autorizados podrán federar con tu servidor.
|
||||||
|
@ -2022,3 +2064,103 @@ remindMeLater: Recordar nuevamente
|
||||||
removeQuote: Eliminar cita
|
removeQuote: Eliminar cita
|
||||||
removeRecipient: Eliminar destinatario
|
removeRecipient: Eliminar destinatario
|
||||||
removeMember: Eliminar miembro
|
removeMember: Eliminar miembro
|
||||||
|
_skinTones:
|
||||||
|
light: Claro
|
||||||
|
dark: Obscuro
|
||||||
|
yellow: Amarillo
|
||||||
|
medium: Medio
|
||||||
|
mediumLight: Claro medio
|
||||||
|
mediumDark: Obscuro medio
|
||||||
|
secureModeInfo: Al pedir a otros servidores, no mandar si no hay prueba de confianza.
|
||||||
|
enableIdenticonGeneration: Activar la generación de Identicon
|
||||||
|
sendModMail: Enviar aviso de moderación
|
||||||
|
reactionPickerSkinTone: Tono de piel preferido en emojis
|
||||||
|
_dialog:
|
||||||
|
charactersExceeded: '¡Límite de caracteres excedido! Actual: {current}/Límite: {max}'
|
||||||
|
charactersBelow: '¡Caracteres insuficientes! Actual: {current}/Límite: {min}'
|
||||||
|
expandOnNoteClick: Abrir publicación al hacer click
|
||||||
|
_experiments:
|
||||||
|
enablePostImports: Habilitar importación de publicaciones
|
||||||
|
title: Experimentos
|
||||||
|
postImportsCaption: Permite a los usuarios importar sus publicaciones desde Firefish,
|
||||||
|
Misskey, Mastodon, Akkoma y Pleroma. Puede causar una bajada en el rendimiento
|
||||||
|
del servidor si la cola de trabajos está atascada.
|
||||||
|
showUpdates: Mostrar una notificación emergente cuando Firefish se actualice
|
||||||
|
recommendedInstancesDescription: Servidores recomendados separador por saltos de línea
|
||||||
|
para que aparezcan el la línea de tiempo recomendados.
|
||||||
|
swipeOnMobile: Permitir el pase entre páginas
|
||||||
|
addRe: Añadir "re:" al comienzo del comentario en una respuesta a una publicación
|
||||||
|
sin aviso de contenido
|
||||||
|
showAdminUpdates: Avisar si hay una nueva versión de Firefish disponible (sólo adminsitrador)
|
||||||
|
_feeds:
|
||||||
|
rss: RSS
|
||||||
|
copyFeed: Copiar feed
|
||||||
|
atom: Atom
|
||||||
|
jsonFeed: Feed JSON
|
||||||
|
secureMode: Modo seguro (Recuperación Autorizada)
|
||||||
|
splash: Pantalla de bienvenida
|
||||||
|
moveToLabel: 'Cuenta a la cual estás migrando:'
|
||||||
|
alt: ALT
|
||||||
|
video: Video
|
||||||
|
audio: Audio
|
||||||
|
swipeOnDesktop: Permitir el pase de páginas del estilo móvil en el escritorio
|
||||||
|
enableCustomKaTeXMacro: Habilitar macros KaTeX personalizadas
|
||||||
|
noteId: ID de publicación
|
||||||
|
preventAiLearning: Prevenir el uso por parte de bots de IA
|
||||||
|
isLocked: Esta cuenta requiere aprobación de seguidores
|
||||||
|
origin: Origen
|
||||||
|
newer: reciente
|
||||||
|
older: antiguo
|
||||||
|
objectStorageS3ForcePathStyle: Usar URL de punto final basada en rutas
|
||||||
|
objectStorageS3ForcePathStyleDesc: Activa esto para construir puntos finales URL en
|
||||||
|
el formato 's3.amazonaws.com/<bucket>/' en lugar de '<bucket>.s3.amazonaws.com'.
|
||||||
|
customSplashIconsDescription: URL para los iconos de la pantalla de bienvenida separadas
|
||||||
|
por saltos de línea para ser mostrados al azar cada vez que el usuario carga/recarga
|
||||||
|
la página. Por favor, asegúrate que las imágenes sean URL estáticas, preferentemente
|
||||||
|
a 192x192.
|
||||||
|
updateAvailable: ¡Quizá hay una actualización disponible!
|
||||||
|
moveTo: Mover la cuenta actual a una cuenta nueva
|
||||||
|
moveFromDescription: 'Esto pondrá un alias en tu cuenta antigua para así poder migrar
|
||||||
|
desde esa cuenta a la nueva. Haz esto ANTES de migrar tu cuenta antigua. Por favor,
|
||||||
|
ingresa la etiqueta de la cuenta con el formato siguiente: @persona@servidor.tld'
|
||||||
|
defaultReaction: Emoji por defecto para reaccionar a las publicaciones entrantes y
|
||||||
|
salientes
|
||||||
|
indexFromDescription: Deja en blanco para indizar todas las publicaciones
|
||||||
|
deletePasskeys: Borrar claves de paso
|
||||||
|
deletePasskeysConfirm: Esto borrará irreversiblemente todas las claves de paso y de
|
||||||
|
seguridad en esta cuenta, ¿Proceder?
|
||||||
|
inputNotMatch: Las entradas no coinciden
|
||||||
|
indexFrom: Indizar desde la ID de la publicación en adelante
|
||||||
|
indexPosts: Indizar publicaciones
|
||||||
|
isModerator: Moderador
|
||||||
|
isAdmin: Administrador
|
||||||
|
isPatron: Mecenas de Firefish
|
||||||
|
logoImageUrl: URL de la imagen del logotipo
|
||||||
|
xl: XL
|
||||||
|
migrationConfirm: "¿Estás absolutamente seguro de que quieres migrar a tu cuenta a
|
||||||
|
{account}? Una vez hecho esto, no podrás revertir el cambio, ni tampoco usar tu
|
||||||
|
cuenta normalmente.\nTambién, asegúrate de que has configurado ésta cuenta como
|
||||||
|
la cuenta desde la cual estás migrando."
|
||||||
|
indexNotice: Indizando ahora. Esto puede llevar bastante tiempo, por favor, no reinicies
|
||||||
|
el servidor por lo menos hasta dentro de una hora.
|
||||||
|
customKaTeXMacro: Macros KaTeX personalizadas
|
||||||
|
customKaTeXMacroDescription: '¡Configura macros para escribir expresiones matemáticas
|
||||||
|
fácilmente! La notación es conforme la las definiciones de comandos LaTeX y puede
|
||||||
|
ser escrita como \nuevocomando{\ nombre}{contenido} o \nuevocomando{\nombre}[número
|
||||||
|
de argumentos]{contenido}. Por ejemplo, \nuevocomando{\añadir}[2]{#1 + #2} expanderá
|
||||||
|
\añadir{3}{foo} a 3 + foo. Las llaves que contienen al nombre de la macro serán
|
||||||
|
cambiadas a paréntesis o corchetes. Esto afecta a los corchetes usados para argumentos.
|
||||||
|
Una (y sólo una) macro puede ser definida por línea, y no podrás saltar la línea
|
||||||
|
en medio de la definición. Líneas erróneas son ignoradas. Sólo funciones de sustitución
|
||||||
|
simple son soportadas; sintaxis avanzada, como ramificación condicional no puede
|
||||||
|
ser usada aquí.'
|
||||||
|
signupsDisabled: Los registros en esta instancia están desactivados, pero, ¡siempre
|
||||||
|
podrás registrarte en otro servidor! Si tienes un código de invitación para este
|
||||||
|
servidor, por favor, rellena el campo siguiente.
|
||||||
|
preventAiLearningDescription: Pedir a los modelos de IA no analizar el contenido de
|
||||||
|
publicas, como publicaciones e imágenes.
|
||||||
|
noGraze: Por favor desactiva la extensión de navegador "Graze for Mastodon" ya que
|
||||||
|
interfiere con Firefish.
|
||||||
|
silencedWarning: Esta página se muestra debido a que estos usuarios son de servidores
|
||||||
|
que tu administrador ha silenciado, ya que son presumiblemente fuente de spam.
|
||||||
|
isBot: Esta cuenta es un bot
|
||||||
|
|
|
@ -53,7 +53,7 @@ sendMessage: "Envoyer un message"
|
||||||
copyUsername: "Copier le nom d’utilisateur·rice"
|
copyUsername: "Copier le nom d’utilisateur·rice"
|
||||||
searchUser: "Chercher un·e utilisateur·rice"
|
searchUser: "Chercher un·e utilisateur·rice"
|
||||||
reply: "Répondre"
|
reply: "Répondre"
|
||||||
loadMore: "Afficher plus"
|
loadMore: "Charger plus"
|
||||||
showMore: "Afficher plus"
|
showMore: "Afficher plus"
|
||||||
showLess: "Fermer"
|
showLess: "Fermer"
|
||||||
youGotNewFollower: "Vous suit"
|
youGotNewFollower: "Vous suit"
|
||||||
|
@ -120,8 +120,8 @@ reactionSettingDescription2: "Déplacer pour réorganiser, cliquer pour effacer,
|
||||||
« + » pour ajouter."
|
« + » pour ajouter."
|
||||||
rememberNoteVisibility: "Se souvenir des paramètres de visibilité des publications"
|
rememberNoteVisibility: "Se souvenir des paramètres de visibilité des publications"
|
||||||
attachCancel: "Supprimer le fichier attaché"
|
attachCancel: "Supprimer le fichier attaché"
|
||||||
markAsSensitive: "Marquer comme sensible"
|
markAsSensitive: "Marquer comme sensible (NSFW)"
|
||||||
unmarkAsSensitive: "Supprimer le marquage comme sensible"
|
unmarkAsSensitive: "Supprimer le marquage comme sensible (NSFW)"
|
||||||
enterFileName: "Entrer le nom du fichier"
|
enterFileName: "Entrer le nom du fichier"
|
||||||
mute: "Masquer"
|
mute: "Masquer"
|
||||||
unmute: "Ne plus masquer"
|
unmute: "Ne plus masquer"
|
||||||
|
@ -245,7 +245,7 @@ currentPassword: "Mot de passe actuel"
|
||||||
newPassword: "Nouveau mot de passe"
|
newPassword: "Nouveau mot de passe"
|
||||||
newPasswordRetype: "Répéter le nouveau mot de passe"
|
newPasswordRetype: "Répéter le nouveau mot de passe"
|
||||||
attachFile: "Joindre un fichier"
|
attachFile: "Joindre un fichier"
|
||||||
more: "Plus"
|
more: "Plus !"
|
||||||
featured: "Tendances"
|
featured: "Tendances"
|
||||||
usernameOrUserId: "Nom d’utilisateur·rice ou ID utilisateur"
|
usernameOrUserId: "Nom d’utilisateur·rice ou ID utilisateur"
|
||||||
noSuchUser: "Utilisateur·rice non trouvé·e"
|
noSuchUser: "Utilisateur·rice non trouvé·e"
|
||||||
|
@ -318,7 +318,7 @@ copyUrl: "Copier l’URL"
|
||||||
rename: "Renommer"
|
rename: "Renommer"
|
||||||
avatar: "Avatar"
|
avatar: "Avatar"
|
||||||
banner: "Bannière"
|
banner: "Bannière"
|
||||||
nsfw: "Contenu sensible"
|
nsfw: "Contenu sensible (NSFW)"
|
||||||
whenServerDisconnected: "Lorsque la connexion au serveur est perdue"
|
whenServerDisconnected: "Lorsque la connexion au serveur est perdue"
|
||||||
disconnectedFromServer: "Déconnecté·e du serveur"
|
disconnectedFromServer: "Déconnecté·e du serveur"
|
||||||
reload: "Rafraîchir"
|
reload: "Rafraîchir"
|
||||||
|
@ -516,11 +516,11 @@ showFeaturedNotesInTimeline: "Afficher les publications des Tendances dans le fi
|
||||||
d'actualité"
|
d'actualité"
|
||||||
objectStorage: "Stockage d'objets"
|
objectStorage: "Stockage d'objets"
|
||||||
useObjectStorage: "Utiliser le stockage d'objets"
|
useObjectStorage: "Utiliser le stockage d'objets"
|
||||||
objectStorageBaseUrl: "Base URL"
|
objectStorageBaseUrl: "URL racine"
|
||||||
objectStorageBaseUrlDesc: "Préfixe d’URL utilisé pour construire l’URL vers le référencement
|
objectStorageBaseUrlDesc: "Préfixe d’URL utilisé pour construire l’URL vers le référencement
|
||||||
d’objet (média). Spécifiez son URL si vous utilisez un CDN ou un proxy, sinon spécifiez
|
d’objet (média). Spécifiez son URL si vous utilisez un CDN ou un proxy, sinon spécifiez
|
||||||
l’adresse accessible au public selon le guide de service que vous allez utiliser.\n
|
l’adresse accessible au public selon le guide de service que vous allez utiliser.\n
|
||||||
Ex: 'https://<bucket>.s3.amazonaws.com' pour AWS S3 et 'https://storage.googleapis.com/<bucket>'
|
Ex : 'https://<bucket>.s3.amazonaws.com' pour AWS S3 et 'https://storage.googleapis.com/<bucket>'
|
||||||
pour GCS."
|
pour GCS."
|
||||||
objectStorageBucket: "Bucket"
|
objectStorageBucket: "Bucket"
|
||||||
objectStorageBucketDesc: "Veuillez spécifier le nom du compartiment utilisé sur le
|
objectStorageBucketDesc: "Veuillez spécifier le nom du compartiment utilisé sur le
|
||||||
|
@ -591,7 +591,7 @@ divider: "Séparateur"
|
||||||
addItem: "Ajouter un élément"
|
addItem: "Ajouter un élément"
|
||||||
relays: "Relais"
|
relays: "Relais"
|
||||||
addRelay: "Ajouter un relais"
|
addRelay: "Ajouter un relais"
|
||||||
inboxUrl: "Inbox URL"
|
inboxUrl: "URL de boîte de récéption"
|
||||||
addedRelays: "Relais ajoutés"
|
addedRelays: "Relais ajoutés"
|
||||||
serviceworkerInfo: "Devrait être activé pour les notifications push."
|
serviceworkerInfo: "Devrait être activé pour les notifications push."
|
||||||
deletedNote: "Publication supprimée"
|
deletedNote: "Publication supprimée"
|
||||||
|
@ -729,7 +729,7 @@ noCrawleDescription: "Demandez aux moteurs de recherche de ne pas indexer votre
|
||||||
lockedAccountInfo: "À moins que vous ne définissiez la visibilité de votre publication
|
lockedAccountInfo: "À moins que vous ne définissiez la visibilité de votre publication
|
||||||
sur \"Abonné-e-s\", vos publications sont visibles par tous, même si vous exigez
|
sur \"Abonné-e-s\", vos publications sont visibles par tous, même si vous exigez
|
||||||
que les demandes d'abonnement soient approuvées manuellement."
|
que les demandes d'abonnement soient approuvées manuellement."
|
||||||
alwaysMarkSensitive: "Marquer les médias comme contenu sensible par défaut"
|
alwaysMarkSensitive: "Marquer les médias comme contenu sensible (NSFW) par défaut"
|
||||||
loadRawImages: "Affichage complet des images jointes au lieu des vignettes"
|
loadRawImages: "Affichage complet des images jointes au lieu des vignettes"
|
||||||
disableShowingAnimatedImages: "Désactiver l'animation des images"
|
disableShowingAnimatedImages: "Désactiver l'animation des images"
|
||||||
verificationEmailSent: "Un e-mail de vérification a été envoyé. Veuillez accéder au
|
verificationEmailSent: "Un e-mail de vérification a été envoyé. Veuillez accéder au
|
||||||
|
@ -839,7 +839,7 @@ gallery: "Galerie"
|
||||||
recentPosts: "Publications récentes"
|
recentPosts: "Publications récentes"
|
||||||
popularPosts: "Publications populaires"
|
popularPosts: "Publications populaires"
|
||||||
shareWithNote: "Partager dans une publication"
|
shareWithNote: "Partager dans une publication"
|
||||||
ads: "Bannière communautaire"
|
ads: "Bannières communautaires"
|
||||||
expiration: "Échéance"
|
expiration: "Échéance"
|
||||||
memo: "Pense-bête"
|
memo: "Pense-bête"
|
||||||
priority: "Priorité"
|
priority: "Priorité"
|
||||||
|
@ -986,8 +986,8 @@ _plugin:
|
||||||
manage: "Gestion des plugins"
|
manage: "Gestion des plugins"
|
||||||
_registry:
|
_registry:
|
||||||
scope: "Portée"
|
scope: "Portée"
|
||||||
key: "Clé "
|
key: "Clé"
|
||||||
keys: "Clé "
|
keys: "Clés"
|
||||||
domain: "Domaine"
|
domain: "Domaine"
|
||||||
createKey: "Créer une clé"
|
createKey: "Créer une clé"
|
||||||
_aboutFirefish:
|
_aboutFirefish:
|
||||||
|
@ -1011,8 +1011,8 @@ _aboutFirefish:
|
||||||
le lien ci-dessus pour avoir votre nom affiché ici !
|
le lien ci-dessus pour avoir votre nom affiché ici !
|
||||||
misskeyContributors: Contributeurs Misskey
|
misskeyContributors: Contributeurs Misskey
|
||||||
_nsfw:
|
_nsfw:
|
||||||
respect: "Cacher les médias marqués comme contenu sensible"
|
respect: "Cacher les médias marqués comme contenu sensible (NSFW)"
|
||||||
ignore: "Afficher les médias sensibles"
|
ignore: "Afficher les médias sensibles (NSFW)"
|
||||||
force: "Cacher tous les médias"
|
force: "Cacher tous les médias"
|
||||||
_mfm:
|
_mfm:
|
||||||
cheatSheet: "Antisèche MFM"
|
cheatSheet: "Antisèche MFM"
|
||||||
|
@ -1021,7 +1021,7 @@ _mfm:
|
||||||
dummy: "La Fédiverse s'agrandit avec Firefish"
|
dummy: "La Fédiverse s'agrandit avec Firefish"
|
||||||
mention: "Mentionner"
|
mention: "Mentionner"
|
||||||
mentionDescription: "Vous pouvez afficher un utilisateur spécifique en indiquant
|
mentionDescription: "Vous pouvez afficher un utilisateur spécifique en indiquant
|
||||||
une arobase suivie d'un nom d'utilisateur"
|
le symbole d'arobase (@) suivie d'un nom d'utilisateur."
|
||||||
hashtag: "Hashtags"
|
hashtag: "Hashtags"
|
||||||
hashtagDescription: "Vous pouvez afficher les hashtags en utilisant un croisillon
|
hashtagDescription: "Vous pouvez afficher les hashtags en utilisant un croisillon
|
||||||
et du texte."
|
et du texte."
|
||||||
|
@ -1034,7 +1034,7 @@ _mfm:
|
||||||
small: "Diminuer l'emphase"
|
small: "Diminuer l'emphase"
|
||||||
smallDescription: "Le contenu peut être affiché en petit et fin."
|
smallDescription: "Le contenu peut être affiché en petit et fin."
|
||||||
center: "Centrer"
|
center: "Centrer"
|
||||||
centerDescription: "Le contenu peut être centré"
|
centerDescription: "Centre le contenu sur la page."
|
||||||
inlineCode: "Code (inline)"
|
inlineCode: "Code (inline)"
|
||||||
inlineCodeDescription: "Affiche la coloration syntaxique des lignes de code."
|
inlineCodeDescription: "Affiche la coloration syntaxique des lignes de code."
|
||||||
blockCode: "Bloc de code"
|
blockCode: "Bloc de code"
|
||||||
|
@ -1105,7 +1105,7 @@ _mfm:
|
||||||
background: Couleur d'arrière-plan
|
background: Couleur d'arrière-plan
|
||||||
plain: Simple
|
plain: Simple
|
||||||
_instanceTicker:
|
_instanceTicker:
|
||||||
none: "Cacher "
|
none: "Cacher"
|
||||||
remote: "Montrer pour les utilisateur·ice·s distant·e·s"
|
remote: "Montrer pour les utilisateur·ice·s distant·e·s"
|
||||||
always: "Toujours afficher"
|
always: "Toujours afficher"
|
||||||
_serverDisconnectedBehavior:
|
_serverDisconnectedBehavior:
|
||||||
|
@ -1170,17 +1170,17 @@ _theme:
|
||||||
color: "Couleur"
|
color: "Couleur"
|
||||||
refProp: "Appeler une propriété"
|
refProp: "Appeler une propriété"
|
||||||
refConst: "Appeler une constante"
|
refConst: "Appeler une constante"
|
||||||
key: "Clé "
|
key: "Clé"
|
||||||
func: "Fonction"
|
func: "Fonction"
|
||||||
funcKind: "Type de fonction"
|
funcKind: "Type de fonction"
|
||||||
argument: "Argument"
|
argument: "Argument"
|
||||||
basedProp: "Nom de la propriété référencée"
|
basedProp: "Nom de la propriété référencée"
|
||||||
alpha: "Transparence"
|
alpha: "Transparence"
|
||||||
darken: "Sombre"
|
darken: "Assombrir"
|
||||||
lighten: "Clair"
|
lighten: "Clair"
|
||||||
inputConstantName: "Insérez un nom de constante"
|
inputConstantName: "Insérez un nom de constante"
|
||||||
importInfo: "Vous pouvez importer un thème vers l’éditeur de thèmes en saisissant
|
importInfo: "Vous pouvez importer un thème vers l’éditeur de thèmes en saisissant
|
||||||
son code ici."
|
son code ici"
|
||||||
deleteConstantConfirm: "Êtes-vous sûr·e de vouloir supprimer la constante {const}
|
deleteConstantConfirm: "Êtes-vous sûr·e de vouloir supprimer la constante {const}
|
||||||
?"
|
?"
|
||||||
keys:
|
keys:
|
||||||
|
@ -1252,9 +1252,9 @@ _time:
|
||||||
day: "j"
|
day: "j"
|
||||||
_tutorial:
|
_tutorial:
|
||||||
title: "Comment utiliser Firefish"
|
title: "Comment utiliser Firefish"
|
||||||
step1_1: "Bienvenue!"
|
step1_1: "Bienvenue !"
|
||||||
step1_2: "On va vous installer. Vous serez opérationnel en un rien de temps"
|
step1_2: "On va vous installer. Vous serez opérationnel en un rien de temps !"
|
||||||
step2_1: "Tout d'abord, remplissez votre profil"
|
step2_1: "Tout d'abord, remplissez votre profil."
|
||||||
step2_2: "En fournissant quelques informations sur qui vous êtes, il sera plus facile
|
step2_2: "En fournissant quelques informations sur qui vous êtes, il sera plus facile
|
||||||
pour les autres de savoir s'ils veulent voir vos publcations ou vous suivre."
|
pour les autres de savoir s'ils veulent voir vos publcations ou vous suivre."
|
||||||
step3_1: "Maintenant il est temps de suivre des gens !"
|
step3_1: "Maintenant il est temps de suivre des gens !"
|
||||||
|
@ -1265,7 +1265,7 @@ _tutorial:
|
||||||
step4_2: "Pour votre première publication, certaines personnes aiment faire une
|
step4_2: "Pour votre première publication, certaines personnes aiment faire une
|
||||||
{introduction} ou un simple 'Bonjour tout le monde !'"
|
{introduction} ou un simple 'Bonjour tout le monde !'"
|
||||||
step5_1: "Des fils, des fils d’actualité partout !"
|
step5_1: "Des fils, des fils d’actualité partout !"
|
||||||
step5_2: "Votre serveur a {timelines} fils différents disponibles !"
|
step5_2: "Votre serveur a {timelines} fils différents activés."
|
||||||
step5_3: "Le fil {icon} Principal est l'endroit où vous pouvez voir les publications
|
step5_3: "Le fil {icon} Principal est l'endroit où vous pouvez voir les publications
|
||||||
de vos abonnements."
|
de vos abonnements."
|
||||||
step5_4: "La fil {icon} Local est l'endroit où vous pouvez voir les publications
|
step5_4: "La fil {icon} Local est l'endroit où vous pouvez voir les publications
|
||||||
|
@ -1357,7 +1357,7 @@ _permissions:
|
||||||
_auth:
|
_auth:
|
||||||
shareAccess: "Autoriser \"{name}\" à accéder à votre compte ?"
|
shareAccess: "Autoriser \"{name}\" à accéder à votre compte ?"
|
||||||
shareAccessAsk: "Voulez-vous vraiment autoriser cette application à accéder à votre
|
shareAccessAsk: "Voulez-vous vraiment autoriser cette application à accéder à votre
|
||||||
compte?"
|
compte ?"
|
||||||
permissionAsk: "Cette application nécessite les autorisations suivantes :"
|
permissionAsk: "Cette application nécessite les autorisations suivantes :"
|
||||||
pleaseGoBack: "Veuillez retourner à l’application"
|
pleaseGoBack: "Veuillez retourner à l’application"
|
||||||
callback: "Retour vers l’application"
|
callback: "Retour vers l’application"
|
||||||
|
@ -1412,7 +1412,7 @@ _widgets:
|
||||||
rssTicker: Bandeau RSS
|
rssTicker: Bandeau RSS
|
||||||
_cw:
|
_cw:
|
||||||
hide: "Masquer"
|
hide: "Masquer"
|
||||||
show: "Afficher plus …"
|
show: "Afficher contenu"
|
||||||
chars: "{count} caractères"
|
chars: "{count} caractères"
|
||||||
files: "{count} fichiers"
|
files: "{count} fichiers"
|
||||||
_poll:
|
_poll:
|
||||||
|
@ -1422,8 +1422,8 @@ _poll:
|
||||||
canMultipleVote: "Autoriser le multi-choix"
|
canMultipleVote: "Autoriser le multi-choix"
|
||||||
expiration: "Fin du sondage"
|
expiration: "Fin du sondage"
|
||||||
infinite: "Illimité"
|
infinite: "Illimité"
|
||||||
at: "Choisir une date"
|
at: "Expire le..."
|
||||||
after: "Choisir la durée"
|
after: "Expire après..."
|
||||||
deadlineDate: "Date de fin"
|
deadlineDate: "Date de fin"
|
||||||
deadlineTime: "Heure de fin"
|
deadlineTime: "Heure de fin"
|
||||||
duration: "Durée"
|
duration: "Durée"
|
||||||
|
@ -1468,7 +1468,7 @@ _profile:
|
||||||
metadataEdit: "Éditer les informations supplémentaires"
|
metadataEdit: "Éditer les informations supplémentaires"
|
||||||
metadataDescription: "Vous pouvez afficher jusqu'à quatre informations supplémentaires
|
metadataDescription: "Vous pouvez afficher jusqu'à quatre informations supplémentaires
|
||||||
dans votre profil. Vous pouvez ajouter une balise {a} ou une balise {l} avec {rel}
|
dans votre profil. Vous pouvez ajouter une balise {a} ou une balise {l} avec {rel}
|
||||||
pour vérifier le lien sur votre profil!"
|
pour vérifier le lien sur votre profil !"
|
||||||
metadataLabel: "Étiquette"
|
metadataLabel: "Étiquette"
|
||||||
metadataContent: "Contenu"
|
metadataContent: "Contenu"
|
||||||
changeAvatar: "Changer l'image de profil"
|
changeAvatar: "Changer l'image de profil"
|
||||||
|
@ -1503,7 +1503,7 @@ _instanceCharts:
|
||||||
usersTotal: "Total cumulé du nombre d'utilisateur·rice·s"
|
usersTotal: "Total cumulé du nombre d'utilisateur·rice·s"
|
||||||
notes: "Variation du nombre de publications"
|
notes: "Variation du nombre de publications"
|
||||||
notesTotal: "Nombre total cumulé des publications"
|
notesTotal: "Nombre total cumulé des publications"
|
||||||
ff: "Variation des abonné·e·s / abonnements"
|
ff: "Variation des abonnements / abonné·e·s "
|
||||||
ffTotal: "Total cumulé du nombre d'abonné·e·s / abonnements"
|
ffTotal: "Total cumulé du nombre d'abonné·e·s / abonnements"
|
||||||
cacheSize: "Variation de la taille du cache"
|
cacheSize: "Variation de la taille du cache"
|
||||||
cacheSizeTotal: "Total cumulé de la taille du cache"
|
cacheSizeTotal: "Total cumulé de la taille du cache"
|
||||||
|
@ -1812,7 +1812,7 @@ _relayStatus:
|
||||||
accepted: "Accepté"
|
accepted: "Accepté"
|
||||||
rejected: "Refusée"
|
rejected: "Refusée"
|
||||||
_notification:
|
_notification:
|
||||||
fileUploaded: "Le fichier a été téléversé !"
|
fileUploaded: "Le fichier a été téléversé"
|
||||||
youGotMention: "{name} vous a mentionné"
|
youGotMention: "{name} vous a mentionné"
|
||||||
youGotReply: "Réponse de {name}"
|
youGotReply: "Réponse de {name}"
|
||||||
youGotQuote: "Cité·e par {name}"
|
youGotQuote: "Cité·e par {name}"
|
||||||
|
@ -1993,7 +1993,7 @@ type: Type
|
||||||
speed: Vitesse
|
speed: Vitesse
|
||||||
slow: Lent
|
slow: Lent
|
||||||
move: Déplacer
|
move: Déplacer
|
||||||
showAds: Afficher les bannières communautaire/publicités
|
showAds: Afficher les bannières communautaire (publicités)
|
||||||
enterSendsMessage: Appuyer sur Entrée pendant la rédaction pour envoyer le message
|
enterSendsMessage: Appuyer sur Entrée pendant la rédaction pour envoyer le message
|
||||||
(sinon Ctrl+Entrée)
|
(sinon Ctrl+Entrée)
|
||||||
allowedInstancesDescription: Noms des serveurs autorisés pour la fédération, chacun
|
allowedInstancesDescription: Noms des serveurs autorisés pour la fédération, chacun
|
||||||
|
@ -2071,14 +2071,14 @@ customKaTeXMacro: Macros KaTeX personnalisées
|
||||||
enableCustomKaTeXMacro: Activer les macros KaTeX personnalisées
|
enableCustomKaTeXMacro: Activer les macros KaTeX personnalisées
|
||||||
noteId: ID des publications
|
noteId: ID des publications
|
||||||
customKaTeXMacroDescription: "Définissez des macros pour écrire des expressions mathématiques
|
customKaTeXMacroDescription: "Définissez des macros pour écrire des expressions mathématiques
|
||||||
simplement ! La notation se conforme aux définitions de commandes LaTeX et s'écrit
|
simplement ! La notation se conforme aux définitions de commandes LaTeX et s'écrit
|
||||||
\\newcommand{\\·name}{content} ou \\newcommand{\\name}[number of arguments]{content}.
|
\\newcommand{\\·name}{content} ou \\newcommand{\\name}[number of arguments]{content}.
|
||||||
Par exemple, \\newcommand{\\add}[2]{#1 + #2} étendra \\add{3}{foo} en 3 + foo. Les
|
Par exemple, \\newcommand{\\add}[2]{#1 + #2} étendra \\add{3}{foo} en 3 + foo. Les
|
||||||
accolades entourant le nom de la macro peuvent être changés pour des parenthèses
|
accolades entourant le nom de la macro peuvent être changés pour des parenthèses
|
||||||
ou des crochets. Cela affectera les types de parenthèses utilisées pour les arguments.
|
ou des crochets. Cela affectera les types de parenthèses utilisées pour les arguments.
|
||||||
Une (et une seule) macro peut être définie par ligne, et vous ne pouvez pas couper
|
Une (et une seule) macro peut être définie par ligne, et vous ne pouvez pas couper
|
||||||
la ligne au milieu d'une définition. Les lignes invalides sont simplement ignorées.
|
la ligne au milieu d'une définition. Les lignes invalides sont simplement ignorées.
|
||||||
Seulement de simples fonctions de substitution de chaines sont supportées; la syntaxe
|
Seulement de simples fonctions de substitution de chaines sont supportées ; la syntaxe
|
||||||
avancée, telle que la ramification conditionnelle, ne peut pas être utilisée ici."
|
avancée, telle que la ramification conditionnelle, ne peut pas être utilisée ici."
|
||||||
enableRecommendedTimeline: Activer le fil recommandé
|
enableRecommendedTimeline: Activer le fil recommandé
|
||||||
silenceThisInstance: Masquer ce serveur
|
silenceThisInstance: Masquer ce serveur
|
||||||
|
@ -2197,7 +2197,7 @@ _skinTones:
|
||||||
objectStorageS3ForcePathStyle: Utiliser des URL d'endpoints basées sur le chemin
|
objectStorageS3ForcePathStyle: Utiliser des URL d'endpoints basées sur le chemin
|
||||||
objectStorageS3ForcePathStyleDesc: Activez cette option pour construire les URL d'endpoints
|
objectStorageS3ForcePathStyleDesc: Activez cette option pour construire les URL d'endpoints
|
||||||
au format 's3.amazonaws.com/<bucket>/' au lieu de '<bucket>.s3.amazonaws.com'.
|
au format 's3.amazonaws.com/<bucket>/' au lieu de '<bucket>.s3.amazonaws.com'.
|
||||||
delete2fa: Supprimer 2FA
|
delete2fa: Désativer A2F
|
||||||
deletePasskeys: Supprimer les clés d'accès
|
deletePasskeys: Supprimer les clés d'accès
|
||||||
delete2faConfirm: Cela supprimera de manière irréversible la double authentification
|
delete2faConfirm: Cela supprimera de manière irréversible la double authentification
|
||||||
sur ce compte. Souhaitez-vous continuer ?
|
sur ce compte. Souhaitez-vous continuer ?
|
||||||
|
@ -2206,3 +2206,7 @@ deletePasskeysConfirm: Cela supprimera de manière irréversible toutes les clé
|
||||||
et les clés de sécurité sur ce compte. Souhaitez-vous continuer ?
|
et les clés de sécurité sur ce compte. Souhaitez-vous continuer ?
|
||||||
addRe: Ajouter "re:" au début d’un avertissement de contenu (CW) en réponse à une
|
addRe: Ajouter "re:" au début d’un avertissement de contenu (CW) en réponse à une
|
||||||
publication avec un avertissement de contenu
|
publication avec un avertissement de contenu
|
||||||
|
confirm: Confirmer
|
||||||
|
importZip: Importer ZIP
|
||||||
|
exportZip: Exporter ZIP
|
||||||
|
emojiPackCreator: Créateur de pack d’emoji
|
||||||
|
|
|
@ -310,7 +310,7 @@ emptyDrive: "Drive kosong"
|
||||||
emptyFolder: "Folder kosong"
|
emptyFolder: "Folder kosong"
|
||||||
unableToDelete: "Tidak dapat menghapus"
|
unableToDelete: "Tidak dapat menghapus"
|
||||||
inputNewFileName: "Masukkan nama berkas yang baru"
|
inputNewFileName: "Masukkan nama berkas yang baru"
|
||||||
inputNewDescription: "Masukkan keterangan disini"
|
inputNewDescription: "Masukkan deskripsi baru"
|
||||||
inputNewFolderName: "Masukkan nama folder yang baru"
|
inputNewFolderName: "Masukkan nama folder yang baru"
|
||||||
circularReferenceFolder: "Folder tujuan adalah subfolder dari folder yang ingin kamu
|
circularReferenceFolder: "Folder tujuan adalah subfolder dari folder yang ingin kamu
|
||||||
pindahkan."
|
pindahkan."
|
||||||
|
@ -598,8 +598,8 @@ disablePlayer: "Tutup pemutar video"
|
||||||
expandTweet: "Perluas utas"
|
expandTweet: "Perluas utas"
|
||||||
themeEditor: "Penyunting tema"
|
themeEditor: "Penyunting tema"
|
||||||
description: "Deskripsi"
|
description: "Deskripsi"
|
||||||
describeFile: "Tambahkan keterangan"
|
describeFile: "Tambahkan deskripsi"
|
||||||
enterFileDescription: "Masukkan keterangan"
|
enterFileDescription: "Masukkan deskripsi"
|
||||||
author: "Pembuat"
|
author: "Pembuat"
|
||||||
leaveConfirm: "Ada perubahan yang belum disimpan. Apakah kamu ingin membuangnya?"
|
leaveConfirm: "Ada perubahan yang belum disimpan. Apakah kamu ingin membuangnya?"
|
||||||
manage: "Manajemen"
|
manage: "Manajemen"
|
||||||
|
@ -1904,7 +1904,7 @@ recommended: Direkomendasikan
|
||||||
silenceThisInstance: Bisukan server ini
|
silenceThisInstance: Bisukan server ini
|
||||||
hiddenTags: Tagar Tersembunyi
|
hiddenTags: Tagar Tersembunyi
|
||||||
preferencesBackups: Preferensi cadangan
|
preferencesBackups: Preferensi cadangan
|
||||||
editNote: Sunting catatan
|
editNote: Sunting kiriman
|
||||||
deleted: Dihapus
|
deleted: Dihapus
|
||||||
edited: Disunting pada {date} {time}
|
edited: Disunting pada {date} {time}
|
||||||
selectInstance: Pilih server
|
selectInstance: Pilih server
|
||||||
|
@ -2019,7 +2019,7 @@ showAdminUpdates: Indikasi versi Firefish baru tersedia (hanya admin)
|
||||||
indexFrom: Indeks dari Post ID berikutnya
|
indexFrom: Indeks dari Post ID berikutnya
|
||||||
noteId: ID Postingan
|
noteId: ID Postingan
|
||||||
findOtherInstance: Cari server lain
|
findOtherInstance: Cari server lain
|
||||||
caption: Keterangan Otomatis
|
caption: Deskripsi itomatis
|
||||||
splash: Layar Percik
|
splash: Layar Percik
|
||||||
migration: Migrasi
|
migration: Migrasi
|
||||||
moveTo: Pindahkan akun sekarang ke akun baru
|
moveTo: Pindahkan akun sekarang ke akun baru
|
||||||
|
@ -2165,3 +2165,7 @@ delete2faConfirm: Ini akan menghapus 2FA secara permanen pada akun ini. Lanjutka
|
||||||
deletePasskeysConfirm: Ini akan menghapus semua passkeys dan kunci keamanan pada akun
|
deletePasskeysConfirm: Ini akan menghapus semua passkeys dan kunci keamanan pada akun
|
||||||
ini secara permanen. Lanjutkan?
|
ini secara permanen. Lanjutkan?
|
||||||
addRe: Tambahkan "re:" pada awal komentar balasan postingan dengan peringatan konten
|
addRe: Tambahkan "re:" pada awal komentar balasan postingan dengan peringatan konten
|
||||||
|
confirm: Konfirmasi
|
||||||
|
importZip: Impor ZIP
|
||||||
|
exportZip: Ekspor ZIP
|
||||||
|
emojiPackCreator: Pembuat paket emoji
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
||||||
_lang_: "日本語"
|
_lang_: "日本語"
|
||||||
headlineFirefish: "ずっと無料でオープンソースの非中央集権型ソーシャルメディアプラットフォーム🚀"
|
headlineFirefish: "ずっと無料でオープンソースの非中央集権型ソーシャルメディアプラットフォーム🚀"
|
||||||
introFirefish: "ようこそ!Firefishは、オープンソースの非中央集権型ソーシャルメディアプラットフォームです。\nいま起こっていることを共有したり、あなたについて皆に発信しましょう📡\n\
|
introFirefish: "ようこそ!Firefishは、オープンソースの非中央集権型ソーシャルメディアプラットフォームです。\nいま起こっていることを共有したり、あなたについて皆に発信したりしましょう📡\n\
|
||||||
「リアクション」機能で、皆の投稿に素早く反応を追加できます👍\n新しい世界を探検しよう🚀"
|
「リアクション」機能で、皆の投稿に素早く反応を追加できます👍\n新しい世界を探検しよう🚀"
|
||||||
monthAndDay: "{month}月 {day}日"
|
monthAndDay: "{month}月 {day}日"
|
||||||
search: "検索"
|
search: "検索"
|
||||||
|
@ -303,7 +303,7 @@ emptyDrive: "ドライブは空です"
|
||||||
emptyFolder: "フォルダーは空です"
|
emptyFolder: "フォルダーは空です"
|
||||||
unableToDelete: "削除できません"
|
unableToDelete: "削除できません"
|
||||||
inputNewFileName: "新しいファイル名を入力してください"
|
inputNewFileName: "新しいファイル名を入力してください"
|
||||||
inputNewDescription: "新しい説明を入力してください"
|
inputNewDescription: "新しい説明を入力"
|
||||||
inputNewFolderName: "新しいフォルダ名を入力してください"
|
inputNewFolderName: "新しいフォルダ名を入力してください"
|
||||||
circularReferenceFolder: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。"
|
circularReferenceFolder: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。"
|
||||||
hasChildFilesOrFolders: "このフォルダは空でないため、削除できません。"
|
hasChildFilesOrFolders: "このフォルダは空でないため、削除できません。"
|
||||||
|
@ -577,7 +577,7 @@ disablePlayer: "プレイヤーを閉じる"
|
||||||
expandTweet: "ツイートを展開する"
|
expandTweet: "ツイートを展開する"
|
||||||
themeEditor: "テーマエディター"
|
themeEditor: "テーマエディター"
|
||||||
description: "説明"
|
description: "説明"
|
||||||
describeFile: "説明を付ける"
|
describeFile: "説明を追加"
|
||||||
enterFileDescription: "説明を入力"
|
enterFileDescription: "説明を入力"
|
||||||
author: "作者"
|
author: "作者"
|
||||||
leaveConfirm: "未保存の変更があります。破棄しますか?"
|
leaveConfirm: "未保存の変更があります。破棄しますか?"
|
||||||
|
@ -849,7 +849,7 @@ filter: "フィルタ"
|
||||||
controlPanel: "コントロールパネル"
|
controlPanel: "コントロールパネル"
|
||||||
manageAccounts: "アカウントを管理"
|
manageAccounts: "アカウントを管理"
|
||||||
makeReactionsPublic: "リアクション一覧を公開する"
|
makeReactionsPublic: "リアクション一覧を公開する"
|
||||||
makeReactionsPublicDescription: "あなたがしたリアクション一覧を誰でも見れるようにします。"
|
makeReactionsPublicDescription: "あなたがしたリアクション一覧を誰でも見られるようにします。"
|
||||||
classic: "中央寄せ"
|
classic: "中央寄せ"
|
||||||
muteThread: "スレッドをミュート"
|
muteThread: "スレッドをミュート"
|
||||||
unmuteThread: "スレッドのミュートを解除"
|
unmuteThread: "スレッドのミュートを解除"
|
||||||
|
@ -949,7 +949,7 @@ customSplashIconsDescription: "ユーザがページをロード/リロードす
|
||||||
showUpdates: "Firefishの更新時にポップアップを表示する"
|
showUpdates: "Firefishの更新時にポップアップを表示する"
|
||||||
recommendedInstances: "おすすめサーバー"
|
recommendedInstances: "おすすめサーバー"
|
||||||
recommendedInstancesDescription: "おすすめタイムラインに表示するサーバーを改行区切りで入力してください。"
|
recommendedInstancesDescription: "おすすめタイムラインに表示するサーバーを改行区切りで入力してください。"
|
||||||
caption: "自動キャプション"
|
caption: "自動で説明をつける"
|
||||||
splash: "スプラッシュスクリーン"
|
splash: "スプラッシュスクリーン"
|
||||||
updateAvailable: "アップデートがありますよ!"
|
updateAvailable: "アップデートがありますよ!"
|
||||||
swipeOnDesktop: "デスクトップでモバイルスタイルのスワイプを可能にする"
|
swipeOnDesktop: "デスクトップでモバイルスタイルのスワイプを可能にする"
|
||||||
|
@ -1996,3 +1996,6 @@ _emojiModPerm:
|
||||||
add: "追加"
|
add: "追加"
|
||||||
mod: "追加と変更"
|
mod: "追加と変更"
|
||||||
full: "全て許可"
|
full: "全て許可"
|
||||||
|
importZip: ZIPをインポート
|
||||||
|
emojiPackCreator: 絵文字パックの作者
|
||||||
|
exportZip: ZIPをエクスポート
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
|
||||||
_lang_: "日本語 (関西弁)"
|
_lang_: "日本語 (関西弁)"
|
||||||
headlineFirefish: "ノートでつながるネットワーク"
|
headlineFirefish: "ずっとタダでオープンソースの非中央集権型ソーシャルメディアプラットフォーム!🚀"
|
||||||
introFirefish: "ようお越し!Misskeyは、オープンソースの分散型マイクロブログサービスやねん。\n「ノート」を作って、いま起こっとることを共有したり、あんたについて皆に発信しよう📡\n「リアクション」機能で、皆のノートに素早く反応を追加したりもできるで✌\nほな新しい世界を探検しよか🚀"
|
introFirefish: "おいでやす。Firefishは、オープンソースの分散型ソーシャルメディアプラットフォームどす。\nいま起きたはるもんを共有したり、あんさんについて皆に発信したりしとくれやす👘\n\
|
||||||
|
「リアクション」機能があるさかい、皆の投稿に素早う反応を送ることもできます🎎\nほんなら、新しい世界を探検しまひょか🎴"
|
||||||
monthAndDay: "{month}月 {day}日"
|
monthAndDay: "{month}月 {day}日"
|
||||||
search: "探す"
|
search: "探す"
|
||||||
notifications: "通知"
|
notifications: "通知"
|
||||||
|
@ -13,10 +13,10 @@ ok: "OKや"
|
||||||
gotIt: "ほい"
|
gotIt: "ほい"
|
||||||
cancel: "やめとく"
|
cancel: "やめとく"
|
||||||
enterUsername: "ユーザー名を入れてや"
|
enterUsername: "ユーザー名を入れてや"
|
||||||
renotedBy: "{user}がRenote"
|
renotedBy: "{user}がブースト"
|
||||||
noNotes: "ノートはあらへん"
|
noNotes: "投稿はありまへん"
|
||||||
noNotifications: "通知はあらへん"
|
noNotifications: "通知はあらへん"
|
||||||
instance: "インスタンス"
|
instance: "サーバー"
|
||||||
settings: "設定"
|
settings: "設定"
|
||||||
basicSettings: "基本設定"
|
basicSettings: "基本設定"
|
||||||
otherSettings: "その他の設定"
|
otherSettings: "その他の設定"
|
||||||
|
@ -44,7 +44,7 @@ copyContent: "内容をコピー"
|
||||||
copyLink: "リンクをコピー"
|
copyLink: "リンクをコピー"
|
||||||
delete: "ほかす"
|
delete: "ほかす"
|
||||||
deleteAndEdit: "ほかして直す"
|
deleteAndEdit: "ほかして直す"
|
||||||
deleteAndEditConfirm: "このノートをほかして書き直すんか?このノートへのリアクション、Renote、返信も全部消えてまうで。"
|
deleteAndEditConfirm: "この投稿をほかして書き直すんか?この投稿へのリアクション、ブースト、返信もみんな消えてまうで。"
|
||||||
addToList: "リストに入れたる"
|
addToList: "リストに入れたる"
|
||||||
sendMessage: "メッセージを送る"
|
sendMessage: "メッセージを送る"
|
||||||
copyUsername: "ユーザー名をコピー"
|
copyUsername: "ユーザー名をコピー"
|
||||||
|
@ -64,26 +64,28 @@ import: "インポート"
|
||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
files: "ファイル"
|
files: "ファイル"
|
||||||
download: "ダウンロード"
|
download: "ダウンロード"
|
||||||
driveFileDeleteConfirm: "ファイル「{name}」を消してしもうてええか?このファイルを添付したノートも消えてまうで。"
|
driveFileDeleteConfirm: "ファイル「{name}」を消してしもうてええか?このファイルを添付した投稿も消えてまうで。"
|
||||||
unfollowConfirm: "{name}のフォローを解除してもええんか?"
|
unfollowConfirm: "{name}のフォローを解除してもええんか?"
|
||||||
exportRequested: "エクスポートしてな、ってリクエストしたけど、これ多分めっちゃ時間かかるで。エクスポート終わったら「ドライブ」に突っ込んどくで。"
|
exportRequested: "エクスポートしてな、ってリクエストしたけど、これ多分めっちゃ時間かかるで。エクスポート終わったら「ドライブ」に突っ込んどくで。"
|
||||||
importRequested: "インポートしてな、ってリクエストしたけど、これ多分めっちゃ時間かかるで。"
|
importRequested: "インポートしてな、ってリクエストしたけど、これ多分めっちゃ時間かかるで。"
|
||||||
lists: "リスト"
|
lists: "リスト"
|
||||||
noLists: "リストなんてあらへんで"
|
noLists: "リストなんてあらへんで"
|
||||||
note: "ノート"
|
note: "投稿"
|
||||||
notes: "ノート"
|
notes: "投稿"
|
||||||
following: "フォロー"
|
following: "フォロー"
|
||||||
followers: "フォロワー"
|
followers: "フォロワー"
|
||||||
followsYou: "フォローされとるで"
|
followsYou: "フォローされとるで"
|
||||||
createList: "リスト作る"
|
createList: "リスト作る"
|
||||||
manageLists: "リストの管理"
|
manageLists: "リストの管理"
|
||||||
error: "エラー"
|
error: "エラー"
|
||||||
somethingHappened: "なんかアカンことが起こったで"
|
somethingHappened: "なんやアカンことが起きたで"
|
||||||
retry: "もっぺんやる?"
|
retry: "もっぺんやる?"
|
||||||
pageLoadError: "ページの読み込みに失敗してしもうたで…"
|
pageLoadError: "ページの読み込みに失敗してもた… えろうすんまへん"
|
||||||
pageLoadErrorDescription: "これは普通、ネットワークかブラウザキャッシュが原因やからね。キャッシュをクリアするか、もうちっとだけ待ってくれへんか?"
|
pageLoadErrorDescription: "これは普通、ネットワークかブラウザキャッシュが原因やからね。キャッシュをクリアするか、もうちっとだけ待ってくれへんか?"
|
||||||
serverIsDead: "The server is not responding. Please wait for a while before trying again."
|
serverIsDead: "The server is not responding. Please wait for a while before trying
|
||||||
youShouldUpgradeClient: "To display this page, please reload and use a new version client. "
|
again."
|
||||||
|
youShouldUpgradeClient: "To display this page, please reload and use a new version
|
||||||
|
client. "
|
||||||
enterListName: "リスト名を入れてや"
|
enterListName: "リスト名を入れてや"
|
||||||
privacy: "プライバシー"
|
privacy: "プライバシー"
|
||||||
makeFollowManuallyApprove: "自分が認めた人だけがこのアカウントをフォローできるようにする"
|
makeFollowManuallyApprove: "自分が認めた人だけがこのアカウントをフォローできるようにする"
|
||||||
|
@ -94,13 +96,13 @@ followRequests: "フォロー申請"
|
||||||
unfollow: "フォローやめる"
|
unfollow: "フォローやめる"
|
||||||
followRequestPending: "フォロー許してくれるん待っとる"
|
followRequestPending: "フォロー許してくれるん待っとる"
|
||||||
enterEmoji: "絵文字を入れてや"
|
enterEmoji: "絵文字を入れてや"
|
||||||
renote: "Renote"
|
renote: "ブースト"
|
||||||
unrenote: "Renoteやめる"
|
unrenote: "ブーストやめる"
|
||||||
renoted: "Renoteしたで。"
|
renoted: "ブーストしたで。"
|
||||||
cantRenote: "この投稿はRenoteできへんらしい。"
|
cantRenote: "この投稿はブーストでけへんらしい。"
|
||||||
cantReRenote: "Renote自体はRenoteできへんで。"
|
cantReRenote: "ブースト自体はブーストでけへんで。"
|
||||||
quote: "引用"
|
quote: "引用"
|
||||||
pinnedNote: "ピン留めされとるノート"
|
pinnedNote: "ピン留めされとる投稿"
|
||||||
pinned: "ピン留めしとく"
|
pinned: "ピン留めしとく"
|
||||||
you: "あんた"
|
you: "あんた"
|
||||||
clickToShow: "押したら見えるで"
|
clickToShow: "押したら見えるで"
|
||||||
|
@ -138,12 +140,13 @@ addEmoji: "絵文字を追加"
|
||||||
settingGuide: "ええ感じの設定"
|
settingGuide: "ええ感じの設定"
|
||||||
cacheRemoteFiles: "リモートのファイルをキャッシュする"
|
cacheRemoteFiles: "リモートのファイルをキャッシュする"
|
||||||
cacheRemoteFilesDescription: "この設定を切っとくと、リモートファイルをキャッシュせず直リンクするようになるで。サーバーの容量は節約できるけど、サムネイルが作られんくなるから通信量が増えるで。"
|
cacheRemoteFilesDescription: "この設定を切っとくと、リモートファイルをキャッシュせず直リンクするようになるで。サーバーの容量は節約できるけど、サムネイルが作られんくなるから通信量が増えるで。"
|
||||||
flagAsBot: "Botやで"
|
flagAsBot: "ワイはBotや 🤖"
|
||||||
flagAsBotDescription: "もしこのアカウントがプログラムによって運用されるんやったら、このフラグをオンにしてたのむで。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Misskeyのシステム上での扱いがBotに合ったもんになるんやで。"
|
flagAsBotDescription: "もしこのアカウントがプログラムによって運用されるんやったら、このフラグをオンにしてたのむで。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Firefishのシステム上での扱いがBotに合ったもんになったりするんやで。"
|
||||||
flagAsCat: "Catやで"
|
flagAsCat: "ワイはCatや 🐯"
|
||||||
flagAsCatDescription: "ワレ、猫ちゃんならこのフラグをつけてみ?"
|
flagAsCatDescription: "自分、猫ちゃんならこのフラグつけてみ?"
|
||||||
flagShowTimelineReplies: "It will display the reply to the note in the timeline. "
|
flagShowTimelineReplies: "It will display the reply to the note in the timeline. "
|
||||||
flagShowTimelineRepliesDescription: "It will display the reply to notes other than the user notes in the timeline when you turn it on. "
|
flagShowTimelineRepliesDescription: "It will display the reply to notes other than
|
||||||
|
the user notes in the timeline when you turn it on. "
|
||||||
autoAcceptFollowed: "フォローしとるユーザーからのフォローリクエストを勝手に許可しとく"
|
autoAcceptFollowed: "フォローしとるユーザーからのフォローリクエストを勝手に許可しとく"
|
||||||
addAccount: "アカウントを追加"
|
addAccount: "アカウントを追加"
|
||||||
loginFailed: "ログインに失敗してしもうた…"
|
loginFailed: "ログインに失敗してしもうた…"
|
||||||
|
@ -162,7 +165,7 @@ selectUser: "ユーザーを選ぶ"
|
||||||
recipient: "宛先"
|
recipient: "宛先"
|
||||||
annotation: "注釈"
|
annotation: "注釈"
|
||||||
federation: "連合"
|
federation: "連合"
|
||||||
instances: "インスタンス"
|
instances: "サーバー"
|
||||||
registeredAt: "初観測"
|
registeredAt: "初観測"
|
||||||
latestRequestSentAt: "ちょっと前のリクエスト送信"
|
latestRequestSentAt: "ちょっと前のリクエスト送信"
|
||||||
latestRequestReceivedAt: "ちょっと前のリクエスト受信"
|
latestRequestReceivedAt: "ちょっと前のリクエスト受信"
|
||||||
|
@ -172,7 +175,7 @@ charts: "チャート"
|
||||||
perHour: "1時間ごと"
|
perHour: "1時間ごと"
|
||||||
perDay: "1日ごと"
|
perDay: "1日ごと"
|
||||||
stopActivityDelivery: "アクティビティの配送をやめる"
|
stopActivityDelivery: "アクティビティの配送をやめる"
|
||||||
blockThisInstance: "このインスタンスをブロック"
|
blockThisInstance: "このサーバーをブロック"
|
||||||
operations: "操作"
|
operations: "操作"
|
||||||
software: "ソフトウェア"
|
software: "ソフトウェア"
|
||||||
version: "バージョン"
|
version: "バージョン"
|
||||||
|
@ -182,23 +185,23 @@ jobQueue: "ジョブキュー"
|
||||||
cpuAndMemory: "CPUとメモリ"
|
cpuAndMemory: "CPUとメモリ"
|
||||||
network: "ネットワーク"
|
network: "ネットワーク"
|
||||||
disk: "ディスク"
|
disk: "ディスク"
|
||||||
instanceInfo: "インスタンス情報"
|
instanceInfo: "サーバー情報"
|
||||||
statistics: "統計"
|
statistics: "統計"
|
||||||
clearQueue: "キューにさいなら"
|
clearQueue: "キューにさいなら"
|
||||||
clearQueueConfirmTitle: "キューをクリアしまっか?"
|
clearQueueConfirmTitle: "キューをクリアしまっか?"
|
||||||
clearQueueConfirmText: "未配達の投稿は配送されなくなるで。通常この操作を行う必要はあらへんや。"
|
clearQueueConfirmText: "未配達の投稿は配送されなくなるで。通常この操作を行う必要はあらへんや。"
|
||||||
clearCachedFiles: "キャッシュにさいなら"
|
clearCachedFiles: "キャッシュにさいなら"
|
||||||
clearCachedFilesConfirm: "キャッシュされとるリモートファイルをみんなほかしてええか?"
|
clearCachedFilesConfirm: "キャッシュされとるリモートファイルをみんなほかしてええか?"
|
||||||
blockedInstances: "インスタンスブロック"
|
blockedInstances: "ブロックしたサーバー"
|
||||||
blockedInstancesDescription: "ブロックしたいインスタンスのホストを改行で区切って設定してな。ブロックされてもうたインスタンスとはもう金輪際やり取りできひんくなるで。"
|
blockedInstancesDescription: "ブロックしたいサーバーのホストを改行で区切って設定してな。ブロックされてもうたサーバーとはもう金輪際やり取りできんくなるで。"
|
||||||
muteAndBlock: "ミュートとブロック"
|
muteAndBlock: "ミュートとブロック"
|
||||||
mutedUsers: "ミュートしたユーザー"
|
mutedUsers: "ミュートしたユーザー"
|
||||||
blockedUsers: "ブロックしたユーザー"
|
blockedUsers: "ブロックしたユーザー"
|
||||||
noUsers: "ユーザーはおらへん"
|
noUsers: "ユーザーはおらへん"
|
||||||
editProfile: "プロフィールをいじる"
|
editProfile: "プロフィールをいじる"
|
||||||
noteDeleteConfirm: "このノートを削除しまっか?"
|
noteDeleteConfirm: "この投稿を削除しまっか?"
|
||||||
pinLimitExceeded: "これ以上ピン留めできひん"
|
pinLimitExceeded: "これ以上ピン留めできひん"
|
||||||
intro: "Misskeyのインストールが完了してん!管理者アカウントを作ってや。"
|
intro: "Firefishのインストールが完了してん!管理者アカウントを作ってや。"
|
||||||
done: "でけた"
|
done: "でけた"
|
||||||
processing: "処理しとる"
|
processing: "処理しとる"
|
||||||
preview: "プレビュー"
|
preview: "プレビュー"
|
||||||
|
@ -213,9 +216,9 @@ all: "みんな"
|
||||||
subscribing: "購読しとる"
|
subscribing: "購読しとる"
|
||||||
publishing: "配信しとる"
|
publishing: "配信しとる"
|
||||||
notResponding: "応答してへんで"
|
notResponding: "応答してへんで"
|
||||||
instanceFollowing: "インスタンスのフォロー"
|
instanceFollowing: "サーバーのフォロー"
|
||||||
instanceFollowers: "インスタンスのフォロワー\n"
|
instanceFollowers: "サーバーのフォロワー"
|
||||||
instanceUsers: "インスタンスのユーザー"
|
instanceUsers: "このサーバーの利用者"
|
||||||
changePassword: "パスワード変える"
|
changePassword: "パスワード変える"
|
||||||
security: "セキュリティ"
|
security: "セキュリティ"
|
||||||
retypedNotMatch: "そやないねん。"
|
retypedNotMatch: "そやないねん。"
|
||||||
|
@ -239,7 +242,8 @@ saved: "保存したで!"
|
||||||
messaging: "チャット"
|
messaging: "チャット"
|
||||||
upload: "アップロード"
|
upload: "アップロード"
|
||||||
keepOriginalUploading: "Retain the original image. "
|
keepOriginalUploading: "Retain the original image. "
|
||||||
keepOriginalUploadingDescription: "When uploading the clip, the original version will be retained. Turning it of then uploading will produce images for public use. "
|
keepOriginalUploadingDescription: "When uploading the clip, the original version will
|
||||||
|
be retained. Turning it of then uploading will produce images for public use. "
|
||||||
fromDrive: "ドライブから"
|
fromDrive: "ドライブから"
|
||||||
fromUrl: "URLから"
|
fromUrl: "URLから"
|
||||||
uploadFromUrl: "URLアップロード"
|
uploadFromUrl: "URLアップロード"
|
||||||
|
@ -286,7 +290,7 @@ emptyDrive: "ドライブにはなんも残っとらん"
|
||||||
emptyFolder: "ふぉろだーにはなんも残っとらん"
|
emptyFolder: "ふぉろだーにはなんも残っとらん"
|
||||||
unableToDelete: "消そうおもってんけどな、あかんかったわ"
|
unableToDelete: "消そうおもってんけどな、あかんかったわ"
|
||||||
inputNewFileName: "今度のファイル名は何にするん?"
|
inputNewFileName: "今度のファイル名は何にするん?"
|
||||||
inputNewDescription: "新しいキャプションを入力しましょ"
|
inputNewDescription: "新しい説明文を入力しまひょ"
|
||||||
inputNewFolderName: "今度のフォルダ名は何にするん?"
|
inputNewFolderName: "今度のフォルダ名は何にするん?"
|
||||||
circularReferenceFolder: "移動先のフォルダーは、移動するフォルダーのサブフォルダーや。"
|
circularReferenceFolder: "移動先のフォルダーは、移動するフォルダーのサブフォルダーや。"
|
||||||
hasChildFilesOrFolders: "このフォルダ、まだなんか入っとるから消されへん"
|
hasChildFilesOrFolders: "このフォルダ、まだなんか入っとるから消されへん"
|
||||||
|
@ -305,8 +309,8 @@ unwatch: "ウォッチやめる"
|
||||||
accept: "ええで"
|
accept: "ええで"
|
||||||
reject: "あかん"
|
reject: "あかん"
|
||||||
normal: "ええ感じ"
|
normal: "ええ感じ"
|
||||||
instanceName: "インスタンス名"
|
instanceName: "サーバー名"
|
||||||
instanceDescription: "インスタンスの紹介"
|
instanceDescription: "サーバーの紹介"
|
||||||
maintainerName: "管理者の名前"
|
maintainerName: "管理者の名前"
|
||||||
maintainerEmail: "管理者のメールアドレス"
|
maintainerEmail: "管理者のメールアドレス"
|
||||||
tosUrl: "利用規約のURL"
|
tosUrl: "利用規約のURL"
|
||||||
|
@ -336,9 +340,9 @@ basicInfo: "基本情報"
|
||||||
pinnedUsers: "ピン留めしたユーザー"
|
pinnedUsers: "ピン留めしたユーザー"
|
||||||
pinnedUsersDescription: "「みつける」ページとかにピン留めしたいユーザーをここに書けばええんやで。他ん人との名前は改行で区切ればええんやで。"
|
pinnedUsersDescription: "「みつける」ページとかにピン留めしたいユーザーをここに書けばええんやで。他ん人との名前は改行で区切ればええんやで。"
|
||||||
pinnedPages: "ピン留めページ"
|
pinnedPages: "ピン留めページ"
|
||||||
pinnedPagesDescription: "インスタンスのいっちゃん上にピン留めしたいページのパスを改行で区切って記述してな"
|
pinnedPagesDescription: "サーバーのいっちゃん上にピン留めしたいページのパスを、改行で区切って記述してな。"
|
||||||
pinnedClipId: "ピン留めするクリップのID"
|
pinnedClipId: "ピン留めするクリップのID"
|
||||||
pinnedNotes: "ピン留めされとるノート"
|
pinnedNotes: "ピン留めされとる投稿"
|
||||||
hcaptcha: "hCaptcha(キャプチャ)"
|
hcaptcha: "hCaptcha(キャプチャ)"
|
||||||
enableHcaptcha: "hCaptcha(キャプチャ)をつけとく"
|
enableHcaptcha: "hCaptcha(キャプチャ)をつけとく"
|
||||||
hcaptchaSiteKey: "サイトキー"
|
hcaptchaSiteKey: "サイトキー"
|
||||||
|
@ -355,8 +359,8 @@ antennaSource: "受信ソース(このソースは食われへん)"
|
||||||
antennaKeywords: "受信キーワード"
|
antennaKeywords: "受信キーワード"
|
||||||
antennaExcludeKeywords: "除外キーワード"
|
antennaExcludeKeywords: "除外キーワード"
|
||||||
antennaKeywordsDescription: "スペースで区切ったるとAND指定で、改行で区切ったるとOR指定や"
|
antennaKeywordsDescription: "スペースで区切ったるとAND指定で、改行で区切ったるとOR指定や"
|
||||||
notifyAntenna: "新しいノートを通知すんで"
|
notifyAntenna: "新しい投稿を通知すんで"
|
||||||
withFileAntenna: "なんか添付されたノートだけ"
|
withFileAntenna: "ファイルが添付された投稿のみ"
|
||||||
enableServiceworker: "ServiceWorkerをつこて"
|
enableServiceworker: "ServiceWorkerをつこて"
|
||||||
antennaUsersDescription: "ユーザー名を改行で区切ったってな"
|
antennaUsersDescription: "ユーザー名を改行で区切ったってな"
|
||||||
caseSensitive: "大文字と小文字は別もんや"
|
caseSensitive: "大文字と小文字は別もんや"
|
||||||
|
@ -377,7 +381,7 @@ exploreFediverse: "Fediverseを探ってみる"
|
||||||
popularTags: "人気のタグ"
|
popularTags: "人気のタグ"
|
||||||
userList: "リスト"
|
userList: "リスト"
|
||||||
about: "情報"
|
about: "情報"
|
||||||
aboutFirefish: "Misskeyってなんや?"
|
aboutFirefish: "Firefishってなんやねん?"
|
||||||
administrator: "管理者"
|
administrator: "管理者"
|
||||||
token: "トークン"
|
token: "トークン"
|
||||||
twoStepAuthentication: "二段階認証"
|
twoStepAuthentication: "二段階認証"
|
||||||
|
@ -420,7 +424,7 @@ text: "テキスト"
|
||||||
enable: "有効にするで"
|
enable: "有効にするで"
|
||||||
next: "次"
|
next: "次"
|
||||||
retype: "もっかい入力"
|
retype: "もっかい入力"
|
||||||
noteOf: "{user}のノート"
|
noteOf: "{user}の投稿"
|
||||||
inviteToGroup: "グループに招く"
|
inviteToGroup: "グループに招く"
|
||||||
quoteAttached: "引用付いとるで"
|
quoteAttached: "引用付いとるで"
|
||||||
quoteQuestion: "引用として添付してもええか?"
|
quoteQuestion: "引用として添付してもええか?"
|
||||||
|
@ -478,12 +482,13 @@ accountSettings: "アカウントの設定"
|
||||||
promotion: "宣伝"
|
promotion: "宣伝"
|
||||||
promote: "宣伝"
|
promote: "宣伝"
|
||||||
numberOfDays: "日数"
|
numberOfDays: "日数"
|
||||||
hideThisNote: "このノートは表示せんでいい"
|
hideThisNote: "この投稿は表示せんでいい"
|
||||||
showFeaturedNotesInTimeline: "タイムラインにおすすめのノートを表示してや"
|
showFeaturedNotesInTimeline: "タイムラインにおすすめの投稿を表示してや"
|
||||||
objectStorage: "オブジェクトストレージ"
|
objectStorage: "オブジェクトストレージ"
|
||||||
useObjectStorage: "オブジェクトストレージを使う"
|
useObjectStorage: "オブジェクトストレージを使う"
|
||||||
objectStorageBaseUrl: "Base URL"
|
objectStorageBaseUrl: "Base URL"
|
||||||
objectStorageBaseUrlDesc: "参照に使うにURLやで。CDNやProxyを使用してるんならそのURL、S3: 'https://<bucket>.s3.amazonaws.com'、GCSとかなら: 'https://storage.googleapis.com/<bucket>'。"
|
objectStorageBaseUrlDesc: "参照に使うにURLやで。CDNやProxyを使用してるんならそのURL、S3: 'https://<bucket>.s3.amazonaws.com'、GCSとかなら:
|
||||||
|
'https://storage.googleapis.com/<bucket>'。"
|
||||||
objectStorageBucket: "Bucket"
|
objectStorageBucket: "Bucket"
|
||||||
objectStorageBucketDesc: "使ってるサービスのbucket名を選んでな"
|
objectStorageBucketDesc: "使ってるサービスのbucket名を選んでな"
|
||||||
objectStoragePrefix: "Prefix"
|
objectStoragePrefix: "Prefix"
|
||||||
|
@ -500,7 +505,7 @@ objectStorageSetPublicRead: "アップロードした時に'public-read'を設
|
||||||
serverLogs: "サーバーログ"
|
serverLogs: "サーバーログ"
|
||||||
deleteAll: "全て削除してや"
|
deleteAll: "全て削除してや"
|
||||||
showFixedPostForm: "タイムラインの上の方で投稿できるようにやってくれへん?"
|
showFixedPostForm: "タイムラインの上の方で投稿できるようにやってくれへん?"
|
||||||
newNoteRecived: "新しいノートがあるで"
|
newNoteRecived: "新しい投稿があるで"
|
||||||
sounds: "サウンド"
|
sounds: "サウンド"
|
||||||
listen: "聴く"
|
listen: "聴く"
|
||||||
none: "なし"
|
none: "なし"
|
||||||
|
@ -523,7 +528,7 @@ sort: "仕分ける"
|
||||||
ascendingOrder: "小さい順"
|
ascendingOrder: "小さい順"
|
||||||
descendingOrder: "大きい順"
|
descendingOrder: "大きい順"
|
||||||
scratchpad: "スクラッチパッド"
|
scratchpad: "スクラッチパッド"
|
||||||
scratchpadDescription: "スクラッチパッドではAiScriptを色々試すことができるんや。Misskeyに対して色々できるコードを書いて動かしてみたり、結果を見たりできるで。"
|
scratchpadDescription: "スクラッチパッドではAiScriptを色々試すことができるんや。Firefishに対して色々できるコードを書いて動かしてみたり、結果を見たりできるで。"
|
||||||
output: "出力"
|
output: "出力"
|
||||||
script: "スクリプト"
|
script: "スクリプト"
|
||||||
disablePagesScript: "Pagesのスクリプトを無効にしてや"
|
disablePagesScript: "Pagesのスクリプトを無効にしてや"
|
||||||
|
@ -531,7 +536,7 @@ updateRemoteUser: "リモートユーザー情報の更新してくれん?"
|
||||||
deleteAllFiles: "すべてのファイルを削除"
|
deleteAllFiles: "すべてのファイルを削除"
|
||||||
deleteAllFilesConfirm: "ホンマにすべてのファイルを削除するん?消したもんはもう戻ってこんのやで?"
|
deleteAllFilesConfirm: "ホンマにすべてのファイルを削除するん?消したもんはもう戻ってこんのやで?"
|
||||||
removeAllFollowing: "フォローを全解除"
|
removeAllFollowing: "フォローを全解除"
|
||||||
removeAllFollowingDescription: "{host}からのフォローをすべて解除するで。そのインスタンスが消えて無くなった時とかには便利な機能やで。"
|
removeAllFollowingDescription: "{host}からのフォローをすべて解除するで。そのサーバーが消えて無くなった時とかに便利な機能やで。"
|
||||||
userSuspended: "このユーザーは...凍結されとる。"
|
userSuspended: "このユーザーは...凍結されとる。"
|
||||||
userSilenced: "このユーザーは...サイレンスされとる。"
|
userSilenced: "このユーザーは...サイレンスされとる。"
|
||||||
yourAccountSuspendedTitle: "あんたのアカウント凍結されとるで"
|
yourAccountSuspendedTitle: "あんたのアカウント凍結されとるで"
|
||||||
|
@ -555,8 +560,8 @@ disablePlayer: "プレイヤーを閉じる"
|
||||||
expandTweet: "ツイートを展開する"
|
expandTweet: "ツイートを展開する"
|
||||||
themeEditor: "テーマエディター"
|
themeEditor: "テーマエディター"
|
||||||
description: "説明"
|
description: "説明"
|
||||||
describeFile: "キャプションを付ける"
|
describeFile: "画像説明文を付ける"
|
||||||
enterFileDescription: "キャプションを入力"
|
enterFileDescription: ""
|
||||||
author: "作者"
|
author: "作者"
|
||||||
leaveConfirm: "未保存の変更があるで!ほかしてええか?"
|
leaveConfirm: "未保存の変更があるで!ほかしてええか?"
|
||||||
manage: "管理"
|
manage: "管理"
|
||||||
|
@ -595,7 +600,7 @@ testEmail: "配信テスト"
|
||||||
wordMute: "ワードミュート"
|
wordMute: "ワードミュート"
|
||||||
regexpError: "正規表現エラー"
|
regexpError: "正規表現エラー"
|
||||||
regexpErrorDescription: "{tab}ワードミュートの{line}行目の正規表現にエラーが出てきたで:"
|
regexpErrorDescription: "{tab}ワードミュートの{line}行目の正規表現にエラーが出てきたで:"
|
||||||
instanceMute: "インスタンスミュート"
|
instanceMute: "サーバーミュート"
|
||||||
userSaysSomething: "{name}が何か言ったようやで"
|
userSaysSomething: "{name}が何か言ったようやで"
|
||||||
makeActive: "使うで"
|
makeActive: "使うで"
|
||||||
display: "表示"
|
display: "表示"
|
||||||
|
@ -621,20 +626,20 @@ sample: "サンプル"
|
||||||
abuseReports: "通報"
|
abuseReports: "通報"
|
||||||
reportAbuse: "通報"
|
reportAbuse: "通報"
|
||||||
reportAbuseOf: "{name}を通報する"
|
reportAbuseOf: "{name}を通報する"
|
||||||
fillAbuseReportDescription: "細かい通報理由を書いてなー。対象ノートがある時はそのURLも書いといてなー。"
|
fillAbuseReportDescription: "細かい通報理由を書いてなー。特定の投稿を通報するなら、そのURLも書いといてなー。"
|
||||||
abuseReported: "無事内容が送信されたみたいやで。おおきに〜。"
|
abuseReported: "無事内容が送信されたみたいやで。おおきに〜。"
|
||||||
reporter: "通報者"
|
reporter: "通報者"
|
||||||
reporteeOrigin: "通報先"
|
reporteeOrigin: "通報先"
|
||||||
reporterOrigin: "通報元"
|
reporterOrigin: "通報元"
|
||||||
forwardReport: "リモートインスタンスに通報を転送するで"
|
forwardReport: "リモートサーバーに通報を転送するで"
|
||||||
forwardReportIsAnonymous: "リモートインスタンスからはあんたの情報は見れへんくって、匿名のシステムアカウントとして表示されるで。"
|
forwardReportIsAnonymous: "リモートサーバーからはあんたの情報は見れへんくて、匿名のシステムアカウントとして表示されるで。"
|
||||||
send: "送信"
|
send: "送信"
|
||||||
abuseMarkAsResolved: "対応したで"
|
abuseMarkAsResolved: "対応したで"
|
||||||
openInNewTab: "新しいタブで開く"
|
openInNewTab: "新しいタブで開く"
|
||||||
openInSideView: "サイドビューで開く"
|
openInSideView: "サイドビューで開く"
|
||||||
defaultNavigationBehaviour: "デフォルトのナビゲーション"
|
defaultNavigationBehaviour: "デフォルトのナビゲーション"
|
||||||
editTheseSettingsMayBreakAccount: "このへんの設定をようわからんままイジるとアカウントが壊れて使えんくなるかも知れへんで?"
|
editTheseSettingsMayBreakAccount: "このへんの設定をようわからんままイジるとアカウントが壊れて使えんくなるかも知れへんで?"
|
||||||
instanceTicker: "ノートのインスタンス情報"
|
instanceTicker: "投稿のサーバー情報"
|
||||||
waitingFor: "{x}を待っとるで"
|
waitingFor: "{x}を待っとるで"
|
||||||
random: "ランダム"
|
random: "ランダム"
|
||||||
system: "システム"
|
system: "システム"
|
||||||
|
@ -645,16 +650,16 @@ createNew: "新しく作るで"
|
||||||
optional: "任意"
|
optional: "任意"
|
||||||
createNewClip: "新しいクリップを作るで"
|
createNewClip: "新しいクリップを作るで"
|
||||||
unclip: "クリップ解除するで"
|
unclip: "クリップ解除するで"
|
||||||
confirmToUnclipAlreadyClippedNote: "このノートはすでにクリップ「{name}」に含まれとるで。ノートをこのクリップから除外したる?"
|
confirmToUnclipAlreadyClippedNote: "この投稿はすでにクリップ「{name}」に含まれとるで。投稿をこのクリップから除外したる?"
|
||||||
public: "パブリック"
|
public: "パブリック"
|
||||||
i18nInfo: "Firefishは有志によっていろんな言語に翻訳されとるで。{link}で翻訳に協力したってやー。"
|
i18nInfo: "Firefishは有志によっていろんな言語に翻訳されとるで。{link}で翻訳に協力したってやー。"
|
||||||
manageAccessTokens: "アクセストークンの管理"
|
manageAccessTokens: "アクセストークンの管理"
|
||||||
accountInfo: "アカウント情報"
|
accountInfo: "アカウント情報"
|
||||||
notesCount: "ノートの数やで"
|
notesCount: "投稿の数やで"
|
||||||
repliesCount: "返信した数やで"
|
repliesCount: "返信した数やで"
|
||||||
renotesCount: "Renoteした数やで"
|
renotesCount: "ブーストした数やで"
|
||||||
repliedCount: "返信された数やで"
|
repliedCount: "返信された数やで"
|
||||||
renotedCount: "Renoteされた数やで"
|
renotedCount: "ブーストされた数やで"
|
||||||
followingCount: "フォロー数やで"
|
followingCount: "フォロー数やで"
|
||||||
followersCount: "フォロワー数やで"
|
followersCount: "フォロワー数やで"
|
||||||
sentReactionsCount: "リアクションした数やで"
|
sentReactionsCount: "リアクションした数やで"
|
||||||
|
@ -666,15 +671,15 @@ no: "いいえ"
|
||||||
driveFilesCount: "ドライブのファイル数"
|
driveFilesCount: "ドライブのファイル数"
|
||||||
driveUsage: "ドライブ使用量やで"
|
driveUsage: "ドライブ使用量やで"
|
||||||
noCrawle: "クローラーによるインデックスを拒否するで"
|
noCrawle: "クローラーによるインデックスを拒否するで"
|
||||||
noCrawleDescription: "検索エンジンにあんたのユーザーページ、ノート、Pagesとかのコンテンツを登録(インデックス)せぇへんように頼むで。"
|
noCrawleDescription: "検索エンジンにあんたのプロフィール、投稿、ページとかのコンテンツを登録(インデックス)せぇへんように頼むで。"
|
||||||
lockedAccountInfo: "フォローを承認制にしとっても、ノートの公開範囲を「フォロワー」にせぇへん限り、誰でもあんたのノートを見れるで。"
|
lockedAccountInfo: "フォローを承認制にしとっても、投稿の公開範囲を「フォロワー」にせん限り、誰でもあんたの投稿を見れるで。"
|
||||||
alwaysMarkSensitive: "デフォルトでメディアを閲覧注意にするで"
|
alwaysMarkSensitive: "デフォルトでメディアを閲覧注意にするで"
|
||||||
loadRawImages: "添付画像のサムネイルをオリジナル画質にするで"
|
loadRawImages: "添付画像のサムネイルをオリジナル画質にするで"
|
||||||
disableShowingAnimatedImages: "アニメーション画像を再生しやへんで"
|
disableShowingAnimatedImages: "アニメーション画像を再生しやへんで"
|
||||||
verificationEmailSent: "無事確認のメールを送れたで。メールに書いてあるリンクにアクセスして、設定を完了してなー。"
|
verificationEmailSent: "無事確認のメールを送れたで。メールに書いてあるリンクにアクセスして、設定を完了してなー。"
|
||||||
notSet: "未設定"
|
notSet: "未設定"
|
||||||
emailVerified: "メールアドレスは確認されたで"
|
emailVerified: "メールアドレスは確認されたで"
|
||||||
noteFavoritesCount: "お気に入りノートの数やで"
|
noteFavoritesCount: "お気に入り投稿の数やで"
|
||||||
pageLikesCount: "Pageにええやんと思った数"
|
pageLikesCount: "Pageにええやんと思った数"
|
||||||
pageLikedCount: "Pageにええやんと思ってくれた数"
|
pageLikedCount: "Pageにええやんと思ってくれた数"
|
||||||
contact: "連絡先"
|
contact: "連絡先"
|
||||||
|
@ -684,7 +689,7 @@ experimentalFeatures: "実験的機能やで"
|
||||||
developer: "開発者やで"
|
developer: "開発者やで"
|
||||||
makeExplorable: "アカウントを見つけやすくするで"
|
makeExplorable: "アカウントを見つけやすくするで"
|
||||||
makeExplorableDescription: "オフにすると、「みつける」にアカウントが載らんくなるで。"
|
makeExplorableDescription: "オフにすると、「みつける」にアカウントが載らんくなるで。"
|
||||||
showGapBetweenNotesInTimeline: "タイムラインのノートを放して表示するで"
|
showGapBetweenNotesInTimeline: "タイムライン上の投稿を離して表示するで"
|
||||||
duplicate: "複製"
|
duplicate: "複製"
|
||||||
left: "左"
|
left: "左"
|
||||||
center: "中央"
|
center: "中央"
|
||||||
|
@ -696,9 +701,10 @@ showTitlebar: "タイトルバーを見せる"
|
||||||
clearCache: "キャッシュをほかす"
|
clearCache: "キャッシュをほかす"
|
||||||
onlineUsersCount: "{n}人が起きとるで"
|
onlineUsersCount: "{n}人が起きとるで"
|
||||||
nUsers: "{n}ユーザー"
|
nUsers: "{n}ユーザー"
|
||||||
nNotes: "{n}ノート"
|
nNotes: "{n}投稿"
|
||||||
sendErrorReports: "エラーリポートを送る"
|
sendErrorReports: "エラーリポートを送る"
|
||||||
sendErrorReportsDescription: "オンにしたら、なんか変なことが起きたときにエラーの詳細がMisskeyに共有されて、ソフトウェアの品質向上に役立てられるんや。エラー情報には、OSのバージョン、ブラウザの種類、行動履歴などが含まれるで。"
|
sendErrorReportsDescription: "オンにしたら、なんやけったいなことが起きたときにエラーの詳細がFirefishに共有されて、ソフトウェアの品質向上に役立てられるんや。\n\
|
||||||
|
エラー情報には、OSのバージョン、ブラウザの種類、行動履歴などが含まれるで。"
|
||||||
myTheme: "マイテーマ"
|
myTheme: "マイテーマ"
|
||||||
backgroundColor: "背景"
|
backgroundColor: "背景"
|
||||||
accentColor: "アクセント"
|
accentColor: "アクセント"
|
||||||
|
@ -722,7 +728,7 @@ capacity: "容量"
|
||||||
inUse: "使用中"
|
inUse: "使用中"
|
||||||
editCode: "コードを編集"
|
editCode: "コードを編集"
|
||||||
apply: "適用"
|
apply: "適用"
|
||||||
receiveAnnouncementFromInstance: "インスタンスからのお知らせを受け取る"
|
receiveAnnouncementFromInstance: "サーバーからのお知らせを受け取る"
|
||||||
emailNotification: "メール通知"
|
emailNotification: "メール通知"
|
||||||
publish: "公開"
|
publish: "公開"
|
||||||
inChannelSearch: "チャンネル内検索"
|
inChannelSearch: "チャンネル内検索"
|
||||||
|
@ -737,7 +743,7 @@ unlikeConfirm: "いいね解除するんか?"
|
||||||
fullView: "フルビュー"
|
fullView: "フルビュー"
|
||||||
quitFullView: "フルビュー解除"
|
quitFullView: "フルビュー解除"
|
||||||
addDescription: "説明を追加するで"
|
addDescription: "説明を追加するで"
|
||||||
userPagePinTip: "個々のノートのメニューから「ピン留め」を選んどくと、ここにノートを表示しておけるで。"
|
userPagePinTip: "個々の投稿のメニューから「ピン留め」を選んどくと、ここにそいつを表示しておけるで。"
|
||||||
notSpecifiedMentionWarning: "宛先に含まれてへんメンションがあるで"
|
notSpecifiedMentionWarning: "宛先に含まれてへんメンションがあるで"
|
||||||
info: "情報"
|
info: "情報"
|
||||||
userInfo: "ユーザー情報やで"
|
userInfo: "ユーザー情報やで"
|
||||||
|
@ -750,7 +756,7 @@ active: "アクティブ"
|
||||||
offline: "オフライン"
|
offline: "オフライン"
|
||||||
notRecommended: "あんま推奨しやんで"
|
notRecommended: "あんま推奨しやんで"
|
||||||
botProtection: "Botプロテクション"
|
botProtection: "Botプロテクション"
|
||||||
instanceBlocking: "インスタンスブロック"
|
instanceBlocking: "連合の管理"
|
||||||
selectAccount: "アカウントを選んでなー"
|
selectAccount: "アカウントを選んでなー"
|
||||||
switchAccount: "アカウントを変えるで"
|
switchAccount: "アカウントを変えるで"
|
||||||
enabled: "有効"
|
enabled: "有効"
|
||||||
|
@ -767,7 +773,7 @@ postToGallery: "ギャラリーへ投稿"
|
||||||
gallery: "ギャラリー"
|
gallery: "ギャラリー"
|
||||||
recentPosts: "最近の投稿"
|
recentPosts: "最近の投稿"
|
||||||
popularPosts: "人気の投稿"
|
popularPosts: "人気の投稿"
|
||||||
shareWithNote: "ノートで共有"
|
shareWithNote: "投稿で共有"
|
||||||
ads: "広告"
|
ads: "広告"
|
||||||
expiration: "期限"
|
expiration: "期限"
|
||||||
memo: "メモ"
|
memo: "メモ"
|
||||||
|
@ -789,7 +795,7 @@ hashtags: "ハッシュタグ"
|
||||||
troubleshooting: "トラブルシューティング"
|
troubleshooting: "トラブルシューティング"
|
||||||
useBlurEffect: "UIにぼかし効果を使うで"
|
useBlurEffect: "UIにぼかし効果を使うで"
|
||||||
learnMore: "詳しく"
|
learnMore: "詳しく"
|
||||||
misskeyUpdated: "Misskeyが更新されたで!\nモデレーターの人らに感謝せなあかんで"
|
misskeyUpdated: "Firefishが更新されたで!\nモデレーターの人らに感謝やね"
|
||||||
whatIsNew: "更新情報を見るで"
|
whatIsNew: "更新情報を見るで"
|
||||||
translate: "翻訳"
|
translate: "翻訳"
|
||||||
translatedFrom: "{x}から翻訳するで"
|
translatedFrom: "{x}から翻訳するで"
|
||||||
|
@ -834,7 +840,7 @@ cannotUploadBecauseInappropriate: "不適切な内容を含むかもしれへん
|
||||||
cannotUploadBecauseNoFreeSpace: "ドライブの空き容量が無いでアップロードできまへん。"
|
cannotUploadBecauseNoFreeSpace: "ドライブの空き容量が無いでアップロードできまへん。"
|
||||||
beta: "ベータ"
|
beta: "ベータ"
|
||||||
enableAutoSensitive: "自動NSFW判定"
|
enableAutoSensitive: "自動NSFW判定"
|
||||||
enableAutoSensitiveDescription: "使える時は、機械学習を使って自動でメディアにNSFWフラグを設定するで。この機能をオフにしても、インスタンスによっては自動で設定されることがあるで。"
|
enableAutoSensitiveDescription: "いけるときは、機械学習を使って自動でメディアにNSFWフラグを設定するで。この機能をオフにしても、サーバーによっては自動で設定されることがあるで。"
|
||||||
activeEmailValidationDescription: "ユーザーのメールアドレスのバリデーションを、捨てアドかどうかや実際に通信可能かどうかとかを判定して積極的に行うで。オフにすると単に文字列として正しいかどうかだけチェックするで。"
|
activeEmailValidationDescription: "ユーザーのメールアドレスのバリデーションを、捨てアドかどうかや実際に通信可能かどうかとかを判定して積極的に行うで。オフにすると単に文字列として正しいかどうかだけチェックするで。"
|
||||||
navbar: "ナビゲーションバー"
|
navbar: "ナビゲーションバー"
|
||||||
shuffle: "シャッフルするで"
|
shuffle: "シャッフルするで"
|
||||||
|
@ -868,14 +874,15 @@ _registry:
|
||||||
domain: "ドメイン"
|
domain: "ドメイン"
|
||||||
createKey: "キーを作る"
|
createKey: "キーを作る"
|
||||||
_aboutFirefish:
|
_aboutFirefish:
|
||||||
about: "Misskeyはsyuiloが2014年からずっと作ってはる、オープンソースなソフトウェアや。"
|
about: "Firefishは、ThatOneCalculatorが2022年にMisskeyをいじって作った、オープンなソースのソフトウェアや。"
|
||||||
contributors: "主な貢献者"
|
contributors: "主な貢献者"
|
||||||
allContributors: "全ての貢献者"
|
allContributors: "全ての貢献者"
|
||||||
source: "ソースコード"
|
source: "ソースコード"
|
||||||
translation: "Misskeyを翻訳"
|
translation: "Firefishを翻訳"
|
||||||
donate: "Misskeyに寄付"
|
donate: "Firefishに寄付"
|
||||||
morePatrons: "他にもぎょうさんの人からサポートしてもろてんねん。ほんまおおきに🥰"
|
morePatrons: "他にもぎょうさんの人からサポートしてもろてんねん。ほんまおおきに🥰"
|
||||||
patrons: "支援者"
|
patrons: "支援者"
|
||||||
|
misskeyContributors: フォーク元のMisskeyを作らはった人ら
|
||||||
_mfm:
|
_mfm:
|
||||||
cheatSheet: "MFMチートシート"
|
cheatSheet: "MFMチートシート"
|
||||||
mention: "メンション"
|
mention: "メンション"
|
||||||
|
@ -896,6 +903,7 @@ _mfm:
|
||||||
blur: "ぼかし"
|
blur: "ぼかし"
|
||||||
font: "フォント"
|
font: "フォント"
|
||||||
rotate: "回転"
|
rotate: "回転"
|
||||||
|
intro: MFMは、MisskeyやFirefish、Akkomaなどの様々な場所で使用できるマークアップ言語なんよ。ここでは、MFMで使用可能な構文一覧が確認できるで。
|
||||||
_instanceTicker:
|
_instanceTicker:
|
||||||
none: "表示せん"
|
none: "表示せん"
|
||||||
remote: "リモートユーザーに表示"
|
remote: "リモートユーザーに表示"
|
||||||
|
@ -958,7 +966,7 @@ _theme:
|
||||||
hashtag: "ハッシュタグ"
|
hashtag: "ハッシュタグ"
|
||||||
mention: "メンション"
|
mention: "メンション"
|
||||||
mentionMe: "うち宛てのメンション"
|
mentionMe: "うち宛てのメンション"
|
||||||
renote: "Renote"
|
renote: "ブースト"
|
||||||
modalBg: "モーダルの背景"
|
modalBg: "モーダルの背景"
|
||||||
divider: "分割線"
|
divider: "分割線"
|
||||||
scrollbarHandle: "スクロールバーの取っ手"
|
scrollbarHandle: "スクロールバーの取っ手"
|
||||||
|
@ -985,8 +993,8 @@ _theme:
|
||||||
accentLighten: "アクセント (明るめ)"
|
accentLighten: "アクセント (明るめ)"
|
||||||
fgHighlighted: "強調されとる文字"
|
fgHighlighted: "強調されとる文字"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "ノート"
|
note: "投稿"
|
||||||
noteMy: "ノート(自分)"
|
noteMy: "投稿(自分)"
|
||||||
notification: "通知"
|
notification: "通知"
|
||||||
chat: "チャット"
|
chat: "チャット"
|
||||||
_ago:
|
_ago:
|
||||||
|
@ -1017,8 +1025,8 @@ _permissions:
|
||||||
_auth:
|
_auth:
|
||||||
permissionAsk: "このアプリは次の権限を要求しとるで"
|
permissionAsk: "このアプリは次の権限を要求しとるで"
|
||||||
_antennaSources:
|
_antennaSources:
|
||||||
all: "みんなのノート"
|
all: "みんなの投稿"
|
||||||
homeTimeline: "フォローしとるユーザーのノート"
|
homeTimeline: "フォローしとるユーザーの投稿"
|
||||||
_weekday:
|
_weekday:
|
||||||
sunday: "日曜日"
|
sunday: "日曜日"
|
||||||
monday: "月曜日"
|
monday: "月曜日"
|
||||||
|
@ -1072,7 +1080,7 @@ _profile:
|
||||||
name: "名前"
|
name: "名前"
|
||||||
username: "ユーザー名"
|
username: "ユーザー名"
|
||||||
_exportOrImport:
|
_exportOrImport:
|
||||||
allNotes: "全てのノート"
|
allNotes: "すべての投稿"
|
||||||
followingList: "フォロー"
|
followingList: "フォロー"
|
||||||
muteList: "ミュート"
|
muteList: "ミュート"
|
||||||
blockingList: "ブロック"
|
blockingList: "ブロック"
|
||||||
|
@ -1082,10 +1090,10 @@ _charts:
|
||||||
apRequest: "リクエスト"
|
apRequest: "リクエスト"
|
||||||
usersTotal: "ユーザーの合計"
|
usersTotal: "ユーザーの合計"
|
||||||
activeUsers: "アクティブユーザー数"
|
activeUsers: "アクティブユーザー数"
|
||||||
notesIncDec: "ノートの増減"
|
notesIncDec: "投稿の増減"
|
||||||
localNotesIncDec: "ローカルのノートの増減"
|
localNotesIncDec: "ローカルの投稿の増減"
|
||||||
remoteNotesIncDec: "リモートのノートの増減"
|
remoteNotesIncDec: "リモートの投稿の増減"
|
||||||
notesTotal: "ノートの合計"
|
notesTotal: "投稿の合計"
|
||||||
filesIncDec: "ファイルの増減"
|
filesIncDec: "ファイルの増減"
|
||||||
filesTotal: "ファイルの合計"
|
filesTotal: "ファイルの合計"
|
||||||
storageUsageIncDec: "ストレージ使用量の増減"
|
storageUsageIncDec: "ストレージ使用量の増減"
|
||||||
|
@ -1094,8 +1102,8 @@ _instanceCharts:
|
||||||
requests: "リクエスト"
|
requests: "リクエスト"
|
||||||
users: "ユーザーの増減"
|
users: "ユーザーの増減"
|
||||||
usersTotal: "ユーザーの累積"
|
usersTotal: "ユーザーの累積"
|
||||||
notes: "ノートの増減"
|
notes: "投稿の増減"
|
||||||
notesTotal: "ノートの累積"
|
notesTotal: "投稿の累積"
|
||||||
ff: "フォロー/フォロワーの増減"
|
ff: "フォロー/フォロワーの増減"
|
||||||
ffTotal: "フォロー/フォロワーの累積"
|
ffTotal: "フォロー/フォロワーの累積"
|
||||||
cacheSize: "キャッシュサイズの増減"
|
cacheSize: "キャッシュサイズの増減"
|
||||||
|
@ -1165,9 +1173,9 @@ _pages:
|
||||||
id: "キャンバスID"
|
id: "キャンバスID"
|
||||||
width: "幅"
|
width: "幅"
|
||||||
height: "高さ"
|
height: "高さ"
|
||||||
note: "ノート埋め込み"
|
note: "投稿の埋め込み"
|
||||||
_note:
|
_note:
|
||||||
id: "ノートID"
|
id: "投稿のID"
|
||||||
detailed: "詳細な表示"
|
detailed: "詳細な表示"
|
||||||
switch: "スイッチ"
|
switch: "スイッチ"
|
||||||
_switch:
|
_switch:
|
||||||
|
@ -1385,14 +1393,14 @@ _notification:
|
||||||
all: "すべて"
|
all: "すべて"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
mention: "メンション"
|
mention: "メンション"
|
||||||
renote: "Renote"
|
renote: "ブースト"
|
||||||
quote: "引用"
|
quote: "引用"
|
||||||
reaction: "リアクション"
|
reaction: "リアクション"
|
||||||
receiveFollowRequest: "フォロー許可してほしいみたいやで"
|
receiveFollowRequest: "フォロー許可してほしいみたいやで"
|
||||||
followRequestAccepted: "フォローが受理されたで"
|
followRequestAccepted: "フォローが受理されたで"
|
||||||
_actions:
|
_actions:
|
||||||
reply: "返事"
|
reply: "返事"
|
||||||
renote: "Renote"
|
renote: "ブースト"
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "いつもメインカラムを表示"
|
alwaysShowMainColumn: "いつもメインカラムを表示"
|
||||||
columnAlign: "カラムの寄せ"
|
columnAlign: "カラムの寄せ"
|
||||||
|
@ -1413,3 +1421,28 @@ _deck:
|
||||||
list: "リスト"
|
list: "リスト"
|
||||||
mentions: "あんた宛て"
|
mentions: "あんた宛て"
|
||||||
direct: "ダイレクト"
|
direct: "ダイレクト"
|
||||||
|
_experiments:
|
||||||
|
postImportsCaption:
|
||||||
|
ユーザーが過去の投稿をFirefish・Misskey・Mastodon・Akkoma・Pleromaからインポートできるようにするで。キューが溜まっとるときにインポートするとサーバーに負荷がかかるかもしれんね。
|
||||||
|
searchPlaceholder: Firefishを検索
|
||||||
|
addInstance: サーバーを追加
|
||||||
|
editNote: 投稿を編集
|
||||||
|
edited: '編集済み: {date} {time}'
|
||||||
|
deleted: 削除済み
|
||||||
|
noThankYou: いらんわ
|
||||||
|
_tutorial:
|
||||||
|
step3_1: ほな、何人かフォローしてみまひょ
|
||||||
|
step1_1: おこしやす
|
||||||
|
step1_2: 使い始める前に、いくつか設定を済ませまひょ。すぐできますえ。
|
||||||
|
step2_1: 最初に、あんさんのプロフィールを作りまひょ
|
||||||
|
step2_2: プロフィールを設定しはることで、他ん人があんさんの投稿を見たり、フォローしたりするときの助けになってます。
|
||||||
|
_postForm:
|
||||||
|
_placeholders:
|
||||||
|
b: なんかおましたか?
|
||||||
|
e: ここに書いとくれやす
|
||||||
|
c: なに考えとりまっか?
|
||||||
|
d: なんや言いたいんちゃいますか?
|
||||||
|
f: あんさん書くんを待っとるんどす...
|
||||||
|
flagSpeakAsCat: 猫弁で話す
|
||||||
|
flagSpeakAsCatDescription: 猫モードが有効の場合にオンにすると、ワレの投稿の「な」を「にゃ」に変換するで。
|
||||||
|
welcomeBackWithName: おおきに、{name}はん
|
||||||
|
|
|
@ -44,7 +44,7 @@ lists: Lister
|
||||||
listsDesc: Lister lar deg lage tidslinjer med utvalgte brukere. De kan hentes frem
|
listsDesc: Lister lar deg lage tidslinjer med utvalgte brukere. De kan hentes frem
|
||||||
fra tidslinje-siden.
|
fra tidslinje-siden.
|
||||||
deleted: Slettet
|
deleted: Slettet
|
||||||
editNote: Rediger notat
|
editNote: Rediger post
|
||||||
followsYou: Følger deg
|
followsYou: Følger deg
|
||||||
createList: Lag liste
|
createList: Lag liste
|
||||||
newer: nyere
|
newer: nyere
|
||||||
|
@ -155,7 +155,7 @@ drive: Disk
|
||||||
renameFile: Omdøp fil
|
renameFile: Omdøp fil
|
||||||
folderName: Katalognavn
|
folderName: Katalognavn
|
||||||
createFolder: Opprett katalog
|
createFolder: Opprett katalog
|
||||||
inputNewDescription: Oppgi ny bildetekst
|
inputNewDescription: Skriv ny beskrivelse
|
||||||
inputNewFolderName: Oppgi nytt katalognavn
|
inputNewFolderName: Oppgi nytt katalognavn
|
||||||
copyUrl: Kopier URL
|
copyUrl: Kopier URL
|
||||||
hcaptchaSiteKey: hCaptcha-nøkkel for nettstedet
|
hcaptchaSiteKey: hCaptcha-nøkkel for nettstedet
|
||||||
|
@ -409,7 +409,7 @@ nothing: Ikke noe å se her
|
||||||
deleteAllFilesConfirm: Er du sikker på at du vil slette alle filer?
|
deleteAllFilesConfirm: Er du sikker på at du vil slette alle filer?
|
||||||
updateRemoteUser: Oppdater informasjon om ekstern bruker
|
updateRemoteUser: Oppdater informasjon om ekstern bruker
|
||||||
deleteAllFiles: Slett alle filer
|
deleteAllFiles: Slett alle filer
|
||||||
enterFileDescription: Legg til bildetekst
|
enterFileDescription: Skriv inn beskrivelse
|
||||||
leaveConfirm: Det er ulagrede endringer. Vil du forkaste dem?
|
leaveConfirm: Det er ulagrede endringer. Vil du forkaste dem?
|
||||||
enableAll: Slå på alle
|
enableAll: Slå på alle
|
||||||
generateAccessToken: Generer adgangstegn
|
generateAccessToken: Generer adgangstegn
|
||||||
|
@ -506,7 +506,7 @@ yourAccountSuspendedDescription: Denne kontoen er suspendert fordi den har brutt
|
||||||
useCw: Skjul innhold
|
useCw: Skjul innhold
|
||||||
enablePlayer: Åpne videospiller
|
enablePlayer: Åpne videospiller
|
||||||
disablePlayer: Lukk videospiller
|
disablePlayer: Lukk videospiller
|
||||||
describeFile: Legg til tekst
|
describeFile: Legg til beskrivelse
|
||||||
author: Forfatter
|
author: Forfatter
|
||||||
useFullReactionPicker: Bruk reaksjonsvelger i full størrelse
|
useFullReactionPicker: Bruk reaksjonsvelger i full størrelse
|
||||||
width: Bredde
|
width: Bredde
|
||||||
|
@ -718,3 +718,405 @@ alwaysMarkSensitive: Merk som "Sensitivt innhold" som standard
|
||||||
verificationEmailSent: En verifiserings-epost er sendt. Følg lenken i eposten for
|
verificationEmailSent: En verifiserings-epost er sendt. Følg lenken i eposten for
|
||||||
å fullføre verifiseringen.
|
å fullføre verifiseringen.
|
||||||
newNoteRecived: Det er nye poster
|
newNoteRecived: Det er nye poster
|
||||||
|
scratchpadDescription: Kladdeblokka gir deg et miljø for å eksperimentere med AiScript.
|
||||||
|
Du kan skrive, kjøre og sjekke resultatene av at koden interagerer med Firefish.
|
||||||
|
disablePagesScript: Slå av AiScript på Sider
|
||||||
|
expandTweet: Ekspander tweet
|
||||||
|
public: Offentlig
|
||||||
|
clearCache: Slett mellomlager
|
||||||
|
onlineUsersCount: '{n} brukere er innlogget'
|
||||||
|
nNotes: '{n} poster'
|
||||||
|
sendErrorReports: Send feilmeldinger
|
||||||
|
deleteConfirm: Virkelig slette?
|
||||||
|
latestVersion: Nyeste versjon
|
||||||
|
receiveAnnouncementFromInstance: Motta varsler fra denne tjeneren
|
||||||
|
inChannelSearch: Søk i kanal
|
||||||
|
selectAccount: Velg konto
|
||||||
|
switch: Bytt
|
||||||
|
instanceDefaultDarkTheme: Standard mørkt tema på tjeneren
|
||||||
|
oneDay: En dag
|
||||||
|
driveCapOverrideCaption: Tilbakestill kapasiteten til standardverdien ved å legge
|
||||||
|
inn en verdi på 0 eller lavere.
|
||||||
|
sendModMail: Send modereringsvarsel
|
||||||
|
enableServerMachineStats: Slå på hardware-statistikk for tjeneren
|
||||||
|
_gallery:
|
||||||
|
liked: Likte poster
|
||||||
|
unlike: Fjern lik
|
||||||
|
my: Mitt galleri
|
||||||
|
like: Lik
|
||||||
|
_preferencesBackups:
|
||||||
|
loadFile: Last fra fil
|
||||||
|
cannotSave: Lagring feilet
|
||||||
|
deleteConfirm: Vil du slette sikkerhetskopien "{name}"?
|
||||||
|
saveConfirm: Lagre sikkerhetskopi som "{name}"?
|
||||||
|
noBackups: Ingen sikkerhetskopier er tatt. Du kan ta en backup av klientinnstillingene
|
||||||
|
dine på denne tjeneren ved å trykke "Lag ny sikkerhetskopi".
|
||||||
|
applyConfirm: Ønsker du å laste inn sikkerhetskopien "{name}" på denne enheten?
|
||||||
|
Eksisterende innstillinger vil bli overskrevet.
|
||||||
|
save: Lagre endringer
|
||||||
|
nameAlreadyExists: En sikkerhetskopi med navnet "{name}" finnes allerede. Skriv
|
||||||
|
inn et annet navn.
|
||||||
|
createdAt: 'Opprettet: {date} {time}'
|
||||||
|
apply: Bruk på denne enheten
|
||||||
|
renameConfirm: Endre navn på sikkerhetskopien fra "{old}" to "{new}"?
|
||||||
|
list: Opprettede sikkerhetskopier
|
||||||
|
saveNew: Ta ny sikkerhetskopi
|
||||||
|
inputName: Gi sikkerhetskopien et navn
|
||||||
|
updatedAt: 'Oppdatert: {date} {time}'
|
||||||
|
cannotLoad: Innlasting feilet
|
||||||
|
invalidFile: Ugyldig filformat
|
||||||
|
_ad:
|
||||||
|
back: Tilbake
|
||||||
|
reduceFrequencyOfThisAd: Vis annonsen sjeldnere
|
||||||
|
_mfm:
|
||||||
|
cheatSheet: Jukseark for tekstmarkering (MFM)
|
||||||
|
stop: Stopp animert markeringsspråk (MFM)
|
||||||
|
warn: Markeringsspråket (MFM) kan inneholde bevegelige eller blinkende animasjoner
|
||||||
|
alwaysPlay: Alltid spill av animert tekstmarkering (MFM)
|
||||||
|
play: Spill animert markeringsspråk (MFM)
|
||||||
|
intro: MFM er et markeringsspråk som burkes av Misskey, Firefish, Akkoma og andre.
|
||||||
|
Her kan du se en liste over tilgjengelig MFM-syntaks.
|
||||||
|
reactionPickerSkinTone: Foretrukket hudfarge i emojier
|
||||||
|
switchUi: Visningsoppsett
|
||||||
|
usageAmount: Bruk
|
||||||
|
memo: Memo
|
||||||
|
priority: Prioritet
|
||||||
|
high: Høy
|
||||||
|
secureMode: Sikker modus (Autorisert henting)
|
||||||
|
requireAdminForView: Du må logge inn på en administratorkonto for å se dette.
|
||||||
|
typeToConfirm: Skriv inn {x} for å bekrefte
|
||||||
|
replayTutorial: Kjør introduksjon på nytt
|
||||||
|
moveTo: Flytt denne kontoen til en ny konto
|
||||||
|
objectStorageBucketDesc: Skriv inn navnet på bøtta hos lagringstjenesten.
|
||||||
|
notRecommended: Ikke anbefalt
|
||||||
|
voteConfirm: Bekreft din stemme på "{choice}"?
|
||||||
|
oneHour: En time
|
||||||
|
_plugin:
|
||||||
|
installWarn: Ikke installer utvidelser du ikke stoler på.
|
||||||
|
install: Installer innstikk
|
||||||
|
manage: Oppsett av innstikk
|
||||||
|
preventAiLearning: Hindre tråling fra AI-boter
|
||||||
|
reporterOrigin: Kilden til den som rapporterer
|
||||||
|
center: Sentrert
|
||||||
|
wide: Bred
|
||||||
|
value: Verdi
|
||||||
|
createdAt: Opprettet
|
||||||
|
active: Aktiv
|
||||||
|
hideOnlineStatus: Skjul om du er pålogget
|
||||||
|
troubleshooting: Problemløsing
|
||||||
|
useBlurEffect: Bruk diffuseringseffekter i brukergrensesnittet
|
||||||
|
learnMore: Lær mer
|
||||||
|
usernameInfo: Et navn som identifiserer din konto på denne tjeneren. Du kan bruke
|
||||||
|
alfabetet (a-z,A-Z), sifre (0-9) og understrek (_). Brukernavn kan ikke endres senere.
|
||||||
|
resolved: Løst
|
||||||
|
unresolved: Uløst
|
||||||
|
welcomeBackWithName: Velkommen tilbake, {name}
|
||||||
|
clickToFinishEmailVerification: Klikk [{ok}] for å fullføre epost-verifisering.
|
||||||
|
cropImage: Beskjær bilde
|
||||||
|
numberOfPageCacheDescription: En økning i dette tallet vil gjøre brukeropplevelsen
|
||||||
|
bedre, men gi mer jobb til tjeneren og kreve mer minne.
|
||||||
|
logoutConfirm: Vil du logge ut?
|
||||||
|
numberOfPageCache: Antall mellomlagrede sider
|
||||||
|
lastActiveDate: Sist brukt
|
||||||
|
refreshInterval: 'Oppdateringsintervall '
|
||||||
|
swipeOnDesktop: Tillat mobil-lignende sveiping på skrivebords-PC
|
||||||
|
migration: Migrering
|
||||||
|
useDrawerReactionPickerForMobile: Vis reaksjosnvelger som en skuff på mobil
|
||||||
|
numberOfColumn: Antall kolonner
|
||||||
|
searchByGoogle: Søk
|
||||||
|
oneWeek: En uke
|
||||||
|
file: Fil
|
||||||
|
recentNHours: Siste {n} timer
|
||||||
|
noEmailServerWarning: E-post-tjener er ikke konfigurert.
|
||||||
|
thereIsUnresolvedAbuseReportWarning: Det er uløste rapporter.
|
||||||
|
colored: I farger
|
||||||
|
recommendedInstancesDescription: Anbefalte tjenere skilt med linjeskift for visning
|
||||||
|
i anbefalt-tidslinjen.
|
||||||
|
caption: Automatisk beskrivelse
|
||||||
|
updateAvailable: En oppdatering kan være tilgjengelig!
|
||||||
|
accentColor: Uthevet farge
|
||||||
|
textColor: Skriftfarge
|
||||||
|
saveAs: Lagre som...
|
||||||
|
swipeOnMobile: Tillat sveiping mellom sider
|
||||||
|
_accountDelete:
|
||||||
|
inProgress: Sletting pågår
|
||||||
|
remote: Ekstern
|
||||||
|
total: Total
|
||||||
|
registry: Register
|
||||||
|
closeAccount: Avslutt konto
|
||||||
|
currentVersion: Nåværende versjon
|
||||||
|
fullView: Full visning
|
||||||
|
gallery: Galleri
|
||||||
|
emailNotConfiguredWarning: E-post-adresse er ikke satt.
|
||||||
|
allowedInstancesDescription: Tjenernavn for tjenere som skal hvitelistes. En per linje.
|
||||||
|
(Vil bare bli brukt i privat modus).
|
||||||
|
previewNoteText: Forhåndsvisning
|
||||||
|
recentNDays: Siste {n} dager
|
||||||
|
indexPosts: Indekser poster
|
||||||
|
objectStorageUseProxy: Koble til gjennom en mellomtjener
|
||||||
|
objectStorageUseProxyDesc: Skru av dette dersom du ikke vil bruke mellomtjenere for
|
||||||
|
API-oppkoblinger
|
||||||
|
masterVolume: Hovedvolum
|
||||||
|
script: Skript
|
||||||
|
divider: Skille
|
||||||
|
addItem: Legg til element
|
||||||
|
manage: Oppsett
|
||||||
|
notificationType: Varseltype
|
||||||
|
useBlurEffectForModal: Bruk diffus-effekt for modale brukergrensesnitt-elementer
|
||||||
|
driveFilesCount: Antall filer på Disk
|
||||||
|
showGapBetweenNotesInTimeline: Legg inn et tomrom mellom postene i tidslinjen
|
||||||
|
newVersionOfClientAvailable: En nyere versjon av klienten er tilgjengelig.
|
||||||
|
capacity: Kapasitet
|
||||||
|
inUse: Brukt
|
||||||
|
publish: Publiser
|
||||||
|
quickAction: Hurtigvalg
|
||||||
|
privateMode: Privat modus
|
||||||
|
customCss: Egendefinert CSS
|
||||||
|
allowedInstances: Hvitelistede tjenere
|
||||||
|
lastCommunication: Siste kommunikasjon
|
||||||
|
breakFollowConfirm: Er du sikker på at du vil fjerne følgeren?
|
||||||
|
filter: Filter
|
||||||
|
makeReactionsPublicDescription: Dette vil gjøre listen over dine tidligere reaksjoner
|
||||||
|
synlige for alle.
|
||||||
|
indefinitely: Permanent
|
||||||
|
tenMinutes: 10 minutter
|
||||||
|
_email:
|
||||||
|
_follow:
|
||||||
|
title: Du har en ny følger
|
||||||
|
_receiveFollowRequest:
|
||||||
|
title: Du har mottatt en følgeforespørsel
|
||||||
|
_registry:
|
||||||
|
key: Nøkkel
|
||||||
|
scope: Omfang
|
||||||
|
domain: Domene
|
||||||
|
createKey: Opprettet nøkkel
|
||||||
|
keys: Nøkler
|
||||||
|
sendErrorReportsDescription: "Detaljert feilinformasjon vli bli delt med utviklerne
|
||||||
|
av Firefish, noe som hjelper til med feilretting og forbedring av programmet.\n
|
||||||
|
- Dette inkluderer informasjon som f.eks. versjonen på operativsystemet og nettleseren
|
||||||
|
din, og aktiviteten din i Firefish."
|
||||||
|
_aboutFirefish:
|
||||||
|
translation: Oversett Firefish
|
||||||
|
donate: Donér til Firefish
|
||||||
|
donateTitle: Liker du Firefish?
|
||||||
|
pleaseDonateToFirefish: Du kan vurdere å donere en slant til Firefish for å støtte
|
||||||
|
videre utvikling og feilretting.
|
||||||
|
donateHost: Donér til {host}
|
||||||
|
morePatrons: Vi er også takknemlige for bidragene fra mange andre som ikke er listet
|
||||||
|
her. Takk til dere alle! 🥰
|
||||||
|
contributors: Hovedutviklere
|
||||||
|
source: Kildekode
|
||||||
|
allContributors: Alle bidragsytere
|
||||||
|
misskeyContributors: Misskeys bidragsytere
|
||||||
|
pleaseDonateToHost: Du kan også vurdere å donere til hjemme-tjeneren din, {host},
|
||||||
|
for å hjelpe dem med driftskostnadene for tjenesten.
|
||||||
|
about: Firefish ble opprettet av ThatOneCalculator i 2022, basert på Misskey.
|
||||||
|
sponsors: Firefishs sponsorer
|
||||||
|
patrons: Firefishs patroner
|
||||||
|
patronsList: Listen er kronologisk, ikke etter donert beløp. Doner med lenken over
|
||||||
|
for å få navnet ditt her!
|
||||||
|
isBot: Denne kontoen er en bot
|
||||||
|
_nsfw:
|
||||||
|
respect: Skjul NSFW-merket media
|
||||||
|
force: Skjul alle media
|
||||||
|
ignore: Ikke skjul NSFW-media
|
||||||
|
disableAnimatedMfm: Slå av animert markeringsspråk
|
||||||
|
objectStorageBucket: Bøtte
|
||||||
|
scratchpad: Kladdeblokk
|
||||||
|
plugins: Innstikk
|
||||||
|
createNew: Lag ny
|
||||||
|
makeExplorable: Gjør kontoen synlig i "Utforsk"
|
||||||
|
needReloadToApply: Siden må lastes på nytt for at denne endringen skal tre inn.
|
||||||
|
customCssWarn: Bruk denne innstillingen bare hvis du vet hva den gjør. Feil innstilling
|
||||||
|
kan få klienten til å ikke fungere som den skal.
|
||||||
|
low: Lav
|
||||||
|
global: Global
|
||||||
|
recommended: Anbefalt
|
||||||
|
instanceSecurity: Tjenersikkerhet
|
||||||
|
squareAvatars: Vis firkantede avatarer
|
||||||
|
deleteAccount: Slett konto
|
||||||
|
customKaTeXMacro: Egne KaTeX-makroer
|
||||||
|
size: Størrelse
|
||||||
|
fast: Raskt
|
||||||
|
showAdminUpdates: Indikerer at en ny versjon av Firefish er tilgjengelig (bare admin)
|
||||||
|
moveAccount: Flytt konto!
|
||||||
|
license: Lisens
|
||||||
|
wordMute: Ordstumming
|
||||||
|
reporteeOrigin: Kilden til den som rapporteres
|
||||||
|
accountInfo: Kontoinformasjon
|
||||||
|
driveUsage: Brukt diskplass
|
||||||
|
noCrawle: Stopp robot-indeksering
|
||||||
|
noCrawleDescription: Be søkemotorer om å ikke indeksere din profil, poster, Sider
|
||||||
|
etc.
|
||||||
|
narrow: Smal
|
||||||
|
reloadToApplySetting: Denne innstillingen aktiveres ikke før du laster siden på nytt.
|
||||||
|
Vil du gjøre det nå?
|
||||||
|
showTitlebar: Vis tittellinje
|
||||||
|
nUsers: '{n} brukere'
|
||||||
|
myTheme: Mitt tema
|
||||||
|
backgroundColor: Bakgrunnsfarge
|
||||||
|
advanced: Avansert
|
||||||
|
updatedAt: Oppdatert
|
||||||
|
editCode: Rediger kode
|
||||||
|
addDescription: Legg til beskrivelse
|
||||||
|
userPagePinTip: Du kan vise poster her ved å klikke "Fest til profil" fra menyen til
|
||||||
|
en post.
|
||||||
|
unknown: Ukjent
|
||||||
|
onlineStatus: Påkoblet status
|
||||||
|
online: Pålogget
|
||||||
|
offline: Ikke pålogget
|
||||||
|
instanceBlocking: Innstillinger for føderering
|
||||||
|
accounts: Kontoer
|
||||||
|
noBotProtectionWarning: Bot-beskyttelse er ikke konfigurert.
|
||||||
|
configure: Konfigurer
|
||||||
|
postToGallery: Lag ny galleripost
|
||||||
|
recentPosts: Nylige sider
|
||||||
|
popularPosts: Populære sider
|
||||||
|
shareWithNote: Del med post
|
||||||
|
expiration: Frist
|
||||||
|
middle: Medium
|
||||||
|
sent: Sendt
|
||||||
|
makeReactionsPublic: La reaksjonshistorikken være offentlig
|
||||||
|
classic: Sentrert
|
||||||
|
muteThread: Stum en tråd
|
||||||
|
ffVisibilityDescription: Lar deg konfigurere hvem som kan se hvem du følger og hvem
|
||||||
|
som følger deg.
|
||||||
|
continueThread: Fortsett tråd
|
||||||
|
deleteAccountConfirm: Dette vil slette kontoen, og det går ikke å omgjøre etterpå.
|
||||||
|
Fortsette?
|
||||||
|
hide: Skjul
|
||||||
|
ffVisibility: Synlighet av følgere og folk du følger
|
||||||
|
leaveGroup: Forlat gruppe
|
||||||
|
leaveGroupConfirm: Er du sikker på at du vil forlate "{name}"?
|
||||||
|
overridedDeviceKind: Enhetstype
|
||||||
|
smartphone: Smarttelefon
|
||||||
|
tablet: Nettbrett
|
||||||
|
auto: Automatisk
|
||||||
|
image: Bilde
|
||||||
|
video: Video
|
||||||
|
driveCapOverrideLabel: Endre brukerens lagringskapasitet
|
||||||
|
isSystemAccount: Denne kontoen er opprettet og kontrollert av systemet. Ikke moderer,
|
||||||
|
rediger, slett eller på annen måte endre noe ved denne kontoen. Tjeneren kan slutte
|
||||||
|
å virke som den skal.
|
||||||
|
document: Dokumentasjon
|
||||||
|
statusbar: Statuslinje
|
||||||
|
pleaseSelect: Velg en innstilling
|
||||||
|
reverse: Reverser
|
||||||
|
slow: Sakte
|
||||||
|
moveFromLabel: 'Kontoen du flytter fra:'
|
||||||
|
silencedWarning: Denne siden vises fordi disse brukerne er fra tjenere administratoren
|
||||||
|
din har stummet, så de kan potensielt inneholde spam.
|
||||||
|
ads: Samfunnsbanner
|
||||||
|
_forgotPassword:
|
||||||
|
contactAdmin: Denne tjeneren støtter ikke bruk av e-post-adresser for gjenoppretting
|
||||||
|
av passord. Kontakt administratoren for tjeneren.
|
||||||
|
enterEmail: Skriv inn e-post-adressen du brukte da du registrerte kontoen. Du vil
|
||||||
|
motta en e-post med en lenke som lar deg endre passordet.
|
||||||
|
ifNoEmail: Dersom du ikke oppga en e-post-adresse da du registrerte kontoen, kontakt
|
||||||
|
administrator i stedet.
|
||||||
|
breakFollow: Slett følger
|
||||||
|
unmuteThread: Fjern stumming av tråden
|
||||||
|
incorrectPassword: Feil passord.
|
||||||
|
logoImageUrl: URL til logo-bilde
|
||||||
|
apps: Apper
|
||||||
|
audio: Lyd
|
||||||
|
moveToLabel: 'Kontoen du flytter til:'
|
||||||
|
moveFrom: Flytt fra en annen konto til denne kontoen
|
||||||
|
migrationConfirm: "Er du helt sikker på at du ønsker å flytte kontoen din til {account}?
|
||||||
|
Når du har gjort dette kan du ikke omgjøre det, og du vil ikke kunne bruke kontoen
|
||||||
|
normalt etterpå.\nPass på at du setter den kontoen du er innlogget på her som kontoen
|
||||||
|
du flytter fra."
|
||||||
|
jumpToSpecifiedDate: Hopp til en gitt dato
|
||||||
|
showingPastTimeline: Du ser nå en gammel tidslinje
|
||||||
|
noMaintainerInformationWarning: Eierinformasjon er ikke konfigueret.
|
||||||
|
notSpecifiedMentionWarning: Denne posten inneholder nevnelser av brukere som ikke
|
||||||
|
er inkludert som mottakere
|
||||||
|
saveConfirm: Lagre endringer?
|
||||||
|
clear: Tøm
|
||||||
|
switchAccount: Bytt konto
|
||||||
|
enabled: Påslått
|
||||||
|
disabled: Avslått
|
||||||
|
user: Bruker
|
||||||
|
administration: Konfigurasjon
|
||||||
|
invalidValue: Ugyldig verdi.
|
||||||
|
youAreRunningUpToDateClient: Du bruker nyeste versjon av klienten.
|
||||||
|
noteId: Post-id
|
||||||
|
noGraze: Slå av "Graze for Mastodon"-utdivdelsen i nettleseren. Den vil forstyrre
|
||||||
|
Firefish.
|
||||||
|
isModerator: Moderator
|
||||||
|
isAdmin: Administrator
|
||||||
|
objectStorageS3ForcePathStyle: Bruk sti-baserte URL-er til endepunktene
|
||||||
|
objectStorageS3ForcePathStyleDesc: Skru på dette for å lage endpunkts-URL-er i formatet
|
||||||
|
's3.amazonaws.com/<bøtte>/' i stedet for '<bøtte>.s3.amazonaws.com'.
|
||||||
|
output: Utputt
|
||||||
|
forwardReport: Videresend rapport til ekstern tjener
|
||||||
|
forwardReportIsAnonymous: I stedet for din konto vil en anonym systemkonto bli vist
|
||||||
|
som rapportør på den eksterne tjeneren.
|
||||||
|
optional: Valgfritt
|
||||||
|
manageAccessTokens: Styr adgangstegn
|
||||||
|
experimentalFeatures: Eksperimentelle funksjoner
|
||||||
|
developer: Utvikler
|
||||||
|
duplicate: Dupliser
|
||||||
|
left: Venstre
|
||||||
|
makeExplorableDescription: Dersom du slår av denne vil kontoen din ikke dukke opp
|
||||||
|
under "Utforsk".
|
||||||
|
apply: Bruk
|
||||||
|
emailNotification: Epostvarsler
|
||||||
|
useReactionPickerForContextMenu: Åpne reaksjonsvelger med høyreklikk
|
||||||
|
typingUsers: '{users} skriver'
|
||||||
|
markAllAsRead: Marker alle som lest
|
||||||
|
goBack: Tilbake
|
||||||
|
info: Om
|
||||||
|
userInfo: Brukerinformasjon
|
||||||
|
hideOnlineStatusDescription: Å skjule hvorvidt du er pålogget vil redusere enkelheten
|
||||||
|
av enkelte funksjoner slik som søk.
|
||||||
|
privateModeInfo: Bare hvitelistede tjenere kan federere med din tjener om du slår
|
||||||
|
på denne. Alle poster vil bli skjult for andre.
|
||||||
|
received: Mottatt
|
||||||
|
searchResult: Søkeresultater
|
||||||
|
hashtags: Emneknagger
|
||||||
|
keepCw: Behold innholdsadvarsler
|
||||||
|
misskeyUpdated: Firefish er oppdatert!
|
||||||
|
whatIsNew: Vis endringer
|
||||||
|
translate: Oversett
|
||||||
|
translatedFrom: Oversatt fra {x}
|
||||||
|
itsOn: Påslått
|
||||||
|
itsOff: Avslått
|
||||||
|
emailRequiredForSignup: Krev e-post-adresse for registrering
|
||||||
|
unread: Ulest
|
||||||
|
controlPanel: Kontrollpanel
|
||||||
|
manageAccounts: Styr kontoer
|
||||||
|
mutePeriod: Periode for stumming
|
||||||
|
instanceDefaultLightTheme: Standard lyst tema på tjeneren
|
||||||
|
reflectMayTakeTime: Det kan ta litt tid før endringen inntrer.
|
||||||
|
failedToFetchAccountInformation: Klarte ikke å hente kontoinformasjon
|
||||||
|
cropImageAsk: Ønsker du å beskjære dette bildet?
|
||||||
|
recommendedInstances: Anbefalte tjenere
|
||||||
|
moveAccountDescription: Denne prosessen er irreversibel! Vær sikker på at du har satt
|
||||||
|
opp et alias for denne kontoen på den nye kontoen før du fortsetter. Skriv inn navnet
|
||||||
|
på kontoen på formen @person@server.com
|
||||||
|
moveFromDescription: Dette vil sette opp et alias for din gamle kontoen slik at du
|
||||||
|
kan flytte fra den gamle kontoen til denne. Gjør dette FØR du flytter fra den gamle
|
||||||
|
kontoen. Skriv inn den gamle kontoen på formen @person@server.com
|
||||||
|
defaultReaction: Standard emoji-reaksjon for utgående og innkommende poster
|
||||||
|
indexFrom: Indekser poster fra post-id og fremover
|
||||||
|
indexNotice: Indekserer. Dette vil sannsynligvis ta litt tid, ikke restart tjeneren
|
||||||
|
før det har gått minst en time.
|
||||||
|
indexFromDescription: La stå tom for å indeksere alle poster
|
||||||
|
customKaTeXMacroDescription: 'Sett opp makroer for å skrive matematiske uttrykk enkelt.
|
||||||
|
Notasjonen følger LaTeX-kommandoer og er skrevet som \newcommand{\ navn}{uttrykk}
|
||||||
|
eller \newcommand{\navn}{antall argumenter}{uttrykk}. For eksempel vil \newcommand{\add}{2}{#1
|
||||||
|
+ #2} vil ekspandere \add{3}{foo} til 3 + foo. Klammeparentesene rundt makroen kan
|
||||||
|
også endres til parenteser eller hakeparenteser. Dette påvirker hvilken parentestype
|
||||||
|
du bruker for argumenter. En og bare en makro kan defineres pr linje, og du kan
|
||||||
|
ikke ha linjeskift inni definisjonen. Linjer som ikke inneholder gyldige makroer
|
||||||
|
vil bli ignorert. Bare enkle streng-erstatnings-makroer er støttet; avansert syntaks
|
||||||
|
f.eks. med flykontroll er ikke tillatt.'
|
||||||
|
signupsDisabled: Registreringer av nye konti på denne tjeneren er slått av, men du
|
||||||
|
kan alltids registrere deg på en annen tjener! Hvis du har en invitasjonskode for
|
||||||
|
denne tjeneren, skriv den inn under.
|
||||||
|
findOtherInstance: Finn en annen tjener
|
||||||
|
preventAiLearningDescription: Ber tredjeparts AI-språkmodeller om å ikke bruke innhold
|
||||||
|
du laster opp, sliks om poster og bilder.
|
||||||
|
enableCustomKaTeXMacro: Slå på egne KaTeX-makroer
|
||||||
|
showPopup: Varsle brukere med oppsprettsvindu
|
||||||
|
|
|
@ -304,7 +304,7 @@ emptyDrive: "Диск пуст"
|
||||||
emptyFolder: "Папка пуста"
|
emptyFolder: "Папка пуста"
|
||||||
unableToDelete: "Удаление невозможно"
|
unableToDelete: "Удаление невозможно"
|
||||||
inputNewFileName: "Введите имя нового файла"
|
inputNewFileName: "Введите имя нового файла"
|
||||||
inputNewDescription: "Введите новую подпись"
|
inputNewDescription: "Введите новое описание"
|
||||||
inputNewFolderName: "Пожалуйста, введите новое имя папки"
|
inputNewFolderName: "Пожалуйста, введите новое имя папки"
|
||||||
circularReferenceFolder: "Вы пытаетесь переместить папку внутрь себя."
|
circularReferenceFolder: "Вы пытаетесь переместить папку внутрь себя."
|
||||||
hasChildFilesOrFolders: "Эта папка не пуста и не может быть удалена."
|
hasChildFilesOrFolders: "Эта папка не пуста и не может быть удалена."
|
||||||
|
@ -513,7 +513,7 @@ objectStorageBaseUrlDesc: "URL используемый для примера.
|
||||||
CDN или прокси, если вы используете любой из них.\nДля S3 используйте 'https://<bucket>.s3.amazonaws.com',
|
CDN или прокси, если вы используете любой из них.\nДля S3 используйте 'https://<bucket>.s3.amazonaws.com',
|
||||||
а для GCS и подобных сервисов используйте 'https://storage.googleapis.com/<bucket>',
|
а для GCS и подобных сервисов используйте 'https://storage.googleapis.com/<bucket>',
|
||||||
и т.п."
|
и т.п."
|
||||||
objectStorageBucket: "Bucket"
|
objectStorageBucket: "Хранилище (Bucket)"
|
||||||
objectStorageBucketDesc: "Укажите название контейнера (Bucket) который используется
|
objectStorageBucketDesc: "Укажите название контейнера (Bucket) который используется
|
||||||
на выбранном сервисе."
|
на выбранном сервисе."
|
||||||
objectStoragePrefix: "Префикс"
|
objectStoragePrefix: "Префикс"
|
||||||
|
@ -596,8 +596,8 @@ disablePlayer: "Выключить проигрыватель"
|
||||||
expandTweet: "Развернуть твит"
|
expandTweet: "Развернуть твит"
|
||||||
themeEditor: "Редактор темы оформления"
|
themeEditor: "Редактор темы оформления"
|
||||||
description: "Описание"
|
description: "Описание"
|
||||||
describeFile: "Добавить подпись"
|
describeFile: "Добавить описание"
|
||||||
enterFileDescription: "Введите подпись"
|
enterFileDescription: "Введите описание"
|
||||||
author: "Автор"
|
author: "Автор"
|
||||||
leaveConfirm: "Вы не сохранили изменения. Хотите выйти и потерять их?"
|
leaveConfirm: "Вы не сохранили изменения. Хотите выйти и потерять их?"
|
||||||
manage: "Управление"
|
manage: "Управление"
|
||||||
|
@ -826,7 +826,7 @@ gallery: "Галерея"
|
||||||
recentPosts: "Недавние публикации"
|
recentPosts: "Недавние публикации"
|
||||||
popularPosts: "Популярные публикации"
|
popularPosts: "Популярные публикации"
|
||||||
shareWithNote: "Поделиться постом"
|
shareWithNote: "Поделиться постом"
|
||||||
ads: "Реклама"
|
ads: "Баннеры сообщества"
|
||||||
expiration: "Опрос длится"
|
expiration: "Опрос длится"
|
||||||
memo: "Памятка"
|
memo: "Памятка"
|
||||||
priority: "Приоритет"
|
priority: "Приоритет"
|
||||||
|
@ -1001,6 +1001,7 @@ _aboutFirefish:
|
||||||
pleaseDonateToHost: Также не забудьте поддержать ваш домашний сервер {host}, чтобы
|
pleaseDonateToHost: Также не забудьте поддержать ваш домашний сервер {host}, чтобы
|
||||||
помочь с его операционными расходами.
|
помочь с его операционными расходами.
|
||||||
donateHost: Пожертвовать на {host}
|
donateHost: Пожертвовать на {host}
|
||||||
|
misskeyContributors: Контрибьюторы Misskey
|
||||||
_nsfw:
|
_nsfw:
|
||||||
respect: "Скрывать содержимое не для всех"
|
respect: "Скрывать содержимое не для всех"
|
||||||
ignore: "Показывать содержимое не для всех"
|
ignore: "Показывать содержимое не для всех"
|
||||||
|
@ -1024,7 +1025,7 @@ _mfm:
|
||||||
boldDescription: "Выделяет текст, делая буквы жирнее."
|
boldDescription: "Выделяет текст, делая буквы жирнее."
|
||||||
small: "Мелкий шрифт"
|
small: "Мелкий шрифт"
|
||||||
smallDescription: "Делает текст маленьким и незаметным."
|
smallDescription: "Делает текст маленьким и незаметным."
|
||||||
center: "Выровнять элементы по центру"
|
center: "По центру"
|
||||||
centerDescription: "Так можно выровнять что-то по центру."
|
centerDescription: "Так можно выровнять что-то по центру."
|
||||||
inlineCode: "Программа (в тексте)"
|
inlineCode: "Программа (в тексте)"
|
||||||
inlineCodeDescription: "Подсвечивает фрагмент программы внутри сплошного текста."
|
inlineCodeDescription: "Подсвечивает фрагмент программы внутри сплошного текста."
|
||||||
|
@ -1267,8 +1268,8 @@ _tutorial:
|
||||||
step6_1: "Итак, что это за место?"
|
step6_1: "Итак, что это за место?"
|
||||||
step6_2: "Ну, вы не просто присоединились к Firefish. Вы вошли в Fediverse, взаимосвязанную
|
step6_2: "Ну, вы не просто присоединились к Firefish. Вы вошли в Fediverse, взаимосвязанную
|
||||||
сеть из тысяч серверов."
|
сеть из тысяч серверов."
|
||||||
step6_3: "Каждый сервер работает по-своему, и не на всех серверах работает Firefish.
|
step6_3: "Каждый сервер работает по-своему, и не все сервера работают на базе Firefish.
|
||||||
Но этот работает! Это немного сложно, но вы быстро разберетесь."
|
Но этот работает! Это сложновато, но вы быстро разберетесь."
|
||||||
step6_4: "Теперь идите, изучайте и развлекайтесь!"
|
step6_4: "Теперь идите, изучайте и развлекайтесь!"
|
||||||
_2fa:
|
_2fa:
|
||||||
alreadyRegistered: "Двухфакторная аутентификация уже настроена."
|
alreadyRegistered: "Двухфакторная аутентификация уже настроена."
|
||||||
|
@ -1475,7 +1476,7 @@ _charts:
|
||||||
remoteNotesIncDec: "Изменения числа постов с других сайтов"
|
remoteNotesIncDec: "Изменения числа постов с других сайтов"
|
||||||
notesTotal: "Общее количество постов"
|
notesTotal: "Общее количество постов"
|
||||||
filesIncDec: "Изменения числа файлов"
|
filesIncDec: "Изменения числа файлов"
|
||||||
filesTotal: "Суммарное количество файлов"
|
filesTotal: "Общее количество файлов"
|
||||||
storageUsageIncDec: "Изменения заполнения хранилища"
|
storageUsageIncDec: "Изменения заполнения хранилища"
|
||||||
storageUsageTotal: "Суммарное заполнение хранилища"
|
storageUsageTotal: "Суммарное заполнение хранилища"
|
||||||
_instanceCharts:
|
_instanceCharts:
|
||||||
|
@ -1903,12 +1904,12 @@ customMOTDDescription: Пользовательские сообщения дл
|
||||||
загружает / перезагружает страницу.
|
загружает / перезагружает страницу.
|
||||||
recommendedInstancesDescription: Рекомендуемые инстансы, разделенные разрывами строк,
|
recommendedInstancesDescription: Рекомендуемые инстансы, разделенные разрывами строк,
|
||||||
должны отображаться на рекомендуемой ленте.
|
должны отображаться на рекомендуемой ленте.
|
||||||
caption: Автоматическая подпись
|
caption: Автоматическое описание
|
||||||
splash: Заставка
|
splash: Заставка
|
||||||
updateAvailable: Возможно, доступно обновление!
|
updateAvailable: Возможно, доступно обновление!
|
||||||
move: Переместить
|
move: Переместить
|
||||||
swipeOnDesktop: Разрешить свайпы в мобильном стиле на десктопе
|
swipeOnDesktop: Разрешить свайпы в мобильном стиле на десктопе
|
||||||
showAds: Показывать рекламу
|
showAds: Показывать баннеры сообщества
|
||||||
noEmailServerWarning: Почтовый сервер не настроен.
|
noEmailServerWarning: Почтовый сервер не настроен.
|
||||||
type: Тип
|
type: Тип
|
||||||
numberOfPageCacheDescription: Увеличение этого числа повысит удобство для пользователей,
|
numberOfPageCacheDescription: Увеличение этого числа повысит удобство для пользователей,
|
||||||
|
@ -2137,3 +2138,19 @@ donationLink: Ссылка на страницу для взносов
|
||||||
isLocked: Этот аккаунт имеет одобрение запросов на подписку
|
isLocked: Этот аккаунт имеет одобрение запросов на подписку
|
||||||
removeRecipient: Удалить получателя
|
removeRecipient: Удалить получателя
|
||||||
removeMember: Удалить участника
|
removeMember: Удалить участника
|
||||||
|
confirm: Подтвердить
|
||||||
|
importZip: Импортировать ZIP
|
||||||
|
exportZip: Экспортировать ZIP
|
||||||
|
emojiPackCreator: Генератор паков эмодзи
|
||||||
|
objectStorageS3ForcePathStyle: Использовать путь вместо домена в URL
|
||||||
|
objectStorageS3ForcePathStyleDesc: Включите, если хотите, чтобы URL был в формате
|
||||||
|
's3.amazonaws.com/<bucket>/' вместо '<bucket>.s3.amazonaws.com'.
|
||||||
|
origin: Источник
|
||||||
|
deletePasskeys: Удалить passkey
|
||||||
|
delete2faConfirm: Двухфакторная аутентификация на этом аккаунте будет безвозвратно
|
||||||
|
удалена. Продолжить?
|
||||||
|
delete2fa: Отключить двухфакторную аутентификацию
|
||||||
|
deletePasskeysConfirm: Это действие безвозвратно удалит все passkey и ключи безопасности
|
||||||
|
на этом аккаунте. Продолжить?
|
||||||
|
inputNotMatch: Введённые данные не совпадают
|
||||||
|
addRe: Добавить "re:" в начале комментария в ответ на запись с предупреждением о содержимом
|
||||||
|
|
|
@ -305,7 +305,7 @@ emptyDrive: "Диск порожній"
|
||||||
emptyFolder: "Тека порожня"
|
emptyFolder: "Тека порожня"
|
||||||
unableToDelete: "Видалення неможливе"
|
unableToDelete: "Видалення неможливе"
|
||||||
inputNewFileName: "Введіть ім'я нового файлу"
|
inputNewFileName: "Введіть ім'я нового файлу"
|
||||||
inputNewDescription: "Введіть новий заголовок"
|
inputNewDescription: "Введіть новий опис"
|
||||||
inputNewFolderName: "Введіть ім'я нової теки"
|
inputNewFolderName: "Введіть ім'я нової теки"
|
||||||
circularReferenceFolder: "Ви намагаєтесь перемістити папку в її підпапку."
|
circularReferenceFolder: "Ви намагаєтесь перемістити папку в її підпапку."
|
||||||
hasChildFilesOrFolders: "Ця тека не порожня і не може бути видалена."
|
hasChildFilesOrFolders: "Ця тека не порожня і не може бути видалена."
|
||||||
|
@ -591,8 +591,8 @@ disablePlayer: "Закрити відеоплеєр"
|
||||||
expandTweet: "Розгорнути твіт"
|
expandTweet: "Розгорнути твіт"
|
||||||
themeEditor: "Редактор тем"
|
themeEditor: "Редактор тем"
|
||||||
description: "Опис"
|
description: "Опис"
|
||||||
describeFile: "Додати підпис"
|
describeFile: "Додати опис"
|
||||||
enterFileDescription: "Введіть підпис"
|
enterFileDescription: "Введіть опис"
|
||||||
author: "Автор"
|
author: "Автор"
|
||||||
leaveConfirm: "Зміни не збережені. Ви дійсно хочете скасувати зміни?"
|
leaveConfirm: "Зміни не збережені. Ви дійсно хочете скасувати зміни?"
|
||||||
manage: "Управління"
|
manage: "Управління"
|
||||||
|
@ -1985,7 +1985,7 @@ showUpdates: Показувати спливаюче вікно при онов
|
||||||
updateAvailable: Можливо, є доступне оновлення!
|
updateAvailable: Можливо, є доступне оновлення!
|
||||||
recommendedInstancesDescription: Рекомендовані сервери відокремлюються переведенням
|
recommendedInstancesDescription: Рекомендовані сервери відокремлюються переведенням
|
||||||
рядка, щоб з'явитися на стрічці рекомендацій.
|
рядка, щоб з'явитися на стрічці рекомендацій.
|
||||||
caption: Автоматичний підпис
|
caption: Автоматичний опис
|
||||||
showAdminUpdates: Вказати, що доступна нова версія Firefish (тільки для адміністратора)
|
showAdminUpdates: Вказати, що доступна нова версія Firefish (тільки для адміністратора)
|
||||||
defaultReaction: Емодзі реакція за замовчуванням для вихідних і вхідних записів
|
defaultReaction: Емодзі реакція за замовчуванням для вихідних і вхідних записів
|
||||||
license: Ліцензія
|
license: Ліцензія
|
||||||
|
@ -2151,3 +2151,7 @@ deletePasskeysConfirm: Це видалить усі ключ-паролі і к
|
||||||
записі без можливости відмінити цю дію. Продовжити?
|
записі без можливости відмінити цю дію. Продовжити?
|
||||||
addRe: Додати "re:" на початку коментаря у відповідь на запис із попередженням про
|
addRe: Додати "re:" на початку коментаря у відповідь на запис із попередженням про
|
||||||
вміст
|
вміст
|
||||||
|
confirm: Підтвердити
|
||||||
|
importZip: Імпортувати ZIP
|
||||||
|
exportZip: Експортувати ZIP
|
||||||
|
emojiPackCreator: Генератор паків емодзі
|
||||||
|
|
|
@ -290,7 +290,7 @@ emptyDrive: "网盘中无文件"
|
||||||
emptyFolder: "此文件夹中无文件"
|
emptyFolder: "此文件夹中无文件"
|
||||||
unableToDelete: "无法删除"
|
unableToDelete: "无法删除"
|
||||||
inputNewFileName: "请输入新文件名"
|
inputNewFileName: "请输入新文件名"
|
||||||
inputNewDescription: "请输入新标题"
|
inputNewDescription: "请输入新描述"
|
||||||
inputNewFolderName: "请输入新文件夹名"
|
inputNewFolderName: "请输入新文件夹名"
|
||||||
circularReferenceFolder: "目标文件夹是您要移动的文件夹的子文件夹。"
|
circularReferenceFolder: "目标文件夹是您要移动的文件夹的子文件夹。"
|
||||||
hasChildFilesOrFolders: "此文件夹中有文件,无法删除。"
|
hasChildFilesOrFolders: "此文件夹中有文件,无法删除。"
|
||||||
|
@ -561,8 +561,8 @@ disablePlayer: "关闭播放器"
|
||||||
expandTweet: "展开帖子"
|
expandTweet: "展开帖子"
|
||||||
themeEditor: "主题编辑器"
|
themeEditor: "主题编辑器"
|
||||||
description: "描述"
|
description: "描述"
|
||||||
describeFile: "添加标题"
|
describeFile: "添加描述"
|
||||||
enterFileDescription: "输入标题"
|
enterFileDescription: "输入描述"
|
||||||
author: "作者"
|
author: "作者"
|
||||||
leaveConfirm: "存在未保存的更改。要放弃更改吗?"
|
leaveConfirm: "存在未保存的更改。要放弃更改吗?"
|
||||||
manage: "管理"
|
manage: "管理"
|
||||||
|
@ -776,7 +776,7 @@ gallery: "图库"
|
||||||
recentPosts: "最新发布"
|
recentPosts: "最新发布"
|
||||||
popularPosts: "热门投稿"
|
popularPosts: "热门投稿"
|
||||||
shareWithNote: "在帖子中分享"
|
shareWithNote: "在帖子中分享"
|
||||||
ads: "广告"
|
ads: "社区横幅"
|
||||||
expiration: "截止时间"
|
expiration: "截止时间"
|
||||||
memo: "便笺"
|
memo: "便笺"
|
||||||
priority: "优先级"
|
priority: "优先级"
|
||||||
|
@ -825,7 +825,7 @@ unmuteThread: "取消静音帖子串"
|
||||||
ffVisibility: "关注/关注者 可见性"
|
ffVisibility: "关注/关注者 可见性"
|
||||||
ffVisibilityDescription: "您可以设置谁可以看到您的关注/关注者信息。"
|
ffVisibilityDescription: "您可以设置谁可以看到您的关注/关注者信息。"
|
||||||
continueThread: "查看更多帖子"
|
continueThread: "查看更多帖子"
|
||||||
deleteAccountConfirm: "将不可逆的删除账号,是否继续?"
|
deleteAccountConfirm: "这将不可逆转地删除账号,是否继续?"
|
||||||
incorrectPassword: "密码错误。"
|
incorrectPassword: "密码错误。"
|
||||||
voteConfirm: "确定投给 “{choice}” ?"
|
voteConfirm: "确定投给 “{choice}” ?"
|
||||||
hide: "隐藏"
|
hide: "隐藏"
|
||||||
|
@ -994,6 +994,7 @@ _aboutFirefish:
|
||||||
pleaseDonateToFirefish: 请考虑赞助 Firefish 以支持其开发。
|
pleaseDonateToFirefish: 请考虑赞助 Firefish 以支持其开发。
|
||||||
pleaseDonateToHost: 也请考虑赞助您的主服务器 {host},以帮助支持其运营成本。
|
pleaseDonateToHost: 也请考虑赞助您的主服务器 {host},以帮助支持其运营成本。
|
||||||
donateHost: 赞助 {host}
|
donateHost: 赞助 {host}
|
||||||
|
misskeyContributors: Misskey 贡献者
|
||||||
_nsfw:
|
_nsfw:
|
||||||
respect: "隐藏敏感内容"
|
respect: "隐藏敏感内容"
|
||||||
ignore: "不隐藏敏感内容"
|
ignore: "不隐藏敏感内容"
|
||||||
|
@ -1857,7 +1858,7 @@ seperateRenoteQuote: 单独的转发和引用按钮
|
||||||
customSplashIcons: 自定义启动屏幕图标(urls)
|
customSplashIcons: 自定义启动屏幕图标(urls)
|
||||||
alt: 替代文字
|
alt: 替代文字
|
||||||
pushNotificationNotSupported: 您的浏览器或者服务器不支持推送通知
|
pushNotificationNotSupported: 您的浏览器或者服务器不支持推送通知
|
||||||
showAds: 显示广告
|
showAds: 显示社区横幅
|
||||||
enterSendsMessage: 按回车键发送信息(关闭则是 Ctrl + Retun 发送)
|
enterSendsMessage: 按回车键发送信息(关闭则是 Ctrl + Retun 发送)
|
||||||
recommendedInstances: 推荐服务器
|
recommendedInstances: 推荐服务器
|
||||||
updateAvailable: 可能有可用更新!
|
updateAvailable: 可能有可用更新!
|
||||||
|
@ -1876,7 +1877,7 @@ clipsDesc: 便签就像可共享的分类书签。您可以从各个帖子的菜
|
||||||
privateModeInfo: 当启用时,只有白名单上的服务器可以与您的服务器联合,所有的帖子都会对公共时间线隐藏。
|
privateModeInfo: 当启用时,只有白名单上的服务器可以与您的服务器联合,所有的帖子都会对公共时间线隐藏。
|
||||||
allowedInstancesDescription: 要列入联合白名单的服务器的主机名,一行一个(仅适用于私密模式)。
|
allowedInstancesDescription: 要列入联合白名单的服务器的主机名,一行一个(仅适用于私密模式)。
|
||||||
breakFollowConfirm: 确定要移除关注者吗?
|
breakFollowConfirm: 确定要移除关注者吗?
|
||||||
caption: 自动显示说明文字
|
caption: 自动显示描述文字
|
||||||
newer: 更新的
|
newer: 更新的
|
||||||
older: 更旧的
|
older: 更旧的
|
||||||
noInstances: 没有服务器
|
noInstances: 没有服务器
|
||||||
|
@ -1967,3 +1968,16 @@ removeQuote: 移除引用
|
||||||
removeRecipient: 移除接收者
|
removeRecipient: 移除接收者
|
||||||
removeMember: 移除成员
|
removeMember: 移除成员
|
||||||
origin: 起源
|
origin: 起源
|
||||||
|
confirm: 确认
|
||||||
|
importZip: 导入 ZIP
|
||||||
|
exportZip: 导出 ZIP
|
||||||
|
emojiPackCreator: 表情包创建工具
|
||||||
|
objectStorageS3ForcePathStyleDesc: 打开此选项可构建格式为 's3.amazonaws.com/<bucket>/' 而非 '<bucket>.s3.amazonaws.com'
|
||||||
|
的端点 URL。
|
||||||
|
objectStorageS3ForcePathStyle: 使用基于路径的端点 URL
|
||||||
|
delete2fa: 禁用 2FA
|
||||||
|
deletePasskeysConfirm: 这将不可逆转地删除此账号上的所有通行密钥和安全密钥。是否继续?
|
||||||
|
inputNotMatch: 输入不匹配
|
||||||
|
deletePasskeys: 删除通行密钥
|
||||||
|
delete2faConfirm: 这将不可逆转地删除此账户上的 2FA。是否继续?
|
||||||
|
addRe: 在回复有内容警告的帖子时,在评论开头添加 "re:"
|
||||||
|
|
1
neko/UPSTREAM_COMMIT_ID
Normal file
1
neko/UPSTREAM_COMMIT_ID
Normal file
|
@ -0,0 +1 @@
|
||||||
|
f309d17667d827f44e9d914f43ddc7af2aef8268
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "firefish",
|
"name": "firefish",
|
||||||
"version": "1.0.5-dev5",
|
"version": "1.0.5-dev6",
|
||||||
"codename": "aqua",
|
"codename": "aqua",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
export class IncreaseHostCharLimit1692374635734 {
|
||||||
|
name = "IncreaseHostCharLimit1692374635734";
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "drive_file" ALTER COLUMN "userHost" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user" ALTER COLUMN "host" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" ALTER COLUMN "userHost" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_publickey" ALTER COLUMN "keyId" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "emoji" ALTER COLUMN "host" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "note" ALTER COLUMN "userHost" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "note" ALTER COLUMN "replyUserHost" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "note" ALTER COLUMN "renoteUserHost" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "instance" ALTER COLUMN "host" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "instance" ALTER COLUMN "iconUrl" TYPE character varying(4096)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "instance" ALTER COLUMN "faviconUrl" TYPE character varying(4096)`,
|
||||||
|
);
|
||||||
|
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "poll" ALTER COLUMN "userHost" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "abuse_user_report" ALTER COLUMN "targetUserHost" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "abuse_user_report" ALTER COLUMN "reporterHost" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "following" ALTER COLUMN "followeeHost" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "following" ALTER COLUMN "followerHost" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "follow_request" ALTER COLUMN "followeeHost" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "follow_request" ALTER COLUMN "followerHost" TYPE character varying(512)`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "drive_file" ALTER COLUMN "userHost" TYPE character varying(128)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user" ALTER COLUMN "host" TYPE character varying(128)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" ALTER COLUMN "userHost" TYPE character varying(128)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_publickey" ALTER COLUMN "keyId" TYPE character varying(256)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "emoji" ALTER COLUMN "host" TYPE character varying(128)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "note" ALTER COLUMN "userHost" TYPE character varying(128)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "note" ALTER COLUMN "replyUserHost" TYPE character varying(128)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "note" ALTER COLUMN "renoteUserHost" TYPE character varying(128)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "instance" ALTER COLUMN "host" TYPE character varying(128)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "instance" ALTER COLUMN "iconUrl" TYPE character varying(256)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "instance" ALTER COLUMN "faviconUrl" TYPE character varying(256)`,
|
||||||
|
);
|
||||||
|
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "poll" ALTER COLUMN "userHost" TYPE character varying(128)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "abuse_user_report" ALTER COLUMN "targetUserHost" TYPE character varying(128)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "abuse_user_report" ALTER COLUMN "reporterHost" TYPE character varying(128)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "following" ALTER COLUMN "followeeHost" TYPE character varying(128)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "following" ALTER COLUMN "followerHost" TYPE character varying(128)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "follow_request" ALTER COLUMN "followeeHost" TYPE character varying(128)`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "follow_request" ALTER COLUMN "followerHost" TYPE character varying(128)`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -78,6 +78,7 @@ export type Source = {
|
||||||
fingerprint?: string;
|
fingerprint?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
outgoingAddress?: string;
|
||||||
outgoingAddressFamily?: "ipv4" | "ipv6" | "dual";
|
outgoingAddressFamily?: "ipv4" | "ipv6" | "dual";
|
||||||
|
|
||||||
deliverJobConcurrency?: number;
|
deliverJobConcurrency?: number;
|
||||||
|
|
|
@ -92,7 +92,7 @@ export async function downloadUrl(url: string, path: string): Promise<void> {
|
||||||
logger.succ(`Download finished: ${chalk.cyan(url)}`);
|
logger.succ(`Download finished: ${chalk.cyan(url)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPrivateIp(ip: string): boolean {
|
export function isPrivateIp(ip: string): boolean {
|
||||||
for (const net of config.allowedPrivateNetworks || []) {
|
for (const net of config.allowedPrivateNetworks || []) {
|
||||||
const cidr = new IPCIDR(net);
|
const cidr = new IPCIDR(net);
|
||||||
if (cidr.contains(ip)) {
|
if (cidr.contains(ip)) {
|
||||||
|
|
|
@ -99,6 +99,7 @@ const _http = new http.Agent({
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
keepAliveMsecs: 30 * 1000,
|
keepAliveMsecs: 30 * 1000,
|
||||||
lookup: cache.lookup,
|
lookup: cache.lookup,
|
||||||
|
localAddress: config.outgoingAddress,
|
||||||
} as http.AgentOptions);
|
} as http.AgentOptions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -108,6 +109,7 @@ const _https = new https.Agent({
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
keepAliveMsecs: 30 * 1000,
|
keepAliveMsecs: 30 * 1000,
|
||||||
lookup: cache.lookup,
|
lookup: cache.lookup,
|
||||||
|
localAddress: config.outgoingAddress,
|
||||||
} as https.AgentOptions);
|
} as https.AgentOptions);
|
||||||
|
|
||||||
const maxSockets = Math.max(256, config.deliverJobConcurrency || 128);
|
const maxSockets = Math.max(256, config.deliverJobConcurrency || 128);
|
||||||
|
@ -123,6 +125,7 @@ export const httpAgent = config.proxy
|
||||||
maxFreeSockets: 256,
|
maxFreeSockets: 256,
|
||||||
scheduling: "lifo",
|
scheduling: "lifo",
|
||||||
proxy: config.proxy,
|
proxy: config.proxy,
|
||||||
|
localAddress: config.outgoingAddress,
|
||||||
})
|
})
|
||||||
: _http;
|
: _http;
|
||||||
|
|
||||||
|
@ -137,6 +140,7 @@ export const httpsAgent = config.proxy
|
||||||
maxFreeSockets: 256,
|
maxFreeSockets: 256,
|
||||||
scheduling: "lifo",
|
scheduling: "lifo",
|
||||||
proxy: config.proxy,
|
proxy: config.proxy,
|
||||||
|
localAddress: config.outgoingAddress,
|
||||||
})
|
})
|
||||||
: _https;
|
: _https;
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ export class AbuseUserReport {
|
||||||
//#region Denormalized fields
|
//#region Denormalized fields
|
||||||
@Index()
|
@Index()
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 128,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
comment: "[Denormalized]",
|
comment: "[Denormalized]",
|
||||||
})
|
})
|
||||||
|
@ -79,7 +79,7 @@ export class AbuseUserReport {
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 128,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
comment: "[Denormalized]",
|
comment: "[Denormalized]",
|
||||||
})
|
})
|
||||||
|
|
|
@ -39,7 +39,7 @@ export class DriveFile {
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 128,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
comment: "The host of owner. It will be null if the user in local.",
|
comment: "The host of owner. It will be null if the user in local.",
|
||||||
})
|
})
|
||||||
|
|
|
@ -20,7 +20,7 @@ export class Emoji {
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 128,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
public host: string | null;
|
public host: string | null;
|
||||||
|
|
|
@ -50,7 +50,7 @@ export class Following {
|
||||||
//#region Denormalized fields
|
//#region Denormalized fields
|
||||||
@Index()
|
@Index()
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 128,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
comment: "[Denormalized]",
|
comment: "[Denormalized]",
|
||||||
})
|
})
|
||||||
|
@ -72,7 +72,7 @@ export class Following {
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 128,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
comment: "[Denormalized]",
|
comment: "[Denormalized]",
|
||||||
})
|
})
|
||||||
|
|
|
@ -20,7 +20,7 @@ export class Instance {
|
||||||
*/
|
*/
|
||||||
@Index({ unique: true })
|
@Index({ unique: true })
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 128,
|
length: 512,
|
||||||
comment: "The host of the Instance.",
|
comment: "The host of the Instance.",
|
||||||
})
|
})
|
||||||
public host: string;
|
public host: string;
|
||||||
|
@ -149,13 +149,13 @@ export class Instance {
|
||||||
public maintainerEmail: string | null;
|
public maintainerEmail: string | null;
|
||||||
|
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 256,
|
length: 4096,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
public iconUrl: string | null;
|
public iconUrl: string | null;
|
||||||
|
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 256,
|
length: 4096,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
public faviconUrl: string | null;
|
public faviconUrl: string | null;
|
||||||
|
|
|
@ -217,7 +217,7 @@ export class Note {
|
||||||
//#region Denormalized fields
|
//#region Denormalized fields
|
||||||
@Index()
|
@Index()
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 128,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
comment: "[Denormalized]",
|
comment: "[Denormalized]",
|
||||||
})
|
})
|
||||||
|
@ -231,7 +231,7 @@ export class Note {
|
||||||
public replyUserId: User["id"] | null;
|
public replyUserId: User["id"] | null;
|
||||||
|
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 128,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
comment: "[Denormalized]",
|
comment: "[Denormalized]",
|
||||||
})
|
})
|
||||||
|
@ -245,7 +245,7 @@ export class Note {
|
||||||
public renoteUserId: User["id"] | null;
|
public renoteUserId: User["id"] | null;
|
||||||
|
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 128,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
comment: "[Denormalized]",
|
comment: "[Denormalized]",
|
||||||
})
|
})
|
||||||
|
|
|
@ -58,7 +58,7 @@ export class Poll {
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 128,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
comment: "[Denormalized]",
|
comment: "[Denormalized]",
|
||||||
})
|
})
|
||||||
|
|
|
@ -242,7 +242,7 @@ export class UserProfile {
|
||||||
//#region Denormalized fields
|
//#region Denormalized fields
|
||||||
@Index()
|
@Index()
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 128,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
comment: "[Denormalized]",
|
comment: "[Denormalized]",
|
||||||
})
|
})
|
||||||
|
|
|
@ -22,7 +22,7 @@ export class UserPublickey {
|
||||||
|
|
||||||
@Index({ unique: true })
|
@Index({ unique: true })
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 256,
|
length: 512,
|
||||||
})
|
})
|
||||||
public keyId: string;
|
public keyId: string;
|
||||||
|
|
||||||
|
|
|
@ -214,7 +214,7 @@ export class User {
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column("varchar", {
|
@Column("varchar", {
|
||||||
length: 128,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
comment:
|
comment:
|
||||||
"The host of the User. It will be null if the origin of the user is local.",
|
"The host of the User. It will be null if the origin of the user is local.",
|
||||||
|
|
|
@ -122,19 +122,31 @@ export default class DeliverManager {
|
||||||
)
|
)
|
||||||
.forEach((recipe) => inboxes.add(recipe.to.inbox!));
|
.forEach((recipe) => inboxes.add(recipe.to.inbox!));
|
||||||
|
|
||||||
|
// Validate Inboxes first
|
||||||
|
const validInboxes = [];
|
||||||
|
for (const inbox of inboxes) {
|
||||||
|
try {
|
||||||
|
validInboxes.push({
|
||||||
|
inbox,
|
||||||
|
host: new URL(inbox).host,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
console.error(`Invalid Inbox ${inbox}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const instancesToSkip = await skippedInstances(
|
const instancesToSkip = await skippedInstances(
|
||||||
// get (unique) list of hosts
|
// get (unique) list of hosts
|
||||||
Array.from(
|
Array.from(new Set(validInboxes.map((valid) => valid.host))),
|
||||||
new Set(Array.from(inboxes).map((inbox) => new URL(inbox).host)),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// deliver
|
// deliver
|
||||||
for (const inbox of inboxes) {
|
for (const valid of validInboxes) {
|
||||||
// skip instances as indicated
|
// skip instances as indicated
|
||||||
if (instancesToSkip.includes(new URL(inbox).host)) continue;
|
if (instancesToSkip.includes(valid.host)) continue;
|
||||||
|
|
||||||
deliver(this.actor, this.activity, inbox);
|
deliver(this.actor, this.activity, valid.inbox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ import remove from "./remove/index.js";
|
||||||
import block from "./block/index.js";
|
import block from "./block/index.js";
|
||||||
import flag from "./flag/index.js";
|
import flag from "./flag/index.js";
|
||||||
import move from "./move/index.js";
|
import move from "./move/index.js";
|
||||||
import type { IObject } from "../type.js";
|
import type { IObject, IActivity } from "../type.js";
|
||||||
import { extractDbHost } from "@/misc/convert-host.js";
|
import { extractDbHost } from "@/misc/convert-host.js";
|
||||||
import { shouldBlockInstance } from "@/misc/should-block-instance.js";
|
import { shouldBlockInstance } from "@/misc/should-block-instance.js";
|
||||||
|
|
||||||
|
@ -106,6 +106,8 @@ async function performOneActivity(
|
||||||
} else if (isMove(activity)) {
|
} else if (isMove(activity)) {
|
||||||
await move(actor, activity);
|
await move(actor, activity);
|
||||||
} else {
|
} else {
|
||||||
apLogger.warn(`unrecognized activity type: ${(activity as any).type}`);
|
apLogger.warn(
|
||||||
|
`Unrecognized activity type: ${(activity as IActivity).type}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,13 +68,13 @@ export class LdSignature {
|
||||||
...options,
|
...options,
|
||||||
"@context": "https://w3id.org/identity/v1",
|
"@context": "https://w3id.org/identity/v1",
|
||||||
};
|
};
|
||||||
delete transformedOptions["type"];
|
transformedOptions.type = undefined;
|
||||||
delete transformedOptions["id"];
|
transformedOptions.id = undefined;
|
||||||
delete transformedOptions["signatureValue"];
|
transformedOptions.signatureValue = undefined;
|
||||||
const canonizedOptions = await this.normalize(transformedOptions);
|
const canonizedOptions = await this.normalize(transformedOptions);
|
||||||
const optionsHash = this.sha256(canonizedOptions);
|
const optionsHash = this.sha256(canonizedOptions);
|
||||||
const transformedData = { ...data };
|
const transformedData = { ...data };
|
||||||
delete transformedData["signature"];
|
transformedData.signature = undefined;
|
||||||
const cannonidedData = await this.normalize(transformedData);
|
const cannonidedData = await this.normalize(transformedData);
|
||||||
if (this.debug) console.debug(`cannonidedData: ${cannonidedData}`);
|
if (this.debug) console.debug(`cannonidedData: ${cannonidedData}`);
|
||||||
const documentHash = this.sha256(cannonidedData);
|
const documentHash = this.sha256(cannonidedData);
|
||||||
|
|
|
@ -231,6 +231,21 @@ export async function createPerson(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let notesCount: number | undefined;
|
||||||
|
|
||||||
|
if (typeof person.outbox === "string") {
|
||||||
|
try {
|
||||||
|
let data = await fetch(person.outbox, {
|
||||||
|
headers: { Accept: "application/json" },
|
||||||
|
});
|
||||||
|
let json_data = JSON.parse(await data.text());
|
||||||
|
|
||||||
|
notesCount = json_data.totalItems;
|
||||||
|
} catch (e) {
|
||||||
|
notesCount = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create user
|
// Create user
|
||||||
let user: IRemoteUser;
|
let user: IRemoteUser;
|
||||||
try {
|
try {
|
||||||
|
@ -274,6 +289,14 @@ export async function createPerson(
|
||||||
isCollectionOrOrderedCollection(person.following)
|
isCollectionOrOrderedCollection(person.following)
|
||||||
? person.following.totalItems
|
? person.following.totalItems
|
||||||
: undefined,
|
: undefined,
|
||||||
|
notesCount:
|
||||||
|
notesCount !== undefined
|
||||||
|
? notesCount
|
||||||
|
: person.outbox &&
|
||||||
|
typeof person.outbox !== "string" &&
|
||||||
|
isCollectionOrOrderedCollection(person.outbox)
|
||||||
|
? person.outbox.totalItems
|
||||||
|
: undefined,
|
||||||
featured: person.featured ? getApId(person.featured) : undefined,
|
featured: person.featured ? getApId(person.featured) : undefined,
|
||||||
uri: person.id,
|
uri: person.id,
|
||||||
tags,
|
tags,
|
||||||
|
@ -472,6 +495,21 @@ export async function updatePerson(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let notesCount: number | undefined;
|
||||||
|
|
||||||
|
if (typeof person.outbox === "string") {
|
||||||
|
try {
|
||||||
|
let data = await fetch(person.outbox, {
|
||||||
|
headers: { Accept: "application/json" },
|
||||||
|
});
|
||||||
|
let json_data = JSON.parse(await data.text());
|
||||||
|
|
||||||
|
notesCount = json_data.totalItems;
|
||||||
|
} catch (e) {
|
||||||
|
notesCount = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const updates = {
|
const updates = {
|
||||||
lastFetchedAt: new Date(),
|
lastFetchedAt: new Date(),
|
||||||
inbox: person.inbox,
|
inbox: person.inbox,
|
||||||
|
@ -495,6 +533,14 @@ export async function updatePerson(
|
||||||
isCollectionOrOrderedCollection(person.following)
|
isCollectionOrOrderedCollection(person.following)
|
||||||
? person.following.totalItems
|
? person.following.totalItems
|
||||||
: undefined,
|
: undefined,
|
||||||
|
notesCount:
|
||||||
|
notesCount !== undefined
|
||||||
|
? notesCount
|
||||||
|
: person.outbox &&
|
||||||
|
typeof person.outbox !== "string" &&
|
||||||
|
isCollectionOrOrderedCollection(person.outbox)
|
||||||
|
? person.outbox.totalItems
|
||||||
|
: undefined,
|
||||||
featured: person.featured,
|
featured: person.featured,
|
||||||
emojis: emojiNames,
|
emojis: emojiNames,
|
||||||
name: truncate(person.name, nameLength),
|
name: truncate(person.name, nameLength),
|
||||||
|
@ -554,7 +600,7 @@ export async function updatePerson(
|
||||||
{
|
{
|
||||||
followerSharedInbox:
|
followerSharedInbox:
|
||||||
person.sharedInbox ||
|
person.sharedInbox ||
|
||||||
(person.endpoints ? person.endpoints.sharedInbox : undefined),
|
(person.endpoints ? person.endpoints.sharedInbox : null),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -663,7 +709,7 @@ export async function updateFeatured(userId: User["id"], resolver?: Resolver) {
|
||||||
? collection.items
|
? collection.items
|
||||||
: collection.orderedItems;
|
: collection.orderedItems;
|
||||||
const items = await Promise.all(
|
const items = await Promise.all(
|
||||||
toArray(unresolvedItems).map((x) => resolver.resolve(x)),
|
toArray(unresolvedItems).map((x) => resolver?.resolve(x)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Resolve and regist Notes
|
// Resolve and regist Notes
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import define from "../../../define.js";
|
import define from "../../../define.js";
|
||||||
import { createImportCustomEmojisJob } from "@/queue/index.js";
|
import { createImportCustomEmojisJob } from "@/queue/index.js";
|
||||||
import { ApiError } from "../../../error.js";
|
import { ApiError } from "../../../error.js";
|
||||||
import ms from "ms";
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["admin", "emoji"],
|
tags: ["admin", "emoji"],
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import * as sanitizeHtml from "sanitize-html";
|
import sanitizeHtml from "sanitize-html";
|
||||||
import define from "../../define.js";
|
import define from "../../define.js";
|
||||||
import { Users, UserProfiles } from "@/models/index.js";
|
import { Users, UserProfiles } from "@/models/index.js";
|
||||||
import { ApiError } from "../../error.js";
|
import { ApiError } from "../../error.js";
|
||||||
|
|
|
@ -24,7 +24,7 @@ export const meta = {
|
||||||
},
|
},
|
||||||
|
|
||||||
recursiveNesting: {
|
recursiveNesting: {
|
||||||
message: "It can not be structured like nesting folders recursively.",
|
message: "It cannot be structured like nesting folders recursively.",
|
||||||
code: "NO_SUCH_PARENT_FOLDER",
|
code: "NO_SUCH_PARENT_FOLDER",
|
||||||
id: "ce104e3a-faaf-49d5-b459-10ff0cbbcaa1",
|
id: "ce104e3a-faaf-49d5-b459-10ff0cbbcaa1",
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,7 +18,7 @@ export const meta = {
|
||||||
},
|
},
|
||||||
|
|
||||||
pinLimitExceeded: {
|
pinLimitExceeded: {
|
||||||
message: "You can not pin notes any more.",
|
message: "You cannot pin notes any more.",
|
||||||
code: "PIN_LIMIT_EXCEEDED",
|
code: "PIN_LIMIT_EXCEEDED",
|
||||||
id: "72dab508-c64d-498f-8740-a8eec1ba385a",
|
id: "72dab508-c64d-498f-8740-a8eec1ba385a",
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,9 +15,7 @@ export const paramDef = {
|
||||||
|
|
||||||
export default define(meta, paramDef, async () => {
|
export default define(meta, paramDef, async () => {
|
||||||
let tag_name;
|
let tag_name;
|
||||||
await fetch(
|
await fetch("https://git.joinfirefish.org/api/v4/projects/7/releases")
|
||||||
"https://codeberg.org/api/v1/repos/firefish/firefish/releases?draft=false&pre-release=false&page=1&limit=1",
|
|
||||||
)
|
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
tag_name = data[0].tag_name;
|
tag_name = data[0].tag_name;
|
||||||
|
|
|
@ -48,7 +48,7 @@ export const meta = {
|
||||||
},
|
},
|
||||||
|
|
||||||
groupAccessDenied: {
|
groupAccessDenied: {
|
||||||
message: "You can not read messages of groups that you have not joined.",
|
message: "You cannot read messages of groups that you have not joined.",
|
||||||
code: "GROUP_ACCESS_DENIED",
|
code: "GROUP_ACCESS_DENIED",
|
||||||
id: "a053a8dd-a491-4718-8f87-50775aad9284",
|
id: "a053a8dd-a491-4718-8f87-50775aad9284",
|
||||||
},
|
},
|
||||||
|
|
|
@ -28,7 +28,7 @@ export const meta = {
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
recipientIsYourself: {
|
recipientIsYourself: {
|
||||||
message: "You can not send a message to yourself.",
|
message: "You cannot send a message to yourself.",
|
||||||
code: "RECIPIENT_IS_YOURSELF",
|
code: "RECIPIENT_IS_YOURSELF",
|
||||||
id: "17e2ba79-e22a-4cbc-bf91-d327643f4a7e",
|
id: "17e2ba79-e22a-4cbc-bf91-d327643f4a7e",
|
||||||
},
|
},
|
||||||
|
@ -46,7 +46,7 @@ export const meta = {
|
||||||
},
|
},
|
||||||
|
|
||||||
groupAccessDenied: {
|
groupAccessDenied: {
|
||||||
message: "You can not send messages to groups that you have not joined.",
|
message: "You cannot send messages to groups that you have not joined.",
|
||||||
code: "GROUP_ACCESS_DENIED",
|
code: "GROUP_ACCESS_DENIED",
|
||||||
id: "d96b3cca-5ad1-438b-ad8b-02f931308fbd",
|
id: "d96b3cca-5ad1-438b-ad8b-02f931308fbd",
|
||||||
},
|
},
|
||||||
|
|
|
@ -52,7 +52,7 @@ export const meta = {
|
||||||
},
|
},
|
||||||
|
|
||||||
cannotReRenote: {
|
cannotReRenote: {
|
||||||
message: "You can not Renote a pure Renote.",
|
message: "You cannot Renote a pure Renote.",
|
||||||
code: "CANNOT_RENOTE_TO_A_PURE_RENOTE",
|
code: "CANNOT_RENOTE_TO_A_PURE_RENOTE",
|
||||||
id: "fd4cc33e-2a37-48dd-99cc-9b806eb2031a",
|
id: "fd4cc33e-2a37-48dd-99cc-9b806eb2031a",
|
||||||
},
|
},
|
||||||
|
@ -64,7 +64,7 @@ export const meta = {
|
||||||
},
|
},
|
||||||
|
|
||||||
cannotReplyToPureRenote: {
|
cannotReplyToPureRenote: {
|
||||||
message: "You can not reply to a pure Renote.",
|
message: "You cannot reply to a pure Renote.",
|
||||||
code: "CANNOT_REPLY_TO_A_PURE_RENOTE",
|
code: "CANNOT_REPLY_TO_A_PURE_RENOTE",
|
||||||
id: "3ac74a84-8fd5-4bb0-870f-01804f82ce15",
|
id: "3ac74a84-8fd5-4bb0-870f-01804f82ce15",
|
||||||
},
|
},
|
||||||
|
|
|
@ -70,7 +70,7 @@ export const meta = {
|
||||||
},
|
},
|
||||||
|
|
||||||
cannotReRenote: {
|
cannotReRenote: {
|
||||||
message: "You can not Renote a pure Renote.",
|
message: "You cannot Renote a pure Renote.",
|
||||||
code: "CANNOT_RENOTE_TO_A_PURE_RENOTE",
|
code: "CANNOT_RENOTE_TO_A_PURE_RENOTE",
|
||||||
id: "fd4cc33e-2a37-48dd-99cc-9b806eb2031a",
|
id: "fd4cc33e-2a37-48dd-99cc-9b806eb2031a",
|
||||||
},
|
},
|
||||||
|
@ -82,7 +82,7 @@ export const meta = {
|
||||||
},
|
},
|
||||||
|
|
||||||
cannotReplyToPureRenote: {
|
cannotReplyToPureRenote: {
|
||||||
message: "You can not reply to a pure Renote.",
|
message: "You cannot reply to a pure Renote.",
|
||||||
code: "CANNOT_REPLY_TO_A_PURE_RENOTE",
|
code: "CANNOT_REPLY_TO_A_PURE_RENOTE",
|
||||||
id: "3ac74a84-8fd5-4bb0-870f-01804f82ce15",
|
id: "3ac74a84-8fd5-4bb0-870f-01804f82ce15",
|
||||||
},
|
},
|
||||||
|
@ -130,7 +130,7 @@ export const meta = {
|
||||||
},
|
},
|
||||||
|
|
||||||
cannotPrivateRenote: {
|
cannotPrivateRenote: {
|
||||||
message: "You can not perform a private renote.",
|
message: "You cannot perform a private renote.",
|
||||||
code: "CANNOT_PRIVATE_RENOTE",
|
code: "CANNOT_PRIVATE_RENOTE",
|
||||||
id: "19a50f1c-84fa-4e33-81d3-17834ccc0ad8",
|
id: "19a50f1c-84fa-4e33-81d3-17834ccc0ad8",
|
||||||
},
|
},
|
||||||
|
@ -140,6 +140,18 @@ export const meta = {
|
||||||
code: "NOT_LOCAL_USER",
|
code: "NOT_LOCAL_USER",
|
||||||
id: "b907f407-2aa0-4283-800b-a2c56290b822",
|
id: "b907f407-2aa0-4283-800b-a2c56290b822",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
cannotChangeVisibility: {
|
||||||
|
message: "You cannot change the visibility of a note.",
|
||||||
|
code: "CANNOT_CHANGE_VISIBILITY",
|
||||||
|
id: "2917fd0b-da04-41de-949f-146835a006c6",
|
||||||
|
},
|
||||||
|
|
||||||
|
cannotQuoteOwnNote: {
|
||||||
|
message: "You cannot quote your own note.",
|
||||||
|
code: "CANNOT_QUOTE_OWN_NOTE",
|
||||||
|
id: "070eee98-5f8a-4eca-9dc0-830b4d4e52ac",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@ -268,6 +280,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
throw e;
|
throw e;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (ps.renoteId === note.id) {
|
||||||
|
throw new ApiError(meta.errors.cannotQuoteOwnNote);
|
||||||
|
}
|
||||||
|
|
||||||
if (renote.renoteId && !renote.text && !renote.fileIds && !renote.hasPoll) {
|
if (renote.renoteId && !renote.text && !renote.fileIds && !renote.hasPoll) {
|
||||||
throw new ApiError(meta.errors.cannotReRenote);
|
throw new ApiError(meta.errors.cannotReRenote);
|
||||||
}
|
}
|
||||||
|
@ -523,7 +539,8 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
update.cw = null;
|
update.cw = null;
|
||||||
}
|
}
|
||||||
if (ps.visibility !== note.visibility) {
|
if (ps.visibility !== note.visibility) {
|
||||||
update.visibility = ps.visibility;
|
// update.visibility = ps.visibility;
|
||||||
|
throw new ApiError(meta.errors.cannotChangeVisibility);
|
||||||
}
|
}
|
||||||
if (ps.localOnly !== note.localOnly) {
|
if (ps.localOnly !== note.localOnly) {
|
||||||
update.localOnly = ps.localOnly;
|
update.localOnly = ps.localOnly;
|
||||||
|
|
|
@ -85,6 +85,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
|
|
||||||
query
|
query
|
||||||
.andWhere("note.text ILIKE :q", { q: `%${sqlLikeEscape(ps.query)}%` })
|
.andWhere("note.text ILIKE :q", { q: `%${sqlLikeEscape(ps.query)}%` })
|
||||||
|
.andWhere("note.visibility = 'public'")
|
||||||
.innerJoinAndSelect("note.user", "user")
|
.innerJoinAndSelect("note.user", "user")
|
||||||
.leftJoinAndSelect("user.avatar", "avatar")
|
.leftJoinAndSelect("user.avatar", "avatar")
|
||||||
.leftJoinAndSelect("user.banner", "banner")
|
.leftJoinAndSelect("user.banner", "banner")
|
||||||
|
|
|
@ -10,7 +10,7 @@ export const meta = {
|
||||||
kind: "write:user-groups",
|
kind: "write:user-groups",
|
||||||
|
|
||||||
description:
|
description:
|
||||||
"Leave a group. The owner of a group can not leave. They must transfer ownership or delete the group instead.",
|
"Leave a group. The owner of a group cannot leave. They must transfer ownership or delete the group instead.",
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchGroup: {
|
noSuchGroup: {
|
||||||
|
|
|
@ -11,7 +11,7 @@ export const meta = {
|
||||||
kind: "write:user-groups",
|
kind: "write:user-groups",
|
||||||
|
|
||||||
description:
|
description:
|
||||||
"Removes a specified user from a group. The owner can not be removed.",
|
"Removes a specified user from a group. The owner cannot be removed.",
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchGroup: {
|
noSuchGroup: {
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import * as sanitizeHtml from "sanitize-html";
|
import * as mfm from "mfm-js";
|
||||||
|
import sanitizeHtml from "sanitize-html";
|
||||||
import { publishAdminStream } from "@/services/stream.js";
|
import { publishAdminStream } from "@/services/stream.js";
|
||||||
import { AbuseUserReports, Users } from "@/models/index.js";
|
import { AbuseUserReports, UserProfiles, Users } from "@/models/index.js";
|
||||||
import { genId } from "@/misc/gen-id.js";
|
import { genId } from "@/misc/gen-id.js";
|
||||||
import { sendEmail } from "@/services/send-email.js";
|
import { sendEmail } from "@/services/send-email.js";
|
||||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||||
import { getUser } from "../../common/getters.js";
|
import { getUser } from "../../common/getters.js";
|
||||||
import { ApiError } from "../../error.js";
|
import { ApiError } from "../../error.js";
|
||||||
import define from "../../define.js";
|
import define from "../../define.js";
|
||||||
|
import { toHtml } from "@/mfm/to-html.js";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["users"],
|
tags: ["users"],
|
||||||
|
@ -84,6 +86,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const meta = await fetchMeta();
|
||||||
for (const moderator of moderators) {
|
for (const moderator of moderators) {
|
||||||
publishAdminStream(moderator.id, "newAbuseUserReport", {
|
publishAdminStream(moderator.id, "newAbuseUserReport", {
|
||||||
id: report.id,
|
id: report.id,
|
||||||
|
@ -91,16 +94,16 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
reporterId: report.reporterId,
|
reporterId: report.reporterId,
|
||||||
comment: report.comment,
|
comment: report.comment,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
const meta = await fetchMeta();
|
const profile = await UserProfiles.findOneBy({ userId: moderator.id });
|
||||||
if (meta.email) {
|
if (profile?.email) {
|
||||||
sendEmail(
|
sendEmail(
|
||||||
meta.email,
|
profile.email,
|
||||||
"New abuse report",
|
"New abuse report",
|
||||||
sanitizeHtml(ps.comment),
|
sanitizeHtml(toHtml(mfm.parse(ps.comment))!),
|
||||||
sanitizeHtml(ps.comment),
|
sanitizeHtml(toHtml(mfm.parse(ps.comment))!),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -74,3 +74,13 @@ export function convertStatus(status: Entity.Status) {
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function convertConversation(conversation: Entity.Conversation) {
|
||||||
|
conversation.id = convertId(conversation.id, IdType.MastodonId);
|
||||||
|
conversation.accounts = conversation.accounts.map(convertAccount);
|
||||||
|
if (conversation.last_status) {
|
||||||
|
conversation.last_status = convertStatus(conversation.last_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return conversation;
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
import Router from "@koa/router";
|
import Router from "@koa/router";
|
||||||
import { getClient } from "../ApiMastodonCompatibleService.js";
|
import { getClient } from "../ApiMastodonCompatibleService.js";
|
||||||
import { ParsedUrlQuery } from "querystring";
|
import { ParsedUrlQuery } from "querystring";
|
||||||
import { convertAccount, convertList, convertStatus } from "../converters.js";
|
import {
|
||||||
|
convertAccount,
|
||||||
|
convertConversation,
|
||||||
|
convertList,
|
||||||
|
convertStatus,
|
||||||
|
} from "../converters.js";
|
||||||
import { convertId, IdType } from "../../index.js";
|
import { convertId, IdType } from "../../index.js";
|
||||||
|
|
||||||
export function limitToInt(q: ParsedUrlQuery) {
|
export function limitToInt(q: ParsedUrlQuery) {
|
||||||
|
@ -136,7 +141,9 @@ export function apiTimelineMastodon(router: Router): void {
|
||||||
const data = await client.getConversationTimeline(
|
const data = await client.getConversationTimeline(
|
||||||
convertTimelinesArgsId(limitToInt(ctx.query)),
|
convertTimelinesArgsId(limitToInt(ctx.query)),
|
||||||
);
|
);
|
||||||
ctx.body = data.data;
|
ctx.body = data.data.map((conversation) =>
|
||||||
|
convertConversation(conversation),
|
||||||
|
);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
console.error(e.response.data);
|
console.error(e.response.data);
|
||||||
|
|
|
@ -167,7 +167,6 @@ export default async function (ctx: Koa.Context) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.length = file.size;
|
|
||||||
ctx.set("Content-Disposition", contentDisposition("inline", filename));
|
ctx.set("Content-Disposition", contentDisposition("inline", filename));
|
||||||
ctx.set("Content-Type", contentType);
|
ctx.set("Content-Type", contentType);
|
||||||
|
|
||||||
|
@ -192,7 +191,6 @@ export default async function (ctx: Koa.Context) {
|
||||||
ctx.set("Accept-Ranges", "bytes");
|
ctx.set("Accept-Ranges", "bytes");
|
||||||
} else {
|
} else {
|
||||||
ctx.status = 206;
|
ctx.status = 206;
|
||||||
ctx.length = readable.size;
|
|
||||||
readable.on("close", async () => {
|
readable.on("close", async () => {
|
||||||
await fileHandle.close();
|
await fileHandle.close();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { URL } from "node:url";
|
import { URL } from "node:url";
|
||||||
import type { User } from "@/models/entities/user.js";
|
import type { User } from "@/models/entities/user.js";
|
||||||
import { createTemp } from "@/misc/create-temp.js";
|
import { createTemp } from "@/misc/create-temp.js";
|
||||||
import { downloadUrl } from "@/misc/download-url.js";
|
import { downloadUrl, isPrivateIp } from "@/misc/download-url.js";
|
||||||
import type { DriveFolder } from "@/models/entities/drive-folder.js";
|
import type { DriveFolder } from "@/models/entities/drive-folder.js";
|
||||||
import type { DriveFile } from "@/models/entities/drive-file.js";
|
import type { DriveFile } from "@/models/entities/drive-file.js";
|
||||||
import { DriveFiles } from "@/models/index.js";
|
import { DriveFiles } from "@/models/index.js";
|
||||||
|
@ -35,7 +35,15 @@ export async function uploadFromUrl({
|
||||||
requestIp = null,
|
requestIp = null,
|
||||||
requestHeaders = null,
|
requestHeaders = null,
|
||||||
}: Args): Promise<DriveFile> {
|
}: Args): Promise<DriveFile> {
|
||||||
let name = new URL(url).pathname.split("/").pop() || null;
|
const parsedUrl = new URL(url);
|
||||||
|
if (
|
||||||
|
process.env.NODE_ENV === "production" &&
|
||||||
|
isPrivateIp(parsedUrl.hostname.replaceAll(/(\[)|(\])/g, ""))
|
||||||
|
) {
|
||||||
|
throw new Error("Private IP is not allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = parsedUrl.pathname.split("/").pop() || null;
|
||||||
if (name == null || !DriveFiles.validateFileName(name)) {
|
if (name == null || !DriveFiles.validateFileName(name)) {
|
||||||
name = null;
|
name = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ export async function addPinned(
|
||||||
if (pinings.length >= 15) {
|
if (pinings.length >= 15) {
|
||||||
throw new IdentifiableError(
|
throw new IdentifiableError(
|
||||||
"15a018eb-58e5-4da1-93be-330fcc5e4e1a",
|
"15a018eb-58e5-4da1-93be-330fcc5e4e1a",
|
||||||
"You can not pin notes any more.",
|
"You cannot pin notes any more.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -171,8 +171,7 @@ export default async (
|
||||||
) =>
|
) =>
|
||||||
// rome-ignore lint/suspicious/noAsyncPromiseExecutor: FIXME
|
// rome-ignore lint/suspicious/noAsyncPromiseExecutor: FIXME
|
||||||
new Promise<Note>(async (res, rej) => {
|
new Promise<Note>(async (res, rej) => {
|
||||||
const dontFederateInitially =
|
const dontFederateInitially = data.visibility === "hidden";
|
||||||
data.localOnly || data.visibility?.startsWith("hidden");
|
|
||||||
|
|
||||||
// If you reply outside the channel, match the scope of the target.
|
// If you reply outside the channel, match the scope of the target.
|
||||||
// TODO (I think it's a process that could be done on the client side, but it's server side for now.)
|
// TODO (I think it's a process that could be done on the client side, but it's server side for now.)
|
||||||
|
@ -806,7 +805,7 @@ async function insertNote(
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function index(note: Note, reindexing: boolean): Promise<void> {
|
export async function index(note: Note, reindexing: boolean): Promise<void> {
|
||||||
if (!note.text) return;
|
if (!note.text || note.visibility !== "public") return;
|
||||||
|
|
||||||
if (config.elasticsearch && es) {
|
if (config.elasticsearch && es) {
|
||||||
es.index({
|
es.index({
|
||||||
|
|
|
@ -11,30 +11,30 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@discordapp/twemoji": "14.1.2",
|
"@discordapp/twemoji": "14.1.2",
|
||||||
"@eslint-sets/eslint-config-vue3": "^5.7.0",
|
"@eslint-sets/eslint-config-vue3": "^5.8.0",
|
||||||
"@eslint-sets/eslint-config-vue3-ts": "^3.3.0",
|
"@eslint-sets/eslint-config-vue3-ts": "^3.3.0",
|
||||||
"@phosphor-icons/web": "^2.0.3",
|
"@phosphor-icons/web": "^2.0.3",
|
||||||
"@rollup/plugin-alias": "3.1.9",
|
"@rollup/plugin-alias": "5.0.0",
|
||||||
"@rollup/plugin-json": "4.1.0",
|
"@rollup/plugin-json": "6.0.0",
|
||||||
"@rollup/pluginutils": "^4.2.1",
|
"@rollup/pluginutils": "^5.0.3",
|
||||||
"@syuilo/aiscript": "0.11.1",
|
"@syuilo/aiscript": "0.11.1",
|
||||||
"@types/escape-regexp": "0.0.1",
|
"@types/escape-regexp": "0.0.1",
|
||||||
"@types/glob": "8.1.0",
|
"@types/glob": "8.1.0",
|
||||||
"@types/gulp": "4.0.13",
|
"@types/gulp": "4.0.13",
|
||||||
"@types/gulp-rename": "2.0.2",
|
"@types/gulp-rename": "2.0.2",
|
||||||
"@types/katex": "0.16.0",
|
"@types/katex": "0.16.2",
|
||||||
"@types/matter-js": "0.18.2",
|
"@types/matter-js": "0.19.0",
|
||||||
"@types/punycode": "2.1.0",
|
"@types/punycode": "2.1.0",
|
||||||
"@types/seedrandom": "3.0.5",
|
"@types/seedrandom": "3.0.5",
|
||||||
"@types/throttle-debounce": "5.0.0",
|
"@types/throttle-debounce": "5.0.0",
|
||||||
"@types/tinycolor2": "1.4.3",
|
"@types/tinycolor2": "1.4.3",
|
||||||
"@types/uuid": "8.3.4",
|
"@types/uuid": "9.0.2",
|
||||||
"@vitejs/plugin-vue": "4.2.3",
|
"@vitejs/plugin-vue": "4.3.1",
|
||||||
"@vue/compiler-sfc": "3.3.4",
|
"@vue/compiler-sfc": "3.3.4",
|
||||||
"autobind-decorator": "2.4.0",
|
"autobind-decorator": "2.4.0",
|
||||||
"autosize": "6.0.1",
|
"autosize": "6.0.1",
|
||||||
"blurhash": "2.0.5",
|
"blurhash": "2.0.5",
|
||||||
"broadcast-channel": "5.1.0",
|
"broadcast-channel": "5.2.0",
|
||||||
"browser-image-resizer": "github:misskey-dev/browser-image-resizer",
|
"browser-image-resizer": "github:misskey-dev/browser-image-resizer",
|
||||||
"chart.js": "4.3.3",
|
"chart.js": "4.3.3",
|
||||||
"chartjs-adapter-date-fns": "3.0.0",
|
"chartjs-adapter-date-fns": "3.0.0",
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
"date-fns": "2.30.0",
|
"date-fns": "2.30.0",
|
||||||
"emojilib": "github:thatonecalculator/emojilib",
|
"emojilib": "github:thatonecalculator/emojilib",
|
||||||
"escape-regexp": "0.0.1",
|
"escape-regexp": "0.0.1",
|
||||||
"eslint-config-prettier": "^8.9.0",
|
"eslint-config-prettier": "9.0.0",
|
||||||
"eslint-plugin-file-progress": "^1.3.0",
|
"eslint-plugin-file-progress": "^1.3.0",
|
||||||
"eventemitter3": "5.0.1",
|
"eventemitter3": "5.0.1",
|
||||||
"fast-blurhash": "^1.1.2",
|
"fast-blurhash": "^1.1.2",
|
||||||
|
@ -61,27 +61,25 @@
|
||||||
"insert-text-at-cursor": "0.3.0",
|
"insert-text-at-cursor": "0.3.0",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"katex": "0.16.8",
|
"katex": "0.16.8",
|
||||||
"matter-js": "0.18.0",
|
"matter-js": "0.19.0",
|
||||||
"mfm-js": "0.23.3",
|
"mfm-js": "0.23.3",
|
||||||
"paralint": "^1.2.1",
|
"paralint": "^1.2.1",
|
||||||
"photoswipe": "5.3.8",
|
"photoswipe": "5.3.8",
|
||||||
"prettier": "3.0.1",
|
"prettier": "3.0.2",
|
||||||
"prettier-plugin-vue": "1.1.6",
|
"prettier-plugin-vue": "1.1.6",
|
||||||
"prismjs": "1.29.0",
|
"prismjs": "1.29.0",
|
||||||
"punycode": "2.3.0",
|
"punycode": "2.3.0",
|
||||||
"querystring": "0.2.1",
|
|
||||||
"rndstr": "1.0.0",
|
"rndstr": "1.0.0",
|
||||||
"rollup": "3.27.2",
|
"rollup": "3.28.0",
|
||||||
"s-age": "1.1.2",
|
"s-age": "1.1.2",
|
||||||
"sass": "1.64.2",
|
"sass": "1.66.0",
|
||||||
"seedrandom": "3.0.5",
|
"seedrandom": "3.0.5",
|
||||||
"start-server-and-test": "1.15.2",
|
|
||||||
"strict-event-emitter-types": "2.0.0",
|
"strict-event-emitter-types": "2.0.0",
|
||||||
"stringz": "2.1.0",
|
"stringz": "2.1.0",
|
||||||
"swiper": "10.1.0",
|
"swiper": "10.2.0",
|
||||||
"syuilo-password-strength": "0.0.1",
|
"syuilo-password-strength": "0.0.1",
|
||||||
"textarea-caret": "3.1.0",
|
"textarea-caret": "3.1.0",
|
||||||
"three": "0.146.0",
|
"three": "0.155.0",
|
||||||
"throttle-debounce": "5.0.0",
|
"throttle-debounce": "5.0.0",
|
||||||
"tinycolor2": "1.6.0",
|
"tinycolor2": "1.6.0",
|
||||||
"tinyld": "1.3.4",
|
"tinyld": "1.3.4",
|
||||||
|
@ -91,11 +89,11 @@
|
||||||
"typescript": "5.1.6",
|
"typescript": "5.1.6",
|
||||||
"unicode-emoji-json": "^0.4.0",
|
"unicode-emoji-json": "^0.4.0",
|
||||||
"uuid": "9.0.0",
|
"uuid": "9.0.0",
|
||||||
"vanilla-tilt": "1.8.0",
|
"vanilla-tilt": "1.8.1",
|
||||||
"vite": "4.4.9",
|
"vite": "4.4.9",
|
||||||
"vite-plugin-compression": "^0.5.1",
|
"vite-plugin-compression": "^0.5.1",
|
||||||
"vue": "3.3.4",
|
"vue": "3.3.4",
|
||||||
"vue-draggable-plus": "^0.2.4",
|
"vue-draggable-plus": "^0.2.5",
|
||||||
"vue-isyourpasswordsafe": "^2.0.0",
|
"vue-isyourpasswordsafe": "^2.0.0",
|
||||||
"vue-plyr": "^7.0.0",
|
"vue-plyr": "^7.0.0",
|
||||||
"vue-prism-editor": "2.0.0-alpha.2"
|
"vue-prism-editor": "2.0.0-alpha.2"
|
||||||
|
|
|
@ -65,6 +65,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
import MkButton from "@/components/MkButton.vue";
|
import MkButton from "@/components/MkButton.vue";
|
||||||
import MkSwitch from "@/components/form/switch.vue";
|
import MkSwitch from "@/components/form/switch.vue";
|
||||||
import MkKeyValue from "@/components/MkKeyValue.vue";
|
import MkKeyValue from "@/components/MkKeyValue.vue";
|
||||||
|
@ -79,11 +81,11 @@ const emit = defineEmits<{
|
||||||
(ev: "resolved", reportId: string): void;
|
(ev: "resolved", reportId: string): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const forward = $ref(props.report.forwarded);
|
const forward = ref(props.report.forwarded);
|
||||||
|
|
||||||
function resolve() {
|
function resolve() {
|
||||||
os.apiWithDialog("admin/resolve-abuse-user-report", {
|
os.apiWithDialog("admin/resolve-abuse-user-report", {
|
||||||
forward,
|
forward: forward.value,
|
||||||
reportId: props.report.id,
|
reportId: props.report.id,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
emit("resolved", props.report.id);
|
emit("resolved", props.report.id);
|
||||||
|
|
|
@ -108,7 +108,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onBeforeUnmount, onMounted } from "vue";
|
import { computed, onBeforeUnmount, onMounted, ref } from "vue";
|
||||||
import tinycolor from "tinycolor2";
|
import tinycolor from "tinycolor2";
|
||||||
import { globalEvents } from "@/events.js";
|
import { globalEvents } from "@/events.js";
|
||||||
|
|
||||||
|
@ -167,19 +167,19 @@ const texts = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
let enabled = true,
|
let enabled = true,
|
||||||
majorGraduationColor = $ref<string>(),
|
majorGraduationColor = ref<string>(),
|
||||||
// let minorGraduationColor = $ref<string>();
|
// let minorGraduationColor = $ref<string>();
|
||||||
sHandColor = $ref<string>(),
|
sHandColor = ref<string>(),
|
||||||
mHandColor = $ref<string>(),
|
mHandColor = ref<string>(),
|
||||||
hHandColor = $ref<string>(),
|
hHandColor = ref<string>(),
|
||||||
nowColor = $ref<string>(),
|
nowColor = ref<string>(),
|
||||||
h = $ref<number>(0),
|
h = ref<number>(0),
|
||||||
m = $ref<number>(0),
|
m = ref<number>(0),
|
||||||
s = $ref<number>(0),
|
s = ref<number>(0),
|
||||||
hAngle = $ref<number>(0),
|
hAngle = ref<number>(0),
|
||||||
mAngle = $ref<number>(0),
|
mAngle = ref<number>(0),
|
||||||
sAngle = $ref<number>(0),
|
sAngle = ref<number>(0),
|
||||||
disableSAnimate = $ref(false),
|
disableSAnimate = ref(false),
|
||||||
sOneRound = false;
|
sOneRound = false;
|
||||||
|
|
||||||
function tick() {
|
function tick() {
|
||||||
|
@ -187,29 +187,31 @@ function tick() {
|
||||||
now.setMinutes(
|
now.setMinutes(
|
||||||
now.getMinutes() + (new Date().getTimezoneOffset() + props.offset),
|
now.getMinutes() + (new Date().getTimezoneOffset() + props.offset),
|
||||||
);
|
);
|
||||||
s = now.getSeconds();
|
s.value = now.getSeconds();
|
||||||
m = now.getMinutes();
|
m.value = now.getMinutes();
|
||||||
h = now.getHours();
|
h.value = now.getHours();
|
||||||
hAngle =
|
hAngle.value =
|
||||||
(Math.PI * ((h % (props.twentyfour ? 24 : 12)) + (m + s / 60) / 60)) /
|
(Math.PI *
|
||||||
|
((h.value % (props.twentyfour ? 24 : 12)) +
|
||||||
|
(m.value + s.value / 60) / 60)) /
|
||||||
(props.twentyfour ? 12 : 6);
|
(props.twentyfour ? 12 : 6);
|
||||||
mAngle = (Math.PI * (m + s / 60)) / 30;
|
mAngle.value = (Math.PI * (m.value + s.value / 60)) / 30;
|
||||||
if (sOneRound) {
|
if (sOneRound) {
|
||||||
// 秒針が一周した際のアニメーションをよしなに処理する(これが無いと秒が59->0になったときに期待したアニメーションにならない)
|
// 秒針が一周した際のアニメーションをよしなに処理する(これが無いと秒が59->0になったときに期待したアニメーションにならない)
|
||||||
sAngle = (Math.PI * 60) / 30;
|
sAngle.value = (Math.PI * 60) / 30;
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
disableSAnimate = true;
|
disableSAnimate.value = true;
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
sAngle = 0;
|
sAngle.value = 0;
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
disableSAnimate = false;
|
disableSAnimate.value = false;
|
||||||
}, 100);
|
}, 100);
|
||||||
}, 100);
|
}, 100);
|
||||||
}, 700);
|
}, 700);
|
||||||
} else {
|
} else {
|
||||||
sAngle = (Math.PI * s) / 30;
|
sAngle.value = (Math.PI * s.value) / 30;
|
||||||
}
|
}
|
||||||
sOneRound = s === 59;
|
sOneRound = s.value === 59;
|
||||||
}
|
}
|
||||||
|
|
||||||
tick();
|
tick();
|
||||||
|
@ -220,16 +222,16 @@ function calcColors() {
|
||||||
const accent = tinycolor(
|
const accent = tinycolor(
|
||||||
computedStyle.getPropertyValue("--accent"),
|
computedStyle.getPropertyValue("--accent"),
|
||||||
).toHexString();
|
).toHexString();
|
||||||
majorGraduationColor = dark
|
majorGraduationColor.value = dark
|
||||||
? "rgba(255, 255, 255, 0.3)"
|
? "rgba(255, 255, 255, 0.3)"
|
||||||
: "rgba(0, 0, 0, 0.3)";
|
: "rgba(0, 0, 0, 0.3)";
|
||||||
// minorGraduationColor = dark ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
// minorGraduationColor = dark ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
||||||
sHandColor = dark ? "rgba(255, 255, 255, 0.5)" : "rgba(0, 0, 0, 0.3)";
|
sHandColor.value = dark ? "rgba(255, 255, 255, 0.5)" : "rgba(0, 0, 0, 0.3)";
|
||||||
mHandColor = tinycolor(
|
mHandColor.value = tinycolor(
|
||||||
computedStyle.getPropertyValue("--fg"),
|
computedStyle.getPropertyValue("--fg"),
|
||||||
).toHexString();
|
).toHexString();
|
||||||
hHandColor = accent;
|
hHandColor.value = accent;
|
||||||
nowColor = accent;
|
nowColor.value = accent;
|
||||||
}
|
}
|
||||||
|
|
||||||
calcColors();
|
calcColors();
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, onMounted } from "vue";
|
import { nextTick, onMounted, ref } from "vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
type?: "button" | "submit" | "reset";
|
type?: "button" | "submit" | "reset";
|
||||||
|
@ -49,13 +49,13 @@ const emit = defineEmits<{
|
||||||
(ev: "click", payload: MouseEvent): void;
|
(ev: "click", payload: MouseEvent): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const el = $ref<HTMLElement | null>(null);
|
const el = ref<HTMLElement | null>(null);
|
||||||
const ripples = $ref<HTMLElement | null>(null);
|
const ripples = ref<HTMLElement | null>(null);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.autofocus) {
|
if (props.autofocus) {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
el!.focus();
|
el.value!.focus();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -81,7 +81,7 @@ function onMousedown(evt: MouseEvent): void {
|
||||||
ripple.style.top = (evt.clientY - rect.top - 1).toString() + "px";
|
ripple.style.top = (evt.clientY - rect.top - 1).toString() + "px";
|
||||||
ripple.style.left = (evt.clientX - rect.left - 1).toString() + "px";
|
ripple.style.left = (evt.clientX - rect.left - 1).toString() + "px";
|
||||||
|
|
||||||
ripples!.appendChild(ripple);
|
ripples.value!.appendChild(ripple);
|
||||||
|
|
||||||
const circleCenterX = evt.clientX - rect.left;
|
const circleCenterX = evt.clientX - rect.left;
|
||||||
const circleCenterY = evt.clientY - rect.top;
|
const circleCenterY = evt.clientY - rect.top;
|
||||||
|
@ -101,7 +101,7 @@ function onMousedown(evt: MouseEvent): void {
|
||||||
ripple.style.opacity = "0";
|
ripple.style.opacity = "0";
|
||||||
}, 1000);
|
}, 1000);
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
if (ripples) ripples.removeChild(ripple);
|
if (ripples.value) ripples.value.removeChild(ripple);
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
import XModalWindow from "@/components/MkModalWindow.vue";
|
import XModalWindow from "@/components/MkModalWindow.vue";
|
||||||
import XCheatSheet from "@/pages/mfm-cheat-sheet.vue";
|
import XCheatSheet from "@/pages/mfm-cheat-sheet.vue";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
|
@ -20,7 +22,7 @@ const emit = defineEmits<{
|
||||||
(ev: "closed"): void;
|
(ev: "closed"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dialog = $ref<InstanceType<typeof XModalWindow>>();
|
const dialog = ref<InstanceType<typeof XModalWindow>>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onBeforeUnmount, onMounted } from "vue";
|
import { onBeforeUnmount, onMounted, ref } from "vue";
|
||||||
import MkMenu from "@/components/MkMenu.vue";
|
import MkMenu from "@/components/MkMenu.vue";
|
||||||
import type { MenuItem } from "@/types/menu";
|
import type { MenuItem } from "@/types/menu";
|
||||||
import contains from "@/scripts/contains";
|
import contains from "@/scripts/contains";
|
||||||
|
@ -27,16 +27,16 @@ const emit = defineEmits<{
|
||||||
(ev: "closed"): void;
|
(ev: "closed"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const rootEl = $ref<HTMLDivElement>();
|
const rootEl = ref<HTMLDivElement>();
|
||||||
|
|
||||||
const zIndex = $ref<number>(os.claimZIndex("high"));
|
const zIndex = ref<number>(os.claimZIndex("high"));
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
let left = props.ev.pageX + 1, // 間違って右ダブルクリックした場合に意図せずアイテムがクリックされるのを防ぐため + 1
|
let left = props.ev.pageX + 1, // 間違って右ダブルクリックした場合に意図せずアイテムがクリックされるのを防ぐため + 1
|
||||||
top = props.ev.pageY + 1; // 間違って右ダブルクリックした場合に意図せずアイテムがクリックされるのを防ぐため + 1
|
top = props.ev.pageY + 1; // 間違って右ダブルクリックした場合に意図せずアイテムがクリックされるのを防ぐため + 1
|
||||||
|
|
||||||
const width = rootEl.offsetWidth;
|
const width = rootEl.value.offsetWidth;
|
||||||
const height = rootEl.offsetHeight;
|
const height = rootEl.value.offsetHeight;
|
||||||
|
|
||||||
if (left + width - window.pageXOffset > window.innerWidth) {
|
if (left + width - window.pageXOffset > window.innerWidth) {
|
||||||
left = window.innerWidth - width + window.pageXOffset;
|
left = window.innerWidth - width + window.pageXOffset;
|
||||||
|
@ -54,8 +54,8 @@ onMounted(() => {
|
||||||
left = 0;
|
left = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rootEl.style.top = `${top}px`;
|
rootEl.value.style.top = `${top}px`;
|
||||||
rootEl.style.left = `${left}px`;
|
rootEl.value.style.left = `${left}px`;
|
||||||
|
|
||||||
document.body.addEventListener("mousedown", onMousedown);
|
document.body.addEventListener("mousedown", onMousedown);
|
||||||
});
|
});
|
||||||
|
@ -65,7 +65,8 @@ onBeforeUnmount(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
function onMousedown(evt: Event) {
|
function onMousedown(evt: Event) {
|
||||||
if (!contains(rootEl, evt.target) && rootEl !== evt.target) emit("closed");
|
if (!contains(rootEl.value, evt.target) && rootEl.value !== evt.target)
|
||||||
|
emit("closed");
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
import type * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import Cropper from "cropperjs";
|
import Cropper from "cropperjs";
|
||||||
import tinycolor from "tinycolor2";
|
import tinycolor from "tinycolor2";
|
||||||
|
@ -62,10 +62,10 @@ const props = defineProps<{
|
||||||
const imgUrl = `${url}/proxy/image.webp?${query({
|
const imgUrl = `${url}/proxy/image.webp?${query({
|
||||||
url: props.file.url,
|
url: props.file.url,
|
||||||
})}`;
|
})}`;
|
||||||
const dialogEl = $ref<InstanceType<typeof XModalWindow>>();
|
const dialogEl = ref<InstanceType<typeof XModalWindow>>();
|
||||||
const imgEl = $ref<HTMLImageElement>();
|
const imgEl = ref<HTMLImageElement>();
|
||||||
let cropper: Cropper | null = null,
|
let cropper: Cropper | null = null,
|
||||||
loading = $ref(true);
|
loading = ref(true);
|
||||||
|
|
||||||
const ok = async () => {
|
const ok = async () => {
|
||||||
const promise = new Promise<misskey.entities.DriveFile>(async (res) => {
|
const promise = new Promise<misskey.entities.DriveFile>(async (res) => {
|
||||||
|
@ -96,16 +96,16 @@ const ok = async () => {
|
||||||
const f = await promise;
|
const f = await promise;
|
||||||
|
|
||||||
emit("ok", f);
|
emit("ok", f);
|
||||||
dialogEl.close();
|
dialogEl.value.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
emit("cancel");
|
emit("cancel");
|
||||||
dialogEl.close();
|
dialogEl.value.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onImageLoad = () => {
|
const onImageLoad = () => {
|
||||||
loading = false;
|
loading.value = false;
|
||||||
|
|
||||||
if (cropper) {
|
if (cropper) {
|
||||||
cropper.getCropperImage()!.$center("contain");
|
cropper.getCropperImage()!.$center("contain");
|
||||||
|
@ -114,7 +114,7 @@ const onImageLoad = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
cropper = new Cropper(imgEl, {});
|
cropper = new Cropper(imgEl.value, {});
|
||||||
|
|
||||||
const computedStyle = getComputedStyle(document.documentElement);
|
const computedStyle = getComputedStyle(document.documentElement);
|
||||||
|
|
||||||
|
|
|
@ -199,7 +199,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onBeforeUnmount, onMounted, ref, shallowRef } from "vue";
|
import { onBeforeUnmount, onMounted, ref, shallowRef, computed } from "vue";
|
||||||
import * as Acct from "firefish-js/built/acct";
|
import * as Acct from "firefish-js/built/acct";
|
||||||
import MkModal from "@/components/MkModal.vue";
|
import MkModal from "@/components/MkModal.vue";
|
||||||
import MkButton from "@/components/MkButton.vue";
|
import MkButton from "@/components/MkButton.vue";
|
||||||
|
@ -281,17 +281,15 @@ const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
const inputValue = ref<string | number | null>(props.input?.default ?? null);
|
const inputValue = ref<string | number | null>(props.input?.default ?? null);
|
||||||
const selectedValue = ref(props.select?.default ?? null);
|
const selectedValue = ref(props.select?.default ?? null);
|
||||||
|
|
||||||
let disabledReason = $ref<null | "charactersExceeded" | "charactersBelow">(
|
let disabledReason = ref<null | "charactersExceeded" | "charactersBelow">(null);
|
||||||
null,
|
const okButtonDisabled = computed<boolean>(() => {
|
||||||
);
|
|
||||||
const okButtonDisabled = $computed<boolean>(() => {
|
|
||||||
if (props.input) {
|
if (props.input) {
|
||||||
if (props.input.minLength) {
|
if (props.input.minLength) {
|
||||||
if (
|
if (
|
||||||
(inputValue.value || inputValue.value === "") &&
|
(inputValue.value || inputValue.value === "") &&
|
||||||
(inputValue.value as string).length < props.input.minLength
|
(inputValue.value as string).length < props.input.minLength
|
||||||
) {
|
) {
|
||||||
disabledReason = "charactersBelow";
|
disabledReason.value = "charactersBelow";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -300,7 +298,7 @@ const okButtonDisabled = $computed<boolean>(() => {
|
||||||
inputValue.value &&
|
inputValue.value &&
|
||||||
(inputValue.value as string).length > props.input.maxLength
|
(inputValue.value as string).length > props.input.maxLength
|
||||||
) {
|
) {
|
||||||
disabledReason = "charactersExceeded";
|
disabledReason.value = "charactersExceeded";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onBeforeUnmount, onMounted } from "vue";
|
import { computed, onBeforeUnmount, onMounted, ref } from "vue";
|
||||||
import type * as Misskey from "firefish-js";
|
import type * as Misskey from "firefish-js";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
import { stream } from "@/stream";
|
import { stream } from "@/stream";
|
||||||
|
@ -89,13 +89,13 @@ const props = withDefaults(
|
||||||
|
|
||||||
const isBlocking = computed(() => props.user.isBlocking);
|
const isBlocking = computed(() => props.user.isBlocking);
|
||||||
|
|
||||||
let state = $ref(i18n.ts.processing);
|
let state = ref(i18n.ts.processing);
|
||||||
|
|
||||||
let isFollowing = $ref(props.user.isFollowing);
|
let isFollowing = ref(props.user.isFollowing);
|
||||||
let hasPendingFollowRequestFromYou = $ref(
|
let hasPendingFollowRequestFromYou = ref(
|
||||||
props.user.hasPendingFollowRequestFromYou,
|
props.user.hasPendingFollowRequestFromYou,
|
||||||
);
|
);
|
||||||
let wait = $ref(false);
|
let wait = ref(false);
|
||||||
const connection = stream.useChannel("main");
|
const connection = stream.useChannel("main");
|
||||||
|
|
||||||
const hideFollowButton = props.hideFollowButton ?? false;
|
const hideFollowButton = props.hideFollowButton ?? false;
|
||||||
|
@ -108,13 +108,14 @@ if (props.user.isFollowing == null) {
|
||||||
|
|
||||||
function onFollowChange(user: Misskey.entities.UserDetailed) {
|
function onFollowChange(user: Misskey.entities.UserDetailed) {
|
||||||
if (user.id === props.user.id) {
|
if (user.id === props.user.id) {
|
||||||
isFollowing = user.isFollowing;
|
isFollowing.value = user.isFollowing;
|
||||||
hasPendingFollowRequestFromYou = user.hasPendingFollowRequestFromYou;
|
hasPendingFollowRequestFromYou.value =
|
||||||
|
user.hasPendingFollowRequestFromYou;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onClick() {
|
async function onClick() {
|
||||||
wait = true;
|
wait.value = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (isBlocking.value) {
|
if (isBlocking.value) {
|
||||||
|
@ -133,7 +134,7 @@ async function onClick() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
emit("refresh");
|
emit("refresh");
|
||||||
} else if (isFollowing) {
|
} else if (isFollowing.value) {
|
||||||
const { canceled } = await os.confirm({
|
const { canceled } = await os.confirm({
|
||||||
type: "warning",
|
type: "warning",
|
||||||
text: i18n.t("unfollowConfirm", {
|
text: i18n.t("unfollowConfirm", {
|
||||||
|
@ -147,22 +148,22 @@ async function onClick() {
|
||||||
userId: props.user.id,
|
userId: props.user.id,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (hasPendingFollowRequestFromYou) {
|
if (hasPendingFollowRequestFromYou.value) {
|
||||||
await os.api("following/requests/cancel", {
|
await os.api("following/requests/cancel", {
|
||||||
userId: props.user.id,
|
userId: props.user.id,
|
||||||
});
|
});
|
||||||
hasPendingFollowRequestFromYou = false;
|
hasPendingFollowRequestFromYou.value = false;
|
||||||
} else {
|
} else {
|
||||||
await os.api("following/create", {
|
await os.api("following/create", {
|
||||||
userId: props.user.id,
|
userId: props.user.id,
|
||||||
});
|
});
|
||||||
hasPendingFollowRequestFromYou = true;
|
hasPendingFollowRequestFromYou.value = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
} finally {
|
} finally {
|
||||||
wait = false;
|
wait.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
import {} from "vue";
|
import {} from "vue";
|
||||||
import XModalWindow from "@/components/MkModalWindow.vue";
|
import XModalWindow from "@/components/MkModalWindow.vue";
|
||||||
import MkButton from "@/components/MkButton.vue";
|
import MkButton from "@/components/MkButton.vue";
|
||||||
|
@ -75,20 +77,20 @@ const emit = defineEmits<{
|
||||||
(ev: "closed"): void;
|
(ev: "closed"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let dialog: InstanceType<typeof XModalWindow> = $ref();
|
let dialog: InstanceType<typeof XModalWindow> = ref();
|
||||||
|
|
||||||
let username = $ref("");
|
let username = ref("");
|
||||||
let email = $ref("");
|
let email = ref("");
|
||||||
let processing = $ref(false);
|
let processing = ref(false);
|
||||||
|
|
||||||
async function onSubmit() {
|
async function onSubmit() {
|
||||||
processing = true;
|
processing.value = true;
|
||||||
await os.apiWithDialog("request-reset-password", {
|
await os.apiWithDialog("request-reset-password", {
|
||||||
username,
|
username: username.value,
|
||||||
email,
|
email: email.value,
|
||||||
});
|
});
|
||||||
emit("done");
|
emit("done");
|
||||||
dialog.close();
|
dialog.value.close();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, nextTick, watch } from "vue";
|
import { onMounted, nextTick, watch, shallowRef, ref } from "vue";
|
||||||
import { Chart } from "chart.js";
|
import { Chart } from "chart.js";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
|
@ -23,11 +23,11 @@ const props = defineProps<{
|
||||||
src: string;
|
src: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const rootEl = $shallowRef<HTMLDivElement>(null);
|
const rootEl = shallowRef<HTMLDivElement>(null);
|
||||||
const chartEl = $shallowRef<HTMLCanvasElement>(null);
|
const chartEl = shallowRef<HTMLCanvasElement>(null);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
let chartInstance: Chart = null;
|
let chartInstance: Chart = null;
|
||||||
let fetching = $ref(true);
|
let fetching = ref(true);
|
||||||
|
|
||||||
const { handler: externalTooltipHandler } = useChartTooltip({
|
const { handler: externalTooltipHandler } = useChartTooltip({
|
||||||
position: "middle",
|
position: "middle",
|
||||||
|
@ -43,8 +43,8 @@ async function renderChart() {
|
||||||
chartInstance.destroy();
|
chartInstance.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
const wide = rootEl.offsetWidth > 700;
|
const wide = rootEl.value.offsetWidth > 700;
|
||||||
const narrow = rootEl.offsetWidth < 400;
|
const narrow = rootEl.value.offsetWidth < 400;
|
||||||
|
|
||||||
const weeks = wide ? 50 : narrow ? 10 : 25;
|
const weeks = wide ? 50 : narrow ? 10 : 25;
|
||||||
const chartLimit = 7 * weeks;
|
const chartLimit = 7 * weeks;
|
||||||
|
@ -113,7 +113,7 @@ async function renderChart() {
|
||||||
values = addArrays(raw.diffs.normal, raw.diffs.reply, raw.diffs.renote);
|
values = addArrays(raw.diffs.normal, raw.diffs.reply, raw.diffs.renote);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetching = false;
|
fetching.value = false;
|
||||||
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ async function renderChart() {
|
||||||
|
|
||||||
const marginEachCell = 4;
|
const marginEachCell = 4;
|
||||||
|
|
||||||
chartInstance = new Chart(chartEl, {
|
chartInstance = new Chart(chartEl.value, {
|
||||||
type: "matrix",
|
type: "matrix",
|
||||||
data: {
|
data: {
|
||||||
datasets: [
|
datasets: [
|
||||||
|
@ -247,7 +247,7 @@ async function renderChart() {
|
||||||
watch(
|
watch(
|
||||||
() => props.src,
|
() => props.src,
|
||||||
() => {
|
() => {
|
||||||
fetching = true;
|
fetching.value = true;
|
||||||
renderChart();
|
renderChart();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
import {} from "vue";
|
import {} from "vue";
|
||||||
import type * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import bytes from "@/filters/bytes";
|
import bytes from "@/filters/bytes";
|
||||||
|
@ -43,7 +45,7 @@ const emit = defineEmits<{
|
||||||
(ev: "closed"): void;
|
(ev: "closed"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const modal = $ref<InstanceType<typeof MkModal>>();
|
const modal = ref<InstanceType<typeof MkModal>>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
import { decodeBlurHash } from "fast-blurhash";
|
import { decodeBlurHash } from "fast-blurhash";
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
|
@ -48,20 +48,20 @@ const props = withDefaults(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const canvas = $ref<HTMLCanvasElement>();
|
const canvas = ref<HTMLCanvasElement>();
|
||||||
let loaded = $ref(false);
|
let loaded = ref(false);
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
if (props.hash == null || canvas == null) return;
|
if (props.hash == null || canvas.value == null) return;
|
||||||
const pixels = decodeBlurHash(props.hash, props.size, props.size);
|
const pixels = decodeBlurHash(props.hash, props.size, props.size);
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.value.getContext("2d");
|
||||||
const imageData = ctx!.createImageData(props.size, props.size);
|
const imageData = ctx!.createImageData(props.size, props.size);
|
||||||
imageData.data.set(pixels);
|
imageData.data.set(pixels);
|
||||||
ctx!.putImageData(imageData, 0, 0);
|
ctx!.putImageData(imageData, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onLoad() {
|
function onLoad() {
|
||||||
loaded = true;
|
loaded.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
import * as firefish from "firefish-js";
|
import * as firefish from "firefish-js";
|
||||||
import MkMiniChart from "@/components/MkMiniChart.vue";
|
import MkMiniChart from "@/components/MkMiniChart.vue";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
|
@ -33,7 +35,7 @@ const props = defineProps<{
|
||||||
instance: firefish.entities.Instance;
|
instance: firefish.entities.Instance;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let chartValues = $ref<number[] | null>(null);
|
let chartValues = ref<number[] | null>(null);
|
||||||
|
|
||||||
os.apiGet("charts/instance", {
|
os.apiGet("charts/instance", {
|
||||||
host: props.instance.host,
|
host: props.instance.host,
|
||||||
|
@ -42,7 +44,7 @@ os.apiGet("charts/instance", {
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
// 今日のぶんの値はまだ途中の値であり、それも含めると大抵の場合前日よりも下降しているようなグラフになってしまうため今日は弾く
|
// 今日のぶんの値はまだ途中の値であり、それも含めると大抵の場合前日よりも下降しているようなグラフになってしまうため今日は弾く
|
||||||
res.requests.received.splice(0, 1);
|
res.requests.received.splice(0, 1);
|
||||||
chartValues = res.requests.received;
|
chartValues.value = res.requests.received;
|
||||||
});
|
});
|
||||||
|
|
||||||
function getInstanceIcon(instance): string {
|
function getInstanceIcon(instance): string {
|
||||||
|
|
|
@ -56,6 +56,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
import MkInput from "@/components/form/input.vue";
|
import MkInput from "@/components/form/input.vue";
|
||||||
import XModalWindow from "@/components/MkModalWindow.vue";
|
import XModalWindow from "@/components/MkModalWindow.vue";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
|
@ -68,28 +70,28 @@ const emit = defineEmits<{
|
||||||
(ev: "closed"): void;
|
(ev: "closed"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let hostname = $ref("");
|
let hostname = ref("");
|
||||||
let instances: Instance[] = $ref([]);
|
let instances: Instance[] = ref([]);
|
||||||
let selected: Instance | null = $ref(null);
|
let selected: Instance | null = ref(null);
|
||||||
let dialogEl = $ref<InstanceType<typeof XModalWindow>>();
|
let dialogEl = ref<InstanceType<typeof XModalWindow>>();
|
||||||
|
|
||||||
let searchOrderLatch = 0;
|
let searchOrderLatch = 0;
|
||||||
const search = () => {
|
const search = () => {
|
||||||
if (hostname === "") {
|
if (hostname.value === "") {
|
||||||
instances = [];
|
instances.value = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchId = ++searchOrderLatch;
|
const searchId = ++searchOrderLatch;
|
||||||
os.api("federation/instances", {
|
os.api("federation/instances", {
|
||||||
host: hostname,
|
host: hostname.value,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
blocked: false,
|
blocked: false,
|
||||||
suspended: false,
|
suspended: false,
|
||||||
sort: "+pubSub",
|
sort: "+pubSub",
|
||||||
}).then((_instances) => {
|
}).then((_instances) => {
|
||||||
if (searchId !== searchOrderLatch) return;
|
if (searchId !== searchOrderLatch) return;
|
||||||
instances = _instances.map(
|
instances.value = _instances.map(
|
||||||
(x) =>
|
(x) =>
|
||||||
({
|
({
|
||||||
id: x.id,
|
id: x.id,
|
||||||
|
@ -101,14 +103,14 @@ const search = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const ok = () => {
|
const ok = () => {
|
||||||
if (selected == null) return;
|
if (selected.value == null) return;
|
||||||
emit("ok", selected);
|
emit("ok", selected.value);
|
||||||
dialogEl?.close();
|
dialogEl.value?.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
emit("cancel");
|
emit("cancel");
|
||||||
dialogEl?.close();
|
dialogEl.value?.close();
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted } from "vue";
|
import { onMounted, ref, shallowRef } from "vue";
|
||||||
import { Chart } from "chart.js";
|
import { Chart } from "chart.js";
|
||||||
import MkSelect from "@/components/form/select.vue";
|
import MkSelect from "@/components/form/select.vue";
|
||||||
import MkChart from "@/components/MkChart.vue";
|
import MkChart from "@/components/MkChart.vue";
|
||||||
|
@ -116,11 +116,11 @@ import { initChart } from "@/scripts/init-chart";
|
||||||
initChart();
|
initChart();
|
||||||
|
|
||||||
const chartLimit = 500;
|
const chartLimit = 500;
|
||||||
let chartSpan = $ref<"hour" | "day">("hour");
|
let chartSpan = ref<"hour" | "day">("hour");
|
||||||
let chartSrc = $ref("active-users");
|
let chartSrc = ref("active-users");
|
||||||
let heatmapSrc = $ref("active-users");
|
let heatmapSrc = ref("active-users");
|
||||||
let subDoughnutEl = $shallowRef<HTMLCanvasElement>();
|
let subDoughnutEl = shallowRef<HTMLCanvasElement>();
|
||||||
let pubDoughnutEl = $shallowRef<HTMLCanvasElement>();
|
let pubDoughnutEl = shallowRef<HTMLCanvasElement>();
|
||||||
|
|
||||||
const { handler: externalTooltipHandler1 } = useChartTooltip({
|
const { handler: externalTooltipHandler1 } = useChartTooltip({
|
||||||
position: "middle",
|
position: "middle",
|
||||||
|
@ -189,7 +189,7 @@ function createDoughnut(chartEl, tooltip, data) {
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
os.apiGet("federation/stats", { limit: 30 }).then((fedStats) => {
|
os.apiGet("federation/stats", { limit: 30 }).then((fedStats) => {
|
||||||
createDoughnut(
|
createDoughnut(
|
||||||
subDoughnutEl,
|
subDoughnutEl.value,
|
||||||
externalTooltipHandler1,
|
externalTooltipHandler1,
|
||||||
fedStats.topSubInstances
|
fedStats.topSubInstances
|
||||||
.map((x) => ({
|
.map((x) => ({
|
||||||
|
@ -210,7 +210,7 @@ onMounted(() => {
|
||||||
);
|
);
|
||||||
|
|
||||||
createDoughnut(
|
createDoughnut(
|
||||||
pubDoughnutEl,
|
pubDoughnutEl.value,
|
||||||
externalTooltipHandler2,
|
externalTooltipHandler2,
|
||||||
fedStats.topPubInstances
|
fedStats.topPubInstances
|
||||||
.map((x) => ({
|
.map((x) => ({
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
import { instanceName, version } from "@/config";
|
import { instanceName, version } from "@/config";
|
||||||
import { instance as Instance } from "@/instance";
|
import { instance as Instance } from "@/instance";
|
||||||
import { getProxiedImageUrlNullable } from "@/scripts/media-proxy";
|
import { getProxiedImageUrlNullable } from "@/scripts/media-proxy";
|
||||||
|
@ -27,7 +29,7 @@ const props = defineProps<{
|
||||||
};
|
};
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let ticker = $ref<HTMLElement | null>(null);
|
let ticker = ref<HTMLElement | null>(null);
|
||||||
|
|
||||||
// if no instance data is given, this is for the local instance
|
// if no instance data is given, this is for the local instance
|
||||||
const instance = props.instance ?? {
|
const instance = props.instance ?? {
|
||||||
|
@ -46,12 +48,15 @@ const commonNames = new Map<string, string>([
|
||||||
["birdsitelive", "BirdsiteLIVE"],
|
["birdsitelive", "BirdsiteLIVE"],
|
||||||
["bookwyrm", "BookWyrm"],
|
["bookwyrm", "BookWyrm"],
|
||||||
["bridgy-fed", "Bridgy Fed"],
|
["bridgy-fed", "Bridgy Fed"],
|
||||||
|
["castopod", "CastoPod"],
|
||||||
["foundkey", "FoundKey"],
|
["foundkey", "FoundKey"],
|
||||||
["gnusocial", "GNU social"],
|
["gnusocial", "GNU social"],
|
||||||
["gotosocial", "GoToSocial"],
|
["gotosocial", "GoToSocial"],
|
||||||
|
["kbin", "/kbin"],
|
||||||
["microblogpub", "microblog.pub"],
|
["microblogpub", "microblog.pub"],
|
||||||
["nextcloud social", "Nextcloud Social"],
|
["nextcloud social", "Nextcloud Social"],
|
||||||
["peertube", "PeerTube"],
|
["peertube", "PeerTube"],
|
||||||
|
["reel2bits", "reel2bits"],
|
||||||
["snac", "snac"],
|
["snac", "snac"],
|
||||||
["snac2", "snac2"],
|
["snac2", "snac2"],
|
||||||
["takahe", "Takahē"],
|
["takahe", "Takahē"],
|
||||||
|
|
|
@ -62,6 +62,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
import MkModal from "@/components/MkModal.vue";
|
import MkModal from "@/components/MkModal.vue";
|
||||||
import { navbarItemDef } from "@/navbar";
|
import { navbarItemDef } from "@/navbar";
|
||||||
import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
|
@ -89,7 +91,7 @@ const preferedModalType =
|
||||||
? "drawer"
|
? "drawer"
|
||||||
: "dialog";
|
: "dialog";
|
||||||
|
|
||||||
const modal = $ref<InstanceType<typeof MkModal>>();
|
const modal = ref<InstanceType<typeof MkModal>>();
|
||||||
|
|
||||||
const menu = defaultStore.state.menu;
|
const menu = defaultStore.state.menu;
|
||||||
|
|
||||||
|
@ -107,7 +109,7 @@ const items = Object.keys(navbarItemDef)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
modal.close();
|
modal.value.close();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineAsyncComponent } from "vue";
|
import { defineAsyncComponent, ref } from "vue";
|
||||||
import { url as local } from "@/config";
|
import { url as local } from "@/config";
|
||||||
import { useTooltip } from "@/scripts/use-tooltip";
|
import { useTooltip } from "@/scripts/use-tooltip";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
|
@ -35,9 +35,9 @@ const self = props.url.startsWith(local);
|
||||||
const attr = self ? "to" : "href";
|
const attr = self ? "to" : "href";
|
||||||
const target = self ? null : "_blank";
|
const target = self ? null : "_blank";
|
||||||
|
|
||||||
const el = $ref();
|
const el = ref();
|
||||||
|
|
||||||
useTooltip($$(el), (showing) => {
|
useTooltip(el, (showing) => {
|
||||||
os.popup(
|
os.popup(
|
||||||
defineAsyncComponent(
|
defineAsyncComponent(
|
||||||
() => import("@/components/MkUrlPreviewPopup.vue"),
|
() => import("@/components/MkUrlPreviewPopup.vue"),
|
||||||
|
@ -45,7 +45,7 @@ useTooltip($$(el), (showing) => {
|
||||||
{
|
{
|
||||||
showing,
|
showing,
|
||||||
url: props.url,
|
url: props.url,
|
||||||
source: el,
|
source: el.value,
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
"closed",
|
"closed",
|
||||||
|
|
|
@ -104,7 +104,7 @@ const props = defineProps<{
|
||||||
raw?: boolean;
|
raw?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let hide = $ref(true);
|
let hide = ref(true);
|
||||||
|
|
||||||
const plyr = ref();
|
const plyr = ref();
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ function captionPopup() {
|
||||||
watch(
|
watch(
|
||||||
() => props.media,
|
() => props.media,
|
||||||
() => {
|
() => {
|
||||||
hide =
|
hide.value =
|
||||||
defaultStore.state.nsfw === "force"
|
defaultStore.state.nsfw === "force"
|
||||||
? true
|
? true
|
||||||
: props.media.isSensitive &&
|
: props.media.isSensitive &&
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
import VuePlyr from "vue-plyr";
|
import VuePlyr from "vue-plyr";
|
||||||
import type * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import { ColdDeviceStorage } from "@/store";
|
import { ColdDeviceStorage } from "@/store";
|
||||||
|
@ -70,15 +70,17 @@ const props = withDefaults(
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
const audioEl = $ref<HTMLAudioElement | null>();
|
const audioEl = ref<HTMLAudioElement | null>();
|
||||||
let hide = $ref(true);
|
let hide = ref(true);
|
||||||
|
|
||||||
function volumechange() {
|
function volumechange() {
|
||||||
if (audioEl) ColdDeviceStorage.set("mediaVolume", audioEl.volume);
|
if (audioEl.value)
|
||||||
|
ColdDeviceStorage.set("mediaVolume", audioEl.value.volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (audioEl) audioEl.volume = ColdDeviceStorage.get("mediaVolume");
|
if (audioEl.value)
|
||||||
|
audioEl.value.volume = ColdDeviceStorage.get("mediaVolume");
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -233,13 +233,13 @@ const emit = defineEmits<{
|
||||||
(ev: "close", actioned?: boolean): void;
|
(ev: "close", actioned?: boolean): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let itemsEl = $ref<HTMLDivElement>();
|
let itemsEl = ref<HTMLDivElement>();
|
||||||
|
|
||||||
let items2: InnerMenuItem[] = $ref([]);
|
let items2: InnerMenuItem[] = ref([]);
|
||||||
|
|
||||||
let child = $ref<InstanceType<typeof XChild>>();
|
let child = ref<InstanceType<typeof XChild>>();
|
||||||
|
|
||||||
let childShowingItem = $ref<MenuItem | null>();
|
let childShowingItem = ref<MenuItem | null>();
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.items,
|
() => props.items,
|
||||||
|
@ -255,24 +255,24 @@ watch(
|
||||||
// if item is Promise
|
// if item is Promise
|
||||||
items[i] = { type: "pending" };
|
items[i] = { type: "pending" };
|
||||||
item.then((actualItem) => {
|
item.then((actualItem) => {
|
||||||
items2[i] = actualItem;
|
items2.value[i] = actualItem;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
items2 = items as InnerMenuItem[];
|
items2.value = items as InnerMenuItem[];
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
immediate: true,
|
immediate: true,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let childMenu = $ref<MenuItem[] | null>();
|
let childMenu = ref<MenuItem[] | null>();
|
||||||
let childTarget = $ref<HTMLElement | null>();
|
let childTarget = ref<HTMLElement | null>();
|
||||||
|
|
||||||
function closeChild() {
|
function closeChild() {
|
||||||
childMenu = null;
|
childMenu.value = null;
|
||||||
childShowingItem = null;
|
childShowingItem.value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function childActioned() {
|
function childActioned() {
|
||||||
|
@ -282,11 +282,12 @@ function childActioned() {
|
||||||
|
|
||||||
function onGlobalMousedown(event: MouseEvent) {
|
function onGlobalMousedown(event: MouseEvent) {
|
||||||
if (
|
if (
|
||||||
childTarget &&
|
childTarget.value &&
|
||||||
(event.target === childTarget || childTarget.contains(event.target))
|
(event.target === childTarget.value ||
|
||||||
|
childTarget.value.contains(event.target))
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
if (child && child.checkHit(event)) return;
|
if (child.value && child.value.checkHit(event)) return;
|
||||||
closeChild();
|
closeChild();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,9 +306,9 @@ async function showChildren(item: MenuItem, ev: MouseEvent) {
|
||||||
os.popupMenu(item.children, ev.currentTarget ?? ev.target);
|
os.popupMenu(item.children, ev.currentTarget ?? ev.target);
|
||||||
close();
|
close();
|
||||||
} else {
|
} else {
|
||||||
childTarget = ev.currentTarget ?? ev.target;
|
childTarget.value = ev.currentTarget ?? ev.target;
|
||||||
childMenu = item.children;
|
childMenu.value = item.children;
|
||||||
childShowingItem = item;
|
childShowingItem.value = item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { watch } from "vue";
|
import { watch, ref } from "vue";
|
||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
import tinycolor from "tinycolor2";
|
import tinycolor from "tinycolor2";
|
||||||
import { useInterval } from "@/scripts/use-interval";
|
import { useInterval } from "@/scripts/use-interval";
|
||||||
|
@ -37,10 +37,10 @@ const props = defineProps<{
|
||||||
const viewBoxX = 50;
|
const viewBoxX = 50;
|
||||||
const viewBoxY = 50;
|
const viewBoxY = 50;
|
||||||
const gradientId = uuid();
|
const gradientId = uuid();
|
||||||
let polylinePoints = $ref("");
|
let polylinePoints = ref("");
|
||||||
let polygonPoints = $ref("");
|
let polygonPoints = ref("");
|
||||||
let headX = $ref<number | null>(null);
|
let headX = ref<number | null>(null);
|
||||||
let headY = $ref<number | null>(null);
|
let headY = ref<number | null>(null);
|
||||||
const accent = tinycolor(
|
const accent = tinycolor(
|
||||||
getComputedStyle(document.documentElement).getPropertyValue("--accent"),
|
getComputedStyle(document.documentElement).getPropertyValue("--accent"),
|
||||||
);
|
);
|
||||||
|
@ -55,12 +55,14 @@ function draw(): void {
|
||||||
(1 - n / peak) * viewBoxY,
|
(1 - n / peak) * viewBoxY,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
polylinePoints = _polylinePoints.map((xy) => `${xy[0]},${xy[1]}`).join(" ");
|
polylinePoints.value = _polylinePoints
|
||||||
|
.map((xy) => `${xy[0]},${xy[1]}`)
|
||||||
|
.join(" ");
|
||||||
|
|
||||||
polygonPoints = `0,${viewBoxY} ${polylinePoints} ${viewBoxX},${viewBoxY}`;
|
polygonPoints.value = `0,${viewBoxY} ${polylinePoints.value} ${viewBoxX},${viewBoxY}`;
|
||||||
|
|
||||||
headX = _polylinePoints[_polylinePoints.length - 1][0];
|
headX.value = _polylinePoints[_polylinePoints.length - 1][0];
|
||||||
headY = _polylinePoints[_polylinePoints.length - 1][1];
|
headY.value = _polylinePoints[_polylinePoints.length - 1][1];
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => props.src, draw, { immediate: true });
|
watch(() => props.src, draw, { immediate: true });
|
||||||
|
|
|
@ -77,7 +77,16 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, onMounted, watch, provide, onUnmounted } from "vue";
|
import {
|
||||||
|
nextTick,
|
||||||
|
onMounted,
|
||||||
|
watch,
|
||||||
|
provide,
|
||||||
|
onUnmounted,
|
||||||
|
ref,
|
||||||
|
shallowRef,
|
||||||
|
computed,
|
||||||
|
} from "vue";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
import { isTouchUsing } from "@/scripts/touch";
|
import { isTouchUsing } from "@/scripts/touch";
|
||||||
import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
|
@ -130,14 +139,14 @@ const emit = defineEmits<{
|
||||||
|
|
||||||
provide("modal", true);
|
provide("modal", true);
|
||||||
|
|
||||||
let maxHeight = $ref<number>();
|
let maxHeight = ref<number>();
|
||||||
let fixed = $ref(false);
|
let fixed = ref(false);
|
||||||
let transformOrigin = $ref("center");
|
let transformOrigin = ref("center");
|
||||||
let showing = $ref(true);
|
let showing = ref(true);
|
||||||
let content = $shallowRef<HTMLElement>();
|
let content = shallowRef<HTMLElement>();
|
||||||
const zIndex = os.claimZIndex(props.zPriority);
|
const zIndex = os.claimZIndex(props.zPriority);
|
||||||
let useSendAnime = $ref(false);
|
let useSendAnime = ref(false);
|
||||||
const type = $computed<ModalTypes>(() => {
|
const type = computed<ModalTypes>(() => {
|
||||||
if (props.preferType === "auto") {
|
if (props.preferType === "auto") {
|
||||||
if (
|
if (
|
||||||
!defaultStore.state.disableDrawer &&
|
!defaultStore.state.disableDrawer &&
|
||||||
|
@ -152,28 +161,28 @@ const type = $computed<ModalTypes>(() => {
|
||||||
return props.preferType!;
|
return props.preferType!;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const isEnableBgTransparent = $computed(
|
const isEnableBgTransparent = computed(
|
||||||
() => props.transparentBg && type === "popup",
|
() => props.transparentBg && type.value === "popup",
|
||||||
);
|
);
|
||||||
let transitionName = $computed(() =>
|
let transitionName = computed(() =>
|
||||||
defaultStore.state.animation
|
defaultStore.state.animation
|
||||||
? useSendAnime
|
? useSendAnime.value
|
||||||
? "send"
|
? "send"
|
||||||
: type === "drawer"
|
: type.value === "drawer"
|
||||||
? "modal-drawer"
|
? "modal-drawer"
|
||||||
: type === "popup"
|
: type.value === "popup"
|
||||||
? "modal-popup"
|
? "modal-popup"
|
||||||
: "modal"
|
: "modal"
|
||||||
: "",
|
: "",
|
||||||
);
|
);
|
||||||
let transitionDuration = $computed(() =>
|
let transitionDuration = computed(() =>
|
||||||
transitionName === "send"
|
transitionName.value === "send"
|
||||||
? 400
|
? 400
|
||||||
: transitionName === "modal-popup"
|
: transitionName.value === "modal-popup"
|
||||||
? 100
|
? 100
|
||||||
: transitionName === "modal"
|
: transitionName.value === "modal"
|
||||||
? 200
|
? 200
|
||||||
: transitionName === "modal-drawer"
|
: transitionName.value === "modal-drawer"
|
||||||
? 200
|
? 200
|
||||||
: 0,
|
: 0,
|
||||||
);
|
);
|
||||||
|
@ -187,12 +196,12 @@ function close(ev, opts: { useSendAnimation?: boolean } = {}) {
|
||||||
// history.forward();
|
// history.forward();
|
||||||
// }
|
// }
|
||||||
if (opts.useSendAnimation) {
|
if (opts.useSendAnimation) {
|
||||||
useSendAnime = true;
|
useSendAnime.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line vue/no-mutating-props
|
// eslint-disable-next-line vue/no-mutating-props
|
||||||
if (props.src) props.src.style.pointerEvents = "auto";
|
if (props.src) props.src.style.pointerEvents = "auto";
|
||||||
showing = false;
|
showing.value = false;
|
||||||
emit("close");
|
emit("close");
|
||||||
if (!props.noReturnFocus) {
|
if (!props.noReturnFocus) {
|
||||||
focusedElement.focus();
|
focusedElement.focus();
|
||||||
|
@ -204,8 +213,8 @@ function onBgClick() {
|
||||||
emit("click");
|
emit("click");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === "drawer") {
|
if (type.value === "drawer") {
|
||||||
maxHeight = window.innerHeight / 1.5;
|
maxHeight.value = window.innerHeight / 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keymap = {
|
const keymap = {
|
||||||
|
@ -216,21 +225,21 @@ const MARGIN = 16;
|
||||||
|
|
||||||
const align = () => {
|
const align = () => {
|
||||||
if (props.src == null) return;
|
if (props.src == null) return;
|
||||||
if (type === "drawer") return;
|
if (type.value === "drawer") return;
|
||||||
if (type === "dialog") return;
|
if (type.value === "dialog") return;
|
||||||
|
|
||||||
if (content == null) return;
|
if (content.value == null) return;
|
||||||
|
|
||||||
const srcRect = props.src.getBoundingClientRect();
|
const srcRect = props.src.getBoundingClientRect();
|
||||||
|
|
||||||
const width = content!.offsetWidth;
|
const width = content.value!.offsetWidth;
|
||||||
const height = content!.offsetHeight;
|
const height = content.value!.offsetHeight;
|
||||||
|
|
||||||
let left;
|
let left;
|
||||||
let top;
|
let top;
|
||||||
|
|
||||||
const x = srcRect.left + (fixed ? 0 : window.pageXOffset);
|
const x = srcRect.left + (fixed.value ? 0 : window.pageXOffset);
|
||||||
const y = srcRect.top + (fixed ? 0 : window.pageYOffset);
|
const y = srcRect.top + (fixed.value ? 0 : window.pageYOffset);
|
||||||
|
|
||||||
if (props.anchor.x === "center") {
|
if (props.anchor.x === "center") {
|
||||||
left = x + props.src.offsetWidth / 2 - width / 2;
|
left = x + props.src.offsetWidth / 2 - width / 2;
|
||||||
|
@ -248,7 +257,7 @@ const align = () => {
|
||||||
top = y + props.src.offsetHeight;
|
top = y + props.src.offsetHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fixed) {
|
if (fixed.value) {
|
||||||
// 画面から横にはみ出る場合
|
// 画面から横にはみ出る場合
|
||||||
if (left + width > window.innerWidth) {
|
if (left + width > window.innerWidth) {
|
||||||
left = window.innerWidth - width;
|
left = window.innerWidth - width;
|
||||||
|
@ -261,16 +270,16 @@ const align = () => {
|
||||||
if (top + height > window.innerHeight - MARGIN) {
|
if (top + height > window.innerHeight - MARGIN) {
|
||||||
if (props.noOverlap && props.anchor.x === "center") {
|
if (props.noOverlap && props.anchor.x === "center") {
|
||||||
if (underSpace >= upperSpace / 3) {
|
if (underSpace >= upperSpace / 3) {
|
||||||
maxHeight = underSpace;
|
maxHeight.value = underSpace;
|
||||||
} else {
|
} else {
|
||||||
maxHeight = upperSpace;
|
maxHeight.value = upperSpace;
|
||||||
top = upperSpace + MARGIN - height;
|
top = upperSpace + MARGIN - height;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
top = window.innerHeight - MARGIN - height;
|
top = window.innerHeight - MARGIN - height;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
maxHeight = underSpace;
|
maxHeight.value = underSpace;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 画面から横にはみ出る場合
|
// 画面から横にはみ出る場合
|
||||||
|
@ -286,9 +295,9 @@ const align = () => {
|
||||||
if (top + height - window.scrollY > window.innerHeight - MARGIN) {
|
if (top + height - window.scrollY > window.innerHeight - MARGIN) {
|
||||||
if (props.noOverlap && props.anchor.x === "center") {
|
if (props.noOverlap && props.anchor.x === "center") {
|
||||||
if (underSpace >= upperSpace / 3) {
|
if (underSpace >= upperSpace / 3) {
|
||||||
maxHeight = underSpace;
|
maxHeight.value = underSpace;
|
||||||
} else {
|
} else {
|
||||||
maxHeight = upperSpace;
|
maxHeight.value = upperSpace;
|
||||||
top = window.scrollY + (upperSpace + MARGIN - height);
|
top = window.scrollY + (upperSpace + MARGIN - height);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -300,7 +309,7 @@ const align = () => {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
maxHeight = underSpace;
|
maxHeight.value = underSpace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,36 +326,43 @@ const align = () => {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
top >=
|
top >=
|
||||||
srcRect.top + props.src.offsetHeight + (fixed ? 0 : window.pageYOffset)
|
srcRect.top +
|
||||||
|
props.src.offsetHeight +
|
||||||
|
(fixed.value ? 0 : window.pageYOffset)
|
||||||
) {
|
) {
|
||||||
transformOriginY = "top";
|
transformOriginY = "top";
|
||||||
} else if (top + height <= srcRect.top + (fixed ? 0 : window.pageYOffset)) {
|
} else if (
|
||||||
|
top + height <=
|
||||||
|
srcRect.top + (fixed.value ? 0 : window.pageYOffset)
|
||||||
|
) {
|
||||||
transformOriginY = "bottom";
|
transformOriginY = "bottom";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
left >=
|
left >=
|
||||||
srcRect.left + props.src.offsetWidth + (fixed ? 0 : window.pageXOffset)
|
srcRect.left +
|
||||||
|
props.src.offsetWidth +
|
||||||
|
(fixed.value ? 0 : window.pageXOffset)
|
||||||
) {
|
) {
|
||||||
transformOriginX = "left";
|
transformOriginX = "left";
|
||||||
} else if (
|
} else if (
|
||||||
left + width <=
|
left + width <=
|
||||||
srcRect.left + (fixed ? 0 : window.pageXOffset)
|
srcRect.left + (fixed.value ? 0 : window.pageXOffset)
|
||||||
) {
|
) {
|
||||||
transformOriginX = "right";
|
transformOriginX = "right";
|
||||||
}
|
}
|
||||||
|
|
||||||
transformOrigin = `${transformOriginX} ${transformOriginY}`;
|
transformOrigin.value = `${transformOriginX} ${transformOriginY}`;
|
||||||
|
|
||||||
content.style.left = left + "px";
|
content.value.style.left = left + "px";
|
||||||
content.style.top = top + "px";
|
content.value.style.top = top + "px";
|
||||||
};
|
};
|
||||||
|
|
||||||
const onOpened = () => {
|
const onOpened = () => {
|
||||||
emit("opened");
|
emit("opened");
|
||||||
|
|
||||||
// モーダルコンテンツにマウスボタンが押され、コンテンツ外でマウスボタンが離されたときにモーダルバックグラウンドクリックと判定させないためにマウスイベントを監視しフラグ管理する
|
// モーダルコンテンツにマウスボタンが押され、コンテンツ外でマウスボタンが離されたときにモーダルバックグラウンドクリックと判定させないためにマウスイベントを監視しフラグ管理する
|
||||||
const el = content!.children[0];
|
const el = content.value!.children[0];
|
||||||
el.addEventListener(
|
el.addEventListener(
|
||||||
"mousedown",
|
"mousedown",
|
||||||
(ev) => {
|
(ev) => {
|
||||||
|
@ -378,7 +394,8 @@ onMounted(() => {
|
||||||
// eslint-disable-next-line vue/no-mutating-props
|
// eslint-disable-next-line vue/no-mutating-props
|
||||||
props.src.style.pointerEvents = "none";
|
props.src.style.pointerEvents = "none";
|
||||||
}
|
}
|
||||||
fixed = type === "drawer" || getFixedContainer(props.src) != null;
|
fixed.value =
|
||||||
|
type.value === "drawer" || getFixedContainer(props.src) != null;
|
||||||
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
|
@ -390,7 +407,7 @@ onMounted(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
new ResizeObserver((entries, observer) => {
|
new ResizeObserver((entries, observer) => {
|
||||||
align();
|
align();
|
||||||
}).observe(content!);
|
}).observe(content.value!);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ComputedRef, provide } from "vue";
|
import { ComputedRef, provide, ref, computed } from "vue";
|
||||||
import MkModal from "@/components/MkModal.vue";
|
import MkModal from "@/components/MkModal.vue";
|
||||||
import { popout as _popout } from "@/scripts/popout";
|
import { popout as _popout } from "@/scripts/popout";
|
||||||
import copyToClipboard from "@/scripts/copy-to-clipboard";
|
import copyToClipboard from "@/scripts/copy-to-clipboard";
|
||||||
|
@ -76,27 +76,27 @@ const router = new Router(routes, props.initialPath);
|
||||||
|
|
||||||
router.addListener("push", (ctx) => {});
|
router.addListener("push", (ctx) => {});
|
||||||
|
|
||||||
let pageMetadata = $ref<null | ComputedRef<PageMetadata>>();
|
let pageMetadata = ref<null | ComputedRef<PageMetadata>>();
|
||||||
let rootEl = $ref();
|
let rootEl = ref();
|
||||||
let modal = $ref<InstanceType<typeof MkModal>>();
|
let modal = ref<InstanceType<typeof MkModal>>();
|
||||||
let path = $ref(props.initialPath);
|
let path = ref(props.initialPath);
|
||||||
let width = $ref(860);
|
let width = ref(860);
|
||||||
let height = $ref(660);
|
let height = ref(660);
|
||||||
const history = [];
|
const history = [];
|
||||||
|
|
||||||
provide("router", router);
|
provide("router", router);
|
||||||
provideMetadataReceiver((info) => {
|
provideMetadataReceiver((info) => {
|
||||||
pageMetadata = info;
|
pageMetadata.value = info;
|
||||||
});
|
});
|
||||||
provide("shouldOmitHeaderTitle", true);
|
provide("shouldOmitHeaderTitle", true);
|
||||||
provide("shouldHeaderThin", true);
|
provide("shouldHeaderThin", true);
|
||||||
|
|
||||||
const pageUrl = $computed(() => url + path);
|
const pageUrl = computed(() => url + path.value);
|
||||||
const contextmenu = $computed(() => {
|
const contextmenu = computed(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
type: "label",
|
type: "label",
|
||||||
text: path,
|
text: path.value,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "ph-arrows-out-simple ph-bold ph-lg",
|
icon: "ph-arrows-out-simple ph-bold ph-lg",
|
||||||
|
@ -113,15 +113,15 @@ const contextmenu = $computed(() => {
|
||||||
icon: "ph-arrow-square-out ph-bold ph-lg",
|
icon: "ph-arrow-square-out ph-bold ph-lg",
|
||||||
text: i18n.ts.openInNewTab,
|
text: i18n.ts.openInNewTab,
|
||||||
action: () => {
|
action: () => {
|
||||||
window.open(pageUrl, "_blank");
|
window.open(pageUrl.value, "_blank");
|
||||||
modal.close();
|
modal.value.close();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "ph-link-simple ph-bold ph-lg",
|
icon: "ph-link-simple ph-bold ph-lg",
|
||||||
text: i18n.ts.copyLink,
|
text: i18n.ts.copyLink,
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(pageUrl);
|
copyToClipboard(pageUrl.value);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -137,17 +137,17 @@ function back() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function expand() {
|
function expand() {
|
||||||
mainRouter.push(path);
|
mainRouter.push(path.value);
|
||||||
modal.close();
|
modal.value.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
function popout() {
|
function popout() {
|
||||||
_popout(path, rootEl);
|
_popout(path.value, rootEl.value);
|
||||||
modal.close();
|
modal.value.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onContextmenu(ev: MouseEvent) {
|
function onContextmenu(ev: MouseEvent) {
|
||||||
os.contextMenu(contextmenu, ev);
|
os.contextMenu(contextmenu.value, ev);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { shallowRef } from "vue";
|
||||||
|
|
||||||
import { FocusTrap } from "focus-trap-vue";
|
import { FocusTrap } from "focus-trap-vue";
|
||||||
import MkModal from "./MkModal.vue";
|
import MkModal from "./MkModal.vue";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
|
@ -90,12 +92,12 @@ const emit = defineEmits<{
|
||||||
(event: "ok"): void;
|
(event: "ok"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let modal = $shallowRef<InstanceType<typeof MkModal>>();
|
let modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
let rootEl = $shallowRef<HTMLElement>();
|
let rootEl = shallowRef<HTMLElement>();
|
||||||
let headerEl = $shallowRef<HTMLElement>();
|
let headerEl = shallowRef<HTMLElement>();
|
||||||
|
|
||||||
const close = (ev) => {
|
const close = (ev) => {
|
||||||
modal?.close(ev);
|
modal.value?.close(ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onBgClick = () => {
|
const onBgClick = () => {
|
||||||
|
|
|
@ -306,7 +306,7 @@ const props = defineProps<{
|
||||||
|
|
||||||
const inChannel = inject("inChannel", null);
|
const inChannel = inject("inChannel", null);
|
||||||
|
|
||||||
let note = $ref(deepClone(props.note));
|
let note = ref(deepClone(props.note));
|
||||||
|
|
||||||
const softMuteReasonI18nSrc = (what?: string) => {
|
const softMuteReasonI18nSrc = (what?: string) => {
|
||||||
if (what === "note") return i18n.ts.userSaysSomethingReason;
|
if (what === "note") return i18n.ts.userSaysSomethingReason;
|
||||||
|
@ -321,19 +321,19 @@ const softMuteReasonI18nSrc = (what?: string) => {
|
||||||
// plugin
|
// plugin
|
||||||
if (noteViewInterruptors.length > 0) {
|
if (noteViewInterruptors.length > 0) {
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
let result = deepClone(note);
|
let result = deepClone(note.value);
|
||||||
for (const interruptor of noteViewInterruptors) {
|
for (const interruptor of noteViewInterruptors) {
|
||||||
result = await interruptor.handler(result);
|
result = await interruptor.handler(result);
|
||||||
}
|
}
|
||||||
note = result;
|
note.value = result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const isRenote =
|
const isRenote =
|
||||||
note.renote != null &&
|
note.value.renote != null &&
|
||||||
note.text == null &&
|
note.value.text == null &&
|
||||||
note.fileIds.length === 0 &&
|
note.value.fileIds.length === 0 &&
|
||||||
note.poll == null;
|
note.value.poll == null;
|
||||||
|
|
||||||
const el = ref<HTMLElement>();
|
const el = ref<HTMLElement>();
|
||||||
const footerEl = ref<HTMLElement>();
|
const footerEl = ref<HTMLElement>();
|
||||||
|
@ -342,13 +342,15 @@ const starButton = ref<InstanceType<typeof XStarButton>>();
|
||||||
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
||||||
const renoteTime = ref<HTMLElement>();
|
const renoteTime = ref<HTMLElement>();
|
||||||
const reactButton = ref<HTMLElement>();
|
const reactButton = ref<HTMLElement>();
|
||||||
let appearNote = $computed(() =>
|
let appearNote = computed(() =>
|
||||||
isRenote ? (note.renote as misskey.entities.Note) : note,
|
isRenote ? (note.value.renote as misskey.entities.Note) : note.value,
|
||||||
);
|
);
|
||||||
const isMyRenote = $i && $i.id === note.userId;
|
const isMyRenote = $i && $i.id === note.value.userId;
|
||||||
const showContent = ref(false);
|
const showContent = ref(false);
|
||||||
const isDeleted = ref(false);
|
const isDeleted = ref(false);
|
||||||
const muted = ref(getWordSoftMute(note, $i, defaultStore.state.mutedWords));
|
const muted = ref(
|
||||||
|
getWordSoftMute(note.value, $i, defaultStore.state.mutedWords),
|
||||||
|
);
|
||||||
const translation = ref(null);
|
const translation = ref(null);
|
||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
const enableEmojiReactions = defaultStore.state.enableEmojiReactions;
|
const enableEmojiReactions = defaultStore.state.enableEmojiReactions;
|
||||||
|
@ -399,7 +401,7 @@ const keymap = {
|
||||||
|
|
||||||
useNoteCapture({
|
useNoteCapture({
|
||||||
rootEl: el,
|
rootEl: el,
|
||||||
note: $$(appearNote),
|
note: appearNote,
|
||||||
isDeletedRef: isDeleted,
|
isDeletedRef: isDeleted,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -407,7 +409,7 @@ function reply(viaKeyboard = false): void {
|
||||||
pleaseLogin();
|
pleaseLogin();
|
||||||
os.post(
|
os.post(
|
||||||
{
|
{
|
||||||
reply: appearNote,
|
reply: appearNote.value,
|
||||||
animation: !viaKeyboard,
|
animation: !viaKeyboard,
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
|
@ -423,7 +425,7 @@ function react(viaKeyboard = false): void {
|
||||||
reactButton.value,
|
reactButton.value,
|
||||||
(reaction) => {
|
(reaction) => {
|
||||||
os.api("notes/reactions/create", {
|
os.api("notes/reactions/create", {
|
||||||
noteId: appearNote.id,
|
noteId: appearNote.value.id,
|
||||||
reaction: reaction,
|
reaction: reaction,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -466,21 +468,24 @@ function onContextmenu(ev: MouseEvent): void {
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
type: "label",
|
type: "label",
|
||||||
text: notePage(appearNote),
|
text: notePage(appearNote.value),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "ph-browser ph-bold ph-lg",
|
icon: "ph-browser ph-bold ph-lg",
|
||||||
text: i18n.ts.openInWindow,
|
text: i18n.ts.openInWindow,
|
||||||
action: () => {
|
action: () => {
|
||||||
os.pageWindow(notePage(appearNote));
|
os.pageWindow(notePage(appearNote.value));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
notePage(appearNote) != location.pathname
|
notePage(appearNote.value) != location.pathname
|
||||||
? {
|
? {
|
||||||
icon: "ph-arrows-out-simple ph-bold ph-lg",
|
icon: "ph-arrows-out-simple ph-bold ph-lg",
|
||||||
text: i18n.ts.showInPage,
|
text: i18n.ts.showInPage,
|
||||||
action: () => {
|
action: () => {
|
||||||
router.push(notePage(appearNote), "forcePage");
|
router.push(
|
||||||
|
notePage(appearNote.value),
|
||||||
|
"forcePage",
|
||||||
|
);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
|
@ -489,22 +494,25 @@ function onContextmenu(ev: MouseEvent): void {
|
||||||
type: "a",
|
type: "a",
|
||||||
icon: "ph-arrow-square-out ph-bold ph-lg",
|
icon: "ph-arrow-square-out ph-bold ph-lg",
|
||||||
text: i18n.ts.openInNewTab,
|
text: i18n.ts.openInNewTab,
|
||||||
href: notePage(appearNote),
|
href: notePage(appearNote.value),
|
||||||
target: "_blank",
|
target: "_blank",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "ph-link-simple ph-bold ph-lg",
|
icon: "ph-link-simple ph-bold ph-lg",
|
||||||
text: i18n.ts.copyLink,
|
text: i18n.ts.copyLink,
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(`${url}${notePage(appearNote)}`);
|
copyToClipboard(`${url}${notePage(appearNote.value)}`);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
appearNote.user.host != null
|
appearNote.value.user.host != null
|
||||||
? {
|
? {
|
||||||
type: "a",
|
type: "a",
|
||||||
icon: "ph-arrow-square-up-right ph-bold ph-lg",
|
icon: "ph-arrow-square-up-right ph-bold ph-lg",
|
||||||
text: i18n.ts.showOnRemote,
|
text: i18n.ts.showOnRemote,
|
||||||
href: appearNote.url ?? appearNote.uri ?? "",
|
href:
|
||||||
|
appearNote.value.url ??
|
||||||
|
appearNote.value.uri ??
|
||||||
|
"",
|
||||||
target: "_blank",
|
target: "_blank",
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
|
@ -517,7 +525,7 @@ function onContextmenu(ev: MouseEvent): void {
|
||||||
function menu(viaKeyboard = false): void {
|
function menu(viaKeyboard = false): void {
|
||||||
os.popupMenu(
|
os.popupMenu(
|
||||||
getNoteMenu({
|
getNoteMenu({
|
||||||
note: note,
|
note: note.value,
|
||||||
translating,
|
translating,
|
||||||
translation,
|
translation,
|
||||||
menuButton,
|
menuButton,
|
||||||
|
@ -541,7 +549,7 @@ function showRenoteMenu(viaKeyboard = false): void {
|
||||||
danger: true,
|
danger: true,
|
||||||
action: () => {
|
action: () => {
|
||||||
os.api("notes/delete", {
|
os.api("notes/delete", {
|
||||||
noteId: note.id,
|
noteId: note.value.id,
|
||||||
});
|
});
|
||||||
isDeleted.value = true;
|
isDeleted.value = true;
|
||||||
},
|
},
|
||||||
|
@ -582,13 +590,13 @@ function noteClick(e) {
|
||||||
) {
|
) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
} else {
|
} else {
|
||||||
router.push(notePage(appearNote));
|
router.push(notePage(appearNote.value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function readPromo() {
|
function readPromo() {
|
||||||
os.api("promo/read", {
|
os.api("promo/read", {
|
||||||
noteId: appearNote.id,
|
noteId: appearNote.value.id,
|
||||||
});
|
});
|
||||||
isDeleted.value = true;
|
isDeleted.value = true;
|
||||||
}
|
}
|
||||||
|
@ -600,28 +608,30 @@ function setPostExpanded(val: boolean) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const accessibleLabel = computed(() => {
|
const accessibleLabel = computed(() => {
|
||||||
let label = `${appearNote.user.username}; `;
|
let label = `${appearNote.value.user.username}; `;
|
||||||
if (appearNote.renote) {
|
if (appearNote.value.renote) {
|
||||||
label += `${i18n.t("renoted")} ${appearNote.renote.user.username}; `;
|
label += `${i18n.t("renoted")} ${
|
||||||
if (appearNote.renote.cw) {
|
appearNote.value.renote.user.username
|
||||||
label += `${i18n.t("cw")}: ${appearNote.renote.cw}; `;
|
}; `;
|
||||||
|
if (appearNote.value.renote.cw) {
|
||||||
|
label += `${i18n.t("cw")}: ${appearNote.value.renote.cw}; `;
|
||||||
if (postIsExpanded.value) {
|
if (postIsExpanded.value) {
|
||||||
label += `${appearNote.renote.text}; `;
|
label += `${appearNote.value.renote.text}; `;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
label += `${appearNote.renote.text}; `;
|
label += `${appearNote.value.renote.text}; `;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (appearNote.cw) {
|
if (appearNote.value.cw) {
|
||||||
label += `${i18n.t("cw")}: ${appearNote.cw}; `;
|
label += `${i18n.t("cw")}: ${appearNote.value.cw}; `;
|
||||||
if (postIsExpanded.value) {
|
if (postIsExpanded.value) {
|
||||||
label += `${appearNote.text}; `;
|
label += `${appearNote.value.text}; `;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
label += `${appearNote.text}; `;
|
label += `${appearNote.value.text}; `;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const date = new Date(appearNote.createdAt);
|
const date = new Date(appearNote.value.createdAt);
|
||||||
label += `${date.toLocaleTimeString()}`;
|
label += `${date.toLocaleTimeString()}`;
|
||||||
return label;
|
return label;
|
||||||
});
|
});
|
||||||
|
|
|
@ -177,9 +177,9 @@ const props = defineProps<{
|
||||||
pinned?: boolean;
|
pinned?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let tab = $ref("replies");
|
let tab = ref("replies");
|
||||||
|
|
||||||
let note = $ref(deepClone(props.note));
|
let note = ref(deepClone(props.note));
|
||||||
|
|
||||||
const softMuteReasonI18nSrc = (what?: string) => {
|
const softMuteReasonI18nSrc = (what?: string) => {
|
||||||
if (what === "note") return i18n.ts.userSaysSomethingReason;
|
if (what === "note") return i18n.ts.userSaysSomethingReason;
|
||||||
|
@ -194,30 +194,32 @@ const softMuteReasonI18nSrc = (what?: string) => {
|
||||||
// plugin
|
// plugin
|
||||||
if (noteViewInterruptors.length > 0) {
|
if (noteViewInterruptors.length > 0) {
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
let result = deepClone(note);
|
let result = deepClone(note.value);
|
||||||
for (const interruptor of noteViewInterruptors) {
|
for (const interruptor of noteViewInterruptors) {
|
||||||
result = await interruptor.handler(result);
|
result = await interruptor.handler(result);
|
||||||
}
|
}
|
||||||
note = result;
|
note.value = result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const el = ref<HTMLElement>();
|
const el = ref<HTMLElement>();
|
||||||
const noteEl = $ref();
|
const noteEl = ref();
|
||||||
const menuButton = ref<HTMLElement>();
|
const menuButton = ref<HTMLElement>();
|
||||||
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
||||||
const reactButton = ref<HTMLElement>();
|
const reactButton = ref<HTMLElement>();
|
||||||
const showContent = ref(false);
|
const showContent = ref(false);
|
||||||
const isDeleted = ref(false);
|
const isDeleted = ref(false);
|
||||||
const muted = ref(getWordSoftMute(note, $i, defaultStore.state.mutedWords));
|
const muted = ref(
|
||||||
|
getWordSoftMute(note.value, $i, defaultStore.state.mutedWords),
|
||||||
|
);
|
||||||
const translation = ref(null);
|
const translation = ref(null);
|
||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
let conversation = $ref<null | misskey.entities.Note[]>([]);
|
let conversation = ref<null | misskey.entities.Note[]>([]);
|
||||||
const replies = ref<misskey.entities.Note[]>([]);
|
const replies = ref<misskey.entities.Note[]>([]);
|
||||||
let directReplies = $ref<null | misskey.entities.Note[]>([]);
|
let directReplies = ref<null | misskey.entities.Note[]>([]);
|
||||||
let directQuotes = $ref<null | misskey.entities.Note[]>([]);
|
let directQuotes = ref<null | misskey.entities.Note[]>([]);
|
||||||
let clips = $ref();
|
let clips = ref();
|
||||||
let renotes = $ref();
|
let renotes = ref();
|
||||||
let isScrolling;
|
let isScrolling;
|
||||||
|
|
||||||
const reactionsCount = Object.values(props.note.reactions).reduce(
|
const reactionsCount = Object.values(props.note.reactions).reduce(
|
||||||
|
@ -236,14 +238,14 @@ const keymap = {
|
||||||
|
|
||||||
useNoteCapture({
|
useNoteCapture({
|
||||||
rootEl: el,
|
rootEl: el,
|
||||||
note: $$(note),
|
note: note,
|
||||||
isDeletedRef: isDeleted,
|
isDeletedRef: isDeleted,
|
||||||
});
|
});
|
||||||
|
|
||||||
function reply(viaKeyboard = false): void {
|
function reply(viaKeyboard = false): void {
|
||||||
pleaseLogin();
|
pleaseLogin();
|
||||||
os.post({
|
os.post({
|
||||||
reply: note,
|
reply: note.value,
|
||||||
animation: !viaKeyboard,
|
animation: !viaKeyboard,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
focus();
|
focus();
|
||||||
|
@ -257,7 +259,7 @@ function react(viaKeyboard = false): void {
|
||||||
reactButton.value,
|
reactButton.value,
|
||||||
(reaction) => {
|
(reaction) => {
|
||||||
os.api("notes/reactions/create", {
|
os.api("notes/reactions/create", {
|
||||||
noteId: note.id,
|
noteId: note.value.id,
|
||||||
reaction: reaction,
|
reaction: reaction,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -291,7 +293,7 @@ function onContextmenu(ev: MouseEvent): void {
|
||||||
} else {
|
} else {
|
||||||
os.contextMenu(
|
os.contextMenu(
|
||||||
getNoteMenu({
|
getNoteMenu({
|
||||||
note: note,
|
note: note.value,
|
||||||
translating,
|
translating,
|
||||||
translation,
|
translation,
|
||||||
menuButton,
|
menuButton,
|
||||||
|
@ -305,7 +307,7 @@ function onContextmenu(ev: MouseEvent): void {
|
||||||
function menu(viaKeyboard = false): void {
|
function menu(viaKeyboard = false): void {
|
||||||
os.popupMenu(
|
os.popupMenu(
|
||||||
getNoteMenu({
|
getNoteMenu({
|
||||||
note: note,
|
note: note.value,
|
||||||
translating,
|
translating,
|
||||||
translation,
|
translation,
|
||||||
menuButton,
|
menuButton,
|
||||||
|
@ -319,48 +321,50 @@ function menu(viaKeyboard = false): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
function focus() {
|
function focus() {
|
||||||
noteEl.focus();
|
noteEl.value.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function blur() {
|
function blur() {
|
||||||
noteEl.blur();
|
noteEl.value.blur();
|
||||||
}
|
}
|
||||||
|
|
||||||
directReplies = null;
|
directReplies.value = null;
|
||||||
os.api("notes/children", {
|
os.api("notes/children", {
|
||||||
noteId: note.id,
|
noteId: note.value.id,
|
||||||
limit: 30,
|
limit: 30,
|
||||||
depth: 12,
|
depth: 12,
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
res = res.reduce((acc, resNote) => {
|
res = res.reduce((acc, resNote) => {
|
||||||
if (resNote.userId == note.userId) {
|
if (resNote.userId == note.value.userId) {
|
||||||
return [...acc, resNote];
|
return [...acc, resNote];
|
||||||
}
|
}
|
||||||
return [resNote, ...acc];
|
return [resNote, ...acc];
|
||||||
}, []);
|
}, []);
|
||||||
replies.value = res;
|
replies.value = res;
|
||||||
directReplies = res
|
directReplies.value = res
|
||||||
.filter((resNote) => resNote.replyId === note.id)
|
.filter((resNote) => resNote.replyId === note.value.id)
|
||||||
.reverse();
|
.reverse();
|
||||||
directQuotes = res.filter((resNote) => resNote.renoteId === note.id);
|
directQuotes.value = res.filter(
|
||||||
|
(resNote) => resNote.renoteId === note.value.id,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
conversation = null;
|
conversation.value = null;
|
||||||
if (note.replyId) {
|
if (note.value.replyId) {
|
||||||
os.api("notes/conversation", {
|
os.api("notes/conversation", {
|
||||||
noteId: note.replyId,
|
noteId: note.value.replyId,
|
||||||
limit: 30,
|
limit: 30,
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
conversation = res.reverse();
|
conversation.value = res.reverse();
|
||||||
focus();
|
focus();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
clips = null;
|
clips.value = null;
|
||||||
os.api("notes/clips", {
|
os.api("notes/clips", {
|
||||||
noteId: note.id,
|
noteId: note.value.id,
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
clips = res;
|
clips.value = res;
|
||||||
});
|
});
|
||||||
|
|
||||||
// const pagination = {
|
// const pagination = {
|
||||||
|
@ -371,14 +375,14 @@ os.api("notes/clips", {
|
||||||
|
|
||||||
// const pagingComponent = $ref<InstanceType<typeof MkPagination>>();
|
// const pagingComponent = $ref<InstanceType<typeof MkPagination>>();
|
||||||
|
|
||||||
renotes = null;
|
renotes.value = null;
|
||||||
function loadTab() {
|
function loadTab() {
|
||||||
if (tab === "renotes" && !renotes) {
|
if (tab.value === "renotes" && !renotes.value) {
|
||||||
os.api("notes/renotes", {
|
os.api("notes/renotes", {
|
||||||
noteId: note.id,
|
noteId: note.value.id,
|
||||||
limit: 100,
|
limit: 100,
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
renotes = res;
|
renotes.value = res;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -387,7 +391,7 @@ async function onNoteUpdated(noteData: NoteUpdatedEvent): Promise<void> {
|
||||||
const { type, id, body } = noteData;
|
const { type, id, body } = noteData;
|
||||||
|
|
||||||
let found = -1;
|
let found = -1;
|
||||||
if (id === note.id) {
|
if (id === note.value.id) {
|
||||||
found = 0;
|
found = 0;
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < replies.value.length; i++) {
|
for (let i = 0; i < replies.value.length; i++) {
|
||||||
|
@ -412,7 +416,7 @@ async function onNoteUpdated(noteData: NoteUpdatedEvent): Promise<void> {
|
||||||
|
|
||||||
replies.value.splice(found, 0, replyNote);
|
replies.value.splice(found, 0, replyNote);
|
||||||
if (found === 0) {
|
if (found === 0) {
|
||||||
directReplies.push(replyNote);
|
directReplies.value.push(replyNote);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -433,12 +437,12 @@ document.addEventListener("wheel", () => {
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
stream.on("noteUpdated", onNoteUpdated);
|
stream.on("noteUpdated", onNoteUpdated);
|
||||||
isScrolling = false;
|
isScrolling = false;
|
||||||
noteEl.scrollIntoView();
|
noteEl.value.scrollIntoView();
|
||||||
});
|
});
|
||||||
|
|
||||||
onUpdated(() => {
|
onUpdated(() => {
|
||||||
if (!isScrolling) {
|
if (!isScrolling) {
|
||||||
noteEl.scrollIntoView();
|
noteEl.value.scrollIntoView();
|
||||||
if (location.hash) {
|
if (location.hash) {
|
||||||
location.replace(location.hash); // Jump to highlighted reply
|
location.replace(location.hash); // Jump to highlighted reply
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
import {} from "vue";
|
import {} from "vue";
|
||||||
import type * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
|
@ -61,11 +63,12 @@ const props = defineProps<{
|
||||||
pinned?: boolean;
|
pinned?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let note = $ref(props.note);
|
let note = ref(props.note);
|
||||||
|
|
||||||
const showTicker =
|
const showTicker =
|
||||||
defaultStore.state.instanceTicker === "always" ||
|
defaultStore.state.instanceTicker === "always" ||
|
||||||
(defaultStore.state.instanceTicker === "remote" && note.user.instance);
|
(defaultStore.state.instanceTicker === "remote" &&
|
||||||
|
note.value.user.instance);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -185,7 +185,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject, ref } from "vue";
|
import { inject, ref, computed } from "vue";
|
||||||
import type { Ref } from "vue";
|
import type { Ref } from "vue";
|
||||||
import * as misskey from "firefish-js";
|
import * as misskey from "firefish-js";
|
||||||
import * as mfm from "mfm-js";
|
import * as mfm from "mfm-js";
|
||||||
|
@ -233,7 +233,7 @@ const props = withDefaults(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let note = $ref(deepClone(props.note));
|
let note = ref(deepClone(props.note));
|
||||||
|
|
||||||
const softMuteReasonI18nSrc = (what?: string) => {
|
const softMuteReasonI18nSrc = (what?: string) => {
|
||||||
if (what === "note") return i18n.ts.userSaysSomethingReason;
|
if (what === "note") return i18n.ts.userSaysSomethingReason;
|
||||||
|
@ -246,10 +246,10 @@ const softMuteReasonI18nSrc = (what?: string) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const isRenote =
|
const isRenote =
|
||||||
note.renote != null &&
|
note.value.renote != null &&
|
||||||
note.text == null &&
|
note.value.text == null &&
|
||||||
note.fileIds.length === 0 &&
|
note.value.fileIds.length === 0 &&
|
||||||
note.poll == null;
|
note.value.poll == null;
|
||||||
|
|
||||||
const el = ref<HTMLElement>();
|
const el = ref<HTMLElement>();
|
||||||
const footerEl = ref<HTMLElement>();
|
const footerEl = ref<HTMLElement>();
|
||||||
|
@ -257,11 +257,13 @@ const menuButton = ref<HTMLElement>();
|
||||||
const starButton = ref<InstanceType<typeof XStarButton>>();
|
const starButton = ref<InstanceType<typeof XStarButton>>();
|
||||||
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
||||||
const reactButton = ref<HTMLElement>();
|
const reactButton = ref<HTMLElement>();
|
||||||
let appearNote = $computed(() =>
|
let appearNote = computed(() =>
|
||||||
isRenote ? (note.renote as misskey.entities.Note) : note,
|
isRenote ? (note.value.renote as misskey.entities.Note) : note.value,
|
||||||
);
|
);
|
||||||
const isDeleted = ref(false);
|
const isDeleted = ref(false);
|
||||||
const muted = ref(getWordSoftMute(note, $i, defaultStore.state.mutedWords));
|
const muted = ref(
|
||||||
|
getWordSoftMute(note.value, $i, defaultStore.state.mutedWords),
|
||||||
|
);
|
||||||
const translation = ref(null);
|
const translation = ref(null);
|
||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
const replies: misskey.entities.Note[] =
|
const replies: misskey.entities.Note[] =
|
||||||
|
@ -309,14 +311,14 @@ const translate = async () => {
|
||||||
|
|
||||||
useNoteCapture({
|
useNoteCapture({
|
||||||
rootEl: el,
|
rootEl: el,
|
||||||
note: $$(appearNote),
|
note: appearNote,
|
||||||
isDeletedRef: isDeleted,
|
isDeletedRef: isDeleted,
|
||||||
});
|
});
|
||||||
|
|
||||||
function reply(viaKeyboard = false): void {
|
function reply(viaKeyboard = false): void {
|
||||||
pleaseLogin();
|
pleaseLogin();
|
||||||
os.post({
|
os.post({
|
||||||
reply: appearNote,
|
reply: appearNote.value,
|
||||||
animation: !viaKeyboard,
|
animation: !viaKeyboard,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
focus();
|
focus();
|
||||||
|
@ -330,7 +332,7 @@ function react(viaKeyboard = false): void {
|
||||||
reactButton.value,
|
reactButton.value,
|
||||||
(reaction) => {
|
(reaction) => {
|
||||||
os.api("notes/reactions/create", {
|
os.api("notes/reactions/create", {
|
||||||
noteId: appearNote.id,
|
noteId: appearNote.value.id,
|
||||||
reaction: reaction,
|
reaction: reaction,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -356,7 +358,7 @@ const currentClipPage = inject<Ref<misskey.entities.Clip> | null>(
|
||||||
function menu(viaKeyboard = false): void {
|
function menu(viaKeyboard = false): void {
|
||||||
os.popupMenu(
|
os.popupMenu(
|
||||||
getNoteMenu({
|
getNoteMenu({
|
||||||
note: note,
|
note: note.value,
|
||||||
translating,
|
translating,
|
||||||
translation,
|
translation,
|
||||||
menuButton,
|
menuButton,
|
||||||
|
@ -388,21 +390,24 @@ function onContextmenu(ev: MouseEvent): void {
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
type: "label",
|
type: "label",
|
||||||
text: notePage(appearNote),
|
text: notePage(appearNote.value),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "ph-browser ph-bold ph-lg",
|
icon: "ph-browser ph-bold ph-lg",
|
||||||
text: i18n.ts.openInWindow,
|
text: i18n.ts.openInWindow,
|
||||||
action: () => {
|
action: () => {
|
||||||
os.pageWindow(notePage(appearNote));
|
os.pageWindow(notePage(appearNote.value));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
notePage(appearNote) != location.pathname
|
notePage(appearNote.value) != location.pathname
|
||||||
? {
|
? {
|
||||||
icon: "ph-arrows-out-simple ph-bold ph-lg",
|
icon: "ph-arrows-out-simple ph-bold ph-lg",
|
||||||
text: i18n.ts.showInPage,
|
text: i18n.ts.showInPage,
|
||||||
action: () => {
|
action: () => {
|
||||||
router.push(notePage(appearNote), "forcePage");
|
router.push(
|
||||||
|
notePage(appearNote.value),
|
||||||
|
"forcePage",
|
||||||
|
);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
|
@ -411,22 +416,22 @@ function onContextmenu(ev: MouseEvent): void {
|
||||||
type: "a",
|
type: "a",
|
||||||
icon: "ph-arrow-square-out ph-bold ph-lg",
|
icon: "ph-arrow-square-out ph-bold ph-lg",
|
||||||
text: i18n.ts.openInNewTab,
|
text: i18n.ts.openInNewTab,
|
||||||
href: notePage(appearNote),
|
href: notePage(appearNote.value),
|
||||||
target: "_blank",
|
target: "_blank",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "ph-link-simple ph-bold ph-lg",
|
icon: "ph-link-simple ph-bold ph-lg",
|
||||||
text: i18n.ts.copyLink,
|
text: i18n.ts.copyLink,
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(`${url}${notePage(appearNote)}`);
|
copyToClipboard(`${url}${notePage(appearNote.value)}`);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
note.user.host != null
|
note.value.user.host != null
|
||||||
? {
|
? {
|
||||||
type: "a",
|
type: "a",
|
||||||
icon: "ph-arrow-square-up-right ph-bold ph-lg",
|
icon: "ph-arrow-square-up-right ph-bold ph-lg",
|
||||||
text: i18n.ts.showOnRemote,
|
text: i18n.ts.showOnRemote,
|
||||||
href: note.url ?? note.uri ?? "",
|
href: note.value.url ?? note.value.uri ?? "",
|
||||||
target: "_blank",
|
target: "_blank",
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref } from "vue";
|
||||||
|
|
||||||
import {} from "vue";
|
import {} from "vue";
|
||||||
import { notificationTypes } from "firefish-js";
|
import { notificationTypes } from "firefish-js";
|
||||||
import MkSwitch from "./form/switch.vue";
|
import MkSwitch from "./form/switch.vue";
|
||||||
|
@ -63,43 +65,45 @@ const props = withDefaults(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let includingTypes = $computed(() => props.includingTypes || []);
|
let includingTypes = computed(() => props.includingTypes || []);
|
||||||
|
|
||||||
const dialog = $ref<InstanceType<typeof XModalWindow>>();
|
const dialog = ref<InstanceType<typeof XModalWindow>>();
|
||||||
|
|
||||||
let typesMap = $ref<Record<(typeof notificationTypes)[number], boolean>>({});
|
let typesMap = ref<Record<(typeof notificationTypes)[number], boolean>>({});
|
||||||
let useGlobalSetting = $ref(
|
let useGlobalSetting = ref(
|
||||||
(includingTypes === null || includingTypes.length === 0) &&
|
(includingTypes.value === null || includingTypes.value.length === 0) &&
|
||||||
props.showGlobalToggle,
|
props.showGlobalToggle,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const ntype of notificationTypes) {
|
for (const ntype of notificationTypes) {
|
||||||
typesMap[ntype] = includingTypes.includes(ntype);
|
typesMap.value[ntype] = includingTypes.value.includes(ntype);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ok() {
|
function ok() {
|
||||||
if (useGlobalSetting) {
|
if (useGlobalSetting.value) {
|
||||||
emit("done", { includingTypes: null });
|
emit("done", { includingTypes: null });
|
||||||
} else {
|
} else {
|
||||||
emit("done", {
|
emit("done", {
|
||||||
includingTypes: (
|
includingTypes: (
|
||||||
Object.keys(typesMap) as (typeof notificationTypes)[number][]
|
Object.keys(
|
||||||
).filter((type) => typesMap[type]),
|
typesMap.value,
|
||||||
|
) as (typeof notificationTypes)[number][]
|
||||||
|
).filter((type) => typesMap.value[type]),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.close();
|
dialog.value.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
function disableAll() {
|
function disableAll() {
|
||||||
for (const type in typesMap) {
|
for (const type in typesMap.value) {
|
||||||
typesMap[type as (typeof notificationTypes)[number]] = false;
|
typesMap.value[type as (typeof notificationTypes)[number]] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function enableAll() {
|
function enableAll() {
|
||||||
for (const type in typesMap) {
|
for (const type in typesMap.value) {
|
||||||
typesMap[type as (typeof notificationTypes)[number]] = true;
|
typesMap.value[type as (typeof notificationTypes)[number]] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
import XNotification from "@/components/MkNotification.vue";
|
import XNotification from "@/components/MkNotification.vue";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
|
|
||||||
|
@ -28,11 +28,11 @@ const emit = defineEmits<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const zIndex = os.claimZIndex("high");
|
const zIndex = os.claimZIndex("high");
|
||||||
let showing = $ref(true);
|
let showing = ref(true);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
showing = false;
|
showing.value = false;
|
||||||
}, 6000);
|
}, 6000);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ComputedRef, provide } from "vue";
|
import { ComputedRef, provide, ref, computed } from "vue";
|
||||||
import RouterView from "@/components/global/RouterView.vue";
|
import RouterView from "@/components/global/RouterView.vue";
|
||||||
import XWindow from "@/components/MkWindow.vue";
|
import XWindow from "@/components/MkWindow.vue";
|
||||||
import { popout as _popout } from "@/scripts/popout";
|
import { popout as _popout } from "@/scripts/popout";
|
||||||
|
@ -51,18 +51,18 @@ defineEmits<{
|
||||||
|
|
||||||
const router = new Router(routes, props.initialPath);
|
const router = new Router(routes, props.initialPath);
|
||||||
|
|
||||||
let pageMetadata = $ref<null | ComputedRef<PageMetadata>>();
|
let pageMetadata = ref<null | ComputedRef<PageMetadata>>();
|
||||||
let windowEl = $ref<InstanceType<typeof XWindow>>();
|
let windowEl = ref<InstanceType<typeof XWindow>>();
|
||||||
const history = $ref<{ path: string; key: any }[]>([
|
const history = ref<{ path: string; key: any }[]>([
|
||||||
{
|
{
|
||||||
path: router.getCurrentPath(),
|
path: router.getCurrentPath(),
|
||||||
key: router.getCurrentKey(),
|
key: router.getCurrentKey(),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const buttonsLeft = $computed(() => {
|
const buttonsLeft = computed(() => {
|
||||||
const buttons = [];
|
const buttons = [];
|
||||||
|
|
||||||
if (history.length > 1) {
|
if (history.value.length > 1) {
|
||||||
buttons.push({
|
buttons.push({
|
||||||
icon: "ph-caret-left ph-bold ph-lg",
|
icon: "ph-caret-left ph-bold ph-lg",
|
||||||
onClick: back,
|
onClick: back,
|
||||||
|
@ -71,7 +71,7 @@ const buttonsLeft = $computed(() => {
|
||||||
|
|
||||||
return buttons;
|
return buttons;
|
||||||
});
|
});
|
||||||
const buttonsRight = $computed(() => {
|
const buttonsRight = computed(() => {
|
||||||
const buttons = [
|
const buttons = [
|
||||||
{
|
{
|
||||||
icon: "ph-arrows-out-simple ph-bold ph-lg",
|
icon: "ph-arrows-out-simple ph-bold ph-lg",
|
||||||
|
@ -84,18 +84,18 @@ const buttonsRight = $computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
router.addListener("push", (ctx) => {
|
router.addListener("push", (ctx) => {
|
||||||
history.push({ path: ctx.path, key: ctx.key });
|
history.value.push({ path: ctx.path, key: ctx.key });
|
||||||
});
|
});
|
||||||
|
|
||||||
provide("router", router);
|
provide("router", router);
|
||||||
provideMetadataReceiver((info) => {
|
provideMetadataReceiver((info) => {
|
||||||
pageMetadata = info;
|
pageMetadata.value = info;
|
||||||
});
|
});
|
||||||
provide("shouldOmitHeaderTitle", true);
|
provide("shouldOmitHeaderTitle", true);
|
||||||
provide("shouldBackButton", false);
|
provide("shouldBackButton", false);
|
||||||
provide("shouldHeaderThin", true);
|
provide("shouldHeaderThin", true);
|
||||||
|
|
||||||
const contextmenu = $computed(() => [
|
const contextmenu = computed(() => [
|
||||||
{
|
{
|
||||||
icon: "ph-arrows-out-simple ph-bold ph-lg",
|
icon: "ph-arrows-out-simple ph-bold ph-lg",
|
||||||
text: i18n.ts.showInPage,
|
text: i18n.ts.showInPage,
|
||||||
|
@ -111,7 +111,7 @@ const contextmenu = $computed(() => [
|
||||||
text: i18n.ts.openInNewTab,
|
text: i18n.ts.openInNewTab,
|
||||||
action: () => {
|
action: () => {
|
||||||
window.open(url + router.getCurrentPath(), "_blank");
|
window.open(url + router.getCurrentPath(), "_blank");
|
||||||
windowEl.close();
|
windowEl.value.close();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -124,25 +124,25 @@ const contextmenu = $computed(() => [
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function back() {
|
function back() {
|
||||||
history.pop();
|
history.value.pop();
|
||||||
router.replace(
|
router.replace(
|
||||||
history[history.length - 1].path,
|
history.value[history.value.length - 1].path,
|
||||||
history[history.length - 1].key,
|
history.value[history.value.length - 1].key,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
windowEl.close();
|
windowEl.value.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
function expand() {
|
function expand() {
|
||||||
mainRouter.push(router.getCurrentPath(), "forcePage");
|
mainRouter.push(router.getCurrentPath(), "forcePage");
|
||||||
windowEl.close();
|
windowEl.value.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
function popout() {
|
function popout() {
|
||||||
_popout(router.getCurrentPath(), windowEl.$el);
|
_popout(router.getCurrentPath(), windowEl.value.$el);
|
||||||
windowEl.close();
|
windowEl.value.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
import MkModal from "./MkModal.vue";
|
import MkModal from "./MkModal.vue";
|
||||||
import MkMenu from "./MkMenu.vue";
|
import MkMenu from "./MkMenu.vue";
|
||||||
import { MenuItem } from "@/types/menu";
|
import { MenuItem } from "@/types/menu";
|
||||||
|
@ -41,7 +43,7 @@ const emit = defineEmits<{
|
||||||
(ev: "closed"): void;
|
(ev: "closed"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let modal = $ref<InstanceType<typeof MkModal>>();
|
let modal = ref<InstanceType<typeof MkModal>>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -245,7 +245,15 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject, watch, nextTick, onMounted, defineAsyncComponent } from "vue";
|
import {
|
||||||
|
inject,
|
||||||
|
watch,
|
||||||
|
nextTick,
|
||||||
|
onMounted,
|
||||||
|
defineAsyncComponent,
|
||||||
|
ref,
|
||||||
|
computed,
|
||||||
|
} from "vue";
|
||||||
import * as mfm from "mfm-js";
|
import * as mfm from "mfm-js";
|
||||||
import * as misskey from "firefish-js";
|
import * as misskey from "firefish-js";
|
||||||
import autosize from "autosize";
|
import autosize from "autosize";
|
||||||
|
@ -311,45 +319,47 @@ const emit = defineEmits<{
|
||||||
(ev: "esc"): void;
|
(ev: "esc"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const textareaEl = $ref<HTMLTextAreaElement | null>(null);
|
const textareaEl = ref<HTMLTextAreaElement | null>(null);
|
||||||
const cwInputEl = $ref<HTMLInputElement | null>(null);
|
const cwInputEl = ref<HTMLInputElement | null>(null);
|
||||||
const hashtagsInputEl = $ref<HTMLInputElement | null>(null);
|
const hashtagsInputEl = ref<HTMLInputElement | null>(null);
|
||||||
const visibilityButton = $ref<HTMLElement | null>(null);
|
const visibilityButton = ref<HTMLElement | null>(null);
|
||||||
|
|
||||||
const showBigPostButton = defaultStore.state.showBigPostButton;
|
const showBigPostButton = defaultStore.state.showBigPostButton;
|
||||||
|
|
||||||
let posting = $ref(false);
|
let posting = ref(false);
|
||||||
let text = $ref(props.initialText ?? "");
|
let text = ref(props.initialText ?? "");
|
||||||
let files = $ref(props.initialFiles ?? []);
|
let files = ref(props.initialFiles ?? []);
|
||||||
let poll = $ref<{
|
let poll = ref<{
|
||||||
choices: string[];
|
choices: string[];
|
||||||
multiple: boolean;
|
multiple: boolean;
|
||||||
expiresAt: string | null;
|
expiresAt: string | null;
|
||||||
expiredAfter: string | null;
|
expiredAfter: string | null;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
let useCw = $ref(false);
|
let useCw = ref(false);
|
||||||
let showPreview = $ref(defaultStore.state.showPreviewByDefault);
|
let showPreview = ref(defaultStore.state.showPreviewByDefault);
|
||||||
let cw = $ref<string | null>(null);
|
let cw = ref<string | null>(null);
|
||||||
let localOnly = $ref<boolean>(
|
let localOnly = ref<boolean>(
|
||||||
props.initialLocalOnly ?? defaultStore.state.rememberNoteVisibility
|
props.initialLocalOnly ?? defaultStore.state.rememberNoteVisibility
|
||||||
? defaultStore.state.localOnly
|
? defaultStore.state.localOnly
|
||||||
: defaultStore.state.defaultNoteLocalOnly,
|
: defaultStore.state.defaultNoteLocalOnly,
|
||||||
);
|
);
|
||||||
let visibility = $ref(
|
let visibility = ref(
|
||||||
props.initialVisibility ??
|
props.initialVisibility ??
|
||||||
((defaultStore.state.rememberNoteVisibility
|
((defaultStore.state.rememberNoteVisibility
|
||||||
? defaultStore.state.visibility
|
? defaultStore.state.visibility
|
||||||
: defaultStore.state
|
: defaultStore.state
|
||||||
.defaultNoteVisibility) as (typeof misskey.noteVisibilities)[number]),
|
.defaultNoteVisibility) as (typeof misskey.noteVisibilities)[number]),
|
||||||
);
|
);
|
||||||
let visibleUsers = $ref([]);
|
let visibleUsers = ref([]);
|
||||||
if (props.initialVisibleUsers) {
|
if (props.initialVisibleUsers) {
|
||||||
props.initialVisibleUsers.forEach(pushVisibleUser);
|
props.initialVisibleUsers.forEach(pushVisibleUser);
|
||||||
}
|
}
|
||||||
let quoteId = $ref(null);
|
let autocomplete = ref(null);
|
||||||
let hasNotSpecifiedMentions = $ref(false);
|
let draghover = ref(false);
|
||||||
let recentHashtags = $ref(JSON.parse(localStorage.getItem("hashtags") || "[]"));
|
let quoteId = ref(null);
|
||||||
let imeText = $ref("");
|
let hasNotSpecifiedMentions = ref(false);
|
||||||
|
let recentHashtags = ref(JSON.parse(localStorage.getItem("hashtags") || "[]"));
|
||||||
|
let imeText = ref("");
|
||||||
|
|
||||||
const typing = throttle(3000, () => {
|
const typing = throttle(3000, () => {
|
||||||
if (props.channel) {
|
if (props.channel) {
|
||||||
|
@ -357,7 +367,7 @@ const typing = throttle(3000, () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const draftKey = $computed((): string => {
|
const draftKey = computed((): string => {
|
||||||
if (props.editId) {
|
if (props.editId) {
|
||||||
return `edit:${props.editId}`;
|
return `edit:${props.editId}`;
|
||||||
}
|
}
|
||||||
|
@ -375,7 +385,7 @@ const draftKey = $computed((): string => {
|
||||||
return key;
|
return key;
|
||||||
});
|
});
|
||||||
|
|
||||||
const placeholder = $computed((): string => {
|
const placeholder = computed((): string => {
|
||||||
if (props.renote) {
|
if (props.renote) {
|
||||||
return i18n.ts._postForm.quotePlaceholder;
|
return i18n.ts._postForm.quotePlaceholder;
|
||||||
} else if (props.reply) {
|
} else if (props.reply) {
|
||||||
|
@ -395,7 +405,7 @@ const placeholder = $computed((): string => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const submitText = $computed((): string => {
|
const submitText = computed((): string => {
|
||||||
return props.editId
|
return props.editId
|
||||||
? i18n.ts.edit
|
? i18n.ts.edit
|
||||||
: props.renote
|
: props.renote
|
||||||
|
@ -405,34 +415,37 @@ const submitText = $computed((): string => {
|
||||||
: i18n.ts.note;
|
: i18n.ts.note;
|
||||||
});
|
});
|
||||||
|
|
||||||
const textLength = $computed((): number => {
|
const textLength = computed((): number => {
|
||||||
return length((preprocess(text) + imeText).trim());
|
return length((preprocess(text.value) + imeText.value).trim());
|
||||||
});
|
});
|
||||||
|
|
||||||
const maxTextLength = $computed((): number => {
|
const maxTextLength = computed((): number => {
|
||||||
return instance ? instance.maxNoteTextLength : 3000;
|
return instance ? instance.maxNoteTextLength : 3000;
|
||||||
});
|
});
|
||||||
|
|
||||||
const canPost = $computed((): boolean => {
|
const canPost = computed((): boolean => {
|
||||||
return (
|
return (
|
||||||
!posting &&
|
!posting.value &&
|
||||||
(1 <= textLength || 1 <= files.length || !!poll || !!props.renote) &&
|
(1 <= textLength.value ||
|
||||||
textLength <= maxTextLength &&
|
1 <= files.value.length ||
|
||||||
(!poll || poll.choices.length >= 2)
|
!!poll.value ||
|
||||||
|
!!props.renote) &&
|
||||||
|
textLength.value <= maxTextLength.value &&
|
||||||
|
(!poll.value || poll.value.choices.length >= 2)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const withHashtags = $computed(
|
const withHashtags = computed(
|
||||||
defaultStore.makeGetterSetter("postFormWithHashtags"),
|
defaultStore.makeGetterSetter("postFormWithHashtags"),
|
||||||
);
|
);
|
||||||
const hashtags = $computed(defaultStore.makeGetterSetter("postFormHashtags"));
|
const hashtags = computed(defaultStore.makeGetterSetter("postFormHashtags"));
|
||||||
|
|
||||||
watch($$(text), () => {
|
watch(text, () => {
|
||||||
checkMissingMention();
|
checkMissingMention();
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
$$(visibleUsers),
|
visibleUsers,
|
||||||
() => {
|
() => {
|
||||||
checkMissingMention();
|
checkMissingMention();
|
||||||
},
|
},
|
||||||
|
@ -442,10 +455,10 @@ watch(
|
||||||
);
|
);
|
||||||
|
|
||||||
if (props.mention) {
|
if (props.mention) {
|
||||||
text = props.mention.host
|
text.value = props.mention.host
|
||||||
? `@${props.mention.username}@${toASCII(props.mention.host)}`
|
? `@${props.mention.username}@${toASCII(props.mention.host)}`
|
||||||
: `@${props.mention.username}`;
|
: `@${props.mention.username}`;
|
||||||
text += " ";
|
text.value += " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -453,7 +466,7 @@ if (
|
||||||
(props.reply.user.username !== $i.username ||
|
(props.reply.user.username !== $i.username ||
|
||||||
(props.reply.user.host != null && props.reply.user.host !== host))
|
(props.reply.user.host != null && props.reply.user.host !== host))
|
||||||
) {
|
) {
|
||||||
text = `@${props.reply.user.username}${
|
text.value = `@${props.reply.user.username}${
|
||||||
props.reply.user.host != null
|
props.reply.user.host != null
|
||||||
? "@" + toASCII(props.reply.user.host)
|
? "@" + toASCII(props.reply.user.host)
|
||||||
: ""
|
: ""
|
||||||
|
@ -476,15 +489,15 @@ if (props.reply && props.reply.text != null) {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// 重複は除外
|
// 重複は除外
|
||||||
if (text.includes(`${mention} `)) continue;
|
if (text.value.includes(`${mention} `)) continue;
|
||||||
|
|
||||||
text += `${mention} `;
|
text.value += `${mention} `;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.channel) {
|
if (props.channel) {
|
||||||
visibility = "public";
|
visibility.value = "public";
|
||||||
localOnly = true; // TODO: チャンネルが連合するようになった折には消す
|
localOnly.value = true; // TODO: チャンネルが連合するようになった折には消す
|
||||||
}
|
}
|
||||||
|
|
||||||
// 公開以外へのリプライ時は元の公開範囲を引き継ぐ
|
// 公開以外へのリプライ時は元の公開範囲を引き継ぐ
|
||||||
|
@ -492,17 +505,17 @@ if (
|
||||||
props.reply &&
|
props.reply &&
|
||||||
["home", "followers", "specified"].includes(props.reply.visibility)
|
["home", "followers", "specified"].includes(props.reply.visibility)
|
||||||
) {
|
) {
|
||||||
if (props.reply.visibility === "home" && visibility === "followers") {
|
if (props.reply.visibility === "home" && visibility.value === "followers") {
|
||||||
visibility = "followers";
|
visibility.value = "followers";
|
||||||
} else if (
|
} else if (
|
||||||
["home", "followers"].includes(props.reply.visibility) &&
|
["home", "followers"].includes(props.reply.visibility) &&
|
||||||
visibility === "specified"
|
visibility.value === "specified"
|
||||||
) {
|
) {
|
||||||
visibility = "specified";
|
visibility.value = "specified";
|
||||||
} else {
|
} else {
|
||||||
visibility = props.reply.visibility;
|
visibility.value = props.reply.visibility;
|
||||||
}
|
}
|
||||||
if (visibility === "specified") {
|
if (visibility.value === "specified") {
|
||||||
if (props.reply.visibleUserIds) {
|
if (props.reply.visibleUserIds) {
|
||||||
os.api("users/show", {
|
os.api("users/show", {
|
||||||
userIds: props.reply.visibleUserIds.filter(
|
userIds: props.reply.visibleUserIds.filter(
|
||||||
|
@ -524,7 +537,7 @@ if (
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.specified) {
|
if (props.specified) {
|
||||||
visibility = "specified";
|
visibility.value = "specified";
|
||||||
pushVisibleUser(props.specified);
|
pushVisibleUser(props.specified);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,53 +553,53 @@ const addRe = (s: string) => {
|
||||||
|
|
||||||
// keep cw when reply
|
// keep cw when reply
|
||||||
if (defaultStore.state.keepCw && props.reply && props.reply.cw) {
|
if (defaultStore.state.keepCw && props.reply && props.reply.cw) {
|
||||||
useCw = true;
|
useCw.value = true;
|
||||||
cw =
|
cw.value =
|
||||||
props.reply.user.username === $i.username
|
props.reply.user.username === $i.username
|
||||||
? props.reply.cw
|
? props.reply.cw
|
||||||
: addRe(props.reply.cw);
|
: addRe(props.reply.cw);
|
||||||
}
|
}
|
||||||
|
|
||||||
function watchForDraft() {
|
function watchForDraft() {
|
||||||
watch($$(text), () => saveDraft());
|
watch(text, () => saveDraft());
|
||||||
watch($$(useCw), () => saveDraft());
|
watch(useCw, () => saveDraft());
|
||||||
watch($$(cw), () => saveDraft());
|
watch(cw, () => saveDraft());
|
||||||
watch($$(poll), () => saveDraft());
|
watch(poll, () => saveDraft());
|
||||||
watch($$(files), () => saveDraft(), { deep: true });
|
watch(files, () => saveDraft(), { deep: true });
|
||||||
watch($$(visibility), () => saveDraft());
|
watch(visibility, () => saveDraft());
|
||||||
watch($$(localOnly), () => saveDraft());
|
watch(localOnly, () => saveDraft());
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkMissingMention() {
|
function checkMissingMention() {
|
||||||
if (visibility === "specified") {
|
if (visibility.value === "specified") {
|
||||||
const ast = mfm.parse(text);
|
const ast = mfm.parse(text.value);
|
||||||
|
|
||||||
for (const x of extractMentions(ast)) {
|
for (const x of extractMentions(ast)) {
|
||||||
if (
|
if (
|
||||||
!visibleUsers.some(
|
!visibleUsers.value.some(
|
||||||
(u) => u.username === x.username && u.host === x.host,
|
(u) => u.username === x.username && u.host === x.host,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
hasNotSpecifiedMentions = true;
|
hasNotSpecifiedMentions.value = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hasNotSpecifiedMentions = false;
|
hasNotSpecifiedMentions.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addMissingMention() {
|
function addMissingMention() {
|
||||||
const ast = mfm.parse(text);
|
const ast = mfm.parse(text.value);
|
||||||
|
|
||||||
for (const x of extractMentions(ast)) {
|
for (const x of extractMentions(ast)) {
|
||||||
if (
|
if (
|
||||||
!visibleUsers.some(
|
!visibleUsers.value.some(
|
||||||
(u) => u.username === x.username && u.host === x.host,
|
(u) => u.username === x.username && u.host === x.host,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
os.api("users/show", { username: x.username, host: x.host }).then(
|
os.api("users/show", { username: x.username, host: x.host }).then(
|
||||||
(user) => {
|
(user) => {
|
||||||
visibleUsers.push(user);
|
visibleUsers.value.push(user);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -594,10 +607,10 @@ function addMissingMention() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function togglePoll() {
|
function togglePoll() {
|
||||||
if (poll) {
|
if (poll.value) {
|
||||||
poll = null;
|
poll.value = null;
|
||||||
} else {
|
} else {
|
||||||
poll = {
|
poll.value = {
|
||||||
choices: ["", ""],
|
choices: ["", ""],
|
||||||
multiple: false,
|
multiple: false,
|
||||||
expiresAt: null,
|
expiresAt: null,
|
||||||
|
@ -606,16 +619,16 @@ function togglePoll() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// function addTag(tag: string) {
|
function addTag(tag: string) {
|
||||||
// insertTextAtCursor(textareaEl, ` #${tag} `);
|
insertTextAtCursor(textareaEl.value, ` #${tag} `);
|
||||||
// }
|
}
|
||||||
|
|
||||||
function focus() {
|
function focus() {
|
||||||
if (textareaEl) {
|
if (textareaEl.value) {
|
||||||
textareaEl.focus();
|
textareaEl.value.focus();
|
||||||
textareaEl.setSelectionRange(
|
textareaEl.value.setSelectionRange(
|
||||||
textareaEl.value.length,
|
textareaEl.value.value.length,
|
||||||
textareaEl.value.length,
|
textareaEl.value.value.length,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -624,31 +637,32 @@ function chooseFileFrom(ev) {
|
||||||
selectFiles(ev.currentTarget ?? ev.target, i18n.ts.attachFile).then(
|
selectFiles(ev.currentTarget ?? ev.target, i18n.ts.attachFile).then(
|
||||||
(files_) => {
|
(files_) => {
|
||||||
for (const file of files_) {
|
for (const file of files_) {
|
||||||
files.push(file);
|
files.value.push(file);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function detachFile(id) {
|
function detachFile(id) {
|
||||||
files = files.filter((x) => x.id !== id);
|
files.value = files.value.filter((x) => x.id !== id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateFiles(_files) {
|
function updateFiles(_files) {
|
||||||
files = _files;
|
files.value = _files;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateFileSensitive(file, sensitive) {
|
function updateFileSensitive(file, sensitive) {
|
||||||
files[files.findIndex((x) => x.id === file.id)].isSensitive = sensitive;
|
files.value[files.value.findIndex((x) => x.id === file.id)].isSensitive =
|
||||||
|
sensitive;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateFileName(file, name) {
|
function updateFileName(file, name) {
|
||||||
files[files.findIndex((x) => x.id === file.id)].name = name;
|
files.value[files.value.findIndex((x) => x.id === file.id)].name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function upload(file: File, name?: string) {
|
function upload(file: File, name?: string) {
|
||||||
uploadFile(file, defaultStore.state.uploadFolder, name).then((res) => {
|
uploadFile(file, defaultStore.state.uploadFolder, name).then((res) => {
|
||||||
files.push(res);
|
files.value.push(res);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -663,21 +677,21 @@ function setVisibility() {
|
||||||
() => import("@/components/MkVisibilityPicker.vue"),
|
() => import("@/components/MkVisibilityPicker.vue"),
|
||||||
),
|
),
|
||||||
{
|
{
|
||||||
currentVisibility: visibility,
|
currentVisibility: visibility.value,
|
||||||
currentLocalOnly: localOnly,
|
currentLocalOnly: localOnly.value,
|
||||||
src: visibilityButton,
|
src: visibilityButton.value,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
changeVisibility: (v) => {
|
changeVisibility: (v) => {
|
||||||
visibility = v;
|
visibility.value = v;
|
||||||
if (defaultStore.state.rememberNoteVisibility) {
|
if (defaultStore.state.rememberNoteVisibility) {
|
||||||
defaultStore.set("visibility", visibility);
|
defaultStore.set("visibility", visibility.value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
changeLocalOnly: (v) => {
|
changeLocalOnly: (v) => {
|
||||||
localOnly = v;
|
localOnly.value = v;
|
||||||
if (defaultStore.state.rememberNoteVisibility) {
|
if (defaultStore.state.rememberNoteVisibility) {
|
||||||
defaultStore.set("localOnly", localOnly);
|
defaultStore.set("localOnly", localOnly.value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -687,11 +701,11 @@ function setVisibility() {
|
||||||
|
|
||||||
function pushVisibleUser(user) {
|
function pushVisibleUser(user) {
|
||||||
if (
|
if (
|
||||||
!visibleUsers.some(
|
!visibleUsers.value.some(
|
||||||
(u) => u.username === user.username && u.host === user.host,
|
(u) => u.username === user.username && u.host === user.host,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
visibleUsers.push(user);
|
visibleUsers.value.push(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -702,21 +716,21 @@ function addVisibleUser() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeVisibleUser(user) {
|
function removeVisibleUser(user) {
|
||||||
visibleUsers = erase(user, visibleUsers);
|
visibleUsers.value = erase(user, visibleUsers.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function clear() {
|
function clear() {
|
||||||
text = "";
|
text.value = "";
|
||||||
files = [];
|
files.value = [];
|
||||||
poll = null;
|
poll.value = null;
|
||||||
quoteId = null;
|
quoteId.value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onKeydown(ev: KeyboardEvent) {
|
function onKeydown(ev: KeyboardEvent) {
|
||||||
if (
|
if (
|
||||||
(ev.which === 10 || ev.which === 13) &&
|
(ev.which === 10 || ev.which === 13) &&
|
||||||
(ev.ctrlKey || ev.metaKey) &&
|
(ev.ctrlKey || ev.metaKey) &&
|
||||||
canPost
|
canPost.value
|
||||||
)
|
)
|
||||||
post();
|
post();
|
||||||
if (ev.which === 27) emit("esc");
|
if (ev.which === 27) emit("esc");
|
||||||
|
@ -724,12 +738,12 @@ function onKeydown(ev: KeyboardEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCompositionUpdate(ev: CompositionEvent) {
|
function onCompositionUpdate(ev: CompositionEvent) {
|
||||||
imeText = ev.data;
|
imeText.value = ev.data;
|
||||||
typing();
|
typing();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCompositionEnd(ev: CompositionEvent) {
|
function onCompositionEnd(ev: CompositionEvent) {
|
||||||
imeText = "";
|
imeText.value = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onPaste(ev: ClipboardEvent) {
|
async function onPaste(ev: ClipboardEvent) {
|
||||||
|
@ -750,7 +764,7 @@ async function onPaste(ev: ClipboardEvent) {
|
||||||
|
|
||||||
const paste = ev.clipboardData.getData("text");
|
const paste = ev.clipboardData.getData("text");
|
||||||
|
|
||||||
if (!props.renote && !quoteId && paste.startsWith(url + "/notes/")) {
|
if (!props.renote && !quoteId.value && paste.startsWith(url + "/notes/")) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
|
|
||||||
os.yesno({
|
os.yesno({
|
||||||
|
@ -758,11 +772,13 @@ async function onPaste(ev: ClipboardEvent) {
|
||||||
text: i18n.ts.quoteQuestion,
|
text: i18n.ts.quoteQuestion,
|
||||||
}).then(({ canceled }) => {
|
}).then(({ canceled }) => {
|
||||||
if (canceled) {
|
if (canceled) {
|
||||||
insertTextAtCursor(textareaEl, paste);
|
insertTextAtCursor(textareaEl.value, paste);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
quoteId = paste.substr(url.length).match(/^\/notes\/(.+?)\/?$/)[1];
|
quoteId.value = paste
|
||||||
|
.substr(url.length)
|
||||||
|
.match(/^\/notes\/(.+?)\/?$/)[1];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -773,7 +789,7 @@ function onDragover(ev) {
|
||||||
const isDriveFile = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FILE_;
|
const isDriveFile = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FILE_;
|
||||||
if (isFile || isDriveFile) {
|
if (isFile || isDriveFile) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
draghover = true;
|
draghover.value = true;
|
||||||
switch (ev.dataTransfer.effectAllowed) {
|
switch (ev.dataTransfer.effectAllowed) {
|
||||||
case "all":
|
case "all":
|
||||||
case "uninitialized":
|
case "uninitialized":
|
||||||
|
@ -794,15 +810,15 @@ function onDragover(ev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDragenter(ev) {
|
function onDragenter(ev) {
|
||||||
draghover = true;
|
draghover.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDragleave(ev) {
|
function onDragleave(ev) {
|
||||||
draghover = false;
|
draghover.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDrop(ev): void {
|
function onDrop(ev): void {
|
||||||
draghover = false;
|
draghover.value = false;
|
||||||
|
|
||||||
// ファイルだったら
|
// ファイルだったら
|
||||||
if (ev.dataTransfer.files.length > 0) {
|
if (ev.dataTransfer.files.length > 0) {
|
||||||
|
@ -815,7 +831,7 @@ function onDrop(ev): void {
|
||||||
const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
|
const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
|
||||||
if (driveFile != null && driveFile !== "") {
|
if (driveFile != null && driveFile !== "") {
|
||||||
const file = JSON.parse(driveFile);
|
const file = JSON.parse(driveFile);
|
||||||
files.push(file);
|
files.value.push(file);
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
@ -824,16 +840,16 @@ function onDrop(ev): void {
|
||||||
function saveDraft() {
|
function saveDraft() {
|
||||||
const draftData = JSON.parse(localStorage.getItem("drafts") || "{}");
|
const draftData = JSON.parse(localStorage.getItem("drafts") || "{}");
|
||||||
|
|
||||||
draftData[draftKey] = {
|
draftData[draftKey.value] = {
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
data: {
|
data: {
|
||||||
text: text,
|
text: text.value,
|
||||||
useCw: useCw,
|
useCw: useCw.value,
|
||||||
cw: cw,
|
cw: cw.value,
|
||||||
visibility: visibility,
|
visibility: visibility.value,
|
||||||
localOnly: localOnly,
|
localOnly: localOnly.value,
|
||||||
files: files,
|
files: files.value,
|
||||||
poll: poll,
|
poll: poll.value,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -843,37 +859,38 @@ function saveDraft() {
|
||||||
function deleteDraft() {
|
function deleteDraft() {
|
||||||
const draftData = JSON.parse(localStorage.getItem("drafts") || "{}");
|
const draftData = JSON.parse(localStorage.getItem("drafts") || "{}");
|
||||||
|
|
||||||
delete draftData[draftKey];
|
delete draftData[draftKey.value];
|
||||||
|
|
||||||
localStorage.setItem("drafts", JSON.stringify(draftData));
|
localStorage.setItem("drafts", JSON.stringify(draftData));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function post() {
|
async function post() {
|
||||||
const processedText = preprocess(text);
|
const processedText = preprocess(text.value);
|
||||||
|
|
||||||
let postData = {
|
let postData = {
|
||||||
editId: props.editId ? props.editId : undefined,
|
editId: props.editId ? props.editId : undefined,
|
||||||
text: processedText === "" ? undefined : processedText,
|
text: processedText === "" ? undefined : processedText,
|
||||||
fileIds: files.length > 0 ? files.map((f) => f.id) : undefined,
|
fileIds:
|
||||||
|
files.value.length > 0 ? files.value.map((f) => f.id) : undefined,
|
||||||
replyId: props.reply ? props.reply.id : undefined,
|
replyId: props.reply ? props.reply.id : undefined,
|
||||||
renoteId: props.renote
|
renoteId: props.renote
|
||||||
? props.renote.id
|
? props.renote.id
|
||||||
: quoteId
|
: quoteId.value
|
||||||
? quoteId
|
? quoteId.value
|
||||||
: undefined,
|
: undefined,
|
||||||
channelId: props.channel ? props.channel.id : undefined,
|
channelId: props.channel ? props.channel.id : undefined,
|
||||||
poll: poll,
|
poll: poll.value,
|
||||||
cw: useCw ? cw || "" : undefined,
|
cw: useCw.value ? cw.value || "" : undefined,
|
||||||
localOnly: localOnly,
|
localOnly: localOnly.value,
|
||||||
visibility: visibility,
|
visibility: visibility.value,
|
||||||
visibleUserIds:
|
visibleUserIds:
|
||||||
visibility === "specified"
|
visibility.value === "specified"
|
||||||
? visibleUsers.map((u) => u.id)
|
? visibleUsers.value.map((u) => u.id)
|
||||||
: undefined,
|
: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (withHashtags && hashtags && hashtags.trim() !== "") {
|
if (withHashtags.value && hashtags.value && hashtags.value.trim() !== "") {
|
||||||
const hashtags_ = hashtags
|
const hashtags_ = hashtags.value
|
||||||
.trim()
|
.trim()
|
||||||
.split(" ")
|
.split(" ")
|
||||||
.map((x) => (x.startsWith("#") ? x : "#" + x))
|
.map((x) => (x.startsWith("#") ? x : "#" + x))
|
||||||
|
@ -892,12 +909,13 @@ async function post() {
|
||||||
|
|
||||||
let token = undefined;
|
let token = undefined;
|
||||||
|
|
||||||
if (postAccount) {
|
if (postAccount.value) {
|
||||||
const storedAccounts = await getAccounts();
|
const storedAccounts = await getAccounts();
|
||||||
token = storedAccounts.find((x) => x.id === postAccount.id)?.token;
|
token = storedAccounts.find((x) => x.id === postAccount.value.id)
|
||||||
|
?.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
posting = true;
|
posting.value = true;
|
||||||
os.api(postData.editId ? "notes/edit" : "notes/create", postData, token)
|
os.api(postData.editId ? "notes/edit" : "notes/create", postData, token)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
clear();
|
clear();
|
||||||
|
@ -917,12 +935,12 @@ async function post() {
|
||||||
JSON.stringify(unique(hashtags_.concat(history))),
|
JSON.stringify(unique(hashtags_.concat(history))),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
posting = false;
|
posting.value = false;
|
||||||
postAccount = null;
|
postAccount.value = null;
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
posting = false;
|
posting.value = false;
|
||||||
os.alert({
|
os.alert({
|
||||||
type: "error",
|
type: "error",
|
||||||
text: err.message + "\n" + (err as any).id,
|
text: err.message + "\n" + (err as any).id,
|
||||||
|
@ -936,12 +954,12 @@ function cancel() {
|
||||||
|
|
||||||
function insertMention() {
|
function insertMention() {
|
||||||
os.selectUser().then((user) => {
|
os.selectUser().then((user) => {
|
||||||
insertTextAtCursor(textareaEl, "@" + Acct.toString(user) + " ");
|
insertTextAtCursor(textareaEl.value, "@" + Acct.toString(user) + " ");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function insertEmoji(ev: MouseEvent) {
|
async function insertEmoji(ev: MouseEvent) {
|
||||||
os.openEmojiPicker(ev.currentTarget ?? ev.target, {}, textareaEl);
|
os.openEmojiPicker(ev.currentTarget ?? ev.target, {}, textareaEl.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showActions(ev) {
|
function showActions(ev) {
|
||||||
|
@ -951,11 +969,11 @@ function showActions(ev) {
|
||||||
action: () => {
|
action: () => {
|
||||||
action.handler(
|
action.handler(
|
||||||
{
|
{
|
||||||
text: text,
|
text: text.value,
|
||||||
},
|
},
|
||||||
(key, value) => {
|
(key, value) => {
|
||||||
if (key === "text") {
|
if (key === "text") {
|
||||||
text = value;
|
text.value = value;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -965,19 +983,19 @@ function showActions(ev) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let postAccount = $ref<misskey.entities.UserDetailed | null>(null);
|
let postAccount = ref<misskey.entities.UserDetailed | null>(null);
|
||||||
|
|
||||||
function openAccountMenu(ev: MouseEvent) {
|
function openAccountMenu(ev: MouseEvent) {
|
||||||
openAccountMenu_(
|
openAccountMenu_(
|
||||||
{
|
{
|
||||||
withExtraOperation: false,
|
withExtraOperation: false,
|
||||||
includeCurrentAccount: true,
|
includeCurrentAccount: true,
|
||||||
active: postAccount != null ? postAccount.id : $i.id,
|
active: postAccount.value != null ? postAccount.value.id : $i.id,
|
||||||
onChoose: (account) => {
|
onChoose: (account) => {
|
||||||
if (account.id === $i.id) {
|
if (account.id === $i.id) {
|
||||||
postAccount = null;
|
postAccount.value = null;
|
||||||
} else {
|
} else {
|
||||||
postAccount = account;
|
postAccount.value = account;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -995,30 +1013,30 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: detach when unmount
|
// TODO: detach when unmount
|
||||||
new Autocomplete(textareaEl, $$(text));
|
new Autocomplete(textareaEl.value, text);
|
||||||
new Autocomplete(cwInputEl, $$(cw));
|
new Autocomplete(cwInputEl.value, cw);
|
||||||
new Autocomplete(hashtagsInputEl, $$(hashtags));
|
new Autocomplete(hashtagsInputEl.value, hashtags);
|
||||||
|
|
||||||
autosize(textareaEl);
|
autosize(textareaEl.value);
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
autosize(textareaEl);
|
autosize(textareaEl.value);
|
||||||
// 書きかけの投稿を復元
|
// 書きかけの投稿を復元
|
||||||
if (!props.instant && !props.mention && !props.specified) {
|
if (!props.instant && !props.mention && !props.specified) {
|
||||||
const draft = JSON.parse(localStorage.getItem("drafts") || "{}")[
|
const draft = JSON.parse(localStorage.getItem("drafts") || "{}")[
|
||||||
draftKey
|
draftKey.value
|
||||||
];
|
];
|
||||||
if (draft) {
|
if (draft) {
|
||||||
text = draft.data.text;
|
text.value = draft.data.text;
|
||||||
useCw = draft.data.useCw;
|
useCw.value = draft.data.useCw;
|
||||||
cw = draft.data.cw;
|
cw.value = draft.data.cw;
|
||||||
visibility = draft.data.visibility;
|
visibility.value = draft.data.visibility;
|
||||||
localOnly = draft.data.localOnly;
|
localOnly.value = draft.data.localOnly;
|
||||||
files = (draft.data.files || []).filter(
|
files.value = (draft.data.files || []).filter(
|
||||||
(draftFile) => draftFile,
|
(draftFile) => draftFile,
|
||||||
);
|
);
|
||||||
if (draft.data.poll) {
|
if (draft.data.poll) {
|
||||||
poll = draft.data.poll;
|
poll.value = draft.data.poll;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1026,21 +1044,21 @@ onMounted(() => {
|
||||||
// 削除して編集
|
// 削除して編集
|
||||||
if (props.initialNote) {
|
if (props.initialNote) {
|
||||||
const init = props.initialNote;
|
const init = props.initialNote;
|
||||||
text = init.text ? init.text : "";
|
text.value = init.text ? init.text : "";
|
||||||
files = init.files;
|
files.value = init.files;
|
||||||
cw = init.cw;
|
cw.value = init.cw;
|
||||||
useCw = init.cw != null;
|
useCw.value = init.cw != null;
|
||||||
if (init.poll) {
|
if (init.poll) {
|
||||||
poll = {
|
poll.value = {
|
||||||
choices: init.poll.choices.map((x) => x.text),
|
choices: init.poll.choices.map((x) => x.text),
|
||||||
multiple: init.poll.multiple,
|
multiple: init.poll.multiple,
|
||||||
expiresAt: init.poll.expiresAt,
|
expiresAt: init.poll.expiresAt,
|
||||||
expiredAfter: init.poll.expiredAfter,
|
expiredAfter: init.poll.expiredAfter,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
visibility = init.visibility;
|
visibility.value = init.visibility;
|
||||||
localOnly = init.localOnly;
|
localOnly.value = init.localOnly;
|
||||||
quoteId = init.renote ? init.renote.id : null;
|
quoteId.value = init.renote ? init.renote.id : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTick(() => watchForDraft());
|
nextTick(() => watchForDraft());
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { shallowRef } from "vue";
|
||||||
|
|
||||||
import {} from "vue";
|
import {} from "vue";
|
||||||
import * as misskey from "firefish-js";
|
import * as misskey from "firefish-js";
|
||||||
import MkModal from "@/components/MkModal.vue";
|
import MkModal from "@/components/MkModal.vue";
|
||||||
|
@ -46,11 +48,11 @@ const emit = defineEmits<{
|
||||||
(ev: "closed"): void;
|
(ev: "closed"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let modal = $shallowRef<InstanceType<typeof MkModal>>();
|
let modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
let form = $shallowRef<InstanceType<typeof MkPostForm>>();
|
let form = shallowRef<InstanceType<typeof MkPostForm>>();
|
||||||
|
|
||||||
function onPosted() {
|
function onPosted() {
|
||||||
modal.close({
|
modal.value.close({
|
||||||
useSendAnimation: true,
|
useSendAnimation: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
import { $i, getAccounts } from "@/account";
|
import { $i, getAccounts } from "@/account";
|
||||||
import MkButton from "@/components/MkButton.vue";
|
import MkButton from "@/components/MkButton.vue";
|
||||||
import { instance } from "@/instance";
|
import { instance } from "@/instance";
|
||||||
|
@ -74,12 +76,12 @@ defineProps<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// ServiceWorker registration
|
// ServiceWorker registration
|
||||||
let registration = $ref<ServiceWorkerRegistration | undefined>();
|
let registration = ref<ServiceWorkerRegistration | undefined>();
|
||||||
// If this browser supports push notification
|
// If this browser supports push notification
|
||||||
let supported = $ref(false);
|
let supported = ref(false);
|
||||||
// If this browser has already subscribed to push notification
|
// If this browser has already subscribed to push notification
|
||||||
let pushSubscription = $ref<PushSubscription | null>(null);
|
let pushSubscription = ref<PushSubscription | null>(null);
|
||||||
let pushRegistrationInServer = $ref<
|
let pushRegistrationInServer = ref<
|
||||||
| {
|
| {
|
||||||
state?: string;
|
state?: string;
|
||||||
key?: string;
|
key?: string;
|
||||||
|
@ -91,11 +93,12 @@ let pushRegistrationInServer = $ref<
|
||||||
>();
|
>();
|
||||||
|
|
||||||
function subscribe() {
|
function subscribe() {
|
||||||
if (!registration || !supported || !instance.swPublickey) return;
|
if (!registration.value || !supported.value || !instance.swPublickey)
|
||||||
|
return;
|
||||||
|
|
||||||
// SEE: https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe#Parameters
|
// SEE: https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe#Parameters
|
||||||
return promiseDialog(
|
return promiseDialog(
|
||||||
registration.pushManager
|
registration.value.pushManager
|
||||||
.subscribe({
|
.subscribe({
|
||||||
userVisibleOnly: true,
|
userVisibleOnly: true,
|
||||||
applicationServerKey: urlBase64ToUint8Array(
|
applicationServerKey: urlBase64ToUint8Array(
|
||||||
|
@ -104,10 +107,10 @@ function subscribe() {
|
||||||
})
|
})
|
||||||
.then(
|
.then(
|
||||||
async (subscription) => {
|
async (subscription) => {
|
||||||
pushSubscription = subscription;
|
pushSubscription.value = subscription;
|
||||||
|
|
||||||
// Register
|
// Register
|
||||||
pushRegistrationInServer = await api("sw/register", {
|
pushRegistrationInServer.value = await api("sw/register", {
|
||||||
endpoint: subscription.endpoint,
|
endpoint: subscription.endpoint,
|
||||||
auth: encode(subscription.getKey("auth")),
|
auth: encode(subscription.getKey("auth")),
|
||||||
publickey: encode(subscription.getKey("p256dh")),
|
publickey: encode(subscription.getKey("p256dh")),
|
||||||
|
@ -136,12 +139,12 @@ function subscribe() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function unsubscribe() {
|
async function unsubscribe() {
|
||||||
if (!pushSubscription) return;
|
if (!pushSubscription.value) return;
|
||||||
|
|
||||||
const endpoint = pushSubscription.endpoint;
|
const endpoint = pushSubscription.value.endpoint;
|
||||||
const accounts = await getAccounts();
|
const accounts = await getAccounts();
|
||||||
|
|
||||||
pushRegistrationInServer = undefined;
|
pushRegistrationInServer.value = undefined;
|
||||||
|
|
||||||
if ($i && accounts.length >= 2) {
|
if ($i && accounts.length >= 2) {
|
||||||
apiWithDialog("sw/unregister", {
|
apiWithDialog("sw/unregister", {
|
||||||
|
@ -149,11 +152,11 @@ async function unsubscribe() {
|
||||||
endpoint,
|
endpoint,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
pushSubscription.unsubscribe();
|
pushSubscription.value.unsubscribe();
|
||||||
apiWithDialog("sw/unregister", {
|
apiWithDialog("sw/unregister", {
|
||||||
endpoint,
|
endpoint,
|
||||||
});
|
});
|
||||||
pushSubscription = null;
|
pushSubscription.value = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,20 +187,21 @@ if (navigator.serviceWorker == null) {
|
||||||
// TODO: よしなに?
|
// TODO: よしなに?
|
||||||
} else {
|
} else {
|
||||||
navigator.serviceWorker.ready.then(async (swr) => {
|
navigator.serviceWorker.ready.then(async (swr) => {
|
||||||
registration = swr;
|
registration.value = swr;
|
||||||
|
|
||||||
pushSubscription = await registration.pushManager.getSubscription();
|
pushSubscription.value =
|
||||||
|
await registration.value.pushManager.getSubscription();
|
||||||
|
|
||||||
if (instance.swPublickey && "PushManager" in window && $i && $i.token) {
|
if (instance.swPublickey && "PushManager" in window && $i && $i.token) {
|
||||||
supported = true;
|
supported.value = true;
|
||||||
|
|
||||||
if (pushSubscription) {
|
if (pushSubscription.value) {
|
||||||
const res = await api("sw/show-registration", {
|
const res = await api("sw/show-registration", {
|
||||||
endpoint: pushSubscription.endpoint,
|
endpoint: pushSubscription.value.endpoint,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
pushRegistrationInServer = res;
|
pushRegistrationInServer.value = res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,6 +209,6 @@ if (navigator.serviceWorker == null) {
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
pushRegistrationInServer: $$(pushRegistrationInServer),
|
pushRegistrationInServer: pushRegistrationInServer,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue