logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe git clone https://anongit.hacktivis.me/git/pleroma-fe.git/

tab_switcher.jsx (4937B)


  1. // eslint-disable-next-line no-unused
  2. import { h, Fragment } from 'vue'
  3. import { mapState } from 'pinia'
  4. import { FontAwesomeIcon as FAIcon } from '@fortawesome/vue-fontawesome'
  5. import './tab_switcher.scss'
  6. import { useInterfaceStore } from 'src/stores/interface'
  7. const findFirstUsable = (slots) => slots.findIndex(_ => _.props)
  8. export default {
  9. name: 'TabSwitcher',
  10. props: {
  11. renderOnlyFocused: {
  12. required: false,
  13. type: Boolean,
  14. default: false
  15. },
  16. onSwitch: {
  17. required: false,
  18. type: Function,
  19. default: undefined
  20. },
  21. activeTab: {
  22. required: false,
  23. type: String,
  24. default: undefined
  25. },
  26. scrollableTabs: {
  27. required: false,
  28. type: Boolean,
  29. default: false
  30. },
  31. sideTabBar: {
  32. required: false,
  33. type: Boolean,
  34. default: false
  35. },
  36. bodyScrollLock: {
  37. required: false,
  38. type: Boolean,
  39. default: false
  40. }
  41. },
  42. data () {
  43. return {
  44. active: findFirstUsable(this.slots())
  45. }
  46. },
  47. computed: {
  48. activeIndex () {
  49. // In case of controlled component
  50. if (this.activeTab) {
  51. return this.slots().findIndex(slot => slot && slot.props && this.activeTab === slot.props.key)
  52. } else {
  53. return this.active
  54. }
  55. },
  56. isActive () {
  57. return tabName => {
  58. const isWanted = slot => slot.props && slot.props['data-tab-name'] === tabName
  59. return this.$slots.default().findIndex(isWanted) === this.activeIndex
  60. }
  61. }
  62. },
  63. beforeUpdate () {
  64. const currentSlot = this.slots()[this.active]
  65. if (!currentSlot.props) {
  66. this.active = findFirstUsable(this.slots())
  67. }
  68. },
  69. methods: {
  70. clickTab (index) {
  71. return (e) => {
  72. e.preventDefault()
  73. this.setTab(index)
  74. }
  75. },
  76. // DO NOT put it to computed, it doesn't work (caching?)
  77. slots () {
  78. if (this.$slots.default()[0].type === Fragment) {
  79. return this.$slots.default()[0].children
  80. }
  81. return this.$slots.default()
  82. },
  83. setTab (index) {
  84. if (typeof this.onSwitch === 'function') {
  85. this.onSwitch.call(null, this.slots()[index].key)
  86. }
  87. this.active = index
  88. if (this.scrollableTabs) {
  89. this.$refs.contents.scrollTop = 0
  90. }
  91. }
  92. },
  93. render () {
  94. const tabs = this.slots()
  95. .map((slot, index) => {
  96. const props = slot.props
  97. if (!props) return
  98. const classesTab = ['tab']
  99. const classesWrapper = ['tab-wrapper']
  100. if (this.activeIndex === index) {
  101. classesTab.push('active')
  102. classesWrapper.push('active')
  103. }
  104. if (props.image) {
  105. return (
  106. <div class={classesWrapper.join(' ')}>
  107. <button
  108. disabled={props.disabled}
  109. onClick={this.clickTab(index)}
  110. class={classesTab.join(' ')}
  111. type="button"
  112. role="tab"
  113. >
  114. <img src={props.image} title={props['image-tooltip']}/>
  115. {props.label ? '' : props.label}
  116. </button>
  117. </div>
  118. )
  119. }
  120. return (
  121. <div class={classesWrapper.join(' ')}>
  122. <button
  123. disabled={props.disabled}
  124. onClick={this.clickTab(index)}
  125. class={classesTab.join(' ')}
  126. type="button"
  127. role="tab"
  128. >
  129. {!props.icon ? '' : (<FAIcon class="tab-icon" size="2x" fixed-width icon={props.icon}/>)}
  130. <span class="text">
  131. {props.label}
  132. </span>
  133. </button>
  134. </div>
  135. )
  136. })
  137. const contents = this.slots().map((slot, index) => {
  138. const props = slot.props
  139. if (!props) return
  140. const active = this.activeIndex === index
  141. const classes = [ active ? 'active' : 'hidden' ]
  142. if (props.fullHeight) {
  143. classes.push('full-height')
  144. }
  145. let delayRender = slot.props['delay-render']
  146. if (delayRender && active) {
  147. slot.props['delay-render'] = false
  148. delayRender = false
  149. }
  150. const renderSlot = (!delayRender && (!this.renderOnlyFocused || active))
  151. ? slot
  152. : ''
  153. return (
  154. <div class={classes}>
  155. {
  156. this.sideTabBar
  157. ? <h1 class="mobile-label">{props.label}</h1>
  158. : ''
  159. }
  160. {renderSlot}
  161. </div>
  162. )
  163. })
  164. return (
  165. <div class={'tab-switcher ' + (this.sideTabBar ? 'side-tabs' : 'top-tabs')}>
  166. <div
  167. class="tabs"
  168. role="tablist"
  169. >
  170. {tabs}
  171. </div>
  172. <div
  173. ref="contents"
  174. role="tabpanel"
  175. class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')}
  176. v-body-scroll-lock={this.bodyScrollLock}
  177. >
  178. {contents}
  179. </div>
  180. </div>
  181. )
  182. }
  183. }