accessibility-expert
WCAG 2.1/2.2 compliance, WAI-ARIA implementation, screen reader optimization, keyboard…
Complete guide for adding, updating, and removing tabs in the Primary Sidebar of OrcaQ. Covers the full flow — ActivityBarItemType enum → useActivityBarStore → PrimarySideBar component → Management panel component. Load this skill for any task involving the left sidebar,
$ npx -y skills add cin12211/orca-q --skill primary-sidebar --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/primary-sidebarContext preview
The summary Claude sees to decide when to auto-load this skill.
Complete guide for adding, updating, and removing tabs in the Primary Sidebar of OrcaQ. Covers the full flow — ActivityBarItemType enum → useActivityBarStore → PrimarySideBar component → Management panel component. Load this skill for any task involving the left sidebar,
name: primary-sidebar description: Complete guide for adding, updating, and removing tabs in the Primary Sidebar of OrcaQ. Covers the full flow — ActivityBarItemType enum → useActivityBarStore → PrimarySideBar component → Management panel component. Load this skill for any task involving the left sidebar, activity bar tabs, or management panels (Explorer, Schemas, ERD, Roles, Export, Agent).
The Primary Sidebar is driven by a single active tab value in a Pinia store. The flow is:
ActivityBarItemType (enum) ← Tab identity useActivityBarStore.activityActive ← Which tab is currently active (persisted) PrimarySideBar.vue ← Watches activityActive, renders the matching component Management***.vue ← The actual panel content (KeepAlive'd)
The Activity Bar (the narrow icon strip on the far left) calls `setActivityActive(type)`. The Primary Sidebar reacts to the change and swaps the rendered panel — all panels are wrapped in `<KeepAlive>` so their state is preserved when the user switches tabs.
---
| Purpose | File | | ------------------------ | ----------------------------------------------------------------------------- | | Tab type enum + store | `core/stores/useActivityBarStore.ts` | | Sidebar shell (switcher) | `components/modules/app-shell/primary-side-bar/components/PrimarySideBar.vue` | | Sidebar public API | `components/modules/app-shell/primary-side-bar/index.ts` | | All management panels | `components/modules/management/` | | Management public API | `components/modules/management/index.ts` | | Shared header component | `components/modules/management/shared/components/ManagementSidebarHeader.vue` |
| Tab | Panel component file | | ------------- | -------------------------------------------------------------------------------- | | Explorer | `components/modules/management/explorer/ManagementExplorer.vue` | | Schemas | `components/modules/management/schemas/ManagementSchemas.vue` | | ERD Diagram | `components/modules/management/erd-diagram/ManagementErdDiagram.vue` | | Users & Roles | `components/modules/management/role-permission/ManagementUsersAndPermission.vue` | | Export | `components/modules/management/export/ManagementExport.vue` | | Agent | `components/modules/management/agent/ManagementAgent.vue` |
---
<script setup lang="ts">
const activityStore = useActivityBarStore();
const current = shallowRef();
watch(
() => activityStore.activityActive,
() => {
if (activityStore.activityActive === ActivityBarItemType.Explorer)
current.value = ManagementExplorer;
if (activityStore.activityActive === ActivityBarItemType.Schemas)
current.value = ManagementSchemas;
// ... one branch per tab
},
{ immediate: true }
);
</script>
<template>
<div class="w-full h-full flex flex-col" v-if="appConfigStore.layoutSize[0]">
<KeepAlive>
<component :is="current" />
</KeepAlive>
</div>
</template>Key points:
---
In `core/stores/useActivityBarStore.ts`:
export enum ActivityBarItemType {
Explorer = 'Explorer',
Schemas = 'Schemas',
ErdDiagram = 'ERDiagram',
UsersRoles = 'UsersRoles',
DatabaseExport = 'DatabaseExport',
Agent = 'Agent',
MyNewTab = 'MyNewTab', // ← new
}Create the folder `components/modules/management/my-new-tab/` with this structure:
my-new-tab/ ├── index.ts ← exports ManagementMyNewTab ├── ManagementMyNewTab.vue ← entry component ├── components/ ← sub-components (optional) ├── hooks/ ← business logic composables (optional) └── services/ ← API calls (optional)
**`ManagementMyNewTab.vue`** minimum template:
<script setup lang="ts">
import { ManagementSidebarHeader } from '../shared';
</script>
<template>
<div class="flex flex-col h-full w-full overflow-y-auto">
<ManagementSidebarHeader title="My New Tab" />
<!-- panel content here -->
</div>
</template>**`index.ts`**:
export { default as ManagementMyNewTab } from './ManagementMyNewTab.vue';In `components/modules/management/index.ts`:
export * from './my-new-tab'; // ← add this line
In `components/modules/app-shell/primary-side-bar/components/PrimarySideBar.vue`:
// 1. Import the component
import { ManagementMyNewTab } from '#components';
// 2. Add a branch in the watch
watch(
() => activityStore.activityActive,
() => {
// ... existing branches ...
if (activityStore.activityActive === ActivityBarItemType.MyNewTab)
current.value = ManagementMyNewTab;
},
{ immediate: true }
);The Activity Bar icon strip that calls `setActivityActive` is separate from the management module. Find the component that renders the icon list and add a button:
activityStore.setActivityActive(A
Repo: cin12211/orca-q
WCAG 2.1/2.2 compliance, WAI-ARIA implementation, screen reader optimization, keyboard…
CSS architecture and styling expert with deep knowledge of modern CSS features, responsive…
Database performance optimization, schema design, query analysis, and connection management…
Expert in documentation structure, cohesion, flow, audience targeting, and information…
Git expert with deep knowledge of merge conflicts, branching strategies, repository recovery,…
Use for any question about a codebase, its architecture, file relationships, or project…