diff --git a/custom/assets/badges/error.avif b/custom/assets/badges/error.avif deleted file mode 100644 index f6f507a5b5..0000000000 Binary files a/custom/assets/badges/error.avif and /dev/null differ diff --git a/custom/assets/badges/error.webp b/custom/assets/badges/error.webp new file mode 100644 index 0000000000..ccdf7ebcbb Binary files /dev/null and b/custom/assets/badges/error.webp differ diff --git a/custom/assets/badges/info.avif b/custom/assets/badges/info.avif deleted file mode 100644 index 6a66997a28..0000000000 Binary files a/custom/assets/badges/info.avif and /dev/null differ diff --git a/custom/assets/badges/info.webp b/custom/assets/badges/info.webp new file mode 100644 index 0000000000..cce0a32d74 Binary files /dev/null and b/custom/assets/badges/info.webp differ diff --git a/custom/assets/badges/not-found.avif b/custom/assets/badges/not-found.avif deleted file mode 100644 index dd27b7470a..0000000000 Binary files a/custom/assets/badges/not-found.avif and /dev/null differ diff --git a/custom/assets/badges/not-found.webp b/custom/assets/badges/not-found.webp new file mode 100644 index 0000000000..502f09fa10 Binary files /dev/null and b/custom/assets/badges/not-found.webp differ diff --git a/docs/api-change.md b/docs/api-change.md index 3dcdfc251e..da170cfa07 100644 --- a/docs/api-change.md +++ b/docs/api-change.md @@ -1,9 +1,11 @@ # Changes to the Firefish API -Breaking changes are indecated by the :warning: icon. +Breaking changes are indicated by the :warning: icon. ## v1.0.5 (unreleased) +### dev17 + - Added `lang` parameter to `notes/create` and `notes/edit`. ### dev11 diff --git a/docs/docker.md b/docs/docker.md index 02035e045b..29af3c4fe0 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -7,7 +7,7 @@ There is a `docker-compose.yml` in the root of the project that you can use to build the container from source -- .config/docker.env (**db config settings**) +- .config/docker_example.env (**db config settings**) - .config/default.yml (**firefish server settings**) ## Configuring @@ -16,7 +16,7 @@ Rename the files: `cp .config/example.yml .config/default.yml` -`cp .config/example.env .config/docker.env` +`cp .config/docker_example.env .config/docker.env` then edit them according to your environment. You can configure `docker.env` with anything you like, but you will have to pay attention to the `default.yml` file: diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index 9ef01815c5..e04c7a6670 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -1441,7 +1441,8 @@ _accountDelete: requestAccountDelete: Sol·licitar la supressió del compte _ad: back: Enrera - reduceFrequencyOfThisAd: Mostrar aquest anunci menys + reduceFrequencyOfThisAd: Mostrar menys aquest anunci + adsBy: Anunci comunitari per {by} _gallery: my: La meva Galeria liked: Publicacions que m'han agradat @@ -1539,8 +1540,8 @@ low: Baixa emailNotConfiguredWarning: L'adreça de correu electrònic no està definida. instanceSecurity: Seguretat del servidor privateMode: Mode Privat -allowedInstances: Servidors a la llista blanca -allowedInstancesDescription: Llista blanca de Hosts amb qui federar, cadascún separat +allowedInstances: Servidors permesos +allowedInstancesDescription: Llista permesa de Hosts amb qui federar, cadascún separat per una línia nova (només s'aplica en mode privat). previewNoteText: Mostra la vista prèvia customCss: CSS personalitzat @@ -1552,7 +1553,7 @@ troubleshooting: Resolució de problemes learnMore: Més informació misskeyUpdated: Firefish s'ha actualitzat! translate: Tradueix -translatedFrom: Traduït per {x} +translatedFrom: Traduït desde {x} aiChanMode: Ai-chan a la interfície d'usuari clàssica keepCw: Mantenir els avisos de contingut pubSub: Comptes Pub/Sub @@ -1646,8 +1647,8 @@ customCssWarn: Aquesta configuració només s'ha d'utilitzar si sabeu què fa. L squareAvatars: Mostra avatars quadrats secureModeInfo: Quan es faci una solicitut d'altres servidors no contestar sense una prova. -privateModeInfo: Quan està activat, només els servidors a la llista blanca es poden - federar amb el vostre servidor. Totes les publicacions s'amagaran al públic. +privateModeInfo: Quan està activat, només els servidors a la llista es poden federar + amb el vostre servidor. Totes les publicacions s'amagaran al públic. useBlurEffect: Utilitzeu efectes de desenfocament a la interfície d'usuari accountDeletionInProgress: La supressió del compte està en curs unmuteThread: Desfés el silenci al fil diff --git a/locales/en-US.yml b/locales/en-US.yml index 2eaec59af3..ae04dd25e7 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -83,7 +83,8 @@ exportRequested: "You've requested an export. This may take a while. It will be to your Drive once completed." importRequested: "You've requested an import. This may take a while." lists: "Lists" -listsDesc: "Lists let you create timelines with specified users. They can be accessed from the timelines page." +listsDesc: "Lists let you create timelines with specified users. They can be accessed + from the timelines page." noLists: "You don't have any lists" note: "Post" notes: "Posts" @@ -408,7 +409,8 @@ avoidMultiCaptchaConfirm: "Using multiple Captcha systems may cause interference them. Would you like to disable the other Captcha systems currently active? If you would like them to stay enabled, press cancel." antennas: "Antennas" -antennasDesc: "Antennas display new posts matching the criteria you set!\n They can be accessed from the timelines page." +antennasDesc: "Antennas display new posts matching the criteria you set!\n They can + be accessed from the timelines page." manageAntennas: "Manage Antennas" name: "Name" antennaSource: "Antenna source" @@ -603,7 +605,8 @@ output: "Output" script: "Script" disablePagesScript: "Disable AiScript on Pages" expandOnNoteClick: "Open post on click" -expandOnNoteClickDesc: "If disabled, you can still open posts in the right-click menu or by clicking the timestamp." +expandOnNoteClickDesc: "If disabled, you can still open posts in the right-click menu + or by clicking the timestamp." updateRemoteUser: "Update remote user information" deleteAllFiles: "Delete all files" deleteAllFilesConfirm: "Are you sure that you want to delete all files?" @@ -743,8 +746,8 @@ unclip: "Unclip" confirmToUnclipAlreadyClippedNote: "This post is already part of the \"{name}\" clip. Do you want to remove it from this clip instead?" public: "Public" -i18nInfo: "Firefish is being translated into various languages by volunteers. You can - help at {link}." +i18nInfo: "Firefish is being translated into various languages by volunteers. You + can help at {link}." manageAccessTokens: "Manage access tokens" accountInfo: "Account Info" notesCount: "Number of posts" @@ -779,7 +782,8 @@ pageLikedCount: "Number of received Page likes" contact: "Contact" useSystemFont: "Use the system's default font" clips: "Clips" -clipsDesc: "Clips are like share-able categorized bookmarks. You can create clips from the menu of individual posts." +clipsDesc: "Clips are like share-able categorized bookmarks. You can create clips + from the menu of individual posts." experimentalFeatures: "Experimental features" developer: "Developer" makeExplorable: "Make account visible in \"Explore\"" @@ -888,10 +892,10 @@ secureMode: "Secure Mode (Authorized Fetch)" instanceSecurity: "Server Security" secureModeInfo: "When requesting from other servers, do not send back without proof." privateMode: "Private Mode" -privateModeInfo: "When enabled, only whitelisted servers can federate with your server. +privateModeInfo: "When enabled, only allowlisted servers can federate with your server. All posts will be hidden from the public." -allowedInstances: "Whitelisted Servers" -allowedInstancesDescription: "Hosts of servers to be whitelisted for federation, each +allowedInstances: "Allowlisted Servers" +allowedInstancesDescription: "Hosts of servers to be allowlisted for federation, each separated by a new line (only applies in private mode)." previewNoteText: "Show preview" customCss: "Custom CSS" @@ -1083,8 +1087,8 @@ license: "License" indexPosts: "Index Posts" indexFrom: "Index from Post ID onwards" indexFromDescription: "Leave blank to index every post" -indexNotice: "Now indexing. This will probably take a while, please don't restart\ - \ your server for at least an hour." +indexNotice: "Now indexing. This will probably take a while, please don't restart + your server for at least an hour." customKaTeXMacro: "Custom KaTeX macros" customKaTeXMacroDescription: "Set up macros to write mathematical expressions easily! The notation conforms to the LaTeX command definitions and is written as \\newcommand{\\ @@ -1132,9 +1136,11 @@ origin: "Origin" delete2fa: "Disable 2FA" deletePasskeys: "Delete passkeys" delete2faConfirm: "This will irreversibly delete 2FA on this account. Proceed?" -deletePasskeysConfirm: "This will irreversibly delete all passkeys and security keys on this account. Proceed?" +deletePasskeysConfirm: "This will irreversibly delete all passkeys and security keys + on this account. Proceed?" inputNotMatch: "Input does not match" -addRe: "Add \"re:\" at the beginning of comment in reply to a post with a content warning" +addRe: "Add \"re:\" at the beginning of comment in reply to a post with a content + warning" confirm: "Confirm" importZip: "Import ZIP" exportZip: "Export ZIP" @@ -1142,7 +1148,8 @@ emojiPackCreator: "Emoji pack creator" indexable: "Indexable" indexableDescription: "Allow built-in search to show your public posts" languageForTranslation: "Post translation language" -detectPostLanguage: "Automatically detect the language and show a translate button for posts in foreign languages" +detectPostLanguage: "Automatically detect the language and show a translate button + for posts in foreign languages" vibrate: "Play vibrations" openServerInfo: "Show server information by clicking the server ticker on a post" @@ -1237,8 +1244,8 @@ _registry: domain: "Domain" createKey: "Create key" _aboutFirefish: - about: "Firefish is a fork of Misskey made by ThatOneCalculator, which has been in - development since 2022." + about: "Firefish is a fork of Misskey made by ThatOneCalculator, which has been + in development since 2022." contributors: "Main contributors" allContributors: "All contributors" misskeyContributors: "Misskey contributors" @@ -1247,13 +1254,15 @@ _aboutFirefish: donate: "Donate to Firefish" donateTitle: "Enjoying Firefish?" pleaseDonateToFirefish: "Please consider donating to Firefish to support its development." - pleaseDonateToHost: "Please also consider donating to your home server, {host}, to help support its operation costs." + pleaseDonateToHost: "Please also consider donating to your home server, {host}, + to help support its operation costs." donateHost: "Donate to {host}" morePatrons: "We also appreciate the support of many other helpers not listed here. Thank you! 🥰" sponsors: "Firefish sponsors" patrons: "Firefish patrons" - patronsList: "Listed chronologically, not by donation size. Donate with the link above to get your name on here!" + patronsList: "Listed chronologically, not by donation size. Donate with the link + above to get your name on here!" _nsfw: respect: "Hide NSFW media" ignore: "Don't hide NSFW media" @@ -1268,7 +1277,8 @@ _mfm: can be used in many places. Here you can view a list of all available MFM syntax." dummy: "Firefish expands the world of the Fediverse" advanced: "Advanced MFM" - advancedDescription: "If disabled, only allows for basic markup unless animated MFM is playing" + advancedDescription: "If disabled, only allows for basic markup unless animated + MFM is playing" mention: "Mention" mentionDescription: "You can specify a user by using an At-Symbol and a username." hashtag: "Hashtag" @@ -1524,10 +1534,10 @@ _tutorial: step5_4: "The Local {icon} timeline is where you can see posts from everyone else on this server." step5_5: "The Social {icon} timeline is a combination of the Home and Local timelines." - step5_6: "The Recommended {icon} timeline is where you can see posts from servers\ - \ the admins recommend." - step5_7: "The Global {icon} timeline is where you can see posts from every other\ - \ connected server." + step5_6: "The Recommended {icon} timeline is where you can see posts from servers + the admins recommend." + step5_7: "The Global {icon} timeline is where you can see posts from every other + connected server." step6_1: "So, what is this place?" step6_2: "Well, you didn't just join Firefish. You joined a portal to the Fediverse, an interconnected network of thousands of servers." @@ -1540,23 +1550,29 @@ _2fa: registerTOTP: "Register authenticator app" step1: "First, install an authentication app (such as {a} or {b}) on your device." step2: "Then, scan the QR code displayed on this screen." - step2Click: "Clicking on this QR code will allow you to register 2FA to your security key or phone authenticator app." + step2Click: "Clicking on this QR code will allow you to register 2FA to your security + key or phone authenticator app." step2Url: "You can also enter this URL if you're using a desktop program:" step3Title: "Enter an authentication code" step3: "Enter the token provided by your app to finish setup." step4: "From now on, any future login attempts will ask for such a login token." securityKeyNotSupported: "Your browser does not support security keys." - registerTOTPBeforeKey: "Please set up an authenticator app to register a security or pass key." - securityKeyInfo: "Besides fingerprint or PIN authentication, you can also setup authentication via hardware security keys that support FIDO2 to further secure your account." + registerTOTPBeforeKey: "Please set up an authenticator app to register a security + or pass key." + securityKeyInfo: "Besides fingerprint or PIN authentication, you can also setup + authentication via hardware security keys that support FIDO2 to further secure + your account." chromePasskeyNotSupported: "Chrome passkeys are currently not supported." registerSecurityKey: "Register a security or pass key" securityKeyName: "Enter a key name" tapSecurityKey: "Please follow your browser to register the security or pass key" removeKey: "Remove security key" removeKeyConfirm: "Really delete the {name} key?" - whyTOTPOnlyRenew: "The authenticator app cannot be removed as long as a security key is registered." + whyTOTPOnlyRenew: "The authenticator app cannot be removed as long as a security + key is registered." renewTOTP: "Reconfigure authenticator app" - renewTOTPConfirm: "This will cause verification codes from your previous app to stop working" + renewTOTPConfirm: "This will cause verification codes from your previous app to + stop working" renewTOTPOk: "Reconfigure" renewTOTPCancel: "Cancel" token: "2FA Token" @@ -1704,10 +1720,9 @@ _profile: youCanIncludeHashtags: "You can also include hashtags in your bio." metadata: "Additional Information" metadataEdit: "Edit additional Information" - metadataDescription: - "Using these, you can display additional information fields - in your profile. You can add an {a} tag or {l} tag with {rel} - to verify the link on your profile!" + metadataDescription: "Using these, you can display additional information fields + in your profile. You can add an {a} tag or {l} tag with {rel} to verify the link + on your profile!" metadataLabel: "Label" metadataContent: "Content" changeAvatar: "Change avatar" @@ -2118,9 +2133,9 @@ _deck: _experiments: title: "Experiments" enablePostImports: "Enable post imports" - postImportsCaption: "Allows users to import their posts from past Firefish,\ - \ Misskey, Mastodon, Akkoma, and Pleroma accounts. It may cause slowdowns during\ - \ load if your queue is bottlenecked." + postImportsCaption: "Allows users to import their posts from past Firefish, Misskey, + Mastodon, Akkoma, and Pleroma accounts. It may cause slowdowns during load if + your queue is bottlenecked." _dialog: charactersExceeded: "Max characters exceeded! Current: {current}/Limit: {max}" charactersBelow: "Not enough characters! Current: {current}/Limit: {min}" diff --git a/locales/id-ID.yml b/locales/id-ID.yml index da599a8fb3..af6afa5dcc 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -953,7 +953,8 @@ _accountDelete: inProgress: "Penghapusan sedang dalam proses" _ad: back: "Kembali" - reduceFrequencyOfThisAd: "Tampilkan iklan ini lebih sedikit" + reduceFrequencyOfThisAd: "Tampilkan banner ini lebih sedikit" + adsBy: Banner komunitas oleh {by} _forgotPassword: enterEmail: "Masukkan alamat surel yang kamu gunakan pada saat mendaftar. Sebuah tautan untuk mengatur ulang kata sandi kamu akan dikirimkan ke alamat surel tersebut." @@ -1923,9 +1924,9 @@ moderation: Moderasi userSaysSomethingReason: '{name} mengatakan {reason}' secureMode: Mode Aman (Pengambilan Terotorisasi) secureModeInfo: Saat meminta dari server lain, jangan kirim kembali tanpa bukti. -privateModeInfo: Saat aktif, hanya server yang masuk daftar putih dapat terfederasi - dengan servermu. Semua postingan akan disembunyikan dari publik. -allowedInstances: Server Masuk Daftar Putih +privateModeInfo: Saat aktif, hanya server yang masuk daftar yang diizinkan yang dapat + terfederasi dengan servermu. Semua postingan akan disembunyikan dari publik. +allowedInstances: Daftar Server Diizinkan newer: lebih baru userSaysSomethingReasonReply: '{name} membalas postingan berisi {reason}' userSaysSomethingReasonRenote: '{name} memposting ulang postingan berisi {reason}' @@ -1935,8 +1936,8 @@ jumpToPrevious: Lompat ke sebelumnya flagSpeakAsCatDescription: Postinganmu akan nyampak dalam mode kucing cw: Peringatan konten flagSpeakAsCat: Bicara sebagai kucing -allowedInstancesDescription: Host server akan masuk daftar putih untuk federasi, mereka - dipisahkan dengan baris baru (hanya diterapkan pada mode pribadi). +allowedInstancesDescription: Server host akan masuk daftar yang diizinkan untuk federasi, + mereka dipisahkan dengan baris baru (hanya diterapkan pada mode pribadi). xl: XL privateMode: Mode Pribadi seperateRenoteQuote: Tombol posting ulang dan kutip terpisah @@ -2182,3 +2183,4 @@ languageForTranslation: Bahasa terjemahan kiriman openServerInfo: Tampilkan informasi server dengan mengeklik ticker server di sebuah kiriman vibrate: Putar getaran +clickToShowPatterns: Klik untuk menampilkan pola modul diff --git a/locales/it-IT.yml b/locales/it-IT.yml index c4c1ab4bf3..360f15560a 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -901,7 +901,8 @@ _accountDelete: caricato. _ad: back: "Indietro" - reduceFrequencyOfThisAd: "Mostra meno spesso questa pubblicità" + reduceFrequencyOfThisAd: "Mostra meno spesso questo banner" + adsBy: Banner della comunità da {by} _forgotPassword: enterEmail: "Inserisci l'e-mail che hai registrato nel tuo profilo. Il link di ripristino della password verrà inviato a questo indirizzo." @@ -1997,11 +1998,11 @@ secureMode: Modalità sicura (Acquisizione autorizzata) secureModeInfo: Le richieste dai server remoti non ricevono risposta senza prima una verifica. privateMode: Modalità privata -allowedInstancesDescription: Gli host dei server che saranno federati in esclusiva, +allowedInstancesDescription: Gli host dei server con cui sarà permessa la federazione, uno per riga (funziona solo in modalità privata). -privateModeInfo: Se abilitata, solo i server in una whitelist potranno essere federati +privateModeInfo: Se abilitata, solo i server nell'elenco potranno essere federati con questo server. Tutti i post saranno nascosti al pubblico. -allowedInstances: Whitelist dei server +allowedInstances: Elenco server permessi customCssWarn: Questa impostazione dovrebbe essere usata solo se sai cosa stai facendo. Inserire valori errati potrebbe bloccare il funzionamento del client. lastCommunication: Ultima comunicazione @@ -2170,3 +2171,4 @@ languageForTranslation: Linguaggio di traduzione dei post openServerInfo: Mostra informazioni sul server cliccando sul riquadro del server in un post vibrate: Abilita la vibrazione +clickToShowPatterns: Clicca per vedere i pattern del modulo diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 5e20452a76..b7a7ff1ddf 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -58,7 +58,7 @@ followRequestAccepted: "关注请求已通过" mention: "提及" mentions: "提及" directNotes: "私信" -importAndExport: "导入/导出数据" +importAndExport: "导入 / 导出数据" import: "导入" export: "导出" files: "文件" @@ -675,7 +675,7 @@ driveFilesCount: "网盘的文件数" driveUsage: "网盘的空间用量" noCrawle: "要求搜索引擎不索引该用户" noCrawleDescription: "要求外部搜索引擎不收录(索引)您的内容。" -lockedAccountInfo: "即使通过了关注请求,只要您不将帖子可见范围设置成“关注者”,任何人都可以看到您的帖子。" +lockedAccountInfo: "即使通过了关注请求,只要您不将帖子可见范围设置成「关注者」,任何人都可以看到您的帖子。" alwaysMarkSensitive: "默认将媒体文件标记为敏感内容" loadRawImages: "加载原始图像而不是显示缩略图" disableShowingAnimatedImages: "不播放动画" @@ -1245,7 +1245,7 @@ _tutorial: step6_1: "那么,这里是什么地方?" step6_2: "好吧,您不只是加入 Firefish。您已经加入了 Fediverse 的一个门户,这是一个由成千上万台服务器组成的互联网络。" step6_3: "每个服务器的工作方式不同,并不是所有的服务器都运行 Firefish。但这个服务器是的! 这有点复杂,但您很快就会明白的。" - step6_4: "现在,去吧,去探索,去享受乐趣吧!" + step6_4: "现在,去吧,去探索,去享受乐趣吧!" _2fa: alreadyRegistered: "您已经注册了两步验证设备。" registerTOTP: "注册身份验证器应用" @@ -1917,7 +1917,7 @@ _skinTones: isModerator: 监察员 isAdmin: 管理员 findOtherInstance: 寻找其它服务器 -moveFromDescription: 这将为您的旧账号设置一个别名,以便您可以从该旧账号迁移到当前账号。在从旧账号迁移之前执行此操作。请输入格式如@person@server.com +moveFromDescription: 这将为您的旧账号设置一个别名,以便您可以从该旧账号迁移到当前账号。在从旧账号迁移之前执行此操作。请输入格式如 @person@server.com 的账号标签 indexPosts: 索引帖子 signupsDisabled: 该服务器目前关闭注册,但您随时可以在另一台服务器上注册!如果您有该服务器的邀请码,请在下面输入。 diff --git a/package.json b/package.json index 579352ef69..cb82aaa074 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "type": "git", "url": "https://git.joinfirefish.org/firefish/firefish.git" }, - "packageManager": "pnpm@8.7.6", + "packageManager": "pnpm@8.8.0", "private": true, "scripts": { "rebuild": "pnpm run clean && ./scripts/build-greet.sh && pnpm --filter !sw -r --parallel run build && pnpm --filter sw run build && pnpm run gulp", @@ -64,7 +64,7 @@ "gulp-replace": "1.1.4", "gulp-terser": "2.1.0", "install-peers": "^1.0.4", - "pnpm": "8.7.1", + "pnpm": "8.8.0", "start-server-and-test": "1.15.2", "typescript": "5.2.2" } diff --git a/packages/backend/assets/badges/error.avif b/packages/backend/assets/badges/error.avif deleted file mode 100644 index f6f507a5b5..0000000000 Binary files a/packages/backend/assets/badges/error.avif and /dev/null differ diff --git a/packages/backend/assets/badges/error.webp b/packages/backend/assets/badges/error.webp new file mode 100644 index 0000000000..ccdf7ebcbb Binary files /dev/null and b/packages/backend/assets/badges/error.webp differ diff --git a/packages/backend/assets/badges/info.avif b/packages/backend/assets/badges/info.avif deleted file mode 100644 index 6a66997a28..0000000000 Binary files a/packages/backend/assets/badges/info.avif and /dev/null differ diff --git a/packages/backend/assets/badges/info.webp b/packages/backend/assets/badges/info.webp new file mode 100644 index 0000000000..cce0a32d74 Binary files /dev/null and b/packages/backend/assets/badges/info.webp differ diff --git a/packages/backend/assets/badges/not-found.avif b/packages/backend/assets/badges/not-found.avif deleted file mode 100644 index dd27b7470a..0000000000 Binary files a/packages/backend/assets/badges/not-found.avif and /dev/null differ diff --git a/packages/backend/assets/badges/not-found.webp b/packages/backend/assets/badges/not-found.webp new file mode 100644 index 0000000000..502f09fa10 Binary files /dev/null and b/packages/backend/assets/badges/not-found.webp differ diff --git a/packages/backend/assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-700.woff2 b/packages/backend/assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-700.woff2 new file mode 100644 index 0000000000..f3898921c8 Binary files /dev/null and b/packages/backend/assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-700.woff2 differ diff --git a/packages/backend/assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-700italic.woff2 b/packages/backend/assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-700italic.woff2 new file mode 100644 index 0000000000..9aac4b88e4 Binary files /dev/null and b/packages/backend/assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-700italic.woff2 differ diff --git a/packages/backend/assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-italic.woff2 b/packages/backend/assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-italic.woff2 new file mode 100644 index 0000000000..ce7c7fed1d Binary files /dev/null and b/packages/backend/assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-italic.woff2 differ diff --git a/packages/backend/assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-regular.woff2 b/packages/backend/assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-regular.woff2 new file mode 100644 index 0000000000..7093c429f2 Binary files /dev/null and b/packages/backend/assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-regular.woff2 differ diff --git a/packages/backend/migration/1000000000000-Init.js b/packages/backend/migration/1000000000000-Init.js index d736f6b8ee..a72f53841c 100644 --- a/packages/backend/migration/1000000000000-Init.js +++ b/packages/backend/migration/1000000000000-Init.js @@ -220,7 +220,7 @@ export class Init1000000000000 { `CREATE INDEX "IDX_3c601b70a1066d2c8b517094cb" ON "notification" ("notifieeId") `, ); await queryRunner.query( - `CREATE TABLE "meta" ("id" character varying(32) NOT NULL, "name" character varying(128), "description" character varying(1024), "maintainerName" character varying(128), "maintainerEmail" character varying(128), "announcements" jsonb NOT NULL DEFAULT '[]', "disableRegistration" boolean NOT NULL DEFAULT false, "disableLocalTimeline" boolean NOT NULL DEFAULT false, "disableGlobalTimeline" boolean NOT NULL DEFAULT false, "enableEmojiReaction" boolean NOT NULL DEFAULT true, "useStarForReactionFallback" boolean NOT NULL DEFAULT false, "langs" character varying(64) array NOT NULL DEFAULT '{}'::varchar[], "hiddenTags" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "blockedHosts" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "mascotImageUrl" character varying(512) DEFAULT '/static-assets/badges/info.avif', "bannerUrl" character varying(512), "errorImageUrl" character varying(512) DEFAULT '/static-assets/badges/error.avif', "iconUrl" character varying(512), "cacheRemoteFiles" boolean NOT NULL DEFAULT false, "proxyAccount" character varying(128), "enableRecaptcha" boolean NOT NULL DEFAULT false, "recaptchaSiteKey" character varying(64), "recaptchaSecretKey" character varying(64), "localDriveCapacityMb" integer NOT NULL DEFAULT 1024, "remoteDriveCapacityMb" integer NOT NULL DEFAULT 32, "maxNoteTextLength" integer NOT NULL DEFAULT 500, "summalyProxy" character varying(128), "enableEmail" boolean NOT NULL DEFAULT false, "email" character varying(128), "smtpSecure" boolean NOT NULL DEFAULT false, "smtpHost" character varying(128), "smtpPort" integer, "smtpUser" character varying(128), "smtpPass" character varying(128), "enableServiceWorker" boolean NOT NULL DEFAULT false, "swPublicKey" character varying(128), "swPrivateKey" character varying(128), "enableTwitterIntegration" boolean NOT NULL DEFAULT false, "twitterConsumerKey" character varying(128), "twitterConsumerSecret" character varying(128), "enableGithubIntegration" boolean NOT NULL DEFAULT false, "githubClientId" character varying(128), "githubClientSecret" character varying(128), "enableDiscordIntegration" boolean NOT NULL DEFAULT false, "discordClientId" character varying(128), "discordClientSecret" character varying(128), CONSTRAINT "PK_c4c17a6c2bd7651338b60fc590b" PRIMARY KEY ("id"))`, + `CREATE TABLE "meta" ("id" character varying(32) NOT NULL, "name" character varying(128), "description" character varying(1024), "maintainerName" character varying(128), "maintainerEmail" character varying(128), "announcements" jsonb NOT NULL DEFAULT '[]', "disableRegistration" boolean NOT NULL DEFAULT false, "disableLocalTimeline" boolean NOT NULL DEFAULT false, "disableGlobalTimeline" boolean NOT NULL DEFAULT false, "enableEmojiReaction" boolean NOT NULL DEFAULT true, "useStarForReactionFallback" boolean NOT NULL DEFAULT false, "langs" character varying(64) array NOT NULL DEFAULT '{}'::varchar[], "hiddenTags" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "blockedHosts" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "mascotImageUrl" character varying(512) DEFAULT '/static-assets/badges/info.webp', "bannerUrl" character varying(512), "errorImageUrl" character varying(512) DEFAULT '/static-assets/badges/error.webp', "iconUrl" character varying(512), "cacheRemoteFiles" boolean NOT NULL DEFAULT false, "proxyAccount" character varying(128), "enableRecaptcha" boolean NOT NULL DEFAULT false, "recaptchaSiteKey" character varying(64), "recaptchaSecretKey" character varying(64), "localDriveCapacityMb" integer NOT NULL DEFAULT 1024, "remoteDriveCapacityMb" integer NOT NULL DEFAULT 32, "maxNoteTextLength" integer NOT NULL DEFAULT 500, "summalyProxy" character varying(128), "enableEmail" boolean NOT NULL DEFAULT false, "email" character varying(128), "smtpSecure" boolean NOT NULL DEFAULT false, "smtpHost" character varying(128), "smtpPort" integer, "smtpUser" character varying(128), "smtpPass" character varying(128), "enableServiceWorker" boolean NOT NULL DEFAULT false, "swPublicKey" character varying(128), "swPrivateKey" character varying(128), "enableTwitterIntegration" boolean NOT NULL DEFAULT false, "twitterConsumerKey" character varying(128), "twitterConsumerSecret" character varying(128), "enableGithubIntegration" boolean NOT NULL DEFAULT false, "githubClientId" character varying(128), "githubClientSecret" character varying(128), "enableDiscordIntegration" boolean NOT NULL DEFAULT false, "discordClientId" character varying(128), "discordClientSecret" character varying(128), CONSTRAINT "PK_c4c17a6c2bd7651338b60fc590b" PRIMARY KEY ("id"))`, ); await queryRunner.query( `CREATE TABLE "following" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "followeeId" character varying(32) NOT NULL, "followerId" character varying(32) NOT NULL, "followerHost" character varying(128), "followerInbox" character varying(512), "followerSharedInbox" character varying(512), "followeeHost" character varying(128), "followeeInbox" character varying(512), "followeeSharedInbox" character varying(512), CONSTRAINT "PK_c76c6e044bdf76ecf8bfb82a645" PRIMARY KEY ("id"))`, diff --git a/packages/backend/src/misc/detect-language.ts b/packages/backend/src/misc/detect-language.ts new file mode 100644 index 0000000000..6147247dee --- /dev/null +++ b/packages/backend/src/misc/detect-language.ts @@ -0,0 +1,11 @@ +import { detect } from "tinyld"; +import * as mfm from "mfm-js"; + +export default function detectLanguage(text: string): string { + const nodes = mfm.parse(text); + const filtered = mfm.extract(nodes, (node) => { + return node.type === "text" || node.type === "quote"; + }); + const purified = mfm.toString(filtered); + return detect(purified); +} diff --git a/packages/backend/src/misc/nyaize.ts b/packages/backend/src/misc/nyaize.ts index 13a112ce57..32c54fbd7b 100644 --- a/packages/backend/src/misc/nyaize.ts +++ b/packages/backend/src/misc/nyaize.ts @@ -1,28 +1,31 @@ -export function nyaize(text: string): string { - return ( - text - // ja-JP - .replaceAll("な", "にゃ") - .replaceAll("ナ", "ニャ") - .replaceAll("ナ", "ニャ") - // en-US - .replace(/(?<=n)a/gi, (x) => (x === "A" ? "YA" : "ya")) - .replace(/(?<=morn)ing/gi, (x) => (x === "ING" ? "YAN" : "yan")) - .replace(/(?<=every)one/gi, (x) => (x === "ONE" ? "NYAN" : "nyan")) - .replace(/non(?=[bcdfghjklmnpqrstvwxyz])/gi, (x) => - x === "NON" ? "NYAN" : "nyan", - ) - // ko-KR - .replace(/[나-낳]/g, (match) => - String.fromCharCode( - match.charCodeAt(0)! + "냐".charCodeAt(0) - "나".charCodeAt(0), - ), - ) - .replace(/(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm, "다냥") - .replace(/(야(?=\?))|(야$)|(야(?= ))/gm, "냥") - // el-GR - .replaceAll("να", "νια") - .replaceAll("ΝΑ", "ΝΙΑ") - .replaceAll("Να", "Νια") - ); +export function nyaize(text: string, lang?: string): string { + text = text + // ja-JP + .replaceAll("な", "にゃ") + .replaceAll("ナ", "ニャ") + .replaceAll("ナ", "ニャ") + // en-US + .replace(/(?<=n)a/gi, (x) => (x === "A" ? "YA" : "ya")) + .replace(/(?<=morn)ing/gi, (x) => (x === "ING" ? "YAN" : "yan")) + .replace(/(?<=every)one/gi, (x) => (x === "ONE" ? "NYAN" : "nyan")) + .replace(/non(?=[bcdfghjklmnpqrstvwxyz])/gi, (x) => + x === "NON" ? "NYAN" : "nyan", + ) + // ko-KR + .replace(/[나-낳]/g, (match) => + String.fromCharCode( + match.charCodeAt(0)! + "냐".charCodeAt(0) - "나".charCodeAt(0), + ), + ) + .replace(/(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm, "다냥") + .replace(/(야(?=\?))|(야$)|(야(?= ))/gm, "냥") + // el-GR + .replaceAll("να", "νια") + .replaceAll("ΝΑ", "ΝΙΑ") + .replaceAll("Να", "Νια"); + + // zh-CN, zh-TW + if (lang === "zh") text = text.replace(/(妙|庙|描|渺|瞄|秒|苗|藐|廟)/g, "喵"); + + return text; } diff --git a/packages/backend/src/models/entities/meta.ts b/packages/backend/src/models/entities/meta.ts index ad7238da52..6a19cdde75 100644 --- a/packages/backend/src/models/entities/meta.ts +++ b/packages/backend/src/models/entities/meta.ts @@ -162,7 +162,7 @@ export class Meta { @Column("varchar", { length: 512, nullable: true, - default: "/static-assets/badges/info.avif", + default: "/static-assets/badges/info.webp", }) public mascotImageUrl: string | null; @@ -187,7 +187,7 @@ export class Meta { @Column("varchar", { length: 512, nullable: true, - default: "/static-assets/badges/error.avif", + default: "/static-assets/badges/error.webp", }) public errorImageUrl: string | null; diff --git a/packages/backend/src/models/repositories/note.ts b/packages/backend/src/models/repositories/note.ts index 54001f9524..60e5a8d5ca 100644 --- a/packages/backend/src/models/repositories/note.ts +++ b/packages/backend/src/models/repositories/note.ts @@ -264,7 +264,8 @@ export const NoteRepository = db.getRepository(Note).extend({ const tokens = packed.text ? mfm.parse(packed.text) : []; function nyaizeNode(node: mfm.MfmNode) { if (node.type === "quote") return; - if (node.type === "text") node.props.text = nyaize(node.props.text); + if (node.type === "text") + node.props.text = nyaize(node.props.text, packed.lang); if (node.children) { for (const child of node.children) { diff --git a/packages/backend/src/remote/activitypub/renderer/note.ts b/packages/backend/src/remote/activitypub/renderer/note.ts index 4c7650e8cc..b840e2d6f1 100644 --- a/packages/backend/src/remote/activitypub/renderer/note.ts +++ b/packages/backend/src/remote/activitypub/renderer/note.ts @@ -1,12 +1,12 @@ import { In, IsNull } from "typeorm"; -import { detect as detectLanguage } from "tinyld"; import config from "@/config/index.js"; import type { Note, IMentionedRemoteUsers } from "@/models/entities/note.js"; import type { DriveFile } from "@/models/entities/drive-file.js"; import { DriveFiles, Notes, Users, Emojis, Polls } from "@/models/index.js"; import type { Emoji } from "@/models/entities/emoji.js"; import type { Poll } from "@/models/entities/poll.js"; -import toHtml from "../misc/get-note-html.js"; +import toHtml from "@/remote/activitypub/misc/get-note-html.js"; +import detectLanguage from "@/misc/detect-language.js"; import renderEmoji from "./emoji.js"; import renderMention from "./mention.js"; import renderHashtag from "./hashtag.js"; diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 098271793e..15f2c96603 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -64,7 +64,7 @@ export const meta = { type: "string", optional: false, nullable: false, - default: "/static-assets/badges/info.avif", + default: "/static-assets/badges/info.webp", }, bannerUrl: { type: "string", @@ -75,7 +75,7 @@ export const meta = { type: "string", optional: false, nullable: false, - default: "/static-assets/badges/error.avif", + default: "/static-assets/badges/error.webp", }, iconUrl: { type: "string", diff --git a/packages/backend/src/server/api/endpoints/admin/send-mod-mail.ts b/packages/backend/src/server/api/endpoints/admin/send-mod-mail.ts index ac0e0528ad..a36dca2f73 100644 --- a/packages/backend/src/server/api/endpoints/admin/send-mod-mail.ts +++ b/packages/backend/src/server/api/endpoints/admin/send-mod-mail.ts @@ -49,7 +49,7 @@ export default define(meta, paramDef, async (ps) => { createNotification(user.id, "app", { customBody: ps.comment, customHeader: "Moderation Notice", - customIcon: "/static-assets/badges/info.avif", + customIcon: "/static-assets/badges/info.webp", }); setImmediate(async () => { diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index b7905e583f..29a0e7a1af 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -155,7 +155,7 @@ export const meta = { type: "string", optional: false, nullable: false, - default: "/static-assets/badges/info.avif", + default: "/static-assets/badges/info.webp", }, bannerUrl: { type: "string", @@ -166,7 +166,7 @@ export const meta = { type: "string", optional: false, nullable: false, - default: "/static-assets/badges/error.avif", + default: "/static-assets/badges/error.webp", }, iconUrl: { type: "string", diff --git a/packages/backend/src/server/api/endpoints/notes/edit.ts b/packages/backend/src/server/api/endpoints/notes/edit.ts index 9add576708..e6d39c5249 100644 --- a/packages/backend/src/server/api/endpoints/notes/edit.ts +++ b/packages/backend/src/server/api/endpoints/notes/edit.ts @@ -35,8 +35,8 @@ import renderUpdate from "@/remote/activitypub/renderer/update.js"; import { deliverToRelays } from "@/services/relay.js"; // import { deliverQuestionUpdate } from "@/services/note/polls/update.js"; import { fetchMeta } from "@/misc/fetch-meta.js"; -import { detect as detectLanguage } from "tinyld"; import { langmap } from "@/misc/langmap.js"; +import detectLanguage from "@/misc/detect-language.js"; export const meta = { tags: ["notes"], diff --git a/packages/backend/src/server/web/style.css b/packages/backend/src/server/web/style.css index 8a16ca8425..ebef7ce8fe 100644 --- a/packages/backend/src/server/web/style.css +++ b/packages/backend/src/server/web/style.css @@ -1,7 +1,18 @@ +/* atkinson-hyperlegible-regular - latin_latin-ext */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Atkinson Hyperlegible"; + font-style: normal; + font-weight: 400; + src: url("/static-assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-regular.woff2") + format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} + html { background-color: var(--bg); color: var(--fg); } + @media (prefers-color-scheme: dark) { html { --bg: rgb(17, 17, 27); @@ -104,7 +115,7 @@ html { } } -@media(prefers-reduced-motion) { +@media (prefers-reduced-motion) { #splashSpinner { display: block; } @@ -122,5 +133,5 @@ html { height: 0; text-align: center; padding-top: 100px; - font-family: sans-serif; + font-family: "Atkinson Hyperlegible", sans-serif; } diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index cc5595caf3..1b049e2928 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -36,9 +36,9 @@ html link(rel='icon' href= icon || `/favicon.ico?${ timestamp }`) link(rel='apple-touch-icon' href= icon || `/apple-touch-icon.png?${ timestamp }`) link(rel='manifest' href='/manifest.json') - link(rel='prefetch' href=`/static-assets/badges/info.avif?${ timestamp }`) - link(rel='prefetch' href=`/static-assets/badges/not-found.avif?${ timestamp }`) - link(rel='prefetch' href=`/static-assets/badges/error.avif?${ timestamp }`) + link(rel='prefetch' href=`/static-assets/badges/info.webp?${ timestamp }`) + link(rel='prefetch' href=`/static-assets/badges/not-found.webp?${ timestamp }`) + link(rel='prefetch' href=`/static-assets/badges/error.webp?${ timestamp }`) link(rel='stylesheet' href=`/static-assets/instance.css?${ timestamp }`) link(rel='modulepreload' href=`/assets/${clientEntry.file}`) diff --git a/packages/backend/src/services/drive/add-file.ts b/packages/backend/src/services/drive/add-file.ts index 9e8e57cc99..6730ddff27 100644 --- a/packages/backend/src/services/drive/add-file.ts +++ b/packages/backend/src/services/drive/add-file.ts @@ -93,7 +93,7 @@ async function save( if (type === "image/png") ext = ".png"; if (type === "image/webp") ext = ".webp"; if (type === "image/apng") ext = ".apng"; - if (type === "image/avif") ext = ".avif"; + if (type === "image/avif") ext = ".webp"; if (type === "image/vnd.mozilla.apng") ext = ".apng"; } diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts index dcd2428fe1..632cb960e2 100644 --- a/packages/backend/src/services/note/create.ts +++ b/packages/backend/src/services/note/create.ts @@ -64,11 +64,11 @@ import type { UserProfile } from "@/models/entities/user-profile.js"; import { db } from "@/db/postgre.js"; import { getActiveWebhooks } from "@/misc/webhook-cache.js"; import { shouldSilenceInstance } from "@/misc/should-block-instance.js"; -import meilisearch from "../../db/meilisearch.js"; +import meilisearch from "@/db/meilisearch.js"; import { redisClient } from "@/db/redis.js"; import { Mutex } from "redis-semaphore"; -import { detect as detectLanguage } from "tinyld"; import { langmap } from "@/misc/langmap.js"; +import detectLanguage from "@/misc/detect-language.js"; const mutedWordsCache = new Cache< { userId: UserProfile["userId"]; mutedWords: UserProfile["mutedWords"] }[] diff --git a/packages/client/src/components/MkChannelList.vue b/packages/client/src/components/MkChannelList.vue index 5f937b05f2..d6c9a44c4e 100644 --- a/packages/client/src/components/MkChannelList.vue +++ b/packages/client/src/components/MkChannelList.vue @@ -3,7 +3,7 @@ <template #empty> <div class="_fullinfo"> <img - src="/static-assets/badges/not-found.avif" + src="/static-assets/badges/not-found.webp" class="_ghost" :alt="i18n.ts.notFound" /> diff --git a/packages/client/src/components/MkDialog.vue b/packages/client/src/components/MkDialog.vue index 5acef39654..688e4edc8e 100644 --- a/packages/client/src/components/MkDialog.vue +++ b/packages/client/src/components/MkDialog.vue @@ -54,7 +54,12 @@ <Mfm :text="i18n.ts.password" /> </header> <div v-if="text" :class="$style.text"> - <Mfm :text="text" /> + <span + v-if="isPlaintext === true" + style="white-space: pre-line" + >{{ text }}</span + > + <Mfm v-else :text="text" /> </div> <MkInput v-if="input && input.type !== 'paragraph'" @@ -245,6 +250,7 @@ const props = withDefaults( | "search"; title: string; text?: string; + isPlaintext?: boolean; input?: Input; select?: Select; icon?: string; @@ -268,6 +274,7 @@ const props = withDefaults( isYesNo: false, cancelableByBgClick: true, + isPlaintext: false, }, ); diff --git a/packages/client/src/components/MkMedia.vue b/packages/client/src/components/MkMedia.vue index ab20bbd792..c8bc6b6e88 100644 --- a/packages/client/src/components/MkMedia.vue +++ b/packages/client/src/components/MkMedia.vue @@ -138,6 +138,7 @@ function captionPopup() { os.alert({ type: "info", text: props.media.comment, + isPlaintext: true, }); } diff --git a/packages/client/src/components/MkMediaList.vue b/packages/client/src/components/MkMediaList.vue index f183e8da28..c0e82515f5 100644 --- a/packages/client/src/components/MkMediaList.vue +++ b/packages/client/src/components/MkMediaList.vue @@ -332,6 +332,7 @@ const previewableCount = props.mediaList.filter((media) => overflow-x: clip; overflow-y: auto; overscroll-behavior: contain; + white-space: pre-line; } .pwsp__alt-text:empty { diff --git a/packages/client/src/components/MkNote.vue b/packages/client/src/components/MkNote.vue index 26cbec5e7e..9a5ff4d509 100644 --- a/packages/client/src/components/MkNote.vue +++ b/packages/client/src/components/MkNote.vue @@ -276,7 +276,6 @@ import { computed, inject, onMounted, ref } from "vue"; import * as mfm from "mfm-js"; import type { Ref } from "vue"; import type * as firefish from "firefish-js"; -import { detect as detectLanguage_ } from "tinyld"; import MkSubNoteContent from "./MkSubNoteContent.vue"; import MkNoteSub from "@/components/MkNoteSub.vue"; import XNoteHeader from "@/components/MkNoteHeader.vue"; @@ -287,6 +286,7 @@ import XStarButtonNoEmoji from "@/components/MkStarButtonNoEmoji.vue"; import XQuoteButton from "@/components/MkQuoteButton.vue"; import MkVisibility from "@/components/MkVisibility.vue"; import copyToClipboard from "@/scripts/copy-to-clipboard"; +import detectLanguage from "@/scripts/detect-language"; import { url } from "@/config"; import { pleaseLogin } from "@/scripts/please-login"; import { focusNext, focusPrev } from "@/scripts/focus"; @@ -372,15 +372,6 @@ const expandOnNoteClick = defaultStore.state.expandOnNoteClick; const lang = localStorage.getItem("lang"); const translateLang = localStorage.getItem("translateLang"); -function detectLanguage(text: string) { - const nodes = mfm.parse(text); - const filtered = mfm.extract(nodes, (node) => { - return node.type === "text" || node.type === "quote"; - }); - const purified = mfm.toString(filtered); - return detectLanguage_(purified); -} - const isForeignLanguage: boolean = defaultStore.state.detectPostLanguage && appearNote.value.text != null && @@ -948,7 +939,7 @@ defineExpose({ padding: 8px; opacity: 0.7; &:disabled { - opacity: 0.5 !important; + opacity: 0.2 !important; } flex-grow: 1; max-width: 3.5em; diff --git a/packages/client/src/components/MkNotePreview.vue b/packages/client/src/components/MkNotePreview.vue index 29d2a9d109..2c8f043dec 100644 --- a/packages/client/src/components/MkNotePreview.vue +++ b/packages/client/src/components/MkNotePreview.vue @@ -20,8 +20,7 @@ </template> <script lang="ts" setup> -import {} from "vue"; -import { preprocess } from "@/scripts/preprocess"; +import preprocess from "@/scripts/preprocess"; const props = defineProps<{ text: string; diff --git a/packages/client/src/components/MkNoteSub.vue b/packages/client/src/components/MkNoteSub.vue index 2468de1af4..20a8c31db6 100644 --- a/packages/client/src/components/MkNoteSub.vue +++ b/packages/client/src/components/MkNoteSub.vue @@ -193,7 +193,6 @@ import { computed, inject, ref } from "vue"; import type { Ref } from "vue"; import type * as firefish from "firefish-js"; import * as mfm from "mfm-js"; -import { detect as detectLanguage_ } from "tinyld"; import XNoteHeader from "@/components/MkNoteHeader.vue"; import MkSubNoteContent from "@/components/MkSubNoteContent.vue"; import XReactionsViewer from "@/components/MkReactionsViewer.vue"; @@ -202,6 +201,7 @@ import XStarButtonNoEmoji from "@/components/MkStarButtonNoEmoji.vue"; import XRenoteButton from "@/components/MkRenoteButton.vue"; import XQuoteButton from "@/components/MkQuoteButton.vue"; import copyToClipboard from "@/scripts/copy-to-clipboard"; +import detectLanguage from "@/scripts/detect-language"; import { url } from "@/config"; import { pleaseLogin } from "@/scripts/please-login"; import { getNoteMenu } from "@/scripts/get-note-menu"; @@ -288,15 +288,6 @@ const expandOnNoteClick = defaultStore.state.expandOnNoteClick; const lang = localStorage.getItem("lang"); const translateLang = localStorage.getItem("translateLang"); -function detectLanguage(text: string) { - const nodes = mfm.parse(text); - const filtered = mfm.extract(nodes, (node) => { - return node.type === "text" || node.type === "quote"; - }); - const purified = mfm.toString(filtered); - return detectLanguage_(purified); -} - const isForeignLanguage: boolean = defaultStore.state.detectPostLanguage && appearNote.value.text != null && @@ -552,7 +543,7 @@ function noteClick(e) { padding: 8px; opacity: 0.7; &:disabled { - opacity: 0.5 !important; + opacity: 0.2 !important; } flex-grow: 1; max-width: 3.5em; diff --git a/packages/client/src/components/MkNotes.vue b/packages/client/src/components/MkNotes.vue index 14433ecfb6..267ce7463b 100644 --- a/packages/client/src/components/MkNotes.vue +++ b/packages/client/src/components/MkNotes.vue @@ -3,7 +3,7 @@ <template #empty> <div class="_fullinfo"> <img - src="/static-assets/badges/info.avif" + src="/static-assets/badges/info.webp" class="_ghost" alt="Info" /> diff --git a/packages/client/src/components/MkNotifications.vue b/packages/client/src/components/MkNotifications.vue index 284b2615fe..e9292342b2 100644 --- a/packages/client/src/components/MkNotifications.vue +++ b/packages/client/src/components/MkNotifications.vue @@ -3,7 +3,7 @@ <template #empty> <div class="_fullinfo"> <img - src="/static-assets/badges/info.avif" + src="/static-assets/badges/info.webp" class="_ghost" alt="Info" /> diff --git a/packages/client/src/components/MkPagination.vue b/packages/client/src/components/MkPagination.vue index d5acc91c5d..cc5329e313 100644 --- a/packages/client/src/components/MkPagination.vue +++ b/packages/client/src/components/MkPagination.vue @@ -8,7 +8,7 @@ <slot name="empty"> <div class="_fullinfo"> <img - src="/static-assets/badges/info.avif" + src="/static-assets/badges/info.webp" class="_ghost" alt="Error" /> diff --git a/packages/client/src/components/MkPostForm.vue b/packages/client/src/components/MkPostForm.vue index 2e91adbf30..907c217c1c 100644 --- a/packages/client/src/components/MkPostForm.vue +++ b/packages/client/src/components/MkPostForm.vue @@ -276,7 +276,7 @@ import { import { uploadFile } from "@/scripts/upload"; import { deepClone } from "@/scripts/clone"; import XCheatSheet from "@/components/MkCheatSheetDialog.vue"; -import { preprocess } from "@/scripts/preprocess"; +import preprocess from "@/scripts/preprocess"; import { vibrate } from "@/scripts/vibrate"; const modal = inject("modal"); diff --git a/packages/client/src/components/MkRenoteButton.vue b/packages/client/src/components/MkRenoteButton.vue index bf60e15a39..68f89d1662 100644 --- a/packages/client/src/components/MkRenoteButton.vue +++ b/packages/client/src/components/MkRenoteButton.vue @@ -3,7 +3,7 @@ v-if="canRenote" ref="buttonRef" v-tooltip.noDelay.bottom="i18n.ts.renote" - class="button _button canRenote" + class="button _button" :class="{ renoted: hasRenotedBefore }" @click.stop="renote(false, $event)" > @@ -13,7 +13,7 @@ <button v-else v-tooltip.noDelay.bottom="i18n.ts.disabled" - class="eddddedb _button" + class="_button" disabled="true" > <i class="ph-rocket-launch ph-bold ph-lg"></i> @@ -266,7 +266,7 @@ const renote = (viaKeyboard = false, ev?: MouseEvent) => { <style lang="scss" scoped> .button { - &:not(.canRenote) { + &:not(.button) { cursor: default; } &.renoted { diff --git a/packages/client/src/components/MkUserList.vue b/packages/client/src/components/MkUserList.vue index 71650cb249..8f5935ee48 100644 --- a/packages/client/src/components/MkUserList.vue +++ b/packages/client/src/components/MkUserList.vue @@ -3,7 +3,7 @@ <template #empty> <div class="_fullinfo"> <img - src="/static-assets/badges/info.avif" + src="/static-assets/badges/info.webp" class="_ghost" alt="Info" /> diff --git a/packages/client/src/components/global/MkError.vue b/packages/client/src/components/global/MkError.vue index 47b38f4e68..05eb0f27a7 100644 --- a/packages/client/src/components/global/MkError.vue +++ b/packages/client/src/components/global/MkError.vue @@ -2,7 +2,7 @@ <transition :name="$store.state.animation ? 'zoom' : ''" appear> <div class="mjndxjcg"> <img - src="/static-assets/badges/error.avif" + src="/static-assets/badges/error.webp" class="_ghost" alt="Error" /> diff --git a/packages/client/src/os.ts b/packages/client/src/os.ts index 1943059298..0e74ff741b 100644 --- a/packages/client/src/os.ts +++ b/packages/client/src/os.ts @@ -277,6 +277,7 @@ export function alert(props: { type?: "error" | "info" | "success" | "warning" | "waiting" | "question"; title?: string | null; text?: string | null; + isPlaintext?: boolean; }): Promise<void> { return new Promise((resolve, reject) => { if (props.text == null && props.type === "error") { @@ -301,6 +302,7 @@ export function confirm(props: { text?: string | null; okText?: string; cancelText?: string; + isPlaintext?: boolean; }): Promise<{ canceled: boolean }> { return new Promise((resolve, reject) => { popup( @@ -323,6 +325,7 @@ export function yesno(props: { type: "error" | "info" | "success" | "warning" | "waiting" | "question"; title?: string | null; text?: string | null; + isPlaintext?: boolean; }): Promise<{ canceled: boolean }> { return new Promise((resolve, reject) => { popup( diff --git a/packages/client/src/pages/_error_.vue b/packages/client/src/pages/_error_.vue index 649f10a0ed..8f814d93c4 100644 --- a/packages/client/src/pages/_error_.vue +++ b/packages/client/src/pages/_error_.vue @@ -3,7 +3,7 @@ <transition :name="$store.state.animation ? 'zoom' : ''" appear> <div v-show="loaded" class="mjndxjch"> <img - src="/static-assets/badges/error.avif" + src="/static-assets/badges/error.webp" class="_ghost" alt="Error" /> diff --git a/packages/client/src/pages/favorites.vue b/packages/client/src/pages/favorites.vue index 5278809f8d..74aac739e2 100644 --- a/packages/client/src/pages/favorites.vue +++ b/packages/client/src/pages/favorites.vue @@ -6,7 +6,7 @@ <template #empty> <div class="_fullinfo"> <img - src="/static-assets/badges/info.avif" + src="/static-assets/badges/info.webp" class="_ghost" alt="Info" /> diff --git a/packages/client/src/pages/follow-requests.vue b/packages/client/src/pages/follow-requests.vue index 7179815b0d..0fac6dd285 100644 --- a/packages/client/src/pages/follow-requests.vue +++ b/packages/client/src/pages/follow-requests.vue @@ -6,7 +6,7 @@ <template #empty> <div class="_fullinfo"> <img - src="/static-assets/badges/info.avif" + src="/static-assets/badges/info.webp" aria-label="none" class="_ghost" /> diff --git a/packages/client/src/pages/messaging/messaging-room.vue b/packages/client/src/pages/messaging/messaging-room.vue index a320091ff7..79446cf131 100644 --- a/packages/client/src/pages/messaging/messaging-room.vue +++ b/packages/client/src/pages/messaging/messaging-room.vue @@ -17,7 +17,7 @@ <template #empty> <div class="_fullinfo"> <img - src="/static-assets/badges/info.avif" + src="/static-assets/badges/info.webp" class="_ghost" alt="Info" /> diff --git a/packages/client/src/pages/no-graze.vue b/packages/client/src/pages/no-graze.vue index bcc23c6a6f..6e798e4029 100644 --- a/packages/client/src/pages/no-graze.vue +++ b/packages/client/src/pages/no-graze.vue @@ -2,7 +2,7 @@ <transition :name="$store.state.animation ? 'zoom' : ''" appear> <div :class="$style.root"> <img - src="/static-assets/badges/info.avif" + src="/static-assets/badges/info.webp" class="_ghost" alt="Error" /> diff --git a/packages/client/src/pages/not-found.vue b/packages/client/src/pages/not-found.vue index 59960c1ebe..528d5e6a97 100644 --- a/packages/client/src/pages/not-found.vue +++ b/packages/client/src/pages/not-found.vue @@ -2,7 +2,7 @@ <div class="ipledcug"> <div class="_fullinfo"> <img - src="/static-assets/badges/not-found.avif" + src="/static-assets/badges/not-found.webp" class="_ghost" alt="Not found" /> diff --git a/packages/client/src/pages/settings/apps.vue b/packages/client/src/pages/settings/apps.vue index f759a672c8..a3ca179446 100644 --- a/packages/client/src/pages/settings/apps.vue +++ b/packages/client/src/pages/settings/apps.vue @@ -4,7 +4,7 @@ <template #empty> <div class="_fullinfo"> <img - src="/static-assets/badges/info.avif" + src="/static-assets/badges/info.webp" class="_ghost" alt="Info" /> diff --git a/packages/client/src/scripts/detect-language.ts b/packages/client/src/scripts/detect-language.ts new file mode 100644 index 0000000000..6147247dee --- /dev/null +++ b/packages/client/src/scripts/detect-language.ts @@ -0,0 +1,11 @@ +import { detect } from "tinyld"; +import * as mfm from "mfm-js"; + +export default function detectLanguage(text: string): string { + const nodes = mfm.parse(text); + const filtered = mfm.extract(nodes, (node) => { + return node.type === "text" || node.type === "quote"; + }); + const purified = mfm.toString(filtered); + return detect(purified); +} diff --git a/packages/client/src/scripts/preprocess.ts b/packages/client/src/scripts/preprocess.ts index bdcb68db9e..835e2185d5 100644 --- a/packages/client/src/scripts/preprocess.ts +++ b/packages/client/src/scripts/preprocess.ts @@ -2,7 +2,7 @@ import * as mfm from "mfm-js"; import { defaultStore } from "@/store"; import { expandKaTeXMacro } from "@/scripts/katex-macro"; -export function preprocess(text: string): string { +export default function preprocess(text: string): string { if (defaultStore.state.enableCustomKaTeXMacro) { const parsedKaTeXMacro = localStorage.getItem("customKaTeXMacroParsed") ?? "{}"; diff --git a/packages/client/src/style.scss b/packages/client/src/style.scss index f345297fd5..aff180c5df 100644 --- a/packages/client/src/style.scss +++ b/packages/client/src/style.scss @@ -25,6 +25,43 @@ //--ad: rgb(255 169 0 / 10%); } +/* atkinson-hyperlegible-regular - latin_latin-ext */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Atkinson Hyperlegible"; + font-style: normal; + font-weight: 400; + src: url("/static-assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-regular.woff2") + format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* atkinson-hyperlegible-italic - latin_latin-ext */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Atkinson Hyperlegible"; + font-style: italic; + font-weight: 400; + src: url("/static-assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-italic.woff2") + format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* atkinson-hyperlegible-700 - latin_latin-ext */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Atkinson Hyperlegible"; + font-style: normal; + font-weight: 700; + src: url("/static-assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-700.woff2") + format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* atkinson-hyperlegible-700italic - latin_latin-ext */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Atkinson Hyperlegible"; + font-style: italic; + font-weight: 700; + src: url("/static-assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-700italic.woff2") + format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} + ::selection { color: #fff; background-color: var(--accent); @@ -39,7 +76,8 @@ html { accent-color: var(--accent); overflow: auto; overflow-wrap: break-word; - font-family: Roboto, HelveticaNeue, Arial, sans-serif; + font-family: "Atkinson Hyperlegible", Roboto, HelveticaNeue, Arial, + sans-serif; font-size: 14px; line-height: 1.6; text-size-adjust: 100%; @@ -50,8 +88,8 @@ html { -webkit-text-size-adjust: none; &.useCJKFont { - font-family: "Hiragino Maru Gothic Pro", "BIZ UDGothic", Roboto, - HelveticaNeue, Arial, sans-serif; + font-family: "Hiragino Maru Gothic Pro", "BIZ UDGothic", + "Atkinson Hyperlegible", Roboto, HelveticaNeue, Arial, sans-serif; } &.useSystemFont { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 79282ed428..f933d2bf19 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -85,8 +85,8 @@ importers: specifier: ^1.0.4 version: 1.0.4 pnpm: - specifier: 8.7.1 - version: 8.7.1 + specifier: 8.8.0 + version: 8.8.0 start-server-and-test: specifier: 1.15.2 version: 1.15.2 @@ -742,7 +742,7 @@ importers: version: 2.30.0 emojilib: specifier: github:thatonecalculator/emojilib - version: github.com/thatonecalculator/emojilib/d3c8c6a77d4362b3b3180099f1d2eac344ce245c + version: github.com/thatonecalculator/emojilib/c3c82a3c8f360e1ec567c61012b95d23f0d22175 escape-regexp: specifier: 0.0.1 version: 0.0.1 @@ -15186,8 +15186,8 @@ packages: engines: {node: '>=14.19.0'} dev: false - /pnpm@8.7.1: - resolution: {integrity: sha512-Qbt3EhYUaXFS2k4FLQA7r2/eYz/JoDeG680/3UXG0Ga03LPuY4GgdvCLe+zO3M7ZnWG4VI4bAwk7QpJyfr5eqA==} + /pnpm@8.8.0: + resolution: {integrity: sha512-eY5rMiZpzmPI2oVr1irR97bzb036oKwCWvK91wDQndXcqUPlytPtrF0bO668Syw/uA+7hTf5NnM8Mr4ux4BRRA==} engines: {node: '>=16.14'} hasBin: true dev: true @@ -19461,8 +19461,8 @@ packages: url-polyfill: 1.1.12 dev: true - github.com/thatonecalculator/emojilib/d3c8c6a77d4362b3b3180099f1d2eac344ce245c: - resolution: {tarball: https://codeload.github.com/thatonecalculator/emojilib/tar.gz/d3c8c6a77d4362b3b3180099f1d2eac344ce245c} + github.com/thatonecalculator/emojilib/c3c82a3c8f360e1ec567c61012b95d23f0d22175: + resolution: {tarball: https://codeload.github.com/thatonecalculator/emojilib/tar.gz/c3c82a3c8f360e1ec567c61012b95d23f0d22175} name: emojilib version: 3.0.10 dev: true