fix(page): 첨부 업로드 검증 실패 시 사용자 안내 토스트 노출

- 페이지 폼 FileUploader 에 onUploadError→toast 연결 (용량/확장자 초과 안내)
- 사용자 템플릿(sirsoft-basic) 개수 초과 시 onUploadError 발화 추가 (silent 무시 방지)
- 개수 초과 문구를 이미지 전용에서 일반 파일 범용 공통 메시지로 통일 (ko/en/ja)
This commit is contained in:
chym1217 committed 2026-07-06 09:37:06 +09:00
1 parent 2473ca7242
commit 98989e3c2c
23 files changed
+6142 -5945

No files matched your search

@@ -4,6 +4,12 @@
형식은 [Keep a Changelog](https://keepachangelog.com/ko/1.1.0/)를 따르며,
[Semantic Versioning](https://semver.org/lang/ko/)을 준수합니다.
## [1.0.1] - 2026-07-01
### Changed
- 첨부 개수 초과 안내 문구(`attachment.upload_limit_exceeded`)를 이미지 전용 표현에서 일반 파일에도 맞는 범용 표현으로 갱신했습니다 — 한국어/영어 원문 변경에 맞춰 일본어 번역을 동기화했습니다.
## [1.0.0] - 2026-07-01
### Added
@@ -7,11 +7,11 @@
"deleting": "削除中...",
"drop_or_click": "ファイルをドラッグするか、クリックしてアップロード",
"upload_limit": "最大{{maxFiles}}個、1個あたり{{maxSize}}MB",
"upload_limit_exceeded": "最大{{max}}個まで添付できます。",
"attached_count": "{{count}}/{{max}}個添付済み",
"max_size": "最大{{size}}MB",
"drag_to_reorder": "ドラッグして順序を変更",
"reorder_failed": "順序変更に失敗しました。",
"primary_image": "メイン画像",
"set_as_primary": "メイン画像に設定",
"upload_limit_exceeded": "画像は最大{{max}}枚までアップロードできます。"
"set_as_primary": "メイン画像に設定"
}
@@ -12,7 +12,7 @@
"en": "G7 template (sirsoft-admin_basic) Japanese language pack (bundled)",
"ja": "G7 テンプレート (sirsoft-admin_basic) 日本語 言語パック(バンドル)"
},
"version": "1.0.0",
"version": "1.0.1",
"license": "MIT",
"scope": "template",
"target_identifier": "sirsoft-admin_basic",
@@ -9,6 +9,7 @@
### Added
- 미발행 페이지 관리자 미리보기 안내 배너(`user.page.preview_banner`) 일본어 번역 추가 — 관리자가 발행 전 페이지를 사용자 화면에서 미리 볼 때의 안내 문구가 일본어 로케일에서 자연스럽게 표시됩니다.
- 첨부 개수 초과 안내 문구(`attachment.upload_limit_exceeded`) 일본어 번역 추가 — 게시글 첨부를 허용 개수보다 많이 선택했을 때의 안내가 일본어 로케일에서 자연스럽게 표시됩니다.
## [1.0.0] - 2026-07-01
@@ -9,5 +9,6 @@
"reorder_failed": "ファイルの順序変更に失敗しました",
"drag_to_reorder": "ドラッグして順序を変更",
"primary_image": "代表画像",
"set_as_primary": "代表画像に設定"
"set_as_primary": "代表画像に設定",
"upload_limit_exceeded": "最大{{max}}個まで添付できます。"
}
@@ -20,6 +20,7 @@
- 페이지 관리 목록에서 아주 긴 검색어를 입력하면 오류 화면이 뜨던 문제를 수정했습니다 — 검색어 길이를 100자로 제한해 안내 메시지로 처리합니다.
- 페이지 상세의 버전 이력에서 "변경내역" 항목이 `title`·`content` 같은 영문 필드명으로 표시되던 문제를 수정했습니다 — 이제 "제목", "내용", "SEO 정보" 처럼 알아보기 쉬운 이름으로 표시됩니다.
- 관리자가 발행 전 페이지를 사용자 화면에서 미리 확인할 수 있게 되었습니다. 미리보기 화면에는 미발행 상태임을 알리는 안내가 표시되며, 비로그인 사용자와 일반 회원에게는 이전과 동일하게 노출되지 않습니다.
- 페이지 첨부파일을 올릴 때 허용 용량을 초과하거나 허용되지 않은 형식의 파일을 선택하면 안내 메시지가 표시됩니다 — 이전에는 업로드가 조용히 막히기만 하고 이유를 알 수 없었습니다.
## [1.0.0] - 2026-07-01
@@ -638,6 +638,21 @@ describe('admin_page_form.json', () => {
expect(onReorder.params['form.attachments']).toContain('$args[0]');
});
// ─── 첨부 검증 실패 안내 (용량/확장자/개수 초과 toast) ───
it('FileUploader 에 onUploadError → toast 액션이 있어 검증 실패를 사용자에게 안내함', () => {
// 회귀 배경: onUploadError 핸들러 부재로 용량/확장자/개수 초과 시 백엔드/클라이언트
// 차단은 되나 toast 안내가 없어 사용자가 이유를 알 수 없었음.
const uploaders = findComponentsByName(adminPageForm, 'FileUploader');
const actions = uploaders[0].actions ?? [];
const onUploadError = actions.find((a: any) => a.event === 'onUploadError');
expect(onUploadError, 'onUploadError 액션').toBeDefined();
expect(onUploadError.handler).toBe('toast');
expect(onUploadError.params.type).toBe('error');
// 훅이 만든 에러 메시지 문자열($args[0])을 그대로 표시
expect(onUploadError.params.message).toContain('$args[0]');
});
it('FileUploader reorder 엔드포인트가 수정 모드(route.id)에서만 활성화됨 (생성 모드는 temp 첨부라 reorder 불가)', () => {
const uploaders = findComponentsByName(adminPageForm, 'FileUploader');
expect(uploaders[0].props.apiEndpoints.reorder).toContain('route?.id');
@@ -756,6 +756,15 @@
"target": "local",
"form.attachments": "{{(_local.form?.attachments ?? []).filter(item => (item.hash || item.id) !== $args[0])}}"
}
},
{
"comment": "업로드 검증 실패(용량/확장자/개수 초과 등) 시 사용자에게 toast 안내",
"event": "onUploadError",
"handler": "toast",
"params": {
"type": "error",
"message": "{{$args[0]}}"
}
}
]
}
@@ -6,8 +6,11 @@
# 무의미 조합이 다수 포함되므로 docblock @scenario 전수 마킹이 부적합하다.
# 실제 회귀 가드는 test_files 의 통과 테스트가 결함별로 담당한다:
# 6-1 → PageControllerTest(Feature) / 6-2 → PageAttachmentServiceTest(Unit) +
# admin-page-layouts.test.ts(레이아웃 렌더) / 7 → admin-page-layouts.test.ts /
# 12-2 → SeoPageCacheListenerTest(Unit) / 13 → admin-page-layouts.test.ts.
# admin-page-layouts.test.ts(레이아웃 렌더) / 7(폼 잔존) → admin-page-layouts.test.ts /
# 12-2 → SeoPageCacheListenerTest(Unit) / 13 → admin-page-layouts.test.ts /
# 7(검증 안내 toast) → admin-page-layouts.test.ts(onUploadError→toast 핸들러 존재) +
# FileUploaderLimit.test.ts(개수 초과 발화). upload_validation 축은 용량/확장자/개수/정상
# 4값이나 용량·확장자는 컴포넌트 기존 검증이라 레이아웃 핸들러 존재로, 개수는 훅 단위로 커버.
# E2E: 페이지 모듈에 Playwright 인프라를 이커머스와 동일 패턴으로 신설(config + page-auth/
# page-seed fixture + playwright:seed-page stub)하고 spec 3건을 form_mode/upload_count/
# page_change axis 와 1:1 매핑해 등록했으며, 대상 화면 data-testid 보강 전까지 skip placeholder
@@ -60,6 +63,7 @@ axes:
upload_count: [single, multiple]
page_change: [create, update, delete, restore]
cached_entry: [layout_tagged, url_only]
upload_validation: [size_exceeded, ext_not_allowed, count_exceeded, valid]
effects:
- admin_context_returns_admin_download_and_preview_url
@@ -76,12 +80,16 @@ effects:
- page_restore_invalidates_page_detail_seo_cache
- page_restore_creates_new_version_and_preserves_history
- page_version_changed_fields_render_localized_labels
- attachment_size_or_ext_rejection_shows_error_toast
- attachment_count_exceeded_shows_error_toast_and_truncates
- valid_attachment_upload_shows_no_error_toast
test_files:
- modules/_bundled/sirsoft-page/tests/Unit/Services/PageAttachmentServiceTest.php
- modules/_bundled/sirsoft-page/tests/Feature/Admin/PageControllerTest.php
- modules/_bundled/sirsoft-page/tests/Unit/Listeners/SeoPageCacheListenerTest.php
- modules/_bundled/sirsoft-page/resources/js/__tests__/layouts/admin-page-layouts.test.ts
- templates/_bundled/sirsoft-basic/src/components/composite/__tests__/FileUploaderLimit.test.ts
- modules/_bundled/sirsoft-page/tests/Playwright/specs/admin/page-form-reset-on-route-switch.spec.ts
- modules/_bundled/sirsoft-page/tests/Playwright/specs/admin/page-attachment-order.spec.ts
- modules/_bundled/sirsoft-page/tests/Playwright/specs/admin/page-version-changed-fields-i18n.spec.ts
@@ -4,6 +4,12 @@
형식은 [Keep a Changelog](https://keepachangelog.com/ko/1.1.0/)를 따르며,
[Semantic Versioning](https://semver.org/lang/ko/)을 준수합니다.
## [1.0.1] - 2026-07-01
### Changed
- 첨부파일을 허용 개수보다 많이 선택했을 때의 안내 문구를 "이미지는 최대 N장까지…"에서 "최대 N개까지 첨부할 수 있습니다"로 바꿔, 이미지뿐 아니라 문서 등 일반 파일을 올리는 화면에서도 자연스럽게 표시되도록 했습니다.
## [1.0.0] - 2026-07-01
### Added
@@ -7,7 +7,7 @@
"deleting": "Deleting...",
"drop_or_click": "Drag and drop files or click to upload",
"upload_limit": "Max {{maxFiles}} files, {{maxSize}}MB each",
"upload_limit_exceeded": "You can upload up to {{max}} images.",
"upload_limit_exceeded": "You can attach up to {{max}} files.",
"attached_count": "{{count}}/{{max}} attached",
"max_size": "Max {{size}}MB",
"drag_to_reorder": "Drag to reorder",
@@ -7,7 +7,7 @@
"deleting": "삭제하는 중...",
"drop_or_click": "파일을 드래그하거나 클릭하여 업로드",
"upload_limit": "최대 {{maxFiles}}개, 개당 {{maxSize}}MB",
"upload_limit_exceeded": "이미지는 최대 {{max}}장까지 업로드할 수 있습니다.",
"upload_limit_exceeded": "최대 {{max}}개까지 첨부할 수 있습니다.",
"attached_count": "{{count}}/{{max}}개 첨부됨",
"max_size": "최대 {{size}}MB",
"drag_to_reorder": "드래그하여 순서 변경",
File diff suppressed because it is too large. Load diff
@@ -1,6 +1,6 @@
{
"name": "sirsoft-admin_basic",
"version": "1.0.0",
"version": "1.0.1",
"description": "Gnuboard7 Basic Admin Template Components",
"type": "module",
"main": "dist/components.js",
@@ -5,7 +5,7 @@
"ko": "Admin Basic",
"en": "Admin Basic"
},
"version": "1.0.0",
"version": "1.0.1",
"license": "MIT",
"description": {
"ko": "그누보드7 기본 관리자 템플릿",
@@ -10,6 +10,10 @@
- 관리자가 발행 전 페이지를 사용자 화면에서 미리 볼 때, 미발행 상태임을 알리는 안내 표시를 추가했습니다.
### Fixed
- 게시글 첨부파일을 허용 개수보다 많이 선택하면, 초과분이 아무 안내 없이 사라지지 않고 "최대 N개까지 첨부할 수 있습니다" 안내 메시지가 표시됩니다.
## [1.0.0] - 2026-07-01
### Added
+1 -1
View File
@@ -1 +1 @@
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-pan-x:initial;--tw-pan-y:initial;--tw-pinch-zoom:initial;--tw-scroll-snap-strictness:proximity;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-divide-x-reverse:0;--tw-border-style:solid;--tw-divide-y-reverse:0;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-content:""}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-200:oklch(88.5% .062 18.334);--color-red-300:oklch(80.8% .114 19.571);--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-800:oklch(44.4% .177 26.899);--color-red-900:oklch(39.6% .141 25.723);--color-red-950:oklch(25.8% .092 26.042);--color-orange-50:oklch(98% .016 73.684);--color-orange-100:oklch(95.4% .038 75.164);--color-orange-200:oklch(90.1% .076 70.697);--color-orange-300:oklch(83.7% .128 66.29);--color-orange-400:oklch(75% .183 55.934);--color-orange-500:oklch(70.5% .213 47.604);--color-orange-600:oklch(64.6% .222 41.116);--color-orange-700:oklch(55.3% .195 38.402);--color-orange-800:oklch(47% .157 37.304);--color-orange-900:oklch(40.8% .123 38.172);--color-orange-950:oklch(26.6% .079 36.259);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-amber-900:oklch(41.4% .112 45.904);--color-amber-950:oklch(27.9% .077 45.635);--color-yellow-50:oklch(98.7% .026 102.212);--color-yellow-100:oklch(97.3% .071 103.193);--color-yellow-200:oklch(94.5% .129 101.54);--color-yellow-300:oklch(90.5% .182 98.111);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-yellow-600:oklch(68.1% .162 75.834);--color-yellow-700:oklch(55.4% .135 66.442);--color-yellow-800:oklch(47.6% .114 61.907);--color-yellow-900:oklch(42.1% .095 57.708);--color-yellow-950:oklch(28.6% .066 53.813);--color-lime-50:oklch(98.6% .031 120.757);--color-lime-100:oklch(96.7% .067 122.328);--color-lime-200:oklch(93.8% .127 124.321);--color-lime-300:oklch(89.7% .196 126.665);--color-lime-400:oklch(84.1% .238 128.85);--color-lime-500:oklch(76.8% .233 130.85);--color-lime-600:oklch(64.8% .2 131.684);--color-lime-700:oklch(53.2% .157 131.589);--color-lime-800:oklch(45.3% .124 130.933);--color-lime-900:oklch(40.5% .101 131.063);--color-lime-950:oklch(27.4% .072 132.109);--color-green-50:oklch(98.2% .018 155.826);--color-green-100:oklch(96.2% .044 156.743);--color-green-200:oklch(92.5% .084 155.995);--color-green-300:oklch(87.1% .15 154.449);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-green-600:oklch(62.7% .194 149.214);--color-green-700:oklch(52.7% .154 150.069);--color-green-800:oklch(Line truncated
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-pan-x:initial;--tw-pan-y:initial;--tw-pinch-zoom:initial;--tw-scroll-snap-strictness:proximity;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-divide-x-reverse:0;--tw-border-style:solid;--tw-divide-y-reverse:0;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-content:""}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-200:oklch(88.5% .062 18.334);--color-red-300:oklch(80.8% .114 19.571);--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-800:oklch(44.4% .177 26.899);--color-red-900:oklch(39.6% .141 25.723);--color-red-950:oklch(25.8% .092 26.042);--color-orange-50:oklch(98% .016 73.684);--color-orange-100:oklch(95.4% .038 75.164);--color-orange-200:oklch(90.1% .076 70.697);--color-orange-300:oklch(83.7% .128 66.29);--color-orange-400:oklch(75% .183 55.934);--color-orange-500:oklch(70.5% .213 47.604);--color-orange-600:oklch(64.6% .222 41.116);--color-orange-700:oklch(55.3% .195 38.402);--color-orange-800:oklch(47% .157 37.304);--color-orange-900:oklch(40.8% .123 38.172);--color-orange-950:oklch(26.6% .079 36.259);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-amber-900:oklch(41.4% .112 45.904);--color-amber-950:oklch(27.9% .077 45.635);--color-yellow-50:oklch(98.7% .026 102.212);--color-yellow-100:oklch(97.3% .071 103.193);--color-yellow-200:oklch(94.5% .129 101.54);--color-yellow-300:oklch(90.5% .182 98.111);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-yellow-600:oklch(68.1% .162 75.834);--color-yellow-700:oklch(55.4% .135 66.442);--color-yellow-800:oklch(47.6% .114 61.907);--color-yellow-900:oklch(42.1% .095 57.708);--color-yellow-950:oklch(28.6% .066 53.813);--color-lime-50:oklch(98.6% .031 120.757);--color-lime-100:oklch(96.7% .067 122.328);--color-lime-200:oklch(93.8% .127 124.321);--color-lime-300:oklch(89.7% .196 126.665);--color-lime-400:oklch(84.1% .238 128.85);--color-lime-500:oklch(76.8% .233 130.85);--color-lime-600:oklch(64.8% .2 131.684);--color-lime-700:oklch(53.2% .157 131.589);--color-lime-800:oklch(45.3% .124 130.933);--color-lime-900:oklch(40.5% .101 131.063);--color-lime-950:oklch(27.4% .072 132.109);--color-green-50:oklch(98.2% .018 155.826);--color-green-100:oklch(96.2% .044 156.743);--color-green-200:oklch(92.5% .084 155.995);--color-green-300:oklch(87.1% .15 154.449);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-green-600:oklch(62.7% .194 149.214);--color-green-700:oklch(52.7% .154 150.069);--color-greLine truncated
+18 -17
View File
@@ -1,23 +1,24 @@
var SirsoftBasic=(function(J,d,k,Jt){"use strict";function Mc(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const r in e)if(r!=="default"){const n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:()=>e[r]})}}return t.default=e,Object.freeze(t)}const T=Mc(k),Oc=()=>window.G7Core,Q=k.forwardRef(({children:e,variant:t="primary",size:r="md",className:n="",...o},a)=>{const s="inline-flex items-center justify-center",l=Oc()?.style?.mergeClasses?.(s,n)??`${s} ${n}`;return d.jsx("button",{ref:a,className:l,...o,children:e})});Q.displayName="Button";const W=k.forwardRef(({children:e,className:t="",...r},n)=>d.jsx("div",{ref:n,className:t,...r,children:e})),te=({children:e,className:t="",...r})=>d.jsx("span",{className:t,...r,children:e}),fn=({children:e,className:t="",...r})=>d.jsx("svg",{className:t,...r,children:e}),xt=k.forwardRef(({label:e,error:t,className:r="",onChange:n,onKeyPress:o,value:a,defaultValue:s,type:l="text",checked:g,defaultChecked:h,...c},i)=>{const u=l==="radio"||l==="checkbox",f=k.useRef(!1),p=k.useRef(null);k.useImperativeHandle(i,()=>p.current);const[m,w]=k.useState(a??s??"");k.useEffect(()=>{!u&&!f.current&&a!==void 0&&w(a)},[a,u]);const x=k.useCallback(()=>{f.current=!0},[]),A=k.useCallback(y=>{if(f.current=!1,n){const N=y.target.value;w(N);const M=new Event("change",{bubbles:!0});Object.defineProperty(M,"target",{writable:!1,value:{value:N}}),Object.defineProperty(M,"currentTarget",{writable:!1,value:{value:N}}),n(M)}},[n]),v=k.useCallback(y=>{const N=y.target.value;w(N),!f.current&&n&&n(y)},[n]),E=k.useCallback(y=>{f.current||o&&o(y)},[o]),{loadingactions:O,formdata:_,...I}=c;if(u)return d.jsx("input",{ref:p,type:l,className:r,onChange:n,checked:g,defaultChecked:h,value:a,...I});const C=a!==void 0?{value:m}:{defaultValue:s};return d.jsx("input",{ref:p,type:l,className:r,onChange:v,onKeyPress:E,onCompositionStart:x,onCompositionEnd:A,...C,...I})});xt.displayName="Input";const Ga=k.forwardRef(({accept:e,maxSize:t,onChange:r,onError:n,buttonText:o="Browse",placeholder:a="No file selected",className:s="",disabled:l,...g},h)=>{const c=k.useRef(null),i=h||c,[u,f]=k.useState(""),p={},m={};Object.entries(g).forEach(([v,E])=>{v.startsWith("data-editor-")||v==="id"||v==="onMouseMove"||v==="onMouseLeave"?p[v]=E:m[v]=E});const w=k.useCallback(()=>{!l&&i.current&&i.current.click()},[l,i]),x=k.useCallback(v=>{const E=v.target.files?.[0]||null;if(!E){f(""),r?.(null);return}if(t&&E.size>t*1024*1024){const O=`File size exceeds ${t}MB limit`;n?.(O),i.current&&(i.current.value=""),f("");return}f(E.name),r?.(E)},[t,r,n,i]),A=k.useCallback(v=>{v.stopPropagation(),i.current&&(i.current.value=""),f(""),r?.(null)},[r,i]);return d.jsxs(W,{className:`flex items-center gap-2 ${s}`,...p,children:[d.jsx(xt,{ref:i,type:"file",accept:e,onChange:x,disabled:l,className:"hidden",...m}),d.jsx(Q,{type:"button",onClick:w,disabled:l,className:"px-4 py-2 bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md text-sm font-medium text-gray-700 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed",children:o}),d.jsx(te,{className:"flex-1 text-sm text-gray-600 dark:text-gray-400 truncate",children:u||a}),u&&!l&&d.jsx(Q,{type:"button",onClick:A,className:"p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-200","aria-label":"Clear file",children:d.jsx(fn,{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:d.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})})})]})});Ga.displayName="FileInput";var Je=(e=>(e.User="fa-user",e.Users="fa-users",e.UserCircle="fa-user-circle",e.UserPlus="fa-user-plus",e.UserMinus="fa-user-minus",e.UserShield="fa-user-shield",e.Search="fa-search",e.Edit="fa-edit",e.Pencil="fa-pencil-alt",e.Trash="fa-trash",e.Save="fa-save",e.Plus="fa-plus",e.Minus="fa-minus",e.Check="fa-check",e.Times="fa-times",e.Download="fa-download",e.Upload="fa-upload",e.Copy="fa-copy",e.ExternalLink="fa-external-link-alt",e.Home="fa-home",e.ChevronLeft="fa-chevron-left",e.ChevronRight="fa-chevron-right",e.ChevronUp="fa-chevron-up",e.ChevronDown="fa-chevron-down",e.AngleLeft="fa-angle-left",e.AngleRight="fa-angle-right",e.AngleUp="fa-angle-up",e.AngleDown="fa-angle-down",e.ArrowUp="fa-arrow-up",e.ArrowDown="fa-arrow-down",e.ArrowLeft="fa-arrow-left",e.ArrowRight="fa-arrow-right",e.Bars="fa-bars",e.EllipsisVertical="fa-ellipsis-v",e.EllipsisHorizontal="fa-ellipsis-h",e.CheckCircle="fa-check-circle",e.TimesCircle="fa-times-circle",e.ExclamationCircle="fa-exclamation-circle",e.ExclamationTriangle="fa-exclamation-triangle",e.InfoCircle="fa-info-circle",e.QuestionCircle="fa-question-circle",e.XCircle="fa-times-circle",e.ShoppingCart="fa-shopping-cart",e.ShoppingBag="fa-shopping-bag",e.CreditCard="fa-credit-card",e.Tag="fa-tag"Line truncated
var SirsoftBasic=(function(J,d,C,Rt){"use strict";function Gc(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const r in e)if(r!=="default"){const n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:()=>e[r]})}}return t.default=e,Object.freeze(t)}const E=Gc(C),jc=()=>window.G7Core,Q=C.forwardRef(({children:e,variant:t="primary",size:r="md",className:n="",...o},a)=>{const s="inline-flex items-center justify-center",l=jc()?.style?.mergeClasses?.(s,n)??`${s} ${n}`;return d.jsx("button",{ref:a,className:l,...o,children:e})});Q.displayName="Button";const W=C.forwardRef(({children:e,className:t="",...r},n)=>d.jsx("div",{ref:n,className:t,...r,children:e})),re=({children:e,className:t="",...r})=>d.jsx("span",{className:t,...r,children:e}),mn=({children:e,className:t="",...r})=>d.jsx("svg",{className:t,...r,children:e}),_t=C.forwardRef(({label:e,error:t,className:r="",onChange:n,onKeyPress:o,value:a,defaultValue:s,type:l="text",checked:f,defaultChecked:h,...c},i)=>{const u=l==="radio"||l==="checkbox",g=C.useRef(!1),p=C.useRef(null);C.useImperativeHandle(i,()=>p.current);const[m,v]=C.useState(a??s??"");C.useEffect(()=>{!u&&!g.current&&a!==void 0&&v(a)},[a,u]);const x=C.useCallback(()=>{g.current=!0},[]),M=C.useCallback(y=>{if(g.current=!1,n){const N=y.target.value;v(N);const D=new Event("change",{bubbles:!0});Object.defineProperty(D,"target",{writable:!1,value:{value:N}}),Object.defineProperty(D,"currentTarget",{writable:!1,value:{value:N}}),n(D)}},[n]),w=C.useCallback(y=>{const N=y.target.value;v(N),!g.current&&n&&n(y)},[n]),T=C.useCallback(y=>{g.current||o&&o(y)},[o]),{loadingactions:A,formdata:_,...I}=c;if(u)return d.jsx("input",{ref:p,type:l,className:r,onChange:n,checked:f,defaultChecked:h,value:a,...I});const k=a!==void 0?{value:m}:{defaultValue:s};return d.jsx("input",{ref:p,type:l,className:r,onChange:w,onKeyPress:T,onCompositionStart:x,onCompositionEnd:M,...k,...I})});_t.displayName="Input";const Va=C.forwardRef(({accept:e,maxSize:t,onChange:r,onError:n,buttonText:o="Browse",placeholder:a="No file selected",className:s="",disabled:l,...f},h)=>{const c=C.useRef(null),i=h||c,[u,g]=C.useState(""),p={},m={};Object.entries(f).forEach(([w,T])=>{w.startsWith("data-editor-")||w==="id"||w==="onMouseMove"||w==="onMouseLeave"?p[w]=T:m[w]=T});const v=C.useCallback(()=>{!l&&i.current&&i.current.click()},[l,i]),x=C.useCallback(w=>{const T=w.target.files?.[0]||null;if(!T){g(""),r?.(null);return}if(t&&T.size>t*1024*1024){const A=`File size exceeds ${t}MB limit`;n?.(A),i.current&&(i.current.value=""),g("");return}g(T.name),r?.(T)},[t,r,n,i]),M=C.useCallback(w=>{w.stopPropagation(),i.current&&(i.current.value=""),g(""),r?.(null)},[r,i]);return d.jsxs(W,{className:`flex items-center gap-2 ${s}`,...p,children:[d.jsx(_t,{ref:i,type:"file",accept:e,onChange:x,disabled:l,className:"hidden",...m}),d.jsx(Q,{type:"button",onClick:v,disabled:l,className:"px-4 py-2 bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md text-sm font-medium text-gray-700 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed",children:o}),d.jsx(re,{className:"flex-1 text-sm text-gray-600 dark:text-gray-400 truncate",children:u||a}),u&&!l&&d.jsx(Q,{type:"button",onClick:M,className:"p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-200","aria-label":"Clear file",children:d.jsx(mn,{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:d.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})})})]})});Va.displayName="FileInput";var Re=(e=>(e.User="fa-user",e.Users="fa-users",e.UserCircle="fa-user-circle",e.UserPlus="fa-user-plus",e.UserMinus="fa-user-minus",e.UserShield="fa-user-shield",e.Search="fa-search",e.Edit="fa-edit",e.Pencil="fa-pencil-alt",e.Trash="fa-trash",e.Save="fa-save",e.Plus="fa-plus",e.Minus="fa-minus",e.Check="fa-check",e.Times="fa-times",e.Download="fa-download",e.Upload="fa-upload",e.Copy="fa-copy",e.ExternalLink="fa-external-link-alt",e.Home="fa-home",e.ChevronLeft="fa-chevron-left",e.ChevronRight="fa-chevron-right",e.ChevronUp="fa-chevron-up",e.ChevronDown="fa-chevron-down",e.AngleLeft="fa-angle-left",e.AngleRight="fa-angle-right",e.AngleUp="fa-angle-up",e.AngleDown="fa-angle-down",e.ArrowUp="fa-arrow-up",e.ArrowDown="fa-arrow-down",e.ArrowLeft="fa-arrow-left",e.ArrowRight="fa-arrow-right",e.Bars="fa-bars",e.EllipsisVertical="fa-ellipsis-v",e.EllipsisHorizontal="fa-ellipsis-h",e.CheckCircle="fa-check-circle",e.TimesCircle="fa-times-circle",e.ExclamationCircle="fa-exclamation-circle",e.ExclamationTriangle="fa-exclamation-triangle",e.InfoCircle="fa-info-circle",e.QuestionCircle="fa-question-circle",e.XCircle="fa-times-circle",e.ShoppingCart="fa-shopping-cart",e.ShoppingBag="fa-shopping-bag",e.CreditCard="fa-credit-card",e.Tag="fa-tag"Line truncated
w-full px-4 py-2 text-left hover:bg-gray-50 dark:hover:bg-gray-700 flex items-center gap-3 transition-colors
${g==="auto"?"bg-gray-50 dark:bg-gray-700":""}
`,children:[d.jsx(ce,{name:Je.Settings,className:"w-5 h-5 text-gray-600 dark:text-gray-400"}),d.jsx(te,{className:"flex-1 text-left text-gray-900 dark:text-white",children:r}),g==="auto"&&d.jsx(ce,{name:Je.Check,className:"w-4 h-4 text-blue-600 dark:text-blue-400 ml-auto"})]}),d.jsxs(Q,{onClick:()=>f("light"),className:`
${f==="auto"?"bg-gray-50 dark:bg-gray-700":""}
`,children:[d.jsx(fe,{name:Re.Settings,className:"w-5 h-5 text-gray-600 dark:text-gray-400"}),d.jsx(re,{className:"flex-1 text-left text-gray-900 dark:text-white",children:r}),f==="auto"&&d.jsx(fe,{name:Re.Check,className:"w-4 h-4 text-blue-600 dark:text-blue-400 ml-auto"})]}),d.jsxs(Q,{onClick:()=>g("light"),className:`
w-full px-4 py-2 text-left hover:bg-gray-50 dark:hover:bg-gray-700 flex items-center gap-3 transition-colors
${g==="light"?"bg-gray-50 dark:bg-gray-700":""}
`,children:[d.jsx(ce,{name:Je.Sun,className:"w-5 h-5 text-gray-600 dark:text-gray-400"}),d.jsx(te,{className:"flex-1 text-left text-gray-900 dark:text-white",children:n}),g==="light"&&d.jsx(ce,{name:Je.Check,className:"w-4 h-4 text-blue-600 dark:text-blue-400 ml-auto"})]}),d.jsxs(Q,{onClick:()=>f("dark"),className:`
${f==="light"?"bg-gray-50 dark:bg-gray-700":""}
`,children:[d.jsx(fe,{name:Re.Sun,className:"w-5 h-5 text-gray-600 dark:text-gray-400"}),d.jsx(re,{className:"flex-1 text-left text-gray-900 dark:text-white",children:n}),f==="light"&&d.jsx(fe,{name:Re.Check,className:"w-4 h-4 text-blue-600 dark:text-blue-400 ml-auto"})]}),d.jsxs(Q,{onClick:()=>g("dark"),className:`
w-full px-4 py-2 text-left hover:bg-gray-50 dark:hover:bg-gray-700 flex items-center gap-3 transition-colors
${g==="dark"?"bg-gray-50 dark:bg-gray-700":""}
`,children:[d.jsx(ce,{name:Je.Moon,className:"w-5 h-5 text-gray-600 dark:text-gray-400"}),d.jsx(te,{className:"flex-1 text-left text-gray-900 dark:text-white",children:o}),g==="dark"&&d.jsx(ce,{name:Je.Check,className:"w-4 h-4 text-blue-600 dark:text-blue-400 ml-auto"})]})]})})]})},qc=Object.freeze(Object.defineProperty({__proto__:null,ThemeToggle:hn,default:hn},Symbol.toStringTag,{value:"Module"})),Za={xs:"w-6 h-6 text-xs",sm:"w-8 h-8 text-sm",md:"w-10 h-10 text-base",lg:"w-12 h-12 text-lg",xl:"w-16 h-16 text-xl","2xl":"w-24 h-24 text-2xl","3xl":"w-32 h-32 text-3xl","4xl":"w-40 h-40 text-4xl","5xl":"w-48 h-48 text-5xl"},Zc="rounded-full overflow-hidden flex-shrink-0 border border-gray-200 dark:border-gray-700",Qc="grayscale opacity-50",co={normal:"bg-gradient-to-br from-blue-500 to-purple-600",withdrawn:"bg-gray-300 dark:bg-gray-600",guest:"bg-gray-200 dark:bg-gray-700"},$r=({author:e,name:t,avatar:r,size:n="md",className:o="",text:a,isWithdrawn:s=!1,isGuest:l=!1,id:g,editorAttrs:h})=>{const c=r??e?.avatar,i=a??t??e?.name??"?",u=s||e?.status==="withdrawn",f=l||e?.is_guest||!1,p=k.useMemo(()=>[Za[n]||Za.md,Zc,u?Qc:"",o].filter(Boolean).join(" "),[n,u,o]),m=f?co.guest:u?co.withdrawn:co.normal,w=()=>f?d.jsx(W,{className:`w-full h-full flex items-center justify-center ${m}`,children:d.jsx(ce,{name:"user",className:"text-gray-400 dark:text-gray-500"})}):u?d.jsx(W,{className:`w-full h-full flex items-center justify-center ${m}`,children:d.jsx(ce,{name:"user",className:"text-gray-500 dark:text-gray-400"})}):d.jsx(W,{className:`w-full h-full flex items-center justify-center text-white font-semibold ${m}`,children:i.charAt(0).toUpperCase()});return d.jsx(W,{className:p,id:g,...h,children:c&&!f&&!u?d.jsx(Lt,{src:c,alt:i,className:"w-full h-full object-cover"}):w()})},Jc=Object.freeze(Object.defineProperty({__proto__:null,Avatar:$r},Symbol.toStringTag,{value:"Module"})),Rc=window.G7Core?.createLogger?.("Comp:SlotContainer")??{log:(...e)=>console.log("[Comp:SlotContainer]",...e),warn:(...e)=>console.warn("[Comp:SlotContainer]",...e),error:(...e)=>console.error("[Comp:SlotContainer]",...e)};function Qa(e,t){return t&&e&&typeof e.id=="string"&&e.id.length>0?{...e,id:`${e.id}__${t}`}:e}const pn=({slotId:e,className:t="",emptyContent:r,style:n,id:o,children:a})=>{const[s,l]=k.useState([]),[,g]=k.useState({}),h=k.useCallback(()=>{const p=window.__slotContextValue;if(p)return p;const m=window.G7Core;return m&&m.getSlotContext?.()||null},[]),c=k.useCallback(()=>{const p=h();p&&p.isEnabled&&l(p.getSlotComponents(e))},[e,h]);k.useEffect(()=>{const p=h();return!p||!p.isEnabled?void 0:(c(),p.subscribeToSlot(e,()=>{c(),g({})}))},[e,h,c]);const i=k.useCallback(()=>{const p=window.G7Core;return p?p.getDynamicRenderer?.():null},[]);if(s.length===0)return r?d.jsx(W,{className:t,style:n,id:o,children:r}):a?d.jsx(W,{className:t,style:n,id:o,children:a}):null;const u=i(),f=window.G7Core;return!u||!f?(Rc.error("G7Core or DynamicRenderer not available"),null):d.jsxs(W,{className:t,style:n,id:o,children:[s.map(p=>{const{componentDef:m,dataContext:w,parentFormContext:x,getParentComponentContext:A,translationContext:v}=p,E=Qa(m,o);return d.jsx(u,{componentDef:E,dataContext:w,translationContext:v,registry:f.getComponentRegistry(),bindingEngine:f.getDataBindingEngine(),translationEngine:f.getTranslationEngine(),actionDispatcher:f.getActionDispatcher(),parentComponentContext:A?.(),parentFormContextProp:x,isRootRenderer:!1},E.id||`slot-${e}-${p.order}`)}),a]})},ed=Object.freeze(Object.defineProperty({__proto__:null,SlotContainer:pn,default:pn,scopeSlotChildDef:Qa},Symbol.toStringTag,{value:"Module"})),mn=({notifications:e=[],unreadCount:t=0,hasMore:r=!1,loading:n=!1,titleText:o="알림",emptyText:a="알림이 없습니다.",markAllReadText:s="모두 읽음",deleteAllText:l="모두 삭제",unreadOnlyText:g="안 읽은 알림만",unreadOnly:h=!1,onNotificationClick:c,onClose:i,onLoadMore:u,onMarkAllRead:f,onDeleteAll:p,onDelete:m,onUnreadOnlyToggle:w,dropdownAlign:x="right",className:A="",id:v,editorAttrs:E})=>{const[O,_]=k.useState(!1),I=k.useRef(null),C=k.useRef(null),y=k.useRef(null),N=k.useRef(null),M=k.useRef(new Set),P=k.useRef(u),D=k.useRef(r),L=k.useRef(n),$=k.useRef(e.length),S=k.useRef(-1);k.useEffect(()=>{P.current=u,D.current=r,L.current=n,$.current=e.length}),k.useEffect(()=>{if(!N.current||!y.current||!O)return;S.current=-1;const G=new IntersectionObserver(([Y])=>{Y.isIntersecting&&(L.current||!D.current||S.current!==$.current&&(S.current=$.current,P.current?.()))},{root:y.current,threshold:.1});return G.observe(N.current),()=>G.disconnect()},[O]),k.useEffect(()=>{if(!y.current||!O)return;const G=new IntersectionObserver(B=>{B.forEach(V=>{const j=V.target.getAttribute("data-notification-id"),H=V.target.getAttribute("data-unread")==="true";j&&H&&V.isIntersecting&&M.current.add(j)})},{root:y.current,threshold:.5});return y.current.querySelectorAll("[data-notification-id]").forEach(B=>G.observe(B)),()=>G.disconnect()},[O, Line truncated
`+wt),Ge&&bn([P,D,L],Qt=>{wt=Hr(wt,Qt," ")}),E&&Le?E.createHTML(wt):wt},t.setConfig=function(){let ge=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};qe(ge),Me=!0},t.clearConfig=function(){Be=null,Me=!1},t.isValidAttribute=function(ge,z,Z){Be||qe({});const ie=Fe(ge),Ye=Fe(z);return _c(ie,Ye,Z)},t.addHook=function(ge,z){typeof z=="function"&&zr(M[ge],z)},t.removeHook=function(ge,z){if(z!==void 0){const Z=ud(M[ge],z);return Z===-1?void 0:fd(M[ge],Z,1)[0]}return os(M[ge])},t.removeHooks=function(ge){M[ge]=[]},t.removeAllHooks=function(){M=fs()},t}var hs=gs();const Ad=()=>{const e=()=>{const n=window.G7Core?.state?.get?.();return n&&n.preferredCurrency||"KRW"},[t,r]=k.useState(e);return k.useEffect(()=>{const n=window.G7Core?.state?.subscribe;if(r(e()),typeof n!="function")return;const o=n(a=>{r(a&&a.preferredCurrency||"KRW")});return typeof o=="function"?o:void 0},[]),t},Md=e=>{window.G7Core?.dispatch?.({handler:"navigate",params:{path:e}})},Od=e=>{const t=Math.round(e*2)/2;return[1,2,3,4,5].map(r=>t>=r?"full":t>=r-.5?"half":"empty")},ps=({product:e,onClick:t,shopBase:r="/shop",className:n="",id:o,editorAttrs:a})=>{const s=Ad(),l=A=>{const v=`multi_currency_${A}`,E=e[v];if(E&&E[s])return E[s].formatted;const O=`${A}_formatted`;return e[O]},g=e.name_localized??(typeof e.name=="string"?e.name:"")??"",h=l("selling_price"),c=l("list_price"),i=e.discount_rate&&e.discount_rate>0,u=e.sales_status&&e.sales_status!=="on_sale",f=e.labels??[],p=A=>hs.sanitize(A,{ALLOWED_TAGS:["mark"],ALLOWED_ATTR:[]}),m=e.name_highlighted,w=e.description_highlighted??e.short_description,x=()=>{t?t(e.id):Md(`${r==="/"?"":r}/products/${e.id}`)};return d.jsxs(Q,{onClick:x,className:`block w-full text-left group bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden hover:shadow-lg transition-shadow cursor-pointer ${n}`,id:o,...a,children:[d.jsxs(W,{className:"relative aspect-square overflow-hidden bg-gray-100 dark:bg-gray-700",children:[d.jsx(Lt,{src:e.thumbnail_url,alt:g,className:"w-full h-full object-cover group-hover:scale-105 transition-transform duration-200",loading:"lazy"}),u&&d.jsx(W,{className:"absolute inset-0 bg-black/50 flex items-center justify-center",children:d.jsx(te,{className:`text-lg font-bold ${e.sales_status==="sold_out"?"text-red-300":e.sales_status==="suspended"?"text-amber-300":"text-blue-300"}`,style:{textShadow:"0 1px 4px rgba(0,0,0,0.6)"},children:e.sales_status_label??e.sales_status})}),i&&e.sales_status!=="sold_out"&&e.sales_status!=="suspended"&&d.jsxs(te,{className:"absolute top-2 left-2 px-2 py-1 bg-red-500 text-white text-xs font-bold rounded",children:[e.discount_rate,"%"]}),f.length>0&&d.jsx(W,{className:"absolute bottom-2 right-2 flex gap-1 flex-wrap justify-end",children:f.map((A,v)=>d.jsx(te,{className:"text-xs text-white font-medium px-1.5 py-0.5 rounded",style:{backgroundColor:A.color||"#6b7280"},children:A.name},v))})]}),d.jsxs(W,{className:"p-4",children:[d.jsxs(W,{className:"flex items-center gap-1.5 flex-wrap",children:[e.primary_category&&d.jsx(te,{className:"inline-block text-xs font-medium text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/30 px-2 py-0.5 rounded",children:e.primary_category}),e.brand_name&&d.jsx(te,{className:"text-xs text-gray-500 dark:text-gray-400",children:e.brand_name})]}),m?d.jsx(W,{className:"mt-1 font-medium text-gray-900 dark:text-white line-clamp-1 [&_mark]:bg-yellow-200 [&_mark]:dark:bg-yellow-500/40 [&_mark]:px-0.5 [&_mark]:rounded",dangerouslySetInnerHTML:{__html:p(m)}}):d.jsx(gn,{className:"mt-1 font-medium text-gray-900 dark:text-white line-clamp-1",children:g}),w&&d.jsx(W,{className:"mt-1 text-sm text-gray-600 dark:text-gray-400 line-clamp-2 [&_mark]:bg-yellow-200 [&_mark]:dark:bg-yellow-500/40 [&_mark]:px-0.5 [&_mark]:rounded",dangerouslySetInnerHTML:{__html:p(w)}}),d.jsxs(W,{className:"mt-1.5 flex items-center gap-1",children:[Od(e.rating_avg??0).map((A,v)=>d.jsxs(te,{className:`text-xs ${A==="empty"?"text-gray-300 dark:text-gray-600":"text-yellow-400"}`,children:[A==="full"&&d.jsx("i",{className:"fa-solid fa-star"}),A==="half"&&d.jsx("i",{className:"fa-solid fa-star-half-stroke"}),A==="empty"&&d.jsx("i",{className:"fa-regular fa-star"})]},v)),d.jsx(te,{className:"text-xs text-gray-600 dark:text-gray-400 ml-0.5",children:(e.rating_avg??0).toFixed(1)}),d.jsxs(te,{className:"text-xs text-gray-400 dark:text-gray-500",children:["(",e.review_count??0,")"]})]}),d.jsxs(W,{className:"mt-2 flex items-baseline gap-2",children:[d.jsx(te,{className:"font-bold text-gray-900 dark:text-white",children:h}),c&&i&&d.jsx(te,{className:"text-sm text-gray-500 dark:text-gray-400 line-through",children:c})]})]})]})},Id=Object.freeze(Object.defineProperty({__proto__:null,default:ps},Symbol.toStringTag,{value:"Module"})),ms="carousel",Wr="controller",Dd="navigation",Ld="no-scroll",wo="portal",Pd="root",bs="toolbar",Fd="counter",Kr="fullscreen",ys="slideshow",Vr="thumbnails",vs="zoom",vr="loading",xo="playing",Yr="error",X Line truncated
${f==="dark"?"bg-gray-50 dark:bg-gray-700":""}
`,children:[d.jsx(fe,{name:Re.Moon,className:"w-5 h-5 text-gray-600 dark:text-gray-400"}),d.jsx(re,{className:"flex-1 text-left text-gray-900 dark:text-white",children:o}),f==="dark"&&d.jsx(fe,{name:Re.Check,className:"w-4 h-4 text-blue-600 dark:text-blue-400 ml-auto"})]})]})})]})},sd=Object.freeze(Object.defineProperty({__proto__:null,ThemeToggle:yn,default:yn},Symbol.toStringTag,{value:"Module"})),ts={xs:"w-6 h-6 text-xs",sm:"w-8 h-8 text-sm",md:"w-10 h-10 text-base",lg:"w-12 h-12 text-lg",xl:"w-16 h-16 text-xl","2xl":"w-24 h-24 text-2xl","3xl":"w-32 h-32 text-3xl","4xl":"w-40 h-40 text-4xl","5xl":"w-48 h-48 text-5xl"},ld="rounded-full overflow-hidden flex-shrink-0 border border-gray-200 dark:border-gray-700",id="grayscale opacity-50",ho={normal:"bg-gradient-to-br from-blue-500 to-purple-600",withdrawn:"bg-gray-300 dark:bg-gray-600",guest:"bg-gray-200 dark:bg-gray-700"},Kr=({author:e,name:t,avatar:r,size:n="md",className:o="",text:a,isWithdrawn:s=!1,isGuest:l=!1,id:f,editorAttrs:h})=>{const c=r??e?.avatar,i=a??t??e?.name??"?",u=s||e?.status==="withdrawn",g=l||e?.is_guest||!1,p=C.useMemo(()=>[ts[n]||ts.md,ld,u?id:"",o].filter(Boolean).join(" "),[n,u,o]),m=g?ho.guest:u?ho.withdrawn:ho.normal,v=()=>g?d.jsx(W,{className:`w-full h-full flex items-center justify-center ${m}`,children:d.jsx(fe,{name:"user",className:"text-gray-400 dark:text-gray-500"})}):u?d.jsx(W,{className:`w-full h-full flex items-center justify-center ${m}`,children:d.jsx(fe,{name:"user",className:"text-gray-500 dark:text-gray-400"})}):d.jsx(W,{className:`w-full h-full flex items-center justify-center text-white font-semibold ${m}`,children:i.charAt(0).toUpperCase()});return d.jsx(W,{className:p,id:f,...h,children:c&&!g&&!u?d.jsx(Ht,{src:c,alt:i,className:"w-full h-full object-cover"}):v()})},cd=Object.freeze(Object.defineProperty({__proto__:null,Avatar:Kr},Symbol.toStringTag,{value:"Module"})),dd=window.G7Core?.createLogger?.("Comp:SlotContainer")??{log:(...e)=>console.log("[Comp:SlotContainer]",...e),warn:(...e)=>console.warn("[Comp:SlotContainer]",...e),error:(...e)=>console.error("[Comp:SlotContainer]",...e)};function rs(e,t){return t&&e&&typeof e.id=="string"&&e.id.length>0?{...e,id:`${e.id}__${t}`}:e}const vn=({slotId:e,className:t="",emptyContent:r,style:n,id:o,children:a})=>{const[s,l]=C.useState([]),[,f]=C.useState({}),h=C.useCallback(()=>{const p=window.__slotContextValue;if(p)return p;const m=window.G7Core;return m&&m.getSlotContext?.()||null},[]),c=C.useCallback(()=>{const p=h();p&&p.isEnabled&&l(p.getSlotComponents(e))},[e,h]);C.useEffect(()=>{const p=h();return!p||!p.isEnabled?void 0:(c(),p.subscribeToSlot(e,()=>{c(),f({})}))},[e,h,c]);const i=C.useCallback(()=>{const p=window.G7Core;return p?p.getDynamicRenderer?.():null},[]);if(s.length===0)return r?d.jsx(W,{className:t,style:n,id:o,children:r}):a?d.jsx(W,{className:t,style:n,id:o,children:a}):null;const u=i(),g=window.G7Core;return!u||!g?(dd.error("G7Core or DynamicRenderer not available"),null):d.jsxs(W,{className:t,style:n,id:o,children:[s.map(p=>{const{componentDef:m,dataContext:v,parentFormContext:x,getParentComponentContext:M,translationContext:w}=p,T=rs(m,o);return d.jsx(u,{componentDef:T,dataContext:v,translationContext:w,registry:g.getComponentRegistry(),bindingEngine:g.getDataBindingEngine(),translationEngine:g.getTranslationEngine(),actionDispatcher:g.getActionDispatcher(),parentComponentContext:M?.(),parentFormContextProp:x,isRootRenderer:!1},T.id||`slot-${e}-${p.order}`)}),a]})},ud=Object.freeze(Object.defineProperty({__proto__:null,SlotContainer:vn,default:vn,scopeSlotChildDef:rs},Symbol.toStringTag,{value:"Module"})),wn=({notifications:e=[],unreadCount:t=0,hasMore:r=!1,loading:n=!1,titleText:o="알림",emptyText:a="알림이 없습니다.",markAllReadText:s="모두 읽음",deleteAllText:l="모두 삭제",unreadOnlyText:f="안 읽은 알림만",unreadOnly:h=!1,onNotificationClick:c,onClose:i,onLoadMore:u,onMarkAllRead:g,onDeleteAll:p,onDelete:m,onUnreadOnlyToggle:v,dropdownAlign:x="right",className:M="",id:w,editorAttrs:T})=>{const[A,_]=C.useState(!1),I=C.useRef(null),k=C.useRef(null),y=C.useRef(null),N=C.useRef(null),D=C.useRef(new Set),P=C.useRef(u),O=C.useRef(r),L=C.useRef(n),$=C.useRef(e.length),S=C.useRef(-1);C.useEffect(()=>{P.current=u,O.current=r,L.current=n,$.current=e.length}),C.useEffect(()=>{if(!N.current||!y.current||!A)return;S.current=-1;const G=new IntersectionObserver(([Y])=>{Y.isIntersecting&&(L.current||!O.current||S.current!==$.current&&(S.current=$.current,P.current?.()))},{root:y.current,threshold:.1});return G.observe(N.current),()=>G.disconnect()},[A]),C.useEffect(()=>{if(!y.current||!A)return;const G=new IntersectionObserver(B=>{B.forEach(V=>{const j=V.target.getAttribute("data-notification-id"),H=V.target.getAttribute("data-unread")==="true";j&&H&&V.isIntersecting&&D.current.add(j)})},{root:y.current,threshold:.5});return y.current.querySelectorAll("[data-notification-id]").forEach(B=>G.observe(B)),()=>G.disconnect()},[A, Line truncated
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function kd(e,t){return vd(e)||wd(e,t)||Cd(e,t)||xd()}function Cd(e,t){if(e){if(typeof e=="string")return ls(e,t);var r={}.toString.call(e).slice(8,-1);return r==="Object"&&e.constructor&&(r=e.constructor.name),r==="Map"||r==="Set"?Array.from(e):r==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?ls(e,t):void 0}}const is=Object.entries,cs=Object.setPrototypeOf,Sd=Object.isFrozen,_d=Object.getPrototypeOf,Ed=Object.getOwnPropertyDescriptor;let pt=Object.freeze,Dt=Object.seal,wr=Object.create,ds=typeof Reflect<"u"&&Reflect,po=ds.apply,mo=ds.construct;pt||(pt=function(t){return t}),Dt||(Dt=function(t){return t}),po||(po=function(t,r){for(var n=arguments.length,o=new Array(n>2?n-2:0),a=2;a<n;a++)o[a-2]=arguments[a];return t.apply(r,o)}),mo||(mo=function(t){for(var r=arguments.length,n=new Array(r>1?r-1:0),o=1;o<r;o++)n[o-1]=arguments[o];return new t(...n)});const xr=qe(Array.prototype.forEach),Td=qe(Array.prototype.lastIndexOf),us=qe(Array.prototype.pop),kr=qe(Array.prototype.push),Nd=qe(Array.prototype.splice),mt=Array.isArray,Vr=qe(String.prototype.toLowerCase),bo=qe(String.prototype.toString),fs=qe(String.prototype.match),Cr=qe(String.prototype.replace),gs=qe(String.prototype.indexOf),Ad=qe(String.prototype.trim),Md=qe(Number.prototype.toString),Od=qe(Boolean.prototype.toString),hs=typeof BigInt>"u"?null:qe(BigInt.prototype.toString),ps=typeof Symbol>"u"?null:qe(Symbol.prototype.toString),Ze=qe(Object.prototype.hasOwnProperty),Yr=qe(Object.prototype.toString),dt=qe(RegExp.prototype.test),xn=Id(TypeError);function qe(e){return function(t){t instanceof RegExp&&(t.lastIndex=0);for(var r=arguments.length,n=new Array(r>1?r-1:0),o=1;o<r;o++)n[o-1]=arguments[o];return po(e,t,n)}}function Id(e){return function(){for(var t=arguments.length,r=new Array(t),n=0;n<t;n++)r[n]=arguments[n];return mo(e,r)}}function Ee(e,t){let r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:Vr;if(cs&&cs(e,null),!mt(t))return e;let n=t.length;for(;n--;){let o=t[n];if(typeof o=="string"){const a=r(o);a!==o&&(Sd(t)||(t[n]=a),o=a)}e[o]=!0}return e}function Dd(e){for(let t=0;t<e.length;t++)Ze(e,t)||(e[t]=null);return e}function yt(e){const t=wr(null);for(const n of is(e)){var r=kd(n,2);const o=r[0],a=r[1];Ze(e,o)&&(mt(a)?t[o]=Dd(a):a&&typeof a=="object"&&a.constructor===Object?t[o]=yt(a):t[o]=a)}return t}function Ld(e){switch(typeof e){case"string":return e;case"number":return Md(e);case"boolean":return Od(e);case"bigint":return hs?hs(e):"0";case"symbol":return ps?ps(e):"Symbol()";case"undefined":return Yr(e);case"function":case"object":{if(e===null)return Yr(e);const t=e,r=Sr(t,"toString");if(typeof r=="function"){const n=r(t);return typeof n=="string"?n:Yr(n)}return Yr(e)}default:return Yr(e)}}function Sr(e,t){for(;e!==null;){const n=Ed(e,t);if(n){if(n.get)return qe(n.get);if(typeof n.value=="function")return qe(n.value)}e=_d(e)}function r(){return null}return r}function Pd(e){try{return dt(e,""),!0}catch{return!1}}const ms=pt(["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","search","section","select","shadow","slot","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr"]),yo=pt(["svg","a","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","circle","clippath","defs","desc","ellipse","enterkeyhint","exportparts","filter","font","g","glyph","glyphref","hkern","image","inputmode","line","lineargradient","marker","mask","metadata","mpath","part","path","pattern","polygon","polyline","radialgradient","rect","stop","style","switch","symbol","text","textpath","title","tref","tspan","view","vkern"]),vo=pt(["feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence"]),Fd=pt(["animate","color-profile","cursor","discard","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignobject","hatch","hatchpath","mesh","meshgradient","meshpatch","meshrow","missing-glyph","s Line truncated
`+St),ye&&xr([L,$,S],Ut=>{St=Cr(St,Ut," ")}),A&&te?A.createHTML(St):St},t.setConfig=function(){let he=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};Ct(he),ke=!0},t.clearConfig=function(){Mt=null,ke=!1},t.isValidAttribute=function(he,F,Z){Mt||Ct({});const ae=Pe(he),Ge=Pe(F);return Fc(ae,Ge,Z)},t.addHook=function(he,F){typeof F=="function"&&kr(O[he],F)},t.removeHook=function(he,F){if(F!==void 0){const Z=Td(O[he],F);return Z===-1?void 0:Nd(O[he],Z,1)[0]}return us(O[he])},t.removeHooks=function(he){O[he]=[]},t.removeAllHooks=function(){O=xs()},t}var Cs=ks();const Zd=()=>{const e=()=>{const n=window.G7Core?.state?.get?.();return n&&n.preferredCurrency||"KRW"},[t,r]=C.useState(e);return C.useEffect(()=>{const n=window.G7Core?.state?.subscribe;if(r(e()),typeof n!="function")return;const o=n(a=>{r(a&&a.preferredCurrency||"KRW")});return typeof o=="function"?o:void 0},[]),t},qd=e=>{window.G7Core?.dispatch?.({handler:"navigate",params:{path:e}})},Qd=e=>{const t=Math.round(e*2)/2;return[1,2,3,4,5].map(r=>t>=r?"full":t>=r-.5?"half":"empty")},Ss=({product:e,onClick:t,shopBase:r="/shop",className:n="",id:o,editorAttrs:a})=>{const s=Zd(),l=M=>{const w=`multi_currency_${M}`,T=e[w];if(T&&T[s])return T[s].formatted;const A=`${M}_formatted`;return e[A]},f=e.name_localized??(typeof e.name=="string"?e.name:"")??"",h=l("selling_price"),c=l("list_price"),i=e.discount_rate&&e.discount_rate>0,u=e.sales_status&&e.sales_status!=="on_sale",g=e.labels??[],p=M=>Cs.sanitize(M,{ALLOWED_TAGS:["mark"],ALLOWED_ATTR:[]}),m=e.name_highlighted,v=e.description_highlighted??e.short_description,x=()=>{t?t(e.id):qd(`${r==="/"?"":r}/products/${e.id}`)};return d.jsxs(Q,{onClick:x,className:`block w-full text-left group bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden hover:shadow-lg transition-shadow cursor-pointer ${n}`,id:o,...a,children:[d.jsxs(W,{className:"relative aspect-square overflow-hidden bg-gray-100 dark:bg-gray-700",children:[d.jsx(Ht,{src:e.thumbnail_url,alt:f,className:"w-full h-full object-cover group-hover:scale-105 transition-transform duration-200",loading:"lazy"}),u&&d.jsx(W,{className:"absolute inset-0 bg-black/50 flex items-center justify-center",children:d.jsx(re,{className:`text-lg font-bold ${e.sales_status==="sold_out"?"text-red-300":e.sales_status==="suspended"?"text-amber-300":"text-blue-300"}`,style:{textShadow:"0 1px 4px rgba(0,0,0,0.6)"},children:e.sales_status_label??e.sales_status})}),i&&e.sales_status!=="sold_out"&&e.sales_status!=="suspended"&&d.jsxs(re,{className:"absolute top-2 left-2 px-2 py-1 bg-red-500 text-white text-xs font-bold rounded",children:[e.discount_rate,"%"]}),g.length>0&&d.jsx(W,{className:"absolute bottom-2 right-2 flex gap-1 flex-wrap justify-end",children:g.map((M,w)=>d.jsx(re,{className:"text-xs text-white font-medium px-1.5 py-0.5 rounded",style:{backgroundColor:M.color||"#6b7280"},children:M.name},w))})]}),d.jsxs(W,{className:"p-4",children:[d.jsxs(W,{className:"flex items-center gap-1.5 flex-wrap",children:[e.primary_category&&d.jsx(re,{className:"inline-block text-xs font-medium text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/30 px-2 py-0.5 rounded",children:e.primary_category}),e.brand_name&&d.jsx(re,{className:"text-xs text-gray-500 dark:text-gray-400",children:e.brand_name})]}),m?d.jsx(W,{className:"mt-1 font-medium text-gray-900 dark:text-white line-clamp-1 [&_mark]:bg-yellow-200 [&_mark]:dark:bg-yellow-500/40 [&_mark]:px-0.5 [&_mark]:rounded",dangerouslySetInnerHTML:{__html:p(m)}}):d.jsx(bn,{className:"mt-1 font-medium text-gray-900 dark:text-white line-clamp-1",children:f}),v&&d.jsx(W,{className:"mt-1 text-sm text-gray-600 dark:text-gray-400 line-clamp-2 [&_mark]:bg-yellow-200 [&_mark]:dark:bg-yellow-500/40 [&_mark]:px-0.5 [&_mark]:rounded",dangerouslySetInnerHTML:{__html:p(v)}}),d.jsxs(W,{className:"mt-1.5 flex items-center gap-1",children:[Qd(e.rating_avg??0).map((M,w)=>d.jsxs(re,{className:`text-xs ${M==="empty"?"text-gray-300 dark:text-gray-600":"text-yellow-400"}`,children:[M==="full"&&d.jsx("i",{className:"fa-solid fa-star"}),M==="half"&&d.jsx("i",{className:"fa-solid fa-star-half-stroke"}),M==="empty"&&d.jsx("i",{className:"fa-regular fa-star"})]},w)),d.jsx(re,{className:"text-xs text-gray-600 dark:text-gray-400 ml-0.5",children:(e.rating_avg??0).toFixed(1)}),d.jsxs(re,{className:"text-xs text-gray-400 dark:text-gray-500",children:["(",e.review_count??0,")"]})]}),d.jsxs(W,{className:"mt-2 flex items-baseline gap-2",children:[d.jsx(re,{className:"font-bold text-gray-900 dark:text-white",children:h}),c&&i&&d.jsx(re,{className:"text-sm text-gray-500 dark:text-gray-400 line-through",children:c})]})]})]})},Jd=Object.freeze(Object.defineProperty({__proto__:null,default:Ss},Symbol.toStringTag,{value:"Module"})),_s="carousel",Xr="controller",Rd="navigation",eu="no-scroll",ko="portal",tu="root",Es="toolbar",ru="counter",Zr="fullscreen",Ts="slideshow",qr="thumbnails",Ns="zoom",Er="loading",Co="playing",Qr="error",J Line truncated
inline-flex items-center rounded-full border transition-colors
${g[o]}
${f[o]}
${p?`${u.activeColor} border-transparent`:"border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700"}
`,title:Ml(u.labelKey),children:[d.jsx(te,{className:h[o],children:u.emoji}),d.jsx(te,{children:Ml(u.labelKey)}),f>0&&d.jsx(te,{className:"font-medium",children:f})]},u.type)})})},jf=Object.freeze(Object.defineProperty({__proto__:null,default:Ol},Symbol.toStringTag,{value:"Module"})),Mn=window.G7Core?.createLogger?.("Comp:RichTextEditor")??{log:(...e)=>console.log("[Comp:RichTextEditor]",...e),warn:(...e)=>console.warn("[Comp:RichTextEditor]",...e),error:(...e)=>console.error("[Comp:RichTextEditor]",...e)},St=(e,t)=>window.G7Core?.t?.(e,t)??e,Il=({name:e,initialValue:t="",placeholder:r,onChange:n,imageUploadUrl:o="/api/upload/image",minHeight:a="300px",disabled:s=!1,className:l="",id:g,editorAttrs:h})=>{const c=k.useRef(null),[i,u]=k.useState(t),[f,p]=k.useState(!1),[m,w]=k.useState(!1),[x,A]=k.useState("");k.useEffect(()=>{c.current&&!c.current.innerHTML&&(c.current.innerHTML=t)},[t]),k.useEffect(()=>{n&&n(i)},[i,n]);const v=N=>{Mn.log("Apply format:",N)},E=async N=>{const M=new FormData;M.append("file",N);try{const P=await fetch(o,{method:"POST",body:M,credentials:"include"});if(!P.ok)throw new Error("업로드 실패");const D=await P.json();Mn.log("Image uploaded:",D.url)}catch(P){Mn.error("이미지 업로드 오류:",P)}},O=N=>{const M=N.target.files?.[0];M&&E(M)},_=()=>{x&&(Mn.log("Insert link:",x),w(!1),A(""))},I=[{format:"bold",icon:"B",title:St("editor.toolbar.bold")},{format:"italic",icon:"I",title:St("editor.toolbar.italic")},{format:"underline",icon:"U",title:St("editor.toolbar.underline")},{format:"strike",icon:"S",title:St("editor.toolbar.strike")},{format:"code",icon:"</>",title:St("editor.toolbar.code")}],C=[{format:"h1",label:"H1"},{format:"h2",label:"H2"},{format:"h3",label:"H3"}],y=[{format:"bulletList",icon:"•",title:St("editor.toolbar.bullet_list")},{format:"orderedList",icon:"1.",title:St("editor.toolbar.ordered_list")},{format:"blockquote",icon:"❝",title:St("editor.toolbar.blockquote")}];return d.jsxs(W,{className:`border border-gray-300 dark:border-gray-600 rounded-lg overflow-hidden ${l}`,id:g,...h,children:[d.jsxs(W,{className:"flex flex-wrap items-center gap-1 p-2 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700",children:[d.jsx(W,{className:"flex items-center gap-1 pr-2 border-r border-gray-200 dark:border-gray-700",children:I.map(N=>d.jsx(Q,{type:"button",onClick:()=>v(N.format),disabled:s,className:"w-8 h-8 flex items-center justify-center text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 rounded disabled:opacity-50",title:N.title,children:N.icon},N.format))}),d.jsx(W,{className:"flex items-center gap-1 pr-2 border-r border-gray-200 dark:border-gray-700",children:C.map(N=>d.jsx(Q,{type:"button",onClick:()=>v(N.format),disabled:s,className:"px-2 h-8 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 rounded disabled:opacity-50",children:N.label},N.format))}),d.jsx(W,{className:"flex items-center gap-1 pr-2 border-r border-gray-200 dark:border-gray-700",children:y.map(N=>d.jsx(Q,{type:"button",onClick:()=>v(N.format),disabled:s,className:"w-8 h-8 flex items-center justify-center text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 rounded disabled:opacity-50",title:N.title,children:N.icon},N.format))}),d.jsxs(W,{className:"flex items-center gap-1 pr-2 border-r border-gray-200 dark:border-gray-700",children:[d.jsx(Q,{type:"button",onClick:()=>w(!0),disabled:s,className:"w-8 h-8 flex items-center justify-center text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 rounded disabled:opacity-50",title:St("editor.toolbar.link"),children:"🔗"}),d.jsxs(yr,{className:"w-8 h-8 flex items-center justify-center text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 rounded cursor-pointer",children:["🖼",d.jsx(xt,{type:"file",accept:"image/*",onChange:O,disabled:s,className:"hidden"})]})]}),d.jsxs(Q,{type:"button",onClick:()=>p(!f),disabled:s,className:`px-2 h-8 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 rounded disabled:opacity-50 ${f?"bg-gray-200 dark:bg-gray-700":""}`,children:["</>",St("editor.toolbar.code_view")]})]}),f?d.jsx(no,{value:i,onChange:N=>u(N.target.value),placeholder:r,disabled:s,className:"w-full p-4 bg-gray-900 text-gray-100 font-mono text-sm focus:outline-none resize-none",style:{minHeight:a}}):d.jsx(W,{ref:c,contentEditable:!s,onInput:N=>u(N.currentTarget.innerHTML),className:"p-4 bg-white dark:bg-gray-900 text-gray-900 dark:text-white focus:outline-none prose dark:prose-invert max-w-none",style:{minHeight:a},"data-placeholder":r}),d.jsx(xt,{type:"hidden",name:e,value:i}),m&&d.jsx(W,{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50",children:d.jsxs(W,{className:"bg-white dark:bg-gray-800 rounded-lg p-6 w-96",children:[d.jsx(gn,{className:"text-lg font-medium text-gray-900 dark:text-white mb-4",children:St("edi Line truncated
`,title:Gl(u.labelKey),children:[d.jsx(re,{className:h[o],children:u.emoji}),d.jsx(re,{children:Gl(u.labelKey)}),g>0&&d.jsx(re,{className:"font-medium",children:g})]},u.type)})})},dg=Object.freeze(Object.defineProperty({__proto__:null,default:jl},Symbol.toStringTag,{value:"Module"})),Dn=window.G7Core?.createLogger?.("Comp:RichTextEditor")??{log:(...e)=>console.log("[Comp:RichTextEditor]",...e),warn:(...e)=>console.warn("[Comp:RichTextEditor]",...e),error:(...e)=>console.error("[Comp:RichTextEditor]",...e)},At=(e,t)=>window.G7Core?.t?.(e,t)??e,Bl=({name:e,initialValue:t="",placeholder:r,onChange:n,imageUploadUrl:o="/api/upload/image",minHeight:a="300px",disabled:s=!1,className:l="",id:f,editorAttrs:h})=>{const c=C.useRef(null),[i,u]=C.useState(t),[g,p]=C.useState(!1),[m,v]=C.useState(!1),[x,M]=C.useState("");C.useEffect(()=>{c.current&&!c.current.innerHTML&&(c.current.innerHTML=t)},[t]),C.useEffect(()=>{n&&n(i)},[i,n]);const w=N=>{Dn.log("Apply format:",N)},T=async N=>{const D=new FormData;D.append("file",N);try{const P=await fetch(o,{method:"POST",body:D,credentials:"include"});if(!P.ok)throw new Error("업로드 실패");const O=await P.json();Dn.log("Image uploaded:",O.url)}catch(P){Dn.error("이미지 업로드 오류:",P)}},A=N=>{const D=N.target.files?.[0];D&&T(D)},_=()=>{x&&(Dn.log("Insert link:",x),v(!1),M(""))},I=[{format:"bold",icon:"B",title:At("editor.toolbar.bold")},{format:"italic",icon:"I",title:At("editor.toolbar.italic")},{format:"underline",icon:"U",title:At("editor.toolbar.underline")},{format:"strike",icon:"S",title:At("editor.toolbar.strike")},{format:"code",icon:"</>",title:At("editor.toolbar.code")}],k=[{format:"h1",label:"H1"},{format:"h2",label:"H2"},{format:"h3",label:"H3"}],y=[{format:"bulletList",icon:"•",title:At("editor.toolbar.bullet_list")},{format:"orderedList",icon:"1.",title:At("editor.toolbar.ordered_list")},{format:"blockquote",icon:"❝",title:At("editor.toolbar.blockquote")}];return d.jsxs(W,{className:`border border-gray-300 dark:border-gray-600 rounded-lg overflow-hidden ${l}`,id:f,...h,children:[d.jsxs(W,{className:"flex flex-wrap items-center gap-1 p-2 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700",children:[d.jsx(W,{className:"flex items-center gap-1 pr-2 border-r border-gray-200 dark:border-gray-700",children:I.map(N=>d.jsx(Q,{type:"button",onClick:()=>w(N.format),disabled:s,className:"w-8 h-8 flex items-center justify-center text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 rounded disabled:opacity-50",title:N.title,children:N.icon},N.format))}),d.jsx(W,{className:"flex items-center gap-1 pr-2 border-r border-gray-200 dark:border-gray-700",children:k.map(N=>d.jsx(Q,{type:"button",onClick:()=>w(N.format),disabled:s,className:"px-2 h-8 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 rounded disabled:opacity-50",children:N.label},N.format))}),d.jsx(W,{className:"flex items-center gap-1 pr-2 border-r border-gray-200 dark:border-gray-700",children:y.map(N=>d.jsx(Q,{type:"button",onClick:()=>w(N.format),disabled:s,className:"w-8 h-8 flex items-center justify-center text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 rounded disabled:opacity-50",title:N.title,children:N.icon},N.format))}),d.jsxs(W,{className:"flex items-center gap-1 pr-2 border-r border-gray-200 dark:border-gray-700",children:[d.jsx(Q,{type:"button",onClick:()=>v(!0),disabled:s,className:"w-8 h-8 flex items-center justify-center text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 rounded disabled:opacity-50",title:At("editor.toolbar.link"),children:"🔗"}),d.jsxs(vr,{className:"w-8 h-8 flex items-center justify-center text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 rounded cursor-pointer",children:["🖼",d.jsx(_t,{type:"file",accept:"image/*",onChange:A,disabled:s,className:"hidden"})]})]}),d.jsxs(Q,{type:"button",onClick:()=>p(!g),disabled:s,className:`px-2 h-8 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 rounded disabled:opacity-50 ${g?"bg-gray-200 dark:bg-gray-700":""}`,children:["</>",At("editor.toolbar.code_view")]})]}),g?d.jsx(lo,{value:i,onChange:N=>u(N.target.value),placeholder:r,disabled:s,className:"w-full p-4 bg-gray-900 text-gray-100 font-mono text-sm focus:outline-none resize-none",style:{minHeight:a}}):d.jsx(W,{ref:c,contentEditable:!s,onInput:N=>u(N.currentTarget.innerHTML),className:"p-4 bg-white dark:bg-gray-900 text-gray-900 dark:text-white focus:outline-none prose dark:prose-invert max-w-none",style:{minHeight:a},"data-placeholder":r}),d.jsx(_t,{type:"hidden",name:e,value:i}),m&&d.jsx(W,{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50",children:d.jsxs(W,{className:"bg-white dark:bg-gray-800 rounded-lg p-6 w-96",children:[d.jsx(bn,{className:"text-lg font-medium text-gray-900 dark:text-white mb-4",children:At("edi Line truncated
whitespace-pre-wrap
text-gray-900 dark:text-gray-100
font-sans
${n}
`.trim().replace(/\s+/g," ");return d.jsx(W,{className:i,id:a,...s,children:l})}const g={FORBID_TAGS:["script","noscript","iframe","frame","frameset","object","embed","applet","portal","form","input","textarea","select","button","style","link","meta","base","body","head","html","title","svg","math","audio","video","source","track","canvas","details","dialog","plaintext","xmp","listing","marquee","noframes","noembed","template","slot"],FORBID_ATTR:["onerror","onload","onclick","onmouseover","onfocus","onblur","ontoggle","oncanplay","onloadstart","formaction","xlink:href","action"],ALLOW_DATA_ATTR:!0,ADD_ATTR:["target"]},h=k.useMemo(()=>{const i=o?{...g,...o,FORBID_TAGS:[...g.FORBID_TAGS,...o.FORBID_TAGS||[]],FORBID_ATTR:[...g.FORBID_ATTR,...o.FORBID_ATTR||[]]}:g;return hs.sanitize(l,i).replace(/<a\s+([^>]*?)href=["']([^"']+)["']([^>]*?)>/gi,(f,p,m,w)=>(m.startsWith("http://")||m.startsWith("https://"))&&!f.includes("rel=")?`<a ${p}href="${m}"${w} rel="noopener noreferrer">`:f)},[l,o]),c=`
`.trim().replace(/\s+/g," ");return d.jsx(W,{className:i,id:a,...s,children:l})}const f={FORBID_TAGS:["script","noscript","iframe","frame","frameset","object","embed","applet","portal","form","input","textarea","select","button","style","link","meta","base","body","head","html","title","svg","math","audio","video","source","track","canvas","details","dialog","plaintext","xmp","listing","marquee","noframes","noembed","template","slot"],FORBID_ATTR:["onerror","onload","onclick","onmouseover","onfocus","onblur","ontoggle","oncanplay","onloadstart","formaction","xlink:href","action"],ALLOW_DATA_ATTR:!0,ADD_ATTR:["target"]},h=C.useMemo(()=>{const i=o?{...f,...o,FORBID_TAGS:[...f.FORBID_TAGS,...o.FORBID_TAGS||[]],FORBID_ATTR:[...f.FORBID_ATTR,...o.FORBID_ATTR||[]]}:f;return Cs.sanitize(l,i).replace(/<a\s+([^>]*?)href=["']([^"']+)["']([^>]*?)>/gi,(g,p,m,v)=>(m.startsWith("http://")||m.startsWith("https://"))&&!g.includes("rel=")?`<a ${p}href="${m}"${v} rel="noopener noreferrer">`:g)},[l,o]),c=`
prose dark:prose-invert max-w-none
prose-p:my-2
prose-headings:font-bold prose-headings:mt-6 prose-headings:mb-4
@@ -39,7 +40,7 @@ var SirsoftBasic=(function(J,d,k,Jt){"use strict";function Mc(e){const t=Object.
[&_tr:hover]:bg-gray-50 dark:[&_tr:hover]:bg-gray-700/50
after:content-[''] after:block after:clear-both
${n}
`.trim().replace(/\s+/g," ");return d.jsx(W,{id:a,className:c,dangerouslySetInnerHTML:{__html:h},...s})},Wf=Object.freeze(Object.defineProperty({__proto__:null,HtmlContent:Yo},Symbol.toStringTag,{value:"Module"})),Xo=()=>window.G7Core,qo=(e,t)=>Xo()?.t?.(e,t)??e,Dl=({content:e="",onChange:t,isHtml:r=!1,onIsHtmlChange:n,rows:o=15,placeholder:a="",label:s,showHtmlModeToggle:l=!0,contentClassName:g="",purifyConfig:h,className:c="",name:i="content",htmlFieldName:u="content_mode",readOnly:f=!1,id:p,editorAttrs:m})=>{const[w,x]=k.useState(r),[A,v]=k.useState(e),[E,O]=k.useState(!1);k.useEffect(()=>{x(r)},[r]),k.useEffect(()=>{v(e)},[e]);const _=k.useCallback(y=>{const N=y.target.value;if(v(N),t){const M=Xo()?.createChangeEvent?.({value:N,name:i,type:"textarea"})??{target:{name:i,value:N}};t(M)}},[t,i]),I=k.useCallback(y=>{const N=y.target.checked;if(x(N),N||O(!1),n){const M=Xo()?.createChangeEvent?.({checked:N,name:u,type:"checkbox"})??{target:{name:u,checked:N}};n(M)}},[n,u]),C=k.useCallback(()=>{O(y=>!y)},[]);return d.jsxs(W,{className:`space-y-2 ${c}`,id:p,...m,children:[d.jsxs(W,{className:"flex items-center justify-between",children:[s&&d.jsx(yr,{className:"block text-sm font-medium text-gray-500 dark:text-gray-400",children:s}),d.jsxs(W,{className:"flex items-center gap-3",children:[w&&!f&&d.jsx(Q,{type:"button",onClick:C,className:`px-3 py-1.5 text-xs font-bold rounded-lg focus:outline-none focus:ring-2 ${E?"text-gray-700 dark:text-gray-200 bg-gray-200 dark:bg-gray-600 border border-gray-300 dark:border-gray-500 hover:bg-gray-300 dark:hover:bg-gray-500 focus:ring-gray-400 dark:focus:ring-gray-500":"text-blue-600 dark:text-blue-400 bg-white dark:bg-gray-700 border border-blue-300 dark:border-blue-600 hover:bg-blue-50 dark:hover:bg-gray-600 focus:ring-blue-500 dark:focus:ring-blue-600"}`,children:qo(E?"common.preview_off":"common.preview")}),l&&d.jsxs(yr,{className:"flex items-center gap-2 p-2 cursor-pointer",children:[d.jsx(xt,{type:"checkbox",name:u,checked:w,onChange:I,disabled:f,className:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"}),d.jsx(W,{className:"text-sm font-medium text-gray-700 dark:text-gray-300",children:qo("common.html_mode")})]})]})]}),!E&&d.jsx(no,{name:i,value:A,onChange:_,placeholder:a,rows:o,readOnly:f,className:`block w-full rounded-lg border px-3 py-2 text-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-1 disabled:opacity-50 disabled:cursor-not-allowed ${w?"font-mono bg-white dark:bg-gray-800 border-blue-300 dark:border-blue-600 text-gray-800 dark:text-gray-200 focus:border-blue-500 focus:ring-blue-500":"bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-white focus:border-blue-500 focus:ring-blue-500"}`}),E&&d.jsx(W,{className:"p-4 bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-800 min-h-[400px]",children:d.jsx(Yo,{content:A,isHtml:!0,className:g||"prose dark:prose-invert max-w-none text-gray-900 dark:text-gray-100",purifyConfig:h})})]})},Kf=Object.freeze(Object.defineProperty({__proto__:null,HtmlEditor:Dl},Symbol.toStringTag,{value:"Module"})),Ll=e=>window.G7Core?.t?.(e)??e,Zo=({maxHeight:e=500,expandText:t,collapseText:r,className:n="",children:o,id:a,editorAttrs:s})=>{const[l,g]=k.useState(!1),[h,c]=k.useState(!1),i=k.useRef(null),u=k.useCallback(()=>{if(i.current){const w=i.current.scrollHeight;c(w>e)}},[e]);k.useEffect(()=>{u();const w=i.current;if(!w)return;const x=w.querySelectorAll("img");x.forEach(v=>{v.complete||v.addEventListener("load",u)});let A=null;return typeof ResizeObserver<"u"&&(A=new ResizeObserver(u),A.observe(w)),()=>{x.forEach(v=>{v.removeEventListener("load",u)}),A?.disconnect()}},[u,o]);const f=()=>{g(w=>!w)},p=t||Ll("sirsoft-ecommerce.shop.product.expand_detail"),m=r||Ll("sirsoft-ecommerce.shop.product.collapse_detail");return d.jsxs(W,{className:n,id:a,...s,children:[d.jsxs(W,{className:"relative",children:[d.jsx(W,{ref:i,className:!l&&h?"overflow-hidden transition-[max-height] duration-300 ease-in-out":"transition-[max-height] duration-300 ease-in-out",style:!l&&h?{maxHeight:`${e}px`}:void 0,children:o}),!l&&h&&d.jsx(W,{className:"absolute bottom-0 left-0 right-0 h-24 bg-gradient-to-t from-white dark:from-gray-900 to-transparent pointer-events-none"})]}),h&&d.jsxs(Q,{type:"button",onClick:f,className:"flex items-center justify-center w-full py-3.5 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors cursor-pointer gap-1.5",children:[d.jsx(te,{className:"text-sm font-semibold text-gray-600 dark:text-gray-400",children:l?m:p}),d.jsx(ce,{name:l?"chevron-up":"chevron-down",size:"sm"})]})]})},Vf=Object.freeze(Object.defineProperty({__proto__:null,ExpandableContent:Zo,default:Zo},Symbol.toStringTag,{value:"Module"})),Yf=(e,t)=>window.G7Core?.t?.(e,t)??e Line truncated
`.trim().replace(/\s+/g," ");return d.jsx(W,{id:a,className:c,dangerouslySetInnerHTML:{__html:h},...s})},fg=Object.freeze(Object.defineProperty({__proto__:null,HtmlContent:Zo},Symbol.toStringTag,{value:"Module"})),qo=()=>window.G7Core,Qo=(e,t)=>qo()?.t?.(e,t)??e,Wl=({content:e="",onChange:t,isHtml:r=!1,onIsHtmlChange:n,rows:o=15,placeholder:a="",label:s,showHtmlModeToggle:l=!0,contentClassName:f="",purifyConfig:h,className:c="",name:i="content",htmlFieldName:u="content_mode",readOnly:g=!1,id:p,editorAttrs:m})=>{const[v,x]=C.useState(r),[M,w]=C.useState(e),[T,A]=C.useState(!1);C.useEffect(()=>{x(r)},[r]),C.useEffect(()=>{w(e)},[e]);const _=C.useCallback(y=>{const N=y.target.value;if(w(N),t){const D=qo()?.createChangeEvent?.({value:N,name:i,type:"textarea"})??{target:{name:i,value:N}};t(D)}},[t,i]),I=C.useCallback(y=>{const N=y.target.checked;if(x(N),N||A(!1),n){const D=qo()?.createChangeEvent?.({checked:N,name:u,type:"checkbox"})??{target:{name:u,checked:N}};n(D)}},[n,u]),k=C.useCallback(()=>{A(y=>!y)},[]);return d.jsxs(W,{className:`space-y-2 ${c}`,id:p,...m,children:[d.jsxs(W,{className:"flex items-center justify-between",children:[s&&d.jsx(vr,{className:"block text-sm font-medium text-gray-500 dark:text-gray-400",children:s}),d.jsxs(W,{className:"flex items-center gap-3",children:[v&&!g&&d.jsx(Q,{type:"button",onClick:k,className:`px-3 py-1.5 text-xs font-bold rounded-lg focus:outline-none focus:ring-2 ${T?"text-gray-700 dark:text-gray-200 bg-gray-200 dark:bg-gray-600 border border-gray-300 dark:border-gray-500 hover:bg-gray-300 dark:hover:bg-gray-500 focus:ring-gray-400 dark:focus:ring-gray-500":"text-blue-600 dark:text-blue-400 bg-white dark:bg-gray-700 border border-blue-300 dark:border-blue-600 hover:bg-blue-50 dark:hover:bg-gray-600 focus:ring-blue-500 dark:focus:ring-blue-600"}`,children:Qo(T?"common.preview_off":"common.preview")}),l&&d.jsxs(vr,{className:"flex items-center gap-2 p-2 cursor-pointer",children:[d.jsx(_t,{type:"checkbox",name:u,checked:v,onChange:I,disabled:g,className:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"}),d.jsx(W,{className:"text-sm font-medium text-gray-700 dark:text-gray-300",children:Qo("common.html_mode")})]})]})]}),!T&&d.jsx(lo,{name:i,value:M,onChange:_,placeholder:a,rows:o,readOnly:g,className:`block w-full rounded-lg border px-3 py-2 text-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-1 disabled:opacity-50 disabled:cursor-not-allowed ${v?"font-mono bg-white dark:bg-gray-800 border-blue-300 dark:border-blue-600 text-gray-800 dark:text-gray-200 focus:border-blue-500 focus:ring-blue-500":"bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-white focus:border-blue-500 focus:ring-blue-500"}`}),T&&d.jsx(W,{className:"p-4 bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-800 min-h-[400px]",children:d.jsx(Zo,{content:M,isHtml:!0,className:f||"prose dark:prose-invert max-w-none text-gray-900 dark:text-gray-100",purifyConfig:h})})]})},gg=Object.freeze(Object.defineProperty({__proto__:null,HtmlEditor:Wl},Symbol.toStringTag,{value:"Module"})),Kl=e=>window.G7Core?.t?.(e)??e,Jo=({maxHeight:e=500,expandText:t,collapseText:r,className:n="",children:o,id:a,editorAttrs:s})=>{const[l,f]=C.useState(!1),[h,c]=C.useState(!1),i=C.useRef(null),u=C.useCallback(()=>{if(i.current){const v=i.current.scrollHeight;c(v>e)}},[e]);C.useEffect(()=>{u();const v=i.current;if(!v)return;const x=v.querySelectorAll("img");x.forEach(w=>{w.complete||w.addEventListener("load",u)});let M=null;return typeof ResizeObserver<"u"&&(M=new ResizeObserver(u),M.observe(v)),()=>{x.forEach(w=>{w.removeEventListener("load",u)}),M?.disconnect()}},[u,o]);const g=()=>{f(v=>!v)},p=t||Kl("sirsoft-ecommerce.shop.product.expand_detail"),m=r||Kl("sirsoft-ecommerce.shop.product.collapse_detail");return d.jsxs(W,{className:n,id:a,...s,children:[d.jsxs(W,{className:"relative",children:[d.jsx(W,{ref:i,className:!l&&h?"overflow-hidden transition-[max-height] duration-300 ease-in-out":"transition-[max-height] duration-300 ease-in-out",style:!l&&h?{maxHeight:`${e}px`}:void 0,children:o}),!l&&h&&d.jsx(W,{className:"absolute bottom-0 left-0 right-0 h-24 bg-gradient-to-t from-white dark:from-gray-900 to-transparent pointer-events-none"})]}),h&&d.jsxs(Q,{type:"button",onClick:g,className:"flex items-center justify-center w-full py-3.5 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors cursor-pointer gap-1.5",children:[d.jsx(re,{className:"text-sm font-semibold text-gray-600 dark:text-gray-400",children:l?m:p}),d.jsx(fe,{name:l?"chevron-up":"chevron-down",size:"sm"})]})]})},hg=Object.freeze(Object.defineProperty({__proto__:null,ExpandableContent:Jo,default:Jo},Symbol.toStringTag,{value:"Module"})),pg=(e,t)=>window.G7Core?.t?.(e,t)??e Line truncated
let scriptImported = false
self.addEventListener('message', async (e) => {
const { file, id, imageCompressionLibUrl, options } = e.data
@@ -58,20 +59,20 @@ self.addEventListener('message', async (e) => {
self.postMessage({ error: e.message + '\\n' + e.stack, id })
}
})
`;let ra;function og(e,t){return new Promise(((r,n)=>{ra||(ra=(function(s){const l=[];return l.push(s),URL.createObjectURL(new Blob(l))})(ng));const o=new Worker(ra);o.addEventListener("message",(function(s){if(t.signal&&t.signal.aborted)o.terminate();else if(s.data.progress===void 0){if(s.data.error)return n(new Error(s.data.error)),void o.terminate();r(s.data.file),o.terminate()}else t.onProgress(s.data.progress)})),o.addEventListener("error",n),t.signal&&t.signal.addEventListener("abort",(()=>{n(t.signal.reason),o.terminate()})),o.postMessage({file:e,imageCompressionLibUrl:t.libURL,options:{...t,onProgress:void 0,signal:void 0}})}))}function ct(e,t){return new Promise((function(r,n){let o,a,s,l,g,h;if(o={...t},s=0,{onProgress:l}=o,o.maxSizeMB=o.maxSizeMB||Number.POSITIVE_INFINITY,g=typeof o.useWebWorker!="boolean"||o.useWebWorker,delete o.useWebWorker,o.onProgress=f=>{s=f,typeof l=="function"&&l(s)},!(e instanceof Blob||e instanceof rg))return n(new Error("The file given is not an instance of Blob or File"));if(!/^image/.test(e.type))return n(new Error("The file given is not an image"));if(h=typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope,!g||typeof Worker!="function"||h)return Xl(e,o).then(function(f){try{return a=f,u.call(this)}catch(p){return n(p)}}.bind(this),n);var c=function(){try{return u.call(this)}catch(f){return n(f)}}.bind(this),i=function(f){try{return Xl(e,o).then((function(p){try{return a=p,c()}catch(m){return n(m)}}),n)}catch(p){return n(p)}};try{return o.libURL=o.libURL||"https://cdn.jsdelivr.net/npm/browser-image-compression@2.0.2/dist/browser-image-compression.js",og(e,o).then((function(f){try{return a=f,c()}catch{return i()}}),i)}catch{i()}function u(){try{a.name=e.name,a.lastModified=e.lastModified}catch{}try{o.preserveExif&&e.type==="image/jpeg"&&(!o.fileType||o.fileType&&o.fileType===e.type)&&(a=Ul(e,a))}catch{}return r(a)}}))}ct.getDataUrlFromFile=Gl,ct.getFilefromDataUrl=ta,ct.loadImage=jl,ct.drawImageInCanvas=Wl,ct.drawFileInCanvas=Pn,ct.canvasToFile=Fn,ct.getExifOrientation=Kl,ct.handleMaxWidthOrHeight=Vl,ct.followExifOrientation=Yl,ct.cleanupCanvasMemory=Vt,ct.isAutoOrientationInBrowser=Nr,ct.approximateBelowMaximumCanvasSizeOfBrowser=Bl,ct.copyExifWithoutOrientation=Ul,ct.getBrowserName=fr,ct.version="2.0.2";const ag=window.G7Core,Un=e=>{const t=["B","KB","MB","GB"];let r=0,n=e;for(;n>=1024&&r<t.length-1;)n/=1024,r++;return`${n.toFixed(2)} ${t[r]}`},ql=e=>{if(e&&typeof e=="object"){const t=e;if(t.response?.data?.message)return t.response.data.message;if(t.response?.data?.errors){const r=Object.values(t.response.data.errors)[0];if(Array.isArray(r)&&r[0])return r[0]}if(t.message)return t.message}return e instanceof Error?e.message:"업로드 실패"},Zl=e=>e?e.startsWith("image/")?"fa-file-image":e.startsWith("video/")?"fa-file-video":e.startsWith("audio/")?"fa-file-audio":e==="application/pdf"?"fa-file-pdf":e.includes("word")||e.includes("document")?"fa-file-word":e.includes("excel")||e.includes("spreadsheet")?"fa-file-excel":e.includes("zip")||e.includes("compressed")?"fa-file-zipper":"fa-file":"fa-file",nt=(e,t)=>ag?.t?.(e,t)??e,gr=window.G7Core;function Ql(e){const{attachmentableType:t,attachmentableId:r,collection:n,maxFiles:o,maxSize:a,maxConcurrentUploads:s,accept:l,imageCompression:g,roleIds:h,autoUpload:c,initialFiles:i,endpoints:u,onFilesChange:f,onUploadComplete:p,onUploadError:m,onRemove:w,onReorder:x,uploadTriggerEvent:A,confirmBeforeRemove:v,uploadParams:E}=e,[O,_]=k.useState(i),[I,C]=k.useState([]),[y,N]=k.useState(!1),M=k.useRef(null),P=k.useRef(0),D=k.useRef(new Set),L=k.useRef(new Map),[$,S]=k.useState(!1),[b,U]=k.useState(null),[F,G]=k.useState(!1),Y=k.useRef(!1),[B,V]=k.useState([]),j=k.useRef(i),[H,q]=k.useState(!1),[ue,ee]=k.useState(0),fe=k.useRef(0),[R,ke]=k.useState(new Map),me=k.useRef(new Map);k.useEffect(()=>{f?.(I)},[I,f]);const Ge=k.useMemo(()=>{const X=j.current;return X===i?X:X.length!==i.length?(j.current=i,i):X.length===0&&i.length===0?X:i.some((de,le)=>de.id!==X[le]?.id)?(j.current=i,i):X},[i]);k.useEffect(()=>{if(Y.current)return;const X=Ge.filter(le=>!D.current.has(le.id)&&(!le.hash||!D.current.has(le.hash))),ae=new Set(X.map(le=>le.id)),de=Array.from(L.current.values()).filter(le=>!ae.has(le.id)&&!D.current.has(le.id));_([...X,...de])},[Ge]);const De=k.useCallback(async X=>{const ae={maxSizeMB:g?.maxSizeMB??1,maxWidthOrHeight:g?.maxWidthOrHeight??1920,useWebWorker:!0};return await ct(X,ae)},[g]),ye=k.useCallback(async X=>{const ae=O.length+I.length,de=o-ae,le=Array.from(X).slice(0,de);for(const se of le){if(se.size>a*1024*1024){m?.(`[${se.name}] 파일 크기(${Un(se.size)})가 최대 허용 크기(${a}MB)를 초과합니다.`,se);continue}if(l){const ve="."+se.name.split(".").pop()?.toLowerCase();if(!l.split(",").map($e=>$e.trim().toLowerCase()).some($e=>{if($e.includes("/")){if($e.endsWith("/*")){const je=$e.slice(0,-2);return se.type.toLowerCase().startsWith(je+"/")}return se.type.toLowerCase()===$e}return ve===$e})){m?.( Line truncated
`;let oa;function Eg(e,t){return new Promise(((r,n)=>{oa||(oa=(function(s){const l=[];return l.push(s),URL.createObjectURL(new Blob(l))})(_g));const o=new Worker(oa);o.addEventListener("message",(function(s){if(t.signal&&t.signal.aborted)o.terminate();else if(s.data.progress===void 0){if(s.data.error)return n(new Error(s.data.error)),void o.terminate();r(s.data.file),o.terminate()}else t.onProgress(s.data.progress)})),o.addEventListener("error",n),t.signal&&t.signal.addEventListener("abort",(()=>{n(t.signal.reason),o.terminate()})),o.postMessage({file:e,imageCompressionLibUrl:t.libURL,options:{...t,onProgress:void 0,signal:void 0}})}))}function ht(e,t){return new Promise((function(r,n){let o,a,s,l,f,h;if(o={...t},s=0,{onProgress:l}=o,o.maxSizeMB=o.maxSizeMB||Number.POSITIVE_INFINITY,f=typeof o.useWebWorker!="boolean"||o.useWebWorker,delete o.useWebWorker,o.onProgress=g=>{s=g,typeof l=="function"&&l(s)},!(e instanceof Blob||e instanceof Sg))return n(new Error("The file given is not an instance of Blob or File"));if(!/^image/.test(e.type))return n(new Error("The file given is not an image"));if(h=typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope,!f||typeof Worker!="function"||h)return ai(e,o).then(function(g){try{return a=g,u.call(this)}catch(p){return n(p)}}.bind(this),n);var c=function(){try{return u.call(this)}catch(g){return n(g)}}.bind(this),i=function(g){try{return ai(e,o).then((function(p){try{return a=p,c()}catch(m){return n(m)}}),n)}catch(p){return n(p)}};try{return o.libURL=o.libURL||"https://cdn.jsdelivr.net/npm/browser-image-compression@2.0.2/dist/browser-image-compression.js",Eg(e,o).then((function(g){try{return a=g,c()}catch{return i()}}),i)}catch{i()}function u(){try{a.name=e.name,a.lastModified=e.lastModified}catch{}try{o.preserveExif&&e.type==="image/jpeg"&&(!o.fileType||o.fileType&&o.fileType===e.type)&&(a=Xl(e,a))}catch{}return r(a)}}))}ht.getDataUrlFromFile=Jl,ht.getFilefromDataUrl=na,ht.loadImage=Rl,ht.drawImageInCanvas=ti,ht.drawFileInCanvas=Un,ht.canvasToFile=zn,ht.getExifOrientation=ri,ht.handleMaxWidthOrHeight=ni,ht.followExifOrientation=oi,ht.cleanupCanvasMemory=Zt,ht.isAutoOrientationInBrowser=Pr,ht.approximateBelowMaximumCanvasSizeOfBrowser=ei,ht.copyExifWithoutOrientation=Xl,ht.getBrowserName=gr,ht.version="2.0.2";const Tg=window.G7Core,Hn=e=>{const t=["B","KB","MB","GB"];let r=0,n=e;for(;n>=1024&&r<t.length-1;)n/=1024,r++;return`${n.toFixed(2)} ${t[r]}`},si=e=>{if(e&&typeof e=="object"){const t=e;if(t.response?.data?.message)return t.response.data.message;if(t.response?.data?.errors){const r=Object.values(t.response.data.errors)[0];if(Array.isArray(r)&&r[0])return r[0]}if(t.message)return t.message}return e instanceof Error?e.message:"업로드 실패"},li=e=>e?e.startsWith("image/")?"fa-file-image":e.startsWith("video/")?"fa-file-video":e.startsWith("audio/")?"fa-file-audio":e==="application/pdf"?"fa-file-pdf":e.includes("word")||e.includes("document")?"fa-file-word":e.includes("excel")||e.includes("spreadsheet")?"fa-file-excel":e.includes("zip")||e.includes("compressed")?"fa-file-zipper":"fa-file":"fa-file",et=(e,t)=>Tg?.t?.(e,t)??e,hr=window.G7Core;function ii(e){const{attachmentableType:t,attachmentableId:r,collection:n,maxFiles:o,maxSize:a,maxConcurrentUploads:s,accept:l,imageCompression:f,roleIds:h,autoUpload:c,initialFiles:i,endpoints:u,onFilesChange:g,onUploadComplete:p,onUploadError:m,onRemove:v,onReorder:x,uploadTriggerEvent:M,confirmBeforeRemove:w,uploadParams:T}=e,[A,_]=C.useState(i),[I,k]=C.useState([]),[y,N]=C.useState(!1),D=C.useRef(null),P=C.useRef(0),O=C.useRef(new Set),L=C.useRef(new Map),[$,S]=C.useState(!1),[b,z]=C.useState(null),[U,G]=C.useState(!1),Y=C.useRef(!1),[B,V]=C.useState([]),j=C.useRef(i),[H,q]=C.useState(!1),[ee,ne]=C.useState(0),ce=C.useRef(0),[R,_e]=C.useState(new Map),me=C.useRef(new Map);C.useEffect(()=>{g?.(I)},[I,g]);const Be=C.useMemo(()=>{const X=j.current;return X===i?X:X.length!==i.length?(j.current=i,i):X.length===0&&i.length===0?X:i.some((de,ue)=>de.id!==X[ue]?.id)?(j.current=i,i):X},[i]);C.useEffect(()=>{if(Y.current)return;const X=Be.filter(ue=>!O.current.has(ue.id)&&(!ue.hash||!O.current.has(ue.hash))),se=new Set(X.map(ue=>ue.id)),de=Array.from(L.current.values()).filter(ue=>!se.has(ue.id)&&!O.current.has(ue.id));_([...X,...de])},[Be]);const $e=C.useCallback(async X=>{const se={maxSizeMB:f?.maxSizeMB??1,maxWidthOrHeight:f?.maxWidthOrHeight??1920,useWebWorker:!0};return await ht(X,se)},[f]),ye=C.useCallback(async X=>{const se=A.length+I.length,de=Math.max(0,o-se),ue=Array.from(X).slice(0,de);if(X.length>de){const ie=Array.from(X).slice(de),De=et("attachment.upload_limit_exceeded",{max:o});m?.(De,ie[0]??X[0])}for(const ie of ue){if(ie.size>a*1024*1024){m?.(`[${ie.name}] 파일 크기(${Hn(ie.size)})가 최대 허용 크기(${a}MB)를 초과합니다.`,ie);continue}if(l){const ge="."+ie.name.split(".").pop()?.toLowerCase();if(!l.split(",").map(ze=>ze.trim().toLowerCase()).some(ze=>{if(ze.includes("/")){if(ze.endsWith("/*" Line truncated
relative border-2 border-dashed rounded-lg transition-colors
${e?"border-blue-500 bg-blue-50 dark:bg-blue-900/20":"border-gray-300 dark:border-gray-600"}
`,onDragOver:h=>{h.preventDefault(),t&&n(!0)},onDragLeave:()=>n(!1),onDrop:h=>{h.preventDefault(),n(!1),t&&r(h.dataTransfer.files)},children:[d.jsx("input",{ref:o,type:"file",multiple:!0,accept:a,onChange:h=>h.target.files&&r(h.target.files),className:"hidden"}),!g&&d.jsxs(W,{className:"p-8 text-center cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors",onClick:()=>o.current?.click(),children:[d.jsx(Ct,{className:"fa-solid fa-cloud-arrow-up text-4xl text-gray-400 dark:text-gray-500 mb-4"}),d.jsx(Dt,{className:"text-sm text-gray-600 dark:text-gray-400",children:nt("attachment.drop_or_click")}),d.jsxs(Dt,{className:"text-xs text-gray-500 dark:text-gray-500 mt-2",children:[nt("attachment.upload_limit",{maxFiles:s,maxSize:l}),a&&` (${a})`]})]}),g]});function sg(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];return k.useMemo(()=>n=>{t.forEach(o=>o(n))},t)}const $n=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function Ar(e){const t=Object.prototype.toString.call(e);return t==="[object Window]"||t==="[object global]"}function na(e){return"nodeType"in e}function yt(e){var t,r;return e?Ar(e)?e:na(e)&&(t=(r=e.ownerDocument)==null?void 0:r.defaultView)!=null?t:window:window}function oa(e){const{Document:t}=yt(e);return e instanceof t}function Qr(e){return Ar(e)?!1:e instanceof yt(e).HTMLElement}function Rl(e){return e instanceof yt(e).SVGElement}function Mr(e){return e?Ar(e)?e.document:na(e)?oa(e)?e:Qr(e)||Rl(e)?e.ownerDocument:document:document:document}const Yt=$n?k.useLayoutEffect:k.useEffect;function aa(e){const t=k.useRef(e);return Yt(()=>{t.current=e}),k.useCallback(function(){for(var r=arguments.length,n=new Array(r),o=0;o<r;o++)n[o]=arguments[o];return t.current==null?void 0:t.current(...n)},[])}function lg(){const e=k.useRef(null),t=k.useCallback((n,o)=>{e.current=setInterval(n,o)},[]),r=k.useCallback(()=>{e.current!==null&&(clearInterval(e.current),e.current=null)},[]);return[t,r]}function Jr(e,t){t===void 0&&(t=[e]);const r=k.useRef(e);return Yt(()=>{r.current!==e&&(r.current=e)},t),r}function Rr(e,t){const r=k.useRef();return k.useMemo(()=>{const n=e(r.current);return r.current=n,n},[...t])}function zn(e){const t=aa(e),r=k.useRef(null),n=k.useCallback(o=>{o!==r.current&&t?.(o,r.current),r.current=o},[]);return[r,n]}function sa(e){const t=k.useRef();return k.useEffect(()=>{t.current=e},[e]),t.current}let la={};function en(e,t){return k.useMemo(()=>{if(t)return t;const r=la[e]==null?0:la[e]+1;return la[e]=r,e+"-"+r},[e,t])}function ei(e){return function(t){for(var r=arguments.length,n=new Array(r>1?r-1:0),o=1;o<r;o++)n[o-1]=arguments[o];return n.reduce((a,s)=>{const l=Object.entries(s);for(const[g,h]of l){const c=a[g];c!=null&&(a[g]=c+e*h)}return a},{...t})}}const Or=ei(1),tn=ei(-1);function ig(e){return"clientX"in e&&"clientY"in e}function ia(e){if(!e)return!1;const{KeyboardEvent:t}=yt(e.target);return t&&e instanceof t}function cg(e){if(!e)return!1;const{TouchEvent:t}=yt(e.target);return t&&e instanceof t}function ca(e){if(cg(e)){if(e.touches&&e.touches.length){const{clientX:t,clientY:r}=e.touches[0];return{x:t,y:r}}else if(e.changedTouches&&e.changedTouches.length){const{clientX:t,clientY:r}=e.changedTouches[0];return{x:t,y:r}}}return ig(e)?{x:e.clientX,y:e.clientY}:null}const rn=Object.freeze({Translate:{toString(e){if(!e)return;const{x:t,y:r}=e;return"translate3d("+(t?Math.round(t):0)+"px, "+(r?Math.round(r):0)+"px, 0)"}},Scale:{toString(e){if(!e)return;const{scaleX:t,scaleY:r}=e;return"scaleX("+t+") scaleY("+r+")"}},Transform:{toString(e){if(e)return[rn.Translate.toString(e),rn.Scale.toString(e)].join(" ")}},Transition:{toString(e){let{property:t,duration:r,easing:n}=e;return t+" "+r+"ms "+n}}}),ti="a,frame,iframe,input:not([type=hidden]):not(:disabled),select:not(:disabled),textarea:not(:disabled),button:not(:disabled),*[tabindex]";function dg(e){return e.matches(ti)?e:e.querySelector(ti)}const ug={display:"none"};function fg(e){let{id:t,value:r}=e;return k.createElement("div",{id:t,style:ug},r)}function gg(e){let{id:t,announcement:r,ariaLiveType:n="assertive"}=e;const o={position:"fixed",top:0,left:0,width:1,height:1,margin:-1,border:0,padding:0,overflow:"hidden",clip:"rect(0 0 0 0)",clipPath:"inset(100%)",whiteSpace:"nowrap"};return k.createElement("div",{id:t,style:o,role:"status","aria-live":n,"aria-atomic":!0},r)}function hg(){const[e,t]=k.useState("");return{announce:k.useCallback(n=>{n!=null&&t(n)},[]),announcement:e}}const ri=k.createContext(null);function pg(e){const t=k.useContext(ri);k.useEffect(()=>{if(!t)throw new Error("useDndMonitor must be used within a children of <DndContext>");return t(e)},[e,t])}function mg(){const[e]=k.useState(()=>new Set),t=k.useCallback(n=>(e.add(n),()=>e.delete(n)),[e]);return[k.useCallback(n=>{let{type:o,event:a}=n;e.forEach(s=>{var l;return(l=s[o])==null?void 0:l.call(s,a)})},[e]),t]}const bg={draggable:`
`,onDragOver:h=>{h.preventDefault(),t&&n(!0)},onDragLeave:()=>n(!1),onDrop:h=>{h.preventDefault(),n(!1),t&&r(h.dataTransfer.files)},children:[d.jsx("input",{ref:o,type:"file",multiple:!0,accept:a,onChange:h=>h.target.files&&r(h.target.files),className:"hidden"}),!f&&d.jsxs(W,{className:"p-8 text-center cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors",onClick:()=>o.current?.click(),children:[d.jsx(Nt,{className:"fa-solid fa-cloud-arrow-up text-4xl text-gray-400 dark:text-gray-500 mb-4"}),d.jsx(zt,{className:"text-sm text-gray-600 dark:text-gray-400",children:et("attachment.drop_or_click")}),d.jsxs(zt,{className:"text-xs text-gray-500 dark:text-gray-500 mt-2",children:[et("attachment.upload_limit",{maxFiles:s,maxSize:l}),a&&` (${a})`]})]}),f]});function Ng(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];return C.useMemo(()=>n=>{t.forEach(o=>o(n))},t)}const Gn=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function Fr(e){const t=Object.prototype.toString.call(e);return t==="[object Window]"||t==="[object global]"}function aa(e){return"nodeType"in e}function xt(e){var t,r;return e?Fr(e)?e:aa(e)&&(t=(r=e.ownerDocument)==null?void 0:r.defaultView)!=null?t:window:window}function sa(e){const{Document:t}=xt(e);return e instanceof t}function tn(e){return Fr(e)?!1:e instanceof xt(e).HTMLElement}function di(e){return e instanceof xt(e).SVGElement}function $r(e){return e?Fr(e)?e.document:aa(e)?sa(e)?e:tn(e)||di(e)?e.ownerDocument:document:document:document}const qt=Gn?C.useLayoutEffect:C.useEffect;function la(e){const t=C.useRef(e);return qt(()=>{t.current=e}),C.useCallback(function(){for(var r=arguments.length,n=new Array(r),o=0;o<r;o++)n[o]=arguments[o];return t.current==null?void 0:t.current(...n)},[])}function Ag(){const e=C.useRef(null),t=C.useCallback((n,o)=>{e.current=setInterval(n,o)},[]),r=C.useCallback(()=>{e.current!==null&&(clearInterval(e.current),e.current=null)},[]);return[t,r]}function rn(e,t){t===void 0&&(t=[e]);const r=C.useRef(e);return qt(()=>{r.current!==e&&(r.current=e)},t),r}function nn(e,t){const r=C.useRef();return C.useMemo(()=>{const n=e(r.current);return r.current=n,n},[...t])}function jn(e){const t=la(e),r=C.useRef(null),n=C.useCallback(o=>{o!==r.current&&t?.(o,r.current),r.current=o},[]);return[r,n]}function ia(e){const t=C.useRef();return C.useEffect(()=>{t.current=e},[e]),t.current}let ca={};function on(e,t){return C.useMemo(()=>{if(t)return t;const r=ca[e]==null?0:ca[e]+1;return ca[e]=r,e+"-"+r},[e,t])}function ui(e){return function(t){for(var r=arguments.length,n=new Array(r>1?r-1:0),o=1;o<r;o++)n[o-1]=arguments[o];return n.reduce((a,s)=>{const l=Object.entries(s);for(const[f,h]of l){const c=a[f];c!=null&&(a[f]=c+e*h)}return a},{...t})}}const Ur=ui(1),an=ui(-1);function Mg(e){return"clientX"in e&&"clientY"in e}function da(e){if(!e)return!1;const{KeyboardEvent:t}=xt(e.target);return t&&e instanceof t}function Og(e){if(!e)return!1;const{TouchEvent:t}=xt(e.target);return t&&e instanceof t}function ua(e){if(Og(e)){if(e.touches&&e.touches.length){const{clientX:t,clientY:r}=e.touches[0];return{x:t,y:r}}else if(e.changedTouches&&e.changedTouches.length){const{clientX:t,clientY:r}=e.changedTouches[0];return{x:t,y:r}}}return Mg(e)?{x:e.clientX,y:e.clientY}:null}const sn=Object.freeze({Translate:{toString(e){if(!e)return;const{x:t,y:r}=e;return"translate3d("+(t?Math.round(t):0)+"px, "+(r?Math.round(r):0)+"px, 0)"}},Scale:{toString(e){if(!e)return;const{scaleX:t,scaleY:r}=e;return"scaleX("+t+") scaleY("+r+")"}},Transform:{toString(e){if(e)return[sn.Translate.toString(e),sn.Scale.toString(e)].join(" ")}},Transition:{toString(e){let{property:t,duration:r,easing:n}=e;return t+" "+r+"ms "+n}}}),fi="a,frame,iframe,input:not([type=hidden]):not(:disabled),select:not(:disabled),textarea:not(:disabled),button:not(:disabled),*[tabindex]";function Ig(e){return e.matches(fi)?e:e.querySelector(fi)}const Dg={display:"none"};function Lg(e){let{id:t,value:r}=e;return C.createElement("div",{id:t,style:Dg},r)}function Pg(e){let{id:t,announcement:r,ariaLiveType:n="assertive"}=e;const o={position:"fixed",top:0,left:0,width:1,height:1,margin:-1,border:0,padding:0,overflow:"hidden",clip:"rect(0 0 0 0)",clipPath:"inset(100%)",whiteSpace:"nowrap"};return C.createElement("div",{id:t,style:o,role:"status","aria-live":n,"aria-atomic":!0},r)}function Fg(){const[e,t]=C.useState("");return{announce:C.useCallback(n=>{n!=null&&t(n)},[]),announcement:e}}const gi=C.createContext(null);function $g(e){const t=C.useContext(gi);C.useEffect(()=>{if(!t)throw new Error("useDndMonitor must be used within a children of <DndContext>");return t(e)},[e,t])}function Ug(){const[e]=C.useState(()=>new Set),t=C.useCallback(n=>(e.add(n),()=>e.delete(n)),[e]);return[C.useCallback(n=>{let{type:o,event:a}=n;e.forEach(s=>{var l;return(l=s[o])==null?void 0:l.call(s,a)})},[e]),t]}const zg={draggable:`
To pick up a draggable item, press the space bar.
While dragging, use the arrow keys to move the item.
Press space again to drop the item in its new position, or press escape to cancel.
`},yg={onDragStart(e){let{active:t}=e;return"Picked up draggable item "+t.id+"."},onDragOver(e){let{active:t,over:r}=e;return r?"Draggable item "+t.id+" was moved over droppable area "+r.id+".":"Draggable item "+t.id+" is no longer over a droppable area."},onDragEnd(e){let{active:t,over:r}=e;return r?"Draggable item "+t.id+" was dropped over droppable area "+r.id:"Draggable item "+t.id+" was dropped."},onDragCancel(e){let{active:t}=e;return"Dragging was cancelled. Draggable item "+t.id+" was dropped."}};function vg(e){let{announcements:t=yg,container:r,hiddenTextDescribedById:n,screenReaderInstructions:o=bg}=e;const{announce:a,announcement:s}=hg(),l=en("DndLiveRegion"),[g,h]=k.useState(!1);if(k.useEffect(()=>{h(!0)},[]),pg(k.useMemo(()=>({onDragStart(i){let{active:u}=i;a(t.onDragStart({active:u}))},onDragMove(i){let{active:u,over:f}=i;t.onDragMove&&a(t.onDragMove({active:u,over:f}))},onDragOver(i){let{active:u,over:f}=i;a(t.onDragOver({active:u,over:f}))},onDragEnd(i){let{active:u,over:f}=i;a(t.onDragEnd({active:u,over:f}))},onDragCancel(i){let{active:u,over:f}=i;a(t.onDragCancel({active:u,over:f}))}}),[a,t])),!g)return null;const c=k.createElement(k.Fragment,null,k.createElement(fg,{id:n,value:o.draggable}),k.createElement(gg,{id:l,announcement:s}));return r?Jt.createPortal(c,r):c}var Re;(function(e){e.DragStart="dragStart",e.DragMove="dragMove",e.DragEnd="dragEnd",e.DragCancel="dragCancel",e.DragOver="dragOver",e.RegisterDroppable="registerDroppable",e.SetDroppableDisabled="setDroppableDisabled",e.UnregisterDroppable="unregisterDroppable"})(Re||(Re={}));function Hn(){}function ni(e,t){return k.useMemo(()=>({sensor:e,options:t??{}}),[e,t])}function wg(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];return k.useMemo(()=>[...t].filter(n=>n!=null),[...t])}const Gt=Object.freeze({x:0,y:0});function oi(e,t){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))}function ai(e,t){let{data:{value:r}}=e,{data:{value:n}}=t;return r-n}function xg(e,t){let{data:{value:r}}=e,{data:{value:n}}=t;return n-r}function si(e){let{left:t,top:r,height:n,width:o}=e;return[{x:t,y:r},{x:t+o,y:r},{x:t,y:r+n},{x:t+o,y:r+n}]}function li(e,t){if(!e||e.length===0)return null;const[r]=e;return r[t]}function ii(e,t,r){return t===void 0&&(t=e.left),r===void 0&&(r=e.top),{x:t+e.width*.5,y:r+e.height*.5}}const kg=e=>{let{collisionRect:t,droppableRects:r,droppableContainers:n}=e;const o=ii(t,t.left,t.top),a=[];for(const s of n){const{id:l}=s,g=r.get(l);if(g){const h=oi(ii(g),o);a.push({id:l,data:{droppableContainer:s,value:h}})}}return a.sort(ai)},Cg=e=>{let{collisionRect:t,droppableRects:r,droppableContainers:n}=e;const o=si(t),a=[];for(const s of n){const{id:l}=s,g=r.get(l);if(g){const h=si(g),c=o.reduce((u,f,p)=>u+oi(h[p],f),0),i=Number((c/4).toFixed(4));a.push({id:l,data:{droppableContainer:s,value:i}})}}return a.sort(ai)};function Sg(e,t){const r=Math.max(t.top,e.top),n=Math.max(t.left,e.left),o=Math.min(t.left+t.width,e.left+e.width),a=Math.min(t.top+t.height,e.top+e.height),s=o-n,l=a-r;if(n<o&&r<a){const g=t.width*t.height,h=e.width*e.height,c=s*l,i=c/(g+h-c);return Number(i.toFixed(4))}return 0}const _g=e=>{let{collisionRect:t,droppableRects:r,droppableContainers:n}=e;const o=[];for(const a of n){const{id:s}=a,l=r.get(s);if(l){const g=Sg(l,t);g>0&&o.push({id:s,data:{droppableContainer:a,value:g}})}}return o.sort(xg)};function Eg(e,t,r){return{...e,scaleX:t&&r?t.width/r.width:1,scaleY:t&&r?t.height/r.height:1}}function ci(e,t){return e&&t?{x:e.left-t.left,y:e.top-t.top}:Gt}function Tg(e){return function(r){for(var n=arguments.length,o=new Array(n>1?n-1:0),a=1;a<n;a++)o[a-1]=arguments[a];return o.reduce((s,l)=>({...s,top:s.top+e*l.y,bottom:s.bottom+e*l.y,left:s.left+e*l.x,right:s.right+e*l.x}),{...r})}}const Ng=Tg(1);function Ag(e){if(e.startsWith("matrix3d(")){const t=e.slice(9,-1).split(/, /);return{x:+t[12],y:+t[13],scaleX:+t[0],scaleY:+t[5]}}else if(e.startsWith("matrix(")){const t=e.slice(7,-1).split(/, /);return{x:+t[4],y:+t[5],scaleX:+t[0],scaleY:+t[3]}}return null}function Mg(e,t,r){const n=Ag(t);if(!n)return e;const{scaleX:o,scaleY:a,x:s,y:l}=n,g=e.left-s-(1-o)*parseFloat(r),h=e.top-l-(1-a)*parseFloat(r.slice(r.indexOf(" ")+1)),c=o?e.width/o:e.width,i=a?e.height/a:e.height;return{width:c,height:i,top:h,right:g+c,bottom:h+i,left:g}}const Og={ignoreTransform:!1};function Ir(e,t){t===void 0&&(t=Og);let r=e.getBoundingClientRect();if(t.ignoreTransform){const{transform:h,transformOrigin:c}=yt(e).getComputedStyle(e);h&&(r=Mg(r,h,c))}const{top:n,left:o,width:a,height:s,bottom:l,right:g}=r;return{top:n,left:o,width:a,height:s,bottom:l,right:g}}function di(e){return Ir(e,{ignoreTransform:!0})}function Ig(e){const t=e.innerWidth,r=e.innerHeight;return{top:0,left:0,right:t,bottom:r,width:t,height:r}}function Dg(e,t){return t===void 0&&(t=yt(e).getComputedStyle(e)),t.position==="fixed"}function Lg(e,t){t===void 0&&(t=yt(e).getComputedStyle(e));const r=/(auto|scroll|overlay)/;return["overflow","overflowX","o Line truncated
`},Hg={onDragStart(e){let{active:t}=e;return"Picked up draggable item "+t.id+"."},onDragOver(e){let{active:t,over:r}=e;return r?"Draggable item "+t.id+" was moved over droppable area "+r.id+".":"Draggable item "+t.id+" is no longer over a droppable area."},onDragEnd(e){let{active:t,over:r}=e;return r?"Draggable item "+t.id+" was dropped over droppable area "+r.id:"Draggable item "+t.id+" was dropped."},onDragCancel(e){let{active:t}=e;return"Dragging was cancelled. Draggable item "+t.id+" was dropped."}};function Gg(e){let{announcements:t=Hg,container:r,hiddenTextDescribedById:n,screenReaderInstructions:o=zg}=e;const{announce:a,announcement:s}=Fg(),l=on("DndLiveRegion"),[f,h]=C.useState(!1);if(C.useEffect(()=>{h(!0)},[]),$g(C.useMemo(()=>({onDragStart(i){let{active:u}=i;a(t.onDragStart({active:u}))},onDragMove(i){let{active:u,over:g}=i;t.onDragMove&&a(t.onDragMove({active:u,over:g}))},onDragOver(i){let{active:u,over:g}=i;a(t.onDragOver({active:u,over:g}))},onDragEnd(i){let{active:u,over:g}=i;a(t.onDragEnd({active:u,over:g}))},onDragCancel(i){let{active:u,over:g}=i;a(t.onDragCancel({active:u,over:g}))}}),[a,t])),!f)return null;const c=C.createElement(C.Fragment,null,C.createElement(Lg,{id:n,value:o.draggable}),C.createElement(Pg,{id:l,announcement:s}));return r?Rt.createPortal(c,r):c}var tt;(function(e){e.DragStart="dragStart",e.DragMove="dragMove",e.DragEnd="dragEnd",e.DragCancel="dragCancel",e.DragOver="dragOver",e.RegisterDroppable="registerDroppable",e.SetDroppableDisabled="setDroppableDisabled",e.UnregisterDroppable="unregisterDroppable"})(tt||(tt={}));function Bn(){}function hi(e,t){return C.useMemo(()=>({sensor:e,options:t??{}}),[e,t])}function jg(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];return C.useMemo(()=>[...t].filter(n=>n!=null),[...t])}const Vt=Object.freeze({x:0,y:0});function pi(e,t){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))}function mi(e,t){let{data:{value:r}}=e,{data:{value:n}}=t;return r-n}function Bg(e,t){let{data:{value:r}}=e,{data:{value:n}}=t;return n-r}function bi(e){let{left:t,top:r,height:n,width:o}=e;return[{x:t,y:r},{x:t+o,y:r},{x:t,y:r+n},{x:t+o,y:r+n}]}function yi(e,t){if(!e||e.length===0)return null;const[r]=e;return r[t]}function vi(e,t,r){return t===void 0&&(t=e.left),r===void 0&&(r=e.top),{x:t+e.width*.5,y:r+e.height*.5}}const Wg=e=>{let{collisionRect:t,droppableRects:r,droppableContainers:n}=e;const o=vi(t,t.left,t.top),a=[];for(const s of n){const{id:l}=s,f=r.get(l);if(f){const h=pi(vi(f),o);a.push({id:l,data:{droppableContainer:s,value:h}})}}return a.sort(mi)},Kg=e=>{let{collisionRect:t,droppableRects:r,droppableContainers:n}=e;const o=bi(t),a=[];for(const s of n){const{id:l}=s,f=r.get(l);if(f){const h=bi(f),c=o.reduce((u,g,p)=>u+pi(h[p],g),0),i=Number((c/4).toFixed(4));a.push({id:l,data:{droppableContainer:s,value:i}})}}return a.sort(mi)};function Vg(e,t){const r=Math.max(t.top,e.top),n=Math.max(t.left,e.left),o=Math.min(t.left+t.width,e.left+e.width),a=Math.min(t.top+t.height,e.top+e.height),s=o-n,l=a-r;if(n<o&&r<a){const f=t.width*t.height,h=e.width*e.height,c=s*l,i=c/(f+h-c);return Number(i.toFixed(4))}return 0}const Yg=e=>{let{collisionRect:t,droppableRects:r,droppableContainers:n}=e;const o=[];for(const a of n){const{id:s}=a,l=r.get(s);if(l){const f=Vg(l,t);f>0&&o.push({id:s,data:{droppableContainer:a,value:f}})}}return o.sort(Bg)};function Xg(e,t,r){return{...e,scaleX:t&&r?t.width/r.width:1,scaleY:t&&r?t.height/r.height:1}}function wi(e,t){return e&&t?{x:e.left-t.left,y:e.top-t.top}:Vt}function Zg(e){return function(r){for(var n=arguments.length,o=new Array(n>1?n-1:0),a=1;a<n;a++)o[a-1]=arguments[a];return o.reduce((s,l)=>({...s,top:s.top+e*l.y,bottom:s.bottom+e*l.y,left:s.left+e*l.x,right:s.right+e*l.x}),{...r})}}const qg=Zg(1);function Qg(e){if(e.startsWith("matrix3d(")){const t=e.slice(9,-1).split(/, /);return{x:+t[12],y:+t[13],scaleX:+t[0],scaleY:+t[5]}}else if(e.startsWith("matrix(")){const t=e.slice(7,-1).split(/, /);return{x:+t[4],y:+t[5],scaleX:+t[0],scaleY:+t[3]}}return null}function Jg(e,t,r){const n=Qg(t);if(!n)return e;const{scaleX:o,scaleY:a,x:s,y:l}=n,f=e.left-s-(1-o)*parseFloat(r),h=e.top-l-(1-a)*parseFloat(r.slice(r.indexOf(" ")+1)),c=o?e.width/o:e.width,i=a?e.height/a:e.height;return{width:c,height:i,top:h,right:f+c,bottom:h+i,left:f}}const Rg={ignoreTransform:!1};function zr(e,t){t===void 0&&(t=Rg);let r=e.getBoundingClientRect();if(t.ignoreTransform){const{transform:h,transformOrigin:c}=xt(e).getComputedStyle(e);h&&(r=Jg(r,h,c))}const{top:n,left:o,width:a,height:s,bottom:l,right:f}=r;return{top:n,left:o,width:a,height:s,bottom:l,right:f}}function xi(e){return zr(e,{ignoreTransform:!0})}function eh(e){const t=e.innerWidth,r=e.innerHeight;return{top:0,left:0,right:t,bottom:r,width:t,height:r}}function th(e,t){return t===void 0&&(t=xt(e).getComputedStyle(e)),t.position==="fixed"}function rh(e,t){t===void 0&&(t=xt(e).getComputedStyle(e));const r=/(auto|scroll|overlay)/;return["overflow","overflowX","o Line truncated
flex items-center gap-3 p-4 rounded-lg border shadow-lg
min-w-[300px] max-w-md
transition-all duration-300
${o.bg}
${r?"opacity-100 translate-y-0":`opacity-0 ${s}`}
`,role:"alert",children:[d.jsx(ce,{name:a,className:`w-5 h-5 flex-shrink-0 ${o.text}`}),d.jsx(te,{className:`flex-1 text-sm font-medium ${o.text}`,children:e.message}),d.jsx(Q,{onClick:n,className:`flex-shrink-0 p-1 rounded hover:bg-black/10 dark:hover:bg-white/10 ${o.text} focus:outline-none`,"aria-label":Yh("common.close"),children:d.jsx(ce,{name:Je.Times,className:"w-4 h-4"})})]})},Qh=Object.freeze(Object.defineProperty({__proto__:null,Toast:xa,default:xa},Symbol.toStringTag,{value:"Module"})),Jh=window.G7Core?.createLogger?.("Comp:PageTransition")??{log:(...e)=>console.log("[Comp:PageTransition]",...e),warn:(...e)=>console.warn("[Comp:PageTransition]",...e),error:(...e)=>console.error("[Comp:PageTransition]",...e)},ka=({className:e="",style:t})=>{const[r,n]=k.useState(!1);return k.useEffect(()=>{const o=window.G7Core?.TransitionManager;if(!o){Jh.warn("TransitionManager를 찾을 수 없습니다.");return}return n(o.getIsPending()),o.subscribe(s=>{n(s)})},[]),r?d.jsxs(W,{className:`fixed top-0 left-0 right-0 z-50 ${e}`,style:t,role:"progressbar","aria-label":"페이지 로딩 중",children:[d.jsx(W,{className:"h-1 bg-gradient-to-r from-blue-500 via-blue-600 to-blue-500 animate-pulse",children:d.jsx(W,{className:"h-full bg-blue-700 animate-[loading_1.5s_ease-in-out_infinite]",style:{width:"30%",animation:"loading 1.5s ease-in-out infinite"}})}),d.jsx("style",{children:`
`,role:"alert",children:[d.jsx(fe,{name:a,className:`w-5 h-5 flex-shrink-0 ${o.text}`}),d.jsx(re,{className:`flex-1 text-sm font-medium ${o.text}`,children:e.message}),d.jsx(Q,{onClick:n,className:`flex-shrink-0 p-1 rounded hover:bg-black/10 dark:hover:bg-white/10 ${o.text} focus:outline-none`,"aria-label":p0("common.close"),children:d.jsx(fe,{name:Re.Times,className:"w-4 h-4"})})]})},v0=Object.freeze(Object.defineProperty({__proto__:null,Toast:Ca,default:Ca},Symbol.toStringTag,{value:"Module"})),w0=window.G7Core?.createLogger?.("Comp:PageTransition")??{log:(...e)=>console.log("[Comp:PageTransition]",...e),warn:(...e)=>console.warn("[Comp:PageTransition]",...e),error:(...e)=>console.error("[Comp:PageTransition]",...e)},Sa=({className:e="",style:t})=>{const[r,n]=C.useState(!1);return C.useEffect(()=>{const o=window.G7Core?.TransitionManager;if(!o){w0.warn("TransitionManager를 찾을 수 없습니다.");return}return n(o.getIsPending()),o.subscribe(s=>{n(s)})},[]),r?d.jsxs(W,{className:`fixed top-0 left-0 right-0 z-50 ${e}`,style:t,role:"progressbar","aria-label":"페이지 로딩 중",children:[d.jsx(W,{className:"h-1 bg-gradient-to-r from-blue-500 via-blue-600 to-blue-500 animate-pulse",children:d.jsx(W,{className:"h-full bg-blue-700 animate-[loading_1.5s_ease-in-out_infinite]",style:{width:"30%",animation:"loading 1.5s ease-in-out infinite"}})}),d.jsx("style",{children:`
@keyframes loading {
0% {
transform: translateX(-100%);
@@ -83,5 +84,5 @@ self.addEventListener('message', async (e) => {
transform: translateX(-100%);
}
}
`})]}):null},Rh=Object.freeze(Object.defineProperty({__proto__:null,PageTransitionIndicator:ka,default:ka},Symbol.toStringTag,{value:"Module"})),Vi=window.G7Core?.createLogger?.("Comp:PageTransitionBlur")??{log:(...e)=>console.log("[Comp:PageTransitionBlur]",...e),warn:(...e)=>console.warn("[Comp:PageTransitionBlur]",...e)},Ca=({className:e="",style:t})=>{const[r,n]=k.useState(!1);return k.useEffect(()=>{const o=window.G7Core?.TransitionManager;if(!o){Vi.warn("TransitionManager를 찾을 수 없습니다.");return}return n(o.getIsPending()),o.subscribe(s=>{Vi.log("isPending changed:",s),n(s)})},[]),r?d.jsx(W,{className:`fixed inset-0 z-40 bg-white/30 dark:bg-gray-900/30 backdrop-blur-sm transition-opacity duration-150 pointer-events-none ${e}`,style:t,role:"status","aria-label":"페이지 전환 중","data-testid":"page-transition-blur"}):null},e0=Object.freeze(Object.defineProperty({__proto__:null,PageTransitionBlur:Ca,default:Ca},Symbol.toStringTag,{value:"Module"})),Yi={sm:640,md:768,lg:1024,xl:1280,"2xl":1536},Xi=new Set(["hidden","block","inline-block","inline","flex","inline-flex","grid","inline-grid","table","table-row","table-cell","contents","list-item","flow-root"]),t0=new Set(["Div","Flex","Grid","Section","Article","Nav","Aside","Main","Header","Footer","Fragment","Form","Container"]),r0=new Set(["H1","H2","H3","H4","H5","H6","P","Span","Label","A","Strong","Em","Small","Badge"]),n0=new Set(["Input","Textarea","Select","Checkbox","Radio","Toggle","DatePicker","TagInput","SearchBar"]),o0=new Set(["Img","Image","Avatar","AvatarUploader","ImageGallery","ProductImageViewer","FileUploader"]),qi={DataGrid:(e,t)=>d.jsxs("div",{className:"w-full border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden",children:[d.jsx("div",{className:`h-10 bg-gray-100 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 ${e}`,children:d.jsxs("div",{className:"flex items-center h-full px-4 gap-8",children:[d.jsx("div",{className:"h-3 w-16 bg-gray-300 dark:bg-gray-600 rounded"}),d.jsx("div",{className:"h-3 w-24 bg-gray-300 dark:bg-gray-600 rounded"}),d.jsx("div",{className:"h-3 w-20 bg-gray-300 dark:bg-gray-600 rounded"}),d.jsx("div",{className:"h-3 w-16 bg-gray-300 dark:bg-gray-600 rounded"})]})}),Array.from({length:t},(r,n)=>d.jsx("div",{className:`h-12 border-b border-gray-100 dark:border-gray-800 ${e}`,style:{animationDelay:`${n*75}ms`},children:d.jsxs("div",{className:"flex items-center h-full px-4 gap-8",children:[d.jsx("div",{className:"h-3 w-12 bg-gray-200 dark:bg-gray-700 rounded"}),d.jsx("div",{className:"h-3 flex-1 bg-gray-200 dark:bg-gray-700 rounded"}),d.jsx("div",{className:"h-3 w-16 bg-gray-100 dark:bg-gray-800 rounded"}),d.jsx("div",{className:"h-3 w-14 bg-gray-100 dark:bg-gray-800 rounded"})]})},n))]}),Pagination:e=>d.jsx("div",{className:"flex justify-center gap-1.5 py-3",children:Array.from({length:5},(t,r)=>d.jsx("div",{className:`w-8 h-8 bg-gray-200 dark:bg-gray-700 rounded ${e}`},r))}),Tabs:e=>d.jsxs("div",{children:[d.jsx("div",{className:"flex gap-4 border-b border-gray-200 dark:border-gray-700 pb-2 mb-3",children:Array.from({length:3},(t,r)=>d.jsx("div",{className:`h-4 w-20 bg-gray-200 dark:bg-gray-700 rounded ${e}`},r))}),d.jsx("div",{className:`h-32 bg-gray-100 dark:bg-gray-800 rounded ${e}`})]}),TabNavigation:e=>d.jsx("div",{className:"flex gap-4 border-b border-gray-200 dark:border-gray-700 pb-2",children:Array.from({length:3},(t,r)=>d.jsx("div",{className:`h-4 w-20 bg-gray-200 dark:bg-gray-700 rounded ${e}`},r))}),ProductCard:e=>d.jsxs("div",{className:"rounded-lg overflow-hidden",children:[d.jsx("div",{className:`h-48 w-full bg-gray-200 dark:bg-gray-700 ${e}`}),d.jsxs("div",{className:"p-3 space-y-2",children:[d.jsx("div",{className:`h-3.5 w-3/4 bg-gray-200 dark:bg-gray-700 rounded ${e}`}),d.jsx("div",{className:`h-4 w-1/3 bg-gray-300 dark:bg-gray-600 rounded ${e}`})]})]}),UserInfo:e=>d.jsx("div",{className:`h-3 w-14 bg-gray-200 dark:bg-gray-700 rounded ${e}`}),QuantitySelector:e=>d.jsx("div",{className:`h-9 w-28 bg-gray-100 dark:bg-gray-800 rounded border border-gray-200 dark:border-gray-700 ${e}`}),Header:e=>d.jsx("header",{className:"bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700",children:d.jsx("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8",children:d.jsxs("div",{className:"flex items-center justify-between h-16",children:[d.jsxs("div",{className:"flex items-center gap-8",children:[d.jsx("div",{className:`h-8 w-24 bg-gray-200 dark:bg-gray-700 rounded ${e}`}),d.jsx("div",{className:"hidden lg:flex items-center gap-6",children:Array.from({length:4},(t,r)=>d.jsx("div",{className:`h-3.5 w-16 bg-gray-200 dark:bg-gray-700 rounded ${e}`},r))})]}),d.jsx("div",{className:"flex items-center gap-4",children:Array.from({length:3},(t,r)=>d.jsx("div",{className:`h-8 w-8 bg-gray-200 dark:bg-gray-700 rounded-full ${e}`},r))})]})})}),Footer:e=>d.jsx("footer",{className:"bg-white dark:bg-gray-800 border-t border-gray-200 dark:border-gray- Line truncated
`})]}):null},x0=Object.freeze(Object.defineProperty({__proto__:null,PageTransitionIndicator:Sa,default:Sa},Symbol.toStringTag,{value:"Module"})),nc=window.G7Core?.createLogger?.("Comp:PageTransitionBlur")??{log:(...e)=>console.log("[Comp:PageTransitionBlur]",...e),warn:(...e)=>console.warn("[Comp:PageTransitionBlur]",...e)},_a=({className:e="",style:t})=>{const[r,n]=C.useState(!1);return C.useEffect(()=>{const o=window.G7Core?.TransitionManager;if(!o){nc.warn("TransitionManager를 찾을 수 없습니다.");return}return n(o.getIsPending()),o.subscribe(s=>{nc.log("isPending changed:",s),n(s)})},[]),r?d.jsx(W,{className:`fixed inset-0 z-40 bg-white/30 dark:bg-gray-900/30 backdrop-blur-sm transition-opacity duration-150 pointer-events-none ${e}`,style:t,role:"status","aria-label":"페이지 전환 중","data-testid":"page-transition-blur"}):null},k0=Object.freeze(Object.defineProperty({__proto__:null,PageTransitionBlur:_a,default:_a},Symbol.toStringTag,{value:"Module"})),oc={sm:640,md:768,lg:1024,xl:1280,"2xl":1536},ac=new Set(["hidden","block","inline-block","inline","flex","inline-flex","grid","inline-grid","table","table-row","table-cell","contents","list-item","flow-root"]),C0=new Set(["Div","Flex","Grid","Section","Article","Nav","Aside","Main","Header","Footer","Fragment","Form","Container"]),S0=new Set(["H1","H2","H3","H4","H5","H6","P","Span","Label","A","Strong","Em","Small","Badge"]),_0=new Set(["Input","Textarea","Select","Checkbox","Radio","Toggle","DatePicker","TagInput","SearchBar"]),E0=new Set(["Img","Image","Avatar","AvatarUploader","ImageGallery","ProductImageViewer","FileUploader"]),sc={DataGrid:(e,t)=>d.jsxs("div",{className:"w-full border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden",children:[d.jsx("div",{className:`h-10 bg-gray-100 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 ${e}`,children:d.jsxs("div",{className:"flex items-center h-full px-4 gap-8",children:[d.jsx("div",{className:"h-3 w-16 bg-gray-300 dark:bg-gray-600 rounded"}),d.jsx("div",{className:"h-3 w-24 bg-gray-300 dark:bg-gray-600 rounded"}),d.jsx("div",{className:"h-3 w-20 bg-gray-300 dark:bg-gray-600 rounded"}),d.jsx("div",{className:"h-3 w-16 bg-gray-300 dark:bg-gray-600 rounded"})]})}),Array.from({length:t},(r,n)=>d.jsx("div",{className:`h-12 border-b border-gray-100 dark:border-gray-800 ${e}`,style:{animationDelay:`${n*75}ms`},children:d.jsxs("div",{className:"flex items-center h-full px-4 gap-8",children:[d.jsx("div",{className:"h-3 w-12 bg-gray-200 dark:bg-gray-700 rounded"}),d.jsx("div",{className:"h-3 flex-1 bg-gray-200 dark:bg-gray-700 rounded"}),d.jsx("div",{className:"h-3 w-16 bg-gray-100 dark:bg-gray-800 rounded"}),d.jsx("div",{className:"h-3 w-14 bg-gray-100 dark:bg-gray-800 rounded"})]})},n))]}),Pagination:e=>d.jsx("div",{className:"flex justify-center gap-1.5 py-3",children:Array.from({length:5},(t,r)=>d.jsx("div",{className:`w-8 h-8 bg-gray-200 dark:bg-gray-700 rounded ${e}`},r))}),Tabs:e=>d.jsxs("div",{children:[d.jsx("div",{className:"flex gap-4 border-b border-gray-200 dark:border-gray-700 pb-2 mb-3",children:Array.from({length:3},(t,r)=>d.jsx("div",{className:`h-4 w-20 bg-gray-200 dark:bg-gray-700 rounded ${e}`},r))}),d.jsx("div",{className:`h-32 bg-gray-100 dark:bg-gray-800 rounded ${e}`})]}),TabNavigation:e=>d.jsx("div",{className:"flex gap-4 border-b border-gray-200 dark:border-gray-700 pb-2",children:Array.from({length:3},(t,r)=>d.jsx("div",{className:`h-4 w-20 bg-gray-200 dark:bg-gray-700 rounded ${e}`},r))}),ProductCard:e=>d.jsxs("div",{className:"rounded-lg overflow-hidden",children:[d.jsx("div",{className:`h-48 w-full bg-gray-200 dark:bg-gray-700 ${e}`}),d.jsxs("div",{className:"p-3 space-y-2",children:[d.jsx("div",{className:`h-3.5 w-3/4 bg-gray-200 dark:bg-gray-700 rounded ${e}`}),d.jsx("div",{className:`h-4 w-1/3 bg-gray-300 dark:bg-gray-600 rounded ${e}`})]})]}),UserInfo:e=>d.jsx("div",{className:`h-3 w-14 bg-gray-200 dark:bg-gray-700 rounded ${e}`}),QuantitySelector:e=>d.jsx("div",{className:`h-9 w-28 bg-gray-100 dark:bg-gray-800 rounded border border-gray-200 dark:border-gray-700 ${e}`}),Header:e=>d.jsx("header",{className:"bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700",children:d.jsx("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8",children:d.jsxs("div",{className:"flex items-center justify-between h-16",children:[d.jsxs("div",{className:"flex items-center gap-8",children:[d.jsx("div",{className:`h-8 w-24 bg-gray-200 dark:bg-gray-700 rounded ${e}`}),d.jsx("div",{className:"hidden lg:flex items-center gap-6",children:Array.from({length:4},(t,r)=>d.jsx("div",{className:`h-3.5 w-16 bg-gray-200 dark:bg-gray-700 rounded ${e}`},r))})]}),d.jsx("div",{className:"flex items-center gap-4",children:Array.from({length:3},(t,r)=>d.jsx("div",{className:`h-8 w-8 bg-gray-200 dark:bg-gray-700 rounded-full ${e}`},r))})]})})}),Footer:e=>d.jsx("footer",{className:"bg-white dark:bg-gray-800 border-t border-gray-200 dark:border-gray- Line truncated
//# sourceMappingURL=components.iife.js.map
@@ -1 +1 @@
{"version":3,"file":"components.iife.js","sources":["../../src/components/basic/Button.tsx","../../src/components/basic/Div.tsx","../../src/components/basic/Span.tsx","../../src/components/basic/Svg.tsx","../../src/components/basic/Input.tsx","../../src/components/basic/FileInput.tsx","../../src/components/basic/IconTypes.ts","../../src/components/basic/Icon.tsx","../../src/components/basic/PasswordInput.tsx","../../src/components/basic/Textarea.tsx","../../src/components/basic/Label.tsx","../../src/components/basic/P.tsx","../../src/components/basic/Img.tsx","../../src/components/basic/H1.tsx","../../src/components/basic/H2.tsx","../../src/components/basic/H3.tsx","../../src/components/basic/H4.tsx","../../src/components/basic/Ul.tsx","../../src/components/basic/Ol.tsx","../../src/components/basic/Li.tsx","../../src/components/basic/A.tsx","../../src/components/basic/Form.tsx","../../src/components/basic/Select.tsx","../../src/components/basic/Option.tsx","../../src/components/basic/Optgroup.tsx","../../src/components/basic/Checkbox.tsx","../../src/components/basic/Table.tsx","../../src/components/basic/Thead.tsx","../../src/components/basic/Tbody.tsx","../../src/components/basic/Tr.tsx","../../src/components/basic/Th.tsx","../../src/components/basic/Td.tsx","../../src/components/basic/Nav.tsx","../../src/components/basic/Section.tsx","../../src/components/basic/Code.tsx","../../src/components/basic/Hr.tsx","../../src/components/basic/Header.tsx","../../src/components/composite/ThemeToggle.tsx","../../src/components/composite/Avatar.tsx","../../src/components/composite/SlotContainer.tsx","../../src/components/composite/NotificationCenter.tsx","../../src/components/composite/Header.tsx","../../src/components/basic/Footer.tsx","../../src/components/composite/Footer.tsx","../../src/components/composite/MobileNav.tsx","../../node_modules/dompurify/dist/purify.es.mjs","../../src/components/composite/ProductCard.tsx","../../node_modules/yet-another-react-lightbox/dist/types.js","../../node_modules/yet-another-react-lightbox/dist/index.js","../../node_modules/yet-another-react-lightbox/dist/plugins/zoom/index.js","../../node_modules/yet-another-react-lightbox/dist/plugins/counter/index.js","../../node_modules/yet-another-react-lightbox/dist/plugins/slideshow/index.js","../../node_modules/yet-another-react-lightbox/dist/plugins/fullscreen/index.js","../../node_modules/yet-another-react-lightbox/dist/plugins/thumbnails/index.js","../../src/components/basic/I.tsx","../../src/components/composite/ImageGallery.tsx","../../src/components/composite/ProductImageViewer.tsx","../../src/components/composite/QuantitySelector.tsx","../../src/components/composite/PostReactions.tsx","../../src/components/composite/RichTextEditor.tsx","../../src/components/composite/HtmlContent.tsx","../../src/components/composite/HtmlEditor.tsx","../../src/components/composite/ExpandableContent.tsx","../../src/components/composite/Modal.tsx","../../src/components/composite/ConfirmDialog.tsx","../../src/components/composite/FileUploader/FileUploaderContext.tsx","../../node_modules/browser-image-compression/dist/browser-image-compression.mjs","../../src/components/composite/FileUploader/utils.ts","../../src/components/composite/FileUploader/useFileUploader.ts","../../src/components/composite/FileUploader/FileDropZone.tsx","../../node_modules/@dnd-kit/utilities/dist/utilities.esm.js","../../node_modules/@dnd-kit/accessibility/dist/accessibility.esm.js","../../node_modules/@dnd-kit/core/dist/core.esm.js","../../node_modules/@dnd-kit/sortable/dist/sortable.esm.js","../../src/components/composite/FileUploader/SortableThumbnailItem.tsx","../../src/components/composite/FileUploader/FileList.tsx","../../src/components/composite/FileUploader/FileUploader.tsx","../../src/components/composite/SocialLoginButtons.tsx","../../src/components/composite/Toast.tsx","../../src/components/composite/PageTransitionIndicator.tsx","../../src/components/composite/PageTransitionBlur.tsx","../../src/components/composite/PageSkeleton.tsx","../../src/components/composite/PageLoading.tsx","../../src/components/composite/Pagination.tsx","../../src/components/composite/SearchBar.tsx","../../src/components/composite/AvatarUploader.tsx","../../src/components/composite/UserInfo.tsx","../../src/components/composite/TabNavigation.tsx","../../src/components/composite/index.ts","../../src/components/layout/Container.tsx","../../src/components/layout/Grid.tsx","../../src/components/layout/Flex.tsx","../../src/components/layout/SectionLayout.tsx","../../src/components/layout/ThreeColumnLayout.tsx","../../src/handlers/productOptions.ts","../../src/handlers/cartHandlers.ts","../../src/handlers/cartOptionChange.ts","../../src/handlers/storageHandlers.ts","../../src/handlers/getDisplayPrice.ts","../../src/handlers/formatCurrency.ts","../../src/handlers/loadPreferredCurrency.ts","../../src/handlers/setThemeHandler.ts","../../src/handlers/redirectToLoginWithReturn.ts","../../src/handlers/doLine truncated
{"version":3,"file":"components.iife.js","sources":["../../src/components/basic/Button.tsx","../../src/components/basic/Div.tsx","../../src/components/basic/Span.tsx","../../src/components/basic/Svg.tsx","../../src/components/basic/Input.tsx","../../src/components/basic/FileInput.tsx","../../src/components/basic/IconTypes.ts","../../src/components/basic/Icon.tsx","../../src/components/basic/PasswordInput.tsx","../../src/components/basic/Textarea.tsx","../../src/components/basic/Label.tsx","../../src/components/basic/P.tsx","../../src/components/basic/Img.tsx","../../src/components/basic/H1.tsx","../../src/components/basic/H2.tsx","../../src/components/basic/H3.tsx","../../src/components/basic/H4.tsx","../../src/components/basic/Ul.tsx","../../src/components/basic/Ol.tsx","../../src/components/basic/Li.tsx","../../src/components/basic/A.tsx","../../src/components/basic/Form.tsx","../../src/components/basic/Select.tsx","../../src/components/basic/Option.tsx","../../src/components/basic/Optgroup.tsx","../../src/components/basic/Checkbox.tsx","../../src/components/basic/Table.tsx","../../src/components/basic/Thead.tsx","../../src/components/basic/Tbody.tsx","../../src/components/basic/Tr.tsx","../../src/components/basic/Th.tsx","../../src/components/basic/Td.tsx","../../src/components/basic/Nav.tsx","../../src/components/basic/Section.tsx","../../src/components/basic/Code.tsx","../../src/components/basic/Hr.tsx","../../src/components/basic/Header.tsx","../../src/components/composite/ThemeToggle.tsx","../../src/components/composite/Avatar.tsx","../../src/components/composite/SlotContainer.tsx","../../src/components/composite/NotificationCenter.tsx","../../src/components/composite/Header.tsx","../../src/components/basic/Footer.tsx","../../src/components/composite/Footer.tsx","../../src/components/composite/MobileNav.tsx","../../node_modules/dompurify/dist/purify.es.mjs","../../src/components/composite/ProductCard.tsx","../../node_modules/yet-another-react-lightbox/dist/types.js","../../node_modules/yet-another-react-lightbox/dist/index.js","../../node_modules/yet-another-react-lightbox/dist/plugins/zoom/index.js","../../node_modules/yet-another-react-lightbox/dist/plugins/counter/index.js","../../node_modules/yet-another-react-lightbox/dist/plugins/slideshow/index.js","../../node_modules/yet-another-react-lightbox/dist/plugins/fullscreen/index.js","../../node_modules/yet-another-react-lightbox/dist/plugins/thumbnails/index.js","../../src/components/basic/I.tsx","../../src/components/composite/ImageGallery.tsx","../../src/components/composite/ProductImageViewer.tsx","../../src/components/composite/QuantitySelector.tsx","../../src/components/composite/PostReactions.tsx","../../src/components/composite/RichTextEditor.tsx","../../src/components/composite/HtmlContent.tsx","../../src/components/composite/HtmlEditor.tsx","../../src/components/composite/ExpandableContent.tsx","../../src/components/composite/Modal.tsx","../../src/components/composite/ConfirmDialog.tsx","../../src/components/composite/FileUploader/FileUploaderContext.tsx","../../node_modules/browser-image-compression/dist/browser-image-compression.mjs","../../src/components/composite/FileUploader/utils.ts","../../src/components/composite/FileUploader/useFileUploader.ts","../../src/components/composite/FileUploader/FileDropZone.tsx","../../node_modules/@dnd-kit/utilities/dist/utilities.esm.js","../../node_modules/@dnd-kit/accessibility/dist/accessibility.esm.js","../../node_modules/@dnd-kit/core/dist/core.esm.js","../../node_modules/@dnd-kit/sortable/dist/sortable.esm.js","../../src/components/composite/FileUploader/SortableThumbnailItem.tsx","../../src/components/composite/FileUploader/FileList.tsx","../../src/components/composite/FileUploader/FileUploader.tsx","../../src/components/composite/SocialLoginButtons.tsx","../../src/components/composite/Toast.tsx","../../src/components/composite/PageTransitionIndicator.tsx","../../src/components/composite/PageTransitionBlur.tsx","../../src/components/composite/PageSkeleton.tsx","../../src/components/composite/PageLoading.tsx","../../src/components/composite/Pagination.tsx","../../src/components/composite/SearchBar.tsx","../../src/components/composite/AvatarUploader.tsx","../../src/components/composite/UserInfo.tsx","../../src/components/composite/TabNavigation.tsx","../../src/components/composite/index.ts","../../src/components/layout/Container.tsx","../../src/components/layout/Grid.tsx","../../src/components/layout/Flex.tsx","../../src/components/layout/SectionLayout.tsx","../../src/components/layout/ThreeColumnLayout.tsx","../../src/handlers/productOptions.ts","../../src/handlers/cartHandlers.ts","../../src/handlers/cartOptionChange.ts","../../src/handlers/storageHandlers.ts","../../src/handlers/getDisplayPrice.ts","../../src/handlers/formatCurrency.ts","../../src/handlers/loadPreferredCurrency.ts","../../src/handlers/setThemeHandler.ts","../../src/handlers/redirectToLoginWithReturn.ts","../../src/handlers/doLine truncated
@@ -5,6 +5,7 @@
"delete_confirm_message": "Are you sure you want to delete this file?",
"deleting": "Deleting...",
"attached_count": "{{count}}/{{max}} attached",
"upload_limit_exceeded": "You can attach up to {{max}} files.",
"max_size": "Max {{size}}MB",
"reorder_failed": "Failed to reorder files",
"drag_to_reorder": "Drag to reorder",
@@ -5,6 +5,7 @@
"delete_confirm_message": "이 파일을 삭제하시겠습니까?",
"deleting": "삭제 중...",
"attached_count": "{{count}}/{{max}}개 첨부됨",
"upload_limit_exceeded": "최대 {{max}}개까지 첨부할 수 있습니다.",
"max_size": "최대 {{size}}MB",
"reorder_failed": "파일 순서 변경에 실패했습니다",
"drag_to_reorder": "드래그하여 순서 변경",
@@ -207,9 +207,17 @@ export function useFileUploader(options: UseFileUploaderOptions): UseFileUploade
const handleFiles = useCallback(
async (selectedFiles: FileList) => {
const totalCount = existingFiles.length + pendingFiles.length;
const remainingSlots = maxFiles - totalCount;
const remainingSlots = Math.max(0, maxFiles - totalCount);
const filesToAdd = Array.from(selectedFiles).slice(0, remainingSlots);
// 개수 상한 초과분은 조용히 절단하지 않고 안내 (개수 초과 silent 무시 방지)
if (selectedFiles.length > remainingSlots) {
const overflow = Array.from(selectedFiles).slice(remainingSlots);
const message = t('attachment.upload_limit_exceeded', { max: maxFiles });
// 잘린 첫 파일을 대표로 콜백에 전달 (없으면 무시)
onUploadError?.(message, overflow[0] ?? selectedFiles[0]);
}
for (const file of filesToAdd) {
// 크기 검증
if (file.size > maxSize * 1024 * 1024) {
@@ -0,0 +1,135 @@
/**
* FileUploader 개수 상한 초과 안내 테스트
*
* maxFiles 를 초과해 파일을 선택하면 초과분을 조용히 버리지 않고
* onUploadError 콜백으로 안내한다. (admin_basic 과 동일 동작 — 공통 문구)
*
* @vitest-environment jsdom
* @module composite/__tests__/FileUploaderLimit.test
*/
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { act, renderHook } from '@testing-library/react';
import { useFileUploader } from '../FileUploader/useFileUploader';
import type { Attachment } from '../FileUploader/types';
// G7Core 모킹 (useFileUploader 가 모듈 스코프에서 window.G7Core 를 캐싱하므로
// 새 객체로 교체하지 않고 기존 객체에 프로퍼티를 직접 추가)
beforeEach(() => {
const listeners = new Map<string, Set<Function>>();
if (!(window as any).G7Core) {
(window as any).G7Core = {};
}
const g7 = (window as any).G7Core;
g7.componentEvent = {
on: vi.fn((event: string, callback: Function) => {
if (!listeners.has(event)) {
listeners.set(event, new Set());
}
listeners.get(event)!.add(callback);
return () => {
listeners.get(event)?.delete(callback);
};
}),
emit: vi.fn(),
};
g7.createLogger = vi.fn(() => ({
log: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
}));
});
vi.mock('browser-image-compression', () => ({
default: vi.fn((file: File) => Promise.resolve(file)),
}));
URL.createObjectURL = vi.fn(() => 'blob:mock-url');
URL.revokeObjectURL = vi.fn();
describe('FileUploader - 개수 상한 초과 안내 (useFileUploader 훅)', () => {
const defaultEndpoints = {
upload: '/api/attachments',
delete: '/api/attachments/:id',
reorder: '/api/attachments/reorder',
};
const STABLE_EMPTY_FILES: Attachment[] = [];
const STABLE_EMPTY_ROLE_IDS: number[] = [];
function makeFileList(files: File[]): FileList {
return {
...files,
length: files.length,
item: (i: number) => files[i] ?? null,
} as unknown as FileList;
}
it('maxFiles 초과 시 onUploadError 로 안내하고 상한까지만 추가한다', async () => {
const onUploadError = vi.fn();
const { result } = renderHook(() =>
useFileUploader({
collection: 'test',
maxFiles: 2,
maxSize: 10,
maxConcurrentUploads: 3,
roleIds: STABLE_EMPTY_ROLE_IDS,
autoUpload: false,
initialFiles: STABLE_EMPTY_FILES,
confirmBeforeRemove: false,
onUploadError,
endpoints: defaultEndpoints,
})
);
// 상한(2)보다 많은 3개 선택
const files = [
new File(['1'], 'a.png', { type: 'image/png' }),
new File(['2'], 'b.png', { type: 'image/png' }),
new File(['3'], 'c.png', { type: 'image/png' }),
];
await act(async () => {
await result.current.handleFiles(makeFileList(files));
});
// 초과 안내 콜백 1회 (조용히 버리지 않음)
expect(onUploadError).toHaveBeenCalledTimes(1);
// 상한까지만 추가 (2개)
expect(result.current.pendingFiles).toHaveLength(2);
});
it('상한 이내로 선택하면 onUploadError 를 발화하지 않는다 (오발화 없음)', async () => {
const onUploadError = vi.fn();
const { result } = renderHook(() =>
useFileUploader({
collection: 'test',
maxFiles: 5,
maxSize: 10,
maxConcurrentUploads: 3,
roleIds: STABLE_EMPTY_ROLE_IDS,
autoUpload: false,
initialFiles: STABLE_EMPTY_FILES,
confirmBeforeRemove: false,
onUploadError,
endpoints: defaultEndpoints,
})
);
const files = [
new File(['1'], 'a.png', { type: 'image/png' }),
new File(['2'], 'b.png', { type: 'image/png' }),
];
await act(async () => {
await result.current.handleFiles(makeFileList(files));
});
expect(onUploadError).not.toHaveBeenCalled();
expect(result.current.pendingFiles).toHaveLength(2);
});
});