Merge branch 'develop' into feat/scylladb

This commit is contained in:
Namekuji 2023-09-02 05:07:53 -04:00
commit 494243cba8
No known key found for this signature in database
GPG key ID: 1D62332C07FBA532
449 changed files with 13903 additions and 3319 deletions

3
.gitignore vendored
View file

@ -32,6 +32,9 @@ coverage
# docker dev config
/dev/docker-compose.yml
# ESLint
.eslintcache
# misskey
built
db

View file

@ -1,7 +1,6 @@
{
"recommendations": [
"editorconfig.editorconfig",
"rome.rome",
"vue.volar",
"vue.vscode-typescript-vue-plugin",
"arcanis.vscode-zipfs",
@ -13,6 +12,7 @@
"mrmlnc.vscode-json5",
"esbenp.prettier-vscode",
"redhat.vscode-yaml",
"yoavbls.pretty-ts-errors"
"yoavbls.pretty-ts-errors",
"biomejs.biome"
]
}

12
biome.json Normal file
View file

@ -0,0 +1,12 @@
{
"$schema": "https://biomejs.dev/schemas/1.0.0/schema.json",
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
}
}

View file

@ -61,6 +61,8 @@ services:
# sonic:
# restart: unless-stopped
# image: docker.io/valeriansaliou/sonic:v1.4.0
# logging:
# driver: none
# networks:
# - calcnet
# volumes:

View file

@ -15,7 +15,7 @@ gotIt: "Ho capito!"
cancel: "Annulla"
enterUsername: "Inserisci un nome utente"
renotedBy: "Boost da {user}"
noNotes: "Nessuna nota!"
noNotes: "Nessun post"
noNotifications: "Nessuna notifica"
instance: "Server"
settings: "Impostazioni"
@ -35,10 +35,10 @@ users: "Utenti"
addUser: "Aggiungi utente"
favorite: "Aggiungi ai preferiti"
favorites: "Preferiti"
unfavorite: "Rimuovi nota dai preferiti"
favorited: "Aggiunta ai tuoi preferiti."
unfavorite: "Rimuovi post dai preferiti"
favorited: "Aggiunto ai tuoi preferiti."
alreadyFavorited: "Già tra i tuoi preferiti."
cantFavorite: "Impossibile aggiungere la nota ai preferiti."
cantFavorite: "Impossibile aggiungere il post ai preferiti."
pin: "Fissa sul profilo"
unpin: "Non fissare sul profilo"
copyContent: "Copia il contenuto"
@ -71,7 +71,7 @@ driveFileDeleteConfirm: "Vuoi davvero eliminare il file \"{name}\"? Sarà rimoss
unfollowConfirm: "Vuoi davvero smettere di seguire {name}?"
exportRequested: "Hai richiesto un'esportazione, e potrebbe volerci tempo. Quando
sarà compiuta, il file verrà aggiunto direttamente al Drive."
importRequested: "Hai richiesto un'importazione. Può volerci tempo. "
importRequested: "Hai richiesto un'importazione. Potrebbe impiegare del tempo."
lists: "Liste"
noLists: "Nessuna lista"
note: "Post"
@ -84,10 +84,10 @@ manageLists: "Gestisci liste"
error: "Errore"
somethingHappened: "Si è verificato un problema"
retry: "Riprova"
pageLoadError: "Caricamento pagina non riuscito. "
pageLoadErrorDescription: "Questo viene normalmente causato dalla rete o dalla cache
del browser. Si prega di pulire la cache, o di attendere e riprovare più tardi."
serverIsDead: "Il server non risponde. Si prega di attendere e riprovare più tardi."
pageLoadError: "Errore nel caricamento della pagina."
pageLoadErrorDescription: "Di solito succede per errori di rete o a causa della cache
del browser. Prova a pulire la cache o a riprovare più tardi."
serverIsDead: "Il server non risponde. Attendi e riprova più tardi."
youShouldUpgradeClient: "Per visualizzare la pagina è necessario aggiornare il client
alla nuova versione e ricaricare."
enterListName: "Nome della lista"
@ -122,7 +122,7 @@ markAsSensitive: "Segna come sensibile"
unmarkAsSensitive: "Segna come non sensibile"
enterFileName: "Nome del file"
mute: "Silenzia"
unmute: "Riattiva"
unmute: "Non silenziare"
block: "Blocca"
unblock: "Sblocca"
suspend: "Sospendi"
@ -135,25 +135,25 @@ selectList: "Seleziona una lista"
selectAntenna: "Scegli un'antenna"
selectWidget: "Seleziona widget"
editWidgets: "Modifica i widget"
editWidgetsExit: "Modifica fine"
editWidgetsExit: "Fine modifica"
customEmojis: "Emoji personalizzati"
emoji: "Emoji"
emojis: "Emoji"
emojiName: "Nome dell'emoji"
emojiUrl: "URL dell'emoji"
addEmoji: "Aggiungi un emoji"
settingGuide: "Configurazione suggerita"
settingGuide: "Impostazioni suggerite"
cacheRemoteFiles: "Memorizzazione nella cache dei file remoti"
cacheRemoteFilesDescription: "Disabilitando questa opzione, i file remoti verranno
scaricati direttamente dal loro server. L'opzione permette di risparmiare spazio
ma aumenta il traffico di rete e non verranno generate anteprime."
flagAsBot: "Io sono un robot"
flagAsBot: "Questo account è un bot"
flagAsBotDescription: "Se l'account esegue principalmente operazioni automatiche,
attiva quest'opzione. Quando attivata, opera come un segnalatore per gli altri sviluppatori
allo scopo di prevenire catene dinterazione senza fine con altri bot, e di adeguare
i sistemi interni di Firefish perché trattino questo account come un bot."
flagAsCat: "Io sono un gatto"
flagAsCatDescription: "Abilita l'opzione \"Io sono un gatto\" per l'account."
flagAsCat: "Sei un gatto? 😺"
flagAsCatDescription: "Ti compariranno le orecchie e parlerai come un gatto!"
autoAcceptFollowed: "Accetta in automatico i follow dagli account che segui"
addAccount: "Aggiungi account"
loginFailed: "Accesso non riuscito"
@ -171,17 +171,17 @@ proxyAccountDescription: "Un account proxy è un account che funziona da followe
una lista, le attività di quell'utente potrebbero comunque non essere visualizzate
in locale se nessun altro utente lo segue su questo server, l'account proxy si occuperà
di seguire e acquisire i post."
host: "Server remoto"
host: "Host"
selectUser: "Seleziona utente"
recipient: "Destinatario"
annotation: "Descrizione"
recipient: "Destinatario(i)"
annotation: "Annotazioni"
federation: "Federazione"
instances: "Server"
registeredAt: "Registrato presso"
latestRequestSentAt: "Ultima richiesta inviata"
latestRequestReceivedAt: "Ultima richiesta ricevuta"
latestStatus: "Ultimo stato"
storageUsage: "Volume di dischi"
storageUsage: "Spazio occupato"
charts: "Grafici"
perHour: "All'ora"
perDay: "al giorno"
@ -190,9 +190,9 @@ blockThisInstance: "Blocca questo server"
operations: "Operazioni"
software: "Software"
version: "Versione"
metadata: "Metadato"
monitor: "Monitorare"
jobQueue: "Coda di lavoro"
metadata: "Metadati"
monitor: "Monitor"
jobQueue: "Coda dei job"
cpuAndMemory: "CPU e Memoria"
network: "Rete"
disk: "Disco"
@ -203,7 +203,7 @@ clearQueueConfirmTitle: "Vuoi davvero svuotare la coda?"
clearQueueConfirmText: "I post ancora in coda non verranno più federati. Solitamente,
non è necessario eseguire questa operazione."
clearCachedFiles: "Svuota cache"
clearCachedFilesConfirm: "Vuoi davvero svuotare la cache da tutti i file remoti?"
clearCachedFilesConfirm: "Vuoi davvero svuotare la cache di tutti i file remoti?"
blockedInstances: "Server bloccati"
blockedInstancesDescription: "Elenca gli hostname dei server che vuoi bloccare. Non
potranno più comunicare con il tuo server."
@ -213,7 +213,7 @@ blockedUsers: "Account bloccati"
noUsers: "Nessun utente trovato"
editProfile: "Modifica profilo"
noteDeleteConfirm: "Vuoi eliminare questo post?"
pinLimitExceeded: "Non puoi fissare più post di così"
pinLimitExceeded: "Hai già fissato il massimo possibile di post"
intro: "L'installazione di Firefish è finita! Si prega di creare un account amministratore."
done: "Fine"
processing: "Elaborazione in corso"
@ -221,12 +221,12 @@ preview: "Anteprima"
default: "Predefinito"
noCustomEmojis: "Nessun emoji"
noJobs: "Nessun lavoro"
federating: "Federando"
federating: "Federazione in corso"
blocked: "Bloccato"
suspended: "Sospes@"
suspended: "Sospeso"
all: "Tutti"
subscribing: "Iscrivendo"
publishing: "Pubblicando"
subscribing: "Sottoscrizione in corso"
publishing: "Pubblicazione in corso"
notResponding: "Nessuna risposta"
instanceFollowing: "Seguiti da te su questo server"
instanceFollowers: "Chi ti segue su questo server"
@ -238,8 +238,8 @@ currentPassword: "Password attuale"
newPassword: "Nuova Password"
newPasswordRetype: "Conferma password"
attachFile: "Allega file"
more: "Altri!"
featured: "Tendenze"
more: "Altro!"
featured: "In primo piano"
usernameOrUserId: "Nome utente o ID utente"
noSuchUser: "Nessun utente trovato"
lookup: "Cercare"
@ -249,7 +249,7 @@ remove: "Elimina"
removed: "Il tuo Tweet è stato eliminato"
removeAreYouSure: "Eliminare \"{x}\"?"
deleteAreYouSure: "Eliminare \"{x}\"?"
resetAreYouSure: "Reimposta"
resetAreYouSure: "Vuoi reimpostare?"
saved: "Salvato"
messaging: "Messaggi"
upload: "Carica"
@ -265,8 +265,8 @@ noMoreHistory: "Non c'è più cronologia da visualizzare"
startMessaging: "Nuovo messaggio"
nUsersRead: "Letto da {n} persone"
agreeTo: "Sono d'accordo con {0}"
tos: "Termini di servizio"
start: "Inizia!"
tos: "Termini d'uso"
start: "Inizia"
home: "Home"
remoteUserCaution: "Può darsi che le informazioni siano incomplete perché questo è
un utente remoto."
@ -274,7 +274,7 @@ activity: "Attività"
images: "Immagini"
birthday: "Compleanno"
yearsOld: "{age}Anni"
registeredDate: "Iscrizione a.."
registeredDate: "Iscrizione il"
location: "Posizione"
theme: "Tema"
themeForLightMode: "Tema da utilizzare per il modo chiaro"
@ -285,7 +285,7 @@ lightThemes: "Tema Chiaro"
darkThemes: "Tema Scuro"
syncDeviceDarkMode: "Sincronizza il tema scuro con le impostazioni del dispositivo"
drive: "Drive"
fileName: "Nome dell'allegato"
fileName: "Nome file"
selectFile: "Scelta allegato"
selectFiles: "Scelta allegato"
selectFolder: "Seleziona cartella"
@ -298,25 +298,25 @@ deleteFolder: "Elimina cartella"
addFile: "Allega"
emptyDrive: "Il Drive è vuoto"
emptyFolder: "La cartella è vuota"
unableToDelete: "Eliminazione impossibile"
unableToDelete: "Impossibile rimuovere"
inputNewFileName: "Inserisci nome del nuovo file"
inputNewDescription: "Inserisci una nuova descrizione"
inputNewFolderName: "Inserisci nome della nuova cartella"
circularReferenceFolder: "La cartella di destinazione è una sottocartella della cartella
che vuoi spostare."
hasChildFilesOrFolders: "La cartella non può essere rimossa perché non è vuota"
hasChildFilesOrFolders: "La cartella non può essere rimossa perché non è vuota."
copyUrl: "Copia URL"
rename: "Modifica nome"
avatar: "Foto del profilo"
banner: "Intestazione"
nsfw: "Contenuti sensibili"
whenServerDisconnected: "Quando la connessione col server è persa"
disconnectedFromServer: "Disconness@ dal server"
disconnectedFromServer: "Server disconnesso"
reload: "Ricarica"
doNothing: "Nessun'azione"
reloadConfirm: "Vuoi ricaricare?"
watch: "Osserva"
unwatch: "Smetti di Osserva"
unwatch: "Smetti di osservare"
accept: "Accetta"
reject: "Rifiuta"
normal: "Normale"
@ -324,7 +324,7 @@ instanceName: "Nome del server"
instanceDescription: "Descrizione del server"
maintainerName: "Nome dell'Amministratore"
maintainerEmail: "Indirizzo e-mail dell'Amministratore"
tosUrl: "Termini di servizio URL"
tosUrl: "URL Termini d'uso"
thisYear: "Anno"
thisMonth: "Mese"
today: "Oggi"
@ -333,8 +333,8 @@ monthX: "{month}"
yearX: "{year}"
pages: "Pagine"
integration: "Integrazioni"
connectService: "Connessione"
disconnectService: "Disconnessione "
connectService: "Connetti"
disconnectService: "Disconnetti"
enableLocalTimeline: "Abilita Timeline locale"
enableGlobalTimeline: "Abilita Timeline federata"
disablingTimelinesInfo: "Anche se disabiliti queste timeline, gli amministratori e
@ -342,16 +342,16 @@ disablingTimelinesInfo: "Anche se disabiliti queste timeline, gli amministratori
registration: "Iscriviti"
enableRegistration: "Permettere nuove registrazioni"
invite: "Invita"
driveCapacityPerLocalAccount: "Volume del Drive per utente locale"
driveCapacityPerRemoteAccount: "Volume del Drive per utente remoto"
inMb: "in Megabytes"
iconUrl: "URL di icona (favicon, ecc.)"
bannerUrl: "URL dell'immagine d'intestazione"
driveCapacityPerLocalAccount: "Dimensione Drive per utenti locali"
driveCapacityPerRemoteAccount: "Dimensione Drive per utenti remoti"
inMb: "In megabytes"
iconUrl: "URL icona"
bannerUrl: "URL dell'immagine banner"
backgroundImageUrl: "URL dello sfondo"
basicInfo: "Informazioni fondamentali"
pinnedUsers: "Utenti in evidenza"
pinnedUsersDescription: "Elenca gli/le utenti che vuoi fissare in cima alla pagina
\"Esplora\", un@ per riga."
basicInfo: "Informazioni di base"
pinnedUsers: "Utenti in fissati"
pinnedUsersDescription: "Elenca gli utenti che vuoi fissare in cima alla pagina \"\
Esplora\", uno per riga."
pinnedPages: "Pagine in evidenza"
pinnedPagesDescription: "Specifica il percorso delle pagine che vuoi fissare in cima
alla home page del server. Una pagina per riga."
@ -371,20 +371,20 @@ avoidMultiCaptchaConfirm: "Utilizzare diversi Captcha può causare interferenze.
antennas: "Antenne"
manageAntennas: "Gestore delle antenne"
name: "Nome"
antennaSource: "Fonte dell'antenna"
antennaSource: "Origine dell'antenna"
antennaKeywords: "Parole chiavi da ricevere"
antennaExcludeKeywords: "Parole chiavi da escludere"
antennaKeywordsDescription: "Separare con uno spazio indica la condizione \"E\". Separare
con un'interruzzione riga indica la condizione \"O\"."
antennaKeywordsDescription: "Separare con uno spazio indica la condizione \"AND\"
. Separare con un'interruzione riga indica la condizione \"OR\"."
notifyAntenna: "Notifica i nuovi post"
withFileAntenna: "Solo post con file allegati"
withFileAntenna: "Solo post con allegati"
enableServiceworker: "Abilita ServiceWorker"
antennaUsersDescription: "Inserisci solo un nome utente per riga"
caseSensitive: "Sensibile alla distinzione tra maiuscole e minuscole"
withReplies: "Includere le risposte"
connectedTo: "Stai seguendo questi account"
notesAndReplies: "Post e risposte"
withFiles: "Con file in allegato"
withFiles: "Con file allegati"
silence: "Silenzia"
silenceConfirm: "Vuoi davvero silenziare l'utente?"
unsilence: "Riattiva"
@ -433,7 +433,7 @@ invites: "Inviti"
groupName: "Nome del gruppo"
members: "Membri"
transfer: "Trasferisci"
messagingWithUser: "Iniziare una chat con un altr@ utente"
messagingWithUser: "Chat privata"
messagingWithGroup: "Chattare in gruppo"
title: "Titolo"
text: "Testo"
@ -452,8 +452,8 @@ invitations: "Invita"
invitationCode: "Codice di invito"
checking: "Confermando"
available: "Consigliati"
unavailable: "Il nome utente è già in uso"
usernameInvalidFormat: "Il nome utente può contenere solo lettere, numeri e '_'"
unavailable: "Nome già in uso"
usernameInvalidFormat: "Puoi usare solo lettere maiuscole, minuscole, numeri e '_'"
tooShort: "Troppo breve"
tooLong: "Troppo lungo"
weakPassword: "Password debole"
@ -556,14 +556,14 @@ scratchpadDescription: "Lo Scratchpad offre un ambiente per esperimenti di AiScr
output: "Uscita"
script: "Script"
disablePagesScript: "Disabilita AiScript nelle pagine"
updateRemoteUser: "Aggiornare le informazioni di utente remot@"
updateRemoteUser: "Aggiorna le informazioni dell'utente remoto"
deleteAllFiles: "Elimina tutti i file"
deleteAllFilesConfirm: "Vuoi davvero eliminare tutti i file?"
removeAllFollowing: "Smetti di seguire tutti"
removeAllFollowingDescription: "Smetti di seguire tutti gli account del server {host}.
È utile specialmente se il server non esiste più."
userSuspended: "L'utente è sospes@."
userSilenced: "L'utente è silenziat@."
userSuspended: "L'utente è sospeso."
userSilenced: "L'utente è silenziato."
yourAccountSuspendedTitle: "Questo account è sospeso."
yourAccountSuspendedDescription: "Questo account è stato sospeso a causa di una violazione
dei termini di servizio del server. Contattare l'amministrazione per i dettagli.
@ -906,8 +906,7 @@ _ad:
reduceFrequencyOfThisAd: "Visualizza questa pubblicità meno spesso"
_forgotPassword:
enterEmail: "Inserisci l'indirizzo di posta elettronica che hai registrato nel tuo
profilo. Il collegamento necessario per ripristinare la password verrà inviato
a questo indirizzo."
profilo. Il di link ripristino della password verrà inviato a questo indirizzo."
ifNoEmail: "Se non hai registrato alcun indirizzo e-mail, contatta l'admin del server."
contactAdmin: "Poiché questo server non permette l'uso di indirizzi mail, contatta
l'admin per poter ripristinare la password."
@ -970,7 +969,7 @@ _mfm:
blockCode: "Codice (blocco)"
inlineMath: "Espressione matematica(Immersione)"
blockMath: "Formula matematica (blocco)"
quote: "Cita il nota"
quote: "Citazione"
emoji: "Emoji personalizzati"
search: "Cerca"
flip: "Inverti"
@ -989,8 +988,8 @@ _mfm:
x4: "Estremamente più grande"
x4Description: "Mostra il contenuto estremamente più ingrandito."
blur: "Sfocatura"
blurDescription: "È possibile rendere sfocato il contenuto. Spostando il cursore
su di esso tornerà visibile chiaramente."
blurDescription: "È possibile rendere sfocato il contenuto. Diventerà visibile al
passaggio del puntatore."
font: "Tipo di carattere"
fontDescription: "Puoi scegliere il tipo di carattere per il contenuto."
rainbow: "Arcobaleno"
@ -1123,7 +1122,7 @@ _theme:
header: "Intestazione"
navBg: "Sfondo della barra laterale"
navFg: "Testo della barra laterale"
navHoverFg: "Testo della barra laterale (al passaggio del mouse)"
navHoverFg: "Testo della barra laterale (hover)"
navActive: "Testo della barra laterale (attivo)"
navIndicator: "Indicatore di barra laterale"
link: "Link"
@ -1138,19 +1137,19 @@ _theme:
infoWarnFg: "Testo di avviso"
cwBg: "Sfondo del CW"
cwFg: "Testo del pulsante CW"
cwHoverBg: "Sfondo del pulsante CW (sorvolato)"
cwHoverBg: "Sfondo del pulsante CW (hover)"
toastBg: "Sfondo di notifica a comparsa"
toastFg: "Testo di notifica a comparsa"
buttonBg: "Sfondo del pulsante"
buttonHoverBg: "Sfondo del pulsante (sorvolato)"
buttonHoverBg: "Sfondo del pulsante (hover)"
inputBorder: "Inquadra casella di testo"
listItemHoverBg: "Sfondo della voce di elenco (sorvolato)"
listItemHoverBg: "Sfondo della voce di elenco (hover)"
driveFolderBg: "Sfondo della cartella di disco"
badge: "Distintivo"
messageBg: "Sfondo della chat"
modalBg: Sfondo modale
scrollbarHandle: Barra di scorrimento
scrollbarHandleHover: Barra di scorrimento (Hover)
scrollbarHandleHover: Barra di scorrimento (hover)
accent: Accento
fgHighlighted: Testo evidenziato
accentLighten: Accento (chiaro)
@ -1512,7 +1511,7 @@ _pages:
width: "Larghezza"
height: "Altezza"
id: Canvas ID
note: "Post embedded"
note: "Post integrato"
_note:
id: "Post ID"
idDescription: "In alternativa puoi incollare qui l'URL del post."
@ -1670,7 +1669,7 @@ _pages:
arg2: Valore massimo
strLen: Lunghezza del testo
join: Concatenazione testo
splitStrByLine: Suddividi il testo al fine riga
splitStrByLine: Suddividi su più righe
subtract: Sottrazione
lt: < A è minore di B
gt: '> A è maggiore di B'
@ -1741,7 +1740,7 @@ _notification:
fileUploaded: "File caricato correttamente"
youGotMention: "{name} ti ha menzionato"
youGotReply: "{name} ti ha risposto"
youGotQuote: "{name} ha citato il tuo Nota e ha detto"
youGotQuote: "{name} ti ha citato"
youRenoted: "Boost da {name}"
youGotPoll: "{name} ha votato"
youGotMessagingMessageFromUser: "{name} ti ha mandato un messaggio"
@ -1789,7 +1788,7 @@ _deck:
widgets: "Widget"
notifications: "Notifiche"
tl: "Timeline"
antenna: "Antenne"
antenna: "Antenna"
list: "Liste"
mentions: "Menzioni"
direct: "Messaggi diretti"
@ -2060,7 +2059,7 @@ shuffle: Casuale
subscribePushNotification: Abilita le notifiche push
unsubscribePushNotification: Disabilita le notifiche push
pushNotificationAlreadySubscribed: Le notifiche push sono già abilitate
driveCapOverrideCaption: Imposta la capacità predefinita inserendo il valore 0.
driveCapOverrideCaption: Reimposta la capacità predefinita inserendo il valore 0.
numberOfPageCacheDescription: Aumentare questo numero migliorerà l'esperienza degli
utenti ma aumenterà il carico sul server e l'uso di memoria.
type: Tipo

View file

@ -1,7 +1,7 @@
---
_lang_: "Português"
headlineFirefish: "Uma rede ligada por notas"
introFirefish: "Bem-vindo! Firefish é um serviço de microblogue descentralizado de código aberto.\nCria \"notas\" e partilha o que te ocorre com todos à tua volta. 📡\nCom \"reações\" podes também expressar logo o que sentes às notas de todos. 👍\nExploremos um novo mundo! 🚀"
introFirefish: "Bem-vindo! Firefish é um serviço de microblogue descentralizado de
código aberto, gratuito para sempre! 🚀"
monthAndDay: "{day}/{month}"
search: "Buscar"
notifications: "Notificações"
@ -44,7 +44,8 @@ copyContent: "Copiar conteúdos"
copyLink: "Copiar hiperligação"
delete: "Eliminar"
deleteAndEdit: "Eliminar e editar"
deleteAndEditConfirm: "Tens a certeza que pretendes eliminar esta nota e editá-la? Irás perder todas as suas reações, renotas e respostas."
deleteAndEditConfirm: "Tens a certeza que pretendes eliminar esta nota e editá-la?
Irás perder todas as suas reações, renotas e respostas."
addToList: "Adicionar a lista"
sendMessage: "Enviar uma mensagem"
copyUsername: "Copiar nome de utilizador"
@ -64,9 +65,11 @@ import: "Importar"
export: "Exportar"
files: "Ficheiros"
download: "Descarregar"
driveFileDeleteConfirm: "Tens a certeza que pretendes apagar o ficheiro \"{name}\"? As notas que tenham este ficheiro anexado serão também apagadas."
driveFileDeleteConfirm: "Tens a certeza que pretendes apagar o ficheiro \"{name}\"\
? As notas que tenham este ficheiro anexado serão também apagadas."
unfollowConfirm: "Tens a certeza que queres deixar de seguir {name}?"
exportRequested: "Pediste uma exportação. Este processo pode demorar algum tempo. Será adicionado à tua Drive após a conclusão do processo."
exportRequested: "Pediste uma exportação. Este processo pode demorar algum tempo.
Será adicionado à tua Drive após a conclusão do processo."
importRequested: "Pediste uma importação. Este processo pode demorar algum tempo."
lists: "Listas"
noLists: "Não tens nenhuma lista"
@ -81,9 +84,12 @@ error: "Erro"
somethingHappened: "Ocorreu um erro"
retry: "Tentar novamente"
pageLoadError: "Ocorreu um erro ao carregar a página."
pageLoadErrorDescription: "Isto é normalmente causado por erros de rede ou pela cache do browser. Experimenta limpar a cache e tenta novamente após algum tempo."
serverIsDead: "O servidor não está respondendo. Por favor espere um pouco e tente novamente."
youShouldUpgradeClient: "Para visualizar essa página, por favor recarregue-a para atualizar seu cliente."
pageLoadErrorDescription: "Isto é normalmente causado por erros de rede ou pela cache
do browser. Experimenta limpar a cache e tenta novamente após algum tempo."
serverIsDead: "O servidor não está respondendo. Por favor espere um pouco e tente
novamente."
youShouldUpgradeClient: "Para visualizar essa página, por favor recarregue-a para
atualizar seu cliente."
enterListName: "Insira um nome para a lista"
privacy: "Privacidade"
makeFollowManuallyApprove: "Pedidos de seguimento precisam ser aprovados"
@ -108,7 +114,8 @@ sensitive: "Conteúdo sensível"
add: "Adicionar"
reaction: "Reações"
reactionSetting: "Quais reações a mostrar no selecionador de reações"
reactionSettingDescription2: "Arraste para reordenar, clique para excluir, pressione + para adicionar."
reactionSettingDescription2: "Arraste para reordenar, clique para excluir, pressione
+ para adicionar."
rememberNoteVisibility: "Lembrar das configurações de visibilidade de notas"
attachCancel: "Remover anexo"
markAsSensitive: "Marcar como sensível"
@ -137,13 +144,18 @@ emojiUrl: "URL do Emoji"
addEmoji: "Adicionar um Emoji"
settingGuide: "Guia de configuração"
cacheRemoteFiles: "Memória transitória de arquivos remotos"
cacheRemoteFilesDescription: "Se você desabilitar essa configuração, os arquivos remotos não serão armazenados em memória transitória e serão vinculados diretamente. Economiza o armazenamento do servidor, mas não gera miniaturas, o que aumenta o tráfego."
cacheRemoteFilesDescription: "Se você desabilitar essa configuração, os arquivos remotos
não serão armazenados em memória transitória e serão vinculados diretamente. Economiza
o armazenamento do servidor, mas não gera miniaturas, o que aumenta o tráfego."
flagAsBot: "Marcar conta como robô"
flagAsBotDescription: "Se esta conta for operada por um programa, ative este sinalizador. Quando ativado, serve como um sinalizador para evitar o encadeamento de reações para outros programadores, e o manuseio do sistema do Firefish é adequado para bots."
flagAsBotDescription: "Se esta conta for operada por um programa, ative este sinalizador.
Quando ativado, serve como um sinalizador para evitar o encadeamento de reações
para outros programadores, e o manuseio do sistema do Firefish é adequado para bots."
flagAsCat: "Marcar conta como gato"
flagAsCatDescription: "Ative essa opção para marcar essa conta como gato."
flagShowTimelineReplies: "Mostrar respostas na linha de tempo"
flagShowTimelineRepliesDescription: "Quando ativado, a linha do tempo mostra as respostas às outras notas do utilizador, além da nota do utilizador."
flagShowTimelineRepliesDescription: "Quando ativado, a linha do tempo mostra as respostas
às outras notas do utilizador, além da nota do utilizador."
autoAcceptFollowed: "Aprove automaticamente os seguidores dos seguintes utilizadores"
addAccount: "Adicionar Conta"
loginFailed: "Não consegui logar"
@ -156,7 +168,10 @@ searchWith: "Buscar: {q}"
youHaveNoLists: "Não tem nenhuma lista"
followConfirm: "Tem certeza que quer deixar de seguir {name}?"
proxyAccount: "Conta proxy"
proxyAccountDescription: "Uma conta proxy é uma conta que atua como seguidora remota para utilizadores sob determinadas condições. Por exemplo, quando um utilizador lista um utilizador remoto, a atividade não será entregue à instância, a menos que alguém esteja seguindo o utilizador listado, portanto, a conta proxy deve seguir."
proxyAccountDescription: "Uma conta proxy é uma conta que atua como seguidora remota
para utilizadores sob determinadas condições. Por exemplo, quando um utilizador
lista um utilizador remoto, a atividade não será entregue à instância, a menos que
alguém esteja seguindo o utilizador listado, portanto, a conta proxy deve seguir."
host: "hospedeiro"
selectUser: "Selecionar utilizador"
recipient: "Morada"
@ -186,11 +201,15 @@ instanceInfo: "Informações da instância"
statistics: "Estatisticas"
clearQueue: "Limpar a fila"
clearQueueConfirmTitle: "Quer limpar a fila?"
clearQueueConfirmText: "Postagens não entregues não serão mais entregues. Normalmente você não precisa fazer isso."
clearQueueConfirmText: "Postagens não entregues não serão mais entregues. Normalmente
você não precisa fazer isso."
clearCachedFiles: "Limpar memória transitória"
clearCachedFilesConfirm: "Tem certeza de que deseja excluir todos os arquivos remotos armazenados em memória transitória?"
clearCachedFilesConfirm: "Tem certeza de que deseja excluir todos os arquivos remotos
armazenados em memória transitória?"
blockedInstances: "Instância bloqueada"
blockedInstancesDescription: "Defina os anfitriões das instâncias que deseja bloquear, separados por quebras de linha. Uma instância bloqueada não poderá interagir com esta instância."
blockedInstancesDescription: "Defina os anfitriões das instâncias que deseja bloquear,
separados por quebras de linha. Uma instância bloqueada não poderá interagir com
esta instância."
muteAndBlock: "Silenciar e bloquear"
mutedUsers: "Silenciar utilizador"
blockedUsers: "Utilizadores bloqueados"
@ -238,7 +257,9 @@ saved: "Salvo"
messaging: "Chat"
upload: "Enviando"
keepOriginalUploading: "Manter a imagem original"
keepOriginalUploadingDescription: "Mantenha a versão original ao carregar a imagem. Quando desligado, a imagem para publicação na web será gerada no navegador no momento do upload."
keepOriginalUploadingDescription: "Mantenha a versão original ao carregar a imagem.
Quando desligado, a imagem para publicação na web será gerada no navegador no momento
do upload."
fromDrive: "\nDa unidade"
fromUrl: "Da URL"
uploadFromUrl: "Carregamento de URL"
@ -262,8 +283,8 @@ yearsOld: "{age} anos"
registeredDate: "Data de registro"
location: "Lugar, colocar"
theme: "tema"
themeForLightMode: "Temas usados no modo de luz"
themeForDarkMode: "Temas usados no modo escuro"
themeForLightMode: "Tema a usar no Modo Diurno"
themeForDarkMode: "Temas usados no Modo Noturno"
light: "Claro"
dark: "Escuro"
lightThemes: "Tema claro"
@ -271,7 +292,7 @@ darkThemes: "Tema escuro"
syncDeviceDarkMode: "Sincronize com o modo escuro do dispositivo"
drive: "Unidades"
fileName: "Nome do Ficheiro"
selectFile: "Selecione os arquivos"
selectFile: "Selecione o arquivo"
selectFiles: "Selecione os arquivos"
selectFolder: "Selecionar uma pasta"
selectFolders: "Selecionar uma pasta"
@ -286,8 +307,9 @@ emptyFolder: "A pasta está vazia"
unableToDelete: "Não é possível eliminar"
inputNewFileName: "Por favor, digite um novo nome para a pasta!"
inputNewDescription: "Insira uma nova legenda"
inputNewFolderName: "Por favor, digite um novo nome para a pasta!"
circularReferenceFolder: "A pasta de destino é uma subpasta da pasta que você deseja mover."
inputNewFolderName: "Por favor, digite um novo nome para a pasta"
circularReferenceFolder: "A pasta de destino é uma subpasta da pasta que você deseja
mover."
hasChildFilesOrFolders: "Esta pasta não está vazia e não pode ser excluída."
copyUrl: "Copiar URL"
rename: "Renomear"
@ -321,7 +343,8 @@ connectService: "Conectar"
disconnectService: "Desconectar"
enableLocalTimeline: "Ativar linha do tempo local"
enableGlobalTimeline: "Ativar linha do tempo global"
disablingTimelinesInfo: "Se você desabilitar essas linhas do tempo, administradores e moderadores ainda poderão usá-las por conveniência."
disablingTimelinesInfo: "Se você desabilitar essas linhas do tempo, administradores
e moderadores ainda poderão usá-las por conveniência."
registration: "Registar"
enableRegistration: "Permitir que qualquer pessoa se registre"
invite: "Convidar"
@ -333,9 +356,11 @@ bannerUrl: "URL da imagem do banner"
backgroundImageUrl: "URL da imagem de fundo"
basicInfo: "Informações básicas"
pinnedUsers: "Utilizador fixado"
pinnedUsersDescription: "Descreva os utilizadores que você deseja fixar na página \"Localizar\", etc., separados por quebras de linha."
pinnedUsersDescription: "Descreva os utilizadores que você deseja fixar na página
\"Localizar\", etc., separados por quebras de linha."
pinnedPages: "Página fixada"
pinnedPagesDescription: "Descreva o caminho da página que você deseja fixar na página superior da instância, separada por quebras de linha."
pinnedPagesDescription: "Descreva o caminho da página que você deseja fixar na página
superior da instância, separada por quebras de linha."
pinnedClipId: "ID do clipe a ser fixado"
pinnedNotes: "Post fixado"
hcaptcha: "hCaptcha"
@ -346,18 +371,21 @@ recaptcha: "reCAPTCHA"
enableRecaptcha: "Habilitar reCAPTCHA"
recaptchaSiteKey: "Chave do sítio web"
recaptchaSecretKey: "Chave secreta"
avoidMultiCaptchaConfirm: "O uso de vários captchas pode causar interferência. Deseja desativar outros captchas? Você também pode cancelar e deixar vários captchas ativados."
avoidMultiCaptchaConfirm: "O uso de vários captchas pode causar interferência. Deseja
desativar outros captchas? Você também pode cancelar e deixar vários captchas ativados."
antennas: "Antenas"
manageAntennas: "Gestão de antena"
name: "Nome"
antennaSource: "Origem de entrada"
antennaKeywords: "Palavras-chave recebidas"
antennaExcludeKeywords: "Palavras-chave negativas"
antennaKeywordsDescription: "Se você separá-lo com um espaço, será uma especificação AND, e se você separá-lo com uma quebra de linha, será uma especificação OR."
antennaKeywordsDescription: "Se você separá-lo com um espaço, será uma especificação
AND, e se você separá-lo com uma quebra de linha, será uma especificação OR."
notifyAntenna: "Notificar novas notas"
withFileAntenna: "Apenas notas com arquivos anexados"
enableServiceworker: "Ative as notificações push para o seu navegador"
antennaUsersDescription: "Especificar nomes de utilizador separados por quebras de linha"
antennaUsersDescription: "Especificar nomes de utilizador separados por quebras de
linha"
caseSensitive: "Maiúsculas e minúsculas"
withReplies: "Incluindo resposta"
connectedTo: "Você está conectado à seguinte conta"
@ -433,15 +461,19 @@ showFeaturedNotesInTimeline: "Mostrar notas recomendadas na linha do tempo"
objectStorage: "Armazenamento de objetos"
useObjectStorage: "Usar armazenamento de objetos"
objectStorageBaseUrl: "URL base"
objectStorageBaseUrlDesc: "O URL usado para referência. Se você estiver usando um CDN ou Proxy, seu URL, S3:'https: // <bucket> .s3.amazonaws.com', GCS, etc .:'https://storage.googleapis.com/ <bucket>' ."
objectStorageBaseUrlDesc: "O URL usado para referência. Se você estiver usando um
CDN ou Proxy, seu URL, S3:'https: // <bucket> .s3.amazonaws.com', GCS, etc .:'https://storage.googleapis.com/
<bucket>' ."
objectStorageBucket: "Bucket"
objectStorageBucketDesc: "Especifique o nome do bucket do serviço a ser usado."
objectStoragePrefix: "Prefixo"
objectStoragePrefixDesc: "Ele é armazenado neste diretório de prefixo."
objectStorageEndpoint: "Ponto final"
objectStorageEndpointDesc: "Especifique vazio para S3, caso contrário, especifique o ponto final para cada serviço. Especifique como'<host>'ou'<host>: <port>'."
objectStorageEndpointDesc: "Especifique vazio para S3, caso contrário, especifique
o ponto final para cada serviço. Especifique como'<host>'ou'<host>: <port>'."
objectStorageRegion: "Região"
objectStorageRegionDesc: "Especifique uma região como 'xx-east-1'. Caso seu serviço não tenha o conceito de região, ele deve estar vazio ou 'us-east-1'."
objectStorageRegionDesc: "Especifique uma região como 'xx-east-1'. Caso seu serviço
não tenha o conceito de região, ele deve estar vazio ou 'us-east-1'."
objectStorageUseSSL: "Usar SSL"
objectStorageUseSSLDesc: "Desative-o se não quiser usar https para conexões de API"
objectStorageUseProxy: "Usar proxy"
@ -449,7 +481,8 @@ objectStorageUseProxyDesc: "Se você não usa proxy para conexão de API, desati
objectStorageSetPublicRead: "Definir 'public-read' ao fazer o upload"
serverLogs: "Registro do servidor"
deleteAll: "Apagar Tudo"
showFixedPostForm: "Exibir o formulário de postagem na parte superior da linha do tempo"
showFixedPostForm: "Exibir o formulário de postagem na parte superior da linha do
tempo"
newNoteRecived: "Nova nota recebida"
sounds: "Sons"
listen: "Ouvir"
@ -618,7 +651,8 @@ _pages:
_dailyRannum:
arg1: "Valor mínimo"
arg2: "Valor máximo"
dailyRandomPick: "Escolher aleatoriamente de uma lista (Muda uma vez por dia para cada usuário)"
dailyRandomPick: "Escolher aleatoriamente de uma lista (Muda uma vez por dia
para cada usuário)"
_dailyRandomPick:
arg1: "Listas"
seedRandom: "Aleatório (com semente)"
@ -634,7 +668,8 @@ _pages:
_seedRandomPick:
arg1: "Semente"
arg2: "Listas"
DRPWPM: "Escolher aleatoriamente de uma lista ponderada (Muda uma vez por dia para cada usuário)"
DRPWPM: "Escolher aleatoriamente de uma lista ponderada (Muda uma vez por dia
para cada usuário)"
_DRPWPM:
arg1: "Lista de texto"
pick: "Escolhe a partir da lista"
@ -665,7 +700,8 @@ _pages:
_for:
arg1: "Número de repetições"
arg2: "Ação"
typeError: "Espaço {slot} aceita valores de tipo \"{expect}\", mas o valor dado é do tipo \"{actual}\"!"
typeError: "Espaço {slot} aceita valores de tipo \"{expect}\", mas o valor dado
é do tipo \"{actual}\"!"
thereIsEmptySlot: "O espaço {slot} está vazio!"
types:
string: "Texto"
@ -730,3 +766,5 @@ _deck:
list: "Listas"
mentions: "Menções"
direct: "Notas diretas"
editNote: Editar post
edited: Editado a {date} às {time}

View file

@ -1,16 +1,16 @@
{
"name": "firefish",
"version": "1.0.5-dev7",
"version": "1.0.5-dev8",
"codename": "aqua",
"repository": {
"type": "git",
"url": "https://git.joinfirefish.org/firefish/firefish.git"
},
"packageManager": "pnpm@8.7.0",
"packageManager": "pnpm@8.7.1",
"private": true,
"scripts": {
"rebuild": "pnpm run clean && pnpm node ./scripts/build-greet.js && pnpm -r --parallel run build && pnpm run gulp",
"build": "pnpm node ./scripts/build-greet.js && pnpm -r --parallel run build && pnpm run gulp",
"rebuild": "pnpm run clean && ./scripts/build-greet.sh && pnpm -r --parallel run build && pnpm run gulp",
"build": "./scripts/build-greet.sh && pnpm -r --parallel run build && pnpm run gulp",
"start": "pnpm --filter backend run start",
"start:test": "pnpm --filter backend run start:test",
"init": "pnpm run migrate",
@ -40,18 +40,19 @@
"chokidar": "^3.3.1"
},
"dependencies": {
"@bull-board/api": "5.7.2",
"@bull-board/ui": "5.7.2",
"@bull-board/api": "5.8.0",
"@bull-board/ui": "5.8.0",
"@napi-rs/cli": "^2.16.2",
"@tensorflow/tfjs": "^3.21.0",
"@tensorflow/tfjs": "^4.10.0",
"js-yaml": "4.1.0",
"seedrandom": "^3.0.5"
},
"devDependencies": {
"@biomejs/biome": "1.0.0",
"@types/gulp": "4.0.13",
"@types/gulp-rename": "2.0.2",
"@types/node": "20.4.9",
"chalk": "4.1.2",
"@types/node": "20.5.8",
"add": "2.0.6",
"cross-env": "7.0.3",
"cypress": "10.11.0",
"execa": "5.1.1",
@ -61,8 +62,8 @@
"gulp-replace": "1.1.4",
"gulp-terser": "2.1.0",
"install-peers": "^1.0.4",
"rome": "^12.1.3",
"pnpm": "8.7.1",
"start-server-and-test": "1.15.2",
"typescript": "5.1.6"
"typescript": "5.2.2"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8 KiB

View file

@ -44,8 +44,8 @@
"test": "pnpm run cargo:test && pnpm run build:napi && ava",
"universal": "napi universal",
"version": "napi version",
"format": "cargo fmt --all",
"lint": "cargo clippy --fix",
"format": "cargo fmt --all -- --check",
"lint": "cargo clippy --fix --allow-dirty --allow-staged && cargo fmt --all -- --check",
"cargo:test": "pnpm run cargo:unit && pnpm run cargo:integration",
"cargo:unit": "cargo test unit_test && cargo test -F napi unit_test",
"cargo:integration": "cargo test -F noarray int_test -- --test-threads=1"

File diff suppressed because one or more lines are too long

View file

@ -17,19 +17,19 @@
"build": "pnpm swc src -d built -D",
"build:debug": "pnpm swc src -d built -s -D",
"watch": "pnpm swc src -d built -D -w",
"lint": "pnpm rome check --apply *",
"lint": "pnpm biome check --apply **/*.ts ; pnpm run format",
"mocha": "cross-env NODE_ENV=test TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha",
"test": "pnpm run mocha",
"format": "pnpm rome format * --write"
"format": "pnpm biome format * --write"
},
"optionalDependencies": {
"@swc/core-android-arm64": "1.3.11",
"@tensorflow/tfjs-node": "3.21.1"
},
"dependencies": {
"@bull-board/api": "5.7.2",
"@bull-board/koa": "5.7.2",
"@bull-board/ui": "5.7.2",
"@bull-board/api": "5.8.0",
"@bull-board/koa": "5.8.0",
"@bull-board/ui": "5.8.0",
"@discordapp/twemoji": "14.1.2",
"@elastic/elasticsearch": "7.17.0",
"@koa/cors": "3.4.3",
@ -42,18 +42,17 @@
"@tensorflow/tfjs": "^4.2.0",
"adm-zip": "^0.5.10",
"ajv": "8.12.0",
"archiver": "5.3.1",
"argon2": "^0.30.3",
"archiver": "6.0.0",
"argon2": "^0.31.1",
"autolinker": "4.0.0",
"autwh": "0.1.0",
"aws-sdk": "2.1413.0",
"axios": "^1.4.0",
"bcryptjs": "2.4.3",
"blurhash": "2.0.5",
"bull": "4.11.2",
"cassandra-driver": "4.6.4",
"bull": "4.11.3",
"cacheable-lookup": "TheEssem/cacheable-lookup",
"cbor": "8.1.0",
"chalk": "5.3.0",
"chalk-template": "0.4.0",
"chokidar": "^3.5.3",
@ -65,19 +64,19 @@
"deep-email-validator": "0.1.21",
"escape-regexp": "0.0.1",
"feed": "4.2.2",
"file-type": "17.1.6",
"file-type": "18.5.0",
"firefish-js": "workspace:*",
"fluent-ffmpeg": "2.1.2",
"got": "12.5.3",
"got": "13.0.0",
"gunzip-maybe": "^1.4.2",
"hpagent": "0.1.2",
"hpagent": "1.2.0",
"ioredis": "5.3.2",
"ip-cidr": "3.1.0",
"is-svg": "4.3.2",
"is-svg": "5.0.0",
"js-yaml": "4.1.0",
"jsdom": "20.0.3",
"jsdom": "22.1.0",
"json5": "2.2.3",
"jsonld": "8.2.0",
"jsonld": "8.2.1",
"jsrsasign": "10.8.6",
"koa": "2.14.2",
"koa-body": "^6.0.1",
@ -91,10 +90,10 @@
"koa-slow": "2.1.0",
"koa-views": "7.0.2",
"megalodon": "workspace:*",
"meilisearch": "0.33.0",
"meilisearch": "0.34.1",
"mfm-js": "0.23.3",
"mime-types": "2.1.35",
"msgpackr": "1.9.6",
"msgpackr": "1.9.7",
"multer": "1.4.4-lts.1",
"native-utils": "link:native-utils",
"nested-property": "4.0.0",
@ -106,19 +105,18 @@
"os-utils": "0.0.14",
"otpauth": "^9.1.4",
"parse5": "7.1.2",
"pg": "8.11.2",
"private-ip": "2.3.4",
"pg": "8.11.3",
"private-ip": "3.0.1",
"probe-image-size": "7.2.3",
"promise-limit": "2.7.0",
"punycode": "2.3.0",
"pureimage": "0.3.15",
"pureimage": "0.4.8",
"qrcode": "1.5.3",
"qs": "6.11.2",
"random-seed": "0.3.0",
"ratelimiter": "3.4.1",
"re2": "1.20.1",
"redis-lock": "0.1.4",
"redis-semaphore": "5.4.0",
"re2": "1.20.3",
"redis-semaphore": "5.5.0",
"reflect-metadata": "0.1.13",
"rename": "1.0.4",
"rndstr": "1.0.0",
@ -126,12 +124,12 @@
"sanitize-html": "2.11.0",
"seedrandom": "^3.0.5",
"semver": "7.5.4",
"sharp": "0.32.4",
"sharp": "0.32.5",
"sonic-channel": "^1.3.1",
"stringz": "2.1.0",
"summaly": "2.7.0",
"syslog-pro": "1.0.0",
"systeminformation": "5.18.13",
"systeminformation": "5.21.3",
"tar-stream": "^3.1.6",
"tesseract.js": "^4.1.1",
"tinycolor2": "1.6.0",
@ -140,7 +138,7 @@
"typeorm": "0.3.17",
"ulid": "2.3.0",
"uuid": "9.0.0",
"web-push": "3.6.4",
"web-push": "3.6.5",
"websocket": "1.0.34",
"xev": "3.0.2"
},
@ -149,7 +147,6 @@
"@swc/core": "^1.3.75",
"@types/adm-zip": "^0.5.0",
"@types/bcryptjs": "2.4.2",
"@types/cbor": "6.0.0",
"@types/escape-regexp": "0.0.1",
"@types/fluent-ffmpeg": "2.1.21",
"@types/js-yaml": "4.0.5",

View file

@ -30,40 +30,34 @@ const themeColor = chalk.hex("#31748f");
function greet() {
if (!envOption.quiet) {
//#region Firefish logo
const v = `v${meta.version}`;
console.log(
themeColor(
" ▄▄▄▄▄▄▄ ▄▄▄ ▄▄▄▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄ ▄▄▄▄▄▄▄ ▄▄ ▄▄ ◯ ",
"██████╗ ██╗██████╗ ███████╗███████╗██╗███████╗██╗ ██╗ ○ ▄ ▄ ",
),
);
console.log(
themeColor(
"█ █ █ ▄ █ █ █ █ █ █ █ █ █ ○ ▄ ▄",
"██╔════╝██║██╔══██╗██╔════╝██╔════╝██║██╔════╝██║ ██║ ⚬ █▄▄ █▄▄ ",
),
);
console.log(
themeColor(
"█ ▄▄▄█ █ █ █ █ █ ▄▄▄█ ▄▄▄█ █ ▄▄▄▄▄█ █▄█ █ ⚬ █▄▄ █▄▄ ",
"█████╗ ██║██████╔╝█████╗ █████╗ ██║███████╗███████║ ▄▄▄▄▄▄ ▄ ",
),
);
console.log(
themeColor(
"█ █▄▄▄█ █ █▄▄█▄█ █▄▄▄█ █▄▄▄█ █ █▄▄▄▄▄█ █ ▄▄▄▄▄▄ ▄",
"██╔══╝ ██║██╔══██╗██╔══╝ ██╔══╝ ██║╚════██║██╔══██║ █ █ █▄▄ ",
),
);
console.log(
themeColor(
"█ ▄▄▄█ █ ▄▄ █ ▄▄▄█ ▄▄▄█ █▄▄▄▄▄ █ ▄ █ █ █ █▄▄",
"██║ ██║██║ ██║███████╗██║ ██║███████║██║ ██║ █ ● ● █ ",
),
);
console.log(
themeColor(
"█ █ █ █ █ █ █ █▄▄▄█ █ █ █▄▄▄▄▄█ █ █ █ █ █ ● ● █",
),
);
console.log(
themeColor(
"█▄▄▄█ █▄▄▄█▄▄▄█ █▄█▄▄▄▄▄▄▄█▄▄▄█ █▄▄▄█▄▄▄▄▄▄▄█▄▄█ █▄▄█ ▀▄▄▄▄▄▄▀",
"╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ▀▄▄▄▄▄▄▀ ",
),
);
//#endregion

View file

@ -1,2 +1,2 @@
// rome-ignore lint/suspicious/noExplicitAny: i have no idea
// biome-ignore lint/suspicious/noExplicitAny: i have no idea
type FIXME = any;

View file

@ -1,33 +1,40 @@
import { redisClient } from "../db/redis.js";
import { promisify } from "node:util";
import redisLock from "redis-lock";
import { Mutex } from "redis-semaphore";
/**
* Retry delay (ms) for lock acquisition
*/
const retryDelay = 100;
const lock: (key: string, timeout?: number) => Promise<() => void> = redisClient
? promisify(redisLock(redisClient, retryDelay))
: async () => () => {};
/**
* Get AP Object lock
* @param uri AP object ID
* @param timeout Lock timeout (ms), The timeout releases previous lock.
* @returns Unlock function
*/
export function getApLock(uri: string, timeout = 30 * 1000) {
return lock(`ap-object:${uri}`, timeout);
export async function getApLock(uri: string, timeout = 30 * 1000) {
const lock = new Mutex(redisClient, `ap-object:${uri}`, {
lockTimeout: timeout,
retryInterval: retryDelay,
});
await lock.acquire();
}
export function getFetchInstanceMetadataLock(
export async function getFetchInstanceMetadataLock(
host: string,
timeout = 30 * 1000,
) {
return lock(`instance:${host}`, timeout);
const lock = new Mutex(redisClient, `instance:${host}`, {
lockTimeout: timeout,
retryInterval: retryDelay,
});
await lock.acquire();
}
export function getChartInsertLock(lockKey: string, timeout = 30 * 1000) {
return lock(`chart-insert:${lockKey}`, timeout);
export async function getChartInsertLock(lockKey: string, timeout = 30 * 1000) {
const lock = new Mutex(redisClient, `chart-insert:${lockKey}`, {
lockTimeout: timeout,
retryInterval: retryDelay,
});
await lock.acquire();
}

View file

@ -32,8 +32,6 @@ export default async function (
// Interrupt if you block the announcement destination
if (await shouldBlockInstance(extractDbHost(uri))) return;
const unlock = await getApLock(uri);
try {
// Check if something with the same URI is already registered
const exist = await fetchNote(uri);
@ -60,9 +58,10 @@ export default async function (
throw e;
}
if (!(await Notes.isVisibleForMe(renote, actor.id)))
return "skip: invalid actor for this activity";
if (renote != null && !(await Notes.isVisibleForMe(renote, actor.id))) {
console.log("skip: invalid actor for this activity");
return;
}
logger.info(`Creating the (Re)Note: ${uri}`);
const activityAudience = await parseAudience(
@ -79,6 +78,6 @@ export default async function (
uri,
});
} finally {
unlock();
await getApLock(uri);
}
}

View file

@ -31,8 +31,6 @@ export default async function (
}
}
const unlock = await getApLock(uri);
try {
const exist = await fetchNote(note);
if (exist) return "skip: note exists";
@ -46,6 +44,6 @@ export default async function (
throw e;
}
} finally {
unlock();
await getApLock(uri);
}
}

View file

@ -13,8 +13,6 @@ export default async function (
): Promise<string> {
logger.info(`Deleting the Note: ${uri}`);
const unlock = await getApLock(uri);
try {
const dbResolver = new DbResolver();
const note = await dbResolver.getNoteFromApId(uri);
@ -39,6 +37,6 @@ export default async function (
await deleteNode(actor, note);
return "ok: note deleted";
} finally {
unlock();
await getApLock(uri);
}
}

View file

@ -68,13 +68,13 @@ export class LdSignature {
...options,
"@context": "https://w3id.org/identity/v1",
};
transformedOptions.type = undefined;
transformedOptions.id = undefined;
transformedOptions.signatureValue = undefined;
delete transformedOptions["type"];
delete transformedOptions["id"];
delete transformedOptions["signatureValue"];
const canonizedOptions = await this.normalize(transformedOptions);
const optionsHash = this.sha256(canonizedOptions);
const transformedData = { ...data };
transformedData.signature = undefined;
delete transformedData["signature"];
const cannonidedData = await this.normalize(transformedData);
if (this.debug) console.debug(`cannonidedData: ${cannonidedData}`);
const documentHash = this.sha256(cannonidedData);

View file

@ -444,8 +444,6 @@ export async function resolveNote(
`host ${extractDbHost(uri)} is blocked`,
);
const unlock = await getApLock(uri);
try {
//#region Returns if already registered with this server
const exist = await fetchNote(uri);
@ -468,7 +466,7 @@ export async function resolveNote(
// Since the attached Note Object may be disguised, always specify the uri and fetch it from the server.
return await createNote(uri, resolver, true);
} finally {
unlock();
await getApLock(uri);
}
}

View file

@ -1,5 +1,4 @@
import { promisify } from "node:util";
import * as cbor from "cbor";
import { decode } from "msgpackr";
import define from "../../../define.js";
import {
UserProfiles,
@ -12,7 +11,6 @@ import { procedures, hash } from "../../../2fa.js";
import { publishMainStream } from "@/services/stream.js";
import { comparePassword } from "@/misc/password.js";
const cborDecodeFirst = promisify(cbor.decodeFirst) as any;
const rpIdHashReal = hash(Buffer.from(config.hostname, "utf-8"));
export const meta = {
@ -64,7 +62,7 @@ export default define(meta, paramDef, async (ps, user) => {
const clientDataJSONHash = hash(Buffer.from(ps.clientDataJSON, "utf-8"));
const attestation = await cborDecodeFirst(ps.attestationObject);
const attestation = decode(Buffer.from(ps.attestationObject, "utf-8"));
const rpIdHash = attestation.authData.slice(0, 32);
if (!rpIdHashReal.equals(rpIdHash)) {
@ -81,7 +79,7 @@ export default define(meta, paramDef, async (ps, user) => {
const credentialIdLength = authData.readUInt16BE(53);
const credentialId = authData.slice(55, 55 + credentialIdLength);
const publicKeyData = authData.slice(55 + credentialIdLength);
const publicKey: Map<number, any> = await cborDecodeFirst(publicKeyData);
const publicKey: Map<number, any> = decode(publicKeyData);
if (publicKey.get(3) !== -7) {
throw new Error("alg mismatch");
}

View file

@ -3,10 +3,11 @@
"name": "Firefish",
"description": "An open source, decentralized social media platform that's free forever!",
"start_url": "/",
"scope": "/",
"display": "standalone",
"background_color": "#1f1d2e",
"theme_color": "#31748f",
"orientation": "portrait-primary",
"orientation": "any",
"icons": [
{
"src": "/static-assets/icons/192.png",
@ -21,7 +22,7 @@
"purpose": "any"
},
{
"src": "/static-assets/icons/maskable.png",
"src": "/static-assets/icons/512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"

View file

@ -11,7 +11,6 @@ export const manifestHandler = async (ctx: Koa.Context) => {
const instance = await fetchMeta(true);
res.short_name = instance.name || "Firefish";
res.name = instance.name || "Firefish";
if (instance.themeColor) res.theme_color = instance.themeColor;
for (const icon of res.icons) {
icon.src = `${icon.src}?v=${config.version.replace(/[^0-9]/g, "")}`;

View file

@ -7,16 +7,16 @@ doctype html
//
-
▄▄▄▄▄▄▄ ▄▄▄ ▄▄▄▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄ ▄▄▄▄▄▄▄ ▄▄ ▄▄ ◯
█ █ █ ▄ █ █ █ █ █ █ █ █ █ ○ ▄ ▄
█ ▄▄▄█ █ █ █ █ █ ▄▄▄█ ▄▄▄█ █ ▄▄▄▄▄█ █▄█ █ ⚬ █▄▄ █▄▄
█ █▄▄▄█ █ █▄▄█▄█ █▄▄▄█ █▄▄▄█ █ █▄▄▄▄▄█ █ ▄▄▄▄▄▄ ▄
█ ▄▄▄█ █ ▄▄ █ ▄▄▄█ ▄▄▄█ █▄▄▄▄▄ █ ▄ █ █ █ █▄▄
█ █ █ █ █ █ █ █▄▄▄█ █ █ █▄▄▄▄▄█ █ █ █ █ █ ● ● █
█▄▄▄█ █▄▄▄█▄▄▄█ █▄█▄▄▄▄▄▄▄█▄▄▄█ █▄▄▄█▄▄▄▄▄▄▄█▄▄█ █▄▄█ ▀▄▄▄▄▄▄▀
██████╗ ██╗██████╗ ███████╗███████╗██╗███████╗██╗ ██╗ ○ ▄ ▄
██╔════╝██║██╔══██╗██╔════╝██╔════╝██║██╔════╝██║ ██║ ⚬ █▄▄ █▄▄
█████╗ ██║██████╔╝█████╗ █████╗ ██║███████╗███████║ ▄▄▄▄▄▄ ▄
██╔══╝ ██║██╔══██╗██╔══╝ ██╔══╝ ██║╚════██║██╔══██║ █ █ █▄▄
██║ ██║██║ ██║███████╗██║ ██║███████║██║ ██║ █ ● ● █
╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ▀▄▄▄▄▄▄▀
Thank you for using Firefish!
If you are reading this message... how about joining the development?
If you're reading this message... how about helping out with development?
https://git.joinfirefish.org/firefish/firefish
html

View file

@ -430,7 +430,6 @@ export default abstract class Chart<T extends Schema> {
? `${this.name}:${date}:${span}:${group}`
: `${this.name}:${date}:${span}`;
const unlock = await getChartInsertLock(lockKey);
try {
// ロック内でもう1回チェックする
const currentLog = (await repository.findOneBy({
@ -466,14 +465,14 @@ export default abstract class Chart<T extends Schema> {
return log;
} finally {
unlock();
await getChartInsertLock(lockKey);
}
}
protected commit(diff: Commit<T>, group: string | null = null): void {
for (const [k, v] of Object.entries(diff)) {
if (v == null || v === 0 || (Array.isArray(v) && v.length === 0))
// rome-ignore lint/performance/noDelete: needs to be deleted not just set to undefined
// biome-ignore lint/performance/noDelete: needs to be deleted not just set to undefined
delete diff[k];
}
this.buffer.push({

View file

@ -15,8 +15,6 @@ export async function fetchInstanceMetadata(
instance: Instance,
force = false,
): Promise<void> {
const unlock = await getFetchInstanceMetadataLock(instance.host);
if (!force) {
const _instance = await Instances.findOneBy({ host: instance.host });
const now = Date.now();
@ -24,7 +22,7 @@ export async function fetchInstanceMetadata(
_instance?.infoUpdatedAt &&
now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 24
) {
unlock();
await getFetchInstanceMetadataLock(instance.host);
return;
}
}
@ -53,7 +51,7 @@ export async function fetchInstanceMetadata(
} as Record<string, any>;
if (info) {
updates.softwareName = info.software?.name.toLowerCase();
updates.softwareName = info.software?.name?.toLowerCase() || null;
updates.softwareVersion = info.software?.version;
updates.openRegistrations = info.openRegistrations;
updates.maintainerName = info.metadata
@ -80,24 +78,24 @@ export async function fetchInstanceMetadata(
} catch (e) {
logger.error(`Failed to update metadata of ${instance.host}: ${e}`);
} finally {
unlock();
await getFetchInstanceMetadataLock(instance.host);
}
}
type NodeInfo = {
openRegistrations?: any;
openRegistrations?: boolean;
software?: {
name?: any;
version?: any;
name?: string;
version?: string;
};
metadata?: {
name?: any;
nodeName?: any;
nodeDescription?: any;
description?: any;
name?: string;
nodeName?: string;
nodeDescription?: string;
description?: string;
maintainer?: {
name?: any;
email?: any;
name?: string;
email?: string;
};
};
};

View file

@ -177,7 +177,7 @@ export default async (
data: Option,
silent = false,
) =>
// rome-ignore lint/suspicious/noAsyncPromiseExecutor: FIXME
// biome-ignore lint/suspicious/noAsyncPromiseExecutor: FIXME
new Promise<Note>(async (res, rej) => {
const dontFederateInitially = data.visibility === "hidden";

View file

@ -1,6 +1,7 @@
{
"extends": ["@eslint-sets/vue3", "@eslint-sets/vue3-ts"],
"plugins": ["file-progress", "prettier"],
"ignorePatterns": ["**/*.json5"],
"rules": {
"file-progress/activate": 1
}

View file

@ -5,9 +5,9 @@
"watch": "pnpm vite build --watch --mode development",
"build": "pnpm vite build",
"build:debug": "pnpm run build",
"lint": "pnpm rome check **/*.ts --apply && pnpm run lint:vue",
"lint:vue": "pnpm paralint --ext .vue --fix '**/*.vue' --cache",
"format": "pnpm rome format * --write && pnpm prettier --write '**/*.{scss,vue}' --cache --cache-strategy metadata"
"lint": "pnpm biome check **/*.ts --apply ; pnpm run lint:vue",
"lint:vue": "pnpm eslint src --fix '**/*.vue' --cache ; pnpm run format",
"format": "pnpm biome format * --write && pnpm prettier --write '**/*.{scss,vue}' --cache --cache-strategy metadata"
},
"devDependencies": {
"@discordapp/twemoji": "14.1.2",
@ -16,7 +16,7 @@
"@phosphor-icons/web": "^2.0.3",
"@rollup/plugin-alias": "5.0.0",
"@rollup/plugin-json": "6.0.0",
"@rollup/pluginutils": "^5.0.3",
"@rollup/pluginutils": "^5.0.4",
"@syuilo/aiscript": "0.11.1",
"@types/escape-regexp": "0.0.1",
"@types/glob": "8.1.0",
@ -28,15 +28,15 @@
"@types/seedrandom": "3.0.5",
"@types/throttle-debounce": "5.0.0",
"@types/tinycolor2": "1.4.3",
"@types/uuid": "9.0.2",
"@vitejs/plugin-vue": "4.3.1",
"@types/uuid": "9.0.3",
"@vitejs/plugin-vue": "4.3.4",
"@vue/compiler-sfc": "3.3.4",
"autobind-decorator": "2.4.0",
"autosize": "6.0.1",
"blurhash": "2.0.5",
"broadcast-channel": "5.2.0",
"broadcast-channel": "5.3.0",
"browser-image-resizer": "github:misskey-dev/browser-image-resizer",
"chart.js": "4.3.3",
"chart.js": "4.4.0",
"chartjs-adapter-date-fns": "3.0.0",
"chartjs-chart-matrix": "^2.0.1",
"chartjs-plugin-gradient": "0.6.1",
@ -63,36 +63,35 @@
"katex": "0.16.8",
"matter-js": "0.19.0",
"mfm-js": "0.23.3",
"paralint": "^1.2.1",
"photoswipe": "5.3.8",
"prettier": "3.0.2",
"prettier": "3.0.3",
"prettier-plugin-vue": "1.1.6",
"prismjs": "1.29.0",
"punycode": "2.3.0",
"rndstr": "1.0.0",
"rollup": "3.28.0",
"rollup": "3.28.1",
"s-age": "1.1.2",
"sass": "1.66.0",
"sass": "1.66.1",
"seedrandom": "3.0.5",
"strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0",
"swiper": "10.2.0",
"syuilo-password-strength": "0.0.1",
"textarea-caret": "3.1.0",
"three": "0.155.0",
"three": "0.156.0",
"throttle-debounce": "5.0.0",
"tinycolor2": "1.6.0",
"tsc-alias": "1.8.7",
"tsconfig-paths": "4.2.0",
"twemoji-parser": "14.0.0",
"typescript": "5.1.6",
"typescript": "5.2.2",
"unicode-emoji-json": "^0.4.0",
"uuid": "9.0.0",
"vanilla-tilt": "1.8.1",
"vite": "4.4.9",
"vite-plugin-compression": "^0.5.1",
"vue": "3.3.4",
"vue-draggable-plus": "^0.2.5",
"vue-draggable-plus": "^0.2.6",
"vue-isyourpasswordsafe": "^2.0.0",
"vue-plyr": "^7.0.0",
"vue-prism-editor": "2.0.0-alpha.2"

View file

@ -1,10 +1,10 @@
import { defineAsyncComponent, reactive } from "vue";
import * as misskey from "firefish-js";
import type * as misskey from "firefish-js";
import { i18n } from "./i18n";
import { del, get, set } from "@/scripts/idb-proxy";
import { apiUrl } from "@/config";
import { waiting, api, popup, popupMenu, success, alert } from "@/os";
import { unisonReload, reloadChannel } from "@/scripts/unison-reload";
import { alert, api, popup, popupMenu, success, waiting } from "@/os";
import { reloadChannel, unisonReload } from "@/scripts/unison-reload";
// TODO: 他のタブと永続化されたstateを同期

View file

@ -199,7 +199,7 @@
</template>
<script lang="ts" setup>
import { onBeforeUnmount, onMounted, ref, shallowRef, computed } from "vue";
import { computed, onBeforeUnmount, onMounted, ref, shallowRef } from "vue";
import * as Acct from "firefish-js/built/acct";
import MkModal from "@/components/MkModal.vue";
import MkButton from "@/components/MkButton.vue";
@ -281,7 +281,9 @@ const modal = shallowRef<InstanceType<typeof MkModal>>();
const inputValue = ref<string | number | null>(props.input?.default ?? null);
const selectedValue = ref(props.select?.default ?? null);
let disabledReason = ref<null | "charactersExceeded" | "charactersBelow">(null);
const disabledReason = ref<null | "charactersExceeded" | "charactersBelow">(
null,
);
const okButtonDisabled = computed<boolean>(() => {
if (props.input) {
if (props.input.minLength) {

View file

@ -39,7 +39,7 @@
<script lang="ts" setup>
import { computed, defineAsyncComponent, ref } from "vue";
import * as Misskey from "firefish-js";
import type * as Misskey from "firefish-js";
import copyToClipboard from "@/scripts/copy-to-clipboard";
import MkDriveFileThumbnail from "@/components/MkDriveFileThumbnail.vue";
import bytes from "@/filters/bytes";
@ -160,7 +160,7 @@ function rename() {
if (canceled) return;
os.api("drive/files/update", {
fileId: props.file.id,
name: name,
name,
});
});
}
@ -179,7 +179,7 @@ function describe() {
{
done: (result) => {
if (!result || result.canceled) return;
let comment = result.result;
const comment = result.result;
os.api("drive/files/update", {
fileId: props.file.id,
comment: comment.length === 0 ? null : comment,

View file

@ -38,7 +38,7 @@
<script lang="ts" setup>
import { computed, defineAsyncComponent, ref } from "vue";
import * as Misskey from "firefish-js";
import type * as Misskey from "firefish-js";
import * as os from "@/os";
import { i18n } from "@/i18n";
import { defaultStore } from "@/store";
@ -207,7 +207,7 @@ function rename() {
if (canceled) return;
os.api("drive/folders/update", {
folderId: props.folder.id,
name: name,
name,
});
});
}

View file

@ -15,7 +15,7 @@
<script lang="ts" setup>
import { ref } from "vue";
import * as Misskey from "firefish-js";
import type * as Misskey from "firefish-js";
import * as os from "@/os";
import { i18n } from "@/i18n";

View file

@ -139,7 +139,7 @@ import {
ref,
watch,
} from "vue";
import * as Misskey from "firefish-js";
import type * as Misskey from "firefish-js";
import MkButton from "./MkButton.vue";
import XNavFolder from "@/components/MkDrive.navFolder.vue";
import XFolder from "@/components/MkDrive.folder.vue";
@ -354,7 +354,7 @@ function urlUpload() {
}).then(({ canceled, result: url }) => {
if (canceled || !url) return;
os.api("drive/files/upload-from-url", {
url: url,
url,
folderId: folder.value ? folder.value.id : undefined,
});
@ -372,7 +372,7 @@ function createFolder() {
}).then(({ canceled, result: name }) => {
if (canceled) return;
os.api("drive/folders/create", {
name: name,
name,
parentId: folder.value ? folder.value.id : undefined,
}).then((createdFolder) => {
addFolder(createdFolder, true);
@ -389,7 +389,7 @@ function renameFolder(folderToRename: Misskey.entities.DriveFolder) {
if (canceled) return;
os.api("drive/folders/update", {
folderId: folderToRename.id,
name: name,
name,
}).then((updatedFolder) => {
// FIXME:
move(updatedFolder);

View file

@ -68,7 +68,7 @@ const is = computed(() => {
"application/x-tar",
"application/gzip",
"application/x-7z-compressed",
].some((archiveType) => archiveType === props.file.type)
].includes(props.file.type)
)
return "archive";
return "unknown";

View file

@ -37,7 +37,7 @@
<script lang="ts" setup>
import { ref } from "vue";
import * as Misskey from "firefish-js";
import type * as Misskey from "firefish-js";
import XDrive from "@/components/MkDrive.vue";
import XModalWindow from "@/components/MkModalWindow.vue";
import number from "@/filters/number";

View file

@ -15,7 +15,7 @@
<script lang="ts" setup>
import {} from "vue";
import * as Misskey from "firefish-js";
import type * as Misskey from "firefish-js";
import XDrive from "@/components/MkDrive.vue";
import XWindow from "@/components/MkWindow.vue";
import { i18n } from "@/i18n";

View file

@ -48,7 +48,7 @@
</template>
<script lang="ts" setup>
import { ref, watch, onMounted } from "vue";
import { onMounted, ref, watch } from "vue";
import { addSkinTone } from "@/scripts/emojilist";
const props = defineProps<{

View file

@ -1,5 +1,5 @@
<template>
<FocusTrap v-bind:active="isActive">
<FocusTrap :active="isActive">
<div
class="omfetrab"
:class="['s' + size, 'w' + width, 'h' + height, { asDrawer }]"
@ -163,14 +163,15 @@
</template>
<script lang="ts" setup>
import { ref, computed, watch, onMounted } from "vue";
import * as Misskey from "firefish-js";
import { computed, onMounted, ref, watch } from "vue";
import type * as Misskey from "firefish-js";
import { FocusTrap } from "focus-trap-vue";
import XSection from "@/components/MkEmojiPicker.section.vue";
import type { UnicodeEmojiDef } from "@/scripts/emojilist";
import {
emojilist,
unicodeEmojiCategories,
UnicodeEmojiDef,
getNicelyLabeledCategory,
unicodeEmojiCategories,
} from "@/scripts/emojilist";
import { getStaticImageUrl } from "@/scripts/get-static-image-url";
import Ripple from "@/components/MkRipple.vue";
@ -180,7 +181,6 @@ import { deviceKind } from "@/scripts/device-kind";
import { emojiCategories, instance } from "@/instance";
import { i18n } from "@/i18n";
import { defaultStore } from "@/store";
import { FocusTrap } from "focus-trap-vue";
const props = withDefaults(
defineProps<{

View file

@ -8,7 +8,7 @@
<script lang="ts" setup>
import { ref } from "vue";
import * as Misskey from "firefish-js";
import type * as Misskey from "firefish-js";
import * as os from "@/os";
const meta = ref<Misskey.entities.DetailedInstanceMetadata>();

View file

@ -1,14 +1,15 @@
<template>
<button
v-if="!hideMenu"
v-tooltip="i18n.ts.menu"
class="menu _button"
@click.stop="menu"
v-tooltip="i18n.ts.menu"
>
<i class="ph-dots-three-outline ph-bold ph-lg"></i>
</button>
<button
v-if="$i != null && $i.id != user.id"
v-tooltip="full ? null : `${state} ${user.name || user.username}`"
class="kpoogebi _button follow-button"
:class="{
wait,
@ -18,9 +19,8 @@
blocking: isBlocking,
}"
:disabled="wait"
@click.stop="onClick"
:aria-label="`${state} ${user.name || user.username}`"
v-tooltip="full ? null : `${state} ${user.name || user.username}`"
@click.stop="onClick"
>
<template v-if="!wait">
<template v-if="isBlocking">
@ -88,13 +88,13 @@ const props = withDefaults(
const isBlocking = computed(() => props.user.isBlocking);
let state = ref(i18n.ts.processing);
const state = ref(i18n.ts.processing);
let isFollowing = ref(props.user.isFollowing);
let hasPendingFollowRequestFromYou = ref(
const isFollowing = ref(props.user.isFollowing);
const hasPendingFollowRequestFromYou = ref(
props.user.hasPendingFollowRequestFromYou,
);
let wait = ref(false);
const wait = ref(false);
const connection = stream.useChannel("main");
if (props.user.isFollowing == null) {

View file

@ -64,7 +64,6 @@
<script lang="ts" setup>
import { ref } from "vue";
import {} from "vue";
import XModalWindow from "@/components/MkModalWindow.vue";
import MkButton from "@/components/MkButton.vue";
import MkInput from "@/components/form/input.vue";
@ -77,11 +76,11 @@ const emit = defineEmits<{
(ev: "closed"): void;
}>();
let dialog: InstanceType<typeof XModalWindow> = ref();
const dialog: InstanceType<typeof XModalWindow> = ref();
let username = ref("");
let email = ref("");
let processing = ref(false);
const username = ref("");
const email = ref("");
const processing = ref(false);
async function onSubmit() {
processing.value = true;

View file

@ -3,7 +3,7 @@
</template>
<script lang="ts">
import { defineComponent, defineAsyncComponent } from "vue";
import { defineAsyncComponent, defineComponent } from "vue";
export default defineComponent({
components: {

View file

@ -8,7 +8,7 @@
</template>
<script lang="ts" setup>
import { onMounted, nextTick, watch, shallowRef, ref } from "vue";
import { nextTick, onMounted, ref, shallowRef, watch } from "vue";
import { Chart } from "chart.js";
import * as os from "@/os";
import { defaultStore } from "@/store";
@ -26,8 +26,8 @@ const props = defineProps<{
const rootEl = shallowRef<HTMLDivElement>(null);
const chartEl = shallowRef<HTMLCanvasElement>(null);
const now = new Date();
let chartInstance: Chart = null;
let fetching = ref(true);
let chartInstance: Chart = null,
fetching = ref(true);
const { handler: externalTooltipHandler } = useChartTooltip({
position: "middle",

View file

@ -28,7 +28,6 @@
<script lang="ts" setup>
import { ref } from "vue";
import {} from "vue";
import type * as misskey from "firefish-js";
import bytes from "@/filters/bytes";
import number from "@/filters/number";

View file

@ -49,7 +49,7 @@ const props = withDefaults(
);
const canvas = ref<HTMLCanvasElement>();
let loaded = ref(false);
const loaded = ref(false);
function draw() {
if (props.hash == null || canvas.value == null) return;

View file

@ -11,8 +11,8 @@
v-if="closeable"
v-tooltip="i18n.ts.close"
class="_buttonIcon close"
@click.stop="close"
:aria-label="i18n.t('close')"
@click.stop="close"
>
<i class="ph-x ph-bold ph-lg"></i>
</button>

View file

@ -26,7 +26,7 @@
<script lang="ts" setup>
import { ref } from "vue";
import * as firefish from "firefish-js";
import type * as firefish from "firefish-js";
import MkMiniChart from "@/components/MkMiniChart.vue";
import * as os from "@/os";
import { getProxiedImageUrlNullable } from "@/scripts/media-proxy";
@ -35,7 +35,7 @@ const props = defineProps<{
instance: firefish.entities.Instance;
}>();
let chartValues = ref<number[] | null>(null);
const chartValues = ref<number[] | null>(null);
os.apiGet("charts/instance", {
host: props.instance.host,

View file

@ -58,11 +58,11 @@
<script lang="ts" setup>
import { ref } from "vue";
import type { Instance } from "firefish-js/built/entities";
import MkInput from "@/components/form/input.vue";
import XModalWindow from "@/components/MkModalWindow.vue";
import * as os from "@/os";
import { i18n } from "@/i18n";
import { Instance } from "firefish-js/built/entities";
const emit = defineEmits<{
(ev: "ok", selected: Instance): void;
@ -70,10 +70,10 @@ const emit = defineEmits<{
(ev: "closed"): void;
}>();
let hostname = ref("");
let instances: Instance[] = ref([]);
let selected: Instance | null = ref(null);
let dialogEl = ref<InstanceType<typeof XModalWindow>>();
const hostname = ref("");
const instances: Instance[] = ref([]);
const selected: Instance | null = ref(null);
const dialogEl = ref<InstanceType<typeof XModalWindow>>();
let searchOrderLatch = 0;
const search = () => {

View file

@ -116,11 +116,11 @@ import { initChart } from "@/scripts/init-chart";
initChart();
const chartLimit = 500;
let chartSpan = ref<"hour" | "day">("hour");
let chartSrc = ref("active-users");
let heatmapSrc = ref("active-users");
let subDoughnutEl = shallowRef<HTMLCanvasElement>();
let pubDoughnutEl = shallowRef<HTMLCanvasElement>();
const chartSpan = ref<"hour" | "day">("hour");
const chartSrc = ref("active-users");
const heatmapSrc = ref("active-users");
const subDoughnutEl = shallowRef<HTMLCanvasElement>();
const pubDoughnutEl = shallowRef<HTMLCanvasElement>();
const { handler: externalTooltipHandler1 } = useChartTooltip({
position: "middle",

View file

@ -1,8 +1,8 @@
<template>
<div
class="hpaizdrt"
v-tooltip="capitalize(instance.softwareName)"
ref="ticker"
v-tooltip="capitalize(instance.softwareName)"
class="hpaizdrt"
:style="bg"
>
<img class="icon" :src="getInstanceIcon(instance)" aria-hidden="true" />
@ -26,7 +26,7 @@ const props = defineProps<{
};
}>();
let ticker = ref<HTMLElement | null>(null);
const ticker = ref<HTMLElement | null>(null);
// if no instance data is given, this is for the local instance
const instance = props.instance ?? {

View file

@ -1,5 +1,5 @@
<template>
<div class="media" v-size="{ max: [350] }">
<div v-size="{ max: [350] }" class="media">
<button v-if="hide" class="hidden" @click="hide = false">
<ImgWithBlurhash
:hash="media.blurhash"
@ -89,7 +89,7 @@
</template>
<script lang="ts" setup>
import { watch, ref, computed } from "vue";
import { computed, ref, watch } from "vue";
import VuePlyr from "vue-plyr";
import "vue-plyr/dist/vue-plyr.css";
import type * as misskey from "firefish-js";
@ -104,7 +104,7 @@ const props = defineProps<{
raw?: boolean;
}>();
let hide = ref(true);
const hide = ref(true);
const plyr = ref();

View file

@ -71,7 +71,7 @@ const props = withDefaults(
);
const audioEl = ref<HTMLAudioElement | null>();
let hide = ref(true);
const hide = ref(true);
function volumechange() {
if (audioEl.value)

View file

@ -29,7 +29,7 @@
<script lang="ts" setup>
import { onMounted, ref } from "vue";
import * as misskey from "firefish-js";
import type * as misskey from "firefish-js";
import PhotoSwipeLightbox from "photoswipe/lightbox";
import PhotoSwipe from "photoswipe";
import "photoswipe/style.css";
@ -125,11 +125,11 @@ onMounted(() => {
className: "pwsp__alt-text-container",
appendTo: "wrapper",
onInit: (el, pwsp) => {
let textBox = document.createElement("p");
const textBox = document.createElement("p");
textBox.className = "pwsp__alt-text";
el.appendChild(textBox);
let preventProp = function (ev: Event): void {
const preventProp = function (ev: Event): void {
ev.stopPropagation();
};

View file

@ -14,7 +14,7 @@
<script lang="ts" setup>
import { nextTick, onMounted, ref } from "vue";
import MkMenu from "./MkMenu.vue";
import { MenuItem } from "@/types/menu";
import type { MenuItem } from "@/types/menu";
const props = defineProps<{
items: MenuItem[];

View file

@ -14,8 +14,8 @@
width: width && !asDrawer ? width + 'px' : '',
maxHeight: maxHeight ? maxHeight + 'px' : '',
}"
@contextmenu.self="(e) => e.preventDefault()"
tabindex="-1"
@contextmenu.self="(e) => e.preventDefault()"
>
<template v-for="item in items2">
<div v-if="item === null" class="divider"></div>
@ -47,7 +47,7 @@
v-if="item.avatar"
:user="item.avatar"
class="avatar"
disableLink
disable-link
/>
<span :style="item.textStyle || ''">{{
item.text
@ -100,7 +100,7 @@
<MkAvatar
:user="item.user"
class="avatar"
disableLink
disable-link
/><MkUserName :user="item.user" />
<span
v-if="item.indicate"
@ -168,7 +168,7 @@
v-if="item.avatar"
:user="item.avatar"
class="avatar"
disableLink
disable-link
/>
<span :style="item.textStyle || ''">{{
item.text
@ -210,11 +210,16 @@ import {
ref,
watch,
} from "vue";
import { FocusTrap } from "focus-trap-vue";
import FormSwitch from "@/components/form/switch.vue";
import { MenuItem, InnerMenuItem, MenuPending, MenuAction } from "@/types/menu";
import type {
InnerMenuItem,
MenuAction,
MenuItem,
MenuPending,
} from "@/types/menu";
import * as os from "@/os";
import { i18n } from "@/i18n";
import { FocusTrap } from "focus-trap-vue";
const XChild = defineAsyncComponent(() => import("./MkMenu.child.vue"));
const focusTrap = ref();
@ -233,13 +238,13 @@ const emit = defineEmits<{
(ev: "close", actioned?: boolean): void;
}>();
let itemsEl = ref<HTMLDivElement>();
const itemsEl = ref<HTMLDivElement>();
let items2: InnerMenuItem[] = ref([]);
const items2: InnerMenuItem[] = ref([]);
let child = ref<InstanceType<typeof XChild>>();
const child = ref<InstanceType<typeof XChild>>();
let childShowingItem = ref<MenuItem | null>();
const childShowingItem = ref<MenuItem | null>();
watch(
() => props.items,
@ -267,8 +272,8 @@ watch(
},
);
let childMenu = ref<MenuItem[] | null>();
let childTarget = ref<HTMLElement | null>();
const childMenu = ref<MenuItem[] | null>();
const childTarget = ref<HTMLElement | null>();
function closeChild() {
childMenu.value = null;

View file

@ -25,7 +25,7 @@
</template>
<script lang="ts" setup>
import { watch, ref } from "vue";
import { ref, watch } from "vue";
import { v4 as uuid } from "uuid";
import tinycolor from "tinycolor2";
import { useInterval } from "@/scripts/use-interval";
@ -37,10 +37,10 @@ const props = defineProps<{
const viewBoxX = 50;
const viewBoxY = 50;
const gradientId = uuid();
let polylinePoints = ref("");
let polygonPoints = ref("");
let headX = ref<number | null>(null);
let headY = ref<number | null>(null);
const polylinePoints = ref("");
const polygonPoints = ref("");
const headX = ref<number | null>(null);
const headY = ref<number | null>(null);
const accent = tinycolor(
getComputedStyle(document.documentElement).getPropertyValue("--accent"),
);

View file

@ -25,6 +25,7 @@
<div
v-show="manualShowing != null ? manualShowing : showing"
v-hotkey.global="keymap"
v-focus
:class="[
$style.root,
{
@ -44,7 +45,6 @@
'--transformOrigin': transformOrigin,
}"
tabindex="-1"
v-focus
>
<div
class="_modalBg data-cy-bg"
@ -78,20 +78,20 @@
<script lang="ts" setup>
import {
computed,
nextTick,
onMounted,
watch,
provide,
onUnmounted,
provide,
ref,
shallowRef,
computed,
watch,
} from "vue";
import { FocusTrap } from "focus-trap-vue";
import * as os from "@/os";
import { isTouchUsing } from "@/scripts/touch";
import { defaultStore } from "@/store";
import { deviceKind } from "@/scripts/device-kind";
import { FocusTrap } from "focus-trap-vue";
function getFixedContainer(el: Element | null): Element | null {
if (el == null || el.tagName === "BODY") return null;
@ -139,13 +139,13 @@ const emit = defineEmits<{
provide("modal", true);
let maxHeight = ref<number>();
let fixed = ref(false);
let transformOrigin = ref("center");
let showing = ref(true);
let content = shallowRef<HTMLElement>();
const maxHeight = ref<number>();
const fixed = ref(false);
const transformOrigin = ref("center");
const showing = ref(true);
const content = shallowRef<HTMLElement>();
const zIndex = os.claimZIndex(props.zPriority);
let useSendAnime = ref(false);
const useSendAnime = ref(false);
const type = computed<ModalTypes>(() => {
if (props.preferType === "auto") {
if (
@ -164,7 +164,7 @@ const type = computed<ModalTypes>(() => {
const isEnableBgTransparent = computed(
() => props.transparentBg && type.value === "popup",
);
let transitionName = computed(() =>
const transitionName = computed(() =>
defaultStore.state.animation
? useSendAnime.value
? "send"
@ -175,7 +175,7 @@ let transitionName = computed(() =>
: "modal"
: "",
);
let transitionDuration = computed(() =>
const transitionDuration = computed(() =>
transitionName.value === "send"
? 400
: transitionName.value === "modal-popup"
@ -235,8 +235,7 @@ const align = () => {
const width = content.value!.offsetWidth;
const height = content.value!.offsetHeight;
let left;
let top;
let left, top;
const x = srcRect.left + (fixed.value ? 0 : window.pageXOffset);
const y = srcRect.top + (fixed.value ? 0 : window.pageYOffset);
@ -321,8 +320,8 @@ const align = () => {
left = 0;
}
let transformOriginX = "center";
let transformOriginY = "center";
let transformOriginX = "center",
transformOriginY = "center";
if (
top >=

View file

@ -28,8 +28,8 @@
</span>
<button
class="_button"
@click="$refs.modal.close()"
:aria-label="i18n.t('close')"
@click="$refs.modal.close()"
>
<i class="ph-x ph-bold ph-lg"></i>
</button>
@ -52,7 +52,8 @@
</template>
<script lang="ts" setup>
import { ComputedRef, provide, ref, computed } from "vue";
import type { ComputedRef } from "vue";
import { computed, provide, ref } from "vue";
import MkModal from "@/components/MkModal.vue";
import { popout as _popout } from "@/scripts/popout";
import copyToClipboard from "@/scripts/copy-to-clipboard";
@ -60,7 +61,8 @@ import { url } from "@/config";
import * as os from "@/os";
import { mainRouter, routes } from "@/router";
import { i18n } from "@/i18n";
import { PageMetadata, provideMetadataReceiver } from "@/scripts/page-metadata";
import type { PageMetadata } from "@/scripts/page-metadata";
import { provideMetadataReceiver } from "@/scripts/page-metadata";
import { Router } from "@/nirax";
const props = defineProps<{
@ -76,12 +78,12 @@ const router = new Router(routes, props.initialPath);
router.addListener("push", (ctx) => {});
let pageMetadata = ref<null | ComputedRef<PageMetadata>>();
let rootEl = ref();
let modal = ref<InstanceType<typeof MkModal>>();
let path = ref(props.initialPath);
let width = ref(860);
let height = ref(660);
const pageMetadata = ref<null | ComputedRef<PageMetadata>>();
const rootEl = ref();
const modal = ref<InstanceType<typeof MkModal>>();
const path = ref(props.initialPath);
const width = ref(860);
const height = ref(660);
const history = [];
provide("router", router);

View file

@ -25,10 +25,10 @@
<div ref="headerEl" class="header">
<button
v-if="props.withOkButton"
v-tooltip="i18n.ts.close"
:aria-label="i18n.t('close')"
class="_button"
@click="$emit('close')"
v-tooltip="i18n.ts.close"
>
<i class="ph-x ph-bold ph-lg"></i>
</button>
@ -92,9 +92,9 @@ const emit = defineEmits<{
(event: "ok"): void;
}>();
let modal = shallowRef<InstanceType<typeof MkModal>>();
let rootEl = shallowRef<HTMLElement>();
let headerEl = shallowRef<HTMLElement>();
const modal = shallowRef<InstanceType<typeof MkModal>>();
const rootEl = shallowRef<HTMLElement>();
const headerEl = shallowRef<HTMLElement>();
const close = (ev) => {
modal.value?.close(ev);

View file

@ -1,15 +1,15 @@
<template>
<div
:aria-label="accessibleLabel"
v-if="!muted.muted"
v-show="!isDeleted"
:id="appearNote.id"
ref="el"
v-hotkey="keymap"
v-size="{ max: [500, 350] }"
:aria-label="accessibleLabel"
class="tkcbzcuz note-container"
:tabindex="!isDeleted ? '-1' : null"
:class="{ renote: isRenote }"
:id="appearNote.id"
>
<MkNoteSub
v-if="appearNote.reply && !detailedView && !collapsedReply"
@ -19,10 +19,10 @@
<div
v-if="!detailedView"
class="note-context"
@click="noteClick"
:class="{
collapsedReply: collapsedReply && appearNote.reply,
}"
@click="noteClick"
>
<div class="line"></div>
<div v-if="appearNote._prId_" class="info">
@ -87,11 +87,11 @@
</div>
<article
class="article"
@contextmenu.stop="onContextmenu"
@click="noteClick"
:style="{
cursor: expandOnNoteClick && !detailedView ? 'pointer' : '',
}"
@contextmenu.stop="onContextmenu"
@click="noteClick"
>
<div class="main">
<div class="header-container">
@ -103,8 +103,8 @@
class="text"
:note="appearNote"
:detailed="true"
:detailedView="detailedView"
:parentId="appearNote.parentId"
:detailed-view="detailedView"
:parent-id="appearNote.parentId"
@push="(e) => router.push(notePage(e))"
@focusfooter="footerEl.focus()"
@expanded="(e) => setPostExpanded(e)"
@ -171,7 +171,7 @@
class="button"
:note="appearNote"
:count="appearNote.renoteCount"
:detailedView="detailedView"
:detailed-view="detailedView"
/>
<XStarButtonNoEmoji
v-if="!enableEmojiReactions"
@ -212,9 +212,9 @@
appearNote.myReaction != null
"
ref="reactButton"
v-tooltip.noDelay.bottom="i18n.ts.removeReaction"
class="button _button reacted"
@click.stop="undoReact(appearNote)"
v-tooltip.noDelay.bottom="i18n.ts.removeReaction"
>
<i class="ph-minus ph-bold ph-lg"></i>
</button>
@ -259,8 +259,8 @@ import { computed, inject, onMounted, ref } from "vue";
import * as mfm from "mfm-js";
import type { Ref } from "vue";
import type * as misskey from "firefish-js";
import MkNoteSub from "@/components/MkNoteSub.vue";
import MkSubNoteContent from "./MkSubNoteContent.vue";
import MkNoteSub from "@/components/MkNoteSub.vue";
import XNoteHeader from "@/components/MkNoteHeader.vue";
import XRenoteButton from "@/components/MkRenoteButton.vue";
import XReactionsViewer from "@/components/MkReactionsViewer.vue";
@ -271,7 +271,7 @@ import MkVisibility from "@/components/MkVisibility.vue";
import copyToClipboard from "@/scripts/copy-to-clipboard";
import { url } from "@/config";
import { pleaseLogin } from "@/scripts/please-login";
import { focusPrev, focusNext } from "@/scripts/focus";
import { focusNext, focusPrev } from "@/scripts/focus";
import { getWordSoftMute } from "@/scripts/check-word-mute";
import { useRouter } from "@/router";
import { userPage } from "@/filters/user";
@ -297,7 +297,7 @@ const props = defineProps<{
const inChannel = inject("inChannel", null);
let note = ref(deepClone(props.note));
const note = ref(deepClone(props.note));
const softMuteReasonI18nSrc = (what?: string) => {
if (what === "note") return i18n.ts.userSaysSomethingReason;
@ -333,7 +333,7 @@ const starButton = ref<InstanceType<typeof XStarButton>>();
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
const renoteTime = ref<HTMLElement>();
const reactButton = ref<HTMLElement>();
let appearNote = computed(() =>
const appearNote = computed(() =>
isRenote ? (note.value.renote as misskey.entities.Note) : note.value,
);
const isMyRenote = $i && $i.id === note.value.userId;
@ -385,7 +385,7 @@ function react(viaKeyboard = false): void {
(reaction) => {
os.api("notes/reactions/create", {
noteId: appearNote.value.id,
reaction: reaction,
reaction,
});
},
() => {
@ -516,7 +516,7 @@ function showRenoteMenu(viaKeyboard = false): void {
],
renoteTime.value,
{
viaKeyboard: viaKeyboard,
viaKeyboard,
},
);
}
@ -560,7 +560,7 @@ function readPromo() {
isDeleted.value = true;
}
let postIsExpanded = ref(false);
const postIsExpanded = ref(false);
function setPostExpanded(val: boolean) {
postIsExpanded.value = val;

View file

@ -10,27 +10,27 @@
:class="{ renote: isRenote }"
>
<MkNoteSub
v-if="conversation"
v-for="note in conversation"
v-if="conversation"
:key="note.id"
class="reply-to"
:note="note"
:detailedView="true"
:detailed-view="true"
/>
<MkLoading v-else-if="note.reply" mini />
<MkNoteSub
v-if="note.reply"
:note="note.reply"
class="reply-to"
:detailedView="true"
:detailed-view="true"
/>
<MkNote
ref="noteEl"
@contextmenu.stop="onContextmenu"
tabindex="-1"
:note="note"
detailedView
detailed-view
@contextmenu.stop="onContextmenu"
></MkNote>
<MkTab v-model="tab" :style="'underline'" @update:modelValue="loadTab">
@ -41,22 +41,22 @@
}}</span>
{{ i18n.ts._notification._types.reply }}
</option>
<option value="renotes" v-if="note.renoteCount > 0">
<option v-if="note.renoteCount > 0" value="renotes">
<!-- <i class="ph-repeat ph-bold ph-lg"></i> -->
<span class="count">{{ note.renoteCount }}</span>
{{ i18n.ts._notification._types.renote }}
</option>
<option value="reactions" v-if="reactionsCount > 0">
<option v-if="reactionsCount > 0" value="reactions">
<!-- <i class="ph-smiley ph-bold ph-lg"></i> -->
<span class="count">{{ reactionsCount }}</span>
{{ i18n.ts.reaction }}
</option>
<option value="quotes" v-if="directQuotes?.length > 0">
<option v-if="directQuotes?.length > 0" value="quotes">
<!-- <i class="ph-quotes ph-bold ph-lg"></i> -->
<span class="count">{{ directQuotes.length }}</span>
{{ i18n.ts._notification._types.quote }}
</option>
<option value="clips" v-if="clips?.length > 0">
<option v-if="clips?.length > 0" value="clips">
<!-- <i class="ph-paperclip ph-bold ph-lg"></i> -->
<span class="count">{{ clips.length }}</span>
{{ i18n.ts.clips }}
@ -64,26 +64,26 @@
</MkTab>
<MkNoteSub
v-if="directReplies && tab === 'replies'"
v-for="note in directReplies"
v-if="directReplies && tab === 'replies'"
:key="note.id"
:note="note"
class="reply"
:conversation="replies"
:detailedView="true"
:parentId="note.id"
:detailed-view="true"
:parent-id="note.id"
/>
<MkLoading v-else-if="tab === 'replies' && note.repliesCount > 0" />
<MkNoteSub
v-if="directQuotes && tab === 'quotes'"
v-for="note in directQuotes"
v-if="directQuotes && tab === 'quotes'"
:key="note.id"
:note="note"
class="reply"
:conversation="replies"
:detailedView="true"
:parentId="note.id"
:detailed-view="true"
:parent-id="note.id"
/>
<MkLoading v-else-if="tab === 'quotes' && directQuotes.length > 0" />
@ -94,8 +94,8 @@
:pagination="pagination"
> -->
<MkUserCardMini
v-if="tab === 'renotes' && renotes"
v-for="item in renotes"
v-if="tab === 'renotes' && renotes"
:key="item.user.id"
:user="item.user"
:with-chart="false"
@ -151,11 +151,12 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, onUpdated, ref } from "vue";
import * as misskey from "firefish-js";
import type * as misskey from "firefish-js";
import type { NoteUpdatedEvent } from "firefish-js/built/streaming.types";
import MkTab from "@/components/MkTab.vue";
import MkNote from "@/components/MkNote.vue";
import MkNoteSub from "@/components/MkNoteSub.vue";
import XRenoteButton from "@/components/MkRenoteButton.vue";
import type XRenoteButton from "@/components/MkRenoteButton.vue";
import MkUserCardMini from "@/components/MkUserCardMini.vue";
import MkReactedUsers from "@/components/MkReactedUsers.vue";
import { pleaseLogin } from "@/scripts/please-login";
@ -170,16 +171,15 @@ import { getNoteMenu } from "@/scripts/get-note-menu";
import { useNoteCapture } from "@/scripts/use-note-capture";
import { deepClone } from "@/scripts/clone";
import { stream } from "@/stream";
import { NoteUpdatedEvent } from "firefish-js/built/streaming.types";
const props = defineProps<{
note: misskey.entities.Note;
pinned?: boolean;
}>();
let tab = ref("replies");
const tab = ref("replies");
let note = ref(deepClone(props.note));
const note = ref(deepClone(props.note));
const softMuteReasonI18nSrc = (what?: string) => {
if (what === "note") return i18n.ts.userSaysSomethingReason;
@ -214,12 +214,12 @@ const muted = ref(
);
const translation = ref(null);
const translating = ref(false);
let conversation = ref<null | misskey.entities.Note[]>([]);
const conversation = ref<null | misskey.entities.Note[]>([]);
const replies = ref<misskey.entities.Note[]>([]);
let directReplies = ref<null | misskey.entities.Note[]>([]);
let directQuotes = ref<null | misskey.entities.Note[]>([]);
let clips = ref();
let renotes = ref();
const directReplies = ref<null | misskey.entities.Note[]>([]);
const directQuotes = ref<null | misskey.entities.Note[]>([]);
const clips = ref();
const renotes = ref();
let isScrolling;
const reactionsCount = Object.values(props.note.reactions).reduce(
@ -238,7 +238,7 @@ const keymap = {
useNoteCapture({
rootEl: el,
note: note,
note,
isDeletedRef: isDeleted,
});
@ -260,7 +260,7 @@ function react(viaKeyboard = false): void {
(reaction) => {
os.api("notes/reactions/create", {
noteId: note.value.id,
reaction: reaction,
reaction,
});
},
() => {

View file

@ -49,7 +49,6 @@
<script lang="ts" setup>
import { ref } from "vue";
import {} from "vue";
import type * as misskey from "firefish-js";
import { defaultStore } from "@/store";
import MkVisibility from "@/components/MkVisibility.vue";
@ -63,7 +62,7 @@ const props = defineProps<{
pinned?: boolean;
}>();
let note = ref(props.note);
const note = ref(props.note);
const showTicker =
defaultStore.state.instanceTicker === "always" ||

View file

@ -1,6 +1,6 @@
<template>
<div v-size="{ min: [350, 500] }" class="fefdfafb">
<MkAvatar class="avatar" :user="$i" disableLink />
<MkAvatar class="avatar" :user="$i" disable-link />
<div class="main">
<div class="header">
<MkUserName :user="$i" />
@ -11,7 +11,7 @@
:text="preprocess(text).trim()"
:author="$i"
:i="$i"
advancedMfm
advanced-mfm
/>
</div>
</div>

View file

@ -11,7 +11,7 @@
</template>
<script lang="ts" setup>
import * as misskey from "firefish-js";
import type * as misskey from "firefish-js";
import XNoteHeader from "@/components/MkNoteHeader.vue";
import MkSubNoteContent from "@/components/MkSubNoteContent.vue";

View file

@ -1,10 +1,10 @@
<template>
<article
v-if="!muted.muted || muted.what === 'reply'"
:id="detailedView ? appearNote.id : null"
ref="el"
v-size="{ max: [450, 500] }"
class="wrpstxzv"
:id="detailedView ? appearNote.id : null"
tabindex="-1"
:class="{
children: depth > 1,
@ -16,8 +16,8 @@
<div v-if="conversation && depth > 1" class="line"></div>
<div
class="main"
@click="noteClick"
:style="{ cursor: expandOnNoteClick ? 'pointer' : '' }"
@click="noteClick"
>
<div class="avatar-container">
<MkAvatar class="avatar" :user="appearNote.user" />
@ -32,9 +32,9 @@
<MkSubNoteContent
class="text"
:note="note"
:parentId="parentId"
:parent-id="parentId"
:conversation="conversation"
:detailedView="detailedView"
:detailed-view="detailedView"
@focusfooter="footerEl.focus()"
/>
<div v-if="translating || translation" class="translation">
@ -117,9 +117,9 @@
appearNote.myReaction != null
"
ref="reactButton"
v-tooltip.noDelay.bottom="i18n.ts.removeReaction"
class="button _button reacted"
@click.stop="undoReact(appearNote)"
v-tooltip.noDelay.bottom="i18n.ts.removeReaction"
>
<i class="ph-minus ph-bold ph-lg"></i>
</button>
@ -137,17 +137,17 @@
</div>
<template v-if="conversation">
<MkNoteSub
v-if="replyLevel < 11 && depth < 5"
v-for="reply in replies"
v-if="replyLevel < 11 && depth < 5"
:key="reply.id"
:note="reply"
class="reply"
:class="{ single: replies.length == 1 }"
:conversation="conversation"
:depth="replies.length == 1 ? depth : depth + 1"
:replyLevel="replyLevel + 1"
:parentId="appearNote.id"
:detailedView="detailedView"
:reply-level="replyLevel + 1"
:parent-id="appearNote.id"
:detailed-view="detailedView"
/>
<div v-else-if="replies.length > 0" class="more">
<div class="line"></div>
@ -177,9 +177,9 @@
</template>
<script lang="ts" setup>
import { inject, ref, computed } from "vue";
import { computed, inject, ref } from "vue";
import type { Ref } from "vue";
import * as misskey from "firefish-js";
import type * as misskey from "firefish-js";
import XNoteHeader from "@/components/MkNoteHeader.vue";
import MkSubNoteContent from "@/components/MkSubNoteContent.vue";
import XReactionsViewer from "@/components/MkReactionsViewer.vue";
@ -223,7 +223,7 @@ const props = withDefaults(
},
);
let note = ref(deepClone(props.note));
const note = ref(deepClone(props.note));
const softMuteReasonI18nSrc = (what?: string) => {
if (what === "note") return i18n.ts.userSaysSomethingReason;
@ -247,7 +247,7 @@ const menuButton = ref<HTMLElement>();
const starButton = ref<InstanceType<typeof XStarButton>>();
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
const reactButton = ref<HTMLElement>();
let appearNote = computed(() =>
const appearNote = computed(() =>
isRenote ? (note.value.renote as misskey.entities.Note) : note.value,
);
const isDeleted = ref(false);
@ -291,7 +291,7 @@ function react(viaKeyboard = false): void {
(reaction) => {
os.api("notes/reactions/create", {
noteId: appearNote.value.id,
reaction: reaction,
reaction,
});
},
() => {

View file

@ -12,7 +12,7 @@
</template>
<template #default="{ items: notes }">
<div class="giivymft" :class="{ noGap }" ref="tlEl">
<div ref="tlEl" class="giivymft" :class="{ noGap }">
<XList
ref="notes"
v-slot="{ item: note }"

View file

@ -219,7 +219,7 @@
<MkFollowButton
:user="notification.user"
:full="true"
:hideMenu="true"
:hide-menu="true"
/></div
></span>
<span
@ -273,8 +273,8 @@
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted, watch } from "vue";
import * as misskey from "firefish-js";
import { onMounted, onUnmounted, ref, watch } from "vue";
import type * as misskey from "firefish-js";
import XReactionIcon from "@/components/MkReactionIcon.vue";
import MkFollowButton from "@/components/MkFollowButton.vue";
import XReactionTooltip from "@/components/MkReactionTooltip.vue";
@ -310,8 +310,7 @@ const defaultReaction = ["⭐", "👍", "❤️"].includes(instance.defaultReact
? instance.defaultReaction
: "⭐";
let readObserver: IntersectionObserver | undefined;
let connection;
let readObserver: IntersectionObserver | undefined, connection;
onMounted(() => {
if (!props.notification.isRead) {

View file

@ -41,7 +41,6 @@
<script lang="ts" setup>
import { computed, ref } from "vue";
import {} from "vue";
import { notificationTypes } from "firefish-js";
import MkSwitch from "./form/switch.vue";
import MkInfo from "./MkInfo.vue";
@ -65,12 +64,12 @@ const props = withDefaults(
},
);
let includingTypes = computed(() => props.includingTypes || []);
const includingTypes = computed(() => props.includingTypes || []);
const dialog = ref<InstanceType<typeof XModalWindow>>();
let typesMap = ref<Record<(typeof notificationTypes)[number], boolean>>({});
let useGlobalSetting = ref(
const typesMap = ref<Record<(typeof notificationTypes)[number], boolean>>({});
const useGlobalSetting = ref(
(includingTypes.value === null || includingTypes.value.length === 0) &&
props.showGlobalToggle,
);

View file

@ -28,7 +28,7 @@ const emit = defineEmits<{
}>();
const zIndex = os.claimZIndex("high");
let showing = ref(true);
const showing = ref(true);
onMounted(() => {
window.setTimeout(() => {

View file

@ -26,7 +26,7 @@
"
:key="notification.id"
:note="notification.note"
:collapsedReply="
:collapsed-reply="
notification.type === 'reply' ||
(notification.type === 'mention' &&
notification.note.replyId != null)
@ -46,9 +46,10 @@
</template>
<script lang="ts" setup>
import { onUnmounted, onMounted, computed, ref } from "vue";
import { notificationTypes } from "firefish-js";
import MkPagination, { Paging } from "@/components/MkPagination.vue";
import { computed, onMounted, onUnmounted, ref } from "vue";
import type { notificationTypes } from "firefish-js";
import type { Paging } from "@/components/MkPagination.vue";
import MkPagination from "@/components/MkPagination.vue";
import XNotification from "@/components/MkNotification.vue";
import XList from "@/components/MkDateSeparatedList.vue";
import XNote from "@/components/MkNote.vue";

View file

@ -8,8 +8,8 @@
:buttons-left="buttonsLeft"
:buttons-right="buttonsRight"
:contextmenu="contextmenu"
@closed="$emit('closed')"
class="page-window"
@closed="$emit('closed')"
>
<template #header>
<template v-if="pageMetadata?.value">
@ -30,7 +30,8 @@
</template>
<script lang="ts" setup>
import { ComputedRef, provide, ref, computed } from "vue";
import type { ComputedRef } from "vue";
import { computed, provide, ref } from "vue";
import RouterView from "@/components/global/RouterView.vue";
import XWindow from "@/components/MkWindow.vue";
import { popout as _popout } from "@/scripts/popout";
@ -39,7 +40,8 @@ import { url } from "@/config";
import { mainRouter, routes } from "@/router";
import { Router } from "@/nirax";
import { i18n } from "@/i18n";
import { PageMetadata, provideMetadataReceiver } from "@/scripts/page-metadata";
import type { PageMetadata } from "@/scripts/page-metadata";
import { provideMetadataReceiver } from "@/scripts/page-metadata";
const props = defineProps<{
initialPath: string;
@ -51,8 +53,8 @@ defineEmits<{
const router = new Router(routes, props.initialPath);
let pageMetadata = ref<null | ComputedRef<PageMetadata>>();
let windowEl = ref<InstanceType<typeof XWindow>>();
const pageMetadata = ref<null | ComputedRef<PageMetadata>>();
const windowEl = ref<InstanceType<typeof XWindow>>();
const history = ref<{ path: string; key: any }[]>([
{
path: router.getCurrentPath(),

View file

@ -63,29 +63,22 @@
</template>
<script lang="ts" setup>
import {
computed,
ComputedRef,
isRef,
onActivated,
onDeactivated,
ref,
watch,
} from "vue";
import * as misskey from "firefish-js";
import type { ComputedRef } from "vue";
import { computed, isRef, onActivated, onDeactivated, ref, watch } from "vue";
import type * as misskey from "firefish-js";
import * as os from "@/os";
import {
onScrollTop,
isTopVisible,
getScrollPosition,
getScrollContainer,
getScrollPosition,
isTopVisible,
onScrollTop,
} from "@/scripts/scroll";
import MkButton from "@/components/MkButton.vue";
import { i18n } from "@/i18n";
export type Paging<
export interface Paging<
E extends keyof misskey.Endpoints = keyof misskey.Endpoints,
> = {
> {
endpoint: E;
limit: number;
params?:
@ -104,7 +97,7 @@ export type Paging<
reversed?: boolean;
offsetMode?: boolean;
};
}
const SECOND_FETCH_LIMIT = 30;
@ -123,7 +116,10 @@ const emit = defineEmits<{
(ev: "queue", count: number): void;
}>();
type Item = { id: string; [another: string]: unknown };
interface Item {
id: string;
[another: string]: unknown;
}
const rootEl = ref<HTMLElement>();
const items = ref<Item[]>([]);
@ -207,12 +203,12 @@ const refresh = async (): void => {
})
.then(
(res) => {
let ids = items.value.reduce(
const ids = items.value.reduce(
(a, b) => {
a[b.id] = true;
return a;
},
{} as { [id: string]: boolean },
{} as Record<string, boolean>,
);
for (let i = 0; i < res.length; i++) {

View file

@ -53,7 +53,7 @@
<script lang="ts" setup>
import { computed, ref } from "vue";
import * as misskey from "firefish-js";
import type * as misskey from "firefish-js";
import { sum } from "@/scripts/array";
import { pleaseLogin } from "@/scripts/please-login";
import * as os from "@/os";

View file

@ -16,8 +16,8 @@
</MkInput>
<button
class="_button"
@click="remove(i)"
:aria-label="i18n.t('remove')"
@click="remove(i)"
>
<i class="ph-x ph-bold ph-lg"></i>
</button>

View file

@ -5,9 +5,9 @@
:z-priority="'high'"
:src="src"
:transparent-bg="true"
tabindex="-1"
@click="modal?.close()"
@closed="emit('closed')"
tabindex="-1"
>
<MkMenu
:items="items"
@ -28,7 +28,7 @@ import { ref } from "vue";
import MkModal from "./MkModal.vue";
import MkMenu from "./MkMenu.vue";
import { MenuItem } from "@/types/menu";
import type { MenuItem } from "@/types/menu";
defineProps<{
items: MenuItem[];
@ -43,7 +43,7 @@ const emit = defineEmits<{
(ev: "closed"): void;
}>();
let modal = ref<InstanceType<typeof MkModal>>();
const modal = ref<InstanceType<typeof MkModal>>();
</script>
<style lang="scss" scoped>

View file

@ -86,8 +86,8 @@
{{ i18n.ts.quoteAttached
}}<button
class="_button"
@click="quoteId = null"
:aria-label="i18n.t('removeQuote')"
@click="quoteId = null"
>
<i class="ph-x ph-bold ph-lg"></i>
</button>
@ -99,8 +99,8 @@
<MkAcct :user="u" />
<button
class="_button"
@click="removeVisibleUser(u)"
:aria-label="i18n.t('removeRecipient')"
@click="removeVisibleUser(u)"
>
<i class="ph-x ph-bold ph-lg"></i>
</button>
@ -234,16 +234,16 @@
<script lang="ts" setup>
import {
computed,
defineAsyncComponent,
inject,
watch,
nextTick,
onMounted,
defineAsyncComponent,
ref,
computed,
watch,
} from "vue";
import * as mfm from "mfm-js";
import * as misskey from "firefish-js";
import type * as misskey from "firefish-js";
import autosize from "autosize";
import insertTextAtCursor from "insert-text-at-cursor";
import { length } from "stringz";
@ -315,40 +315,42 @@ const cwInputEl = ref<HTMLInputElement | null>(null);
const hashtagsInputEl = ref<HTMLInputElement | null>(null);
const visibilityButton = ref<HTMLElement | null>(null);
let posting = ref(false);
let text = ref(props.initialText ?? "");
let files = ref(props.initialFiles ?? []);
let poll = ref<{
const posting = ref(false);
const text = ref(props.initialText ?? "");
const files = ref(props.initialFiles ?? []);
const poll = ref<{
choices: string[];
multiple: boolean;
expiresAt: string | null;
expiredAfter: string | null;
} | null>(null);
let useCw = ref(false);
let showPreview = ref(false);
let cw = ref<string | null>(null);
let localOnly = ref<boolean>(
const useCw = ref(false);
const showPreview = ref(false);
const cw = ref<string | null>(null);
const localOnly = ref<boolean>(
props.initialLocalOnly ?? defaultStore.state.rememberNoteVisibility
? defaultStore.state.localOnly
: defaultStore.state.defaultNoteLocalOnly,
);
let visibility = ref(
const visibility = ref(
props.initialVisibility ??
((defaultStore.state.rememberNoteVisibility
? defaultStore.state.visibility
: defaultStore.state
.defaultNoteVisibility) as (typeof misskey.noteVisibilities)[number]),
);
let visibleUsers = ref([]);
const visibleUsers = ref([]);
if (props.initialVisibleUsers) {
props.initialVisibleUsers.forEach(pushVisibleUser);
}
let autocomplete = ref(null);
let draghover = ref(false);
let quoteId = ref(null);
let hasNotSpecifiedMentions = ref(false);
let recentHashtags = ref(JSON.parse(localStorage.getItem("hashtags") || "[]"));
let imeText = ref("");
const autocomplete = ref(null);
const draghover = ref(false);
const quoteId = ref(null);
const hasNotSpecifiedMentions = ref(false);
const recentHashtags = ref(
JSON.parse(localStorage.getItem("hashtags") || "[]"),
);
const imeText = ref("");
const typing = throttle(3000, () => {
if (props.channel) {
@ -415,8 +417,8 @@ const maxTextLength = computed((): number => {
const canPost = computed((): boolean => {
return (
!posting.value &&
(1 <= textLength.value ||
1 <= files.value.length ||
(textLength.value >= 1 ||
files.value.length >= 1 ||
!!poll.value ||
!!props.renote) &&
textLength.value <= maxTextLength.value &&
@ -896,7 +898,7 @@ async function post() {
}
}
let token = undefined;
let token;
if (postAccount.value) {
const storedAccounts = await getAccounts();
@ -976,7 +978,7 @@ function showActions(ev) {
);
}
let postAccount = ref<misskey.entities.UserDetailed | null>(null);
const postAccount = ref<misskey.entities.UserDetailed | null>(null);
function openAccountMenu(ev: MouseEvent) {
openAccountMenu_(

View file

@ -8,9 +8,9 @@
delay-on-touch-only="true"
>
<div
class="file"
v-for="element in _files"
:key="element.id"
class="file"
@click="showFileMenu(element, $event)"
@contextmenu.prevent="showFileMenu(element, $event)"
>
@ -30,7 +30,7 @@
</template>
<script lang="ts" setup>
import { defineAsyncComponent, ref, computed } from "vue";
import { computed, defineAsyncComponent, ref } from "vue";
import { VueDraggable } from "vue-draggable-plus";
import MkDriveFileThumbnail from "@/components/MkDriveFileThumbnail.vue";
import * as os from "@/os";
@ -105,10 +105,11 @@ async function describe(file) {
{
done: (result) => {
if (!result || result.canceled) return;
let comment = result.result.length === 0 ? null : result.result;
const comment =
result.result.length === 0 ? null : result.result;
os.api("drive/files/update", {
fileId: file.id,
comment: comment,
comment,
}).then(() => {
file.comment = comment;
});

View file

@ -21,8 +21,7 @@
<script lang="ts" setup>
import { shallowRef } from "vue";
import {} from "vue";
import * as misskey from "firefish-js";
import type * as misskey from "firefish-js";
import MkModal from "@/components/MkModal.vue";
import MkPostForm from "@/components/MkPostForm.vue";
@ -48,8 +47,8 @@ const emit = defineEmits<{
(ev: "closed"): void;
}>();
let modal = shallowRef<InstanceType<typeof MkModal>>();
let form = shallowRef<InstanceType<typeof MkPostForm>>();
const modal = shallowRef<InstanceType<typeof MkModal>>();
const form = shallowRef<InstanceType<typeof MkPostForm>>();
function onPosted() {
modal.value.close({

View file

@ -76,12 +76,12 @@ defineProps<{
}>();
// ServiceWorker registration
let registration = ref<ServiceWorkerRegistration | undefined>();
const registration = ref<ServiceWorkerRegistration | undefined>();
// If this browser supports push notification
let supported = ref(false);
const supported = ref(false);
// If this browser has already subscribed to push notification
let pushSubscription = ref<PushSubscription | null>(null);
let pushRegistrationInServer = ref<
const pushSubscription = ref<PushSubscription | null>(null);
const pushRegistrationInServer = ref<
| {
state?: string;
key?: string;
@ -209,6 +209,6 @@ if (navigator.serviceWorker == null) {
}
defineExpose({
pushRegistrationInServer: pushRegistrationInServer,
pushRegistrationInServer,
});
</script>

View file

@ -36,8 +36,8 @@
</template>
<script lang="ts" setup>
import { onMounted, watch, ref } from "vue";
import * as misskey from "firefish-js";
import { onMounted, ref, watch } from "vue";
import type * as misskey from "firefish-js";
import MkReactionIcon from "@/components/MkReactionIcon.vue";
import MkUserCardMini from "@/components/MkUserCardMini.vue";
import * as os from "@/os";
@ -46,10 +46,10 @@ const props = defineProps<{
noteId: misskey.entities.Note["id"];
}>();
let note = ref<misskey.entities.Note>();
let tab = ref<string>();
let reactions = ref<string[]>();
let users = ref();
const note = ref<misskey.entities.Note>();
const tab = ref<string>();
const reactions = ref<string[]>();
const users = ref();
watch(tab, async () => {
const res = await os.api("notes/reactions", {

View file

@ -22,7 +22,7 @@
<script lang="ts" setup>
import { computed, ref } from "vue";
import * as misskey from "firefish-js";
import type * as misskey from "firefish-js";
import XDetails from "@/components/MkReactionsViewer.details.vue";
import XReactionIcon from "@/components/MkReactionIcon.vue";
import * as os from "@/os";

View file

@ -18,7 +18,7 @@
<script lang="ts" setup>
import { computed, ref } from "vue";
import * as misskey from "firefish-js";
import type * as misskey from "firefish-js";
import { $i } from "@/account";
import XReaction from "@/components/MkReactionsViewer.reaction.vue";

View file

@ -12,9 +12,9 @@
</button>
<button
v-else
v-tooltip.noDelay.bottom="i18n.ts.disabled"
class="eddddedb _button"
disabled="true"
v-tooltip.noDelay.bottom="i18n.ts.disabled"
>
<i class="ph-repeat ph-bold ph-lg"></i>
</button>
@ -31,7 +31,7 @@ import { $i } from "@/account";
import { useTooltip } from "@/scripts/use-tooltip";
import { i18n } from "@/i18n";
import { defaultStore } from "@/store";
import { MenuItem } from "@/types/menu";
import type { MenuItem } from "@/types/menu";
const props = defineProps<{
note: misskey.entities.Note;
@ -70,7 +70,7 @@ useTooltip(buttonRef, async (showing) => {
);
});
let hasRenotedBefore = ref(false);
const hasRenotedBefore = ref(false);
os.api("notes/renotes", {
noteId: props.note.id,
userId: $i.id,
@ -82,7 +82,7 @@ os.api("notes/renotes", {
const renote = (viaKeyboard = false, ev?: MouseEvent) => {
pleaseLogin();
let buttonActions: Array<MenuItem> = [];
const buttonActions: Array<MenuItem> = [];
if (props.note.visibility === "public") {
buttonActions.push({
@ -191,7 +191,7 @@ const renote = (viaKeyboard = false, ev?: MouseEvent) => {
});
}
if (canRenote) {
if (canRenote.value) {
buttonActions.push({
text: `${i18n.ts.renote} (${i18n.ts.local})`,
icon: "ph-hand-fist ph-bold ph-lg",

View file

@ -9,8 +9,8 @@
</button>
</template>
<script lang="ts" setup>
import { i18n } from "@/i18n";
import { ref } from "vue";
import { i18n } from "@/i18n";
const props = defineProps<{
modelValue: boolean;

View file

@ -160,7 +160,7 @@
</template>
<script lang="ts" setup>
import { defineAsyncComponent, ref, computed } from "vue";
import { computed, defineAsyncComponent, ref } from "vue";
import { toUnicode } from "punycode/";
import MkButton from "@/components/MkButton.vue";
import MkInput from "@/components/form/input.vue";
@ -172,17 +172,17 @@ import { login } from "@/account";
import { instance } from "@/instance";
import { i18n } from "@/i18n";
let signing = ref(false);
let user = ref(null);
let username = ref("");
let password = ref("");
let token = ref("");
let host = ref(toUnicode(configHost));
let totpLogin = ref(false);
let challengeData = ref(null);
let queryingKey = ref(false);
let hCaptchaResponse = ref(null);
let reCaptchaResponse = ref(null);
const signing = ref(false);
const user = ref(null);
const username = ref("");
const password = ref("");
const token = ref("");
const host = ref(toUnicode(configHost));
const totpLogin = ref(false);
const challengeData = ref(null);
const queryingKey = ref(false);
const hCaptchaResponse = ref(null);
const reCaptchaResponse = ref(null);
const meta = computed(() => instance);

View file

@ -14,7 +14,6 @@
<script lang="ts" setup>
import { ref } from "vue";
import {} from "vue";
import MkSignin from "@/components/MkSignin.vue";
import XModalWindow from "@/components/MkModalWindow.vue";
import { i18n } from "@/i18n";

View file

@ -284,7 +284,7 @@
</template>
<script lang="ts" setup>
import { ref, computed } from "vue";
import { computed, ref } from "vue";
import getPasswordStrength from "syuilo-password-strength";
import { toUnicode } from "punycode/";
@ -314,15 +314,15 @@ const emit = defineEmits<{
const host = toUnicode(config.host);
let hcaptcha = ref();
let recaptcha = ref();
const hcaptcha = ref();
const recaptcha = ref();
let username: string = ref("");
let password: string = ref("");
let retypedPassword: string = ref("");
let invitationCode: string = ref("");
let email = ref("");
let usernameState:
const username: string = ref("");
const password: string = ref("");
const retypedPassword: string = ref("");
const invitationCode: string = ref("");
const email = ref("");
const usernameState:
| null
| "wait"
| "ok"
@ -331,8 +331,8 @@ let usernameState:
| "invalid-format"
| "min-range"
| "max-range" = ref(null);
let invitationState: null | "entered" = ref(null);
let emailState:
const invitationState: null | "entered" = ref(null);
const emailState:
| null
| "wait"
| "ok"
@ -343,12 +343,12 @@ let emailState:
| "unavailable:smtp"
| "unavailable"
| "error" = ref(null);
let passwordStrength: "" | "low" | "medium" | "high" = ref("");
let passwordRetypeState: null | "match" | "not-match" = ref(null);
let submitting: boolean = ref(false);
let ToSAgreement: boolean = ref(false);
let hCaptchaResponse = ref(null);
let reCaptchaResponse = ref(null);
const passwordStrength: "" | "low" | "medium" | "high" = ref("");
const passwordRetypeState: null | "match" | "not-match" = ref(null);
const submitting: boolean = ref(false);
const ToSAgreement: boolean = ref(false);
const hCaptchaResponse = ref(null);
const reCaptchaResponse = ref(null);
const shouldDisableSubmitting = computed((): boolean => {
return (

View file

@ -79,8 +79,8 @@ const el = ref<HTMLElement>();
const width = ref(0);
const height = ref(0);
const colors = ["#eb6f92", "#9ccfd8", "#f6c177", "#f6c177", "#f6c177"];
let stop = false;
let ro: ResizeObserver | undefined;
let stop = false,
ro: ResizeObserver | undefined;
onMounted(() => {
if (!reducedMotion()) {

View file

@ -1,9 +1,9 @@
<template>
<button
ref="buttonRef"
v-tooltip.noDelay.bottom="i18n.ts._gallery.like"
class="button _button"
:class="$style.root"
ref="buttonRef"
@click.stop="toggleStar($event)"
>
<span v-if="!reacted">

View file

@ -13,13 +13,13 @@
</MkA>
<MkA
v-else-if="!detailed && note.replyId"
v-tooltip="i18n.ts.jumpToPrevious"
:to="
detailedView
? `#${note.replyId}`
: `${notePage(note)}#${note.replyId}`
"
behavior="browser"
v-tooltip="i18n.ts.jumpToPrevious"
class="reply-icon"
@click.stop
>
@ -46,18 +46,18 @@
}"
>
<XShowMoreButton
ref="showMoreButton"
v-if="isLong && collapsed"
ref="showMoreButton"
v-model="collapsed"
v-on:keydown="focusFooter"
@keydown="focusFooter"
></XShowMoreButton>
<XCwButton
ref="cwButton"
v-if="note.cw && !showContent"
ref="cwButton"
v-model="showContent"
:note="note"
v-on:keydown="focusFooter"
v-on:update:model-value="(val) => emit('expanded', val)"
@keydown="focusFooter"
@update:model-value="(val) => emit('expanded', val)"
/>
<div
class="body"
@ -85,13 +85,13 @@
</MkA>
<MkA
v-else-if="!detailed && note.replyId"
v-tooltip="i18n.ts.jumpToPrevious"
:to="
detailedView
? `#${note.replyId}`
: `${notePage(note)}#${note.replyId}`
"
behavior="browser"
v-tooltip="i18n.ts.jumpToPrevious"
class="reply-icon"
@click.stop
>
@ -139,7 +139,7 @@
(showMoreButton && collapsed)
"
tabindex="0"
v-on:focus="
@focus="
cwButton?.focus();
showMoreButton?.focus();
"
@ -157,9 +157,9 @@
</div>
<MkButton
v-if="hasMfm && defaultStore.state.animatedMfm"
@click.stop="toggleMfm"
mini
rounded
@click.stop="toggleMfm"
>
<template v-if="disableMfm">
<i class="ph-play ph-bold"></i> {{ i18n.ts._mfm.play }}
@ -177,7 +177,7 @@
<script lang="ts" setup>
import { ref } from "vue";
import * as misskey from "firefish-js";
import type * as misskey from "firefish-js";
import * as mfm from "mfm-js";
import * as os from "@/os";
import XNoteSimple from "@/components/MkNoteSimple.vue";
@ -222,7 +222,7 @@ const urls = props.note.text
? extractUrlFromMfm(mfm.parse(props.note.text)).slice(0, 5)
: null;
let showContent = ref(false);
const showContent = ref(false);
const mfms = props.note.text
? extractMfmWithAnimation(mfm.parse(props.note.text))
@ -230,7 +230,7 @@ const mfms = props.note.text
const hasMfm = ref(mfms && mfms.length > 0);
let disableMfm = ref(defaultStore.state.animatedMfm);
const disableMfm = ref(defaultStore.state.animatedMfm);
async function toggleMfm() {
if (disableMfm.value) {

View file

@ -17,7 +17,7 @@
</template>
<script lang="ts" setup>
import { onMounted, watch, onBeforeUnmount, ref } from "vue";
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
import tinycolor from "tinycolor2";
const loaded = !!window.TagCanvas;
@ -39,11 +39,11 @@ const idForTags = Array.from(Array(16))
],
)
.join("");
let available = ref(false);
let rootEl = ref<HTMLElement | null>(null);
let canvasEl = ref<HTMLCanvasElement | null>(null);
let tagsEl = ref<HTMLElement | null>(null);
let width = ref(300);
const available = ref(false);
const rootEl = ref<HTMLElement | null>(null);
const canvasEl = ref<HTMLCanvasElement | null>(null);
const tagsEl = ref<HTMLElement | null>(null);
const width = ref(300);
watch(available, () => {
try {

View file

@ -12,8 +12,8 @@
<div v-if="queue > 0" class="new">
<button
class="_buttonPrimary _shadow"
@click="tlComponent.scrollTop()"
:class="{ instant: !$store.state.animation }"
@click="tlComponent.scrollTop()"
>
{{ i18n.ts.newNoteRecived }}
<i class="ph-arrow-up ph-bold"></i>
@ -28,7 +28,7 @@
</template>
<script lang="ts" setup>
import { computed, provide, onUnmounted, ref } from "vue";
import { computed, onUnmounted, provide, ref } from "vue";
import XNotes from "@/components/MkNotes.vue";
import MkInfo from "@/components/MkInfo.vue";
import { stream } from "@/stream";
@ -45,7 +45,7 @@ const props = defineProps<{
sound?: boolean;
}>();
let queue = ref(0);
const queue = ref(0);
const emit = defineEmits<{
(ev: "note"): void;
@ -83,13 +83,7 @@ const onChangeFollowing = () => {
}
};
let endpoint;
let query;
let connection;
let connection2;
let tlHint;
let tlHintClosed;
let endpoint, query, connection, connection2, tlHint, tlHintClosed;
if (props.src === "antenna") {
endpoint = "antennas/notes";
@ -223,7 +217,7 @@ function closeHint() {
}
const pagination = {
endpoint: endpoint,
endpoint,
limit: 10,
params: query,
};

View file

@ -30,7 +30,7 @@ const emit = defineEmits<{
}>();
const zIndex = os.claimZIndex("high");
let showing = ref(true);
const showing = ref(true);
onMounted(() => {
window.setTimeout(() => {

View file

@ -6,10 +6,10 @@
:with-ok-button="true"
:ok-button-disabled="false"
:can-close="false"
style="padding: 12px"
@close="dialog.close()"
@closed="$emit('closed')"
@ok="ok()"
style="padding: 12px"
>
<template #header>{{ title || i18n.ts.generateAccessToken }}</template>
<div v-if="information" class="_section">
@ -19,7 +19,7 @@
<div style="margin-bottom: 16px">
<b>{{ i18n.ts.name }}</b>
</div>
<MkInput style="margin-bottom: 16px" v-model="name" />
<MkInput v-model="name" style="margin-bottom: 16px" />
</div>
<div class="_section">
<div style="margin-bottom: 16px">
@ -32,10 +32,10 @@
i18n.ts.enableAll
}}</MkButton>
<MkSwitch
style="margin-bottom: 6px"
v-for="kind in initialPermissions || kinds"
:key="kind"
v-model="permissions[kind]"
style="margin-bottom: 6px"
>{{ i18n.t(`_permissions.${kind}`) }}</MkSwitch
>
</div>
@ -45,7 +45,6 @@
<script lang="ts" setup>
import { ref } from "vue";
import {} from "vue";
import { permissions as kinds } from "firefish-js";
import MkInput from "./form/input.vue";
import MkSwitch from "./form/switch.vue";
@ -75,8 +74,8 @@ const emit = defineEmits<{
}>();
const dialog = ref<InstanceType<typeof XModalWindow>>();
let name = ref(props.initialName);
let permissions = ref({});
const name = ref(props.initialName);
const permissions = ref({});
if (props.initialPermissions) {
for (const kind of props.initialPermissions) {

View file

@ -230,7 +230,7 @@ const isGlobalTimelineAvailable =
!instance.disableGlobalTimeline ||
($i != null && ($i.isModerator || $i.isAdmin));
let timelines = ["home"];
const timelines = ["home"];
if (isLocalTimelineAvailable) {
timelines.push("local");

View file

@ -33,7 +33,7 @@
</template>
<script lang="ts" setup>
import { shallowRef, ref } from "vue";
import { ref, shallowRef } from "vue";
import MkModal from "@/components/MkModal.vue";
import MkSparkle from "@/components/MkSparkle.vue";
import MkButton from "@/components/MkButton.vue";
@ -43,8 +43,8 @@ import * as os from "@/os";
const modal = shallowRef<InstanceType<typeof MkModal>>();
let newRelease = ref(false);
let data = ref(Object);
const newRelease = ref(false);
const data = ref(Object);
os.api("release").then((res) => {
data.value = res;

Some files were not shown because too many files have changed in this diff Show more