1import { MessageId, ProjectId, ThreadId } from "@t3tools/contracts";
2import { isMacPlatform } from "@t3tools/shared/keybindings";
3import { type CxOptions, cx } from "class-variance-authority";
4import * as Hex from "effect/encoding/Hex";
5import { extendTailwindMerge } from "tailwind-merge";
6import { DraftId } from "../composerDraftStore";
7
8// The theme's extra font sizes (index.css). Unregistered, tailwind-merge reads
9// text-2xs as a colour and drops it next to text-muted-foreground.
10const twMerge = extendTailwindMerge({ extend: { theme: { text: ["2xs", "3xs", "4xs", "5xs"] } } });
11
12export function cn(...inputs: CxOptions) {
13 return twMerge(cx(inputs));
14}
15
16export { isMacPlatform };
17
18export function isWindowsPlatform(platform: string): boolean {
19 return /^win(dows)?/i.test(platform);
20}
21
22export function normalizeSearchText(value: string): string {
23 return value.normalize("NFKD").replace(/\p{M}/gu, "").toLowerCase().replace(/\s+/g, " ").trim();
24}
25
26export function getLocalFileManagerName(platform: string): string {
27 if (isMacPlatform(platform)) {
28 return "Finder";
29 }
30 if (isWindowsPlatform(platform)) {
31 return "File Explorer";
32 }
33 return "Files";
34}
35
36export function randomUUID(): string {
37 const bytes = globalThis.crypto.getRandomValues(new Uint8Array(16));
38 bytes[6] = (bytes[6]! & 0x0f) | 0x40;
39 bytes[8] = (bytes[8]! & 0x3f) | 0x80;
40 const hex = Hex.encode(bytes);
41 return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
42}
43
44export const newProjectId = (): ProjectId => ProjectId.make(randomUUID());
45
46export const newThreadId = (): ThreadId => ThreadId.make(randomUUID());
47
48export const newDraftId = (): DraftId => DraftId.make(randomUUID());
49
50export const newMessageId = (): MessageId => MessageId.make(randomUUID());