Skip to content

Commit

Permalink
Basic embedded Zapp example (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
robknight authored Sep 24, 2024
1 parent a4d22f0 commit 7910330
Show file tree
Hide file tree
Showing 29 changed files with 1,257 additions and 163 deletions.
20 changes: 20 additions & 0 deletions apps/client-web/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/index.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
}
}
2 changes: 1 addition & 1 deletion apps/client-web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PARCNET Client</title>
</head>
<body class="bg-black h-screen w-screen overflow-scroll">
<body class="bg-black h-screen w-screen overflow-scroll dark">
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
Expand Down
7 changes: 7 additions & 0 deletions apps/client-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,18 @@
"@pcd/gpc": "0.0.8",
"@pcd/pod": "0.1.7",
"@pcd/proto-pod-gpc-artifacts": "^0.9.0",
"@radix-ui/react-dialog": "^1.1.1",
"@semaphore-protocol/core": "^4.0.3",
"@semaphore-protocol/identity": "3.15.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"eventemitter3": "^5.0.1",
"lucide-react": "^0.445.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.26.2",
"tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7",
"vite-plugin-node-polyfills": "^0.22.0"
},
"devDependencies": {
Expand Down
91 changes: 39 additions & 52 deletions apps/client-web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,29 @@ import { gpcProve } from "@pcd/gpc";
import type { POD } from "@pcd/pod";
import { POD_INT_MAX, POD_INT_MIN } from "@pcd/pod";
import type { Dispatch, ReactNode } from "react";
import { Fragment, useEffect, useReducer, useState } from "react";
import { Fragment, useEffect, useState } from "react";
import { ParcnetClientProcessor } from "./client/client";
import { PODCollection } from "./client/pod_collection";
import {
getIdentity,
loadPODsFromStorage,
savePODsToStorage
} from "./client/utils";
import { Rabbit } from "./rabbit";
import { getIdentity, savePODsToStorage } from "./client/utils";
import { Layout } from "./components/Layout";
import type { ClientAction, ClientState } from "./state";
import { clientReducer } from "./state";
import { useAppState } from "./state";

function App() {
const [state, dispatch] = useReducer(clientReducer, {
loggedIn: false,
advice: null,
zapp: null,
authorized: false,
proofInProgress: undefined,
identity: getIdentity()
});
const { state, dispatch } = useAppState();

useEffect(() => {
state.pods.onUpdate(() => {
savePODsToStorage(state.pods.getAll());
});
}, [state.pods]);

useEffect(() => {
void (async () => {
const { zapp, advice } = await listen();
dispatch({ type: "set-zapp", zapp });
dispatch({ type: "set-advice", advice });
})();
}, []);
}, [dispatch]);

useEffect(() => {
if (state.advice && !state.loggedIn) {
Expand All @@ -43,46 +37,39 @@ function App() {
}, [state.advice, state.loggedIn]);

useEffect(() => {
if (state.authorized && state.advice) {
if (state.advice && state.authorized) {
state.advice.hideClient();
const pods = new PODCollection(loadPODsFromStorage());
pods.onUpdate(() => {
savePODsToStorage(pods.getAll());
});
state.advice.ready(
new ParcnetClientProcessor(state.advice, pods, dispatch, getIdentity())
new ParcnetClientProcessor(
state.advice,
state.pods,
dispatch,
state.identity
)
);
}
}, [state.authorized, state.advice]);
}, [state.advice, state.authorized, state.pods, state.identity, dispatch]);

return (
<main className="mx-auto max-w-md container">
<div className="font-mono my-4 bg-black text-white p-4 rounded-lg">
<div className="flex items-center w-full my-4">
<div className="my-4 w-full">Welcome to PARCNET</div>
<div className="w-8 h-8">
<Rabbit />
</div>
</div>
{!state.loggedIn && (
<button
className="border-2 font-semibold cursor-pointer border-white py-1 px-2 uppercase active:translate-x-[2px] active:translate-y-[2px]"
onClick={() => dispatch({ type: "login", loggedIn: true })}
>
Connect
</button>
)}
{state.loggedIn && !state.authorized && state.zapp && (
<Authorize zapp={state.zapp} dispatch={dispatch} />
<Layout>
{!state.loggedIn && (
<button
className="border-2 font-semibold cursor-pointer border-white py-1 px-2 uppercase active:translate-x-[2px] active:translate-y-[2px]"
onClick={() => dispatch({ type: "login", loggedIn: true })}
>
Connect
</button>
)}
{state.loggedIn && !state.authorized && state.zapp && (
<Authorize zapp={state.zapp} dispatch={dispatch} />
)}
{state.loggedIn &&
state.authorized &&
state.zapp &&
state.proofInProgress && (
<Prove proveOperation={state.proofInProgress} dispatch={dispatch} />
)}
{state.loggedIn &&
state.authorized &&
state.zapp &&
state.proofInProgress && (
<Prove proveOperation={state.proofInProgress} dispatch={dispatch} />
)}
</div>
</main>
</Layout>
);
}

Expand Down Expand Up @@ -238,7 +225,7 @@ function ProvePODInfo({
);
}

function Prove({
export function Prove({
proveOperation,
dispatch
}: {
Expand Down
4 changes: 0 additions & 4 deletions apps/client-web/src/client/gpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@ export class ParcnetGPCProcessor implements ParcnetGPCRPC {

public async prove(request: PodspecProofRequest): Promise<ProveResult> {
const prs = proofRequest(request);

console.dir(prs, { depth: null });
console.dir(this.pods.getAll(), { depth: null });

const inputPods = prs.queryForInputs(this.pods.getAll());
if (
Object.values(inputPods).some((candidates) => candidates.length === 0)
Expand Down
17 changes: 17 additions & 0 deletions apps/client-web/src/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Rabbit } from "../rabbit";

export function Layout({ children }: { children: React.ReactNode }) {
return (
<main className="mx-auto max-w-md container">
<div className="font-mono my-4 bg-black text-white p-4 rounded-lg">
<div className="flex items-center w-full my-4">
<div className="my-4 w-full">Welcome to PARCNET</div>
<div className="w-8 h-8">
<Rabbit />
</div>
</div>
{children}
</div>
</main>
);
}
120 changes: 120 additions & 0 deletions apps/client-web/src/components/ui/dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import * as DialogPrimitive from "@radix-ui/react-dialog";
import { X } from "lucide-react";
import * as React from "react";

import { cn } from "@/lib/utils";

const Dialog = DialogPrimitive.Root;

const DialogTrigger = DialogPrimitive.Trigger;

const DialogPortal = DialogPrimitive.Portal;

const DialogClose = DialogPrimitive.Close;

const DialogOverlay = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
ref={ref}
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
/>
));
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;

const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
className
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
));
DialogContent.displayName = DialogPrimitive.Content.displayName;

const DialogHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-1.5 text-center sm:text-left",
className
)}
{...props}
/>
);
DialogHeader.displayName = "DialogHeader";

const DialogFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
);
DialogFooter.displayName = "DialogFooter";

const DialogTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
));
DialogTitle.displayName = DialogPrimitive.Title.displayName;

const DialogDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
DialogDescription.displayName = DialogPrimitive.Description.displayName;

export {
Dialog,
DialogPortal,
DialogOverlay,
DialogClose,
DialogTrigger,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription
};
63 changes: 63 additions & 0 deletions apps/client-web/src/index.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,66 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
--card: 0 0% 100%;
--card-foreground: 0 0% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 3.9%;
--primary: 0 0% 9%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 9%;
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 45.1%;
--accent: 0 0% 96.1%;
--accent-foreground: 0 0% 9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--ring: 0 0% 3.9%;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
--radius: 0.5rem;
}
.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--card: 0 0% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 0 0% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 0 0% 9%;
--secondary: 0 0% 14.9%;
--secondary-foreground: 0 0% 98%;
--muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%;
--accent: 0 0% 14.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 14.9%;
--input: 0 0% 14.9%;
--ring: 0 0% 83.1%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
Loading

0 comments on commit 7910330

Please sign in to comment.