From f6128874039b462f080674f7e0c80e3b25b43677 Mon Sep 17 00:00:00 2001 From: Jordan Santell Date: Wed, 26 Nov 2025 11:48:47 -0800 Subject: [PATCH] feat: Add home space to shell when on the root path --- packages/shell/src/lib/default-pattern.ts | 35 ------------- packages/shell/src/lib/pattern-factory.ts | 61 +++++++++++++++++++++++ packages/shell/src/lib/runtime.ts | 4 +- packages/shell/src/views/AppView.ts | 23 ++++++++- packages/shell/src/views/BodyView.ts | 6 +-- packages/shell/src/views/RootView.ts | 2 +- 6 files changed, 88 insertions(+), 43 deletions(-) delete mode 100644 packages/shell/src/lib/default-pattern.ts create mode 100644 packages/shell/src/lib/pattern-factory.ts diff --git a/packages/shell/src/lib/default-pattern.ts b/packages/shell/src/lib/default-pattern.ts deleted file mode 100644 index f99f24fae..000000000 --- a/packages/shell/src/lib/default-pattern.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { CharmController, CharmsController } from "@commontools/charm/ops"; -import { HttpProgramResolver } from "@commontools/js-compiler"; -import { API_URL } from "./env.ts"; - -const DEFAULT_CHARM_NAME = "DefaultCharmList"; -const DEFAULT_APP_URL = `${API_URL}api/patterns/default-app.tsx`; - -export async function create(cc: CharmsController): Promise { - const manager = cc.manager(); - const runtime = manager.runtime; - - const program = await cc.manager().runtime.harness.resolve( - new HttpProgramResolver(DEFAULT_APP_URL), - ); - - const charm = await cc.create(program, undefined, "default-charm"); - - // Wait for the link to be processed - await runtime.idle(); - await manager.synced(); - - // Link the default pattern to the space cell - await manager.linkDefaultPattern(charm.getCell()); - - return charm; -} - -export function getDefaultPattern( - charms: CharmController[], -): CharmController | undefined { - return charms.find((c) => { - const name = c.name(); - return name && name.startsWith(DEFAULT_CHARM_NAME); - }); -} diff --git a/packages/shell/src/lib/pattern-factory.ts b/packages/shell/src/lib/pattern-factory.ts new file mode 100644 index 000000000..fa312d2dd --- /dev/null +++ b/packages/shell/src/lib/pattern-factory.ts @@ -0,0 +1,61 @@ +import { CharmController, CharmsController } from "@commontools/charm/ops"; +import { HttpProgramResolver } from "@commontools/js-compiler"; +import { API_URL } from "./env.ts"; + +export type BuiltinPatternType = "home" | "space-default"; + +type BuiltinPatternConfig = { + url: URL; + cause: string; + name: string; +}; + +const Configs: Record = { + "home": { + name: "Home", + url: new URL(`/api/patterns/home.tsx`, API_URL), + cause: "home-pattern", + }, + "space-default": { + name: "DefaultCharmList", + url: new URL(`/api/patterns/default-app.tsx`, API_URL), + cause: "default-charm", + }, +}; + +export async function create( + cc: CharmsController, + type: BuiltinPatternType, +): Promise { + const config = Configs[type]; + const manager = cc.manager(); + const runtime = manager.runtime; + + const program = await cc.manager().runtime.harness.resolve( + new HttpProgramResolver(config.url.href), + ); + + const charm = await cc.create(program, undefined, config.cause); + + // Wait for the link to be processed + await runtime.idle(); + await manager.synced(); + + if (type === "space-default") { + // Link the default pattern to the space cell + await manager.linkDefaultPattern(charm.getCell()); + } + + return charm; +} + +export function getPattern( + charms: CharmController[], + type: BuiltinPatternType, +): CharmController | undefined { + const config = Configs[type]; + return charms.find((c) => { + const name = c.name(); + return name && name.startsWith(config.name); + }); +} diff --git a/packages/shell/src/lib/runtime.ts b/packages/shell/src/lib/runtime.ts index 5f54460c9..e0bfefdf2 100644 --- a/packages/shell/src/lib/runtime.ts +++ b/packages/shell/src/lib/runtime.ts @@ -106,8 +106,8 @@ export class RuntimeInternals extends EventTarget { ): Promise { let session; let spaceName; - if (typeof view === "string") { - switch (view) { + if ("builtin" in view) { + switch (view.builtin) { case "home": session = await createSession({ identity, spaceDid: identity.did() }); spaceName = ""; diff --git a/packages/shell/src/views/AppView.ts b/packages/shell/src/views/AppView.ts index 7ef29b4ea..292470ed9 100644 --- a/packages/shell/src/views/AppView.ts +++ b/packages/shell/src/views/AppView.ts @@ -16,6 +16,7 @@ import { navigate, updatePageTitle } from "../lib/navigate.ts"; import { provide } from "@lit/context"; import { KeyboardRouter } from "../lib/keyboard-router.ts"; import { keyboardRouterContext } from "@commontools/ui"; +import * as PatternFactory from "../lib/pattern-factory.ts"; export class XAppView extends BaseView { static override styles = css` @@ -126,12 +127,30 @@ export class XAppView extends BaseView { // Maps the app level view to a specific charm to load // as the primary, active charm. _activeCharmId = new Task(this, { - task: ([app, rt]): string | undefined => { + task: async ([app, rt]): Promise => { if (!app || !rt) { return; } if ("builtin" in app.view) { - console.warn("Unsupported view type"); + if (app.view.builtin !== "home") { + console.warn("Unsupported view type"); + return; + } + { + await rt.cc().manager().synced(); + const pattern = await PatternFactory.getPattern( + rt.cc().getAllCharms(), + "home", + ); + if (pattern) { + return pattern.id; + } + } + const pattern = await PatternFactory.create( + rt.cc(), + "home", + ); + return pattern.id; } else if ("spaceDid" in app.view) { console.warn("Unsupported view type"); } else if ("spaceName" in app.view) { diff --git a/packages/shell/src/views/BodyView.ts b/packages/shell/src/views/BodyView.ts index e14fb553e..87b81aafc 100644 --- a/packages/shell/src/views/BodyView.ts +++ b/packages/shell/src/views/BodyView.ts @@ -4,7 +4,7 @@ import { Task } from "@lit/task"; import { BaseView } from "./BaseView.ts"; import { RuntimeInternals } from "../lib/runtime.ts"; import { CharmController } from "@commontools/charm/ops"; -import * as DefaultPattern from "../lib/default-pattern.ts"; +import * as PatternFactory from "../lib/pattern-factory.ts"; import "../components/OmniLayout.ts"; export class XBodyView extends BaseView { @@ -79,7 +79,7 @@ export class XBodyView extends BaseView { this.creatingDefaultPattern = true; try { - await DefaultPattern.create(this.rt.cc()); + await PatternFactory.create(this.rt.cc(), "space-default"); } catch (error) { console.error("Could not create default pattern:", error); // Re-throw to expose errors instead of swallowing them @@ -117,7 +117,7 @@ export class XBodyView extends BaseView { } const defaultPattern = charms - ? DefaultPattern.getDefaultPattern(charms) + ? PatternFactory.getPattern(charms, "space-default") : undefined; const activeCharm = this.activeCharm; diff --git a/packages/shell/src/views/RootView.ts b/packages/shell/src/views/RootView.ts index 191d04822..65f5fbb2a 100644 --- a/packages/shell/src/views/RootView.ts +++ b/packages/shell/src/views/RootView.ts @@ -42,7 +42,7 @@ export class XRootView extends BaseView { // Non-private for typing in `updated()` callback _app = { apiUrl: API_URL, - view: { spaceName: "common-knowledge" }, + view: { builtin: "home" }, } as AppState; @property()