Files
homefeed/frontend/src/lib/api.ts
T
Claude 55622d0a1a Add 1/2/3-column layout option to the Bookmarks widget
The bookmarks list can now render as 1 (default), 2, or 3 columns
instead of always being a single-column list, admin-configurable via
a pill picker on the Widgets tab. Column count lives in widget_kv
(same idiom as weather's config) and rides along in the public
GET /api/widget/bookmarks response so the sidebar picks it up without
a separate request.
2026-08-01 23:55:18 +00:00

68 lines
2.5 KiB
TypeScript

import { getBackendUrl } from './config';
import type { MergedArticle, Tag, TrackedEventPublic, Category, Weather, StockTicker, BookmarksFeed, Poe2Data, WidgetsEnabled } from './types';
async function get<T>(path: string, fetchFn: typeof fetch = fetch): Promise<T> {
// credentials: 'include' so the private-access cookie (see lib/privateAccess.ts)
// is sent cross-origin to the backend, revealing private categories/articles to
// anyone who's logged in — without it every request would look unauthenticated.
const res = await fetchFn(`${getBackendUrl()}${path}`, { credentials: 'include' });
if (!res.ok) throw new Error(`Request failed: ${path} (${res.status})`);
return res.json();
}
export interface FeedParams {
category?: string;
geo?: string;
eventId?: string;
tag?: string;
before?: string;
limit?: number;
}
export function getFeed(params: FeedParams = {}, fetchFn?: typeof fetch): Promise<MergedArticle[]> {
const qs = new URLSearchParams(
Object.fromEntries(Object.entries(params).filter(([, v]) => v !== undefined).map(([k, v]) => [k, String(v)]))
).toString();
return get<MergedArticle[]>(`/api/feed${qs ? `?${qs}` : ''}`, fetchFn);
}
export function getArticle(id: string, fetchFn?: typeof fetch): Promise<MergedArticle> {
return get<MergedArticle>(`/api/article/${id}`, fetchFn);
}
export function getTags(fetchFn?: typeof fetch): Promise<Tag[]> {
return get<Tag[]>('/api/tags', fetchFn);
}
export function getTagBySlug(slug: string, fetchFn?: typeof fetch): Promise<Tag> {
return get<Tag>(`/api/tag/${slug}`, fetchFn);
}
export function getEvents(fetchFn?: typeof fetch): Promise<TrackedEventPublic[]> {
return get<TrackedEventPublic[]>('/api/events', fetchFn);
}
export function getCategories(fetchFn?: typeof fetch): Promise<Category[]> {
return get<Category[]>('/api/categories', fetchFn);
}
export function getWeather(fetchFn?: typeof fetch): Promise<Weather> {
return get<Weather>('/api/widget/weather', fetchFn);
}
export function getStocks(fetchFn?: typeof fetch): Promise<StockTicker[]> {
return get<StockTicker[]>('/api/widget/stocks', fetchFn);
}
export function getBookmarks(fetchFn?: typeof fetch): Promise<BookmarksFeed> {
return get<BookmarksFeed>('/api/widget/bookmarks', fetchFn);
}
export function getPoe2(fetchFn?: typeof fetch): Promise<Poe2Data> {
return get<Poe2Data>('/api/widget/poe2', fetchFn);
}
export function getWidgetsEnabled(fetchFn?: typeof fetch): Promise<WidgetsEnabled> {
return get<WidgetsEnabled>('/api/widgets', fetchFn);
}