diff --git a/public/js/pagination.js b/public/js/pagination.js index 7f668007..2f620118 100644 --- a/public/js/pagination.js +++ b/public/js/pagination.js @@ -114,13 +114,9 @@ document.body.addEventListener('htmx:afterSwap', function(event) { setTimeout(function() { const perPageSelect = document.getElementById('perPageSelect'); if (perPageSelect) { - // 서버에서 받은 값(data-server-value)을 우선 사용 - const serverValue = perPageSelect.dataset.serverValue; - if (serverValue) { - perPageSelect.value = serverValue; - // 쿠키도 서버 값으로 업데이트 - setCookie('pagination_per_page', serverValue); - } + // 쿠키에 저장된 값으로 selectbox 설정 (서버 값으로 덮어쓰지 않음) + const cookieValue = getPerPageFromCookie(); + perPageSelect.value = cookieValue; } }, 50); }); diff --git a/resources/views/menus/create.blade.php b/resources/views/menus/create.blade.php index a4ebbe5e..990f80fd 100644 --- a/resources/views/menus/create.blade.php +++ b/resources/views/menus/create.blade.php @@ -30,7 +30,7 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none foc @foreach($parentMenus as $parent) @endforeach diff --git a/resources/views/menus/edit.blade.php b/resources/views/menus/edit.blade.php index 6ead1259..9d034aba 100644 --- a/resources/views/menus/edit.blade.php +++ b/resources/views/menus/edit.blade.php @@ -32,7 +32,7 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none foc @foreach($parentMenus as $parent) @if($parent->id != $menu->id) @endif @endforeach diff --git a/resources/views/menus/global-create.blade.php b/resources/views/menus/global-create.blade.php index 5de470f0..0b61f7e3 100644 --- a/resources/views/menus/global-create.blade.php +++ b/resources/views/menus/global-create.blade.php @@ -7,7 +7,10 @@
-

글로벌 메뉴 생성

+

+ + 글로벌 메뉴 생성 +

시스템 전체에서 사용되는 기본 메뉴를 생성합니다.

@@ -29,7 +32,9 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500"> @foreach($parentMenus as $parent) - + @endforeach
@@ -58,9 +63,39 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none foc - +
+
+ +
+ +
+ +
+

사용 가능한 아이콘 (클릭하여 선택)

+
+ @php + $sampleIcons = [ + 'home', 'folder', 'chart-bar', 'calendar', 'building', + 'users', 'user-group', 'menu', 'shield-check', 'key', + 'cog', 'beaker', 'code', 'document-text', 'clipboard-list', + 'cube', 'collection', 'tag', 'database', 'terminal', + 'server', 'adjustments', 'sparkles', 'lightning-bolt', 'puzzle', 'external-link', + ]; + @endphp + @foreach($sampleIcons as $iconKey) + + @endforeach +
+
@@ -112,6 +147,43 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none foc placeholder="https://example.com"> + +
+
+

확장 옵션

+ +
+ +
+ +
+ + +

사이드바 영역 구분. main: 메인 메뉴, tools: 개발도구 영역, labs: R&D 실험실 영역

+
+ + +
+ + +

추가 메타 데이터 (JSON 형식). 탭 구분, 뱃지 표시 등 커스텀 속성 저장

+
+
+
+
${iconKey}`; + } + }; + // 외부 링크 체크박스 토글 document.getElementById('is_external').addEventListener('change', function() { const externalUrlGroup = document.getElementById('external-url-group'); @@ -140,6 +243,41 @@ class="px-6 py-2 bg-purple-600 hover:bg-purple-700 text-white rounded-lg transit } }); + // 확장 옵션 섹션 토글 + window.toggleOptionsSection = function() { + const section = document.getElementById('options-section'); + const toggleText = document.getElementById('options-toggle-text'); + if (section.classList.contains('hidden')) { + section.classList.remove('hidden'); + toggleText.textContent = '접기'; + } else { + section.classList.add('hidden'); + toggleText.textContent = '펼치기'; + } + }; + + // options 객체 생성 + function buildOptionsObject() { + const options = {}; + + const section = document.getElementById('option_section').value; + if (section && section !== 'main') { + options.section = section; + } + + const metaStr = document.getElementById('option_meta').value.trim(); + if (metaStr) { + try { + options.meta = JSON.parse(metaStr); + } catch (e) { + showToast('meta 필드의 JSON 형식이 올바르지 않습니다.', 'error'); + throw e; + } + } + + return Object.keys(options).length > 0 ? options : null; + } + // 폼 제출 처리 document.getElementById('menuForm').addEventListener('submit', async function(e) { e.preventDefault(); @@ -147,6 +285,20 @@ class="px-6 py-2 bg-purple-600 hover:bg-purple-700 text-white rounded-lg transit const formData = new FormData(this); const data = Object.fromEntries(formData.entries()); + // option_ 접두사 필드 제거 + delete data.option_section; + delete data.option_meta; + + // options 객체 추가 + try { + const options = buildOptionsObject(); + if (options) { + data.options = options; + } + } catch (e) { + return; // JSON 파싱 에러 + } + try { const response = await fetch('/api/admin/global-menus', { method: 'POST', diff --git a/resources/views/menus/global-edit.blade.php b/resources/views/menus/global-edit.blade.php index 4603956b..115dba73 100644 --- a/resources/views/menus/global-edit.blade.php +++ b/resources/views/menus/global-edit.blade.php @@ -7,7 +7,10 @@
-

글로벌 메뉴 수정

+

+ + 글로벌 메뉴 수정 +

시스템 전체에서 사용되는 기본 메뉴를 수정합니다.

@@ -32,7 +35,7 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none foc @foreach($parentMenus as $parent) @if($parent->id != $menu->id) @endif @endforeach @@ -61,14 +64,51 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none foc
+ @php + $currentIcon = old('icon', $menu->icon); + $sampleIcons = [ + 'home', 'folder', 'chart-bar', 'calendar', 'building', + 'users', 'user-group', 'menu', 'shield-check', 'key', + 'cog', 'beaker', 'code', 'document-text', 'clipboard-list', + 'cube', 'collection', 'tag', 'database', 'terminal', + 'server', 'adjustments', 'sparkles', 'lightning-bolt', 'puzzle', 'external-link', + ]; + @endphp
- +
+
+ @if($currentIcon && in_array($currentIcon, $sampleIcons)) + + @elseif($currentIcon) + {{ $currentIcon }} + @else + + @endif +
+ +
+ +
+

사용 가능한 아이콘 (클릭하여 선택)

+
+ @foreach($sampleIcons as $iconKey) + + @endforeach +
+
@@ -125,6 +165,54 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none foc placeholder="https://example.com">
+ + @php + $hasOptions = $menu->options && count($menu->options) > 0; + $currentSection = $menu->getSection() ?? 'main'; + $currentMeta = $menu->getMeta(); + $currentMetaJson = $currentMeta ? json_encode($currentMeta, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : ''; + @endphp +
+
+

+ 확장 옵션 + @if($hasOptions) + {{ count($menu->options) }} + @endif +

+ +
+ +
+ +
+ + +

사이드바 영역 구분. main: 메인 메뉴, tools: 개발도구 영역, labs: R&D 실험실 영역

+
+ + +
+ + +

추가 메타 데이터 (JSON 형식). 탭 구분, 뱃지 표시 등 커스텀 속성 저장

+
+
+
+
${iconKey}`; + } + }; + // 외부 링크 체크박스 토글 document.getElementById('is_external').addEventListener('change', function() { const externalUrlGroup = document.getElementById('external-url-group'); @@ -153,6 +272,41 @@ class="px-6 py-2 bg-purple-600 hover:bg-purple-700 text-white rounded-lg transit } }); + // 확장 옵션 섹션 토글 + window.toggleOptionsSection = function() { + const section = document.getElementById('options-section'); + const toggleText = document.getElementById('options-toggle-text'); + if (section.classList.contains('hidden')) { + section.classList.remove('hidden'); + toggleText.textContent = '접기'; + } else { + section.classList.add('hidden'); + toggleText.textContent = '펼치기'; + } + }; + + // options 객체 생성 + function buildOptionsObject() { + const options = {}; + + const section = document.getElementById('option_section').value; + if (section && section !== 'main') { + options.section = section; + } + + const metaStr = document.getElementById('option_meta').value.trim(); + if (metaStr) { + try { + options.meta = JSON.parse(metaStr); + } catch (e) { + showToast('meta 필드의 JSON 형식이 올바르지 않습니다.', 'error'); + throw e; + } + } + + return Object.keys(options).length > 0 ? options : null; + } + // 폼 제출 처리 document.getElementById('menuForm').addEventListener('submit', async function(e) { e.preventDefault(); @@ -160,6 +314,20 @@ class="px-6 py-2 bg-purple-600 hover:bg-purple-700 text-white rounded-lg transit const formData = new FormData(this); const data = Object.fromEntries(formData.entries()); + // option_ 접두사 필드 제거 + delete data.option_section; + delete data.option_meta; + + // options 객체 추가 + try { + const options = buildOptionsObject(); + if (options) { + data.options = options; + } + } catch (e) { + return; // JSON 파싱 에러 + } + try { const response = await fetch('/api/admin/global-menus/{{ $menu->id }}', { method: 'PUT',