From 433ea02a18c0328b8079a40657220633c09e363a Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 18 Apr 2021 14:58:02 +0300
Subject: Changed some of TabSwitcher's internals for easier Vue3 migration

---
 src/components/tab_switcher/tab_switcher.jsx | 171 +++++++++++++++++++++++++++
 1 file changed, 171 insertions(+)
 create mode 100644 src/components/tab_switcher/tab_switcher.jsx

(limited to 'src/components/tab_switcher/tab_switcher.jsx')

diff --git a/src/components/tab_switcher/tab_switcher.jsx b/src/components/tab_switcher/tab_switcher.jsx
new file mode 100644
index 00000000..68eee122
--- /dev/null
+++ b/src/components/tab_switcher/tab_switcher.jsx
@@ -0,0 +1,171 @@
+import { mapState } from 'vuex'
+import { FontAwesomeIcon as FAIcon } from '@fortawesome/vue-fontawesome'
+
+import './tab_switcher.scss'
+
+// TODO VUE3: change data to props
+const findFirstUsable = (slots) => slots.findIndex(_ => _.data && _.data.attrs)
+
+export default {
+  name: 'TabSwitcher',
+  props: {
+    renderOnlyFocused: {
+      required: false,
+      type: Boolean,
+      default: false
+    },
+    onSwitch: {
+      required: false,
+      type: Function,
+      default: undefined
+    },
+    activeTab: {
+      required: false,
+      type: String,
+      default: undefined
+    },
+    scrollableTabs: {
+      required: false,
+      type: Boolean,
+      default: false
+    },
+    sideTabBar: {
+      required: false,
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    console.log(this.$slots.default)
+    return {
+      // TODO VUE3: add () after 'default'
+      active: findFirstUsable(this.$slots.default)
+    }
+  },
+  computed: {
+    slots () {
+      // TODO VUE3: add () at the end
+      return this.$slots.default
+    },
+    activeIndex () {
+      // In case of controlled component
+      if (this.activeTab) {
+        return this.$slots.default.findIndex(slot => this.activeTab === slot.key)
+      } else {
+        return this.active
+      }
+    },
+    settingsModalVisible () {
+      return this.settingsModalState === 'visible'
+    },
+    ...mapState({
+      settingsModalState: state => state.interface.settingsModalState
+    })
+  },
+  beforeUpdate () {
+    console.log(this.slots, this.active)
+    const currentSlot = this.slots[this.active]
+    // TODO VUE3: change data to props
+    if (!currentSlot.data) {
+      this.active = findFirstUsable(this.slots)
+    }
+  },
+  methods: {
+    clickTab (index) {
+      return (e) => {
+        e.preventDefault()
+        this.setTab(index)
+      }
+    },
+    setTab (index) {
+      if (typeof this.onSwitch === 'function') {
+        this.onSwitch.call(null, this.slots[index].key)
+      }
+      this.active = index
+      if (this.scrollableTabs) {
+        this.$refs.contents.scrollTop = 0
+      }
+    }
+  },
+  // TODO VUE3: remove 'h' here
+  render (h) {
+    const tabs = this.slots
+      .map((slot, index) => {
+        // TODO VUE3 change to slot.props
+        const props = slot.data && slot.data.attrs
+        if (!props) return
+        const classesTab = ['tab', 'button-default']
+        const classesWrapper = ['tab-wrapper']
+        if (this.activeIndex === index) {
+          classesTab.push('active')
+          classesWrapper.push('active')
+        }
+        if (props.image) {
+          return (
+            <div class={classesWrapper.join(' ')}>
+              <button
+                disabled={props.disabled}
+                onClick={this.clickTab(index)}
+                class={classesTab.join(' ')}
+                type="button"
+              >
+                <img src={props.image} title={props['image-tooltip']}/>
+                {props.label ? '' : props.label}
+              </button>
+            </div>
+          )
+        }
+        return (
+          <div class={classesWrapper.join(' ')}>
+            <button
+              disabled={props.disabled}
+              onClick={this.clickTab(index)}
+              class={classesTab.join(' ')}
+              type="button"
+            >
+              {!props.icon ? '' : (<FAIcon class="tab-icon" size="2x" fixed-width icon={props.icon}/>)}
+              <span class="text">
+                {props.label}
+              </span>
+            </button>
+          </div>
+        )
+      })
+
+    const contents = this.slots.map((slot, index) => {
+      // TODO VUE3 change to slot.props
+      const props = slot.data && slot.data.attrs
+      if (!props) return
+      const active = this.activeIndex === index
+      const classes = [ active ? 'active' : 'hidden' ]
+      if (props.fullHeight) {
+        classes.push('full-height')
+      }
+      const renderSlot = (!this.renderOnlyFocused || active)
+        ? slot
+        : ''
+
+      return (
+        <div class={classes}>
+          {
+            this.sideTabBar
+              ? <h1 class="mobile-label">{props.label}</h1>
+              : ''
+          }
+          {renderSlot}
+        </div>
+      )
+    })
+
+    return (
+      <div class={'tab-switcher ' + (this.sideTabBar ? 'side-tabs' : 'top-tabs')}>
+        <div class="tabs">
+          {tabs}
+        </div>
+        <div ref="contents" class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')} v-body-scroll-lock={this.settingsModalVisible}>
+          {contents}
+        </div>
+      </div>
+    )
+  }
+}
-- 
cgit v1.2.3-70-g09d2


From b0789fd6fd280a3dc8cefb4cb2410abec4be9ae6 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 18 Apr 2021 15:03:28 +0300
Subject: fix theme tab, remove console.logs

---
 src/components/tab_switcher/tab_switcher.jsx | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

(limited to 'src/components/tab_switcher/tab_switcher.jsx')

diff --git a/src/components/tab_switcher/tab_switcher.jsx b/src/components/tab_switcher/tab_switcher.jsx
index 68eee122..44221d50 100644
--- a/src/components/tab_switcher/tab_switcher.jsx
+++ b/src/components/tab_switcher/tab_switcher.jsx
@@ -36,17 +36,12 @@ export default {
     }
   },
   data () {
-    console.log(this.$slots.default)
     return {
       // TODO VUE3: add () after 'default'
       active: findFirstUsable(this.$slots.default)
     }
   },
   computed: {
-    slots () {
-      // TODO VUE3: add () at the end
-      return this.$slots.default
-    },
     activeIndex () {
       // In case of controlled component
       if (this.activeTab) {
@@ -63,11 +58,10 @@ export default {
     })
   },
   beforeUpdate () {
-    console.log(this.slots, this.active)
-    const currentSlot = this.slots[this.active]
+    const currentSlot = this.slots()[this.active]
     // TODO VUE3: change data to props
     if (!currentSlot.data) {
-      this.active = findFirstUsable(this.slots)
+      this.active = findFirstUsable(this.slots())
     }
   },
   methods: {
@@ -77,9 +71,14 @@ export default {
         this.setTab(index)
       }
     },
+    // DO NOT put it to computed, it doesn't work (caching?)
+    slots () {
+      // TODO VUE3: add () at the end
+      return this.$slots.default
+    },
     setTab (index) {
       if (typeof this.onSwitch === 'function') {
-        this.onSwitch.call(null, this.slots[index].key)
+        this.onSwitch.call(null, this.slots()[index].key)
       }
       this.active = index
       if (this.scrollableTabs) {
@@ -89,7 +88,7 @@ export default {
   },
   // TODO VUE3: remove 'h' here
   render (h) {
-    const tabs = this.slots
+    const tabs = this.slots()
       .map((slot, index) => {
         // TODO VUE3 change to slot.props
         const props = slot.data && slot.data.attrs
@@ -132,7 +131,7 @@ export default {
         )
       })
 
-    const contents = this.slots.map((slot, index) => {
+    const contents = this.slots().map((slot, index) => {
       // TODO VUE3 change to slot.props
       const props = slot.data && slot.data.attrs
       if (!props) return
-- 
cgit v1.2.3-70-g09d2


From 33777fab47b65975d343d219c0b1866ba6849b3f Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 18 Apr 2021 15:39:06 +0300
Subject: small refactoring to uncouple tab-switcher from settings modal

---
 src/components/settings_modal/settings_modal_content.js  |  3 +++
 src/components/settings_modal/settings_modal_content.vue |  1 +
 src/components/tab_switcher/tab_switcher.jsx             | 14 ++++++++++----
 3 files changed, 14 insertions(+), 4 deletions(-)

(limited to 'src/components/tab_switcher/tab_switcher.jsx')

diff --git a/src/components/settings_modal/settings_modal_content.js b/src/components/settings_modal/settings_modal_content.js
index 7e366580..deb77298 100644
--- a/src/components/settings_modal/settings_modal_content.js
+++ b/src/components/settings_modal/settings_modal_content.js
@@ -53,6 +53,9 @@ const SettingsModalContent = {
     },
     open () {
       return this.$store.state.interface.settingsModalState !== 'hidden'
+    },
+    bodyLock () {
+      return this.$store.state.interface.settingsModalState === 'visible'
     }
   },
   methods: {
diff --git a/src/components/settings_modal/settings_modal_content.vue b/src/components/settings_modal/settings_modal_content.vue
index c9ed2a38..0be76d22 100644
--- a/src/components/settings_modal/settings_modal_content.vue
+++ b/src/components/settings_modal/settings_modal_content.vue
@@ -4,6 +4,7 @@
     class="settings_tab-switcher"
     :side-tab-bar="true"
     :scrollable-tabs="true"
+    :body-scroll-lock="bodyLock"
   >
     <div
       :label="$t('settings.general')"
diff --git a/src/components/tab_switcher/tab_switcher.jsx b/src/components/tab_switcher/tab_switcher.jsx
index 44221d50..2869e59c 100644
--- a/src/components/tab_switcher/tab_switcher.jsx
+++ b/src/components/tab_switcher/tab_switcher.jsx
@@ -33,6 +33,11 @@ export default {
       required: false,
       type: Boolean,
       default: false
+    },
+    bodyScrollLock: {
+      required: false,
+      type: Boolean,
+      default: false
     }
   },
   data () {
@@ -50,9 +55,6 @@ export default {
         return this.active
       }
     },
-    settingsModalVisible () {
-      return this.settingsModalState === 'visible'
-    },
     ...mapState({
       settingsModalState: state => state.interface.settingsModalState
     })
@@ -161,7 +163,11 @@ export default {
         <div class="tabs">
           {tabs}
         </div>
-        <div ref="contents" class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')} v-body-scroll-lock={this.settingsModalVisible}>
+        <div
+          ref="contents"
+          class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')}
+          v-body-scroll-lock={this.bodyScrollLock}
+        >
           {contents}
         </div>
       </div>
-- 
cgit v1.2.3-70-g09d2


From fca885e665094b8efcbc65a3f4ec9ba31679c4c2 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 25 Apr 2021 13:23:16 +0300
Subject: resolve TODO VUE3

---
 src/components/color_input/color_input.vue         | 20 ++++++++---------
 src/components/emoji_input/emoji_input.js          | 23 ++++++++++----------
 src/components/font_control/font_control.vue       |  2 +-
 src/components/opacity_input/opacity_input.vue     |  4 ++--
 src/components/range_input/range_input.vue         |  6 +++---
 .../settings_modal/settings_modal_content.js       |  2 +-
 src/components/status_popover/status_popover.js    |  5 +++--
 src/components/tab_switcher/tab_switcher.jsx       | 25 +++++++++-------------
 8 files changed, 41 insertions(+), 46 deletions(-)

(limited to 'src/components/tab_switcher/tab_switcher.jsx')

diff --git a/src/components/color_input/color_input.vue b/src/components/color_input/color_input.vue
index 8fb16113..81462979 100644
--- a/src/components/color_input/color_input.vue
+++ b/src/components/color_input/color_input.vue
@@ -14,25 +14,25 @@
       :checked="present"
       :disabled="disabled"
       class="opt"
-      @change="$emit('input', typeof value === 'undefined' ? fallback : undefined)"
+      @change="$emit('update:modelValue', typeof value === 'undefined' ? fallback : undefined)"
     />
     <div class="input color-input-field">
       <input
         :id="name + '-t'"
         class="textColor unstyled"
         type="text"
-        :value="value || fallback"
+        :value="modelValue || fallback"
         :disabled="!present || disabled"
-        @input="$emit('input', $event.target.value)"
+        @input="$emit('update:modelValue', $event.target.value)"
       >
       <input
         v-if="validColor"
         :id="name"
         class="nativeColor unstyled"
         type="color"
-        :value="value || fallback"
+        :value="modelValue || fallback"
         :disabled="!present || disabled"
-        @input="$emit('input', $event.target.value)"
+        @input="$emit('update:modelValue', $event.target.value)"
       >
       <div
         v-if="transparentColor"
@@ -67,7 +67,7 @@ export default {
     },
     // Color value, should be required but vue cannot tell the difference
     // between "property missing" and "property set to undefined"
-    value: {
+    modelValue: {
       required: false,
       type: String,
       default: undefined
@@ -93,16 +93,16 @@ export default {
   },
   computed: {
     present () {
-      return typeof this.value !== 'undefined'
+      return typeof this.modelValue !== 'undefined'
     },
     validColor () {
-      return hex2rgb(this.value || this.fallback)
+      return hex2rgb(this.modelValue || this.fallback)
     },
     transparentColor () {
-      return this.value === 'transparent'
+      return this.modelValue === 'transparent'
     },
     computedColor () {
-      return this.value && this.value.startsWith('--')
+      return this.modelValue && this.modelValue.startsWith('--')
     }
   }
 }
diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js
index c4d235c0..389b6787 100644
--- a/src/components/emoji_input/emoji_input.js
+++ b/src/components/emoji_input/emoji_input.js
@@ -57,8 +57,7 @@ const EmojiInput = {
       required: true,
       type: Function
     },
-    // TODO VUE3: change to modelValue, change 'input' event to 'input'
-    value: {
+    modelValue: {
       /**
        * Used for v-model
        */
@@ -137,8 +136,8 @@ const EmojiInput = {
       return (this.wordAtCaret || {}).word || ''
     },
     wordAtCaret () {
-      if (this.value && this.caret) {
-        const word = Completion.wordAtPosition(this.value, this.caret - 1) || {}
+      if (this.modelValue && this.caret) {
+        const word = Completion.wordAtPosition(this.modelValue, this.caret - 1) || {}
         return word
       }
     }
@@ -225,13 +224,13 @@ const EmojiInput = {
       }
     },
     replace (replacement) {
-      const newValue = Completion.replaceWord(this.value, this.wordAtCaret, replacement)
-      this.$emit('input', newValue)
+      const newValue = Completion.replaceWord(this.modelValue, this.wordAtCaret, replacement)
+      this.$emit('update:modelValue', newValue)
       this.caret = 0
     },
     insert ({ insertion, keepOpen, surroundingSpace = true }) {
-      const before = this.value.substring(0, this.caret) || ''
-      const after = this.value.substring(this.caret) || ''
+      const before = this.modelValue.substring(0, this.caret) || ''
+      const after = this.modelValue.substring(this.caret) || ''
 
       /* Using a bit more smart approach to padding emojis with spaces:
        * - put a space before cursor if there isn't one already, unless we
@@ -259,7 +258,7 @@ const EmojiInput = {
         after
       ].join('')
       this.keepOpen = keepOpen
-      this.$emit('input', newValue)
+      this.$emit('update:modelValue', newValue)
       const position = this.caret + (insertion + spaceAfter + spaceBefore).length
       if (!keepOpen) {
         this.input.focus()
@@ -278,8 +277,8 @@ const EmojiInput = {
       if (len > 0 || suggestion) {
         const chosenSuggestion = suggestion || this.suggestions[this.highlighted]
         const replacement = chosenSuggestion.replacement
-        const newValue = Completion.replaceWord(this.value, this.wordAtCaret, replacement)
-        this.$emit('input', newValue)
+        const newValue = Completion.replaceWord(this.modelValue, this.wordAtCaret, replacement)
+        this.$emit('update:modelValue', newValue)
         this.highlighted = 0
         const position = this.wordAtCaret.start + replacement.length
 
@@ -455,7 +454,7 @@ const EmojiInput = {
       this.showPicker = false
       this.setCaret(e)
       this.resize()
-      this.$emit('input', e.target.value)
+      this.$emit('update:modelValue', e.target.value)
     },
     onClickInput (e) {
       this.showPicker = false
diff --git a/src/components/font_control/font_control.vue b/src/components/font_control/font_control.vue
index dd117ec0..0cee2edc 100644
--- a/src/components/font_control/font_control.vue
+++ b/src/components/font_control/font_control.vue
@@ -15,7 +15,7 @@
       class="opt exlcude-disabled"
       type="checkbox"
       :checked="present"
-      @input="$emit('input', typeof value === 'undefined' ? fallback : undefined)"
+      @input="$emit('update:modelValue', typeof value === 'undefined' ? fallback : undefined)"
     >
     <label
       v-if="typeof fallback !== 'undefined'"
diff --git a/src/components/opacity_input/opacity_input.vue b/src/components/opacity_input/opacity_input.vue
index 3cc3942b..e1d31fc2 100644
--- a/src/components/opacity_input/opacity_input.vue
+++ b/src/components/opacity_input/opacity_input.vue
@@ -14,7 +14,7 @@
       :checked="present"
       :disabled="disabled"
       class="opt"
-      @change="$emit('input', !present ? fallback : undefined)"
+      @change="$emit('update:modelValue', !present ? fallback : undefined)"
     />
     <input
       :id="name"
@@ -25,7 +25,7 @@
       max="1"
       min="0"
       step=".05"
-      @input="$emit('input', $event.target.value)"
+      @input="$emit('update:modelValue', $event.target.value)"
     >
   </div>
 </template>
diff --git a/src/components/range_input/range_input.vue b/src/components/range_input/range_input.vue
index 5857a5c1..82681809 100644
--- a/src/components/range_input/range_input.vue
+++ b/src/components/range_input/range_input.vue
@@ -15,7 +15,7 @@
       class="opt"
       type="checkbox"
       :checked="present"
-      @input="$emit('input', !present ? fallback : undefined)"
+      @input="$emit('update:modelValue', !present ? fallback : undefined)"
     >
     <label
       v-if="typeof fallback !== 'undefined'"
@@ -31,7 +31,7 @@
       :max="max || hardMax || 100"
       :min="min || hardMin || 0"
       :step="step || 1"
-      @input="$emit('input', $event.target.value)"
+      @input="$emit('update:modelValue', $event.target.value)"
     >
     <input
       :id="name"
@@ -42,7 +42,7 @@
       :max="hardMax"
       :min="hardMin"
       :step="step || 1"
-      @input="$emit('input', $event.target.value)"
+      @input="$emit('update:modelValue', $event.target.value)"
     >
   </div>
 </template>
diff --git a/src/components/settings_modal/settings_modal_content.js b/src/components/settings_modal/settings_modal_content.js
index deb77298..506b52e4 100644
--- a/src/components/settings_modal/settings_modal_content.js
+++ b/src/components/settings_modal/settings_modal_content.js
@@ -63,7 +63,7 @@ const SettingsModalContent = {
       const targetTab = this.$store.state.interface.settingsModalTargetTab
       // We're being told to open in specific tab
       if (targetTab) {
-        const tabIndex = this.$refs.tabSwitcher.$slots.default.findIndex(elm => {
+        const tabIndex = this.$refs.tabSwitcher.$slots.default().findIndex(elm => {
           return elm.data && elm.data.attrs['data-tab-name'] === targetTab
         })
         if (tabIndex >= 0) {
diff --git a/src/components/status_popover/status_popover.js b/src/components/status_popover/status_popover.js
index c47f5631..e0962ccd 100644
--- a/src/components/status_popover/status_popover.js
+++ b/src/components/status_popover/status_popover.js
@@ -1,6 +1,7 @@
 import { find } from 'lodash'
 import { library } from '@fortawesome/fontawesome-svg-core'
 import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
+import { defineAsyncComponent } from 'vue'
 
 library.add(
   faCircleNotch
@@ -22,8 +23,8 @@ const StatusPopover = {
     }
   },
   components: {
-    Status: () => import('../status/status.vue'),
-    Popover: () => import('../popover/popover.vue')
+    Status: defineAsyncComponent(() => import('../status/status.vue')),
+    Popover: defineAsyncComponent(() => import('../popover/popover.vue'))
   },
   methods: {
     enter () {
diff --git a/src/components/tab_switcher/tab_switcher.jsx b/src/components/tab_switcher/tab_switcher.jsx
index 2869e59c..db82e075 100644
--- a/src/components/tab_switcher/tab_switcher.jsx
+++ b/src/components/tab_switcher/tab_switcher.jsx
@@ -1,10 +1,11 @@
+// eslint-disable-next-line no-unused
+import { h } from 'vue'
 import { mapState } from 'vuex'
 import { FontAwesomeIcon as FAIcon } from '@fortawesome/vue-fontawesome'
 
 import './tab_switcher.scss'
 
-// TODO VUE3: change data to props
-const findFirstUsable = (slots) => slots.findIndex(_ => _.data && _.data.attrs)
+const findFirstUsable = (slots) => slots.findIndex(_ => _.props)
 
 export default {
   name: 'TabSwitcher',
@@ -42,15 +43,14 @@ export default {
   },
   data () {
     return {
-      // TODO VUE3: add () after 'default'
-      active: findFirstUsable(this.$slots.default)
+      active: findFirstUsable(this.$slots.default())
     }
   },
   computed: {
     activeIndex () {
       // In case of controlled component
       if (this.activeTab) {
-        return this.$slots.default.findIndex(slot => this.activeTab === slot.key)
+        return this.$slots.default().findIndex(slot => this.activeTab === slot.key)
       } else {
         return this.active
       }
@@ -61,8 +61,7 @@ export default {
   },
   beforeUpdate () {
     const currentSlot = this.slots()[this.active]
-    // TODO VUE3: change data to props
-    if (!currentSlot.data) {
+    if (!currentSlot.props) {
       this.active = findFirstUsable(this.slots())
     }
   },
@@ -75,8 +74,7 @@ export default {
     },
     // DO NOT put it to computed, it doesn't work (caching?)
     slots () {
-      // TODO VUE3: add () at the end
-      return this.$slots.default
+      return this.$slots.default()
     },
     setTab (index) {
       if (typeof this.onSwitch === 'function') {
@@ -88,12 +86,10 @@ export default {
       }
     }
   },
-  // TODO VUE3: remove 'h' here
-  render (h) {
+  render () {
     const tabs = this.slots()
       .map((slot, index) => {
-        // TODO VUE3 change to slot.props
-        const props = slot.data && slot.data.attrs
+        const props = slot.props
         if (!props) return
         const classesTab = ['tab', 'button-default']
         const classesWrapper = ['tab-wrapper']
@@ -134,8 +130,7 @@ export default {
       })
 
     const contents = this.slots().map((slot, index) => {
-      // TODO VUE3 change to slot.props
-      const props = slot.data && slot.data.attrs
+      const props = slot.props
       if (!props) return
       const active = this.activeIndex === index
       const classes = [ active ? 'active' : 'hidden' ]
-- 
cgit v1.2.3-70-g09d2


From 0671aa0dd0cd199dc6206ae8b3fb0de114acddfe Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Thu, 17 Mar 2022 08:47:11 +0200
Subject: fix tabswitcher

---
 src/components/settings_modal/settings_modal_content.js | 2 +-
 src/components/tab_switcher/tab_switcher.jsx            | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

(limited to 'src/components/tab_switcher/tab_switcher.jsx')

diff --git a/src/components/settings_modal/settings_modal_content.js b/src/components/settings_modal/settings_modal_content.js
index 506b52e4..deb77298 100644
--- a/src/components/settings_modal/settings_modal_content.js
+++ b/src/components/settings_modal/settings_modal_content.js
@@ -63,7 +63,7 @@ const SettingsModalContent = {
       const targetTab = this.$store.state.interface.settingsModalTargetTab
       // We're being told to open in specific tab
       if (targetTab) {
-        const tabIndex = this.$refs.tabSwitcher.$slots.default().findIndex(elm => {
+        const tabIndex = this.$refs.tabSwitcher.$slots.default.findIndex(elm => {
           return elm.data && elm.data.attrs['data-tab-name'] === targetTab
         })
         if (tabIndex >= 0) {
diff --git a/src/components/tab_switcher/tab_switcher.jsx b/src/components/tab_switcher/tab_switcher.jsx
index db82e075..d9df42ce 100644
--- a/src/components/tab_switcher/tab_switcher.jsx
+++ b/src/components/tab_switcher/tab_switcher.jsx
@@ -43,14 +43,14 @@ export default {
   },
   data () {
     return {
-      active: findFirstUsable(this.$slots.default())
+      active: findFirstUsable(this.$slots.default)
     }
   },
   computed: {
     activeIndex () {
       // In case of controlled component
       if (this.activeTab) {
-        return this.$slots.default().findIndex(slot => this.activeTab === slot.key)
+        return this.$slots.default.findIndex(slot => this.activeTab === slot.key)
       } else {
         return this.active
       }
@@ -74,7 +74,7 @@ export default {
     },
     // DO NOT put it to computed, it doesn't work (caching?)
     slots () {
-      return this.$slots.default()
+      return this.$slots.default
     },
     setTab (index) {
       if (typeof this.onSwitch === 'function') {
-- 
cgit v1.2.3-70-g09d2


From b3ed29ff02fa3db46a1ec7b5856f2c9131b8fa33 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Fri, 18 Mar 2022 13:32:36 +0200
Subject: made withLoadMore work... sorta

---
 src/boot/after_store.js                      |  4 +++-
 src/boot/routes.js                           |  2 +-
 src/components/gallery/gallery.js            |  4 ++--
 src/components/tab_switcher/tab_switcher.jsx |  6 +++---
 src/hocs/with_load_more/with_load_more.jsx   | 11 ++++-------
 5 files changed, 13 insertions(+), 14 deletions(-)

(limited to 'src/components/tab_switcher/tab_switcher.jsx')

diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 5ddc7465..91a13174 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -17,7 +17,9 @@ import FaviconService from '../services/favicon_service/favicon_service.js'
 
 // disable compat for certain features
 configureCompat({
-  COMPONENT_V_MODEL: false
+  COMPONENT_V_MODEL: false,
+  INSTANCE_SET: false,
+  RENDER_FUNCTION: false
 })
 
 let staticInitialResults = null
diff --git a/src/boot/routes.js b/src/boot/routes.js
index 1bc1f9f7..e5bdd1f0 100644
--- a/src/boot/routes.js
+++ b/src/boot/routes.js
@@ -69,7 +69,7 @@ export default (store) => {
     { name: 'search', path: '/search', component: Search, props: (route) => ({ query: route.query.query }) },
     { name: 'who-to-follow', path: '/who-to-follow', component: WhoToFollow, beforeEnter: validateAuthenticatedRoute },
     { name: 'about', path: '/about', component: About },
-    { name: 'user-profile', path: '/(users/)?:name', component: UserProfile }
+    { name: 'user-profile', path: '/:_(users)?/:name', component: UserProfile }
   ]
 
   if (store.state.instance.pleromaChatMessagesAvailable) {
diff --git a/src/components/gallery/gallery.js b/src/components/gallery/gallery.js
index 094b3e57..4e1bda55 100644
--- a/src/components/gallery/gallery.js
+++ b/src/components/gallery/gallery.js
@@ -1,5 +1,5 @@
 import Attachment from '../attachment/attachment.vue'
-import { sumBy } from 'lodash'
+import { sumBy, set } from 'lodash'
 
 const Gallery = {
   props: [
@@ -85,7 +85,7 @@ const Gallery = {
   },
   methods: {
     onNaturalSizeLoad ({ id, width, height }) {
-      this.$set(this.sizes, id, { width, height })
+      set(this.sizes, id, { width, height })
     },
     rowStyle (row) {
       if (row.audio) {
diff --git a/src/components/tab_switcher/tab_switcher.jsx b/src/components/tab_switcher/tab_switcher.jsx
index d9df42ce..db82e075 100644
--- a/src/components/tab_switcher/tab_switcher.jsx
+++ b/src/components/tab_switcher/tab_switcher.jsx
@@ -43,14 +43,14 @@ export default {
   },
   data () {
     return {
-      active: findFirstUsable(this.$slots.default)
+      active: findFirstUsable(this.$slots.default())
     }
   },
   computed: {
     activeIndex () {
       // In case of controlled component
       if (this.activeTab) {
-        return this.$slots.default.findIndex(slot => this.activeTab === slot.key)
+        return this.$slots.default().findIndex(slot => this.activeTab === slot.key)
       } else {
         return this.active
       }
@@ -74,7 +74,7 @@ export default {
     },
     // DO NOT put it to computed, it doesn't work (caching?)
     slots () {
-      return this.$slots.default
+      return this.$slots.default()
     },
     setTab (index) {
       if (typeof this.onSwitch === 'function') {
diff --git a/src/hocs/with_load_more/with_load_more.jsx b/src/hocs/with_load_more/with_load_more.jsx
index 6cd198ed..e57f9b20 100644
--- a/src/hocs/with_load_more/with_load_more.jsx
+++ b/src/hocs/with_load_more/with_load_more.jsx
@@ -82,14 +82,11 @@ const withLoadMore = ({
     },
     render () {
       const props = {
-        props: {
-          ...this.$props,
-          [childPropName]: this.entries
-        },
-        on: this.$listeners,
-        scopedSlots: this.$scopedSlots
+        ...this.$props,
+        [childPropName]: this.entries
+        // on: this.$listeners // TODO fix listeners
       }
-      const children = Object.entries(this.$slots).map(([key, value]) => h('template', { slot: key }, value))
+      const children = this.$slots
       return (
         <div class="with-load-more">
           <WrappedComponent {...props}>
-- 
cgit v1.2.3-70-g09d2


From 1187727b6065363c253f399a6da53725a493fb32 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 21 Mar 2022 21:29:51 +0200
Subject: fix tabswitcher bugs

---
 src/components/interactions/interactions.js  | 4 +++-
 src/components/tab_switcher/tab_switcher.jsx | 9 ++++++---
 2 files changed, 9 insertions(+), 4 deletions(-)

(limited to 'src/components/tab_switcher/tab_switcher.jsx')

diff --git a/src/components/interactions/interactions.js b/src/components/interactions/interactions.js
index 7fe5e76d..c5ceb63d 100644
--- a/src/components/interactions/interactions.js
+++ b/src/components/interactions/interactions.js
@@ -1,4 +1,5 @@
 import Notifications from '../notifications/notifications.vue'
+import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
 
 const tabModeDict = {
   mentions: ['mention'],
@@ -20,7 +21,8 @@ const Interactions = {
     }
   },
   components: {
-    Notifications
+    Notifications,
+    TabSwitcher
   }
 }
 
diff --git a/src/components/tab_switcher/tab_switcher.jsx b/src/components/tab_switcher/tab_switcher.jsx
index db82e075..a5c6cd2b 100644
--- a/src/components/tab_switcher/tab_switcher.jsx
+++ b/src/components/tab_switcher/tab_switcher.jsx
@@ -1,5 +1,5 @@
 // eslint-disable-next-line no-unused
-import { h } from 'vue'
+import { h, Fragment } from 'vue'
 import { mapState } from 'vuex'
 import { FontAwesomeIcon as FAIcon } from '@fortawesome/vue-fontawesome'
 
@@ -43,14 +43,14 @@ export default {
   },
   data () {
     return {
-      active: findFirstUsable(this.$slots.default())
+      active: findFirstUsable(this.slots())
     }
   },
   computed: {
     activeIndex () {
       // In case of controlled component
       if (this.activeTab) {
-        return this.$slots.default().findIndex(slot => this.activeTab === slot.key)
+        return this.slots().findIndex(slot => this.activeTab === slot.key)
       } else {
         return this.active
       }
@@ -74,6 +74,9 @@ export default {
     },
     // DO NOT put it to computed, it doesn't work (caching?)
     slots () {
+      if (this.$slots.default()[0].type === Fragment) {
+        return this.$slots.default()[0].children
+      }
       return this.$slots.default()
     },
     setTab (index) {
-- 
cgit v1.2.3-70-g09d2


From 87d420a92bdcf9e94923482986ea772bd3753184 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 27 Mar 2022 12:58:28 +0300
Subject: port !1488 to vue3

---
 src/components/settings_modal/settings_modal.vue           | 4 ++--
 src/components/settings_modal/tabs/theme_tab/theme_tab.vue | 6 +++---
 src/components/tab_switcher/tab_switcher.jsx               | 4 ++--
 3 files changed, 7 insertions(+), 7 deletions(-)

(limited to 'src/components/tab_switcher/tab_switcher.jsx')

diff --git a/src/components/settings_modal/settings_modal.vue b/src/components/settings_modal/settings_modal.vue
index 28f85423..18dd3d7a 100644
--- a/src/components/settings_modal/settings_modal.vue
+++ b/src/components/settings_modal/settings_modal.vue
@@ -113,9 +113,9 @@
         <Checkbox :modelValue="!!expertLevel" @update:modelValue="expertLevel = Number($event)">
           {{ $t("settings.expert_mode") }}
         </Checkbox>
-        <portal-target
+        <span
           class="extra-content"
-          name="unscrolled-content"
+          id="unscrolled-content"
         />
       </div>
     </div>
diff --git a/src/components/settings_modal/tabs/theme_tab/theme_tab.vue b/src/components/settings_modal/tabs/theme_tab/theme_tab.vue
index 9cdd229a..cf049a70 100644
--- a/src/components/settings_modal/tabs/theme_tab/theme_tab.vue
+++ b/src/components/settings_modal/tabs/theme_tab/theme_tab.vue
@@ -1018,9 +1018,9 @@
       </tab-switcher>
     </keep-alive>
 
-    <portal
+    <teleport
       v-if="isActive"
-      to="unscrolled-content"
+      to="#unscrolled-content"
     >
       <div class="apply-container">
         <button
@@ -1037,7 +1037,7 @@
           {{ $t('settings.style.switcher.reset') }}
         </button>
       </div>
-    </portal>
+    </teleport>
   </div>
 </template>
 
diff --git a/src/components/tab_switcher/tab_switcher.jsx b/src/components/tab_switcher/tab_switcher.jsx
index 59ff98df..f5a1e603 100644
--- a/src/components/tab_switcher/tab_switcher.jsx
+++ b/src/components/tab_switcher/tab_switcher.jsx
@@ -50,7 +50,7 @@ export default {
     activeIndex () {
       // In case of controlled component
       if (this.activeTab) {
-        return this.slots().findIndex(slot => this.activeTab === slot.key)
+        return this.slots().findIndex(slot => this.activeTab === slot.props.key)
       } else {
         return this.active
       }
@@ -58,7 +58,7 @@ export default {
     isActive () {
       return tabName => {
         const isWanted = slot => slot.props && slot.props['data-tab-name'] === tabName
-        return this.$slots.default.findIndex(isWanted) === this.activeIndex
+        return this.$slots.default().findIndex(isWanted) === this.activeIndex
       }
     },
     settingsModalVisible () {
-- 
cgit v1.2.3-70-g09d2


From 3b02566e16d33956604815e4bd5190f8f8144253 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Sat, 9 Apr 2022 23:49:22 -0400
Subject: Fix tab switcher not working when some tabs hidden

---
 src/components/tab_switcher/tab_switcher.jsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/components/tab_switcher/tab_switcher.jsx')

diff --git a/src/components/tab_switcher/tab_switcher.jsx b/src/components/tab_switcher/tab_switcher.jsx
index f5a1e603..c8d390bc 100644
--- a/src/components/tab_switcher/tab_switcher.jsx
+++ b/src/components/tab_switcher/tab_switcher.jsx
@@ -50,7 +50,7 @@ export default {
     activeIndex () {
       // In case of controlled component
       if (this.activeTab) {
-        return this.slots().findIndex(slot => this.activeTab === slot.props.key)
+        return this.slots().findIndex(slot => slot && slot.props && this.activeTab === slot.props.key)
       } else {
         return this.active
       }
-- 
cgit v1.2.3-70-g09d2

