|
|
|
|
@ -22,7 +22,7 @@ const MemoHeader: React.FC<MemoHeaderProps> = ({ showCreator, showVisibility, sh
|
|
|
|
|
const [reactionSelectorOpen, setReactionSelectorOpen] = useState(false);
|
|
|
|
|
|
|
|
|
|
const { memo, creator, currentUser, parentPage, isArchived, readonly, openEditor } = useMemoViewContext();
|
|
|
|
|
const { displayTime: memoDisplayTime, relativeTimeFormat } = useMemoViewDerived();
|
|
|
|
|
const { createTime, updateTime, displayTime: memoDisplayTime, isDisplayingUpdatedTime, relativeTimeFormat } = useMemoViewDerived();
|
|
|
|
|
|
|
|
|
|
const navigateTo = useNavigateTo();
|
|
|
|
|
const handleGotoMemoDetailPage = useCallback(() => {
|
|
|
|
|
@ -31,19 +31,30 @@ const MemoHeader: React.FC<MemoHeaderProps> = ({ showCreator, showVisibility, sh
|
|
|
|
|
|
|
|
|
|
const { unpinMemo } = useMemoActions(memo);
|
|
|
|
|
|
|
|
|
|
const displayTime = isArchived ? (
|
|
|
|
|
const timeValue = isArchived ? (
|
|
|
|
|
memoDisplayTime?.toLocaleString(i18n.language)
|
|
|
|
|
) : (
|
|
|
|
|
<relative-time datetime={memoDisplayTime?.toISOString()} lang={i18n.language} format={relativeTimeFormat}></relative-time>
|
|
|
|
|
<relative-time datetime={memoDisplayTime?.toISOString()} lang={i18n.language} format={relativeTimeFormat} no-title=""></relative-time>
|
|
|
|
|
);
|
|
|
|
|
const displayTime = isDisplayingUpdatedTime ? (
|
|
|
|
|
<>
|
|
|
|
|
{t("common.last-updated-at")} {timeValue}
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
timeValue
|
|
|
|
|
);
|
|
|
|
|
const timeTooltip = {
|
|
|
|
|
createdAt: createTime ? `${t("common.created-at")}: ${createTime.toLocaleString(i18n.language)}` : undefined,
|
|
|
|
|
updatedAt: updateTime ? `${t("common.last-updated-at")}: ${updateTime.toLocaleString(i18n.language)}` : undefined,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="w-full flex flex-row justify-between items-center gap-2">
|
|
|
|
|
<div className="w-auto max-w-[calc(100%-8rem)] grow flex flex-row justify-start items-center">
|
|
|
|
|
{showCreator && creator ? (
|
|
|
|
|
<CreatorDisplay creator={creator} displayTime={displayTime} onGotoDetail={handleGotoMemoDetailPage} />
|
|
|
|
|
<CreatorDisplay creator={creator} displayTime={displayTime} timeTooltip={timeTooltip} onGotoDetail={handleGotoMemoDetailPage} />
|
|
|
|
|
) : (
|
|
|
|
|
<TimeDisplay displayTime={displayTime} onGotoDetail={handleGotoMemoDetailPage} />
|
|
|
|
|
<TimeDisplay displayTime={displayTime} timeTooltip={timeTooltip} onGotoDetail={handleGotoMemoDetailPage} />
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
@ -93,10 +104,11 @@ const MemoHeader: React.FC<MemoHeaderProps> = ({ showCreator, showVisibility, sh
|
|
|
|
|
interface CreatorDisplayProps {
|
|
|
|
|
creator: User;
|
|
|
|
|
displayTime: React.ReactNode;
|
|
|
|
|
timeTooltip: TimeTooltipContent;
|
|
|
|
|
onGotoDetail: () => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const CreatorDisplay: React.FC<CreatorDisplayProps> = ({ creator, displayTime, onGotoDetail }) => (
|
|
|
|
|
const CreatorDisplay: React.FC<CreatorDisplayProps> = ({ creator, displayTime, timeTooltip, onGotoDetail }) => (
|
|
|
|
|
<div className="w-full flex flex-row justify-start items-center">
|
|
|
|
|
<Link className="w-auto hover:opacity-80 rounded-md transition-colors" to={`/u/${encodeURIComponent(creator.username)}`} viewTransition>
|
|
|
|
|
<UserAvatar className="mr-2 shrink-0" avatarUrl={creator.avatarUrl} />
|
|
|
|
|
@ -109,30 +121,50 @@ const CreatorDisplay: React.FC<CreatorDisplayProps> = ({ creator, displayTime, o
|
|
|
|
|
>
|
|
|
|
|
{creator.displayName || creator.username}
|
|
|
|
|
</Link>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="w-auto -mt-0.5 text-xs leading-tight text-muted-foreground select-none cursor-pointer hover:opacity-80 transition-colors text-left"
|
|
|
|
|
onClick={onGotoDetail}
|
|
|
|
|
>
|
|
|
|
|
{displayTime}
|
|
|
|
|
</button>
|
|
|
|
|
<TimeTooltip content={timeTooltip}>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="w-auto -mt-0.5 text-xs leading-tight text-muted-foreground select-none cursor-pointer hover:opacity-80 transition-colors text-left"
|
|
|
|
|
onClick={onGotoDetail}
|
|
|
|
|
>
|
|
|
|
|
{displayTime}
|
|
|
|
|
</button>
|
|
|
|
|
</TimeTooltip>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
interface TimeTooltipContent {
|
|
|
|
|
createdAt?: string;
|
|
|
|
|
updatedAt?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const TimeTooltip = ({ children, content }: { children: React.ReactElement; content: TimeTooltipContent }) => (
|
|
|
|
|
<Tooltip>
|
|
|
|
|
<TooltipTrigger asChild>{children}</TooltipTrigger>
|
|
|
|
|
<TooltipContent align="start" className="flex flex-col items-start gap-0.5 whitespace-nowrap text-left">
|
|
|
|
|
{content.createdAt && <span>{content.createdAt}</span>}
|
|
|
|
|
{content.updatedAt && <span>{content.updatedAt}</span>}
|
|
|
|
|
</TooltipContent>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
interface TimeDisplayProps {
|
|
|
|
|
displayTime: React.ReactNode;
|
|
|
|
|
timeTooltip: TimeTooltipContent;
|
|
|
|
|
onGotoDetail: () => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const TimeDisplay: React.FC<TimeDisplayProps> = ({ displayTime, onGotoDetail }) => (
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="w-full text-sm leading-tight text-muted-foreground select-none cursor-pointer hover:text-foreground transition-colors text-left"
|
|
|
|
|
onClick={onGotoDetail}
|
|
|
|
|
>
|
|
|
|
|
{displayTime}
|
|
|
|
|
</button>
|
|
|
|
|
const TimeDisplay: React.FC<TimeDisplayProps> = ({ displayTime, timeTooltip, onGotoDetail }) => (
|
|
|
|
|
<TimeTooltip content={timeTooltip}>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="w-auto text-sm leading-tight text-muted-foreground select-none cursor-pointer hover:text-foreground transition-colors text-left"
|
|
|
|
|
onClick={onGotoDetail}
|
|
|
|
|
>
|
|
|
|
|
{displayTime}
|
|
|
|
|
</button>
|
|
|
|
|
</TimeTooltip>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
export default MemoHeader;
|
|
|
|
|
|