Skip to content

Commit

Permalink
feat: show more on reply content
Browse files Browse the repository at this point in the history
  • Loading branch information
dudu0506 committed Jan 10, 2025
1 parent 69ac6df commit a726773
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 45 deletions.
5 changes: 3 additions & 2 deletions src/components/Compose/DraftList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ const DraftListItem = memo<DraftListItemProps>(function DraftListItem({ draft, h
export const DraftList = memo(function DraftList() {
const currentProfileAll = useCurrentProfileAll();
const { drafts, removeDraft } = useComposeDraftStateStore();
const { updateChars, apply, currentDraftId, clear } = useComposeStateStore();
const { updateChars, apply, focused, currentDraftId, clear } = useComposeStateStore();
const { updateScheduleTime } = useComposeScheduleStateStore();
const setEditorContent = useSetEditorContent();

Expand Down Expand Up @@ -191,6 +191,7 @@ export const DraftList = memo(function DraftList() {
);
apply({
...draft,
focused,
posts: draft.posts.map((x) => ({
...x,
...(full
Expand All @@ -211,7 +212,7 @@ export const DraftList = memo(function DraftList() {
if (draft.scheduleTime) updateScheduleTime(draft.scheduleTime);
router.history.push('/');
},
[apply, router, setEditorContent, updateChars, updateScheduleTime, currentProfileAll],
[apply, router, setEditorContent, updateChars, updateScheduleTime, currentProfileAll, focused],
);

if (!drafts.length) {
Expand Down
4 changes: 3 additions & 1 deletion src/components/Compose/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ interface EditorProps {
}

export const Editor = memo(function Editor({ post, replying }: EditorProps) {
const { type, posts, updateChars, loadComponentsFromChars } = useComposeStateStore();
const { type, posts, updateChars, updateFocused, loadComponentsFromChars } = useComposeStateStore();
const [, startTransition] = useTransition();

const { chars } = post;
Expand Down Expand Up @@ -103,6 +103,8 @@ export const Editor = memo(function Editor({ post, replying }: EditorProps) {
contentEditable={
<ContentEditable
key="editable"
onFocus={() => updateFocused(true)}
onBlur={() => updateFocused(false)}
className="flex-1 flex-shrink-0 cursor-text resize-none appearance-none border-none bg-transparent p-0 pb-2 text-left text-[16px] leading-6 text-main outline-none outline-0 focus:ring-0"
/>
}
Expand Down
46 changes: 4 additions & 42 deletions src/components/Posts/PostBodyContent.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
'use client';

import { t } from '@lingui/core/macro';
import { Select, Trans } from '@lingui/react/macro';
import { Trans } from '@lingui/react/macro';
import { useForkRef } from '@mui/material';
import { compact } from 'lodash-es';
import { usePathname, useRouter } from 'next/navigation.js';
import { forwardRef, type HTMLProps, useMemo, useState } from 'react';
import { forwardRef, useMemo, useState } from 'react';
import { useAsync } from 'react-use';

import { TwitterArticleBody } from '@/components/Article/TwitterArticleBody.js';
Expand All @@ -17,18 +16,17 @@ import { PollCard } from '@/components/Poll/PollCard.js';
import { Attachments } from '@/components/Posts/Attachment.js';
import { CollapsedContent } from '@/components/Posts/CollapsedContent.js';
import { ContentTranslator } from '@/components/Posts/ContentTranslator.js';
import { PostBodyReplyContent } from '@/components/Posts/PostBodyReplyContent.js';
import { PostLinks } from '@/components/Posts/PostLinks.js';
import { Quote } from '@/components/Posts/Quote.js';
import { RedPacketInspector } from '@/components/RedPacket/RedPacketInspector.js';
import { IS_APPLE, IS_SAFARI } from '@/constants/bowser.js';
import { PageRoute, Source } from '@/constants/enum.js';
import { EMPTY_LIST, RP_HASH_TAG } from '@/constants/index.js';
import { classNames } from '@/helpers/classNames.js';
import { formatUrl } from '@/helpers/formatUrl.js';
import { getEncryptedPayloadFromImageAttachment, getEncryptedPayloadFromText } from '@/helpers/getEncryptedPayload.js';
import { getPostUrl } from '@/helpers/getPostUrl.js';
import { isRoutePathname } from '@/helpers/isRoutePathname.js';
import { isValidUrl } from '@/helpers/isValidUrl.js';
import { resolveOembedUrl } from '@/helpers/resolveOembedUrl.js';
import { resolvePostArticleUrl } from '@/helpers/resolvePostArticleUrl.js';
import { trimify } from '@/helpers/trimify.js';
Expand All @@ -50,12 +48,6 @@ export interface PostBodyContentProps {
showTranslate?: boolean;
}

const overrideComponents = {
a: function Anchor({ title }: HTMLProps<HTMLAnchorElement>) {
return <span>{title && isValidUrl(title) ? formatUrl(title, 30) : title}</span>;
},
};

function canSkipWaitingForPayload(post: Post) {
const content = post.metadata.content?.content;

Expand Down Expand Up @@ -181,37 +173,7 @@ export const PostBodyContent = forwardRef<HTMLDivElement, PostBodyContentProps>(
);
}

if (isReply) {
return (
<div>
<NakedMarkup
post={post}
className={classNames(
'single-post line-clamp-3 w-full self-stretch break-words text-base text-main',
{
'max-h-[7.8rem]': IS_SAFARI && IS_APPLE,
},
)}
components={overrideComponents}
>
{liteRawContent}
</NakedMarkup>
<div className="flex flex-col text-base text-main">
{post.metadata.content?.asset?.type ? (
<Select
value={post.metadata.content.asset.type}
_Image="[Image]"
_Video="[Video]"
_Audio="[Audio]"
_Poll="[Poll]"
other=""
/>
) : null}
{post.quoteOn ? <span>{t`[Quote]`}</span> : null}
</div>
</div>
);
}
if (isReply) return <PostBodyReplyContent post={post} />;

return (
<article
Expand Down
74 changes: 74 additions & 0 deletions src/components/Posts/PostBodyReplyContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { t } from '@lingui/core/macro';
import { Select, Trans } from '@lingui/react/macro';
import { type HTMLProps, memo, useCallback, useEffect, useState } from 'react';

import { ClickableButton } from '@/components/ClickableButton.js';
import { NakedMarkup } from '@/components/Markup/NakedMarkup.js';
import { IS_APPLE, IS_SAFARI } from '@/constants/bowser.js';
import { classNames } from '@/helpers/classNames.js';
import { formatUrl } from '@/helpers/formatUrl.js';
import { isValidUrl } from '@/helpers/isValidUrl.js';
import { useDetectOverflow } from '@/hooks/useDetectOverflow.js';
import type { Post } from '@/providers/types/SocialMedia.js';
import { useComposeStateStore } from '@/store/useComposeStore.js';

interface PostBodyReplyContentProps {
post: Post;
}

const overrideComponents = {
a: function Anchor({ title }: HTMLProps<HTMLAnchorElement>) {
return <span>{title && isValidUrl(title) ? formatUrl(title, 30) : title}</span>;
},
};

export const PostBodyReplyContent = memo<PostBodyReplyContentProps>(function PostBodyReplyContent({ post }) {
const liteRawContent = post.metadata.content?.content;
const [overflow, ref] = useDetectOverflow<HTMLDivElement>();
const [multiple, setMultiple] = useState(1);
const { focused } = useComposeStateStore();

const toggleShowMore = useCallback(() => {
setMultiple((prev) => (overflow ? prev + 1 : Math.max(1, prev - 1)));
}, [overflow]);

useEffect(() => {
if (focused) {
setMultiple(1);
}
}, [focused]);

return (
<div>
<div
ref={ref}
className={classNames('single-post line-clamp-3 w-full self-stretch break-words text-base text-main', {
'max-h-[7.8rem]': IS_SAFARI && IS_APPLE,
})}
style={{ WebkitLineClamp: multiple * 3 }}
>
<NakedMarkup post={post} components={overrideComponents}>
{liteRawContent}
</NakedMarkup>
</div>
<div className="flex flex-col text-base text-main">
{overflow || multiple > 1 ? (
<ClickableButton className="inline-flex text-highlight" onClick={toggleShowMore}>
{overflow ? <Trans>Show more</Trans> : <Trans>Show less</Trans>}
</ClickableButton>
) : null}
{post.metadata.content?.asset?.type ? (
<Select
value={post.metadata.content.asset.type}
_Image="[Image]"
_Video="[Video]"
_Audio="[Audio]"
_Poll="[Poll]"
other=""
/>
) : null}
{post.quoteOn ? <span>{t`[Quote]`}</span> : null}
</div>
</div>
);
});
11 changes: 11 additions & 0 deletions src/store/useComposeStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ export interface ComposeBaseState {
cursor: Cursor;
// tracking the current applied draft id
currentDraftId?: string;

// editor focus state
focused: boolean;
}

interface ComposeState extends ComposeBaseState {
Expand Down Expand Up @@ -134,6 +137,8 @@ interface ComposeState extends ComposeBaseState {
// reset the editor
apply: (state: ComposeBaseState) => void;
clear: () => void;

updateFocused: (focused: boolean) => void;
}

export function createInitPostState(): Record<SocialSource, null> {
Expand Down Expand Up @@ -183,6 +188,7 @@ const useComposeStateBase = create<ComposeState, [['zustand/immer', unknown]]>(
immer((set, get) => ({
type: 'compose',
cursor: initialPostCursor,
focused: false,
posts: [createInitSinglePostState(initialPostCursor)],
computed: {
get nextAvailablePost() {
Expand Down Expand Up @@ -623,11 +629,16 @@ const useComposeStateBase = create<ComposeState, [['zustand/immer', unknown]]>(
type: state.type,
cursor: id,
currentDraftId: undefined,
focused: false,
posts: [createInitSinglePostState(id)],
} satisfies ComposeBaseState;

Object.assign(state, nextState);
}),
updateFocused: (focused) =>
set((state) => {
state.focused = focused;
}),
})),
);

Expand Down

0 comments on commit a726773

Please sign in to comment.