diff --git a/.yarn/cache/aveta-npm-1.5.2-2bc9533fb8-48381cbc42.zip b/.yarn/cache/aveta-npm-1.5.2-2bc9533fb8-48381cbc42.zip deleted file mode 100644 index c69a12e5b..000000000 Binary files a/.yarn/cache/aveta-npm-1.5.2-2bc9533fb8-48381cbc42.zip and /dev/null differ diff --git a/.yarn/cache/cliui-npm-8.0.1-3b029092cf-eaa5561aeb.zip b/.yarn/cache/cliui-npm-8.0.1-3b029092cf-eaa5561aeb.zip deleted file mode 100644 index 8701b6450..000000000 Binary files a/.yarn/cache/cliui-npm-8.0.1-3b029092cf-eaa5561aeb.zip and /dev/null differ diff --git a/.yarn/cache/get-caller-file-npm-2.0.5-80e8a86305-b9769a836d.zip b/.yarn/cache/get-caller-file-npm-2.0.5-80e8a86305-b9769a836d.zip deleted file mode 100644 index 0aa2c9cd0..000000000 Binary files a/.yarn/cache/get-caller-file-npm-2.0.5-80e8a86305-b9769a836d.zip and /dev/null differ diff --git a/.yarn/cache/require-directory-npm-2.1.1-8608aee50b-a72468e258.zip b/.yarn/cache/require-directory-npm-2.1.1-8608aee50b-a72468e258.zip deleted file mode 100644 index bc4ba9cb9..000000000 Binary files a/.yarn/cache/require-directory-npm-2.1.1-8608aee50b-a72468e258.zip and /dev/null differ diff --git a/.yarn/cache/y18n-npm-5.0.8-5f3a0a7e62-5f1b5f95e3.zip b/.yarn/cache/y18n-npm-5.0.8-5f3a0a7e62-5f1b5f95e3.zip deleted file mode 100644 index 8237762e5..000000000 Binary files a/.yarn/cache/y18n-npm-5.0.8-5f3a0a7e62-5f1b5f95e3.zip and /dev/null differ diff --git a/.yarn/cache/yargs-npm-17.7.2-80b62638e1-abb3e37678.zip b/.yarn/cache/yargs-npm-17.7.2-80b62638e1-abb3e37678.zip deleted file mode 100644 index 44b97347f..000000000 Binary files a/.yarn/cache/yargs-npm-17.7.2-80b62638e1-abb3e37678.zip and /dev/null differ diff --git a/.yarn/cache/yargs-parser-npm-21.1.1-8fdc003314-9dc2c217ea.zip b/.yarn/cache/yargs-parser-npm-21.1.1-8fdc003314-9dc2c217ea.zip deleted file mode 100644 index 32e7f6b59..000000000 Binary files a/.yarn/cache/yargs-parser-npm-21.1.1-8fdc003314-9dc2c217ea.zip and /dev/null differ diff --git a/plugins/google-search-console/package.json b/plugins/google-search-console/package.json index 1f047b2f0..0a532a93c 100644 --- a/plugins/google-search-console/package.json +++ b/plugins/google-search-console/package.json @@ -10,11 +10,11 @@ "check-eslint": "run g:check-eslint", "pack": "run g:pack", "preview": "run g:preview", - "check-typescript": "run g:check-typescript" + "check-typescript": "run g:check-typescript", + "check-vitest": "run g:check-vitest" }, "dependencies": { "@ataverascrespo/react18-ts-textfit": "^1.0.0", - "aveta": "^1.5.2", "cheerio": "^1.1.2", "framer-plugin": "3.11.0-alpha.12", "react": "^18.3.1", diff --git a/plugins/google-search-console/src/formatStat.test.ts b/plugins/google-search-console/src/formatStat.test.ts new file mode 100644 index 000000000..2de80b961 --- /dev/null +++ b/plugins/google-search-console/src/formatStat.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, it } from "vitest" +import { formatStat } from "./formatStat" + +describe("formatStat", () => { + it("keeps values below one thousand unchanged", () => { + expect(formatStat(0)).toBe("0") + expect(formatStat(12)).toBe("12") + expect(formatStat(999)).toBe("999") + }) + + it("abbreviates large values with one decimal place", () => { + expect(formatStat(1000)).toBe("1K") + expect(formatStat(1234)).toBe("1.2K") + expect(formatStat(10_500)).toBe("10.5K") + expect(formatStat(1_200_000)).toBe("1.2M") + }) + + it("carries rounded values into the next unit", () => { + expect(formatStat(999_950)).toBe("1M") + }) + + it("preserves negative values", () => { + expect(formatStat(-1234)).toBe("-1.2K") + }) + + it("returns a dash for non-finite values", () => { + expect(formatStat(Number.POSITIVE_INFINITY)).toBe("—") + expect(formatStat(Number.NaN)).toBe("—") + }) +}) diff --git a/plugins/google-search-console/src/formatStat.ts b/plugins/google-search-console/src/formatStat.ts new file mode 100644 index 000000000..b12f42a7c --- /dev/null +++ b/plugins/google-search-console/src/formatStat.ts @@ -0,0 +1,31 @@ +const statUnits = ["", "K", "M", "B", "T", "P", "E"] as const + +export function formatStat(value: number) { + if (!Number.isFinite(value)) { + return "—" + } + + const sign = value < 0 ? "-" : "" + let scaledValue = Math.abs(value) + let unitIndex = 0 + + while (scaledValue >= 1000 && unitIndex < statUnits.length - 1) { + scaledValue /= 1000 + unitIndex += 1 + } + + if (scaledValue >= 1000) { + return value.toString() + } + + let roundedValue = Number.isInteger(scaledValue) ? scaledValue : Number(scaledValue.toFixed(1)) + + while (roundedValue >= 1000 && unitIndex < statUnits.length - 1) { + roundedValue /= 1000 + unitIndex += 1 + } + + const unit = statUnits[unitIndex] ?? "" + + return `${sign}${roundedValue.toString()}${unit}` +} diff --git a/plugins/google-search-console/src/screens/Performance.tsx b/plugins/google-search-console/src/screens/Performance.tsx index 9fc6b4ecd..8bcd0ada9 100644 --- a/plugins/google-search-console/src/screens/Performance.tsx +++ b/plugins/google-search-console/src/screens/Performance.tsx @@ -1,9 +1,9 @@ -import aveta from "aveta" import { type CSSProperties, useMemo, useState } from "react" import { Area, AreaChart, ResponsiveContainer, Tooltip, type TooltipContentProps, XAxis } from "recharts" import type { NameType, Payload, ValueType } from "recharts/types/component/DefaultTooltipContent" import FitText from "../components/FitText" import Loading from "../components/Loading" +import { formatStat } from "../formatStat" import type { GoogleQueryResult } from "../types" import { mapQueries } from "../utils" @@ -151,7 +151,7 @@ export default function Performance({ performance }: PerformanceProps) { }} >
- {aveta(totalClicks)} + {formatStat(totalClicks)}
{`Click${totalClicks === 1 ? "" : "s"}`}
@@ -166,7 +166,7 @@ export default function Performance({ performance }: PerformanceProps) { }} >
- {aveta(totalImpressions)} + {formatStat(totalImpressions)}
{`Impression${totalImpressions === 1 ? "" : "s"}`}
diff --git a/yarn.lock b/yarn.lock index 3d942c8d0..85d1d2ba3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3841,17 +3841,6 @@ __metadata: languageName: node linkType: hard -"aveta@npm:^1.5.2": - version: 1.5.2 - resolution: "aveta@npm:1.5.2" - dependencies: - yargs: "npm:^17.3.1" - bin: - aveta: bin/aveta - checksum: 10/48381cbc4217d65432185bd0667308a38d9b2f0531187f9348a858f48bfe4673afd0d45a3fbec019519dc2b4d1bfd9113041dc544d2bcd1159847737770a546e - languageName: node - linkType: hard - "axios@npm:^1.8.3": version: 1.13.6 resolution: "axios@npm:1.13.6" @@ -4132,17 +4121,6 @@ __metadata: languageName: node linkType: hard -"cliui@npm:^8.0.1": - version: 8.0.1 - resolution: "cliui@npm:8.0.1" - dependencies: - string-width: "npm:^4.2.0" - strip-ansi: "npm:^6.0.1" - wrap-ansi: "npm:^7.0.0" - checksum: 10/eaa5561aeb3135c2cddf7a3b3f562fc4238ff3b3fc666869ef2adf264be0f372136702f16add9299087fb1907c2e4ec5dbfe83bd24bce815c70a80c6c1a2e950 - languageName: node - linkType: hard - "clsx@npm:^2.1.1": version: 2.1.1 resolution: "clsx@npm:2.1.1" @@ -4998,7 +4976,7 @@ __metadata: languageName: node linkType: hard -"escalade@npm:^3.1.1, escalade@npm:^3.2.0": +"escalade@npm:^3.2.0": version: 3.2.0 resolution: "escalade@npm:3.2.0" checksum: 10/9d7169e3965b2f9ae46971afa392f6e5a25545ea30f2e2dd99c9b0a95a3f52b5653681a84f5b2911a413ddad2d7a93d3514165072f349b5ffc59c75a899970d6 @@ -5481,13 +5459,6 @@ __metadata: languageName: node linkType: hard -"get-caller-file@npm:^2.0.5": - version: 2.0.5 - resolution: "get-caller-file@npm:2.0.5" - checksum: 10/b9769a836d2a98c3ee734a88ba712e62703f1df31b94b784762c433c27a386dd6029ff55c2a920c392e33657d80191edbf18c61487e198844844516f843496b9 - languageName: node - linkType: hard - "get-nonce@npm:^1.0.0": version: 1.0.1 resolution: "get-nonce@npm:1.0.1" @@ -5583,7 +5554,6 @@ __metadata: "@ataverascrespo/react18-ts-textfit": "npm:^1.0.0" "@types/react": "npm:^18.3.24" "@types/react-dom": "npm:^18.3.7" - aveta: "npm:^1.5.2" cheerio: "npm:^1.1.2" framer-plugin: "npm:3.11.0-alpha.12" react: "npm:^18.3.1" @@ -7620,13 +7590,6 @@ __metadata: languageName: unknown linkType: soft -"require-directory@npm:^2.1.1": - version: 2.1.1 - resolution: "require-directory@npm:2.1.1" - checksum: 10/a72468e2589270d91f06c7d36ec97a88db53ae5d6fe3787fadc943f0b0276b10347f89b363b2a82285f650bdcc135ad4a257c61bdd4d00d6df1fa24875b0ddaf - languageName: node - linkType: hard - "reselect@npm:5.1.1, reselect@npm:^5.1.0": version: 5.1.1 resolution: "reselect@npm:5.1.1" @@ -8060,7 +8023,7 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -9152,7 +9115,7 @@ __metadata: languageName: node linkType: hard -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" dependencies: @@ -9189,13 +9152,6 @@ __metadata: languageName: node linkType: hard -"y18n@npm:^5.0.5": - version: 5.0.8 - resolution: "y18n@npm:5.0.8" - checksum: 10/5f1b5f95e3775de4514edbb142398a2c37849ccfaf04a015be5d75521e9629d3be29bd4432d23c57f37e5b61ade592fb0197022e9993f81a06a5afbdcda9346d - languageName: node - linkType: hard - "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" @@ -9210,28 +9166,6 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:^21.1.1": - version: 21.1.1 - resolution: "yargs-parser@npm:21.1.1" - checksum: 10/9dc2c217ea3bf8d858041252d43e074f7166b53f3d010a8c711275e09cd3d62a002969a39858b92bbda2a6a63a585c7127014534a560b9c69ed2d923d113406e - languageName: node - linkType: hard - -"yargs@npm:^17.3.1": - version: 17.7.2 - resolution: "yargs@npm:17.7.2" - dependencies: - cliui: "npm:^8.0.1" - escalade: "npm:^3.1.1" - get-caller-file: "npm:^2.0.5" - require-directory: "npm:^2.1.1" - string-width: "npm:^4.2.3" - y18n: "npm:^5.0.5" - yargs-parser: "npm:^21.1.1" - checksum: 10/abb3e37678d6e38ea85485ed86ebe0d1e3464c640d7d9069805ea0da12f69d5a32df8e5625e370f9c96dd1c2dc088ab2d0a4dd32af18222ef3c4224a19471576 - languageName: node - linkType: hard - "yocto-queue@npm:^0.1.0": version: 0.1.0 resolution: "yocto-queue@npm:0.1.0"