Compare commits
167 Commits
Author | SHA1 | Date | |
---|---|---|---|
2924f0e434 | |||
1e419a9e1f | |||
097ece9dc9 | |||
6b6483c9fc | |||
22049b10ff | |||
de86644cb6 | |||
657aac5bc5 | |||
7ae3640d1a | |||
6fb42857c6 | |||
abf21349cd | |||
ed17af8339 | |||
67f391f6d4 | |||
c6b25f317e | |||
d91fa1a37a | |||
6c3f052996 | |||
33b0c87fb1 | |||
5c490e7521 | |||
54961235a4 | |||
17eca2a18f | |||
137f3ee609 | |||
498f6e9be2 | |||
a5e841f59c | |||
9adab1e85e | |||
4288a843cb | |||
1669f5b265 | |||
1157298eb8 | |||
948a65bf39 | |||
20c076b369 | |||
b67ed64116 | |||
1da3777bfb | |||
ea6aa40b09 | |||
b002651194 | |||
1452512daf | |||
0e7778bebf | |||
698fbdf88b | |||
7b738deabf | |||
3c65e7b76e | |||
3fc427b699 | |||
03667e1fe6 | |||
5cfd000a7d | |||
fa66eac096 | |||
70eb75b7e6 | |||
2f6187a26a | |||
167da988da | |||
6935e647a6 | |||
743eca4a95 | |||
78598a92f9 | |||
94598ab555 | |||
c5bdee086d | |||
c6cfc3f908 | |||
84b488a912 | |||
ec4d5857d8 | |||
4576641105 | |||
572e475b39 | |||
882a30fabe | |||
feec35bf4f | |||
c9fea5a7a0 | |||
00f3a1e1ec | |||
5a8cc7851b | |||
9d81d06853 | |||
4fce5d8066 | |||
329e367bda | |||
ce056bf936 | |||
c6ab5faba6 | |||
6ce0804b43 | |||
a7a6563281 | |||
0a084a3363 | |||
beeb8de6da | |||
e73297f260 | |||
b408ef5ba5 | |||
50539099ab | |||
9a3a77cff0 | |||
cdc07945af | |||
9f9194ab5c | |||
136a087ae7 | |||
b9e91afa26 | |||
f943e39c89 | |||
75bdbff36d | |||
43930e6a84 | |||
57d0c19a98 | |||
66a11378d2 | |||
62b680cadd | |||
1e1ac13999 | |||
d27c454674 | |||
3263eaec32 | |||
de4e9a857c | |||
d838876ab1 | |||
03336f01b5 | |||
d212d693a4 | |||
d17fcd8e48 | |||
49b3ee36bd | |||
100d7adc3d | |||
68b1fea6bb | |||
4de6e1e28a | |||
84f8c34e90 | |||
77567cf114 | |||
3cf8e1917c | |||
84cbabec29 | |||
b88c65ab67 | |||
10782822de | |||
5457172aa5 | |||
d20a2c7080 | |||
c01098de16 | |||
0b14a57d55 | |||
405d104208 | |||
83e3316f06 | |||
2037d4c21d | |||
6cabf052b1 | |||
359e1b2e6e | |||
7b553b13ac | |||
79872ec3e8 | |||
e9df7265fa | |||
1ade89be35 | |||
3356f7113f | |||
e6495ea6e2 | |||
629991443a | |||
6848f05ea5 | |||
e58dd71829 | |||
1afa2f1202 | |||
f322cb444a | |||
69c3c4e3dc | |||
488e6feed9 | |||
40891aca48 | |||
cd0e557991 | |||
679f8ad614 | |||
00c647c736 | |||
1ac6af6ad1 | |||
a5d7099a3c | |||
e9c8a0f5d5 | |||
adcda0889e | |||
95cbcdd379 | |||
a5e8eb4b7b | |||
ed440f80f3 | |||
4e2ef94107 | |||
de690e0622 | |||
062e1a4940 | |||
cc3779b197 | |||
92dc34b51a | |||
f8ee615640 | |||
5dde8b4bdc | |||
2c70055a87 | |||
db8ab8b890 | |||
28da5c5a31 | |||
b345aad52c | |||
aa5af89dfc | |||
9a3a74db34 | |||
328619f1fc | |||
121e12785f | |||
cc3f0737a2 | |||
bc3714139f | |||
9200379997 | |||
0ee664db2b | |||
86487e6f66 | |||
adc2bcc59b | |||
21a54f559a | |||
145e16c266 | |||
68f4edd0ee | |||
7fd6a134d1 | |||
0db8d566e2 | |||
c6f6291fc0 | |||
c2d79450ea | |||
d58ae601f7 | |||
3ad73ad7d9 | |||
f0c4df1cc5 | |||
839784bc8c | |||
b758ec96ef | |||
2f8ceb9d22 |
@ -32,7 +32,7 @@ jobs:
|
||||
apk update && apk add jq
|
||||
docker tag misskey/misskey misskey/misskey:$(cat package.json | jq -r .version)
|
||||
docker login -u $DOCKERHUB_USERNAME -p $DOCKERHUB_PASSWORD
|
||||
docker push misskey/misskey
|
||||
docker push -a misskey/misskey
|
||||
else
|
||||
echo -e '\033[0;33mAborted deploying to Docker Hub\033[0;39m'
|
||||
fi
|
||||
|
@ -1,3 +1,7 @@
|
||||
files:
|
||||
- source: /locales/ja-JP.yml
|
||||
translation: /locales/%locale%.yml
|
||||
update_option: update_as_unapproved
|
||||
- source: /src/docs/ja-JP/*.md
|
||||
translation: /src/docs/%locale%/%original_file_name%
|
||||
update_option: update_as_unapproved
|
||||
|
27
gulpfile.ts
27
gulpfile.ts
@ -7,6 +7,9 @@ import * as gulp from 'gulp';
|
||||
import * as ts from 'gulp-typescript';
|
||||
import * as rimraf from 'rimraf';
|
||||
import * as rename from 'gulp-rename';
|
||||
import * as replace from 'gulp-replace';
|
||||
const terser = require('gulp-terser');
|
||||
const cssnano = require('gulp-cssnano');
|
||||
|
||||
const locales: { [x: string]: any } = require('./locales');
|
||||
const meta = require('./package.json');
|
||||
@ -25,6 +28,10 @@ gulp.task('build:copy:views', () =>
|
||||
gulp.src('./src/server/web/views/**/*').pipe(gulp.dest('./built/server/web/views'))
|
||||
);
|
||||
|
||||
gulp.task('build:copy:fonts', () =>
|
||||
gulp.src('./node_modules/three/examples/fonts/**/*').pipe(gulp.dest('./built/client/assets/fonts/'))
|
||||
);
|
||||
|
||||
gulp.task('build:copy:locales', cb => {
|
||||
fs.mkdirSync('./built/client/assets/locales', { recursive: true });
|
||||
|
||||
@ -37,11 +44,23 @@ gulp.task('build:copy:locales', cb => {
|
||||
cb();
|
||||
});
|
||||
|
||||
gulp.task('build:copy:fonts', () =>
|
||||
gulp.src('./node_modules/three/examples/fonts/**/*').pipe(gulp.dest('./built/client/assets/fonts/'))
|
||||
);
|
||||
gulp.task('build:client:script', () => {
|
||||
return gulp.src(['./src/server/web/boot.js'])
|
||||
.pipe(replace('VERSION', JSON.stringify(meta.version)))
|
||||
.pipe(replace('LANGS', JSON.stringify(Object.keys(locales))))
|
||||
.pipe(terser({
|
||||
toplevel: true
|
||||
}))
|
||||
.pipe(gulp.dest('./built/server/web/'));
|
||||
});
|
||||
|
||||
gulp.task('build:copy', gulp.parallel('build:copy:views', 'build:copy:locales', 'build:copy:fonts', () =>
|
||||
gulp.task('build:client:style', () => {
|
||||
return gulp.src(['./src/server/web/style.css'])
|
||||
.pipe(cssnano())
|
||||
.pipe(gulp.dest('./built/server/web/'));
|
||||
});
|
||||
|
||||
gulp.task('build:copy', gulp.parallel('build:copy:locales', 'build:copy:views', 'build:client:script', 'build:client:style', 'build:copy:fonts', () =>
|
||||
gulp.src([
|
||||
'./src/emojilist.json',
|
||||
'./src/server/web/views/**/*',
|
||||
|
@ -33,6 +33,9 @@ addUser: "Benutzer hinzufügen"
|
||||
favorite: "Zu Favoriten hinzufügen"
|
||||
favorites: "Favoriten"
|
||||
unfavorite: "Aus Favoriten entfernen"
|
||||
favorited: "Zu Favoriten hinzugefügt."
|
||||
alreadyFavorited: "Bereits zu den Favoriten hinzugefügt."
|
||||
cantFavorite: "Hinzufügen zu Favoriten fehlgeschlagen."
|
||||
pin: "Anheften"
|
||||
unpin: "Lösen"
|
||||
copyContent: "Inhalt kopieren"
|
||||
@ -87,6 +90,9 @@ followRequestPending: "Ausstehende Follow-Anfrage"
|
||||
enterEmoji: "Gib ein Emoji ein"
|
||||
renote: "Renote"
|
||||
unrenote: "Renote zurücknehmen"
|
||||
renoted: "Renote getätigt."
|
||||
cantRenote: "Renote dieses Beitrags nicht möglich."
|
||||
cantReRenote: "Renote einer Renote nicht möglich."
|
||||
quote: "Zitieren"
|
||||
pinnedNote: "Angepinnte Notiz"
|
||||
you: "Du"
|
||||
@ -237,7 +243,7 @@ nUsersRead: "Von {n} gelesen"
|
||||
agreeTo: "Ich stimme {0} zu"
|
||||
tos: "Nutzungsbedingungen"
|
||||
start: "Anfangen"
|
||||
home: "Startseite"
|
||||
home: "Home"
|
||||
remoteUserCaution: "Diese Informationen sind möglicherweise veraltet, da der Benutzer von einer anderen Instanz stammt."
|
||||
activity: "Aktivität"
|
||||
images: "Bilder"
|
||||
@ -619,7 +625,7 @@ createNew: "Neu erstellen"
|
||||
optional: "Optional"
|
||||
createNewClip: "Neuen Clip erstellen"
|
||||
public: "Öffentlich"
|
||||
i18nInfo: "Misskey wird durch freiwillige Helfer in viele verschiedene Sprachen übersetzt. Unter {link} kannst du mithelfen."
|
||||
i18nInfo: "Misskey wird durch freiwillige Helfer in viele verschiedene Sprachen übersetzt. Auf {link} kannst du mithelfen."
|
||||
manageAccessTokens: "Zugriffstoken verwalten"
|
||||
accountInfo: "Benutzerkonto-Informationen"
|
||||
notesCount: "Anzahl von Notizen"
|
||||
@ -655,6 +661,15 @@ useSystemFont: "Standardschriftart des Systems verwenden"
|
||||
clips: "Clips"
|
||||
experimentalFeatures: "Experimentelle Funktionalitäten"
|
||||
developer: "Entwickler"
|
||||
makeExplorable: "Benutzerkonto in \"Erkunden\" sichtbar machen"
|
||||
makeExplorableDescription: "Wenn diese Option deaktiviert ist, ist dein Benutzerkonto nicht im \"Erkunden\"-Bereich sichtbar."
|
||||
showGapBetweenNotesInTimeline: "Abstände zwischen Notizen auf der Chronik anzeigen"
|
||||
duplicate: "Duplizieren"
|
||||
left: "Links"
|
||||
center: "Mitte"
|
||||
wide: "Breit"
|
||||
narrow: "Schmal"
|
||||
reloadToApplySetting: "Einstellungen treten nach einer Aktualisierung der Seite in Kraft. Jetzt aktualisieren?"
|
||||
_aboutMisskey:
|
||||
about: "Misskey ist Open-Source-Software die von syuilo seit 2014 entwickelt wird."
|
||||
contributors: "Hauptmitwirkende"
|
||||
@ -975,6 +990,7 @@ _widgets:
|
||||
federation: "Föderation"
|
||||
postForm: "Neue Notiz anfertigen"
|
||||
slideshow: "Diashow"
|
||||
button: "Knopf"
|
||||
_cw:
|
||||
hide: "Ausblenden"
|
||||
show: "Mehr anzeigen"
|
||||
@ -1457,6 +1473,8 @@ _notification:
|
||||
_deck:
|
||||
alwaysShowMainColumn: "Hauptspalte immer zeigen"
|
||||
columnAlign: "Spalten ausrichten"
|
||||
columnMargin: "Spaltenabstand"
|
||||
columnHeaderHeight: "Spaltenkopfhöhe"
|
||||
addColumn: "Spalte hinzufügen"
|
||||
swapLeft: "Nach links verschieben"
|
||||
swapRight: "Nach rechts verschieben"
|
||||
@ -1465,6 +1483,7 @@ _deck:
|
||||
stackLeft: "Nach links stapeln"
|
||||
popRight: "Nach rechts vom Stapel nehmen"
|
||||
_columns:
|
||||
main: "Hauptspalte"
|
||||
widgets: "Widgets"
|
||||
notifications: "Benachrichtigungen"
|
||||
tl: "Chronik"
|
||||
|
@ -33,6 +33,9 @@ addUser: "Add a user"
|
||||
favorite: "Favorite"
|
||||
favorites: "Favorites"
|
||||
unfavorite: "Unfavorite"
|
||||
favorited: "Added to favorites."
|
||||
alreadyFavorited: "Already added to favorites."
|
||||
cantFavorite: "Couldn't add to favorites."
|
||||
pin: "Pin to profile"
|
||||
unpin: "Unpin from profile"
|
||||
copyContent: "Copy contents"
|
||||
@ -63,7 +66,7 @@ exportRequested: "You have requested an export. This may take a while. After the
|
||||
importRequested: "You requested an import. This may take a while."
|
||||
lists: "Lists"
|
||||
noLists: "You don't have any lists"
|
||||
note: "Notes"
|
||||
note: "Note"
|
||||
notes: "Notes"
|
||||
following: "Following"
|
||||
followers: "Followers"
|
||||
@ -87,6 +90,9 @@ followRequestPending: "Pending follow request"
|
||||
enterEmoji: "Enter an emoji"
|
||||
renote: "Renote"
|
||||
unrenote: "Unrenote"
|
||||
renoted: "Renoted."
|
||||
cantRenote: "This post can't be renoted."
|
||||
cantReRenote: "A renote can't be renoted."
|
||||
quote: "Quote"
|
||||
pinnedNote: "Pinned note"
|
||||
you: "You"
|
||||
@ -245,7 +251,7 @@ birthday: "Birthday"
|
||||
yearsOld: "{age} years old"
|
||||
registeredDate: "Joined on"
|
||||
location: "Location"
|
||||
theme: "Theme"
|
||||
theme: "Themes"
|
||||
themeForLightMode: "Theme to use in Light Mode"
|
||||
themeForDarkMode: "Theme to use in Dark Mode"
|
||||
light: "Light"
|
||||
@ -655,6 +661,15 @@ useSystemFont: "Use the system's default font"
|
||||
clips: "Clips"
|
||||
experimentalFeatures: "Experimental features"
|
||||
developer: "Developer"
|
||||
makeExplorable: "Make account visible in \"Explore\""
|
||||
makeExplorableDescription: "If you turn this off, your account will not show up in the \"Explore\" section."
|
||||
showGapBetweenNotesInTimeline: "Show a gap between posts on the timeline"
|
||||
duplicate: "Duplicate"
|
||||
left: "Left"
|
||||
center: "Center"
|
||||
wide: "Wide"
|
||||
narrow: "Narrow"
|
||||
reloadToApplySetting: "Settings will be applied upon page reload. Reload now?"
|
||||
_aboutMisskey:
|
||||
about: "Misskey is open-source software being developed by syuilo since 2014."
|
||||
contributors: "Main contributors"
|
||||
@ -975,6 +990,7 @@ _widgets:
|
||||
federation: "Federation"
|
||||
postForm: "Compose a note"
|
||||
slideshow: "Slideshow"
|
||||
button: "Button"
|
||||
_cw:
|
||||
hide: "Hide"
|
||||
show: "Load more"
|
||||
@ -1457,6 +1473,8 @@ _notification:
|
||||
_deck:
|
||||
alwaysShowMainColumn: "Always show main column"
|
||||
columnAlign: "Align columns"
|
||||
columnMargin: "Margin between columns"
|
||||
columnHeaderHeight: " Column header height"
|
||||
addColumn: "Add column"
|
||||
swapLeft: "Swap to left"
|
||||
swapRight: "Swap to right"
|
||||
@ -1465,6 +1483,7 @@ _deck:
|
||||
stackLeft: "Stack on the left"
|
||||
popRight: "Pop to the right"
|
||||
_columns:
|
||||
main: "Main"
|
||||
widgets: "Widgets"
|
||||
notifications: "Notifications"
|
||||
tl: "Timeline"
|
||||
|
@ -33,6 +33,9 @@ addUser: "Agregar usuario"
|
||||
favorite: "Favorito"
|
||||
favorites: "Favoritos"
|
||||
unfavorite: "Quitar de favoritos"
|
||||
favorited: "Añadido a favoritos"
|
||||
alreadyFavorited: "Ya había sido añadido a favoritos"
|
||||
cantFavorite: "No fue añadido a favoritos"
|
||||
pin: "Fijar"
|
||||
unpin: "Desfijar"
|
||||
copyContent: "Copiar contenido"
|
||||
@ -87,6 +90,9 @@ followRequestPending: "Solicitudes de seguimiento pendientes"
|
||||
enterEmoji: "Ingresar emojis"
|
||||
renote: "Renotar"
|
||||
unrenote: "Quitar renota"
|
||||
renoted: "Renotado"
|
||||
cantRenote: "No se puede renotar este post"
|
||||
cantReRenote: "No se puede renotar una renota"
|
||||
quote: "Citar"
|
||||
pinnedNote: "Nota fijada"
|
||||
you: "Tú"
|
||||
@ -95,6 +101,7 @@ sensitive: "Marcado como sensible"
|
||||
add: "Agregar"
|
||||
reaction: "Reacción"
|
||||
reactionSettingDescription: "Asigne sus reacción favoritas que desean anclar en el selector de reacciones."
|
||||
reactionSettingDescription2: "Arrastre para reordenar, click para borrar, apriete la tecla + para añadir."
|
||||
rememberNoteVisibility: "Recordar visibilidad"
|
||||
attachCancel: "Quitar adjunto"
|
||||
markAsSensitive: "Marcar como sensible"
|
||||
@ -124,7 +131,9 @@ settingGuide: "Configuración sugerida"
|
||||
cacheRemoteFiles: "Mantener en cache los archivos remotos"
|
||||
cacheRemoteFilesDescription: "Si desactiva esta configuración, Los archivos remotos se cargarán desde el link directo sin usar la caché. Con eso se puede ahorrar almacenamiento del servidor, pero eso aumentará el tráfico al no crear miniaturas."
|
||||
flagAsBot: "Esta cuenta es un bot"
|
||||
flagAsBotDescription: "En caso de que esta cuenta fuera usada por un programa, active esta opción. Al hacerlo, esta opción servirá para otros desarrolladores para evitar cadenas infinitas de reacciones, y ajustará los sistemas internos de Misskey para que trate a esta cuenta como un bot."
|
||||
flagAsCat: "Esta cuenta es un gato"
|
||||
flagAsCatDescription: "En caso de que declare que esta cuenta es de un gato, active esta opción."
|
||||
autoAcceptFollowed: "Aceptar automáticamente las solicitudes de seguimiento de los usuarios que sigues"
|
||||
addAcount: "Agregar cuenta"
|
||||
loginFailed: "Error al iniciar sesión."
|
||||
@ -215,6 +224,7 @@ remove: "Borrar"
|
||||
removed: "Borrado"
|
||||
removeAreYouSure: "¿Desea borrar \"{x}\"?"
|
||||
deleteAreYouSure: "¿Desea borrar \"{x}\"?"
|
||||
resetAreYouSure: "¿Desea reestablecer?"
|
||||
saved: "Guardado"
|
||||
messaging: "Chat"
|
||||
upload: "Subir"
|
||||
@ -314,6 +324,9 @@ bannerUrl: "URL de la imagen del banner"
|
||||
basicInfo: "Información básica"
|
||||
pinnedUsers: "Usuarios fijados"
|
||||
pinnedUsersDescription: "Describir los usuarios que quiere fijar en la página \"Descubrir\" separados por una linea nueva"
|
||||
pinnedPages: "Páginas fijadas"
|
||||
pinnedPagesDescription: "Describa las rutas de las páginas que desea fijar a la página principal de la instancia, separadas por lineas nuevas"
|
||||
pinnedClipId: "Id del clip fijado"
|
||||
pinnedNotes: "Nota fijada"
|
||||
hcaptcha: "hCaptcha"
|
||||
enableHcaptcha: "Habilitar hCaptcha"
|
||||
@ -429,6 +442,7 @@ useOsNativeEmojis: "Usa los emojis nativos de la plataforma"
|
||||
youHaveNoGroups: "Sin grupos"
|
||||
joinOrCreateGroup: "Obtenga una invitación para unirse al grupos o puede crear su propio grupo."
|
||||
noHistory: "No hay datos en el historial"
|
||||
signinHistory: "Historial de ingresos"
|
||||
disableAnimatedMfm: "Deshabilitar MFM que tiene animaciones"
|
||||
doing: "Voy en camino"
|
||||
category: "Categoría"
|
||||
@ -481,6 +495,7 @@ none: "Ninguna"
|
||||
showInPage: "Mostrar en la página"
|
||||
popout: "Popout"
|
||||
volume: "Volumen"
|
||||
masterVolume: "Volumen principal"
|
||||
details: "Detalles"
|
||||
chooseEmoji: "Elije un emoji"
|
||||
unableToProcess: "La operación no se puede llevar a cabo"
|
||||
@ -538,6 +553,9 @@ useBlurEffectForModal: "Usar efecto borroso en modales"
|
||||
useFullReactionPicker: "Reacción"
|
||||
width: "Ancho"
|
||||
height: "Altura"
|
||||
large: "Grande"
|
||||
medium: "Mediano"
|
||||
small: "Pequeño"
|
||||
generateAccessToken: "Generar token de acceso"
|
||||
permission: "Permisos"
|
||||
enableAll: "Activar todo"
|
||||
@ -550,6 +568,8 @@ useStarForReactionFallback: "En caso de que los emojis de reacciones no sean cla
|
||||
emailConfig: "Configuración del servidor de correos"
|
||||
enableEmail: "Activar el envío de correos electrónicos"
|
||||
emailConfigInfo: "Usar en caso de validación de correo electrónico y pedido de contraseña"
|
||||
email: "Correo"
|
||||
emailAddress: "Correo electrónico"
|
||||
smtpConfig: "Configuración del servidor SMTP"
|
||||
smtpHost: "Host"
|
||||
smtpPort: "Puerto"
|
||||
@ -581,6 +601,7 @@ regenerateLoginTokenDescription: "Regenerar el token usado internamente durante
|
||||
setMultipleBySeparatingWithSpace: "Puedes añadir mas de uno, separado por espacios."
|
||||
fileIdOrUrl: "Id del archivo o URL"
|
||||
chatOpenBehavior: "Comportamiento al abrir el chat"
|
||||
behavior: "Comportamiento"
|
||||
sample: "Muestra"
|
||||
abuseReports: "Reportes"
|
||||
reportAbuse: "Reportar"
|
||||
@ -599,7 +620,32 @@ random: "Aleatorio"
|
||||
system: "Sistema"
|
||||
switchUi: "Cambiar interfaz de usuario"
|
||||
desktop: "Escritorio"
|
||||
clip: "Clip"
|
||||
createNew: "Crear"
|
||||
optional: "Opcional"
|
||||
createNewClip: "Crear clip nuevo"
|
||||
public: "Público"
|
||||
i18nInfo: "Misskey está siendo traducido a varios idiomas gracias a voluntarios. Se puede colaborar traduciendo en {link}"
|
||||
manageAccessTokens: "Administrar tokens de acceso"
|
||||
accountInfo: "Información de la Cuenta"
|
||||
notesCount: "Cantidad de notas"
|
||||
repliesCount: "Cantidad de respuestas hechas"
|
||||
renotesCount: "Cantidad de renotas hechas"
|
||||
repliedCount: "Cantidad de respuestas recibidas"
|
||||
renotedCount: "Cantidad de renotas recibidas"
|
||||
followingCount: "Cantidad de seguidos"
|
||||
followersCount: "Cantidad de seguidores"
|
||||
sentReactionsCount: "Cantidad de reacciones hechas"
|
||||
receivedReactionsCount: "Cantidad de reacciones recibidas"
|
||||
pollVotesCount: "Cantidad de votaciones hechas"
|
||||
pollVotedCount: "Cantidad de votaciones recibidas"
|
||||
yes: "Si"
|
||||
no: "No"
|
||||
driveFilesCount: "Cantidad de archivos en el drive"
|
||||
driveUsage: "Uso del drive"
|
||||
noCrawle: "Rechazar indexación del crawler"
|
||||
noCrawleDescription: "Pedir a los motores de búsqueda que no indexen tu perfil, notas, páginas, etc."
|
||||
clips: "Clip"
|
||||
_mfm:
|
||||
cheatSheet: "Hoja de referencia de MFM"
|
||||
intro: "MFM es un lenguaje de marcado dedicado que se puede usar en varios lugares dentro de Misskey. Aquí puede ver una lista de sintaxis disponibles en MFM."
|
||||
@ -871,6 +917,7 @@ _widgets:
|
||||
digitalClock: "Reloj digital"
|
||||
federation: "Federación"
|
||||
postForm: "Formulario"
|
||||
button: "Botón"
|
||||
_cw:
|
||||
hide: "Ocultar"
|
||||
show: "Ver más"
|
||||
|
@ -762,6 +762,7 @@ _widgets:
|
||||
digitalClock: "Horloge numérique"
|
||||
federation: "Fédération"
|
||||
postForm: "Formulaire à publier"
|
||||
button: "Bouton"
|
||||
_cw:
|
||||
hide: "Masquer"
|
||||
show: "Afficher plus …"
|
||||
|
@ -33,6 +33,9 @@ addUser: "ユーザーを追加"
|
||||
favorite: "お気に入り"
|
||||
favorites: "お気に入り"
|
||||
unfavorite: "お気に入り解除"
|
||||
favorited: "お気に入りに登録しました。"
|
||||
alreadyFavorited: "既にお気に入りに登録されています。"
|
||||
cantFavorite: "お気に入りに登録できませんでした。"
|
||||
pin: "ピン留め"
|
||||
unpin: "ピン留め解除"
|
||||
copyContent: "内容をコピー"
|
||||
@ -87,6 +90,9 @@ followRequestPending: "フォロー許可待ち"
|
||||
enterEmoji: "絵文字を入力"
|
||||
renote: "Renote"
|
||||
unrenote: "Renote解除"
|
||||
renoted: "Renoteしました。"
|
||||
cantRenote: "この投稿はRenoteできません。"
|
||||
cantReRenote: "RenoteをRenoteすることはできません。"
|
||||
quote: "引用"
|
||||
pinnedNote: "ピン留めされたノート"
|
||||
you: "あなた"
|
||||
@ -655,6 +661,16 @@ useSystemFont: "システムのデフォルトのフォントを使う"
|
||||
clips: "クリップ"
|
||||
experimentalFeatures: "実験的機能"
|
||||
developer: "開発者"
|
||||
makeExplorable: "アカウントを見つけやすくする"
|
||||
makeExplorableDescription: "オフにすると、「みつける」にアカウントが載らなくなります。"
|
||||
showGapBetweenNotesInTimeline: "タイムラインのノートを離して表示"
|
||||
duplicate: "複製"
|
||||
left: "左"
|
||||
center: "中央"
|
||||
wide: "広い"
|
||||
narrow: "狭い"
|
||||
reloadToApplySetting: "設定はページリロード後に反映されます。今すぐリロードしますか?"
|
||||
showTitlebar: "タイトルバーを表示する"
|
||||
|
||||
_aboutMisskey:
|
||||
about: "Misskeyはsyuiloによって2014年から開発されている、オープンソースのソフトウェアです。"
|
||||
@ -996,6 +1012,7 @@ _widgets:
|
||||
federation: "連合"
|
||||
postForm: "投稿フォーム"
|
||||
slideshow: "スライドショー"
|
||||
button: "ボタン"
|
||||
|
||||
_cw:
|
||||
hide: "隠す"
|
||||
@ -1505,6 +1522,8 @@ _notification:
|
||||
_deck:
|
||||
alwaysShowMainColumn: "常にメインカラムを表示"
|
||||
columnAlign: "カラムの寄せ"
|
||||
columnMargin: "カラム間のマージン"
|
||||
columnHeaderHeight: "カラムのヘッダー幅"
|
||||
addColumn: "カラムを追加"
|
||||
swapLeft: "左に移動"
|
||||
swapRight: "右に移動"
|
||||
@ -1514,6 +1533,7 @@ _deck:
|
||||
popRight: "右に出す"
|
||||
|
||||
_columns:
|
||||
main: "メイン"
|
||||
widgets: "ウィジェット"
|
||||
notifications: "通知"
|
||||
tl: "タイムライン"
|
||||
|
@ -33,6 +33,9 @@ addUser: "ユーザーを追加や"
|
||||
favorite: "お気に入り"
|
||||
favorites: "お気に入り"
|
||||
unfavorite: "やっぱ気に入らん"
|
||||
favorited: "お気に入りに登録したで"
|
||||
alreadyFavorited: "もうお気に入りに入れとるがな。"
|
||||
cantFavorite: "アカン、お気に入り登録できへんかったで。"
|
||||
pin: "ピン留めしとく"
|
||||
unpin: "やっぱピン留めせん"
|
||||
copyContent: "内容をコピー"
|
||||
@ -87,6 +90,9 @@ followRequestPending: "フォロー許してくれるん待っとる"
|
||||
enterEmoji: "絵文字を入れてや"
|
||||
renote: "Renote"
|
||||
unrenote: "Renoteやめる"
|
||||
renoted: "Renoteしたで。"
|
||||
cantRenote: "この投稿はRenoteできへんらしい。"
|
||||
cantReRenote: "すまん、今このRenoteにRenoteはできへんのや。"
|
||||
quote: "引用"
|
||||
pinnedNote: "ピン留めされとるノート"
|
||||
you: "あんた"
|
||||
@ -95,6 +101,7 @@ sensitive: "ちょっとアカンやつやで"
|
||||
add: "増やす"
|
||||
reaction: "リアクション"
|
||||
reactionSettingDescription: "リアクションピッカーに出しとくリアクションを選んでや。"
|
||||
reactionSettingDescription2: "ドラッグして並び替え、クリックして削除、+を押すと追加できるで。"
|
||||
rememberNoteVisibility: "公開範囲覚えといて"
|
||||
attachCancel: "やっぱ添付やめてくれん?"
|
||||
markAsSensitive: "ちょっとこれはアカン"
|
||||
@ -124,7 +131,9 @@ settingGuide: "ええ感じの設定"
|
||||
cacheRemoteFiles: "リモートのファイルをキャッシュする"
|
||||
cacheRemoteFilesDescription: "この設定を切っとくと、リモートファイルをキャッシュせず直リンクするようになってしまうんやで? サーバーのストレージは節約できるんやけど、かわりにサムネイルが作られんくなるから通信量が増えるで?"
|
||||
flagAsBot: "Botやで"
|
||||
flagAsBotDescription: "もしこのアカウントがプログラムによって運用されるんやったら、このフラグをオンにしてたのむで。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Misskeyのシステム上での扱いがBotに合ったもんになるんやで。"
|
||||
flagAsCat: "Catやで"
|
||||
flagAsCatDescription: "ワレ、猫ちゃんならこのフラグをつけてみ?"
|
||||
autoAcceptFollowed: "フォローしとるユーザーからのフォローリクエストには勝手に許可しとくで。"
|
||||
addAcount: "アカウント追加"
|
||||
loginFailed: "ログインに失敗してしもうた…"
|
||||
@ -215,6 +224,7 @@ remove: "ほかす"
|
||||
removed: "削除したで!"
|
||||
removeAreYouSure: "「{x}」はなおしてしもてええか?"
|
||||
deleteAreYouSure: "「{x}」はなおしてしもてええか?"
|
||||
resetAreYouSure: "リセットしてええん?"
|
||||
saved: "保存したで!"
|
||||
messaging: "チャット"
|
||||
upload: "アップロード"
|
||||
@ -314,6 +324,7 @@ bannerUrl: "バナー画像のURL"
|
||||
basicInfo: "基本情報"
|
||||
pinnedUsers: "ピン留めしたユーザー"
|
||||
pinnedUsersDescription: "「みつける」ページとかにピン留めしたいユーザーをここに書けばええんやで。他ん人との名前は改行で区切ればええんやで。"
|
||||
pinnedPages: "ピン留めページ"
|
||||
pinnedNotes: "ピン留めされとるノート"
|
||||
hcaptcha: "hCaptcha(キャプチャ)"
|
||||
enableHcaptcha: "hCaptcha(キャプチャ)をつけとく"
|
||||
@ -404,9 +415,42 @@ quoteQuestion: "引用として添付してもええか?"
|
||||
noMessagesYet: "まだチャットはあらへんで"
|
||||
newMessageExists: "新しいメッセージがきたで"
|
||||
onlyOneFileCanBeAttached: "すまん、メッセージに添付できるファイルはひとつだけなんや。"
|
||||
signinRequired: "ログインしてくれへん?"
|
||||
invitations: "来てや"
|
||||
invitationCode: "招待コード"
|
||||
checking: "確認しとるで"
|
||||
available: "利用できる\n"
|
||||
unavailable: "利用できん"
|
||||
usernameInvalidFormat: "a~z、A~Z、0~9、_が使えるで"
|
||||
tooShort: "短すぎやろ!"
|
||||
tooLong: "長すぎやろ!"
|
||||
weakPassword: "弱いパスワード"
|
||||
normalPassword: "普通のパスワード"
|
||||
strongPassword: "ええ感じのパスワード"
|
||||
passwordMatched: "よし!一致や!"
|
||||
passwordNotMatched: "一致しとらんで?"
|
||||
signinWith: "{x}でログイン"
|
||||
or: "それか"
|
||||
uiLanguage: "UIの表示言語"
|
||||
groupInvited: "グループに招待されとるで"
|
||||
aboutX: "{x}について"
|
||||
useOsNativeEmojis: "OSネイティブの絵文字を使う"
|
||||
youHaveNoGroups: "グループがあらへんねぇ。"
|
||||
noHistory: "履歴はあらへんねぇ。"
|
||||
signinHistory: "ログイン履歴"
|
||||
doing: "やっとるがな"
|
||||
category: "カテゴリ"
|
||||
tags: "タグ"
|
||||
docSource: "このドキュメントのソース"
|
||||
createAccount: "アカウントを作成"
|
||||
existingAcount: "既存のアカウント"
|
||||
regenerate: "再生成"
|
||||
fontSize: "フォントサイズ"
|
||||
noFollowRequests: "フォロー申請はあらへんで"
|
||||
openImageInNewTab: "画像を新しいタブで開く"
|
||||
dashboard: "ダッシュボード"
|
||||
local: "ローカル"
|
||||
remote: "リモート"
|
||||
smtpHost: "ホスト"
|
||||
smtpUser: "ユーザー名"
|
||||
smtpPass: "パスワード"
|
||||
@ -501,6 +545,7 @@ _pages:
|
||||
array: "リスト"
|
||||
_notification:
|
||||
youWereFollowed: "フォローされたで"
|
||||
youWereInvitedToGroup: "グループに招待されとるで"
|
||||
_types:
|
||||
follow: "フォロー"
|
||||
mention: "メンション"
|
||||
|
@ -834,6 +834,7 @@ _widgets:
|
||||
digitalClock: "디지털 시계"
|
||||
federation: "연합"
|
||||
postForm: "글 입력란"
|
||||
button: "버튼"
|
||||
_cw:
|
||||
hide: "숨기기"
|
||||
show: "더 보기"
|
||||
|
@ -33,6 +33,9 @@ addUser: "Добавить пользователя"
|
||||
favorite: "В избранное"
|
||||
favorites: "Избранное"
|
||||
unfavorite: "Убрать из избранного"
|
||||
favorited: "Добавлено в избранное."
|
||||
alreadyFavorited: "Уже есть в избранном."
|
||||
cantFavorite: "Не удалось добавить в избранное."
|
||||
pin: "Закрепить в профиле"
|
||||
unpin: "Открепить от профиля"
|
||||
copyContent: "Скопировать содержимое"
|
||||
@ -87,6 +90,9 @@ followRequestPending: "Нерассмотренный запрос на подп
|
||||
enterEmoji: "Введите эмодзи"
|
||||
renote: "Репост"
|
||||
unrenote: "Отмена репоста"
|
||||
renoted: "Репост совершён."
|
||||
cantRenote: "Это нельзя репостить."
|
||||
cantReRenote: "Невозможно репостить репост."
|
||||
quote: "Цитата"
|
||||
pinnedNote: "Закреплённая заметка"
|
||||
you: "Вы"
|
||||
@ -655,6 +661,12 @@ useSystemFont: "Использовать шрифт, предлагаемый с
|
||||
clips: "Памятки"
|
||||
experimentalFeatures: "Экспериментальные функции"
|
||||
developer: "Разработчик"
|
||||
makeExplorable: "Опубликовать профиль в «Обзоре»."
|
||||
makeExplorableDescription: "Если выключить, ваш профиль не будет показан в разделе «Обзор»."
|
||||
showGapBetweenNotesInTimeline: "Показывать разделитель между заметками в ленте"
|
||||
duplicate: "Дубликат"
|
||||
left: "Влево"
|
||||
center: "По центру"
|
||||
_aboutMisskey:
|
||||
about: "Misskey — программа с открытым исходным кодом, которую разрабатывает syuilo с 2014 года."
|
||||
contributors: "Основные соавторы"
|
||||
@ -975,6 +987,7 @@ _widgets:
|
||||
federation: "Федерация"
|
||||
postForm: "Форма отправки"
|
||||
slideshow: "Показ слайдов"
|
||||
button: "Кнопка"
|
||||
_cw:
|
||||
hide: "Спрятать"
|
||||
show: "Показать еще"
|
||||
@ -1457,6 +1470,8 @@ _notification:
|
||||
_deck:
|
||||
alwaysShowMainColumn: "Всегда показывать главную колонку"
|
||||
columnAlign: "Выравнивание колонок"
|
||||
columnMargin: "Расстояние между колонками"
|
||||
columnHeaderHeight: "Высота заголовка колонки"
|
||||
addColumn: "Добавить колонку"
|
||||
swapLeft: "Переставить левее"
|
||||
swapRight: "Переставить правее"
|
||||
@ -1465,6 +1480,7 @@ _deck:
|
||||
stackLeft: "В столбик влево"
|
||||
popRight: "Из столбика вправо"
|
||||
_columns:
|
||||
main: "Основная"
|
||||
widgets: "Виджеты"
|
||||
notifications: "Уведомления"
|
||||
tl: "Лента"
|
||||
|
@ -82,7 +82,7 @@ defaultNoteVisibility: "Видимість за замовчуванням"
|
||||
follow: "Підписка"
|
||||
followRequest: "Запит на підписку"
|
||||
followRequests: "Запити на підписку"
|
||||
unfollow: "Відписатися"
|
||||
unfollow: "Відписатись"
|
||||
followRequestPending: "Очікуючі запити на підписку"
|
||||
enterEmoji: "Введіть емодзі"
|
||||
renote: "Поширити"
|
||||
@ -143,7 +143,7 @@ recipient: "Кому"
|
||||
annotation: "Коментар"
|
||||
federation: "Федіверс"
|
||||
instances: "Інстанс"
|
||||
registeredAt: "Приєднався(-лась)"
|
||||
registeredAt: "Приєднався(лась)"
|
||||
latestRequestSentAt: "Останній запит надіслано"
|
||||
latestRequestReceivedAt: "Останній запит прийнято"
|
||||
latestStatus: "Останній статус"
|
||||
@ -239,7 +239,7 @@ activity: "Активність"
|
||||
images: "Зображення"
|
||||
birthday: "День народження"
|
||||
yearsOld: "{age} років"
|
||||
registeredDate: "Приєднався(-лась)"
|
||||
registeredDate: "Приєднався(лась)"
|
||||
location: "Локація"
|
||||
theme: "Тема"
|
||||
themeForLightMode: "Світла тема"
|
||||
@ -717,6 +717,8 @@ _wordMute:
|
||||
hard: "Жорстко"
|
||||
mutedNotes: "Заблоковані нотатки"
|
||||
_theme:
|
||||
defaultValue: "Значення за замовчуванням"
|
||||
func: "Функції"
|
||||
keys:
|
||||
accent: "Акцент"
|
||||
bg: "Фон"
|
||||
@ -739,8 +741,10 @@ _theme:
|
||||
divider: "Розділювач"
|
||||
_sfx:
|
||||
note: "Нотатки"
|
||||
noteMy: "Мої нотатки"
|
||||
notification: "Сповіщення"
|
||||
chat: "Чати"
|
||||
chatBg: "Чати (фон)"
|
||||
_ago:
|
||||
unknown: "Невідомо"
|
||||
future: "Майбутнє"
|
||||
@ -765,58 +769,441 @@ _tutorial:
|
||||
_2fa:
|
||||
registerKey: "Зареєструвати новий ключ безпеки"
|
||||
_permissions:
|
||||
"read:account": "Переглядати дані профілю"
|
||||
"write:account": "Змінити дані акаунту"
|
||||
"read:blocks": "Переглянути список заблокованих"
|
||||
"write:blocks": "Редагувати список заблокованих"
|
||||
"read:drive": "Переглянути вміст Диска"
|
||||
"write:drive": "Змінювати вміст Диска"
|
||||
"read:favorites": "Переглядати обране"
|
||||
"write:favorites": "Змінювати обране"
|
||||
"read:following": "Переглядати підписки"
|
||||
"write:following": "Змінювати підписки"
|
||||
"read:messaging": "Переглядати повідомлення"
|
||||
"write:messaging": "Створювати та видаляти повідомлення"
|
||||
"read:mutes": "Переглядати список ігнорованих"
|
||||
"write:mutes": "Змінювати список ігнорованих"
|
||||
"write:notes": "Писати і видаляти нотатки"
|
||||
"read:notifications": "Переглядати сповіщення"
|
||||
"read:reactions": "Переглядати реакції"
|
||||
"write:reactions": "Змінювати реакції"
|
||||
"write:votes": "Голосувати в опитуваннях"
|
||||
"read:pages": "Переглядати сторінки"
|
||||
"write:pages": "Змінювати і видаляти сторінки"
|
||||
"read:page-likes": "Переглядати вподобання сторінок"
|
||||
"write:page-likes": "Змінювати вподобання сторінок"
|
||||
"read:user-groups": "Переглядати групи користувача"
|
||||
"write:user-groups": "Змінювати групи користувача"
|
||||
"read:channels": "Переглядати канали"
|
||||
"write:channels": "Змінювати канали"
|
||||
_auth:
|
||||
shareAccess: "Ви хочете надати \"{name}\" доступ до цього акаунту?"
|
||||
shareAccessAsk: "Ви впевнені, що хочете надати цій програмі доступ до вашого акаунту?"
|
||||
denied: "У доступі відмовлено"
|
||||
_antennaSources:
|
||||
all: "Всі нотатки"
|
||||
homeTimeline: "Нотатки тих, на кого ви підписані"
|
||||
_weekday:
|
||||
sunday: "Неділя"
|
||||
monday: "Понеділок"
|
||||
tuesday: "Вівторок"
|
||||
wednesday: "Середа"
|
||||
thursday: "Четвер"
|
||||
friday: "П'ятниця"
|
||||
saturday: "Субота"
|
||||
_widgets:
|
||||
notifications: "Сповіщення"
|
||||
timeline: "Стрічка"
|
||||
calendar: "Календар"
|
||||
trends: "Тенденції"
|
||||
clock: "Годинник"
|
||||
rss: "RSS-читач"
|
||||
activity: "Активність"
|
||||
photos: "Фото"
|
||||
digitalClock: "Цифровий годинник"
|
||||
federation: "Федіверс"
|
||||
postForm: "Створення нотатки"
|
||||
slideshow: "Слайд-шоу"
|
||||
button: "Кнопка"
|
||||
_cw:
|
||||
hide: "Сховати"
|
||||
show: "Показати більше"
|
||||
chars: "{count} символів"
|
||||
files: "{count} файлів"
|
||||
_poll:
|
||||
noOnlyOneChoice: "Потрібні принаймні два варіанти."
|
||||
noMore: "Більше варіантів додати не можна"
|
||||
canMultipleVote: "Можна вибрати кілька варіантів"
|
||||
expiration: "Опитування закінчується"
|
||||
infinite: "Ніколи"
|
||||
deadlineDate: "Дата закінчення"
|
||||
deadlineTime: "г"
|
||||
duration: "Тривалість"
|
||||
votesCount: "{n} голосів"
|
||||
totalVotes: "Всього {n} голосів"
|
||||
vote: "Голосувати"
|
||||
showResult: "Переглянути результати"
|
||||
voted: "Проголосовано"
|
||||
closed: "Завершено"
|
||||
remainingDays: "Залишилось {d} днів {h} годин"
|
||||
remainingHours: "Залишилось {h} годин {m} хвилин"
|
||||
remainingMinutes: "Залишилось {m} хвилин {s} секунд"
|
||||
remainingSeconds: "Залишилось {s} секунд"
|
||||
_visibility:
|
||||
public: "Публічний"
|
||||
publicDescription: "Для всіх користувачів"
|
||||
home: "Домівка"
|
||||
homeDescription: "Лише на домашній стрічці"
|
||||
followers: "Підписники"
|
||||
localOnly: "Лише локально"
|
||||
followersDescription: "Тільки для підписників"
|
||||
specified: "Особисто"
|
||||
specifiedDescription: "Лише для певних користувачів"
|
||||
localOnly: "Локально"
|
||||
localOnlyDescription: "Приховано для віддалених користувачів"
|
||||
_postForm:
|
||||
replyPlaceholder: "Відповідь на цю нотатку..."
|
||||
quotePlaceholder: "Прокоментуйте цю нотатку..."
|
||||
channelPlaceholder: "Опублікувати в каналі"
|
||||
_placeholders:
|
||||
a: "Чим займаєтесь?"
|
||||
b: "Що відбувається навколо вас?"
|
||||
c: "Що у вас на думці?"
|
||||
d: "Що ви хочете висловити?"
|
||||
e: "Напишіть тут, будь ласка..."
|
||||
f: "Чекаю коли ви напишете..."
|
||||
_profile:
|
||||
name: "Ім'я"
|
||||
username: "Ім'я користувача"
|
||||
description: "Про себе"
|
||||
youCanIncludeHashtags: "Ви також можете включити хештеги у свій опис."
|
||||
metadata: "Додаткова інформація"
|
||||
metadataEdit: "Редагувати додаткову інформацію"
|
||||
metadataDescription: "Ви можете вказати до чотирьох пунктів додаткової інформації у своєму профілі."
|
||||
metadataLabel: "Назва"
|
||||
metadataContent: "Вміст"
|
||||
changeAvatar: "Змінити аватар"
|
||||
changeBanner: "Змінити банер"
|
||||
_exportOrImport:
|
||||
allNotes: "Всі нотатки"
|
||||
followingList: "Підписки"
|
||||
muteList: "Ігнорувати"
|
||||
blockingList: "Заблокувати"
|
||||
userLists: "Списки"
|
||||
_charts:
|
||||
federationInstancesTotal: "Загальна кількість федеративних інстансів"
|
||||
usersTotal: "Загальна кількість користувачів"
|
||||
activeUsers: "Активні користувачі"
|
||||
notesTotal: "Загальна кількість нотаток"
|
||||
filesIncDec: "Зміни кількості файлів"
|
||||
filesTotal: "Загальна кількість файлів"
|
||||
_instanceCharts:
|
||||
requests: "Запити"
|
||||
usersTotal: "Сумарна кількість користувачів"
|
||||
notesTotal: "Сумарна кількість нотаток"
|
||||
cacheSizeTotal: "Сумарний розмір кешу"
|
||||
filesTotal: "Сумарна кількість файлів"
|
||||
_timelines:
|
||||
home: "Домівка"
|
||||
local: "Локальна"
|
||||
social: "Соціальна"
|
||||
global: "Глобальна"
|
||||
_rooms:
|
||||
roomOf: "Кімната {user}"
|
||||
addFurniture: "Розмістити меблі"
|
||||
translate: "Пересунути"
|
||||
rotate: "Обертати"
|
||||
exit: "Назад"
|
||||
remove: "Видалити"
|
||||
clear: "Видалити все"
|
||||
leaveConfirm: "Є незбережені зміни. Ви дійсно хочете вийти?"
|
||||
chooseImage: "Виберіть зображення"
|
||||
roomType: "Тип кімнати"
|
||||
carpetColor: "Колір килима"
|
||||
_roomType:
|
||||
default: "За умовчанням"
|
||||
default: "За замовчуванням"
|
||||
washitsu: "В японському стилі"
|
||||
_furnitures:
|
||||
milk: "Пакет молока"
|
||||
bed: "Ліжко"
|
||||
low-table: "Журнальний стіл"
|
||||
desk: "Письмовий стіл"
|
||||
chair: "Стілець"
|
||||
chair2: "Стілець 2"
|
||||
fan: "Вентилятор"
|
||||
pc: "Комп’ютер"
|
||||
plant: "Кімнатна рослина"
|
||||
plant2: "Кімнатна рослина 2"
|
||||
eraser: "Ластик"
|
||||
pencil: "Олівець"
|
||||
pudding: "Пудинг"
|
||||
cardboard-box: "Картонна коробка"
|
||||
cardboard-box2: "Картонна коробка 2"
|
||||
cardboard-box3: "Картонна коробка 3"
|
||||
book: "Книга"
|
||||
book2: "Книга 2"
|
||||
piano: "Піаніно"
|
||||
facial-tissue: "Серветки"
|
||||
server: "Сервер"
|
||||
moon: "Місяць"
|
||||
corkboard: "Коркова дошка"
|
||||
mousepad: "Килимок для миші"
|
||||
monitor: "Монітор"
|
||||
keyboard: "Клавіатура"
|
||||
carpet-stripe: "Смугастий килим"
|
||||
mat: "Мат"
|
||||
color-box: "Книжкова полиця"
|
||||
wall-clock: "Настінний годинник"
|
||||
photoframe: "Фоторамка"
|
||||
cube: "Куб"
|
||||
tv: "Телевізор"
|
||||
pinguin: "Пінгвін"
|
||||
rubik-cube: "Кубик Рубіка"
|
||||
poster-h: "Плакат (горизонтальний)"
|
||||
poster-v: "Плакат (вертикальний)"
|
||||
sofa: "Диван"
|
||||
spiral: "Гвинтові сходи"
|
||||
bin: "Смітник"
|
||||
holo-display: "Голографічний дисплей"
|
||||
energy-drink: "Енергетичний напій"
|
||||
doll-ai: "Лялька Аі-тян"
|
||||
banknote: "Пачка грошей"
|
||||
_pages:
|
||||
newPage: "Створити сторінку"
|
||||
editPage: "Редагувати сторінку"
|
||||
readPage: "Перегляд вихідного коду"
|
||||
created: "Сторінка успішно створена."
|
||||
updated: "Сторінка успішно оновлена."
|
||||
deleted: "Сторінку видалено"
|
||||
pageSetting: "Налаштування сторінки"
|
||||
nameAlreadyExists: "Вказана адреса сторінки вже існує."
|
||||
invalidNameTitle: "Вказана адреса сторінки неприпустима."
|
||||
invalidNameText: "Переконайтеся, що не залишили порожнім."
|
||||
editThisPage: "Редагувати цю сторінку"
|
||||
viewSource: "Переглянути вихідний код"
|
||||
viewPage: "Переглянути свої сторінки"
|
||||
like: "Вподобати"
|
||||
unlike: "Не вподобати"
|
||||
my: "Мої сторінки"
|
||||
liked: "Вподобані сторінки"
|
||||
featured: "Популярні"
|
||||
inspector: "Інспектор"
|
||||
contents: "Вміст"
|
||||
variables: "Змінні"
|
||||
title: "Заголовок"
|
||||
url: "URL сторінки"
|
||||
summary: "Короткий зміст"
|
||||
alignCenter: "Рівняти елементи по центру"
|
||||
hideTitleWhenPinned: "Приховати заголовок сторінки при закріпленні в профілі"
|
||||
font: "Шрифт"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans serif"
|
||||
eyeCatchingImageSet: "Встановити привабливе зображення"
|
||||
eyeCatchingImageRemove: "Видалити привабливе зображення"
|
||||
chooseBlock: "Додати блок"
|
||||
selectType: "Виберіть тип"
|
||||
enterVariableName: "Введіть назву для змінної"
|
||||
contentBlocks: "Контент"
|
||||
inputBlocks: "Ввід"
|
||||
specialBlocks: "Особливе"
|
||||
blocks:
|
||||
text: "Текст"
|
||||
textarea: "Текстова область"
|
||||
section: "Розділ"
|
||||
image: "Зображення"
|
||||
button: "Кнопка"
|
||||
if: "Якщо"
|
||||
_if:
|
||||
variable: "Змінні"
|
||||
post: "Створення нотатки"
|
||||
_post:
|
||||
text: "Вміст"
|
||||
textInput: "Введення тексту"
|
||||
_textInput:
|
||||
name: "Ім'я змінної"
|
||||
text: "Назва"
|
||||
default: "Значення за замовчуванням"
|
||||
textareaInput: "Багаторядкове введення тексту"
|
||||
_textareaInput:
|
||||
name: "Ім'я змінної"
|
||||
text: "Назва"
|
||||
default: "Значення за замовчуванням"
|
||||
numberInput: "Числове введення"
|
||||
_numberInput:
|
||||
name: "Ім'я змінної"
|
||||
text: "Назва"
|
||||
default: "Значення за замовчуванням"
|
||||
_canvas:
|
||||
width: "Ширина"
|
||||
height: "Висота"
|
||||
note: "Вбудована нотатка"
|
||||
_note:
|
||||
id: "Ідентифікатор нотатки"
|
||||
idDescription: "Також можна вказати посилання на нотатку"
|
||||
detailed: "Детальний вигляд"
|
||||
switch: "Перемикач"
|
||||
_switch:
|
||||
name: "Ім'я змінної"
|
||||
text: "Назва"
|
||||
default: "Значення за замовчуванням"
|
||||
counter: "Лічильник"
|
||||
_counter:
|
||||
name: "Ім'я змінної"
|
||||
text: "Назва"
|
||||
inc: "Збільшити на"
|
||||
_button:
|
||||
text: "Напис"
|
||||
_action:
|
||||
_dialog:
|
||||
content: "Вміст"
|
||||
resetRandom: "Скидання генератора випадковості"
|
||||
pushEvent: "Надіслати подію"
|
||||
_pushEvent:
|
||||
event: "Назві події"
|
||||
message: "Повідомлення для відображення при активації"
|
||||
variable: "Змінна для надсилання"
|
||||
no-variable: "Відсутньо"
|
||||
callAiScript: "Виклик AiScript"
|
||||
_callAiScript:
|
||||
functionName: "Ім'я функції"
|
||||
radioButton: "Вибір"
|
||||
_radioButton:
|
||||
name: "Ім'я змінної"
|
||||
title: "Напис"
|
||||
values: "Варіанти, розділені розривами рядків"
|
||||
default: "Значення за замовчуванням"
|
||||
script:
|
||||
categories:
|
||||
flow: "Керування потоком"
|
||||
logical: "Логічні операції"
|
||||
operation: "Обчислення"
|
||||
comparison: "Порівняння"
|
||||
random: "Випадковість"
|
||||
value: "Значення"
|
||||
fn: "Функції"
|
||||
text: "Дії з текстом"
|
||||
convert: "Перетворення"
|
||||
list: "Списки"
|
||||
blocks:
|
||||
text: "Текст"
|
||||
multiLineText: "Текст (багаторядковий)"
|
||||
textList: "Текстовий список"
|
||||
strLen: "Довжина тексту"
|
||||
_strLen:
|
||||
arg1: "Текст"
|
||||
_strPick:
|
||||
arg1: "Текст"
|
||||
strReplace: "Заміна тексту"
|
||||
_strReplace:
|
||||
arg1: "Текст"
|
||||
arg2: "Текст, який потрібно замінити"
|
||||
arg3: "Заміняти на"
|
||||
strReverse: "Перевернути текст"
|
||||
_strReverse:
|
||||
arg1: "Текст"
|
||||
join: "Конкатенація тексту"
|
||||
_join:
|
||||
arg1: "Списки"
|
||||
arg2: "Розділювач"
|
||||
add: "Додати"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "Відняти"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "Помножити"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "Поділити"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "Остача"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "Десяткове округлення"
|
||||
_round:
|
||||
arg1: "Число"
|
||||
eq: "A дорівнює B"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A не дорівнює B"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "А І Б"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A АБО B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< A менше, ніж B"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> A більше, ніж B"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= A менше або дорівнює B"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= A більше або дорівнює B"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "Умова"
|
||||
_if:
|
||||
arg1: "Якщо"
|
||||
arg2: "Якщо так"
|
||||
arg3: "Якщо ні"
|
||||
not: "НЕ"
|
||||
_not:
|
||||
arg1: "НЕ"
|
||||
random: "Випадково"
|
||||
_random:
|
||||
arg1: "Імовірність"
|
||||
rannum: "Випадкове число"
|
||||
_rannum:
|
||||
arg1: "Мінімальне значення"
|
||||
arg2: "Максимальне значення"
|
||||
randomPick: "Випадковий вибір зі списку"
|
||||
_randomPick:
|
||||
arg1: "Списки"
|
||||
dailyRandom: "Випадково (триває добу)"
|
||||
_dailyRandom:
|
||||
arg1: "Імовірність"
|
||||
dailyRannum: "Випадкове число (триває добу)"
|
||||
_dailyRannum:
|
||||
arg1: "Мінімальне значення"
|
||||
arg2: "Максимальне значення"
|
||||
dailyRandomPick: "Випадково вибрати зі списку (триває добу)"
|
||||
_dailyRandomPick:
|
||||
arg1: "Списки"
|
||||
seedRandom: "Випадковість (з насінням)"
|
||||
_seedRandom:
|
||||
arg1: "Насіння"
|
||||
arg2: "Імовірність"
|
||||
seedRannum: "Випадкове число (з насінням)"
|
||||
_seedRannum:
|
||||
arg1: "Насіння"
|
||||
arg2: "Мінімальне значення"
|
||||
arg3: "Максимальне значення"
|
||||
seedRandomPick: "Випадково вибрати зі списку (з насінням)"
|
||||
_seedRandomPick:
|
||||
arg1: "Насіння"
|
||||
arg2: "Списки"
|
||||
DRPWPM: "Випадково вибрати зі зваженого списку (триває добу)"
|
||||
_DRPWPM:
|
||||
arg1: "Текстовий список"
|
||||
pick: "Вибір зі списку"
|
||||
_pick:
|
||||
arg1: "Списки"
|
||||
arg2: "Позиція"
|
||||
@ -847,6 +1234,7 @@ _pages:
|
||||
number: "Число"
|
||||
boolean: "Прапорець"
|
||||
array: "Списки"
|
||||
stringArray: "Текстовий список"
|
||||
_relayStatus:
|
||||
requesting: "Очікує затвердження"
|
||||
accepted: "Затверджено"
|
||||
|
@ -11,7 +11,7 @@ ok: "OK"
|
||||
gotIt: "我明白了"
|
||||
cancel: "取消"
|
||||
enterUsername: "输入用户名"
|
||||
renotedBy: "{user} 转贴了"
|
||||
renotedBy: "{user} 转发了"
|
||||
noNotes: "没有帖文"
|
||||
noNotifications: "无通知"
|
||||
instance: "实例"
|
||||
@ -33,6 +33,9 @@ addUser: "添加用户"
|
||||
favorite: "收藏"
|
||||
favorites: "收藏"
|
||||
unfavorite: "取消收藏"
|
||||
favorited: "已加入收藏夹。"
|
||||
alreadyFavorited: "收藏夹中已存在。"
|
||||
cantFavorite: "无法添加到收藏夹。"
|
||||
pin: "置顶"
|
||||
unpin: "取消置顶"
|
||||
copyContent: "复制内容"
|
||||
@ -87,6 +90,9 @@ followRequestPending: "发送关注申请"
|
||||
enterEmoji: "输入表情符号"
|
||||
renote: "转发"
|
||||
unrenote: "取消转发"
|
||||
renoted: "已转发。"
|
||||
cantRenote: "该帖子无法转发。"
|
||||
cantReRenote: "转发无法被再次转发。"
|
||||
quote: "引用"
|
||||
pinnedNote: "已置顶的帖子"
|
||||
you: "您"
|
||||
@ -116,7 +122,7 @@ selectAntenna: "天线选择"
|
||||
selectWidget: "选择小工具"
|
||||
editWidgets: "编辑小工具"
|
||||
editWidgetsExit: "完成编辑"
|
||||
customEmojis: "自定义Emoji"
|
||||
customEmojis: "自定义表情符号"
|
||||
emoji: "表情符号"
|
||||
emojiName: "表情符号名称"
|
||||
emojiUrl: "表情符号地址"
|
||||
@ -533,7 +539,7 @@ poll: "调查问卷"
|
||||
useCw: "隐藏内容"
|
||||
enablePlayer: "打开播放器"
|
||||
disablePlayer: "关闭播放器"
|
||||
expandTweet: "展开推文"
|
||||
expandTweet: "展开贴文"
|
||||
themeEditor: "主题编辑器"
|
||||
description: "描述"
|
||||
author: "作者"
|
||||
@ -655,6 +661,15 @@ useSystemFont: "使用系统默认字体"
|
||||
clips: "片段"
|
||||
experimentalFeatures: "实验性功能"
|
||||
developer: "开发者"
|
||||
makeExplorable: "使账号可见。"
|
||||
makeExplorableDescription: "关闭时,账号不会显示在\"发现\"中。"
|
||||
showGapBetweenNotesInTimeline: "时间线上的帖子分开显示。"
|
||||
duplicate: "复制"
|
||||
left: "左"
|
||||
center: "中央"
|
||||
wide: "宽"
|
||||
narrow: "窄"
|
||||
reloadToApplySetting: "页面刷新后设置才会生效。是否现在刷新页面?"
|
||||
_aboutMisskey:
|
||||
about: "Misskey是由syuilo于2014年开发的开源软件。"
|
||||
contributors: "主要贡献者"
|
||||
@ -775,7 +790,7 @@ _wordMute:
|
||||
muteWords: "禁用词"
|
||||
muteWordsDescription: "使用空格分隔表示AND逻辑,使用换行符分隔表示OR逻辑。"
|
||||
muteWordsDescription2: "将关键字用斜线括起来表示正则表达式。"
|
||||
softDescription: "隐藏时间轴中指定条件的帖文。"
|
||||
softDescription: "隐藏时间线中指定条件的帖文。"
|
||||
hardDescription: "防止将具有指定条件的帖文添加到时间线。 即使您更改条件,未添加的帖文也会被排除在外。"
|
||||
soft: "软屏蔽"
|
||||
hard: "硬屏蔽"
|
||||
@ -975,6 +990,7 @@ _widgets:
|
||||
federation: "联邦宇宙"
|
||||
postForm: "投稿窗口"
|
||||
slideshow: "幻灯片展示"
|
||||
button: "按钮"
|
||||
_cw:
|
||||
hide: "隐藏"
|
||||
show: "查看更多"
|
||||
@ -1457,6 +1473,8 @@ _notification:
|
||||
_deck:
|
||||
alwaysShowMainColumn: "总是显示主列"
|
||||
columnAlign: "列对齐"
|
||||
columnMargin: "列间距"
|
||||
columnHeaderHeight: "列标题高度"
|
||||
addColumn: "添加列"
|
||||
swapLeft: "向左移动"
|
||||
swapRight: "向右移动"
|
||||
@ -1465,6 +1483,7 @@ _deck:
|
||||
stackLeft: "向左折叠"
|
||||
popRight: "向右弹出"
|
||||
_columns:
|
||||
main: "主列"
|
||||
widgets: "小工具"
|
||||
notifications: "通知"
|
||||
tl: "时间线"
|
||||
|
@ -12,7 +12,7 @@ gotIt: "知道了"
|
||||
cancel: "取消"
|
||||
enterUsername: "輸入使用者名稱"
|
||||
renotedBy: "{user} 轉發了"
|
||||
noNotes: "貼文不可用。"
|
||||
noNotes: "箋文不可用。"
|
||||
noNotifications: "沒有通知"
|
||||
instance: "實例"
|
||||
settings: "設定"
|
||||
@ -33,6 +33,9 @@ addUser: "新增使用者"
|
||||
favorite: "收藏"
|
||||
favorites: "已加星號"
|
||||
unfavorite: "取消收藏"
|
||||
favorited: "已添加至收藏夾"
|
||||
alreadyFavorited: "已經有添加入收藏夾過了"
|
||||
cantFavorite: "無法添加至收藏夾"
|
||||
pin: "置頂"
|
||||
unpin: "取消置頂"
|
||||
copyContent: "複製內容"
|
||||
@ -63,8 +66,8 @@ exportRequested: "已請求匯出。這可能會花一點時間。結束後檔
|
||||
importRequested: "已請求匯入。這可能會花一點時間"
|
||||
lists: "清單"
|
||||
noLists: "沒有清單"
|
||||
note: "貼文"
|
||||
notes: "筆記"
|
||||
note: "箋文"
|
||||
notes: "箋文"
|
||||
following: "追隨中"
|
||||
followers: "追隨者"
|
||||
followsYou: "追隨你的人"
|
||||
@ -74,6 +77,7 @@ error: "錯誤"
|
||||
somethingHappened: "發生錯誤"
|
||||
retry: "重試"
|
||||
pageLoadError: "載入頁面失敗"
|
||||
pageLoadErrorDescription: "這通常是因為網路錯誤或是瀏覽器快取殘留的原因。請先清除瀏覽器快取,稍後再重試"
|
||||
enterListName: "輸入清單名稱"
|
||||
privacy: "隱私"
|
||||
makeFollowManuallyApprove: "手動審核追隨請求"
|
||||
@ -86,6 +90,9 @@ followRequestPending: "追隨許可批准中"
|
||||
enterEmoji: "輸入表情符號"
|
||||
renote: "轉發貼文"
|
||||
unrenote: "取消轉發貼文"
|
||||
renoted: "轉發成功"
|
||||
cantRenote: "這篇貼文無法轉發。"
|
||||
cantReRenote: "無法轉發之前已經轉發過的內容"
|
||||
quote: "引用"
|
||||
pinnedNote: "已置頂的貼文"
|
||||
you: "您"
|
||||
@ -94,6 +101,7 @@ sensitive: "敏感內容"
|
||||
add: "新增"
|
||||
reaction: "反應"
|
||||
reactionSettingDescription: "置頂「反應」表情符號\n"
|
||||
reactionSettingDescription2: "拖動以重新列序,點擊以刪除,按下 + 添加。"
|
||||
rememberNoteVisibility: "記住筆記隱私設定"
|
||||
attachCancel: "移除附件"
|
||||
markAsSensitive: "標記為敏感內容"
|
||||
@ -123,7 +131,9 @@ settingGuide: "推薦設定"
|
||||
cacheRemoteFiles: "緩存非遠程檔案"
|
||||
cacheRemoteFilesDescription: "禁用此設定會停止遠端檔案的緩存,從而節省儲存空間。但資料會因直接連線從而產生額外連接數據。"
|
||||
flagAsBot: "此使用者是機器人"
|
||||
flagAsBotDescription: "如果本帳戶是由程式控制,請啟用此選項。啟用後,會作為標示幫助其他開發者防止機器人之間產生無限互動的行為,並會調整Misskey內部系統將本帳戶識別為機器人"
|
||||
flagAsCat: "此使用者是貓"
|
||||
flagAsCatDescription: "如果想將本帳戶標示為一隻貓,請開啟此標示"
|
||||
autoAcceptFollowed: "自動許可追隨"
|
||||
addAcount: "新增帳號"
|
||||
loginFailed: "登入失敗"
|
||||
@ -213,6 +223,7 @@ remove: "刪除"
|
||||
removed: "成功移除"
|
||||
removeAreYouSure: "確定要刪掉「{x}」嗎?"
|
||||
deleteAreYouSure: "確定要刪掉「{x}」嗎?"
|
||||
resetAreYouSure: "確定要重設嗎?"
|
||||
saved: "已保存"
|
||||
messaging: "傳送訊息"
|
||||
upload: "上傳"
|
||||
@ -289,7 +300,7 @@ tosUrl: "服務條款URL"
|
||||
thisYear: "今年"
|
||||
thisMonth: "本月"
|
||||
today: "本日"
|
||||
dayX: "{day}天"
|
||||
dayX: "{day}日"
|
||||
monthX: "{month}月"
|
||||
yearX: "{year}年"
|
||||
pages: "頁面"
|
||||
@ -312,6 +323,8 @@ bannerUrl: "橫幅圖片URL"
|
||||
basicInfo: "基本資訊"
|
||||
pinnedUsers: "置頂用戶"
|
||||
pinnedUsersDescription: "在「發現」頁面中使用換行標記想要置頂的用戶。"
|
||||
pinnedPages: "釘選頁面"
|
||||
pinnedPagesDescription: "輸入要固定至實例首頁的頁面路徑,以換行符分隔。"
|
||||
pinnedNotes: "已置頂的貼文"
|
||||
hcaptcha: "hCaptcha"
|
||||
enableHcaptcha: "啟用 hCaptcha"
|
||||
@ -330,6 +343,7 @@ antennaKeywords: "包含關鍵字"
|
||||
antennaExcludeKeywords: "排除關鍵字"
|
||||
antennaKeywordsDescription: "用空格分隔指定AND、用換行符分隔指定OR"
|
||||
notifyAntenna: "通知我有新的貼文"
|
||||
withFileAntenna: "僅帶有附件的箋文"
|
||||
serviceworker: "ServiceWorker"
|
||||
enableServiceworker: "開啟 ServiceWorker"
|
||||
antennaUsersDescription: "指定用換行符分隔的用戶名"
|
||||
@ -393,7 +407,7 @@ text: "文字"
|
||||
enable: "啟用"
|
||||
next: "下一步"
|
||||
retype: "重新輸入"
|
||||
noteOf: "{user}的貼文"
|
||||
noteOf: "{user}的箋文"
|
||||
inviteToGroup: "邀請至群組"
|
||||
maxNoteTextLength: "貼文的字數限制"
|
||||
quoteAttached: "引用"
|
||||
@ -426,6 +440,7 @@ useOsNativeEmojis: "使用OS原生表情符號"
|
||||
youHaveNoGroups: "找不到群組"
|
||||
joinOrCreateGroup: "請加入現有群組,或創建新群組。"
|
||||
noHistory: "沒有歷史紀錄"
|
||||
signinHistory: "登錄歷史"
|
||||
disableAnimatedMfm: "禁用MFM動畫"
|
||||
doing: "正在進行"
|
||||
category: "類別"
|
||||
@ -435,7 +450,9 @@ createAccount: "建立帳戶"
|
||||
existingAcount: "現有帳戶"
|
||||
regenerate: "再生"
|
||||
fontSize: "字體大小"
|
||||
noFollowRequests: "沒有要求跟隨您的申請"
|
||||
openImageInNewTab: "於新分頁中開啟圖片"
|
||||
dashboard: "儀表板"
|
||||
local: "本地"
|
||||
remote: "遠端"
|
||||
total: "合計"
|
||||
@ -457,12 +474,18 @@ objectStorageEndpointDesc: "如要使用AWS S3,請留空。否則請根據伺
|
||||
objectStorageRegion: "地域(Region)"
|
||||
objectStorageUseSSL: "使用SSL"
|
||||
objectStorageUseProxy: "使用網路代理"
|
||||
objectStorageSetPublicRead: "上載時設定為\"public-read\""
|
||||
serverLogs: "伺服器日誌"
|
||||
deleteAll: "刪除所有記錄"
|
||||
showFixedPostForm: "在時間線頂部顯示貼文表格"
|
||||
newNoteRecived: "有新的箋文"
|
||||
sounds: "音效"
|
||||
listen: "聆聽"
|
||||
none: "無"
|
||||
showInPage: "在頁面中顯示"
|
||||
popout: "彈出型窗口"
|
||||
volume: "音量"
|
||||
masterVolume: "主音量"
|
||||
details: "詳細資訊"
|
||||
chooseEmoji: "選擇您的表情符號\n"
|
||||
unableToProcess: "操作無法完成"
|
||||
@ -480,10 +503,12 @@ descendingOrder: "降冪"
|
||||
scratchpad: "暫存記憶體"
|
||||
output: "輸出"
|
||||
script: "腳本"
|
||||
disablePagesScript: "停用頁面的AiScript腳本"
|
||||
updateRemoteUser: "更新非本地用戶資料"
|
||||
deleteAllFiles: "刪除所有檔案"
|
||||
deleteAllFilesConfirm: "要删除所有檔案吗?"
|
||||
removeAllFollowing: "解除所有追隨"
|
||||
removeAllFollowingDescription: "解除{host}所有的跟隨。在實例不再存在時執行。"
|
||||
userSuspended: "該用戶已被凍結"
|
||||
userSilenced: "該用戶已被禁言。"
|
||||
sidebar: "側邊列"
|
||||
@ -513,8 +538,12 @@ plugins: "插件"
|
||||
pluginInstallWarn: "請不要安裝來源不明的插件。"
|
||||
deck: "多欄模式"
|
||||
undeck: "取消多欄模式"
|
||||
useBlurEffectForModal: "在模態框使用模糊效果"
|
||||
width: "寬度"
|
||||
height: "高度"
|
||||
large: "大"
|
||||
medium: "中"
|
||||
small: "小"
|
||||
permission: "權限"
|
||||
enableAll: "啟用全部"
|
||||
disableAll: "停用全部"
|
||||
@ -525,6 +554,8 @@ useStarForReactionFallback: "以★代替未知的表情符號"
|
||||
emailConfig: "電子郵件伺服器設定"
|
||||
enableEmail: "啟用發送電郵功能"
|
||||
emailConfigInfo: "用於確認電郵地址及密碼重置"
|
||||
email: "電子郵件"
|
||||
emailAddress: "電郵地址"
|
||||
smtpConfig: "SMTP伺服器設定"
|
||||
smtpHost: "主機"
|
||||
smtpPort: "端口"
|
||||
@ -533,6 +564,8 @@ smtpPass: "密碼"
|
||||
emptyToDisableSmtpAuth: "留空使用者名稱和密碼以禁用SMTP驗證。"
|
||||
testEmail: "郵件測試發送"
|
||||
wordMute: "靜音文字"
|
||||
userSaysSomething: "{name}說了什麼"
|
||||
makeActive: "啟用"
|
||||
display: "檢視"
|
||||
copy: "複製"
|
||||
metrics: "指標"
|
||||
@ -543,21 +576,72 @@ database: "資料庫"
|
||||
channel: "頻道"
|
||||
create: "新增"
|
||||
notificationSetting: "通知設定"
|
||||
notificationSettingDesc: "選擇顯示通知的類型"
|
||||
useGlobalSetting: "使用全域設定"
|
||||
other: "其他"
|
||||
regenerateLoginTokenDescription: "再生用於登入的內部權杖。一般情況下是不需要這樣做的。一旦再生,所有裝置將會被登出。"
|
||||
fileIdOrUrl: "文檔ID或者URL"
|
||||
chatOpenBehavior: "開啟聊天窗口時的行為"
|
||||
behavior: "行為"
|
||||
sample: "範例 "
|
||||
abuseReports: "檢舉"
|
||||
reportAbuse: "檢舉"
|
||||
reportAbuseOf: "檢舉{name}"
|
||||
fillAbuseReportDescription: "請填寫檢舉的詳細理由。可以的話,請附上針對的URL網址。"
|
||||
abuseReported: "內容已經發送。感謝您的報告。"
|
||||
send: "發送"
|
||||
abuseMarkAsResolved: "處理完畢"
|
||||
openInNewTab: "在新分頁中開啟"
|
||||
openInSideView: "在側欄中開啟"
|
||||
instanceTicker: "箋文的實例資訊"
|
||||
random: "隨機"
|
||||
system: "系統"
|
||||
switchUi: "切換界面"
|
||||
optional: "可選"
|
||||
public: "公開"
|
||||
notesCount: "箋文數量"
|
||||
repliesCount: "回覆數量\n"
|
||||
renotesCount: "轉發數量"
|
||||
repliedCount: "回覆數量"
|
||||
yes: "確定"
|
||||
no: "取消"
|
||||
driveFilesCount: "雲端硬碟檔案數量"
|
||||
driveUsage: "雲端硬碟使用量"
|
||||
noCrawleDescription: "請求網路搜尋引擎不要索引你的個人資料頁、箋文及頁面等。"
|
||||
lockedAccountInfo: "即使你通過了追隨者請求,除非你將筆記的公開範圍設定為 「追隨者」,否則任何人都能看見你的箋文。"
|
||||
notSet: "未設定"
|
||||
noteFavoritesCount: "收藏箋文的數目"
|
||||
pageLikesCount: "頁面被喜歡次數"
|
||||
pageLikedCount: "頁面被喜歡次數"
|
||||
contact: "聯絡人"
|
||||
clips: "標籤"
|
||||
experimentalFeatures: "測試中的功能"
|
||||
developer: "開發者"
|
||||
showGapBetweenNotesInTimeline: "分開顯示時間線上的箋文。"
|
||||
left: "左"
|
||||
wide: "寬"
|
||||
narrow: "窄"
|
||||
reloadToApplySetting: "設定將會在頁面重新載入之後生效。要現在就重載頁面嗎?"
|
||||
_aboutMisskey:
|
||||
about: "Misskey是由syuilo於2014年開發的開源軟件。"
|
||||
contributors: "主要貢獻者"
|
||||
allContributors: "全體貢獻人員"
|
||||
source: "原始碼"
|
||||
translation: "翻譯Misskey"
|
||||
donate: "捐贈給Misskey"
|
||||
morePatrons: "感謝你們的支持、 幫助。 🥰"
|
||||
patrons: "贊助者"
|
||||
_nsfw:
|
||||
respect: "隱藏NSFW內容"
|
||||
ignore: "不隱藏NSFW內容"
|
||||
force: "隱藏所有內容"
|
||||
_mfm:
|
||||
mention: "提及"
|
||||
hashtag: "#tag"
|
||||
url: "URL"
|
||||
link: "鏈接"
|
||||
bold: "粗體"
|
||||
center: "置中"
|
||||
quote: "引用"
|
||||
emoji: "自訂表情符號"
|
||||
search: "搜尋"
|
||||
@ -598,7 +682,8 @@ _sidebar:
|
||||
hide: "隱藏"
|
||||
_wordMute:
|
||||
muteWords: "加入靜音文字"
|
||||
mutedNotes: "已靜音的貼文"
|
||||
softDescription: "隱藏時間軸中指定條件的箋文。"
|
||||
mutedNotes: "已靜音的箋文"
|
||||
_theme:
|
||||
constant: "常數"
|
||||
defaultValue: "預設值"
|
||||
@ -623,8 +708,8 @@ _theme:
|
||||
infoWarnBg: "警告背景"
|
||||
infoWarnFg: "警告字元"
|
||||
_sfx:
|
||||
note: "貼文"
|
||||
noteMy: "我的貼文"
|
||||
note: "箋文"
|
||||
noteMy: "我的箋文"
|
||||
notification: "通知"
|
||||
chat: "傳送訊息"
|
||||
channel: "頻道通知"
|
||||
@ -643,7 +728,7 @@ _time:
|
||||
second: "秒"
|
||||
minute: "分鐘"
|
||||
hour: "小時"
|
||||
day: "天"
|
||||
day: "日"
|
||||
_tutorial:
|
||||
title: "Misskey使用方法"
|
||||
step1_1: "歡迎!"
|
||||
@ -656,7 +741,7 @@ _tutorial:
|
||||
step3_3: "輸入完內容後,按視窗右上角的按鈕來發文"
|
||||
step3_4: "不知道該寫什麼內容嗎?試試看「開始使用Misskey了」如何。"
|
||||
step4_1: "筆記發出去了嗎?"
|
||||
step4_2: "如果你的貼文有顯示在時間軸上,就代表已經發文成功。"
|
||||
step4_2: "如果你的箋文出現在時間軸上,就代表發文成功。"
|
||||
step5_1: "現在試試看追隨其他人來讓你的時間軸變得更生動吧。"
|
||||
step5_2: "你可以在{featured}上看到受歡迎的貼文,你也可以選擇從列表中追隨你喜歡的人,或者在{explore}上找到熱門使用者。"
|
||||
step5_3: "想要追隨其他人,只要點擊他們的頭像並按「追隨」即可。"
|
||||
@ -680,7 +765,7 @@ _permissions:
|
||||
"write:messaging": "撰寫或刪除私人訊息"
|
||||
"read:mutes": "顯示已靜音列表"
|
||||
"write:mutes": "編輯已靜音列表"
|
||||
"write:notes": "撰寫或刪除貼文"
|
||||
"write:notes": "撰寫或刪除箋文"
|
||||
"read:notifications": "查看通知"
|
||||
"write:notifications": "編輯通知"
|
||||
"read:reactions": "查看反應"
|
||||
@ -697,11 +782,11 @@ _permissions:
|
||||
_auth:
|
||||
shareAccess: "要授權「“{name}”」存取您的帳戶嗎?"
|
||||
_antennaSources:
|
||||
all: "全部貼文"
|
||||
homeTimeline: "來自已追隨使用者的貼文"
|
||||
users: "來自特定使用者的貼文"
|
||||
userList: "來自特定清單中的貼文"
|
||||
userGroup: "來自特定群組的貼文"
|
||||
all: "全部箋文"
|
||||
homeTimeline: "來自已追隨使用者的箋文"
|
||||
users: "來自特定使用者的箋文"
|
||||
userList: "來自特定清單中的箋文"
|
||||
userGroup: "來自特定群組的箋文"
|
||||
_weekday:
|
||||
sunday: "週日"
|
||||
monday: "週一"
|
||||
@ -722,6 +807,7 @@ _widgets:
|
||||
photos: "照片"
|
||||
digitalClock: "電子時鐘"
|
||||
federation: "聯邦宇宙"
|
||||
button: "按鈕"
|
||||
_cw:
|
||||
hide: "隱藏"
|
||||
show: "瀏覽更多"
|
||||
@ -751,7 +837,7 @@ _visibility:
|
||||
localOnly: "僅限本地"
|
||||
localOnlyDescription: "對遠端使用者隱藏"
|
||||
_postForm:
|
||||
replyPlaceholder: "回覆此貼文..."
|
||||
replyPlaceholder: "回覆此箋文..."
|
||||
quotePlaceholder: "引用此貼文..."
|
||||
channelPlaceholder: "發佈到頻道"
|
||||
_placeholders:
|
||||
@ -769,7 +855,7 @@ _profile:
|
||||
metadataLabel: "標籤"
|
||||
metadataContent: "内容"
|
||||
_exportOrImport:
|
||||
allNotes: "全部貼文"
|
||||
allNotes: "全部箋文"
|
||||
followingList: "追隨中"
|
||||
muteList: "靜音"
|
||||
blockingList: "封鎖"
|
||||
@ -778,10 +864,10 @@ _charts:
|
||||
usersIncDec: "使用者増減"
|
||||
usersTotal: "使用者合共"
|
||||
activeUsers: "活躍使用者"
|
||||
notesIncDec: "貼文増減"
|
||||
localNotesIncDec: "本地貼文増減"
|
||||
remoteNotesIncDec: "非本地貼文的數目增减"
|
||||
notesTotal: "貼文合共"
|
||||
notesIncDec: "箋文増減"
|
||||
localNotesIncDec: "本地箋文増減"
|
||||
remoteNotesIncDec: "遠端箋文數目增减"
|
||||
notesTotal: "箋文合共"
|
||||
filesIncDec: "檔案増減"
|
||||
filesTotal: "累計檔案"
|
||||
storageUsageIncDec: "儲存空間的増減"
|
||||
@ -790,8 +876,8 @@ _instanceCharts:
|
||||
requests: "請求"
|
||||
users: "使用者増減"
|
||||
usersTotal: "總計使用者"
|
||||
notes: "貼文増減"
|
||||
notesTotal: "累計貼文"
|
||||
notes: "箋文増減"
|
||||
notesTotal: "累計箋文"
|
||||
ff: "追隨/追隨者的増減"
|
||||
ffTotal: "追隨/追隨者累計"
|
||||
cacheSize: "增加或減少快取用量"
|
||||
@ -854,9 +940,14 @@ _rooms:
|
||||
_pages:
|
||||
newPage: "建立頁面"
|
||||
editPage: "編輯頁面"
|
||||
readPage: "正檢視原始碼"
|
||||
created: "頁面已建立"
|
||||
updated: "頁面已更新"
|
||||
deleted: "頁面已被刪除"
|
||||
pageSetting: "頁面設定"
|
||||
nameAlreadyExists: "指定的頁面URL已經存在"
|
||||
invalidNameTitle: "指定的頁面URL無效"
|
||||
invalidNameText: "請確定是否為非空白"
|
||||
editThisPage: "編輯此頁面"
|
||||
viewSource: "檢視原始碼"
|
||||
viewPage: "顯示頁面"
|
||||
@ -864,14 +955,28 @@ _pages:
|
||||
unlike: "收回喜歡"
|
||||
my: "我的頁面"
|
||||
liked: "已喜歡的頁面"
|
||||
featured: "人氣"
|
||||
inspector: "面板檢查"
|
||||
contents: "內容"
|
||||
content: "頁面方塊"
|
||||
variables: "變數"
|
||||
title: "標題"
|
||||
url: "頁面網址"
|
||||
summary: "頁面摘要"
|
||||
alignCenter: "置中"
|
||||
hideTitleWhenPinned: "被置頂於個人資料時隱藏頁面標題"
|
||||
font: "字型"
|
||||
fontSerif: "襯線體"
|
||||
fontSansSerif: "無襯線體"
|
||||
eyeCatchingImageSet: "設定封面影像"
|
||||
eyeCatchingImageRemove: "刪除封面影像"
|
||||
chooseBlock: "新增方塊"
|
||||
selectType: "選擇類型"
|
||||
enterVariableName: "請輸入變數名稱"
|
||||
variableNameIsAlreadyUsed: "變數名稱已被佔用"
|
||||
contentBlocks: "內容"
|
||||
inputBlocks: "輸入"
|
||||
specialBlocks: "特殊"
|
||||
blocks:
|
||||
text: "文本"
|
||||
textarea: "文字區域"
|
||||
@ -904,6 +1009,10 @@ _pages:
|
||||
id: "畫布ID"
|
||||
width: "寬度"
|
||||
height: "高度"
|
||||
note: "嵌式箋文"
|
||||
_note:
|
||||
id: "箋文ID"
|
||||
detailed: "顯示詳細內容"
|
||||
switch: "開關"
|
||||
_switch:
|
||||
name: "變數名稱"
|
||||
|
18
migration/1607353487793-isExplorable.ts
Normal file
18
migration/1607353487793-isExplorable.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class isExplorable1607353487793 implements MigrationInterface {
|
||||
name = 'isExplorable1607353487793'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "user" ADD "isExplorable" boolean NOT NULL DEFAULT true`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isExplorable" IS 'Whether the User is explorable.'`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_d5a1b83c7cab66f167e6888188" ON "user" ("isExplorable") `);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`DROP INDEX "IDX_d5a1b83c7cab66f167e6888188"`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isExplorable" IS 'Whether the User is explorable.'`);
|
||||
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "isExplorable"`);
|
||||
}
|
||||
|
||||
}
|
70
package.json
70
package.json
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
||||
"version": "12.62.1",
|
||||
"version": "12.65.0",
|
||||
"codename": "indigo",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -41,7 +41,7 @@
|
||||
"@fortawesome/free-brands-svg-icons": "5.15.1",
|
||||
"@fortawesome/free-regular-svg-icons": "5.15.1",
|
||||
"@fortawesome/free-solid-svg-icons": "5.15.1",
|
||||
"@fortawesome/vue-fontawesome": "3.0.0-2",
|
||||
"@fortawesome/vue-fontawesome": "3.0.0-3",
|
||||
"@koa/cors": "3.1.0",
|
||||
"@koa/multer": "3.0.0",
|
||||
"@koa/router": "9.0.1",
|
||||
@ -62,7 +62,7 @@
|
||||
"@types/jsdom": "16.2.5",
|
||||
"@types/jsonld": "1.5.1",
|
||||
"@types/katex": "0.11.0",
|
||||
"@types/koa": "2.11.3",
|
||||
"@types/koa": "2.11.6",
|
||||
"@types/koa-bodyparser": "4.3.0",
|
||||
"@types/koa-cors": "0.0.0",
|
||||
"@types/koa-favicon": "2.0.19",
|
||||
@ -70,30 +70,30 @@
|
||||
"@types/koa-mount": "4.0.0",
|
||||
"@types/koa-send": "4.1.2",
|
||||
"@types/koa-views": "2.0.4",
|
||||
"@types/koa__cors": "3.0.1",
|
||||
"@types/koa__cors": "3.0.2",
|
||||
"@types/koa__multer": "2.0.2",
|
||||
"@types/koa__router": "8.0.2",
|
||||
"@types/markdown-it": "10.0.3",
|
||||
"@types/matter-js": "0.14.7",
|
||||
"@types/matter-js": "0.14.8",
|
||||
"@types/mocha": "7.0.2",
|
||||
"@types/node": "14.0.22",
|
||||
"@types/node": "14.14.13",
|
||||
"@types/node-fetch": "2.5.7",
|
||||
"@types/nodemailer": "6.4.0",
|
||||
"@types/nprogress": "0.2.0",
|
||||
"@types/oauth": "0.9.1",
|
||||
"@types/parse5": "5.0.3",
|
||||
"@types/parsimmon": "1.10.5",
|
||||
"@types/parsimmon": "1.10.6",
|
||||
"@types/portscanner": "2.1.0",
|
||||
"@types/pug": "2.0.4",
|
||||
"@types/qrcode": "1.3.5",
|
||||
"@types/random-seed": "0.3.3",
|
||||
"@types/ratelimiter": "3.4.0",
|
||||
"@types/ratelimiter": "3.4.1",
|
||||
"@types/redis": "2.8.28",
|
||||
"@types/rename": "1.0.2",
|
||||
"@types/request-stats": "3.0.0",
|
||||
"@types/rimraf": "3.0.0",
|
||||
"@types/seedrandom": "2.4.28",
|
||||
"@types/sharp": "0.26.0",
|
||||
"@types/sharp": "0.26.1",
|
||||
"@types/sinonjs__fake-timers": "6.0.1",
|
||||
"@types/speakeasy": "2.0.5",
|
||||
"@types/tinycolor2": "1.4.2",
|
||||
@ -104,17 +104,17 @@
|
||||
"@types/webpack-stream": "3.2.11",
|
||||
"@types/websocket": "1.0.1",
|
||||
"@types/ws": "7.4.0",
|
||||
"@typescript-eslint/parser": "4.6.1",
|
||||
"@typescript-eslint/parser": "4.10.0",
|
||||
"@vue/compiler-sfc": "3.0.3",
|
||||
"abort-controller": "3.0.0",
|
||||
"apexcharts": "3.22.2",
|
||||
"apexcharts": "3.22.3",
|
||||
"autobind-decorator": "2.4.0",
|
||||
"autosize": "4.0.2",
|
||||
"autwh": "0.1.0",
|
||||
"aws-sdk": "2.787.0",
|
||||
"aws-sdk": "2.809.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"blurhash": "1.1.3",
|
||||
"bull": "3.18.1",
|
||||
"bull": "3.20.0",
|
||||
"cafy": "15.2.1",
|
||||
"cbor": "5.1.0",
|
||||
"chalk": "4.1.0",
|
||||
@ -122,28 +122,30 @@
|
||||
"cli-highlight": "2.1.9",
|
||||
"commander": "4.1.1",
|
||||
"content-disposition": "0.5.3",
|
||||
"core-js": "3.7.0",
|
||||
"core-js": "3.8.1",
|
||||
"crc-32": "1.2.0",
|
||||
"css-loader": "5.0.1",
|
||||
"cssnano": "4.1.10",
|
||||
"dateformat": "3.0.3",
|
||||
"dateformat": "4.3.1",
|
||||
"deep-entries": "3.1.0",
|
||||
"diskusage": "1.1.3",
|
||||
"double-ended-queue": "2.1.0-0",
|
||||
"escape-regexp": "0.0.1",
|
||||
"eslint": "7.14.0",
|
||||
"eslint-plugin-vue": "7.1.0",
|
||||
"eslint": "7.16.0",
|
||||
"eslint-plugin-vue": "7.3.0",
|
||||
"eventemitter3": "4.0.7",
|
||||
"feed": "4.2.1",
|
||||
"fibers": "5.0.0",
|
||||
"file-type": "16.0.1",
|
||||
"fluent-ffmpeg": "2.1.2",
|
||||
"glob": "7.1.6",
|
||||
"got": "11.8.0",
|
||||
"got": "11.8.1",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-cssnano": "2.1.3",
|
||||
"gulp-rename": "2.0.0",
|
||||
"gulp-replace": "1.0.0",
|
||||
"gulp-sourcemaps": "2.6.5",
|
||||
"gulp-terser": "2.0.0",
|
||||
"gulp-tslint": "8.1.4",
|
||||
"gulp-typescript": "6.0.0-alpha.1",
|
||||
"hard-source-webpack-plugin": "0.13.1",
|
||||
@ -152,7 +154,6 @@
|
||||
"http-proxy-agent": "4.0.1",
|
||||
"http-signature": "1.3.5",
|
||||
"https-proxy-agent": "5.0.0",
|
||||
"idb-keyval": "3.2.0",
|
||||
"insert-text-at-cursor": "0.3.0",
|
||||
"is-root": "2.1.0",
|
||||
"is-svg": "4.2.1",
|
||||
@ -179,11 +180,11 @@
|
||||
"matter-js": "0.14.2",
|
||||
"mocha": "8.2.1",
|
||||
"moji": "0.5.1",
|
||||
"ms": "2.1.2",
|
||||
"ms": "2.1.3",
|
||||
"multer": "1.4.2",
|
||||
"nested-property": "4.0.0",
|
||||
"node-fetch": "2.6.1",
|
||||
"nodemailer": "6.4.16",
|
||||
"nodemailer": "6.4.17",
|
||||
"object-assign-deep": "0.4.0",
|
||||
"os-utils": "0.0.14",
|
||||
"p-cancelable": "2.0.0",
|
||||
@ -191,7 +192,7 @@
|
||||
"parsimmon": "1.16.0",
|
||||
"pg": "8.5.1",
|
||||
"portscanner": "2.2.0",
|
||||
"postcss": "8.1.14",
|
||||
"postcss": "8.2.1",
|
||||
"postcss-loader": "4.1.0",
|
||||
"prismjs": "1.22.0",
|
||||
"probe-image-size": "6.0.0",
|
||||
@ -225,45 +226,42 @@
|
||||
"style-loader": "2.0.0",
|
||||
"summaly": "2.4.0",
|
||||
"syslog-pro": "1.0.0",
|
||||
"systeminformation": "4.30.7",
|
||||
"systeminformation": "4.31.1",
|
||||
"syuilo-password-strength": "0.0.1",
|
||||
"textarea-caret": "3.1.0",
|
||||
"three": "0.117.1",
|
||||
"tinycolor2": "1.4.2",
|
||||
"tmp": "0.2.1",
|
||||
"ts-loader": "8.0.9",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.0",
|
||||
"tslint": "6.1.3",
|
||||
"tslint-sonarts": "1.9.0",
|
||||
"typeorm": "0.2.29",
|
||||
"typescript": "4.0.5",
|
||||
"typescript": "4.1.2",
|
||||
"ulid": "2.3.0",
|
||||
"url-loader": "4.1.1",
|
||||
"uuid": "8.3.1",
|
||||
"uuid": "8.3.2",
|
||||
"v-debounce": "0.1.2",
|
||||
"vanilla-tilt": "1.7.0",
|
||||
"vue": "3.0.3",
|
||||
"vue-color": "2.7.1",
|
||||
"vue-i18n": "9.0.0-beta.7",
|
||||
"vue-json-pretty": "1.7.1",
|
||||
"vue-loader": "16.0.0",
|
||||
"vue-prism-editor": "2.0.0-alpha.2",
|
||||
"vue-router": "4.0.0-rc.6",
|
||||
"vue-router": "4.0.1",
|
||||
"vue-style-loader": "4.1.2",
|
||||
"vuedraggable": "4.0.1",
|
||||
"vuex": "4.0.0-rc.2",
|
||||
"vuex-persistedstate": "3.1.0",
|
||||
"web-push": "3.4.4",
|
||||
"webpack": "5.9.0",
|
||||
"webpack-cli": "4.2.0",
|
||||
"websocket": "1.0.32",
|
||||
"ws": "7.4.0",
|
||||
"webpack": "5.10.1",
|
||||
"webpack-cli": "4.3.0",
|
||||
"websocket": "1.0.33",
|
||||
"ws": "7.4.1",
|
||||
"xev": "2.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "4.2.11",
|
||||
"@types/chai": "4.2.14",
|
||||
"@types/fluent-ffmpeg": "2.1.16",
|
||||
"chai": "4.2.0",
|
||||
"cross-env": "7.0.2"
|
||||
"cross-env": "7.0.3"
|
||||
}
|
||||
}
|
||||
|
2
src/client/@types/global.d.ts
vendored
2
src/client/@types/global.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
declare const _LANGS_: string[];
|
||||
declare const _LANGS_: string[][];
|
||||
declare const _VERSION_: string;
|
||||
declare const _ENV_: string;
|
||||
declare const _DEV_: boolean;
|
||||
|
4
src/client/@types/vue.d.ts
vendored
4
src/client/@types/vue.d.ts
vendored
@ -1,5 +1,5 @@
|
||||
declare module '*.vue' {
|
||||
import { defineComponent } from 'vue';
|
||||
const component: ReturnType<typeof defineComponent>;
|
||||
import type { DefineComponent } from 'vue';
|
||||
const component: DefineComponent<{}, {}, any>;
|
||||
export default component;
|
||||
}
|
||||
|
12
src/client/@types/vuex-shim.d.ts
vendored
12
src/client/@types/vuex-shim.d.ts
vendored
@ -1,12 +0,0 @@
|
||||
import { ComponentCustomProperties } from 'vue';
|
||||
import { Store } from 'vuex';
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
// tslint:disable-next-line:no-empty-interface
|
||||
interface State {
|
||||
}
|
||||
|
||||
interface ComponentCustomProperties {
|
||||
$store: Store<State>;
|
||||
}
|
||||
}
|
86
src/client/account.ts
Normal file
86
src/client/account.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { reactive } from 'vue';
|
||||
import { apiUrl } from '@/config';
|
||||
import { waiting } from '@/os';
|
||||
|
||||
// TODO: 他のタブと永続化されたstateを同期
|
||||
|
||||
type Account = {
|
||||
id: string;
|
||||
token: string;
|
||||
clientData: Record<string, any>;
|
||||
};
|
||||
|
||||
const data = localStorage.getItem('account');
|
||||
|
||||
// TODO: 外部からはreadonlyに
|
||||
export const $i = data ? reactive(JSON.parse(data) as Account) : null;
|
||||
|
||||
export function signout() {
|
||||
localStorage.removeItem('account');
|
||||
document.cookie = `igi=; path=/`;
|
||||
location.href = '/';
|
||||
}
|
||||
|
||||
export function getAccounts() {
|
||||
const accountsData = localStorage.getItem('accounts');
|
||||
const accounts: { id: Account['id'], token: Account['token'] }[] = accountsData ? JSON.parse(accountsData) : [];
|
||||
return accounts;
|
||||
}
|
||||
|
||||
export function addAccount(id: Account['id'], token: Account['token']) {
|
||||
const accounts = getAccounts();
|
||||
if (!accounts.some(x => x.id === id)) {
|
||||
localStorage.setItem('accounts', JSON.stringify(accounts.concat([{ id, token }])));
|
||||
}
|
||||
}
|
||||
|
||||
function fetchAccount(token): Promise<Account> {
|
||||
return new Promise((done, fail) => {
|
||||
// Fetch user
|
||||
fetch(`${apiUrl}/i`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
i: token
|
||||
})
|
||||
})
|
||||
.then(res => {
|
||||
// When failed to authenticate user
|
||||
if (res.status !== 200 && res.status < 500) {
|
||||
return signout();
|
||||
}
|
||||
|
||||
// Parse response
|
||||
res.json().then(i => {
|
||||
i.token = token;
|
||||
done(i);
|
||||
});
|
||||
})
|
||||
.catch(fail);
|
||||
});
|
||||
}
|
||||
|
||||
export function updateAccount(data) {
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
$i[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
export function refreshAccount() {
|
||||
fetchAccount($i.token).then(updateAccount);
|
||||
}
|
||||
|
||||
export async function login(token: Account['token']) {
|
||||
waiting();
|
||||
if (_DEV_) console.log('logging as token ', token);
|
||||
const me = await fetchAccount(token);
|
||||
localStorage.setItem('account', JSON.stringify(me));
|
||||
addAccount(me.id, token);
|
||||
location.reload();
|
||||
}
|
||||
|
||||
// このファイルに書きたくないけどここに書かないと何故かVeturが認識しない
|
||||
declare module '@vue/runtime-core' {
|
||||
interface ComponentCustomProperties {
|
||||
$i: typeof $i;
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
// 常にメモリにロードしておく必要がないような設定情報を保管するストレージ
|
||||
|
||||
const PREFIX = 'miux:';
|
||||
|
||||
export const defaultDeviceSettings = {
|
||||
sound_masterVolume: 0.3,
|
||||
sound_note: { type: 'syuilo/down', volume: 1 },
|
||||
sound_noteMy: { type: 'syuilo/up', volume: 1 },
|
||||
sound_notification: { type: 'syuilo/pope2', volume: 1 },
|
||||
sound_chat: { type: 'syuilo/pope1', volume: 1 },
|
||||
sound_chatBg: { type: 'syuilo/waon', volume: 1 },
|
||||
sound_antenna: { type: 'syuilo/triple', volume: 1 },
|
||||
sound_channel: { type: 'syuilo/square-pico', volume: 1 },
|
||||
sound_reversiPutBlack: { type: 'syuilo/kick', volume: 0.3 },
|
||||
sound_reversiPutWhite: { type: 'syuilo/snare', volume: 0.3 },
|
||||
};
|
||||
|
||||
export const device = {
|
||||
get<T extends keyof typeof defaultDeviceSettings>(key: T): typeof defaultDeviceSettings[T] {
|
||||
// TODO: indexedDBにする
|
||||
// ただしその際はnullチェックではなくキー存在チェックにしないとダメ
|
||||
// (indexedDBはnullを保存できるため、ユーザーが意図してnullを格納した可能性がある)
|
||||
const value = localStorage.getItem(PREFIX + key);
|
||||
if (value == null) {
|
||||
return defaultDeviceSettings[key];
|
||||
} else {
|
||||
return JSON.parse(value);
|
||||
}
|
||||
},
|
||||
|
||||
set(key: keyof typeof defaultDeviceSettings, value: any): any {
|
||||
localStorage.setItem(PREFIX + key, JSON.stringify(value));
|
||||
},
|
||||
};
|
@ -2,24 +2,24 @@
|
||||
<XWindow ref="window" :initial-width="400" :initial-height="500" :can-resize="true" @closed="$emit('closed')">
|
||||
<template #header>
|
||||
<Fa :icon="faExclamationCircle" style="margin-right: 0.5em;"/>
|
||||
<i18n-t keypath="reportAbuseOf" tag="span">
|
||||
<I18n :src="$ts.reportAbuseOf" tag="span">
|
||||
<template #name>
|
||||
<b><MkAcct :user="user"/></b>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</I18n>
|
||||
</template>
|
||||
<div class="dpvffvvy">
|
||||
<div class="_section">
|
||||
<div class="_content">
|
||||
<MkTextarea v-model:value="comment">
|
||||
<span>{{ $t('details') }}</span>
|
||||
<template #desc>{{ $t('fillAbuseReportDescription') }}</template>
|
||||
<span>{{ $ts.details }}</span>
|
||||
<template #desc>{{ $ts.fillAbuseReportDescription }}</template>
|
||||
</MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="_section">
|
||||
<div class="_content">
|
||||
<MkButton @click="send" primary full :disabled="comment.length === 0">{{ $t('send') }}</MkButton>
|
||||
<MkButton @click="send" primary full :disabled="comment.length === 0">{{ $ts.send }}</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -69,7 +69,7 @@ export default defineComponent({
|
||||
}, undefined, res => {
|
||||
os.dialog({
|
||||
type: 'success',
|
||||
text: this.$t('abuseReported')
|
||||
text: this.$ts.abuseReported
|
||||
});
|
||||
this.$refs.window.close();
|
||||
});
|
||||
|
@ -116,16 +116,6 @@ export default defineComponent({
|
||||
}
|
||||
};
|
||||
update();
|
||||
|
||||
this.$store.subscribe((mutation, state) => {
|
||||
if (mutation.type !== 'device/set') return;
|
||||
|
||||
if (mutation?.payload?.key !== 'theme') return;
|
||||
|
||||
setTimeout(() => {
|
||||
this.computedStyle = getComputedStyle(document.documentElement);
|
||||
}, 250);
|
||||
});
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
|
@ -8,7 +8,7 @@
|
||||
</span>
|
||||
<span class="username">@{{ acct(user) }}</span>
|
||||
</li>
|
||||
<li @click="chooseUser()" @keydown="onKeydown" tabindex="-1" class="choose">{{ $t('selectUser') }}</li>
|
||||
<li @click="chooseUser()" @keydown="onKeydown" tabindex="-1" class="choose">{{ $ts.selectUser }}</li>
|
||||
</ol>
|
||||
<ol class="hashtags" ref="suggests" v-if="hashtags.length > 0">
|
||||
<li v-for="hashtag in hashtags" @click="complete(type, hashtag)" @keydown="onKeydown" tabindex="-1">
|
||||
@ -17,8 +17,8 @@
|
||||
</ol>
|
||||
<ol class="emojis" ref="suggests" v-if="emojis.length > 0">
|
||||
<li v-for="emoji in emojis" @click="complete(type, emoji.emoji)" @keydown="onKeydown" tabindex="-1">
|
||||
<span class="emoji" v-if="emoji.isCustomEmoji"><img :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url" :alt="emoji.emoji"/></span>
|
||||
<span class="emoji" v-else-if="!useOsNativeEmojis"><img :src="emoji.url" :alt="emoji.emoji"/></span>
|
||||
<span class="emoji" v-if="emoji.isCustomEmoji"><img :src="$store.state.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url" :alt="emoji.emoji"/></span>
|
||||
<span class="emoji" v-else-if="!$store.state.useOsNativeEmojis"><img :src="emoji.url" :alt="emoji.emoji"/></span>
|
||||
<span class="emoji" v-else>{{ emoji.emoji }}</span>
|
||||
<span class="name" v-html="emoji.name.replace(q, `<b>${q}</b>`)"></span>
|
||||
<span class="alias" v-if="emoji.aliasOf">({{ emoji.aliasOf }})</span>
|
||||
@ -128,12 +128,6 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
useOsNativeEmojis(): boolean {
|
||||
return this.$store.state.device.useOsNativeEmojis;
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
showing() {
|
||||
if (!this.showing) {
|
||||
@ -151,7 +145,7 @@ export default defineComponent({
|
||||
this.setPosition();
|
||||
|
||||
//#region Construct Emoji DB
|
||||
const customEmojis = this.$store.state.instance.meta.emojis;
|
||||
const customEmojis = this.$instance.emojis;
|
||||
const emojiDefinitions: EmojiDef[] = [];
|
||||
|
||||
for (const x of customEmojis) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<span v-if="!available">{{ $t('waiting') }}<MkEllipsis/></span>
|
||||
<span v-if="!available">{{ $ts.waiting }}<MkEllipsis/></span>
|
||||
<div ref="captcha"></div>
|
||||
</div>
|
||||
</template>
|
||||
@ -28,7 +28,6 @@ declare global {
|
||||
interface Window extends CaptchaContainer {
|
||||
}
|
||||
}
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@ -101,7 +100,7 @@ export default defineComponent({
|
||||
if (this.captcha.render && this.$refs.captcha instanceof Element) {
|
||||
this.captcha.render(this.$refs.captcha, {
|
||||
sitekey: this.sitekey,
|
||||
theme: this.$store.state.device.darkMode ? 'dark' : 'light',
|
||||
theme: this.$store.state.darkMode ? 'dark' : 'light',
|
||||
callback: this.callback,
|
||||
'expired-callback': this.callback,
|
||||
'error-callback': this.callback,
|
||||
|
@ -6,14 +6,14 @@
|
||||
>
|
||||
<template v-if="!wait">
|
||||
<template v-if="isFollowing">
|
||||
<span v-if="full">{{ $t('unfollow') }}</span><Fa :icon="faMinus"/>
|
||||
<span v-if="full">{{ $ts.unfollow }}</span><Fa :icon="faMinus"/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span v-if="full">{{ $t('follow') }}</span><Fa :icon="faPlus"/>
|
||||
<span v-if="full">{{ $ts.follow }}</span><Fa :icon="faPlus"/>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span v-if="full">{{ $t('processing') }}</span><Fa :icon="faSpinner" pulse fixed-width/>
|
||||
<span v-if="full">{{ $ts.processing }}</span><Fa :icon="faSpinner" pulse fixed-width/>
|
||||
</template>
|
||||
</button>
|
||||
</template>
|
||||
|
@ -6,19 +6,19 @@
|
||||
<div class="status">
|
||||
<div>
|
||||
<Fa :icon="faUsers" fixed-width/>
|
||||
<i18n-t keypath="_channel.usersCount" tag="span" style="margin-left: 4px;">
|
||||
<I18n :src="$ts._channel.usersCount" tag="span" style="margin-left: 4px;">
|
||||
<template #n>
|
||||
<b>{{ channel.usersCount }}</b>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</I18n>
|
||||
</div>
|
||||
<div>
|
||||
<Fa :icon="faPencilAlt" fixed-width/>
|
||||
<i18n-t keypath="_channel.notesCount" tag="span" style="margin-left: 4px;">
|
||||
<I18n :src="$ts._channel.notesCount" tag="span" style="margin-left: 4px;">
|
||||
<template #n>
|
||||
<b>{{ channel.notesCount }}</b>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</I18n>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -27,7 +27,7 @@
|
||||
</article>
|
||||
<footer>
|
||||
<span v-if="channel.lastNotedAt">
|
||||
{{ $t('updatedAt') }}: <MkTime :time="channel.lastNotedAt"/>
|
||||
{{ $ts.updatedAt }}: <MkTime :time="channel.lastNotedAt"/>
|
||||
</span>
|
||||
</footer>
|
||||
</MkA>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<button class="nrvgflfu _button" @click="toggle">
|
||||
<b>{{ value ? $t('_cw.hide') : $t('_cw.show') }}</b>
|
||||
<b>{{ value ? $ts._cw.hide : $ts._cw.show }}</b>
|
||||
<span v-if="!value">{{ label }}</span>
|
||||
</button>
|
||||
</template>
|
||||
@ -27,7 +27,7 @@ export default defineComponent({
|
||||
return concat([
|
||||
this.note.text ? [this.$t('_cw.chars', { count: length(this.note.text) })] : [],
|
||||
this.note.files && this.note.files.length !== 0 ? [this.$t('_cw.files', { count: this.note.files.length }) ] : [],
|
||||
this.note.poll != null ? [this.$t('poll')] : []
|
||||
this.note.poll != null ? [this.$ts.poll] : []
|
||||
] as string[][]).join(' / ');
|
||||
}
|
||||
},
|
||||
|
@ -1,20 +1,7 @@
|
||||
<template>
|
||||
<transition-group class="sqadhkmv _list_" name="list" tag="div" :data-direction="direction" :data-reversed="reversed ? 'true' : 'false'">
|
||||
<template v-for="(item, i) in items">
|
||||
<slot :item="item"></slot>
|
||||
<div class="separator" v-if="showDate(i, item)" :key="item.id + '_date'">
|
||||
<p class="date">
|
||||
<span><Fa class="icon" :icon="faAngleUp"/>{{ getDateText(item.createdAt) }}</span>
|
||||
<span>{{ getDateText(items[i + 1].createdAt) }}<Fa class="icon" :icon="faAngleDown"/></span>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
</transition-group>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { defineComponent, h, TransitionGroup } from 'vue';
|
||||
import { faAngleUp, faAngleDown } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@ -34,36 +21,72 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
faAngleUp, faAngleDown
|
||||
};
|
||||
methods: {
|
||||
focus() {
|
||||
this.$slots.default[0].elm.focus();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getDateText(time: string) {
|
||||
render() {
|
||||
const getDateText = (time: string) => {
|
||||
const date = new Date(time).getDate();
|
||||
const month = new Date(time).getMonth() + 1;
|
||||
return this.$t('monthAndDay', {
|
||||
month: month.toString(),
|
||||
day: date.toString()
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
showDate(i, item) {
|
||||
return (
|
||||
return h(this.$store.state.animation ? TransitionGroup : 'div', this.$store.state.animation ? {
|
||||
class: 'sqadhkmv _list_',
|
||||
name: 'list',
|
||||
tag: 'div',
|
||||
'data-direction': this.direction,
|
||||
'data-reversed': this.reversed ? 'true' : 'false',
|
||||
} : {
|
||||
class: 'sqadhkmv _list_',
|
||||
}, this.items.map((item, i) => {
|
||||
const el = this.$slots.default({
|
||||
item: item
|
||||
})[0];
|
||||
el.key = item.id;
|
||||
|
||||
if (
|
||||
i != this.items.length - 1 &&
|
||||
new Date(item.createdAt).getDate() != new Date(this.items[i + 1].createdAt).getDate() &&
|
||||
!item._prId_ &&
|
||||
!this.items[i + 1]._prId_ &&
|
||||
!item._featuredId_ &&
|
||||
!this.items[i + 1]._featuredId_);
|
||||
},
|
||||
!this.items[i + 1]._featuredId_
|
||||
) {
|
||||
const separator = h('div', {
|
||||
class: 'separator',
|
||||
key: item.id + ':separator',
|
||||
}, h('p', {
|
||||
class: 'date'
|
||||
}, [
|
||||
h('span', [
|
||||
h(FontAwesomeIcon, {
|
||||
class: 'icon',
|
||||
icon: faAngleUp,
|
||||
}),
|
||||
getDateText(item.createdAt)
|
||||
]),
|
||||
h('span', [
|
||||
getDateText(this.items[i + 1].createdAt),
|
||||
h(FontAwesomeIcon, {
|
||||
class: 'icon',
|
||||
icon: faAngleDown,
|
||||
})
|
||||
])
|
||||
]));
|
||||
|
||||
focus() {
|
||||
this.$slots.default[0].elm.focus();
|
||||
}
|
||||
}
|
||||
return [el, separator];
|
||||
} else {
|
||||
return el;
|
||||
}
|
||||
}));
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -97,7 +120,7 @@ export default defineComponent({
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style lang="scss">
|
||||
.sqadhkmv {
|
||||
> .separator {
|
||||
text-align: center;
|
||||
|
@ -26,8 +26,8 @@
|
||||
</template>
|
||||
</MkSelect>
|
||||
<div class="buttons" v-if="(showOkButton || showCancelButton) && !actions">
|
||||
<MkButton inline @click="ok" v-if="showOkButton" primary :autofocus="!input && !select">{{ (showCancelButton || input || select) ? $t('ok') : $t('gotIt') }}</MkButton>
|
||||
<MkButton inline @click="cancel" v-if="showCancelButton || input || select">{{ $t('cancel') }}</MkButton>
|
||||
<MkButton inline @click="ok" v-if="showOkButton" primary :autofocus="!input && !select">{{ (showCancelButton || input || select) ? $ts.ok : $ts.gotIt }}</MkButton>
|
||||
<MkButton inline @click="cancel" v-if="showCancelButton || input || select">{{ $ts.cancel }}</MkButton>
|
||||
</div>
|
||||
<div class="buttons" v-if="actions">
|
||||
<MkButton v-for="action in actions" inline @click="() => { action.callback(); close(); }" :primary="action.primary" :key="action.text">{{ action.text }}</MkButton>
|
||||
|
@ -27,6 +27,7 @@ import {
|
||||
faFilm
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import ImgWithBlurhash from './img-with-blurhash.vue';
|
||||
import { ColdDeviceStorage } from '@/store';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
@ -89,12 +90,12 @@ export default defineComponent({
|
||||
},
|
||||
mounted() {
|
||||
const audioTag = this.$refs.volumectrl as HTMLAudioElement;
|
||||
if (audioTag) audioTag.volume = this.$store.state.device.mediaVolume;
|
||||
if (audioTag) audioTag.volume = ColdDeviceStorage.get('mediaVolume');
|
||||
},
|
||||
methods: {
|
||||
volumechange() {
|
||||
const audioTag = this.$refs.volumectrl as HTMLAudioElement;
|
||||
this.$store.commit('device/set', { key: 'mediaVolume', value: audioTag.volume });
|
||||
ColdDeviceStorage.set('mediaVolume', audioTag.volume);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -10,7 +10,7 @@
|
||||
@closed="$emit('closed')"
|
||||
>
|
||||
<template #header>
|
||||
{{ multiple ? ((type === 'file') ? $t('selectFiles') : $t('selectFolders')) : ((type === 'file') ? $t('selectFile') : $t('selectFolder')) }}
|
||||
{{ multiple ? ((type === 'file') ? $ts.selectFiles : $ts.selectFolders) : ((type === 'file') ? $ts.selectFile : $ts.selectFolder) }}
|
||||
<span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ number(selected.length) }})</span>
|
||||
</template>
|
||||
<XDrive :multiple="multiple" @changeSelection="onChangeSelection" @selected="ok()" :select="type"/>
|
||||
|
@ -6,7 +6,7 @@
|
||||
@closed="$emit('closed')"
|
||||
>
|
||||
<template #header>
|
||||
{{ $t('drive') }}
|
||||
{{ $ts.drive }}
|
||||
</template>
|
||||
<XDrive :initial-folder="initialFolder"/>
|
||||
</XWindow>
|
||||
|
@ -8,17 +8,17 @@
|
||||
@dragend="onDragend"
|
||||
:title="title"
|
||||
>
|
||||
<div class="label" v-if="$store.state.i.avatarId == file.id">
|
||||
<div class="label" v-if="$i.avatarId == file.id">
|
||||
<img src="/assets/label.svg"/>
|
||||
<p>{{ $t('avatar') }}</p>
|
||||
<p>{{ $ts.avatar }}</p>
|
||||
</div>
|
||||
<div class="label" v-if="$store.state.i.bannerId == file.id">
|
||||
<div class="label" v-if="$i.bannerId == file.id">
|
||||
<img src="/assets/label.svg"/>
|
||||
<p>{{ $t('banner') }}</p>
|
||||
<p>{{ $ts.banner }}</p>
|
||||
</div>
|
||||
<div class="label red" v-if="file.isSensitive">
|
||||
<img src="/assets/label-red.svg"/>
|
||||
<p>{{ $t('nsfw') }}</p>
|
||||
<p>{{ $ts.nsfw }}</p>
|
||||
</div>
|
||||
|
||||
<MkDriveFileThumbnail class="thumbnail" :file="file" fit="contain"/>
|
||||
@ -82,26 +82,26 @@ export default defineComponent({
|
||||
methods: {
|
||||
getMenu() {
|
||||
return [{
|
||||
text: this.$t('rename'),
|
||||
text: this.$ts.rename,
|
||||
icon: faICursor,
|
||||
action: this.rename
|
||||
}, {
|
||||
text: this.file.isSensitive ? this.$t('unmarkAsSensitive') : this.$t('markAsSensitive'),
|
||||
text: this.file.isSensitive ? this.$ts.unmarkAsSensitive : this.$ts.markAsSensitive,
|
||||
icon: this.file.isSensitive ? faEye : faEyeSlash,
|
||||
action: this.toggleSensitive
|
||||
}, null, {
|
||||
text: this.$t('copyUrl'),
|
||||
text: this.$ts.copyUrl,
|
||||
icon: faLink,
|
||||
action: this.copyUrl
|
||||
}, {
|
||||
type: 'a',
|
||||
href: this.file.url,
|
||||
target: '_blank',
|
||||
text: this.$t('download'),
|
||||
text: this.$ts.download,
|
||||
icon: faDownload,
|
||||
download: this.file.name
|
||||
}, null, {
|
||||
text: this.$t('delete'),
|
||||
text: this.$ts.delete,
|
||||
icon: faTrashAlt,
|
||||
danger: true,
|
||||
action: this.deleteFile
|
||||
@ -137,9 +137,9 @@ export default defineComponent({
|
||||
|
||||
rename() {
|
||||
os.dialog({
|
||||
title: this.$t('renameFile'),
|
||||
title: this.$ts.renameFile,
|
||||
input: {
|
||||
placeholder: this.$t('inputNewFileName'),
|
||||
placeholder: this.$ts.inputNewFileName,
|
||||
default: this.file.name,
|
||||
allowEmpty: false
|
||||
}
|
||||
|
@ -19,8 +19,8 @@
|
||||
<template v-if="!hover"><Fa :icon="faFolder" fixed-width/></template>
|
||||
{{ folder.name }}
|
||||
</p>
|
||||
<p class="upload" v-if="$store.state.settings.uploadFolder == folder.id">
|
||||
{{ $t('uploadFolder') }}
|
||||
<p class="upload" v-if="$store.state.uploadFolder == folder.id">
|
||||
{{ $ts.uploadFolder }}
|
||||
</p>
|
||||
<button v-if="selectMode" class="checkbox _button" :class="{ checked: isSelected }" @click.prevent.stop="checkboxClicked"></button>
|
||||
</div>
|
||||
@ -155,14 +155,14 @@ export default defineComponent({
|
||||
switch (err) {
|
||||
case 'detected-circular-definition':
|
||||
os.dialog({
|
||||
title: this.$t('unableToProcess'),
|
||||
text: this.$t('circularReferenceFolder')
|
||||
title: this.$ts.unableToProcess,
|
||||
text: this.$ts.circularReferenceFolder
|
||||
});
|
||||
break;
|
||||
default:
|
||||
os.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('somethingHappened')
|
||||
text: this.$ts.somethingHappened
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -195,9 +195,9 @@ export default defineComponent({
|
||||
|
||||
rename() {
|
||||
os.dialog({
|
||||
title: this.$t('renameFolder'),
|
||||
title: this.$ts.renameFolder,
|
||||
input: {
|
||||
placeholder: this.$t('inputNewFolderName'),
|
||||
placeholder: this.$ts.inputNewFolderName,
|
||||
default: this.folder.name
|
||||
}
|
||||
}).then(({ canceled, result: name }) => {
|
||||
@ -213,40 +213,34 @@ export default defineComponent({
|
||||
os.api('drive/folders/delete', {
|
||||
folderId: this.folder.id
|
||||
}).then(() => {
|
||||
if (this.$store.state.settings.uploadFolder === this.folder.id) {
|
||||
this.$store.dispatch('settings/set', {
|
||||
key: 'uploadFolder',
|
||||
value: null
|
||||
});
|
||||
if (this.$store.state.uploadFolder === this.folder.id) {
|
||||
this.$store.set('uploadFolder', null);
|
||||
}
|
||||
}).catch(err => {
|
||||
switch(err.id) {
|
||||
case 'b0fc8a17-963c-405d-bfbc-859a487295e1':
|
||||
os.dialog({
|
||||
type: 'error',
|
||||
title: this.$t('unableToDelete'),
|
||||
text: this.$t('hasChildFilesOrFolders')
|
||||
title: this.$ts.unableToDelete,
|
||||
text: this.$ts.hasChildFilesOrFolders
|
||||
});
|
||||
break;
|
||||
default:
|
||||
os.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('unableToDelete')
|
||||
text: this.$ts.unableToDelete
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setAsUploadFolder() {
|
||||
this.$store.dispatch('settings/set', {
|
||||
key: 'uploadFolder',
|
||||
value: this.folder.id
|
||||
});
|
||||
this.$store.set('uploadFolder', this.folder.id);
|
||||
},
|
||||
|
||||
onContextmenu(e) {
|
||||
os.contextMenu([{
|
||||
text: this.$t('openInWindow'),
|
||||
text: this.$ts.openInWindow,
|
||||
icon: faWindowRestore,
|
||||
action: () => {
|
||||
os.popup(import('./drive-window.vue'), {
|
||||
@ -255,11 +249,11 @@ export default defineComponent({
|
||||
}, 'closed');
|
||||
}
|
||||
}, null, {
|
||||
text: this.$t('rename'),
|
||||
text: this.$ts.rename,
|
||||
icon: faICursor,
|
||||
action: this.rename
|
||||
}, null, {
|
||||
text: this.$t('delete'),
|
||||
text: this.$ts.delete,
|
||||
icon: faTrashAlt,
|
||||
danger: true,
|
||||
action: this.deleteFolder
|
||||
|
@ -8,7 +8,7 @@
|
||||
@drop.stop="onDrop"
|
||||
>
|
||||
<i v-if="folder == null"><Fa :icon="faCloud"/></i>
|
||||
<span>{{ folder == null ? $t('drive') : folder.name }}</span>
|
||||
<span>{{ folder == null ? $ts.drive : folder.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -24,18 +24,18 @@
|
||||
<XFolder v-for="f in folders" :key="f.id" class="folder" :folder="f" :select-mode="select === 'folder'" :is-selected="selectedFolders.some(x => x.id === f.id)" @chosen="chooseFolder"/>
|
||||
<!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
|
||||
<div class="padding" v-for="(n, i) in 16" :key="i"></div>
|
||||
<MkButton ref="moreFolders" v-if="moreFolders">{{ $t('loadMore') }}</MkButton>
|
||||
<MkButton ref="moreFolders" v-if="moreFolders">{{ $ts.loadMore }}</MkButton>
|
||||
</div>
|
||||
<div class="files" ref="filesContainer" v-show="files.length > 0">
|
||||
<XFile v-for="file in files" :key="file.id" class="file" :file="file" :select-mode="select === 'file'" :is-selected="selectedFiles.some(x => x.id === file.id)" @chosen="chooseFile"/>
|
||||
<!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
|
||||
<div class="padding" v-for="(n, i) in 16" :key="i"></div>
|
||||
<MkButton ref="loadMoreFiles" @click="fetchMoreFiles" v-show="moreFiles">{{ $t('loadMore') }}</MkButton>
|
||||
<MkButton ref="loadMoreFiles" @click="fetchMoreFiles" v-show="moreFiles">{{ $ts.loadMore }}</MkButton>
|
||||
</div>
|
||||
<div class="empty" v-if="files.length == 0 && folders.length == 0 && !fetching">
|
||||
<p v-if="draghover">{{ $t('empty-draghover') }}</p>
|
||||
<p v-if="!draghover && folder == null"><strong>{{ $t('emptyDrive') }}</strong><br/>{{ $t('empty-drive-description') }}</p>
|
||||
<p v-if="!draghover && folder != null">{{ $t('emptyFolder') }}</p>
|
||||
<p v-if="!draghover && folder == null"><strong>{{ $ts.emptyDrive }}</strong><br/>{{ $t('empty-drive-description') }}</p>
|
||||
<p v-if="!draghover && folder != null">{{ $ts.emptyFolder }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<MkLoading v-if="fetching"/>
|
||||
@ -136,7 +136,7 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.$store.state.device.enableInfiniteScroll && this.$refs.loadMoreFiles) {
|
||||
if (this.$store.state.enableInfiniteScroll && this.$refs.loadMoreFiles) {
|
||||
this.$nextTick(() => {
|
||||
this.ilFilesObserver.observe((this.$refs.loadMoreFiles as Vue).$el)
|
||||
});
|
||||
@ -159,7 +159,7 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
activated() {
|
||||
if (this.$store.state.device.enableInfiniteScroll) {
|
||||
if (this.$store.state.enableInfiniteScroll) {
|
||||
this.$nextTick(() => {
|
||||
this.ilFilesObserver.observe((this.$refs.loadMoreFiles as Vue).$el)
|
||||
});
|
||||
@ -277,14 +277,14 @@ export default defineComponent({
|
||||
switch (err) {
|
||||
case 'detected-circular-definition':
|
||||
os.dialog({
|
||||
title: this.$t('unableToProcess'),
|
||||
text: this.$t('circularReferenceFolder')
|
||||
title: this.$ts.unableToProcess,
|
||||
text: this.$ts.circularReferenceFolder
|
||||
});
|
||||
break;
|
||||
default:
|
||||
os.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('somethingHappened')
|
||||
text: this.$ts.somethingHappened
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -298,9 +298,9 @@ export default defineComponent({
|
||||
|
||||
urlUpload() {
|
||||
os.dialog({
|
||||
title: this.$t('uploadFromUrl'),
|
||||
title: this.$ts.uploadFromUrl,
|
||||
input: {
|
||||
placeholder: this.$t('uploadFromUrlDescription')
|
||||
placeholder: this.$ts.uploadFromUrlDescription
|
||||
}
|
||||
}).then(({ canceled, result: url }) => {
|
||||
if (canceled) return;
|
||||
@ -310,17 +310,17 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
os.dialog({
|
||||
title: this.$t('uploadFromUrlRequested'),
|
||||
text: this.$t('uploadFromUrlMayTakeTime')
|
||||
title: this.$ts.uploadFromUrlRequested,
|
||||
text: this.$ts.uploadFromUrlMayTakeTime
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
createFolder() {
|
||||
os.dialog({
|
||||
title: this.$t('createFolder'),
|
||||
title: this.$ts.createFolder,
|
||||
input: {
|
||||
placeholder: this.$t('folderName')
|
||||
placeholder: this.$ts.folderName
|
||||
}
|
||||
}).then(({ canceled, result: name }) => {
|
||||
if (canceled) return;
|
||||
@ -335,9 +335,9 @@ export default defineComponent({
|
||||
|
||||
renameFolder(folder) {
|
||||
os.dialog({
|
||||
title: this.$t('renameFolder'),
|
||||
title: this.$ts.renameFolder,
|
||||
input: {
|
||||
placeholder: this.$t('inputNewFolderName'),
|
||||
placeholder: this.$ts.inputNewFolderName,
|
||||
default: folder.name
|
||||
}
|
||||
}).then(({ canceled, result: name }) => {
|
||||
@ -363,14 +363,14 @@ export default defineComponent({
|
||||
case 'b0fc8a17-963c-405d-bfbc-859a487295e1':
|
||||
os.dialog({
|
||||
type: 'error',
|
||||
title: this.$t('unableToDelete'),
|
||||
text: this.$t('hasChildFilesOrFolders')
|
||||
title: this.$ts.unableToDelete,
|
||||
text: this.$ts.hasChildFilesOrFolders
|
||||
});
|
||||
break;
|
||||
default:
|
||||
os.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('unableToDelete')
|
||||
text: this.$ts.unableToDelete
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -602,29 +602,29 @@ export default defineComponent({
|
||||
|
||||
getMenu() {
|
||||
return [{
|
||||
text: this.$t('addFile'),
|
||||
text: this.$ts.addFile,
|
||||
type: 'label'
|
||||
}, {
|
||||
text: this.$t('upload'),
|
||||
text: this.$ts.upload,
|
||||
icon: faUpload,
|
||||
action: () => { this.selectLocalFile(); }
|
||||
}, {
|
||||
text: this.$t('fromUrl'),
|
||||
text: this.$ts.fromUrl,
|
||||
icon: faLink,
|
||||
action: () => { this.urlUpload(); }
|
||||
}, null, {
|
||||
text: this.folder ? this.folder.name : this.$t('drive'),
|
||||
text: this.folder ? this.folder.name : this.$ts.drive,
|
||||
type: 'label'
|
||||
}, this.folder ? {
|
||||
text: this.$t('renameFolder'),
|
||||
text: this.$ts.renameFolder,
|
||||
icon: faICursor,
|
||||
action: () => { this.renameFolder(this.folder); }
|
||||
} : undefined, this.folder ? {
|
||||
text: this.$t('deleteFolder'),
|
||||
text: this.$ts.deleteFolder,
|
||||
icon: faTrashAlt,
|
||||
action: () => { this.deleteFolder(this.folder); }
|
||||
} : undefined, {
|
||||
text: this.$t('createFolder'),
|
||||
text: this.$ts.createFolder,
|
||||
icon: faFolderPlus,
|
||||
action: () => { this.createFolder(); }
|
||||
}];
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<MkModal ref="modal" :src="src" @click="$refs.modal.close()" @closed="$emit('closed')">
|
||||
<div class="omfetrab _popup" :class="['w' + width, 'h' + height, { big }]">
|
||||
<input ref="search" class="search" :class="{ filled: q != null && q != '' }" v-model.trim="q" :placeholder="$t('search')" @paste.stop="paste" @keyup.enter="done()">
|
||||
<input ref="search" class="search" :class="{ filled: q != null && q != '' }" v-model.trim="q" :placeholder="$ts.search" @paste.stop="paste" @keyup.enter="done()">
|
||||
<div class="emojis">
|
||||
<section class="result">
|
||||
<div v-if="searchResultCustom.length > 0">
|
||||
@ -13,7 +13,7 @@
|
||||
tabindex="0"
|
||||
>
|
||||
<MkEmoji v-if="emoji.char != null" :emoji="emoji.char"/>
|
||||
<img v-else :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
|
||||
<img v-else :src="$store.state.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="searchResultUnicode.length > 0">
|
||||
@ -43,9 +43,9 @@
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<header class="_acrylic"><Fa :icon="faClock" fixed-width/> {{ $t('recentUsed') }}</header>
|
||||
<header class="_acrylic"><Fa :icon="faClock" fixed-width/> {{ $ts.recentUsed }}</header>
|
||||
<div>
|
||||
<button v-for="emoji in $store.state.device.recentlyUsedEmojis"
|
||||
<button v-for="emoji in $store.state.recentlyUsedEmojis"
|
||||
class="_button"
|
||||
@click="chosen(emoji, $event)"
|
||||
:key="emoji"
|
||||
@ -59,7 +59,7 @@
|
||||
</div>
|
||||
|
||||
<section v-for="category in customEmojiCategories" :key="'custom:' + category" class="custom">
|
||||
<header class="_acrylic" v-appear="() => visibleCategories[category] = true">{{ category || $t('other') }}</header>
|
||||
<header class="_acrylic" v-appear="() => visibleCategories[category] = true">{{ category || $ts.other }}</header>
|
||||
<div v-if="visibleCategories[category]">
|
||||
<button v-for="emoji in customEmojis.filter(e => e.category === category)"
|
||||
class="_button"
|
||||
@ -67,7 +67,7 @@
|
||||
@click="chosen(emoji, $event)"
|
||||
:key="emoji.name"
|
||||
>
|
||||
<img :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
|
||||
<img :src="$store.state.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
@ -100,6 +100,7 @@ import MkModal from '@/components/ui/modal.vue';
|
||||
import Particle from '@/components/particle.vue';
|
||||
import * as os from '@/os';
|
||||
import { isDeviceTouch } from '../scripts/is-device-touch';
|
||||
import { emojiCategories } from '@/instance';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
@ -125,12 +126,12 @@ export default defineComponent({
|
||||
return {
|
||||
emojilist: markRaw(emojilist),
|
||||
getStaticImageUrl,
|
||||
pinned: this.$store.state.settings.reactions,
|
||||
width: this.asReactionPicker ? this.$store.state.device.reactionPickerWidth : 3,
|
||||
height: this.asReactionPicker ? this.$store.state.device.reactionPickerHeight : 2,
|
||||
pinned: this.$store.state.reactions,
|
||||
width: this.asReactionPicker ? this.$store.state.reactionPickerWidth : 3,
|
||||
height: this.asReactionPicker ? this.$store.state.reactionPickerHeight : 2,
|
||||
big: this.asReactionPicker ? isDeviceTouch : false,
|
||||
customEmojiCategories: this.$store.getters['instance/emojiCategories'],
|
||||
customEmojis: this.$store.state.instance.meta.emojis,
|
||||
customEmojiCategories: emojiCategories,
|
||||
customEmojis: this.$instance.emojis,
|
||||
visibleCategories: {},
|
||||
q: null,
|
||||
searchResultCustom: [],
|
||||
@ -346,10 +347,10 @@ export default defineComponent({
|
||||
|
||||
// 最近使った絵文字更新
|
||||
if (!this.pinned.includes(key)) {
|
||||
let recents = this.$store.state.device.recentlyUsedEmojis;
|
||||
let recents = this.$store.state.recentlyUsedEmojis;
|
||||
recents = recents.filter((e: any) => e !== key);
|
||||
recents.unshift(key);
|
||||
this.$store.commit('device/set', { key: 'recentlyUsedEmojis', value: recents.splice(0, 16) });
|
||||
this.$store.set('recentlyUsedEmojis', recents.splice(0, 16));
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -6,23 +6,23 @@
|
||||
>
|
||||
<template v-if="!wait">
|
||||
<template v-if="hasPendingFollowRequestFromYou && user.isLocked">
|
||||
<span v-if="full">{{ $t('followRequestPending') }}</span><Fa :icon="faHourglassHalf"/>
|
||||
<span v-if="full">{{ $ts.followRequestPending }}</span><Fa :icon="faHourglassHalf"/>
|
||||
</template>
|
||||
<template v-else-if="hasPendingFollowRequestFromYou && !user.isLocked"> <!-- つまりリモートフォローの場合。 -->
|
||||
<span v-if="full">{{ $t('processing') }}</span><Fa :icon="faSpinner" pulse/>
|
||||
<span v-if="full">{{ $ts.processing }}</span><Fa :icon="faSpinner" pulse/>
|
||||
</template>
|
||||
<template v-else-if="isFollowing">
|
||||
<span v-if="full">{{ $t('unfollow') }}</span><Fa :icon="faMinus"/>
|
||||
<span v-if="full">{{ $ts.unfollow }}</span><Fa :icon="faMinus"/>
|
||||
</template>
|
||||
<template v-else-if="!isFollowing && user.isLocked">
|
||||
<span v-if="full">{{ $t('followRequest') }}</span><Fa :icon="faPlus"/>
|
||||
<span v-if="full">{{ $ts.followRequest }}</span><Fa :icon="faPlus"/>
|
||||
</template>
|
||||
<template v-else-if="!isFollowing && !user.isLocked">
|
||||
<span v-if="full">{{ $t('follow') }}</span><Fa :icon="faPlus"/>
|
||||
<span v-if="full">{{ $ts.follow }}</span><Fa :icon="faPlus"/>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span v-if="full">{{ $t('processing') }}</span><Fa :icon="faSpinner" pulse fixed-width/>
|
||||
<span v-if="full">{{ $ts.processing }}</span><Fa :icon="faSpinner" pulse fixed-width/>
|
||||
</template>
|
||||
</button>
|
||||
</template>
|
||||
|
@ -15,15 +15,15 @@
|
||||
<FormBase class="xkpnjxcv">
|
||||
<template v-for="item in Object.keys(form).filter(item => !form[item].hidden)">
|
||||
<FormInput v-if="form[item].type === 'number'" v-model:value="values[item]" type="number" :step="form[item].step || 1">
|
||||
<span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $t('optional') }})</span>
|
||||
<span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span>
|
||||
<template v-if="form[item].description" #desc>{{ form[item].description }}</template>
|
||||
</FormInput>
|
||||
<FormInput v-else-if="form[item].type === 'string' && !form[item].multiline" v-model:value="values[item]" type="text">
|
||||
<span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $t('optional') }})</span>
|
||||
<span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span>
|
||||
<template v-if="form[item].description" #desc>{{ form[item].description }}</template>
|
||||
</FormInput>
|
||||
<FormTextarea v-else-if="form[item].type === 'string' && form[item].multiline" v-model:value="values[item]">
|
||||
<span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $t('optional') }})</span>
|
||||
<span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span>
|
||||
<template v-if="form[item].description" #desc>{{ form[item].description }}</template>
|
||||
</FormTextarea>
|
||||
<FormSwitch v-else-if="form[item].type === 'boolean'" v-model:value="values[item]">
|
||||
@ -31,11 +31,11 @@
|
||||
<template v-if="form[item].description" #desc>{{ form[item].description }}</template>
|
||||
</FormSwitch>
|
||||
<FormSelect v-else-if="form[item].type === 'enum'" v-model:value="values[item]">
|
||||
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $t('optional') }})</span></template>
|
||||
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
||||
<option v-for="item in form[item].enum" :value="item.value" :key="item.value">{{ item.label }}</option>
|
||||
</FormSelect>
|
||||
<FormRange v-else-if="form[item].type === 'range'" v-model:value="values[item]" :min="form[item].mim" :max="form[item].max" :step="form[item].step">
|
||||
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $t('optional') }})</span></template>
|
||||
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
||||
<template v-if="form[item].description" #desc>{{ form[item].description }}</template>
|
||||
</FormRange>
|
||||
<FormButton v-else-if="form[item].type === 'button'" @click="form[item].action($event, values)">
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
&._formClickable {
|
||||
&:hover {
|
||||
background: var(--panelHighlight);
|
||||
//background: var(--panelHighlight);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,6 +12,7 @@
|
||||
._formLabel {
|
||||
font-size: 80%;
|
||||
padding: 0 16px 8px 16px;
|
||||
opacity: 0.8;
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
@ -21,6 +22,7 @@
|
||||
._formCaption {
|
||||
font-size: 80%;
|
||||
padding: 8px 16px 0 16px;
|
||||
opacity: 0.8;
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
|
@ -44,7 +44,7 @@
|
||||
</datalist>
|
||||
<div class="suffix" ref="suffixEl"><slot name="suffix"></slot></div>
|
||||
</div>
|
||||
<button class="save _textButton" v-if="save && changed" @click="() => { changed = false; save(); }">{{ $t('save') }}</button>
|
||||
<button class="save _textButton" v-if="save && changed" @click="() => { changed = false; save(); }">{{ $ts.save }}</button>
|
||||
<div class="_formCaption"><slot name="desc"></slot></div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<slot name="empty"></slot>
|
||||
</div>
|
||||
<FormButton v-show="more" class="button" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary>
|
||||
<template v-if="!moreFetching">{{ $t('loadMore') }}</template>
|
||||
<template v-if="!moreFetching">{{ $ts.loadMore }}</template>
|
||||
<template v-if="moreFetching"><MkLoading inline/></template>
|
||||
</FormButton>
|
||||
</FormGroup>
|
||||
|
@ -14,7 +14,7 @@
|
||||
@blur="focused = false"
|
||||
></textarea>
|
||||
</div>
|
||||
<button class="save _textButton" v-if="save && changed" @click="() => { changed = false; save(); }">{{ $t('save') }}</button>
|
||||
<button class="save _textButton" v-if="save && changed" @click="() => { changed = false; save(); }">{{ $ts.save }}</button>
|
||||
<div class="_formCaption"><slot name="desc"></slot></div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -10,8 +10,9 @@ import { faExpandAlt, faColumns, faExternalLinkAlt, faLink, faWindowMaximize } f
|
||||
import * as os from '@/os';
|
||||
import copyToClipboard from '@/scripts/copy-to-clipboard';
|
||||
import { router } from '@/router';
|
||||
import { ui, url } from '@/config';
|
||||
import { url } from '@/config';
|
||||
import { popout } from '@/scripts/popout';
|
||||
import { ColdDeviceStorage } from '@/store';
|
||||
|
||||
export default defineComponent({
|
||||
inject: {
|
||||
@ -57,31 +58,31 @@ export default defineComponent({
|
||||
text: this.to,
|
||||
}, {
|
||||
icon: faWindowMaximize,
|
||||
text: this.$t('openInWindow'),
|
||||
text: this.$ts.openInWindow,
|
||||
action: () => {
|
||||
os.pageWindow(this.to);
|
||||
}
|
||||
}, this.sideViewHook ? {
|
||||
icon: faColumns,
|
||||
text: this.$t('openInSideView'),
|
||||
text: this.$ts.openInSideView,
|
||||
action: () => {
|
||||
this.sideViewHook(this.to);
|
||||
}
|
||||
} : undefined, {
|
||||
icon: faExpandAlt,
|
||||
text: this.$t('showInPage'),
|
||||
text: this.$ts.showInPage,
|
||||
action: () => {
|
||||
this.$router.push(this.to);
|
||||
}
|
||||
}, null, {
|
||||
icon: faExternalLinkAlt,
|
||||
text: this.$t('openInNewTab'),
|
||||
text: this.$ts.openInNewTab,
|
||||
action: () => {
|
||||
window.open(this.to, '_blank');
|
||||
}
|
||||
}, {
|
||||
icon: faLink,
|
||||
text: this.$t('copyLink'),
|
||||
text: this.$ts.copyLink,
|
||||
action: () => {
|
||||
copyToClipboard(`${url}${this.to}`);
|
||||
}
|
||||
@ -98,8 +99,8 @@ export default defineComponent({
|
||||
|
||||
nav() {
|
||||
if (this.to.startsWith('/my/messaging')) {
|
||||
if (this.$store.state.device.chatOpenBehavior === 'window') return this.window();
|
||||
if (this.$store.state.device.chatOpenBehavior === 'popout') return this.popout();
|
||||
if (ColdDeviceStorage.get('chatOpenBehavior') === 'window') return this.window();
|
||||
if (ColdDeviceStorage.get('chatOpenBehavior') === 'popout') return this.popout();
|
||||
}
|
||||
|
||||
if (this.behavior) {
|
||||
@ -111,15 +112,9 @@ export default defineComponent({
|
||||
if (this.navHook) {
|
||||
this.navHook(this.to);
|
||||
} else {
|
||||
if (this.$store.state.device.defaultSideView && this.sideViewHook && this.to !== '/') {
|
||||
if (this.$store.state.defaultSideView && this.sideViewHook && this.to !== '/') {
|
||||
return this.sideViewHook(this.to);
|
||||
}
|
||||
if (this.$store.state.device.deckNavWindow && (ui === 'deck') && this.to !== '/') {
|
||||
return this.window();
|
||||
}
|
||||
if (ui === 'desktop') {
|
||||
return this.window();
|
||||
}
|
||||
|
||||
if (this.$router.currentRoute.value.path === this.to) {
|
||||
window.scroll({ top: 0, behavior: 'smooth' });
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<span class="mk-acct" v-once>
|
||||
<span class="name">@{{ user.username }}</span>
|
||||
<span class="host" v-if="user.host || detail || $store.state.settings.showFullAcct">@{{ user.host || host }}</span>
|
||||
<span class="host" v-if="user.host || detail || $store.state.showFullAcct">@{{ user.host || host }}</span>
|
||||
</span>
|
||||
</template>
|
||||
|
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<span class="eiwwqkts" :class="{ cat }" :title="acct(user)" v-if="disableLink" v-user-preview="disablePreview ? undefined : user.id" @click="onClick">
|
||||
<img class="inner" :src="url"/>
|
||||
<img class="inner" :src="url" decoding="async"/>
|
||||
</span>
|
||||
<MkA class="eiwwqkts" :class="{ cat }" :to="userPage(user)" :title="acct(user)" :target="target" v-else v-user-preview="disablePreview ? undefined : user.id">
|
||||
<img class="inner" :src="url"/>
|
||||
<img class="inner" :src="url" decoding="async"/>
|
||||
</MkA>
|
||||
</template>
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
|
||||
import { extractAvgColorFromBlurhash } from '@/scripts/extract-avg-color-from-blurhash';
|
||||
import { acct, userPage } from '../filters/user';
|
||||
import { acct, userPage } from '@/filters/user';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@ -38,7 +38,7 @@ export default defineComponent({
|
||||
return this.user.isCat;
|
||||
},
|
||||
url(): string {
|
||||
return this.$store.state.device.disableShowingAnimatedImages
|
||||
return this.$store.state.disableShowingAnimatedImages
|
||||
? getStaticImageUrl(this.user.avatarUrl)
|
||||
: this.user.avatarUrl;
|
||||
},
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<img v-if="customEmoji" class="mk-emoji custom" :class="{ normal, noStyle }" :src="url" :alt="alt" :title="alt"/>
|
||||
<img v-else-if="char && !useOsNativeEmojis" class="mk-emoji" :src="url" :alt="alt" :title="alt"/>
|
||||
<img v-if="customEmoji" class="mk-emoji custom" :class="{ normal, noStyle }" :src="url" :alt="alt" :title="alt" decoding="async"/>
|
||||
<img v-else-if="char && !useOsNativeEmojis" class="mk-emoji" :src="url" :alt="alt" :title="alt" decoding="async"/>
|
||||
<span v-else-if="char && useOsNativeEmojis">{{ char }}</span>
|
||||
<span v-else>{{ emoji }}</span>
|
||||
</template>
|
||||
@ -8,7 +8,7 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
|
||||
import { twemojiSvgBase } from '../../misc/twemoji-base';
|
||||
import { twemojiSvgBase } from '@/../misc/twemoji-base';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@ -54,13 +54,13 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
useOsNativeEmojis(): boolean {
|
||||
return this.$store.state.device.useOsNativeEmojis && !this.isReaction;
|
||||
return this.$store.state.useOsNativeEmojis && !this.isReaction;
|
||||
},
|
||||
|
||||
ce() {
|
||||
let ce = [];
|
||||
if (this.customEmojis) ce = ce.concat(this.customEmojis);
|
||||
if (this.$store.state.instance.meta && this.$store.state.instance.meta.emojis) ce = ce.concat(this.$store.state.instance.meta.emojis);
|
||||
if (this.$instance && this.$instance.emojis) ce = ce.concat(this.$instance.emojis);
|
||||
return ce;
|
||||
}
|
||||
},
|
||||
@ -72,7 +72,7 @@ export default defineComponent({
|
||||
const customEmoji = this.ce.find(x => x.name === this.emoji.substr(1, this.emoji.length - 2));
|
||||
if (customEmoji) {
|
||||
this.customEmoji = customEmoji;
|
||||
this.url = this.$store.state.device.disableShowingAnimatedImages
|
||||
this.url = this.$store.state.disableShowingAnimatedImages
|
||||
? getStaticImageUrl(customEmoji.url)
|
||||
: customEmoji.url;
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<transition :name="$store.state.device.animation ? 'zoom' : ''" appear>
|
||||
<transition :name="$store.state.animation ? 'zoom' : ''" appear>
|
||||
<div class="mjndxjcg">
|
||||
<img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>
|
||||
<p><Fa :icon="faExclamationTriangle"/> {{ $t('somethingHappened') }}</p>
|
||||
<MkButton @click="() => $emit('retry')" class="button">{{ $t('retry') }}</MkButton>
|
||||
<p><Fa :icon="faExclamationTriangle"/> {{ $ts.somethingHappened }}</p>
|
||||
<MkButton @click="() => $emit('retry')" class="button">{{ $ts.retry }}</MkButton>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
@ -11,7 +11,7 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
|
||||
import MkButton from './ui/button.vue';
|
||||
import MkButton from '@/components/ui/button.vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
37
src/client/components/global/i18n.ts
Normal file
37
src/client/components/global/i18n.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { h, defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
src: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
tag: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'span',
|
||||
},
|
||||
},
|
||||
render() {
|
||||
let str = this.src;
|
||||
const parsed = [] as (string | { arg: string; })[];
|
||||
while (true) {
|
||||
const nextBracketOpen = str.indexOf('{');
|
||||
const nextBracketClose = str.indexOf('}');
|
||||
|
||||
if (nextBracketOpen === -1) {
|
||||
parsed.push(str);
|
||||
break;
|
||||
} else {
|
||||
if (nextBracketOpen > 0) parsed.push(str.substr(0, nextBracketOpen));
|
||||
parsed.push({
|
||||
arg: str.substring(nextBracketOpen + 1, nextBracketClose)
|
||||
});
|
||||
}
|
||||
|
||||
str = str.substr(nextBracketClose + 1);
|
||||
}
|
||||
|
||||
return h(this.tag, parsed.map(x => typeof x === 'string' ? x : this.$slots[x.arg]()));
|
||||
}
|
||||
});
|
@ -4,7 +4,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import MfmCore from './mfm';
|
||||
import MfmCore from '@/components/mfm';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
@ -44,9 +44,9 @@ export default defineComponent({
|
||||
ago >= 3600 ? this.$t('_ago.hoursAgo', { n: (~~(ago / 3600)).toString() }) :
|
||||
ago >= 60 ? this.$t('_ago.minutesAgo', { n: (~~(ago / 60)).toString() }) :
|
||||
ago >= 10 ? this.$t('_ago.secondsAgo', { n: (~~(ago % 60)).toString() }) :
|
||||
ago >= -1 ? this.$t('_ago.justNow') :
|
||||
ago < -1 ? this.$t('_ago.future') :
|
||||
this.$t('_ago.unknown'));
|
||||
ago >= -1 ? this.$ts._ago.justNow :
|
||||
ago < -1 ? this.$ts._ago.future :
|
||||
this.$ts._ago.unknown);
|
||||
}
|
||||
},
|
||||
created() {
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="mk-google">
|
||||
<input type="search" v-model="query" :placeholder="q">
|
||||
<button @click="search"><Fa :icon="faSearch"/> {{ $t('search') }}</button>
|
||||
<button @click="search"><Fa :icon="faSearch"/> {{ $ts.search }}</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -23,7 +23,7 @@ export default defineComponent({
|
||||
},
|
||||
methods: {
|
||||
search() {
|
||||
const engine = this.$store.state.settings.webSearchEngine ||
|
||||
const engine = this.$store.state.webSearchEngine ||
|
||||
'https://www.google.com/search?q={{query}}';
|
||||
const url = engine.replace('{{query}}', this.query)
|
||||
window.open(url, '_blank');
|
||||
|
@ -1,16 +1,17 @@
|
||||
import { App } from 'vue';
|
||||
|
||||
import mfm from './misskey-flavored-markdown.vue';
|
||||
import a from './ui/a.vue';
|
||||
import acct from './acct.vue';
|
||||
import avatar from './avatar.vue';
|
||||
import emoji from './emoji.vue';
|
||||
import userName from './user-name.vue';
|
||||
import ellipsis from './ellipsis.vue';
|
||||
import time from './time.vue';
|
||||
import url from './url.vue';
|
||||
import loading from './loading.vue';
|
||||
import error from './error.vue';
|
||||
import mfm from './global/misskey-flavored-markdown.vue';
|
||||
import a from './global/a.vue';
|
||||
import acct from './global/acct.vue';
|
||||
import avatar from './global/avatar.vue';
|
||||
import emoji from './global/emoji.vue';
|
||||
import userName from './global/user-name.vue';
|
||||
import ellipsis from './global/ellipsis.vue';
|
||||
import time from './global/time.vue';
|
||||
import url from './global/url.vue';
|
||||
import i18n from './global/i18n';
|
||||
import loading from './global/loading.vue';
|
||||
import error from './global/error.vue';
|
||||
|
||||
export default function(app: App) {
|
||||
app.component('Mfm', mfm);
|
||||
@ -24,4 +25,5 @@ export default function(app: App) {
|
||||
app.component('MkUrl', url);
|
||||
app.component('MkLoading', loading);
|
||||
app.component('MkError', error);
|
||||
app.component('I18n', i18n);
|
||||
}
|
||||
|
@ -3,80 +3,80 @@
|
||||
<div class="stats" v-if="info">
|
||||
<div class="_panel">
|
||||
<div>
|
||||
<b><Fa :icon="faUser"/>{{ $t('users') }}</b>
|
||||
<small>{{ $t('local') }}</small>
|
||||
<b><Fa :icon="faUser"/>{{ $ts.users }}</b>
|
||||
<small>{{ $ts.local }}</small>
|
||||
</div>
|
||||
<div>
|
||||
<dl class="total">
|
||||
<dt>{{ $t('total') }}</dt>
|
||||
<dt>{{ $ts.total }}</dt>
|
||||
<dd>{{ number(info.originalUsersCount) }}</dd>
|
||||
</dl>
|
||||
<dl class="diff" :class="{ inc: usersLocalDoD > 0 }">
|
||||
<dt>{{ $t('dayOverDayChanges') }}</dt>
|
||||
<dt>{{ $ts.dayOverDayChanges }}</dt>
|
||||
<dd>{{ number(usersLocalDoD) }}</dd>
|
||||
</dl>
|
||||
<dl class="diff" :class="{ inc: usersLocalWoW > 0 }">
|
||||
<dt>{{ $t('weekOverWeekChanges') }}</dt>
|
||||
<dt>{{ $ts.weekOverWeekChanges }}</dt>
|
||||
<dd>{{ number(usersLocalWoW) }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<div class="_panel">
|
||||
<div>
|
||||
<b><Fa :icon="faUser"/>{{ $t('users') }}</b>
|
||||
<small>{{ $t('remote') }}</small>
|
||||
<b><Fa :icon="faUser"/>{{ $ts.users }}</b>
|
||||
<small>{{ $ts.remote }}</small>
|
||||
</div>
|
||||
<div>
|
||||
<dl class="total">
|
||||
<dt>{{ $t('total') }}</dt>
|
||||
<dt>{{ $ts.total }}</dt>
|
||||
<dd>{{ number((info.usersCount - info.originalUsersCount)) }}</dd>
|
||||
</dl>
|
||||
<dl class="diff" :class="{ inc: usersRemoteDoD > 0 }">
|
||||
<dt>{{ $t('dayOverDayChanges') }}</dt>
|
||||
<dt>{{ $ts.dayOverDayChanges }}</dt>
|
||||
<dd>{{ number(usersRemoteDoD) }}</dd>
|
||||
</dl>
|
||||
<dl class="diff" :class="{ inc: usersRemoteWoW > 0 }">
|
||||
<dt>{{ $t('weekOverWeekChanges') }}</dt>
|
||||
<dt>{{ $ts.weekOverWeekChanges }}</dt>
|
||||
<dd>{{ number(usersRemoteWoW) }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<div class="_panel">
|
||||
<div>
|
||||
<b><Fa :icon="faPencilAlt"/>{{ $t('notes') }}</b>
|
||||
<small>{{ $t('local') }}</small>
|
||||
<b><Fa :icon="faPencilAlt"/>{{ $ts.notes }}</b>
|
||||
<small>{{ $ts.local }}</small>
|
||||
</div>
|
||||
<div>
|
||||
<dl class="total">
|
||||
<dt>{{ $t('total') }}</dt>
|
||||
<dt>{{ $ts.total }}</dt>
|
||||
<dd>{{ number(info.originalNotesCount) }}</dd>
|
||||
</dl>
|
||||
<dl class="diff" :class="{ inc: notesLocalDoD > 0 }">
|
||||
<dt>{{ $t('dayOverDayChanges') }}</dt>
|
||||
<dt>{{ $ts.dayOverDayChanges }}</dt>
|
||||
<dd>{{ number(notesLocalDoD) }}</dd>
|
||||
</dl>
|
||||
<dl class="diff" :class="{ inc: notesLocalWoW > 0 }">
|
||||
<dt>{{ $t('weekOverWeekChanges') }}</dt>
|
||||
<dt>{{ $ts.weekOverWeekChanges }}</dt>
|
||||
<dd>{{ number(notesLocalWoW) }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<div class="_panel">
|
||||
<div>
|
||||
<b><Fa :icon="faPencilAlt"/>{{ $t('notes') }}</b>
|
||||
<small>{{ $t('remote') }}</small>
|
||||
<b><Fa :icon="faPencilAlt"/>{{ $ts.notes }}</b>
|
||||
<small>{{ $ts.remote }}</small>
|
||||
</div>
|
||||
<div>
|
||||
<dl class="total">
|
||||
<dt>{{ $t('total') }}</dt>
|
||||
<dt>{{ $ts.total }}</dt>
|
||||
<dd>{{ number((info.notesCount - info.originalNotesCount)) }}</dd>
|
||||
</dl>
|
||||
<dl class="diff" :class="{ inc: notesRemoteDoD > 0 }">
|
||||
<dt>{{ $t('dayOverDayChanges') }}</dt>
|
||||
<dt>{{ $ts.dayOverDayChanges }}</dt>
|
||||
<dd>{{ number(notesRemoteDoD) }}</dd>
|
||||
</dl>
|
||||
<dl class="diff" :class="{ inc: notesRemoteWoW > 0 }">
|
||||
<dt>{{ $t('weekOverWeekChanges') }}</dt>
|
||||
<dt>{{ $ts.weekOverWeekChanges }}</dt>
|
||||
<dd>{{ number(notesRemoteWoW) }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
@ -84,35 +84,35 @@
|
||||
</div>
|
||||
|
||||
<section class="_card">
|
||||
<div class="_title" style="position: relative;"><Fa :icon="faChartBar"/> {{ $t('statistics') }}<button @click="fetchChart" class="_button" style="position: absolute; right: 0; bottom: 0; top: 0; padding: inherit;"><Fa :icon="faSync"/></button></div>
|
||||
<div class="_title" style="position: relative;"><Fa :icon="faChartBar"/> {{ $ts.statistics }}<button @click="fetchChart" class="_button" style="position: absolute; right: 0; bottom: 0; top: 0; padding: inherit;"><Fa :icon="faSync"/></button></div>
|
||||
<div class="_content" style="margin-top: -8px;">
|
||||
<div class="selects" style="display: flex;">
|
||||
<MkSelect v-model:value="chartSrc" style="margin: 0; flex: 1;">
|
||||
<optgroup :label="$t('federation')">
|
||||
<option value="federation-instances">{{ $t('_charts.federationInstancesIncDec') }}</option>
|
||||
<option value="federation-instances-total">{{ $t('_charts.federationInstancesTotal') }}</option>
|
||||
<optgroup :label="$ts.federation">
|
||||
<option value="federation-instances">{{ $ts._charts.federationInstancesIncDec }}</option>
|
||||
<option value="federation-instances-total">{{ $ts._charts.federationInstancesTotal }}</option>
|
||||
</optgroup>
|
||||
<optgroup :label="$t('users')">
|
||||
<option value="users">{{ $t('_charts.usersIncDec') }}</option>
|
||||
<option value="users-total">{{ $t('_charts.usersTotal') }}</option>
|
||||
<option value="active-users">{{ $t('_charts.activeUsers') }}</option>
|
||||
<optgroup :label="$ts.users">
|
||||
<option value="users">{{ $ts._charts.usersIncDec }}</option>
|
||||
<option value="users-total">{{ $ts._charts.usersTotal }}</option>
|
||||
<option value="active-users">{{ $ts._charts.activeUsers }}</option>
|
||||
</optgroup>
|
||||
<optgroup :label="$t('notes')">
|
||||
<option value="notes">{{ $t('_charts.notesIncDec') }}</option>
|
||||
<option value="local-notes">{{ $t('_charts.localNotesIncDec') }}</option>
|
||||
<option value="remote-notes">{{ $t('_charts.remoteNotesIncDec') }}</option>
|
||||
<option value="notes-total">{{ $t('_charts.notesTotal') }}</option>
|
||||
<optgroup :label="$ts.notes">
|
||||
<option value="notes">{{ $ts._charts.notesIncDec }}</option>
|
||||
<option value="local-notes">{{ $ts._charts.localNotesIncDec }}</option>
|
||||
<option value="remote-notes">{{ $ts._charts.remoteNotesIncDec }}</option>
|
||||
<option value="notes-total">{{ $ts._charts.notesTotal }}</option>
|
||||
</optgroup>
|
||||
<optgroup :label="$t('drive')">
|
||||
<option value="drive-files">{{ $t('_charts.filesIncDec') }}</option>
|
||||
<option value="drive-files-total">{{ $t('_charts.filesTotal') }}</option>
|
||||
<option value="drive">{{ $t('_charts.storageUsageIncDec') }}</option>
|
||||
<option value="drive-total">{{ $t('_charts.storageUsageTotal') }}</option>
|
||||
<optgroup :label="$ts.drive">
|
||||
<option value="drive-files">{{ $ts._charts.filesIncDec }}</option>
|
||||
<option value="drive-files-total">{{ $ts._charts.filesTotal }}</option>
|
||||
<option value="drive">{{ $ts._charts.storageUsageIncDec }}</option>
|
||||
<option value="drive-total">{{ $ts._charts.storageUsageTotal }}</option>
|
||||
</optgroup>
|
||||
</MkSelect>
|
||||
<MkSelect v-model:value="chartSpan" style="margin: 0;">
|
||||
<option value="hour">{{ $t('perHour') }}</option>
|
||||
<option value="day">{{ $t('perDay') }}</option>
|
||||
<option value="hour">{{ $ts.perHour }}</option>
|
||||
<option value="day">{{ $ts.perDay }}</option>
|
||||
</MkSelect>
|
||||
</div>
|
||||
<canvas ref="chart"></canvas>
|
||||
@ -278,7 +278,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
// TODO: var(--panel)の色が暗いか明るいかで判定する
|
||||
const gridColor = this.$store.state.device.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
|
||||
const gridColor = this.$store.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
|
||||
|
||||
Chart.defaults.global.defaultFontColor = getComputedStyle(document.documentElement).getPropertyValue('--fg');
|
||||
this.chartInstance = markRaw(new Chart(this.$refs.chart, {
|
||||
|
@ -18,7 +18,7 @@
|
||||
<div class="sub">
|
||||
<MkA to="/docs" @click.passive="close()">
|
||||
<Fa :icon="faQuestionCircle" class="icon"/>
|
||||
<div class="text">{{ $t('help') }}</div>
|
||||
<div class="text">{{ $ts.help }}</div>
|
||||
</MkA>
|
||||
<MkA to="/about" @click.passive="close()">
|
||||
<Fa :icon="faInfoCircle" class="icon"/>
|
||||
@ -26,7 +26,7 @@
|
||||
</MkA>
|
||||
<MkA to="/about-misskey" @click.passive="close()">
|
||||
<Fa :icon="faInfoCircle" class="icon"/>
|
||||
<div class="text">{{ $t('aboutMisskey') }}</div>
|
||||
<div class="text">{{ $ts.aboutMisskey }}</div>
|
||||
</MkA>
|
||||
</div>
|
||||
</div>
|
||||
@ -58,14 +58,14 @@ export default defineComponent({
|
||||
|
||||
computed: {
|
||||
menu(): string[] {
|
||||
return this.$store.state.deviceUser.menu;
|
||||
return this.$store.state.menu;
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.items = Object.keys(this.menuDef).filter(k => !this.menu.includes(k)).map(k => this.menuDef[k]).filter(def => def.show == null ? true : def.show).map(def => ({
|
||||
type: def.to ? 'link' : 'button',
|
||||
text: this.$t(def.title),
|
||||
text: this.$ts[def.title],
|
||||
icon: def.icon,
|
||||
to: def.to,
|
||||
action: def.action,
|
||||
|
@ -2,8 +2,8 @@
|
||||
<div class="mk-media-banner">
|
||||
<div class="sensitive" v-if="media.isSensitive && hide" @click="hide = false">
|
||||
<span class="icon"><Fa :icon="faExclamationTriangle"/></span>
|
||||
<b>{{ $t('sensitive') }}</b>
|
||||
<span>{{ $t('clickToShow') }}</span>
|
||||
<b>{{ $ts.sensitive }}</b>
|
||||
<span>{{ $ts.clickToShow }}</span>
|
||||
</div>
|
||||
<div class="audio" v-else-if="media.type.startsWith('audio') && media.type !== 'audio/midi'">
|
||||
<audio class="audio"
|
||||
@ -29,6 +29,7 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
|
||||
import * as os from '@/os';
|
||||
import { ColdDeviceStorage } from '@/store';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@ -45,12 +46,12 @@ export default defineComponent({
|
||||
},
|
||||
mounted() {
|
||||
const audioTag = this.$refs.audio as HTMLAudioElement;
|
||||
if (audioTag) audioTag.volume = this.$store.state.device.mediaVolume;
|
||||
if (audioTag) audioTag.volume = ColdDeviceStorage.get('mediaVolume');
|
||||
},
|
||||
methods: {
|
||||
volumechange() {
|
||||
const audioTag = this.$refs.audio as HTMLAudioElement;
|
||||
this.$store.commit('device/set', { key: 'mediaVolume', value: audioTag.volume });
|
||||
ColdDeviceStorage.set('mediaVolume', audioTag.volume);
|
||||
},
|
||||
},
|
||||
})
|
||||
|
@ -3,8 +3,8 @@
|
||||
<ImgWithBlurhash class="bg" :hash="image.blurhash" :title="image.name"/>
|
||||
<div class="text">
|
||||
<div>
|
||||
<b><Fa :icon="faExclamationTriangle"/> {{ $t('sensitive') }}</b>
|
||||
<span>{{ $t('clickToShow') }}</span>
|
||||
<b><Fa :icon="faExclamationTriangle"/> {{ $ts.sensitive }}</b>
|
||||
<span>{{ $ts.clickToShow }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -52,13 +52,11 @@ export default defineComponent({
|
||||
},
|
||||
computed: {
|
||||
url(): any {
|
||||
let url = this.$store.state.device.disableShowingAnimatedImages
|
||||
let url = this.$store.state.disableShowingAnimatedImages
|
||||
? getStaticImageUrl(this.image.thumbnailUrl)
|
||||
: this.image.thumbnailUrl;
|
||||
|
||||
if (this.$store.state.device.loadRemoteMedia) {
|
||||
url = null;
|
||||
} else if (this.raw || this.$store.state.device.loadRawImages) {
|
||||
if (this.raw || this.$store.state.loadRawImages) {
|
||||
url = this.image.url;
|
||||
}
|
||||
|
||||
@ -68,7 +66,7 @@ export default defineComponent({
|
||||
created() {
|
||||
// Plugin:register_note_view_interruptor を使って書き換えられる可能性があるためwatchする
|
||||
this.$watch('image', () => {
|
||||
this.hide = (this.$store.state.device.nsfw === 'force') ? true : this.image.isSensitive && (this.$store.state.device.nsfw !== 'ignore');
|
||||
this.hide = (this.$store.state.nsfw === 'force') ? true : this.image.isSensitive && (this.$store.state.nsfw !== 'ignore');
|
||||
if (this.image.blurhash) {
|
||||
this.color = extractAvgColorFromBlurhash(this.image.blurhash);
|
||||
}
|
||||
@ -79,7 +77,7 @@ export default defineComponent({
|
||||
},
|
||||
methods: {
|
||||
onClick() {
|
||||
if (this.$store.state.device.imageNewTab) {
|
||||
if (this.$store.state.imageNewTab) {
|
||||
window.open(this.image.url, '_blank');
|
||||
} else {
|
||||
os.popup(ImageViewer, {
|
||||
|
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="icozogqfvdetwohsdglrbswgrejoxbdj" v-if="hide" @click="hide = false">
|
||||
<div>
|
||||
<b><Fa :icon="faExclamationTriangle"/> {{ $t('sensitive') }}</b>
|
||||
<span>{{ $t('clickToShow') }}</span>
|
||||
<b><Fa :icon="faExclamationTriangle"/> {{ $ts.sensitive }}</b>
|
||||
<span>{{ $ts.clickToShow }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="kkjnbbplepmiyuadieoenjgutgcmtsvu" v-else>
|
||||
@ -48,7 +48,7 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.hide = (this.$store.state.device.nsfw === 'force') ? true : this.video.isSensitive && (this.$store.state.device.nsfw !== 'ignore');
|
||||
this.hide = (this.$store.state.nsfw === 'force') ? true : this.video.isSensitive && (this.$store.state.nsfw !== 'ignore');
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<MkA class="ldlomzub" :class="{ isMe }" :to="url" v-user-preview="canonical" v-if="url.startsWith('/')">
|
||||
<span class="me" v-if="isMe">{{ $t('you') }}</span>
|
||||
<span class="me" v-if="isMe">{{ $ts.you }}</span>
|
||||
<span class="main">
|
||||
<span class="username">@{{ username }}</span>
|
||||
<span class="host" v-if="(host != localHost) || $store.state.settings.showFullAcct">@{{ toUnicode(host) }}</span>
|
||||
<span class="host" v-if="(host != localHost) || $store.state.showFullAcct">@{{ toUnicode(host) }}</span>
|
||||
</span>
|
||||
</MkA>
|
||||
<a class="ldlomzub" :href="url" target="_blank" rel="noopener" v-else>
|
||||
@ -50,8 +50,8 @@ export default defineComponent({
|
||||
return this.host === localHost ? `@${this.username}` : `@${this.username}@${toUnicode(this.host)}`;
|
||||
},
|
||||
isMe(): boolean {
|
||||
return this.$store.getters.isSignedIn && (
|
||||
`@${this.username}@${toUnicode(this.host)}` === `@${this.$store.state.i.username}@${toUnicode(localHost)}`.toLowerCase()
|
||||
return this.$i && (
|
||||
`@${this.username}@${toUnicode(this.host)}` === `@${this.$i.username}@${toUnicode(localHost)}`.toLowerCase()
|
||||
);
|
||||
}
|
||||
},
|
||||
|
@ -1,15 +1,15 @@
|
||||
import { VNode, defineComponent, h } from 'vue';
|
||||
import { MfmForest } from '../../mfm/prelude';
|
||||
import { parse, parsePlain } from '../../mfm/parse';
|
||||
import MkUrl from './url.vue';
|
||||
import MkLink from './link.vue';
|
||||
import MkMention from './mention.vue';
|
||||
import MkEmoji from './emoji.vue';
|
||||
import { concat } from '../../prelude/array';
|
||||
import MkFormula from './formula.vue';
|
||||
import MkCode from './code.vue';
|
||||
import MkGoogle from './google.vue';
|
||||
import MkA from './ui/a.vue';
|
||||
import { MfmForest } from '@/../mfm/prelude';
|
||||
import { parse, parsePlain } from '@/../mfm/parse';
|
||||
import MkUrl from '@/components/global/url.vue';
|
||||
import MkLink from '@/components/link.vue';
|
||||
import MkMention from '@/components/mention.vue';
|
||||
import MkEmoji from '@/components/global/emoji.vue';
|
||||
import { concat } from '@/../prelude/array';
|
||||
import MkFormula from '@/components/formula.vue';
|
||||
import MkCode from '@/components/code.vue';
|
||||
import MkGoogle from '@/components/google.vue';
|
||||
import MkA from '@/components/global/a.vue';
|
||||
import { host } from '@/config';
|
||||
|
||||
export default defineComponent({
|
||||
@ -82,22 +82,22 @@ export default defineComponent({
|
||||
let style;
|
||||
switch (token.node.props.name) {
|
||||
case 'tada': {
|
||||
style = `font-size: 150%;` + (this.$store.state.device.animatedMfm ? 'animation: tada 1s linear infinite both;' : '');
|
||||
style = `font-size: 150%;` + (this.$store.state.animatedMfm ? 'animation: tada 1s linear infinite both;' : '');
|
||||
break;
|
||||
}
|
||||
case 'jelly': {
|
||||
const speed = token.node.props.args.speed || '1s';
|
||||
style = (this.$store.state.device.animatedMfm ? `animation: mfm-rubberBand ${speed} linear infinite both;` : '');
|
||||
style = (this.$store.state.animatedMfm ? `animation: mfm-rubberBand ${speed} linear infinite both;` : '');
|
||||
break;
|
||||
}
|
||||
case 'twitch': {
|
||||
const speed = token.node.props.args.speed || '0.5s';
|
||||
style = this.$store.state.device.animatedMfm ? `animation: mfm-twitch ${speed} ease infinite;` : '';
|
||||
style = this.$store.state.animatedMfm ? `animation: mfm-twitch ${speed} ease infinite;` : '';
|
||||
break;
|
||||
}
|
||||
case 'shake': {
|
||||
const speed = token.node.props.args.speed || '0.5s';
|
||||
style = this.$store.state.device.animatedMfm ? `animation: mfm-shake ${speed} ease infinite;` : '';
|
||||
style = this.$store.state.animatedMfm ? `animation: mfm-shake ${speed} ease infinite;` : '';
|
||||
break;
|
||||
}
|
||||
case 'spin': {
|
||||
@ -110,15 +110,15 @@ export default defineComponent({
|
||||
token.node.props.args.y ? 'mfm-spinY' :
|
||||
'mfm-spin';
|
||||
const speed = token.node.props.args.speed || '1.5s';
|
||||
style = this.$store.state.device.animatedMfm ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction};` : '';
|
||||
style = this.$store.state.animatedMfm ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction};` : '';
|
||||
break;
|
||||
}
|
||||
case 'jump': {
|
||||
style = this.$store.state.device.animatedMfm ? 'animation: mfm-jump 0.75s linear infinite;' : '';
|
||||
style = this.$store.state.animatedMfm ? 'animation: mfm-jump 0.75s linear infinite;' : '';
|
||||
break;
|
||||
}
|
||||
case 'bounce': {
|
||||
style = this.$store.state.device.animatedMfm ? 'animation: mfm-bounce 0.75s linear infinite; transform-origin: center bottom;' : '';
|
||||
style = this.$store.state.animatedMfm ? 'animation: mfm-bounce 0.75s linear infinite; transform-origin: center bottom;' : '';
|
||||
break;
|
||||
}
|
||||
case 'flip': {
|
||||
|
@ -6,7 +6,7 @@
|
||||
<XNoteHeader class="header" :note="note" :mini="true"/>
|
||||
<div class="body">
|
||||
<p v-if="note.cw != null" class="cw">
|
||||
<Mfm v-if="note.cw != ''" class="text" :text="note.cw" :author="note.user" :i="$store.state.i" :custom-emojis="note.emojis" />
|
||||
<Mfm v-if="note.cw != ''" class="text" :text="note.cw" :author="note.user" :i="$i" :custom-emojis="note.emojis" />
|
||||
<XCwButton v-model:value="showContent" :note="note"/>
|
||||
</p>
|
||||
<div class="content" v-show="note.cw == null || showContent">
|
||||
|
@ -10,19 +10,19 @@
|
||||
>
|
||||
<XSub v-for="note in conversation" class="reply-to-more" :key="note.id" :note="note"/>
|
||||
<XSub :note="appearNote.reply" class="reply-to" v-if="appearNote.reply"/>
|
||||
<div class="info" v-if="pinned"><Fa :icon="faThumbtack"/> {{ $t('pinnedNote') }}</div>
|
||||
<div class="info" v-if="appearNote._prId_"><Fa :icon="faBullhorn"/> {{ $t('promotion') }}<button class="_textButton hide" @click="readPromo()">{{ $t('hideThisNote') }} <Fa :icon="faTimes"/></button></div>
|
||||
<div class="info" v-if="appearNote._featuredId_"><Fa :icon="faBolt"/> {{ $t('featured') }}</div>
|
||||
<div class="info" v-if="pinned"><Fa :icon="faThumbtack"/> {{ $ts.pinnedNote }}</div>
|
||||
<div class="info" v-if="appearNote._prId_"><Fa :icon="faBullhorn"/> {{ $ts.promotion }}<button class="_textButton hide" @click="readPromo()">{{ $ts.hideThisNote }} <Fa :icon="faTimes"/></button></div>
|
||||
<div class="info" v-if="appearNote._featuredId_"><Fa :icon="faBolt"/> {{ $ts.featured }}</div>
|
||||
<div class="renote" v-if="isRenote">
|
||||
<MkAvatar class="avatar" :user="note.user"/>
|
||||
<Fa :icon="faRetweet"/>
|
||||
<i18n-t keypath="renotedBy" tag="span">
|
||||
<I18n :src="$ts.renotedBy" tag="span">
|
||||
<template #user>
|
||||
<MkA class="name" :to="userPage(note.user)" v-user-preview="note.userId">
|
||||
<MkUserName :user="note.user"/>
|
||||
</MkA>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</I18n>
|
||||
<div class="info">
|
||||
<button class="_button time" @click="showRenoteMenu()" ref="renoteTime">
|
||||
<Fa class="dropdownIcon" v-if="isMyRenote" :icon="faEllipsisH"/>
|
||||
@ -36,21 +36,21 @@
|
||||
<span class="localOnly" v-if="note.localOnly"><Fa :icon="faBiohazard"/></span>
|
||||
</div>
|
||||
</div>
|
||||
<article class="article" @contextmenu="onContextmenu">
|
||||
<article class="article" @contextmenu.prevent.stop="onContextmenu">
|
||||
<MkAvatar class="avatar" :user="appearNote.user"/>
|
||||
<div class="main">
|
||||
<XNoteHeader class="header" :note="appearNote" :mini="true"/>
|
||||
<MkInstanceTicker v-if="showTicker" class="ticker" :instance="appearNote.user.instance"/>
|
||||
<div class="body">
|
||||
<p v-if="appearNote.cw != null" class="cw">
|
||||
<Mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis"/>
|
||||
<Mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
|
||||
<XCwButton v-model:value="showContent" :note="appearNote"/>
|
||||
</p>
|
||||
<div class="content" v-show="appearNote.cw == null || showContent">
|
||||
<div class="text">
|
||||
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
|
||||
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $ts.private }})</span>
|
||||
<MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><Fa :icon="faReply"/></MkA>
|
||||
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis"/>
|
||||
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
|
||||
<a class="rp" v-if="appearNote.renote != null">RN:</a>
|
||||
</div>
|
||||
<div class="files" v-if="appearNote.files.length > 0">
|
||||
@ -90,13 +90,13 @@
|
||||
<XSub v-for="note in replies" :key="note.id" :note="note" class="reply" :detail="true"/>
|
||||
</div>
|
||||
<div v-else class="_panel muted" @click="muted = false">
|
||||
<i18n-t keypath="userSaysSomething" tag="small">
|
||||
<I18n :src="$ts.userSaysSomething" tag="small">
|
||||
<template #name>
|
||||
<MkA class="name" :to="userPage(appearNote.user)" v-user-preview="appearNote.userId">
|
||||
<MkUserName :user="appearNote.user"/>
|
||||
</MkA>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</I18n>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -182,7 +182,7 @@ export default defineComponent({
|
||||
|
||||
computed: {
|
||||
rs() {
|
||||
return this.$store.state.settings.reactions;
|
||||
return this.$store.state.reactions;
|
||||
},
|
||||
keymap(): any {
|
||||
return {
|
||||
@ -222,11 +222,11 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
isMyNote(): boolean {
|
||||
return this.$store.getters.isSignedIn && (this.$store.state.i.id === this.appearNote.userId);
|
||||
return this.$i && (this.$i.id === this.appearNote.userId);
|
||||
},
|
||||
|
||||
isMyRenote(): boolean {
|
||||
return this.$store.getters.isSignedIn && (this.$store.state.i.id === this.note.userId);
|
||||
return this.$i && (this.$i.id === this.note.userId);
|
||||
},
|
||||
|
||||
canRenote(): boolean {
|
||||
@ -262,14 +262,14 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
showTicker() {
|
||||
if (this.$store.state.device.instanceTicker === 'always') return true;
|
||||
if (this.$store.state.device.instanceTicker === 'remote' && this.appearNote.user.instance) return true;
|
||||
if (this.$store.state.instanceTicker === 'always') return true;
|
||||
if (this.$store.state.instanceTicker === 'remote' && this.appearNote.user.instance) return true;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
async created() {
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
if (this.$i) {
|
||||
this.connection = os.stream;
|
||||
}
|
||||
|
||||
@ -282,7 +282,7 @@ export default defineComponent({
|
||||
this.$emit('update:note', Object.freeze(result));
|
||||
}
|
||||
|
||||
this.muted = await checkWordMute(this.appearNote, this.$store.state.i, this.$store.state.settings.mutedWords);
|
||||
this.muted = await checkWordMute(this.appearNote, this.$i, this.$store.state.mutedWords);
|
||||
|
||||
if (this.detail) {
|
||||
os.api('notes/children', {
|
||||
@ -305,7 +305,7 @@ export default defineComponent({
|
||||
mounted() {
|
||||
this.capture(true);
|
||||
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
if (this.$i) {
|
||||
this.connection.on('_connected_', this.onStreamConnected);
|
||||
}
|
||||
},
|
||||
@ -313,7 +313,7 @@ export default defineComponent({
|
||||
beforeUnmount() {
|
||||
this.decapture(true);
|
||||
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
if (this.$i) {
|
||||
this.connection.off('_connected_', this.onStreamConnected);
|
||||
}
|
||||
},
|
||||
@ -340,14 +340,14 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
capture(withHandler = false) {
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
if (this.$i) {
|
||||
this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id });
|
||||
if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated);
|
||||
}
|
||||
},
|
||||
|
||||
decapture(withHandler = false) {
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
if (this.$i) {
|
||||
this.connection.send('un', {
|
||||
id: this.appearNote.id
|
||||
});
|
||||
@ -389,7 +389,7 @@ export default defineComponent({
|
||||
[reaction]: currentCount + 1
|
||||
};
|
||||
|
||||
if (body.userId === this.$store.state.i.id) {
|
||||
if (body.userId === this.$i.id) {
|
||||
n.myReaction = reaction;
|
||||
}
|
||||
|
||||
@ -414,7 +414,7 @@ export default defineComponent({
|
||||
[reaction]: Math.max(0, currentCount - 1)
|
||||
};
|
||||
|
||||
if (body.userId === this.$store.state.i.id) {
|
||||
if (body.userId === this.$i.id) {
|
||||
n.myReaction = null;
|
||||
}
|
||||
|
||||
@ -434,7 +434,7 @@ export default defineComponent({
|
||||
choices[choice] = {
|
||||
...choices[choice],
|
||||
votes: choices[choice].votes + 1,
|
||||
...(body.userId === this.$store.state.i.id ? {
|
||||
...(body.userId === this.$i.id ? {
|
||||
isVoted: true
|
||||
} : {})
|
||||
};
|
||||
@ -469,7 +469,7 @@ export default defineComponent({
|
||||
pleaseLogin();
|
||||
this.blur();
|
||||
os.modalMenu([{
|
||||
text: this.$t('renote'),
|
||||
text: this.$ts.renote,
|
||||
icon: faRetweet,
|
||||
action: () => {
|
||||
os.api('notes/create', {
|
||||
@ -477,7 +477,7 @@ export default defineComponent({
|
||||
});
|
||||
}
|
||||
}, {
|
||||
text: this.$t('quote'),
|
||||
text: this.$ts.quote,
|
||||
icon: faQuoteRight,
|
||||
action: () => {
|
||||
os.post({
|
||||
@ -490,8 +490,25 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
renoteDirectly() {
|
||||
os.api('notes/create', {
|
||||
os.apiWithDialog('notes/create', {
|
||||
renoteId: this.appearNote.id
|
||||
}, undefined, (res: any) => {
|
||||
os.dialog({
|
||||
type: 'success',
|
||||
text: this.$ts.renoted,
|
||||
});
|
||||
}, (e: Error) => {
|
||||
if (e.id === 'b5c90186-4ab0-49c8-9bba-a1f76c282ba4') {
|
||||
os.dialog({
|
||||
type: 'error',
|
||||
text: this.$ts.cantRenote,
|
||||
});
|
||||
} else if (e.id === 'fd4cc33e-2a37-48dd-99cc-9b806eb2031a') {
|
||||
os.dialog({
|
||||
type: 'error',
|
||||
text: this.$ts.cantReRenote,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@ -533,13 +550,30 @@ export default defineComponent({
|
||||
pleaseLogin();
|
||||
os.apiWithDialog('notes/favorites/create', {
|
||||
noteId: this.appearNote.id
|
||||
}, undefined, (res: any) => {
|
||||
os.dialog({
|
||||
type: 'success',
|
||||
text: this.$ts.favorited,
|
||||
});
|
||||
}, (e: Error) => {
|
||||
if (e.id === 'a402c12b-34dd-41d2-97d8-4d2ffd96a1a6') {
|
||||
os.dialog({
|
||||
type: 'error',
|
||||
text: this.$ts.alreadyFavorited,
|
||||
});
|
||||
} else if (e.id === '6dd26674-e060-4816-909a-45ba3f4da458') {
|
||||
os.dialog({
|
||||
type: 'error',
|
||||
text: this.$ts.cantFavorite,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
del() {
|
||||
os.dialog({
|
||||
type: 'warning',
|
||||
text: this.$t('noteDeleteConfirm'),
|
||||
text: this.$ts.noteDeleteConfirm,
|
||||
showCancelButton: true
|
||||
}).then(({ canceled }) => {
|
||||
if (canceled) return;
|
||||
@ -553,7 +587,7 @@ export default defineComponent({
|
||||
delEdit() {
|
||||
os.dialog({
|
||||
type: 'warning',
|
||||
text: this.$t('deleteAndEditConfirm'),
|
||||
text: this.$ts.deleteAndEditConfirm,
|
||||
showCancelButton: true
|
||||
}).then(({ canceled }) => {
|
||||
if (canceled) return;
|
||||
@ -580,22 +614,22 @@ export default defineComponent({
|
||||
|
||||
getMenu() {
|
||||
let menu;
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
if (this.$i) {
|
||||
const statePromise = os.api('notes/state', {
|
||||
noteId: this.appearNote.id
|
||||
});
|
||||
|
||||
menu = [{
|
||||
icon: faCopy,
|
||||
text: this.$t('copyContent'),
|
||||
text: this.$ts.copyContent,
|
||||
action: this.copyContent
|
||||
}, {
|
||||
icon: faLink,
|
||||
text: this.$t('copyLink'),
|
||||
text: this.$ts.copyLink,
|
||||
action: this.copyLink
|
||||
}, (this.appearNote.url || this.appearNote.uri) ? {
|
||||
icon: faExternalLinkSquareAlt,
|
||||
text: this.$t('showOnRemote'),
|
||||
text: this.$ts.showOnRemote,
|
||||
action: () => {
|
||||
window.open(this.appearNote.url || this.appearNote.uri, '_blank');
|
||||
}
|
||||
@ -603,50 +637,50 @@ export default defineComponent({
|
||||
null,
|
||||
statePromise.then(state => state.isFavorited ? {
|
||||
icon: faStar,
|
||||
text: this.$t('unfavorite'),
|
||||
text: this.$ts.unfavorite,
|
||||
action: () => this.toggleFavorite(false)
|
||||
} : {
|
||||
icon: faStar,
|
||||
text: this.$t('favorite'),
|
||||
text: this.$ts.favorite,
|
||||
action: () => this.toggleFavorite(true)
|
||||
}),
|
||||
{
|
||||
icon: faPaperclip,
|
||||
text: this.$t('clip'),
|
||||
text: this.$ts.clip,
|
||||
action: () => this.clip()
|
||||
},
|
||||
(this.appearNote.userId != this.$store.state.i.id) ? statePromise.then(state => state.isWatching ? {
|
||||
(this.appearNote.userId != this.$i.id) ? statePromise.then(state => state.isWatching ? {
|
||||
icon: faEyeSlash,
|
||||
text: this.$t('unwatch'),
|
||||
text: this.$ts.unwatch,
|
||||
action: () => this.toggleWatch(false)
|
||||
} : {
|
||||
icon: faEye,
|
||||
text: this.$t('watch'),
|
||||
text: this.$ts.watch,
|
||||
action: () => this.toggleWatch(true)
|
||||
}) : undefined,
|
||||
this.appearNote.userId == this.$store.state.i.id ? (this.$store.state.i.pinnedNoteIds || []).includes(this.appearNote.id) ? {
|
||||
this.appearNote.userId == this.$i.id ? (this.$i.pinnedNoteIds || []).includes(this.appearNote.id) ? {
|
||||
icon: faThumbtack,
|
||||
text: this.$t('unpin'),
|
||||
text: this.$ts.unpin,
|
||||
action: () => this.togglePin(false)
|
||||
} : {
|
||||
icon: faThumbtack,
|
||||
text: this.$t('pin'),
|
||||
text: this.$ts.pin,
|
||||
action: () => this.togglePin(true)
|
||||
} : undefined,
|
||||
...(this.$store.state.i.isModerator || this.$store.state.i.isAdmin ? [
|
||||
...(this.$i.isModerator || this.$i.isAdmin ? [
|
||||
null,
|
||||
{
|
||||
icon: faBullhorn,
|
||||
text: this.$t('promote'),
|
||||
text: this.$ts.promote,
|
||||
action: this.promote
|
||||
}]
|
||||
: []
|
||||
),
|
||||
...(this.appearNote.userId != this.$store.state.i.id ? [
|
||||
...(this.appearNote.userId != this.$i.id ? [
|
||||
null,
|
||||
{
|
||||
icon: faExclamationCircle,
|
||||
text: this.$t('reportAbuse'),
|
||||
text: this.$ts.reportAbuse,
|
||||
action: () => {
|
||||
const u = `${url}/notes/${this.appearNote.id}`;
|
||||
os.popup(import('@/components/abuse-report-window.vue'), {
|
||||
@ -657,16 +691,16 @@ export default defineComponent({
|
||||
}]
|
||||
: []
|
||||
),
|
||||
...(this.appearNote.userId == this.$store.state.i.id || this.$store.state.i.isModerator || this.$store.state.i.isAdmin ? [
|
||||
...(this.appearNote.userId == this.$i.id || this.$i.isModerator || this.$i.isAdmin ? [
|
||||
null,
|
||||
this.appearNote.userId == this.$store.state.i.id ? {
|
||||
this.appearNote.userId == this.$i.id ? {
|
||||
icon: faEdit,
|
||||
text: this.$t('deleteAndEdit'),
|
||||
text: this.$ts.deleteAndEdit,
|
||||
action: this.delEdit
|
||||
} : undefined,
|
||||
{
|
||||
icon: faTrashAlt,
|
||||
text: this.$t('delete'),
|
||||
text: this.$ts.delete,
|
||||
danger: true,
|
||||
action: this.del
|
||||
}]
|
||||
@ -676,15 +710,15 @@ export default defineComponent({
|
||||
} else {
|
||||
menu = [{
|
||||
icon: faCopy,
|
||||
text: this.$t('copyContent'),
|
||||
text: this.$ts.copyContent,
|
||||
action: this.copyContent
|
||||
}, {
|
||||
icon: faLink,
|
||||
text: this.$t('copyLink'),
|
||||
text: this.$ts.copyLink,
|
||||
action: this.copyLink
|
||||
}, (this.appearNote.url || this.appearNote.uri) ? {
|
||||
icon: faExternalLinkSquareAlt,
|
||||
text: this.$t('showOnRemote'),
|
||||
text: this.$ts.showOnRemote,
|
||||
action: () => {
|
||||
window.open(this.appearNote.url || this.appearNote.uri, '_blank');
|
||||
}
|
||||
@ -726,7 +760,7 @@ export default defineComponent({
|
||||
showRenoteMenu(viaKeyboard = false) {
|
||||
if (!this.isMyRenote) return;
|
||||
os.modalMenu([{
|
||||
text: this.$t('unrenote'),
|
||||
text: this.$ts.unrenote,
|
||||
icon: faTrashAlt,
|
||||
danger: true,
|
||||
action: () => {
|
||||
@ -761,7 +795,7 @@ export default defineComponent({
|
||||
if (e.id === '72dab508-c64d-498f-8740-a8eec1ba385a') {
|
||||
os.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('pinLimitExceeded')
|
||||
text: this.$ts.pinLimitExceeded
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -771,22 +805,22 @@ export default defineComponent({
|
||||
const clips = await os.api('clips/list');
|
||||
os.modalMenu([{
|
||||
icon: faPlus,
|
||||
text: this.$t('createNew'),
|
||||
text: this.$ts.createNew,
|
||||
action: async () => {
|
||||
const { canceled, result } = await os.form(this.$t('createNewClip'), {
|
||||
const { canceled, result } = await os.form(this.$ts.createNewClip, {
|
||||
name: {
|
||||
type: 'string',
|
||||
label: this.$t('name')
|
||||
label: this.$ts.name
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
multiline: true,
|
||||
label: this.$t('description')
|
||||
label: this.$ts.description
|
||||
},
|
||||
isPublic: {
|
||||
type: 'boolean',
|
||||
label: this.$t('public'),
|
||||
label: this.$ts.public,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
@ -807,7 +841,7 @@ export default defineComponent({
|
||||
|
||||
async promote() {
|
||||
const { canceled, result: days } = await os.dialog({
|
||||
title: this.$t('numberOfDays'),
|
||||
title: this.$ts.numberOfDays,
|
||||
input: { type: 'number' }
|
||||
});
|
||||
|
||||
@ -847,6 +881,14 @@ export default defineComponent({
|
||||
overflow: hidden;
|
||||
contain: content;
|
||||
|
||||
// これらの指定はパフォーマンス向上には有効だが、ノートの高さは一定でないため、
|
||||
// 下の方までスクロールすると上のノートの高さがここで決め打ちされたものに変化し、表示しているノートの位置が変わってしまう
|
||||
// ノートがマウントされたときに自身の高さを取得し contain-intrinsic-size を設定しなおせばほぼ解決できそうだが、
|
||||
// 今度はその処理自体がパフォーマンス低下の原因にならないか懸念される。また、被リアクションでも高さは変化するため、やはり多少のズレは生じる
|
||||
// 一度レンダリングされた要素はブラウザがよしなにサイズを覚えておいてくれるような実装になるまで待った方が良さそう(なるのか?)
|
||||
//content-visibility: auto;
|
||||
//contain-intrinsic-size: 0 128px;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
|
||||
|
@ -2,14 +2,14 @@
|
||||
<div class="_list_">
|
||||
<div class="_fullinfo" v-if="empty">
|
||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
||||
<div>{{ $t('noNotes') }}</div>
|
||||
<div>{{ $ts.noNotes }}</div>
|
||||
</div>
|
||||
|
||||
<MkError v-if="error" @retry="init()"/>
|
||||
|
||||
<div v-show="more && reversed" style="margin-bottom: var(--margin);">
|
||||
<button class="_loadMore" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
|
||||
<template v-if="!moreFetching">{{ $t('loadMore') }}</template>
|
||||
<template v-if="!moreFetching">{{ $ts.loadMore }}</template>
|
||||
<template v-if="moreFetching"><MkLoading inline/></template>
|
||||
</button>
|
||||
</div>
|
||||
@ -19,8 +19,8 @@
|
||||
</XList>
|
||||
|
||||
<div v-show="more && !reversed" style="margin-top: var(--margin);">
|
||||
<button class="_loadMore" v-appear="$store.state.device.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
|
||||
<template v-if="!moreFetching">{{ $t('loadMore') }}</template>
|
||||
<button class="_loadMore" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
|
||||
<template v-if="!moreFetching">{{ $ts.loadMore }}</template>
|
||||
<template v-if="moreFetching"><MkLoading inline/></template>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -8,17 +8,17 @@
|
||||
@close="$refs.dialog.close()"
|
||||
@closed="$emit('closed')"
|
||||
>
|
||||
<template #header>{{ $t('notificationSetting') }}</template>
|
||||
<template #header>{{ $ts.notificationSetting }}</template>
|
||||
<div v-if="showGlobalToggle" class="_section">
|
||||
<MkSwitch v-model:value="useGlobalSetting">
|
||||
{{ $t('useGlobalSetting') }}
|
||||
<template #desc>{{ $t('useGlobalSettingDesc') }}</template>
|
||||
{{ $ts.useGlobalSetting }}
|
||||
<template #desc>{{ $ts.useGlobalSettingDesc }}</template>
|
||||
</MkSwitch>
|
||||
</div>
|
||||
<div v-if="!useGlobalSetting" class="_section">
|
||||
<MkInfo>{{ $t('notificationSettingDesc') }}</MkInfo>
|
||||
<MkButton inline @click="disableAll">{{ $t('disableAll') }}</MkButton>
|
||||
<MkButton inline @click="enableAll">{{ $t('enableAll') }}</MkButton>
|
||||
<MkInfo>{{ $ts.notificationSettingDesc }}</MkInfo>
|
||||
<MkButton inline @click="disableAll">{{ $ts.disableAll }}</MkButton>
|
||||
<MkButton inline @click="enableAll">{{ $ts.enableAll }}</MkButton>
|
||||
<MkSwitch v-for="type in notificationTypes" :key="type" v-model:value="typesMap[type]">{{ $t(`_notification._types.${type}`) }}</MkSwitch>
|
||||
</div>
|
||||
</XModalWindow>
|
||||
|
@ -46,10 +46,10 @@
|
||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
|
||||
<Fa :icon="faQuoteRight"/>
|
||||
</MkA>
|
||||
<span v-if="notification.type === 'follow'" class="text" style="opacity: 0.6;">{{ $t('youGotNewFollower') }}<div v-if="full"><MkFollowButton :user="notification.user" :full="true"/></div></span>
|
||||
<span v-if="notification.type === 'followRequestAccepted'" class="text" style="opacity: 0.6;">{{ $t('followRequestAccepted') }}</span>
|
||||
<span v-if="notification.type === 'receiveFollowRequest'" class="text" style="opacity: 0.6;">{{ $t('receiveFollowRequest') }}<div v-if="full && !followRequestDone"><button class="_textButton" @click="acceptFollowRequest()">{{ $t('accept') }}</button> | <button class="_textButton" @click="rejectFollowRequest()">{{ $t('reject') }}</button></div></span>
|
||||
<span v-if="notification.type === 'groupInvited'" class="text" style="opacity: 0.6;">{{ $t('groupInvited') }}: <b>{{ notification.invitation.group.name }}</b><div v-if="full && !groupInviteDone"><button class="_textButton" @click="acceptGroupInvitation()">{{ $t('accept') }}</button> | <button class="_textButton" @click="rejectGroupInvitation()">{{ $t('reject') }}</button></div></span>
|
||||
<span v-if="notification.type === 'follow'" class="text" style="opacity: 0.6;">{{ $ts.youGotNewFollower }}<div v-if="full"><MkFollowButton :user="notification.user" :full="true"/></div></span>
|
||||
<span v-if="notification.type === 'followRequestAccepted'" class="text" style="opacity: 0.6;">{{ $ts.followRequestAccepted }}</span>
|
||||
<span v-if="notification.type === 'receiveFollowRequest'" class="text" style="opacity: 0.6;">{{ $ts.receiveFollowRequest }}<div v-if="full && !followRequestDone"><button class="_textButton" @click="acceptFollowRequest()">{{ $ts.accept }}</button> | <button class="_textButton" @click="rejectFollowRequest()">{{ $ts.reject }}</button></div></span>
|
||||
<span v-if="notification.type === 'groupInvited'" class="text" style="opacity: 0.6;">{{ $ts.groupInvited }}: <b>{{ notification.invitation.group.name }}</b><div v-if="full && !groupInviteDone"><button class="_textButton" @click="acceptGroupInvitation()">{{ $ts.accept }}</button> | <button class="_textButton" @click="rejectGroupInvitation()">{{ $ts.reject }}</button></div></span>
|
||||
<span v-if="notification.type === 'app'" class="text">
|
||||
<Mfm :text="notification.body" :nowrap="!full"/>
|
||||
</span>
|
||||
@ -61,12 +61,12 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { faIdCardAlt, faPlus, faQuoteLeft, faQuoteRight, faRetweet, faReply, faAt, faCheck, faPollH } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faClock } from '@fortawesome/free-regular-svg-icons';
|
||||
import noteSummary from '../../misc/get-note-summary';
|
||||
import { getNoteSummary } from '../../misc/get-note-summary';
|
||||
import XReactionIcon from './reaction-icon.vue';
|
||||
import MkFollowButton from './follow-button.vue';
|
||||
import notePage from '../filters/note';
|
||||
import { userPage } from '../filters/user';
|
||||
import { locale } from '../i18n';
|
||||
import { i18n } from '@/i18n';
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
@ -91,7 +91,7 @@ export default defineComponent({
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
getNoteSummary: (text: string) => noteSummary(text, locale),
|
||||
getNoteSummary: (text: string) => getNoteSummary(text, i18n.locale),
|
||||
followRequestDone: false,
|
||||
groupInviteDone: false,
|
||||
connection: null,
|
||||
|
@ -5,12 +5,12 @@
|
||||
<XNotification v-else :notification="notification" :with-time="true" :full="true" class="_panel notification" :key="notification.id"/>
|
||||
</XList>
|
||||
|
||||
<button class="_loadMore" v-appear="$store.state.device.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" v-show="more" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
|
||||
<template v-if="!moreFetching">{{ $t('loadMore') }}</template>
|
||||
<button class="_loadMore" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" v-show="more" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
|
||||
<template v-if="!moreFetching">{{ $ts.loadMore }}</template>
|
||||
<template v-if="moreFetching"><MkLoading inline/></template>
|
||||
</button>
|
||||
|
||||
<p class="empty" v-if="empty">{{ $t('noNotifications') }}</p>
|
||||
<p class="empty" v-if="empty">{{ $ts.noNotifications }}</p>
|
||||
|
||||
<MkError v-if="error" @retry="init()"/>
|
||||
</div>
|
||||
@ -59,7 +59,7 @@ export default defineComponent({
|
||||
|
||||
computed: {
|
||||
allIncludeTypes() {
|
||||
return this.includeTypes ?? notificationTypes.filter(x => !this.$store.state.i.mutingNotificationTypes.includes(x));
|
||||
return this.includeTypes ?? notificationTypes.filter(x => !this.$i.mutingNotificationTypes.includes(x));
|
||||
}
|
||||
},
|
||||
|
||||
@ -70,9 +70,9 @@ export default defineComponent({
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
// TODO: vue/vuexのバグか仕様かは不明なものの、プロフィール更新するなどして $store.state.i が更新されると、
|
||||
// TODO: vue/vuexのバグか仕様かは不明なものの、プロフィール更新するなどして $i が更新されると、
|
||||
// mutingNotificationTypes に変化が無くてもこのハンドラーが呼び出され無駄なリロードが発生するのを直す
|
||||
'$store.state.i.mutingNotificationTypes': {
|
||||
'$i.mutingNotificationTypes': {
|
||||
handler() {
|
||||
if (this.includeTypes === null) {
|
||||
this.reload();
|
||||
|
@ -90,29 +90,29 @@ export default defineComponent({
|
||||
text: this.path,
|
||||
}, {
|
||||
icon: faExpandAlt,
|
||||
text: this.$t('showInPage'),
|
||||
text: this.$ts.showInPage,
|
||||
action: this.expand
|
||||
}, this.sideViewHook ? {
|
||||
icon: faColumns,
|
||||
text: this.$t('openInSideView'),
|
||||
text: this.$ts.openInSideView,
|
||||
action: () => {
|
||||
this.sideViewHook(this.path);
|
||||
this.$refs.window.close();
|
||||
}
|
||||
} : undefined, {
|
||||
icon: faExternalLinkAlt,
|
||||
text: this.$t('popout'),
|
||||
text: this.$ts.popout,
|
||||
action: this.popout
|
||||
}, null, {
|
||||
icon: faExternalLinkAlt,
|
||||
text: this.$t('openInNewTab'),
|
||||
text: this.$ts.openInNewTab,
|
||||
action: () => {
|
||||
window.open(this.url, '_blank');
|
||||
this.$refs.window.close();
|
||||
}
|
||||
}, {
|
||||
icon: faLink,
|
||||
text: this.$t('copyLink'),
|
||||
text: this.$ts.copyLink,
|
||||
action: () => {
|
||||
copyToClipboard(this.url);
|
||||
}
|
||||
|
@ -49,9 +49,9 @@ export default defineComponent({
|
||||
canvas.toBlob(blob => {
|
||||
const data = new FormData();
|
||||
data.append('file', blob);
|
||||
data.append('i', this.$store.state.i.token);
|
||||
if (this.$store.state.settings.uploadFolder) {
|
||||
data.append('folderId', this.$store.state.settings.uploadFolder);
|
||||
data.append('i', this.$i.token);
|
||||
if (this.$store.state.uploadFolder) {
|
||||
data.append('folderId', this.$store.state.uploadFolder);
|
||||
}
|
||||
|
||||
fetch(apiUrl + '/drive/files/create', {
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<div>{{ hpml.interpolate(value.title) }}</div>
|
||||
<MkRadio v-for="x in value.values" v-model:value="v" :value="x" :key="x">{{ x }}</MkRadio>
|
||||
<MkRadio v-for="x in value.values" v-model="v" :value="x" :key="x">{{ x }}</MkRadio>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="mrdgzndn">
|
||||
<Mfm :text="text" :is-note="false" :i="$store.state.i" :key="text"/>
|
||||
<Mfm :text="text" :is-note="false" :i="$i" :key="text"/>
|
||||
<MkUrlPreview v-for="url in urls" :url="url" :key="url" class="url"/>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="iroscrza" :class="{ center: page.alignCenter, serif: page.font === 'serif' }" v-if="hpml">
|
||||
<XBlock v-for="child in page.content" :value="child" @update:value="v => updateBlock(v)" :page="page" :hpml="hpml" :key="child.id" :h="2"/>
|
||||
<XBlock v-for="child in page.content" :value="child" :page="page" :hpml="hpml" :key="child.id" :h="2"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -35,9 +35,9 @@ export default defineComponent({
|
||||
created() {
|
||||
this.hpml = new Hpml(this.page, {
|
||||
randomSeed: Math.random(),
|
||||
visitor: this.$store.state.i,
|
||||
visitor: this.$i,
|
||||
url: url,
|
||||
enableAiScript: !this.$store.state.device.disablePagesScript
|
||||
enableAiScript: !this.$store.state.disablePagesScript
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="zmdxowus">
|
||||
<p class="caution" v-if="choices.length < 2">
|
||||
<Fa :icon="faExclamationTriangle"/>{{ $t('_poll.noOnlyOneChoice') }}
|
||||
<Fa :icon="faExclamationTriangle"/>{{ $ts._poll.noOnlyOneChoice }}
|
||||
</p>
|
||||
<ul ref="choices">
|
||||
<li v-for="(choice, i) in choices" :key="i">
|
||||
@ -13,34 +13,34 @@
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<MkButton class="add" v-if="choices.length < 10" @click="add">{{ $t('add') }}</MkButton>
|
||||
<MkButton class="add" v-else disabled>{{ $t('_poll.noMore') }}</MkButton>
|
||||
<MkButton class="add" v-if="choices.length < 10" @click="add">{{ $ts.add }}</MkButton>
|
||||
<MkButton class="add" v-else disabled>{{ $ts._poll.noMore }}</MkButton>
|
||||
<section>
|
||||
<MkSwitch v-model:value="multiple">{{ $t('_poll.canMultipleVote') }}</MkSwitch>
|
||||
<MkSwitch v-model:value="multiple">{{ $ts._poll.canMultipleVote }}</MkSwitch>
|
||||
<div>
|
||||
<MkSelect v-model:value="expiration">
|
||||
<template #label>{{ $t('_poll.expiration') }}</template>
|
||||
<option value="infinite">{{ $t('_poll.infinite') }}</option>
|
||||
<option value="at">{{ $t('_poll.at') }}</option>
|
||||
<option value="after">{{ $t('_poll.after') }}</option>
|
||||
<template #label>{{ $ts._poll.expiration }}</template>
|
||||
<option value="infinite">{{ $ts._poll.infinite }}</option>
|
||||
<option value="at">{{ $ts._poll.at }}</option>
|
||||
<option value="after">{{ $ts._poll.after }}</option>
|
||||
</MkSelect>
|
||||
<section v-if="expiration === 'at'">
|
||||
<MkInput v-model:value="atDate" type="date" class="input">
|
||||
<span>{{ $t('_poll.deadlineDate') }}</span>
|
||||
<span>{{ $ts._poll.deadlineDate }}</span>
|
||||
</MkInput>
|
||||
<MkInput v-model:value="atTime" type="time" class="input">
|
||||
<span>{{ $t('_poll.deadlineTime') }}</span>
|
||||
<span>{{ $ts._poll.deadlineTime }}</span>
|
||||
</MkInput>
|
||||
</section>
|
||||
<section v-if="expiration === 'after'">
|
||||
<MkInput v-model:value="after" type="number" class="input">
|
||||
<span>{{ $t('_poll.duration') }}</span>
|
||||
<span>{{ $ts._poll.duration }}</span>
|
||||
</MkInput>
|
||||
<MkSelect v-model:value="unit">
|
||||
<option value="second">{{ $t('_time.second') }}</option>
|
||||
<option value="minute">{{ $t('_time.minute') }}</option>
|
||||
<option value="hour">{{ $t('_time.hour') }}</option>
|
||||
<option value="day">{{ $t('_time.day') }}</option>
|
||||
<option value="second">{{ $ts._time.second }}</option>
|
||||
<option value="minute">{{ $ts._time.minute }}</option>
|
||||
<option value="hour">{{ $ts._time.hour }}</option>
|
||||
<option value="day">{{ $ts._time.day }}</option>
|
||||
</MkSelect>
|
||||
</section>
|
||||
</div>
|
||||
|
@ -13,9 +13,9 @@
|
||||
<p>
|
||||
<span>{{ $t('_poll.totalVotes', { n: total }) }}</span>
|
||||
<span> · </span>
|
||||
<a v-if="!closed && !isVoted" @click="toggleShowResult">{{ showResult ? $t('_poll.vote') : $t('_poll.showResult') }}</a>
|
||||
<span v-if="isVoted">{{ $t('_poll.voted') }}</span>
|
||||
<span v-else-if="closed">{{ $t('_poll.closed') }}</span>
|
||||
<a v-if="!closed && !isVoted" @click="toggleShowResult">{{ showResult ? $ts._poll.vote : $ts._poll.showResult }}</a>
|
||||
<span v-if="isVoted">{{ $ts._poll.voted }}</span>
|
||||
<span v-else-if="closed">{{ $ts._poll.closed }}</span>
|
||||
<span v-if="remaining > 0"> · {{ timer }}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
@ -77,7 +77,7 @@ export default defineComponent({
|
||||
},
|
||||
async rename(file) {
|
||||
const { canceled, result } = await os.dialog({
|
||||
title: this.$t('enterFileName'),
|
||||
title: this.$ts.enterFileName,
|
||||
input: {
|
||||
default: file.name
|
||||
},
|
||||
@ -95,15 +95,15 @@ export default defineComponent({
|
||||
showFileMenu(file, ev: MouseEvent) {
|
||||
if (this.menu) return;
|
||||
this.menu = os.modalMenu([{
|
||||
text: this.$t('renameFile'),
|
||||
text: this.$ts.renameFile,
|
||||
icon: faICursor,
|
||||
action: () => { this.rename(file) }
|
||||
}, {
|
||||
text: file.isSensitive ? this.$t('unmarkAsSensitive') : this.$t('markAsSensitive'),
|
||||
text: file.isSensitive ? this.$ts.unmarkAsSensitive : this.$ts.markAsSensitive,
|
||||
icon: file.isSensitive ? faEyeSlash : faEye,
|
||||
action: () => { this.toggleSensitive(file) }
|
||||
}, {
|
||||
text: this.$t('attachCancel'),
|
||||
text: this.$ts.attachCancel,
|
||||
icon: faTimesCircle,
|
||||
action: () => { this.detachMedia(file.id) }
|
||||
}], ev.currentTarget || ev.target).then(() => this.menu = null);
|
||||
|
@ -11,7 +11,7 @@
|
||||
<div>
|
||||
<span class="text-count" :class="{ over: trimmedLength(text) > max }">{{ max - trimmedLength(text) }}</span>
|
||||
<span class="local-only" v-if="localOnly"><Fa :icon="faBiohazard"/></span>
|
||||
<button class="_button visibility" @click="setVisibility" ref="visibilityButton" v-tooltip="$t('visibility')" :disabled="channel != null">
|
||||
<button class="_button visibility" @click="setVisibility" ref="visibilityButton" v-tooltip="$ts.visibility" :disabled="channel != null">
|
||||
<span v-if="visibility === 'public'"><Fa :icon="faGlobe"/></span>
|
||||
<span v-if="visibility === 'home'"><Fa :icon="faHome"/></span>
|
||||
<span v-if="visibility === 'followers'"><Fa :icon="faUnlock"/></span>
|
||||
@ -23,9 +23,9 @@
|
||||
<div class="form" :class="{ fixed }">
|
||||
<XNotePreview class="preview" v-if="reply" :note="reply"/>
|
||||
<XNotePreview class="preview" v-if="renote" :note="renote"/>
|
||||
<div class="with-quote" v-if="quoteId"><Fa icon="quote-left"/> {{ $t('quoteAttached') }}<button @click="quoteId = null"><Fa icon="times"/></button></div>
|
||||
<div class="with-quote" v-if="quoteId"><Fa icon="quote-left"/> {{ $ts.quoteAttached }}<button @click="quoteId = null"><Fa icon="times"/></button></div>
|
||||
<div v-if="visibility === 'specified'" class="to-specified">
|
||||
<span style="margin-right: 8px;">{{ $t('recipient') }}</span>
|
||||
<span style="margin-right: 8px;">{{ $ts.recipient }}</span>
|
||||
<div class="visibleUsers">
|
||||
<span v-for="u in visibleUsers" :key="u.id">
|
||||
<MkAcct :user="u"/>
|
||||
@ -34,17 +34,17 @@
|
||||
<button @click="addVisibleUser" class="_buttonPrimary"><Fa :icon="faPlus" fixed-width/></button>
|
||||
</div>
|
||||
</div>
|
||||
<input v-show="useCw" ref="cw" class="cw" v-model="cw" :placeholder="$t('annotation')" @keydown="onKeydown">
|
||||
<input v-show="useCw" ref="cw" class="cw" v-model="cw" :placeholder="$ts.annotation" @keydown="onKeydown">
|
||||
<textarea v-model="text" class="text" :class="{ withCw: useCw }" ref="text" :disabled="posting" :placeholder="placeholder" @keydown="onKeydown" @paste="onPaste"></textarea>
|
||||
<XPostFormAttaches class="attaches" :files="files" @updated="updateFiles" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/>
|
||||
<XPollEditor v-if="poll" :poll="poll" @destroyed="poll = null" @updated="onPollUpdate"/>
|
||||
<footer>
|
||||
<button class="_button" @click="chooseFileFrom" v-tooltip="$t('attachFile')"><Fa :icon="faPhotoVideo"/></button>
|
||||
<button class="_button" @click="togglePoll" :class="{ active: poll }" v-tooltip="$t('poll')"><Fa :icon="faPollH"/></button>
|
||||
<button class="_button" @click="useCw = !useCw" :class="{ active: useCw }" v-tooltip="$t('useCw')"><Fa :icon="faEyeSlash"/></button>
|
||||
<button class="_button" @click="insertMention" v-tooltip="$t('mention')"><Fa :icon="faAt"/></button>
|
||||
<button class="_button" @click="insertEmoji" v-tooltip="$t('emoji')"><Fa :icon="faLaughSquint"/></button>
|
||||
<button class="_button" @click="showActions" v-tooltip="$t('plugin')" v-if="postFormActions.length > 0"><Fa :icon="faPlug"/></button>
|
||||
<button class="_button" @click="chooseFileFrom" v-tooltip="$ts.attachFile"><Fa :icon="faPhotoVideo"/></button>
|
||||
<button class="_button" @click="togglePoll" :class="{ active: poll }" v-tooltip="$ts.poll"><Fa :icon="faPollH"/></button>
|
||||
<button class="_button" @click="useCw = !useCw" :class="{ active: useCw }" v-tooltip="$ts.useCw"><Fa :icon="faEyeSlash"/></button>
|
||||
<button class="_button" @click="insertMention" v-tooltip="$ts.mention"><Fa :icon="faAt"/></button>
|
||||
<button class="_button" @click="insertEmoji" v-tooltip="$ts.emoji"><Fa :icon="faLaughSquint"/></button>
|
||||
<button class="_button" @click="showActions" v-tooltip="$ts.plugin" v-if="postFormActions.length > 0"><Fa :icon="faPlug"/></button>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
@ -135,8 +135,8 @@ export default defineComponent({
|
||||
poll: null,
|
||||
useCw: false,
|
||||
cw: null,
|
||||
localOnly: this.$store.state.settings.rememberNoteVisibility ? this.$store.state.deviceUser.localOnly : this.$store.state.settings.defaultNoteLocalOnly,
|
||||
visibility: this.$store.state.settings.rememberNoteVisibility ? this.$store.state.deviceUser.visibility : this.$store.state.settings.defaultNoteVisibility,
|
||||
localOnly: this.$store.state.rememberNoteVisibility ? this.$store.state.localOnly : this.$store.state.defaultNoteLocalOnly,
|
||||
visibility: this.$store.state.rememberNoteVisibility ? this.$store.state.visibility : this.$store.state.defaultNoteVisibility,
|
||||
visibleUsers: [],
|
||||
autocomplete: null,
|
||||
draghover: false,
|
||||
@ -164,19 +164,19 @@ export default defineComponent({
|
||||
|
||||
placeholder(): string {
|
||||
if (this.renote) {
|
||||
return this.$t('_postForm.quotePlaceholder');
|
||||
return this.$ts._postForm.quotePlaceholder;
|
||||
} else if (this.reply) {
|
||||
return this.$t('_postForm.replyPlaceholder');
|
||||
return this.$ts._postForm.replyPlaceholder;
|
||||
} else if (this.channel) {
|
||||
return this.$t('_postForm.channelPlaceholder');
|
||||
return this.$ts._postForm.channelPlaceholder;
|
||||
} else {
|
||||
const xs = [
|
||||
this.$t('_postForm._placeholders.a'),
|
||||
this.$t('_postForm._placeholders.b'),
|
||||
this.$t('_postForm._placeholders.c'),
|
||||
this.$t('_postForm._placeholders.d'),
|
||||
this.$t('_postForm._placeholders.e'),
|
||||
this.$t('_postForm._placeholders.f')
|
||||
this.$ts._postForm._placeholders.a,
|
||||
this.$ts._postForm._placeholders.b,
|
||||
this.$ts._postForm._placeholders.c,
|
||||
this.$ts._postForm._placeholders.d,
|
||||
this.$ts._postForm._placeholders.e,
|
||||
this.$ts._postForm._placeholders.f
|
||||
];
|
||||
return xs[Math.floor(Math.random() * xs.length)];
|
||||
}
|
||||
@ -184,10 +184,10 @@ export default defineComponent({
|
||||
|
||||
submitText(): string {
|
||||
return this.renote
|
||||
? this.$t('quote')
|
||||
? this.$ts.quote
|
||||
: this.reply
|
||||
? this.$t('reply')
|
||||
: this.$t('note');
|
||||
? this.$ts.reply
|
||||
: this.$ts.note;
|
||||
},
|
||||
|
||||
canPost(): boolean {
|
||||
@ -198,7 +198,7 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
max(): number {
|
||||
return this.$store.state.instance.meta ? this.$store.state.instance.meta.maxNoteTextLength : 1000;
|
||||
return this.$instance ? this.$instance.maxNoteTextLength : 1000;
|
||||
}
|
||||
},
|
||||
|
||||
@ -223,8 +223,8 @@ export default defineComponent({
|
||||
const mention = x.host ? `@${x.username}@${toASCII(x.host)}` : `@${x.username}`;
|
||||
|
||||
// 自分は除外
|
||||
if (this.$store.state.i.username == x.username && x.host == null) continue;
|
||||
if (this.$store.state.i.username == x.username && x.host == host) continue;
|
||||
if (this.$i.username == x.username && x.host == null) continue;
|
||||
if (this.$i.username == x.username && x.host == host) continue;
|
||||
|
||||
// 重複は除外
|
||||
if (this.text.indexOf(`${mention} `) != -1) continue;
|
||||
@ -243,12 +243,12 @@ export default defineComponent({
|
||||
this.visibility = this.reply.visibility;
|
||||
if (this.reply.visibility === 'specified') {
|
||||
os.api('users/show', {
|
||||
userIds: this.reply.visibleUserIds.filter(uid => uid !== this.$store.state.i.id && uid !== this.reply.userId)
|
||||
userIds: this.reply.visibleUserIds.filter(uid => uid !== this.$i.id && uid !== this.reply.userId)
|
||||
}).then(users => {
|
||||
this.visibleUsers.push(...users);
|
||||
});
|
||||
|
||||
if (this.reply.userId !== this.$store.state.i.id) {
|
||||
if (this.reply.userId !== this.$i.id) {
|
||||
os.api('users/show', { userId: this.reply.userId }).then(user => {
|
||||
this.visibleUsers.push(user);
|
||||
});
|
||||
@ -262,7 +262,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
// keep cw when reply
|
||||
if (this.$store.state.settings.keepCw && this.reply && this.reply.cw) {
|
||||
if (this.$store.keepCw && this.reply && this.reply.cw) {
|
||||
this.useCw = true;
|
||||
this.cw = this.reply.cw;
|
||||
}
|
||||
@ -352,7 +352,7 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
chooseFileFrom(ev) {
|
||||
selectFile(ev.currentTarget || ev.target, this.$t('attachFile'), true).then(files => {
|
||||
selectFile(ev.currentTarget || ev.target, this.$ts.attachFile, true).then(files => {
|
||||
for (const file of files) {
|
||||
this.files.push(file);
|
||||
}
|
||||
@ -376,7 +376,7 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
upload(file: File, name?: string) {
|
||||
os.upload(file, this.$store.state.settings.uploadFolder, name).then(res => {
|
||||
os.upload(file, this.$store.state.uploadFolder, name).then(res => {
|
||||
this.files.push(res);
|
||||
});
|
||||
},
|
||||
@ -399,14 +399,14 @@ export default defineComponent({
|
||||
}, {
|
||||
changeVisibility: visibility => {
|
||||
this.visibility = visibility;
|
||||
if (this.$store.state.settings.rememberNoteVisibility) {
|
||||
this.$store.commit('deviceUser/setVisibility', visibility);
|
||||
if (this.$store.state.rememberNoteVisibility) {
|
||||
this.$store.set('visibility', visibility);
|
||||
}
|
||||
},
|
||||
changeLocalOnly: localOnly => {
|
||||
this.localOnly = localOnly;
|
||||
if (this.$store.state.settings.rememberNoteVisibility) {
|
||||
this.$store.commit('deviceUser/setLocalOnly', localOnly);
|
||||
if (this.$store.state.rememberNoteVisibility) {
|
||||
this.$store.set('localOnly', localOnly);
|
||||
}
|
||||
}
|
||||
}, 'closed');
|
||||
@ -440,7 +440,7 @@ export default defineComponent({
|
||||
const file = item.getAsFile();
|
||||
const lio = file.name.lastIndexOf('.');
|
||||
const ext = lio >= 0 ? file.name.slice(lio) : '';
|
||||
const formatted = `${formatTimeString(new Date(file.lastModified), this.$store.state.settings.pastedFileName).replace(/{{number}}/g, `${i + 1}`)}${ext}`;
|
||||
const formatted = `${formatTimeString(new Date(file.lastModified), this.$store.state.pastedFileName).replace(/{{number}}/g, `${i + 1}`)}${ext}`;
|
||||
this.upload(file, formatted);
|
||||
}
|
||||
}
|
||||
@ -452,7 +452,7 @@ export default defineComponent({
|
||||
|
||||
os.dialog({
|
||||
type: 'info',
|
||||
text: this.$t('quoteQuestion'),
|
||||
text: this.$ts.quoteQuestion,
|
||||
showCancelButton: true
|
||||
}).then(({ canceled }) => {
|
||||
if (canceled) {
|
||||
|
@ -53,7 +53,7 @@ export default defineComponent({
|
||||
},
|
||||
computed: {
|
||||
canToggle(): boolean {
|
||||
return !this.reaction.match(/@\w/) && this.$store.getters.isSignedIn;
|
||||
return !this.reaction.match(/@\w/) && this.$i;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
@ -25,7 +25,7 @@ export default defineComponent({
|
||||
},
|
||||
computed: {
|
||||
isMe(): boolean {
|
||||
return this.$store.getters.isSignedIn && this.$store.state.i.id === this.note.userId;
|
||||
return this.$i && this.$i.id === this.note.userId;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="jmgmzlwq _panel"><Fa :icon="faExclamationTriangle" style="margin-right: 8px;"/>{{ $t('remoteUserCaution') }}<a :href="href" rel="nofollow noopener" target="_blank">{{ $t('showOnRemote') }}</a></div>
|
||||
<div class="jmgmzlwq _panel"><Fa :icon="faExclamationTriangle" style="margin-right: 8px;"/>{{ $ts.remoteUserCaution }}<a :href="href" rel="nofollow noopener" target="_blank">{{ $ts.showOnRemote }}</a></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -51,7 +51,7 @@ export default defineComponent({
|
||||
text: '',
|
||||
flag: false,
|
||||
radio: 'misskey',
|
||||
mfm: `Hello world! This is an @example mention. BTW you are @${this.$store.state.i.username}.\nAlso, here is ${config.url} and [example link](${config.url}). for more details, see https://example.com.\nAs you know #misskey is open-source software.`
|
||||
mfm: `Hello world! This is an @example mention. BTW you are @${this.$i.username}.\nAlso, here is ${config.url} and [example link](${config.url}). for more details, see https://example.com.\nAs you know #misskey is open-source software.`
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -12,29 +12,32 @@
|
||||
<nav class="nav" :class="{ iconOnly, hidden }" v-show="showing">
|
||||
<div>
|
||||
<button class="item _button account" @click="openAccountMenu">
|
||||
<MkAvatar :user="$store.state.i" class="avatar"/><MkAcct class="text" :user="$store.state.i"/>
|
||||
<MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/>
|
||||
</button>
|
||||
<MkA class="item index" active-class="active" to="/" exact>
|
||||
<Fa :icon="faHome" fixed-width/><span class="text">{{ $t('timeline') }}</span>
|
||||
<Fa :icon="faHome" fixed-width/><span class="text">{{ $ts.timeline }}</span>
|
||||
</MkA>
|
||||
<template v-for="item in menu">
|
||||
<div v-if="item === '-'" class="divider"></div>
|
||||
<component v-else-if="menuDef[item] && (menuDef[item].show !== false)" :is="menuDef[item].to ? 'MkA' : 'button'" class="item _button" :class="item" active-class="active" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}" :to="menuDef[item].to">
|
||||
<Fa :icon="menuDef[item].icon" fixed-width/><span class="text">{{ $t(menuDef[item].title) }}</span>
|
||||
<Fa :icon="menuDef[item].icon" fixed-width/><span class="text">{{ $ts[menuDef[item].title] }}</span>
|
||||
<i v-if="menuDef[item].indicated"><Fa :icon="faCircle"/></i>
|
||||
</component>
|
||||
</template>
|
||||
<div class="divider"></div>
|
||||
<button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$store.state.i.isAdmin || $store.state.i.isModerator" @click="oepnInstanceMenu">
|
||||
<Fa :icon="faServer" fixed-width/><span class="text">{{ $t('instance') }}</span>
|
||||
<button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$i.isAdmin || $i.isModerator" @click="oepnInstanceMenu">
|
||||
<Fa :icon="faServer" fixed-width/><span class="text">{{ $ts.instance }}</span>
|
||||
</button>
|
||||
<button class="item _button" @click="more">
|
||||
<Fa :icon="faEllipsisH" fixed-width/><span class="text">{{ $t('more') }}</span>
|
||||
<Fa :icon="faEllipsisH" fixed-width/><span class="text">{{ $ts.more }}</span>
|
||||
<i v-if="otherNavItemIndicated"><Fa :icon="faCircle"/></i>
|
||||
</button>
|
||||
<MkA class="item" active-class="active" to="/settings">
|
||||
<Fa :icon="faCog" fixed-width/><span class="text">{{ $t('settings') }}</span>
|
||||
<Fa :icon="faCog" fixed-width/><span class="text">{{ $ts.settings }}</span>
|
||||
</MkA>
|
||||
<button class="item _button post" @click="post">
|
||||
<Fa :icon="faPencilAlt" fixed-width/><span class="text">{{ $ts.note }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
</transition>
|
||||
@ -49,6 +52,7 @@ import { host } from '@/config';
|
||||
import { search } from '@/scripts/search';
|
||||
import * as os from '@/os';
|
||||
import { sidebarDef } from '@/sidebar';
|
||||
import { getAccounts, addAccount, login } from '@/account';
|
||||
|
||||
export default defineComponent({
|
||||
data() {
|
||||
@ -67,7 +71,7 @@ export default defineComponent({
|
||||
|
||||
computed: {
|
||||
menu(): string[] {
|
||||
return this.$store.state.deviceUser.menu;
|
||||
return this.$store.state.menu;
|
||||
},
|
||||
|
||||
otherNavItemIndicated(): boolean {
|
||||
@ -84,7 +88,7 @@ export default defineComponent({
|
||||
this.showing = false;
|
||||
},
|
||||
|
||||
'$store.state.device.sidebarDisplay'() {
|
||||
'$store.reactiveState.sidebarDisplay.value'() {
|
||||
this.calcViewState();
|
||||
},
|
||||
|
||||
@ -108,19 +112,23 @@ export default defineComponent({
|
||||
|
||||
methods: {
|
||||
calcViewState() {
|
||||
this.iconOnly = (window.innerWidth <= 1279) || (this.$store.state.device.sidebarDisplay === 'icon');
|
||||
this.hidden = (window.innerWidth <= 650) || (this.$store.state.device.sidebarDisplay === 'hide');
|
||||
this.iconOnly = (window.innerWidth <= 1279) || (this.$store.state.sidebarDisplay === 'icon');
|
||||
this.hidden = (window.innerWidth <= 650);
|
||||
},
|
||||
|
||||
show() {
|
||||
this.showing = true;
|
||||
},
|
||||
|
||||
post() {
|
||||
os.post();
|
||||
},
|
||||
|
||||
search() {
|
||||
if (this.searching) return;
|
||||
|
||||
os.dialog({
|
||||
title: this.$t('search'),
|
||||
title: this.$ts.search,
|
||||
input: true
|
||||
}).then(async ({ canceled, result: query }) => {
|
||||
if (canceled || query == null || query === '') return;
|
||||
@ -133,7 +141,8 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
async openAccountMenu(ev) {
|
||||
const accounts = (await os.api('users/show', { userIds: this.$store.state.device.accounts.map(x => x.id) })).filter(x => x.id !== this.$store.state.i.id);
|
||||
const storedAccounts = getAccounts();
|
||||
const accounts = (await os.api('users/show', { userIds: storedAccounts.map(x => x.id) })).filter(x => x.id !== this.$i.id);
|
||||
|
||||
const accountItems = accounts.map(account => ({
|
||||
type: 'user',
|
||||
@ -143,18 +152,18 @@ export default defineComponent({
|
||||
|
||||
os.modalMenu([...[{
|
||||
type: 'link',
|
||||
text: this.$t('profile'),
|
||||
to: `/@${ this.$store.state.i.username }`,
|
||||
avatar: this.$store.state.i,
|
||||
text: this.$ts.profile,
|
||||
to: `/@${ this.$i.username }`,
|
||||
avatar: this.$i,
|
||||
}, null, ...accountItems, {
|
||||
icon: faPlus,
|
||||
text: this.$t('addAcount'),
|
||||
text: this.$ts.addAcount,
|
||||
action: () => {
|
||||
os.modalMenu([{
|
||||
text: this.$t('existingAcount'),
|
||||
text: this.$ts.existingAcount,
|
||||
action: () => { this.addAcount(); },
|
||||
}, {
|
||||
text: this.$t('createAccount'),
|
||||
text: this.$ts.createAccount,
|
||||
action: () => { this.createAccount(); },
|
||||
}], ev.currentTarget || ev.target);
|
||||
},
|
||||
@ -166,57 +175,57 @@ export default defineComponent({
|
||||
oepnInstanceMenu(ev) {
|
||||
os.modalMenu([{
|
||||
type: 'link',
|
||||
text: this.$t('dashboard'),
|
||||
text: this.$ts.dashboard,
|
||||
to: '/instance',
|
||||
icon: faTachometerAlt,
|
||||
}, null, this.$store.state.i.isAdmin ? {
|
||||
}, null, this.$i.isAdmin ? {
|
||||
type: 'link',
|
||||
text: this.$t('settings'),
|
||||
text: this.$ts.settings,
|
||||
to: '/instance/settings',
|
||||
icon: faCog,
|
||||
} : undefined, {
|
||||
type: 'link',
|
||||
text: this.$t('customEmojis'),
|
||||
text: this.$ts.customEmojis,
|
||||
to: '/instance/emojis',
|
||||
icon: faLaugh,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('users'),
|
||||
text: this.$ts.users,
|
||||
to: '/instance/users',
|
||||
icon: faUsers,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('files'),
|
||||
text: this.$ts.files,
|
||||
to: '/instance/files',
|
||||
icon: faCloud,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('jobQueue'),
|
||||
text: this.$ts.jobQueue,
|
||||
to: '/instance/queue',
|
||||
icon: faExchangeAlt,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('federation'),
|
||||
text: this.$ts.federation,
|
||||
to: '/instance/federation',
|
||||
icon: faGlobe,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('relays'),
|
||||
text: this.$ts.relays,
|
||||
to: '/instance/relays',
|
||||
icon: faProjectDiagram,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('announcements'),
|
||||
text: this.$ts.announcements,
|
||||
to: '/instance/announcements',
|
||||
icon: faBroadcastTower,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('abuseReports'),
|
||||
text: this.$ts.abuseReports,
|
||||
to: '/instance/abuses',
|
||||
icon: faExclamationCircle,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('logs'),
|
||||
text: this.$ts.logs,
|
||||
to: '/instance/logs',
|
||||
icon: faStream,
|
||||
}], ev.currentTarget || ev.target);
|
||||
@ -230,7 +239,7 @@ export default defineComponent({
|
||||
addAcount() {
|
||||
os.popup(import('./signin-dialog.vue'), {}, {
|
||||
done: res => {
|
||||
this.$store.dispatch('addAcount', res);
|
||||
addAccount(res.id, res.i);
|
||||
os.success();
|
||||
},
|
||||
}, 'closed');
|
||||
@ -239,30 +248,20 @@ export default defineComponent({
|
||||
createAccount() {
|
||||
os.popup(import('./signup-dialog.vue'), {}, {
|
||||
done: res => {
|
||||
this.$store.dispatch('addAcount', res);
|
||||
addAccount(res.id, res.i);
|
||||
this.switchAccountWithToken(res.i);
|
||||
},
|
||||
}, 'closed');
|
||||
},
|
||||
|
||||
switchAccount(account: any) {
|
||||
const token = this.$store.state.device.accounts.find((x: any) => x.id === account.id).token;
|
||||
const storedAccounts = getAccounts();
|
||||
const token = storedAccounts.find(x => x.id === account.id).token;
|
||||
this.switchAccountWithToken(token);
|
||||
},
|
||||
|
||||
switchAccountWithToken(token: string) {
|
||||
os.waiting();
|
||||
|
||||
os.api('i', {}, token).then((i: any) => {
|
||||
this.$store.dispatch('switchAccount', {
|
||||
...i,
|
||||
token: token
|
||||
}).then(() => {
|
||||
this.$nextTick(() => {
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
});
|
||||
login(token);
|
||||
},
|
||||
}
|
||||
});
|
||||
@ -294,7 +293,7 @@ export default defineComponent({
|
||||
.mvcprjjd {
|
||||
$ui-font-size: 1em; // TODO: どこかに集約したい
|
||||
$nav-width: 250px;
|
||||
$nav-icon-only-width: 80px;
|
||||
$nav-icon-only-width: 86px;
|
||||
|
||||
> .nav-back {
|
||||
z-index: 1001;
|
||||
@ -360,7 +359,6 @@ export default defineComponent({
|
||||
z-index: 1001;
|
||||
|
||||
> div {
|
||||
> .index,
|
||||
> .notifications {
|
||||
display: none;
|
||||
}
|
||||
@ -382,7 +380,6 @@ export default defineComponent({
|
||||
box-sizing: border-box;
|
||||
overflow: auto;
|
||||
background: var(--navBg);
|
||||
border-right: solid 1px var(--divider);
|
||||
|
||||
> .divider {
|
||||
margin: 16px 0;
|
||||
|
@ -5,7 +5,7 @@
|
||||
@close="$refs.dialog.close()"
|
||||
@closed="$emit('closed')"
|
||||
>
|
||||
<template #header>{{ $t('login') }}</template>
|
||||
<template #header>{{ $ts.login }}</template>
|
||||
|
||||
<MkSignin :auto-set="autoSet" @login="onLogin"/>
|
||||
</XModalWindow>
|
||||
|
@ -4,37 +4,37 @@
|
||||
<div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar"></div>
|
||||
<div class="normal-signin" v-if="!totpLogin">
|
||||
<MkInput v-model:value="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @update:value="onUsernameChange">
|
||||
<span>{{ $t('username') }}</span>
|
||||
<span>{{ $ts.username }}</span>
|
||||
<template #prefix>@</template>
|
||||
<template #suffix>@{{ host }}</template>
|
||||
</MkInput>
|
||||
<MkInput v-model:value="password" type="password" :with-password-toggle="true" v-if="!user || user && !user.usePasswordLessLogin" required>
|
||||
<span>{{ $t('password') }}</span>
|
||||
<span>{{ $ts.password }}</span>
|
||||
<template #prefix><Fa :icon="faLock"/></template>
|
||||
</MkInput>
|
||||
<MkButton type="submit" primary :disabled="signing" style="margin: 0 auto;">{{ signing ? $t('loggingIn') : $t('login') }}</MkButton>
|
||||
<MkButton type="submit" primary :disabled="signing" style="margin: 0 auto;">{{ signing ? $ts.loggingIn : $ts.login }}</MkButton>
|
||||
</div>
|
||||
<div class="2fa-signin" v-if="totpLogin" :class="{ securityKeys: user && user.securityKeys }">
|
||||
<div v-if="user && user.securityKeys" class="twofa-group tap-group">
|
||||
<p>{{ $t('tapSecurityKey') }}</p>
|
||||
<p>{{ $ts.tapSecurityKey }}</p>
|
||||
<MkButton @click="queryKey" v-if="!queryingKey">
|
||||
{{ $t('retry') }}
|
||||
{{ $ts.retry }}
|
||||
</MkButton>
|
||||
</div>
|
||||
<div class="or-hr" v-if="user && user.securityKeys">
|
||||
<p class="or-msg">{{ $t('or') }}</p>
|
||||
<p class="or-msg">{{ $ts.or }}</p>
|
||||
</div>
|
||||
<div class="twofa-group totp-group">
|
||||
<p style="margin-bottom:0;">{{ $t('twoStepAuthentication') }}</p>
|
||||
<p style="margin-bottom:0;">{{ $ts.twoStepAuthentication }}</p>
|
||||
<MkInput v-model:value="password" type="password" :with-password-toggle="true" v-if="user && user.usePasswordLessLogin" required>
|
||||
<span>{{ $t('password') }}</span>
|
||||
<span>{{ $ts.password }}</span>
|
||||
<template #prefix><Fa :icon="faLock"/></template>
|
||||
</MkInput>
|
||||
<MkInput v-model:value="token" type="text" pattern="^[0-9]{6}$" autocomplete="off" spellcheck="false" required>
|
||||
<span>{{ $t('token') }}</span>
|
||||
<span>{{ $ts.token }}</span>
|
||||
<template #prefix><Fa :icon="faGavel"/></template>
|
||||
</MkInput>
|
||||
<MkButton type="submit" :disabled="signing" primary style="margin: 0 auto;">{{ signing ? $t('loggingIn') : $t('login') }}</MkButton>
|
||||
<MkButton type="submit" :disabled="signing" primary style="margin: 0 auto;">{{ signing ? $ts.loggingIn : $ts.login }}</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -56,6 +56,7 @@ import MkInput from './ui/input.vue';
|
||||
import { apiUrl, host } from '@/config';
|
||||
import { byteify, hexify } from '@/scripts/2fa';
|
||||
import * as os from '@/os';
|
||||
import { login } from '@/account';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
@ -97,7 +98,7 @@ export default defineComponent({
|
||||
|
||||
computed: {
|
||||
meta() {
|
||||
return this.$store.state.instance.meta;
|
||||
return this.$instance;
|
||||
},
|
||||
},
|
||||
|
||||
@ -114,8 +115,7 @@ export default defineComponent({
|
||||
|
||||
onLogin(res) {
|
||||
if (this.autoSet) {
|
||||
localStorage.setItem('i', res.i);
|
||||
location.reload();
|
||||
login(res.i);
|
||||
}
|
||||
},
|
||||
|
||||
@ -153,7 +153,7 @@ export default defineComponent({
|
||||
if (err === null) return;
|
||||
os.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('signinFailed')
|
||||
text: this.$ts.signinFailed
|
||||
});
|
||||
this.signing = false;
|
||||
});
|
||||
@ -174,7 +174,7 @@ export default defineComponent({
|
||||
}).catch(() => {
|
||||
os.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('signinFailed')
|
||||
text: this.$ts.signinFailed
|
||||
});
|
||||
this.challengeData = null;
|
||||
this.totpLogin = false;
|
||||
@ -195,7 +195,7 @@ export default defineComponent({
|
||||
}).catch(() => {
|
||||
os.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('loginFailed')
|
||||
text: this.$ts.loginFailed
|
||||
});
|
||||
this.signing = false;
|
||||
});
|
||||
|
@ -5,7 +5,7 @@
|
||||
@close="$refs.dialog.close()"
|
||||
@closed="$emit('closed')"
|
||||
>
|
||||
<template #header>{{ $t('signup') }}</template>
|
||||
<template #header>{{ $ts.signup }}</template>
|
||||
|
||||
<div class="_section">
|
||||
<XSignup :auto-set="autoSet" @signup="onSignup"/>
|
||||
|
@ -2,49 +2,51 @@
|
||||
<form class="mk-signup" @submit.prevent="onSubmit" :autocomplete="Math.random()">
|
||||
<template v-if="meta">
|
||||
<MkInput v-if="meta.disableRegistration" v-model:value="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required>
|
||||
<span>{{ $t('invitationCode') }}</span>
|
||||
<span>{{ $ts.invitationCode }}</span>
|
||||
<template #prefix><Fa :icon="faKey"/></template>
|
||||
</MkInput>
|
||||
<MkInput v-model:value="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @update:value="onChangeUsername">
|
||||
<span>{{ $t('username') }}</span>
|
||||
<span>{{ $ts.username }}</span>
|
||||
<template #prefix>@</template>
|
||||
<template #suffix>@{{ host }}</template>
|
||||
<template #desc>
|
||||
<span v-if="usernameState == 'wait'" style="color:#999"><Fa :icon="faSpinner" pulse fixed-width/> {{ $t('checking') }}</span>
|
||||
<span v-if="usernameState == 'ok'" style="color:#3CB7B5"><Fa :icon="faCheck" fixed-width/> {{ $t('available') }}</span>
|
||||
<span v-if="usernameState == 'unavailable'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $t('unavailable') }}</span>
|
||||
<span v-if="usernameState == 'error'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $t('error') }}</span>
|
||||
<span v-if="usernameState == 'invalid-format'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $t('usernameInvalidFormat') }}</span>
|
||||
<span v-if="usernameState == 'min-range'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $t('tooShort') }}</span>
|
||||
<span v-if="usernameState == 'max-range'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $t('tooLong') }}</span>
|
||||
<span v-if="usernameState == 'wait'" style="color:#999"><Fa :icon="faSpinner" pulse fixed-width/> {{ $ts.checking }}</span>
|
||||
<span v-if="usernameState == 'ok'" style="color:#3CB7B5"><Fa :icon="faCheck" fixed-width/> {{ $ts.available }}</span>
|
||||
<span v-if="usernameState == 'unavailable'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $ts.unavailable }}</span>
|
||||
<span v-if="usernameState == 'error'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $ts.error }}</span>
|
||||
<span v-if="usernameState == 'invalid-format'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $ts.usernameInvalidFormat }}</span>
|
||||
<span v-if="usernameState == 'min-range'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $ts.tooShort }}</span>
|
||||
<span v-if="usernameState == 'max-range'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $ts.tooLong }}</span>
|
||||
</template>
|
||||
</MkInput>
|
||||
<MkInput v-model:value="password" type="password" :autocomplete="Math.random()" required @update:value="onChangePassword">
|
||||
<span>{{ $t('password') }}</span>
|
||||
<span>{{ $ts.password }}</span>
|
||||
<template #prefix><Fa :icon="faLock"/></template>
|
||||
<template #desc>
|
||||
<p v-if="passwordStrength == 'low'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $t('weakPassword') }}</p>
|
||||
<p v-if="passwordStrength == 'medium'" style="color:#3CB7B5"><Fa :icon="faCheck" fixed-width/> {{ $t('normalPassword') }}</p>
|
||||
<p v-if="passwordStrength == 'high'" style="color:#3CB7B5"><Fa :icon="faCheck" fixed-width/> {{ $t('strongPassword') }}</p>
|
||||
<p v-if="passwordStrength == 'low'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $ts.weakPassword }}</p>
|
||||
<p v-if="passwordStrength == 'medium'" style="color:#3CB7B5"><Fa :icon="faCheck" fixed-width/> {{ $ts.normalPassword }}</p>
|
||||
<p v-if="passwordStrength == 'high'" style="color:#3CB7B5"><Fa :icon="faCheck" fixed-width/> {{ $ts.strongPassword }}</p>
|
||||
</template>
|
||||
</MkInput>
|
||||
<MkInput v-model:value="retypedPassword" type="password" :autocomplete="Math.random()" required @update:value="onChangePasswordRetype">
|
||||
<span>{{ $t('password') }} ({{ $t('retype') }})</span>
|
||||
<span>{{ $ts.password }} ({{ $ts.retype }})</span>
|
||||
<template #prefix><Fa :icon="faLock"/></template>
|
||||
<template #desc>
|
||||
<p v-if="passwordRetypeState == 'match'" style="color:#3CB7B5"><Fa :icon="faCheck" fixed-width/> {{ $t('passwordMatched') }}</p>
|
||||
<p v-if="passwordRetypeState == 'not-match'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $t('passwordNotMatched') }}</p>
|
||||
<p v-if="passwordRetypeState == 'match'" style="color:#3CB7B5"><Fa :icon="faCheck" fixed-width/> {{ $ts.passwordMatched }}</p>
|
||||
<p v-if="passwordRetypeState == 'not-match'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $ts.passwordNotMatched }}</p>
|
||||
</template>
|
||||
</MkInput>
|
||||
<label v-if="meta.tosUrl" class="tou">
|
||||
<input type="checkbox" v-model="ToSAgreement">
|
||||
<i18n-t keypath="agreeTo">
|
||||
<a :href="meta.tosUrl" class="_link" target="_blank">{{ $t('tos') }}</a>
|
||||
</i18n-t>
|
||||
<I18n :src="$ts.agreeTo">
|
||||
<template #0>
|
||||
<a :href="meta.tosUrl" class="_link" target="_blank">{{ $ts.tos }}</a>
|
||||
</template>
|
||||
</I18n>
|
||||
</label>
|
||||
<captcha v-if="meta.enableHcaptcha" class="captcha" provider="hcaptcha" ref="hcaptcha" v-model:value="hCaptchaResponse" :sitekey="meta.hcaptchaSiteKey"/>
|
||||
<captcha v-if="meta.enableRecaptcha" class="captcha" provider="grecaptcha" ref="recaptcha" v-model:value="reCaptchaResponse" :sitekey="meta.recaptchaSiteKey"/>
|
||||
<MkButton type="submit" :disabled="shouldDisableSubmitting" primary>{{ $t('start') }}</MkButton>
|
||||
<MkButton type="submit" :disabled="shouldDisableSubmitting" primary>{{ $ts.start }}</MkButton>
|
||||
</template>
|
||||
</form>
|
||||
</template>
|
||||
@ -59,6 +61,7 @@ import MkButton from './ui/button.vue';
|
||||
import MkInput from './ui/input.vue';
|
||||
import MkSwitch from './ui/switch.vue';
|
||||
import * as os from '@/os';
|
||||
import { login } from '@/account';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
@ -99,7 +102,7 @@ export default defineComponent({
|
||||
|
||||
computed: {
|
||||
meta() {
|
||||
return this.$store.state.instance.meta;
|
||||
return this.$instance;
|
||||
},
|
||||
|
||||
shouldDisableSubmitting(): boolean {
|
||||
@ -184,8 +187,7 @@ export default defineComponent({
|
||||
this.$emit('signup', res);
|
||||
|
||||
if (this.autoSet) {
|
||||
localStorage.setItem('i', res.i);
|
||||
location.reload();
|
||||
login(res.i);
|
||||
}
|
||||
});
|
||||
}).catch(() => {
|
||||
@ -195,7 +197,7 @@ export default defineComponent({
|
||||
|
||||
os.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('somethingHappened')
|
||||
text: this.$ts.somethingHappened
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="wrmlmaau">
|
||||
<div class="body">
|
||||
<span v-if="note.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
|
||||
<span v-if="note.deletedAt" style="opacity: 0.5">({{ $t('deleted') }})</span>
|
||||
<span v-if="note.isHidden" style="opacity: 0.5">({{ $ts.private }})</span>
|
||||
<span v-if="note.deletedAt" style="opacity: 0.5">({{ $ts.deleted }})</span>
|
||||
<MkA class="reply" v-if="note.replyId" :to="`/notes/${note.replyId}`"><Fa :icon="faReply"/></MkA>
|
||||
<Mfm v-if="note.text" :text="note.text" :author="note.user" :i="$store.state.i" :custom-emojis="note.emojis"/>
|
||||
<Mfm v-if="note.text" :text="note.text" :author="note.user" :i="$i" :custom-emojis="note.emojis"/>
|
||||
<MkA class="rp" v-if="note.renoteId" :to="`/notes/${note.renoteId}`">RN: ...</MkA>
|
||||
</div>
|
||||
<details v-if="note.files.length > 0">
|
||||
@ -12,7 +12,7 @@
|
||||
<XMediaList :media-list="note.files"/>
|
||||
</details>
|
||||
<details v-if="note.poll">
|
||||
<summary>{{ $t('poll') }}</summary>
|
||||
<summary>{{ $ts.poll }}</summary>
|
||||
<XPoll :note="note"/>
|
||||
</details>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<XNotes ref="tl" :pagination="pagination" @before="$emit('before')" @after="e => $emit('after', e)" @queue="$emit('queue', $event)"/>
|
||||
<XNotes :class="{ _noGap_: !$store.state.showGapBetweenNotesInTimeline }" ref="tl" :pagination="pagination" @before="$emit('before')" @after="e => $emit('after', e)" @queue="$emit('queue', $event)"/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@ -51,9 +51,9 @@ export default defineComponent({
|
||||
connection2: null,
|
||||
pagination: null,
|
||||
baseQuery: {
|
||||
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
|
||||
includeLocalRenotes: this.$store.state.settings.showLocalRenotes
|
||||
includeMyRenotes: this.$store.state.showMyRenotes,
|
||||
includeRenotedMyNotes: this.$store.state.showRenotedMyNotes,
|
||||
includeLocalRenotes: this.$store.state.showLocalRenotes
|
||||
},
|
||||
query: {},
|
||||
};
|
||||
@ -66,7 +66,7 @@ export default defineComponent({
|
||||
this.$emit('note');
|
||||
|
||||
if (this.sound) {
|
||||
sound.play(note.userId === this.$store.state.i.id ? 'noteMy' : 'note');
|
||||
sound.play(note.userId === this.$i.id ? 'noteMy' : 'note');
|
||||
}
|
||||
};
|
||||
|
||||
@ -115,6 +115,22 @@ export default defineComponent({
|
||||
endpoint = 'notes/global-timeline';
|
||||
this.connection = os.stream.useSharedConnection('globalTimeline');
|
||||
this.connection.on('note', prepend);
|
||||
} else if (this.src == 'mentions') {
|
||||
endpoint = 'notes/mentions';
|
||||
this.connection = os.stream.useSharedConnection('main');
|
||||
this.connection.on('mention', prepend);
|
||||
} else if (this.src == 'directs') {
|
||||
endpoint = 'notes/mentions';
|
||||
this.query = {
|
||||
visibility: 'specified'
|
||||
};
|
||||
const onNote = note => {
|
||||
if (note.visibility == 'specified') {
|
||||
prepend(note);
|
||||
}
|
||||
};
|
||||
this.connection = os.stream.useSharedConnection('main');
|
||||
this.connection.on('mention', onNote);
|
||||
} else if (this.src == 'list') {
|
||||
endpoint = 'notes/user-list-timeline';
|
||||
this.query = {
|
||||
|
@ -9,17 +9,17 @@
|
||||
@closed="$emit('closed')"
|
||||
@ok="ok()"
|
||||
>
|
||||
<template #header>{{ title || $t('generateAccessToken') }}</template>
|
||||
<template #header>{{ title || $ts.generateAccessToken }}</template>
|
||||
<div v-if="information" class="_section">
|
||||
<MkInfo warn>{{ information }}</MkInfo>
|
||||
</div>
|
||||
<div class="_section">
|
||||
<MkInput v-model:value="name">{{ $t('name') }}</MkInput>
|
||||
<MkInput v-model:value="name">{{ $ts.name }}</MkInput>
|
||||
</div>
|
||||
<div class="_section">
|
||||
<div style="margin-bottom: 16px;"><b>{{ $t('permission') }}</b></div>
|
||||
<MkButton inline @click="disableAll">{{ $t('disableAll') }}</MkButton>
|
||||
<MkButton inline @click="enableAll">{{ $t('enableAll') }}</MkButton>
|
||||
<div style="margin-bottom: 16px;"><b>{{ $ts.permission }}</b></div>
|
||||
<MkButton inline @click="disableAll">{{ $ts.disableAll }}</MkButton>
|
||||
<MkButton inline @click="enableAll">{{ $ts.enableAll }}</MkButton>
|
||||
<MkSwitch v-for="kind in (initialPermissions || kinds)" :key="kind" v-model:value="permissions[kind]">{{ $t(`_permissions.${kind}`) }}</MkSwitch>
|
||||
</div>
|
||||
</XModalWindow>
|
||||
|
@ -123,7 +123,7 @@ export default defineComponent({
|
||||
box-shadow: none;
|
||||
text-decoration: none;
|
||||
background: var(--buttonBg);
|
||||
border-radius: 6px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
|
||||
&:not(:disabled):hover {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<transition :name="$store.state.device.animation ? 'fade' : ''" appear>
|
||||
<transition :name="$store.state.animation ? 'fade' : ''" appear>
|
||||
<div class="nvlagfpb" @contextmenu.prevent.stop="() => {}">
|
||||
<MkMenu :items="items" @close="$emit('closed')" class="_popup _shadow" :align="'left'"/>
|
||||
</div>
|
||||
|
@ -48,7 +48,7 @@
|
||||
</datalist>
|
||||
<div class="suffix" ref="suffixEl"><slot name="suffix"></slot></div>
|
||||
</div>
|
||||
<button class="save _textButton" v-if="save && changed" @click="() => { changed = false; save(); }">{{ $t('save') }}</button>
|
||||
<button class="save _textButton" v-if="save && changed" @click="() => { changed = false; save(); }">{{ $ts.save }}</button>
|
||||
<div class="desc _caption"><slot name="desc"></slot></div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -35,7 +35,7 @@
|
||||
</button>
|
||||
</template>
|
||||
<span v-if="_items.length === 0" class="none item">
|
||||
<span>{{ $t('none') }}</span>
|
||||
<span>{{ $ts.none }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="mk-modal" v-hotkey.global="keymap" :style="{ pointerEvents: showing ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
|
||||
<transition :name="$store.state.device.animation ? 'modal-bg' : ''" appear>
|
||||
<transition :name="$store.state.animation ? 'modal-bg' : ''" appear>
|
||||
<div class="bg _modalBg" v-if="showing" @click="onBgClick"></div>
|
||||
</transition>
|
||||
<div class="content" :class="{ popup, fixed, top: position === 'top' }" @click.self="onBgClick" ref="content">
|
||||
<transition :name="$store.state.device.animation ? popup ? 'modal-popup-content' : 'modal-content' : ''" appear @after-leave="$emit('closed')" @after-enter="childRendered">
|
||||
<transition :name="$store.state.animation ? popup ? 'modal-popup-content' : 'modal-content' : ''" appear @after-leave="$emit('closed')" @after-enter="childRendered">
|
||||
<slot v-if="showing"></slot>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -5,8 +5,8 @@
|
||||
<slot name="empty"></slot>
|
||||
</div>
|
||||
<div class="more" v-show="more" key="_more_">
|
||||
<MkButton class="button" v-appear="$store.state.device.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary>
|
||||
<template v-if="!moreFetching">{{ $t('loadMore') }}</template>
|
||||
<MkButton class="button" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary>
|
||||
<template v-if="!moreFetching">{{ $ts.loadMore }}</template>
|
||||
<template v-if="moreFetching"><MkLoading inline/></template>
|
||||
</MkButton>
|
||||
</div>
|
||||
|
@ -14,7 +14,7 @@
|
||||
@blur="focused = false"
|
||||
></textarea>
|
||||
</div>
|
||||
<button class="save _textButton" v-if="save && changed" @click="() => { changed = false; save(); }">{{ $t('save') }}</button>
|
||||
<button class="save _textButton" v-if="save && changed" @click="() => { changed = false; save(); }">{{ $ts.save }}</button>
|
||||
<div class="desc _caption"><slot name="desc"></slot></div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<transition :name="$store.state.device.animation ? 'window' : ''" appear @after-leave="$emit('closed')">
|
||||
<transition :name="$store.state.animation ? 'window' : ''" appear @after-leave="$emit('closed')">
|
||||
<div class="ebkgocck" v-if="showing">
|
||||
<div class="body _popup _shadow _narrow_" @mousedown="onBodyMousedown" @keydown="onKeydown">
|
||||
<div class="header" @contextmenu.prevent.stop="onContextmenu">
|
||||
@ -401,7 +401,6 @@ export default defineComponent({
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0px 1px var(--divider);
|
||||
user-select: none;
|
||||
height: $height;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user