Atproto AMA app
1import { For, Show, type JSX } from "solid-js";
2
3import { SourceAttribution } from "~/components/SourceAttribution";
4import { AnswerBlock } from "~/components/AnswerBlock";
5import { formatWhen } from "~/lib/format";
6
7import styles from "~/routes/[handle].module.css";
8
9interface AnswerLike {
10 id: string;
11 content: string;
12 createdAt: Date | string;
13 sourceType?: string | null;
14 sourceUri?: string | null;
15 sourceData?: string | null;
16}
17
18interface AuthorLike {
19 handle: string;
20 displayName?: string | null;
21}
22
23interface QuestionCardProps {
24 id?: string;
25 content: string;
26 createdAt: Date | string;
27 anonymous: boolean;
28 author?: AuthorLike | null;
29 sourceType?: string | null;
30 sourceUri?: string | null;
31 sourceData?: string | null;
32 answers?: AnswerLike[];
33 /** When true, show a "Pending answer" hint if no answers are present. */
34 showPendingHint?: boolean;
35 /** Optional slot for trailing content (e.g. "Click to answer →"). */
36 trailing?: JSX.Element;
37}
38
39export function QuestionCard(props: QuestionCardProps) {
40 const authorLabel = () => {
41 if (props.anonymous) return "Anonymous";
42 return props.author?.displayName || props.author?.handle || "Unknown";
43 };
44
45 return (
46 <article id={props.id} class={styles.questionCard}>
47 <div class={styles.questionContent}>{props.content}</div>
48 <div class={styles.questionMeta}>
49 {authorLabel()} · {formatWhen(props.createdAt)}
50 <SourceAttribution
51 sourceType={props.sourceType || "askimut"}
52 sourceUri={props.sourceUri}
53 sourceData={props.sourceData}
54 />
55 </div>
56 <Show when={props.answers}>
57 <For each={props.answers}>
58 {(a) => (
59 <AnswerBlock
60 content={a.content}
61 createdAt={a.createdAt}
62 sourceType={a.sourceType}
63 sourceUri={a.sourceUri}
64 sourceData={a.sourceData}
65 />
66 )}
67 </For>
68 </Show>
69 <Show
70 when={
71 props.showPendingHint && (props.answers?.length ?? 0) === 0
72 }
73 >
74 <div class={styles.pendingIndicator}>
75 <span class={styles.pendingText}>Pending answer</span>
76 </div>
77 </Show>
78 {props.trailing}
79 </article>
80 );
81}
82
83export default QuestionCard;