-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
11,207 additions
and
903 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"$schema": "https://ui.shadcn.com/schema.json", | ||
"style": "default", | ||
"rsc": false, | ||
"tsx": true, | ||
"tailwind": { | ||
"config": "tailwind.config.ts", | ||
"css": "styles/globals.css", | ||
"baseColor": "slate", | ||
"cssVariables": false, | ||
"prefix": "" | ||
}, | ||
"aliases": { | ||
"components": "@/components", | ||
"utils": "@/lib/utils", | ||
"ui": "@/components/ui", | ||
"lib": "@/lib", | ||
"hooks": "@/hooks" | ||
}, | ||
"iconLibrary": "lucide" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
import React from 'react' | ||
import { useMachine } from '@xstate/react' | ||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' | ||
import { Button } from '@/components/ui/button' | ||
import { Input } from '@/components/ui/input' | ||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' | ||
import { Alert, AlertDescription } from '@/components/ui/alert' | ||
import { createBrowserInspector } from '@statelyai/inspect' | ||
import { ipnsMachine, Mode } from '../lib/ipns-machine' | ||
import { Spinner } from './ui/spinner' | ||
|
||
const MIN_SEQUENCE = 0 | ||
const MAX_VALIDITY = 365 * 24 * 60 * 60 // 1 year in seconds | ||
|
||
const inspector = createBrowserInspector({ | ||
autoStart: false, | ||
}) | ||
|
||
interface RecordFieldProps { | ||
label: string; | ||
value: string; | ||
monospace?: boolean; | ||
} | ||
|
||
|
||
|
||
// Simplified component | ||
export default function IPNSInspector() { | ||
const [state, send] = useMachine(ipnsMachine, { | ||
inspect: inspector?.inspect, | ||
}) | ||
const isLoading = state.value === 'init' | ||
console.log(state.value) | ||
console.log(state.context) | ||
|
||
return ( | ||
<Card className="w-full max-w-2xl mx-auto"> | ||
<CardHeader> | ||
<CardTitle>IPNS Record Inspector & Creator</CardTitle> | ||
</CardHeader> | ||
<CardContent> | ||
<Tabs | ||
value={state.value} | ||
onValueChange={(value) => send({ type: 'UPDATE_MODE', value: value as Mode })} | ||
> | ||
<TabsList className="mb-4"> | ||
<TabsTrigger value="inspect">Inspect Record</TabsTrigger> | ||
<TabsTrigger value="create">Create Record</TabsTrigger> | ||
</TabsList> | ||
|
||
{state.value === 'init' && <div>Loading...</div>} | ||
|
||
<TabsContent value="inspect"> | ||
<div className="space-y-4"> | ||
<div className="space-y-2"> | ||
<label className="block text-sm font-medium">IPNS Name</label> | ||
<div className="flex gap-2"> | ||
<Input | ||
value={state.context.nameToInspect} | ||
onChange={(e) => send({ type: 'UPDATE_NAME_TO_INSPECT', value: e.target.value })} | ||
placeholder="k51... or 12D..." | ||
/> | ||
{ | ||
<Button | ||
onClick={() => send({ type: 'INSPECT_NAME' })} | ||
disabled={ | ||
isLoading || | ||
state.context.nameValidationError != null || | ||
state.context.nameToInspect.length === 0 | ||
} | ||
> | ||
Fetch Record {state.context.fetchingRecord ? <Spinner /> : null} | ||
</Button> | ||
} | ||
</div> | ||
{state.context.nameValidationError && ( | ||
<Alert variant="destructive" className="mt-4"> | ||
<AlertDescription>{state.context.nameValidationError}</AlertDescription> | ||
</Alert> | ||
)} | ||
</div> | ||
</div> | ||
</TabsContent> | ||
|
||
<TabsContent value="create"> | ||
<div className="space-y-4"> | ||
<div className="space-y-2"> | ||
<label className="block text-sm font-medium">Value</label> | ||
<Input | ||
value={state.context.formData.value} | ||
onChange={(e) => send({ type: 'UPDATE_FORM', field: 'value', value: e.target.value })} | ||
placeholder="CID or path to publish" | ||
/> | ||
</div> | ||
|
||
<div className="space-y-2"> | ||
<label className="block text-sm font-medium">TTL (seconds)</label> | ||
<Input | ||
type="number" | ||
value={state.context.formData.ttl} | ||
onChange={(e) => send({ type: 'UPDATE_FORM', field: 'ttl', value: e.target.value })} | ||
min="1" | ||
/> | ||
</div> | ||
|
||
<div className="space-y-2"> | ||
<label className="block text-sm font-medium">Validity (seconds)</label> | ||
<Input | ||
type="number" | ||
value={state.context.formData.validity} | ||
onChange={(e) => send({ type: 'UPDATE_FORM', field: 'validity', value: e.target.value })} | ||
min="1" | ||
max={MAX_VALIDITY} | ||
/> | ||
</div> | ||
|
||
<div className="space-y-2"> | ||
<label className="block text-sm font-medium">Sequence Number</label> | ||
<Input | ||
type="number" | ||
value={state.context.formData.sequence} | ||
onChange={(e) => send({ type: 'UPDATE_FORM', field: 'sequence', value: e.target.value })} | ||
min={MIN_SEQUENCE} | ||
/> | ||
</div> | ||
|
||
<Button onClick={() => send({ type: 'CREATE' })} disabled={isLoading} className="w-full"> | ||
Create Record | ||
</Button> | ||
</div> | ||
</TabsContent> | ||
|
||
{state.context.error && ( | ||
<Alert variant="destructive" className="mt-4"> | ||
<AlertDescription>{state.context.error.toString()}</AlertDescription> | ||
</Alert> | ||
)} | ||
|
||
{state.context.record && ( | ||
<div className="mt-4 p-4 bg-gray-50 rounded"> | ||
<h3 className="font-medium mb-2">Name: {state.context.nameInspecting}</h3> | ||
<h3 className="font-medium mb-2"> | ||
IPNS Record Version: {state.context.record.hasOwnProperty('signatureV1') ? 'V1+V2' : 'V2'} | ||
</h3> | ||
<div className="grid grid-cols-1 gap-3"> | ||
<RecordField label="Value" value={state.context.record.value} /> | ||
<RecordField label="Validity Type" value={state.context.record.validityType} /> | ||
<RecordField label="Validity" value={state.context.record.validity} /> | ||
<RecordField label="Sequence" value={state.context.record.sequence.toString()} /> | ||
<RecordField | ||
label="TTL" | ||
value={state.context.record.ttl ? (Number(state.context.record.ttl) / 1e9).toString() + ' seconds' : 'Not set'} | ||
/> | ||
<RecordField | ||
label="Signature V2" | ||
value={state.context.record.signatureV2.toString()} | ||
monospace | ||
/> | ||
<RecordField | ||
label="Data" | ||
value={state.context.record.data.toString()} | ||
monospace | ||
/> | ||
</div> | ||
</div> | ||
)} | ||
</Tabs> | ||
</CardContent> | ||
</Card> | ||
) | ||
} | ||
|
||
const RecordField: React.FC<RecordFieldProps> = ({ label, value, monospace }) => ( | ||
<div className="border rounded p-3 bg-white"> | ||
<div className="text-sm font-medium text-gray-500 mb-1">{label}</div> | ||
<div className={`break-all ${monospace ? 'font-mono text-sm' : ''}`}> | ||
{value} | ||
</div> | ||
</div> | ||
); | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import * as React from "react" | ||
import { cva, type VariantProps } from "class-variance-authority" | ||
|
||
import { cn } from "@/lib/utils" | ||
|
||
const alertVariants = cva( | ||
"relative w-full rounded-lg border border-slate-200 p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-slate-950 dark:border-slate-800 dark:[&>svg]:text-slate-50", | ||
{ | ||
variants: { | ||
variant: { | ||
default: "bg-white text-slate-950 dark:bg-slate-950 dark:text-slate-50", | ||
destructive: | ||
"border-red-500/50 text-red-500 dark:border-red-500 [&>svg]:text-red-500 dark:border-red-900/50 dark:text-red-900 dark:dark:border-red-900 dark:[&>svg]:text-red-900", | ||
}, | ||
}, | ||
defaultVariants: { | ||
variant: "default", | ||
}, | ||
} | ||
) | ||
|
||
const Alert = React.forwardRef< | ||
HTMLDivElement, | ||
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants> | ||
>(({ className, variant, ...props }, ref) => ( | ||
<div | ||
ref={ref} | ||
role="alert" | ||
className={cn(alertVariants({ variant }), className)} | ||
{...props} | ||
/> | ||
)) | ||
Alert.displayName = "Alert" | ||
|
||
const AlertTitle = React.forwardRef< | ||
HTMLParagraphElement, | ||
React.HTMLAttributes<HTMLHeadingElement> | ||
>(({ className, ...props }, ref) => ( | ||
<h5 | ||
ref={ref} | ||
className={cn("mb-1 font-medium leading-none tracking-tight", className)} | ||
{...props} | ||
/> | ||
)) | ||
AlertTitle.displayName = "AlertTitle" | ||
|
||
const AlertDescription = React.forwardRef< | ||
HTMLParagraphElement, | ||
React.HTMLAttributes<HTMLParagraphElement> | ||
>(({ className, ...props }, ref) => ( | ||
<div | ||
ref={ref} | ||
className={cn("text-sm [&_p]:leading-relaxed", className)} | ||
{...props} | ||
/> | ||
)) | ||
AlertDescription.displayName = "AlertDescription" | ||
|
||
export { Alert, AlertTitle, AlertDescription } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import * as React from "react" | ||
import { Slot } from "@radix-ui/react-slot" | ||
import { cva, type VariantProps } from "class-variance-authority" | ||
|
||
import { cn } from "@/lib/utils" | ||
|
||
const buttonVariants = cva( | ||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 dark:ring-offset-slate-950 dark:focus-visible:ring-slate-300", | ||
{ | ||
variants: { | ||
variant: { | ||
default: "bg-slate-900 text-slate-50 hover:bg-slate-900/90 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50/90", | ||
destructive: | ||
"bg-red-500 text-slate-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-slate-50 dark:hover:bg-red-900/90", | ||
outline: | ||
"border border-slate-200 bg-white hover:bg-slate-100 hover:text-slate-900 dark:border-slate-800 dark:bg-slate-950 dark:hover:bg-slate-800 dark:hover:text-slate-50", | ||
secondary: | ||
"bg-slate-100 text-slate-900 hover:bg-slate-100/80 dark:bg-slate-800 dark:text-slate-50 dark:hover:bg-slate-800/80", | ||
ghost: "hover:bg-slate-100 hover:text-slate-900 dark:hover:bg-slate-800 dark:hover:text-slate-50", | ||
link: "text-slate-900 underline-offset-4 hover:underline dark:text-slate-50", | ||
}, | ||
size: { | ||
default: "h-10 px-4 py-2", | ||
sm: "h-9 rounded-md px-3", | ||
lg: "h-11 rounded-md px-8", | ||
icon: "h-10 w-10", | ||
}, | ||
}, | ||
defaultVariants: { | ||
variant: "default", | ||
size: "default", | ||
}, | ||
} | ||
) | ||
|
||
export interface ButtonProps | ||
extends React.ButtonHTMLAttributes<HTMLButtonElement>, | ||
VariantProps<typeof buttonVariants> { | ||
asChild?: boolean | ||
} | ||
|
||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( | ||
({ className, variant, size, asChild = false, ...props }, ref) => { | ||
const Comp = asChild ? Slot : "button" | ||
return ( | ||
<Comp | ||
className={cn(buttonVariants({ variant, size, className }))} | ||
ref={ref} | ||
{...props} | ||
/> | ||
) | ||
} | ||
) | ||
Button.displayName = "Button" | ||
|
||
export { Button, buttonVariants } |
Oops, something went wrong.