Compare commits
10 commits
f5b1b924a5
...
f21a65da9a
Author | SHA1 | Date | |
---|---|---|---|
|
f21a65da9a | ||
|
a97478097b | ||
|
71d2db31e0 | ||
|
88547fa403 | ||
|
1765defa56 | ||
|
437d721c26 | ||
|
e13a2feec8 | ||
|
39bcb01894 | ||
|
7fb0044471 | ||
|
f645815b84 |
|
@ -62,29 +62,32 @@ function Avatar({ url, size, alt = '', squircle, ...props }) {
|
||||||
if (avatarRef.current) avatarRef.current.dataset.loaded = true;
|
if (avatarRef.current) avatarRef.current.dataset.loaded = true;
|
||||||
if (alphaCache[url] !== undefined) return;
|
if (alphaCache[url] !== undefined) return;
|
||||||
if (isMissing) return;
|
if (isMissing) return;
|
||||||
try {
|
queueMicrotask(() => {
|
||||||
// Check if image has alpha channel
|
try {
|
||||||
const { width, height } = e.target;
|
// Check if image has alpha channel
|
||||||
if (canvas.width !== width) canvas.width = width;
|
const { width, height } = e.target;
|
||||||
if (canvas.height !== height) canvas.height = height;
|
if (canvas.width !== width) canvas.width = width;
|
||||||
ctx.drawImage(e.target, 0, 0);
|
if (canvas.height !== height) canvas.height = height;
|
||||||
const allPixels = ctx.getImageData(0, 0, width, height);
|
ctx.drawImage(e.target, 0, 0);
|
||||||
// At least 10% of pixels have alpha <= 128
|
const allPixels = ctx.getImageData(0, 0, width, height);
|
||||||
const hasAlpha =
|
// At least 10% of pixels have alpha <= 128
|
||||||
allPixels.data.filter((pixel, i) => i % 4 === 3 && pixel <= 128)
|
const hasAlpha =
|
||||||
.length /
|
allPixels.data.filter(
|
||||||
(allPixels.data.length / 4) >
|
(pixel, i) => i % 4 === 3 && pixel <= 128,
|
||||||
0.1;
|
).length /
|
||||||
if (hasAlpha) {
|
(allPixels.data.length / 4) >
|
||||||
// console.log('hasAlpha', hasAlpha, allPixels.data);
|
0.1;
|
||||||
avatarRef.current.classList.add('has-alpha');
|
if (hasAlpha) {
|
||||||
|
// console.log('hasAlpha', hasAlpha, allPixels.data);
|
||||||
|
avatarRef.current.classList.add('has-alpha');
|
||||||
|
}
|
||||||
|
alphaCache[url] = hasAlpha;
|
||||||
|
ctx.clearRect(0, 0, width, height);
|
||||||
|
} catch (e) {
|
||||||
|
// Silent fail
|
||||||
|
alphaCache[url] = false;
|
||||||
}
|
}
|
||||||
alphaCache[url] = hasAlpha;
|
});
|
||||||
ctx.clearRect(0, 0, width, height);
|
|
||||||
} catch (e) {
|
|
||||||
// Silent fail
|
|
||||||
alphaCache[url] = false;
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -105,6 +105,7 @@ export const ICONS = {
|
||||||
month: () => import('@iconify-icons/mingcute/calendar-month-line'),
|
month: () => import('@iconify-icons/mingcute/calendar-month-line'),
|
||||||
media: () => import('@iconify-icons/mingcute/photo-album-line'),
|
media: () => import('@iconify-icons/mingcute/photo-album-line'),
|
||||||
speak: () => import('@iconify-icons/mingcute/radar-line'),
|
speak: () => import('@iconify-icons/mingcute/radar-line'),
|
||||||
|
building: () => import('@iconify-icons/mingcute/building-5-line'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const ICONDATA = {};
|
const ICONDATA = {};
|
||||||
|
|
|
@ -202,7 +202,7 @@ function NavMenu(props) {
|
||||||
<Icon icon="search" size="l" /> <span>Search</span>
|
<Icon icon="search" size="l" /> <span>Search</span>
|
||||||
</MenuLink>
|
</MenuLink>
|
||||||
<MenuLink to={`/${instance}/p/l`}>
|
<MenuLink to={`/${instance}/p/l`}>
|
||||||
<Icon icon="group" size="l" /> <span>Local</span>
|
<Icon icon="building" size="l" /> <span>Local</span>
|
||||||
</MenuLink>
|
</MenuLink>
|
||||||
<MenuLink to={`/${instance}/p`}>
|
<MenuLink to={`/${instance}/p`}>
|
||||||
<Icon icon="earth" size="l" /> <span>Federated</span>
|
<Icon icon="earth" size="l" /> <span>Federated</span>
|
||||||
|
|
|
@ -159,7 +159,7 @@ export const SHORTCUTS_META = {
|
||||||
title: ({ local }) => (local ? 'Local' : 'Federated'),
|
title: ({ local }) => (local ? 'Local' : 'Federated'),
|
||||||
subtitle: ({ instance }) => instance || api().instance,
|
subtitle: ({ instance }) => instance || api().instance,
|
||||||
path: ({ local, instance }) => `/${instance}/p${local ? '/l' : ''}`,
|
path: ({ local, instance }) => `/${instance}/p${local ? '/l' : ''}`,
|
||||||
icon: ({ local }) => (local ? 'group' : 'earth'),
|
icon: ({ local }) => (local ? 'building' : 'earth'),
|
||||||
},
|
},
|
||||||
trending: {
|
trending: {
|
||||||
id: 'trending',
|
id: 'trending',
|
||||||
|
|
|
@ -554,6 +554,13 @@
|
||||||
text-rendering: optimizeSpeed;
|
text-rendering: optimizeSpeed;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
|
* {
|
||||||
|
text-decoration-color: inherit;
|
||||||
|
text-decoration-thickness: 1.5em;
|
||||||
|
text-decoration-line: line-through;
|
||||||
|
text-rendering: optimizeSpeed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,7 @@ function Status({
|
||||||
const { instance: currentInstance } = api();
|
const { instance: currentInstance } = api();
|
||||||
const sameInstance = instance === currentInstance;
|
const sameInstance = instance === currentInstance;
|
||||||
|
|
||||||
let sKey = statusKey(statusID, instance);
|
let sKey = statusKey(statusID || status?.id, instance);
|
||||||
const snapStates = useSnapshot(states);
|
const snapStates = useSnapshot(states);
|
||||||
if (!status) {
|
if (!status) {
|
||||||
status = snapStates.statuses[sKey] || snapStates.statuses[statusID];
|
status = snapStates.statuses[sKey] || snapStates.statuses[statusID];
|
||||||
|
@ -2364,9 +2364,18 @@ function _unfurlMastodonLink(instance, url) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remoteInstanceFetch) {
|
if (remoteInstanceFetch) {
|
||||||
return Promise.any([remoteInstanceFetch, mastoSearchFetch])
|
// return Promise.any([remoteInstanceFetch, mastoSearchFetch])
|
||||||
.then(handleFulfill)
|
// .then(handleFulfill)
|
||||||
.catch(handleCatch);
|
// .catch(handleCatch);
|
||||||
|
// If mastoSearchFetch is fulfilled within 3s, return it, else return remoteInstanceFetch
|
||||||
|
const finalPromise = Promise.race([
|
||||||
|
mastoSearchFetch,
|
||||||
|
new Promise((resolve, reject) => setTimeout(reject, 3000)),
|
||||||
|
]).catch(() => {
|
||||||
|
// If remoteInstanceFetch is fullfilled, return it, else return mastoSearchFetch
|
||||||
|
return remoteInstanceFetch.catch(() => mastoSearchFetch);
|
||||||
|
});
|
||||||
|
return finalPromise.then(handleFulfill).catch(handleCatch);
|
||||||
} else {
|
} else {
|
||||||
return mastoSearchFetch.then(handleFulfill).catch(handleCatch);
|
return mastoSearchFetch.then(handleFulfill).catch(handleCatch);
|
||||||
}
|
}
|
||||||
|
|
|
@ -446,6 +446,9 @@ function Settings({ onClose }) {
|
||||||
Image description generator{' '}
|
Image description generator{' '}
|
||||||
<Icon icon="sparkles2" class="more-insignificant" />
|
<Icon icon="sparkles2" class="more-insignificant" />
|
||||||
</label>
|
</label>
|
||||||
|
<div class="sub-section insignificant">
|
||||||
|
<small>Only for new images while composing new posts.</small>
|
||||||
|
</div>
|
||||||
<div class="sub-section insignificant">
|
<div class="sub-section insignificant">
|
||||||
<small>
|
<small>
|
||||||
Note: This feature uses external AI service, powered by{' '}
|
Note: This feature uses external AI service, powered by{' '}
|
||||||
|
|
|
@ -10,22 +10,20 @@ function _enhanceContent(content, opts = {}) {
|
||||||
const dom = document.createElement('div');
|
const dom = document.createElement('div');
|
||||||
dom.innerHTML = enhancedContent;
|
dom.innerHTML = enhancedContent;
|
||||||
const hasLink = /<a/i.test(enhancedContent);
|
const hasLink = /<a/i.test(enhancedContent);
|
||||||
const hasCodeBlock = enhancedContent.indexOf('```') !== -1;
|
const hasCodeBlock = enhancedContent.includes('```');
|
||||||
|
|
||||||
if (hasLink) {
|
if (hasLink) {
|
||||||
// Add target="_blank" to all links with no target="_blank"
|
// Add target="_blank" to all links with no target="_blank"
|
||||||
// E.g. `note` in `account`
|
// E.g. `note` in `account`
|
||||||
const noTargetBlankLinks = Array.from(
|
const noTargetBlankLinks = dom.querySelectorAll('a:not([target="_blank"])');
|
||||||
dom.querySelectorAll('a:not([target="_blank"])'),
|
|
||||||
);
|
|
||||||
noTargetBlankLinks.forEach((link) => {
|
noTargetBlankLinks.forEach((link) => {
|
||||||
link.setAttribute('target', '_blank');
|
link.setAttribute('target', '_blank');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove all classes except `u-url`, `mention`, `hashtag`
|
// Remove all classes except `u-url`, `mention`, `hashtag`
|
||||||
const links = Array.from(dom.querySelectorAll('a[class]'));
|
const links = dom.querySelectorAll('a[class]');
|
||||||
links.forEach((link) => {
|
links.forEach((link) => {
|
||||||
Array.from(link.classList).forEach((c) => {
|
link.classList.forEach((c) => {
|
||||||
if (!whitelistLinkClasses.includes(c)) {
|
if (!whitelistLinkClasses.includes(c)) {
|
||||||
link.classList.remove(c);
|
link.classList.remove(c);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +33,7 @@ function _enhanceContent(content, opts = {}) {
|
||||||
|
|
||||||
// Add 'has-url-text' to all links that contains a url
|
// Add 'has-url-text' to all links that contains a url
|
||||||
if (hasLink) {
|
if (hasLink) {
|
||||||
const links = Array.from(dom.querySelectorAll('a[href]'));
|
const links = dom.querySelectorAll('a[href]');
|
||||||
links.forEach((link) => {
|
links.forEach((link) => {
|
||||||
if (/^https?:\/\//i.test(link.textContent.trim())) {
|
if (/^https?:\/\//i.test(link.textContent.trim())) {
|
||||||
link.classList.add('has-url-text');
|
link.classList.add('has-url-text');
|
||||||
|
@ -45,7 +43,7 @@ function _enhanceContent(content, opts = {}) {
|
||||||
|
|
||||||
// Spanify un-spanned mentions
|
// Spanify un-spanned mentions
|
||||||
if (hasLink) {
|
if (hasLink) {
|
||||||
const links = Array.from(dom.querySelectorAll('a[href]'));
|
const links = dom.querySelectorAll('a[href]');
|
||||||
const usernames = [];
|
const usernames = [];
|
||||||
links.forEach((link) => {
|
links.forEach((link) => {
|
||||||
const text = link.innerText.trim();
|
const text = link.innerText.trim();
|
||||||
|
@ -56,8 +54,8 @@ function _enhanceContent(content, opts = {}) {
|
||||||
const [_, username, domain] = text.split('@');
|
const [_, username, domain] = text.split('@');
|
||||||
if (!hasChildren) {
|
if (!hasChildren) {
|
||||||
if (
|
if (
|
||||||
!usernames.find(([u]) => u === username) ||
|
!usernames.some(([u]) => u === username) ||
|
||||||
usernames.find(([u, d]) => u === username && d === domain)
|
usernames.some(([u, d]) => u === username && d === domain)
|
||||||
) {
|
) {
|
||||||
link.innerHTML = `@<span>${username}</span>`;
|
link.innerHTML = `@<span>${username}</span>`;
|
||||||
usernames.push([username, domain]);
|
usernames.push([username, domain]);
|
||||||
|
@ -79,7 +77,7 @@ function _enhanceContent(content, opts = {}) {
|
||||||
// ======
|
// ======
|
||||||
// Convert :shortcode: to <img />
|
// Convert :shortcode: to <img />
|
||||||
let textNodes;
|
let textNodes;
|
||||||
if (enhancedContent.indexOf(':') !== -1) {
|
if (enhancedContent.includes(':')) {
|
||||||
textNodes = extractTextNodes(dom);
|
textNodes = extractTextNodes(dom);
|
||||||
textNodes.forEach((node) => {
|
textNodes.forEach((node) => {
|
||||||
let html = node.nodeValue
|
let html = node.nodeValue
|
||||||
|
@ -90,8 +88,8 @@ function _enhanceContent(content, opts = {}) {
|
||||||
html = emojifyText(html, emojis);
|
html = emojifyText(html, emojis);
|
||||||
}
|
}
|
||||||
fauxDiv.innerHTML = html;
|
fauxDiv.innerHTML = html;
|
||||||
const nodes = Array.from(fauxDiv.childNodes);
|
// const nodes = [...fauxDiv.childNodes];
|
||||||
node.replaceWith(...nodes);
|
node.replaceWith(...fauxDiv.childNodes);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +97,7 @@ function _enhanceContent(content, opts = {}) {
|
||||||
// ===========
|
// ===========
|
||||||
// Convert ```code``` to <pre><code>code</code></pre>
|
// Convert ```code``` to <pre><code>code</code></pre>
|
||||||
if (hasCodeBlock) {
|
if (hasCodeBlock) {
|
||||||
const blocks = Array.from(dom.querySelectorAll('p')).filter((p) =>
|
const blocks = [...dom.querySelectorAll('p')].filter((p) =>
|
||||||
/^```[^]+```$/g.test(p.innerText.trim()),
|
/^```[^]+```$/g.test(p.innerText.trim()),
|
||||||
);
|
);
|
||||||
blocks.forEach((block) => {
|
blocks.forEach((block) => {
|
||||||
|
@ -113,7 +111,7 @@ function _enhanceContent(content, opts = {}) {
|
||||||
|
|
||||||
// Convert multi-paragraph code blocks to <pre><code>code</code></pre>
|
// Convert multi-paragraph code blocks to <pre><code>code</code></pre>
|
||||||
if (hasCodeBlock) {
|
if (hasCodeBlock) {
|
||||||
const paragraphs = Array.from(dom.querySelectorAll('p'));
|
const paragraphs = [...dom.querySelectorAll('p')];
|
||||||
// Filter out paragraphs with ``` in beginning only
|
// Filter out paragraphs with ``` in beginning only
|
||||||
const codeBlocks = paragraphs.filter((p) => /^```/g.test(p.innerText));
|
const codeBlocks = paragraphs.filter((p) => /^```/g.test(p.innerText));
|
||||||
// For each codeBlocks, get all paragraphs until the last paragraph with ``` at the end only
|
// For each codeBlocks, get all paragraphs until the last paragraph with ``` at the end only
|
||||||
|
@ -153,7 +151,7 @@ function _enhanceContent(content, opts = {}) {
|
||||||
// INLINE CODE
|
// INLINE CODE
|
||||||
// ===========
|
// ===========
|
||||||
// Convert `code` to <code>code</code>
|
// Convert `code` to <code>code</code>
|
||||||
if (enhancedContent.indexOf('`') !== -1) {
|
if (enhancedContent.includes('`')) {
|
||||||
textNodes = extractTextNodes(dom);
|
textNodes = extractTextNodes(dom);
|
||||||
textNodes.forEach((node) => {
|
textNodes.forEach((node) => {
|
||||||
let html = node.nodeValue
|
let html = node.nodeValue
|
||||||
|
@ -164,8 +162,8 @@ function _enhanceContent(content, opts = {}) {
|
||||||
html = html.replaceAll(/(`[^]+?`)/g, '<code>$1</code>');
|
html = html.replaceAll(/(`[^]+?`)/g, '<code>$1</code>');
|
||||||
}
|
}
|
||||||
fauxDiv.innerHTML = html;
|
fauxDiv.innerHTML = html;
|
||||||
const nodes = Array.from(fauxDiv.childNodes);
|
// const nodes = [...fauxDiv.childNodes];
|
||||||
node.replaceWith(...nodes);
|
node.replaceWith(...fauxDiv.childNodes);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,53 +186,53 @@ function _enhanceContent(content, opts = {}) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
fauxDiv.innerHTML = html;
|
fauxDiv.innerHTML = html;
|
||||||
const nodes = Array.from(fauxDiv.childNodes);
|
// const nodes = [...fauxDiv.childNodes];
|
||||||
node.replaceWith(...nodes);
|
node.replaceWith(...fauxDiv.childNodes);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// HASHTAG STUFFING
|
// HASHTAG STUFFING
|
||||||
// ================
|
// ================
|
||||||
// Get the <p> that contains a lot of hashtags, add a class to it
|
// Get the <p> that contains a lot of hashtags, add a class to it
|
||||||
if (enhancedContent.indexOf('#') !== -1) {
|
if (enhancedContent.includes('#')) {
|
||||||
let prevIndex = null;
|
let prevIndex = null;
|
||||||
const hashtagStuffedParagraphs = Array.from(
|
const hashtagStuffedParagraphs = [...dom.querySelectorAll('p')].filter(
|
||||||
dom.querySelectorAll('p'),
|
(p, index) => {
|
||||||
).filter((p, index) => {
|
let hashtagCount = 0;
|
||||||
let hashtagCount = 0;
|
for (let i = 0; i < p.childNodes.length; i++) {
|
||||||
for (let i = 0; i < p.childNodes.length; i++) {
|
const node = p.childNodes[i];
|
||||||
const node = p.childNodes[i];
|
|
||||||
|
|
||||||
if (node.nodeType === Node.TEXT_NODE) {
|
if (node.nodeType === Node.TEXT_NODE) {
|
||||||
const text = node.textContent.trim();
|
const text = node.textContent.trim();
|
||||||
if (text !== '') {
|
if (text !== '') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (node.tagName === 'BR') {
|
} else if (node.tagName === 'BR') {
|
||||||
// Ignore <br />
|
// Ignore <br />
|
||||||
} else if (node.tagName === 'A') {
|
} else if (node.tagName === 'A') {
|
||||||
const linkText = node.textContent.trim();
|
const linkText = node.textContent.trim();
|
||||||
if (!linkText || !linkText.startsWith('#')) {
|
if (!linkText || !linkText.startsWith('#')) {
|
||||||
return false;
|
return false;
|
||||||
|
} else {
|
||||||
|
hashtagCount++;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
hashtagCount++;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
// Only consider "stuffing" if:
|
||||||
// Only consider "stuffing" if:
|
// - there are more than 3 hashtags
|
||||||
// - there are more than 3 hashtags
|
// - there are more than 1 hashtag in adjacent paragraphs
|
||||||
// - there are more than 1 hashtag in adjacent paragraphs
|
if (hashtagCount > 3) {
|
||||||
if (hashtagCount > 3) {
|
prevIndex = index;
|
||||||
prevIndex = index;
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
if (hashtagCount > 1 && prevIndex && index === prevIndex + 1) {
|
||||||
if (hashtagCount > 1 && prevIndex && index === prevIndex + 1) {
|
prevIndex = index;
|
||||||
prevIndex = index;
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
},
|
||||||
});
|
);
|
||||||
if (hashtagStuffedParagraphs?.length) {
|
if (hashtagStuffedParagraphs?.length) {
|
||||||
hashtagStuffedParagraphs.forEach((p) => {
|
hashtagStuffedParagraphs.forEach((p) => {
|
||||||
p.classList.add('hashtag-stuffing');
|
p.classList.add('hashtag-stuffing');
|
||||||
|
@ -291,18 +289,20 @@ const defaultRejectFilterMap = Object.fromEntries(
|
||||||
);
|
);
|
||||||
function extractTextNodes(dom, opts = {}) {
|
function extractTextNodes(dom, opts = {}) {
|
||||||
const textNodes = [];
|
const textNodes = [];
|
||||||
|
const rejectFilterMap = Object.assign(
|
||||||
|
{},
|
||||||
|
defaultRejectFilterMap,
|
||||||
|
opts.rejectFilter?.reduce((acc, cur) => {
|
||||||
|
acc[cur] = true;
|
||||||
|
return acc;
|
||||||
|
}, {}),
|
||||||
|
);
|
||||||
const walk = document.createTreeWalker(
|
const walk = document.createTreeWalker(
|
||||||
dom,
|
dom,
|
||||||
NodeFilter.SHOW_TEXT,
|
NodeFilter.SHOW_TEXT,
|
||||||
{
|
{
|
||||||
acceptNode(node) {
|
acceptNode(node) {
|
||||||
if (defaultRejectFilterMap[node.parentNode.nodeName]) {
|
if (rejectFilterMap[node.parentNode.nodeName]) {
|
||||||
return NodeFilter.FILTER_REJECT;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
opts.rejectFilter &&
|
|
||||||
opts.rejectFilter.includes(node.parentNode.nodeName)
|
|
||||||
) {
|
|
||||||
return NodeFilter.FILTER_REJECT;
|
return NodeFilter.FILTER_REJECT;
|
||||||
}
|
}
|
||||||
return NodeFilter.FILTER_ACCEPT;
|
return NodeFilter.FILTER_ACCEPT;
|
||||||
|
|
|
@ -8,6 +8,12 @@ const locales = [
|
||||||
...navigator.languages,
|
...navigator.languages,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const localeTargetLanguages = localeMatch(
|
||||||
|
locales,
|
||||||
|
translationTargetLanguages.map((l) => l.code.replace('_', '-')), // The underscore will fail Intl.Locale inside `match`
|
||||||
|
'en',
|
||||||
|
);
|
||||||
|
|
||||||
function getTranslateTargetLanguage(fromSettings = false) {
|
function getTranslateTargetLanguage(fromSettings = false) {
|
||||||
if (fromSettings) {
|
if (fromSettings) {
|
||||||
const { contentTranslationTargetLanguage } = states.settings;
|
const { contentTranslationTargetLanguage } = states.settings;
|
||||||
|
@ -15,11 +21,7 @@ function getTranslateTargetLanguage(fromSettings = false) {
|
||||||
return contentTranslationTargetLanguage;
|
return contentTranslationTargetLanguage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return localeMatch(
|
return localeTargetLanguages;
|
||||||
locales,
|
|
||||||
translationTargetLanguages.map((l) => l.code.replace('_', '-')), // The underscore will fail Intl.Locale inside `match`
|
|
||||||
'en',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default getTranslateTargetLanguage;
|
export default getTranslateTargetLanguage;
|
||||||
|
|
|
@ -3,9 +3,8 @@ export default function isMastodonLinkMaybe(url) {
|
||||||
const { pathname, hash } = new URL(url);
|
const { pathname, hash } = new URL(url);
|
||||||
return (
|
return (
|
||||||
/^\/.*\/\d+$/i.test(pathname) ||
|
/^\/.*\/\d+$/i.test(pathname) ||
|
||||||
/^\/@[^/]+\/(statuses|posts)\/\w+\/?$/i.test(pathname) || // GoToSocial, Takahe
|
/^\/(@[^/]+|users\/[^/]+)\/(statuses|posts)\/\w+\/?$/i.test(pathname) || // GoToSocial, Takahe
|
||||||
/^\/notes\/[a-z0-9]+$/i.test(pathname) || // Misskey, Firefish
|
/^\/notes\/[a-z0-9]+$/i.test(pathname) || // Misskey, Firefish
|
||||||
/^\/notes\/[a-z0-9]+$/i.test(pathname) || // Misskey, Calckey
|
|
||||||
/^\/(notice|objects)\/[a-z0-9-]+$/i.test(pathname) || // Pleroma
|
/^\/(notice|objects)\/[a-z0-9-]+$/i.test(pathname) || // Pleroma
|
||||||
/#\/[^\/]+\.[^\/]+\/s\/.+/i.test(hash) // Phanpy 🫣
|
/#\/[^\/]+\.[^\/]+\/s\/.+/i.test(hash) // Phanpy 🫣
|
||||||
);
|
);
|
||||||
|
|
|
@ -175,21 +175,25 @@ export function saveStatus(status, instance, opts) {
|
||||||
if (!status) return;
|
if (!status) return;
|
||||||
const oldStatus = getStatus(status.id, instance);
|
const oldStatus = getStatus(status.id, instance);
|
||||||
if (!override && oldStatus) return;
|
if (!override && oldStatus) return;
|
||||||
const key = statusKey(status.id, instance);
|
queueMicrotask(() => {
|
||||||
if (oldStatus?._pinned) status._pinned = oldStatus._pinned;
|
const key = statusKey(status.id, instance);
|
||||||
// if (oldStatus?._filtered) status._filtered = oldStatus._filtered;
|
if (oldStatus?._pinned) status._pinned = oldStatus._pinned;
|
||||||
states.statuses[key] = status;
|
// if (oldStatus?._filtered) status._filtered = oldStatus._filtered;
|
||||||
if (status.reblog) {
|
states.statuses[key] = status;
|
||||||
const key = statusKey(status.reblog.id, instance);
|
if (status.reblog) {
|
||||||
states.statuses[key] = status.reblog;
|
const key = statusKey(status.reblog.id, instance);
|
||||||
}
|
states.statuses[key] = status.reblog;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// THREAD TRAVERSER
|
// THREAD TRAVERSER
|
||||||
if (!skipThreading) {
|
if (!skipThreading) {
|
||||||
queueMicrotask(() => {
|
queueMicrotask(() => {
|
||||||
threadifyStatus(status, instance);
|
threadifyStatus(status, instance);
|
||||||
if (status.reblog) {
|
if (status.reblog) {
|
||||||
threadifyStatus(status.reblog, instance);
|
queueMicrotask(() => {
|
||||||
|
threadifyStatus(status.reblog, instance);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue