mirror of
https://github.com/System-End/hackatime.git
synced 2026-04-19 16:38:23 +00:00
* make leaderboards go vrooom * goog * Make leaderboards great again * Bit o' cleanup? * goog * goog * Greptile
112 lines
3.6 KiB
TypeScript
112 lines
3.6 KiB
TypeScript
export const pluralize = (count: number, singular: string, plural: string) =>
|
|
count === 1 ? singular : plural;
|
|
|
|
export const toSentence = (items: string[]) => {
|
|
if (items.length === 0) return "";
|
|
if (items.length === 1) return items[0];
|
|
if (items.length === 2) return `${items[0]} and ${items[1]}`;
|
|
return `${items.slice(0, -1).join(", ")}, and ${items[items.length - 1]}`;
|
|
};
|
|
|
|
export const secondsToDisplay = (seconds?: number) => {
|
|
if (!seconds) return "0m";
|
|
const hours = Math.floor(seconds / 3600);
|
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|
return hours > 0 ? (minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`) : `${minutes}m`;
|
|
};
|
|
|
|
export const secondsToDetailedDisplay = (seconds: number) => {
|
|
const h = Math.floor(seconds / 3600);
|
|
const m = Math.floor((seconds % 3600) / 60);
|
|
const s = seconds % 60;
|
|
const parts: string[] = [];
|
|
if (h > 0) parts.push(`${h}h`);
|
|
if (m > 0) parts.push(`${m}m`);
|
|
if (s > 0) parts.push(`${s}s`);
|
|
return parts.join(" ") || "0s";
|
|
};
|
|
|
|
export const secondsToCompactDisplay = (seconds?: number) => {
|
|
if (!seconds) return "0m";
|
|
const hours = Math.floor(seconds / 3600);
|
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|
return hours > 0 ? `${hours}h` : `${minutes}m`;
|
|
};
|
|
|
|
export const durationInWords = (seconds: number): string => {
|
|
if (seconds < 60) return "less than a minute";
|
|
const hours = Math.floor(seconds / 3600);
|
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|
if (hours > 0) return `about ${hours} ${hours === 1 ? "hour" : "hours"}`;
|
|
return `${minutes} ${minutes === 1 ? "minute" : "minutes"}`;
|
|
};
|
|
|
|
export const percentOf = (value: number, max: number) => {
|
|
if (!max || max === 0) return 0;
|
|
return Math.max(2, Math.round((value / max) * 100));
|
|
};
|
|
|
|
export const logScale = (value: number, maxVal: number): number => {
|
|
if (value === 0) return 0;
|
|
const minPercent = 5;
|
|
const maxPercent = 100;
|
|
const linearRatio = value / maxVal;
|
|
const logRatio = Math.log(value + 1) / Math.log(maxVal + 1);
|
|
const linearWeight = 0.8;
|
|
const logWeight = 0.2;
|
|
const scaled =
|
|
minPercent +
|
|
(linearWeight * linearRatio + logWeight * logRatio) *
|
|
(maxPercent - minPercent);
|
|
return Math.min(Math.round(scaled), maxPercent);
|
|
};
|
|
|
|
export const timeAgo = (isoString: string) => {
|
|
const diff = Date.now() - new Date(isoString).getTime();
|
|
const mins = Math.floor(diff / 60000);
|
|
if (mins < 1) return "just now";
|
|
if (mins < 60) return `${mins} minute${mins === 1 ? "" : "s"} ago`;
|
|
const hours = Math.floor(mins / 60);
|
|
if (hours < 24) return `${hours} hour${hours === 1 ? "" : "s"} ago`;
|
|
const days = Math.floor(hours / 24);
|
|
return `${days} day${days === 1 ? "" : "s"} ago`;
|
|
};
|
|
|
|
export const streakTheme = (count: number) => {
|
|
if (count >= 30)
|
|
return {
|
|
bg: "from-blue/20 to-purple/20",
|
|
hbg: "hover:from-blue/30 hover:to-purple/30",
|
|
bc: "border-blue",
|
|
ic: "text-blue",
|
|
tc: "text-blue",
|
|
tm: "text-blue",
|
|
};
|
|
if (count >= 7)
|
|
return {
|
|
bg: "from-red/20 to-orange/20",
|
|
hbg: "hover:from-red/30 hover:to-orange/30",
|
|
bc: "border-red",
|
|
ic: "text-red",
|
|
tc: "text-red",
|
|
tm: "text-red",
|
|
};
|
|
return {
|
|
bg: "from-orange/20 to-yellow/20",
|
|
hbg: "hover:from-orange/30 hover:to-yellow/30",
|
|
bc: "border-orange",
|
|
ic: "text-orange",
|
|
tc: "text-orange",
|
|
tm: "text-orange",
|
|
};
|
|
};
|
|
|
|
export const streakLabel = (count: number) =>
|
|
count > 30 ? "30+" : `${count}`;
|
|
|
|
export const rankDisplay = (index: number) => {
|
|
if (index === 0) return "🥇";
|
|
if (index === 1) return "🥈";
|
|
if (index === 2) return "🥉";
|
|
return `${index + 1}`;
|
|
};
|