메뉴 관리 개편, 추천 사이트·1뎁스 네비, 우측 Recommended 연동(v1.1.13)
상단 네비는 평면 테이블·드래그로 편집하고 한 단계 하위만 허용한다. 추천 사이트 탭·location recommended·공개 API와 우측 사이드 카드·파비콘 URL 유틸을 추가한다. 문서·배포 마이그레이션 안내·관리자 레이아웃·설정 화면 등 누적 변경을 반영한다.
This commit is contained in:
@@ -4,17 +4,17 @@ export const adminNavigationItemInputSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
label: z.string().trim().min(1),
|
||||
url: z.string().trim().min(1).regex(/^(\/|https?:\/\/|#)/),
|
||||
location: z.enum(['primary', 'footer']),
|
||||
location: z.enum(['primary', 'footer', 'recommended']),
|
||||
sortOrder: z.coerce.number().int().min(0).default(0),
|
||||
isVisible: z.boolean().default(true),
|
||||
parentId: z.union([z.string().uuid(), z.null()]).optional(),
|
||||
isFolder: z.boolean().default(false)
|
||||
}).superRefine((data, ctx) => {
|
||||
if (data.location === 'footer' && data.parentId) {
|
||||
if ((data.location === 'footer' || data.location === 'recommended') && data.parentId) {
|
||||
ctx.addIssue({
|
||||
code: 'custom',
|
||||
path: ['parentId'],
|
||||
message: '하단 메뉴는 하위 항목을 가질 수 없습니다.'
|
||||
message: '해당 위치 메뉴는 하위 항목을 가질 수 없습니다.'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -35,6 +35,13 @@ export const validateNavigationItems = (items) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (loc === 'recommended') {
|
||||
const p = item.parentId
|
||||
if (p != null && String(p).trim() !== '') {
|
||||
return { ok: false, message: '추천 사이트에는 하위 항목을 둘 수 없습니다.' }
|
||||
}
|
||||
}
|
||||
|
||||
const p = item.parentId
|
||||
if (p != null && String(p).trim() !== '') {
|
||||
const pid = String(p).trim()
|
||||
@@ -43,7 +50,13 @@ export const validateNavigationItems = (items) => {
|
||||
}
|
||||
const parent = byId.get(pid)
|
||||
if (parent.location !== loc) {
|
||||
return { ok: false, message: '상위 메뉴는 같은 위치(상단/하단)에 있어야 합니다.' }
|
||||
return { ok: false, message: '상위 메뉴는 같은 위치(상단/하단/추천)에 있어야 합니다.' }
|
||||
}
|
||||
if (loc === 'primary') {
|
||||
const gp = parent.parentId
|
||||
if (gp != null && String(gp).trim() !== '') {
|
||||
return { ok: false, message: '상단 메뉴는 하위 한 단계까지만 허용됩니다.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,7 +149,7 @@ export const orderNavigationItemsForInsert = (items) => {
|
||||
/**
|
||||
* location 기준 DFS로 sort_order를 10단위로 다시 부여한다.
|
||||
* @param {Array<Object>} items - 전체 항목(변경됨)
|
||||
* @param {'primary'|'footer'} location - 위치
|
||||
* @param {'primary'|'footer'|'recommended'} location - 위치
|
||||
* @returns {void}
|
||||
*/
|
||||
export const renumberSortOrderByTree = (items, location) => {
|
||||
@@ -212,8 +225,14 @@ export const buildPublicPrimaryTree = (flatPrimary) => {
|
||||
const p = row.parentId
|
||||
const pid = p != null && String(p).trim() !== '' ? String(p).trim() : ''
|
||||
if (pid && pid !== id && byId.has(pid)) {
|
||||
byId.get(pid).children.push(node)
|
||||
attachedAsChild.add(id)
|
||||
const parentRow = list.find((r) => String(r.id) === pid)
|
||||
const parentIsRoot =
|
||||
parentRow &&
|
||||
(parentRow.parentId == null || String(parentRow.parentId).trim() === '')
|
||||
if (parentIsRoot) {
|
||||
byId.get(pid).children.push(node)
|
||||
attachedAsChild.add(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user