From 789b8470b6d394b6a00d21ba9823590821700f1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=BCl=C3=B6p=20Kov=C3=A1cs?= <43729152+fulopkovacs@users.noreply.github.com> Date: Tue, 13 Jan 2026 13:51:52 +0100 Subject: [PATCH] highlight the json content of the api requests --- package.json | 1 + pnpm-lock.yaml | 66 +++++++++++++++++++++++++++++ src/components/ApiRequestsPanel.tsx | 8 ++-- src/components/CodeHighlighter.tsx | 55 ++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 src/components/CodeHighlighter.tsx diff --git a/package.json b/package.json index 4464c1f..280d4a6 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "react": "^19.2.0", "react-dom": "^19.2.0", "react-resizable-panels": "^3.0.6", + "shiki": "^3.21.0", "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.17", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c2a5503..9ef3c00 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -146,6 +146,9 @@ importers: react-resizable-panels: specifier: ^3.0.6 version: 3.0.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + shiki: + specifier: ^3.21.0 + version: 3.21.0 sonner: specifier: ^2.0.7 version: 2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -1869,27 +1872,45 @@ packages: '@shikijs/core@3.20.0': resolution: {integrity: sha512-f2ED7HYV4JEk827mtMDwe/yQ25pRiXZmtHjWF8uzZKuKiEsJR7Ce1nuQ+HhV9FzDcbIo4ObBCD9GPTzNuy9S1g==} + '@shikijs/core@3.21.0': + resolution: {integrity: sha512-AXSQu/2n1UIQekY8euBJlvFYZIw0PHY63jUzGbrOma4wPxzznJXTXkri+QcHeBNaFxiiOljKxxJkVSoB3PjbyA==} + '@shikijs/engine-javascript@3.20.0': resolution: {integrity: sha512-OFx8fHAZuk7I42Z9YAdZ95To6jDePQ9Rnfbw9uSRTSbBhYBp1kEOKv/3jOimcj3VRUKusDYM6DswLauwfhboLg==} + '@shikijs/engine-javascript@3.21.0': + resolution: {integrity: sha512-ATwv86xlbmfD9n9gKRiwuPpWgPENAWCLwYCGz9ugTJlsO2kOzhOkvoyV/UD+tJ0uT7YRyD530x6ugNSffmvIiQ==} + '@shikijs/engine-oniguruma@3.20.0': resolution: {integrity: sha512-Yx3gy7xLzM0ZOjqoxciHjA7dAt5tyzJE3L4uQoM83agahy+PlW244XJSrmJRSBvGYELDhYXPacD4R/cauV5bzQ==} + '@shikijs/engine-oniguruma@3.21.0': + resolution: {integrity: sha512-OYknTCct6qiwpQDqDdf3iedRdzj6hFlOPv5hMvI+hkWfCKs5mlJ4TXziBG9nyabLwGulrUjHiCq3xCspSzErYQ==} + '@shikijs/langs@3.20.0': resolution: {integrity: sha512-le+bssCxcSHrygCWuOrYJHvjus6zhQ2K7q/0mgjiffRbkhM4o1EWu2m+29l0yEsHDbWaWPNnDUTRVVBvBBeKaA==} + '@shikijs/langs@3.21.0': + resolution: {integrity: sha512-g6mn5m+Y6GBJ4wxmBYqalK9Sp0CFkUqfNzUy2pJglUginz6ZpWbaWjDB4fbQ/8SHzFjYbtU6Ddlp1pc+PPNDVA==} + '@shikijs/rehype@3.20.0': resolution: {integrity: sha512-/sqob3V/lJK0m2mZ64nkcWPN88im0D9atkI3S3PUBvtJZTHnJXVwZhHQFRDyObgEIa37IpHYHR3CuFtXB5bT2g==} '@shikijs/themes@3.20.0': resolution: {integrity: sha512-U1NSU7Sl26Q7ErRvJUouArxfM2euWqq1xaSrbqMu2iqa+tSp0D1Yah8216sDYbdDHw4C8b75UpE65eWorm2erQ==} + '@shikijs/themes@3.21.0': + resolution: {integrity: sha512-BAE4cr9EDiZyYzwIHEk7JTBJ9CzlPuM4PchfcA5ao1dWXb25nv6hYsoDiBq2aZK9E3dlt3WB78uI96UESD+8Mw==} + '@shikijs/transformers@3.20.0': resolution: {integrity: sha512-PrHHMRr3Q5W1qB/42kJW6laqFyWdhrPF2hNR9qjOm1xcSiAO3hAHo7HaVyHE6pMyevmy3i51O8kuGGXC78uK3g==} '@shikijs/types@3.20.0': resolution: {integrity: sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw==} + '@shikijs/types@3.21.0': + resolution: {integrity: sha512-zGrWOxZ0/+0ovPY7PvBU2gIS9tmhSUUt30jAcNV0Bq0gb2S98gwfjIs1vxlmH5zM7/4YxLamT6ChlqqAJmPPjA==} + '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} @@ -3661,6 +3682,9 @@ packages: shiki@3.20.0: resolution: {integrity: sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg==} + shiki@3.21.0: + resolution: {integrity: sha512-N65B/3bqL/TI2crrXr+4UivctrAGEjmsib5rPMMPpFp1xAx/w03v8WZ9RDDFYteXoEgY7qZ4HGgl5KBIu1153w==} + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -5537,21 +5561,43 @@ snapshots: '@types/hast': 3.0.4 hast-util-to-html: 9.0.5 + '@shikijs/core@3.21.0': + dependencies: + '@shikijs/types': 3.21.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + '@shikijs/engine-javascript@3.20.0': dependencies: '@shikijs/types': 3.20.0 '@shikijs/vscode-textmate': 10.0.2 oniguruma-to-es: 4.3.4 + '@shikijs/engine-javascript@3.21.0': + dependencies: + '@shikijs/types': 3.21.0 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.4 + '@shikijs/engine-oniguruma@3.20.0': dependencies: '@shikijs/types': 3.20.0 '@shikijs/vscode-textmate': 10.0.2 + '@shikijs/engine-oniguruma@3.21.0': + dependencies: + '@shikijs/types': 3.21.0 + '@shikijs/vscode-textmate': 10.0.2 + '@shikijs/langs@3.20.0': dependencies: '@shikijs/types': 3.20.0 + '@shikijs/langs@3.21.0': + dependencies: + '@shikijs/types': 3.21.0 + '@shikijs/rehype@3.20.0': dependencies: '@shikijs/types': 3.20.0 @@ -5565,6 +5611,10 @@ snapshots: dependencies: '@shikijs/types': 3.20.0 + '@shikijs/themes@3.21.0': + dependencies: + '@shikijs/types': 3.21.0 + '@shikijs/transformers@3.20.0': dependencies: '@shikijs/core': 3.20.0 @@ -5575,6 +5625,11 @@ snapshots: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 + '@shikijs/types@3.21.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + '@shikijs/vscode-textmate@10.0.2': {} '@sindresorhus/is@7.1.1': {} @@ -7775,6 +7830,17 @@ snapshots: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 + shiki@3.21.0: + dependencies: + '@shikijs/core': 3.21.0 + '@shikijs/engine-javascript': 3.21.0 + '@shikijs/engine-oniguruma': 3.21.0 + '@shikijs/langs': 3.21.0 + '@shikijs/themes': 3.21.0 + '@shikijs/types': 3.21.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + siginfo@2.0.0: {} simple-concat@1.0.1: diff --git a/src/components/ApiRequestsPanel.tsx b/src/components/ApiRequestsPanel.tsx index c5eb9b9..56beb0d 100644 --- a/src/components/ApiRequestsPanel.tsx +++ b/src/components/ApiRequestsPanel.tsx @@ -15,6 +15,7 @@ import { userPreferencesCollection } from "@/collections/UserPreferences"; import { cn } from "@/lib/utils"; import { HighlightWrapper } from "@/utils/highlight-collection-related-info"; import { USER_PLACEHOLDER } from "@/utils/USER_PLACEHOLDER_CONSTANT"; +import { CodeHighlighter } from "./CodeHighlighter"; import { Badge } from "./ui/badge"; import { Button } from "./ui/button"; import { @@ -58,6 +59,9 @@ function JsonViewer({ return null; } + const jsonString = + typeof data === "string" ? data : JSON.stringify(data, null, 2); + return ( @@ -69,9 +73,7 @@ function JsonViewer({ {label} - - {typeof data === "string" ? data : JSON.stringify(data, null, 2)} - + ); diff --git a/src/components/CodeHighlighter.tsx b/src/components/CodeHighlighter.tsx new file mode 100644 index 0000000..9ebd103 --- /dev/null +++ b/src/components/CodeHighlighter.tsx @@ -0,0 +1,55 @@ +import { useEffect, useState } from "react"; +import { type BundledLanguage, codeToHtml } from "shiki"; + +type CodeHighlighterProps = { + code: string; + language?: BundledLanguage; +}; + +const className = + "mt-1 rounded-md text-xs overflow-x-auto max-h-40 overflow-y-auto [&_.shiki]:p-3! [&_.shiki]:m-0! [&_.shiki]:bg-muted/50 [&_.shiki]:border [&_.shiki]:border-border/50 [&_.shiki]:rounded-md! [&_.shiki]:[--shiki-light-bg:transparent] [&_.shiki]:[--shiki-dark-bg:transparent] [&_.shiki_span]:[--shiki-light-bg:transparent] [&_.shiki_span]:[--shiki-dark-bg:transparent]"; + +export function CodeHighlighter({ + code, + language = "json", +}: CodeHighlighterProps) { + const [html, setHtml] = useState(null); + + useEffect(() => { + let cancelled = false; + + codeToHtml(code, { + lang: language, + themes: { + light: "material-theme-lighter", + dark: "material-theme-darker", + }, + defaultColor: false, + }).then((result) => { + if (!cancelled) { + setHtml(result); + } + }); + + return () => { + cancelled = true; + }; + }, [code, language]); + + if (html === null) { + // Show plain text while loading + return ( + + {code} + + ); + } + + return ( + + ); +}
- {typeof data === "string" ? data : JSON.stringify(data, null, 2)} -
+ {code} +
{code}