|
|
|
|
@ -5,7 +5,7 @@
|
|
|
|
|
import { ref, computed, watch, onMounted, onBeforeUnmount } from "vue";
|
|
|
|
|
import { useRoute, useRouter } from "vue-router";
|
|
|
|
|
import { storage } from "@/utils/storage.js";
|
|
|
|
|
import { UserManagerService } from "@/components/service/management/userManagerService";
|
|
|
|
|
import { UserManagerService } from "@/components/service/management/UserManagerService";
|
|
|
|
|
import { menuUtils } from "@/utils/menuUtils";
|
|
|
|
|
|
|
|
|
|
/* ================================
|
|
|
|
|
@ -20,7 +20,7 @@ type MenuItem = {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* ================================
|
|
|
|
|
* Router / Base states
|
|
|
|
|
* Router / Reactive base state
|
|
|
|
|
* ================================ */
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
@ -29,9 +29,12 @@ const username = ref<string>("");
|
|
|
|
|
const projectName = ref<string>(localStorage.getItem("projectName") || "");
|
|
|
|
|
|
|
|
|
|
const isAdmin = ref<boolean>(false);
|
|
|
|
|
const adminMode = ref<boolean>(false);
|
|
|
|
|
const adminMode = ref<boolean>(false); // Settings 버튼으로 온/오프
|
|
|
|
|
const lastNonAdminPath = ref<string>("/home");
|
|
|
|
|
|
|
|
|
|
/* ================================
|
|
|
|
|
* Auth / Role helpers
|
|
|
|
|
* ================================ */
|
|
|
|
|
function readAuth() {
|
|
|
|
|
try {
|
|
|
|
|
const raw =
|
|
|
|
|
@ -43,6 +46,7 @@ function readAuth() {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function computeIsAdmin() {
|
|
|
|
|
const auth = readAuth();
|
|
|
|
|
const roles = auth?.userInfo?.roles ?? auth?.roles ?? [];
|
|
|
|
|
@ -52,6 +56,7 @@ function computeIsAdmin() {
|
|
|
|
|
: roles === "ROLE_ADMIN";
|
|
|
|
|
isAdmin.value = inRoles || authCd === "ADMIN";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateUsername() {
|
|
|
|
|
const auth = readAuth();
|
|
|
|
|
username.value = auth?.userInfo?.username ?? auth?.username ?? "";
|
|
|
|
|
@ -59,6 +64,8 @@ function updateUsername() {
|
|
|
|
|
|
|
|
|
|
/* ================================
|
|
|
|
|
* Derived route state
|
|
|
|
|
* - /select 에서는 상단 메뉴 전체 숨김
|
|
|
|
|
* - 관리자 탭 표시 조건: adminMode ON || 관리자 라우트
|
|
|
|
|
* ================================ */
|
|
|
|
|
const hideAllMenus = computed<boolean>(() => route.path.startsWith("/select"));
|
|
|
|
|
|
|
|
|
|
@ -71,16 +78,18 @@ const isAdminRoute = computed<boolean>(() => {
|
|
|
|
|
const hitMeta = route.matched.some((r) => r.meta?.requiresAdmin);
|
|
|
|
|
return hitPath || hitMeta;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const showAdminTabs = computed<boolean>(
|
|
|
|
|
() => adminMode.value || isAdminRoute.value,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* ================================
|
|
|
|
|
* Menus
|
|
|
|
|
* Menus (기본/관리자)
|
|
|
|
|
* ================================ */
|
|
|
|
|
const baseMenus = computed<MenuItem[]>(
|
|
|
|
|
() => (menuUtils?.menuItem ?? []) as MenuItem[],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const adminMenus = computed<MenuItem[]>(() => {
|
|
|
|
|
const fromUtil = (menuUtils?.adminMenuItem ?? []) as MenuItem[];
|
|
|
|
|
return fromUtil.length
|
|
|
|
|
@ -90,75 +99,50 @@ const adminMenus = computed<MenuItem[]>(() => {
|
|
|
|
|
{ title: "Users", icon: "mdi-account-multiple", path: "/users" },
|
|
|
|
|
];
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const isLinkActive = (path?: string) => !!path && route.path.startsWith(path);
|
|
|
|
|
|
|
|
|
|
/* ================================
|
|
|
|
|
* 사용자 메뉴 (우측)
|
|
|
|
|
* Header dropdown menu
|
|
|
|
|
* ================================ */
|
|
|
|
|
const menu = ref<MenuItem[]>([]);
|
|
|
|
|
const menuItems: MenuItem[] = [
|
|
|
|
|
{ title: "Select Project", click: () => goSelect() },
|
|
|
|
|
{ title: "Change Password", click: () => {} },
|
|
|
|
|
{
|
|
|
|
|
title: "Change Password",
|
|
|
|
|
click: () => {
|
|
|
|
|
/* open modal */
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{ title: "Logout", icon: "mdi-logout", click: () => logOut() },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
/* ================================
|
|
|
|
|
* 상단 Hover 하위 메뉴 스트립
|
|
|
|
|
* ================================ */
|
|
|
|
|
type DepthItem = { title: string; path: string };
|
|
|
|
|
|
|
|
|
|
const hoverBar = ref<{
|
|
|
|
|
open: boolean;
|
|
|
|
|
items: DepthItem[];
|
|
|
|
|
}>({ open: false, items: [] });
|
|
|
|
|
|
|
|
|
|
let hideTimer: number | null = null;
|
|
|
|
|
|
|
|
|
|
function showHoverStrip(m: MenuItem) {
|
|
|
|
|
if (!m.depth?.length) return;
|
|
|
|
|
if (hideTimer) {
|
|
|
|
|
window.clearTimeout(hideTimer);
|
|
|
|
|
hideTimer = null;
|
|
|
|
|
}
|
|
|
|
|
hoverBar.value = {
|
|
|
|
|
open: true,
|
|
|
|
|
items: m.depth,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
function scheduleHideStrip() {
|
|
|
|
|
if (hideTimer) window.clearTimeout(hideTimer);
|
|
|
|
|
hideTimer = window.setTimeout(() => {
|
|
|
|
|
hoverBar.value.open = false;
|
|
|
|
|
}, 140);
|
|
|
|
|
}
|
|
|
|
|
function keepStrip() {
|
|
|
|
|
if (hideTimer) {
|
|
|
|
|
window.clearTimeout(hideTimer);
|
|
|
|
|
hideTimer = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ================================
|
|
|
|
|
* Navigation
|
|
|
|
|
* Navigation actions
|
|
|
|
|
* ================================ */
|
|
|
|
|
function goMain() {
|
|
|
|
|
adminMode.value = false;
|
|
|
|
|
router.push("/home");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function goSelect() {
|
|
|
|
|
adminMode.value = false;
|
|
|
|
|
router.push("/select");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function toggleAdmin() {
|
|
|
|
|
if (!isAdmin.value) return;
|
|
|
|
|
if (adminMode.value) {
|
|
|
|
|
// 끌 때는 무조건 홈으로
|
|
|
|
|
adminMode.value = false;
|
|
|
|
|
router.push("/home");
|
|
|
|
|
} else {
|
|
|
|
|
adminMode.value = true;
|
|
|
|
|
// 켰는데 일반 라우트면 프로젝트로 이동
|
|
|
|
|
if (!isAdminRoute.value) router.push("/project");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function logOut() {
|
|
|
|
|
UserManagerService.signOut()
|
|
|
|
|
.catch(console.error)
|
|
|
|
|
@ -181,16 +165,18 @@ function logOut() {
|
|
|
|
|
function refreshProjectName() {
|
|
|
|
|
projectName.value = localStorage.getItem("projectName") || "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 라우트 변경 시 프로젝트명 동기화 및 마지막 일반 경로 저장
|
|
|
|
|
watch(
|
|
|
|
|
() => route.fullPath,
|
|
|
|
|
() => {
|
|
|
|
|
refreshProjectName();
|
|
|
|
|
// 라우트가 바뀌면 스트립 닫기
|
|
|
|
|
hoverBar.value.open = false;
|
|
|
|
|
if (!isAdminRoute.value) lastNonAdminPath.value = route.fullPath || "/home";
|
|
|
|
|
},
|
|
|
|
|
{ immediate: true },
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// storage 이벤트 동기화
|
|
|
|
|
function onStorage(e: StorageEvent) {
|
|
|
|
|
if (!e.key || e.key === "projectName") {
|
|
|
|
|
refreshProjectName();
|
|
|
|
|
@ -212,9 +198,9 @@ onMounted(() => {
|
|
|
|
|
menu.value = menuItems;
|
|
|
|
|
window.addEventListener("storage", onStorage);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onBeforeUnmount(() => {
|
|
|
|
|
window.removeEventListener("storage", onStorage);
|
|
|
|
|
if (hideTimer) window.clearTimeout(hideTimer);
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
@ -232,24 +218,54 @@ onBeforeUnmount(() => {
|
|
|
|
|
AUTOFLOW WEB CONSOLE
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- ✅ 여기 스페이서를 '브랜드 다음'에 둬서 오른쪽으로 밀기 -->
|
|
|
|
|
<v-spacer />
|
|
|
|
|
|
|
|
|
|
<!-- ✅ 메뉴는 우측 정렬 -->
|
|
|
|
|
<div class="right-nav d-none d-md-flex" v-if="!hideAllMenus">
|
|
|
|
|
<!-- 관리자 메뉴 -->
|
|
|
|
|
<!-- 중앙: 메뉴 그룹 (Settings 전/후 분기) -->
|
|
|
|
|
<div class="center-nav d-none d-md-flex" v-if="!hideAllMenus">
|
|
|
|
|
<!-- 관리자 메뉴: showAdminTabs 조건으로 표시 -->
|
|
|
|
|
<!-- 관리자 메뉴바: 기본 메뉴바와 1:1 동일 구조 -->
|
|
|
|
|
<template v-if="showAdminTabs">
|
|
|
|
|
<template v-for="(m, i) in adminMenus" :key="'am_' + i">
|
|
|
|
|
<!-- 드롭다운 있는 항목 -->
|
|
|
|
|
<v-menu
|
|
|
|
|
v-if="m.depth?.length"
|
|
|
|
|
open-on-hover
|
|
|
|
|
close-on-content-click
|
|
|
|
|
location="bottom"
|
|
|
|
|
>
|
|
|
|
|
<template #activator="{ props }">
|
|
|
|
|
<v-btn
|
|
|
|
|
v-bind="props"
|
|
|
|
|
variant="text"
|
|
|
|
|
class="nav-btn"
|
|
|
|
|
:class="{
|
|
|
|
|
'nav-active': m.depth?.some((d: any) =>
|
|
|
|
|
isLinkActive(d.path),
|
|
|
|
|
),
|
|
|
|
|
}"
|
|
|
|
|
append-icon="mdi-chevron-down"
|
|
|
|
|
>
|
|
|
|
|
<v-icon start :icon="m.icon" class="mr-1" />
|
|
|
|
|
{{ m.title }}
|
|
|
|
|
</v-btn>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<v-list density="compact" class="min-w-48">
|
|
|
|
|
<v-list-item
|
|
|
|
|
v-for="(d, j) in m.depth"
|
|
|
|
|
:key="'amd_' + j"
|
|
|
|
|
:title="d.title"
|
|
|
|
|
:to="d.path"
|
|
|
|
|
:active="isLinkActive(d.path)"
|
|
|
|
|
active-class="nav-active"
|
|
|
|
|
/>
|
|
|
|
|
</v-list>
|
|
|
|
|
</v-menu>
|
|
|
|
|
|
|
|
|
|
<!-- 드롭다운 없는 단일 항목 -->
|
|
|
|
|
<v-btn
|
|
|
|
|
v-else
|
|
|
|
|
variant="text"
|
|
|
|
|
class="nav-btn"
|
|
|
|
|
:class="{
|
|
|
|
|
'nav-active':
|
|
|
|
|
m.depth?.some((d: any) => isLinkActive(d.path)) ||
|
|
|
|
|
isLinkActive(m.path),
|
|
|
|
|
}"
|
|
|
|
|
@mouseenter="showHoverStrip(m)"
|
|
|
|
|
@mouseleave="scheduleHideStrip"
|
|
|
|
|
:class="{ 'nav-active': isLinkActive(m.path) }"
|
|
|
|
|
@click="m.path && router.push(m.path)"
|
|
|
|
|
>
|
|
|
|
|
<v-icon start :icon="m.icon" class="mr-1" />
|
|
|
|
|
@ -261,17 +277,87 @@ onBeforeUnmount(() => {
|
|
|
|
|
<!-- 기본 메뉴 -->
|
|
|
|
|
<template v-else>
|
|
|
|
|
<template v-for="(m, i) in baseMenus" :key="'m_' + i">
|
|
|
|
|
<v-menu
|
|
|
|
|
v-if="m.depth?.length"
|
|
|
|
|
open-on-hover
|
|
|
|
|
close-on-content-click
|
|
|
|
|
location="bottom"
|
|
|
|
|
transition="scale-transition"
|
|
|
|
|
>
|
|
|
|
|
<template #activator="{ props }">
|
|
|
|
|
<v-btn
|
|
|
|
|
v-bind="props"
|
|
|
|
|
variant="text"
|
|
|
|
|
class="nav-btn text-white"
|
|
|
|
|
:class="{
|
|
|
|
|
'nav-active': m.depth?.some((d: any) =>
|
|
|
|
|
isLinkActive(d.path),
|
|
|
|
|
),
|
|
|
|
|
}"
|
|
|
|
|
append-icon="mdi-chevron-down"
|
|
|
|
|
>
|
|
|
|
|
<v-icon start :icon="m.icon" class="mr-1" />
|
|
|
|
|
{{ m.title }}
|
|
|
|
|
</v-btn>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- ✅ 여기부터: Run 전용 디자인 -->
|
|
|
|
|
<template
|
|
|
|
|
v-if="
|
|
|
|
|
(m.title && m.title.toLowerCase() === 'run') ||
|
|
|
|
|
(m.path && m.path.startsWith('/run'))
|
|
|
|
|
"
|
|
|
|
|
>
|
|
|
|
|
<v-card
|
|
|
|
|
rounded="lg"
|
|
|
|
|
elevation="12"
|
|
|
|
|
color="surface"
|
|
|
|
|
class="px-2 py-2"
|
|
|
|
|
>
|
|
|
|
|
<v-list density="comfortable" lines="one" class="min-w-48">
|
|
|
|
|
<template v-for="(d, j) in m.depth" :key="'run_' + j">
|
|
|
|
|
<v-hover v-slot="{ isHovering, props: liProps }">
|
|
|
|
|
<v-list-item
|
|
|
|
|
v-bind="liProps"
|
|
|
|
|
:title="d.title"
|
|
|
|
|
:to="d.path"
|
|
|
|
|
:active="isLinkActive(d.path)"
|
|
|
|
|
color="primary"
|
|
|
|
|
:rounded="'lg'"
|
|
|
|
|
:variant="
|
|
|
|
|
isHovering || isLinkActive(d.path)
|
|
|
|
|
? 'tonal'
|
|
|
|
|
: 'text'
|
|
|
|
|
"
|
|
|
|
|
class="mx-2 my-1 text-white"
|
|
|
|
|
/>
|
|
|
|
|
</v-hover>
|
|
|
|
|
</template>
|
|
|
|
|
</v-list>
|
|
|
|
|
</v-card>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- 기본 하위메뉴 (Run 이외는 기존 그대로) -->
|
|
|
|
|
<template v-else>
|
|
|
|
|
<v-list density="compact" class="min-w-48 subnav-list">
|
|
|
|
|
<v-list-item
|
|
|
|
|
v-for="(d, j) in m.depth"
|
|
|
|
|
:key="'d_' + j"
|
|
|
|
|
:title="d.title"
|
|
|
|
|
:to="d.path"
|
|
|
|
|
class="submenu-item text-white"
|
|
|
|
|
:class="{ 'submenu-active': isLinkActive(d.path) }"
|
|
|
|
|
/>
|
|
|
|
|
</v-list>
|
|
|
|
|
</template>
|
|
|
|
|
</v-menu>
|
|
|
|
|
|
|
|
|
|
<v-btn
|
|
|
|
|
v-else
|
|
|
|
|
variant="text"
|
|
|
|
|
class="nav-btn text-white"
|
|
|
|
|
:class="{
|
|
|
|
|
'nav-active':
|
|
|
|
|
m.depth?.some((d: any) => isLinkActive(d.path)) ||
|
|
|
|
|
isLinkActive(m.path),
|
|
|
|
|
}"
|
|
|
|
|
@mouseenter="showHoverStrip(m)"
|
|
|
|
|
@mouseleave="scheduleHideStrip"
|
|
|
|
|
@click="!m.depth?.length && m.path && router.push(m.path)"
|
|
|
|
|
class="nav-btn"
|
|
|
|
|
:class="{ 'nav-active': isLinkActive(m.path) }"
|
|
|
|
|
@click="m.path && router.push(m.path)"
|
|
|
|
|
>
|
|
|
|
|
<v-icon start :icon="m.icon" class="mr-1" />
|
|
|
|
|
{{ m.title }}
|
|
|
|
|
@ -279,7 +365,10 @@ onBeforeUnmount(() => {
|
|
|
|
|
</template>
|
|
|
|
|
</template>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- 우측 아이콘들 -->
|
|
|
|
|
|
|
|
|
|
<v-spacer />
|
|
|
|
|
|
|
|
|
|
<!-- 우측: 기존 기능 유지 -->
|
|
|
|
|
<v-tooltip v-if="isAdmin" location="bottom" text="Settings">
|
|
|
|
|
<template #activator="{ props }" v-if="!hideAllMenus">
|
|
|
|
|
<v-btn
|
|
|
|
|
@ -337,37 +426,6 @@ onBeforeUnmount(() => {
|
|
|
|
|
</v-menu>
|
|
|
|
|
</v-app-bar>
|
|
|
|
|
|
|
|
|
|
<!-- ===== 상단 하위 메뉴 스트립 (호버 시 표시) ===== -->
|
|
|
|
|
<v-slide-y-transition>
|
|
|
|
|
<v-sheet
|
|
|
|
|
v-if="hoverBar.open"
|
|
|
|
|
class="hover-strip"
|
|
|
|
|
elevation="8"
|
|
|
|
|
color="surface"
|
|
|
|
|
@mouseenter="keepStrip"
|
|
|
|
|
@mouseleave="scheduleHideStrip"
|
|
|
|
|
>
|
|
|
|
|
<v-container class="py-2" :fluid="true">
|
|
|
|
|
<!-- 중앙 정렬 -->
|
|
|
|
|
<v-row class="g-2" no-gutters justify="center" align="center">
|
|
|
|
|
<v-col class="d-flex flex-wrap justify-center" cols="12">
|
|
|
|
|
<v-btn
|
|
|
|
|
v-for="d in hoverBar.items"
|
|
|
|
|
:key="d.path"
|
|
|
|
|
size="small"
|
|
|
|
|
class="mx-1 my-1 strip-chip"
|
|
|
|
|
:variant="isLinkActive(d.path) ? 'tonal' : 'text'"
|
|
|
|
|
:color="isLinkActive(d.path) ? 'primary' : undefined"
|
|
|
|
|
@click="router.push(d.path)"
|
|
|
|
|
>
|
|
|
|
|
{{ d.title }}
|
|
|
|
|
</v-btn>
|
|
|
|
|
</v-col>
|
|
|
|
|
</v-row>
|
|
|
|
|
</v-container>
|
|
|
|
|
</v-sheet>
|
|
|
|
|
</v-slide-y-transition>
|
|
|
|
|
|
|
|
|
|
<!-- 본문 -->
|
|
|
|
|
<v-main>
|
|
|
|
|
<v-container
|
|
|
|
|
@ -388,70 +446,64 @@ onBeforeUnmount(() => {
|
|
|
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 브랜드 */
|
|
|
|
|
/* 더 커진 홈(브랜드) 버튼 */
|
|
|
|
|
.brand-btn {
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
letter-spacing: 0.08em;
|
|
|
|
|
padding: 0 14px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.right-nav {
|
|
|
|
|
display: flex;
|
|
|
|
|
/* 중앙 고정 네비게이션 */
|
|
|
|
|
.center-nav {
|
|
|
|
|
position: absolute;
|
|
|
|
|
left: 50%;
|
|
|
|
|
transform: translateX(-50%);
|
|
|
|
|
gap: 8px;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 8px; /* 버튼 간격 */
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.nav-btn {
|
|
|
|
|
text-transform: none;
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
padding: 0 16px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
color: #fff !important;
|
|
|
|
|
color: #fff !important; /* 흰색 텍스트 통일 */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.nav-btn:hover {
|
|
|
|
|
background: rgba(59, 130, 246, 0.08);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.nav-active {
|
|
|
|
|
background: rgba(59, 130, 246, 0.22);
|
|
|
|
|
height: 46px;
|
|
|
|
|
color: #fff !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.userbox {
|
|
|
|
|
min-width: 180px;
|
|
|
|
|
/* 드롭다운(하위 메뉴)도 동일 룩으로 */
|
|
|
|
|
.subnav-list {
|
|
|
|
|
background: transparent; /* 탑바 느낌 유지 */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ===== 호버 스트립 (상단 바로 아래, 이미지 스타일) ===== */
|
|
|
|
|
.hover-strip {
|
|
|
|
|
position: fixed;
|
|
|
|
|
top: var(--v-layout-top, 64px); /* app-bar 바로 아래 */
|
|
|
|
|
left: 0;
|
|
|
|
|
right: 0;
|
|
|
|
|
z-index: 2500;
|
|
|
|
|
/* 다크 배경 + 살짝 투명 + 경계 */
|
|
|
|
|
background: rgba(32, 32, 32, 0.96);
|
|
|
|
|
border-bottom: 1px solid rgb(145, 61, 61);
|
|
|
|
|
backdrop-filter: blur(6px);
|
|
|
|
|
.submenu-item {
|
|
|
|
|
color: #fff !important;
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
margin: 2px 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 버튼(알약) – 다크에서도 비활성 글자/테두리 선명 */
|
|
|
|
|
.strip-chip {
|
|
|
|
|
border-radius: 9999px !important;
|
|
|
|
|
text-transform: none;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
letter-spacing: 0;
|
|
|
|
|
height: 30px;
|
|
|
|
|
padding: 0 14px;
|
|
|
|
|
color: #e5e7eb !important; /* 비활성도 흐려 보이지 않게 */
|
|
|
|
|
.submenu-item:hover {
|
|
|
|
|
background: rgba(59, 130, 246, 0.08);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.strip-chip.v-btn--variant-text {
|
|
|
|
|
/* text 변형일 때도 흐릿하지 않게 약한 테두리 */
|
|
|
|
|
border: 1px solid rgba(255, 255, 255, 0.14) !important;
|
|
|
|
|
background: transparent !important;
|
|
|
|
|
.submenu-active {
|
|
|
|
|
background: rgba(59, 130, 246, 0.22);
|
|
|
|
|
color: #fff !important;
|
|
|
|
|
}
|
|
|
|
|
.min-w-48 {
|
|
|
|
|
min-width: 12rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.strip-chip:hover {
|
|
|
|
|
background: rgba(255, 255, 255, 0.06) !important;
|
|
|
|
|
.userbox {
|
|
|
|
|
min-width: 180px;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|