tutu/src/timelines/TootThread.tsx

103 lines
2.7 KiB
TypeScript
Raw Normal View History

2024-07-14 12:28:44 +00:00
import type { mastodon } from "masto";
import { Show, createResource, createSignal, type Component, type Ref } from "solid-js";
2024-07-14 12:28:44 +00:00
import CompactToot from "./CompactToot";
import { useTimeSource } from "../platform/timesrc";
import RegularToot from "./RegularToot";
import cardStyle from "../material/cards.module.css";
import { css } from "solid-styled";
type TootThreadProps = {
ref?: Ref<HTMLElement>,
2024-07-14 12:28:44 +00:00
status: mastodon.v1.Status;
client: mastodon.rest.Client;
expanded?: 0 | 1 | 2;
onBoost?(client: mastodon.rest.Client, status: mastodon.v1.Status): void;
onBookmark?(client: mastodon.rest.Client, status: mastodon.v1.Status): void;
2024-09-28 07:29:21 +00:00
onReply?(client: mastodon.rest.Client, status: mastodon.v1.Status): void
onExpandChange?(level: 0 | 1 | 2): void;
2024-07-14 12:28:44 +00:00
};
const TootThread: Component<TootThreadProps> = (props) => {
const status = () => props.status;
const now = useTimeSource();
const expanded = () => props.expanded ?? 0;
2024-07-14 12:28:44 +00:00
const [inReplyTo] = createResource(
() => [props.client, status().inReplyToId || null] as const,
async ([client, replyToId]) => {
if (!(client && replyToId)) return null;
return await client.v1.statuses.$select(replyToId).fetch();
},
);
const boost = (status: mastodon.v1.Status) => {
props.onBoost?.(props.client, status);
};
const bookmark = (status: mastodon.v1.Status) => {
props.onBookmark?.(props.client, status);
};
2024-09-28 07:29:21 +00:00
const reply = (status: mastodon.v1.Status) => {
props.onReply?.(props.client, status)
}
2024-07-14 12:28:44 +00:00
css`
article {
2024-08-05 07:33:00 +00:00
transition:
margin 90ms var(--tutu-anim-curve-sharp),
var(--tutu-transition-shadow);
2024-07-14 12:28:44 +00:00
user-select: none;
cursor: pointer;
}
.thread-line {
position: relative;
&::before {
content: "";
position: absolute;
left: 36px;
top: 16px;
bottom: 0;
background-color: var(--tutu-color-secondary);
width: 2px;
display: block;
}
}
.expanded {
margin-block: 20px;
box-shadow: var(--tutu-shadow-e9);
}
`;
const nextExpandLevel = [1, 2, 2] as const;
2024-07-14 12:28:44 +00:00
return (
2024-08-05 07:33:00 +00:00
<article
ref={props.ref}
classList={{ "thread-line": !!inReplyTo(), expanded: expanded() > 0 }}
onClick={() => props.onExpandChange?.(nextExpandLevel[expanded()])}
2024-08-05 07:33:00 +00:00
>
2024-07-14 12:28:44 +00:00
<Show when={inReplyTo()}>
<CompactToot
status={inReplyTo()!}
now={now()}
class={[cardStyle.card, cardStyle.manualMargin].join(" ")}
/>
</Show>
<RegularToot
status={status()}
class={cardStyle.card}
actionable={expanded() > 0}
2024-07-14 12:28:44 +00:00
onBookmark={(s) => bookmark(s)}
onRetoot={(s) => boost(s)}
2024-09-28 07:29:21 +00:00
onReply={s => reply(s)}
2024-07-14 12:28:44 +00:00
/>
</article>
);
};
export default TootThread;