How to Add a New Page Component to the Celeris Web Application

Developers extend the Celeris Web admin panel by creating a Vue single-file component in the pages directory and registering it as a typed route module in the routes folder, which the router auto-discovers via file glob patterns.

Celeris Web is a modern Vue 3 admin dashboard framework that implements file-based route conventions to streamline page registration. When you need to add a new page component to the Celeris Web application, the framework's modular router system eliminates manual route imports by automatically scanning specific directories. This guide walks through creating a page component, registering its route definition, and configuring navigation metadata using the actual source architecture from the kirklin/celeris-web repository.

Create the Vue Page Component

Start by creating the user interface for your new page. The convention places page components in apps/admin/src/pages/ using a directory structure that matches your desired URL path.

  1. Create the directory and file – Add a new folder under apps/admin/src/pages/ (e.g., hello-world/) with an index.vue file.

  2. Use the setup script pattern – Follow the existing codebase style with <script setup lang="ts"> and defineOptions for the component name.

  3. Wrap with PageWrapper – Import and use the PageWrapper component to maintain consistent layout padding and styling.

<!-- apps/admin/src/pages/hello-world/index.vue -->
<script setup lang="ts">
import { defineOptions } from "vue";

defineOptions({ name: "HelloWorldPage" });
</script>

<template>
  <PageWrapper>
    <h1>Hello, Celeris Web!</h1>
    <p>This is a brand-new page component.</p>
  </PageWrapper>
</template>

<style scoped></style>

Reference the Dashboard page at apps/admin/src/pages/dashboard/index.vue for production-ready patterns including data fetching and state management.

Register a Route Module

The router automatically discovers route definitions by importing all TypeScript files in apps/admin/src/router/routes/modules/. You do not need to manually import your new route into the router configuration.

Create a new TypeScript file in that directory that exports a RouteRecordRaw object. The loadRoutesFromModules utility in packages/web/utils/src/router.ts processes these files automatically.

// apps/admin/src/router/routes/modules/hello-world.ts
import type { RouteRecordRaw } from "vue-router";
import { LAYOUT } from "~/router/constant";

const helloWorld: RouteRecordRaw = {
  path: "/hello-world",
  name: "HelloWorldRoot",
  component: LAYOUT,
  redirect: "/hello-world/index",
  meta: {
    title: "routes.helloWorld.helloWorld",
    icon: "i-mdi-emoticon-happy",
    orderNumber: 100,
  },
  children: [
    {
      path: "index",
      name: "HelloWorld",
      component: () => import("~/pages/hello-world/index.vue"),
      meta: {
        title: "routes.helloWorld.helloWorld",
        icon: "i-mdi-emoticon-happy",
        shouldAffixToNavBar: true,
      },
    },
  ],
};

export default helloWorld;

Key implementation details:

  • LAYOUT – Imported from ~/router/constant, this wrapper component provides the common admin UI shell including headers and sidebars.
  • Lazy loading – Use () => import() for the component property to enable code-splitting and improve initial load performance.
  • Meta fields – The title supports i18n keys, icon uses the project's iconify preset, and orderNumber controls the sidebar menu sort order.

The automatic discovery happens in apps/admin/src/router/routes/index.ts via import.meta.glob:

const modules = import.meta.glob<{ default: any }>("./modules/**/*.ts", { eager: true });
const routeModuleList: RouteRecordRaw[] = loadRoutesFromModules(modules);

Configure Sidebar Navigation

To display the page in the left-hand navigation menu, provide the required meta fields in your route definition. The menu system in apps/admin/src/router/menus/index.ts reads the router's meta data to generate the sidebar structure automatically.

  • Set title with an i18n key or string for the menu label.
  • Set icon using the project's icon naming convention (e.g., i-mdi-emoticon-happy).
  • Set orderNumber to position the item relative to other routes.

To hide a page from the menu while keeping it accessible via URL, add shouldHideInMenu: true to the route's meta object. To pin it to the navigation bar, use shouldAffixToNavBar: true.

Verify the New Page

Start the development server to test your implementation:

pnpm run dev

Navigate to http://localhost:8888/#/hello-world to confirm the page renders within the layout shell. Check that:

  • The component loads without console errors.
  • The sidebar displays your new entry (unless hidden).
  • The URL routing resolves correctly.

Summary

  • Create the Vue SFC in apps/admin/src/pages/[page-name]/index.vue using the setup script pattern.
  • Register the route by exporting a RouteRecordRaw object from a new file in apps/admin/src/router/routes/modules/.
  • Leverage the auto-discovery system in packages/web/utils/src/router.ts via loadRoutesFromModules to avoid manual imports.
  • Configure navigation visibility using meta fields like title, icon, orderNumber, and shouldHideInMenu.
  • Use LAYOUT from ~/router/constant to maintain consistent UI wrapping.

Frequently Asked Questions

Do I need to manually import new route files into the router configuration?

No. The system uses import.meta.glob in apps/admin/src/router/routes/index.ts to eagerly import all .ts files under apps/admin/src/router/routes/modules/. The loadRoutesFromModules function in packages/web/utils/src/router.ts automatically processes these into the asyncRoutes array without requiring manual imports.

What is the purpose of the LAYOUT constant in route definitions?

LAYOUT (exported from apps/admin/src/router/constant.ts) is the root wrapper component that renders the common admin interface structure, including the sidebar navigation and header. Assigning it to the parent route's component property ensures your page renders within this shell, while child routes lazy-load the specific page components.

How do I prevent a page from appearing in the sidebar menu?

Add shouldHideInMenu: true to the route's meta object. The menu generation logic in apps/admin/src/router/menus/index.ts filters out routes with this flag set, making the page accessible only via direct URL or programmatic navigation while keeping it out of the navigation UI.

Can I organize route modules into subdirectories?

Yes. The glob pattern "./modules/**/*.ts" recursively searches all subdirectories within apps/admin/src/router/routes/modules/. You can organize routes by feature (e.g., modules/users/profile.ts, modules/users/settings.ts) and the router will discover them automatically.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →