From 0582f19e7c2c6f916b427d5ecfbbb571178ce841 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Fri, 6 Aug 2021 20:18:27 -0400
Subject: Add tree-style thread display

---
 src/components/settings_modal/tabs/general_tab.vue | 9 +++++++++
 1 file changed, 9 insertions(+)

(limited to 'src/components/settings_modal/tabs/general_tab.vue')

diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index eba3b268..8951c021 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -152,6 +152,15 @@
             {{ $t('settings.show_yous') }}
           </BooleanSetting>
         </li>
+        <li>
+          <ChoiceSetting
+            id="conversationDisplay"
+            path="conversationDisplay"
+            :options="conversationDisplayOptions"
+          >
+            {{ $t('settings.conversation_display') }}
+          </ChoiceSetting>
+        </li>
         <li>
           <ChoiceSetting
             id="mentionLinkDisplay"
-- 
cgit v1.2.3-70-g09d2


From 2e54cf12c76e94f980fbe49f58c080a4a3d17ca4 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Sat, 7 Aug 2021 20:14:14 -0400
Subject: Add settings for max depth in thread

---
 src/components/conversation/conversation.js        | 15 ++++++++++-----
 src/components/settings_modal/tabs/general_tab.vue | 13 +++++++++++++
 src/modules/config.js                              |  3 ++-
 src/modules/instance.js                            |  1 +
 4 files changed, 26 insertions(+), 6 deletions(-)

(limited to 'src/components/settings_modal/tabs/general_tab.vue')

diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js
index 8e4eda51..853161df 100644
--- a/src/components/conversation/conversation.js
+++ b/src/components/conversation/conversation.js
@@ -74,7 +74,11 @@ const conversation = {
   },
   computed: {
     maxDepthToShowByDefault () {
-      return 4
+      // maxDepthInThread = max number of depths that is *visible*
+      // since our depth starts with 0 and "showing" means "showing children"
+      // there is a -2 here
+      const maxDepth = this.$store.getters.mergedConfig.maxDepthInThread - 2
+      return maxDepth >= 1 ? maxDepth : 1
     },
     displayStyle () {
       return this.$store.getters.mergedConfig.conversationDisplay
@@ -351,7 +355,8 @@ const conversation = {
         }
         this._diven = true
         const parentOrSelf = this.parentOrSelf(this.originalStatusId)
-        if (this.threadDisplayStatus[this.statusId] === 'hidden') {
+        // If current status is not visible
+        if (this.threadDisplayStatus[parentOrSelf] === 'hidden') {
           this.diveIntoStatus(parentOrSelf, /* preventScroll */ true)
           this.tryScrollTo(this.statusId)
         }
@@ -429,7 +434,7 @@ const conversation = {
     toggleStatusContentProperty (id, name) {
       this.setStatusContentProperty(id, name, !this.statusContentProperties[id][name])
     },
-    leastShowingAncestor (id) {
+    leastVisibleAncestor (id) {
       let cur = id
       let parent = this.parentOf(cur)
       while (cur) {
@@ -453,14 +458,14 @@ const conversation = {
       const oldHighlight = this.highlight
       this.diveHistory = [...this.diveHistory.slice(0, this.diveHistory.length - 1)]
       if (oldHighlight) {
-        this.tryScrollTo(this.leastShowingAncestor(oldHighlight))
+        this.tryScrollTo(this.leastVisibleAncestor(oldHighlight))
       }
     },
     undive () {
       const oldHighlight = this.highlight
       this.diveHistory = []
       if (oldHighlight) {
-        this.tryScrollTo(this.leastShowingAncestor(oldHighlight))
+        this.tryScrollTo(this.leastVisibleAncestor(oldHighlight))
       } else {
         this.goToCurrent()
       }
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index 8951c021..f97d92c3 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -161,6 +161,19 @@
             {{ $t('settings.conversation_display') }}
           </ChoiceSetting>
         </li>
+        <li v-if="conversationDisplay !== 'linear'">
+          <label for="maxDepthInThread">
+            {{ $t('settings.max_depth_in_thread') }}
+          </label>
+          <input
+            id="maxDepthInThread"
+            path.number="maxDepthInThread"
+            class="number-input"
+            type="number"
+            min="3"
+            step="1"
+          >
+        </li>
         <li>
           <ChoiceSetting
             id="mentionLinkDisplay"
diff --git a/src/modules/config.js b/src/modules/config.js
index ec75dbfb..b3c7e5ab 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -83,7 +83,8 @@ export const defaultState = {
   hideUserStats: undefined, // instance default
   virtualScrolling: undefined, // instance default
   sensitiveByDefault: undefined, // instance default
-  conversationDisplay: undefined // instance default
+  conversationDisplay: undefined, // instance default
+  maxDepthInThread: 6
 }
 
 // caching the instance default properties
diff --git a/src/modules/instance.js b/src/modules/instance.js
index 8a5bbbd1..853be737 100644
--- a/src/modules/instance.js
+++ b/src/modules/instance.js
@@ -54,6 +54,7 @@ const defaultState = {
   virtualScrolling: true,
   sensitiveByDefault: false,
   conversationDisplay: 'simple_tree',
+  maxDepthInThread: 6,
 
   // Nasty stuff
   customEmoji: [],
-- 
cgit v1.2.3-70-g09d2


From 863255d52fdcbbabe45c86c7e36ebafc0f7e1c53 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Sun, 5 Sep 2021 16:35:47 -0400
Subject: Make position of other replies button a pref

---
 src/components/conversation/conversation.js        |  9 +++++
 src/components/conversation/conversation.vue       |  7 ++--
 src/components/settings_modal/tabs/general_tab.js  |  5 +++
 src/components/settings_modal/tabs/general_tab.vue | 40 +++++++++++++++-------
 src/components/status/status.js                    |  1 +
 src/components/status/status.vue                   | 15 +++++++-
 src/modules/config.js                              |  2 ++
 src/modules/instance.js                            |  1 +
 8 files changed, 63 insertions(+), 17 deletions(-)

(limited to 'src/components/settings_modal/tabs/general_tab.vue')

diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js
index 423930af..d4972fbc 100644
--- a/src/components/conversation/conversation.js
+++ b/src/components/conversation/conversation.js
@@ -92,6 +92,15 @@ const conversation = {
     isLinearView () {
       return this.displayStyle === 'linear'
     },
+    otherRepliesButtonPosition () {
+      return this.$store.getters.mergedConfig.conversationOtherRepliesButton
+    },
+    showOtherRepliesButtonBelowStatus () {
+      return this.otherRepliesButtonPosition === 'below'
+    },
+    showOtherRepliesButtonInsideStatus () {
+      return this.otherRepliesButtonPosition === 'inside'
+    },
     hideStatus () {
       if (this.$refs.statusComponent && this.$refs.statusComponent[0]) {
         return this.virtualHidden && this.$refs.statusComponent[0].suspendable
diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue
index f0eb88c1..b3d97075 100644
--- a/src/components/conversation/conversation.vue
+++ b/src/components/conversation/conversation.vue
@@ -66,13 +66,14 @@
               :profile-user-id="profileUserId"
               class="conversation-status status-fadein panel-body"
 
-              :simple="treeViewIsSimple"
+              :simple-tree="treeViewIsSimple"
               :toggle-thread-display="toggleThreadDisplay"
               :thread-display-status="threadDisplayStatus"
               :show-thread-recursively="showThreadRecursively"
               :total-reply-count="totalReplyCount"
               :total-reply-depth="totalReplyDepth"
-              :dive="(!treeViewIsSimple) ? () => diveIntoStatus(status.id) : null"
+              :show-other-replies-as-button="showOtherRepliesButtonInsideStatus"
+              :dive="() => diveIntoStatus(status.id)"
 
               :controlled-showing-tall="statusContentProperties[status.id].showingTall"
               :controlled-expanding-subject="statusContentProperties[status.id].expandingSubject"
@@ -85,7 +86,7 @@
               @toggleExpanded="toggleExpanded"
             />
             <div
-              v-if="getReplies(status.id).length > 1"
+              v-if="showOtherRepliesButtonBelowStatus && getReplies(status.id).length > 1"
               class="thread-ancestor-dive-box"
             >
               <div
diff --git a/src/components/settings_modal/tabs/general_tab.js b/src/components/settings_modal/tabs/general_tab.js
index c43abe8a..a963d204 100644
--- a/src/components/settings_modal/tabs/general_tab.js
+++ b/src/components/settings_modal/tabs/general_tab.js
@@ -25,6 +25,11 @@ const GeneralTab = {
         value: mode,
         label: this.$t(`settings.conversation_display_${mode}`)
       })),
+      conversationOtherRepliesButtonOptions: ['below', 'inside'].map(mode => ({
+        key: mode,
+        value: mode,
+        label: this.$t(`settings.conversation_other_replies_button_${mode}`)
+      })),
       mentionLinkDisplayOptions: ['short', 'full_for_remote', 'full'].map(mode => ({
         key: mode,
         value: mode,
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index f97d92c3..d5ae7810 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -161,19 +161,33 @@
             {{ $t('settings.conversation_display') }}
           </ChoiceSetting>
         </li>
-        <li v-if="conversationDisplay !== 'linear'">
-          <label for="maxDepthInThread">
-            {{ $t('settings.max_depth_in_thread') }}
-          </label>
-          <input
-            id="maxDepthInThread"
-            path.number="maxDepthInThread"
-            class="number-input"
-            type="number"
-            min="3"
-            step="1"
-          >
-        </li>
+        <ul
+          v-if="conversationDisplay !== 'linear'"
+          class="setting-list suboptions"
+        >
+          <li>
+            <label for="maxDepthInThread">
+              {{ $t('settings.max_depth_in_thread') }}
+            </label>
+            <input
+              id="maxDepthInThread"
+              path.number="maxDepthInThread"
+              class="number-input"
+              type="number"
+              min="3"
+              step="1"
+            >
+          </li>
+          <li>
+            <ChoiceSetting
+              id="conversationOtherRepliesButton"
+              path="conversationOtherRepliesButton"
+              :options="conversationOtherRepliesButtonOptions"
+            >
+              {{ $t('settings.conversation_other_replies_button') }}
+            </ChoiceSetting>
+          </li>
+        </ul>
         <li>
           <ChoiceSetting
             id="mentionLinkDisplay"
diff --git a/src/components/status/status.js b/src/components/status/status.js
index 15c2d029..700b9764 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -100,6 +100,7 @@ const Status = {
     'simpleTree',
     'controlledThreadDisplayStatus',
     'controlledToggleThreadDisplay',
+    'showOtherRepliesAsButton',
 
     'controlledShowingTall',
     'controlledToggleShowingTall',
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index e4812711..bc0aeaf0 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -346,7 +346,20 @@
             v-if="inConversation && !isPreview && replies && replies.length"
             class="replies"
           >
-            <span class="faint">{{ $t('status.replies_list') }}</span>
+            <button
+              v-if="showOtherRepliesAsButton"
+              class="button-unstyled -link faint"
+              :title="$tc('status.ancestor_follow', replies.length - 1, { numReplies: replies.length - 1 })"
+              @click.prevent="dive"
+            >
+              {{ $t('status.replies_list') }}
+            </button>
+            <span
+              v-else
+              class="faint"
+            >
+              {{ $t('status.replies_list') }}
+            </span>
             <StatusPopover
               v-for="reply in replies"
               :key="reply.id"
diff --git a/src/modules/config.js b/src/modules/config.js
index b3c7e5ab..a111abca 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -13,6 +13,7 @@ export const multiChoiceProperties = [
   'postContentType',
   'subjectLineBehavior',
   'conversationDisplay', // tree | linear
+  'conversationOtherRepliesButton', // below | inside
   'mentionLinkDisplay' // short | full_for_remote | full
 ]
 
@@ -84,6 +85,7 @@ export const defaultState = {
   virtualScrolling: undefined, // instance default
   sensitiveByDefault: undefined, // instance default
   conversationDisplay: undefined, // instance default
+  conversationOtherRepliesButton: undefined, // instance default
   maxDepthInThread: 6
 }
 
diff --git a/src/modules/instance.js b/src/modules/instance.js
index 853be737..cd17c23d 100644
--- a/src/modules/instance.js
+++ b/src/modules/instance.js
@@ -54,6 +54,7 @@ const defaultState = {
   virtualScrolling: true,
   sensitiveByDefault: false,
   conversationDisplay: 'simple_tree',
+  conversationOtherRepliesButton: 'below',
   maxDepthInThread: 6,
 
   // Nasty stuff
-- 
cgit v1.2.3-70-g09d2


From e7f5033c7d05038b116f7170fedc352a662cc646 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Sun, 6 Mar 2022 13:57:48 -0500
Subject: Split conversation display style into two different settings

linear => linear (now default)
simple_tree => tree / conversationTreeAdvanced=false
tree => tree / conversationTreeAdvanced=true
---
 src/components/conversation/conversation.js        | 4 ++--
 src/components/settings_modal/tabs/general_tab.js  | 2 +-
 src/components/settings_modal/tabs/general_tab.vue | 5 +++++
 src/modules/config.js                              | 1 +
 src/modules/instance.js                            | 3 ++-
 5 files changed, 11 insertions(+), 4 deletions(-)

(limited to 'src/components/settings_modal/tabs/general_tab.vue')

diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js
index b9ebe7eb..46228e37 100644
--- a/src/components/conversation/conversation.js
+++ b/src/components/conversation/conversation.js
@@ -81,10 +81,10 @@ const conversation = {
       return this.$store.getters.mergedConfig.conversationDisplay
     },
     isTreeView () {
-      return this.displayStyle === 'tree' || this.displayStyle === 'simple_tree'
+      return !this.isLinearView
     },
     treeViewIsSimple () {
-      return this.displayStyle === 'simple_tree'
+      return !this.$store.getters.mergedConfig.conversationTreeAdvanced
     },
     isLinearView () {
       return this.displayStyle === 'linear'
diff --git a/src/components/settings_modal/tabs/general_tab.js b/src/components/settings_modal/tabs/general_tab.js
index a963d204..8ae0021c 100644
--- a/src/components/settings_modal/tabs/general_tab.js
+++ b/src/components/settings_modal/tabs/general_tab.js
@@ -20,7 +20,7 @@ const GeneralTab = {
         value: mode,
         label: this.$t(`settings.subject_line_${mode === 'masto' ? 'mastodon' : mode}`)
       })),
-      conversationDisplayOptions: ['tree', 'simple_tree', 'linear'].map(mode => ({
+      conversationDisplayOptions: ['tree', 'linear'].map(mode => ({
         key: mode,
         value: mode,
         label: this.$t(`settings.conversation_display_${mode}`)
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index d5ae7810..28b39d7b 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -165,6 +165,11 @@
           v-if="conversationDisplay !== 'linear'"
           class="setting-list suboptions"
         >
+          <li>
+            <BooleanSetting path="conversationTreeAdvanced">
+              {{ $t('settings.tree_advanced') }}
+            </BooleanSetting>
+          </li>
           <li>
             <label for="maxDepthInThread">
               {{ $t('settings.max_depth_in_thread') }}
diff --git a/src/modules/config.js b/src/modules/config.js
index a111abca..8cb3097c 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -85,6 +85,7 @@ export const defaultState = {
   virtualScrolling: undefined, // instance default
   sensitiveByDefault: undefined, // instance default
   conversationDisplay: undefined, // instance default
+  conversationTreeAdvanced: undefined, // instance default
   conversationOtherRepliesButton: undefined, // instance default
   maxDepthInThread: 6
 }
diff --git a/src/modules/instance.js b/src/modules/instance.js
index cd17c23d..6c5cb4b1 100644
--- a/src/modules/instance.js
+++ b/src/modules/instance.js
@@ -53,7 +53,8 @@ const defaultState = {
   theme: 'pleroma-dark',
   virtualScrolling: true,
   sensitiveByDefault: false,
-  conversationDisplay: 'simple_tree',
+  conversationDisplay: 'linear',
+  conversationTreeAdvanced: false,
   conversationOtherRepliesButton: 'below',
   maxDepthInThread: 6,
 
-- 
cgit v1.2.3-70-g09d2


From d157f6738195325c59870fe02df8fa16985c84af Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Sun, 6 Mar 2022 14:13:35 -0500
Subject: Make fading ancestors optional

---
 src/components/conversation/conversation.js        | 3 +++
 src/components/conversation/conversation.vue       | 4 ++--
 src/components/settings_modal/tabs/general_tab.vue | 5 +++++
 src/modules/config.js                              | 1 +
 src/modules/instance.js                            | 1 +
 5 files changed, 12 insertions(+), 2 deletions(-)

(limited to 'src/components/settings_modal/tabs/general_tab.vue')

diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js
index 46228e37..89ff2f6f 100644
--- a/src/components/conversation/conversation.js
+++ b/src/components/conversation/conversation.js
@@ -89,6 +89,9 @@ const conversation = {
     isLinearView () {
       return this.displayStyle === 'linear'
     },
+    shouldFadeAncestors () {
+      return this.$store.getters.mergedConfig.conversationTreeFadeAncestors
+    },
     otherRepliesButtonPosition () {
       return this.$store.getters.mergedConfig.conversationOtherRepliesButton
     },
diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue
index 73c613b9..3e96fba2 100644
--- a/src/components/conversation/conversation.vue
+++ b/src/components/conversation/conversation.vue
@@ -50,7 +50,7 @@
             v-for="status in ancestorsOf(diveRoot)"
             :key="status.id"
             class="thread-ancestor"
-            :class="{'thread-ancestor-has-other-replies': getReplies(status.id).length > 1}"
+            :class="{'thread-ancestor-has-other-replies': getReplies(status.id).length > 1, '-faded': shouldFadeAncestors}"
           >
             <status
               ref="statusComponent"
@@ -210,7 +210,7 @@
     border-left: 2px solid var(--border, $fallback--border);
   }
 
-  .thread-ancestor .StatusContent {
+  .thread-ancestor.-faded .StatusContent {
     --link: var(--faintLink);
     --text: var(--faint);
     color: var(--text);
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index 28b39d7b..6c108292 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -170,6 +170,11 @@
               {{ $t('settings.tree_advanced') }}
             </BooleanSetting>
           </li>
+          <li>
+            <BooleanSetting path="conversationTreeFadeAncestors">
+              {{ $t('settings.tree_fade_ancestors') }}
+            </BooleanSetting>
+          </li>
           <li>
             <label for="maxDepthInThread">
               {{ $t('settings.max_depth_in_thread') }}
diff --git a/src/modules/config.js b/src/modules/config.js
index 8cb3097c..acc71b80 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -87,6 +87,7 @@ export const defaultState = {
   conversationDisplay: undefined, // instance default
   conversationTreeAdvanced: undefined, // instance default
   conversationOtherRepliesButton: undefined, // instance default
+  conversationTreeFadeAncestors: undefined, // instance default
   maxDepthInThread: 6
 }
 
diff --git a/src/modules/instance.js b/src/modules/instance.js
index 6c5cb4b1..f09dd0b3 100644
--- a/src/modules/instance.js
+++ b/src/modules/instance.js
@@ -56,6 +56,7 @@ const defaultState = {
   conversationDisplay: 'linear',
   conversationTreeAdvanced: false,
   conversationOtherRepliesButton: 'below',
+  conversationTreeFadeAncestors: false,
   maxDepthInThread: 6,
 
   // Nasty stuff
-- 
cgit v1.2.3-70-g09d2


From 551b8f3690bab1f53ec22ccf6963009a30fa45d0 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Mon, 7 Mar 2022 20:02:53 -0500
Subject: Fix "max depth in thread" setting

---
 .../settings_modal/helpers/integer_setting.js      | 37 ++++++++++++++++++++++
 .../settings_modal/helpers/integer_setting.vue     | 20 ++++++++++++
 .../settings_modal/tabs/filtering_tab.js           |  4 ++-
 .../settings_modal/tabs/filtering_tab.vue          | 15 +++------
 src/components/settings_modal/tabs/general_tab.js  |  2 ++
 src/components/settings_modal/tabs/general_tab.vue | 15 +++------
 6 files changed, 72 insertions(+), 21 deletions(-)
 create mode 100644 src/components/settings_modal/helpers/integer_setting.js
 create mode 100644 src/components/settings_modal/helpers/integer_setting.vue

(limited to 'src/components/settings_modal/tabs/general_tab.vue')

diff --git a/src/components/settings_modal/helpers/integer_setting.js b/src/components/settings_modal/helpers/integer_setting.js
new file mode 100644
index 00000000..fa6569ab
--- /dev/null
+++ b/src/components/settings_modal/helpers/integer_setting.js
@@ -0,0 +1,37 @@
+import { get, set } from 'lodash'
+import ModifiedIndicator from './modified_indicator.vue'
+export default {
+  components: {
+    ModifiedIndicator
+  },
+  props: {
+    path: String,
+    disabled: Boolean,
+    min: Number
+  },
+  computed: {
+    pathDefault () {
+      const [firstSegment, ...rest] = this.path.split('.')
+      return [firstSegment + 'DefaultValue', ...rest].join('.')
+    },
+    state () {
+      const value = get(this.$parent, this.path)
+      if (value === undefined) {
+        return this.defaultState
+      } else {
+        return value
+      }
+    },
+    defaultState () {
+      return get(this.$parent, this.pathDefault)
+    },
+    isChanged () {
+      return this.state !== this.defaultState
+    }
+  },
+  methods: {
+    update (e) {
+      set(this.$parent, this.path, parseInt(e.target.value))
+    }
+  }
+}
diff --git a/src/components/settings_modal/helpers/integer_setting.vue b/src/components/settings_modal/helpers/integer_setting.vue
new file mode 100644
index 00000000..8284abcc
--- /dev/null
+++ b/src/components/settings_modal/helpers/integer_setting.vue
@@ -0,0 +1,20 @@
+<template>
+  <span class="IntegerSetting">
+    <label :for="path">
+      <slot />
+    </label>
+    <input
+      :id="path"
+      class="number-input"
+      type="number"
+      step="1"
+      :disabled="disabled"
+      :min="min || 0"
+      :value="state"
+      @change="update"
+    >
+    <ModifiedIndicator :changed="isChanged" />
+  </span>
+</template>
+
+<script src="./integer_setting.js"></script>
diff --git a/src/components/settings_modal/tabs/filtering_tab.js b/src/components/settings_modal/tabs/filtering_tab.js
index 4eaf4217..73413b48 100644
--- a/src/components/settings_modal/tabs/filtering_tab.js
+++ b/src/components/settings_modal/tabs/filtering_tab.js
@@ -1,6 +1,7 @@
 import { filter, trim } from 'lodash'
 import BooleanSetting from '../helpers/boolean_setting.vue'
 import ChoiceSetting from '../helpers/choice_setting.vue'
+import IntegerSetting from '../helpers/integer_setting.vue'
 
 import SharedComputedObject from '../helpers/shared_computed_object.js'
 
@@ -17,7 +18,8 @@ const FilteringTab = {
   },
   components: {
     BooleanSetting,
-    ChoiceSetting
+    ChoiceSetting,
+    IntegerSetting
   },
   computed: {
     ...SharedComputedObject(),
diff --git a/src/components/settings_modal/tabs/filtering_tab.vue b/src/components/settings_modal/tabs/filtering_tab.vue
index 50ee20e0..eb1705e7 100644
--- a/src/components/settings_modal/tabs/filtering_tab.vue
+++ b/src/components/settings_modal/tabs/filtering_tab.vue
@@ -60,17 +60,12 @@
         </li>
         <h3>{{ $t('settings.attachments') }}</h3>
         <li>
-          <label for="maxThumbnails">
-            {{ $t('settings.max_thumbnails') }}
-          </label>
-          <input
-            id="maxThumbnails"
-            path.number="maxThumbnails"
-            class="number-input"
-            type="number"
-            min="0"
-            step="1"
+          <IntegerSetting
+            path="maxThumbnails"
+            :min="0"
           >
+            {{ $t('settings.max_thumbnails') }}
+          </IntegerSetting>
         </li>
         <li>
           <BooleanSetting path="hideAttachments">
diff --git a/src/components/settings_modal/tabs/general_tab.js b/src/components/settings_modal/tabs/general_tab.js
index 8ae0021c..03ca99fa 100644
--- a/src/components/settings_modal/tabs/general_tab.js
+++ b/src/components/settings_modal/tabs/general_tab.js
@@ -1,5 +1,6 @@
 import BooleanSetting from '../helpers/boolean_setting.vue'
 import ChoiceSetting from '../helpers/choice_setting.vue'
+import IntegerSetting from '../helpers/integer_setting.vue'
 import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
 
 import SharedComputedObject from '../helpers/shared_computed_object.js'
@@ -47,6 +48,7 @@ const GeneralTab = {
   components: {
     BooleanSetting,
     ChoiceSetting,
+    IntegerSetting,
     InterfaceLanguageSwitcher
   },
   computed: {
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index 6c108292..ba01fdeb 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -176,17 +176,12 @@
             </BooleanSetting>
           </li>
           <li>
-            <label for="maxDepthInThread">
-              {{ $t('settings.max_depth_in_thread') }}
-            </label>
-            <input
-              id="maxDepthInThread"
-              path.number="maxDepthInThread"
-              class="number-input"
-              type="number"
-              min="3"
-              step="1"
+            <IntegerSetting
+              path="maxDepthInThread"
+              :min="3"
             >
+              {{ $t('settings.max_depth_in_thread') }}
+            </IntegerSetting>
           </li>
           <li>
             <ChoiceSetting
-- 
cgit v1.2.3-70-g09d2

