Compare commits

...

19 commits

Author SHA1 Message Date
Natsu Kagami 2fc7357be1
Merge branch 'main' of github.com:cheeaun/phanpy 2023-07-23 02:22:28 +02:00
Lim Chee Aun 5fa02f9cc4 Fix max-width bug for profile field 2023-07-23 01:00:22 +08:00
Lim Chee Aun 32a853ecc0 Make auto inline translation as a setting, turned off by default 2023-07-22 20:59:07 +08:00
Lim Chee Aun d8b385a742 Fix logic not checking different language 2023-07-22 20:50:53 +08:00
Lim Chee Aun bc3e946f61 lol why need to keep checking the text 2023-07-22 20:48:01 +08:00
Lim Chee Aun eb13fe8ce0 Fix logic again
I really need to rename these variables to be less confusing
2023-07-22 20:31:13 +08:00
Lim Chee Aun 28ad18bd0b Show pronunciation text in tooltip 2023-07-22 20:30:32 +08:00
Lim Chee Aun 9869c9dc5b If translated text is same as original text, don't show it
This means language detection messed up
2023-07-22 20:30:18 +08:00
Lim Chee Aun ac9962b051 Don't show inline translation if has card 2023-07-22 10:10:41 +08:00
Lim Chee Aun 075c729807 Fix logic again 2023-07-22 00:06:15 +08:00
Lim Chee Aun 587864893c Getting confused with the logic
Also more accurate content length calc
2023-07-21 23:54:03 +08:00
Lim Chee Aun 658872cbd9 Fix logic again 2023-07-21 23:00:58 +08:00
Lim Chee Aun 5502d08d28 Fix typo and logic 2023-07-21 22:52:53 +08:00
Lim Chee Aun 58bf8e16c2 Persist auto-inline-translation to the large size status too 2023-07-21 13:25:18 +08:00
Lim Chee Aun 4aab2d39cc Set max width for very long profile metadata 2023-07-21 00:55:37 +08:00
Lim Chee Aun 6f28db2532 Make "tabs" work for Mentions page in Columns mode 2023-07-20 20:06:07 +08:00
Lim Chee Aun 8112f0a9d6 Upgrade dependencies 2023-07-20 19:29:49 +08:00
Lim Chee Aun 9b0e63d289 Handle elk links 2023-07-19 15:51:00 +08:00
Lim Chee Aun da425b4a70 Fix wrong url cached 2023-07-19 15:46:00 +08:00
9 changed files with 181 additions and 95 deletions

60
package-lock.json generated
View file

@ -12,7 +12,7 @@
"@github/text-expander-element": "~2.5.0",
"@iconify-icons/mingcute": "~1.2.6",
"@justinribeiro/lite-youtube": "~1.5.0",
"@szhsin/react-menu": "~4.0.1",
"@szhsin/react-menu": "~4.0.2",
"@uidotdev/usehooks": "~2.0.1",
"dayjs": "~1.11.9",
"dayjs-twitter": "~0.5.0",
@ -20,7 +20,7 @@
"fast-deep-equal": "~3.1.3",
"idb-keyval": "~6.2.1",
"just-debounce-it": "~3.2.0",
"masto": "~5.11.3",
"masto": "~5.11.4",
"mem": "~9.0.2",
"p-retry": "~5.1.2",
"p-throttle": "~5.1.0",
@ -41,11 +41,11 @@
"devDependencies": {
"@preact/preset-vite": "~2.5.0",
"@trivago/prettier-plugin-sort-imports": "~4.1.1",
"postcss": "~8.4.25",
"postcss": "~8.4.26",
"postcss-dark-theme-class": "~0.7.3",
"postcss-preset-env": "~9.0.0",
"twitter-text": "~3.1.0",
"vite": "~4.4.2",
"vite": "~4.4.4",
"vite-plugin-generate-file": "~0.0.4",
"vite-plugin-html-config": "~1.0.11",
"vite-plugin-pwa": "~0.16.4",
@ -3316,9 +3316,9 @@
}
},
"node_modules/@szhsin/react-menu": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-4.0.1.tgz",
"integrity": "sha512-6oYIyKOZcxKWqZoFvKaKUmF2DnrBI+T7bCGxNqK0R/uBFDXpybGogw4Yl3eGJUmT/TJKEnIQ8OG5XDoDNitv5Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-4.0.2.tgz",
"integrity": "sha512-cYpktkWng7jCTPKog33w5iYldbaHQso5aJFd+7j3SkhInqYWjxiG0TtxUS0c5yFqLm6woGQEJHiBpiYHIaYMxg==",
"dependencies": {
"prop-types": "^15.7.2",
"react-transition-state": "^2.1.0"
@ -5368,9 +5368,9 @@
}
},
"node_modules/masto": {
"version": "5.11.3",
"resolved": "https://registry.npmjs.org/masto/-/masto-5.11.3.tgz",
"integrity": "sha512-GtSnrqm5fHPaaU0iwag4LCmvpp82rDng6yOZinmOJHHlUfo6Gnq5QY6x3lJCxCnsPIXpTu1yaX42bWrSQyoQPA==",
"version": "5.11.4",
"resolved": "https://registry.npmjs.org/masto/-/masto-5.11.4.tgz",
"integrity": "sha512-sLF3SJTNZDAP57Y+8vAdd1KQTuWWxmGUrBF1R2GLPL6zij/1wXxV05+h8GZhnfg+696arkt+w6ZlKvEEfH1yvg==",
"dependencies": {
"@mastojs/ponyfills": "^1.0.4",
"change-case": "^4.1.2",
@ -5713,9 +5713,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.25",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz",
"integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==",
"version": "8.4.26",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.26.tgz",
"integrity": "sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw==",
"dev": true,
"funding": [
{
@ -7528,13 +7528,13 @@
}
},
"node_modules/vite": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.2.tgz",
"integrity": "sha512-zUcsJN+UvdSyHhYa277UHhiJ3iq4hUBwHavOpsNUGsTgjBeoBlK8eDt+iT09pBq0h9/knhG/SPrZiM7cGmg7NA==",
"version": "4.4.4",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.4.tgz",
"integrity": "sha512-4mvsTxjkveWrKDJI70QmelfVqTm+ihFAb6+xf4sjEU2TmUCTlVX87tmg/QooPEMQb/lM9qGHT99ebqPziEd3wg==",
"dev": true,
"dependencies": {
"esbuild": "^0.18.10",
"postcss": "^8.4.24",
"postcss": "^8.4.25",
"rollup": "^3.25.2"
},
"bin": {
@ -10064,9 +10064,9 @@
}
},
"@szhsin/react-menu": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-4.0.1.tgz",
"integrity": "sha512-6oYIyKOZcxKWqZoFvKaKUmF2DnrBI+T7bCGxNqK0R/uBFDXpybGogw4Yl3eGJUmT/TJKEnIQ8OG5XDoDNitv5Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-4.0.2.tgz",
"integrity": "sha512-cYpktkWng7jCTPKog33w5iYldbaHQso5aJFd+7j3SkhInqYWjxiG0TtxUS0c5yFqLm6woGQEJHiBpiYHIaYMxg==",
"requires": {
"prop-types": "^15.7.2",
"react-transition-state": "^2.1.0"
@ -11574,9 +11574,9 @@
}
},
"masto": {
"version": "5.11.3",
"resolved": "https://registry.npmjs.org/masto/-/masto-5.11.3.tgz",
"integrity": "sha512-GtSnrqm5fHPaaU0iwag4LCmvpp82rDng6yOZinmOJHHlUfo6Gnq5QY6x3lJCxCnsPIXpTu1yaX42bWrSQyoQPA==",
"version": "5.11.4",
"resolved": "https://registry.npmjs.org/masto/-/masto-5.11.4.tgz",
"integrity": "sha512-sLF3SJTNZDAP57Y+8vAdd1KQTuWWxmGUrBF1R2GLPL6zij/1wXxV05+h8GZhnfg+696arkt+w6ZlKvEEfH1yvg==",
"requires": {
"@mastojs/ponyfills": "^1.0.4",
"change-case": "^4.1.2",
@ -11825,9 +11825,9 @@
"dev": true
},
"postcss": {
"version": "8.4.25",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz",
"integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==",
"version": "8.4.26",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.26.tgz",
"integrity": "sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw==",
"dev": true,
"requires": {
"nanoid": "^3.3.6",
@ -12904,14 +12904,14 @@
}
},
"vite": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.2.tgz",
"integrity": "sha512-zUcsJN+UvdSyHhYa277UHhiJ3iq4hUBwHavOpsNUGsTgjBeoBlK8eDt+iT09pBq0h9/knhG/SPrZiM7cGmg7NA==",
"version": "4.4.4",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.4.tgz",
"integrity": "sha512-4mvsTxjkveWrKDJI70QmelfVqTm+ihFAb6+xf4sjEU2TmUCTlVX87tmg/QooPEMQb/lM9qGHT99ebqPziEd3wg==",
"dev": true,
"requires": {
"esbuild": "^0.18.10",
"fsevents": "~2.3.2",
"postcss": "^8.4.24",
"postcss": "^8.4.25",
"rollup": "^3.25.2"
}
},

View file

@ -14,7 +14,7 @@
"@github/text-expander-element": "~2.5.0",
"@iconify-icons/mingcute": "~1.2.6",
"@justinribeiro/lite-youtube": "~1.5.0",
"@szhsin/react-menu": "~4.0.1",
"@szhsin/react-menu": "~4.0.2",
"@uidotdev/usehooks": "~2.0.1",
"dayjs": "~1.11.9",
"dayjs-twitter": "~0.5.0",
@ -22,7 +22,7 @@
"fast-deep-equal": "~3.1.3",
"idb-keyval": "~6.2.1",
"just-debounce-it": "~3.2.0",
"masto": "~5.11.3",
"masto": "~5.11.4",
"mem": "~9.0.2",
"p-retry": "~5.1.2",
"p-throttle": "~5.1.0",
@ -43,11 +43,11 @@
"devDependencies": {
"@preact/preset-vite": "~2.5.0",
"@trivago/prettier-plugin-sort-imports": "~4.1.1",
"postcss": "~8.4.25",
"postcss": "~8.4.26",
"postcss-dark-theme-class": "~0.7.3",
"postcss-preset-env": "~9.0.0",
"twitter-text": "~3.1.0",
"vite": "~4.4.2",
"vite": "~4.4.4",
"vite-plugin-generate-file": "~0.0.4",
"vite-plugin-html-config": "~1.0.11",
"vite-plugin-pwa": "~0.16.4",

View file

@ -197,9 +197,14 @@
filter: saturate(0.75);
line-height: 1.25;
flex-shrink: 0;
max-width: calc(100% - 12px - 2em);
}
.account-container .profile-field:only-child {
max-width: 100%;
}
.timeline-start .account-container .profile-field {
flex-shrink: 1;
max-width: 100%;
}
.account-container :is(.note, .profile-field) .invisible {

View file

@ -57,7 +57,7 @@ import MenuLink from './menu-link';
import RelativeTime from './relative-time';
import TranslationBlock from './translation-block';
const INLINE_TRASNSLATE_LIMIT = 140;
const INLINE_TRANSLATE_LIMIT = 140;
const throttle = pThrottle({
limit: 1,
interval: 1000,
@ -251,17 +251,40 @@ function Status({
const targetLanguage = getTranslateTargetLanguage(true);
const contentTranslationHideLanguages =
snapStates.settings.contentTranslationHideLanguages || [];
if (!snapStates.settings.contentTranslation) enableTranslate = false;
const { contentTranslation, contentTranslationAutoInline } =
snapStates.settings;
if (!contentTranslation) enableTranslate = false;
const inlineTranslate = useMemo(() => {
return (
!isSizeLarge &&
!spoilerText &&
!poll &&
!mediaAttachments?.length &&
content?.length > 0 &&
content?.length <= INLINE_TRASNSLATE_LIMIT
);
}, [isSizeLarge, content, spoilerText, poll, mediaAttachments]);
if (
!contentTranslation ||
!contentTranslationAutoInline ||
readOnly ||
(withinContext && !isSizeLarge) ||
previewMode ||
spoilerText ||
sensitive ||
poll ||
card ||
mediaAttachments?.length
) {
return false;
}
const contentLength = htmlContentLength(content);
return contentLength > 0 && contentLength <= INLINE_TRANSLATE_LIMIT;
}, [
contentTranslation,
contentTranslationAutoInline,
readOnly,
withinContext,
isSizeLarge,
previewMode,
spoilerText,
sensitive,
poll,
card,
mediaAttachments,
content,
]);
const [showEdited, setShowEdited] = useState(false);
const [showReactions, setShowReactions] = useState(false);
@ -1104,13 +1127,11 @@ function Status({
}}
/>
)}
{(((enableTranslate || inlineTranslate) &&
!!content.trim() &&
differentLanguage) ||
{(((enableTranslate || inlineTranslate) && !!content.trim() && differentLanguage) ||
forceTranslate) && (
<TranslationBlock
forceTranslate={forceTranslate || inlineTranslate}
mini={inlineTranslate}
mini={!isSizeLarge && !withinContext}
sourceLanguage={language}
text={
(spoilerText ? `${spoilerText}\n\n` : '') +
@ -1836,7 +1857,12 @@ function _unfurlMastodonLink(instance, url) {
console.debug('🦦 Unfurling URL', url);
let remoteInstanceFetch;
const urlObj = new URL(url);
let theURL = url;
if (/\/\/elk\.[^\/]+\/[^.]+\.[^.]+/i.test(theURL)) {
// E.g. https://elk.zone/domain.com/@stest/123 -> https://domain.com/@stest/123
theURL = theURL.replace(/elk\.[^\/]+\//i, '');
}
const urlObj = new URL(theURL);
const domain = urlObj.hostname;
const path = urlObj.pathname;
// Regex /:username/:id, where username = @username or @username@domain, id = number
@ -1880,12 +1906,12 @@ function _unfurlMastodonLink(instance, url) {
function handleFulfill(result) {
const { status, instance } = result;
const { id } = status;
const url = `/${instance}/s/${id}`;
console.debug('🦦 Unfurled URL', url, id, url);
const selfURL = `/${instance}/s/${id}`;
console.debug('🦦 Unfurled URL', url, id, selfURL);
const data = {
id,
instance,
url,
url: selfURL,
};
states.unfurledLinks[url] = data;
saveStatus(status, instance, {

View file

@ -81,7 +81,7 @@ function TranslationBlock({
}
setTranslatedContent(content);
setUIState('default');
if (!mini) {
if (!mini && content.trim() !== text.trim()) {
detailsRef.current.open = true;
detailsRef.current.scrollIntoView({
behavior: 'smooth',
@ -105,14 +105,22 @@ function TranslationBlock({
}, [forceTranslate]);
if (mini) {
if (!!translatedContent && detectedLang !== targetLangText) {
if (
!!translatedContent &&
translatedContent.trim() !== text.trim() &&
detectedLang !== targetLangText
) {
return (
<div class="status-translation-block-mini">
<Icon
icon="translate"
alt={`Auto-translated from ${sourceLangText}`}
/>
<output lang={targetLang} dir="auto">
<output
lang={targetLang}
dir="auto"
title={pronunciationContent || ''}
>
{translatedContent}
</output>
</div>

View file

@ -1,4 +1,4 @@
import { useMemo, useRef } from 'preact/hooks';
import { useMemo, useRef, useState } from 'preact/hooks';
import { useSearchParams } from 'react-router-dom';
import Link from '../components/link';
@ -14,7 +14,8 @@ function Mentions({ columnMode, ...props }) {
useTitle('Mentions', '/mentions');
const { masto, instance } = api();
const [searchParams] = columnMode ? [emptySearchParams] : useSearchParams();
const type = props?.type || searchParams.get('type');
const [stateType, setStateType] = useState(null);
const type = props?.type || searchParams.get('type') || stateType;
const mentionsIterator = useRef();
const latestItem = useRef();
@ -127,12 +128,27 @@ function Mentions({ columnMode, ...props }) {
const TimelineStart = useMemo(() => {
return (
<div class="filter-bar centered">
<Link to="/mentions" class={!type ? 'is-active' : ''}>
<Link
to="/mentions"
class={!type ? 'is-active' : ''}
onClick={(e) => {
if (columnMode) {
e.preventDefault();
setStateType(null);
}
}}
>
All
</Link>
<Link
to="/mentions?type=private"
class={type === 'private' ? 'is-active' : ''}
onClick={(e) => {
if (columnMode) {
e.preventDefault();
setStateType('private');
}
}}
>
Private
</Link>

View file

@ -59,6 +59,9 @@
#settings-container div {
vertical-align: middle;
}
#settings-container section > ul > li .sub-section hr {
margin: 8px 0;
}
#settings-container section select {
padding: 4px;

View file

@ -255,42 +255,43 @@ function Settings({ onClose }) {
: ''
}`}
>
<label>
Translate to{' '}
<select
value={targetLanguage || ''}
disabled={!snapStates.settings.contentTranslation}
onChange={(e) => {
states.settings.contentTranslationTargetLanguage =
e.target.value || null;
}}
>
<option value="">
System language ({systemTargetLanguageText})
</option>
<option disabled></option>
{targetLanguages.map((lang) => (
<option value={lang.code}>{lang.name}</option>
))}
</select>
</label>
<div>
<label>
Translate to{' '}
<select
value={targetLanguage || ''}
disabled={!snapStates.settings.contentTranslation}
onChange={(e) => {
states.settings.contentTranslationTargetLanguage =
e.target.value || null;
}}
>
<option value="">
System language ({systemTargetLanguageText})
</option>
<option disabled></option>
{targetLanguages.map((lang) => (
<option value={lang.code}>{lang.name}</option>
))}
</select>
</label>
</div>
<hr />
<p class="checkbox-fieldset">
<small>
Hide "Translate" button for
{snapStates.settings.contentTranslationHideLanguages
.length > 0 && (
<>
{' '}
(
{
snapStates.settings.contentTranslationHideLanguages
.length
}
)
</>
)}
:
</small>
Hide "Translate" button for
{snapStates.settings.contentTranslationHideLanguages.length >
0 && (
<>
{' '}
(
{
snapStates.settings.contentTranslationHideLanguages
.length
}
)
</>
)}
:
<div class="checkbox-fields">
{targetLanguages.map((lang) => (
<label>
@ -318,7 +319,7 @@ function Settings({ onClose }) {
))}
</div>
</p>
<p>
<p class="insignificant">
<small>
Note: This feature uses an external API to translate,
powered by{' '}
@ -331,6 +332,28 @@ function Settings({ onClose }) {
.
</small>
</p>
<hr />
<div>
<label>
<input
type="checkbox"
checked={snapStates.settings.contentTranslationAutoInline}
disabled={!snapStates.settings.contentTranslation}
onChange={(e) => {
states.settings.contentTranslationAutoInline =
e.target.checked;
}}
/>{' '}
Auto inline translation
</label>
<p class="insignificant">
<small>
Automatically show translation for posts in timeline. Only
works for <b>short</b> posts without content warning,
media and poll.
</small>
</p>
</div>
</div>
</li>
<li>

View file

@ -52,6 +52,8 @@ const states = proxy({
store.account.get('settings-contentTranslationTargetLanguage') || null,
contentTranslationHideLanguages:
store.account.get('settings-contentTranslationHideLanguages') || [],
contentTranslationAutoInline:
store.account.get('settings-contentTranslationAutoInline') ?? false,
cloakMode: store.account.get('settings-cloakMode') ?? false,
},
});
@ -80,6 +82,9 @@ subscribe(states, (changes) => {
if (path.join('.') === 'settings.contentTranslation') {
store.account.set('settings-contentTranslation', !!value);
}
if (path.join('.') === 'settings.contentTranslationAutoInline') {
store.account.set('settings-contentTranslationAutoInline', !!value);
}
if (path.join('.') === 'settings.contentTranslationTargetLanguage') {
console.log('SET', value);
store.account.set('settings-contentTranslationTargetLanguage', value);