Init Repo

This commit is contained in:
2026-02-28 03:22:04 +08:00
commit de59b57ee7
883 changed files with 156857 additions and 0 deletions
@@ -0,0 +1,178 @@
<template>
<div class="w-full">
<div class="grid w-full grid-cols-5 h-auto bg-muted/50 p-1 rounded-md">
<button
v-for="tab in tabs"
:key="tab.id"
@click="setActiveTab(tab.id)"
:class="[
'flex flex-col sm:flex-row items-center justify-center gap-1 sm:gap-2 py-2 px-1 sm:px-3 min-h-[3rem] sm:min-h-[2.5rem] transition-all duration-200 text-center rounded-sm',
activeTab === tab.id
? 'bg-background shadow-sm text-foreground'
: 'text-muted-foreground hover:text-foreground hover:bg-background/50'
]"
>
<div class="flex items-center gap-1 sm:gap-2">
<component :is="tab.icon" class="h-4 w-4 flex-shrink-0" />
<span class="hidden sm:inline text-sm font-medium">{{ tab.label }}</span>
<span class="sm:hidden text-xs font-medium">{{ getMobileLabel(tab) }}</span>
</div>
<Badge
v-if="tab.count !== undefined"
variant="secondary"
class="text-xs hidden sm:inline-flex min-w-[1.5rem] h-5"
>
{{ tab.count }}
</Badge>
<!-- Mobile count display -->
<div
v-if="tab.count !== undefined"
class="sm:hidden text-xs text-muted-foreground font-medium"
>
{{ tab.count }}
</div>
</button>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { LayoutDashboard, Camera, Package, ListTodo, Settings } from "lucide-vue-next";
import { Badge } from "@/components/ui/badge";
interface Tab {
id: string;
label: string;
icon: any;
route: string;
count?: number;
}
interface Props {
projectId: number;
shotCount?: number;
assetCount?: number;
taskCount?: number;
}
const props = defineProps<Props>();
const route = useRoute();
const router = useRouter();
// Define available tabs
const tabs = computed<Tab[]>(() => [
{
id: "overview",
label: "Overview",
icon: LayoutDashboard,
route: `/projects/${props.projectId}`,
},
{
id: "shots",
label: "Shots",
icon: Camera,
route: `/projects/${props.projectId}/shots`,
count: props.shotCount,
},
{
id: "assets",
label: "Assets",
icon: Package,
route: `/projects/${props.projectId}/assets`,
count: props.assetCount,
},
{
id: "tasks",
label: "Tasks",
icon: ListTodo,
route: `/projects/${props.projectId}/tasks`,
count: props.taskCount,
},
{
id: "settings",
label: "Settings",
icon: Settings,
route: `/projects/${props.projectId}/settings`,
},
]);
// Determine active tab based on current route
const activeTab = computed(() => {
const currentPath = route.path;
// Debug logging
console.log('ProjectTabs - Current path:', currentPath);
console.log('ProjectTabs - Project ID:', props.projectId);
if (currentPath === `/projects/${props.projectId}`) {
console.log('ProjectTabs - Active tab: overview');
return "overview";
} else if (currentPath.startsWith(`/projects/${props.projectId}/shots`)) {
console.log('ProjectTabs - Active tab: shots');
return "shots";
} else if (currentPath.startsWith(`/projects/${props.projectId}/assets`)) {
console.log('ProjectTabs - Active tab: assets');
return "assets";
} else if (currentPath.startsWith(`/projects/${props.projectId}/tasks`)) {
console.log('ProjectTabs - Active tab: tasks');
return "tasks";
} else if (
currentPath.startsWith(`/projects/${props.projectId}/settings`)
) {
console.log('ProjectTabs - Active tab: settings');
return "settings";
}
console.log('ProjectTabs - Active tab: overview (default)');
return "overview";
});
// Set active tab and navigate
const setActiveTab = (tabId: string) => {
const tab = tabs.value.find((t) => t.id === tabId);
console.log('ProjectTabs - Setting active tab:', tabId);
console.log('ProjectTabs - Tab found:', tab);
console.log('ProjectTabs - Current route path:', route.path);
console.log('ProjectTabs - Target route:', tab?.route);
if (tab) {
console.log('ProjectTabs - Navigating to:', tab.route);
router.push(tab.route).catch(err => {
console.error('ProjectTabs - Navigation error:', err);
});
} else {
console.log('ProjectTabs - Tab not found');
}
};
// Get mobile label for tabs
const getMobileLabel = (tab: Tab) => {
switch (tab.id) {
case "settings":
return "Settings";
case "overview":
return "Info";
case "shots":
return "Shots";
case "assets":
return "Assets";
case "tasks":
return "Tasks";
default:
return tab.label.charAt(0);
}
};
// Watch for route changes to ensure tab state persistence
watch(
() => route.path,
() => {
// Tab state is automatically updated via activeTab computed property
// This ensures tab state persistence during project navigation
},
{ immediate: true }
);
</script>