Thread: removed
This commit is contained in:
parent
5afaf21f4b
commit
17e738e21a
3 changed files with 56 additions and 118 deletions
|
@ -1,90 +0,0 @@
|
||||||
import type { mastodon } from "masto";
|
|
||||||
import { Index, type Component, type Ref } from "solid-js";
|
|
||||||
import RegularToot, { findRootToot } from "./RegularToot";
|
|
||||||
import cardStyle from "../material/cards.module.css";
|
|
||||||
import { css } from "solid-styled";
|
|
||||||
|
|
||||||
type TootActionTarget = {
|
|
||||||
client: mastodon.rest.Client;
|
|
||||||
status: mastodon.v1.Status;
|
|
||||||
};
|
|
||||||
|
|
||||||
type TootActions = {
|
|
||||||
onBoost(client: mastodon.rest.Client, status: mastodon.v1.Status): void;
|
|
||||||
onBookmark(client: mastodon.rest.Client, status: mastodon.v1.Status): void;
|
|
||||||
onReply(target: TootActionTarget, element: HTMLElement): void;
|
|
||||||
onFavourite(status: mastodon.v1.Status): void
|
|
||||||
};
|
|
||||||
|
|
||||||
type ThreadProps = {
|
|
||||||
ref?: Ref<HTMLElement>;
|
|
||||||
client: mastodon.rest.Client;
|
|
||||||
toots: readonly mastodon.v1.Status[];
|
|
||||||
isExpended: (status: mastodon.v1.Status) => boolean;
|
|
||||||
|
|
||||||
onItemClick(status: mastodon.v1.Status, event: MouseEvent): void;
|
|
||||||
} & TootActions;
|
|
||||||
|
|
||||||
const Thread: Component<ThreadProps> = (props) => {
|
|
||||||
const boost = (status: mastodon.v1.Status) => {
|
|
||||||
props.onBoost(props.client, status);
|
|
||||||
};
|
|
||||||
|
|
||||||
const bookmark = (status: mastodon.v1.Status) => {
|
|
||||||
props.onBookmark(props.client, status);
|
|
||||||
};
|
|
||||||
|
|
||||||
const reply = (
|
|
||||||
status: mastodon.v1.Status,
|
|
||||||
event: MouseEvent & { currentTarget: HTMLElement },
|
|
||||||
) => {
|
|
||||||
const element = findRootToot(event.currentTarget);
|
|
||||||
props.onReply({ client: props.client, status }, element);
|
|
||||||
};
|
|
||||||
|
|
||||||
const threading = () => props.toots.length > 1;
|
|
||||||
|
|
||||||
const posThread = (index: number) => {
|
|
||||||
if (!threading()) return;
|
|
||||||
|
|
||||||
if (index === 0) {
|
|
||||||
return "top";
|
|
||||||
} else if (index === props.toots.length - 1) {
|
|
||||||
return "bottom";
|
|
||||||
}
|
|
||||||
return "middle";
|
|
||||||
};
|
|
||||||
|
|
||||||
css`
|
|
||||||
.thread {
|
|
||||||
user-select: none;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
return (
|
|
||||||
<article ref={props.ref} class="thread" aria-setsize={props.toots.length}>
|
|
||||||
<Index each={props.toots}>
|
|
||||||
{(status, index) => {
|
|
||||||
return (
|
|
||||||
<RegularToot
|
|
||||||
data-status-id={status().id}
|
|
||||||
data-thread-sort={index}
|
|
||||||
status={status()}
|
|
||||||
thread={posThread(index)}
|
|
||||||
class={cardStyle.card}
|
|
||||||
evaluated={props.isExpended(status())}
|
|
||||||
actionable={props.isExpended(status())}
|
|
||||||
onBookmark={(s) => bookmark(s)}
|
|
||||||
onRetoot={(s) => boost(s)}
|
|
||||||
onFavourite={props.onFavourite}
|
|
||||||
onReply={reply}
|
|
||||||
onClick={[props.onItemClick, status()]}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Index>
|
|
||||||
</article>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Thread;
|
|
|
@ -5,16 +5,30 @@ import {
|
||||||
ErrorBoundary,
|
ErrorBoundary,
|
||||||
type Ref,
|
type Ref,
|
||||||
createSelector,
|
createSelector,
|
||||||
|
Index,
|
||||||
|
createMemo,
|
||||||
} from "solid-js";
|
} from "solid-js";
|
||||||
import { type mastodon } from "masto";
|
import { type mastodon } from "masto";
|
||||||
import { vibrate } from "../platform/hardware";
|
import { vibrate } from "../platform/hardware";
|
||||||
import Thread from "./Thread.jsx";
|
|
||||||
import { useDefaultSession } from "../masto/clients";
|
import { useDefaultSession } from "../masto/clients";
|
||||||
import { useHeroSource } from "../platform/anim";
|
import { useHeroSource } from "../platform/anim";
|
||||||
import { HERO as BOTTOM_SHEET_HERO } from "../material/BottomSheet";
|
import { HERO as BOTTOM_SHEET_HERO } from "../material/BottomSheet";
|
||||||
import { setCache as setTootBottomSheetCache } from "./TootBottomSheet";
|
import { setCache as setTootBottomSheetCache } from "./TootBottomSheet";
|
||||||
import { useNavigate } from "@solidjs/router";
|
import { useNavigate } from "@solidjs/router";
|
||||||
import { findElementActionable } from "./RegularToot";
|
import RegularToot, {
|
||||||
|
findElementActionable,
|
||||||
|
findRootToot,
|
||||||
|
} from "./RegularToot";
|
||||||
|
import cardStyle from "../material/cards.module.css";
|
||||||
|
|
||||||
|
function positionTootInThread(index: number, threadLength: number) {
|
||||||
|
if (index === 0) {
|
||||||
|
return "top";
|
||||||
|
} else if (index === threadLength - 1) {
|
||||||
|
return "bottom";
|
||||||
|
}
|
||||||
|
return "middle";
|
||||||
|
}
|
||||||
|
|
||||||
const TootList: Component<{
|
const TootList: Component<{
|
||||||
ref?: Ref<HTMLDivElement>;
|
ref?: Ref<HTMLDivElement>;
|
||||||
|
@ -28,20 +42,20 @@ const TootList: Component<{
|
||||||
const [expandedThreadId, setExpandedThreadId] = createSignal<string>();
|
const [expandedThreadId, setExpandedThreadId] = createSignal<string>();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const onBookmark = async (
|
const onBookmark = async (status: mastodon.v1.Status) => {
|
||||||
client: mastodon.rest.Client,
|
const client = session()?.client;
|
||||||
status: mastodon.v1.Status,
|
if (!client) return;
|
||||||
) => {
|
|
||||||
const result = await (status.bookmarked
|
const result = await (status.bookmarked
|
||||||
? client.v1.statuses.$select(status.id).unbookmark()
|
? client.v1.statuses.$select(status.id).unbookmark()
|
||||||
: client.v1.statuses.$select(status.id).bookmark());
|
: client.v1.statuses.$select(status.id).bookmark());
|
||||||
props.onChangeToot(result.id, result);
|
props.onChangeToot(result.id, result);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleBoost = async (
|
const toggleBoost = async (status: mastodon.v1.Status) => {
|
||||||
client: mastodon.rest.Client,
|
const client = session()?.client;
|
||||||
status: mastodon.v1.Status,
|
if (!client) return;
|
||||||
) => {
|
|
||||||
vibrate(50);
|
vibrate(50);
|
||||||
const rootStatus = status.reblog ? status.reblog : status;
|
const rootStatus = status.reblog ? status.reblog : status;
|
||||||
const reblogged = rootStatus.reblogged;
|
const reblogged = rootStatus.reblogged;
|
||||||
|
@ -110,8 +124,11 @@ const TootList: Component<{
|
||||||
|
|
||||||
const onItemClick = (
|
const onItemClick = (
|
||||||
status: mastodon.v1.Status,
|
status: mastodon.v1.Status,
|
||||||
event: MouseEvent & { target: HTMLElement; currentTarget: HTMLElement },
|
event: MouseEvent & { target: EventTarget; currentTarget: HTMLElement },
|
||||||
) => {
|
) => {
|
||||||
|
if (!(event.target instanceof HTMLElement)) {
|
||||||
|
throw new Error("target is not an element");
|
||||||
|
}
|
||||||
const actionableElement = findElementActionable(
|
const actionableElement = findElementActionable(
|
||||||
event.target,
|
event.target,
|
||||||
event.currentTarget,
|
event.currentTarget,
|
||||||
|
@ -153,13 +170,6 @@ const TootList: Component<{
|
||||||
const checkIsExpended = (status: mastodon.v1.Status) =>
|
const checkIsExpended = (status: mastodon.v1.Status) =>
|
||||||
checkIsExpendedId(status.id);
|
checkIsExpendedId(status.id);
|
||||||
|
|
||||||
const onReply = (
|
|
||||||
{ status }: { status: mastodon.v1.Status },
|
|
||||||
element: HTMLElement,
|
|
||||||
) => {
|
|
||||||
openFullScreenToot(status, element, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getPath = (itemId: string) => {
|
const getPath = (itemId: string) => {
|
||||||
return props
|
return props
|
||||||
.onUnknownThread(itemId)!
|
.onUnknownThread(itemId)!
|
||||||
|
@ -176,17 +186,33 @@ const TootList: Component<{
|
||||||
<div ref={props.ref} id={props.id} class="toot-list">
|
<div ref={props.ref} id={props.id} class="toot-list">
|
||||||
<For each={props.threads}>
|
<For each={props.threads}>
|
||||||
{(itemId) => {
|
{(itemId) => {
|
||||||
|
const toots = createMemo(() => getPath(itemId));
|
||||||
return (
|
return (
|
||||||
<Thread
|
<Index each={toots()}>
|
||||||
toots={getPath(itemId)}
|
{(status, index) => (
|
||||||
onBoost={toggleBoost}
|
<RegularToot
|
||||||
onBookmark={onBookmark}
|
data-status-id={status().id}
|
||||||
onReply={onReply}
|
data-thread-sort={index}
|
||||||
onFavourite={toggleFavourite}
|
status={status()}
|
||||||
client={session()?.client!}
|
thread={
|
||||||
isExpended={checkIsExpended}
|
toots().length > 1
|
||||||
onItemClick={onItemClick}
|
? positionTootInThread(index, toots().length)
|
||||||
/>
|
: undefined
|
||||||
|
}
|
||||||
|
class={cardStyle.card}
|
||||||
|
evaluated={checkIsExpended(status())}
|
||||||
|
actionable={checkIsExpended(status())}
|
||||||
|
onBookmark={onBookmark}
|
||||||
|
onRetoot={toggleBoost}
|
||||||
|
onFavourite={toggleFavourite}
|
||||||
|
onReply={(status, event) => {
|
||||||
|
const element = findRootToot(event.currentTarget);
|
||||||
|
openFullScreenToot(status, element, true);
|
||||||
|
}}
|
||||||
|
onClick={[onItemClick, status()]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Index>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</For>
|
</For>
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
margin-block: 0;
|
margin-block: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
contain: content;
|
contain: content;
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
&.toot {
|
&.toot {
|
||||||
/* fix composition ordering: I think the css module processor should aware the overriding and behaves, but no */
|
/* fix composition ordering: I think the css module processor should aware the overriding and behaves, but no */
|
||||||
|
|
Loading…
Reference in a new issue