RegularToot: refactor, add env context
This commit is contained in:
		
							parent
							
								
									cbdf5e667d
								
							
						
					
					
						commit
						ad7db8e865
					
				
					 5 changed files with 164 additions and 123 deletions
				
			
		| 
						 | 
				
			
			@ -7,6 +7,8 @@ import {
 | 
			
		|||
  createRenderEffect,
 | 
			
		||||
  createSignal,
 | 
			
		||||
  type Setter,
 | 
			
		||||
  createContext,
 | 
			
		||||
  useContext,
 | 
			
		||||
} from "solid-js";
 | 
			
		||||
import tootStyle from "./toot.module.css";
 | 
			
		||||
import { formatRelative, parseISO } from "date-fns";
 | 
			
		||||
| 
						 | 
				
			
			@ -38,27 +40,38 @@ import BoostIcon from "./toots/BoostIcon";
 | 
			
		|||
import PreviewCard from "./toots/PreviewCard";
 | 
			
		||||
import TootPoll from "./toots/TootPoll";
 | 
			
		||||
 | 
			
		||||
type TootActionGroupProps<T extends mastodon.v1.Status> = {
 | 
			
		||||
  onRetoot?: (value: T) => void;
 | 
			
		||||
  onFavourite?: (value: T) => void;
 | 
			
		||||
  onBookmark?: (value: T) => void;
 | 
			
		||||
  onReply?: (
 | 
			
		||||
    value: T,
 | 
			
		||||
export type TootEnv = {
 | 
			
		||||
  boost: (value: mastodon.v1.Status) => void;
 | 
			
		||||
  favourite: (value: mastodon.v1.Status) => void;
 | 
			
		||||
  bookmark: (value: mastodon.v1.Status) => void;
 | 
			
		||||
  reply?: (
 | 
			
		||||
    value: mastodon.v1.Status,
 | 
			
		||||
    event: MouseEvent & { currentTarget: HTMLButtonElement },
 | 
			
		||||
  ) => void;
 | 
			
		||||
  vote: (
 | 
			
		||||
    status: mastodon.v1.Status,
 | 
			
		||||
    votes: readonly number[],
 | 
			
		||||
  ) => void | Promise<void>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const TootEnvContext = /* @__PURE__ */ createContext<TootEnv>();
 | 
			
		||||
 | 
			
		||||
export const TootEnvProvider = TootEnvContext.Provider;
 | 
			
		||||
 | 
			
		||||
export function useTootEnv() {
 | 
			
		||||
  const env = useContext(TootEnvContext);
 | 
			
		||||
  if (!env) {
 | 
			
		||||
    throw new TypeError("environment not found, use TootEnvProvider to provide")
 | 
			
		||||
  }
 | 
			
		||||
  return env
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RegularTootProps = {
 | 
			
		||||
  status: mastodon.v1.Status;
 | 
			
		||||
  actionable?: boolean;
 | 
			
		||||
  evaluated?: boolean;
 | 
			
		||||
  thread?: "top" | "bottom" | "middle";
 | 
			
		||||
 | 
			
		||||
  onVote?: (value: {
 | 
			
		||||
    status: mastodon.v1.Status;
 | 
			
		||||
    votes: readonly number[];
 | 
			
		||||
  }) => void | Promise<void>;
 | 
			
		||||
} & TootActionGroupProps<mastodon.v1.Status> &
 | 
			
		||||
} &
 | 
			
		||||
  JSX.HTMLElementTags["article"];
 | 
			
		||||
 | 
			
		||||
function isolatedCallback(e: MouseEvent) {
 | 
			
		||||
| 
						 | 
				
			
			@ -79,8 +92,9 @@ export function findRootToot(element: HTMLElement) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function TootActionGroup<T extends mastodon.v1.Status>(
 | 
			
		||||
  props: TootActionGroupProps<T> & { value: T },
 | 
			
		||||
  props: { value: T },
 | 
			
		||||
) {
 | 
			
		||||
  const {reply, boost, favourite, bookmark} = useTootEnv()
 | 
			
		||||
  let actGrpElement: HTMLDivElement;
 | 
			
		||||
  const toot = () => props.value;
 | 
			
		||||
  return (
 | 
			
		||||
| 
						 | 
				
			
			@ -89,10 +103,10 @@ function TootActionGroup<T extends mastodon.v1.Status>(
 | 
			
		|||
      class={tootStyle.tootBottomActionGrp}
 | 
			
		||||
      onClick={isolatedCallback}
 | 
			
		||||
    >
 | 
			
		||||
      <Show when={props.onReply}>
 | 
			
		||||
      <Show when={reply}>
 | 
			
		||||
        <Button
 | 
			
		||||
          class={tootStyle.tootActionWithCount}
 | 
			
		||||
          onClick={[props.onReply!, props.value]}
 | 
			
		||||
          onClick={[reply!, props.value]}
 | 
			
		||||
        >
 | 
			
		||||
          <ReplyAll />
 | 
			
		||||
          <span>{toot().repliesCount}</span>
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +118,7 @@ function TootActionGroup<T extends mastodon.v1.Status>(
 | 
			
		|||
        style={{
 | 
			
		||||
          color: toot().reblogged ? "var(--tutu-color-primary)" : undefined,
 | 
			
		||||
        }}
 | 
			
		||||
        onClick={() => props.onRetoot?.(toot())}
 | 
			
		||||
        onClick={[boost, props.value]}
 | 
			
		||||
      >
 | 
			
		||||
        <Repeat />
 | 
			
		||||
        <span>{toot().reblogsCount}</span>
 | 
			
		||||
| 
						 | 
				
			
			@ -114,7 +128,7 @@ function TootActionGroup<T extends mastodon.v1.Status>(
 | 
			
		|||
        style={{
 | 
			
		||||
          color: toot().favourited ? "var(--tutu-color-primary)" : undefined,
 | 
			
		||||
        }}
 | 
			
		||||
        onClick={() => props.onFavourite?.(toot())}
 | 
			
		||||
        onClick={[favourite, props.value]}
 | 
			
		||||
      >
 | 
			
		||||
        {toot().favourited ? <Star /> : <StarOutline />}
 | 
			
		||||
        <span>{toot().favouritesCount}</span>
 | 
			
		||||
| 
						 | 
				
			
			@ -124,7 +138,7 @@ function TootActionGroup<T extends mastodon.v1.Status>(
 | 
			
		|||
        style={{
 | 
			
		||||
          color: toot().bookmarked ? "var(--tutu-color-primary)" : undefined,
 | 
			
		||||
        }}
 | 
			
		||||
        onClick={() => props.onBookmark?.(toot())}
 | 
			
		||||
        onClick={[bookmark, props.value]}
 | 
			
		||||
      >
 | 
			
		||||
        {toot().bookmarked ? <Bookmark /> : <BookmarkAddOutlined />}
 | 
			
		||||
      </Button>
 | 
			
		||||
| 
						 | 
				
			
			@ -243,11 +257,10 @@ function onToggleReveal(setValue: Setter<boolean>, event: Event) {
 | 
			
		|||
 */
 | 
			
		||||
const RegularToot: Component<RegularTootProps> = (props) => {
 | 
			
		||||
  let rootRef: HTMLElement;
 | 
			
		||||
  const [managed, managedActionGroup, pollProps, rest] = splitProps(
 | 
			
		||||
  const {vote} = useTootEnv()
 | 
			
		||||
  const [managed, rest] = splitProps(
 | 
			
		||||
    props,
 | 
			
		||||
    ["status", "lang", "class", "actionable", "evaluated", "thread"],
 | 
			
		||||
    ["onRetoot", "onFavourite", "onBookmark", "onReply"],
 | 
			
		||||
    ["onVote"],
 | 
			
		||||
  );
 | 
			
		||||
  const now = useTimeSource();
 | 
			
		||||
  const status = () => managed.status;
 | 
			
		||||
| 
						 | 
				
			
			@ -361,18 +374,8 @@ const RegularToot: Component<RegularTootProps> = (props) => {
 | 
			
		|||
        </Show>
 | 
			
		||||
        <Show when={toot().poll}>
 | 
			
		||||
          <TootPoll
 | 
			
		||||
            options={toot().poll!.options}
 | 
			
		||||
            multiple={toot().poll!.multiple}
 | 
			
		||||
            votesCount={toot().poll!.votesCount}
 | 
			
		||||
            expired={toot().poll!.expired}
 | 
			
		||||
            expiredAt={
 | 
			
		||||
              toot().poll!.expiresAt
 | 
			
		||||
                ? parseISO(toot().poll!.expiresAt!)
 | 
			
		||||
                : undefined
 | 
			
		||||
            }
 | 
			
		||||
            voted={toot().poll!.voted}
 | 
			
		||||
            ownVotes={toot().poll!.ownVotes || undefined}
 | 
			
		||||
            onVote={(votes) => pollProps.onVote?.({ status: status(), votes })}
 | 
			
		||||
            value={toot().poll!}
 | 
			
		||||
            status={toot()}
 | 
			
		||||
          />
 | 
			
		||||
        </Show>
 | 
			
		||||
        <Show when={managed.actionable}>
 | 
			
		||||
| 
						 | 
				
			
			@ -380,7 +383,7 @@ const RegularToot: Component<RegularTootProps> = (props) => {
 | 
			
		|||
            class={cardStyle.cardNoPad}
 | 
			
		||||
            style={{ "margin-top": "8px" }}
 | 
			
		||||
          />
 | 
			
		||||
          <TootActionGroup value={toot()} {...managedActionGroup} />
 | 
			
		||||
          <TootActionGroup value={toot()} />
 | 
			
		||||
        </Show>
 | 
			
		||||
      </article>
 | 
			
		||||
    </>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,10 @@ import { Title } from "~material/typography";
 | 
			
		|||
import { Close as CloseIcon } from "@suid/icons-material";
 | 
			
		||||
import { useSessionForAcctStr } from "../masto/clients";
 | 
			
		||||
import { resolveCustomEmoji } from "../masto/toot";
 | 
			
		||||
import RegularToot, { findElementActionable } from "./RegularToot";
 | 
			
		||||
import RegularToot, {
 | 
			
		||||
  findElementActionable,
 | 
			
		||||
  TootEnvProvider,
 | 
			
		||||
} from "./RegularToot";
 | 
			
		||||
import type { mastodon } from "masto";
 | 
			
		||||
import cards from "~material/cards.module.css";
 | 
			
		||||
import { css } from "solid-styled";
 | 
			
		||||
| 
						 | 
				
			
			@ -169,6 +172,33 @@ const TootBottomSheet: Component = (props) => {
 | 
			
		|||
    return Array.from(new Set(values).keys());
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const vote = async (status: mastodon.v1.Status, votes: readonly number[]) => {
 | 
			
		||||
    const client = session()?.client;
 | 
			
		||||
    if (!client) return;
 | 
			
		||||
 | 
			
		||||
    const toot = status.reblog ?? status;
 | 
			
		||||
    if (!toot.poll) return;
 | 
			
		||||
 | 
			
		||||
    const npoll = await client.v1.polls.$select(toot.poll.id).votes.create({
 | 
			
		||||
      choices: votes,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (status.reblog) {
 | 
			
		||||
      setRemoteToot({
 | 
			
		||||
        ...status,
 | 
			
		||||
        reblog: {
 | 
			
		||||
          ...status.reblog,
 | 
			
		||||
          poll: npoll,
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      setRemoteToot({
 | 
			
		||||
        ...status,
 | 
			
		||||
        poll: npoll,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleMainTootClick = (
 | 
			
		||||
    event: MouseEvent & { currentTarget: HTMLElement },
 | 
			
		||||
  ) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -255,23 +285,29 @@ const TootBottomSheet: Component = (props) => {
 | 
			
		|||
 | 
			
		||||
          <article>
 | 
			
		||||
            <Show when={toot()}>
 | 
			
		||||
              <RegularToot
 | 
			
		||||
                id={`toot-${toot()!.id}`}
 | 
			
		||||
                class={cards.card}
 | 
			
		||||
                style={{
 | 
			
		||||
                  "scroll-margin-top":
 | 
			
		||||
                    "calc(var(--scaffold-topbar-height) + 20px)",
 | 
			
		||||
                  "cursor": "auto",
 | 
			
		||||
                  "user-select": "auto",
 | 
			
		||||
              <TootEnvProvider
 | 
			
		||||
                value={{
 | 
			
		||||
                  bookmark: onBookmark,
 | 
			
		||||
                  boost: onBoost,
 | 
			
		||||
                  favourite: onFav,
 | 
			
		||||
                  vote,
 | 
			
		||||
                }}
 | 
			
		||||
                status={toot()!}
 | 
			
		||||
                actionable={!!actSession()}
 | 
			
		||||
                evaluated={true}
 | 
			
		||||
                onBookmark={onBookmark}
 | 
			
		||||
                onRetoot={onBoost}
 | 
			
		||||
                onFavourite={onFav}
 | 
			
		||||
                onClick={handleMainTootClick}
 | 
			
		||||
              ></RegularToot>
 | 
			
		||||
              >
 | 
			
		||||
                <RegularToot
 | 
			
		||||
                  id={`toot-${toot()!.id}`}
 | 
			
		||||
                  class={cards.card}
 | 
			
		||||
                  style={{
 | 
			
		||||
                    "scroll-margin-top":
 | 
			
		||||
                      "calc(var(--scaffold-topbar-height) + 20px)",
 | 
			
		||||
                    cursor: "auto",
 | 
			
		||||
                    "user-select": "auto",
 | 
			
		||||
                  }}
 | 
			
		||||
                  status={toot()!}
 | 
			
		||||
                  actionable={!!actSession()}
 | 
			
		||||
                  evaluated={true}
 | 
			
		||||
                  onClick={handleMainTootClick}
 | 
			
		||||
                ></RegularToot>
 | 
			
		||||
              </TootEnvProvider>
 | 
			
		||||
            </Show>
 | 
			
		||||
          </article>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@ import { setCache as setTootBottomSheetCache } from "./TootBottomSheet";
 | 
			
		|||
import RegularToot, {
 | 
			
		||||
  findElementActionable,
 | 
			
		||||
  findRootToot,
 | 
			
		||||
  TootEnvProvider,
 | 
			
		||||
} from "./RegularToot";
 | 
			
		||||
import cardStyle from "~material/cards.module.css";
 | 
			
		||||
import type { ThreadNode } from "../masto/timelines";
 | 
			
		||||
| 
						 | 
				
			
			@ -232,13 +233,10 @@ const TootList: Component<{
 | 
			
		|||
    openFullScreenToot(status, element, true);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const vote = async ({
 | 
			
		||||
    status,
 | 
			
		||||
    votes,
 | 
			
		||||
  }: {
 | 
			
		||||
    status: mastodon.v1.Status;
 | 
			
		||||
    votes: readonly number[];
 | 
			
		||||
  }) => {
 | 
			
		||||
  const vote = async (
 | 
			
		||||
    status: mastodon.v1.Status,
 | 
			
		||||
    votes: readonly number[]
 | 
			
		||||
  ) => {
 | 
			
		||||
    const client = session()?.client;
 | 
			
		||||
    if (!client) return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -263,7 +261,6 @@ const TootList: Component<{
 | 
			
		|||
        poll: npoll,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
| 
						 | 
				
			
			@ -273,49 +270,50 @@ const TootList: Component<{
 | 
			
		|||
        return <p>Oops: {String(err)}</p>;
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div ref={props.ref} id={props.id} class="toot-list">
 | 
			
		||||
        <Index each={props.threads}>
 | 
			
		||||
          {(threadId, threadIdx) => {
 | 
			
		||||
            const thread = createMemo(() =>
 | 
			
		||||
              props.onUnknownThread(threadId())?.reverse(),
 | 
			
		||||
            );
 | 
			
		||||
      <TootEnvProvider value={{
 | 
			
		||||
        boost: toggleBoost,
 | 
			
		||||
        bookmark: onBookmark,
 | 
			
		||||
        favourite: toggleFavourite,
 | 
			
		||||
        reply: reply,
 | 
			
		||||
        vote: vote
 | 
			
		||||
      }}>
 | 
			
		||||
        <div ref={props.ref} id={props.id} class="toot-list">
 | 
			
		||||
          <Index each={props.threads}>
 | 
			
		||||
            {(threadId, threadIdx) => {
 | 
			
		||||
              const thread = createMemo(() =>
 | 
			
		||||
                props.onUnknownThread(threadId())?.reverse(),
 | 
			
		||||
              );
 | 
			
		||||
 | 
			
		||||
            const threadLength = () => thread()?.length ?? 0;
 | 
			
		||||
              const threadLength = () => thread()?.length ?? 0;
 | 
			
		||||
 | 
			
		||||
            return (
 | 
			
		||||
              <Index each={thread()}>
 | 
			
		||||
                {(threadNode, index) => {
 | 
			
		||||
                  const status = () => threadNode().value;
 | 
			
		||||
              return (
 | 
			
		||||
                <Index each={thread()}>
 | 
			
		||||
                  {(threadNode, index) => {
 | 
			
		||||
                    const status = () => threadNode().value;
 | 
			
		||||
 | 
			
		||||
                  return (
 | 
			
		||||
                    <RegularToot
 | 
			
		||||
                      data-status-id={status().id}
 | 
			
		||||
                      data-thread={threadIdx}
 | 
			
		||||
                      data-thread-len={threadLength()}
 | 
			
		||||
                      data-thread-sort={index}
 | 
			
		||||
                      status={status()}
 | 
			
		||||
                      thread={
 | 
			
		||||
                        threadLength() > 1
 | 
			
		||||
                          ? positionTootInThread(index, threadLength())
 | 
			
		||||
                          : undefined
 | 
			
		||||
                      }
 | 
			
		||||
                      class={cardStyle.card}
 | 
			
		||||
                      evaluated={checkIsExpended(status())}
 | 
			
		||||
                      actionable={checkIsExpended(status())}
 | 
			
		||||
                      onBookmark={onBookmark}
 | 
			
		||||
                      onRetoot={toggleBoost}
 | 
			
		||||
                      onFavourite={toggleFavourite}
 | 
			
		||||
                      onReply={reply}
 | 
			
		||||
                      onVote={vote}
 | 
			
		||||
                      onClick={[onItemClick, status()]}
 | 
			
		||||
                    />
 | 
			
		||||
                  );
 | 
			
		||||
                }}
 | 
			
		||||
              </Index>
 | 
			
		||||
            );
 | 
			
		||||
          }}
 | 
			
		||||
        </Index>
 | 
			
		||||
      </div>
 | 
			
		||||
                    return (
 | 
			
		||||
                      <RegularToot
 | 
			
		||||
                        data-status-id={status().id}
 | 
			
		||||
                        data-thread-sort={index}
 | 
			
		||||
                        status={status()}
 | 
			
		||||
                        thread={
 | 
			
		||||
                          threadLength() > 1
 | 
			
		||||
                            ? positionTootInThread(index, threadLength())
 | 
			
		||||
                            : undefined
 | 
			
		||||
                        }
 | 
			
		||||
                        class={cardStyle.card}
 | 
			
		||||
                        evaluated={checkIsExpended(status())}
 | 
			
		||||
                        actionable={checkIsExpended(status())}
 | 
			
		||||
                        onClick={[onItemClick, status()]}
 | 
			
		||||
                      />
 | 
			
		||||
                    );
 | 
			
		||||
                  }}
 | 
			
		||||
                </Index>
 | 
			
		||||
              );
 | 
			
		||||
            }}
 | 
			
		||||
          </Index>
 | 
			
		||||
        </div>
 | 
			
		||||
      </TootEnvProvider>
 | 
			
		||||
    </ErrorBoundary>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,21 +28,17 @@ import { useTimeSource } from "~platform/timesrc";
 | 
			
		|||
import { useDateFnLocale } from "~platform/i18n";
 | 
			
		||||
import TootPollDialog from "./TootPollDialog";
 | 
			
		||||
import { ANIM_CURVE_STD } from "~material/theme";
 | 
			
		||||
import { useTootEnv } from "../RegularToot";
 | 
			
		||||
 | 
			
		||||
type TootPollProps = {
 | 
			
		||||
  options: Readonly<mastodon.v1.Poll["options"]>;
 | 
			
		||||
  multiple?: boolean;
 | 
			
		||||
  votesCount: number;
 | 
			
		||||
  expired?: boolean;
 | 
			
		||||
  expiredAt?: Date;
 | 
			
		||||
  voted?: boolean;
 | 
			
		||||
  ownVotes?: readonly number[];
 | 
			
		||||
 | 
			
		||||
  onVote(votes: readonly number[]): void | Promise<void>;
 | 
			
		||||
  value: mastodon.v1.Poll
 | 
			
		||||
  status: mastodon.v1.Status
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const TootPoll: Component<TootPollProps> = (props) => {
 | 
			
		||||
  let list: HTMLUListElement;
 | 
			
		||||
  const {vote}= useTootEnv()
 | 
			
		||||
 | 
			
		||||
  const now = useTimeSource();
 | 
			
		||||
  const dateFnLocale = useDateFnLocale();
 | 
			
		||||
  const [mustShowResult, setMustShowResult] = createSignal<boolean>();
 | 
			
		||||
| 
						 | 
				
			
			@ -50,24 +46,26 @@ const TootPoll: Component<TootPollProps> = (props) => {
 | 
			
		|||
 | 
			
		||||
  const [initialVote, setInitialVote] = createSignal(0);
 | 
			
		||||
 | 
			
		||||
  const poll = () => props.value
 | 
			
		||||
 | 
			
		||||
  const isShowResult = () => {
 | 
			
		||||
    const n = mustShowResult();
 | 
			
		||||
    if (typeof n !== "undefined") {
 | 
			
		||||
      return n;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return props.expired || props.voted;
 | 
			
		||||
    return poll().expired || poll().voted;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const isOwnVote = createSelector(
 | 
			
		||||
    () => props.ownVotes,
 | 
			
		||||
    () => poll().ownVotes,
 | 
			
		||||
    (idx: number, votes) => votes?.includes(idx) || false,
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const openVote = (i: number, event: Event) => {
 | 
			
		||||
    event.stopPropagation();
 | 
			
		||||
 | 
			
		||||
    if (props.expired || props.voted) {
 | 
			
		||||
    if (poll().expired || poll().voted) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -100,13 +98,13 @@ const TootPoll: Component<TootPollProps> = (props) => {
 | 
			
		|||
  return (
 | 
			
		||||
    <section class="TootPoll">
 | 
			
		||||
      <div class="hints">
 | 
			
		||||
        <span>{props.votesCount} votes in total</span>
 | 
			
		||||
        <Show when={props.expired}>
 | 
			
		||||
        <span>{poll().votesCount} votes in total</span>
 | 
			
		||||
        <Show when={poll().expired}>
 | 
			
		||||
          <span>Poll is ended</span>
 | 
			
		||||
        </Show>
 | 
			
		||||
      </div>
 | 
			
		||||
      <List ref={list!} disablePadding class="option-list">
 | 
			
		||||
        <Index each={props.options}>
 | 
			
		||||
        <Index each={poll().options}>
 | 
			
		||||
          {(option, index) => {
 | 
			
		||||
            return (
 | 
			
		||||
              <>
 | 
			
		||||
| 
						 | 
				
			
			@ -140,7 +138,7 @@ const TootPoll: Component<TootPollProps> = (props) => {
 | 
			
		|||
                  </Show>
 | 
			
		||||
 | 
			
		||||
                  <Show
 | 
			
		||||
                    when={props.multiple}
 | 
			
		||||
                    when={poll().multiple}
 | 
			
		||||
                    fallback={
 | 
			
		||||
                      <Radio
 | 
			
		||||
                        checked={isOwnVote(index)}
 | 
			
		||||
| 
						 | 
				
			
			@ -164,14 +162,14 @@ const TootPoll: Component<TootPollProps> = (props) => {
 | 
			
		|||
        <Button onClick={animateAndSetMustShow}>
 | 
			
		||||
          {isShowResult() ? "Hide result" : "Reveal result"}
 | 
			
		||||
        </Button>
 | 
			
		||||
        <Show when={props.expiredAt}>
 | 
			
		||||
        <Show when={poll().expiresAt}>
 | 
			
		||||
          <span>
 | 
			
		||||
            <span style={{ "margin-inline-end": "0.5ch" }}>
 | 
			
		||||
              {isBefore(now(), props.expiredAt!) ? "Expire in" : "Expired"}
 | 
			
		||||
              {isBefore(now(), poll().expiresAt!) ? "Expire in" : "Expired"}
 | 
			
		||||
            </span>
 | 
			
		||||
 | 
			
		||||
            <time dateTime={props.expiredAt!.toISOString()}>
 | 
			
		||||
              {formatDistance(now(), props.expiredAt!, {
 | 
			
		||||
            <time dateTime={poll().expiresAt!}>
 | 
			
		||||
              {formatDistance(now(), poll().expiresAt!, {
 | 
			
		||||
                locale: dateFnLocale(),
 | 
			
		||||
              })}
 | 
			
		||||
            </time>
 | 
			
		||||
| 
						 | 
				
			
			@ -181,8 +179,8 @@ const TootPoll: Component<TootPollProps> = (props) => {
 | 
			
		|||
 | 
			
		||||
      <TootPollDialog
 | 
			
		||||
        open={showVoteDialog()}
 | 
			
		||||
        options={props.options}
 | 
			
		||||
        onVote={(votes) => console.debug(votes)}
 | 
			
		||||
        options={poll().options}
 | 
			
		||||
        onVote={[vote, props.status]}
 | 
			
		||||
        onClose={() => setShowVoteDialog(false)}
 | 
			
		||||
        initialVotes={[initialVote()]}
 | 
			
		||||
      />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,13 @@ export type TootPollDialogPoll = {
 | 
			
		|||
  initialVotes?: readonly number[];
 | 
			
		||||
  multiple?: boolean;
 | 
			
		||||
 | 
			
		||||
  onVote(votes: readonly number[]): void | Promise<void>;
 | 
			
		||||
  onVote: [
 | 
			
		||||
    (
 | 
			
		||||
      status: mastodon.v1.Status,
 | 
			
		||||
      votes: readonly number[],
 | 
			
		||||
    ) => void | Promise<void>,
 | 
			
		||||
    mastodon.v1.Status,
 | 
			
		||||
  ];
 | 
			
		||||
  onClose?: BottomSheetProps["onClose"] &
 | 
			
		||||
    ((reason: "cancel" | "success") => void);
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +56,7 @@ const TootPollDialog: Component<TootPollDialogPoll> = (props) => {
 | 
			
		|||
  const sendVote = async () => {
 | 
			
		||||
    setInProgress(true);
 | 
			
		||||
    try {
 | 
			
		||||
      await props.onVote(votes());
 | 
			
		||||
      await props.onVote[0](props.onVote[1], votes());
 | 
			
		||||
    } catch (reason) {
 | 
			
		||||
      console.error(reason);
 | 
			
		||||
      props.onClose?.("cancel");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue