mirror of
https://github.com/dotwee/obsidian-raindropio-plugin.git
synced 2026-07-22 06:50:29 +00:00
feat(renderer): add configurable result display fields
Introduce a display fields option so callers can toggle cover, domain, created date, excerpt, tags and collection per result row. Render an optional cover thumbnail and a collection label resolved from a collection title map. Defaults keep the previous appearance, so existing views render unchanged. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
a41574e926
commit
b643644fb0
2 changed files with 73 additions and 3 deletions
|
|
@ -2,10 +2,47 @@ import type { RaindropItem } from "./raindrop-api";
|
|||
|
||||
export type RaindropStatusKind = "loading" | "empty" | "error" | "info";
|
||||
|
||||
export interface RaindropDisplayFields {
|
||||
cover: boolean;
|
||||
domain: boolean;
|
||||
created: boolean;
|
||||
excerpt: boolean;
|
||||
tags: boolean;
|
||||
collection: boolean;
|
||||
}
|
||||
|
||||
export const DEFAULT_DISPLAY_FIELDS: RaindropDisplayFields = {
|
||||
cover: false,
|
||||
domain: true,
|
||||
created: true,
|
||||
excerpt: true,
|
||||
tags: true,
|
||||
collection: false,
|
||||
};
|
||||
|
||||
export const RAINDROP_FIELD_NAMES = Object.keys(DEFAULT_DISPLAY_FIELDS) as (keyof RaindropDisplayFields)[];
|
||||
|
||||
export function isRaindropFieldName(value: string): value is keyof RaindropDisplayFields {
|
||||
return (RAINDROP_FIELD_NAMES as string[]).includes(value);
|
||||
}
|
||||
|
||||
export function resolveRaindropDisplayFields(
|
||||
defaults: RaindropDisplayFields,
|
||||
show?: (keyof RaindropDisplayFields)[],
|
||||
hide?: (keyof RaindropDisplayFields)[],
|
||||
): RaindropDisplayFields {
|
||||
const fields = { ...defaults };
|
||||
for (const field of show ?? []) fields[field] = true;
|
||||
for (const field of hide ?? []) fields[field] = false;
|
||||
return fields;
|
||||
}
|
||||
|
||||
export interface RenderRaindropOptions {
|
||||
title?: string;
|
||||
warnings?: string[];
|
||||
onTagClick?: (tag: string) => void;
|
||||
fields?: RaindropDisplayFields;
|
||||
collectionTitles?: Map<number, string>;
|
||||
}
|
||||
|
||||
function getDisplayDate(value: string | undefined): string | undefined {
|
||||
|
|
@ -17,6 +54,13 @@ function getDisplayDate(value: string | undefined): string | undefined {
|
|||
return date.toLocaleDateString();
|
||||
}
|
||||
|
||||
function getCollectionTitle(item: RaindropItem, collectionTitles: Map<number, string> | undefined): string | undefined {
|
||||
const collectionId = item.collection?.$id;
|
||||
if (typeof collectionId !== "number") return undefined;
|
||||
|
||||
return collectionTitles?.get(collectionId);
|
||||
}
|
||||
|
||||
export function renderRaindropStatus(container: HTMLElement, message: string, kind: RaindropStatusKind): void {
|
||||
container.empty();
|
||||
container.createDiv({
|
||||
|
|
@ -32,6 +76,7 @@ export function renderRaindropItems(
|
|||
): void {
|
||||
container.empty();
|
||||
|
||||
const fields = options.fields ?? DEFAULT_DISPLAY_FIELDS;
|
||||
const root = container.createDiv({ cls: "raindrop-results" });
|
||||
if (options.title) {
|
||||
root.createEl("h4", { cls: "raindrop-results-title", text: options.title });
|
||||
|
|
@ -52,6 +97,18 @@ export function renderRaindropItems(
|
|||
const list = root.createDiv({ cls: "raindrop-list" });
|
||||
for (const item of items) {
|
||||
const row = list.createDiv({ cls: "raindrop-item" });
|
||||
|
||||
if (fields.cover && item.cover) {
|
||||
row.createEl("img", {
|
||||
cls: "raindrop-item-cover",
|
||||
attr: {
|
||||
src: item.cover,
|
||||
alt: "",
|
||||
loading: "lazy",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const title = row.createEl("a", {
|
||||
cls: "raindrop-item-title",
|
||||
text: item.title || item.link,
|
||||
|
|
@ -63,16 +120,20 @@ export function renderRaindropItems(
|
|||
});
|
||||
title.setAttr("aria-label", `Open ${item.title || item.link}`);
|
||||
|
||||
const metaParts = [item.domain, getDisplayDate(item.created)].filter((part): part is string => Boolean(part));
|
||||
const metaParts = [
|
||||
fields.collection ? getCollectionTitle(item, options.collectionTitles) : undefined,
|
||||
fields.domain ? item.domain : undefined,
|
||||
fields.created ? getDisplayDate(item.created) : undefined,
|
||||
].filter((part): part is string => Boolean(part));
|
||||
if (metaParts.length > 0) {
|
||||
row.createDiv({ cls: "raindrop-item-meta", text: metaParts.join(" - ") });
|
||||
}
|
||||
|
||||
if (item.excerpt) {
|
||||
if (fields.excerpt && item.excerpt) {
|
||||
row.createDiv({ cls: "raindrop-item-excerpt", text: item.excerpt });
|
||||
}
|
||||
|
||||
if (item.tags && item.tags.length > 0) {
|
||||
if (fields.tags && item.tags && item.tags.length > 0) {
|
||||
const tags = row.createDiv({ cls: "raindrop-item-tags" });
|
||||
for (const tag of item.tags) {
|
||||
const tagEl = tags.createEl("a", {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,15 @@
|
|||
background: var(--background-primary);
|
||||
}
|
||||
|
||||
.raindrop-item-cover {
|
||||
border-radius: var(--radius-s);
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
max-height: 8rem;
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.raindrop-item-title {
|
||||
display: inline-block;
|
||||
font-weight: var(--font-semibold);
|
||||
|
|
|
|||
Loading…
Reference in a new issue