tab, toast grid 추가
This commit is contained in:
@@ -1,42 +1,18 @@
|
||||
<template>
|
||||
<div class="layout">
|
||||
<AppHeader v-model="activeMenu" @update:model-value="onMenuClick" />
|
||||
<nav
|
||||
v-if="subMenus && subMenus.length && showSubmenuBar"
|
||||
class="submenu-bar"
|
||||
@click.stop
|
||||
>
|
||||
<NuxtLink
|
||||
v-for="sub in subMenus"
|
||||
:key="sub.key"
|
||||
:to="sub.to"
|
||||
class="submenu-btn"
|
||||
:class="{ active: $route.path === sub.to }"
|
||||
>
|
||||
{{ sub.label }}
|
||||
</NuxtLink>
|
||||
</nav>
|
||||
<main class="main">
|
||||
<slot />
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<p>© 2024 Nuxt.js App</p>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import AppHeader from "../components/AppHeader.vue";
|
||||
import { ref, computed, watch, onMounted, onBeforeUnmount } from "vue";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import { useTabsStore } from "../stores/tab";
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const activeMenu = ref("home");
|
||||
const showSubmenuBar = ref(false);
|
||||
|
||||
const tabsStore = useTabsStore();
|
||||
|
||||
// HOME 메뉴가 선택되었을 때 최상단 경로로 이동
|
||||
watch(activeMenu, newValue => {
|
||||
watch(activeMenu, (newValue) => {
|
||||
if (newValue === "home") {
|
||||
router.push("/");
|
||||
}
|
||||
@@ -46,6 +22,7 @@ watch(route, () => {
|
||||
showSubmenuBar.value = false;
|
||||
});
|
||||
|
||||
// 서브메뉴 정의
|
||||
const subMenus = computed(() => {
|
||||
if (activeMenu.value === "test") {
|
||||
return [
|
||||
@@ -58,16 +35,10 @@ const subMenus = computed(() => {
|
||||
{ key: "pathway4", label: "pathway4", to: "/cultureGraph/pathway4" },
|
||||
{ key: "pathwayjson", label: "pathwayjson", to: "/test/pathwayjson" },
|
||||
{ key: "cultureGraph", label: "배양그래프", to: "/test/culture-graph" },
|
||||
{
|
||||
key: "cultureGraphMulti",
|
||||
label: "배양그래프 멀티",
|
||||
to: "/test/culture-graph-multi",
|
||||
},
|
||||
{
|
||||
key: "cultureGraphTab",
|
||||
label: "배양그래프 탭",
|
||||
to: "/test/culture-graph-tab",
|
||||
},
|
||||
{ key: "cultureGraphMulti", label: "배양그래프 멀티", to: "/test/culture-graph-multi" },
|
||||
{ key: "cultureGraphTab", label: "배양그래프 탭", to: "/test/culture-graph-tab" },
|
||||
{ key: "tui-grid", label: "tui-grid", to: "/tui" },
|
||||
{ key: "리소스", label: "리소스", to: "/admin/resource" },
|
||||
];
|
||||
} else if (activeMenu.value === "admin") {
|
||||
return [
|
||||
@@ -76,7 +47,6 @@ const subMenus = computed(() => {
|
||||
{ key: "programs", label: "프로그램", to: "/admin/programs" },
|
||||
];
|
||||
}
|
||||
// HOME 메뉴일 때는 서브메뉴 없음
|
||||
return [];
|
||||
});
|
||||
|
||||
@@ -85,9 +55,14 @@ function onMenuClick(menu: string) {
|
||||
showSubmenuBar.value = true;
|
||||
}
|
||||
|
||||
// 서브메뉴 클릭 시 탭 추가
|
||||
function onSubMenuClick(sub: { key: string; label: string; to: string, componentName:string }) {
|
||||
tabsStore.addTab(sub);
|
||||
router.push(sub.to);
|
||||
}
|
||||
|
||||
function handleClickOutsideSubmenuBar(event: MouseEvent) {
|
||||
const submenu = document.querySelector(".submenu-bar");
|
||||
// menu-btn(대메뉴) 클릭 시에는 닫히지 않도록 예외 처리
|
||||
if (
|
||||
submenu &&
|
||||
!submenu.contains(event.target as Node) &&
|
||||
@@ -103,14 +78,53 @@ onMounted(() => {
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener("click", handleClickOutsideSubmenuBar);
|
||||
});
|
||||
/*
|
||||
useHead({
|
||||
title: "Integrated Bio Foundry Platform",
|
||||
meta: [{ name: "description", content: "Integrated Bio Foundry Platform" }],
|
||||
});
|
||||
*/
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="layout">
|
||||
<AppHeader v-model="activeMenu" @update:model-value="onMenuClick" />
|
||||
|
||||
<!-- 서브메뉴 바 -->
|
||||
<nav
|
||||
v-if="subMenus && subMenus.length && showSubmenuBar"
|
||||
class="submenu-bar"
|
||||
@click.stop
|
||||
>
|
||||
<button
|
||||
v-for="sub in subMenus"
|
||||
:key="sub.key"
|
||||
class="submenu-btn"
|
||||
:class="{ active: $route.path === sub.to }"
|
||||
@click="onSubMenuClick({...sub, componentName : sub.key})"
|
||||
>
|
||||
{{ sub.label }}
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<!-- 동적 탭 바 -->
|
||||
<div v-if="tabsStore.tabs.length" class="tab-bar">
|
||||
<div
|
||||
v-for="tab in tabsStore.tabs"
|
||||
:key="tab.key"
|
||||
class="tab-item"
|
||||
:class="{ active: tabsStore.activeTab === tab.key }"
|
||||
@click="tabsStore.setActiveTab(tab.key); router.push(tab.to)"
|
||||
>
|
||||
{{ tab.label }}
|
||||
<span class="close-btn" @click.stop="tabsStore.removeTab(tab.key)">×</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="main">
|
||||
<slot />
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
<p>© 2024 Nuxt.js App</p>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.layout {
|
||||
min-height: 100vh;
|
||||
@@ -162,4 +176,29 @@ useHead({
|
||||
background: #e6f0fa;
|
||||
color: #1976d2;
|
||||
}
|
||||
|
||||
/* 탭바 스타일 */
|
||||
.tab-bar {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
padding: 0.4rem 0.8rem;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
.tab-item {
|
||||
padding: 0.3rem 0.8rem;
|
||||
background: #f2f2f2;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.tab-item.active {
|
||||
background: #1976d2;
|
||||
color: white;
|
||||
}
|
||||
.close-btn {
|
||||
margin-left: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
Reference in New Issue
Block a user