summaryrefslogtreecommitdiff
path: root/apps/web/src/lib/stickers/providers/shapes.ts
blob: 81873dcb83ce4eb07040b92852f35926a2d7366d (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
import { buildStickerId, parseStickerId } from "../sticker-id";
import type {
	StickerItem,
	StickerProvider,
	StickerSearchResult,
} from "../types";

const SHAPES_PROVIDER_ID = "shapes";

const SHAPES = [
	{ key: "circle", name: "Circle" },
	{ key: "square", name: "Square" },
	{ key: "triangle", name: "Triangle" },
	{ key: "star", name: "Star" },
	{ key: "hexagon", name: "Hexagon" },
	{ key: "diamond", name: "Diamond" },
] as const;

function buildShapeUrl({ shapeKey }: { shapeKey: string }): string {
	return `/shapes/${shapeKey}.svg`;
}

function toStickerItem({
	shape,
}: {
	shape: (typeof SHAPES)[number];
}): StickerItem {
	return {
		id: buildStickerId({
			providerId: SHAPES_PROVIDER_ID,
			providerValue: shape.key,
		}),
		provider: SHAPES_PROVIDER_ID,
		name: shape.name,
		previewUrl: buildShapeUrl({ shapeKey: shape.key }),
		metadata: { shape: shape.key },
	};
}

function filterShapesByQuery({
	query,
}: {
	query: string;
}): Array<(typeof SHAPES)[number]> {
	const normalizedQuery = query.trim().toLowerCase();
	if (!normalizedQuery) {
		return [...SHAPES];
	}

	return SHAPES.filter((shape) =>
		shape.name.toLowerCase().includes(normalizedQuery),
	);
}

function paginateShapes({
	shapes,
	options,
}: {
	shapes: Array<(typeof SHAPES)[number]>;
	options?: { page?: number; limit?: number };
}): { items: Array<(typeof SHAPES)[number]>; hasMore: boolean; total: number } {
	const page = Math.max(1, options?.page ?? 1);
	const limit = Math.max(1, options?.limit ?? SHAPES.length);
	const startIndex = (page - 1) * limit;
	const endIndex = startIndex + limit;
	const pagedItems = shapes.slice(startIndex, endIndex);
	return {
		items: pagedItems,
		hasMore: endIndex < shapes.length,
		total: shapes.length,
	};
}

export const shapesProvider: StickerProvider = {
	id: SHAPES_PROVIDER_ID,
	async search({
		query,
		options,
	}: {
		query: string;
		options?: { limit?: number };
	}): Promise<StickerSearchResult> {
		const filteredShapes = filterShapesByQuery({ query });
		const paged = paginateShapes({
			shapes: filteredShapes,
			options: { page: 1, limit: options?.limit ?? SHAPES.length },
		});
		return {
			items: paged.items.map((shape) => toStickerItem({ shape })),
			total: paged.total,
			hasMore: paged.hasMore,
		};
	},
	async browse({
		options,
	}: {
		options?: { page?: number; limit?: number };
	}): Promise<StickerSearchResult> {
		const paged = paginateShapes({
			shapes: [...SHAPES],
			options,
		});
		return {
			items: paged.items.map((shape) => toStickerItem({ shape })),
			total: paged.total,
			hasMore: paged.hasMore,
		};
	},
	resolveUrl({
		stickerId,
	}: {
		stickerId: string;
		options?: { width?: number; height?: number };
	}): string {
		const { providerValue } = parseStickerId({ stickerId });
		return buildShapeUrl({ shapeKey: providerValue });
	},
};