feat: redesign constants into card grid (#150)
* feat: redesign constants into card grid * cleanup constants classnames
This commit is contained in:
@@ -12,27 +12,30 @@ import {
|
||||
} from "@/components/ui/tooltip"
|
||||
import { withSubscribe } from "@/components/withSuspense"
|
||||
import { pushWorkspaceEntry, setWorkspaceOpen } from "@/components/Workspace"
|
||||
import { lookup$, runtimeCtx$ } from "@/state/chains/chain.state"
|
||||
import { getTypeComplexity } from "@/utils/shape"
|
||||
import type { RuntimeContext } from "@polkadot-api/observable-client"
|
||||
import { CodecComponentType } from "@polkadot-api/react-builder"
|
||||
import { state, useStateObservable, withDefault } from "@react-rxjs/core"
|
||||
import { state, useStateObservable } from "@react-rxjs/core"
|
||||
import { Dot, SquareEqual } from "lucide-react"
|
||||
import { HexString } from "polkadot-api"
|
||||
import { FC, useState } from "react"
|
||||
import { firstValueFrom, map } from "rxjs"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
import { v4 } from "uuid"
|
||||
import { BlockPicker, selectedBlock$ } from "./Storage/BlockPicker"
|
||||
import { ValueDisplay } from "./Storage/StorageSubscriptions"
|
||||
|
||||
const metadataConstants$ = state(
|
||||
lookup$.pipe(
|
||||
map((lookup) =>
|
||||
lookup.metadata.pallets
|
||||
selectedBlock$.pipe(
|
||||
map(({ ctx }) =>
|
||||
[...ctx.lookup.metadata.pallets]
|
||||
.filter((p) => p.constants.length > 0)
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map((p) => ({
|
||||
name: p.name,
|
||||
constants: p.constants.sort((a, b) => a.name.localeCompare(b.name)),
|
||||
constants: [...p.constants].sort((a, b) =>
|
||||
a.name.localeCompare(b.name),
|
||||
),
|
||||
})),
|
||||
),
|
||||
),
|
||||
@@ -43,8 +46,14 @@ export const Constants = withSubscribe(
|
||||
const entries = useStateObservable(metadataConstants$)
|
||||
|
||||
return (
|
||||
<div className="p-4 pb-0 flex flex-col gap-2 items-start leading-relaxed overflow-auto">
|
||||
<ul>
|
||||
<div className="p-4 space-y-2 overflow-auto @container">
|
||||
<div className="w-full border-b border-border pb-3">
|
||||
<label className="inline-flex flex-col gap-1 text-sm font-medium">
|
||||
Block
|
||||
<BlockPicker />
|
||||
</label>
|
||||
</div>
|
||||
<ul className="grid w-full grid-cols-[repeat(auto-fill,minmax(min(100%,25rem),1fr))] gap-2">
|
||||
{entries.map(({ name, constants }) => (
|
||||
<PalletConstants key={name} pallet={name} entries={constants} />
|
||||
))}
|
||||
@@ -66,21 +75,13 @@ const PalletConstants: FC<{
|
||||
docs: string[]
|
||||
}>
|
||||
}> = ({ pallet, entries }) => {
|
||||
const [expanded, setExpanded] = useState(false)
|
||||
|
||||
return (
|
||||
<li className="group">
|
||||
<div
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
onClick={() => setExpanded((e) => !e)}
|
||||
>
|
||||
<ExpandBtn expanded={expanded} />
|
||||
<div>{pallet}</div>
|
||||
<li className="min-w-0 rounded-lg border border-border bg-card text-card-foreground shadow-sm">
|
||||
<div className="flex min-h-14 items-center gap-3 border-b border-border px-3">
|
||||
<h2 className="truncate flex-1">{pallet}</h2>
|
||||
<AddToWorkspace
|
||||
className="h-7 w-7 opacity-0 group-hover:opacity-100"
|
||||
onClick={async (evt) => {
|
||||
evt.stopPropagation()
|
||||
const ctx = await firstValueFrom(runtimeCtx$)
|
||||
onClick={async () => {
|
||||
const { ctx } = await firstValueFrom(selectedBlock$)
|
||||
|
||||
addPalletConstantsToWorkspace(
|
||||
pallet,
|
||||
@@ -97,13 +98,11 @@ const PalletConstants: FC<{
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{expanded && (
|
||||
<ul>
|
||||
{entries.map((props) => (
|
||||
<ConstantEntry key={props.name} {...props} />
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
<ul className="divide-y divide-border">
|
||||
{entries.map((props) => (
|
||||
<ConstantEntry key={props.name} {...props} />
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
@@ -137,10 +136,11 @@ const ConstantsWorkspaceEntry: FC<{ context: ConstantsWorkspaceContext }> = ({
|
||||
}
|
||||
|
||||
const constantValueProps$ = state(
|
||||
runtimeCtx$.pipe(
|
||||
map(({ dynamicBuilder, lookup }) => ({
|
||||
builder: dynamicBuilder,
|
||||
lookup,
|
||||
selectedBlock$.pipe(
|
||||
map(({ ctx }) => ({
|
||||
ctx,
|
||||
builder: ctx.dynamicBuilder,
|
||||
lookup: ctx.lookup,
|
||||
})),
|
||||
),
|
||||
null,
|
||||
@@ -162,15 +162,22 @@ const ConstantEntry: FC<{
|
||||
const titleElement = (
|
||||
<div
|
||||
className={twMerge(
|
||||
"flex items-center gap-2",
|
||||
"flex min-w-0 items-center gap-2",
|
||||
!isInline && "cursor-pointer",
|
||||
)}
|
||||
onClick={() => setExpanded((e) => !e)}
|
||||
>
|
||||
{isInline ? <Dot size={16} /> : <ExpandBtn expanded={expanded} />}
|
||||
<span className="shrink-0">
|
||||
{isInline ? <Dot size={16} /> : <ExpandBtn expanded={expanded} />}
|
||||
</span>
|
||||
<Tooltip disableHoverableContent>
|
||||
<TooltipTrigger className="cursor-default">
|
||||
<div className={isInline ? "text-foreground/60" : ""}>
|
||||
<TooltipTrigger className="min-w-0 cursor-default shrink-0">
|
||||
<div
|
||||
className={twMerge(
|
||||
"truncate text-left text-sm",
|
||||
isInline ? "text-foreground/60" : "font-medium",
|
||||
)}
|
||||
>
|
||||
{name + (isInline ? ":" : "")}
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
@@ -181,23 +188,26 @@ const ConstantEntry: FC<{
|
||||
) : null}
|
||||
</Tooltip>
|
||||
{isInline ? (
|
||||
<ViewCodec
|
||||
codecType={type}
|
||||
value={{
|
||||
type: CodecComponentType.Initial,
|
||||
value: value,
|
||||
}}
|
||||
metadata={props.lookup.metadata}
|
||||
/>
|
||||
<div className="min-w-0 text-sm">
|
||||
<ViewCodec
|
||||
codecType={type}
|
||||
value={{
|
||||
type: CodecComponentType.Initial,
|
||||
value: value,
|
||||
}}
|
||||
metadata={props.lookup.metadata}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<li className="pl-4">
|
||||
<li className="min-w-0 px-3 py-2">
|
||||
{titleElement}
|
||||
{!isInline && expanded && (
|
||||
<ConstantValue
|
||||
ctx={props.ctx}
|
||||
type={type}
|
||||
decoded={props.builder.buildDefinition(type).dec(value)}
|
||||
/>
|
||||
@@ -206,17 +216,15 @@ const ConstantEntry: FC<{
|
||||
)
|
||||
}
|
||||
|
||||
const defaultedCtx$ = runtimeCtx$.pipeState(withDefault(null))
|
||||
const ConstantValue: FC<{ type: number; decoded: unknown }> = ({
|
||||
type,
|
||||
decoded,
|
||||
}) => {
|
||||
const ConstantValue: FC<{
|
||||
ctx: Pick<RuntimeContext, "lookup" | "dynamicBuilder">
|
||||
type: number
|
||||
decoded: unknown
|
||||
}> = ({ ctx, type, decoded }) => {
|
||||
const [mode, setMode] = useState<"json" | "decoded">("decoded")
|
||||
const ctx = useStateObservable(defaultedCtx$)
|
||||
if (!ctx) return null
|
||||
|
||||
return (
|
||||
<div className="pl-6 py-2 flex flex-col gap-2 items-start overflow-hidden w-full">
|
||||
<div className="flex w-full flex-col items-start gap-2 overflow-hidden py-2 pl-6">
|
||||
<ButtonGroup
|
||||
value={mode}
|
||||
onValueChange={setMode as any}
|
||||
@@ -231,7 +239,7 @@ const ConstantValue: FC<{ type: number; decoded: unknown }> = ({
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<div className="overflow-auto w-full">
|
||||
<div className="w-full overflow-auto">
|
||||
<ValueDisplay
|
||||
mode={mode}
|
||||
ctx={ctx}
|
||||
|
||||
Reference in New Issue
Block a user