189 lines
4.0 KiB
TypeScript
189 lines
4.0 KiB
TypeScript
import { ask, message, open } from "@tauri-apps/plugin-dialog";
|
|
import { readFile } from "@tauri-apps/plugin-fs";
|
|
import { relaunch } from "@tauri-apps/plugin-process";
|
|
import { check } from "@tauri-apps/plugin-updater";
|
|
import { type ClassValue, clsx } from "clsx";
|
|
import dayjs from "dayjs";
|
|
import relativeTime from "dayjs/plugin/relativeTime";
|
|
import updateLocale from "dayjs/plugin/updateLocale";
|
|
import { type NostrEvent, nip19 } from "nostr-tools";
|
|
import { twMerge } from "tailwind-merge";
|
|
|
|
dayjs.extend(relativeTime);
|
|
dayjs.extend(updateLocale);
|
|
|
|
dayjs.updateLocale("en", {
|
|
relativeTime: {
|
|
past: "%s",
|
|
s: "now",
|
|
m: "1m",
|
|
mm: "%dm",
|
|
h: "1h",
|
|
hh: "%dh",
|
|
d: "1d",
|
|
dd: "%dd",
|
|
},
|
|
});
|
|
|
|
export function cn(...inputs: ClassValue[]) {
|
|
return twMerge(clsx(inputs));
|
|
}
|
|
|
|
export function npub(pubkey: string, len: number) {
|
|
if (pubkey.length <= len) return pubkey;
|
|
|
|
const npub = pubkey.startsWith("npub1") ? pubkey : nip19.npubEncode(pubkey);
|
|
const separator = " ... ";
|
|
|
|
const sepLen = separator.length;
|
|
const charsToShow = len - sepLen;
|
|
const frontChars = Math.ceil(charsToShow / 2);
|
|
const backChars = Math.floor(charsToShow / 2);
|
|
|
|
return (
|
|
npub.substring(0, frontChars) +
|
|
separator +
|
|
npub.substring(npub.length - backChars)
|
|
);
|
|
}
|
|
|
|
export function ago(time: number) {
|
|
let formated: string;
|
|
|
|
const now = dayjs();
|
|
const inputTime = dayjs.unix(time);
|
|
const diff = now.diff(inputTime, "hour");
|
|
|
|
if (diff < 24) {
|
|
formated = inputTime.from(now, true);
|
|
} else {
|
|
formated = inputTime.format("MMM DD");
|
|
}
|
|
|
|
return formated;
|
|
}
|
|
|
|
export function time(time: number) {
|
|
const input = new Date(time * 1000);
|
|
const formattedTime = input.toLocaleTimeString([], {
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
hour12: true,
|
|
});
|
|
|
|
return formattedTime;
|
|
}
|
|
|
|
export function getReceivers(tags: string[][]) {
|
|
const p = tags.map((tag) => tag[0] === "p" && tag[1]);
|
|
return p;
|
|
}
|
|
|
|
export function groupEventByDate(events: NostrEvent[]) {
|
|
const groups = Object.groupBy(events, (event) => {
|
|
return dayjs.unix(event.created_at).startOf("day").format("MMM DD, YYYY");
|
|
});
|
|
|
|
return groups;
|
|
}
|
|
|
|
/*
|
|
export function isEmojiOnly(str: string) {
|
|
const stringToTest = str.replace(/ /g, "");
|
|
const emojiRegex =
|
|
/^(?:(?:\p{RI}\p{RI}|\p{Emoji}(?:\p{Emoji_Modifier}|\u{FE0F}\u{20E3}?|[\u{E0020}-\u{E007E}]+\u{E007F})?(?:\u{200D}\p{Emoji}(?:\p{Emoji_Modifier}|\u{FE0F}\u{20E3}?|[\u{E0020}-\u{E007E}]+\u{E007F})?)*)|[\u{1f900}-\u{1f9ff}\u{2600}-\u{26ff}\u{2700}-\u{27bf}])+$/u;
|
|
return emojiRegex.test(stringToTest) && Number.isNaN(Number(stringToTest));
|
|
}
|
|
*/
|
|
|
|
export async function checkForAppUpdates(silent: boolean) {
|
|
try {
|
|
const update = await check();
|
|
|
|
if (!update) {
|
|
if (silent) return;
|
|
|
|
await message("You are on the latest version. Stay awesome!", {
|
|
title: "No Update Available",
|
|
kind: "info",
|
|
okLabel: "OK",
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
if (update?.available) {
|
|
const yes = await ask(
|
|
`Update to ${update.version} is available!\n\nRelease notes: ${update.body}`,
|
|
{
|
|
title: "Update Available",
|
|
kind: "info",
|
|
okLabel: "Update",
|
|
cancelLabel: "Cancel",
|
|
},
|
|
);
|
|
|
|
if (yes) {
|
|
await update.downloadAndInstall();
|
|
await relaunch();
|
|
}
|
|
|
|
return;
|
|
}
|
|
} catch {
|
|
return;
|
|
}
|
|
}
|
|
|
|
export async function upload() {
|
|
const allowExts = [
|
|
"png",
|
|
"jpeg",
|
|
"jpg",
|
|
"gif",
|
|
"mp4",
|
|
"mp3",
|
|
"webm",
|
|
"mkv",
|
|
"avi",
|
|
"mov",
|
|
];
|
|
|
|
const selected = await open({
|
|
multiple: false,
|
|
filters: [
|
|
{
|
|
name: "Media",
|
|
extensions: allowExts,
|
|
},
|
|
],
|
|
});
|
|
|
|
// User cancelled action
|
|
if (!selected) return null;
|
|
|
|
try {
|
|
const selectedPath = selected.path;
|
|
const file = await readFile(selectedPath);
|
|
const blob = new Blob([file]);
|
|
|
|
const data = new FormData();
|
|
data.append("fileToUpload", blob);
|
|
data.append("submit", "Upload Image");
|
|
|
|
const res = await fetch("https://nostr.build/api/v2/upload/files", {
|
|
method: "POST",
|
|
body: data,
|
|
});
|
|
|
|
if (!res.ok) return null;
|
|
|
|
const json = await res.json();
|
|
const content = json.data[0];
|
|
|
|
return content.url as string;
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|