From 4424a9965ec1a2a56a6a669dd47f04fa9d6d5cf2 Mon Sep 17 00:00:00 2001 From: Ben Follington <5009316+bfollington@users.noreply.github.com> Date: Mon, 3 Feb 2025 11:52:20 +1000 Subject: [PATCH 1/4] Factoring chunks out for re-use between lit and react --- typescript/packages/common-charm/src/index.ts | 12 ++- .../src/localBuild.ts | 0 .../packages/common-charm/src/syncRecipe.ts | 83 ++++++++++++++++++ .../test/storage.test.ts | 0 .../src/components/annotation.ts | 2 +- .../src/components/common-spell-editor.ts | 3 +- .../src/components/iframe-spell-ai.ts | 39 +++++++-- .../src/components/sidebar.ts | 3 +- .../src/components/window-manager.ts | 9 +- .../packages/lookslike-high-level/src/data.ts | 84 +------------------ .../src/recipes/annotation.tsx | 3 +- 11 files changed, 137 insertions(+), 101 deletions(-) rename typescript/packages/{lookslike-high-level => common-charm}/src/localBuild.ts (100%) create mode 100644 typescript/packages/common-charm/src/syncRecipe.ts rename typescript/packages/{lookslike-high-level => common-charm}/test/storage.test.ts (100%) diff --git a/typescript/packages/common-charm/src/index.ts b/typescript/packages/common-charm/src/index.ts index aa35b48a8..0c9337cfc 100644 --- a/typescript/packages/common-charm/src/index.ts +++ b/typescript/packages/common-charm/src/index.ts @@ -1 +1,11 @@ -export { runPersistent, type Charm, addCharms, removeCharm, storage, syncCharm, charms } from "./charm.js"; +export { + runPersistent, + type Charm, + addCharms, + removeCharm, + storage, + syncCharm, + charms, +} from "./charm.js"; +export { syncRecipe, saveRecipe } from "./syncRecipe.js"; +export { buildRecipe, tsToExports } from "./localBuild.js"; diff --git a/typescript/packages/lookslike-high-level/src/localBuild.ts b/typescript/packages/common-charm/src/localBuild.ts similarity index 100% rename from typescript/packages/lookslike-high-level/src/localBuild.ts rename to typescript/packages/common-charm/src/localBuild.ts diff --git a/typescript/packages/common-charm/src/syncRecipe.ts b/typescript/packages/common-charm/src/syncRecipe.ts new file mode 100644 index 000000000..b2b661f59 --- /dev/null +++ b/typescript/packages/common-charm/src/syncRecipe.ts @@ -0,0 +1,83 @@ +import { + addRecipe, + getRecipe, + getRecipeParents, + getRecipeSrc, + getRecipeSpec, + getRecipeName, +} from "@commontools/runner"; +import { buildRecipe } from "./localBuild.js"; + +export const BLOBBY_SERVER_URL = + typeof window !== "undefined" + ? window.location.protocol + "//" + window.location.host + "/api/storage/blobby" + : "//api/storage/blobby"; + +const recipesKnownToStorage = new Set(); + +export async function syncRecipe(id: string) { + if (getRecipe(id)) { + if (recipesKnownToStorage.has(id)) return; + const src = getRecipeSrc(id); + const spec = getRecipeSpec(id); + const parents = getRecipeParents(id); + if (src) saveRecipe(id, src, spec, parents); + return; + } + + const response = await fetch(`${BLOBBY_SERVER_URL}/spell-${id}`); + let src: string; + let spec: string; + let parents: string[]; + try { + const resp = await response.json(); + src = resp.src; + spec = resp.spec; + parents = resp.parents || []; + } catch (e) { + src = await response.text(); + spec = ""; + parents = []; + } + + const { recipe, errors } = await buildRecipe(src); + if (errors) throw new Error(errors); + + const recipeId = addRecipe(recipe!, src, spec, parents); + if (id !== recipeId) { + throw new Error(`Recipe ID mismatch: ${id} !== ${recipeId}`); + } + recipesKnownToStorage.add(recipeId); +} + +export async function saveRecipe( + id: string, + src: string, + spec?: string, + parents?: string[], + spellbookTitle?: string, + spellbookTags?: string[], +) { + // If the recipe is already known to storage, we don't need to save it again, + // unless the user is trying to attach a spellbook title or tags. + if (recipesKnownToStorage.has(id) && !spellbookTitle) return; + recipesKnownToStorage.add(id); + + console.log("Saving recipe", id); + const response = await fetch(`${BLOBBY_SERVER_URL}/spell-${id}`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + src, + recipe: JSON.parse(JSON.stringify(getRecipe(id))), + spec, + parents, + recipeName: getRecipeName(id), + spellbookTitle, + spellbookTags, + }), + }); + return response.ok; +} diff --git a/typescript/packages/lookslike-high-level/test/storage.test.ts b/typescript/packages/common-charm/test/storage.test.ts similarity index 100% rename from typescript/packages/lookslike-high-level/test/storage.test.ts rename to typescript/packages/common-charm/test/storage.test.ts diff --git a/typescript/packages/lookslike-high-level/src/components/annotation.ts b/typescript/packages/lookslike-high-level/src/components/annotation.ts index 13bd2377d..58ded4fe4 100644 --- a/typescript/packages/lookslike-high-level/src/components/annotation.ts +++ b/typescript/packages/lookslike-high-level/src/components/annotation.ts @@ -2,7 +2,7 @@ import { LitElement, html } from "lit"; import { customElement, property } from "lit/decorators.js"; import { ref, createRef } from "lit/directives/ref.js"; import { render } from "@commontools/html"; -import { charms, UI, annotationsEnabled } from "../data.js"; +import { annotationsEnabled } from "../data.js"; import { run, getDoc, DocImpl, getDocLinkOrValue } from "@commontools/runner"; import { annotation } from "../recipes/annotation.jsx"; diff --git a/typescript/packages/lookslike-high-level/src/components/common-spell-editor.ts b/typescript/packages/lookslike-high-level/src/components/common-spell-editor.ts index 86d0ce4bb..72331e958 100644 --- a/typescript/packages/lookslike-high-level/src/components/common-spell-editor.ts +++ b/typescript/packages/lookslike-high-level/src/components/common-spell-editor.ts @@ -2,8 +2,7 @@ import { html, LitElement } from "lit"; import { customElement, property } from "lit/decorators.js"; import { when } from "lit/directives/when.js"; import { addRecipe, getRecipeSpec, getRecipeSrc, run } from "@commontools/runner"; -import { addCharms } from "@commontools/charm"; -import { tsToExports } from "../localBuild.js"; +import { addCharms, tsToExports } from "@commontools/charm"; import { iterate, llmTweakSpec, generateSuggestions } from "./spell-ai.js"; import { createRef, ref } from "lit/directives/ref.js"; diff --git a/typescript/packages/lookslike-high-level/src/components/iframe-spell-ai.ts b/typescript/packages/lookslike-high-level/src/components/iframe-spell-ai.ts index 09acd46c9..f7abdb2b9 100644 --- a/typescript/packages/lookslike-high-level/src/components/iframe-spell-ai.ts +++ b/typescript/packages/lookslike-high-level/src/components/iframe-spell-ai.ts @@ -1,14 +1,17 @@ import { getRecipe, getRecipeSrc, addRecipe, run } from "@commontools/runner"; -import { addCharms, Charm } from "@commontools/charm"; +import { addCharms, Charm, tsToExports } from "@commontools/charm"; import { openCharm } from "../data.js"; import { LLMClient } from "@commontools/llm-client"; import { createJsonSchema, JSONSchema, TYPE } from "@commontools/builder"; -import { tsToExports } from "../localBuild.js"; import { type DocImpl } from "@commontools/runner"; import demoSrc from "./demo.html?raw"; -const SELECTED_MODEL = ["groq:llama-3.3-70b-specdec", "cerebras:llama-3.3-70b", "anthropic:claude-3-5-sonnet"]; +const SELECTED_MODEL = [ + "groq:llama-3.3-70b-specdec", + "cerebras:llama-3.3-70b", + "anthropic:claude-3-5-sonnet", +]; const responsePrefill = "```html\n" + @@ -177,7 +180,17 @@ const llmUrl = const llm = new LLMClient(llmUrl); -const genSrc = async ({ src, spec, newSpec, schema }: { src?: string; spec?: string; newSpec: string; schema: JSONSchema }) => { +const genSrc = async ({ + src, + spec, + newSpec, + schema, +}: { + src?: string; + spec?: string; + newSpec: string; + schema: JSONSchema; +}) => { const messages = []; if (spec && src) { messages.push(spec); @@ -228,7 +241,7 @@ ${newSpec} ${JSON.stringify(schema, null, 2)} - + You can use the generateImage function to get a url for a generated image.`; const payload = { @@ -292,7 +305,12 @@ export async function iterate(charm: DocImpl | null, value: string, shift const newSpec = shiftKey ? iframe.spec + "\n" + value : value; - const newIFrameSrc = await genSrc({ src: iframe.src, spec: iframe.spec, newSpec, schema: iframe.argumentSchema }); + const newIFrameSrc = await genSrc({ + src: iframe.src, + spec: iframe.spec, + newSpec, + schema: iframe.argumentSchema, + }); const name = newIFrameSrc.match(/(.*?)<\/title>/)?.[1] ?? newSpec; const newRecipeSrc = buildFullRecipe({ ...iframe, src: newIFrameSrc, spec: newSpec, name }); @@ -325,14 +343,19 @@ export async function iterate(charm: DocImpl | null, value: string, shift } } - export async function castNewRecipe(data: any, newSpec: string) { const schema = createJsonSchema({}, data); schema.description = newSpec; const newIFrameSrc = await genSrc({ newSpec, schema }); const name = newIFrameSrc.match(/(.*?)<\/title>/)?.[1] ?? newSpec; - const newRecipeSrc = buildFullRecipe({ src: newIFrameSrc, spec: newSpec, argumentSchema: schema, resultSchema: {}, name }); + const newRecipeSrc = buildFullRecipe({ + src: newIFrameSrc, + spec: newSpec, + argumentSchema: schema, + resultSchema: {}, + name, + }); const { exports, errors } = await tsToExports(newRecipeSrc); diff --git a/typescript/packages/lookslike-high-level/src/components/sidebar.ts b/typescript/packages/lookslike-high-level/src/components/sidebar.ts index 6608708f1..3b317f1a0 100644 --- a/typescript/packages/lookslike-high-level/src/components/sidebar.ts +++ b/typescript/packages/lookslike-high-level/src/components/sidebar.ts @@ -2,7 +2,7 @@ import { css, html, LitElement, PropertyValues } from "lit"; import { customElement, property } from "lit/decorators.js"; import { style } from "@commontools/ui"; import { when } from "lit/directives/when.js"; -import { Charm, charms, runPersistent } from "@commontools/charm"; +import { Charm, charms, runPersistent, saveRecipe } from "@commontools/charm"; import { BLOBBY_SERVER_URL, recipes } from "../data.js"; import { refer } from "merkle-reference"; @@ -20,7 +20,6 @@ import { watchCell } from "../watchCell.js"; import { createRef, ref } from "lit/directives/ref.js"; import { home } from "../recipes/home.jsx"; import { render } from "@commontools/html"; -import { saveRecipe } from "../data.js"; import { castNewRecipe } from "./iframe-spell-ai.js"; const uploadBlob = async (data: any) => { diff --git a/typescript/packages/lookslike-high-level/src/components/window-manager.ts b/typescript/packages/lookslike-high-level/src/components/window-manager.ts index 2549e004a..b086e8a4a 100644 --- a/typescript/packages/lookslike-high-level/src/components/window-manager.ts +++ b/typescript/packages/lookslike-high-level/src/components/window-manager.ts @@ -3,16 +3,14 @@ import { customElement, state } from "lit/decorators.js"; import { createRef, Ref, ref } from "lit/directives/ref.js"; import { style } from "@commontools/ui"; import { render } from "@commontools/html"; -import { - closeCharm, - openCharm, - syncRecipe, -} from "../data.js"; +import { closeCharm, openCharm } from "../data.js"; import { syncCharm, addCharms, Charm, runPersistent, + syncRecipe, + buildRecipe, } from "@commontools/charm"; import { @@ -28,7 +26,6 @@ import { import { repeat } from "lit/directives/repeat.js"; import { UI, NAME, TYPE } from "@commontools/builder"; import { matchRoute, navigate } from "../router.js"; -import { buildRecipe } from "../localBuild.js"; import * as iframeSpellAi from "./iframe-spell-ai.js"; async function castSpell(value: string, openCharm: (charmId: string) => void) { diff --git a/typescript/packages/lookslike-high-level/src/data.ts b/typescript/packages/lookslike-high-level/src/data.ts index 600c846d5..8cff2a74a 100644 --- a/typescript/packages/lookslike-high-level/src/data.ts +++ b/typescript/packages/lookslike-high-level/src/data.ts @@ -8,100 +8,24 @@ import { type DocImpl, EntityId, getEntityId, - getRecipe, - getRecipeParents, - getRecipeSrc, raw, type ReactivityLog, - getRecipeSpec, - getRecipeName, Action, addAction, removeAction, } from "@commontools/runner"; import * as allRecipes from "./recipes/index.js"; -import { buildRecipe } from "./localBuild.js"; import { setIframeContextHandler } from "@commontools/iframe-sandbox"; import { addCharms } from "@commontools/charm"; -// Necessary, so that suggestions are indexed. -// import "./recipes/todo-list-as-task.jsx"; -// import "./recipes/playlist.jsx"; - - export const BLOBBY_SERVER_URL = typeof window !== "undefined" ? window.location.protocol + "//" + window.location.host + "/api/storage/blobby" : "//api/storage/blobby"; -const recipesKnownToStorage = new Set(); - -export async function syncRecipe(id: string) { - if (getRecipe(id)) { - if (recipesKnownToStorage.has(id)) return; - const src = getRecipeSrc(id); - const spec = getRecipeSpec(id); - const parents = getRecipeParents(id); - if (src) saveRecipe(id, src, spec, parents); - return; - } - - const response = await fetch(`${BLOBBY_SERVER_URL}/spell-${id}`); - let src: string; - let spec: string; - let parents: string[]; - try { - const resp = await response.json(); - src = resp.src; - spec = resp.spec; - parents = resp.parents || []; - } catch (e) { - src = await response.text(); - spec = ""; - parents = []; - } - - const { recipe, errors } = await buildRecipe(src); - if (errors) throw new Error(errors); - - const recipeId = addRecipe(recipe!, src, spec, parents); - if (id !== recipeId) { - throw new Error(`Recipe ID mismatch: ${id} !== ${recipeId}`); - } - recipesKnownToStorage.add(recipeId); -} - -export async function saveRecipe( - id: string, - src: string, - spec?: string, - parents?: string[], - spellbookTitle?: string, - spellbookTags?: string[], -) { - // If the recipe is already known to storage, we don't need to save it again, - // unless the user is trying to attach a spellbook title or tags. - if (recipesKnownToStorage.has(id) && !spellbookTitle) return; - recipesKnownToStorage.add(id); - - console.log("Saving recipe", id); - const response = await fetch(`${BLOBBY_SERVER_URL}/spell-${id}`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - src, - recipe: JSON.parse(JSON.stringify(getRecipe(id))), - spec, - parents, - recipeName: getRecipeName(id), - spellbookTitle, - spellbookTags, - }), - }); - return response.ok; -} +// Necessary, so that suggestions are indexed. +// import "./recipes/todo-list-as-task.jsx"; +// import "./recipes/playlist.jsx"; import smolIframe from "./recipes/smolIframe.js"; import complexIframe from "./recipes/complexIframe.js"; @@ -195,4 +119,4 @@ setIframeContextHandler({ unsubscribe(_context: any, receipt: any) { removeAction(receipt); }, -}); \ No newline at end of file +}); diff --git a/typescript/packages/lookslike-high-level/src/recipes/annotation.tsx b/typescript/packages/lookslike-high-level/src/recipes/annotation.tsx index 10eebb0ba..6bc469480 100644 --- a/typescript/packages/lookslike-high-level/src/recipes/annotation.tsx +++ b/typescript/packages/lookslike-high-level/src/recipes/annotation.tsx @@ -1,6 +1,7 @@ import { h, type VNode } from "@commontools/html"; import { recipe, lift, handler, cell, UI, NAME, TYPE, ifElse, llm } from "@commontools/builder"; -import { type Charm, openCharm } from "../data.js"; +import { type Charm } from "@commontools/charm"; +import { openCharm } from "../data.js"; import { run, getDocLinkOrValue, getEntityId, getDocByEntityId } from "@commontools/runner"; import { suggestions } from "../suggestions.js"; import { z } from "zod"; From d84e5cea41150fa714169ce011cf02dba021473a Mon Sep 17 00:00:00 2001 From: Ben Follington <5009316+bfollington@users.noreply.github.com> Date: Mon, 3 Feb 2025 13:24:26 +1000 Subject: [PATCH 2/4] Port os-chrome to React experiment --- .../common-os-ui/src/components/os-tab-bar.ts | 2 +- typescript/packages/jumble/package.json | 1 + .../jumble/src/components/CharmRunner.tsx | 6 +- .../jumble/src/components/Sidebar.tsx | 207 ++++++++++++++++++ .../jumble/src/components/WebComponent.tsx | 13 ++ .../packages/jumble/src/hooks/use-charm.ts | 24 ++ .../jumble/src/hooks/use-web-component.tsx | 53 +++++ .../packages/jumble/src/views/Shell.tsx | 90 +++++++- typescript/packages/jumble/src/views/main.css | 5 + typescript/packages/jumble/src/views/state.ts | 3 + typescript/packages/pnpm-lock.yaml | 3 + 11 files changed, 399 insertions(+), 8 deletions(-) create mode 100644 typescript/packages/jumble/src/components/Sidebar.tsx create mode 100644 typescript/packages/jumble/src/components/WebComponent.tsx create mode 100644 typescript/packages/jumble/src/hooks/use-charm.ts create mode 100644 typescript/packages/jumble/src/hooks/use-web-component.tsx create mode 100644 typescript/packages/jumble/src/views/main.css create mode 100644 typescript/packages/jumble/src/views/state.ts diff --git a/typescript/packages/common-os-ui/src/components/os-tab-bar.ts b/typescript/packages/common-os-ui/src/components/os-tab-bar.ts index dd52df6b7..7297198a7 100644 --- a/typescript/packages/common-os-ui/src/components/os-tab-bar.ts +++ b/typescript/packages/common-os-ui/src/components/os-tab-bar.ts @@ -115,7 +115,7 @@ export class OsTabBar extends LitElement { return html`
- ${this.items.map( + ${this.items?.map( (item) => html`
+
+
+
+
+ +
+ + ), + "recipe-json": ( +
+
Recipe JSON
+
+ +
+
+ ), + data: ( +
+
+ Data + console.log(JSON.stringify(focusedCharm?.getAsQueryResult()))} + className="close-button" + > + log + +
+
+ +
+
+ ), + prompt: ( +
+ +
+ +
+
+ ), + }; + + return ( +
+ + {panels[sidebarTab as keyof typeof panels]} + handleSidebarTabChange(e.detail.selected)} + /> +
+ ); +}; + +export default Sidebar; diff --git a/typescript/packages/jumble/src/components/WebComponent.tsx b/typescript/packages/jumble/src/components/WebComponent.tsx new file mode 100644 index 000000000..167f0acbb --- /dev/null +++ b/typescript/packages/jumble/src/components/WebComponent.tsx @@ -0,0 +1,13 @@ +import { useWebComponent } from "@/hooks/use-web-component"; +import React from "react"; + +export function WebComponent

>({ + as: Element, + children, + ...props +}: { as: string; children?: React.ReactNode } & P) { + const ref = React.useRef(null); + useWebComponent(ref, props); + + return React.createElement(Element, { ref, ...props }, children); +} diff --git a/typescript/packages/jumble/src/hooks/use-charm.ts b/typescript/packages/jumble/src/hooks/use-charm.ts new file mode 100644 index 000000000..55635729a --- /dev/null +++ b/typescript/packages/jumble/src/hooks/use-charm.ts @@ -0,0 +1,24 @@ +import { useEffect, useState } from "react"; +import { DocImpl, effect } from "@commontools/runner"; + +export function useCell(cell: DocImpl): [T, (value: T) => void] { + const [value, setValue] = useState(cell.get()); + + useEffect(() => { + // Set up effect to update state when cell changes + const cleanup = effect(cell, (newValue) => { + setValue(newValue); + }); + + // Clean up effect when component unmounts or cell changes + return cleanup; + }, [cell]); + + // Return tuple of current value and setter function + return [ + value, + (newValue: T) => { + cell.asCell().set(newValue); + }, + ]; +} diff --git a/typescript/packages/jumble/src/hooks/use-web-component.tsx b/typescript/packages/jumble/src/hooks/use-web-component.tsx new file mode 100644 index 000000000..3b0f227bb --- /dev/null +++ b/typescript/packages/jumble/src/hooks/use-web-component.tsx @@ -0,0 +1,53 @@ +import React from "react"; + +export function useWebComponent

>( + ref: React.RefObject, + props: P, +) { + React.useEffect(() => { + if (!ref.current) return; + + const element = ref.current; + // Handle regular props + Object.entries(props).forEach(([key, value]) => { + if (!key.startsWith("on")) { + if (key === "className") { + element.setAttribute("class", value); + } else if (typeof value === "boolean") { + if (value) { + element.setAttribute(key, ""); + } else { + element.removeAttribute(key); + } + } else { + element[key] = value; + } + } + }); + + // Handle event listeners + const eventHandlers = Object.entries(props) + .filter(([key]) => key.startsWith("on")) + .map(([key, handler]) => { + // Convert onEventName to event-name + const eventName = key + .slice(2) + .split(/(?=[A-Z])/) + .map((part) => part.toLowerCase()) + .join("-"); + return { eventName, handler }; + }); + + // Add event listeners + eventHandlers.forEach(({ eventName, handler }) => { + element.addEventListener(eventName, handler); + }); + + // Cleanup + return () => { + eventHandlers.forEach(({ eventName, handler }) => { + element.removeEventListener(eventName, handler); + }); + }; + }, [ref, props]); +} diff --git a/typescript/packages/jumble/src/views/Shell.tsx b/typescript/packages/jumble/src/views/Shell.tsx index 4db67a503..b55a690e1 100644 --- a/typescript/packages/jumble/src/views/Shell.tsx +++ b/typescript/packages/jumble/src/views/Shell.tsx @@ -3,7 +3,17 @@ import "@commontools/ui"; import { setIframeContextHandler } from "@commontools/iframe-sandbox"; import { Action, ReactivityLog, addAction, removeAction } from "@commontools/runner"; import { CharmRunner } from "@/components/CharmRunner"; -import { useState } from "react"; +import { WebComponent } from "@/components/WebComponent"; +import { useEffect, useRef, useState } from "react"; + +import * as osUi from "@commontools/os-ui"; +import { OsChrome } from "@commontools/os-ui/src/components/os-chrome"; +console.log(osUi); +import "@commontools/os-ui/src/static/main.css"; +import Sidebar from "@/components/Sidebar"; +import { useCell } from "@/hooks/use-charm"; +import { sidebar } from "./state"; +import "./main.css"; // FIXME(ja): perhaps this could be in common-charm? needed to enable iframe with sandboxing setIframeContextHandler({ @@ -25,7 +35,47 @@ setIframeContextHandler({ }, }); -export default function Shell() { +interface OsChromeProps { + wide?: boolean; + locationTitle?: string; + children?: React.ReactNode; + onLocation?: () => void; +} + +function Chrome({ + wide = false, + locationTitle = "Test", + children = "test", + onLocation, +}: OsChromeProps) { + const chromeRef = useRef(null); + + useEffect(() => { + const element = chromeRef.current; + if (!element) return; + + (element as any).wide = wide; + element.locationtitle = locationTitle; + + const handleLocation = () => { + if (onLocation) { + onLocation(); + } + }; + + element.addEventListener("location", handleLocation); + + return () => { + element.removeEventListener("location", handleLocation); + }; + }, [wide, locationTitle, onLocation]); + + return {children}; +} + +// bf: probably not the best way to make a cell but it works + +function Content() { const [count, setCount] = useState(0); const incrementCount = () => { @@ -33,7 +83,7 @@ export default function Shell() { }; return ( -

+ <> @@ -41,9 +91,41 @@ export default function Shell() { import("@/recipes/smol.tsx")} argument={{ count }} - className="border border-red-500 mt-4 p-2" + className="w-full h-full" autoLoad /> + + ); +} + +export default function Shell() { + const [sidebarTab] = useCell(sidebar); + + return ( +
+ { + debugger; + }} + > + + + { + console.log("submitted"); + }} + /> + + + + +
); } diff --git a/typescript/packages/jumble/src/views/main.css b/typescript/packages/jumble/src/views/main.css new file mode 100644 index 000000000..4cad0286f --- /dev/null +++ b/typescript/packages/jumble/src/views/main.css @@ -0,0 +1,5 @@ +.pin-br { + position: absolute; + right: 0; + bottom: 0; +} diff --git a/typescript/packages/jumble/src/views/state.ts b/typescript/packages/jumble/src/views/state.ts new file mode 100644 index 000000000..37e20327a --- /dev/null +++ b/typescript/packages/jumble/src/views/state.ts @@ -0,0 +1,3 @@ +import { getDoc } from "@commontools/runner"; + +export const sidebar = getDoc("home"); diff --git a/typescript/packages/pnpm-lock.yaml b/typescript/packages/pnpm-lock.yaml index 6b31a75e9..82e715be1 100644 --- a/typescript/packages/pnpm-lock.yaml +++ b/typescript/packages/pnpm-lock.yaml @@ -429,6 +429,9 @@ importers: '@commontools/iframe-sandbox': specifier: workspace:* version: link:../common-iframe-sandbox + '@commontools/os-ui': + specifier: workspace:* + version: link:../common-os-ui '@commontools/runner': specifier: workspace:* version: link:../common-runner From 2fc100e9fc3091fa32432a05698a5deaea221f51 Mon Sep 17 00:00:00 2001 From: Ben Follington <5009316+bfollington@users.noreply.github.com> Date: Mon, 3 Feb 2025 13:29:27 +1000 Subject: [PATCH 3/4] Remove unused component --- .../packages/jumble/src/views/Shell.tsx | 43 +------------------ typescript/packages/jumble/src/views/state.ts | 1 + 2 files changed, 2 insertions(+), 42 deletions(-) diff --git a/typescript/packages/jumble/src/views/Shell.tsx b/typescript/packages/jumble/src/views/Shell.tsx index b55a690e1..ce59962f0 100644 --- a/typescript/packages/jumble/src/views/Shell.tsx +++ b/typescript/packages/jumble/src/views/Shell.tsx @@ -4,10 +4,9 @@ import { setIframeContextHandler } from "@commontools/iframe-sandbox"; import { Action, ReactivityLog, addAction, removeAction } from "@commontools/runner"; import { CharmRunner } from "@/components/CharmRunner"; import { WebComponent } from "@/components/WebComponent"; -import { useEffect, useRef, useState } from "react"; +import { useState } from "react"; import * as osUi from "@commontools/os-ui"; -import { OsChrome } from "@commontools/os-ui/src/components/os-chrome"; console.log(osUi); import "@commontools/os-ui/src/static/main.css"; import Sidebar from "@/components/Sidebar"; @@ -35,46 +34,6 @@ setIframeContextHandler({ }, }); -interface OsChromeProps { - wide?: boolean; - locationTitle?: string; - children?: React.ReactNode; - onLocation?: () => void; -} - -function Chrome({ - wide = false, - locationTitle = "Test", - children = "test", - onLocation, -}: OsChromeProps) { - const chromeRef = useRef(null); - - useEffect(() => { - const element = chromeRef.current; - if (!element) return; - - (element as any).wide = wide; - element.locationtitle = locationTitle; - - const handleLocation = () => { - if (onLocation) { - onLocation(); - } - }; - - element.addEventListener("location", handleLocation); - - return () => { - element.removeEventListener("location", handleLocation); - }; - }, [wide, locationTitle, onLocation]); - - return {children}; -} - -// bf: probably not the best way to make a cell but it works - function Content() { const [count, setCount] = useState(0); diff --git a/typescript/packages/jumble/src/views/state.ts b/typescript/packages/jumble/src/views/state.ts index 37e20327a..1d8e8cc68 100644 --- a/typescript/packages/jumble/src/views/state.ts +++ b/typescript/packages/jumble/src/views/state.ts @@ -1,3 +1,4 @@ import { getDoc } from "@commontools/runner"; +// bf: probably not the best way to make a cell but it works export const sidebar = getDoc("home"); From bdf9515269c7beb1dc93dfe208c56978ec04340e Mon Sep 17 00:00:00 2001 From: jakedahn Date: Mon, 3 Feb 2025 10:00:52 -0700 Subject: [PATCH 4/4] adding merkle-reference to jumble packages --- typescript/packages/jumble/package.json | 9 +++++---- typescript/packages/pnpm-lock.yaml | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/typescript/packages/jumble/package.json b/typescript/packages/jumble/package.json index d5bbf19ec..5f66c352e 100644 --- a/typescript/packages/jumble/package.json +++ b/typescript/packages/jumble/package.json @@ -24,13 +24,13 @@ "@codemirror/lang-javascript": "^6.2.2", "@codemirror/lang-markdown": "^6.3.2", "@codemirror/view": "^6.36.2", - "@commontools/ui": "workspace:*", - "@commontools/os-ui": "workspace:*", "@commontools/builder": "workspace:*", - "@commontools/runner": "workspace:*", - "@commontools/html": "workspace:*", "@commontools/charm": "workspace:*", + "@commontools/html": "workspace:*", "@commontools/iframe-sandbox": "workspace:*", + "@commontools/os-ui": "workspace:*", + "@commontools/runner": "workspace:*", + "@commontools/ui": "workspace:*", "@react-spring/web": "^9.7.5", "@tailwindcss/typography": "^0.5.16", "@tailwindcss/vite": "^4.0.1", @@ -39,6 +39,7 @@ "@uiw/react-codemirror": "^4.23.7", "@use-gesture/react": "^10.3.1", "emoji-picker-react": "^4.12.0", + "merkle-reference": "^2.0.1", "react": "^18.3.1", "react-dom": "^18.3.1", "react-dropzone": "^14.3.5", diff --git a/typescript/packages/pnpm-lock.yaml b/typescript/packages/pnpm-lock.yaml index 82e715be1..121dd8979 100644 --- a/typescript/packages/pnpm-lock.yaml +++ b/typescript/packages/pnpm-lock.yaml @@ -462,6 +462,9 @@ importers: emoji-picker-react: specifier: ^4.12.0 version: 4.12.0(react@18.3.1) + merkle-reference: + specifier: ^2.0.1 + version: 2.0.1 react: specifier: ^18.3.1 version: 18.3.1