Merge branch 'develop' of https://codeberg.org/calckey/calckey into keyboard-accessability
|
@ -27,9 +27,9 @@
|
|||
- Notable differences:
|
||||
- Improved UI/UX (especially on mobile)
|
||||
- Improved notifications
|
||||
- Fediverse account migration
|
||||
- Improved instance security
|
||||
- Improved accessibility
|
||||
- Improved threads
|
||||
- Recommended Instances timeline
|
||||
- OCR image captioning
|
||||
- New and improved Groups
|
||||
|
|
|
@ -675,3 +675,48 @@ useGlobalSetting: Fes servir els ajustos globals
|
|||
useGlobalSettingDesc: Si s'activa, es faran servir els ajustos de notificacions del
|
||||
teu compte. Si es desactiva , es poden fer configuracions individuals.
|
||||
other: Altres
|
||||
menu: Menú
|
||||
addItem: Afegeix un element
|
||||
divider: Divisor
|
||||
relays: Relés
|
||||
addRelay: Afegeix un Relé
|
||||
inboxUrl: Adreça de la safata d'entrada
|
||||
addedRelays: Relés afegits
|
||||
serviceworkerInfo: Ha de estar activat per les notificacions push.
|
||||
poll: Enquesta
|
||||
deletedNote: Article eliminat
|
||||
disablePlayer: Tancar el reproductor de vídeo
|
||||
fileIdOrUrl: ID o adreça URL del fitxer
|
||||
behavior: Comportament
|
||||
regenerateLoginTokenDescription: Regenera el token que es fa servir de manera interna
|
||||
durant l'inici de sessió. Normalment això no és necessari. Si es torna a genera
|
||||
el token, es tancarà la sessió a tots els dispositius.
|
||||
setMultipleBySeparatingWithSpace: Separa diferents entrades amb espais.
|
||||
reportAbuseOf: Informa sobre {name}
|
||||
sample: Exemple
|
||||
abuseReports: Informes
|
||||
reportAbuse: Informe
|
||||
reporter: Informador
|
||||
reporterOrigin: Origen d'el informador
|
||||
forwardReport: Envia l'informe a una instancia remota
|
||||
abuseReported: El teu informe ha sigut enviat. Moltes gràcies.
|
||||
reporteeOrigin: Origen de l'informe
|
||||
send: Enviar
|
||||
abuseMarkAsResolved: Marcar l'informe com a resolt
|
||||
visibility: Visibilitat
|
||||
useCw: Amaga el contingut
|
||||
enablePlayer: Obre el reproductor de vídeo
|
||||
yourAccountSuspendedDescription: Aquest compte ha sigut suspesa per no seguir els
|
||||
termes de servei del servidor o quelcom similar. Contacte amb l'administrador si
|
||||
vols conèixer la raó amb més detall. Si us plau no facis un compte nou.
|
||||
invisibleNote: Article ocult
|
||||
enableInfiniteScroll: Carregar més de forma automàtica
|
||||
fillAbuseReportDescription: Si us plau omple els detalls sobre aquest informe. Si
|
||||
es sobre un article en concret, si us plau inclou l'adreça URL.
|
||||
forwardReportIsAnonymous: Com a informador a l'instància remota no es mostrarà el
|
||||
teu compte, si no un compte anònim.
|
||||
openInNewTab: Obrir en una pestanya nova
|
||||
openInSideView: Obrir a la vista lateral
|
||||
defaultNavigationBehaviour: Navegació per defecte
|
||||
editTheseSettingsMayBreakAccount: Si edites aquestes configuracions pots fer mal bé
|
||||
el teu compte.
|
||||
|
|
|
@ -1042,7 +1042,7 @@ moveFromLabel: "Account you're moving from:"
|
|||
moveFromDescription: "This will set an alias of your old account so that you can move\
|
||||
\ from that account to this current one. Do this BEFORE moving from your older account.\
|
||||
\ Please enter the tag of the account formatted like @person@instance.com"
|
||||
migrationConfirm: "Are you absolutely sure you want to migrate your acccount to {account}?\
|
||||
migrationConfirm: "Are you absolutely sure you want to migrate your account to {account}?\
|
||||
\ Once you do this, you won't be able to reverse it, and you won't be able to use\
|
||||
\ your account normally again.\nAlso, please ensure that you've set this current\
|
||||
\ account as the account you're moving from."
|
||||
|
|
182
locales/fi.yml
|
@ -3,7 +3,7 @@ fetchingAsApObject: Hae Fedeversestä
|
|||
gotIt: Selvä!
|
||||
cancel: Peruuta
|
||||
enterUsername: Anna käyttäjänimi
|
||||
renotedBy: Buustannut {käyttäjä}
|
||||
renotedBy: Buustannut {user}
|
||||
noNotes: Ei lähetyksiä
|
||||
noNotifications: Ei ilmoituksia
|
||||
instance: Instanssi
|
||||
|
@ -41,3 +41,183 @@ favorite: Lisää kirjanmerkkeihin
|
|||
copyContent: Kopioi sisältö
|
||||
deleteAndEdit: Poista ja muokkaa
|
||||
copyLink: Kopioi linkki
|
||||
makeFollowManuallyApprove: Seuraajapyyntö vaatii hyväksymistä
|
||||
follow: Seuraa
|
||||
pinned: Kiinnitä profiiliin
|
||||
followRequestPending: Seuraajapyyntö odottaa
|
||||
you: Sinä
|
||||
unrenote: Peruuta buustaus
|
||||
reaction: Reaktiot
|
||||
reactionSettingDescription2: Vedä uudelleenjärjestelläksesi, napsauta poistaaksesi,
|
||||
paina "+" lisätäksesi.
|
||||
attachCancel: Poista liite
|
||||
enterFileName: Anna tiedostonimi
|
||||
mute: Hiljennä
|
||||
unmute: Poista hiljennys
|
||||
headlineMisskey: Avoimen lähdekoodin, hajautettu sosiaalisen median alusta, joka on
|
||||
ikuisesti ilmainen! 🚀
|
||||
monthAndDay: '{day}/{month}'
|
||||
deleteAndEditConfirm: Oletko varma, että haluat poistaa tämän lähetyksen ja muokata
|
||||
sitä? Menetät kaikki reaktiot, buustaukset ja vastaukset lähetyksestäsi.
|
||||
addToList: Lisää listaan
|
||||
sendMessage: Lähetä viesti
|
||||
reply: Vastaa
|
||||
loadMore: Lataa enemmän
|
||||
showMore: Näytä enemmän
|
||||
receiveFollowRequest: Seuraajapyyntö vastaanotettu
|
||||
followRequestAccepted: Seuraajapyyntö hyväksytty
|
||||
mentions: Maininnat
|
||||
importAndExport: Tuo/Vie Tietosisältö
|
||||
import: Tuo
|
||||
export: Vie
|
||||
files: Tiedostot
|
||||
download: Lataa
|
||||
unfollowConfirm: Oletko varma, ettet halua seurata enää käyttäjää {name}?
|
||||
noLists: Sinulla ei ole listoja
|
||||
note: Lähetys
|
||||
notes: Lähetykset
|
||||
following: Seuraa
|
||||
createList: Luo lista
|
||||
manageLists: Hallitse listoja
|
||||
error: Virhe
|
||||
somethingHappened: On tapahtunut virhe
|
||||
retry: Yritä uudelleen
|
||||
pageLoadError: Virhe ladattaessa sivua.
|
||||
serverIsDead: Tämä palvelin ei vastaa. Yritä hetken kuluttua uudelleen.
|
||||
youShouldUpgradeClient: Nähdäksesi tämän sivun, virkistä päivittääksesi asiakasohjelmasi.
|
||||
privacy: Tietosuoja
|
||||
defaultNoteVisibility: Oletusnäkyvyys
|
||||
followRequest: Seuraajapyyntö
|
||||
followRequests: Seuraajapyynnöt
|
||||
unfollow: Poista seuraaminen
|
||||
enterEmoji: Syötä emoji
|
||||
renote: Buustaa
|
||||
renoted: Buustattu.
|
||||
cantRenote: Tätä lähetystä ei voi buustata.
|
||||
cantReRenote: Buustausta ei voi buustata.
|
||||
quote: Lainaus
|
||||
pinnedNote: Lukittu lähetys
|
||||
clickToShow: Napsauta nähdäksesi
|
||||
sensitive: Herkkää sisältöä (NSFW)
|
||||
add: Lisää
|
||||
enableEmojiReactions: Ota käyttöön emoji-reaktiot
|
||||
showEmojisInReactionNotifications: Näytä emojit reaktioilmoituksissa
|
||||
reactionSetting: Reaktiot näytettäväksi reaktiovalitsimessa
|
||||
rememberNoteVisibility: Muista lähetyksen näkyvyysasetukset
|
||||
markAsSensitive: Merkitse herkäksi sisällöksi (NSFW)
|
||||
unmarkAsSensitive: Poista merkintä herkkää sisältöä (NSFW)
|
||||
renoteMute: Hiljennä buustit
|
||||
renoteUnmute: Poista buustien hiljennys
|
||||
block: Estä
|
||||
unblock: Poista esto
|
||||
unsuspend: Poista keskeytys
|
||||
suspend: Keskeytys
|
||||
blockConfirm: Oletko varma, että haluat estää tämän tilin?
|
||||
unblockConfirm: Oletko varma, että haluat poistaa tämän tilin eston?
|
||||
selectAntenna: Valitse antenni
|
||||
selectWidget: Valitse vimpain
|
||||
editWidgets: Muokkaa vimpaimia
|
||||
editWidgetsExit: Valmis
|
||||
emoji: Emoji
|
||||
emojis: Emojit
|
||||
emojiName: Emojin nimi
|
||||
emojiUrl: Emojin URL-linkki
|
||||
cacheRemoteFiles: Taltioi etätiedostot välimuistiin
|
||||
flagAsBot: Merkitse tili botiksi
|
||||
flagAsBotDescription: Ota tämä vaihtoehto käyttöön, jos tätä tiliä ohjaa ohjelma.
|
||||
Jos se on käytössä, se toimii lippuna muille kehittäjille, jotta estetään loputtomat
|
||||
vuorovaikutusketjut muiden bottien kanssa ja säädetään Calckeyn sisäiset järjestelmät
|
||||
käsittelemään tätä tiliä botina.
|
||||
flagAsCat: Oletko kissa? 🐱
|
||||
flagAsCatDescription: Saat kissan korvat ja puhut kuin kissa!
|
||||
flagSpeakAsCat: Puhu kuin kissa
|
||||
flagShowTimelineReplies: Näytä vastaukset aikajanalla
|
||||
addAccount: Lisää tili
|
||||
loginFailed: Kirjautuminen epäonnistui
|
||||
showOnRemote: Katsele etäinstanssilla
|
||||
general: Yleistä
|
||||
accountMoved: 'Käyttäjä on muuttanut uuteen tiliin:'
|
||||
wallpaper: Taustakuva
|
||||
setWallpaper: Aseta taustakuva
|
||||
searchWith: 'Etsi: {q}'
|
||||
youHaveNoLists: Sinulla ei ole listoja
|
||||
followConfirm: Oletko varma, että haluat seurata käyttäjää {name}?
|
||||
host: Isäntä
|
||||
selectUser: Valitse käyttäjä
|
||||
annotation: Kommentit
|
||||
registeredAt: Rekisteröity
|
||||
latestRequestReceivedAt: Viimeisin pyyntö vastaanotettu
|
||||
latestRequestSentAt: Viimeisin pyyntö lähetetty
|
||||
storageUsage: Tallennustilan käyttö
|
||||
charts: Kaaviot
|
||||
stopActivityDelivery: Lopeta toimintojen lähettäminen
|
||||
blockThisInstance: Estä tämä instanssi
|
||||
operations: Toiminnot
|
||||
metadata: Metatieto
|
||||
monitor: Seuranta
|
||||
jobQueue: Työjono
|
||||
cpuAndMemory: Prosessori ja muisti
|
||||
network: Verkko
|
||||
disk: Levy
|
||||
clearCachedFiles: Tyhjennä välimuisti
|
||||
clearCachedFilesConfirm: Oletko varma, että haluat tyhjentää kaikki välimuistiin tallennetut
|
||||
etätiedostot?
|
||||
blockedInstances: Estetyt instanssit
|
||||
hiddenTags: Piilotetut asiatunnisteet
|
||||
mention: Maininta
|
||||
copyUsername: Kopioi käyttäjänimi
|
||||
searchUser: Etsi käyttäjää
|
||||
showLess: Sulje
|
||||
youGotNewFollower: seurasi sinua
|
||||
directNotes: Yksityisviestit
|
||||
driveFileDeleteConfirm: Oletko varma, että haluat poistaa tiedoston " {name}"? Lähetykset,
|
||||
jotka sisältyvät tiedostoon, poistuvat myös.
|
||||
importRequested: Olet pyytänyt viemistä. Tämä voi viedä hetken.
|
||||
exportRequested: Olet pyytänyt tuomista. Tämä voi viedä hetken. Se lisätään asemaan
|
||||
kun tuonti valmistuu.
|
||||
lists: Listat
|
||||
followers: Seuraajat
|
||||
followsYou: Seuraa sinua
|
||||
pageLoadErrorDescription: Tämä yleensä johtuu verkkovirheistä tai selaimen välimuistista.
|
||||
Kokeile tyhjentämällä välimuisti ja yritä sitten hetken kuluttua uudelleen.
|
||||
enterListName: Anna listalle nimi
|
||||
withNFiles: '{n} tiedosto(t)'
|
||||
instanceInfo: Instanssin tiedot
|
||||
clearQueue: Tyhjennä jono
|
||||
suspendConfirm: Oletko varma, että haluat keskeyttää tämän tilin?
|
||||
unsuspendConfirm: Oletko varma, että haluat poistaa tämän tilin keskeytyksen?
|
||||
selectList: Valitse lista
|
||||
customEmojis: Kustomoitu Emoji
|
||||
addEmoji: Lisää
|
||||
settingGuide: Suositellut asetukset
|
||||
cacheRemoteFilesDescription: Kun tämä asetus ei ole käytössä, etätiedostot on ladattu
|
||||
suoraan etäinstanssilta. Asetuksen poistaminen käytöstä vähentää tallennustilan
|
||||
käyttöä, mutta lisää verkkoliikennettä kun pienoiskuvat eivät muodostu.
|
||||
flagSpeakAsCatDescription: Lähetyksesi nyanifioidaan, kun olet kissatilassa
|
||||
flagShowTimelineRepliesDescription: Näyttää käyttäjien vastaukset muiden käyttäjien
|
||||
lähetyksiin aikajanalla, jos se on päällä.
|
||||
autoAcceptFollowed: Automaattisesti hyväksy seuraamispyynnöt käyttäjiltä, joita seuraat
|
||||
perHour: Tunnissa
|
||||
removeWallpaper: Poista taustakuva
|
||||
recipient: Vastaanottaja(t)
|
||||
federation: Federaatio
|
||||
software: Ohjelmisto
|
||||
proxyAccount: Proxy-tili
|
||||
proxyAccountDescription: Välitystili (Proxy-tili) on tili, joka toimii käyttäjien
|
||||
etäseuraajana tietyin edellytyksin. Kun käyttäjä esimerkiksi lisää etäkäyttäjän
|
||||
luetteloon, etäkäyttäjän toimintaa ei toimiteta instanssiin, jos yksikään paikallinen
|
||||
käyttäjä ei seuraa kyseistä käyttäjää, joten välitystili seuraa sen sijaan.
|
||||
latestStatus: Viimeisin tila
|
||||
selectInstance: Valitse instanssi
|
||||
instances: Instanssit
|
||||
perDay: Päivässä
|
||||
version: Versio
|
||||
statistics: Tilastot
|
||||
clearQueueConfirmTitle: Oletko varma, että haluat tyhjentää jonon?
|
||||
introMisskey: Tervetuloa! Calckey on avoimen lähdekoodin, hajautettu sosiaalisen median
|
||||
alusta, joka on ikuisesti ilmainen! 🚀
|
||||
clearQueueConfirmText: Mitkään välittämättömät lähetykset, jotka ovat jonossa, eivät
|
||||
federoidu. Yleensä tätä toimintoa ei tarvita.
|
||||
blockedInstancesDescription: Lista instanssien isäntänimistä, jotka haluat estää.
|
||||
Listatut instanssit eivät kykene kommunikoimaan enää tämän instanssin kanssa.
|
||||
_lang_: Suomi
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "calckey",
|
||||
"version": "13.2.0-dev38",
|
||||
"version": "13.2.0-dev41",
|
||||
"codename": "aqua",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 6 KiB |
|
@ -1,25 +1 @@
|
|||
<svg id="svg10" version="1.1" sodipodi:docname="title_float.svg" inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="1.95 0.97 167.97 103.23">
|
||||
<sodipodi:namedview id="namedview21" pagecolor="#ffffff" bordercolor="#000000" borderopacity="0.25" inkscape:showpageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1" showgrid="false" inkscape:zoom="1.1507704" inkscape:cx="260.69492" inkscape:cy="102.54" inkscape:window-width="1600" inkscape:window-height="931" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="svg10"/>
|
||||
<metadata id="metadata16">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<linearGradient id="myGradient" gradientTransform="rotate(90)">
|
||||
<stop offset="5%" stop-color="#9ccfd8" id="stop5" style="--darkreader-inline-stopcolor: #265760;" data-darkreader-inline-stopcolor=""/>
|
||||
<stop offset="95%" stop-color="#31748f" id="stop7" style="--darkreader-inline-stopcolor: #275d72;" data-darkreader-inline-stopcolor=""/>
|
||||
</linearGradient>
|
||||
<defs id="defs14"/>
|
||||
<g id="g8" fill="url('#myGradient')" word-spacing="0" letter-spacing="0" font-family="OTADESIGN Rounded" font-weight="400">
|
||||
<g id="g17">
|
||||
<g transform="matrix(.26953 0 0 .26953 -55.341 -52.023)" id="g11"/>
|
||||
<g transform="matrix(3.6954 0 0 3.6954 208.34 -284.25)" clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" id="g15">
|
||||
<path d="m -41.8312,77.19 c -3.8683,0 -7.1782,1.3578 -9.9311,4.0734 -2.716,2.7525 -4.0734,6.0628 -4.0734,9.9311 5.0539,0.04979 6.082,0.01348 8.7525,0.0011 0.0024,-4.51e-4 0.0044,-6.05e-4 0.0069,-0.0011 0.03779,-2.8423 2.2103,-4.9346 5.2451,-5.2451 1.4137,0 2.6227,0.52089 3.6268,1.5629 0.855,0.8548 1.897,1.2822 3.1257,1.2822 1.2258,0 2.2676,-0.42741 3.1236,-1.2822 0.85499,-0.85567 1.2833,-1.8976 1.2833,-3.1257 0,-1.2264 -0.42828,-2.2673 -1.2833,-3.1231 -2.7528,-2.7156 -6.0446,-4.0734 -9.8761,-4.0734 z m -5.252,14.006 c -3.4453,-5.5934 -3.4667,0.08539 -8.7525,-0.0011 0,3.8683 1.3584,7.0406 4.0744,9.7931 2.7528,2.7156 6.0623,4.0734 9.9305,4.0734 3.8315,0 7.1238,-1.3578 9.8766,-4.0734 0.85499,-0.85577 1.2827,-1.8967 1.2827,-3.1231 0,-1.2282 -0.42775,-2.2701 -1.2827,-3.1257 -0.85596,-0.8548 -1.8978,-1.2822 -3.1236,-1.2822 -1.2287,0 -2.2707,0.42741 -3.1257,1.2822 -1.0041,1.042 -2.2136,1.5623 -3.6273,1.5623 -3.0348,-0.31051 -5.2084,-2.2633 -5.2462,-5.1056 -0.0024,1.1e-5 -0.0039,-1.2e-5 -0.0063,0 z m 26.154,-7.0965 c -2.8795,0 -5.3538,1.0204 -7.4227,3.0612 -0.64257,0.64316 -0.96404,1.4255 -0.96404,2.3472 0,0.92303 0.32146,1.7062 0.96404,2.3493 0.64331,0.64243 1.4265,0.96351 2.3477,0.96351 0.92347,0 1.7068,-0.32108 2.3493,-0.96351 0.75465,-0.78308 1.6632,-1.1744 2.7256,-1.1744 1.0894,0 2.0261,0.37695 2.8091,1.1316 0.75536,0.78309 1.1332,1.7201 1.1332,2.8102 0,1.0617 -0.39242,1.9703 -1.1754,2.7256 -0.39149,0.4193 -0.86676,0.69884 -1.4249,0.83878 -0.14116,0.02773 -0.25248,0.01369 -0.33614,-0.04175 -0.05605,-0.08456 -0.02751,-0.16827 0.08456,-0.25211 l 0.83825,-0.88053 c 0.64329,-0.64315 0.9651,-1.412 0.9651,-2.306 0,-0.92236 -0.27937,-1.6632 -0.83825,-2.2225 -0.55888,-0.55932 -1.3422,-0.83878 -2.3493,-0.83878 -0.6986,0 -1.397,0.34902 -2.0956,1.0475 l -4.8651,4.8223 c -0.64328,0.6438 -0.96457,1.4271 -0.96457,2.3488 0,0.92302 0.32128,1.7053 0.96457,2.3477 1.9568,1.9293 4.3751,2.8942 7.2546,2.8942 2.9072,0 5.3945,-1.0343 7.4634,-3.103 2.0412,-2.0409 3.0618,-4.501 3.0618,-7.3804 0,-2.9072 -1.0206,-5.3952 -3.0618,-7.4639 -2.0689,-2.0409 -4.5562,-3.0612 -7.4634,-3.0612 z" clip-rule="evenodd" fill-rule="nonzero" stroke-miterlimit="2" stroke-width="0" id="path13" sodipodi:nodetypes="cccccccscsccccccscscscccccccscscscscccccscsccscscsccc"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<svg viewBox="1.95 0.97 128 128" width="128" height="128" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><linearGradient id="a" gradientTransform="rotate(90)"><stop offset="5%" stop-color="#9ccfd8" style="--darkreader-inline-stopcolor:#265760"/><stop offset="95%" stop-color="#31748f" style="--darkreader-inline-stopcolor:#275d72"/></linearGradient><defs><linearGradient xlink:href="#a" id="f" gradientTransform="scale(1.27567 .7839)" x1="-43.77" y1="98.469" x2="-27.05" y2="137.466" gradientUnits="userSpaceOnUse"/><linearGradient xlink:href="#a" id="d" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"/><linearGradient xlink:href="#a" id="e" gradientTransform="scale(1.27567 .7839)" x1="-43.77" y1="98.468" x2="-8.156" y2="98.468" gradientUnits="userSpaceOnUse"/><linearGradient xlink:href="#a" id="c" gradientTransform="scale(1.27567 .7839)" x1="1.571" y1="1.27" x2="133.179" y2="1.27" gradientUnits="userSpaceOnUse"/><linearGradient xlink:href="#a" id="b" gradientTransform="scale(1.27567 .7839)" x1="1.571" y1="1.27" x2="133.179" y2="1.27" gradientUnits="userSpaceOnUse"/></defs><g style="fill:url(#b)" transform="translate(.934 25.196) scale(.75646)"><g style="fill:url(#c)" fill="url(#a)" word-spacing="0" letter-spacing="0" font-family="'OTADESIGN Rounded'" font-weight="400"><g transform="translate(-55.341 -52.023) scale(.26953)" style="fill:url(#d)"/><g style="fill:url(#e)"><path style="fill:url(#f)" d="M-41.832 77.19c-3.868 0-7.177 1.358-9.93 4.074-2.716 2.752-4.074 6.063-4.074 9.931 0 3.869 1.358 7.04 4.074 9.793 2.753 2.716 6.064 4.073 9.932 4.073 3.831 0 7.122-1.357 9.875-4.073.855-.855 1.283-1.896 1.283-3.123 0-1.228-.428-2.271-1.283-3.127-.856-.855-1.897-1.281-3.123-1.281-1.229 0-2.27.426-3.125 1.281-1.004 1.042-2.213 1.563-3.627 1.563-3.035-.31-5.208-2.263-5.246-5.106.038-2.842 2.21-4.935 5.244-5.246 1.414 0 2.623.52 3.627 1.563.855.855 1.898 1.283 3.127 1.283 1.226 0 2.267-.428 3.123-1.283.855-.856 1.283-1.897 1.283-3.125 0-1.227-.428-2.268-1.283-3.123-2.753-2.716-6.046-4.075-9.877-4.075zm20.902 6.91c-2.88 0-5.353 1.02-7.422 3.06-.642.643-.964 1.426-.964 2.348 0 .923.322 1.706.964 2.35.644.642 1.427.962 2.348.962.924 0 1.707-.32 2.35-.963.754-.783 1.662-1.173 2.724-1.173 1.09 0 2.026.376 2.809 1.13a3.909 3.909 0 0 1 1.135 2.811c0 1.062-.393 1.97-1.176 2.725-.392.419-.868.7-1.426.84-.141.027-.252.012-.336-.044-.056-.084-.028-.168.084-.251l.84-.881c.643-.643.965-1.411.965-2.305 0-.922-.28-1.663-.838-2.223-.559-.559-1.343-.84-2.35-.84-.698 0-1.397.35-2.095 1.05l-4.866 4.822c-.643.643-.964 1.426-.964 2.347 0 .923.321 1.705.964 2.348 1.957 1.93 4.375 2.894 7.254 2.894 2.908 0 5.396-1.034 7.465-3.103 2.041-2.041 3.06-4.5 3.06-7.379 0-2.907-1.019-5.396-3.06-7.465-2.069-2.04-4.557-3.06-7.465-3.06z" transform="translate(208.34 -284.25) scale(3.6954)" clip-rule="evenodd" fill-rule="evenodd"/></g></g></g></svg>
|
||||
|
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 21 KiB |
BIN
packages/backend/assets/inverse wordmark.png
Normal file
After Width: | Height: | Size: 21 KiB |
|
@ -1,65 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="512.0px"
|
||||
height="512.0px"
|
||||
viewBox="0 0 512.0 512.0"
|
||||
version="1.1"
|
||||
id="SVGRoot"
|
||||
sodipodi:docname="inverse wordmark.svg"
|
||||
xml:space="preserve"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview71"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:document-units="px"
|
||||
showgrid="true"
|
||||
inkscape:zoom="0.50150542"
|
||||
inkscape:cx="59.819892"
|
||||
inkscape:cy="189.42966"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="931"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1"><inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid77" /></sodipodi:namedview><defs
|
||||
id="defs66" /><g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"><path
|
||||
id="rect136"
|
||||
style="fill:#31748f;fill-opacity:1;stroke-width:0.996356"
|
||||
d="M 0,0 V 512 H 512 V 0 Z" /><g
|
||||
id="g17"
|
||||
style="font-weight:400;font-family:'OTADESIGN Rounded';letter-spacing:0;word-spacing:0;fill:#ffffff"
|
||||
transform="matrix(2.0847185,0,0,2.0847185,76.820648,146.38203)"><g
|
||||
transform="matrix(0.26953,0,0,0.26953,-55.341,-52.023)"
|
||||
id="g11"
|
||||
style="fill:#ffffff" /><g
|
||||
transform="matrix(3.6954,0,0,3.6954,208.34,-284.25)"
|
||||
clip-rule="evenodd"
|
||||
fill-rule="evenodd"
|
||||
stroke-linejoin="round"
|
||||
stroke-miterlimit="2"
|
||||
id="g15"
|
||||
style="fill:#ffffff"><path
|
||||
d="m -41.8312,77.19 c -3.8683,0 -7.1782,1.3578 -9.9311,4.0734 -2.716,2.7525 -4.0734,6.0628 -4.0734,9.9311 5.0539,0.04979 6.082,0.01348 8.7525,0.0011 0.0024,-4.51e-4 0.0044,-6.05e-4 0.0069,-0.0011 0.03779,-2.8423 2.2103,-4.9346 5.2451,-5.2451 1.4137,0 2.6227,0.52089 3.6268,1.5629 0.855,0.8548 1.897,1.2822 3.1257,1.2822 1.2258,0 2.2676,-0.42741 3.1236,-1.2822 0.85499,-0.85567 1.2833,-1.8976 1.2833,-3.1257 0,-1.2264 -0.42828,-2.2673 -1.2833,-3.1231 -2.7528,-2.7156 -6.0446,-4.0734 -9.8761,-4.0734 z m -5.252,14.006 c -3.4453,-5.5934 -3.4667,0.08539 -8.7525,-0.0011 0,3.8683 1.3584,7.0406 4.0744,9.7931 2.7528,2.7156 6.0623,4.0734 9.9305,4.0734 3.8315,0 7.1238,-1.3578 9.8766,-4.0734 0.85499,-0.85577 1.2827,-1.8967 1.2827,-3.1231 0,-1.2282 -0.42775,-2.2701 -1.2827,-3.1257 -0.85596,-0.8548 -1.8978,-1.2822 -3.1236,-1.2822 -1.2287,0 -2.2707,0.42741 -3.1257,1.2822 -1.0041,1.042 -2.2136,1.5623 -3.6273,1.5623 -3.0348,-0.31051 -5.2084,-2.2633 -5.2462,-5.1056 -0.0024,1.1e-5 -0.0039,-1.2e-5 -0.0063,0 z m 26.154,-7.0965 c -2.8795,0 -5.3538,1.0204 -7.4227,3.0612 -0.64257,0.64316 -0.96404,1.4255 -0.96404,2.3472 0,0.92303 0.32146,1.7062 0.96404,2.3493 0.64331,0.64243 1.4265,0.96351 2.3477,0.96351 0.92347,0 1.7068,-0.32108 2.3493,-0.96351 0.75465,-0.78308 1.6632,-1.1744 2.7256,-1.1744 1.0894,0 2.0261,0.37695 2.8091,1.1316 0.75536,0.78309 1.1332,1.7201 1.1332,2.8102 0,1.0617 -0.39242,1.9703 -1.1754,2.7256 -0.39149,0.4193 -0.86676,0.69884 -1.4249,0.83878 -0.14116,0.02773 -0.25248,0.01369 -0.33614,-0.04175 -0.05605,-0.08456 -0.02751,-0.16827 0.08456,-0.25211 l 0.83825,-0.88053 c 0.64329,-0.64315 0.9651,-1.412 0.9651,-2.306 0,-0.92236 -0.27937,-1.6632 -0.83825,-2.2225 -0.55888,-0.55932 -1.3422,-0.83878 -2.3493,-0.83878 -0.6986,0 -1.397,0.34902 -2.0956,1.0475 l -4.8651,4.8223 c -0.64328,0.6438 -0.96457,1.4271 -0.96457,2.3488 0,0.92302 0.32128,1.7053 0.96457,2.3477 1.9568,1.9293 4.3751,2.8942 7.2546,2.8942 2.9072,0 5.3945,-1.0343 7.4634,-3.103 2.0412,-2.0409 3.0618,-4.501 3.0618,-7.3804 0,-2.9072 -1.0206,-5.3952 -3.0618,-7.4639 -2.0689,-2.0409 -4.5562,-3.0612 -7.4634,-3.0612 z"
|
||||
clip-rule="evenodd"
|
||||
fill-rule="nonzero"
|
||||
stroke-miterlimit="2"
|
||||
stroke-width="0"
|
||||
id="path13"
|
||||
sodipodi:nodetypes="cccccccscsccccccscscscccccccscscscscccccscsccscscsccc"
|
||||
style="fill:#ffffff" /></g></g></g></svg>
|
||||
<svg xml:space="preserve" viewBox="0 0 512 512" height="512" width="512" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="a"><stop style="stop-color:#31748f;stop-opacity:1" offset="0"/><stop style="stop-color:#9ccfd8;stop-opacity:1" offset="1"/></linearGradient><linearGradient xlink:href="#a" id="b" x1="254.819" y1="411.542" x2="259.34" y2="-1.41" gradientUnits="userSpaceOnUse"/></defs><path style="fill:url(#b);fill-opacity:1;stroke-width:.996356" d="M0 0v512h512V0Z"/><g style="font-weight:400;font-family:"OTADESIGN Rounded";letter-spacing:0;word-spacing:0;fill:#fff"><g transform="translate(-38.55 37.929) scale(.5619)" style="fill:#fff"/><path style="fill:#fff" d="M-41.832 77.19c-3.868 0-7.177 1.358-9.93 4.074-2.716 2.752-4.074 6.063-4.074 9.931 0 3.869 1.358 7.04 4.074 9.793 2.753 2.716 6.064 4.073 9.932 4.073 3.831 0 7.122-1.357 9.875-4.073.855-.855 1.283-1.896 1.283-3.123 0-1.228-.428-2.271-1.283-3.127-.856-.855-1.897-1.281-3.123-1.281-1.229 0-2.27.426-3.125 1.281-1.004 1.042-2.213 1.563-3.627 1.563-3.035-.31-5.208-2.263-5.246-5.106.038-2.842 2.21-4.935 5.244-5.246 1.414 0 2.623.52 3.627 1.563.855.855 1.898 1.283 3.127 1.283 1.226 0 2.267-.428 3.123-1.283.855-.856 1.283-1.897 1.283-3.125 0-1.227-.428-2.268-1.283-3.123-2.753-2.716-6.046-4.075-9.877-4.075zm20.902 6.91c-2.88 0-5.353 1.02-7.422 3.06-.642.643-.964 1.426-.964 2.348 0 .923.322 1.706.964 2.35.644.642 1.427.962 2.348.962.924 0 1.707-.32 2.35-.963.754-.783 1.662-1.173 2.724-1.173 1.09 0 2.026.376 2.809 1.13a3.909 3.909 0 0 1 1.135 2.811c0 1.062-.393 1.97-1.176 2.725-.392.419-.868.7-1.426.84-.141.027-.252.012-.336-.044-.056-.084-.028-.168.084-.251l.84-.881c.643-.643.965-1.411.965-2.305 0-.922-.28-1.663-.838-2.223-.559-.559-1.343-.84-2.35-.84-.698 0-1.397.35-2.095 1.05l-4.866 4.822c-.643.643-.964 1.426-.964 2.347 0 .923.321 1.705.964 2.348 1.957 1.93 4.375 2.894 7.254 2.894 2.908 0 5.396-1.034 7.465-3.103 2.041-2.041 3.06-4.5 3.06-7.379 0-2.907-1.019-5.396-3.06-7.465-2.069-2.04-4.557-3.06-7.465-3.06z" transform="translate(511.15 -446.2) scale(7.70387)" clip-rule="evenodd" fill-rule="evenodd"/></g></svg>
|
||||
|
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 20 KiB |
23
packages/backend/migration/1682777547198-LibreTranslate.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
export class LibreTranslate1682777547198 {
|
||||
name = "LibreTranslate1682777547198";
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE "meta"
|
||||
ADD "libreTranslateApiUrl" character varying(512)
|
||||
`);
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE "meta"
|
||||
ADD "libreTranslateApiKey" character varying(128)
|
||||
`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE "meta" DROP COLUMN "libreTranslateApiKey"
|
||||
`);
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE "meta" DROP COLUMN "libreTranslateApiUrl"
|
||||
`);
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@
|
|||
"@bull-board/api": "^4.6.4",
|
||||
"@bull-board/koa": "^4.6.4",
|
||||
"@bull-board/ui": "^4.6.4",
|
||||
"@calckey/megalodon": "5.1.24",
|
||||
"@calckey/megalodon": "5.2.0",
|
||||
"@discordapp/twemoji": "14.0.2",
|
||||
"@elastic/elasticsearch": "7.17.0",
|
||||
"@koa/cors": "3.4.3",
|
||||
|
|
|
@ -89,6 +89,11 @@ export type Source = {
|
|||
authKey?: string;
|
||||
isPro?: boolean;
|
||||
};
|
||||
libreTranslate: {
|
||||
managed?: boolean;
|
||||
apiUrl?: string;
|
||||
apiKey?: string;
|
||||
};
|
||||
email: {
|
||||
managed?: boolean;
|
||||
address?: string;
|
||||
|
|
|
@ -386,6 +386,18 @@ export class Meta {
|
|||
})
|
||||
public deeplIsPro: boolean;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 512,
|
||||
nullable: true,
|
||||
})
|
||||
public libreTranslateApiUrl: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 128,
|
||||
nullable: true,
|
||||
})
|
||||
public libreTranslateApiKey: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 512,
|
||||
nullable: true,
|
||||
|
|
|
@ -30,6 +30,17 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
set.deeplIsPro = config.deepl.isPro;
|
||||
}
|
||||
}
|
||||
if (
|
||||
config.libreTranslate.managed != null &&
|
||||
config.libreTranslate.managed === true
|
||||
) {
|
||||
if (typeof config.libreTranslate.apiUrl === "string") {
|
||||
set.libreTranslateApiUrl = config.libreTranslate.apiUrl;
|
||||
}
|
||||
if (typeof config.libreTranslate.apiKey === "string") {
|
||||
set.libreTranslateApiKey = config.libreTranslate.apiKey;
|
||||
}
|
||||
}
|
||||
if (config.email.managed != null && config.email.managed === true) {
|
||||
set.enableEmail = true;
|
||||
if (typeof config.email.address === "string") {
|
||||
|
|
|
@ -512,7 +512,8 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
enableGithubIntegration: instance.enableGithubIntegration,
|
||||
enableDiscordIntegration: instance.enableDiscordIntegration,
|
||||
enableServiceWorker: instance.enableServiceWorker,
|
||||
translatorAvailable: instance.deeplAuthKey != null,
|
||||
translatorAvailable:
|
||||
instance.deeplAuthKey != null || instance.libreTranslateApiUrl != null,
|
||||
pinnedPages: instance.pinnedPages,
|
||||
pinnedClipId: instance.pinnedClipId,
|
||||
cacheRemoteFiles: instance.cacheRemoteFiles,
|
||||
|
@ -564,6 +565,8 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle,
|
||||
deeplAuthKey: instance.deeplAuthKey,
|
||||
deeplIsPro: instance.deeplIsPro,
|
||||
libreTranslateApiUrl: instance.libreTranslateApiUrl,
|
||||
libreTranslateApiKey: instance.libreTranslateApiKey,
|
||||
enableIpLogging: instance.enableIpLogging,
|
||||
enableActiveEmailValidation: instance.enableActiveEmailValidation,
|
||||
};
|
||||
|
|
|
@ -124,6 +124,8 @@ export const paramDef = {
|
|||
summalyProxy: { type: "string", nullable: true },
|
||||
deeplAuthKey: { type: "string", nullable: true },
|
||||
deeplIsPro: { type: "boolean" },
|
||||
libreTranslateApiUrl: { type: "string", nullable: true },
|
||||
libreTranslateApiKey: { type: "string", nullable: true },
|
||||
enableTwitterIntegration: { type: "boolean" },
|
||||
twitterConsumerKey: { type: "string", nullable: true },
|
||||
twitterConsumerSecret: { type: "string", nullable: true },
|
||||
|
@ -515,6 +517,22 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
set.deeplIsPro = ps.deeplIsPro;
|
||||
}
|
||||
|
||||
if (ps.libreTranslateApiUrl !== undefined) {
|
||||
if (ps.libreTranslateApiUrl === "") {
|
||||
set.libreTranslateApiUrl = null;
|
||||
} else {
|
||||
set.libreTranslateApiUrl = ps.libreTranslateApiUrl;
|
||||
}
|
||||
}
|
||||
|
||||
if (ps.libreTranslateApiKey !== undefined) {
|
||||
if (ps.libreTranslateApiKey === "") {
|
||||
set.libreTranslateApiKey = null;
|
||||
} else {
|
||||
set.libreTranslateApiKey = ps.libreTranslateApiKey;
|
||||
}
|
||||
}
|
||||
|
||||
if (ps.enableIpLogging !== undefined) {
|
||||
set.enableIpLogging = ps.enableIpLogging;
|
||||
}
|
||||
|
|
|
@ -482,7 +482,8 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
|
||||
enableServiceWorker: instance.enableServiceWorker,
|
||||
|
||||
translatorAvailable: instance.deeplAuthKey != null,
|
||||
translatorAvailable:
|
||||
instance.deeplAuthKey != null || instance.libreTranslateApiUrl != null,
|
||||
defaultReaction: instance.defaultReaction,
|
||||
|
||||
...(ps.detail
|
||||
|
|
|
@ -51,15 +51,54 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
|
||||
const instance = await fetchMeta();
|
||||
|
||||
if (instance.deeplAuthKey == null) {
|
||||
if (instance.deeplAuthKey == null && instance.libreTranslateApiUrl == null) {
|
||||
return 204; // TODO: 良い感じのエラー返す
|
||||
}
|
||||
|
||||
let targetLang = ps.targetLang;
|
||||
if (targetLang.includes("-")) targetLang = targetLang.split("-")[0];
|
||||
|
||||
if (instance.libreTranslateApiUrl != null) {
|
||||
const jsonBody = {
|
||||
q: note.text,
|
||||
source: "auto",
|
||||
target: targetLang,
|
||||
format: "text",
|
||||
api_key: instance.libreTranslateApiKey ?? "",
|
||||
};
|
||||
|
||||
const url = new URL(instance.libreTranslateApiUrl);
|
||||
if (url.pathname.endsWith("/")) {
|
||||
url.pathname = url.pathname.slice(0, -1);
|
||||
}
|
||||
if (!url.pathname.endsWith("/translate")) {
|
||||
url.pathname += "/translate";
|
||||
}
|
||||
const res = await fetch(url.toString(), {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(jsonBody),
|
||||
agent: getAgentByUrl,
|
||||
});
|
||||
|
||||
const json = (await res.json()) as {
|
||||
detectedLanguage?: {
|
||||
confidence: number;
|
||||
language: string;
|
||||
};
|
||||
translatedText: string;
|
||||
};
|
||||
|
||||
return {
|
||||
sourceLang: json.detectedLanguage?.language,
|
||||
text: json.translatedText,
|
||||
};
|
||||
}
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.append("auth_key", instance.deeplAuthKey);
|
||||
params.append("auth_key", instance.deeplAuthKey ?? "");
|
||||
params.append("text", note.text);
|
||||
params.append("target_lang", targetLang);
|
||||
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
node_modules
|
||||
/built
|
||||
/coverage
|
||||
/.eslintrc.js
|
||||
/jest.config.ts
|
||||
/test
|
||||
/test-d
|
|
@ -1,65 +0,0 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ["./tsconfig.json"],
|
||||
},
|
||||
plugins: ["@typescript-eslint"],
|
||||
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
||||
rules: {
|
||||
indent: [
|
||||
"error",
|
||||
"tab",
|
||||
{
|
||||
SwitchCase: 1,
|
||||
MemberExpression: "off",
|
||||
flatTernaryExpressions: true,
|
||||
ArrayExpression: "first",
|
||||
ObjectExpression: "first",
|
||||
},
|
||||
],
|
||||
"eol-last": ["error", "always"],
|
||||
semi: ["error", "always"],
|
||||
quotes: ["error", "single"],
|
||||
"comma-dangle": ["error", "always-multiline"],
|
||||
"keyword-spacing": [
|
||||
"error",
|
||||
{
|
||||
before: true,
|
||||
after: true,
|
||||
},
|
||||
],
|
||||
"key-spacing": [
|
||||
"error",
|
||||
{
|
||||
beforeColon: false,
|
||||
afterColon: true,
|
||||
},
|
||||
],
|
||||
"space-infix-ops": ["error"],
|
||||
"space-before-blocks": ["error", "always"],
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"nonblock-statement-body-position": ["error", "beside"],
|
||||
eqeqeq: ["error", "always", { null: "ignore" }],
|
||||
"no-multiple-empty-lines": ["error", { max: 1 }],
|
||||
"no-multi-spaces": ["error"],
|
||||
"no-var": ["error"],
|
||||
"prefer-arrow-callback": ["error"],
|
||||
"no-throw-literal": ["error"],
|
||||
"no-param-reassign": ["warn"],
|
||||
"no-constant-condition": ["warn"],
|
||||
"no-empty-pattern": ["warn"],
|
||||
"@typescript-eslint/no-unnecessary-condition": ["error"],
|
||||
"@typescript-eslint/no-inferrable-types": ["warn"],
|
||||
"@typescript-eslint/no-non-null-assertion": ["warn"],
|
||||
"@typescript-eslint/explicit-function-return-type": ["warn"],
|
||||
"@typescript-eslint/no-misused-promises": [
|
||||
"error",
|
||||
{
|
||||
checksVoidReturn: false,
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/consistent-type-imports": "error",
|
||||
},
|
||||
};
|
|
@ -9,9 +9,8 @@
|
|||
"tsd": "tsd",
|
||||
"api": "pnpm api-extractor run --local --verbose",
|
||||
"api-prod": "pnpm api-extractor run --verbose",
|
||||
"eslint": "eslint . --ext .js,.jsx,.ts,.tsx",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"lint": "pnpm typecheck && pnpm eslint",
|
||||
"lint": "pnpm typecheck && pnpm rome check \"src/*.ts\"",
|
||||
"jest": "jest --coverage --detectOpenHandles",
|
||||
"test": "pnpm jest && pnpm tsd"
|
||||
},
|
||||
|
|
|
@ -20,9 +20,12 @@ export default defineComponent({
|
|||
},
|
||||
computed: {
|
||||
compiledFormula(): any {
|
||||
return katex.renderToString(this.formula, {
|
||||
const katexString = katex.renderToString(this.formula, {
|
||||
throwOnError: false,
|
||||
} as any);
|
||||
return this.block
|
||||
? `<div style="text-align:center">${katexString}</div>`
|
||||
: katexString;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -89,7 +89,7 @@
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tail" :class="{ collapsed }">
|
||||
<div class="tail">
|
||||
<header>
|
||||
<span v-if="notification.type === 'pollEnded'">{{
|
||||
i18n.ts._notification.pollEnded
|
||||
|
@ -112,11 +112,11 @@
|
|||
v-if="notification.type === 'reaction'"
|
||||
class="text"
|
||||
:to="notePage(notification.note)"
|
||||
:title="summary"
|
||||
:title="getNoteSummary(notification.note)"
|
||||
>
|
||||
<i class="ph-quotes ph-fill ph-lg"></i>
|
||||
<Mfm
|
||||
:text="summary"
|
||||
:text="getNoteSummary(notification.note)"
|
||||
:plain="true"
|
||||
:nowrap="!full"
|
||||
:custom-emojis="notification.note.emojis"
|
||||
|
@ -142,10 +142,10 @@
|
|||
v-if="notification.type === 'reply'"
|
||||
class="text"
|
||||
:to="notePage(notification.note)"
|
||||
:title="summary"
|
||||
:title="getNoteSummary(notification.note)"
|
||||
>
|
||||
<Mfm
|
||||
:text="summary"
|
||||
:text="getNoteSummary(notification.note)"
|
||||
:plain="true"
|
||||
:nowrap="!full"
|
||||
:custom-emojis="notification.note.emojis"
|
||||
|
@ -155,10 +155,10 @@
|
|||
v-if="notification.type === 'mention'"
|
||||
class="text"
|
||||
:to="notePage(notification.note)"
|
||||
:title="summary"
|
||||
:title="getNoteSummary(notification.note)"
|
||||
>
|
||||
<Mfm
|
||||
:text="summary"
|
||||
:text="getNoteSummary(notification.note)"
|
||||
:plain="true"
|
||||
:nowrap="!full"
|
||||
:custom-emojis="notification.note.emojis"
|
||||
|
@ -168,10 +168,10 @@
|
|||
v-if="notification.type === 'quote'"
|
||||
class="text"
|
||||
:to="notePage(notification.note)"
|
||||
:title="summary"
|
||||
:title="getNoteSummary(notification.note)"
|
||||
>
|
||||
<Mfm
|
||||
:text="summary"
|
||||
:text="getNoteSummary(notification.note)"
|
||||
:plain="true"
|
||||
:nowrap="!full"
|
||||
:custom-emojis="notification.note.emojis"
|
||||
|
@ -181,11 +181,11 @@
|
|||
v-if="notification.type === 'pollVote'"
|
||||
class="text"
|
||||
:to="notePage(notification.note)"
|
||||
:title="summary"
|
||||
:title="getNoteSummary(notification.note)"
|
||||
>
|
||||
<i class="ph-quotes ph-fill ph-lg"></i>
|
||||
<Mfm
|
||||
:text="summary"
|
||||
:text="getNoteSummary(notification.note)"
|
||||
:plain="true"
|
||||
:nowrap="!full"
|
||||
:custom-emojis="notification.note.emojis"
|
||||
|
@ -196,11 +196,11 @@
|
|||
v-if="notification.type === 'pollEnded'"
|
||||
class="text"
|
||||
:to="notePage(notification.note)"
|
||||
:title="summary"
|
||||
:title="getNoteSummary(notification.note)"
|
||||
>
|
||||
<i class="ph-quotes ph-fill ph-lg"></i>
|
||||
<Mfm
|
||||
:text="summary"
|
||||
:text="getNoteSummary(notification.note)"
|
||||
:plain="true"
|
||||
:nowrap="!full"
|
||||
:custom-emojis="notification.note.emojis"
|
||||
|
@ -264,7 +264,6 @@
|
|||
<span v-if="notification.type === 'app'" class="text">
|
||||
<Mfm :text="notification.body" :nowrap="!full" />
|
||||
</span>
|
||||
<xShowMoreButton v-if="isLong" v-model="collapsed"></xShowMoreButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -275,7 +274,6 @@ import * as misskey from "calckey-js";
|
|||
import XReactionIcon from "@/components/MkReactionIcon.vue";
|
||||
import MkFollowButton from "@/components/MkFollowButton.vue";
|
||||
import XReactionTooltip from "@/components/MkReactionTooltip.vue";
|
||||
import XShowMoreButton from "./MkShowMoreButton.vue";
|
||||
import { getNoteSummary } from "@/scripts/get-note-summary";
|
||||
import { notePage } from "@/filters/note";
|
||||
import { userPage } from "@/filters/user";
|
||||
|
@ -301,19 +299,12 @@ const props = withDefaults(
|
|||
const elRef = ref<HTMLElement>(null);
|
||||
const reactionRef = ref(null);
|
||||
|
||||
const summary = getNoteSummary(props.notification.note);
|
||||
|
||||
const showEmojiReactions =
|
||||
defaultStore.state.enableEmojiReactions ||
|
||||
defaultStore.state.showEmojisInReactionNotifications;
|
||||
const defaultReaction = ["⭐", "👍", "❤️"].includes(instance.defaultReaction)
|
||||
? instance.defaultReaction
|
||||
: "⭐";
|
||||
const isLong = (summary.split("\n").length > 3 || summary.length > 200);
|
||||
const collapsed = $ref(isLong);
|
||||
|
||||
|
||||
|
||||
|
||||
let readObserver: IntersectionObserver | undefined;
|
||||
let connection;
|
||||
|
@ -495,7 +486,6 @@ useTooltip(reactionRef, (showing) => {
|
|||
}
|
||||
|
||||
> .tail {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
|
@ -536,17 +526,6 @@ useTooltip(reactionRef, (showing) => {
|
|||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
&.collapsed > .text {
|
||||
display: block;
|
||||
position: relative;
|
||||
max-height: calc(4em + 50px);
|
||||
overflow: hidden;
|
||||
mask: linear-gradient(black calc(100% - 64px), transparent);
|
||||
-webkit-mask: linear-gradient(
|
||||
black calc(100% - 64px),
|
||||
transparent
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
<template>
|
||||
<button
|
||||
v-if="modelValue"
|
||||
class="fade _button"
|
||||
@click.stop="toggle"
|
||||
>
|
||||
<span>{{ i18n.ts.showMore }}</span>
|
||||
</button>
|
||||
<button
|
||||
v-if="!modelValue"
|
||||
class="showLess _button"
|
||||
@click.stop="toggle"
|
||||
>
|
||||
<span>{{ i18n.ts.showLess }}</span>
|
||||
</button>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { i18n } from "@/i18n";
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: "update:modelValue", v: boolean): void;
|
||||
}>();
|
||||
|
||||
const toggle = () => {
|
||||
emit("update:modelValue", !props.modelValue);
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.fade {
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
> span {
|
||||
display: inline-block;
|
||||
background: var(--panel);
|
||||
padding: 0.4em 1em;
|
||||
font-size: 0.8em;
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
|
||||
}
|
||||
&:hover {
|
||||
> span {
|
||||
background: var(--panelHighlight);
|
||||
}
|
||||
}
|
||||
}
|
||||
.showLess {
|
||||
width: 100%;
|
||||
margin-top: 1em;
|
||||
position: sticky;
|
||||
bottom: var(--stickyBottom);
|
||||
|
||||
> span {
|
||||
display: inline-block;
|
||||
background: var(--panel);
|
||||
padding: 6px 10px;
|
||||
font-size: 0.8em;
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 0 7px 7px var(--bg);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -120,7 +120,6 @@ import XNoteSimple from "@/components/MkNoteSimple.vue";
|
|||
import XMediaList from "@/components/MkMediaList.vue";
|
||||
import XPoll from "@/components/MkPoll.vue";
|
||||
import MkUrlPreview from "@/components/MkUrlPreview.vue";
|
||||
import XShowMoreButton from "./MkShowMoreButton.vue";
|
||||
import XCwButton from "@/components/MkCwButton.vue";
|
||||
import { extractUrlFromMfm } from "@/scripts/extract-url-from-mfm";
|
||||
import { i18n } from "@/i18n";
|
||||
|
@ -145,7 +144,6 @@ const isLong =
|
|||
props.note.text != null &&
|
||||
(props.note.text.split("\n").length > 9 || props.note.text.length > 500);
|
||||
const collapsed = $ref(props.note.cw == null && isLong);
|
||||
|
||||
const urls = props.note.text
|
||||
? extractUrlFromMfm(mfm.parse(props.note.text)).slice(0, 5)
|
||||
: null;
|
||||
|
@ -274,6 +272,43 @@ function focusFooter(ev) {
|
|||
top: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.fade) {
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
> span {
|
||||
display: inline-block;
|
||||
background: var(--panel);
|
||||
padding: 0.4em 1em;
|
||||
font-size: 0.8em;
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
|
||||
}
|
||||
&:hover {
|
||||
> span {
|
||||
background: var(--panelHighlight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.showLess) {
|
||||
width: 100%;
|
||||
margin-top: 1em;
|
||||
position: sticky;
|
||||
bottom: var(--stickyBottom);
|
||||
|
||||
> span {
|
||||
display: inline-block;
|
||||
background: var(--panel);
|
||||
padding: 6px 10px;
|
||||
font-size: 0.8em;
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 0 7px 7px var(--bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,20 @@
|
|||
:custom-emojis="user.emojis"
|
||||
/>
|
||||
</div>
|
||||
<XShowMoreButton v-if="isLong" v-model="collapsed"></XShowMoreButton>
|
||||
<button
|
||||
v-if="isLong && collapsed"
|
||||
class="fade _button"
|
||||
@click.stop="collapsed = false"
|
||||
>
|
||||
<span>{{ i18n.ts.showMore }}</span>
|
||||
</button>
|
||||
<button
|
||||
v-if="isLong && !collapsed"
|
||||
class="showLess _button"
|
||||
@click.stop="collapsed = true"
|
||||
>
|
||||
<span>{{ i18n.ts.showLess }}</span>
|
||||
</button>
|
||||
<div v-if="user.fields.length > 0" class="fields">
|
||||
<dl
|
||||
v-for="(field, i) in user.fields"
|
||||
|
@ -115,7 +128,6 @@ import * as Acct from "calckey-js/built/acct";
|
|||
import type * as misskey from "calckey-js";
|
||||
import MkFollowButton from "@/components/MkFollowButton.vue";
|
||||
import { userPage } from "@/filters/user";
|
||||
import XShowMoreButton from "./MkShowMoreButton.vue";
|
||||
import * as os from "@/os";
|
||||
import { $i } from "@/account";
|
||||
import { i18n } from "@/i18n";
|
||||
|
|
|
@ -371,6 +371,34 @@
|
|||
<template #label>Pro account</template>
|
||||
</FormSwitch>
|
||||
</FormSection>
|
||||
|
||||
<FormSection>
|
||||
<template #label>Libre Translate</template>
|
||||
|
||||
<FormInput
|
||||
v-model="libreTranslateApiUrl"
|
||||
class="_formBlock"
|
||||
>
|
||||
<template #prefix
|
||||
><i class="ph-link ph-bold ph-lg"></i
|
||||
></template>
|
||||
<template #label
|
||||
>Libre Translate API URL</template
|
||||
>
|
||||
</FormInput>
|
||||
|
||||
<FormInput
|
||||
v-model="libreTranslateApiKey"
|
||||
class="_formBlock"
|
||||
>
|
||||
<template #prefix
|
||||
><i class="ph-key ph-bold ph-lg"></i
|
||||
></template>
|
||||
<template #label
|
||||
>Libre Translate API Key</template
|
||||
>
|
||||
</FormInput>
|
||||
</FormSection>
|
||||
</div>
|
||||
</FormSuspense>
|
||||
</MkSpacer>
|
||||
|
@ -422,6 +450,8 @@ let swPublicKey: any = $ref(null);
|
|||
let swPrivateKey: any = $ref(null);
|
||||
let deeplAuthKey: string = $ref("");
|
||||
let deeplIsPro: boolean = $ref(false);
|
||||
let libreTranslateApiUrl: string = $ref("");
|
||||
let libreTranslateApiKey: string = $ref("");
|
||||
let defaultReaction: string = $ref("");
|
||||
let defaultReactionCustom: string = $ref("");
|
||||
|
||||
|
@ -456,6 +486,8 @@ async function init() {
|
|||
swPrivateKey = meta.swPrivateKey;
|
||||
deeplAuthKey = meta.deeplAuthKey;
|
||||
deeplIsPro = meta.deeplIsPro;
|
||||
libreTranslateApiUrl = meta.libreTranslateApiUrl;
|
||||
libreTranslateApiKey = meta.libreTranslateApiKey;
|
||||
defaultReaction = ["⭐", "👍", "❤️"].includes(meta.defaultReaction)
|
||||
? meta.defaultReaction
|
||||
: "custom";
|
||||
|
@ -498,6 +530,8 @@ function save() {
|
|||
swPrivateKey,
|
||||
deeplAuthKey,
|
||||
deeplIsPro,
|
||||
libreTranslateApiUrl,
|
||||
libreTranslateApiKey,
|
||||
defaultReaction,
|
||||
}).then(() => {
|
||||
fetchInstance();
|
||||
|
|
|
@ -87,8 +87,8 @@ importers:
|
|||
specifier: ^4.6.4
|
||||
version: 4.10.2
|
||||
'@calckey/megalodon':
|
||||
specifier: 5.1.24
|
||||
version: 5.1.24
|
||||
specifier: 5.2.0
|
||||
version: 5.2.0
|
||||
'@discordapp/twemoji':
|
||||
specifier: 14.0.2
|
||||
version: 14.0.2
|
||||
|
@ -1384,8 +1384,8 @@ packages:
|
|||
'@bull-board/api': 4.10.2
|
||||
dev: false
|
||||
|
||||
/@calckey/megalodon@5.1.24:
|
||||
resolution: {integrity: sha512-VRd6x8MFQ2pMF0rnGF67/GVxgp/92CV7lg2XT1wnPAfQZ1NTsjwlDQX3HewEW3fSG/r7Nzh5WbIBXC8WMWKs9g==}
|
||||
/@calckey/megalodon@5.2.0:
|
||||
resolution: {integrity: sha512-9MEjzKJPyd7o5bHGGlNq4oE1tMt22GUJ8o8tZXcXSpXlrSDb2rSwumirM1KXUWTW8G6NGi1leCM59gOBGLko3w==}
|
||||
engines: {node: '>=15.0.0'}
|
||||
dependencies:
|
||||
'@types/oauth': 0.9.1
|
||||
|
@ -5910,8 +5910,8 @@ packages:
|
|||
requiresBuild: true
|
||||
dev: false
|
||||
|
||||
/core-js@3.30.0:
|
||||
resolution: {integrity: sha512-hQotSSARoNh1mYPi9O2YaWeiq/cEB95kOrFb4NCrO4RIFt1qqNpKsaE+vy/L3oiqvND5cThqXzUU3r9F7Efztg==}
|
||||
/core-js@3.30.1:
|
||||
resolution: {integrity: sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==}
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
|
||||
|
@ -15413,7 +15413,7 @@ packages:
|
|||
name: plyr
|
||||
version: 3.7.0
|
||||
dependencies:
|
||||
core-js: 3.30.0
|
||||
core-js: 3.30.1
|
||||
custom-event-polyfill: 1.0.7
|
||||
loadjs: 4.2.0
|
||||
rangetouch: 2.0.1
|
||||
|
|