Newer
Older
navi-1 / webclient / src / components / ui / registry.js
/**
 * Auto-discovered registry of UI components rendered by the navi_ui MCP server.
 *
 * Add a new Vue SFC named in PascalCase matching the snake_case component name:
 *   card_grid  -> CardGrid.vue
 *   code_block -> CodeBlock.vue
 *
 * The registry exports:
 *   - resolve(name): look up a component constructor by snake_case name
 *   - list(): array of registered names
 */

import { defineAsyncComponent, markRaw } from 'vue'

const modules = import.meta.glob('./*.vue', { eager: true })

function pascalCaseFromSnake(name) {
  return name
    .split('_')
    .map(part => part.charAt(0).toUpperCase() + part.slice(1))
    .join('')
}

const registry = new Map()

for (const path in modules) {
  const fileName = path.replace(/^.*\//, '').replace(/\.vue$/, '')
  const component = modules[path].default
  if (!component) continue

  // Register under PascalCase file name (e.g. CardGrid)
  registry.set(fileName, markRaw(component))

  // Also register under snake_case alias (e.g. card_grid)
  const snakeAlias = fileName
    .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
    .toLowerCase()
  registry.set(snakeAlias, markRaw(component))
}

export function resolve(name) {
  if (!name || typeof name !== 'string') return null
  if (registry.has(name)) return registry.get(name)

  const pascal = pascalCaseFromSnake(name)
  return registry.get(pascal) || null
}

export function list() {
  return Array.from(registry.keys())
}