rnxcmkidd: Add the viewport-fit bento shell and a dev feed preview with fixtures
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
// Fixture data for the dev-only preview routes (/dev/feed). Nothing here is
|
||||
// real: no Minnect person, post, token or URL. Images are inline SVG data URIs
|
||||
// so the preview never calls the network. Later tasks extend this file.
|
||||
import type { Person } from "@/lib/auth-client";
|
||||
import type { DiscoverCategory, DiscoverData, DiscoverExpert, DiscoverMinnect } from "@/lib/discover";
|
||||
import type { ExpertResult } from "@/lib/experts-search";
|
||||
|
||||
/** Fixed "now" so relative times in the preview are stable. */
|
||||
export const FIXTURE_NOW = Date.parse("2026-10-19T12:00:00Z");
|
||||
|
||||
/** A 16:9 gradient placeholder image, drawn with hsl() so no fetch happens. */
|
||||
export function placeholderImage(hue: number, label = ""): string {
|
||||
const svg =
|
||||
`<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">` +
|
||||
`<defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1">` +
|
||||
`<stop offset="0" stop-color="hsl(${hue} 45% 32%)"/><stop offset="1" stop-color="hsl(${(hue + 40) % 360} 40% 14%)"/>` +
|
||||
`</linearGradient></defs><rect width="1280" height="720" fill="url(#g)"/>` +
|
||||
(label
|
||||
? `<text x="64" y="660" font-family="system-ui,sans-serif" font-size="56" font-weight="700" fill="hsl(0 0% 100% / .85)">${label}</text>`
|
||||
: "") +
|
||||
`</svg>`;
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
||||
}
|
||||
|
||||
export const FIXTURE_FEED_USER_ID = "dev-user-1";
|
||||
|
||||
export const FIXTURE_PERSON: Person = {
|
||||
name: "Jordan Rivera",
|
||||
email: "jordan.rivera@example.com",
|
||||
pictureUrl: null,
|
||||
feedUserId: FIXTURE_FEED_USER_ID,
|
||||
};
|
||||
|
||||
const author = (id: string, displayName: string, picture: string | null = null) => ({
|
||||
id,
|
||||
displayName,
|
||||
profilePictureUrl: picture,
|
||||
});
|
||||
|
||||
/** Raw feed items in the shape /api/feed returns; run them through toCardPosts. */
|
||||
export const FIXTURE_FEED_ITEMS: unknown[] = [
|
||||
{
|
||||
type: "post",
|
||||
publishedAt: "2026-10-19T11:42:00Z",
|
||||
likesCount: 4,
|
||||
commentsCount: 1,
|
||||
post: {
|
||||
id: "p1",
|
||||
content: "Shipped the new onboarding flow this morning. The best feedback so far came from a five minute call, not a survey.",
|
||||
author: author(FIXTURE_FEED_USER_ID, "Jordan Rivera"),
|
||||
mediaItems: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "post",
|
||||
publishedAt: "2026-10-19T10:15:00Z",
|
||||
likesCount: 128,
|
||||
commentsCount: 23,
|
||||
isLiked: true,
|
||||
post: {
|
||||
id: "p2",
|
||||
content: "Three questions I ask before every pricing change:\n• Who pays more?\n• Who leaves?\n• What do we learn either way?",
|
||||
author: author("a2", "Priya Natarajan"),
|
||||
mediaItems: [{ mediaType: "image", imageUrl: placeholderImage(352, "Pricing review"), order: 0 }],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "post",
|
||||
publishedAt: "2026-10-19T08:30:00Z",
|
||||
likesCount: 56,
|
||||
commentsCount: 7,
|
||||
post: {
|
||||
id: "p3",
|
||||
content: "A short walkthrough of how we run weekly reviews with a remote team.",
|
||||
author: author("a3", "Marcus Bell"),
|
||||
mediaItems: [{ mediaType: "video", thumbnailUrl: placeholderImage(210, "Weekly reviews"), order: 0 }],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "post",
|
||||
publishedAt: "2026-10-18T19:05:00Z",
|
||||
likesCount: 9,
|
||||
commentsCount: 0,
|
||||
post: {
|
||||
id: "p4",
|
||||
content: "Reading list for anyone moving from engineering into product: start with the customer interviews, then the numbers.",
|
||||
author: author("a4", "Elena Kovac"),
|
||||
mediaItems: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "post",
|
||||
publishedAt: "2026-10-18T14:40:00Z",
|
||||
likesCount: 312,
|
||||
commentsCount: 41,
|
||||
post: {
|
||||
id: "p5",
|
||||
content: "Fundraising tip: send the update even when the month was bad. Especially when the month was bad.",
|
||||
author: author("a5", "Samuel Okafor"),
|
||||
mediaItems: [{ mediaType: "image", imageUrl: placeholderImage(30, "Monthly update"), order: 0 }],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "post",
|
||||
publishedAt: "2026-10-17T09:00:00Z",
|
||||
likesCount: 17,
|
||||
commentsCount: 3,
|
||||
post: {
|
||||
id: "p6",
|
||||
content: "Your first ten customers will tell you what the product is. Listen before you build the next feature.",
|
||||
author: author("a6", "Hannah Lindqvist"),
|
||||
mediaItems: [],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const expert = (id: string, displayName: string, byline: string, rating: number, reviewsCount: number): DiscoverExpert => ({
|
||||
id,
|
||||
slug: displayName.replace(/\s+/g, ""),
|
||||
displayName,
|
||||
byline,
|
||||
pictureUrl: null,
|
||||
rating,
|
||||
reviewsCount,
|
||||
available: true,
|
||||
location: { city: null, country: null },
|
||||
});
|
||||
|
||||
export const FIXTURE_FEATURED: DiscoverExpert[] = [
|
||||
expert("e1", "Priya Natarajan", "Pricing and growth advisor", 4.9, 212),
|
||||
expert("e2", "Marcus Bell", "Remote team coach", 4.8, 96),
|
||||
expert("e3", "Elena Kovac", "Product leadership", 4.7, 58),
|
||||
expert("e4", "Samuel Okafor", "Seed-stage fundraising", 5.0, 140),
|
||||
expert("e5", "Hannah Lindqvist", "Customer research", 4.6, 33),
|
||||
];
|
||||
|
||||
const minnect = (id: string, who: DiscoverExpert, question: string, views: number, hue: number): DiscoverMinnect => ({
|
||||
id,
|
||||
question,
|
||||
views,
|
||||
thumbnailUrl: placeholderImage(hue),
|
||||
media: null,
|
||||
expert: { slug: who.slug, displayName: who.displayName, pictureUrl: null, byline: who.byline, rating: who.rating },
|
||||
});
|
||||
|
||||
export const FIXTURE_TRENDING: DiscoverMinnect[] = [
|
||||
minnect("m1", FIXTURE_FEATURED[0], "How do I raise prices without losing my best customers?", 12840, 352),
|
||||
minnect("m2", FIXTURE_FEATURED[3], "What should a pre-seed deck show in the first three slides?", 9310, 30),
|
||||
minnect("m3", FIXTURE_FEATURED[1], "How often should a remote team meet in person?", 6120, 210),
|
||||
minnect("m4", FIXTURE_FEATURED[2], "When is the right time to hire a first product manager?", 4470, 270),
|
||||
minnect("m5", FIXTURE_FEATURED[4], "How many customer interviews are enough before building?", 2015, 150),
|
||||
];
|
||||
|
||||
export const FIXTURE_CATEGORIES: DiscoverCategory[] = [
|
||||
{ id: 1, name: "Business", icon: null, sortOrder: 1 },
|
||||
{ id: 2, name: "Coaching", icon: null, sortOrder: 2 },
|
||||
{ id: 3, name: "Finance", icon: null, sortOrder: 3 },
|
||||
{ id: 4, name: "Product", icon: null, sortOrder: 4 },
|
||||
{ id: 5, name: "Media", icon: null, sortOrder: 5 },
|
||||
];
|
||||
|
||||
export const FIXTURE_DISCOVER: DiscoverData = {
|
||||
featuredExperts: FIXTURE_FEATURED,
|
||||
trendingMinnects: FIXTURE_TRENDING,
|
||||
categories: FIXTURE_CATEGORIES,
|
||||
};
|
||||
|
||||
/** Find experts results: every featured expert plus a few more, filterable by name. */
|
||||
export const FIXTURE_SEARCH_RESULTS: ExpertResult[] = [
|
||||
...FIXTURE_FEATURED,
|
||||
expert("e6", "Daniel Moreau", "Sales operations", 4.5, 21),
|
||||
expert("e7", "Aiko Tanaka", "Brand strategy", 4.8, 77),
|
||||
expert("e8", "Rafael Duarte", "Engineering management", 4.4, 18),
|
||||
].map((e) => ({
|
||||
id: e.id,
|
||||
slug: e.slug,
|
||||
displayName: e.displayName,
|
||||
byline: e.byline,
|
||||
pictureUrl: e.pictureUrl,
|
||||
rating: e.rating,
|
||||
categories: [],
|
||||
}));
|
||||
Reference in New Issue
Block a user