mirror of
https://github.com/cheeaun/phanpy.git
synced 2025-01-23 17:16:26 +01:00
Experimental reply parent hint
This commit is contained in:
parent
14f5c37721
commit
f3d77dd04e
7 changed files with 847 additions and 700 deletions
|
@ -330,6 +330,62 @@
|
|||
font-size: 90%;
|
||||
}
|
||||
|
||||
.status.compact-reply {
|
||||
--avatar-size: 20px;
|
||||
--line-start: 40px;
|
||||
--line-width: 3px;
|
||||
--line-end: calc(var(--line-start) + var(--line-width));
|
||||
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
--top-padding: 8px;
|
||||
padding-top: var(--top-padding);
|
||||
padding-bottom: 0;
|
||||
background-image: linear-gradient(
|
||||
160deg,
|
||||
var(--reply-to-faded-color),
|
||||
transparent
|
||||
);
|
||||
|
||||
> * {
|
||||
opacity: 0.65;
|
||||
transition: opacity 1s ease-out;
|
||||
}
|
||||
.status-link:hover & > * {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: calc(var(--top-padding) + var(--avatar-size));
|
||||
left: var(--line-start);
|
||||
width: var(--line-width);
|
||||
height: calc(100% - var(--top-padding) - var(--avatar-size) + 16px);
|
||||
background-color: var(--comment-line-color);
|
||||
z-index: 0;
|
||||
mask-image: linear-gradient(to bottom, #000 8px, transparent);
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin-left: calc((50px - var(--avatar-size)) / 2);
|
||||
justify-self: center;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.content-compact {
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
display: box;
|
||||
-webkit-box-orient: vertical;
|
||||
box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
font-size: 90%;
|
||||
line-height: var(--avatar-size);
|
||||
}
|
||||
}
|
||||
|
||||
.status .container {
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
|
|
|
@ -126,6 +126,7 @@ function Status({
|
|||
showFollowedTags,
|
||||
allowContextMenu,
|
||||
showActionsBar,
|
||||
showReplyParent,
|
||||
}) {
|
||||
if (skeleton) {
|
||||
return (
|
||||
|
@ -1271,6 +1272,10 @@ function Status({
|
|||
]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{showReplyParent && !!(inReplyToId && inReplyToAccount) && (
|
||||
<StatusCompact sKey={sKey} />
|
||||
)}
|
||||
<article
|
||||
data-state-post-id={sKey}
|
||||
ref={(node) => {
|
||||
|
@ -1670,7 +1675,11 @@ function Status({
|
|||
</>
|
||||
)}
|
||||
{!!content && (
|
||||
<div class="content" ref={contentRef} data-read-more={readMoreText}>
|
||||
<div
|
||||
class="content"
|
||||
ref={contentRef}
|
||||
data-read-more={readMoreText}
|
||||
>
|
||||
<div
|
||||
lang={language}
|
||||
dir="auto"
|
||||
|
@ -1814,7 +1823,9 @@ function Status({
|
|||
showCaption={mediaAttachments.length === 1}
|
||||
lang={language}
|
||||
altIndex={
|
||||
showMultipleMediaCaptions && !!media.description && i + 1
|
||||
showMultipleMediaCaptions &&
|
||||
!!media.description &&
|
||||
i + 1
|
||||
}
|
||||
to={`/${instance}/s/${id}?${
|
||||
withinContext ? 'media' : 'media-only'
|
||||
|
@ -1920,7 +1931,9 @@ function Status({
|
|||
confirmLabel={
|
||||
<>
|
||||
<Icon icon="rocket" />
|
||||
<span>{reblogged ? 'Unboost?' : 'Boost to everyone?'}</span>
|
||||
<span>
|
||||
{reblogged ? 'Unboost?' : 'Boost to everyone?'}
|
||||
</span>
|
||||
</>
|
||||
}
|
||||
menuFooter={
|
||||
|
@ -2018,6 +2031,7 @@ function Status({
|
|||
</Modal>
|
||||
)}
|
||||
</article>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2412,6 +2426,41 @@ function nicePostURL(url) {
|
|||
);
|
||||
}
|
||||
|
||||
function StatusCompact({ sKey }) {
|
||||
const snapStates = useSnapshot(states);
|
||||
const statusReply = snapStates.statusReply[sKey];
|
||||
if (!statusReply) return null;
|
||||
|
||||
const { id, instance } = statusReply;
|
||||
const status = getStatus(id, instance);
|
||||
if (!status) return null;
|
||||
|
||||
const {
|
||||
sensitive,
|
||||
spoilerText,
|
||||
account: { avatar, avatarStatic, bot },
|
||||
visibility,
|
||||
content,
|
||||
} = status;
|
||||
if (sensitive || spoilerText) return null;
|
||||
if (!content) return null;
|
||||
|
||||
const statusPeekText = statusPeek(status);
|
||||
return (
|
||||
<article
|
||||
class={`status compact-reply ${
|
||||
visibility === 'direct' ? 'visibility-direct' : ''
|
||||
}`}
|
||||
tabindex="-1"
|
||||
>
|
||||
<Avatar url={avatarStatic || avatar} squircle={bot} />
|
||||
<div class="content-compact" title={statusPeekText}>
|
||||
{statusPeekText}
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
function FilteredStatus({
|
||||
status,
|
||||
filterInfo,
|
||||
|
|
|
@ -46,6 +46,7 @@ function Timeline({
|
|||
view,
|
||||
filterContext,
|
||||
showFollowedTags,
|
||||
showReplyParent,
|
||||
}) {
|
||||
const snapStates = useSnapshot(states);
|
||||
const [items, setItems] = useState([]);
|
||||
|
@ -84,7 +85,7 @@ function Timeline({
|
|||
if (boostsCarousel) {
|
||||
value = groupBoosts(value);
|
||||
}
|
||||
value = groupContext(value);
|
||||
value = groupContext(value, instance);
|
||||
}
|
||||
if (pinnedPosts.length) {
|
||||
value = pinnedPosts.concat(value);
|
||||
|
@ -522,6 +523,7 @@ function TimelineItem({
|
|||
filterContext,
|
||||
view,
|
||||
showFollowedTags,
|
||||
showReplyParent,
|
||||
}) {
|
||||
const { id: statusID, reblog, items, type, _pinned } = status;
|
||||
if (_pinned) useItemID = false;
|
||||
|
@ -680,6 +682,7 @@ function TimelineItem({
|
|||
instance={instance}
|
||||
enableCommentHint
|
||||
showFollowedTags={showFollowedTags}
|
||||
showReplyParent
|
||||
// allowFilters={allowFilters}
|
||||
/>
|
||||
) : (
|
||||
|
@ -688,6 +691,7 @@ function TimelineItem({
|
|||
instance={instance}
|
||||
enableCommentHint
|
||||
showFollowedTags={showFollowedTags}
|
||||
showReplyParent
|
||||
// allowFilters={allowFilters}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -129,6 +129,7 @@ function Following({ title, path, id, ...props }) {
|
|||
// allowFilters
|
||||
filterContext="home"
|
||||
showFollowedTags
|
||||
showReplyParent
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ function List(props) {
|
|||
boostsCarousel={snapStates.settings.boostsCarousel}
|
||||
// allowFilters
|
||||
filterContext="home"
|
||||
showReplyParent
|
||||
// refresh={reloadCount}
|
||||
headerStart={
|
||||
<Link to="/l" class="button plain">
|
||||
|
|
|
@ -37,6 +37,7 @@ const states = proxy({
|
|||
unfurledLinks: {},
|
||||
statusQuotes: {},
|
||||
statusFollowedTags: {},
|
||||
statusReply: {},
|
||||
accounts: {},
|
||||
routeNotification: null,
|
||||
// Modals
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { api } from './api';
|
||||
import { extractTagsFromStatus, getFollowedTags } from './followed-tags';
|
||||
import pmem from './pmem';
|
||||
import { fetchRelationships } from './relationships';
|
||||
import states, { statusKey } from './states';
|
||||
import states, { saveStatus, statusKey } from './states';
|
||||
import store from './store';
|
||||
|
||||
export function groupBoosts(values) {
|
||||
|
@ -81,7 +83,7 @@ export function dedupeBoosts(items, instance) {
|
|||
return filteredItems;
|
||||
}
|
||||
|
||||
export function groupContext(items) {
|
||||
export function groupContext(items, instance) {
|
||||
const contexts = [];
|
||||
let contextIndex = 0;
|
||||
items.forEach((item) => {
|
||||
|
@ -173,12 +175,45 @@ export function groupContext(items) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.inReplyToId && item.inReplyToAccountId !== item.account.id) {
|
||||
const sKey = statusKey(item.id, instance);
|
||||
if (states.statusReply[sKey]) {
|
||||
return;
|
||||
}
|
||||
// If it's a reply and not a thread
|
||||
queueMicrotask(async () => {
|
||||
try {
|
||||
const { masto } = api({ instance });
|
||||
// const replyToStatus = await masto.v1.statuses
|
||||
// .$select(item.inReplyToId)
|
||||
// .fetch();
|
||||
const replyToStatus = await fetchStatus(item.inReplyToId, masto);
|
||||
saveStatus(replyToStatus, instance, {
|
||||
skipThreading: true,
|
||||
skipUnfurling: true,
|
||||
});
|
||||
states.statusReply[sKey] = {
|
||||
id: replyToStatus.id,
|
||||
instance,
|
||||
};
|
||||
} catch (e) {
|
||||
// Silently fail
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
newItems.push(item);
|
||||
});
|
||||
|
||||
return newItems;
|
||||
}
|
||||
|
||||
const fetchStatus = pmem((statusID, masto) => {
|
||||
return masto.v1.statuses.$select(statusID).fetch();
|
||||
});
|
||||
|
||||
export async function assignFollowedTags(items, instance) {
|
||||
const followedTags = await getFollowedTags(); // [{name: 'tag'}, {...}]
|
||||
if (!followedTags.length) return;
|
||||
|
|
Loading…
Reference in a new issue