diff --git a/apps/shelve/app/components/CommandPalette.vue b/apps/shelve/app/components/CommandPalette.vue
index 85279cb1..80e31070 100644
--- a/apps/shelve/app/components/CommandPalette.vue
+++ b/apps/shelve/app/components/CommandPalette.vue
@@ -267,6 +267,9 @@ function playAction(item: CommandItem, index: number) {
+
+ {{ item.suffix }}
+
{
+ try {
+ const projects = useProjects(team.slug)
+ if (!projects.value || projects.value.length === 0) {
+ projects.value = await $fetch(`/api/teams/${team.slug}/projects`)
+ }
+ } catch (error) {
+ console.error(`Failed to fetch projects for ${team.slug}:`, error)
+ }
+ }))
+ }
+
+ // Eagerly fetch projects when teams are available
+ watch(teams, (newTeams) => {
+ if (newTeams && newTeams.length > 0) {
+ fetchAllProjects()
+ }
+ }, { immediate: true })
+
// Submenu state
const subMenuState = reactive({
active: false,
@@ -252,6 +275,40 @@ export function useAppCommands() {
}))
})
+ // Project commands - all projects from all teams
+ const projectCommands = computed(() => {
+ if (!teams.value || teams.value.length === 0) return []
+
+ const currentTeamSlug = getTeamSlug()
+ const allProjects: CommandItem[] = []
+
+ // useProjects returns useState keyed by slug - safe to call in computed
+ for (const team of teams.value) {
+ const projects = useProjects(team.slug)
+ if (!projects.value || projects.value.length === 0) continue
+
+ const isCurrentTeam = team.slug === currentTeamSlug
+ for (const project of projects.value) {
+ allProjects.push({
+ id: `project-${project.id}`,
+ label: project.name,
+ icon: project.logo || 'lucide:folder',
+ isAvatar: Boolean(project.logo),
+ suffix: isCurrentTeam ? undefined : team.name,
+ description: isCurrentTeam ? undefined : `in ${team.name}`,
+ action: () => navigateTo(`/${team.slug}/projects/${project.id}`),
+ keywords: ['project', 'switch', project.name, team.name],
+ active: route.params.projectId === String(project.id),
+ })
+ }
+ }
+
+ // Hide if only 1 project total
+ if (allProjects.length <= 1) return []
+
+ return allProjects
+ })
+
// Help & Support commands
const helpCommands = computed(() => [
{
@@ -346,6 +403,15 @@ export function useAppCommands() {
})
}
+ // Only show projects if available
+ if (projectCommands.value.length > 0) {
+ groups.push({
+ id: 'projects',
+ label: 'Projects',
+ items: projectCommands.value
+ })
+ }
+
// Only show navigation if we have teams
if (teams.value && teams.value.length > 0) {
groups.push({
diff --git a/packages/types/src/Command.ts b/packages/types/src/Command.ts
index afc3ce53..d467151f 100644
--- a/packages/types/src/Command.ts
+++ b/packages/types/src/Command.ts
@@ -4,6 +4,7 @@ export interface CommandItem {
icon: string
isAvatar?: boolean
description?: string
+ suffix?: string
action?: () => void | Promise
keywords?: string[]
active?: boolean