@designbasekorea/ui-wc 0.5.5 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/dist/chunks/lottie-e273b936.js +17032 -0
  2. package/dist/esm/components/animation-background/canvas-controller.js +121 -1
  3. package/dist/esm/components/animation-background/controls.js +180 -1
  4. package/dist/esm/components/animation-background/graphite-controller.js +196 -1
  5. package/dist/esm/components/animation-background/graphite-presets.js +42 -1
  6. package/dist/esm/components/animation-background/graphite-shader.js +111 -1
  7. package/dist/esm/components/animation-background/layers.js +369 -1
  8. package/dist/esm/components/animation-background/lumina-presets.js +53 -1
  9. package/dist/esm/components/animation-background/lumina-shaders.js +181 -1
  10. package/dist/esm/components/animation-background/lumina-utils.js +60 -1
  11. package/dist/esm/components/animation-background/particle-defaults.js +36 -1
  12. package/dist/esm/components/animation-background/renderers.js +167 -1
  13. package/dist/esm/components/animation-background/shader-controller.js +154 -1
  14. package/dist/esm/components/color-picker-utils.js +134 -1
  15. package/dist/esm/components/date-picker-utils.js +140 -1
  16. package/dist/esm/components/db-accordion.js +304 -1
  17. package/dist/esm/components/db-ad-banner.js +455 -1
  18. package/dist/esm/components/db-alert.js +149 -1
  19. package/dist/esm/components/db-animation-background.js +486 -1
  20. package/dist/esm/components/db-animation-text.js +601 -1
  21. package/dist/esm/components/db-app-badge.js +88 -1
  22. package/dist/esm/components/db-audio-player.js +752 -1
  23. package/dist/esm/components/db-avatar.js +188 -1
  24. package/dist/esm/components/db-backdrop.js +139 -1
  25. package/dist/esm/components/db-badge.js +91 -1
  26. package/dist/esm/components/db-banner.js +188 -1
  27. package/dist/esm/components/db-bottom-navigation.js +146 -1
  28. package/dist/esm/components/db-bottom-sheet.js +481 -1
  29. package/dist/esm/components/db-breadcrumbs.js +329 -1
  30. package/dist/esm/components/db-button.js +316 -1
  31. package/dist/esm/components/db-calendar.js +675 -1
  32. package/dist/esm/components/db-card.js +265 -1
  33. package/dist/esm/components/db-carousel.js +264 -1
  34. package/dist/esm/components/db-checkbox.js +202 -1
  35. package/dist/esm/components/db-chip.js +104 -1
  36. package/dist/esm/components/db-code-block.js +304 -1
  37. package/dist/esm/components/db-color-picker.js +746 -1
  38. package/dist/esm/components/db-confirm.js +191 -1
  39. package/dist/esm/components/db-container.js +39 -1
  40. package/dist/esm/components/db-context-menu.js +265 -1
  41. package/dist/esm/components/db-countdown.js +146 -1
  42. package/dist/esm/components/db-cursor-follower.js +173 -1
  43. package/dist/esm/components/db-date-picker.js +837 -1
  44. package/dist/esm/components/db-divider.js +66 -1
  45. package/dist/esm/components/db-drawer.js +245 -1
  46. package/dist/esm/components/db-dropdown.js +493 -1
  47. package/dist/esm/components/db-dropzone.js +266 -1
  48. package/dist/esm/components/db-empty-state.js +97 -1
  49. package/dist/esm/components/db-file-uploader.js +256 -1
  50. package/dist/esm/components/db-floating-action-button.js +139 -1
  51. package/dist/esm/components/db-footer.js +385 -1
  52. package/dist/esm/components/db-form.js +566 -1
  53. package/dist/esm/components/db-gantt.js +882 -1
  54. package/dist/esm/components/db-gradient.js +133 -1
  55. package/dist/esm/components/db-grid-background.js +909 -1
  56. package/dist/esm/components/db-grid.js +73 -1
  57. package/dist/esm/components/db-icons.js +82 -1
  58. package/dist/esm/components/db-image-list.js +214 -1
  59. package/dist/esm/components/db-image-placeholder.js +96 -1
  60. package/dist/esm/components/db-image.js +289 -1
  61. package/dist/esm/components/db-indicator.js +517 -1
  62. package/dist/esm/components/db-input.js +420 -1
  63. package/dist/esm/components/db-kanban.js +538 -1
  64. package/dist/esm/components/db-label.js +66 -1
  65. package/dist/esm/components/db-lightbox.js +372 -1
  66. package/dist/esm/components/db-list.js +340 -1
  67. package/dist/esm/components/db-logo-svg.js +72 -1
  68. package/dist/esm/components/db-logo.js +106 -1
  69. package/dist/esm/components/db-lottie.js +109 -1
  70. package/dist/esm/components/db-markdown-editor.js +458 -1
  71. package/dist/esm/components/db-marquee.js +402 -1
  72. package/dist/esm/components/db-masonry.js +94 -1
  73. package/dist/esm/components/db-menu-item.js +211 -1
  74. package/dist/esm/components/db-modal.js +522 -1
  75. package/dist/esm/components/db-navbar.js +680 -1
  76. package/dist/esm/components/db-onboarding-modal.js +322 -1
  77. package/dist/esm/components/db-page-header.js +312 -1
  78. package/dist/esm/components/db-pagination.js +271 -1
  79. package/dist/esm/components/db-popover.js +580 -1
  80. package/dist/esm/components/db-progress-step.js +166 -1
  81. package/dist/esm/components/db-progress.js +171 -1
  82. package/dist/esm/components/db-progressbar.js +72 -1
  83. package/dist/esm/components/db-radio.js +172 -1
  84. package/dist/esm/components/db-random-gradient.js +121 -1
  85. package/dist/esm/components/db-range-slider.js +811 -1
  86. package/dist/esm/components/db-rating.js +325 -1
  87. package/dist/esm/components/db-reorder.js +286 -1
  88. package/dist/esm/components/db-resizable-panels.js +282 -1
  89. package/dist/esm/components/db-scroll-area.js +126 -1
  90. package/dist/esm/components/db-search-bar.js +668 -1
  91. package/dist/esm/components/db-section-app-download.js +101 -1
  92. package/dist/esm/components/db-section-contact.js +102 -1
  93. package/dist/esm/components/db-section-cta.js +150 -1
  94. package/dist/esm/components/db-section-faq.js +120 -1
  95. package/dist/esm/components/db-section-feature-grid.js +137 -1
  96. package/dist/esm/components/db-section-feature.js +179 -1
  97. package/dist/esm/components/db-section-hero.js +243 -1
  98. package/dist/esm/components/db-section-logo-cloud.js +138 -1
  99. package/dist/esm/components/db-section-pricing.js +166 -1
  100. package/dist/esm/components/db-section-stats.js +129 -1
  101. package/dist/esm/components/db-section-testimonials.js +252 -1
  102. package/dist/esm/components/db-section.js +385 -1
  103. package/dist/esm/components/db-segment-control.js +231 -1
  104. package/dist/esm/components/db-select.js +571 -1
  105. package/dist/esm/components/db-share-icons.js +40 -1
  106. package/dist/esm/components/db-share.js +489 -1
  107. package/dist/esm/components/db-sidebar.js +1068 -1
  108. package/dist/esm/components/db-skeleton.js +94 -1
  109. package/dist/esm/components/db-spinner.js +102 -1
  110. package/dist/esm/components/db-split-view.js +297 -1
  111. package/dist/esm/components/db-stack.js +46 -1
  112. package/dist/esm/components/db-stat.js +218 -1
  113. package/dist/esm/components/db-stepper.js +398 -1
  114. package/dist/esm/components/db-table.js +412 -1
  115. package/dist/esm/components/db-tabs.js +335 -1
  116. package/dist/esm/components/db-testimonial.js +162 -1
  117. package/dist/esm/components/db-textarea.js +233 -1
  118. package/dist/esm/components/db-time-picker.js +523 -1
  119. package/dist/esm/components/db-timeline.js +174 -1
  120. package/dist/esm/components/db-toast.js +158 -1
  121. package/dist/esm/components/db-toggle.js +162 -1
  122. package/dist/esm/components/db-toolbar.js +94 -1
  123. package/dist/esm/components/db-tooltip.js +440 -1
  124. package/dist/esm/components/db-top-banner.js +121 -1
  125. package/dist/esm/components/db-tutorial.js +324 -1
  126. package/dist/esm/components/db-video-player.js +503 -1
  127. package/dist/esm/components/db-youtube-player.js +194 -1
  128. package/dist/esm/components/highlight-code.js +65 -1
  129. package/dist/esm/components/input-validation.js +50 -1
  130. package/dist/esm/components/marketing-block-host-utils.js +9 -1
  131. package/dist/esm/components/number-scrub.js +117 -1
  132. package/dist/esm/components/random-gradient-palettes.js +67 -1
  133. package/dist/esm/components/section-block-header-utils.js +48 -1
  134. package/dist/esm/helpers/confirm.js +52 -1
  135. package/dist/esm/helpers/toast.js +73 -1
  136. package/dist/esm/index.js +111 -1
  137. package/dist/esm/node_modules/prismjs/components/prism-bash.js +235 -1
  138. package/dist/esm/node_modules/prismjs/components/prism-clike.js +31 -1
  139. package/dist/esm/node_modules/prismjs/components/prism-css.js +64 -1
  140. package/dist/esm/node_modules/prismjs/components/prism-javascript.js +172 -1
  141. package/dist/esm/node_modules/prismjs/components/prism-json.js +27 -1
  142. package/dist/esm/node_modules/prismjs/components/prism-jsx.js +143 -1
  143. package/dist/esm/node_modules/prismjs/components/prism-markup.js +186 -1
  144. package/dist/esm/node_modules/prismjs/components/prism-scss.js +81 -1
  145. package/dist/esm/node_modules/prismjs/components/prism-tsx.js +15 -1
  146. package/dist/esm/node_modules/prismjs/components/prism-typescript.js +60 -1
  147. package/dist/index.cjs +55414 -1
  148. package/dist/index.css +1 -1
  149. package/dist/index.esm.js +38284 -1
  150. package/dist/react/chunks/lottie-72a4c6d4.js +17032 -0
  151. package/dist/react/index.cjs +56503 -1
  152. package/dist/react/index.esm.js +39373 -1
  153. package/package.json +1 -1
  154. package/dist/chunks/lottie-2637aa0f.js +0 -1
  155. package/dist/react/chunks/lottie-14e7addb.js +0 -1
@@ -1 +1,1068 @@
1
- import{createDbIcon as e,isDbIconName as t}from"./db-icons.js";const s=["s","m","l"],i=["default","dark","light"],r=["left","right"];class DbSidebar extends HTMLElement{constructor(){super(...arguments),this.expandedItems=new Set,this.userMenuOpen=!1,this.projectMenuOpen=!1,this.flyoutItemId=null,this.flyoutCloseTimer=null,this.outsideHandler=null}static get observedAttributes(){return["items","sections","user-menu-items","user-profile","default-expanded-ids","projects","selected-project-id","project-manage-label","project-manage-href","project-section-label","project-empty-label","project-empty-trigger-label","bottom-items","bottom-sections","promo-banner","size","variant","position","collapsed","collapsible","show-logo","full-height","shadow"]}connectedCallback(){this.seedExpanded(),this.render(),this.bindOutsideClick()}disconnectedCallback(){this.unbindOutsideClick(),this.cancelFlyoutClose()}attributeChangedCallback(e){this.isConnected&&("default-expanded-ids"===e&&this.seedExpanded(),"collapsed"===e&&this.hasAttribute("collapsed")&&(this.userMenuOpen=!1,this.projectMenuOpen=!1,this.flyoutItemId=null,this.cancelFlyoutClose()),this.render())}seedExpanded(){try{const e=JSON.parse(this.getAttribute("default-expanded-ids")||"[]");Array.isArray(e)&&(this.expandedItems=new Set(e))}catch{this.expandedItems=new Set}}get items(){try{const e=JSON.parse(this.getAttribute("items")||"[]");return Array.isArray(e)?e:[]}catch{return[]}}set items(e){this.setAttribute("items","string"==typeof e?e:JSON.stringify(e))}get sections(){return this.parseSections()}set sections(e){this.setAttribute("sections","string"==typeof e?e:JSON.stringify(e))}get userMenuItems(){return this.parseUserMenuItems()}set userMenuItems(e){this.setAttribute("user-menu-items","string"==typeof e?e:JSON.stringify(e))}get userProfile(){return this.parseUserProfile()}set userProfile(e){null==e?this.removeAttribute("user-profile"):this.setAttribute("user-profile","string"==typeof e?e:JSON.stringify(e))}get projects(){return this.parseProjects()}set projects(e){this.setAttribute("projects","string"==typeof e?e:JSON.stringify(e))}get selectedProjectId(){return this.getAttribute("selected-project-id")||""}set selectedProjectId(e){e?this.setAttribute("selected-project-id",e):this.removeAttribute("selected-project-id")}get projectManageLabel(){return this.getAttribute("project-manage-label")||"프로젝트 관리"}set projectManageLabel(e){this.setAttribute("project-manage-label",e)}get projectManageHref(){return this.getAttribute("project-manage-href")||""}set projectManageHref(e){e?this.setAttribute("project-manage-href",e):this.removeAttribute("project-manage-href")}get projectSectionLabel(){return this.getAttribute("project-section-label")||"프로젝트"}set projectSectionLabel(e){this.setAttribute("project-section-label",e)}get projectEmptyLabel(){return this.getAttribute("project-empty-label")||"프로젝트를 추가해 주세요"}set projectEmptyLabel(e){this.setAttribute("project-empty-label",e)}get projectEmptyTriggerLabel(){return this.getAttribute("project-empty-trigger-label")||"프로젝트 추가"}set projectEmptyTriggerLabel(e){this.setAttribute("project-empty-trigger-label",e)}get bottomItems(){return this.parseBottomItems()}set bottomItems(e){this.setAttribute("bottom-items","string"==typeof e?e:JSON.stringify(e))}get bottomSections(){return this.parseBottomSections()}set bottomSections(e){this.setAttribute("bottom-sections","string"==typeof e?e:JSON.stringify(e))}get promoBanner(){return this.parsePromoBanner()}set promoBanner(e){null==e?this.removeAttribute("promo-banner"):this.setAttribute("promo-banner","string"==typeof e?e:JSON.stringify(e))}parseSections(){const e=this.getAttribute("sections");if(e)try{const t=JSON.parse(e);if(Array.isArray(t)&&t.length)return t}catch{}try{const e=JSON.parse(this.getAttribute("items")||"[]");return[{id:"main",items:Array.isArray(e)?e:[]}]}catch{return[{id:"main",items:[]}]}}parseUserMenuItems(){try{const e=JSON.parse(this.getAttribute("user-menu-items")||"[]");return Array.isArray(e)?e:[]}catch{return[]}}parseUserProfile(){const e=this.getAttribute("user-profile");if(!e)return null;try{return JSON.parse(e)}catch{return null}}parseProjects(){try{const e=JSON.parse(this.getAttribute("projects")||"[]");return Array.isArray(e)?e:[]}catch{return[]}}parseBottomItems(){try{const e=JSON.parse(this.getAttribute("bottom-items")||"[]");return Array.isArray(e)?e:[]}catch{return[]}}parseBottomSections(){const e=this.getAttribute("bottom-sections");if(e)try{const t=JSON.parse(e);if(Array.isArray(t)&&t.length)return t}catch{}const t=this.parseBottomItems();return t.length?[{id:"bottom",items:t}]:[]}parsePromoBanner(){const e=this.getAttribute("promo-banner");if(!e)return null;try{return JSON.parse(e)}catch{return null}}getSelectedProject(){const e=this.parseProjects();if(!e.length)return null;const t=this.selectedProjectId;return e.find(e=>e.id===t)||e[0]}bindOutsideClick(){this.outsideHandler||(this.outsideHandler=e=>{const t=e.target;if(this.contains(t))return;let s=!1;this.userMenuOpen&&(this.userMenuOpen=!1,s=!0),this.projectMenuOpen&&(this.projectMenuOpen=!1,s=!0),s&&this.render()},document.addEventListener("mousedown",this.outsideHandler))}closeOverlayMenus(){const e=this.projectMenuOpen,t=this.userMenuOpen;if(!e&&!t)return!1;this.projectMenuOpen=!1,this.userMenuOpen=!1,this.querySelector(".designbase-wc-sidebar__project-dropdown")?.remove(),this.querySelector(".designbase-wc-sidebar__project-selector")?.classList.remove("designbase-wc-sidebar__project-selector--open");const s=this.querySelector(".designbase-wc-sidebar__project-trigger");s?.setAttribute("aria-expanded","false");const i=this.querySelector(".designbase-wc-sidebar__user-dropdown");return i&&(i.hidden=!0),this.querySelector(".designbase-wc-sidebar__user-info")?.setAttribute("aria-expanded","false"),this.querySelector(".designbase-wc-sidebar__user-collapsed")?.setAttribute("aria-expanded","false"),this.querySelector(".designbase-wc-sidebar__user-collapsed")?.classList.remove("designbase-wc-sidebar__user-collapsed--open"),!0}syncExclusiveAccordion(e){[...Array.from(this.querySelectorAll(".designbase-wc-sidebar__nav-list > .designbase-wc-sidebar__item > db-menu-item")),...Array.from(this.querySelectorAll(".designbase-wc-sidebar__bottom-nav .designbase-wc-sidebar__nav-list > .designbase-wc-sidebar__item > db-menu-item"))].forEach(t=>{const s=t.getAttribute("data-item-id");s&&(e&&s===e?t.setAttribute("expanded",""):t.removeAttribute("expanded"))})}unbindOutsideClick(){this.outsideHandler&&(document.removeEventListener("mousedown",this.outsideHandler),this.outsideHandler=null)}cancelFlyoutClose(){this.flyoutCloseTimer&&(clearTimeout(this.flyoutCloseTimer),this.flyoutCloseTimer=null)}showFlyout(e){this.cancelFlyoutClose(),this.flyoutItemId!==e&&(this.flyoutItemId=e,this.renderNav(),this.renderBottomNav())}scheduleFlyoutClose(){this.cancelFlyoutClose(),this.flyoutCloseTimer=setTimeout(()=>{this.flyoutCloseTimer=null,this.flyoutItemId=null,this.renderNav(),this.renderBottomNav()},120)}syncHostClasses(){const e=this.getAttribute("size")||"m",t=this.getAttribute("variant")||"default",a=this.getAttribute("position")||"left";this.className=["designbase-wc-sidebar",`designbase-wc-sidebar--${s.includes(e)?e:"m"}`,`designbase-wc-sidebar--${i.includes(t)?t:"default"}`,`designbase-wc-sidebar--${r.includes(a)?a:"left"}`,this.hasAttribute("collapsed")&&"designbase-wc-sidebar--collapsed",this.hasAttribute("full-height")&&"designbase-wc-sidebar--full-height",this.hasAttribute("shadow")&&"designbase-wc-sidebar--shadow"].filter(Boolean).join(" ")}dispatchItemClick(e){this.dispatchEvent(new CustomEvent("db-item-click",{bubbles:!0,composed:!0,detail:{item:e}}))}dispatchUserMenuItemClick(e){this.dispatchEvent(new CustomEvent("db-user-menu-item-click",{bubbles:!0,composed:!0,detail:{item:e}}))}dispatchProjectChange(e){this.dispatchEvent(new CustomEvent("db-project-change",{bubbles:!0,composed:!0,detail:{project:e}}))}dispatchProjectManage(){this.dispatchEvent(new CustomEvent("db-project-manage",{bubbles:!0,composed:!0,detail:{}}))}dispatchPromoCtaClick(e){this.dispatchEvent(new CustomEvent("db-promo-cta-click",{bubbles:!0,composed:!0,detail:{banner:e}}))}createProjectAvatar(e,t="s"){const s=document.createElement("db-avatar");if(s.className="designbase-wc-sidebar__project-avatar",s.setAttribute("size",t),s.setAttribute("initials",(e.label||"?").trim()),s.setAttribute("alt",e.label),e.color){const applyColor=()=>{const t=s.querySelector(".designbase-wc-avatar__initials");return!!t&&(t.style.backgroundColor=e.color,t.style.color="#fff",!0)},t=new MutationObserver(()=>{applyColor()&&t.disconnect()});t.observe(s,{childList:!0,subtree:!0}),queueMicrotask(()=>{applyColor()&&t.disconnect()})}return s}createProjectEmptyMark(t="s"){const s=document.createElement("span");return s.className=["designbase-wc-sidebar__project-mark",`designbase-wc-sidebar__project-mark--${t}`,"designbase-wc-sidebar__project-mark--empty"].join(" "),s.setAttribute("aria-hidden","true"),s.append(e("plus","m"===t?16:14)),s}createProjectBadge(e){if(!e.badge)return null;const t=document.createElement("db-badge");return t.className="designbase-wc-sidebar__project-badge",t.setAttribute("size","s"),t.setAttribute("variant",e.badgeColor||"warning"),t.setAttribute("badge-style","text"),t.textContent=e.badge,t}createProjectSelector(t){if(!this.hasAttribute("projects"))return null;const s=this.parseProjects(),i=0===s.length,r=this.getSelectedProject(),a=document.createElement("div");a.className=["designbase-wc-sidebar__project-selector",t&&"designbase-wc-sidebar__project-selector--collapsed",this.projectMenuOpen&&"designbase-wc-sidebar__project-selector--open",i&&"designbase-wc-sidebar__project-selector--empty"].filter(Boolean).join(" ");const n=this.getAttribute("project-section-label");if(!t&&n&&n.trim()){const e=document.createElement("div");e.className="designbase-wc-sidebar__project-section-label",e.textContent=n.trim(),a.append(e)}const o=document.createElement("button");if(o.type="button",o.className="designbase-wc-sidebar__project-trigger",o.setAttribute("aria-haspopup","menu"),o.setAttribute("aria-expanded",String(this.projectMenuOpen)),i||!r){if(o.setAttribute("aria-label",this.projectEmptyTriggerLabel),o.append(this.createProjectEmptyMark(t?"m":"s")),!t){const e=document.createElement("span");e.className="designbase-wc-sidebar__project-label",e.textContent=this.projectEmptyTriggerLabel,o.append(e)}}else if(o.setAttribute("aria-label",r.label),o.append(this.createProjectAvatar(r,t?"m":"s")),!t){const e=document.createElement("span");e.className="designbase-wc-sidebar__project-label",e.textContent=r.label,o.append(e)}const c=document.createElement("span");if(c.className="designbase-wc-sidebar__project-chevron",c.setAttribute("aria-hidden","true"),c.append(e("chevron-down",14)),o.append(c),o.addEventListener("click",()=>{this.projectMenuOpen=!this.projectMenuOpen,this.userMenuOpen=!1,this.render()}),a.append(o),this.projectMenuOpen){const t=document.createElement("div");if(t.className="designbase-wc-sidebar__project-dropdown",t.setAttribute("role","menu"),t.setAttribute("aria-label",this.projectSectionLabel),i){const e=document.createElement("div");e.className="designbase-wc-sidebar__project-empty",e.setAttribute("role","presentation");const s=document.createElement("p");s.className="designbase-wc-sidebar__project-empty-text",s.textContent=this.projectEmptyLabel,e.append(s),t.append(e)}else{const e=document.createElement("ul");e.className="designbase-wc-sidebar__project-list",s.forEach(t=>{const s=document.createElement("li");s.className="designbase-wc-sidebar__project-option";const i=document.createElement("button");i.type="button",i.className=["designbase-wc-sidebar__project-option-btn",r&&t.id===r.id&&"designbase-wc-sidebar__project-option-btn--active"].filter(Boolean).join(" "),i.setAttribute("role","menuitem"),i.append(this.createProjectAvatar(t,"s"));const a=document.createElement("span");a.className="designbase-wc-sidebar__project-option-label",a.textContent=t.label,i.append(a);const n=this.createProjectBadge(t);n&&i.append(n),i.addEventListener("click",()=>{this.projectMenuOpen=!1,this.setAttribute("selected-project-id",t.id),this.dispatchProjectChange(t),this.render()}),s.append(i),e.append(s)}),t.append(e)}const n=document.createElement("button");n.type="button",n.className="designbase-wc-sidebar__project-manage",n.setAttribute("role","menuitem"),n.append(e("plus",14));const o=document.createElement("span");o.textContent=this.projectManageLabel,n.append(o),n.addEventListener("click",()=>{this.projectMenuOpen=!1;const e=this.projectManageHref;e&&window.location.assign(e),this.dispatchProjectManage(),this.render()}),t.append(n),a.append(t)}return a}createFlyout(e,t){const s=this.getAttribute("position")||"left",i=document.createElement("div");i.className=["designbase-wc-sidebar__flyout","right"===s&&"designbase-wc-sidebar__flyout--align-left"].filter(Boolean).join(" "),i.setAttribute("role","menu"),i.setAttribute("aria-label",`${e.label} 하위 메뉴`),i.addEventListener("mouseenter",()=>this.cancelFlyoutClose()),i.addEventListener("mouseleave",()=>this.scheduleFlyoutClose());const r=document.createElement("div");r.className="designbase-wc-sidebar__flyout-title",r.textContent=e.label,i.append(r);const a=document.createElement("ul");return a.className="designbase-wc-sidebar__flyout-list",(e.children||[]).forEach(e=>{const s=document.createElement("li");s.className="designbase-wc-sidebar__flyout-item";const i=document.createElement("db-menu-item");i.setAttribute("label",e.label),i.setAttribute("type","block"),i.setAttribute("menu-style","dropdown"),i.setAttribute("size",t),e.href&&i.setAttribute("href",e.href),e.active&&i.setAttribute("active",""),e.disabled&&i.setAttribute("disabled",""),void 0!==e.badge&&i.setAttribute("badge",String(e.badge)),e.badgeColor&&i.setAttribute("badge-color",e.badgeColor),i.addEventListener("db-click",()=>{e.disabled||(this.flyoutItemId=null,this.dispatchItemClick(e),this.renderNav(),this.renderBottomNav())}),s.append(i),a.append(s)}),i.append(a),i}createSidebarMenuItem(e,t,s=0){const i=Boolean(e.children?.length),r=this.expandedItems.has(e.id),a=this.hasAttribute("collapsed"),n=a&&i,o=document.createElement("li");o.className=["designbase-wc-sidebar__item",n&&this.flyoutItemId===e.id&&"designbase-wc-sidebar__item--flyout-active"].filter(Boolean).join(" "),n&&(o.addEventListener("mouseenter",()=>this.showFlyout(e.id)),o.addEventListener("mouseleave",()=>this.scheduleFlyoutClose()));const c=document.createElement("db-menu-item");if(c.setAttribute("data-item-id",e.id),c.setAttribute("label",e.label),c.setAttribute("type","block"),c.setAttribute("menu-style","accordion"),c.setAttribute("size",t),c.setAttribute("depth",String(s)),e.href&&c.setAttribute("href",e.href),e.icon&&c.setAttribute("icon",e.icon),e.active&&c.setAttribute("active",""),e.disabled&&c.setAttribute("disabled",""),void 0!==e.badge&&c.setAttribute("badge",String(e.badge)),e.badgeColor&&c.setAttribute("badge-color",e.badgeColor),i&&!n&&(c.setAttribute("expandable",""),c.subItems=(e.children||[]).map(e=>({id:e.id,label:e.label,href:e.href,active:e.active,disabled:e.disabled,badge:e.badge,badgeColor:e.badgeColor})),r&&!a&&c.setAttribute("expanded","")),c.addEventListener("db-click",t=>{if(!e.disabled){if(i&&!a){const s=t.detail?.expanded??!this.expandedItems.has(e.id);return this.closeOverlayMenus(),void(s?(this.expandedItems.clear(),this.expandedItems.add(e.id),this.syncExclusiveAccordion(e.id)):(this.expandedItems.delete(e.id),this.syncExclusiveAccordion(null)))}if(n)return this.closeOverlayMenus(),void this.showFlyout(e.id);this.closeOverlayMenus(),this.dispatchItemClick(e)}}),c.addEventListener("db-child-click",e=>{const t=e.detail;this.dispatchItemClick(t.child)}),o.append(c),a&&void 0!==e.badge&&null!==e.badge&&""!==e.badge){const t=e.badgeColor||"primary",s=document.createElement("span");s.className=["designbase-wc-sidebar__collapsed-badge-dot",`designbase-wc-sidebar__collapsed-badge-dot--${t}`].join(" "),s.setAttribute("aria-hidden","true"),o.append(s)}if(a&&!i){const t=document.createElement("span");t.className="designbase-wc-sidebar__item-tooltip",t.textContent=e.label,t.setAttribute("role","tooltip"),o.append(t)}return n&&this.flyoutItemId===e.id&&o.append(this.createFlyout(e,t)),o}renderSectionList(e,t,s){const i=document.createDocumentFragment();return e.forEach(e=>{const r=document.createElement("div");if(r.className="designbase-wc-sidebar__section",!s&&e.title){const t=document.createElement("div");t.className="designbase-wc-sidebar__section-title",t.textContent=e.title,r.append(t)}const a=document.createElement("ul");a.className="designbase-wc-sidebar__nav-list",e.items.forEach(e=>a.append(this.createSidebarMenuItem(e,t))),r.append(a),i.append(r)}),i}renderNav(){const e=this.querySelector(".designbase-wc-sidebar__nav");if(!e)return;const t=this.getAttribute("size")||"m",s=this.hasAttribute("collapsed");e.replaceChildren(this.renderSectionList(this.parseSections(),t,s))}renderBottomNav(){const e=this.querySelector(".designbase-wc-sidebar__bottom-nav");if(!e)return;const t=this.getAttribute("size")||"m",s=this.hasAttribute("collapsed");e.replaceChildren(this.renderSectionList(this.parseBottomSections(),t,s))}createUserDropdown(e,t=!1){if(!e.length)return null;const s=this.getAttribute("size")||"m",i=document.createElement("div");i.className=["designbase-wc-sidebar__user-dropdown",t&&"designbase-wc-sidebar__user-dropdown--collapsed"].filter(Boolean).join(" "),i.setAttribute("role","menu"),i.setAttribute("aria-label","사용자 메뉴"),i.hidden=!this.userMenuOpen;const r=document.createElement("ul");return r.className="designbase-wc-sidebar__user-menu",e.forEach(e=>{const t=document.createElement("li");t.className="designbase-wc-sidebar__user-menu-item";const i=document.createElement("db-menu-item");i.setAttribute("label",e.label),i.setAttribute("type","block"),i.setAttribute("menu-style","accordion"),i.setAttribute("size",s),e.icon&&i.setAttribute("icon",e.icon),e.href&&i.setAttribute("href",e.href),i.addEventListener("db-click",()=>{this.userMenuOpen=!1,this.dispatchUserMenuItemClick(e),this.render()}),t.append(i),r.append(t)}),i.append(r),i}createPromoBanner(s){const i=this.parsePromoBanner();if(!i)return null;if(s){const s=document.createElement("button");s.type="button",s.className="designbase-wc-sidebar__promo-collapsed",s.setAttribute("aria-label",i.ctaLabel||i.title);const r=document.createElement("db-animation-background");r.className="designbase-wc-sidebar__promo-bg",r.setAttribute("type","aurora"),r.setAttribute("theme","light"),r.setAttribute("intensity","subtle"),r.setAttribute("blur","40"),r.setAttribute("speed","4000"),r.setAttribute("colors",JSON.stringify(["#c7d2fe","#ddd6fe","#fbcfe8"])),s.append(r),s.append(e(i.icon&&t(i.icon)?i.icon:"sparkle",18)),s.addEventListener("click",()=>this.dispatchPromoCtaClick(i));const a=document.createElement("span");a.className="designbase-wc-sidebar__item-tooltip",a.textContent=i.title,a.setAttribute("role","tooltip");const n=document.createElement("div");return n.className="designbase-wc-sidebar__promo-collapsed-wrap",n.append(s,a),n}const r=document.createElement("div");r.className="designbase-wc-sidebar__promo";const a=document.createElement("db-animation-background");a.className="designbase-wc-sidebar__promo-bg",a.setAttribute("type","aurora"),a.setAttribute("theme","light"),a.setAttribute("intensity","subtle"),a.setAttribute("blur","60"),a.setAttribute("speed","5000"),a.setAttribute("colors",JSON.stringify(["#c7d2fe","#ddd6fe","#fbcfe8","#bfdbfe"])),r.append(a);const n=document.createElement("div");n.className="designbase-wc-sidebar__promo-content";const o=document.createElement("div");o.className="designbase-wc-sidebar__promo-title-row";const c=document.createElement("span");c.className="designbase-wc-sidebar__promo-icon",c.setAttribute("aria-hidden","true"),c.append(e(i.icon&&t(i.icon)?i.icon:"sparkle",16));const d=document.createElement("div");if(d.className="designbase-wc-sidebar__promo-title",d.textContent=i.title,o.append(c,d),n.append(o),i.description){const e=document.createElement("div");e.className="designbase-wc-sidebar__promo-desc",e.textContent=i.description,n.append(e)}if(i.ctaLabel){const e=document.createElement("db-button");e.className="designbase-wc-sidebar__promo-action",e.setAttribute("variant","secondary"),e.setAttribute("size","s"),e.setAttribute("full-width",""),e.textContent=i.ctaLabel,e.addEventListener("db-click",()=>{i.ctaHref&&window.location.assign(i.ctaHref),this.dispatchPromoCtaClick(i)}),n.append(e)}return r.append(n),r}render(){this.syncHostClasses(),this.setAttribute("role","complementary"),this.setAttribute("aria-label","사이드바 네비게이션");const t=this.getAttribute("size")||"m",s="false"!==this.getAttribute("collapsible"),i="false"!==this.getAttribute("show-logo"),r=this.hasAttribute("collapsed"),a=this.parseUserProfile(),n=this.parseUserMenuItems(),o=this.parseBottomSections(),c="l"===t?"m":"s"===t?"xs":"s";this.replaceChildren();const d=document.createElement("div");if(d.className="designbase-wc-sidebar__container",s||i&&!r){const e=document.createElement("div");if(e.className=["designbase-wc-sidebar__header",(r||!i)&&"designbase-wc-sidebar__header--collapsed-only"].filter(Boolean).join(" "),!r&&i){const t=document.createElement("div");t.className="designbase-wc-sidebar__logo";const s=document.createElement("db-logo");s.setAttribute("type","designbase"),s.setAttribute("size",c),t.append(s),t.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("db-logo-click",{bubbles:!0,composed:!0}))}),e.append(t)}if(s){const t=document.createElement("db-button");t.className="designbase-wc-sidebar__toggle",t.setAttribute("variant","tertiary"),t.setAttribute("size","s"),t.setAttribute("icon-only",""),t.setAttribute("start-icon",r?"arrow-bar-right":"arrow-bar-left"),t.setAttribute("aria-label",r?"사이드바 펼치기":"사이드바 접기"),t.addEventListener("db-click",()=>{const e=!this.hasAttribute("collapsed");e?this.setAttribute("collapsed",""):this.removeAttribute("collapsed"),this.dispatchEvent(new CustomEvent("db-toggle",{bubbles:!0,composed:!0,detail:{collapsed:e}}))}),e.append(t)}d.append(e)}const l=document.createElement("div");l.className="designbase-wc-sidebar__nav-wrapper";const b=this.createProjectSelector(r);b&&l.append(b);const u=document.createElement("nav");if(u.className="designbase-wc-sidebar__nav",u.setAttribute("aria-label","주 메뉴"),l.append(u),o.length>0){const e=document.createElement("nav");e.className="designbase-wc-sidebar__bottom-nav",e.setAttribute("aria-label","하단 메뉴"),l.append(e)}d.append(l);const p=document.createElement("div");p.className="designbase-wc-sidebar__footer";const m=this.createPromoBanner(r);if(m&&p.append(m),a&&!r){const t=document.createElement("div");t.className="designbase-wc-sidebar__user";const s=this.createUserDropdown(n);s&&t.append(s);const i=document.createElement("div");i.className="designbase-wc-sidebar__user-info",i.setAttribute("role","button"),i.setAttribute("tabindex","0"),i.setAttribute("aria-expanded",String(this.userMenuOpen));const r=document.createElement("db-avatar");r.className="designbase-wc-sidebar__user-avatar",r.setAttribute("size","s"),r.setAttribute("initials",a.name),r.setAttribute("alt",a.name),a.avatar&&r.setAttribute("src",a.avatar);const o=document.createElement("div");o.className="designbase-wc-sidebar__user-details";const c=document.createElement("div");if(c.className="designbase-wc-sidebar__user-name",c.textContent=a.name,o.append(c),a.email){const e=document.createElement("div");e.className="designbase-wc-sidebar__user-email",e.textContent=a.email,o.append(e)}if(i.append(r,o),n.length){const t=document.createElement("span");t.className="designbase-wc-sidebar__user-more",t.setAttribute("aria-hidden","true"),t.append(e("more-vertical",16)),i.append(t),i.setAttribute("aria-haspopup","menu")}i.addEventListener("click",()=>{n.length&&(this.userMenuOpen=!this.userMenuOpen,this.projectMenuOpen=!1,this.render())}),t.append(i),p.append(t)}else if(a&&r){const e=document.createElement("div");e.className=["designbase-wc-sidebar__user-collapsed",this.userMenuOpen&&"designbase-wc-sidebar__user-collapsed--open"].filter(Boolean).join(" "),e.setAttribute("role","button"),e.setAttribute("tabindex","0"),e.setAttribute("aria-label",a.name),e.setAttribute("aria-expanded",String(this.userMenuOpen)),n.length&&e.setAttribute("aria-haspopup","menu");const t=document.createElement("db-avatar");if(t.className="designbase-wc-sidebar__user-avatar-collapsed",t.setAttribute("size","s"),t.setAttribute("initials",a.name),t.setAttribute("alt",a.name),a.avatar&&t.setAttribute("src",a.avatar),e.append(t),!this.userMenuOpen){const t=document.createElement("span");t.className="designbase-wc-sidebar__item-tooltip",t.textContent=a.name,t.setAttribute("role","tooltip"),e.append(t)}const s=this.createUserDropdown(n,!0);s&&e.append(s),e.addEventListener("click",e=>{n.length&&(e.target.closest(".designbase-wc-sidebar__user-dropdown")||(this.userMenuOpen=!this.userMenuOpen,this.projectMenuOpen=!1,this.render()))}),p.append(e)}d.append(p),this.append(d),this.renderNav(),this.renderBottomNav()}}customElements.get("db-sidebar")||customElements.define("db-sidebar",DbSidebar);export{DbSidebar};
1
+ import { createDbIcon, isDbIconName } from './db-icons.js';
2
+
3
+ const SIZES = ['s', 'm', 'l'];
4
+ const VARIANTS = ['default', 'dark', 'light'];
5
+ const POSITIONS = ['left', 'right'];
6
+ const FLYOUT_CLOSE_DELAY_MS = 120;
7
+ class DbSidebar extends HTMLElement {
8
+ constructor() {
9
+ super(...arguments);
10
+ this.expandedItems = new Set();
11
+ this.userMenuOpen = false;
12
+ this.projectMenuOpen = false;
13
+ this.flyoutItemId = null;
14
+ this.flyoutCloseTimer = null;
15
+ this.outsideHandler = null;
16
+ }
17
+ static get observedAttributes() {
18
+ return [
19
+ 'items',
20
+ 'sections',
21
+ 'user-menu-items',
22
+ 'user-profile',
23
+ 'default-expanded-ids',
24
+ 'projects',
25
+ 'selected-project-id',
26
+ 'project-manage-label',
27
+ 'project-manage-href',
28
+ 'project-section-label',
29
+ 'project-empty-label',
30
+ 'project-empty-trigger-label',
31
+ 'bottom-items',
32
+ 'bottom-sections',
33
+ 'promo-banner',
34
+ 'size',
35
+ 'variant',
36
+ 'position',
37
+ 'collapsed',
38
+ 'collapsible',
39
+ 'show-logo',
40
+ 'full-height',
41
+ 'shadow',
42
+ ];
43
+ }
44
+ connectedCallback() {
45
+ this.seedExpanded();
46
+ this.render();
47
+ this.bindOutsideClick();
48
+ }
49
+ disconnectedCallback() {
50
+ this.unbindOutsideClick();
51
+ this.cancelFlyoutClose();
52
+ }
53
+ attributeChangedCallback(name) {
54
+ if (!this.isConnected)
55
+ return;
56
+ if (name === 'default-expanded-ids')
57
+ this.seedExpanded();
58
+ if (name === 'collapsed' && this.hasAttribute('collapsed')) {
59
+ this.userMenuOpen = false;
60
+ this.projectMenuOpen = false;
61
+ this.flyoutItemId = null;
62
+ this.cancelFlyoutClose();
63
+ }
64
+ this.render();
65
+ }
66
+ seedExpanded() {
67
+ try {
68
+ const ids = JSON.parse(this.getAttribute('default-expanded-ids') || '[]');
69
+ if (Array.isArray(ids))
70
+ this.expandedItems = new Set(ids);
71
+ }
72
+ catch {
73
+ this.expandedItems = new Set();
74
+ }
75
+ }
76
+ get items() {
77
+ try {
78
+ const parsed = JSON.parse(this.getAttribute('items') || '[]');
79
+ return Array.isArray(parsed) ? parsed : [];
80
+ }
81
+ catch {
82
+ return [];
83
+ }
84
+ }
85
+ set items(value) {
86
+ this.setAttribute('items', typeof value === 'string' ? value : JSON.stringify(value));
87
+ }
88
+ get sections() {
89
+ return this.parseSections();
90
+ }
91
+ set sections(value) {
92
+ this.setAttribute('sections', typeof value === 'string' ? value : JSON.stringify(value));
93
+ }
94
+ get userMenuItems() {
95
+ return this.parseUserMenuItems();
96
+ }
97
+ set userMenuItems(value) {
98
+ this.setAttribute('user-menu-items', typeof value === 'string' ? value : JSON.stringify(value));
99
+ }
100
+ get userProfile() {
101
+ return this.parseUserProfile();
102
+ }
103
+ set userProfile(value) {
104
+ if (value === null || value === undefined)
105
+ this.removeAttribute('user-profile');
106
+ else
107
+ this.setAttribute('user-profile', typeof value === 'string' ? value : JSON.stringify(value));
108
+ }
109
+ get projects() {
110
+ return this.parseProjects();
111
+ }
112
+ set projects(value) {
113
+ this.setAttribute('projects', typeof value === 'string' ? value : JSON.stringify(value));
114
+ }
115
+ get selectedProjectId() {
116
+ return this.getAttribute('selected-project-id') || '';
117
+ }
118
+ set selectedProjectId(value) {
119
+ if (value)
120
+ this.setAttribute('selected-project-id', value);
121
+ else
122
+ this.removeAttribute('selected-project-id');
123
+ }
124
+ get projectManageLabel() {
125
+ return this.getAttribute('project-manage-label') || '프로젝트 관리';
126
+ }
127
+ set projectManageLabel(value) {
128
+ this.setAttribute('project-manage-label', value);
129
+ }
130
+ get projectManageHref() {
131
+ return this.getAttribute('project-manage-href') || '';
132
+ }
133
+ set projectManageHref(value) {
134
+ if (value)
135
+ this.setAttribute('project-manage-href', value);
136
+ else
137
+ this.removeAttribute('project-manage-href');
138
+ }
139
+ get projectSectionLabel() {
140
+ return this.getAttribute('project-section-label') || '프로젝트';
141
+ }
142
+ set projectSectionLabel(value) {
143
+ this.setAttribute('project-section-label', value);
144
+ }
145
+ get projectEmptyLabel() {
146
+ return this.getAttribute('project-empty-label') || '프로젝트를 추가해 주세요';
147
+ }
148
+ set projectEmptyLabel(value) {
149
+ this.setAttribute('project-empty-label', value);
150
+ }
151
+ get projectEmptyTriggerLabel() {
152
+ return this.getAttribute('project-empty-trigger-label') || '프로젝트 추가';
153
+ }
154
+ set projectEmptyTriggerLabel(value) {
155
+ this.setAttribute('project-empty-trigger-label', value);
156
+ }
157
+ get bottomItems() {
158
+ return this.parseBottomItems();
159
+ }
160
+ set bottomItems(value) {
161
+ this.setAttribute('bottom-items', typeof value === 'string' ? value : JSON.stringify(value));
162
+ }
163
+ get bottomSections() {
164
+ return this.parseBottomSections();
165
+ }
166
+ set bottomSections(value) {
167
+ this.setAttribute('bottom-sections', typeof value === 'string' ? value : JSON.stringify(value));
168
+ }
169
+ get promoBanner() {
170
+ return this.parsePromoBanner();
171
+ }
172
+ set promoBanner(value) {
173
+ if (value === null || value === undefined)
174
+ this.removeAttribute('promo-banner');
175
+ else
176
+ this.setAttribute('promo-banner', typeof value === 'string' ? value : JSON.stringify(value));
177
+ }
178
+ parseSections() {
179
+ const sectionsRaw = this.getAttribute('sections');
180
+ if (sectionsRaw) {
181
+ try {
182
+ const parsed = JSON.parse(sectionsRaw);
183
+ if (Array.isArray(parsed) && parsed.length)
184
+ return parsed;
185
+ }
186
+ catch {
187
+ /* fall through */
188
+ }
189
+ }
190
+ try {
191
+ const items = JSON.parse(this.getAttribute('items') || '[]');
192
+ return [{ id: 'main', items: Array.isArray(items) ? items : [] }];
193
+ }
194
+ catch {
195
+ return [{ id: 'main', items: [] }];
196
+ }
197
+ }
198
+ parseUserMenuItems() {
199
+ try {
200
+ const parsed = JSON.parse(this.getAttribute('user-menu-items') || '[]');
201
+ return Array.isArray(parsed) ? parsed : [];
202
+ }
203
+ catch {
204
+ return [];
205
+ }
206
+ }
207
+ parseUserProfile() {
208
+ const raw = this.getAttribute('user-profile');
209
+ if (!raw)
210
+ return null;
211
+ try {
212
+ return JSON.parse(raw);
213
+ }
214
+ catch {
215
+ return null;
216
+ }
217
+ }
218
+ parseProjects() {
219
+ try {
220
+ const parsed = JSON.parse(this.getAttribute('projects') || '[]');
221
+ return Array.isArray(parsed) ? parsed : [];
222
+ }
223
+ catch {
224
+ return [];
225
+ }
226
+ }
227
+ parseBottomItems() {
228
+ try {
229
+ const parsed = JSON.parse(this.getAttribute('bottom-items') || '[]');
230
+ return Array.isArray(parsed) ? parsed : [];
231
+ }
232
+ catch {
233
+ return [];
234
+ }
235
+ }
236
+ parseBottomSections() {
237
+ const sectionsRaw = this.getAttribute('bottom-sections');
238
+ if (sectionsRaw) {
239
+ try {
240
+ const parsed = JSON.parse(sectionsRaw);
241
+ if (Array.isArray(parsed) && parsed.length)
242
+ return parsed;
243
+ }
244
+ catch {
245
+ /* fall through */
246
+ }
247
+ }
248
+ const items = this.parseBottomItems();
249
+ return items.length ? [{ id: 'bottom', items }] : [];
250
+ }
251
+ parsePromoBanner() {
252
+ const raw = this.getAttribute('promo-banner');
253
+ if (!raw)
254
+ return null;
255
+ try {
256
+ return JSON.parse(raw);
257
+ }
258
+ catch {
259
+ return null;
260
+ }
261
+ }
262
+ getSelectedProject() {
263
+ const projects = this.parseProjects();
264
+ if (!projects.length)
265
+ return null;
266
+ const selectedId = this.selectedProjectId;
267
+ return projects.find((project) => project.id === selectedId) || projects[0];
268
+ }
269
+ bindOutsideClick() {
270
+ if (this.outsideHandler)
271
+ return;
272
+ this.outsideHandler = (event) => {
273
+ const target = event.target;
274
+ // 사이드바 내부 클릭은 각 핸들러가 exclusive open을 처리 — mousedown에서 remount하면 클릭이 씹힘
275
+ if (this.contains(target))
276
+ return;
277
+ let changed = false;
278
+ if (this.userMenuOpen) {
279
+ this.userMenuOpen = false;
280
+ changed = true;
281
+ }
282
+ if (this.projectMenuOpen) {
283
+ this.projectMenuOpen = false;
284
+ changed = true;
285
+ }
286
+ if (changed)
287
+ this.render();
288
+ };
289
+ document.addEventListener('mousedown', this.outsideHandler);
290
+ }
291
+ closeOverlayMenus() {
292
+ const projectOpen = this.projectMenuOpen;
293
+ const userOpen = this.userMenuOpen;
294
+ if (!projectOpen && !userOpen)
295
+ return false;
296
+ this.projectMenuOpen = false;
297
+ this.userMenuOpen = false;
298
+ this.querySelector('.designbase-wc-sidebar__project-dropdown')?.remove();
299
+ this.querySelector('.designbase-wc-sidebar__project-selector')?.classList.remove('designbase-wc-sidebar__project-selector--open');
300
+ const projectTrigger = this.querySelector('.designbase-wc-sidebar__project-trigger');
301
+ projectTrigger?.setAttribute('aria-expanded', 'false');
302
+ const userDropdown = this.querySelector('.designbase-wc-sidebar__user-dropdown');
303
+ if (userDropdown)
304
+ userDropdown.hidden = true;
305
+ this.querySelector('.designbase-wc-sidebar__user-info')?.setAttribute('aria-expanded', 'false');
306
+ this.querySelector('.designbase-wc-sidebar__user-collapsed')?.setAttribute('aria-expanded', 'false');
307
+ this.querySelector('.designbase-wc-sidebar__user-collapsed')?.classList.remove('designbase-wc-sidebar__user-collapsed--open');
308
+ return true;
309
+ }
310
+ syncExclusiveAccordion(openId) {
311
+ const roots = [
312
+ ...Array.from(this.querySelectorAll('.designbase-wc-sidebar__nav-list > .designbase-wc-sidebar__item > db-menu-item')),
313
+ ...Array.from(this.querySelectorAll('.designbase-wc-sidebar__bottom-nav .designbase-wc-sidebar__nav-list > .designbase-wc-sidebar__item > db-menu-item')),
314
+ ];
315
+ roots.forEach((el) => {
316
+ const id = el.getAttribute('data-item-id');
317
+ if (!id)
318
+ return;
319
+ if (openId && id === openId)
320
+ el.setAttribute('expanded', '');
321
+ else
322
+ el.removeAttribute('expanded');
323
+ });
324
+ }
325
+ unbindOutsideClick() {
326
+ if (!this.outsideHandler)
327
+ return;
328
+ document.removeEventListener('mousedown', this.outsideHandler);
329
+ this.outsideHandler = null;
330
+ }
331
+ cancelFlyoutClose() {
332
+ if (this.flyoutCloseTimer) {
333
+ clearTimeout(this.flyoutCloseTimer);
334
+ this.flyoutCloseTimer = null;
335
+ }
336
+ }
337
+ showFlyout(itemId) {
338
+ this.cancelFlyoutClose();
339
+ if (this.flyoutItemId === itemId)
340
+ return;
341
+ this.flyoutItemId = itemId;
342
+ this.renderNav();
343
+ this.renderBottomNav();
344
+ }
345
+ scheduleFlyoutClose() {
346
+ this.cancelFlyoutClose();
347
+ this.flyoutCloseTimer = setTimeout(() => {
348
+ this.flyoutCloseTimer = null;
349
+ this.flyoutItemId = null;
350
+ this.renderNav();
351
+ this.renderBottomNav();
352
+ }, FLYOUT_CLOSE_DELAY_MS);
353
+ }
354
+ syncHostClasses() {
355
+ const size = this.getAttribute('size') || 'm';
356
+ const variant = this.getAttribute('variant') || 'default';
357
+ const position = this.getAttribute('position') || 'left';
358
+ this.className = [
359
+ 'designbase-wc-sidebar',
360
+ `designbase-wc-sidebar--${SIZES.includes(size) ? size : 'm'}`,
361
+ `designbase-wc-sidebar--${VARIANTS.includes(variant) ? variant : 'default'}`,
362
+ `designbase-wc-sidebar--${POSITIONS.includes(position) ? position : 'left'}`,
363
+ this.hasAttribute('collapsed') && 'designbase-wc-sidebar--collapsed',
364
+ this.hasAttribute('full-height') && 'designbase-wc-sidebar--full-height',
365
+ this.hasAttribute('shadow') && 'designbase-wc-sidebar--shadow',
366
+ ]
367
+ .filter(Boolean)
368
+ .join(' ');
369
+ }
370
+ dispatchItemClick(item) {
371
+ this.dispatchEvent(new CustomEvent('db-item-click', {
372
+ bubbles: true,
373
+ composed: true,
374
+ detail: { item },
375
+ }));
376
+ }
377
+ dispatchUserMenuItemClick(item) {
378
+ this.dispatchEvent(new CustomEvent('db-user-menu-item-click', {
379
+ bubbles: true,
380
+ composed: true,
381
+ detail: { item },
382
+ }));
383
+ }
384
+ dispatchProjectChange(project) {
385
+ this.dispatchEvent(new CustomEvent('db-project-change', {
386
+ bubbles: true,
387
+ composed: true,
388
+ detail: { project },
389
+ }));
390
+ }
391
+ dispatchProjectManage() {
392
+ this.dispatchEvent(new CustomEvent('db-project-manage', {
393
+ bubbles: true,
394
+ composed: true,
395
+ detail: {},
396
+ }));
397
+ }
398
+ dispatchPromoCtaClick(banner) {
399
+ this.dispatchEvent(new CustomEvent('db-promo-cta-click', {
400
+ bubbles: true,
401
+ composed: true,
402
+ detail: { banner },
403
+ }));
404
+ }
405
+ createProjectAvatar(project, size = 's') {
406
+ const avatar = document.createElement('db-avatar');
407
+ avatar.className = 'designbase-wc-sidebar__project-avatar';
408
+ avatar.setAttribute('size', size);
409
+ avatar.setAttribute('initials', (project.label || '?').trim());
410
+ avatar.setAttribute('alt', project.label);
411
+ if (project.color) {
412
+ const applyColor = () => {
413
+ const initials = avatar.querySelector('.designbase-wc-avatar__initials');
414
+ if (!initials)
415
+ return false;
416
+ initials.style.backgroundColor = project.color;
417
+ initials.style.color = '#fff';
418
+ return true;
419
+ };
420
+ const observer = new MutationObserver(() => {
421
+ if (applyColor())
422
+ observer.disconnect();
423
+ });
424
+ observer.observe(avatar, { childList: true, subtree: true });
425
+ queueMicrotask(() => {
426
+ if (applyColor())
427
+ observer.disconnect();
428
+ });
429
+ }
430
+ return avatar;
431
+ }
432
+ createProjectEmptyMark(size = 's') {
433
+ const mark = document.createElement('span');
434
+ mark.className = [
435
+ 'designbase-wc-sidebar__project-mark',
436
+ `designbase-wc-sidebar__project-mark--${size}`,
437
+ 'designbase-wc-sidebar__project-mark--empty',
438
+ ].join(' ');
439
+ mark.setAttribute('aria-hidden', 'true');
440
+ mark.append(createDbIcon('plus', size === 'm' ? 16 : 14));
441
+ return mark;
442
+ }
443
+ createProjectBadge(project) {
444
+ if (!project.badge)
445
+ return null;
446
+ const badge = document.createElement('db-badge');
447
+ badge.className = 'designbase-wc-sidebar__project-badge';
448
+ badge.setAttribute('size', 's');
449
+ badge.setAttribute('variant', project.badgeColor || 'warning');
450
+ badge.setAttribute('badge-style', 'text');
451
+ badge.textContent = project.badge;
452
+ return badge;
453
+ }
454
+ createProjectSelector(collapsed) {
455
+ if (!this.hasAttribute('projects'))
456
+ return null;
457
+ const projects = this.parseProjects();
458
+ const isEmpty = projects.length === 0;
459
+ const selected = this.getSelectedProject();
460
+ const wrap = document.createElement('div');
461
+ wrap.className = [
462
+ 'designbase-wc-sidebar__project-selector',
463
+ collapsed && 'designbase-wc-sidebar__project-selector--collapsed',
464
+ this.projectMenuOpen && 'designbase-wc-sidebar__project-selector--open',
465
+ isEmpty && 'designbase-wc-sidebar__project-selector--empty',
466
+ ]
467
+ .filter(Boolean)
468
+ .join(' ');
469
+ const sectionLabelAttr = this.getAttribute('project-section-label');
470
+ if (!collapsed && sectionLabelAttr && sectionLabelAttr.trim()) {
471
+ const sectionLabel = document.createElement('div');
472
+ sectionLabel.className = 'designbase-wc-sidebar__project-section-label';
473
+ sectionLabel.textContent = sectionLabelAttr.trim();
474
+ wrap.append(sectionLabel);
475
+ }
476
+ const trigger = document.createElement('button');
477
+ trigger.type = 'button';
478
+ trigger.className = 'designbase-wc-sidebar__project-trigger';
479
+ trigger.setAttribute('aria-haspopup', 'menu');
480
+ trigger.setAttribute('aria-expanded', String(this.projectMenuOpen));
481
+ if (isEmpty || !selected) {
482
+ trigger.setAttribute('aria-label', this.projectEmptyTriggerLabel);
483
+ trigger.append(this.createProjectEmptyMark(collapsed ? 'm' : 's'));
484
+ if (!collapsed) {
485
+ const label = document.createElement('span');
486
+ label.className = 'designbase-wc-sidebar__project-label';
487
+ label.textContent = this.projectEmptyTriggerLabel;
488
+ trigger.append(label);
489
+ }
490
+ }
491
+ else {
492
+ trigger.setAttribute('aria-label', selected.label);
493
+ trigger.append(this.createProjectAvatar(selected, collapsed ? 'm' : 's'));
494
+ if (!collapsed) {
495
+ const label = document.createElement('span');
496
+ label.className = 'designbase-wc-sidebar__project-label';
497
+ label.textContent = selected.label;
498
+ trigger.append(label);
499
+ }
500
+ }
501
+ const chevron = document.createElement('span');
502
+ chevron.className = 'designbase-wc-sidebar__project-chevron';
503
+ chevron.setAttribute('aria-hidden', 'true');
504
+ chevron.append(createDbIcon('chevron-down', 14));
505
+ trigger.append(chevron);
506
+ trigger.addEventListener('click', () => {
507
+ this.projectMenuOpen = !this.projectMenuOpen;
508
+ this.userMenuOpen = false;
509
+ this.render();
510
+ });
511
+ wrap.append(trigger);
512
+ if (this.projectMenuOpen) {
513
+ const dropdown = document.createElement('div');
514
+ dropdown.className = 'designbase-wc-sidebar__project-dropdown';
515
+ dropdown.setAttribute('role', 'menu');
516
+ dropdown.setAttribute('aria-label', this.projectSectionLabel);
517
+ if (isEmpty) {
518
+ const empty = document.createElement('div');
519
+ empty.className = 'designbase-wc-sidebar__project-empty';
520
+ empty.setAttribute('role', 'presentation');
521
+ const emptyText = document.createElement('p');
522
+ emptyText.className = 'designbase-wc-sidebar__project-empty-text';
523
+ emptyText.textContent = this.projectEmptyLabel;
524
+ empty.append(emptyText);
525
+ dropdown.append(empty);
526
+ }
527
+ else {
528
+ const list = document.createElement('ul');
529
+ list.className = 'designbase-wc-sidebar__project-list';
530
+ projects.forEach((project) => {
531
+ const li = document.createElement('li');
532
+ li.className = 'designbase-wc-sidebar__project-option';
533
+ const button = document.createElement('button');
534
+ button.type = 'button';
535
+ button.className = [
536
+ 'designbase-wc-sidebar__project-option-btn',
537
+ selected && project.id === selected.id && 'designbase-wc-sidebar__project-option-btn--active',
538
+ ]
539
+ .filter(Boolean)
540
+ .join(' ');
541
+ button.setAttribute('role', 'menuitem');
542
+ button.append(this.createProjectAvatar(project, 's'));
543
+ const optionLabel = document.createElement('span');
544
+ optionLabel.className = 'designbase-wc-sidebar__project-option-label';
545
+ optionLabel.textContent = project.label;
546
+ button.append(optionLabel);
547
+ const badge = this.createProjectBadge(project);
548
+ if (badge)
549
+ button.append(badge);
550
+ button.addEventListener('click', () => {
551
+ this.projectMenuOpen = false;
552
+ this.setAttribute('selected-project-id', project.id);
553
+ this.dispatchProjectChange(project);
554
+ this.render();
555
+ });
556
+ li.append(button);
557
+ list.append(li);
558
+ });
559
+ dropdown.append(list);
560
+ }
561
+ const manage = document.createElement('button');
562
+ manage.type = 'button';
563
+ manage.className = 'designbase-wc-sidebar__project-manage';
564
+ manage.setAttribute('role', 'menuitem');
565
+ manage.append(createDbIcon('plus', 14));
566
+ const manageLabel = document.createElement('span');
567
+ manageLabel.textContent = this.projectManageLabel;
568
+ manage.append(manageLabel);
569
+ manage.addEventListener('click', () => {
570
+ this.projectMenuOpen = false;
571
+ const href = this.projectManageHref;
572
+ if (href) {
573
+ window.location.assign(href);
574
+ }
575
+ this.dispatchProjectManage();
576
+ this.render();
577
+ });
578
+ dropdown.append(manage);
579
+ wrap.append(dropdown);
580
+ }
581
+ return wrap;
582
+ }
583
+ createFlyout(item, size) {
584
+ const position = this.getAttribute('position') || 'left';
585
+ const flyout = document.createElement('div');
586
+ flyout.className = [
587
+ 'designbase-wc-sidebar__flyout',
588
+ position === 'right' && 'designbase-wc-sidebar__flyout--align-left',
589
+ ]
590
+ .filter(Boolean)
591
+ .join(' ');
592
+ flyout.setAttribute('role', 'menu');
593
+ flyout.setAttribute('aria-label', `${item.label} 하위 메뉴`);
594
+ flyout.addEventListener('mouseenter', () => this.cancelFlyoutClose());
595
+ flyout.addEventListener('mouseleave', () => this.scheduleFlyoutClose());
596
+ const title = document.createElement('div');
597
+ title.className = 'designbase-wc-sidebar__flyout-title';
598
+ title.textContent = item.label;
599
+ flyout.append(title);
600
+ const list = document.createElement('ul');
601
+ list.className = 'designbase-wc-sidebar__flyout-list';
602
+ (item.children || []).forEach((child) => {
603
+ const li = document.createElement('li');
604
+ li.className = 'designbase-wc-sidebar__flyout-item';
605
+ const menuItem = document.createElement('db-menu-item');
606
+ menuItem.setAttribute('label', child.label);
607
+ menuItem.setAttribute('type', 'block');
608
+ menuItem.setAttribute('menu-style', 'dropdown');
609
+ menuItem.setAttribute('size', size);
610
+ if (child.href)
611
+ menuItem.setAttribute('href', child.href);
612
+ if (child.active)
613
+ menuItem.setAttribute('active', '');
614
+ if (child.disabled)
615
+ menuItem.setAttribute('disabled', '');
616
+ if (child.badge !== undefined)
617
+ menuItem.setAttribute('badge', String(child.badge));
618
+ if (child.badgeColor)
619
+ menuItem.setAttribute('badge-color', child.badgeColor);
620
+ menuItem.addEventListener('db-click', () => {
621
+ if (child.disabled)
622
+ return;
623
+ this.flyoutItemId = null;
624
+ this.dispatchItemClick(child);
625
+ this.renderNav();
626
+ this.renderBottomNav();
627
+ });
628
+ li.append(menuItem);
629
+ list.append(li);
630
+ });
631
+ flyout.append(list);
632
+ return flyout;
633
+ }
634
+ createSidebarMenuItem(item, size, depth = 0) {
635
+ const hasChildren = Boolean(item.children?.length);
636
+ const expanded = this.expandedItems.has(item.id);
637
+ const collapsed = this.hasAttribute('collapsed');
638
+ const useFlyout = collapsed && hasChildren;
639
+ const li = document.createElement('li');
640
+ li.className = [
641
+ 'designbase-wc-sidebar__item',
642
+ useFlyout && this.flyoutItemId === item.id && 'designbase-wc-sidebar__item--flyout-active',
643
+ ]
644
+ .filter(Boolean)
645
+ .join(' ');
646
+ if (useFlyout) {
647
+ li.addEventListener('mouseenter', () => this.showFlyout(item.id));
648
+ li.addEventListener('mouseleave', () => this.scheduleFlyoutClose());
649
+ }
650
+ const menuItem = document.createElement('db-menu-item');
651
+ menuItem.setAttribute('data-item-id', item.id);
652
+ menuItem.setAttribute('label', item.label);
653
+ menuItem.setAttribute('type', 'block');
654
+ menuItem.setAttribute('menu-style', 'accordion');
655
+ menuItem.setAttribute('size', size);
656
+ menuItem.setAttribute('depth', String(depth));
657
+ if (item.href)
658
+ menuItem.setAttribute('href', item.href);
659
+ if (item.icon)
660
+ menuItem.setAttribute('icon', item.icon);
661
+ if (item.active)
662
+ menuItem.setAttribute('active', '');
663
+ if (item.disabled)
664
+ menuItem.setAttribute('disabled', '');
665
+ if (item.badge !== undefined)
666
+ menuItem.setAttribute('badge', String(item.badge));
667
+ if (item.badgeColor)
668
+ menuItem.setAttribute('badge-color', item.badgeColor);
669
+ if (hasChildren && !useFlyout) {
670
+ menuItem.setAttribute('expandable', '');
671
+ menuItem.subItems = (item.children || []).map((child) => ({
672
+ id: child.id,
673
+ label: child.label,
674
+ href: child.href,
675
+ active: child.active,
676
+ disabled: child.disabled,
677
+ badge: child.badge,
678
+ badgeColor: child.badgeColor,
679
+ }));
680
+ if (expanded && !collapsed)
681
+ menuItem.setAttribute('expanded', '');
682
+ }
683
+ menuItem.addEventListener('db-click', (event) => {
684
+ if (item.disabled)
685
+ return;
686
+ if (hasChildren && !collapsed) {
687
+ const willOpen = event.detail?.expanded
688
+ ?? !this.expandedItems.has(item.id);
689
+ this.closeOverlayMenus();
690
+ if (willOpen) {
691
+ this.expandedItems.clear();
692
+ this.expandedItems.add(item.id);
693
+ this.syncExclusiveAccordion(item.id);
694
+ }
695
+ else {
696
+ this.expandedItems.delete(item.id);
697
+ this.syncExclusiveAccordion(null);
698
+ }
699
+ return;
700
+ }
701
+ if (useFlyout) {
702
+ this.closeOverlayMenus();
703
+ this.showFlyout(item.id);
704
+ return;
705
+ }
706
+ this.closeOverlayMenus();
707
+ this.dispatchItemClick(item);
708
+ });
709
+ menuItem.addEventListener('db-child-click', (event) => {
710
+ const detail = event.detail;
711
+ this.dispatchItemClick(detail.child);
712
+ });
713
+ li.append(menuItem);
714
+ if (collapsed && item.badge !== undefined && item.badge !== null && item.badge !== '') {
715
+ const badgeColor = item.badgeColor || 'primary';
716
+ const dot = document.createElement('span');
717
+ dot.className = [
718
+ 'designbase-wc-sidebar__collapsed-badge-dot',
719
+ `designbase-wc-sidebar__collapsed-badge-dot--${badgeColor}`,
720
+ ].join(' ');
721
+ dot.setAttribute('aria-hidden', 'true');
722
+ li.append(dot);
723
+ }
724
+ if (collapsed && !hasChildren) {
725
+ const tooltip = document.createElement('span');
726
+ tooltip.className = 'designbase-wc-sidebar__item-tooltip';
727
+ tooltip.textContent = item.label;
728
+ tooltip.setAttribute('role', 'tooltip');
729
+ li.append(tooltip);
730
+ }
731
+ if (useFlyout && this.flyoutItemId === item.id) {
732
+ li.append(this.createFlyout(item, size));
733
+ }
734
+ return li;
735
+ }
736
+ renderSectionList(sections, size, collapsed) {
737
+ const fragment = document.createDocumentFragment();
738
+ sections.forEach((section) => {
739
+ const sectionEl = document.createElement('div');
740
+ sectionEl.className = 'designbase-wc-sidebar__section';
741
+ if (!collapsed && section.title) {
742
+ const title = document.createElement('div');
743
+ title.className = 'designbase-wc-sidebar__section-title';
744
+ title.textContent = section.title;
745
+ sectionEl.append(title);
746
+ }
747
+ const list = document.createElement('ul');
748
+ list.className = 'designbase-wc-sidebar__nav-list';
749
+ section.items.forEach((item) => list.append(this.createSidebarMenuItem(item, size)));
750
+ sectionEl.append(list);
751
+ fragment.append(sectionEl);
752
+ });
753
+ return fragment;
754
+ }
755
+ renderNav() {
756
+ const nav = this.querySelector('.designbase-wc-sidebar__nav');
757
+ if (!nav)
758
+ return;
759
+ const size = this.getAttribute('size') || 'm';
760
+ const collapsed = this.hasAttribute('collapsed');
761
+ nav.replaceChildren(this.renderSectionList(this.parseSections(), size, collapsed));
762
+ }
763
+ renderBottomNav() {
764
+ const bottomNav = this.querySelector('.designbase-wc-sidebar__bottom-nav');
765
+ if (!bottomNav)
766
+ return;
767
+ const size = this.getAttribute('size') || 'm';
768
+ const collapsed = this.hasAttribute('collapsed');
769
+ bottomNav.replaceChildren(this.renderSectionList(this.parseBottomSections(), size, collapsed));
770
+ }
771
+ createUserDropdown(userMenuItems, collapsed = false) {
772
+ if (!userMenuItems.length)
773
+ return null;
774
+ const size = this.getAttribute('size') || 'm';
775
+ const dropdown = document.createElement('div');
776
+ dropdown.className = [
777
+ 'designbase-wc-sidebar__user-dropdown',
778
+ collapsed && 'designbase-wc-sidebar__user-dropdown--collapsed',
779
+ ]
780
+ .filter(Boolean)
781
+ .join(' ');
782
+ dropdown.setAttribute('role', 'menu');
783
+ dropdown.setAttribute('aria-label', '사용자 메뉴');
784
+ dropdown.hidden = !this.userMenuOpen;
785
+ const menu = document.createElement('ul');
786
+ menu.className = 'designbase-wc-sidebar__user-menu';
787
+ userMenuItems.forEach((item) => {
788
+ const li = document.createElement('li');
789
+ li.className = 'designbase-wc-sidebar__user-menu-item';
790
+ const menuItem = document.createElement('db-menu-item');
791
+ menuItem.setAttribute('label', item.label);
792
+ menuItem.setAttribute('type', 'block');
793
+ menuItem.setAttribute('menu-style', 'accordion');
794
+ menuItem.setAttribute('size', size);
795
+ if (item.icon)
796
+ menuItem.setAttribute('icon', item.icon);
797
+ if (item.href)
798
+ menuItem.setAttribute('href', item.href);
799
+ menuItem.addEventListener('db-click', () => {
800
+ this.userMenuOpen = false;
801
+ this.dispatchUserMenuItemClick(item);
802
+ this.render();
803
+ });
804
+ li.append(menuItem);
805
+ menu.append(li);
806
+ });
807
+ dropdown.append(menu);
808
+ return dropdown;
809
+ }
810
+ createPromoBanner(collapsed) {
811
+ const banner = this.parsePromoBanner();
812
+ if (!banner)
813
+ return null;
814
+ if (collapsed) {
815
+ const collapsedPromo = document.createElement('button');
816
+ collapsedPromo.type = 'button';
817
+ collapsedPromo.className = 'designbase-wc-sidebar__promo-collapsed';
818
+ collapsedPromo.setAttribute('aria-label', banner.ctaLabel || banner.title);
819
+ const animBg = document.createElement('db-animation-background');
820
+ animBg.className = 'designbase-wc-sidebar__promo-bg';
821
+ animBg.setAttribute('type', 'aurora');
822
+ animBg.setAttribute('theme', 'light');
823
+ animBg.setAttribute('intensity', 'subtle');
824
+ animBg.setAttribute('blur', '40');
825
+ animBg.setAttribute('speed', '4000');
826
+ animBg.setAttribute('colors', JSON.stringify(['#c7d2fe', '#ddd6fe', '#fbcfe8']));
827
+ collapsedPromo.append(animBg);
828
+ collapsedPromo.append(createDbIcon(banner.icon && isDbIconName(banner.icon) ? banner.icon : 'sparkle', 18));
829
+ collapsedPromo.addEventListener('click', () => this.dispatchPromoCtaClick(banner));
830
+ const tooltip = document.createElement('span');
831
+ tooltip.className = 'designbase-wc-sidebar__item-tooltip';
832
+ tooltip.textContent = banner.title;
833
+ tooltip.setAttribute('role', 'tooltip');
834
+ const wrap = document.createElement('div');
835
+ wrap.className = 'designbase-wc-sidebar__promo-collapsed-wrap';
836
+ wrap.append(collapsedPromo, tooltip);
837
+ return wrap;
838
+ }
839
+ const promo = document.createElement('div');
840
+ promo.className = 'designbase-wc-sidebar__promo';
841
+ const animBg = document.createElement('db-animation-background');
842
+ animBg.className = 'designbase-wc-sidebar__promo-bg';
843
+ animBg.setAttribute('type', 'aurora');
844
+ animBg.setAttribute('theme', 'light');
845
+ animBg.setAttribute('intensity', 'subtle');
846
+ animBg.setAttribute('blur', '60');
847
+ animBg.setAttribute('speed', '5000');
848
+ animBg.setAttribute('colors', JSON.stringify(['#c7d2fe', '#ddd6fe', '#fbcfe8', '#bfdbfe']));
849
+ promo.append(animBg);
850
+ const content = document.createElement('div');
851
+ content.className = 'designbase-wc-sidebar__promo-content';
852
+ const titleRow = document.createElement('div');
853
+ titleRow.className = 'designbase-wc-sidebar__promo-title-row';
854
+ const iconWrap = document.createElement('span');
855
+ iconWrap.className = 'designbase-wc-sidebar__promo-icon';
856
+ iconWrap.setAttribute('aria-hidden', 'true');
857
+ iconWrap.append(createDbIcon(banner.icon && isDbIconName(banner.icon) ? banner.icon : 'sparkle', 16));
858
+ const title = document.createElement('div');
859
+ title.className = 'designbase-wc-sidebar__promo-title';
860
+ title.textContent = banner.title;
861
+ titleRow.append(iconWrap, title);
862
+ content.append(titleRow);
863
+ if (banner.description) {
864
+ const desc = document.createElement('div');
865
+ desc.className = 'designbase-wc-sidebar__promo-desc';
866
+ desc.textContent = banner.description;
867
+ content.append(desc);
868
+ }
869
+ if (banner.ctaLabel) {
870
+ const cta = document.createElement('db-button');
871
+ cta.className = 'designbase-wc-sidebar__promo-action';
872
+ cta.setAttribute('variant', 'secondary');
873
+ cta.setAttribute('size', 's');
874
+ cta.setAttribute('full-width', '');
875
+ cta.textContent = banner.ctaLabel;
876
+ cta.addEventListener('db-click', () => {
877
+ if (banner.ctaHref)
878
+ window.location.assign(banner.ctaHref);
879
+ this.dispatchPromoCtaClick(banner);
880
+ });
881
+ content.append(cta);
882
+ }
883
+ promo.append(content);
884
+ return promo;
885
+ }
886
+ render() {
887
+ this.syncHostClasses();
888
+ this.setAttribute('role', 'complementary');
889
+ this.setAttribute('aria-label', '사이드바 네비게이션');
890
+ const size = this.getAttribute('size') || 'm';
891
+ const collapsible = this.getAttribute('collapsible') !== 'false';
892
+ const showLogo = this.getAttribute('show-logo') !== 'false';
893
+ const collapsed = this.hasAttribute('collapsed');
894
+ const userProfile = this.parseUserProfile();
895
+ const userMenuItems = this.parseUserMenuItems();
896
+ const bottomSections = this.parseBottomSections();
897
+ const logoSize = size === 'l' ? 'm' : size === 's' ? 'xs' : 's';
898
+ this.replaceChildren();
899
+ const container = document.createElement('div');
900
+ container.className = 'designbase-wc-sidebar__container';
901
+ if (collapsible || (showLogo && !collapsed)) {
902
+ const header = document.createElement('div');
903
+ header.className = [
904
+ 'designbase-wc-sidebar__header',
905
+ (collapsed || !showLogo) && 'designbase-wc-sidebar__header--collapsed-only',
906
+ ]
907
+ .filter(Boolean)
908
+ .join(' ');
909
+ if (!collapsed && showLogo) {
910
+ const logoWrap = document.createElement('div');
911
+ logoWrap.className = 'designbase-wc-sidebar__logo';
912
+ const logo = document.createElement('db-logo');
913
+ logo.setAttribute('type', 'designbase');
914
+ logo.setAttribute('size', logoSize);
915
+ logoWrap.append(logo);
916
+ logoWrap.addEventListener('click', () => {
917
+ this.dispatchEvent(new CustomEvent('db-logo-click', { bubbles: true, composed: true }));
918
+ });
919
+ header.append(logoWrap);
920
+ }
921
+ if (collapsible) {
922
+ const toggle = document.createElement('db-button');
923
+ toggle.className = 'designbase-wc-sidebar__toggle';
924
+ toggle.setAttribute('variant', 'tertiary');
925
+ toggle.setAttribute('size', 's');
926
+ toggle.setAttribute('icon-only', '');
927
+ toggle.setAttribute('start-icon', collapsed ? 'arrow-bar-right' : 'arrow-bar-left');
928
+ toggle.setAttribute('aria-label', collapsed ? '사이드바 펼치기' : '사이드바 접기');
929
+ toggle.addEventListener('db-click', () => {
930
+ const next = !this.hasAttribute('collapsed');
931
+ if (next)
932
+ this.setAttribute('collapsed', '');
933
+ else
934
+ this.removeAttribute('collapsed');
935
+ this.dispatchEvent(new CustomEvent('db-toggle', {
936
+ bubbles: true,
937
+ composed: true,
938
+ detail: { collapsed: next },
939
+ }));
940
+ });
941
+ header.append(toggle);
942
+ }
943
+ container.append(header);
944
+ }
945
+ const navWrapper = document.createElement('div');
946
+ navWrapper.className = 'designbase-wc-sidebar__nav-wrapper';
947
+ const projectSelector = this.createProjectSelector(collapsed);
948
+ if (projectSelector)
949
+ navWrapper.append(projectSelector);
950
+ const nav = document.createElement('nav');
951
+ nav.className = 'designbase-wc-sidebar__nav';
952
+ nav.setAttribute('aria-label', '주 메뉴');
953
+ navWrapper.append(nav);
954
+ if (bottomSections.length > 0) {
955
+ const bottomNav = document.createElement('nav');
956
+ bottomNav.className = 'designbase-wc-sidebar__bottom-nav';
957
+ bottomNav.setAttribute('aria-label', '하단 메뉴');
958
+ navWrapper.append(bottomNav);
959
+ }
960
+ container.append(navWrapper);
961
+ const footer = document.createElement('div');
962
+ footer.className = 'designbase-wc-sidebar__footer';
963
+ const promo = this.createPromoBanner(collapsed);
964
+ if (promo)
965
+ footer.append(promo);
966
+ if (userProfile && !collapsed) {
967
+ const user = document.createElement('div');
968
+ user.className = 'designbase-wc-sidebar__user';
969
+ const dropdown = this.createUserDropdown(userMenuItems);
970
+ if (dropdown)
971
+ user.append(dropdown);
972
+ const info = document.createElement('div');
973
+ info.className = 'designbase-wc-sidebar__user-info';
974
+ info.setAttribute('role', 'button');
975
+ info.setAttribute('tabindex', '0');
976
+ info.setAttribute('aria-expanded', String(this.userMenuOpen));
977
+ const avatar = document.createElement('db-avatar');
978
+ avatar.className = 'designbase-wc-sidebar__user-avatar';
979
+ avatar.setAttribute('size', 's');
980
+ avatar.setAttribute('initials', userProfile.name);
981
+ avatar.setAttribute('alt', userProfile.name);
982
+ if (userProfile.avatar)
983
+ avatar.setAttribute('src', userProfile.avatar);
984
+ const details = document.createElement('div');
985
+ details.className = 'designbase-wc-sidebar__user-details';
986
+ const name = document.createElement('div');
987
+ name.className = 'designbase-wc-sidebar__user-name';
988
+ name.textContent = userProfile.name;
989
+ details.append(name);
990
+ if (userProfile.email) {
991
+ const email = document.createElement('div');
992
+ email.className = 'designbase-wc-sidebar__user-email';
993
+ email.textContent = userProfile.email;
994
+ details.append(email);
995
+ }
996
+ info.append(avatar, details);
997
+ if (userMenuItems.length) {
998
+ const moreIcon = document.createElement('span');
999
+ moreIcon.className = 'designbase-wc-sidebar__user-more';
1000
+ moreIcon.setAttribute('aria-hidden', 'true');
1001
+ moreIcon.append(createDbIcon('more-vertical', 16));
1002
+ info.append(moreIcon);
1003
+ info.setAttribute('aria-haspopup', 'menu');
1004
+ }
1005
+ info.addEventListener('click', () => {
1006
+ if (!userMenuItems.length)
1007
+ return;
1008
+ this.userMenuOpen = !this.userMenuOpen;
1009
+ this.projectMenuOpen = false;
1010
+ this.render();
1011
+ });
1012
+ user.append(info);
1013
+ footer.append(user);
1014
+ }
1015
+ else if (userProfile && collapsed) {
1016
+ const collapsedUser = document.createElement('div');
1017
+ collapsedUser.className = [
1018
+ 'designbase-wc-sidebar__user-collapsed',
1019
+ this.userMenuOpen && 'designbase-wc-sidebar__user-collapsed--open',
1020
+ ]
1021
+ .filter(Boolean)
1022
+ .join(' ');
1023
+ collapsedUser.setAttribute('role', 'button');
1024
+ collapsedUser.setAttribute('tabindex', '0');
1025
+ collapsedUser.setAttribute('aria-label', userProfile.name);
1026
+ collapsedUser.setAttribute('aria-expanded', String(this.userMenuOpen));
1027
+ if (userMenuItems.length)
1028
+ collapsedUser.setAttribute('aria-haspopup', 'menu');
1029
+ const avatar = document.createElement('db-avatar');
1030
+ avatar.className = 'designbase-wc-sidebar__user-avatar-collapsed';
1031
+ avatar.setAttribute('size', 's');
1032
+ avatar.setAttribute('initials', userProfile.name);
1033
+ avatar.setAttribute('alt', userProfile.name);
1034
+ if (userProfile.avatar)
1035
+ avatar.setAttribute('src', userProfile.avatar);
1036
+ collapsedUser.append(avatar);
1037
+ if (!this.userMenuOpen) {
1038
+ const tooltip = document.createElement('span');
1039
+ tooltip.className = 'designbase-wc-sidebar__item-tooltip';
1040
+ tooltip.textContent = userProfile.name;
1041
+ tooltip.setAttribute('role', 'tooltip');
1042
+ collapsedUser.append(tooltip);
1043
+ }
1044
+ const dropdown = this.createUserDropdown(userMenuItems, true);
1045
+ if (dropdown)
1046
+ collapsedUser.append(dropdown);
1047
+ collapsedUser.addEventListener('click', (event) => {
1048
+ if (!userMenuItems.length)
1049
+ return;
1050
+ if (event.target.closest('.designbase-wc-sidebar__user-dropdown'))
1051
+ return;
1052
+ this.userMenuOpen = !this.userMenuOpen;
1053
+ this.projectMenuOpen = false;
1054
+ this.render();
1055
+ });
1056
+ footer.append(collapsedUser);
1057
+ }
1058
+ container.append(footer);
1059
+ this.append(container);
1060
+ this.renderNav();
1061
+ this.renderBottomNav();
1062
+ }
1063
+ }
1064
+ if (!customElements.get('db-sidebar')) {
1065
+ customElements.define('db-sidebar', DbSidebar);
1066
+ }
1067
+
1068
+ export { DbSidebar };