Files
sam-manage/resources/views/menus/_sync_menu_item.blade.php
권혁성 982dee994c feat:메뉴 동기화 UI/기능 개선
- 테넌트 선택: 헤더에서 선택된 테넌트 기준으로 동작
- UI 개선: 레벨 뱃지(Lv.2, Lv.3), 동기화 필요 메뉴만 체크박스 활성화
- 전체선택 체크박스 추가 (로컬/원격 각각)
- 선택된 메뉴 개수 표시 (Push/Pull 버튼 옆)
- 상위 메뉴 선택 시 하위 메뉴 자동 선택
- Pull 시 부모 메뉴 이름 기반 매핑 수정

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 19:59:31 +09:00

122 lines
6.3 KiB
PHP

@php
$isLocalOnly = $side === 'local' && in_array($menu['name'], $diff['local_only'] ?? []);
$isRemoteOnly = $side === 'remote' && in_array($menu['name'], $diff['remote_only'] ?? []);
$isBoth = in_array($menu['name'], $diff['both'] ?? []);
// 동기화 필요 여부 (로컬에서는 local_only만, 원격에서는 remote_only만 체크 가능)
$needsSync = $isLocalOnly || $isRemoteOnly;
$bgClass = '';
$badgeClass = '';
$badgeText = '';
if ($isLocalOnly) {
$bgClass = 'bg-green-50';
$badgeClass = 'bg-green-100 text-green-700';
$badgeText = 'NEW';
} elseif ($isRemoteOnly) {
$bgClass = 'bg-purple-50';
$badgeClass = 'bg-purple-100 text-purple-700';
$badgeText = 'NEW';
} else {
$bgClass = 'hover:bg-gray-50';
}
@endphp
@php
$menuKey = $side . '_' . ($menu['id'] ?? Str::slug($menu['name']));
@endphp
<div class="menu-group" data-menu-key="{{ $menuKey }}">
<div class="border rounded-lg mb-1 {{ $bgClass }}" style="margin-left: {{ $depth * 2 }}rem;">
<div class="flex items-center gap-2 px-3 py-2">
<!-- 체크박스 (동기화 필요한 메뉴만 활성화) - 양쪽 모두 이름으로 매핑 -->
@if($side === 'local')
<input type="checkbox" name="local_menu" value="{{ $menu['name'] }}"
data-menu-id="{{ $menu['id'] }}"
data-menu-key="{{ $menuKey }}"
data-has-children="{{ !empty($menu['children']) ? 'true' : 'false' }}"
onchange="toggleChildren(this)"
class="w-4 h-4 rounded focus:ring-green-500 {{ $needsSync ? 'text-green-600 border-gray-300' : 'bg-gray-200 border-gray-300 cursor-not-allowed' }}"
{{ !$needsSync ? 'disabled' : '' }}>
@else
<input type="checkbox" name="remote_menu" value="{{ $menu['name'] }}"
data-menu-key="{{ $menuKey }}"
data-has-children="{{ !empty($menu['children']) ? 'true' : 'false' }}"
onchange="toggleChildren(this)"
class="w-4 h-4 rounded focus:ring-purple-500 {{ $needsSync ? 'text-purple-600 border-gray-300' : 'bg-gray-200 border-gray-300 cursor-not-allowed' }}"
{{ !$needsSync ? 'disabled' : '' }}>
@endif
<!-- 아이콘 -->
@if(!empty($menu['icon']))
<span class="w-5 h-5 flex items-center justify-center text-gray-400">
@switch($menu['icon'])
@case('home')
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
</svg>
@break
@case('folder')
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
</svg>
@break
@case('cog')
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
@break
@case('cube')
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
</svg>
@break
@case('collection')
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
</svg>
@break
@default
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
@endswitch
</span>
@endif
<!-- 메뉴 이름 + 뎁스 레벨 -->
<span class="flex-1 text-sm text-gray-800 flex items-center gap-2">
{{ $menu['name'] }}
@if($depth > 0)
<span class="text-[10px] text-gray-400 bg-gray-100 px-1 rounded">Lv.{{ $depth + 1 }}</span>
@endif
</span>
<!-- 배지 -->
@if($badgeText)
<span class="px-1.5 py-0.5 text-xs font-medium rounded {{ $badgeClass }}">{{ $badgeText }}</span>
@endif
<!-- URL -->
@if($menu['url'] !== '#')
<span class="text-xs text-gray-400 font-mono">{{ Str::limit($menu['url'], 20) }}</span>
@endif
</div>
</div>
<!-- 자식 메뉴 -->
@if(!empty($menu['children']))
<div class="children-container">
@foreach($menu['children'] as $child)
@include('menus._sync_menu_item', [
'menu' => $child,
'side' => $side,
'diff' => $diff,
'depth' => $depth + 1
])
@endforeach
</div>
@endif
</div>