사이드바 메뉴 버그 수정
- 테넌트 메뉴: session 대신 로그인 사용자의 tenant_id만 사용 - 메뉴 그룹 토글: 자식 있으면 기본 표시, localStorage 복원 로직 통일 - 프레젠테이션 페이지 CSS: 글로벌 선택자를 .presentation-container로 스코핑
This commit is contained in:
@@ -16,7 +16,8 @@ class SidebarMenuService
|
||||
public function getUserMenuTree(?User $user = null): Collection
|
||||
{
|
||||
$user = $user ?? auth()->user();
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
// 로그인한 사용자의 tenant_id만 사용 (session 값 무시)
|
||||
$tenantId = $user?->tenant_id ?? 1;
|
||||
|
||||
// 테넌트의 모든 활성 메뉴 조회
|
||||
$allMenus = Menu::withoutGlobalScopes()
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
$isExpanded = $sidebarMenuService->isMenuOrChildActive($menu);
|
||||
$groupId = 'menu-group-' . $menu->id;
|
||||
$children = $menu->menuChildren ?? collect();
|
||||
$hasChildren = $children->isNotEmpty();
|
||||
$paddingLeft = $depth > 0 ? ($depth * 0.75 + 0.75) . 'rem' : '0.75rem';
|
||||
@endphp
|
||||
|
||||
<li class="pt-4 pb-1 border-t border-gray-200 mt-2">
|
||||
{{-- 그룹 헤더 (접기/펼치기 버튼) --}}
|
||||
<button
|
||||
onclick="toggleGroup('{{ $groupId }}')"
|
||||
onclick="toggleMenuGroup('{{ $groupId }}')"
|
||||
class="sidebar-group-header w-full flex items-center justify-between px-3 py-2 text-xs font-bold text-gray-600 uppercase tracking-wider hover:bg-gray-50 rounded"
|
||||
style="padding-left: {{ $paddingLeft }}"
|
||||
>
|
||||
@@ -23,7 +24,7 @@ class="sidebar-group-header w-full flex items-center justify-between px-3 py-2 t
|
||||
</span>
|
||||
<svg
|
||||
id="{{ $groupId }}-icon"
|
||||
class="w-3 h-3 transition-transform sidebar-text {{ $isExpanded ? 'rotate-180' : '' }}"
|
||||
class="w-3 h-3 transition-transform sidebar-text {{ $hasChildren ? 'rotate-180' : '' }}"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
@@ -32,8 +33,8 @@ class="w-3 h-3 transition-transform sidebar-text {{ $isExpanded ? 'rotate-180' :
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{{-- 하위 메뉴 --}}
|
||||
<ul id="{{ $groupId }}" class="space-y-1 mt-1 {{ $isExpanded ? '' : 'hidden' }}">
|
||||
{{-- 하위 메뉴 (자식이 있으면 기본 표시, localStorage에서 상태 복원) --}}
|
||||
<ul id="{{ $groupId }}" class="space-y-1 mt-1" style="display: {{ $hasChildren ? 'block' : 'none' }};">
|
||||
@foreach($children as $child)
|
||||
@if($child->menuChildren && $child->menuChildren->isNotEmpty())
|
||||
{{-- 하위에 또 그룹이 있는 경우 (중첩 그룹) --}}
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
.slide.active { display: flex; animation: slideInRight 0.5s ease-out; }
|
||||
.slide-content { background: rgba(255, 255, 255, 0.98); border-radius: 24px; padding: 60px; max-width: 1200px; width: 100%; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15), 0 0 0 1px rgba(0, 0, 0, 0.05); animation: fadeIn 0.8s ease-out; margin: auto 0; border: 1px solid rgba(255, 255, 255, 0.2); }
|
||||
|
||||
h1 { color: #2563eb; font-size: 3em; margin-bottom: 20px; text-align: center; font-weight: 800; }
|
||||
h2 { color: #1e40af; font-size: 2.5em; margin-bottom: 30px; text-align: center; border-bottom: 3px solid #2563eb; padding-bottom: 15px; font-weight: 700; }
|
||||
h3 { color: #2563eb; font-size: 1.8em; margin: 25px 0 15px 0; font-weight: 700; }
|
||||
h4 { color: #1e40af; font-size: 1.3em; margin: 15px 0 10px 0; font-weight: 700; }
|
||||
p, li { font-size: 1.2em; line-height: 1.8; color: #1e293b; margin-bottom: 15px; }
|
||||
ul, ol { margin-left: 30px; }
|
||||
.presentation-container h1 { color: #2563eb; font-size: 3em; margin-bottom: 20px; text-align: center; font-weight: 800; }
|
||||
.presentation-container h2 { color: #1e40af; font-size: 2.5em; margin-bottom: 30px; text-align: center; border-bottom: 3px solid #2563eb; padding-bottom: 15px; font-weight: 700; }
|
||||
.presentation-container h3 { color: #2563eb; font-size: 1.8em; margin: 25px 0 15px 0; font-weight: 700; }
|
||||
.presentation-container h4 { color: #1e40af; font-size: 1.3em; margin: 15px 0 10px 0; font-weight: 700; }
|
||||
.presentation-container p, .presentation-container li { font-size: 1.2em; line-height: 1.8; color: #1e293b; margin-bottom: 15px; }
|
||||
.presentation-container ul, .presentation-container ol { margin-left: 30px; }
|
||||
|
||||
.company-info { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; margin: 30px 0; }
|
||||
.info-card { background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%); color: white; padding: 25px; border-radius: 16px; box-shadow: 0 4px 12px rgba(37, 99, 235, 0.2); animation: scaleIn 0.5s ease-out; border: 1px solid rgba(255, 255, 255, 0.1); }
|
||||
@@ -60,8 +60,8 @@
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.slide-content { padding: 30px; }
|
||||
h1 { font-size: 2em; } h2 { font-size: 1.8em; } h3 { font-size: 1.4em; }
|
||||
p, li { font-size: 1em; }
|
||||
.presentation-container h1 { font-size: 2em; } .presentation-container h2 { font-size: 1.8em; } .presentation-container h3 { font-size: 1.4em; }
|
||||
.presentation-container p, .presentation-container li { font-size: 1em; }
|
||||
.navigation { bottom: 15px; right: 15px; }
|
||||
.nav-btn { padding: 10px 20px; font-size: 0.9em; }
|
||||
.slide-number { bottom: 15px; left: 15px; padding: 8px 15px; font-size: 0.9em; }
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
.slide.active { display: flex; animation: slideInRight 0.5s ease-out; }
|
||||
.slide-content { background: rgba(255, 255, 255, 0.98); border-radius: 24px; padding: 60px; max-width: 1200px; width: 100%; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15), 0 0 0 1px rgba(0, 0, 0, 0.05); animation: fadeIn 0.8s ease-out; margin: auto 0; border: 1px solid rgba(255, 255, 255, 0.2); }
|
||||
|
||||
h1 { color: #2563eb; font-size: 3em; margin-bottom: 20px; text-align: center; font-weight: 800; }
|
||||
h2 { color: #1e40af; font-size: 2.5em; margin-bottom: 30px; text-align: center; border-bottom: 3px solid #2563eb; padding-bottom: 15px; font-weight: 700; }
|
||||
h3 { color: #2563eb; font-size: 1.8em; margin: 25px 0 15px 0; font-weight: 700; }
|
||||
p, li { font-size: 1.2em; line-height: 1.8; color: #1e293b; margin-bottom: 15px; }
|
||||
ul { margin-left: 30px; }
|
||||
.presentation-container h1 { color: #2563eb; font-size: 3em; margin-bottom: 20px; text-align: center; font-weight: 800; }
|
||||
.presentation-container h2 { color: #1e40af; font-size: 2.5em; margin-bottom: 30px; text-align: center; border-bottom: 3px solid #2563eb; padding-bottom: 15px; font-weight: 700; }
|
||||
.presentation-container h3 { color: #2563eb; font-size: 1.8em; margin: 25px 0 15px 0; font-weight: 700; }
|
||||
.presentation-container p, .presentation-container li { font-size: 1.2em; line-height: 1.8; color: #1e293b; margin-bottom: 15px; }
|
||||
.presentation-container ul { margin-left: 30px; }
|
||||
|
||||
.company-info { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; margin: 30px 0; }
|
||||
.info-card { background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%); color: white; padding: 25px; border-radius: 16px; box-shadow: 0 4px 12px rgba(37, 99, 235, 0.2); animation: scaleIn 0.5s ease-out; border: 1px solid rgba(255, 255, 255, 0.1); }
|
||||
@@ -48,8 +48,8 @@
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.slide-content { padding: 30px; }
|
||||
h1 { font-size: 2em; } h2 { font-size: 1.8em; } h3 { font-size: 1.4em; }
|
||||
p, li { font-size: 1em; }
|
||||
.presentation-container h1 { font-size: 2em; } .presentation-container h2 { font-size: 1.8em; } .presentation-container h3 { font-size: 1.4em; }
|
||||
.presentation-container p, .presentation-container li { font-size: 1em; }
|
||||
.navigation { bottom: 15px; right: 15px; }
|
||||
.nav-btn { padding: 10px 20px; font-size: 0.9em; }
|
||||
.slide-number { bottom: 15px; left: 15px; padding: 8px 15px; font-size: 0.9em; }
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
.slide.active { display: flex; animation: slideInRight 0.5s ease-out; }
|
||||
.slide-content { background: rgba(255, 255, 255, 0.98); border-radius: 24px; padding: 60px; max-width: 1200px; width: 100%; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15), 0 0 0 1px rgba(0, 0, 0, 0.05); animation: fadeIn 0.8s ease-out; margin: auto 0; border: 1px solid rgba(255, 255, 255, 0.2); }
|
||||
|
||||
h1 { color: #2563eb; font-size: 3em; margin-bottom: 20px; text-align: center; font-weight: 800; }
|
||||
h2 { color: #1e40af; font-size: 2.5em; margin-bottom: 30px; text-align: center; border-bottom: 3px solid #2563eb; padding-bottom: 15px; font-weight: 700; }
|
||||
h3 { color: #2563eb; font-size: 1.8em; margin: 25px 0 15px 0; font-weight: 700; }
|
||||
p, li { font-size: 1.2em; line-height: 1.8; color: #1e293b; margin-bottom: 15px; }
|
||||
ul { margin-left: 30px; }
|
||||
.presentation-container h1 { color: #2563eb; font-size: 3em; margin-bottom: 20px; text-align: center; font-weight: 800; }
|
||||
.presentation-container h2 { color: #1e40af; font-size: 2.5em; margin-bottom: 30px; text-align: center; border-bottom: 3px solid #2563eb; padding-bottom: 15px; font-weight: 700; }
|
||||
.presentation-container h3 { color: #2563eb; font-size: 1.8em; margin: 25px 0 15px 0; font-weight: 700; }
|
||||
.presentation-container p, .presentation-container li { font-size: 1.2em; line-height: 1.8; color: #1e293b; margin-bottom: 15px; }
|
||||
.presentation-container ul { margin-left: 30px; }
|
||||
|
||||
.company-info { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; margin: 30px 0; }
|
||||
.info-card { background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%); color: white; padding: 25px; border-radius: 16px; box-shadow: 0 4px 12px rgba(37, 99, 235, 0.2); animation: scaleIn 0.5s ease-out; border: 1px solid rgba(255, 255, 255, 0.1); }
|
||||
@@ -48,8 +48,8 @@
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.slide-content { padding: 30px; }
|
||||
h1 { font-size: 2em; } h2 { font-size: 1.8em; } h3 { font-size: 1.4em; }
|
||||
p, li { font-size: 1em; }
|
||||
.presentation-container h1 { font-size: 2em; } .presentation-container h2 { font-size: 1.8em; } .presentation-container h3 { font-size: 1.4em; }
|
||||
.presentation-container p, .presentation-container li { font-size: 1em; }
|
||||
.navigation { bottom: 15px; right: 15px; }
|
||||
.nav-btn { padding: 10px 20px; font-size: 0.9em; }
|
||||
.slide-number { bottom: 15px; left: 15px; padding: 8px 15px; font-size: 0.9em; }
|
||||
|
||||
@@ -49,11 +49,11 @@
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
h1 { color: #2563eb; font-size: 3em; margin-bottom: 20px; text-align: center; font-weight: 800; }
|
||||
h2 { color: #1e40af; font-size: 2.5em; margin-bottom: 30px; text-align: center; border-bottom: 3px solid #2563eb; padding-bottom: 15px; font-weight: 700; }
|
||||
h3 { color: #2563eb; font-size: 1.8em; margin: 25px 0 15px 0; font-weight: 700; }
|
||||
p, li { font-size: 1.2em; line-height: 1.8; color: #1e293b; margin-bottom: 15px; }
|
||||
ul { margin-left: 30px; }
|
||||
.presentation-container h1 { color: #2563eb; font-size: 3em; margin-bottom: 20px; text-align: center; font-weight: 800; }
|
||||
.presentation-container h2 { color: #1e40af; font-size: 2.5em; margin-bottom: 30px; text-align: center; border-bottom: 3px solid #2563eb; padding-bottom: 15px; font-weight: 700; }
|
||||
.presentation-container h3 { color: #2563eb; font-size: 1.8em; margin: 25px 0 15px 0; font-weight: 700; }
|
||||
.presentation-container p, .presentation-container li { font-size: 1.2em; line-height: 1.8; color: #1e293b; margin-bottom: 15px; }
|
||||
.presentation-container ul { margin-left: 30px; }
|
||||
|
||||
.company-info { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; margin: 30px 0; }
|
||||
.info-card {
|
||||
@@ -155,10 +155,10 @@
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.slide-content { padding: 30px; }
|
||||
h1 { font-size: 2em; }
|
||||
h2 { font-size: 1.8em; }
|
||||
h3 { font-size: 1.4em; }
|
||||
p, li { font-size: 1em; }
|
||||
.presentation-container h1 { font-size: 2em; }
|
||||
.presentation-container h2 { font-size: 1.8em; }
|
||||
.presentation-container h3 { font-size: 1.4em; }
|
||||
.presentation-container p, .presentation-container li { font-size: 1em; }
|
||||
.navigation { bottom: 15px; right: 15px; }
|
||||
.nav-btn { padding: 10px 20px; font-size: 0.9em; }
|
||||
.slide-number { bottom: 15px; left: 50%; transform: translateX(-50%); padding: 8px 15px; font-size: 0.9em; }
|
||||
|
||||
@@ -555,7 +555,7 @@ function toggleSidebar() {
|
||||
}
|
||||
}
|
||||
|
||||
// 메뉴 그룹 토글
|
||||
// 메뉴 그룹 토글 (R&D Labs, 개발 도구 등)
|
||||
function toggleGroup(groupId) {
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
// 사이드바가 접힌 상태면 그룹 토글 무시
|
||||
@@ -577,6 +577,36 @@ function toggleGroup(groupId) {
|
||||
}
|
||||
}
|
||||
|
||||
// 동적 메뉴 그룹 토글 (DB에서 가져온 메뉴)
|
||||
function toggleMenuGroup(groupId) {
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
// 사이드바가 접힌 상태면 그룹 토글 무시
|
||||
if (sidebar.classList.contains('sidebar-collapsed') || document.documentElement.classList.contains('sidebar-is-collapsed')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const group = document.getElementById(groupId);
|
||||
const icon = document.getElementById(groupId + '-icon');
|
||||
|
||||
if (!group) return;
|
||||
|
||||
const isHidden = group.style.display === 'none' || group.style.display === '';
|
||||
|
||||
if (isHidden) {
|
||||
group.style.display = 'block';
|
||||
if (icon) {
|
||||
icon.classList.add('rotate-180');
|
||||
}
|
||||
localStorage.setItem('menu-group-' + groupId, 'visible');
|
||||
} else {
|
||||
group.style.display = 'none';
|
||||
if (icon) {
|
||||
icon.classList.remove('rotate-180');
|
||||
}
|
||||
localStorage.setItem('menu-group-' + groupId, 'hidden');
|
||||
}
|
||||
}
|
||||
|
||||
// ========== R&D Labs 사이드바 스크롤 함수 ==========
|
||||
|
||||
// 사이드바를 최하단으로 스크롤하고 위치 저장
|
||||
@@ -812,19 +842,20 @@ function initSidebarTooltips() {
|
||||
}
|
||||
});
|
||||
|
||||
// 메뉴 그룹 상태 복원 (동적 메뉴)
|
||||
// 메뉴 그룹 상태 복원 (동적 메뉴) - inline style로 통일
|
||||
document.querySelectorAll('[id^="menu-group-"]').forEach(function(group) {
|
||||
const groupId = group.id;
|
||||
const savedState = localStorage.getItem('menu-group-' + groupId);
|
||||
const icon = document.getElementById(groupId + '-icon');
|
||||
|
||||
if (savedState === 'hidden') {
|
||||
group.classList.add('hidden');
|
||||
group.style.display = 'none';
|
||||
icon?.classList.remove('rotate-180');
|
||||
} else if (savedState === 'visible') {
|
||||
group.classList.remove('hidden');
|
||||
group.style.display = 'block';
|
||||
icon?.classList.add('rotate-180');
|
||||
}
|
||||
// savedState가 없으면 서버에서 렌더링한 초기 상태 유지
|
||||
});
|
||||
|
||||
// R&D Labs 탭 상태 복원
|
||||
|
||||
Reference in New Issue
Block a user