Skip to content

Developing a Widget

This section shows how to build a simple custom module-list widget for the designer sidebar.

Directory

text
modulesWidget/
  index.jsx

index.jsx

jsx
import { inject } from 'vue';
import { PTAH_INSTANCE, RESOURCE_TYPE } from '@ptahjs/ui-vue';

export const ModulesWidget = {
    name: 'ModulesWidget',
    setup() {
        const app = inject(PTAH_INSTANCE);
        const moduleTree = app.getResource(RESOURCE_TYPE.INITIAL_MODULE_TREE) || [];

        const addModule = (node) => {
            app.designer.addModule({
                type: node.type,
                parentId: app.$state.currentSceneId,
            });
        };

        const renderTree = (nodes = []) => {
            return nodes.map((node) => (
                <section key={node.type || node.title} data-title={node.title}>
                    {node.type && node.visible !== false && (
                        <div class="module-item" onClick={() => addModule(node)}>
                            {node.title}
                        </div>
                    )}
                    {node.children?.length > 0 && (
                        <div class="module-children">{renderTree(node.children)}</div>
                    )}
                </section>
            ));
        };

        return () => <aside class="modules-widget">{renderTree(moduleTree)}</aside>;
    },
};

Explanation

  • inject(PTAH_INSTANCE) gets the current runtime
  • RESOURCE_TYPE.INITIAL_MODULE_TREE provides the registered module tree
  • app.designer.addModule() inserts a module into the current scene
  • app.$state.currentSceneId is the active scene ID

Usage

vue
<template>
    <DesignerRoot :app="runtime">
        <aside>
            <ModulesWidget />
        </aside>
        <main>
            <WorkspaceWidget />
        </main>
    </DesignerRoot>
</template>

<script setup>
import { useDesignerApp, DesignerRoot, WorkspaceWidget } from '@ptahjs/ui-vue';
import { ModulesWidget } from './modulesWidget';

const runtime = useDesignerApp({ id: 've1' });
</script>