@nextcloud/vue
Version:
Nextcloud vue components
1 lines • 78.9 kB
Source Map (JSON)
{"version":3,"file":"NcAppSidebar-BvBvQsXb.mjs","sources":["../../node_modules/vue-material-design-icons/DockRight.vue","../../node_modules/vue-material-design-icons/Star.vue","../../node_modules/vue-material-design-icons/StarOutline.vue","../../src/components/NcAppSidebar/NcAppSidebarTabsButton.vue","../../src/components/NcAppSidebar/NcAppSidebarTabs.vue","../../src/components/NcAppSidebar/NcAppSidebar.vue"],"sourcesContent":["<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon dock-right-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M20 4H4A2 2 0 0 0 2 6V18A2 2 0 0 0 4 20H20A2 2 0 0 0 22 18V6A2 2 0 0 0 20 4M15 18H4V6H15Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"DockRightIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon star-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M12,17.27L18.18,21L16.54,13.97L22,9.24L14.81,8.62L12,2L9.19,8.62L2,9.24L7.45,13.97L5.82,21L12,17.27Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"StarIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon star-outline-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M12,15.39L8.24,17.66L9.23,13.38L5.91,10.5L10.29,10.13L12,6.09L13.71,10.13L18.09,10.5L14.77,13.38L15.76,17.66M22,9.24L14.81,8.63L12,2L9.19,8.63L2,9.24L7.45,13.97L5.82,21L12,17.27L18.18,21L16.54,13.97L22,9.24Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"StarOutlineIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<!--\n - SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type NcAppSidebarTab from '../NcAppSidebarTab/NcAppSidebarTab.vue'\n\nimport NcVNodes from '../NcVNodes/NcVNodes.vue'\n\nconst selected = defineModel<boolean>('selected', { required: true })\n\ndefineProps<{\n\t/**\n\t * The sidebar tab this button controls\n\t */\n\ttab: InstanceType<typeof NcAppSidebarTab>\n}>()\n</script>\n\n<template>\n\t<button\n\t\tclass=\"button-vue\"\n\t\t:class=\"[$style.sidebarTabsButton, {\n\t\t\t[$style.sidebarTabsButton_selected]: selected,\n\t\t}]\"\n\t\trole=\"tab\"\n\t\t:aria-selected=\"selected\"\n\t\t:tabindex=\"selected ? 0 : -1\"\n\t\t@click=\"selected = true\">\n\t\t<span :class=\"$style.sidebarTabsButton__icon\">\n\t\t\t<NcVNodes :vnodes=\"tab.renderIcon()\">\n\t\t\t\t<span :class=\"[$style.sidebarTabsButton__legacyIcon, tab.icon]\" />\n\t\t\t</NcVNodes>\n\t\t</span>\n\t\t<span :class=\"$style.sidebarTabsButton__name\">\n\t\t\t{{ tab.name }}\n\t\t</span>\n\t</button>\n</template>\n\n<style module lang=\"scss\">\n.sidebarTabsButton {\n\tborder: none;\n\tborder-bottom: var(--default-grid-baseline) solid transparent !important;\n\tborder-radius: var(--border-radius-small);\n\tbackground-color: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont-size: var(--default-font-size);\n\tcursor: pointer;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: var(--default-grid-baseline);\n\tpadding: var(--border-radius-small);\n\ttransition:\n\t\tbackground-color var(--animation-quick),\n\t\tborder-bottom-color var(--animation-quick);\n\tmin-width: var(--default-clickable-area);\n\n\t&:hover {\n\t\tbackground-color: var(--color-background-hover) !important;\n\t}\n\n\t&:active,\n\t&:focus {\n\t\tbackground-color: var(--color-main-background) !important;\n\t}\n\n\t* {\n\t\tcursor: pointer;\n\t}\n}\n\n.sidebarTabsButton_selected {\n\tborder-bottom-color: var(--color-primary-element) !important;\n\tborder-bottom-left-radius: 0px;\n\tborder-bottom-right-radius: 0px;\n\tcursor: default;\n\n\t&:hover {\n\t\tbackground-color: var(--color-primary-element-light-hover) !important;\n\t\tcolor: var(--color-primary-element-light-text) !important;\n\t}\n\n\t* {\n\t\tcursor: default;\n\t}\n}\n\n.sidebarTabsButton__name {\n\tfont-weight: normal;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\ttext-wrap: nowrap;\n}\n\n.sidebarTabsButton_selected .sidebarTabsButton__name {\n\tfont-weight: bold;\n}\n\n.sidebarTabsButton__icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.sidebarTabsButton__legacyIcon {\n\tbackground-size: 20px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<!-- Follows the tab aria guidelines\n\thttps://www.w3.org/TR/wai-aria-practices/examples/tabs/tabs-1/tabs.html -->\n<template>\n\t<div class=\"app-sidebar-tabs\">\n\t\t<!-- tabs navigation -->\n\t\t<!-- 33 and 34 code is for page up and page down -->\n\t\t<div\n\t\t\tv-if=\"hasMultipleTabs || showForSingleTab\"\n\t\t\trole=\"tablist\"\n\t\t\tclass=\"app-sidebar-tabs__nav\"\n\t\t\t@keydown.left.exact.prevent.stop=\"focusPreviousTab\"\n\t\t\t@keydown.right.exact.prevent.stop=\"focusNextTab\"\n\t\t\t@keydown.tab.exact.prevent.stop=\"focusActiveTabContent\"\n\t\t\t@keydown.home.exact.prevent.stop=\"focusFirstTab\"\n\t\t\t@keydown.end.exact.prevent.stop=\"focusLastTab\"\n\t\t\t@keydown.page-up.exact.prevent.stop=\"focusFirstTab\"\n\t\t\t@keydown.page-down.exact.prevent.stop=\"focusLastTab\">\n\t\t\t<NcAppSidebarTabsButton\n\t\t\t\tv-for=\"tab in tabs\"\n\t\t\t\t:id=\"`tab-button-${tab.id}`\"\n\t\t\t\t:key=\"tab.id\"\n\t\t\t\tclass=\"app-sidebar-tabs__tab\"\n\t\t\t\t:aria-controls=\"`tab-${tab.id}`\"\n\t\t\t\t:selected=\"activeTab === tab.id\"\n\t\t\t\t:tab\n\t\t\t\t@update:selected=\"setActive(tab.id)\" />\n\t\t</div>\n\n\t\t<!-- tabs content -->\n\t\t<div\n\t\t\tclass=\"app-sidebar-tabs__content\"\n\t\t\t:class=\"{ 'app-sidebar-tabs__content--multiple': hasMultipleTabs }\">\n\t\t\t<!-- @slot Tabs content - NcAppSidebarTab components or any content if there is no tabs -->\n\t\t\t<slot />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { getCanonicalLocale } from '@nextcloud/l10n'\nimport NcAppSidebarTabsButton from './NcAppSidebarTabsButton.vue'\n\nexport default {\n\tname: 'NcAppSidebarTabs',\n\n\tcomponents: {\n\t\tNcAppSidebarTabsButton,\n\t},\n\n\tprovide() {\n\t\treturn {\n\t\t\tregisterTab: this.registerTab,\n\t\t\tunregisterTab: this.unregisterTab,\n\t\t\t// Getter as an alternative to Vue 2.7 computed(() => this.activeTab)\n\t\t\tgetActiveTab: () => this.activeTab,\n\t\t\t// Used to check whether the tab header is shown so the tabs can reference the tab header for `aria-labelledby` or not\n\t\t\tisTablistShown: () => this.hasMultipleTabs,\n\t\t}\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Id of the tab to activate\n\t\t */\n\t\tactive: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Force the tab navigation to display even if there is only one tab\n\t\t */\n\t\tforceTabs: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\temits: ['update:active'],\n\n\tdata(props) {\n\t\treturn {\n\t\t\t/**\n\t\t\t * Tab descriptions from the passed NcSidebarTab components' props to build the tab navbar from.\n\t\t\t */\n\t\t\ttabs: [],\n\t\t\t/**\n\t\t\t * Local active (open) tab's ID. It allows to use component without v-model:active\n\t\t\t */\n\t\t\tactiveTab: props.active,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Has multiple tabs. If only one tab - its content is shown without navigation\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\thasMultipleTabs() {\n\t\t\treturn this.tabs.length > 1\n\t\t},\n\n\t\tshowForSingleTab() {\n\t\t\treturn this.forceTabs && this.tabs.length === 1\n\t\t},\n\n\t\tcurrentTabIndex() {\n\t\t\treturn this.tabs.findIndex((tab) => tab.id === this.activeTab)\n\t\t},\n\t},\n\n\twatch: {\n\t\ttabs() {\n\t\t\tif (this.active) {\n\t\t\t\tthis.updateActive()\n\t\t\t}\n\t\t},\n\n\t\tactive(active) {\n\t\t\t// Prevent running it twice\n\t\t\tif (active !== this.activeTab) {\n\t\t\t\tthis.updateActive()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\n\t\t/**\n\t\t * Set the current active tab\n\t\t *\n\t\t * @param {string} id the id of the tab\n\t\t */\n\t\tsetActive(id) {\n\t\t\tthis.activeTab = id\n\t\t\t/**\n\t\t\t * @property {string} active - active tab's id\n\t\t\t */\n\t\t\tthis.$emit('update:active', this.activeTab)\n\t\t},\n\n\t\t/**\n\t\t * Focus the previous tab\n\t\t * and emit to the parent component\n\t\t */\n\t\tfocusPreviousTab() {\n\t\t\tif (this.currentTabIndex > 0) {\n\t\t\t\tthis.setActive(this.tabs[this.currentTabIndex - 1].id)\n\t\t\t}\n\t\t\tthis.focusActiveTab()\n\t\t},\n\n\t\t/**\n\t\t * Focus the next tab\n\t\t * and emit to the parent component\n\t\t */\n\t\tfocusNextTab() {\n\t\t\tif (this.currentTabIndex < this.tabs.length - 1) {\n\t\t\t\tthis.setActive(this.tabs[this.currentTabIndex + 1].id)\n\t\t\t}\n\t\t\tthis.focusActiveTab()\n\t\t},\n\n\t\t/**\n\t\t * Focus the first tab\n\t\t * and emit to the parent component\n\t\t */\n\t\tfocusFirstTab() {\n\t\t\tthis.setActive(this.tabs[0].id)\n\t\t\tthis.focusActiveTab()\n\t\t},\n\n\t\t/**\n\t\t * Focus the last tab\n\t\t * and emit to the parent component\n\t\t */\n\t\tfocusLastTab() {\n\t\t\tthis.setActive(this.tabs[this.tabs.length - 1].id)\n\t\t\tthis.focusActiveTab()\n\t\t},\n\n\t\t/**\n\t\t * Focus the current active tab\n\t\t */\n\t\tfocusActiveTab() {\n\t\t\tthis.$el.querySelector(`#tab-button-${this.activeTab}`).focus()\n\t\t},\n\n\t\t/**\n\t\t * Focus the content on tab\n\t\t * see aria accessibility guidelines\n\t\t */\n\t\tfocusActiveTabContent() {\n\t\t\tthis.$el.querySelector('#tab-' + this.activeTab).focus()\n\t\t},\n\n\t\t/**\n\t\t * Update the current active tab\n\t\t */\n\t\tupdateActive() {\n\t\t\tthis.activeTab = (this.active && this.tabs.some(({ id }) => id === this.active))\n\t\t\t\t? this.active\n\t\t\t\t: (this.tabs[0]?.id ?? '')\n\t\t},\n\n\t\t/**\n\t\t * Register child tab in the tabs\n\t\t *\n\t\t * @param {object} tab child tab passed to slot\n\t\t */\n\t\tregisterTab(tab) {\n\t\t\tthis.tabs.push(tab)\n\t\t\tthis.tabs.sort((a, b) => {\n\t\t\t\tif (a.order === b.order) {\n\t\t\t\t\treturn a.name.localeCompare(b.name, [getCanonicalLocale()])\n\t\t\t\t}\n\t\t\t\treturn a.order - b.order\n\t\t\t})\n\t\t\tthis.updateActive()\n\t\t},\n\n\t\t/**\n\t\t * Unregister child tab from the tabs\n\t\t *\n\t\t * @param {string} id tab's id\n\t\t */\n\t\tunregisterTab(id) {\n\t\t\tconst tabIndex = this.tabs.findIndex((tab) => tab.id === id)\n\t\t\tif (tabIndex !== -1) {\n\t\t\t\tthis.tabs.splice(tabIndex, 1)\n\t\t\t}\n\t\t\tif (this.activeTab === id) {\n\t\t\t\tthis.updateActive()\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.app-sidebar-tabs {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmin-height: 0;\n\tflex: 1 1 100%;\n\n\t&__nav {\n\t\tdisplay: flex;\n\t\tjustify-content: stretch;\n\t\tmargin: 10px 8px 0 8px;\n\t\tborder-bottom: 1px solid var(--color-border);\n\t}\n\n\t&__tab {\n\t\tflex: 1 1 1px;\n\t}\n\n\t&__content {\n\t\tposition: relative;\n\t\tmin-height: 256px;\n\t\theight: 100%;\n\t\t// force the use of the tab component if more than one tab\n\t\t// you can just put raw content if you don't use tabs\n\t\t&--multiple > :not(section) {\n\t\t\tdisplay: none;\n\t\t}\n\t}\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<docs>\n### Exposed CSS Variables\n\n| Variable | Description |\n|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------|\n| `--app-sidebar-padding` | The padding between the toggle button and the page border. |\n| `--app-sidebar-offset` | The minimal offset width required to be reserved for the toggle button. <br /> Automatically changes to 0 when there is no toggle button. |\n\n### General description\n\nThis component provides a way to include the standardised sidebar.\nThe standard properties like name, subname, starred, etc. allow to automatically\ninclude a standard-header like it's used by the files app.\n\nTo conditionally show the sidebar either use `v-if` on the sidebar component,\nor use the `open` property of the component to control the state.\nUsing `v-show` directly will result in usability issues due to internal focus trap handling.\n\n### Standard usage\n\n```vue\n<template>\n\t<div class=\"content-styleguidist\">\n\t\t<main id=\"content-styleguidist-1\" />\n\t\t<NcAppSidebar\n\t\t\tv-model:open=\"open\"\n\t\t\t:starred=\"starred\"\n\t\t\tname=\"cat-picture.jpg\"\n\t\t\tsubname=\"last edited 3 weeks ago\"\n\t\t\tbackground=\"https://nextcloud.com/wp-content/uploads/2022/08/nextcloud-logo-icon.svg\"\n\t\t\t@figure-click=\"figureClick\">\n\t\t\t<NcAppSidebarTab name=\"Search\" id=\"search-tab\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<IconMagnify :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\tSearch tab content\n\t\t\t</NcAppSidebarTab>\n\t\t\t<NcAppSidebarTab name=\"Settings\" id=\"settings-tab\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<IconCogOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\tSettings tab content\n\t\t\t</NcAppSidebarTab>\n\t\t\t<NcAppSidebarTab name=\"Sharing\" id=\"share-tab\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<IconShareVariantOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\tSharing tab content\n\t\t\t</NcAppSidebarTab>\n\t\t</NcAppSidebar>\n\t</div>\n</template>\n\n<script>\n\timport IconMagnify from 'vue-material-design-icons/Magnify.vue'\n\timport IconCogOutline from 'vue-material-design-icons/CogOutline.vue'\n\timport IconShareVariantOutline from 'vue-material-design-icons/ShareVariantOutline.vue'\n\n\texport default {\n\t\tcomponents: {\n\t\t\tIconMagnify,\n\t\t\tIconCogOutline,\n\t\t\tIconShareVariantOutline,\n\t\t},\n\t\tprovide() {\n\t\t\treturn {\n\t\t\t\t'NcContent:selector': '#content-styleguidist-1',\n\t\t\t}\n\t\t},\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\topen: true,\n\t\t\t\tstarred: false,\n\t\t\t}\n\t\t},\n\t\tmethods: {\n\t\t\tfigureClick() {\n\t\t\t\talert('figure clicked')\n\t\t\t},\n\t\t},\n\t}\n</script>\n\n<style scoped>\n\t/* This styles just mock NcContent and NcAppContent */\n\t.content-styleguidist {\n\t\t--app-sidebar-padding: 8px;\n\t\t--app-sidebar-offset: calc(var(--app-sidebar-padding) + var(--default-clickable-area));\n\t\tdisplay: flex;\n\t\tposition: relative !important;\n\t\t/* Just to prevent jumping when the sidebar is hidden */\n\t\tmin-height: 360px;\n\t\toverflow: hidden;\n\n\t\tmain {\n\t\t\twidth: 100%;\n\t\t}\n\t}\n\n\t/* Fix styles on this style guide page */\n\t@media only screen and (max-width: 512px) {\n\t\t:deep(aside) {\n\t\t\twidth: calc(100vw - 64px) !important;\n\t\t}\n\t}\n</style>\n```\n\n### Dynamic tabs\n\nSidebar tabs and their content can be changed dynamically.\n\nSingle tab is rendered without navigation, but it is possible to force it.\n\n```vue\n<template>\n\t<div class=\"content-styleguidist\">\n\t\t<main id=\"content-styleguidist-2\">\n\t\t\t<NcCheckboxRadioSwitch v-model=\"forceTabs\">Force tab navigation</NcCheckboxRadioSwitch>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"showTabs[0]\">Show search tab</NcCheckboxRadioSwitch>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"showTabs[1]\">Show settings tab</NcCheckboxRadioSwitch>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"showTabs[2]\">Show sharing tab</NcCheckboxRadioSwitch>\n\t\t</main>\n\t\t<NcAppSidebar\n\t\t\tv-model:open=\"open\"\n\t\t\t:force-tabs=\"forceTabs\"\n\t\t\tname=\"cat-picture.jpg\"\n\t\t\tsubname=\"last edited 3 weeks ago\">\n\t\t\t<NcAppSidebarTab v-if=\"showTabs[0]\" name=\"Search\" id=\"search-tab\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<IconMagnify :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\tSearch tab content\n\t\t\t</NcAppSidebarTab>\n\t\t\t<NcAppSidebarTab v-if=\"showTabs[1]\" name=\"Settings\" id=\"settings-tab\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<IconCogOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\tSettings\n\t\t\t</NcAppSidebarTab>\n\t\t\t<NcAppSidebarTab v-if=\"showTabs[2]\" name=\"Sharing\" id=\"share-tab\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<IconShareVariantOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\tSharing tab content\n\t\t\t</NcAppSidebarTab>\n\t\t</NcAppSidebar>\n\t</div>\n</template>\n\n<script>\n\timport IconMagnify from 'vue-material-design-icons/Magnify.vue'\n\timport IconCogOutline from 'vue-material-design-icons/CogOutline.vue'\n\timport IconShareVariantOutline from 'vue-material-design-icons/ShareVariantOutline.vue'\n\n\texport default {\n\t\tcomponents: {\n\t\t\tIconMagnify,\n\t\t\tIconCogOutline,\n\t\t\tIconShareVariantOutline,\n\t\t},\n\t\tprovide() {\n\t\t\treturn {\n\t\t\t\t'NcContent:selector': '#content-styleguidist-2',\n\t\t\t}\n\t\t},\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\topen: true,\n\t\t\t\tforceTabs: false,\n\t\t\t\tshowTabs: [true, true, false],\n\t\t\t}\n\t\t},\n\t}\n</script>\n\n<style scoped>\n\t/* This styles just mock NcContent and NcAppContent */\n\t.content-styleguidist {\n\t\t--app-sidebar-padding: 8px;\n\t\t--app-sidebar-offset: calc(var(--app-sidebar-padding) + var(--default-clickable-area));\n\t\tdisplay: flex;\n\t\tposition: relative !important;\n\t\t/* Just to prevent jumping when the sidebar is hidden */\n\t\tmin-height: 360px;\n\t\toverflow: hidden;\n\n\t\tmain {\n\t\t\twidth: 100%;\n\t\t}\n\t}\n\n\t/* Fix styles on this style guide page */\n\t@media only screen and (max-width: 512px) {\n\t\t:deep(aside) {\n\t\t\twidth: calc(100vw - 64px) !important;\n\t\t}\n\t}\n</style>\n```\n\n### Tabs order and programmatic activation\n\nTo customize the order of tabs, ``order`` prop can be used on child components.\n\n``active`` prop on NcAppSidebar can be modified to show required tab as active\n\n```vue\n<template>\n\t<div class=\"content-styleguidist\">\n\t\t<main id=\"content-styleguidist-3\">\n\t\t\t<NcSelect v-model=\"active\" :options=\"['search-tab', 'settings-tab', 'share-tab']\"/>\n\t\t</main>\n\t\t<NcAppSidebar\n\t\t\tname=\"cat-picture.jpg\"\n\t\t\tsubname=\"last edited 3 weeks ago\"\n\t\t\tv-model:open=\"open\"\n\t\t\tv-model:active=\"active\">\n\t\t\t<NcAppSidebarTab name=\"Search\" id=\"search-tab\" :order=\"3\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<IconMagnify :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\tSearch tab content\n\t\t\t</NcAppSidebarTab>\n\t\t\t<NcAppSidebarTab name=\"Settings\" id=\"settings-tab\" :order=\"2\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<IconCogOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\tSettings\n\t\t\t</NcAppSidebarTab>\n\t\t\t<NcAppSidebarTab name=\"Sharing\" id=\"share-tab\" :order=\"1\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<IconShareVariantOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\tSharing tab content\n\t\t\t</NcAppSidebarTab>\n\t\t</NcAppSidebar>\n\t</div>\n</template>\n\n<script>\n\timport IconMagnify from 'vue-material-design-icons/Magnify.vue'\n\timport IconCogOutline from 'vue-material-design-icons/CogOutline.vue'\n\timport IconShareVariantOutline from 'vue-material-design-icons/ShareVariantOutline.vue'\n\n\texport default {\n\t\tcomponents: {\n\t\t\tIconMagnify,\n\t\t\tIconCogOutline,\n\t\t\tIconShareVariantOutline,\n\t\t},\n\t\tprovide() {\n\t\t\treturn {\n\t\t\t\t'NcContent:selector': '#content-styleguidist-3',\n\t\t\t}\n\t\t},\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\topen: true,\n\t\t\t\tactive: 'search-tab',\n\t\t\t}\n\t\t},\n\t}\n</script>\n\n<style scoped>\n\t/* This styles just mock NcContent and NcAppContent */\n\t.content-styleguidist {\n\t\t--app-sidebar-padding: 8px;\n\t\t--app-sidebar-offset: calc(var(--app-sidebar-padding) + var(--default-clickable-area));\n\t\tdisplay: flex;\n\t\tposition: relative !important;\n\t\t/* Just to prevent jumping when the sidebar is hidden */\n\t\tmin-height: 360px;\n\t\toverflow: hidden;\n\n\t\tmain {\n\t\t\twidth: 100%;\n\t\t}\n\t}\n\n\t/* Fix styles on this style guide page */\n\t@media only screen and (max-width: 512px) {\n\t\t:deep(aside) {\n\t\t\twidth: calc(100vw - 64px) !important;\n\t\t}\n\t}\n</style>\n```\n\n### Editable name\n\n```vue\n<template>\n\t<div class=\"content-styleguidist\">\n\t\t<main id=\"content-styleguidist-4\" />\n\t\t<NcAppSidebar\n\t\t\tv-model:open=\"open\"\n\t\t\tv-model:name=\"name\"\n\t\t\t:name-editable=\"true\"\n\t\t\tname-placeholder=\"Filename\"\n\t\t\tsubname=\"last edited 3 weeks ago\">\n\t\t\t<!-- Insert your slots and tabs here -->\n\t\t</NcAppSidebar>\n\t</div>\n</template>\n\n<script>\n\texport default {\n\t\tprovide() {\n\t\t\treturn {\n\t\t\t\t'NcContent:selector': '#content-styleguidist-4',\n\t\t\t}\n\t\t},\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\topen: true,\n\t\t\t\tname: 'cat-picture.jpg',\n\t\t\t}\n\t\t},\n\t}\n</script>\n\n<style scoped>\n\t/* This styles just mock NcContent and NcAppContent */\n\t.content-styleguidist {\n\t\t--app-sidebar-padding: 8px;\n\t\t--app-sidebar-offset: calc(var(--app-sidebar-padding) + var(--default-clickable-area));\n\t\tdisplay: flex;\n\t\tposition: relative !important;\n\t\t/* Just to prevent jumping when the sidebar is hidden */\n\t\tmin-height: 360px;\n\t\toverflow: hidden;\n\n\t\tmain {\n\t\t\twidth: 100%;\n\t\t}\n\t}\n\n\t/* Fix styles on this style guide page */\n\t@media only screen and (max-width: 512px) {\n\t\t:deep(aside) {\n\t\t\twidth: calc(100vw - 64px) !important;\n\t\t}\n\t}\n</style>\n```\n\n### Editable name after click with custom tertiary action\n\n```vue\n<template>\n\t<div class=\"content-styleguidist\">\n\t\t<main id=\"content-styleguidist-5\" />\n\t\t<NcAppSidebar\n\t\t\t:name=\"name\"\n\t\t\tv-model:open=\"open\"\n\t\t\tv-model:name-editable=\"nameEditable\"\n\t\t\t:name-placeholder=\"namePlaceholder\"\n\t\t\t:subname=\"subname\"\n\t\t\t@update:name=\"nameUpdate\">\n\t\t\t<template #tertiary-actions>\n\t\t\t\t<form>\n\t\t\t\t\t<input type=\"checkbox\" @click=\"toggledCheckbox\"/>\n\t\t\t\t</form>\n\t\t\t</template>\n\t\t</NcAppSidebar>\n\t</div>\n</template>\n\n<script>\n\texport default {\n\t\tprovide() {\n\t\t\treturn {\n\t\t\t\t'NcContent:selector': '#content-styleguidist-5',\n\t\t\t}\n\t\t},\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\topen: true,\n\t\t\t\tname: 'cat-picture.jpg',\n\t\t\t\tnamePlaceholder: 'Filename',\n\t\t\t\tsubname: 'last edited 3 weeks ago',\n\t\t\t\tnameEditable: false\n\t\t\t}\n\t\t},\n\t\tmethods: {\n\t\t\tnameUpdate(e) {\n\t\t\t\tthis.name = e\n\t\t\t},\n\t\t\ttoggledCheckbox() {\n\t\t\t\talert('toggle')\n\t\t\t}\n\t\t}\n\t}\n</script>\n\n<style scoped>\n\t/* This styles just mock NcContent and NcAppContent */\n\t.content-styleguidist {\n\t\t--app-sidebar-padding: 8px;\n\t\t--app-sidebar-offset: calc(var(--app-sidebar-padding) + var(--default-clickable-area));\n\t\tdisplay: flex;\n\t\tposition: relative !important;\n\t\t/* Just to prevent jumping when the sidebar is hidden */\n\t\tmin-height: 360px;\n\t\toverflow: hidden;\n\n\t\tmain {\n\t\t\twidth: 100%;\n\t\t}\n\t}\n\n\t/* Fix styles on this style guide page */\n\t@media only screen and (max-width: 512px) {\n\t\t:deep(aside) {\n\t\t\twidth: calc(100vw - 64px) !important;\n\t\t}\n\t}\n</style>\n```\n\n### Custom subname\n\nInstead of using the `subname` prop you can use the same called slot. This is handy if you need to add accessible information.\nLike in the following example where the goal is to show a star icon to mark the file a favorite.\nSimply adding `★` would not work as screen readers might not or wrongly announce the icon meaning this information is lost.\n\nA working alternative would be using an icon together with an `aria-label`:\n\n```vue\n<template>\n\t<div class=\"content-styleguidist\">\n\t\t<main id=\"content-styleguidist-6\" />\n\t\t<NcAppSidebar\n\t\t\tv-model:open=\"open\"\n\t\t\tname=\"cat-picture.jpg\">\n\t\t\t<template #subname>\n\t\t\t\t<NcIconSvgWrapper inline :path=\"mdiStar\" name=\"Favorite\" />\n\t\t\t\t123 KiB, a month ago\n\t\t\t</template>\n\t\t</NcAppSidebar>\n\t</div>\n</template>\n\n<script>\n\timport { mdiStar } from '@mdi/js'\n\n\texport default {\n\t\tsetup() {\n\t\t\treturn {\n\t\t\t\tmdiStar,\n\t\t\t}\n\t\t},\n\t\tprovide() {\n\t\t\treturn {\n\t\t\t\t'NcContent:selector': '#content-styleguidist-6',\n\t\t\t}\n\t\t},\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\topen: true,\n\t\t\t}\n\t\t},\n\t}\n</script>\n\n<style scoped>\n\t/* This styles just mock NcContent and NcAppContent */\n\t.content-styleguidist {\n\t\t--app-sidebar-padding: 8px;\n\t\t--app-sidebar-offset: calc(var(--app-sidebar-padding) + var(--default-clickable-area));\n\t\tdisplay: flex;\n\t\tposition: relative !important;\n\t\t/* Just to prevent jumping when the sidebar is hidden */\n\t\tmin-height: 360px;\n\t\toverflow: hidden;\n\n\t\tmain {\n\t\t\twidth: 100%;\n\t\t}\n\t}\n\n\t/* Fix styles on this style guide page */\n\t@media only screen and (max-width: 512px) {\n\t\t:deep(aside) {\n\t\t\twidth: calc(100vw - 64px) !important;\n\t\t}\n\t}\n</style>\n```\n\n### Empty sidebar for e.g. empty content component.\n\n```vue\n<template>\n\t<div class=\"content-styleguidist\">\n\t\t<main id=\"content-styleguidist-7\" />\n\t\t<NcAppSidebar\n\t\t\tv-model:open=\"open\"\n\t\t\tname=\"cat-picture.jpg\"\n\t\t\t:empty=\"true\">\n\t\t\t<NcEmptyContent name=\"Content not found.\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Magnify :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcEmptyContent>\n\t\t</NcAppSidebar>\n\t</div>\n</template>\n\n<script>\n\timport Magnify from 'vue-material-design-icons/Magnify.vue'\n\n\texport default {\n\t\tcomponents: {\n\t\t\tMagnify,\n\t\t},\n\t\tprovide() {\n\t\t\treturn {\n\t\t\t\t'NcContent:selector': '#content-styleguidist-7',\n\t\t\t}\n\t\t},\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\topen: true,\n\t\t\t}\n\t\t},\n\t}\n</script>\n\n<style scoped>\n\t/* This styles just mock NcContent and NcAppContent */\n\t.content-styleguidist {\n\t\t--app-sidebar-padding: 8px;\n\t\t--app-sidebar-offset: calc(var(--app-sidebar-padding) + var(--default-clickable-area));\n\t\tdisplay: flex;\n\t\tposition: relative !important;\n\t\t/* Just to prevent jumping when the sidebar is hidden */\n\t\tmin-height: 360px;\n\t\toverflow: hidden;\n\n\t\tmain {\n\t\t\twidth: 100%;\n\t\t}\n\t}\n\n\t/* Fix styles on this style guide page */\n\t@media only screen and (max-width: 512px) {\n\t\t:deep(aside) {\n\t\t\twidth: calc(100vw - 64px) !important;\n\t\t}\n\t}\n</style>\n```\n\n### Conditionally show the sidebar with `open`\n\nIf the sidebar should be shown conditionally, you can use `open` prop to define sidebar visibility.\nIt automatically shows a toggle button to open the sidebar if it is closed.\n\nYou can also use `--app-sidebar-offset` CSS variable to preserve space\nfor the toggle button, for example, in top bar of `NcAppContent`.\n\nThe built-in toggle button can be removed with `no-toggle` prop.\n\nNote: the built-in toggle button is only available then NcAppSidebar is used in NcContent.\n\n```vue\n<template>\n\t<div class=\"content-styleguidist\">\n\t\t<main id=\"content-styleguidist-8\">\n\t\t\t<div class=\"top-bar\">\n\t\t\t\t<NcButton variant=\"primary\">Start a call</NcButton>\n\t\t\t</div>\n\t\t</main>\n\t\t<NcAppSidebar\n\t\t\tv-model:open=\"open\"\n\t\t\tname=\"cat-picture.jpg\"\n\t\t\tsubname=\"last edited 3 weeks ago\">\n\t\t\t<NcAppSidebarTab name=\"Settings\" id=\"settings-tab\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Cog :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\tSingle tab content\n\t\t\t</NcAppSidebarTab>\n\t\t</NcAppSidebar>\n\t</div>\n</template>\n\n<script>\n\timport Cog from 'vue-material-design-icons/Cog'\n\n\texport default {\n\t\tcomponents: {\n\t\t\tCog,\n\t\t},\n\t\tprovide() {\n\t\t\treturn {\n\t\t\t\t'NcContent:selector': '#content-styleguidist-8',\n\t\t\t}\n\t\t},\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\topen: true,\n\t\t\t}\n\t\t},\n\t}\n</script>\n\n<style scoped>\n\t/* This styles just mock NcContent and NcAppContent */\n\t.content-styleguidist {\n\t\t--app-sidebar-padding: 8px;\n\t\t--app-sidebar-offset: calc(var(--app-sidebar-padding) + var(--default-clickable-area));\n\t\tdisplay: flex;\n\t\tposition: relative !important;\n\t\t/* Just to prevent jumping when the sidebar is hidden */\n\t\tmin-height: 360px;\n\t\toverflow: hidden;\n\n\t\tmain {\n\t\t\twidth: 100%;\n\t\t}\n\t}\n\n\t/* Fix styles on this style guide page */\n\t@media only screen and (max-width: 512px) {\n\t\t:deep(aside) {\n\t\t\twidth: calc(100vw - 64px) !important;\n\t\t}\n\t}\n\n\t.top-bar {\n\t\tdisplay: flex;\n\t\tjustify-content: flex-end;\n\t\t/* preserve space for toggle button */\n\t\tpadding-inline-end: var(--app-sidebar-offset);\n\t\t/* same as on toggle button, but doesn't have to be the same */\n\t\tmargin: var(--app-sidebar-padding);\n\t}\n</style>\n```\n\n### Conditionally show the sidebar programmatically with `v-if`\n\nIf the sidebar should be shown conditionally without any explicit toggle button, you can use `v-if`.\n\n**Note about performance**: using `v-if` might result in bad performance and loosing sidebar content state.\n\n**Note about `v-show`**: using `v-show` to hide sidebar will result in usability issues due to active focus trap on mobile.\n\n```vue\n<template>\n\t<div class=\"content-styleguidist\">\n\t\t<main id=\"content-styleguidist-9\">\n\t\t\t<div class=\"top-bar\">\n\t\t\t\t<NcButton @click.prevent=\"open = !open\">\n\t\t\t\t\tToggle sidebar\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</main>\n\t\t<!-- The sidebar -->\n\t\t<NcAppSidebar\n\t\t\tv-if=\"open\"\n\t\t\tname=\"cat-picture.jpg\"\n\t\t\tsubname=\"last edited 3 weeks ago\"\n\t\t\t@close=\"open = false\">\n\t\t\t<NcAppSidebarTab name=\"Settings\" id=\"settings-tab\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Cog :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\tSingle tab content\n\t\t\t</NcAppSidebarTab>\n\t\t</NcAppSidebar>\n\t</div>\n</template>\n\n<script>\n\timport Cog from 'vue-material-design-icons/Cog'\n\n\texport default {\n\t\tcomponents: {\n\t\t\tCog,\n\t\t},\n\t\tprovide() {\n\t\t\treturn {\n\t\t\t\t'NcContent:selector': '#content-styleguidist-9',\n\t\t\t}\n\t\t},\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\topen: true,\n\t\t\t}\n\t\t},\n\t}\n</script>\n<style scoped>\n\t/* This styles just mock NcContent and NcAppContent */\n\t.content-styleguidist {\n\t\t--app-sidebar-padding: 8px;\n\t\t--app-sidebar-offset: calc(var(--app-sidebar-padding) + var(--default-clickable-area));\n\t\tdisplay: flex;\n\t\tposition: relative !important;\n\t\t/* Just to prevent jumping when the sidebar is hidden */\n\t\tmin-height: 360px;\n\t\toverflow: hidden;\n\n\t\tmain {\n\t\t\twidth: 100%;\n\t\t}\n\t}\n\n\t/* Fix styles on this style guide page */\n\t@media only screen and (max-width: 512px) {\n\t\t:deep(aside) {\n\t\t\twidth: calc(100vw - 64px) !important;\n\t\t}\n\t}\n\n\t.top-bar {\n\t\tdisplay: flex;\n\t\tjustify-content: flex-end;\n\t\t/* preserve space for toggle button */\n\t\tpadding-inline-end: var(--app-sidebar-offset);\n\t\t/* same as on toggle button, but doesn't have to be the same */\n\t\tmargin: var(--app-sidebar-padding);\n\t}\n</style>\n```\n</docs>\n\n<template>\n\t<transition\n\t\tappear\n\t\tname=\"slide-right\"\n\t\t@after-enter=\"onAfterEnter\"\n\t\t@after-leave=\"onAfterLeave\">\n\t\t<aside\n\t\t\tv-show=\"open\"\n\t\t\tid=\"app-sidebar-vue\"\n\t\t\tref=\"sidebar\"\n\t\t\tclass=\"app-sidebar\"\n\t\t\t:aria-labelledby=\"`app-sidebar-vue-${uid}__header`\"\n\t\t\t@keydown.esc=\"onKeydownEsc\">\n\t\t\t<!--\n\t\t\t\tWe cannot render toggle button inside sidebar (aside#app-sidebar-vue), because it is hidden then the toggle is needed.\n\t\t\t\tBut we also need transition with the sidebar to be the root of this component to use it as a single UI element, allowing to use `v-show`.\n\t\t\t\tSo we cannot render the toggle button directly in this component.\n\t\t\t\tAs a simple solution - render it in the content to keep correct position.\n\t\t\t-->\n\t\t\t<Teleport v-if=\"ncContentSelector && !open && !noToggle\" :to=\"ncContentSelector\">\n\t\t\t\t<NcButton\n\t\t\t\t\tref=\"toggle\"\n\t\t\t\t\t:aria-label=\"t('Open sidebar')\"\n\t\t\t\t\tclass=\"app-sidebar__toggle\"\n\t\t\t\t\t:class=\"toggleClasses\"\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\tv-bind=\"toggleAttrs\"\n\t\t\t\t\t@click=\"$emit('update:open', true)\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<!-- @slot Custom icon for the toggle button, defaults to the dock-right icon from MDI -->\n\t\t\t\t\t\t<slot name=\"toggle-icon\">\n\t\t\t\t\t\t\t<IconDockRight :size=\"20\" />\n\t\t\t\t\t\t</slot>\n\t\t\t\t\t</template>\n\t\t\t\t</NcButton>\n\t\t\t</Teleport>\n\n\t\t\t<header\n\t\t\t\tclass=\"app-sidebar-header\"\n\t\t\t\t:class=\"{\n\t\t\t\t\t'app-sidebar-header--with-figure': isSlotPopulated($slots.header?.()) || background,\n\t\t\t\t\t'app-sidebar-header--compact': compact,\n\t\t\t\t}\">\n\t\t\t\t<!-- @slot Alternative to the default header info: use for bare NcAppSidebar with tabs.\n\t\t\t\t\tNcAppSidebarHeader would be required to use for accessibility reasons.\n\t\t\t\t\tThis will be overridden by `empty` prop.\n\t\t\t\t-->\n\t\t\t\t<slot v-if=\"!empty\" name=\"info\">\n\t\t\t\t\t<!-- container for figure and description, allows easy switching to compact mode -->\n\t\t\t\t\t<div class=\"app-sidebar-header__info\">\n\t\t\t\t\t\t<!-- sidebar header illustration/figure -->\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tv-if=\"(isSlotPopulated($slots.header?.()) || background)\"\n\t\t\t\t\t\t\tclass=\"app-sidebar-header__figure\"\n\t\t\t\t\t\t\t:class=\"{\n\t\t\t\t\t\t\t\t'app-sidebar-header__figure--with-action': hasFigureClickListener,\n\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t\t:style=\"{\n\t\t\t\t\t\t\t\tbackgroundImage: `url(${background})`,\n\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t\ttabindex=\"0\"\n\t\t\t\t\t\t\t@click=\"onFigureClick\"\n\t\t\t\t\t\t\t@keydown.enter=\"onFigureClick\">\n\t\t\t\t\t\t\t<slot class=\"app-sidebar-header__background\" name=\"header\" />\n\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t<!-- sidebar details -->\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclass=\"app-sidebar-header__desc\"\n\t\t\t\t\t\t\t:class=\"{\n\t\t\t\t\t\t\t\t'app-sidebar-header__desc--with-tertiary-action': canStar || isSlotPopulated($slots['tertiary-actions']?.()),\n\t\t\t\t\t\t\t\t'app-sidebar-header__desc--editable': nameEditable && !subname,\n\t\t\t\t\t\t\t\t'app-sidebar-header__desc--with-subname--editable': nameEditable && subname,\n\t\t\t\t\t\t\t\t'app-sidebar-header__desc--without-actions': !isSlotPopulated($slots['secondary-actions']?.()),\n\t\t\t\t\t\t\t}\">\n\t\t\t\t\t\t\t<!-- favourite icon -->\n\t\t\t\t\t\t\t<div v-if=\"canStar || isSlotPopulated($slots['tertiary-actions']?.())\" class=\"app-sidebar-header__tertiary-actions\">\n\t\t\t\t\t\t\t\t<slot name=\"tertiary-actions\">\n\t\t\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\t\t\tv-if=\"canStar\"\n\t\t\t\t\t\t\t\t\t\t:aria-label=\"favoriteTranslated\"\n\t\t\t\t\t\t\t\t\t\t:pressed=\"isStarred\"\n\t\t\t\t\t\t\t\t\t\tclass=\"app-sidebar-header__star\"\n\t\t\t\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\t\t\t\t@click.prevent=\"toggleStarred\">\n\t\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t\t<NcLoadingIcon v-if=\"starLoading\" />\n\t\t\t\t\t\t\t\t\t\t\t<IconStar v-else-if=\"isStarred\" :size=\"20\" />\n\t\t\t\t\t\t\t\t\t\t\t<IconStarOutline v-else :size=\"20\" />\n\t\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t\t\t</slot>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<!-- name -->\n\t\t\t\t\t\t\t<div class=\"app-sidebar-header__name-container\">\n\t\t\t\t\t\t\t\t<div class=\"app-sidebar-header__mainname-container\">\n\t\t\t\t\t\t\t\t\t<!-- main name -->\n\t\t\t\t\t\t\t\t\t<NcAppSidebarHeader\n\t\t\t\t\t\t\t\t\t\tv-show=\"!nameEditable\"\n\t\t\t\t\t\t\t\t\t\tclass=\"app-sidebar-header__mainname\"\n\t\t\t\t\t\t\t\t\t\t:name\n\t\t\t\t\t\t\t\t\t\t:linkify=\"linkifyName\"\n\t\t\t\t\t\t\t\t\t\t:title\n\t\t\t\t\t\t\t\t\t\t:tabindex=\"nameEditable ? 0 : -1\"\n\t\t\t\t\t\t\t\t\t\t@click.self=\"editName\" />\n\t\t\t\t\t\t\t\t\t<template v-if=\"nameEditable\">\n\t\t\t\t\t\t\t\t\t\t<form\n\t\t\t\t\t\t\t\t\t\t\tv-click-outside=\"() => onSubmitName()\"\n\t\t\t\t\t\t\t\t\t\t\tclass=\"app-sidebar-header__mainname-form\"\n\t\t\t\t\t\t\t\t\t\t\t@submit.prevent=\"onSubmitName\">\n\t\t\t\t\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t\t\t\t\tref=\"nameInput\"\n\t\t\t\t\t\t\t\t\t\t\t\tv-focus\n\t\t\t\t\t\t\t\t\t\t\t\tclass=\"app-sidebar-header__mainname-input\"\n\t\t\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\t\t\t:placeholder=\"namePlaceholder\"\n\t\t\t\t\t\t\t\t\t\t\t\t:value=\"name\"\n\t\t\t\t\t\t\t\t\t\t\t\t@keydown.esc.stop=\"onDismissEditing\"\n\t\t\t\t\t\t\t\t\t\t\t\t@input=\"onNameInput\">\n\t\t\t\t\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\t\t\t\t\t:aria-label=\"changeNameTranslated\"\n\t\t\t\t\t\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\t\t\t\t\t\tvariant=\"tertiary-no-background\">\n\t\t\t\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<IconArrowRight :size=\"20\" />\n\t\t\t\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t\t\t\t\t</form>\n\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t\t<!-- header main menu -->\n\t\t\t\t\t\t\t\t\t<NcActions\n\t\t\t\t\t\t\t\t\t\tv-if=\"isSlotPopulated($slots['secondary-actions']?.())\"\n\t\t\t\t\t\t\t\t\t\tclass=\"app-sidebar-header__menu\"\n\t\t\t\t\t\t\t\t\t\t:force-menu=\"forceMenu\">\n\t\t\t\t\t\t\t\t\t\t<slot name=\"secondary-actions\" />\n\t\t\t\t\t\t\t\t\t</NcActions>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<!-- secondary name -->\n\t\t\t\t\t\t\t\t<p\n\t\t\t\t\t\t\t\t\tv-if=\"subname.trim() !== '' || $slots['subname']\"\n\t\t\t\t\t\t\t\t\t:title=\"subtitle || undefined\"\n\t\t\t\t\t\t\t\t\tclass=\"app-sidebar-header__subname\">\n\t\t\t\t\t\t\t\t\t<!-- @slot Alternative to the `subname` prop can be used for more complex content. It will be rendered within a `p` tag. -->\n\t\t\t\t\t\t\t\t\t<slot name=\"subname\">\n\t\t\t\t\t\t\t\t\t\t{{ subname }}\n\t\t\t\t\t\t\t\t\t</slot>\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</slot>\n\t\t\t\t<!-- a11y fallback for empty content -->\n\t\t\t\t<NcAppSidebarHeader\n\t\t\t\t\tv-else\n\t\t\t\t\tclass=\"app-sidebar-header__mainname--hidden\"\n\t\t\t\t\t:name\n\t\t\t\t\ttabindex=\"-1\" />\n\n\t\t\t\t<NcButton\n\t\t\t\t\tref=\"closeButton\"\n\t\t\t\t\t:aria-label=\"closeTranslated\"\n\t\t\t\t\t:title=\"closeTranslated\"\n\t\t\t\t\tclass=\"app-sidebar__close\"\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t@click.prevent=\"closeSidebar\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<IconClose :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t</NcButton>\n\n\t\t\t\t<div v-if=\"isSlotPopulated($slots.description?.()) && !empty\" class=\"app-sidebar-header__description\">\n\t\t\t\t\t<slot name=\"description\" />\n\t\t\t\t</div>\n\t\t\t</header>\n\n\t\t\t<NcAppSidebarTabs\n\t\t\t\tv-show=\"!loading\"\n\t\t\t\tref=\"tabs\"\n\t\t\t\t:active=\"active\"\n\t\t\t\t:force-tabs=\"forceTabs\"\n\t\t\t\t@update:active=\"onUpdateActive\">\n\t\t\t\t<slot />\n\t\t\t</NcAppSidebarTabs>\n\n\t\t\t<NcEmptyContent v-if=\"loading\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon :size=\"64\" />\n\t\t\t\t</template>\n\t\t\t</NcEmptyContent>\n\t\t</aside>\n\t</transition>\n</template>\n\n<script>\nimport { vOnClickOutside as ClickOutside } from '@vueuse/components'\nimport { createFocusTrap } from 'focus-trap'\nimport { provide, ref, warn } from 'vue'\nimport IconArrowRight from 'vue-material-design-icons/ArrowRight.vue'\nimport IconClose from 'vue-material-design-icons/Close.vue'\nimport IconDockRight from 'vue-material-design-icons/DockRight.vue'\nimport IconStar from 'vue-material-design-icons/Star.vue'\nimport IconStarOutline from 'vue-material-design-icons/StarOutline.vue'\nimport NcAppSidebarTabs from './NcAppSidebarTabs.vue'\nimport { useIsSmallMobile } from '../../composables/useIsMobile/index.js'\nimport Focus from '../../directives/Focus/index.ts'\nimport { t } from '../../l10n.ts'\nimport { createElementId } from '../../utils/createElementId.ts'\nimport { getTrapStack } from '../../utils/focusTrap.ts'\nimport { isSlotPopulated } from '../../utils/isSlotPopulated.ts'\nimport { logger } from '../../utils/logger.ts'\nimport NcActions from '../NcActions/index.js'\nimport NcAppSidebarHeader from '../NcAppSidebarHeader/index.ts'\nimport NcButton from '../NcButton/index.ts'\nimport { CONTENT_SELECTOR_KEY } from '../NcContent/constants.ts'\nimport NcEmptyContent from '../NcEmptyContent/index.ts'\nimport NcLoadingIcon from '../NcLoadingIcon/index.ts'\n\nexport default {\n\tname: 'NcAppSidebar',\n\n\tcomponents: {\n\t\tNcActions,\n\t\tNcAppSidebarHeader,\n\t\tNcAppSidebarTabs,\n\t\tNcButton,\n\t\tNcLoadingIcon,\n\t\tNcEmptyContent,\n\t\tIconArrowRight,\n\t\tIconClose,\n\t\tIconDockRight,\n\t\tIconStar,\n\t\tIconStarOutline,\n\t},\n\n\tdirectives: {\n\t\tFocus,\n\t\t/** @type {import('vue').ObjectDirective} */\n\t\tClickOutside,\n\t},\n\n\tinject: {\n\t\tncContentSelector: {\n\t\t\tfrom: CONTENT_SELECTOR_KEY,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The active tab\n\t\t */\n\t\tactive: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Main text of the sidebar\n\t\t */\n\t\tname: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * Allow to edit the sidebar name.\n\t\t */\n\t\tnameEditable: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Placeholder in the edit field if the name is editable.\n\t\t */\n\t\tnamePlaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Secondary name of the sidebar (subline)\n\t\t */\n\t\tsubname: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Title to display for the subname.\n\t\t */\n\t\tsubtitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Url to the top header background image\n\t\t * Applied with css\n\t\t */\n\t\tbackground: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Enable the favourite icon if not null\n\t\t * See fired events\n\t\t */\n\t\tstarred: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Show loading spinner instead of the star icon\n\t\t */\n\t\tstarLoading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Show loading spinner instead of tabs\n\t\t */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Display the sidebar in compact mode\n\t\t */\n\t\tcompact: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Only display close button and default slot content.\n\t\t * Don't display other header content and primary and secondary actions.\n\t\t * Useful when showing the EmptyContent component as content.\n\t\t */\n\t\tempty: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Force the actions to display in a three dot menu\n\t\t */\n\t\tforceMenu: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Force the tab navigation to display even if there is only one tab\n\t\t */\n\t\tforceTabs: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Linkify the name\n\t\t */\n\t\tlinkifyName: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Title to display for the name.\n\t\t * Can be set to the same text in case it's too long.\n\t\t */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Allow to conditionally show the sidebar\n\t\t * You can also use `v-if` on the sidebar, but using the open prop allow to keep\n\t\t * the sidebar inside the DOM for performance if it is opened and closed multiple times.\n\t\t *\n\t\t * When using the `open` property to close the sidebar a built-in toggle button will be shown to reopen it,\n\t\t * similar to the app navigation. You can remove this button with the `no-toggle` prop.\n\t\t */\n\t\topen: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Custom classes to assign to the sidebar toggle button.\n\t\t * If needed this can be used to assign styles to the button using `:deep()` selector.\n\t\t */\n\t\ttoggleClasses: {\n\t\t\ttype: [String, Array, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Custom attrs to assign to the sidebar toggle button.\n\t\t */\n\t\ttoggleAttrs: {\n\t\t\ttype: Object,\n\t\t\tdefault: undefined,\n\t\t},\n\n\t\t/**\n\t\t * Do not add the built-in toggle button with `open` prop.\n\t\t */\n\t\tnoToggle: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\temits: [\n\t\t'close',\n\t\t'closed',\n\t\t'opened',\n\t\t// 'figureClick', not emitted on purpose to make \"hasFigureClickListener\" work\n\t\t'update:active',\n\t\t'update:name',\n\t\t'update:nameEditable',\n\t\t'update:open',\n\t\t'update:starred',\n\t\t'submitName',\n\t\t'dismissEditing',\n\t],\n\n\tsetup() {\n\t\tconst headerRef = ref(null)\n\t\tprovide('NcAppSidebar:header:ref', headerRef)\n\n\t\treturn {\n\t\t\tuid: createElementId(),\n\t\t\tisMobile: useIsSmallMobile(),\n\t\t\theaderRef,\n\t\t}\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tchangeNameTranslated: t('Change name'),\n\t\t\tcloseTranslated: t('Close sidebar'),\n\t\t\tfavoriteTranslated: t('Favorite'),\n\t\t\tisStarred: this.starred,\n\t\t\tfocusTrap: null,\n\t\t\telementToReturnFocus: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tcanStar() {\n\t\t\treturn this.isStarred !== null\n\t\t},\n\n\t\thasFigureClickListener() {\n\t\t\treturn !!this.$attrs.onFigureClick\n\t\t},\n\t},\n\n\twatch: {\n\t\tstarred() {\n\t\t\tthis.isStarred = this.starred\n\t\t},\n\n\t\tisMobile() {\n\t\t\tthis.toggleFocusTrap()\n\t\t},\n\n\t\topen() {\n\t\t\tthis.checkToggleButtonContainerAvailability()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.preserveElementToReturnFocus()\n\n\t\tthis.checkToggleButtonContainerAvailability()\n\t},\n\n\tbeforeUnmount() {\n\t\t// Make sure that the 'closed' event is dispatched even if this element is destroyed before the 'after-leave' event is received.\n\t\tthis.$emit('closed')\n\t\tthis.focusTrap?.deactivate()\n\t},\n\n\tmethods: {\n\t\tisSlotPopulated,\n\n\t\tt,\n\n\t\tpreserveElementToReturnFocus() {\n\t\t\t// Save the element that had focus before the sidebar was opened to return back on close\n\t\t\tif (document.activeElement && document.activeElement !== document.body) {\n\t\t\t\tthis.elementToReturnFocus = document.activeElement\n\n\t\t\t\t// Special case for menus (NcActions)\n\t\t\t\t// If a sidebar was opened from a menu item, we want to return focus to the menu trigger instead of the item\n\t\t\t\tif (this.elementToReturnFocus.getAttribute('role') === 'menuitem') {\n\t\t\t\t\tconst menu = this.elementToReturnFocus.closest('[role=\"menu\"]')\n\t\t\t\t\tif (menu) {\n\t\t\t\t\t\tconst menuTrigger = document.querySelector(`[aria-controls=\"${menu.id}\"]`)\n\t\t\t\t\t\tthis.elementToReturnFocus = menuTrigger\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tinitFocusTrap() {\n\t\t\tif (this.focusTrap) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tthis.focusTrap = createFocusTrap([\n\t\t\t\t// The sidebar itself\n\t\t\t\tthis.$refs.sidebar,\n\t\t\t\t// Nextcloud Server header navigation\n\t\t\t\tdocument.querySelector('#header'),\n\t\t\t], {\n\t\t\t\tallowOutsideClick: true,\n\t\t\t\tfallbackFocus: this.$refs.closeButton.$el,\n\t\t\t\ttrapStack: getTrapStack(),\n\t\t\t\tescapeDeactivates: false,\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Activate focus trap if it is currently needed, otherwise deactivate\n\t\t */\n\t\ttoggleFocusTrap() {\n\t\t\tif (this.open && this.isMobile) {\n\t\t\t\tthis.initFocusTrap()\n\t\t\t\tthis.focusTrap.activate()\n\t\t\t} else {\n\t\t\t\tthis.focusTrap?.deactivate()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Close the sidebar on pressing the escape key on mobile\n\t\t *\n\t\t * @param {KeyboardEvent} event key down event\n\t\t */\n\t\tonKeydownEsc(event) {\n\t\t\tif (this.isMobile) {\n\t\t\t\tevent.stopPropagation()\n\t\t\t\tthis.closeSidebar()\n\t\t\t}\n\t\t},\n\n\t\tonAfterEnter(element) {\n\t\t\t// Focus sidebar on open only if it was opened by a user interaction\n\t\t\tif (this.elementToReturnFocus) {\n\t\t\t\tthis.focus()\n\t\t\t}\n\n\t\t\tthis.toggleFocusTrap()\n\n\t\t\t/**\n\t\t\t * The sidebar is opened and the transition is complete\n\t\t\t *\n\t\t\t * @type {HTMLElement}\n\t\t\t */\n\t\t\tthis.$emit('opened', element)\n\t\t},\n\n\t\tonAfterLe