Experimental 'Add to thread'

This commit is contained in:
Lim Chee Aun 2025-03-05 14:14:12 +08:00
parent 8ada3cebf8
commit 119cff3825
3 changed files with 150 additions and 13 deletions
src

View file

@ -444,7 +444,8 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
var(--line-radius), var(--line-radius); */
--curves-radius: calc(var(--curves-width) / 2);
height: calc(var(--curves-width) - var(--line-width));
background-image: radial-gradient(
background-image:
radial-gradient(
circle at bottom var(--forward),
transparent calc(var(--curves-radius) - var(--line-width)),
var(--comment-line-color) calc(var(--curves-radius) - var(--line-width))
@ -475,7 +476,8 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
transparent
);
&.hero:not(:has(+ .thread), :first-child, :only-child, :last-child) {
background-image: linear-gradient(
background-image:
linear-gradient(
var(--line-dir),
transparent,
transparent var(--indent-small-start),
@ -1050,7 +1052,8 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
position: absolute;
inset: 0;
pointer-events: none;
background-image: radial-gradient(
background-image:
radial-gradient(
ellipse 50% 32px at bottom center,
var(--carousel-faded-color),
transparent
@ -1736,6 +1739,18 @@ body:has(.media-modal-container + .status-deck) .media-post-link {
}
}
.menu-post-text {
max-width: 250px;
overflow: hidden;
/* ellipsis 2 lines */
white-space: normal;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
text-overflow: ellipsis;
}
/* SHEET */
.sheet {
@ -2311,7 +2326,8 @@ body > .szh-menu-container {
var(--bg-color) var(--middle-circle-radius),
transparent var(--middle-circle-radius)
);
background-image: var(--middle-circle),
background-image:
var(--middle-circle),
conic-gradient(var(--color) var(--fill), var(--outline-color) 0);
transform: scale(0.7);
&:dir(rtl) {

View file

@ -1,24 +1,52 @@
import { Trans, useLingui } from '@lingui/react/macro';
import { ControlledMenu } from '@szhsin/react-menu';
import { useRef, useState } from 'preact/hooks';
import { ControlledMenu, MenuDivider, MenuItem } from '@szhsin/react-menu';
import { useCallback, useRef, useState } from 'preact/hooks';
import { useHotkeys } from 'react-hotkeys-hook';
import { useLongPress } from 'use-long-press';
import { useSnapshot } from 'valtio';
import { api } from '../utils/api';
import niceDateTime from '../utils/nice-date-time';
import openCompose from '../utils/open-compose';
import openOSK from '../utils/open-osk';
import pmem from '../utils/pmem';
import safeBoundingBoxPadding from '../utils/safe-bounding-box-padding';
import showCompose from '../utils/show-compose';
import states from '../utils/states';
import statusPeek from '../utils/status-peek';
import { getCurrentAccountID } from '../utils/store-utils';
import Icon from './icon';
import MenuLink from './menu-link';
import RelativeTime from './relative-time';
import SubMenu2 from './submenu2';
// Function to fetch the latest posts from the current user
// Use pmem to memoize fetch results for 1 minute
const fetchLatestPostsMemoized = pmem(
async (masto, currentAccountID) => {
const statusesIterator = masto.v1.accounts
.$select(currentAccountID)
.statuses.list({
limit: 3,
exclude_replies: true,
exclude_reblogs: true,
});
const { value } = await statusesIterator.next();
return value || [];
},
{ maxAge: 60000 },
); // 1 minute cache
export default function ComposeButton() {
const { t } = useLingui();
const snapStates = useSnapshot(states);
const { masto } = api();
// Context menu state
const [menuOpen, setMenuOpen] = useState(false);
const [latestPosts, setLatestPosts] = useState([]);
const [loadingPosts, setLoadingPosts] = useState(false);
const buttonRef = useRef(null);
const menuRef = useRef(null);
@ -58,6 +86,29 @@ export default function ComposeButton() {
},
);
const fetchLatestPosts = useCallback(async () => {
try {
setLoadingPosts(true);
const currentAccountID = getCurrentAccountID();
if (!currentAccountID) {
return;
}
const posts = await fetchLatestPostsMemoized(masto, currentAccountID);
setLatestPosts(posts);
} catch (error) {
} finally {
setLoadingPosts(false);
}
}, [masto]);
// Function to handle opening the compose window to reply to a post
const handleReplyToPost = useCallback((post) => {
showCompose({
replyToStatus: post,
});
setMenuOpen(false);
}, []);
return (
<>
<button
@ -100,6 +151,67 @@ export default function ComposeButton() {
<Trans>Scheduled Posts</Trans>
</span>
</MenuLink>
<MenuDivider />
<SubMenu2
label={
<>
<Icon icon="comment" size="l" />{' '}
<span className="menu-grow">
<Trans>Add to thread</Trans>
</span>
<Icon icon="chevron-right" />
</>
}
onMenuChange={(e) => {
if (e.open) {
fetchLatestPosts();
}
}}
>
{loadingPosts ? (
<MenuItem disabled>
<span>
<Trans>Loading</Trans>
</span>
</MenuItem>
) : latestPosts.length === 0 ? (
<MenuItem disabled>
<small>
<Trans>No posts found</Trans>
</small>
</MenuItem>
) : (
latestPosts.map((post) => {
const createdDate = new Date(post.createdAt);
const isWithinDay =
new Date().getTime() - createdDate.getTime() < 86400000;
return (
<MenuItem key={post.id} onClick={() => handleReplyToPost(post)}>
<small>
<div class="menu-post-text">{statusPeek(post)}</div>
<span className="more-insignificant">
{/* Show relative time if within a day */}
{isWithinDay && (
<>
<RelativeTime datetime={createdDate} format="micro" />{' '}
{' '}
</>
)}
<time
className="created"
dateTime={createdDate.toISOString()}
title={createdDate.toLocaleString()}
>
{niceDateTime(post.createdAt)}
</time>
</span>
</small>
</MenuItem>
);
})
)}
</SubMenu2>
</ControlledMenu>
</>
);

23
src/locales/en.po generated
View file

@ -565,18 +565,32 @@ msgstr ""
msgid "Home"
msgstr ""
#: src/components/compose-button.jsx:77
#: src/components/compose-button.jsx:128
#: src/compose.jsx:38
msgid "Compose"
msgstr ""
#: src/components/compose-button.jsx:100
#: src/components/compose-button.jsx:151
#: src/components/nav-menu.jsx:260
#: src/pages/scheduled-posts.jsx:31
#: src/pages/scheduled-posts.jsx:76
msgid "Scheduled Posts"
msgstr "Scheduled Posts"
#: src/components/compose-button.jsx:160
msgid "Add to thread"
msgstr "Add to thread"
#: src/components/compose-button.jsx:174
#: src/components/status.jsx:3034
#: src/pages/annual-report.jsx:45
msgid "Loading…"
msgstr ""
#: src/components/compose-button.jsx:180
msgid "No posts found"
msgstr "No posts found"
#: src/components/compose.jsx:211
msgid "Add media"
msgstr "Add media"
@ -2392,11 +2406,6 @@ msgstr ""
msgid "Failed to load history"
msgstr ""
#: src/components/status.jsx:3034
#: src/pages/annual-report.jsx:45
msgid "Loading…"
msgstr ""
#: src/components/status.jsx:3270
msgid "HTML Code"
msgstr ""