1936 lines
114 KiB
JSON
1936 lines
114 KiB
JSON
{
|
|
"version": "1.0.0",
|
|
"layout_name": "_user_base",
|
|
"meta": {
|
|
"title": "$t:user.base_layout_title",
|
|
"description": "$t:user.base_layout_description",
|
|
"is_base": true,
|
|
"seo": {
|
|
"enabled": false,
|
|
"data_sources": ["boards"],
|
|
"vars": {
|
|
"site_name": "$core_settings:general.site_name"
|
|
},
|
|
"og": {
|
|
"type": "website"
|
|
}
|
|
}
|
|
},
|
|
"globalHeaders": [
|
|
{
|
|
"pattern": "/api/modules/sirsoft-ecommerce/*",
|
|
"headers": {
|
|
"X-Cart-Key": "{{_global.cartKey}}"
|
|
}
|
|
},
|
|
{
|
|
"pattern": "/api/auth/*",
|
|
"headers": {
|
|
"X-Cart-Key": "{{_global.cartKey}}"
|
|
}
|
|
}
|
|
],
|
|
"transition_overlay": {
|
|
"enabled": true,
|
|
"style": "spinner",
|
|
"target": "main_content_area",
|
|
"spinner": {
|
|
"component": "PageLoading"
|
|
}
|
|
},
|
|
"init_actions": [
|
|
{
|
|
"handler": "initTheme"
|
|
},
|
|
{
|
|
"handler": "initCartKey"
|
|
},
|
|
{
|
|
"handler": "loadFromLocalStorage",
|
|
"params": {
|
|
"key": "g7_preferred_currency",
|
|
"stateKey": "preferredCurrency",
|
|
"defaultValue": "KRW"
|
|
}
|
|
},
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"shopBase": "{{_global.modules?.['sirsoft-ecommerce']?.basic_info?.no_route ? '' : ('/' + (_global.modules?.['sirsoft-ecommerce']?.basic_info?.route_path ?? 'shop'))}}"
|
|
}
|
|
}
|
|
],
|
|
"data_sources": [
|
|
{
|
|
"id": "boards",
|
|
"type": "api",
|
|
"endpoint": "/api/modules/sirsoft-board/boards/board-menu",
|
|
"method": "GET",
|
|
"auto_fetch": true,
|
|
"loading_strategy": "progressive",
|
|
"fallback": { "data": [] }
|
|
},
|
|
{
|
|
"id": "current_user",
|
|
"type": "api",
|
|
"endpoint": "/api/auth/user",
|
|
"method": "GET",
|
|
"auto_fetch": true,
|
|
"auth_required": true,
|
|
"loading_strategy": "progressive",
|
|
"initGlobal": "currentUser",
|
|
"fallback": { "data": [] },
|
|
"errorHandling": {
|
|
"401": {
|
|
"comment": "비회원의 /api/auth/user 401은 정상 — fallback 사용, 레이아웃 에러 핸들링으로 전파 방지",
|
|
"handler": "suppress"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"id": "cart",
|
|
"type": "api",
|
|
"endpoint": "/api/modules/sirsoft-ecommerce/cart/count",
|
|
"method": "GET",
|
|
"auto_fetch": true,
|
|
"auth_mode": "optional",
|
|
"loading_strategy": "progressive",
|
|
"headers": {
|
|
"X-Cart-Key": "{{_global.cartKey}}"
|
|
},
|
|
"initGlobal": {
|
|
"key": "cartCount",
|
|
"path": "count"
|
|
},
|
|
"fallback": { "data": { "count": 0 } }
|
|
},
|
|
{
|
|
"id": "notification_unread_count",
|
|
"type": "api",
|
|
"endpoint": "/api/user/notifications/unread-count",
|
|
"method": "GET",
|
|
"auto_fetch": true,
|
|
"auth_required": true,
|
|
"loading_strategy": "progressive",
|
|
"initGlobal": {
|
|
"key": "notificationCount",
|
|
"path": "unread_count"
|
|
},
|
|
"fallback": { "data": { "unread_count": 0 } },
|
|
"errorHandling": {
|
|
"401": { "handler": "suppress" },
|
|
"403": { "handler": "suppress" }
|
|
}
|
|
},
|
|
{
|
|
"comment": "알림 목록 — 드롭다운 NotificationCenter 에서 사용. unreadOnly 토글에 따라 read 필터 동적 적용",
|
|
"id": "notifications",
|
|
"type": "api",
|
|
"endpoint": "/api/user/notifications",
|
|
"method": "GET",
|
|
"auto_fetch": true,
|
|
"auth_required": true,
|
|
"loading_strategy": "progressive",
|
|
"params": {
|
|
"per_page": 15,
|
|
"read": "{{(_global.notificationsUnreadOnly ?? true) ? 'unread' : 'all'}}"
|
|
},
|
|
"fallback": { "data": { "data": [] } },
|
|
"errorHandling": {
|
|
"401": { "handler": "suppress" },
|
|
"403": { "handler": "suppress" }
|
|
}
|
|
},
|
|
{
|
|
"id": "user_notification_ws",
|
|
"type": "websocket",
|
|
"channel": "core.user.notifications.{{_global.currentUser?.uuid}}",
|
|
"event": "notification.received",
|
|
"channel_type": "private",
|
|
"target_source": "notification_unread_count",
|
|
"onReceive": [
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notification_unread_count" }
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notifications" }
|
|
},
|
|
{
|
|
"handler": "toast",
|
|
"params": {
|
|
"type": "info",
|
|
"message": "{{$args[0].subject ?? '$t:mypage.notifications.new_notification_received'}}",
|
|
"duration": 5000
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"components": [
|
|
{
|
|
"id": "global_toast",
|
|
"type": "composite",
|
|
"name": "Toast",
|
|
"props": {
|
|
"toasts": "{{_global.toasts}}",
|
|
"position": "bottom-center",
|
|
"duration": 5000
|
|
}
|
|
},
|
|
{
|
|
"id": "page_transition_indicator",
|
|
"type": "composite",
|
|
"name": "PageTransitionIndicator"
|
|
},
|
|
{
|
|
"id": "user_layout_root",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "min-h-screen flex flex-col bg-gray-50 dark:bg-gray-900"
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "=== 모바일 오버레이 (사이드 메뉴 열릴 때) ===",
|
|
"id": "mobile_overlay",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{false}}",
|
|
"props": {
|
|
"className": "fixed inset-0 z-40 bg-black/50"
|
|
},
|
|
"responsive": {
|
|
"portable": {
|
|
"if": "{{_global.mobileMenuOpen}}"
|
|
}
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "=== 모바일 헤더 (툴바) - 데스크톱에서 숨김 ===",
|
|
"id": "mobile_header",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "hidden"
|
|
},
|
|
"responsive": {
|
|
"portable": {
|
|
"props": {
|
|
"className": "flex items-center justify-between h-14 px-4 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 sticky top-0 z-30"
|
|
}
|
|
}
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "모바일 헤더 좌측 - 로고",
|
|
"id": "mobile_header_left",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "flex items-center cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/"
|
|
}
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{_global.settings?.general?.site_logo_url}}",
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Img",
|
|
"props": {
|
|
"src": "{{_global.settings?.general?.site_logo_url}}",
|
|
"alt": "{{_global.settings?.general?.site_name ?? 'Site'}}",
|
|
"className": "h-8 w-auto"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{!_global.settings?.general?.site_logo_url}}",
|
|
"props": {
|
|
"className": "text-lg font-bold text-gray-900 dark:text-white"
|
|
},
|
|
"text": "{{_global.settings?.general?.site_name ?? 'Site'}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "모바일 헤더 우측 - 액션 버튼들",
|
|
"id": "mobile_header_right",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex items-center gap-1"
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "다크모드 전환",
|
|
"id": "mobile_theme_btn",
|
|
"type": "composite",
|
|
"name": "ThemeToggle",
|
|
"props": {
|
|
"autoText": "$t:common.theme.auto",
|
|
"lightText": "$t:common.theme.light",
|
|
"darkText": "$t:common.theme.dark"
|
|
}
|
|
},
|
|
{
|
|
"comment": "알림센터 드롭다운 — 모바일 (PC와 동일 순서: 알림 → 장바구니)",
|
|
"id": "mobile_notification_center",
|
|
"type": "composite",
|
|
"name": "NotificationCenter",
|
|
"if": "{{_global.currentUser?.uuid}}",
|
|
"props": {
|
|
"notifications": "{{(notifications?.data?.data ?? []).map(n => ({ id: n.id, title: n.subject ?? '', message: n.body ?? '', time: n.created_at ?? '', read: !!n.read_at, url: n.url ?? '', data: n.data ?? {} }))}}",
|
|
"unreadCount": "{{_global.notificationCount ?? 0}}",
|
|
"hasMore": "{{_global.notificationsHasMore ?? notifications?.data?.pagination?.has_more_pages ?? false}}",
|
|
"loading": "{{_global.notificationsLoadingMore ?? notifications?.loading ?? false}}",
|
|
"titleText": "$t:mypage.notifications.title",
|
|
"emptyText": "$t:mypage.notifications.empty",
|
|
"markAllReadText": "$t:mypage.notifications.mark_all_read",
|
|
"deleteAllText": "$t:mypage.notifications.delete_all",
|
|
"unreadOnlyText": "$t:mypage.notifications.unread_only",
|
|
"unreadOnly": "{{_global.notificationsUnreadOnly ?? true}}",
|
|
"dropdownAlign": "right"
|
|
},
|
|
"actions": [
|
|
{
|
|
"event": "onClose",
|
|
"handler": "sequence",
|
|
"params": {
|
|
"actions": [
|
|
{
|
|
"handler": "apiCall",
|
|
"auth_required": true,
|
|
"target": "/api/user/notifications/read-batch",
|
|
"params": {
|
|
"method": "POST",
|
|
"body": { "ids": "{{$args[0]}}" }
|
|
},
|
|
"onSuccess": [
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notification_unread_count" }
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"event": "onNotificationClick",
|
|
"handler": "parallel",
|
|
"params": {
|
|
"actions": [
|
|
{
|
|
"handler": "navigate",
|
|
"params": { "path": "{{$args[0].url ?? '/mypage/notifications'}}" }
|
|
},
|
|
{
|
|
"handler": "apiCall",
|
|
"auth_required": true,
|
|
"target": "/api/user/notifications/{{$args[0].id}}/read",
|
|
"params": { "method": "PATCH" },
|
|
"onSuccess": [
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notification_unread_count" }
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"event": "onMarkAllRead",
|
|
"handler": "sequence",
|
|
"params": {
|
|
"actions": [
|
|
{
|
|
"handler": "apiCall",
|
|
"auth_required": true,
|
|
"target": "/api/user/notifications/read-all",
|
|
"params": { "method": "POST" },
|
|
"onSuccess": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"notificationsCurrentPage": 1,
|
|
"notificationsHasMore": null,
|
|
"notificationsLoadingMore": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notifications" }
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notification_unread_count" }
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"event": "onUnreadOnlyToggle",
|
|
"handler": "sequence",
|
|
"params": {
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"notificationsUnreadOnly": "{{$args[0]}}",
|
|
"notificationsCurrentPage": 1,
|
|
"notificationsHasMore": null,
|
|
"notificationsLoadingMore": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notifications" }
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"event": "onDelete",
|
|
"handler": "apiCall",
|
|
"auth_required": true,
|
|
"target": "/api/user/notifications/{{$args[0].id}}",
|
|
"params": { "method": "DELETE" },
|
|
"onSuccess": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"notificationsCurrentPage": 1,
|
|
"notificationsHasMore": null
|
|
}
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notifications" }
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notification_unread_count" }
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"event": "onDeleteAll",
|
|
"handler": "openModal",
|
|
"target": "notification_delete_all_confirm_modal"
|
|
},
|
|
{
|
|
"event": "onLoadMore",
|
|
"handler": "sequence",
|
|
"params": {
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"notificationsLoadingMore": true
|
|
}
|
|
},
|
|
{
|
|
"handler": "apiCall",
|
|
"auth_required": true,
|
|
"target": "/api/user/notifications",
|
|
"params": {
|
|
"method": "GET",
|
|
"query": {
|
|
"page": "{{(_global.notificationsCurrentPage ?? notifications?.data?.pagination?.current_page ?? 1) + 1}}",
|
|
"per_page": 15
|
|
}
|
|
},
|
|
"onSuccess": [
|
|
{
|
|
"handler": "appendDataSource",
|
|
"params": {
|
|
"dataSourceId": "notifications",
|
|
"dataPath": "data.data",
|
|
"newData": "{{response.data.data ?? []}}"
|
|
}
|
|
},
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"notificationsCurrentPage": "{{response.data.pagination.current_page}}",
|
|
"notificationsHasMore": "{{response.data.pagination.has_more_pages}}",
|
|
"notificationsLoadingMore": false
|
|
}
|
|
}
|
|
],
|
|
"onError": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"notificationsLoadingMore": false
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "장바구니 — PC와 동일 순서 (알림 → 장바구니)",
|
|
"id": "mobile_cart_btn",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "p-2 text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg relative cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "{{_global.shopBase}}/cart"
|
|
}
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "shopping-cart",
|
|
"className": "w-5 h-5"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{_global.cartCount > 0}}",
|
|
"props": {
|
|
"className": "absolute -top-1 -right-1 w-5 h-5 bg-blue-500 text-white text-xs font-bold rounded-full flex items-center justify-center"
|
|
},
|
|
"text": "{{_global.cartCount > 99 ? '99+' : _global.cartCount}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "사용자 아이콘 (로그인 시) / 로그인 버튼",
|
|
"id": "mobile_user_btn",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "p-2 text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "{{_global.currentUser ? '/mypage' : '/login'}}"
|
|
}
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "user",
|
|
"className": "w-5 h-5"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "햄버거 메뉴 버튼",
|
|
"id": "mobile_menu_toggle",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "p-2 text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": "{{!_global.mobileMenuOpen}}"
|
|
}
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "menu",
|
|
"className": "w-5 h-5"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "=== 모바일 사이드 메뉴 (MobileNav 드로어) ===",
|
|
"id": "mobile_nav_drawer",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "hidden"
|
|
},
|
|
"responsive": {
|
|
"portable": {
|
|
"props": {
|
|
"className": "{{_global.mobileMenuOpen ? 'translate-x-0' : 'translate-x-full'}} fixed inset-y-0 right-0 z-50 w-80 max-w-full transition-transform duration-300 bg-white dark:bg-gray-800 shadow-xl overflow-y-auto"
|
|
}
|
|
}
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "드로어 헤더 - 닫기 버튼",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"props": {
|
|
"className": "font-semibold text-gray-900 dark:text-white"
|
|
},
|
|
"text": "$t:user.menu"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "p-2 text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false
|
|
}
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "x",
|
|
"className": "w-5 h-5"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "검색바",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "p-4"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "relative"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "search",
|
|
"className": "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 dark:text-gray-500"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Input",
|
|
"props": {
|
|
"type": "text",
|
|
"name": "q",
|
|
"placeholder": "$t:user.search_placeholder",
|
|
"className": "w-full pl-10 pr-4 py-2.5 border border-gray-300 dark:border-gray-600 rounded-lg bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white text-sm focus:ring-2 focus:ring-blue-500"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "keydown",
|
|
"key": "Enter",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": { "target": "global", "mobileMenuOpen": false }
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": { "path": "/search", "query": { "q": "{{$event.target.value}}" } }
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "로그인된 사용자 정보 - 아코디언 토글",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{_global.currentUser?.uuid}}",
|
|
"props": {
|
|
"className": "px-4 pb-4 border-b border-gray-200 dark:border-gray-700"
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "사용자 프로필 버튼 (아코디언 토글)",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "w-full flex items-center gap-3 p-3 bg-gray-50 dark:bg-gray-700 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileUserMenuOpen": "{{!_global.mobileUserMenuOpen}}"
|
|
}
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "composite",
|
|
"name": "Avatar",
|
|
"props": {
|
|
"avatar": "{{_global.currentUser?.avatar}}",
|
|
"name": "{{_global.currentUser?.name ?? '?'}}",
|
|
"size": "md"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex-1 min-w-0 text-left"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "font-medium text-gray-900 dark:text-white truncate"
|
|
},
|
|
"text": "{{_global.currentUser?.name}}"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "text-sm text-gray-500 dark:text-gray-400 truncate"
|
|
},
|
|
"text": "{{_global.currentUser?.email}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "아코디언 화살표 아이콘",
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "chevron-down",
|
|
"className": "{{_global.mobileUserMenuOpen ? 'rotate-180' : ''}} w-5 h-5 text-gray-400 dark:text-gray-500 transition-transform duration-200"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "아코디언 펼침 영역 - 부드러운 애니메이션",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "overflow-hidden transition-all duration-300 ease-in-out {{_global.mobileUserMenuOpen ? 'max-h-screen opacity-100 mt-2' : 'max-h-0 opacity-0 mt-0'}}"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "overflow-hidden min-h-0 py-2 bg-gray-100 dark:bg-gray-700/50 rounded-lg"
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "관리자 메뉴 (is_admin일 때만) - 하이퍼링크로 전체 페이지 새로고침",
|
|
"type": "basic",
|
|
"name": "A",
|
|
"if": "{{_global.currentUser?.is_admin}}",
|
|
"props": {
|
|
"href": "/admin",
|
|
"className": "w-full flex items-center justify-start gap-3 px-4 py-2.5 text-blue-600 dark:text-blue-400 hover:bg-gray-200 dark:hover:bg-gray-600 font-medium"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "settings",
|
|
"className": "w-4 h-4"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "$t:common.admin_menu"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "마이페이지",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "w-full flex items-center justify-start gap-3 px-4 py-2.5 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600 cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false,
|
|
"mobileUserMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/mypage"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "user",
|
|
"className": "w-4 h-4"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "$t:common.mypage"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "주문 내역",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "w-full flex items-center justify-start gap-3 px-4 py-2.5 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600 cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false,
|
|
"mobileUserMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/mypage/orders"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "shopping-bag",
|
|
"className": "w-4 h-4"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "$t:mypage.tabs.orders"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "위시리스트",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "w-full flex items-center justify-start gap-3 px-4 py-2.5 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600 cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false,
|
|
"mobileUserMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/mypage/wishlist"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "heart",
|
|
"className": "w-4 h-4"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "$t:mypage.tabs.wishlist"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "언어 선택 (여러 언어 지원 시)",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{$locales.length > 1}}",
|
|
"props": {
|
|
"className": "mt-2 pt-2 border-t border-gray-200 dark:border-gray-600"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "px-4 py-1 text-xs font-medium text-gray-500 dark:text-gray-400 uppercase"
|
|
},
|
|
"text": "$t:common.language"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"iteration": {
|
|
"source": "{{$locales}}",
|
|
"item_var": "loc"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "{{loc === $locale ? 'bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400' : 'text-gray-700 dark:text-gray-300'}} w-full flex items-center justify-start gap-3 px-4 py-2 hover:bg-gray-200 dark:hover:bg-gray-600 cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "setLocale",
|
|
"target": "{{loc}}"
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "globe",
|
|
"className": "w-4 h-4"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "{{_global.appConfig?.localeNames?.[loc] ?? loc}}"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "로그아웃 버튼",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "w-full flex items-center gap-3 px-4 py-2.5 mt-2 pt-2 border-t border-gray-200 dark:border-gray-600 text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "logout",
|
|
"onSuccess": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false,
|
|
"mobileUserMenuOpen": false
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "log-out",
|
|
"className": "w-4 h-4"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "$t:auth.logout"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "비로그인 상태 - 로그인/회원가입 버튼",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{!_global.currentUser?.uuid}}",
|
|
"props": {
|
|
"className": "px-4 pb-4 border-b border-gray-200 dark:border-gray-700"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex gap-2"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "flex-1 py-2.5 text-center bg-gray-900 dark:bg-white text-white dark:text-gray-900 rounded-lg font-medium text-sm cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/login"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"text": "$t:auth.login"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "flex-1 py-2.5 text-center border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 rounded-lg font-medium text-sm cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/register"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"text": "$t:auth.register_link"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "메뉴 섹션 - 홈",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "p-4"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "w-full flex items-center justify-start gap-3 px-3 py-2.5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg font-medium cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "home",
|
|
"className": "w-5 h-5"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "$t:user.nav.home"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "w-full flex items-center justify-start gap-3 px-3 py-2.5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/boards/popular"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "flame",
|
|
"className": "w-5 h-5 text-orange-500"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "$t:user.nav.popular"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "메뉴 섹션 - 게시판",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "px-4 pb-4"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-2 px-3"
|
|
},
|
|
"text": "$t:user.nav.boards"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"iteration": {
|
|
"source": "{{boards.data ?? []}}",
|
|
"item_var": "board"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "w-full flex items-center justify-between px-3 py-2.5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/board/{{board.slug}}"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "{{board.name}}"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{board.post_count > 0}}",
|
|
"props": {
|
|
"className": "text-xs text-gray-500 dark:text-gray-400"
|
|
},
|
|
"text": "{{board.post_count}}"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "메뉴 섹션 - 쇼핑",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "px-4 pb-4 border-b border-gray-200 dark:border-gray-700"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-2 px-3"
|
|
},
|
|
"text": "$t:user.nav.shop"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "w-full flex items-center justify-start gap-3 px-3 py-2.5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "{{_global.shopBase}}/products"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "shopping-bag",
|
|
"className": "w-5 h-5"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "$t:user.nav.products"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "w-full flex items-center justify-between px-3 py-2.5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "{{_global.shopBase}}/cart"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex items-center gap-3"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "shopping-cart",
|
|
"className": "w-5 h-5"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "$t:user.nav.cart"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{_global.cartCount > 0}}",
|
|
"props": {
|
|
"className": "px-2 py-0.5 bg-red-500 text-white text-xs font-bold rounded-full"
|
|
},
|
|
"text": "{{_global.cartCount}}"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "메뉴 섹션 - 정보/정책",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "px-4 py-4 border-b border-gray-200 dark:border-gray-700"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "grid grid-cols-2 gap-x-4"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-2"
|
|
},
|
|
"text": "$t:user.footer.info"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "block w-full py-1.5 text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white text-left cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/page/about"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"text": "$t:user.footer.about"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "block w-full py-1.5 text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white text-left cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/page/faq"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"text": "$t:user.footer.faq"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "block w-full py-1.5 text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white text-left cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/page/contact"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"text": "$t:user.footer.contact"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-2"
|
|
},
|
|
"text": "$t:user.footer.policy"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "block w-full py-1.5 text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white text-left cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/page/terms"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"text": "$t:user.footer.terms"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "block w-full py-1.5 text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white text-left cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/page/privacy"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"text": "$t:user.footer.privacy"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "block w-full py-1.5 text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white text-left cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"mobileMenuOpen": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/page/refund"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"text": "$t:user.footer.refund"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "=== 데스크톱 헤더 (Header 컴포넌트) - 모바일에서 숨김 ===",
|
|
"id": "desktop_header",
|
|
"type": "composite",
|
|
"name": "Header",
|
|
"props": {
|
|
"logo": "{{_global.settings?.general?.site_logo_url}}",
|
|
"siteName": "{{_global.settings?.general?.site_name ?? 'Site'}}",
|
|
"user": "{{_global.currentUser}}",
|
|
"cartCount": "{{_global.cartCount ?? 0}}",
|
|
"notificationCount": "{{_global.notificationCount ?? 0}}",
|
|
"shopBase": "{{_global.shopBase ?? '/shop'}}",
|
|
"boards": "{{boards.data ?? []}}",
|
|
"maxVisibleBoards": 5,
|
|
"availableLocales": "{{$locales}}",
|
|
"currentLocale": "{{$locale}}",
|
|
"className": "hidden",
|
|
"notifications": "{{(notifications?.data?.data ?? []).map(n => ({ id: n.id, title: n.subject ?? '', message: n.body ?? '', time: n.created_at ?? '', read: !!n.read_at, url: n.url ?? '', data: n.data ?? {} }))}}",
|
|
"notificationHasMore": "{{_global.notificationsHasMore ?? notifications?.data?.pagination?.has_more_pages ?? false}}",
|
|
"notificationLoading": "{{_global.notificationsLoadingMore ?? notifications?.loading ?? false}}",
|
|
"notificationUnreadOnly": "{{_global.notificationsUnreadOnly ?? true}}"
|
|
},
|
|
"responsive": {
|
|
"desktop": {
|
|
"props": { "className": "block" }
|
|
}
|
|
},
|
|
"actions": [
|
|
{
|
|
"event": "onNotificationClose",
|
|
"handler": "sequence",
|
|
"params": {
|
|
"actions": [
|
|
{
|
|
"handler": "apiCall",
|
|
"auth_required": true,
|
|
"target": "/api/user/notifications/read-batch",
|
|
"params": {
|
|
"method": "POST",
|
|
"body": { "ids": "{{$args[0]}}" }
|
|
},
|
|
"onSuccess": [
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notification_unread_count" }
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"event": "onNotificationClick",
|
|
"handler": "sequence",
|
|
"params": {
|
|
"actions": [
|
|
{
|
|
"handler": "apiCall",
|
|
"auth_required": true,
|
|
"target": "/api/user/notifications/{{$args[0].id}}/read",
|
|
"params": { "method": "PATCH" },
|
|
"onSuccess": [
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notification_unread_count" }
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"handler": "navigate",
|
|
"if": "{{$args[0].url}}",
|
|
"params": { "path": "{{$args[0].url ?? '/mypage/notifications'}}" }
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"event": "onNotificationMarkAllRead",
|
|
"handler": "sequence",
|
|
"params": {
|
|
"actions": [
|
|
{
|
|
"handler": "apiCall",
|
|
"auth_required": true,
|
|
"target": "/api/user/notifications/read-all",
|
|
"params": { "method": "POST" },
|
|
"onSuccess": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"notificationsCurrentPage": 1,
|
|
"notificationsHasMore": null,
|
|
"notificationsLoadingMore": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notifications" }
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notification_unread_count" }
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"event": "onNotificationUnreadOnlyToggle",
|
|
"handler": "sequence",
|
|
"params": {
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"notificationsUnreadOnly": "{{$args[0]}}",
|
|
"notificationsCurrentPage": 1,
|
|
"notificationsHasMore": null,
|
|
"notificationsLoadingMore": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notifications" }
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"event": "onNotificationDelete",
|
|
"handler": "apiCall",
|
|
"auth_required": true,
|
|
"target": "/api/user/notifications/{{$args[0].id}}",
|
|
"params": { "method": "DELETE" },
|
|
"onSuccess": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"notificationsCurrentPage": 1,
|
|
"notificationsHasMore": null
|
|
}
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notifications" }
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": { "dataSourceId": "notification_unread_count" }
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"event": "onNotificationDeleteAll",
|
|
"handler": "openModal",
|
|
"target": "notification_delete_all_confirm_modal"
|
|
},
|
|
{
|
|
"event": "onNotificationLoadMore",
|
|
"handler": "sequence",
|
|
"params": {
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"notificationsLoadingMore": true
|
|
}
|
|
},
|
|
{
|
|
"handler": "apiCall",
|
|
"auth_required": true,
|
|
"target": "/api/user/notifications",
|
|
"params": {
|
|
"method": "GET",
|
|
"query": {
|
|
"page": "{{(_global.notificationsCurrentPage ?? notifications?.data?.pagination?.current_page ?? 1) + 1}}",
|
|
"per_page": 15
|
|
}
|
|
},
|
|
"onSuccess": [
|
|
{
|
|
"handler": "appendDataSource",
|
|
"params": {
|
|
"dataSourceId": "notifications",
|
|
"dataPath": "data.data",
|
|
"newData": "{{response.data.data ?? []}}"
|
|
}
|
|
},
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"notificationsCurrentPage": "{{response.data.pagination.current_page}}",
|
|
"notificationsHasMore": "{{response.data.pagination.has_more_pages}}",
|
|
"notificationsLoadingMore": false
|
|
}
|
|
}
|
|
],
|
|
"onError": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"notificationsLoadingMore": false
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "=== 메인 콘텐츠 영역 ===",
|
|
"id": "main_content_area",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex-1"
|
|
},
|
|
"children": [
|
|
{
|
|
"id": "main_content",
|
|
"type": "layout",
|
|
"name": "Container",
|
|
"slot": "content",
|
|
"props": {
|
|
"className": "min-h-fit px-4"
|
|
},
|
|
"responsive": {
|
|
"desktop": {
|
|
"props": {
|
|
"className": "min-h-fit max-w-7xl mx-auto px-8"
|
|
}
|
|
}
|
|
},
|
|
"children": []
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "=== 푸터 (Footer 컴포넌트) ===",
|
|
"id": "footer",
|
|
"type": "composite",
|
|
"name": "Footer",
|
|
"props": {
|
|
"siteName": "{{_global.settings?.general?.site_name ?? 'Site'}}",
|
|
"siteDescription": "{{_global.settings?.general?.site_description ?? ''}}",
|
|
"copyrightText": "$t:footer.copyright|siteName={{_global.settings?.general?.site_name ?? '그누보드7'}}",
|
|
"socialLinks": {
|
|
"github": "{{_global.settings?.social?.github}}",
|
|
"twitter": "{{_global.settings?.social?.twitter}}",
|
|
"discord": "{{_global.settings?.social?.discord}}"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"modals": [
|
|
{
|
|
"partial": "partials/_modal_notification_delete_all_confirm.json"
|
|
}
|
|
]
|
|
}
|