Merge branch 'main' into feature/markdown

This commit is contained in:
Stefano Pigozzi 2025-01-02 16:58:44 +01:00 committed by GitHub
commit 08de74ddde
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
93 changed files with 30470 additions and 22445 deletions

View file

@ -97,7 +97,7 @@ Everything is designed and engineered following my taste and vision. This is a p
## Development ## Development
Prerequisites: Node.js 18+ Prerequisites: Node.js 20+
- `npm install` - Install dependencies - `npm install` - Install dependencies
- `npm run dev` - Start development server and `messages:extract` (`clean` + ``watch`) in parallel - `npm run dev` - Start development server and `messages:extract` (`clean` + ``watch`) in parallel
@ -305,6 +305,7 @@ Costs involved in running and developing this web app:
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/15460040/medium/1cfcfe5f5511b783b5d9f2b968bad819.png" alt="" width="16" height="16" /> cbasje (Dutch) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/15460040/medium/1cfcfe5f5511b783b5d9f2b968bad819.png" alt="" width="16" height="16" /> cbasje (Dutch)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/15525631/medium/51293156034d0236f1a1020c10f7d539_default.png" alt="" width="16" height="16" /> cbo92 (French) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/15525631/medium/51293156034d0236f1a1020c10f7d539_default.png" alt="" width="16" height="16" /> cbo92 (French)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/15910131/medium/67fab7eeab5551853450e76e2ef19e59.jpeg" alt="" width="16" height="16" /> CDN (Chinese Simplified) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/15910131/medium/67fab7eeab5551853450e76e2ef19e59.jpeg" alt="" width="16" height="16" /> CDN (Chinese Simplified)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/12513809/medium/b56324e44ae26da6db7793bc467a70e2.png" alt="" width="16" height="16" /> codl (French)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16556801/medium/ed5e501ca1f3cc6525d2da28db646346.jpeg" alt="" width="16" height="16" /> dannypsnl (Chinese Traditional) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/16556801/medium/ed5e501ca1f3cc6525d2da28db646346.jpeg" alt="" width="16" height="16" /> dannypsnl (Chinese Traditional)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/3711/medium/c97239bb54623a50eb43cc6b801bb156.jpg" alt="" width="16" height="16" /> databio (Catalan) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/3711/medium/c97239bb54623a50eb43cc6b801bb156.jpg" alt="" width="16" height="16" /> databio (Catalan)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16533843/medium/ac7af8776858a992d992cf6702d1aaae.jpg" alt="" width="16" height="16" /> Dizro (Italian) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/16533843/medium/ac7af8776858a992d992cf6702d1aaae.jpg" alt="" width="16" height="16" /> Dizro (Italian)
@ -314,13 +315,13 @@ Costs involved in running and developing this web app:
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16528627/medium/9036f6eced0257f4e1ea4c5bd499de2d_default.png" alt="" width="16" height="16" /> ElPamplina (Spanish) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/16528627/medium/9036f6eced0257f4e1ea4c5bd499de2d_default.png" alt="" width="16" height="16" /> ElPamplina (Spanish)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/14277386/medium/29b30d2c73a214000e3941c9978f49e4_default.png" alt="" width="16" height="16" /> Fitik (Esperanto, Hebrew) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/14277386/medium/29b30d2c73a214000e3941c9978f49e4_default.png" alt="" width="16" height="16" /> Fitik (Esperanto, Hebrew)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/14444512/medium/99d0e7a3076deccbdfe0aa0b0612308c.jpeg" alt="" width="16" height="16" /> Freeesia (Japanese) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/14444512/medium/99d0e7a3076deccbdfe0aa0b0612308c.jpeg" alt="" width="16" height="16" /> Freeesia (Japanese)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/12617257/medium/a201650da44fed28890b0e0d8477a663.jpg" alt="" width="16" height="16" /> ghose (Galician) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/12617257/medium/7a0122f352a94d95be10780bb83f63ef.jpg" alt="" width="16" height="16" /> ghose (Galician)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/15248754/medium/0dac6334ea0f4e8d4194a605c0a5594a.jpeg" alt="" width="16" height="16" /> hongminhee (Korean) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/15248754/medium/0dac6334ea0f4e8d4194a605c0a5594a.jpeg" alt="" width="16" height="16" /> hongminhee (Korean)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16529833/medium/2122d0c5d61c00786ab6d5e5672d4098.png" alt="" width="16" height="16" /> Hugoglyph (Esperanto, Spanish) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/16529833/medium/2122d0c5d61c00786ab6d5e5672d4098.png" alt="" width="16" height="16" /> Hugoglyph (Esperanto, Spanish)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/13454728/medium/1f78b7124b3c962bc4ae55e8d701fc91_default.png" alt="" width="16" height="16" /> isard (Catalan) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/13454728/medium/1f78b7124b3c962bc4ae55e8d701fc91_default.png" alt="" width="16" height="16" /> isard (Catalan)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16646485/medium/5d76c44212a4048a815ab437fb170856_default.png" alt="" width="16" height="16" /> kaliuwu (Polish) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/16646485/medium/5d76c44212a4048a815ab437fb170856_default.png" alt="" width="16" height="16" /> kaliuwu (Polish)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16532403/medium/4cefb19623bcc44d7cdb9e25aebf5250.jpeg" alt="" width="16" height="16" /> karlafej (Czech) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/16532403/medium/4cefb19623bcc44d7cdb9e25aebf5250.jpeg" alt="" width="16" height="16" /> karlafej (Czech)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/15791971/medium/88bdda3090339f16f6083390d32bb434_default.png" alt="" width="16" height="16" /> katullo11 (Italian) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/15791971/medium/1790a2101ceb13f61816b8fe6fbe6d90.jpeg" alt="" width="16" height="16" /> katullo11 (Italian)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/14677260/medium/e53420d200961f48602324e18c091bdc.png" alt="" width="16" height="16" /> Kytta (German) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/14677260/medium/e53420d200961f48602324e18c091bdc.png" alt="" width="16" height="16" /> Kytta (German)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16529521/medium/ae6add93a901b0fefa2d9b1077920d73.png" alt="" width="16" height="16" /> llun (Thai) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/16529521/medium/ae6add93a901b0fefa2d9b1077920d73.png" alt="" width="16" height="16" /> llun (Thai)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16291756/medium/c008af10bc117fa9c9dcb70f2b291ee6.jpg" alt="" width="16" height="16" /> lucasofchirst (Occitan, Portuguese, Portuguese, Brazilian) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/16291756/medium/c008af10bc117fa9c9dcb70f2b291ee6.jpg" alt="" width="16" height="16" /> lucasofchirst (Occitan, Portuguese, Portuguese, Brazilian)
@ -350,6 +351,7 @@ Costs involved in running and developing this web app:
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16530049/medium/683f3581620c6b4a5c753b416ed695a7.jpeg" alt="" width="16" height="16" /> tferrermo (Spanish) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/16530049/medium/683f3581620c6b4a5c753b416ed695a7.jpeg" alt="" width="16" height="16" /> tferrermo (Spanish)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/15752199/medium/7e9efd828c4691368d063b19d19eb894.png" alt="" width="16" height="16" /> tkbremnes (Norwegian Bokmal) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/15752199/medium/7e9efd828c4691368d063b19d19eb894.png" alt="" width="16" height="16" /> tkbremnes (Norwegian Bokmal)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16527851/medium/649e5a9a8a8cc61ced670d89e9cca082.png" alt="" width="16" height="16" /> tux93 (German) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/16527851/medium/649e5a9a8a8cc61ced670d89e9cca082.png" alt="" width="16" height="16" /> tux93 (German)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16791511/medium/321c72613cd27efc3005e7c3bf383578.jpeg" alt="" width="16" height="16" /> uzaylul (Turkish)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/14427566/medium/ab733b5044c21867fc5a9d1b22cd2c03.png" alt="" width="16" height="16" /> Vac31. (Lithuanian) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/14427566/medium/ab733b5044c21867fc5a9d1b22cd2c03.png" alt="" width="16" height="16" /> Vac31. (Lithuanian)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16026914/medium/e3ca187f354a298ef0c9d02a0ed17be7.jpg" alt="" width="16" height="16" /> valtlai (Finnish) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/16026914/medium/e3ca187f354a298ef0c9d02a0ed17be7.jpg" alt="" width="16" height="16" /> valtlai (Finnish)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16608515/medium/85506c21dce8df07843ca11908ee3951.jpeg" alt="" width="16" height="16" /> vasiriri (Polish) - <img src="https://crowdin-static.downloads.crowdin.com/avatar/16608515/medium/85506c21dce8df07843ca11908ee3951.jpeg" alt="" width="16" height="16" /> vasiriri (Polish)

1635
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -16,15 +16,15 @@
"readme:i18n-volunteers": "node scripts/update-i18n-volunteers-readme.js" "readme:i18n-volunteers": "node scripts/update-i18n-volunteers-readme.js"
}, },
"dependencies": { "dependencies": {
"@formatjs/intl-localematcher": "~0.5.8", "@formatjs/intl-localematcher": "~0.5.9",
"@formatjs/intl-segmenter": "~11.7.4", "@formatjs/intl-segmenter": "~11.7.7",
"@formkit/auto-animate": "~0.8.2", "@formkit/auto-animate": "~0.8.2",
"@github/text-expander-element": "~2.8.0", "@github/text-expander-element": "~2.8.0",
"@iconify-icons/mingcute": "~1.2.9", "@iconify-icons/mingcute": "~1.2.9",
"@justinribeiro/lite-youtube": "~1.6.0", "@justinribeiro/lite-youtube": "~1.6.0",
"@lingui/detect-locale": "~4.14.0", "@lingui/detect-locale": "~5.1.2",
"@lingui/macro": "~4.14.0", "@lingui/macro": "~5.1.2",
"@lingui/react": "~4.14.0", "@lingui/react": "~5.1.2",
"@szhsin/react-menu": "~4.2.3", "@szhsin/react-menu": "~4.2.3",
"chroma-js": "~3.1.2", "chroma-js": "~3.1.2",
"compare-versions": "~6.1.1", "compare-versions": "~6.1.1",
@ -40,11 +40,11 @@
"masto": "~6.10.1", "masto": "~6.10.1",
"moize": "~6.1.6", "moize": "~6.1.6",
"p-retry": "~6.2.1", "p-retry": "~6.2.1",
"p-throttle": "~6.2.0", "p-throttle": "~7.0.0",
"preact": "~10.24.3", "preact": "~10.25.3",
"punycode": "~2.3.1", "punycode": "~2.3.1",
"react-hotkeys-hook": "~4.6.1", "react-hotkeys-hook": "~4.6.1",
"react-intersection-observer": "~9.13.1", "react-intersection-observer": "~9.14.0",
"react-quick-pinch-zoom": "~5.1.0", "react-quick-pinch-zoom": "~5.1.0",
"react-router-dom": "6.6.2", "react-router-dom": "6.6.2",
"string-length": "6.0.0", "string-length": "6.0.0",
@ -59,20 +59,20 @@
}, },
"devDependencies": { "devDependencies": {
"@ianvs/prettier-plugin-sort-imports": "~4.4.0", "@ianvs/prettier-plugin-sort-imports": "~4.4.0",
"@lingui/cli": "~4.14.0", "@lingui/cli": "~5.1.2",
"@lingui/vite-plugin": "~4.14.0", "@lingui/vite-plugin": "~5.1.2",
"@preact/preset-vite": "~2.9.1", "@preact/preset-vite": "~2.9.3",
"babel-plugin-macros": "~3.1.0", "babel-plugin-macros": "~3.1.0",
"postcss": "~8.4.49", "postcss": "~8.4.49",
"postcss-dark-theme-class": "~1.3.0", "postcss-dark-theme-class": "~1.3.0",
"postcss-preset-env": "~10.1.1", "postcss-preset-env": "~10.1.2",
"prettier": "3.4.1", "prettier": "3.4.2",
"sonda": "~0.6.1", "sonda": "~0.6.2",
"twitter-text": "~3.1.0", "twitter-text": "~3.1.0",
"vite": "~5.4.11", "vite": "~6.0.5",
"vite-plugin-generate-file": "~0.2.0", "vite-plugin-generate-file": "~0.2.0",
"vite-plugin-html-config": "~2.0.2", "vite-plugin-html-config": "~2.0.2",
"vite-plugin-pwa": "~0.21.0", "vite-plugin-pwa": "~0.21.1",
"vite-plugin-remove-console": "~2.2.0", "vite-plugin-remove-console": "~2.2.0",
"vite-plugin-run": "~0.6.1", "vite-plugin-run": "~0.6.1",
"workbox-cacheable-response": "~7.3.0", "workbox-cacheable-response": "~7.3.0",

View file

@ -1,6 +1,6 @@
import './account-block.css'; import './account-block.css';
import { Plural, t, Trans } from '@lingui/macro'; import { Plural, Trans, useLingui } from '@lingui/react/macro';
// import { useNavigate } from 'react-router-dom'; // import { useNavigate } from 'react-router-dom';
import enhanceContent from '../utils/enhance-content'; import enhanceContent from '../utils/enhance-content';
@ -28,6 +28,7 @@ function AccountBlock({
relationship = {}, relationship = {},
excludeRelationshipAttrs = [], excludeRelationshipAttrs = [],
}) { }) {
const { t } = useLingui();
if (skeleton) { if (skeleton) {
return ( return (
<div class="account-block skeleton"> <div class="account-block skeleton">

View file

@ -1,7 +1,7 @@
import './account-info.css'; import './account-info.css';
import { msg, plural, t, Trans } from '@lingui/macro'; import { msg, plural } from '@lingui/core/macro';
import { useLingui } from '@lingui/react'; import { Trans, useLingui } from '@lingui/react/macro';
import { MenuDivider, MenuItem } from '@szhsin/react-menu'; import { MenuDivider, MenuItem } from '@szhsin/react-menu';
import { import {
useCallback, useCallback,
@ -24,7 +24,7 @@ import pmem from '../utils/pmem';
import shortenNumber from '../utils/shorten-number'; import shortenNumber from '../utils/shorten-number';
import showCompose from '../utils/show-compose'; import showCompose from '../utils/show-compose';
import showToast from '../utils/show-toast'; import showToast from '../utils/show-toast';
import states, { hideAllModals } from '../utils/states'; import states from '../utils/states';
import store from '../utils/store'; import store from '../utils/store';
import { getCurrentAccountID, updateAccount } from '../utils/store-utils'; import { getCurrentAccountID, updateAccount } from '../utils/store-utils';
import supports from '../utils/supports'; import supports from '../utils/supports';
@ -135,7 +135,7 @@ function AccountInfo({
instance, instance,
authenticated, authenticated,
}) { }) {
const { i18n } = useLingui(); const { i18n, t } = useLingui();
const { masto } = api({ const { masto } = api({
instance, instance,
}); });
@ -941,7 +941,7 @@ function RelatedActions({
onProfileUpdate = () => {}, onProfileUpdate = () => {},
}) { }) {
if (!info) return null; if (!info) return null;
const { _ } = useLingui(); const { _, t } = useLingui();
const { const {
masto: currentMasto, masto: currentMasto,
instance: currentInstance, instance: currentInstance,
@ -1793,6 +1793,7 @@ function niceAccountURL(url) {
} }
function TranslatedBioSheet({ note, fields, onClose }) { function TranslatedBioSheet({ note, fields, onClose }) {
const { t } = useLingui();
const fieldsText = const fieldsText =
fields fields
?.map(({ name, value }) => `${name}\n${getHTMLText(value)}`) ?.map(({ name, value }) => `${name}\n${getHTMLText(value)}`)
@ -1827,6 +1828,7 @@ function TranslatedBioSheet({ note, fields, onClose }) {
} }
function AddRemoveListsSheet({ accountID, onClose }) { function AddRemoveListsSheet({ accountID, onClose }) {
const { t } = useLingui();
const { masto } = api(); const { masto } = api();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const [lists, setLists] = useState([]); const [lists, setLists] = useState([]);
@ -1971,6 +1973,7 @@ function PrivateNoteSheet({
onRelationshipChange = () => {}, onRelationshipChange = () => {},
onClose = () => {}, onClose = () => {},
}) { }) {
const { t } = useLingui();
const { masto } = api(); const { masto } = api();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const textareaRef = useRef(null); const textareaRef = useRef(null);
@ -2065,6 +2068,7 @@ function PrivateNoteSheet({
} }
function EditProfileSheet({ onClose = () => {} }) { function EditProfileSheet({ onClose = () => {} }) {
const { t } = useLingui();
const { masto } = api(); const { masto } = api();
const [uiState, setUIState] = useState('loading'); const [uiState, setUIState] = useState('loading');
const [account, setAccount] = useState(null); const [account, setAccount] = useState(null);

View file

@ -1,4 +1,4 @@
import { t } from '@lingui/macro'; import { useLingui } from '@lingui/react/macro';
import { useEffect } from 'preact/hooks'; import { useEffect } from 'preact/hooks';
import { api } from '../utils/api'; import { api } from '../utils/api';
@ -9,6 +9,7 @@ import AccountInfo from './account-info';
import Icon from './icon'; import Icon from './icon';
function AccountSheet({ account, instance: propInstance, onClose }) { function AccountSheet({ account, instance: propInstance, onClose }) {
const { t } = useLingui();
const { masto, instance, authenticated } = api({ instance: propInstance }); const { masto, instance, authenticated } = api({ instance: propInstance });
const isString = typeof account === 'string'; const isString = typeof account === 'string';

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { useLingui } from '@lingui/react/macro';
import { memo } from 'preact/compat'; import { memo } from 'preact/compat';
import { useEffect, useRef, useState } from 'preact/hooks'; import { useEffect, useRef, useState } from 'preact/hooks';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
@ -13,6 +13,8 @@ const STREAMING_TIMEOUT = 1000 * 3; // 3 seconds
const POLL_INTERVAL = 20_000; // 20 seconds const POLL_INTERVAL = 20_000; // 20 seconds
export default memo(function BackgroundService({ isLoggedIn }) { export default memo(function BackgroundService({ isLoggedIn }) {
const { t } = useLingui();
// Notifications service // Notifications service
// - WebSocket to receive notifications when page is visible // - WebSocket to receive notifications when page is visible
const [visible, setVisible] = useState(true); const [visible, setVisible] = useState(true);

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { useLingui } from '@lingui/react/macro';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { useSnapshot } from 'valtio'; import { useSnapshot } from 'valtio';
@ -23,6 +23,7 @@ const scrollIntoViewOptions = {
}; };
function Columns() { function Columns() {
const { t } = useLingui();
useTitle(t`Home`, '/'); useTitle(t`Home`, '/');
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
const { shortcuts } = snapStates; const { shortcuts } = snapStates;

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { useLingui } from '@lingui/react/macro';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { useSnapshot } from 'valtio'; import { useSnapshot } from 'valtio';
@ -9,6 +9,7 @@ import states from '../utils/states';
import Icon from './icon'; import Icon from './icon';
export default function ComposeButton() { export default function ComposeButton() {
const { t } = useLingui();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
function handleButton(e) { function handleButton(e) {

View file

@ -1,8 +1,7 @@
import './compose.css'; import './compose.css';
import '@github/text-expander-element'; import '@github/text-expander-element';
import { msg, plural, t } from '@lingui/core/macro';
import { plural, t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { useLingui } from '@lingui/react';
import { MenuItem } from '@szhsin/react-menu'; import { MenuItem } from '@szhsin/react-menu';
import { deepEqual } from 'fast-equals'; import { deepEqual } from 'fast-equals';
import Fuse from 'fuse.js'; import Fuse from 'fuse.js';
@ -224,7 +223,7 @@ function Compose({
standalone, standalone,
hasOpener, hasOpener,
}) { }) {
const { i18n, _ } = useLingui(); const { i18n, _, t } = useLingui();
const rtf = RTF(i18n.locale); const rtf = RTF(i18n.locale);
const lf = LF(i18n.locale); const lf = LF(i18n.locale);
@ -1868,6 +1867,7 @@ const detectLangs = async (text) => {
}; };
const Textarea = forwardRef((props, ref) => { const Textarea = forwardRef((props, ref) => {
const { t } = useLingui();
const { masto, instance } = api(); const { masto, instance } = api();
const [text, setText] = useState(ref.current?.value || ''); const [text, setText] = useState(ref.current?.value || '');
const { const {
@ -1894,8 +1894,13 @@ const Textarea = forwardRef((props, ref) => {
const textExpanderRef = useRef(); const textExpanderRef = useRef();
const textExpanderTextRef = useRef(''); const textExpanderTextRef = useRef('');
const hasTextExpanderRef = useRef(false);
useEffect(() => { useEffect(() => {
let handleChange, handleValue, handleCommited; let handleChange,
handleValue,
handleCommited,
handleActivate,
handleDeactivate;
if (textExpanderRef.current) { if (textExpanderRef.current) {
handleChange = (e) => { handleChange = (e) => {
// console.log('text-expander-change', e); // console.log('text-expander-change', e);
@ -2076,6 +2081,24 @@ const Textarea = forwardRef((props, ref) => {
'text-expander-committed', 'text-expander-committed',
handleCommited, handleCommited,
); );
handleActivate = () => {
hasTextExpanderRef.current = true;
};
textExpanderRef.current.addEventListener(
'text-expander-activate',
handleActivate,
);
handleDeactivate = () => {
hasTextExpanderRef.current = false;
};
textExpanderRef.current.addEventListener(
'text-expander-deactivate',
handleDeactivate,
);
} }
return () => { return () => {
@ -2092,6 +2115,14 @@ const Textarea = forwardRef((props, ref) => {
'text-expander-committed', 'text-expander-committed',
handleCommited, handleCommited,
); );
textExpanderRef.current.removeEventListener(
'text-expander-activate',
handleActivate,
);
textExpanderRef.current.removeEventListener(
'text-expander-deactivate',
handleDeactivate,
);
} }
}; };
}, []); }, []);
@ -2181,7 +2212,8 @@ const Textarea = forwardRef((props, ref) => {
onKeyDown={(e) => { onKeyDown={(e) => {
// Get line before cursor position after pressing 'Enter' // Get line before cursor position after pressing 'Enter'
const { key, target } = e; const { key, target } = e;
if (key === 'Enter' && !(e.ctrlKey || e.metaKey)) { const hasTextExpander = hasTextExpanderRef.current;
if (key === 'Enter' && !(e.ctrlKey || e.metaKey || hasTextExpander)) {
try { try {
const { value, selectionStart } = target; const { value, selectionStart } = target;
const textBeforeCursor = value.slice(0, selectionStart); const textBeforeCursor = value.slice(0, selectionStart);
@ -2299,7 +2331,7 @@ function MediaAttachment({
onDescriptionChange = () => {}, onDescriptionChange = () => {},
onRemove = () => {}, onRemove = () => {},
}) { }) {
const { i18n } = useLingui(); const { i18n, t } = useLingui();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const supportsEdit = supports('@mastodon/edit-media-attributes'); const supportsEdit = supports('@mastodon/edit-media-attributes');
const { type, id, file } = attachment; const { type, id, file } = attachment;
@ -2780,7 +2812,7 @@ function Poll({
minExpiration, minExpiration,
maxCharactersPerOption, maxCharactersPerOption,
}) { }) {
const { _ } = useLingui(); const { t } = useLingui();
const { options, expiresIn, multiple } = poll; const { options, expiresIn, multiple } = poll;
return ( return (
@ -2935,6 +2967,7 @@ function MentionModal({
onSelect = () => {}, onSelect = () => {},
defaultSearchTerm, defaultSearchTerm,
}) { }) {
const { t } = useLingui();
const { masto } = api(); const { masto } = api();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const [accounts, setAccounts] = useState([]); const [accounts, setAccounts] = useState([]);
@ -3159,6 +3192,7 @@ function CustomEmojisModal({
onSelect = () => {}, onSelect = () => {},
defaultSearchTerm, defaultSearchTerm,
}) { }) {
const { t } = useLingui();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const customEmojisList = useRef([]); const customEmojisList = useRef([]);
const [customEmojis, setCustomEmojis] = useState([]); const [customEmojis, setCustomEmojis] = useState([]);
@ -3454,7 +3488,7 @@ const CustomEmojiButton = memo(({ emoji, onClick, showCode }) => {
const GIFS_PER_PAGE = 20; const GIFS_PER_PAGE = 20;
function GIFPickerModal({ onClose = () => {}, onSelect = () => {} }) { function GIFPickerModal({ onClose = () => {}, onSelect = () => {} }) {
const { i18n } = useLingui(); const { i18n, t } = useLingui();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const [results, setResults] = useState([]); const [results, setResults] = useState([]);
const formRef = useRef(null); const formRef = useRef(null);

View file

@ -1,6 +1,6 @@
import './drafts.css'; import './drafts.css';
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { useEffect, useMemo, useReducer, useState } from 'react'; import { useEffect, useMemo, useReducer, useState } from 'react';
import { api } from '../utils/api'; import { api } from '../utils/api';
@ -14,6 +14,7 @@ import Loader from './loader';
import MenuConfirm from './menu-confirm'; import MenuConfirm from './menu-confirm';
function Drafts({ onClose }) { function Drafts({ onClose }) {
const { t } = useLingui();
const { masto } = api(); const { masto } = api();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const [drafts, setDrafts] = useState([]); const [drafts, setDrafts] = useState([]);
@ -215,6 +216,7 @@ function Drafts({ onClose }) {
} }
function MiniDraft({ draft }) { function MiniDraft({ draft }) {
const { t } = useLingui();
const { draftStatus, replyTo } = draft; const { draftStatus, replyTo } = draft;
const { status, spoilerText, poll, mediaAttachments } = draftStatus; const { status, spoilerText, poll, mediaAttachments } = draftStatus;
const hasPoll = poll?.options?.length > 0; const hasPoll = poll?.options?.length > 0;

View file

@ -1,10 +1,11 @@
import './embed-modal.css'; import './embed-modal.css';
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import Icon from './icon'; import Icon from './icon';
function EmbedModal({ html, url, width, height, onClose = () => {} }) { function EmbedModal({ html, url, width, height, onClose = () => {} }) {
const { t } = useLingui();
return ( return (
<div class="embed-modal-container"> <div class="embed-modal-container">
<div class="top-controls"> <div class="top-controls">

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { useState } from 'preact/hooks'; import { useState } from 'preact/hooks';
import { api } from '../utils/api'; import { api } from '../utils/api';
@ -7,6 +7,7 @@ import Icon from './icon';
import Loader from './loader'; import Loader from './loader';
function FollowRequestButtons({ accountID, onChange }) { function FollowRequestButtons({ accountID, onChange }) {
const { t } = useLingui();
const { masto } = api(); const { masto } = api();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const [requestState, setRequestState] = useState(null); // accept, reject const [requestState, setRequestState] = useState(null); // accept, reject

View file

@ -1,6 +1,6 @@
import './generic-accounts.css'; import './generic-accounts.css';
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { useEffect, useRef, useState } from 'preact/hooks'; import { useEffect, useRef, useState } from 'preact/hooks';
import { InView } from 'react-intersection-observer'; import { InView } from 'react-intersection-observer';
import { useSnapshot } from 'valtio'; import { useSnapshot } from 'valtio';
@ -21,8 +21,9 @@ export default function GenericAccounts({
excludeRelationshipAttrs = [], excludeRelationshipAttrs = [],
postID, postID,
onClose = () => {}, onClose = () => {},
blankCopy = t`Nothing to show`, blankCopy,
}) { }) {
const { t } = useLingui();
const { masto, instance: currentInstance } = api(); const { masto, instance: currentInstance } = api();
const isCurrentInstance = instance ? instance === currentInstance : true; const isCurrentInstance = instance ? instance === currentInstance : true;
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
@ -227,7 +228,9 @@ export default function GenericAccounts({
<Trans>Error loading accounts</Trans> <Trans>Error loading accounts</Trans>
</p> </p>
) : ( ) : (
<p class="ui-state insignificant">{blankCopy}</p> <p class="ui-state insignificant">
{blankCopy || t`Nothing to show`}
</p>
)} )}
</main> </main>
</div> </div>

View file

@ -1,6 +1,6 @@
import './keyboard-shortcuts-help.css'; import './keyboard-shortcuts-help.css';
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { memo } from 'preact/compat'; import { memo } from 'preact/compat';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { useSnapshot } from 'valtio'; import { useSnapshot } from 'valtio';
@ -11,6 +11,7 @@ import Icon from './icon';
import Modal from './modal'; import Modal from './modal';
export default memo(function KeyboardShortcutsHelp() { export default memo(function KeyboardShortcutsHelp() {
const { t } = useLingui();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
function onClose() { function onClose() {

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { useEffect, useRef, useState } from 'preact/hooks'; import { useEffect, useRef, useState } from 'preact/hooks';
import { api } from '../utils/api'; import { api } from '../utils/api';
@ -9,6 +9,7 @@ import Icon from './icon';
import MenuConfirm from './menu-confirm'; import MenuConfirm from './menu-confirm';
function ListAddEdit({ list, onClose }) { function ListAddEdit({ list, onClose }) {
const { t } = useLingui();
const { masto } = api(); const { masto } = api();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const editMode = !!list; const editMode = !!list;

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { Menu, MenuItem } from '@szhsin/react-menu'; import { Menu, MenuItem } from '@szhsin/react-menu';
import { useState } from 'preact/hooks'; import { useState } from 'preact/hooks';
import { useSnapshot } from 'valtio'; import { useSnapshot } from 'valtio';
@ -13,6 +13,7 @@ import Menu2 from './menu2';
import TranslationBlock from './translation-block'; import TranslationBlock from './translation-block';
export default function MediaAltModal({ alt, lang, onClose }) { export default function MediaAltModal({ alt, lang, onClose }) {
const { t } = useLingui();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
const [forceTranslate, setForceTranslate] = useState(false); const [forceTranslate, setForceTranslate] = useState(false);
const targetLanguage = getTranslateTargetLanguage(true); const targetLanguage = getTranslateTargetLanguage(true);

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { MenuDivider, MenuItem } from '@szhsin/react-menu'; import { MenuDivider, MenuItem } from '@szhsin/react-menu';
import { getBlurHashAverageColor } from 'fast-blurhash'; import { getBlurHashAverageColor } from 'fast-blurhash';
import { import {
@ -32,6 +32,7 @@ function MediaModal({
index = 0, index = 0,
onClose = () => {}, onClose = () => {},
}) { }) {
const { t } = useLingui();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const carouselRef = useRef(null); const carouselRef = useRef(null);

View file

@ -1,6 +1,6 @@
import './media-post.css'; import './media-post.css';
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { memo } from 'preact/compat'; import { memo } from 'preact/compat';
import { useContext, useMemo } from 'preact/hooks'; import { useContext, useMemo } from 'preact/hooks';
import { useSnapshot } from 'valtio'; import { useSnapshot } from 'valtio';
@ -22,6 +22,7 @@ function MediaPost({
// allowFilters, // allowFilters,
onMediaClick, onMediaClick,
}) { }) {
const { t } = useLingui();
let sKey = statusKey(statusID, instance); let sKey = statusKey(statusID, instance);
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
if (!status) { if (!status) {

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { useLingui } from '@lingui/react/macro';
import { getBlurHashAverageColor } from 'fast-blurhash'; import { getBlurHashAverageColor } from 'fast-blurhash';
import { Fragment } from 'preact'; import { Fragment } from 'preact';
import { memo } from 'preact/compat'; import { memo } from 'preact/compat';
@ -32,6 +32,7 @@ audio = Audio track
const dataAltLabel = 'ALT'; const dataAltLabel = 'ALT';
const AltBadge = (props) => { const AltBadge = (props) => {
const { t } = useLingui();
const { alt, lang, index, ...rest } = props; const { alt, lang, index, ...rest } = props;
if (!alt || !alt.trim()) return null; if (!alt || !alt.trim()) return null;
return ( return (

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { useLingui } from '@lingui/react/macro';
import { useEffect } from 'preact/hooks'; import { useEffect } from 'preact/hooks';
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from 'react-router-dom';
import { subscribe, useSnapshot } from 'valtio'; import { subscribe, useSnapshot } from 'valtio';
@ -30,6 +30,7 @@ subscribe(states, (changes) => {
}); });
export default function Modals() { export default function Modals() {
const { t } = useLingui();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const location = useLocation();

View file

@ -1,6 +1,6 @@
import './nav-menu.css'; import './nav-menu.css';
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { ControlledMenu, MenuDivider, MenuItem } from '@szhsin/react-menu'; import { ControlledMenu, MenuDivider, MenuItem } from '@szhsin/react-menu';
import { memo } from 'preact/compat'; import { memo } from 'preact/compat';
import { useEffect, useMemo, useRef, useState } from 'preact/hooks'; import { useEffect, useMemo, useRef, useState } from 'preact/hooks';
@ -21,6 +21,7 @@ import MenuLink from './menu-link';
import SubMenu2 from './submenu2'; import SubMenu2 from './submenu2';
function NavMenu(props) { function NavMenu(props) {
const { t } = useLingui();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
const { masto, instance, authenticated } = api(); const { masto, instance, authenticated } = api();

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { memo } from 'preact/compat'; import { memo } from 'preact/compat';
import { useLayoutEffect, useState } from 'preact/hooks'; import { useLayoutEffect, useState } from 'preact/hooks';
import { useSnapshot } from 'valtio'; import { useSnapshot } from 'valtio';
@ -33,6 +33,7 @@ import Notification from './notification';
} }
export default memo(function NotificationService() { export default memo(function NotificationService() {
const { t } = useLingui();
if (!('serviceWorker' in navigator)) return null; if (!('serviceWorker' in navigator)) return null;
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);

View file

@ -1,5 +1,5 @@
import { msg, Plural, Select, t, Trans } from '@lingui/macro'; import { msg, t } from '@lingui/core/macro';
import { useLingui } from '@lingui/react'; import { Plural, Select, Trans, useLingui } from '@lingui/react/macro';
import { Fragment } from 'preact'; import { Fragment } from 'preact';
import { memo } from 'preact/compat'; import { memo } from 'preact/compat';

View file

@ -1,4 +1,6 @@
import { Plural, plural, t, Trans } from '@lingui/macro'; import { i18n } from '@lingui/core';
import { plural } from '@lingui/core/macro';
import { Plural, Trans, useLingui } from '@lingui/react/macro';
import { useState } from 'preact/hooks'; import { useState } from 'preact/hooks';
import shortenNumber from '../utils/shorten-number'; import shortenNumber from '../utils/shorten-number';
@ -14,6 +16,7 @@ export default function Poll({
refresh = () => {}, refresh = () => {},
votePoll = () => {}, votePoll = () => {},
}) { }) {
const { t } = useLingui();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const { const {
expired, expired,

View file

@ -1,5 +1,5 @@
import { i18n } from '@lingui/core'; import { i18n } from '@lingui/core';
import { t, Trans } from '@lingui/macro'; import { t } from '@lingui/core/macro';
import { useEffect, useMemo, useReducer } from 'preact/hooks'; import { useEffect, useMemo, useReducer } from 'preact/hooks';
import localeMatch from '../utils/locale-match'; import localeMatch from '../utils/locale-match';

View file

@ -1,7 +1,7 @@
import './report-modal.css'; import './report-modal.css';
import { msg, t, Trans } from '@lingui/macro'; import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react'; import { Trans, useLingui } from '@lingui/react/macro';
import { Fragment } from 'preact'; import { Fragment } from 'preact';
import { useMemo, useRef, useState } from 'preact/hooks'; import { useMemo, useRef, useState } from 'preact/hooks';
@ -46,7 +46,7 @@ const CATEGORIES_INFO = {
}; };
function ReportModal({ account, post, onClose }) { function ReportModal({ account, post, onClose }) {
const { _ } = useLingui(); const { _, t } = useLingui();
const { masto } = api(); const { masto } = api();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const [username, domain] = account.acct.split('@'); const [username, domain] = account.acct.split('@');

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { forwardRef } from 'preact/compat'; import { forwardRef } from 'preact/compat';
import { useImperativeHandle, useRef, useState } from 'preact/hooks'; import { useImperativeHandle, useRef, useState } from 'preact/hooks';
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
@ -9,6 +9,7 @@ import Icon from './icon';
import Link from './link'; import Link from './link';
const SearchForm = forwardRef((props, ref) => { const SearchForm = forwardRef((props, ref) => {
const { t } = useLingui();
const { instance } = api(); const { instance } = api();
const [searchParams, setSearchParams] = useSearchParams(); const [searchParams, setSearchParams] = useSearchParams();
const [searchMenuOpen, setSearchMenuOpen] = useState(false); const [searchMenuOpen, setSearchMenuOpen] = useState(false);

View file

@ -1,8 +1,8 @@
import './shortcuts-settings.css'; import './shortcuts-settings.css';
import { useAutoAnimate } from '@formkit/auto-animate/preact'; import { useAutoAnimate } from '@formkit/auto-animate/preact';
import { msg, Plural, t, Trans } from '@lingui/macro'; import { msg, t } from '@lingui/core/macro';
import { useLingui } from '@lingui/react'; import { Plural, Trans, useLingui } from '@lingui/react/macro';
import { import {
compressToEncodedURIComponent, compressToEncodedURIComponent,
decompressFromEncodedURIComponent, decompressFromEncodedURIComponent,

View file

@ -1,7 +1,6 @@
import './shortcuts.css'; import './shortcuts.css';
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { useLingui } from '@lingui/react';
import { MenuDivider } from '@szhsin/react-menu'; import { MenuDivider } from '@szhsin/react-menu';
import { memo } from 'preact/compat'; import { memo } from 'preact/compat';
import { useRef, useState } from 'preact/hooks'; import { useRef, useState } from 'preact/hooks';
@ -22,6 +21,7 @@ import Menu2 from './menu2';
import SubMenu2 from './submenu2'; import SubMenu2 from './submenu2';
function Shortcuts() { function Shortcuts() {
const { t } = useLingui();
const { _ } = useLingui(); const { _ } = useLingui();
const { instance } = api(); const { instance } = api();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);

View file

@ -180,8 +180,11 @@
color: var(--text-color); color: var(--text-color);
background-color: var(--bg-faded-color); background-color: var(--bg-faded-color);
border: 1px dashed var(--link-color); border: 1px dashed var(--link-color);
box-shadow: 0 0 0 1px var(--bg-color), 0 -5px 10px var(--bg-color), box-shadow:
0 -5px 15px var(--bg-color), 0 -5px 20px var(--bg-color); 0 0 0 1px var(--bg-color),
0 -5px 10px var(--bg-color),
0 -5px 15px var(--bg-color),
0 -5px 20px var(--bg-color);
padding: 0.5em 0.75em; padding: 0.5em 0.75em;
border-radius: 10em; border-radius: 10em;
font-size: 90%; font-size: 90%;
@ -682,7 +685,8 @@
.spoiler-media-button .spoiler-media-button
), ),
~ .card .meta-container { ~ .card .meta-container {
img { img,
video {
filter: invert(0.5); filter: invert(0.5);
background-color: black; background-color: black;
} }
@ -851,8 +855,11 @@
border-radius: 10em; border-radius: 10em;
font-size: 90%; font-size: 90%;
white-space: nowrap; white-space: nowrap;
box-shadow: 0 0 0 1px var(--bg-color), 0 -5px 10px var(--bg-color), box-shadow:
0 -5px 15px var(--bg-color), 0 -5px 20px var(--bg-color); 0 0 0 1px var(--bg-color),
0 -5px 10px var(--bg-color),
0 -5px 15px var(--bg-color),
0 -5px 20px var(--bg-color);
transition: transform 0.5s ease-in-out; transition: transform 0.5s ease-in-out;
} }
.timeline-deck .status .content.truncated:hover:after { .timeline-deck .status .content.truncated:hover:after {
@ -2298,7 +2305,8 @@ a.card:is(:hover, :focus):visited {
&, &,
& .szh-menu__item { & .szh-menu__item {
box-shadow: inset 0 -2px 0 var(--checked-color), box-shadow:
inset 0 -2px 0 var(--checked-color),
inset 0 -16px 8px -16px var(--checked-color); inset 0 -16px 8px -16px var(--checked-color);
} }
&:has(.szh-menu__item) { &:has(.szh-menu__item) {
@ -2357,7 +2365,9 @@ a.card:is(:hover, :focus):visited {
pointer-events: none; pointer-events: none;
transform: translate3d(0, 6px, 0); transform: translate3d(0, 6px, 0);
transform-origin: var(--forward) center; transform-origin: var(--forward) center;
transition: all 0.15s ease-out 0.3s, border-color 0.3s ease-out; transition:
all 0.15s ease-out 0.3s,
border-color 0.3s ease-out;
.timeline.contextual .replies[data-comments-level='4'] & { .timeline.contextual .replies[data-comments-level='4'] & {
top: 0; top: 0;
@ -2623,7 +2633,8 @@ a.card:is(:hover, :focus):visited {
font-size: 0.9em; font-size: 0.9em;
border: 2px dashed var(--link-light-color); border: 2px dashed var(--link-light-color);
border-radius: 8px; border-radius: 8px;
box-shadow: 0 4px 8px -4px var(--drop-shadow-color), box-shadow:
0 4px 8px -4px var(--drop-shadow-color),
0 8px 32px -8px var(--drop-shadow-color); 0 8px 32px -8px var(--drop-shadow-color);
padding: 16px; padding: 16px;
@ -2731,8 +2742,11 @@ a.card:is(:hover, :focus):visited {
color: var(--text-color); color: var(--text-color);
background-color: var(--bg-faded-color); background-color: var(--bg-faded-color);
border: 1px dashed var(--link-color); border: 1px dashed var(--link-color);
box-shadow: 0 0 0 1px var(--bg-color), 0 -5px 10px var(--bg-color), box-shadow:
0 -5px 15px var(--bg-color), 0 -5px 20px var(--bg-color); 0 0 0 1px var(--bg-color),
0 -5px 10px var(--bg-color),
0 -5px 15px var(--bg-color),
0 -5px 20px var(--bg-color);
padding: 0.5em 0.75em; padding: 0.5em 0.75em;
border-radius: 10em; border-radius: 10em;
font-size: 90%; font-size: 90%;

View file

@ -1,8 +1,8 @@
import './status.css'; import './status.css';
import '@justinribeiro/lite-youtube'; import '@justinribeiro/lite-youtube';
import { msg, plural, Plural, t, Trans } from '@lingui/macro'; import { msg, plural } from '@lingui/core/macro';
import { useLingui } from '@lingui/react'; import { Trans, useLingui } from '@lingui/react/macro';
import { import {
ControlledMenu, ControlledMenu,
Menu, Menu,
@ -308,7 +308,7 @@ function Status({
showReplyParent, showReplyParent,
mediaFirst, mediaFirst,
}) { }) {
const { _ } = useLingui(); const { _, t } = useLingui();
if (skeleton) { if (skeleton) {
return ( return (
@ -2967,6 +2967,7 @@ function EditedAtModal({
fetchStatusHistory = () => {}, fetchStatusHistory = () => {},
onClose, onClose,
}) { }) {
const { t } = useLingui();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const [editHistory, setEditHistory] = useState([]); const [editHistory, setEditHistory] = useState([]);
@ -3202,6 +3203,7 @@ function generateHTMLCode(post, instance, level = 0) {
} }
function EmbedModal({ post, instance, onClose }) { function EmbedModal({ post, instance, onClose }) {
const { t } = useLingui();
const { const {
account: { account: {
url: accountURL, url: accountURL,
@ -3578,7 +3580,7 @@ function FilteredStatus({
showFollowedTags, showFollowedTags,
quoted, quoted,
}) { }) {
const { _ } = useLingui(); const { _, t } = useLingui();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
const { const {
id: statusID, id: statusID,

View file

@ -1,4 +1,5 @@
import { plural, t, Trans } from '@lingui/macro'; import { plural } from '@lingui/core/macro';
import { Trans, useLingui } from '@lingui/react/macro';
import { memo } from 'preact/compat'; import { memo } from 'preact/compat';
import { import {
useCallback, useCallback,
@ -60,6 +61,7 @@ function Timeline({
showReplyParent, showReplyParent,
clearWhenRefresh, clearWhenRefresh,
}) { }) {
const { t } = useLingui();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
const [items, setItems] = useState([]); const [items, setItems] = useState([]);
const [uiState, setUIState] = useState('start'); const [uiState, setUIState] = useState('start');
@ -573,6 +575,7 @@ const TimelineItem = memo(
showReplyParent, showReplyParent,
mediaFirst, mediaFirst,
}) => { }) => {
const { t } = useLingui();
console.debug('RENDER TimelineItem', status.id); console.debug('RENDER TimelineItem', status.id);
const { id: statusID, reblog, items, type, _pinned } = status; const { id: statusID, reblog, items, type, _pinned } = status;
if (_pinned) useItemID = false; if (_pinned) useItemID = false;
@ -836,6 +839,7 @@ const TimelineItem = memo(
); );
function StatusCarousel({ title, class: className, children }) { function StatusCarousel({ title, class: className, children }) {
const { t } = useLingui();
const carouselRef = useRef(); const carouselRef = useRef();
// const { reachStart, reachEnd, init } = useScroll({ // const { reachStart, reachEnd, init } = useScroll({
// scrollableRef: carouselRef, // scrollableRef: carouselRef,
@ -929,6 +933,7 @@ function StatusCarousel({ title, class: className, children }) {
} }
function TimelineStatusCompact({ status, instance, filterContext }) { function TimelineStatusCompact({ status, instance, filterContext }) {
const { t } = useLingui();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
const { id, visibility, language } = status; const { id, visibility, language } = status;
const statusPeekText = statusPeek(status); const statusPeekText = statusPeek(status);

View file

@ -1,6 +1,6 @@
import './translation-block.css'; import './translation-block.css';
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import pRetry from 'p-retry'; import pRetry from 'p-retry';
import pThrottle from 'p-throttle'; import pThrottle from 'p-throttle';
import { useEffect, useRef, useState } from 'preact/hooks'; import { useEffect, useRef, useState } from 'preact/hooks';
@ -80,6 +80,7 @@ function TranslationBlock({
mini, mini,
autoDetected, autoDetected,
}) { }) {
const { t } = useLingui();
const targetLang = getTranslateTargetLanguage(true); const targetLang = getTranslateTargetLanguage(true);
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const [pronunciationContent, setPronunciationContent] = useState(null); const [pronunciationContent, setPronunciationContent] = useState(null);

View file

@ -3,8 +3,8 @@ import './app.css';
import './polyfills'; import './polyfills';
import { i18n } from '@lingui/core'; import { i18n } from '@lingui/core';
import { t, Trans } from '@lingui/macro';
import { I18nProvider } from '@lingui/react'; import { I18nProvider } from '@lingui/react';
import { Trans, useLingui } from '@lingui/react/macro';
import { render } from 'preact'; import { render } from 'preact';
import { useEffect, useState } from 'preact/hooks'; import { useEffect, useState } from 'preact/hooks';
@ -12,7 +12,7 @@ import ComposeSuspense from './components/compose-suspense';
import Loader from './components/loader'; import Loader from './components/loader';
import { initActivateLang } from './utils/lang'; import { initActivateLang } from './utils/lang';
import { initStates } from './utils/states'; import { initStates } from './utils/states';
import { getCurrentAccount, setCurrentAccountID } from './utils/store-utils'; import { getCurrentAccount } from './utils/store-utils';
import useTitle from './utils/useTitle'; import useTitle from './utils/useTitle';
initActivateLang(); initActivateLang();
@ -22,6 +22,7 @@ if (window.opener) {
} }
function App() { function App() {
const { t } = useLingui();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const [isLoggedIn, setIsLoggedIn] = useState(null); const [isLoggedIn, setIsLoggedIn] = useState(null);

View file

@ -3,7 +3,7 @@
"code": "ar-SA", "code": "ar-SA",
"nativeName": "العربية", "nativeName": "العربية",
"name": "Arabic", "name": "Arabic",
"completion": 25 "completion": 24
}, },
{ {
"code": "ca-ES", "code": "ca-ES",
@ -15,13 +15,13 @@
"code": "cs-CZ", "code": "cs-CZ",
"nativeName": "čeština", "nativeName": "čeština",
"name": "Czech", "name": "Czech",
"completion": 79 "completion": 74
}, },
{ {
"code": "de-DE", "code": "de-DE",
"nativeName": "Deutsch", "nativeName": "Deutsch",
"name": "German", "name": "German",
"completion": 94 "completion": 89
}, },
{ {
"code": "eo-UY", "code": "eo-UY",
@ -45,7 +45,7 @@
"code": "fa-IR", "code": "fa-IR",
"nativeName": "فارسی", "nativeName": "فارسی",
"name": "Persian", "name": "Persian",
"completion": 78 "completion": 72
}, },
{ {
"code": "fi-FI", "code": "fi-FI",
@ -57,7 +57,7 @@
"code": "fr-FR", "code": "fr-FR",
"nativeName": "français", "nativeName": "français",
"name": "French", "name": "French",
"completion": 97 "completion": 93
}, },
{ {
"code": "gl-ES", "code": "gl-ES",
@ -69,7 +69,7 @@
"code": "he-IL", "code": "he-IL",
"nativeName": "עברית", "nativeName": "עברית",
"name": "Hebrew", "name": "Hebrew",
"completion": 12 "completion": 10
}, },
{ {
"code": "it-IT", "code": "it-IT",
@ -81,43 +81,43 @@
"code": "ja-JP", "code": "ja-JP",
"nativeName": "日本語", "nativeName": "日本語",
"name": "Japanese", "name": "Japanese",
"completion": 51 "completion": 48
}, },
{ {
"code": "kab", "code": "kab",
"nativeName": "Taqbaylit", "nativeName": "Taqbaylit",
"name": "Kabyle", "name": "Kabyle",
"completion": 98 "completion": 93
}, },
{ {
"code": "ko-KR", "code": "ko-KR",
"nativeName": "한국어", "nativeName": "한국어",
"name": "Korean", "name": "Korean",
"completion": 95 "completion": 90
}, },
{ {
"code": "lt-LT", "code": "lt-LT",
"nativeName": "lietuvių", "nativeName": "lietuvių",
"name": "Lithuanian", "name": "Lithuanian",
"completion": 98 "completion": 100
}, },
{ {
"code": "nb-NO", "code": "nb-NO",
"nativeName": "norsk bokmål", "nativeName": "norsk bokmål",
"name": "Norwegian Bokmål", "name": "Norwegian Bokmål",
"completion": 52 "completion": 47
}, },
{ {
"code": "nl-NL", "code": "nl-NL",
"nativeName": "Nederlands", "nativeName": "Nederlands",
"name": "Dutch", "name": "Dutch",
"completion": 82 "completion": 77
}, },
{ {
"code": "pl-PL", "code": "pl-PL",
"nativeName": "polski", "nativeName": "polski",
"name": "Polish", "name": "Polish",
"completion": 10 "completion": 9
}, },
{ {
"code": "pt-BR", "code": "pt-BR",
@ -143,11 +143,17 @@
"name": "Thai", "name": "Thai",
"completion": 9 "completion": 9
}, },
{
"code": "tr-TR",
"nativeName": "Türkçe",
"name": "Turkish",
"completion": 48
},
{ {
"code": "uk-UA", "code": "uk-UA",
"nativeName": "українська", "nativeName": "українська",
"name": "Ukrainian", "name": "Ukrainian",
"completion": 100 "completion": 94
}, },
{ {
"code": "zh-CN", "code": "zh-CN",
@ -159,6 +165,6 @@
"code": "zh-TW", "code": "zh-TW",
"nativeName": "繁體中文", "nativeName": "繁體中文",
"name": "Traditional Chinese", "name": "Traditional Chinese",
"completion": 32 "completion": 28
} }
] ]

1598
src/locales/ar-SA.po generated

File diff suppressed because it is too large Load diff

1612
src/locales/ca-ES.po generated

File diff suppressed because it is too large Load diff

1658
src/locales/cs-CZ.po generated

File diff suppressed because it is too large Load diff

1662
src/locales/de-DE.po generated

File diff suppressed because it is too large Load diff

1630
src/locales/en.po generated

File diff suppressed because it is too large Load diff

1484
src/locales/eo-UY.po generated

File diff suppressed because it is too large Load diff

1484
src/locales/es-ES.po generated

File diff suppressed because it is too large Load diff

1608
src/locales/eu-ES.po generated

File diff suppressed because it is too large Load diff

1660
src/locales/fa-IR.po generated

File diff suppressed because it is too large Load diff

1612
src/locales/fi-FI.po generated

File diff suppressed because it is too large Load diff

1690
src/locales/fr-FR.po generated

File diff suppressed because it is too large Load diff

1612
src/locales/gl-ES.po generated

File diff suppressed because it is too large Load diff

1604
src/locales/he-IL.po generated

File diff suppressed because it is too large Load diff

1650
src/locales/it-IT.po generated

File diff suppressed because it is too large Load diff

1632
src/locales/ja-JP.po generated

File diff suppressed because it is too large Load diff

1662
src/locales/kab.po generated

File diff suppressed because it is too large Load diff

1660
src/locales/ko-KR.po generated

File diff suppressed because it is too large Load diff

1642
src/locales/lt-LT.po generated

File diff suppressed because it is too large Load diff

1642
src/locales/nb-NO.po generated

File diff suppressed because it is too large Load diff

1660
src/locales/nl-NL.po generated

File diff suppressed because it is too large Load diff

1574
src/locales/oc-FR.po generated

File diff suppressed because it is too large Load diff

1592
src/locales/pl-PL.po generated

File diff suppressed because it is too large Load diff

1606
src/locales/pt-BR.po generated

File diff suppressed because it is too large Load diff

1604
src/locales/pt-PT.po generated

File diff suppressed because it is too large Load diff

1614
src/locales/ru-RU.po generated

File diff suppressed because it is too large Load diff

1578
src/locales/th-TH.po generated

File diff suppressed because it is too large Load diff

3927
src/locales/tr-TR.po generated Normal file

File diff suppressed because it is too large Load diff

1664
src/locales/uk-UA.po generated

File diff suppressed because it is too large Load diff

1616
src/locales/zh-CN.po generated

File diff suppressed because it is too large Load diff

1638
src/locales/zh-TW.po generated

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { useLingui } from '@lingui/react';
import { MenuItem } from '@szhsin/react-menu'; import { MenuItem } from '@szhsin/react-menu';
import { import {
useCallback, useCallback,
@ -51,6 +50,7 @@ async function _isSearchEnabled(instance) {
const isSearchEnabled = pmem(_isSearchEnabled); const isSearchEnabled = pmem(_isSearchEnabled);
function AccountStatuses() { function AccountStatuses() {
const { i18n, t } = useLingui();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
const { id, ...params } = useParams(); const { id, ...params } = useParams();
const [searchParams, setSearchParams] = useSearchParams(); const [searchParams, setSearchParams] = useSearchParams();
@ -229,7 +229,6 @@ function AccountStatuses() {
} }
const [featuredTags, setFeaturedTags] = useState([]); const [featuredTags, setFeaturedTags] = useState([]);
const { i18n } = useLingui();
let title = t`Account posts`; let title = t`Account posts`;
if (account?.acct) { if (account?.acct) {
const acctDisplay = (/@/.test(account.acct) ? '' : '@') + account.acct; const acctDisplay = (/@/.test(account.acct) ? '' : '@') + account.acct;

View file

@ -1,7 +1,7 @@
import './accounts.css'; import './accounts.css';
import { useAutoAnimate } from '@formkit/auto-animate/preact'; import { useAutoAnimate } from '@formkit/auto-animate/preact';
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { Menu, MenuDivider, MenuItem } from '@szhsin/react-menu'; import { Menu, MenuDivider, MenuItem } from '@szhsin/react-menu';
import { useReducer } from 'preact/hooks'; import { useReducer } from 'preact/hooks';
@ -20,6 +20,7 @@ import { getCurrentAccountID, setCurrentAccountID } from '../utils/store-utils';
const isStandalone = window.matchMedia('(display-mode: standalone)').matches; const isStandalone = window.matchMedia('(display-mode: standalone)').matches;
function Accounts({ onClose }) { function Accounts({ onClose }) {
const { t } = useLingui();
const { masto } = api(); const { masto } = api();
// Accounts // Accounts
const accounts = store.local.getJSON('accounts'); const accounts = store.local.getJSON('accounts');

View file

@ -1,7 +1,6 @@
import { t, Trans } from '@lingui/macro';
import './annual-report.css'; import './annual-report.css';
import { Trans } from '@lingui/react/macro';
import { useEffect, useState } from 'preact/hooks'; import { useEffect, useState } from 'preact/hooks';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { useLingui } from '@lingui/react/macro';
import { useRef } from 'preact/hooks'; import { useRef } from 'preact/hooks';
import Timeline from '../components/timeline'; import Timeline from '../components/timeline';
@ -8,6 +8,7 @@ import useTitle from '../utils/useTitle';
const LIMIT = 20; const LIMIT = 20;
function Bookmarks() { function Bookmarks() {
const { t } = useLingui();
useTitle(t`Bookmarks`, '/bookmarks'); useTitle(t`Bookmarks`, '/bookmarks');
const { masto, instance } = api(); const { masto, instance } = api();
const bookmarksIterator = useRef(); const bookmarksIterator = useRef();

View file

@ -2,8 +2,8 @@ import '../components/links-bar.css';
import './catchup.css'; import './catchup.css';
import autoAnimate from '@formkit/auto-animate'; import autoAnimate from '@formkit/auto-animate';
import { msg, Plural, select, t, Trans } from '@lingui/macro'; import { msg, select } from '@lingui/core/macro';
import { useLingui } from '@lingui/react'; import { Plural, Trans, useLingui } from '@lingui/react/macro';
import { getBlurHashAverageColor } from 'fast-blurhash'; import { getBlurHashAverageColor } from 'fast-blurhash';
import { Fragment } from 'preact'; import { Fragment } from 'preact';
import { memo } from 'preact/compat'; import { memo } from 'preact/compat';
@ -95,7 +95,7 @@ const DTF = mem(
); );
function Catchup() { function Catchup() {
const { i18n, _ } = useLingui(); const { i18n, _, t } = useLingui();
const dtf = DTF(i18n.locale); const dtf = DTF(i18n.locale);
useTitle(`Catch-up`, '/catchup'); useTitle(`Catch-up`, '/catchup');
@ -1834,6 +1834,7 @@ function postDensity(post) {
const MEDIA_SIZE = 48; const MEDIA_SIZE = 48;
function PostPeek({ post, filterInfo }) { function PostPeek({ post, filterInfo }) {
const { t } = useLingui();
const { const {
spoilerText, spoilerText,
sensitive, sensitive,
@ -2048,6 +2049,7 @@ function PostPeek({ post, filterInfo }) {
} }
function PostStats({ post }) { function PostStats({ post }) {
const { t } = useLingui();
const { reblogsCount, repliesCount, favouritesCount } = post; const { reblogsCount, repliesCount, favouritesCount } = post;
return ( return (
<span class="post-stats"> <span class="post-stats">

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { useRef } from 'preact/hooks'; import { useRef } from 'preact/hooks';
import Timeline from '../components/timeline'; import Timeline from '../components/timeline';
@ -8,6 +8,7 @@ import useTitle from '../utils/useTitle';
const LIMIT = 20; const LIMIT = 20;
function Favourites() { function Favourites() {
const { t } = useLingui();
useTitle(t`Likes`, '/favourites'); useTitle(t`Likes`, '/favourites');
const { masto, instance } = api(); const { masto, instance } = api();
const favouritesIterator = useRef(); const favouritesIterator = useRef();

View file

@ -1,8 +1,7 @@
import './filters.css'; import './filters.css';
import { i18n } from '@lingui/core'; import { msg } from '@lingui/core/macro';
import { msg, Plural, t, Trans } from '@lingui/macro'; import { Plural, Trans, useLingui } from '@lingui/react/macro';
import { useLingui } from '@lingui/react';
import { useEffect, useReducer, useRef, useState } from 'preact/hooks'; import { useEffect, useReducer, useRef, useState } from 'preact/hooks';
import Icon from '../components/icon'; import Icon from '../components/icon';
@ -50,6 +49,7 @@ const EXPIRY_DURATIONS_LABELS = {
}; };
function Filters() { function Filters() {
const { t } = useLingui();
const { masto } = api(); const { masto } = api();
useTitle(t`Filters`, `/ft`); useTitle(t`Filters`, `/ft`);
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
@ -197,7 +197,7 @@ function Filters() {
let _id = 1; let _id = 1;
const incID = () => _id++; const incID = () => _id++;
function FiltersAddEdit({ filter, onClose }) { function FiltersAddEdit({ filter, onClose }) {
const { _ } = useLingui(); const { _, t } = useLingui();
const { masto } = api(); const { masto } = api();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const editMode = !!filter; const editMode = !!filter;
@ -596,6 +596,7 @@ function FiltersAddEdit({ filter, onClose }) {
} }
function ExpiryStatus({ expiresAt, showNeverExpires }) { function ExpiryStatus({ expiresAt, showNeverExpires }) {
const { t } = useLingui();
const hasExpiry = !!expiresAt; const hasExpiry = !!expiresAt;
const expiresAtDate = hasExpiry && new Date(expiresAt); const expiresAtDate = hasExpiry && new Date(expiresAt);
const expired = hasExpiry && expiresAtDate <= new Date(); const expired = hasExpiry && expiresAtDate <= new Date();

View file

@ -1,4 +1,4 @@
import { Plural, t, Trans } from '@lingui/macro'; import { Plural, Trans, useLingui } from '@lingui/react/macro';
import { useEffect, useState } from 'preact/hooks'; import { useEffect, useState } from 'preact/hooks';
import Icon from '../components/icon'; import Icon from '../components/icon';
@ -10,6 +10,7 @@ import { fetchFollowedTags } from '../utils/followed-tags';
import useTitle from '../utils/useTitle'; import useTitle from '../utils/useTitle';
function FollowedHashtags() { function FollowedHashtags() {
const { t } = useLingui();
const { masto, instance } = api(); const { masto, instance } = api();
useTitle(t`Followed Hashtags`, `/fh`); useTitle(t`Followed Hashtags`, `/fh`);
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { useLingui } from '@lingui/react/macro';
import { useEffect, useRef } from 'preact/hooks'; import { useEffect, useRef } from 'preact/hooks';
import { useSnapshot } from 'valtio'; import { useSnapshot } from 'valtio';
@ -17,6 +17,7 @@ import useTitle from '../utils/useTitle';
const LIMIT = 20; const LIMIT = 20;
function Following({ title, path, id, ...props }) { function Following({ title, path, id, ...props }) {
const { t } = useLingui();
useTitle( useTitle(
title || title ||
t({ t({

View file

@ -1,5 +1,5 @@
import { plural, t, Trans } from '@lingui/macro'; import { plural } from '@lingui/core/macro';
import { useLingui } from '@lingui/react'; import { Trans, useLingui } from '@lingui/react/macro';
import { import {
FocusableItem, FocusableItem,
MenuDivider, MenuDivider,
@ -31,6 +31,7 @@ const TAGS_LIMIT_PER_MODE = 4;
const TOTAL_TAGS_LIMIT = TAGS_LIMIT_PER_MODE + 1; const TOTAL_TAGS_LIMIT = TAGS_LIMIT_PER_MODE + 1;
function Hashtags({ media: mediaView, columnMode, ...props }) { function Hashtags({ media: mediaView, columnMode, ...props }) {
const { t } = useLingui();
// const navigate = useNavigate(); // const navigate = useNavigate();
let { hashtag, ...params } = columnMode ? {} : useParams(); let { hashtag, ...params } = columnMode ? {} : useParams();
if (props.hashtag) hashtag = props.hashtag; if (props.hashtag) hashtag = props.hashtag;

View file

@ -1,7 +1,7 @@
import './notifications-menu.css'; import './notifications-menu.css';
import { msg, t, Trans } from '@lingui/macro'; import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react'; import { Trans, useLingui } from '@lingui/react/macro';
import { ControlledMenu } from '@szhsin/react-menu'; import { ControlledMenu } from '@szhsin/react-menu';
import { memo } from 'preact/compat'; import { memo } from 'preact/compat';
import { useEffect, useRef, useState } from 'preact/hooks'; import { useEffect, useRef, useState } from 'preact/hooks';
@ -62,6 +62,7 @@ function Home() {
} }
function NotificationsLink() { function NotificationsLink() {
const { t } = useLingui();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
const notificationLinkRef = useRef(); const notificationLinkRef = useRef();
const [menuState, setMenuState] = useState(undefined); const [menuState, setMenuState] = useState(undefined);

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { Trans } from '@lingui/react/macro';
import { useLayoutEffect, useState } from 'preact/hooks'; import { useLayoutEffect, useState } from 'preact/hooks';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';

View file

@ -1,6 +1,6 @@
import './lists.css'; import './lists.css';
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { Menu, MenuDivider, MenuItem } from '@szhsin/react-menu'; import { Menu, MenuDivider, MenuItem } from '@szhsin/react-menu';
import { useEffect, useRef, useState } from 'preact/hooks'; import { useEffect, useRef, useState } from 'preact/hooks';
import { InView } from 'react-intersection-observer'; import { InView } from 'react-intersection-observer';
@ -25,6 +25,7 @@ import useTitle from '../utils/useTitle';
const LIMIT = 20; const LIMIT = 20;
function List(props) { function List(props) {
const { t } = useLingui();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
const { masto, instance } = api(); const { masto, instance } = api();
const id = props?.id || useParams()?.id; const id = props?.id || useParams()?.id;
@ -222,6 +223,7 @@ function List(props) {
const MEMBERS_LIMIT = 40; const MEMBERS_LIMIT = 40;
function ListManageMembers({ listID, onClose }) { function ListManageMembers({ listID, onClose }) {
const { t } = useLingui();
// Show list of members with [Remove] button // Show list of members with [Remove] button
// API only returns 40 members at a time, so this need to be paginated with infinite scroll // API only returns 40 members at a time, so this need to be paginated with infinite scroll
// Show [Add] button after removing a member // Show [Add] button after removing a member
@ -301,6 +303,7 @@ function ListManageMembers({ listID, onClose }) {
} }
function RemoveAddButton({ account, listID }) { function RemoveAddButton({ account, listID }) {
const { t } = useLingui();
const { masto } = api(); const { masto } = api();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const [removed, setRemoved] = useState(false); const [removed, setRemoved] = useState(false);

View file

@ -1,6 +1,6 @@
import './lists.css'; import './lists.css';
import { Plural, t, Trans } from '@lingui/macro'; import { Plural, Trans, useLingui } from '@lingui/react/macro';
import { useEffect, useReducer, useState } from 'preact/hooks'; import { useEffect, useReducer, useState } from 'preact/hooks';
import Icon from '../components/icon'; import Icon from '../components/icon';
@ -13,6 +13,7 @@ import { fetchLists } from '../utils/lists';
import useTitle from '../utils/useTitle'; import useTitle from '../utils/useTitle';
function Lists() { function Lists() {
const { t } = useLingui();
useTitle(t`Lists`, `/l`); useTitle(t`Lists`, `/l`);
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');

View file

@ -1,6 +1,6 @@
import './login.css'; import './login.css';
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import Fuse from 'fuse.js'; import Fuse from 'fuse.js';
import { useEffect, useRef, useState } from 'preact/hooks'; import { useEffect, useRef, useState } from 'preact/hooks';
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
@ -23,6 +23,7 @@ import useTitle from '../utils/useTitle';
const { PHANPY_DEFAULT_INSTANCE: DEFAULT_INSTANCE } = import.meta.env; const { PHANPY_DEFAULT_INSTANCE: DEFAULT_INSTANCE } = import.meta.env;
function Login() { function Login() {
const { t } = useLingui();
useTitle('Log in'); useTitle('Log in');
const instanceURLRef = useRef(); const instanceURLRef = useRef();
const cachedInstanceURL = store.local.get('instanceURL'); const cachedInstanceURL = store.local.get('instanceURL');

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { useMemo, useRef, useState } from 'preact/hooks'; import { useMemo, useRef, useState } from 'preact/hooks';
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
@ -13,6 +13,7 @@ const LIMIT = 20;
const emptySearchParams = new URLSearchParams(); const emptySearchParams = new URLSearchParams();
function Mentions({ columnMode, ...props }) { function Mentions({ columnMode, ...props }) {
const { t } = useLingui();
const { masto, instance } = api(); const { masto, instance } = api();
const [searchParams] = columnMode ? [emptySearchParams] : useSearchParams(); const [searchParams] = columnMode ? [emptySearchParams] : useSearchParams();
const [stateType, setStateType] = useState(null); const [stateType, setStateType] = useState(null);

View file

@ -1,7 +1,7 @@
import './notifications.css'; import './notifications.css';
import { msg, Plural, t, Trans } from '@lingui/macro'; import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react'; import { Plural, Trans, useLingui } from '@lingui/react/macro';
import { Fragment } from 'preact'; import { Fragment } from 'preact';
import { memo } from 'preact/compat'; import { memo } from 'preact/compat';
import { import {
@ -109,7 +109,7 @@ const NOTIFICATIONS_POLICIES_TEXT = {
}; };
function Notifications({ columnMode }) { function Notifications({ columnMode }) {
const { _ } = useLingui(); const { _, t } = useLingui();
useTitle(t`Notifications`, '/notifications'); useTitle(t`Notifications`, '/notifications');
const { masto, instance } = api(); const { masto, instance } = api();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
@ -1173,6 +1173,7 @@ function NotificationRequestModalButton({ request }) {
} }
function NotificationRequestButtons({ request, onChange }) { function NotificationRequestButtons({ request, onChange }) {
const { t } = useLingui();
const { masto } = api(); const { masto } = api();
const [uiState, setUIState] = useState('default'); const [uiState, setUIState] = useState('default');
const [requestState, setRequestState] = useState(null); // accept, dismiss const [requestState, setRequestState] = useState(null); // accept, dismiss

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { Menu, MenuDivider, MenuItem } from '@szhsin/react-menu'; import { Menu, MenuDivider, MenuItem } from '@szhsin/react-menu';
import { useRef } from 'preact/hooks'; import { useRef } from 'preact/hooks';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
@ -16,6 +16,7 @@ import useTitle from '../utils/useTitle';
const LIMIT = 20; const LIMIT = 20;
function Public({ local, columnMode, ...props }) { function Public({ local, columnMode, ...props }) {
const { t } = useLingui();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
const isLocal = !!local; const isLocal = !!local;
const params = columnMode ? {} : useParams(); const params = columnMode ? {} : useParams();

View file

@ -1,7 +1,7 @@
import './search.css'; import './search.css';
import { useAutoAnimate } from '@formkit/auto-animate/preact'; import { useAutoAnimate } from '@formkit/auto-animate/preact';
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { useEffect, useLayoutEffect, useRef, useState } from 'preact/hooks'; import { useEffect, useLayoutEffect, useRef, useState } from 'preact/hooks';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { InView } from 'react-intersection-observer'; import { InView } from 'react-intersection-observer';
@ -31,6 +31,7 @@ const scrollIntoViewOptions = {
}; };
function Search({ columnMode, ...props }) { function Search({ columnMode, ...props }) {
const { t } = useLingui();
const params = columnMode ? {} : useParams(); const params = columnMode ? {} : useParams();
const { masto, instance, authenticated } = api({ const { masto, instance, authenticated } = api({
instance: params.instance, instance: params.instance,

View file

@ -1,6 +1,6 @@
import './settings.css'; import './settings.css';
import { Plural, t, Trans } from '@lingui/macro'; import { Plural, Trans, useLingui } from '@lingui/react/macro';
import { useEffect, useRef, useState } from 'preact/hooks'; import { useEffect, useRef, useState } from 'preact/hooks';
import { useSnapshot } from 'valtio'; import { useSnapshot } from 'valtio';
@ -36,6 +36,7 @@ const {
} = import.meta.env; } = import.meta.env;
function Settings({ onClose }) { function Settings({ onClose }) {
const { t } = useLingui();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
const currentTheme = store.local.get('theme') || 'auto'; const currentTheme = store.local.get('theme') || 'auto';
const themeFormRef = useRef(); const themeFormRef = useRef();
@ -957,6 +958,7 @@ async function clearCaches() {
} }
function PushNotificationsSection({ onClose }) { function PushNotificationsSection({ onClose }) {
const { t } = useLingui();
if (!isPushSupported()) return null; if (!isPushSupported()) return null;
const { instance } = api(); const { instance } = api();

View file

@ -1,6 +1,6 @@
import './status.css'; import './status.css';
import { Plural, t, Trans } from '@lingui/macro'; import { Plural, Trans, useLingui } from '@lingui/react/macro';
import { Menu, MenuDivider, MenuHeader, MenuItem } from '@szhsin/react-menu'; import { Menu, MenuDivider, MenuHeader, MenuItem } from '@szhsin/react-menu';
import debounce from 'just-debounce-it'; import debounce from 'just-debounce-it';
import pRetry from 'p-retry'; import pRetry from 'p-retry';
@ -73,6 +73,7 @@ const STATUSES_SELECTOR =
const STATUS_URL_REGEX = /\/s\//i; const STATUS_URL_REGEX = /\/s\//i;
function StatusPage(params) { function StatusPage(params) {
const { t } = useLingui();
const { id } = params; const { id } = params;
const { masto, instance } = api({ instance: params.instance }); const { masto, instance } = api({ instance: params.instance });
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
@ -214,6 +215,7 @@ function createdAtSort(a, b) {
} }
function StatusThread({ id, closeLink = '/', instance: propInstance }) { function StatusThread({ id, closeLink = '/', instance: propInstance }) {
const { t } = useLingui();
const [searchParams, setSearchParams] = useSearchParams(); const [searchParams, setSearchParams] = useSearchParams();
const mediaParam = searchParams.get('media'); const mediaParam = searchParams.get('media');
const mediaStatusID = searchParams.get('mediaStatusID'); const mediaStatusID = searchParams.get('mediaStatusID');
@ -1377,6 +1379,7 @@ function SubComments({
openAll, openAll,
parentLink, parentLink,
}) { }) {
const { t } = useLingui();
const [searchParams, setSearchParams] = useSearchParams(); const [searchParams, setSearchParams] = useSearchParams();
// Total comments count, including sub-replies // Total comments count, including sub-replies

View file

@ -1,7 +1,7 @@
import '../components/links-bar.css'; import '../components/links-bar.css';
import './trending.css'; import './trending.css';
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import { MenuItem } from '@szhsin/react-menu'; import { MenuItem } from '@szhsin/react-menu';
import { getBlurHashAverageColor } from 'fast-blurhash'; import { getBlurHashAverageColor } from 'fast-blurhash';
import { useEffect, useMemo, useRef, useState } from 'preact/hooks'; import { useEffect, useMemo, useRef, useState } from 'preact/hooks';
@ -62,6 +62,7 @@ function fetchLinkList(masto, params) {
} }
function Trending({ columnMode, ...props }) { function Trending({ columnMode, ...props }) {
const { t } = useLingui();
const snapStates = useSnapshot(states); const snapStates = useSnapshot(states);
const params = columnMode ? {} : useParams(); const params = columnMode ? {} : useParams();
const { masto, instance } = api({ const { masto, instance } = api({

View file

@ -1,6 +1,6 @@
import './welcome.css'; import './welcome.css';
import { t, Trans } from '@lingui/macro'; import { Trans, useLingui } from '@lingui/react/macro';
import boostsCarouselUrl from '../assets/features/boosts-carousel.jpg'; import boostsCarouselUrl from '../assets/features/boosts-carousel.jpg';
import groupedNotificationsUrl from '../assets/features/grouped-notifications.jpg'; import groupedNotificationsUrl from '../assets/features/grouped-notifications.jpg';
@ -31,6 +31,7 @@ const appVersion = __BUILD_TIME__
: null; : null;
function Welcome() { function Welcome() {
const { t } = useLingui();
useTitle(null, ['/', '/welcome']); useTitle(null, ['/', '/welcome']);
return ( return (
<main id="welcome"> <main id="welcome">

View file

@ -8,12 +8,12 @@ const focusDeck = () => {
focusedColumn.focus(); focusedColumn.focus();
} else { } else {
// Focus first column within viewport // Focus first column within viewport
const firstVisibleColumn = columns const firstVisibleColumn = Array.from(
.querySelectorAll('.deck-container') columns.querySelectorAll('.deck-container'),
.find((column) => { ).find((column) => {
const columnRect = column.getBoundingClientRect(); const columnRect = column.getBoundingClientRect();
return columnRect.left >= 0; return columnRect.left >= 0;
}); });
if (firstVisibleColumn) { if (firstVisibleColumn) {
firstVisibleColumn.focus(); firstVisibleColumn.focus();
} else { } else {

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { t } from '@lingui/core/macro';
export default function openCompose(opts) { export default function openCompose(opts) {
const url = URL.parse('/compose/', window.location); const url = URL.parse('/compose/', window.location);

View file

@ -1,4 +1,4 @@
import { t, Trans } from '@lingui/macro'; import { t } from '@lingui/core/macro';
import openOSK from './open-osk'; import openOSK from './open-osk';
import showToast from './show-toast'; import showToast from './show-toast';

View file

@ -157,7 +157,9 @@ export default defineConfig({
], ],
build: { build: {
sourcemap: true, sourcemap: true,
cssCodeSplit: false, // Note: In Vite 6, if cssCodeSplit = false, it will show error "Cannot read properties of undefined (reading 'includes')"
// TODO: Revisit this when this issue is fixed
// cssCodeSplit: false,
rollupOptions: { rollupOptions: {
treeshake: false, treeshake: false,
input: { input: {