|
| 1 | +<template> |
| 2 | + <button |
| 3 | + class="flex gap-2 px-2 rounded-md bg-transparent hover:bg-gray-200" |
| 4 | + :disabled="!element[lang]" |
| 5 | + :class="{ |
| 6 | + 'selected-toc-config-item': element[lang] === currentSlide, |
| 7 | + 'py-1': !isMobileSidebar, |
| 8 | + 'py-2': isMobileSidebar, |
| 9 | + 'border-2 border-blue-500': isMobileSidebar && element[lang] === currentSlide, |
| 10 | + 'cursor-not-allowed border-2 border-red-400': !element[lang] |
| 11 | + }" |
| 12 | + @click.stop=" |
| 13 | + $emit('select-slide'); |
| 14 | + isMobileSidebar && $emit('close-sidebar'); |
| 15 | + " |
| 16 | + > |
| 17 | + <!-- ::lang:: text --> |
| 18 | + <p class="font-bold italic text-gray-500 select-none" :class="{ 'text-gray-700': isActiveSlide }"> |
| 19 | + {{ lang === 'en' ? 'EN' : 'FR' }} |
| 20 | + </p> |
| 21 | + <!-- Config title --> |
| 22 | + <p |
| 23 | + class="text-left select-none truncate-multiline" |
| 24 | + :class="{ |
| 25 | + italic: !element[lang]?.title |
| 26 | + }" |
| 27 | + v-truncate="{ |
| 28 | + options: { |
| 29 | + delay: '200', |
| 30 | + placement: isMobileSidebar ? 'top' : 'right', |
| 31 | + content: content, |
| 32 | + animateFill: true, |
| 33 | + offset: [0, isMobileSidebar ? 0 : 50], |
| 34 | + touch: ['hold', 500] |
| 35 | + } |
| 36 | + }" |
| 37 | + > |
| 38 | + {{ content }} |
| 39 | + </p> |
| 40 | + <!-- Options for ::lang:: items with missing configs (e.g. one language has config, other doesn't) --> |
| 41 | + <div v-if="!element[lang]" class="ml-auto flex my-auto"> |
| 42 | + <!-- Create a new blank config --> |
| 43 | + <button |
| 44 | + class="slide-toc-button" |
| 45 | + v-tippy="{ |
| 46 | + delay: '200', |
| 47 | + placement: 'top-start', |
| 48 | + content: $t('editor.slides.toc.newBlankConfig'), |
| 49 | + animateFill: false, |
| 50 | + touch: ['hold', 500] |
| 51 | + }" |
| 52 | + @click="$emit('create-config')" |
| 53 | + > |
| 54 | + <svg |
| 55 | + xmlns="http://www.w3.org/2000/svg" |
| 56 | + shape-rendering="geometricPrecision" |
| 57 | + text-rendering="geometricPrecision" |
| 58 | + image-rendering="optimizeQuality" |
| 59 | + fill-rule="evenodd" |
| 60 | + clip-rule="evenodd" |
| 61 | + viewBox="0 0 399 511.66" |
| 62 | + width="14" |
| 63 | + height="14" |
| 64 | + class="mx-1" |
| 65 | + > |
| 66 | + <path |
| 67 | + fill-rule="nonzero" |
| 68 | + d="M71.1 0h190.92c5.22 0 9.85 2.5 12.77 6.38L394.7 136.11c2.81 3.05 4.21 6.92 4.21 10.78l.09 293.67c0 19.47-8.02 37.23-20.9 50.14l-.09.08c-12.9 12.87-30.66 20.88-50.11 20.88H71.1c-19.54 0-37.33-8.01-50.22-20.9C8.01 477.89 0 460.1 0 440.56V71.1c0-19.56 8-37.35 20.87-50.23C33.75 8 51.54 0 71.1 0zm45.78 254.04c-8.81 0-15.96-7.15-15.96-15.95 0-8.81 7.15-15.96 15.96-15.96h165.23c8.81 0 15.96 7.15 15.96 15.96 0 8.8-7.15 15.95-15.96 15.95H116.88zm0 79.38c-8.81 0-15.96-7.15-15.96-15.96 0-8.8 7.15-15.95 15.96-15.95h156.47c8.81 0 15.96 7.15 15.96 15.95 0 8.81-7.15 15.96-15.96 15.96H116.88zm0 79.39c-8.81 0-15.96-7.15-15.96-15.96s7.15-15.95 15.96-15.95h132.7c8.81 0 15.95 7.14 15.95 15.95 0 8.81-7.14 15.96-15.95 15.96h-132.7zm154.2-363.67v54.21c1.07 13.59 5.77 24.22 13.99 31.24 8.63 7.37 21.65 11.52 38.95 11.83l36.93-.05-89.87-97.23zm96.01 129.11-43.31-.05c-25.2-.4-45.08-7.2-59.39-19.43-14.91-12.76-23.34-30.81-25.07-53.11l-.15-2.22V31.91H71.1c-10.77 0-20.58 4.42-27.68 11.51-7.09 7.1-11.51 16.91-11.51 27.68v369.46c0 10.76 4.43 20.56 11.52 27.65 7.11 7.12 16.92 11.53 27.67 11.53h256.8c10.78 0 20.58-4.4 27.65-11.48 7.13-7.12 11.54-16.93 11.54-27.7V178.25z" |
| 69 | + /> |
| 70 | + </svg> |
| 71 | + </button> |
| 72 | + <!-- Button: Copy the ::oppositeLang:: config in the same slide, if it exists --> |
| 73 | + <!-- Only available if the slide's ::lang:: config is undefined --> |
| 74 | + <button |
| 75 | + v-if="element[oppositeLang]" |
| 76 | + class="slide-toc-button" |
| 77 | + v-tippy="{ |
| 78 | + delay: '200', |
| 79 | + placement: 'top-start', |
| 80 | + content: |
| 81 | + lang === 'en' |
| 82 | + ? $t('editor.slides.toc.newConfigFromFR') |
| 83 | + : $t('editor.slides.toc.newConfigFromEng'), |
| 84 | + animateFill: false, |
| 85 | + touch: ['hold', 500] |
| 86 | + }" |
| 87 | + @click="$emit('copy-config')" |
| 88 | + > |
| 89 | + <svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 24 24" class="mx-1"> |
| 90 | + <path |
| 91 | + d="M5 22q-.825 0-1.413-.587Q3 20.825 3 20V6h2v14h11v2Zm4-4q-.825 0-1.412-.587Q7 16.825 7 16V4q0-.825.588-1.413Q8.175 2 9 2h9q.825 0 1.413.587Q20 3.175 20 4v12q0 .825-.587 1.413Q18.825 18 18 18Zm0-2h9V4H9v12Zm0 0V4v12Z" |
| 92 | + /> |
| 93 | + </svg> |
| 94 | + </button> |
| 95 | + </div> |
| 96 | + <div v-else class="ml-auto flex my-auto"> |
| 97 | + <!-- ::lang:: options dropdown menu --> |
| 98 | + <toc-options :copy-allowed="!!element[oppositeLang]" @copy="$emit('copy')" @clear="$emit('clear')" /> |
| 99 | + </div> |
| 100 | + </button> |
| 101 | +</template> |
| 102 | + |
| 103 | +<script lang="ts"> |
| 104 | +import { Slide } from '@/definitions'; |
| 105 | +import { Options, Prop, Vue } from 'vue-property-decorator'; |
| 106 | +import TocOptions from '@/components/helpers/toc-options.vue'; |
| 107 | +
|
| 108 | +@Options({ |
| 109 | + components: { |
| 110 | + TocOptions |
| 111 | + } |
| 112 | +}) |
| 113 | +export default class SlideTocV extends Vue { |
| 114 | + @Prop() lang!: string; |
| 115 | + @Prop() element: Slide; |
| 116 | + @Prop() currentSlide!: Slide | string; |
| 117 | + @Prop({ default: false }) isMobileSidebar!: boolean; |
| 118 | + @Prop() isActiveSlide: boolean; |
| 119 | +
|
| 120 | + oppositeLang = ''; |
| 121 | + content = ''; |
| 122 | +
|
| 123 | + updateContent(): void { |
| 124 | + if (this.element[this.lang]?.title) { |
| 125 | + this.content = this.element[this.lang]?.title; |
| 126 | + } else if (this.element[this.lang]?.title === '') { |
| 127 | + this.content = |
| 128 | + this.lang === 'en' |
| 129 | + ? this.$t('editor.slides.toc.newENGSlideText') |
| 130 | + : this.$t('editor.slides.toc.newFRSlideText'); |
| 131 | + } else { |
| 132 | + this.content = |
| 133 | + this.lang === 'en' ? this.$t('editor.slide.toc.noENGslide') : this.$t('editor.slide.toc.noFRSlide'); |
| 134 | + } |
| 135 | + } |
| 136 | +
|
| 137 | + mounted(): void { |
| 138 | + this.oppositeLang = this.lang === 'en' ? 'fr' : 'en'; |
| 139 | + this.updateContent(); |
| 140 | + } |
| 141 | +
|
| 142 | + updated(): void { |
| 143 | + this.updateContent(); |
| 144 | + } |
| 145 | +} |
| 146 | +</script> |
| 147 | + |
| 148 | +<style lang="scss" scoped> |
| 149 | +.truncate-multiline { |
| 150 | + overflow: hidden; |
| 151 | + text-overflow: ellipsis; |
| 152 | + display: -webkit-box; |
| 153 | + -webkit-box-orient: vertical; |
| 154 | + -webkit-line-clamp: 2; |
| 155 | +} |
| 156 | +
|
| 157 | +.slide-toc-button { |
| 158 | + border-radius: 3px; |
| 159 | + padding: 2px; |
| 160 | +} |
| 161 | +.slide-toc-button:hover { |
| 162 | + background-color: rgb(209, 213, 219); |
| 163 | +} |
| 164 | +</style> |
0 commit comments