rnxcmkidd: Add the viewport-fit bento shell and a dev feed preview with fixtures
This commit is contained in:
+57
-42
@@ -1,4 +1,4 @@
|
||||
import type { Ref } from "react";
|
||||
import type { ReactNode, Ref } from "react";
|
||||
import { canDelete, type CardPost } from "@/lib/feed-model";
|
||||
import { Composer, type ComposerProps } from "./Composer";
|
||||
import { PostCard } from "./PostCard";
|
||||
@@ -24,6 +24,8 @@ export interface FeedViewProps {
|
||||
deleteErrors?: ReadonlySet<string>;
|
||||
composer?: ComposerProps;
|
||||
sentinelRef?: Ref<HTMLDivElement>;
|
||||
/** The scrolling feed list; the page itself never scrolls. */
|
||||
listRef?: Ref<HTMLDivElement>;
|
||||
now?: number;
|
||||
}
|
||||
|
||||
@@ -31,63 +33,76 @@ function Spinner() {
|
||||
return <span className="spinner" role="status" aria-label="Loading" />;
|
||||
}
|
||||
|
||||
function FeedPanel({ children, composer }: { children: ReactNode; composer?: ReactNode }) {
|
||||
return (
|
||||
<section className="tile panel feed" aria-labelledby="h-feed">
|
||||
<div className="panel-head feed-head">
|
||||
<h2 id="h-feed" className="type-title type-title-strong">Home feed</h2>
|
||||
</div>
|
||||
{composer}
|
||||
{children}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export function FeedView(p: FeedViewProps) {
|
||||
if (p.status === "loading") {
|
||||
return (
|
||||
<section className="feed">
|
||||
<FeedPanel>
|
||||
<div className="feed-center">
|
||||
<Spinner />
|
||||
</div>
|
||||
</section>
|
||||
</FeedPanel>
|
||||
);
|
||||
}
|
||||
if (p.status === "error") {
|
||||
return (
|
||||
<section className="feed">
|
||||
<FeedPanel>
|
||||
<div className="feed-message" role="alert">
|
||||
<p>The feed did not load.</p>
|
||||
<button type="button" onClick={p.onRetry}>Try again</button>
|
||||
</div>
|
||||
</section>
|
||||
</FeedPanel>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<section className="feed">
|
||||
{p.composer ? <Composer {...p.composer} /> : null}
|
||||
{p.newCount > 0 ? (
|
||||
<button type="button" className="new-posts" onClick={p.onShowNew}>
|
||||
{p.newCount === 1 ? "1 new post" : `${p.newCount} new posts`}
|
||||
</button>
|
||||
) : null}
|
||||
{p.posts.length === 0 ? (
|
||||
<p className="feed-message">No posts yet.</p>
|
||||
) : (
|
||||
p.posts.map((post) => <PostCard
|
||||
key={post.key}
|
||||
post={post}
|
||||
now={p.now}
|
||||
onToggleLike={p.onToggleLike}
|
||||
likeBusy={p.likeBusy?.has(post.key)}
|
||||
likeError={p.likeErrors?.has(post.key)}
|
||||
onSignedOut={p.onSignedOut}
|
||||
canDelete={canDelete(post, p.feedUserId)}
|
||||
onDelete={p.onDelete}
|
||||
deleteBusy={p.deleteBusy?.has(post.key)}
|
||||
deleteError={p.deleteErrors?.has(post.key)}
|
||||
/>)
|
||||
)}
|
||||
{p.loadMoreFailed ? (
|
||||
<div className="feed-message" role="alert">
|
||||
<p>The feed did not load.</p>
|
||||
<button type="button" onClick={p.onRetry}>Try again</button>
|
||||
</div>
|
||||
) : null}
|
||||
{p.loadingMore ? (
|
||||
<div className="feed-center">
|
||||
<Spinner />
|
||||
</div>
|
||||
) : null}
|
||||
<div ref={p.sentinelRef} className="sentinel" aria-hidden="true" />
|
||||
</section>
|
||||
<FeedPanel composer={p.composer ? <Composer {...p.composer} /> : null}>
|
||||
<div ref={p.listRef} className="feed-list panel-scroll fade-edges">
|
||||
{p.newCount > 0 ? (
|
||||
<button type="button" className="new-posts" onClick={p.onShowNew}>
|
||||
{p.newCount === 1 ? "1 new post" : `${p.newCount} new posts`}
|
||||
</button>
|
||||
) : null}
|
||||
{p.posts.length === 0 ? (
|
||||
<p className="feed-message">No posts yet.</p>
|
||||
) : (
|
||||
p.posts.map((post) => <PostCard
|
||||
key={post.key}
|
||||
post={post}
|
||||
now={p.now}
|
||||
onToggleLike={p.onToggleLike}
|
||||
likeBusy={p.likeBusy?.has(post.key)}
|
||||
likeError={p.likeErrors?.has(post.key)}
|
||||
onSignedOut={p.onSignedOut}
|
||||
canDelete={canDelete(post, p.feedUserId)}
|
||||
onDelete={p.onDelete}
|
||||
deleteBusy={p.deleteBusy?.has(post.key)}
|
||||
deleteError={p.deleteErrors?.has(post.key)}
|
||||
/>)
|
||||
)}
|
||||
{p.loadMoreFailed ? (
|
||||
<div className="feed-message" role="alert">
|
||||
<p>The feed did not load.</p>
|
||||
<button type="button" onClick={p.onRetry}>Try again</button>
|
||||
</div>
|
||||
) : null}
|
||||
{p.loadingMore ? (
|
||||
<div className="feed-center">
|
||||
<Spinner />
|
||||
</div>
|
||||
) : null}
|
||||
<div ref={p.sentinelRef} className="sentinel" aria-hidden="true" />
|
||||
</div>
|
||||
</FeedPanel>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user