feat: add binary <-> text toggle to bytes view

This commit is contained in:
Victor Oliva
2025-06-19 09:09:40 +02:00
parent 6087080423
commit 57f8e1efbc
4 changed files with 53 additions and 6 deletions

View File

@@ -1,13 +1,27 @@
import { bytesToString } from "@/components/BinaryInput"
import { getBytesFormat } from "@/components/BinaryInput"
import { ViewBytes } from "@polkadot-api/react-builder"
import { useReportBinary } from "./CopyBinary"
import { SwitchBinary } from "@/components/Icons"
import { useState } from "react"
export const CBytes: ViewBytes = ({ value, encodedValue }) => {
const [forceBinary, setForceBinary] = useState(false)
useReportBinary(encodedValue)
const format = getBytesFormat(value)
return (
<div className="min-w-80 border-none p-0 outline-hidden bg-transparent flex-1 overflow-hidden text-ellipsis">
{bytesToString(value)}
{format.type === "text" ? (
<button
className="align-middle mr-2 cursor-pointer text-foreground/90"
type="button"
onClick={() => setForceBinary((b) => !b)}
>
<SwitchBinary size={24} />
</button>
) : null}
{forceBinary ? value.asHex() : format.value}
</div>
)
}

View File

@@ -71,7 +71,7 @@ export const BinaryInput: React.FC<{
{(input) => (
<div
className={twMerge(
"px-4 py-2 border border-border rounded leading-tight focus-within:outline focus-within:outline-1 flex items-center gap-2 bg-input",
"px-4 py-2 border border-border rounded leading-tight focus-within:outline flex items-center gap-2 bg-input",
warn ? "border-orange-400" : null,
uploadError ? "border-red-600" : null,
)}
@@ -159,15 +159,22 @@ const serializeValue = (value: Binary): string | Binary => {
}
const textDecoder = new TextDecoder("utf-8", { fatal: true })
export const bytesToString = (value: Binary) => {
export const getBytesFormat = (value: Binary) => {
try {
const bytes = value.asBytes()
if (bytes.slice(0, 5).every((b) => b < 32)) throw null
return textDecoder.decode(bytes)
return {
type: "text",
value: textDecoder.decode(bytes),
}
} catch (_) {
return value.asHex()
return {
type: "hex",
value: value.asHex(),
}
}
}
export const bytesToString = (value: Binary) => getBytesFormat(value).value
export const checkEqualInputBinary = (
input: string | Binary,

View File

@@ -20,6 +20,7 @@ import chopsticksLogoDark from "./icons/chopsticks_dark.svg"
import chopsticksLogoLight from "./icons/chopsticks_light.svg"
import enumSvg from "./icons/enum.svg"
import focusSvg from "./icons/focus.svg"
import switchBinarySvg from "./icons/switch_binary.svg"
import walletConnectSvg from "./icons/walletConnect.svg"
type CustomIconProps = Omit<Props, "ref" | "src"> & { size?: number }
@@ -62,6 +63,7 @@ export const Focus = customIcon(focusSvg)
export const Enum = customIcon(enumSvg)
export const BinaryEdit = customIcon(binarySvg)
export const WalletConnect = customIcon(walletConnectSvg)
export const SwitchBinary = customIcon(switchBinarySvg)
export const Chopsticks = themeIcon(chopsticksLogoLight, chopsticksLogoDark)
export const Spinner = (props: LucideProps) => (

View File

@@ -0,0 +1,24 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24" height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1"
stroke-linecap="round"
stroke-linejoin="round"
>
<text x="2" y="19" font-size="8" font-family="monospace" fill="currentColor" stroke="none">
0x
</text>
<text x="14" y="8" font-size="8" font-family="sans-serif" fill="currentColor" stroke="none">
Aa
</text>
<path d="M4 11 L4 5 L12 5" />
<path d="M10 3 L12 5 L10 7" />
<path d="M22 10 L22 16 L14 16" />
<path d="M16 14 L14 16 L16 18" />
</svg>

After

Width:  |  Height:  |  Size: 600 B