summaryrefslogtreecommitdiff
path: root/apps/web/src/lib/stickers/providers/icons.ts
blob: 06b2a4c276d6171a40970b4fc773529aeb0cb92a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import {
	POPULAR_COLLECTIONS,
	getIconSvgUrl,
	searchIcons,
} from "@/lib/iconify-api";
import { buildStickerId, parseStickerId } from "../sticker-id";
import type {
	StickerItem,
	StickerProvider,
	StickerSearchResult,
} from "../types";

const ICONS_PROVIDER_ID = "icons";
const DEFAULT_SEARCH_LIMIT = 100;

const ICONS_PREFIXES = Array.from(
	new Set(
		[...POPULAR_COLLECTIONS.general, ...POPULAR_COLLECTIONS.brands].map(
			(collection) => collection.prefix,
		),
	),
);

const DEFAULT_ICONS_BROWSE = [
	"mdi:home",
	"mdi:star",
	"mdi:heart",
	"mdi:check-circle",
	"mdi:account",
	"mdi:camera",
	"mdi:music",
	"mdi:map-marker",
	"mdi:calendar",
	"mdi:lightning-bolt",
	"mdi:cog",
	"mdi:rocket",
];

function getDisplayNameFromIconName({
	iconName,
}: {
	iconName: string;
}): string {
	const [, rawName = iconName] = iconName.split(":");
	return rawName.replaceAll("-", " ").replaceAll("_", " ");
}

function toStickerItem({ iconName }: { iconName: string }): StickerItem {
	return {
		id: buildStickerId({
			providerId: ICONS_PROVIDER_ID,
			providerValue: iconName,
		}),
		provider: ICONS_PROVIDER_ID,
		name: getDisplayNameFromIconName({ iconName }),
		previewUrl: getIconSvgUrl(iconName, { width: 64, height: 64 }),
		metadata: { iconName },
	};
}

function computeHasMore({
	total,
	limit,
	start = 0,
}: {
	total: number;
	limit: number;
	start?: number;
}): boolean {
	return start + limit < total;
}

export const iconsProvider: StickerProvider = {
	id: ICONS_PROVIDER_ID,
	async search({
		query,
		options,
	}: {
		query: string;
		options?: { limit?: number };
	}): Promise<StickerSearchResult> {
		const limit = options?.limit ?? DEFAULT_SEARCH_LIMIT;
		const searchResult = await searchIcons(query, limit, ICONS_PREFIXES);
		return {
			items: searchResult.icons.map((iconName) => toStickerItem({ iconName })),
			total: searchResult.total,
			hasMore: computeHasMore({
				total: searchResult.total,
				limit: searchResult.limit,
				start: searchResult.start,
			}),
		};
	},
	async browse({
		options,
	}: {
		options?: { page?: number; limit?: number };
	}): Promise<StickerSearchResult> {
		const limit = options?.limit ?? DEFAULT_ICONS_BROWSE.length;
		const items = DEFAULT_ICONS_BROWSE.slice(0, limit).map((iconName) =>
			toStickerItem({ iconName }),
		);
		return {
			items,
			total: items.length,
			hasMore: false,
		};
	},
	resolveUrl({
		stickerId,
		options,
	}: {
		stickerId: string;
		options?: { width?: number; height?: number };
	}): string {
		const { providerValue } = parseStickerId({ stickerId });
		return getIconSvgUrl(providerValue, {
			width: options?.width,
			height: options?.height,
		});
	},
};