diff --git a/src/app.css b/src/app.css index bb7adb62..e145aa5b 100644 --- a/src/app.css +++ b/src/app.css @@ -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) { diff --git a/src/components/compose-button.jsx b/src/components/compose-button.jsx index 914af31d..583f0742 100644 --- a/src/components/compose-button.jsx +++ b/src/components/compose-button.jsx @@ -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 ( <>