Files
halo-dark-mode-plugin/.agents/skills/halo-plugin-dev/references/ui-entry.md
T
Serendipity edbf78f236 feat: 初始化 Halo 暗色模式插件
- Halo Plugin 后端(Java/Gradle),含 DarkModePlugin 主类和测试
- Vue 3 + TypeScript 前端 UI,包含主题切换组件和设置页面
- 暗色模式 CSS 变量和覆盖样式(布局/编辑器/表单/滚动条等)
- 设计文档和调查文档
- Halo 插件/主题开发 Agent Skills

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-06 21:03:00 +08:00

4.1 KiB

UI Entry & Routes

The frontend entry file exports a plugin definition using definePlugin from @halo-dev/ui-shared.

Entry File (ui/src/index.ts)

import { definePlugin } from "@halo-dev/ui-shared";
import HomeView from "./views/HomeView.vue";
import { IconComputer } from "@halo-dev/components";
import { markRaw } from "vue";

export default definePlugin({
  components: {
    // Global component registration
    // "MyComponent": MyComponent
  },
  routes: [
    // Console routes
    {
      parentName: "Root",
      route: {
        path: "/my-plugin",
        name: "MyPluginHome",
        component: HomeView,
        meta: {
          title: "My Plugin",
          permissions: [],
          menu: {
            name: "My Plugin",
            group: "tool", // dashboard | content | interface | system | tool
            icon: markRaw(IconComputer),
            priority: 40,
          },
        },
      },
    },
  ],
  ucRoutes: [
    // UC (User Center) routes
    {
      parentName: "Root",
      route: {
        path: "/uc-my-plugin",
        name: "MyPluginUCHome",
        component: HomeView,
        meta: {
          permissions: [],
          menu: {
            name: "My Plugin",
            priority: 40,
          },
        },
      },
    },
  ],
  extensionPoints: {
    // UI extension point implementations
  },
  formkit: {
    inputs: {
      // Custom FormKit inputs (Halo 2.25+)
    },
  },
});

Route Definition

With parentName (RouteRecordAppend)

{
  parentName: "Root",
  route: { /* RouteRecordRaw */ }
}

Without parentName (RouteRecordRaw)

{
  path: "/standalone",
  name: "StandalonePage",
  component: MyView
}

Console Parent Routes

parentName Section
Root Top level
AttachmentsRoot Attachment management
CommentsRoot Comments
SinglePagesRoot Single pages
PostsRoot Posts
MenusRoot Menus
ThemeRoot Themes
OverviewRoot Overview
BackupRoot Backups
PluginsRoot Plugins
SettingsRoot Settings
UsersRoot Users
ToolsRoot Tools

UC Parent Routes

parentName Section
PostsRoot Posts
NotificationsRoot Notifications

RouteMeta

interface RouteMeta {
  title?: string; // Browser tab title
  searchable?: boolean; // Include in Console global search
  permissions?: string[]; // Required UI permissions
  menu?: {
    name: string; // Menu display name
    group?: CoreMenuGroupId; // Built-in group or custom group name
    icon?: Component; // Vue icon component (use markRaw)
    priority: number; // Sort order (lower = higher)
    mobile?: boolean; // Show on mobile
  };
}

Using markRaw for Icons

Always wrap icon components with markRaw:

import { IconComputer } from "@halo-dev/components";
import { markRaw } from "vue";

icon: markRaw(IconComputer);

Permissions in Routes

meta: {
  permissions: ["plugin:my-plugin:person:manage"];
}

The route is hidden if the user lacks any of the listed permissions.

Custom FormKit Inputs

Halo 2.25+ lets plugin UI entries register custom FormKit inputs for use in plugin-provided FormKit Schema.

import { createInput } from "@formkit/vue";
import { definePlugin } from "@halo-dev/ui-shared";
import { defineAsyncComponent } from "vue";

export default definePlugin({
  formkit: {
    inputs: {
      myPluginInput: createInput(
        defineAsyncComponent(() => import("./components/MyPluginInput.vue")),
      ),
    },
  },
});

Use a plugin-prefixed input name to avoid collisions with Halo built-ins or earlier-loaded plugins. If the input definition uses @formkit/vue, require @halo-dev/ui-plugin-bundler-kit@2.25.0+ and set plugin.yaml spec.requires to >=2.25.0.