diff --git a/client/components/admin/admin-theme.vue b/client/components/admin/admin-theme.vue
index 6443f1b6588231c31341159e6d1e38b98c26b89c..b3aed1a139e619aa4f2173d33cf8a633d9d49e24 100644
--- a/client/components/admin/admin-theme.vue
+++ b/client/components/admin/admin-theme.vue
@@ -1,5 +1,5 @@
 <template lang='pug'>
-v-container(fluid, grid-list-lg)
+  v-container(fluid, grid-list-lg)
     v-layout(row wrap)
       v-flex(xs12)
         .admin-header
@@ -54,54 +54,17 @@ v-container(fluid, grid-list-lg)
               v-card.mt-3.animated.fadeInUp.wait-p1s
                 v-toolbar(color='primary', dark, dense, flat)
                   v-toolbar-title.subtitle-1 {{$t(`admin:theme.options`)}}
-                  v-spacer
-                  v-chip(label, color='white', small).primary--text coming soon
                 v-card-text
-                  v-select(
-                    :items='[]'
-                    outlined
-                    prepend-icon='mdi-border-vertical'
-                    v-model='config.iconset'
-                    label='Table of Contents Position'
-                    persistent-hint
-                    hint='Select whether the table of contents is shown on the left, right or not at all.'
-                    disabled
-                    )
                   v-range-slider(
-                    prepend-icon='mdi-serial-port'
-                    label='Heading Levels in ToC'
-                    hint='The table of contents will show headings from and up to the selected levels.'
+                    prepend-icon='mdi-menu-open'
+                    :label='$t(`admin:theme.tocHeadingLevels`)'
                     v-model='tocRange'
                     :min='1'
                     :max='6'
                     :tick-labels='["H1", "H2", "H3", "H4", "H5", "H6"]'
                   )
+                  .text-caption {{$t('admin:theme.tocHeadingLevelsHint')}}
             v-flex(lg6 xs12)
-              //- v-card.animated.fadeInUp.wait-p2s
-              //-   v-toolbar(color='teal', dark, dense, flat)
-              //-     v-toolbar-title.subtitle-1 {{$t('admin:theme.downloadThemes')}}
-              //-     v-spacer
-              //-     v-chip(label, color='white', small).teal--text coming soon
-              //-   v-data-table(
-              //-     :headers='headers',
-              //-     :items='themes',
-              //-     hide-default-footer,
-              //-     item-key='value',
-              //-     :items-per-page='1000'
-              //-   )
-              //-     template(v-slot:item='thm')
-              //-       td
-              //-         strong {{thm.item.text}}
-              //-       td
-              //-         span {{ thm.item.author }}
-              //-       td.text-xs-center
-              //-         v-progress-circular(v-if='thm.item.isDownloading', indeterminate, color='blue', size='20', :width='2')
-              //-         v-btn(v-else-if='thm.item.isInstalled && thm.item.installDate < thm.item.updatedAt', icon)
-              //-           v-icon.blue--text mdi-cached
-              //-         v-btn(v-else-if='thm.item.isInstalled', icon)
-              //-           v-icon.green--text mdi-check-bold
-              //-         v-btn(v-else, icon)
-              //-           v-icon.grey--text mdi-cloud-download
 
               v-card.animated.fadeInUp.wait-p2s
                 v-toolbar(color='primary', dark, dense, flat)
@@ -161,9 +124,10 @@ export default {
       config: {
         theme: 'default',
         darkMode: false,
-        minTocLevel: 0,
-        tocLevel: 2,
-        tocCollapseLevel: 2,
+        tocDepth: {
+          min: 1,
+          max: 2
+        },
         iconset: '',
         injectCSS: '',
         injectHead: '',
@@ -175,13 +139,14 @@ export default {
   computed: {
     tocRange: {
       get() {
-        var range = [this.config.minTocLevel, this.config.tocLevel]
+        var range = [this.config.tocDepth.min, this.config.tocDepth.max]
         return range
       },
       set(value) {
-        this.config.minTocLevel = value[0]
-        this.config.tocLevel = value[1]
-        this.config.tocCollapseLevel = value[1]
+        this.config.tocDepth = {
+          min: parseInt(value[0]),
+          max: parseInt(value[1])
+        }
       }
     },
     darkMode: sync('site/dark'),
@@ -230,9 +195,7 @@ export default {
             theme: this.config.theme,
             iconset: this.config.iconset,
             darkMode: this.darkMode,
-            minTocLevel: parseInt(this.config.minTocLevel, 10),
-            tocLevel: parseInt(this.config.tocLevel, 10),
-            tocCollapseLevel: parseInt(this.config.tocCollapseLevel, 10),
+            tocDepth: this.config.tocDepth,
             injectCSS: this.config.injectCSS,
             injectHead: this.config.injectHead,
             injectBody: this.config.injectBody
diff --git a/client/components/editor.vue b/client/components/editor.vue
index 0a589897e2c86c9b390feb4365a5f16e2372726e..530c99fbffa888f59c3b6b663086ea052d911088 100644
--- a/client/components/editor.vue
+++ b/client/components/editor.vue
@@ -144,21 +144,9 @@ export default {
       type: Number,
       default: 0
     },
-    minTocLevel: {
-      type: Number,
-      default: 0
-    },
-    tocLevel: {
-      type: Number,
-      default: 1
-    },
-    tocCollapseLevel: {
-      type: Number,
-      default: 0
-    },
-    doUseTocDefault: {
-      type: Boolean,
-      default: true
+    tocOptions: {
+      type: String,
+      default: ''
     },
     checkoutDate: {
       type: String,
@@ -187,7 +175,9 @@ export default {
         tags: '',
         title: '',
         css: '',
-        js: ''
+        js: '',
+        tocDepth: 0,
+        useDefaultTocDepth: false
       }
     }
   },
@@ -206,10 +196,8 @@ export default {
         this.path !== this.$store.get('page/path'),
         this.savedState.title !== this.$store.get('page/title'),
         this.savedState.description !== this.$store.get('page/description'),
-        this.savedState.minTocLevel !== this.$store.get('page/minTocLevel'),
-        this.savedState.tocLevel !== this.$store.get('page/tocLevel'),
-        this.savedState.tocCollapseLevel !== this.$store.get('page/tocCollapseLevel'),
-        this.savedState.doUseTocDefault !== this.$store.get('page/doUseTocDefault'),
+        this.savedState.tocDepth !== this.$store.get('page/tocDepth@min') + (this.$store.get('page/tocDepth@max') * 10),
+        this.savedState.useDefaultTocDepth !== this.$store.get('page/useDefaultTocDepth'),
         this.savedState.tags !== this.$store.get('page/tags'),
         this.savedState.isPublished !== this.$store.get('page/isPublished'),
         this.savedState.publishStartDate !== this.$store.get('page/publishStartDate'),
@@ -243,12 +231,15 @@ export default {
     this.$store.set('page/title', this.title)
     this.$store.set('page/scriptCss', this.scriptCss)
     this.$store.set('page/scriptJs', this.scriptJs)
-    this.$store.set('page/minTocLevel', this.minTocLevel)
-    this.$store.set('page/tocLevel', this.tocLevel)
-    this.$store.set('page/tocCollapseLevel', this.tocCollapseLevel)
-    this.$store.set('page/doUseTocDefault', this.doUseTocDefault)
     this.$store.set('page/mode', 'edit')
 
+    const tocOptions = JSON.parse(Buffer.from(this.tocOptions, 'base64').toString())
+    this.$store.set('page/tocDepth', {
+      min: tocOptions.min,
+      max: tocOptions.max
+    })
+    this.$store.set('page/useDefaultTocDepth', tocOptions.useDefault)
+
     this.setCurrentSavedState()
 
     this.checkoutDateActive = this.checkoutDate
@@ -326,10 +317,8 @@ export default {
                 $publishStartDate: Date
                 $scriptCss: String
                 $scriptJs: String
-                $minTocLevel: Int!
-                $tocLevel: Int!
-                $tocCollapseLevel: Int!
-                $doUseTocDefault: Boolean!
+                $tocDepth: RangeInput
+                $useDefaultTocDepth: Boolean
                 $tags: [String]!
                 $title: String!
               ) {
@@ -346,10 +335,8 @@ export default {
                     publishStartDate: $publishStartDate
                     scriptCss: $scriptCss
                     scriptJs: $scriptJs
-                    minTocLevel: $minTocLevel
-                    tocLevel: $tocLevel
-                    tocCollapseLevel: $tocCollapseLevel
-                    doUseTocDefault: $doUseTocDefault
+                    tocDepth: $tocDepth
+                    useDefaultTocDepth: $useDefaultTocDepth
                     tags: $tags
                     title: $title
                   ) {
@@ -379,10 +366,8 @@ export default {
               publishStartDate: this.$store.get('page/publishStartDate') || '',
               scriptCss: this.$store.get('page/scriptCss'),
               scriptJs: this.$store.get('page/scriptJs'),
-              minTocLevel: this.$store.get('page/minTocLevel'),
-              tocLevel: this.$store.get('page/tocLevel'),
-              tocCollapseLevel: this.$store.get('page/tocCollapseLevel'),
-              doUseTocDefault: this.$store.get('page/doUseTocDefault'),
+              tocDepth: this.$store.get('page/tocDepth'),
+              useDefaultTocDepth: this.$store.get('page/useDefaultTocDepth'),
               tags: this.$store.get('page/tags'),
               title: this.$store.get('page/title')
             }
@@ -441,10 +426,8 @@ export default {
                 $publishStartDate: Date
                 $scriptCss: String
                 $scriptJs: String
-                $minTocLevel: Int
-                $tocLevel: Int
-                $tocCollapseLevel: Int
-                $doUseTocDefault: Boolean
+                $tocDepth: RangeInput
+                $useDefaultTocDepth: Boolean
                 $tags: [String]
                 $title: String
               ) {
@@ -462,10 +445,8 @@ export default {
                     publishStartDate: $publishStartDate
                     scriptCss: $scriptCss
                     scriptJs: $scriptJs
-                    minTocLevel: $minTocLevel
-                    tocLevel: $tocLevel
-                    tocCollapseLevel: $tocCollapseLevel
-                    doUseTocDefault: $doUseTocDefault
+                    tocDepth: $tocDepth
+                    useDefaultTocDepth: $useDefaultTocDepth
                     tags: $tags
                     title: $title
                   ) {
@@ -495,10 +476,8 @@ export default {
               publishStartDate: this.$store.get('page/publishStartDate') || '',
               scriptCss: this.$store.get('page/scriptCss'),
               scriptJs: this.$store.get('page/scriptJs'),
-              minTocLevel: this.$store.get('page/minTocLevel'),
-              tocLevel: this.$store.get('page/tocLevel'),
-              tocCollapseLevel: this.$store.get('page/tocCollapseLevel'),
-              doUseTocDefault: this.$store.get('page/doUseTocDefault'),
+              tocDepth: this.$store.get('page/tocDepth'),
+              useDefaultTocDepth: this.$store.get('page/useDefaultTocDepth'),
               tags: this.$store.get('page/tags'),
               title: this.$store.get('page/title')
             }
@@ -582,10 +561,8 @@ export default {
         title: this.$store.get('page/title'),
         css: this.$store.get('page/scriptCss'),
         js: this.$store.get('page/scriptJs'),
-        minTocLevel: this.$store.get('page/minTocLevel'),
-        tocLevel: this.$store.get('page/tocLevel'),
-        tocCollapseLevel: this.$store.get('page/tocCollapseLevel'),
-        doUseTocDefault: this.$store.get('page/doUseTocDefault')
+        tocDepth: this.$store.get('page/tocDepth@min') + (this.$store.get('page/tocDepth@max') * 10),
+        useDefaultTocDepth: this.$store.get('page/useDefaultTocDepth')
       }
     },
     injectCustomCss: _.debounce(css => {
diff --git a/client/components/editor/editor-modal-properties.vue b/client/components/editor/editor-modal-properties.vue
index a0e8b22b94076928e6c1f327b4276d93db320c59..79a32e6cdbaff90aca712754c74e55f2a7bd7d4d 100644
--- a/client/components/editor/editor-modal-properties.vue
+++ b/client/components/editor/editor-modal-properties.vue
@@ -19,9 +19,9 @@ v-dialog(
     v-card(tile)
       v-tabs(color='white', background-color='blue darken-1', dark, centered, v-model='currentTab')
         v-tab {{$t('editor:props.info')}}
+        v-tab {{$t('editor:props.toc')}}
         v-tab {{$t('editor:props.scheduling')}}
         v-tab(:disabled='!hasScriptPermission') {{$t('editor:props.scripts')}}
-        v-tab(disabled) {{$t('editor:props.social')}}
         v-tab(:disabled='!hasStylePermission') {{$t('editor:props.styles')}}
         v-tab-item(transition='fade-transition', reverse-transition='fade-transition')
           v-card-text.pt-5
@@ -67,23 +67,6 @@ v-dialog(
                     :rules='[rules.required, rules.path]'
                     )
           v-divider
-          v-card-text.grey.pt-5(:class='$vuetify.theme.dark ? `darken-3-d3` : `lighten-5`')
-            .overline.pb-5 Theme Options
-            v-switch(
-              label='Use Site Defaults'
-              v-model='doUseTocDefault'
-            )
-            v-range-slider(
-              :disabled='doUseTocDefault'
-              prepend-icon='mdi-serial-port'
-              label='Heading Levels in ToC'
-              hint='The table of contents will show headings from and up to the selected levels.'
-              v-model='tocRange'
-              :min='1'
-              :max='6'
-              :tick-labels='["H1", "H2", "H3", "H4", "H5", "H6"]'
-              )
-          v-divider
           v-card-text.grey.pt-5(:class='$vuetify.theme.dark ? `darken-3-d5` : `lighten-4`')
             .overline.pb-5 {{$t('editor:props.categorization')}}
             v-chip-group.radius-5.mb-5(column, v-if='tags && tags.length > 0')
@@ -107,6 +90,24 @@ v-dialog(
               hide-no-data
               :search-input.sync='newTagSearch'
               )
+        v-tab-item(transition='fade-transition', reverse-transition='fade-transition')
+          v-card-text
+            .overline {{$t('editor:props.tocTitle')}}
+            v-switch(
+              :label='$t(`editor:props.tocUseDefault`)'
+              v-model='useDefaultTocDepth'
+            )
+            v-range-slider(
+              :disabled='useDefaultTocDepth'
+              prepend-icon='mdi-menu-open'
+              :label='$t(`editor:props.tocHeadingLevels`)'
+              v-model='tocDepth'
+              :min='1'
+              :max='6'
+              :tick-labels='["H1", "H2", "H3", "H4", "H5", "H6"]'
+              )
+            .text-caption.pl-8.grey--text {{$t('editor:props.tocHeadingLevelsHint')}}
+
         v-tab-item(transition='fade-transition', reverse-transition='fade-transition')
           v-card-text
             .overline {{$t('editor:props.publishState')}}
@@ -213,43 +214,6 @@ v-dialog(
           .editor-props-codeeditor-hint
             .caption {{$t('editor:props.htmlHint')}}
 
-        v-tab-item(transition='fade-transition', reverse-transition='fade-transition')
-          v-card-text
-            .overline {{$t('editor:props.socialFeatures')}}
-            v-switch(
-              :label='$t(`editor:props.allowComments`)'
-              v-model='isPublished'
-              color='primary'
-              :hint='$t(`editor:props.allowCommentsHint`)'
-              persistent-hint
-              inset
-              )
-            v-switch(
-              :label='$t(`editor:props.allowRatings`)'
-              v-model='isPublished'
-              color='primary'
-              :hint='$t(`editor:props.allowRatingsHint`)'
-              persistent-hint
-              disabled
-              inset
-              )
-            v-switch(
-              :label='$t(`editor:props.displayAuthor`)'
-              v-model='isPublished'
-              color='primary'
-              :hint='$t(`editor:props.displayAuthorHint`)'
-              persistent-hint
-              inset
-              )
-            v-switch(
-              :label='$t(`editor:props.displaySharingBar`)'
-              v-model='isPublished'
-              color='primary'
-              :hint='$t(`editor:props.displaySharingBarHint`)'
-              persistent-hint
-              inset
-              )
-
         v-tab-item(:transition='false', :reverse-transition='false')
           .editor-props-codeeditor-title
             .overline {{$t('editor:props.css')}}
@@ -315,19 +279,19 @@ export default {
     isPublished: sync('page/isPublished'),
     publishStartDate: sync('page/publishStartDate'),
     publishEndDate: sync('page/publishEndDate'),
-    tocRange: {
+    tocDepth: {
       get() {
-        var range = [this.$store.get('page/minTocLevel'), this.$store.get('page/tocLevel')]
-        return range
-        // return [get('page/minTocLevel'), get('page/tocLevel')]
+        const tocDepth = this.$store.get('page/tocDepth')
+        return [tocDepth.min, tocDepth.max]
       },
       set(value) {
-        this.$store.set('page/minTocLevel', value[0])
-        this.$store.set('page/tocLevel', value[1])
-        this.$store.set('page/tocCollapseLevel', value[1])
+        this.$store.set('page/tocDepth', {
+          min: parseInt(value[0]),
+          max: parseInt(value[1])
+        })
       }
     },
-    doUseTocDefault: sync('page/doUseTocDefault'),
+    useDefaultTocDepth: sync('page/useDefaultTocDepth'),
     scriptJs: sync('page/scriptJs'),
     scriptCss: sync('page/scriptCss'),
     hasScriptPermission: get('page/effectivePermissions@pages.script'),
@@ -359,7 +323,7 @@ export default {
       if (this.cm) {
         this.cm.toTextArea()
       }
-      if (newValue === 2) {
+      if (newValue === 3) {
         this.$nextTick(() => {
           setTimeout(() => {
             this.loadEditor(this.$refs.codejs, 'html')
diff --git a/client/graph/admin/theme/theme-mutation-save.gql b/client/graph/admin/theme/theme-mutation-save.gql
index ab0425acd3b014e18effc87512de16ce853358af..ba4e43476bfdfc0fab8b5705f4db9008610e2a55 100644
--- a/client/graph/admin/theme/theme-mutation-save.gql
+++ b/client/graph/admin/theme/theme-mutation-save.gql
@@ -1,6 +1,22 @@
-mutation($theme: String!, $iconset: String!, $darkMode: Boolean!, $minTocLevel: Int!, $tocLevel: Int!, $tocCollapseLevel: Int!, $injectCSS: String, $injectHead: String, $injectBody: String) {
+mutation(
+  $theme: String!
+  $iconset: String!
+  $darkMode: Boolean!
+  $tocDepth: RangeInput!
+  $injectCSS: String
+  $injectHead: String
+  $injectBody: String
+  ) {
   theming {
-    setConfig(theme: $theme, iconset: $iconset, darkMode: $darkMode, minTocLevel: $minTocLevel, tocLevel: $tocLevel, tocCollapseLevel: $tocCollapseLevel, injectCSS: $injectCSS, injectHead: $injectHead, injectBody: $injectBody) {
+    setConfig(
+      theme: $theme
+      iconset: $iconset
+      darkMode: $darkMode
+      tocDepth: $tocDepth
+      injectCSS: $injectCSS
+      injectHead: $injectHead
+      injectBody: $injectBody
+      ) {
       responseResult {
         succeeded
         errorCode
diff --git a/client/graph/admin/theme/theme-query-config.gql b/client/graph/admin/theme/theme-query-config.gql
index 27ef6a6a52bd3547a554ef1c48e02ce65742bbce..48a8ead19a8d84c27ce51fb147f8083e2054cf59 100644
--- a/client/graph/admin/theme/theme-query-config.gql
+++ b/client/graph/admin/theme/theme-query-config.gql
@@ -4,9 +4,10 @@ query {
       theme
       iconset
       darkMode
-      minTocLevel
-      tocLevel
-      tocCollapseLevel
+      tocDepth {
+        min
+        max
+      }
       injectCSS
       injectHead
       injectBody
diff --git a/client/store/page.js b/client/store/page.js
index c9f736fd75a807874b0410e8cbe235800565ed71..c187c58e19f5ecfb0d5ce014ba8687da6af0bd8f 100644
--- a/client/store/page.js
+++ b/client/store/page.js
@@ -17,10 +17,11 @@ const state = {
   editor: '',
   mode: '',
   scriptJs: '',
-  minTocLevel: 0,
-  tocLevel: 2,
-  tocCollapseLevel: 2,
-  doUseTocDefault: true,
+  tocDepth: {
+    min: 1,
+    max: 2
+  },
+  useDefaultTocDepth: true,
   scriptCss: '',
   effectivePermissions: {
     comments: {
diff --git a/client/themes/default/components/page-toc-item.vue b/client/themes/default/components/page-toc-item.vue
index 752e1efdb3fbedde677c722406cd63792329b6e7..9478999fa65f201a437f499df08539f0fb93f3d1 100644
--- a/client/themes/default/components/page-toc-item.vue
+++ b/client/themes/default/components/page-toc-item.vue
@@ -1,7 +1,7 @@
 <template lang="pug">
-  div
-    template(v-if='level >= minTocLevel')
-      v-list-item(@click='click(item.anchor)', v-if='(item.children.length === 0 && tocCollapseLevel > level) || tocCollapseLevel > level',
+  .page-toc-item
+    template(v-if='level >= min')
+      v-list-item(@click='click(item.anchor)', v-if='(item.children.length === 0 && max > level) || max > level',
         :key='item.anchor', :class='isNestedLevel ? `pl-9` : `pl-6`')
         v-icon.pl-0(small, color='grey lighten-1') {{ $vuetify.rtl ? `mdi-chevron-left` : `mdi-chevron-right` }}
         v-list-item-title.pl-4(v-bind:class='titleClasses') {{item.title}}
@@ -10,11 +10,11 @@
           v-list-item.pl-0(@click='click(item.anchor)', :key='item.anchor')
             v-list-item-title(v-bind:class='titleClasses') {{item.title}}
         template(v-if='item.children.length !== 0', v-for='subItem in item.children')
-          page-toc-item(:item='subItem', :level='level + 1', :tocLevel='tocLevel', :minTocLevel='minTocLevel', :tocCollapseLevel='tocCollapseLevel')
-      template(v-if='tocCollapseLevel > level', v-for='subItem in item.children')
-        page-toc-item(:item='subItem', :level='level + 1', :tocLevel='tocLevel', :minTocLevel='minTocLevel', :tocCollapseLevel='tocCollapseLevel')
+          page-toc-item(:item='subItem', :level='level + 1', :min='min', :max='max')
+      template(v-if='max > level', v-for='subItem in item.children')
+        page-toc-item(:item='subItem', :level='level + 1', :min='min', :max='max')
     template(v-else, v-for='subItem in item.children')
-      page-toc-item(:item='subItem', :level='level + 1', :tocLevel='tocLevel', :minTocLevel='minTocLevel', :tocCollapseLevel='tocCollapseLevel')
+      page-toc-item(:item='subItem', :level='level + 1', :min='min', :max='max')
 </template>
 
 <script>
@@ -26,15 +26,11 @@ export default {
       type: Object,
       default: () => {}
     },
-    minTocLevel: {
+    min: {
       type: Number,
-      default: 0
-    },
-    tocLevel: {
-      type: Number,
-      default: 2
+      default: 1
     },
-    tocCollapseLevel: {
+    max: {
       type: Number,
       default: 2
     },
@@ -54,7 +50,7 @@ export default {
   },
   computed: {
     isNestedLevel() {
-      return this.level > this.minTocLevel
+      return this.level > this.min
     },
     titleClasses() {
       return {
@@ -75,7 +71,7 @@ export default {
 
 <style lang='scss'>
 // Hack to fix animations of multi level nesting v-list-group
-.v-list-group--sub-group.v-list-group--active .v-list-item:not(.v-list-item--active) .v-list-item__icon.v-list-group__header__prepend-icon .v-icon {
+.page-toc-item .v-list-group--sub-group.v-list-group--active .v-list-item:not(.v-list-item--active) .v-list-item__icon.v-list-group__header__prepend-icon .v-icon {
   transform: rotate(0deg)!important;
 }
 </style>
diff --git a/client/themes/default/components/page.vue b/client/themes/default/components/page.vue
index d2bbd43ec9b055422bd8c650ddc8e739900d9215..9c318c57cb51f9a7d8a628ce2c6604099f06998a 100644
--- a/client/themes/default/components/page.vue
+++ b/client/themes/default/components/page.vue
@@ -60,8 +60,13 @@
             v-card.mb-5(v-if='tocDecoded.length')
               .overline.pa-5.pb-0(:class='$vuetify.theme.dark ? `blue--text text--lighten-2` : `primary--text`') {{$t('common:page.toc')}}
               v-list.py-0(dense, nav, :class='$vuetify.theme.dark ? `darken-3-d3` : ``')
-                template(v-for='item in tocDecoded')
-                  page-toc-item(:item='item', :tocLevel='tocLevel', :minTocLevel='minTocLevel', :tocCollapseLevel='tocCollapseLevel')
+                page-toc-item(
+                  v-for='(item, idx) in tocDecoded'
+                  :key='`tocitem-` + idx'
+                  :item='item'
+                  :min='tocOptionsDecoded.min'
+                  :max='tocOptionsDecoded.max'
+                  )
             v-card.mb-5(v-if='tags.length > 0')
               .pa-5
                 .overline.teal--text.pb-2(:class='$vuetify.theme.dark ? `text--lighten-3` : ``') {{$t('common:page.tags')}}
@@ -434,21 +439,9 @@ export default {
       type: Boolean,
       default: false
     },
-    minTocLevel: {
-      type: Number,
-      default: 0
-    },
-    tocLevel: {
-      type: Number,
-      default: 2
-    },
-    tocCollapseLevel: {
-      type: Number,
-      default: 2
-    },
-    doUseTocDefault: {
-      type: Boolean,
-      default: true
+    tocOptions: {
+      type: String,
+      default: ''
     }
   },
   data() {
@@ -518,6 +511,9 @@ export default {
     tocDecoded () {
       return JSON.parse(Buffer.from(this.toc, 'base64').toString())
     },
+    tocOptionsDecoded () {
+      return JSON.parse(Buffer.from(this.tocOptions, 'base64').toString())
+    },
     hasAdminPermission: get('page/effectivePermissions@system.manage'),
     hasWritePagesPermission: get('page/effectivePermissions@pages.write'),
     hasManagePagesPermission: get('page/effectivePermissions@pages.manage'),
diff --git a/dev/containers/Dockerfile b/dev/containers/Dockerfile
index 7d37f805262ef8e324a4bfe56353f1e4ed6deb6c..34e5c0164d7d40e271eb639e68d4e32be2bddd3a 100644
--- a/dev/containers/Dockerfile
+++ b/dev/containers/Dockerfile
@@ -5,7 +5,7 @@ FROM node:14
 LABEL maintainer "requarks.io"
 
 RUN apt-get update && \
-    apt-get install -y bash curl git python make g++ nano openssh-server gnupg cmake && \
+    apt-get install -y bash curl git python make g++ nano openssh-server gnupg && \
     mkdir -p /wiki
 
 WORKDIR /wiki
diff --git a/server/app/data.yml b/server/app/data.yml
index 1e6de4ea12c955e28cd73128ef6323c628325317..3e8f10d1b6b20c4a8877cd53d456a625b4ab68ef 100644
--- a/server/app/data.yml
+++ b/server/app/data.yml
@@ -55,10 +55,9 @@ defaults:
       theme: 'default'
       iconset: 'md'
       darkMode: false
-      minTocLevel: 0
-      tocLevel: 2
-      tocCollapseLevel: 2
-      doUseTocDefault: true
+      tocDepth:
+        min: 1
+        max: 2
     auth:
       autoLogin: false
       enforce2FA: false
diff --git a/server/controllers/common.js b/server/controllers/common.js
index 31725b897f9656c79c03312a21f2b5f51a2a8a20..31e055eb0ff3a4d3a391d3b66ff10207d73224b2 100644
--- a/server/controllers/common.js
+++ b/server/controllers/common.js
@@ -178,6 +178,11 @@ router.get(['/e', '/e/*'], async (req, res, next) => {
       title: null,
       description: null,
       updatedAt: new Date().toISOString(),
+      tocOptions: {
+        min: 1,
+        max: 2,
+        useDefault: true
+      },
       extra: {
         css: '',
         js: ''
@@ -504,19 +509,12 @@ router.get('/*', async (req, res, next) => {
         if (!_.isEmpty(page.extra.js)) {
           injectCode.body = `${injectCode.body}\n${page.extra.js}`
         }
-        const doUseTocDefault = page.doUseTocDefault === true || page.doUseTocDefault === 1
-        var tocLevel
-        var tocCollapseLevel
-        var minTocLevel
-        if (doUseTocDefault) {
-          minTocLevel = WIKI.config.theming.minTocLevel
-          tocLevel = WIKI.config.theming.tocLevel
-          tocCollapseLevel = WIKI.config.theming.tocCollapseLevel
-        } else {
-          minTocLevel = page.minTocLevel || WIKI.config.theming.minTocLevel
-          tocLevel = page.tocLevel || WIKI.config.theming.tocLevel
-          tocCollapseLevel = page.tocCollapseLevel || WIKI.config.theming.tocCollapseLevel
-        }
+
+        // -> Set TOC display options
+        const tocOptions = _.get(page, 'tocOptions.useDefault', true) ? {
+          min: page.tocOptions.min,
+          max: page.tocOptions.max
+        } : WIKI.config.theming.tocDepth
 
         if (req.query.legacy || req.get('user-agent').indexOf('Trident') >= 0) {
           // -> Convert page TOC
@@ -528,10 +526,6 @@ router.get('/*', async (req, res, next) => {
           res.render('legacy/page', {
             page,
             sidebar,
-            minTocLevel,
-            tocLevel,
-            tocCollapseLevel,
-            doUseTocDefault,
             injectCode,
             isAuthenticated: req.user && req.user.id !== 2
           })
@@ -563,10 +557,7 @@ router.get('/*', async (req, res, next) => {
           res.render('page', {
             page,
             sidebar,
-            minTocLevel,
-            tocLevel,
-            tocCollapseLevel,
-            doUseTocDefault,
+            tocOptions,
             injectCode,
             comments: commentTmpl,
             effectivePermissions
diff --git a/server/db/migrations-sqlite/2.5.13.js b/server/db/migrations-sqlite/2.5.13.js
deleted file mode 100644
index 35d7f60dd75bf37590435b01834fbc8c52bb6e9a..0000000000000000000000000000000000000000
--- a/server/db/migrations-sqlite/2.5.13.js
+++ /dev/null
@@ -1,11 +0,0 @@
-exports.up = async knex => {
-  await knex.schema
-    .alterTable('pages', table => {
-      table.integer('minTocLevel').notNullable().defaultTo(0)
-      table.integer('tocLevel').notNullable().defaultTo(0)
-      table.integer('tocCollapseLevel').notNullable().defaultTo(0)
-      table.boolean('doUseTocDefault').notNullable().defaultTo(true)
-    })
-}
-
-exports.down = knex => { }
diff --git a/server/db/migrations-sqlite/2.5.284.js b/server/db/migrations-sqlite/2.5.284.js
new file mode 100644
index 0000000000000000000000000000000000000000..cd362a52e088024c74030ff038ec842061ff0ecc
--- /dev/null
+++ b/server/db/migrations-sqlite/2.5.284.js
@@ -0,0 +1,12 @@
+exports.up = async knex => {
+  await knex.schema
+    .alterTable('pages', table => {
+      table.json('tocOptions').notNullable().defaultTo(JSON.stringify({
+        min: 1,
+        max: 2,
+        useDefault: true
+      }))
+    })
+}
+
+exports.down = knex => { }
diff --git a/server/db/migrations/2.5.13.js b/server/db/migrations/2.5.13.js
deleted file mode 100644
index 35d7f60dd75bf37590435b01834fbc8c52bb6e9a..0000000000000000000000000000000000000000
--- a/server/db/migrations/2.5.13.js
+++ /dev/null
@@ -1,11 +0,0 @@
-exports.up = async knex => {
-  await knex.schema
-    .alterTable('pages', table => {
-      table.integer('minTocLevel').notNullable().defaultTo(0)
-      table.integer('tocLevel').notNullable().defaultTo(0)
-      table.integer('tocCollapseLevel').notNullable().defaultTo(0)
-      table.boolean('doUseTocDefault').notNullable().defaultTo(true)
-    })
-}
-
-exports.down = knex => { }
diff --git a/server/db/migrations/2.5.284.js b/server/db/migrations/2.5.284.js
new file mode 100644
index 0000000000000000000000000000000000000000..cd362a52e088024c74030ff038ec842061ff0ecc
--- /dev/null
+++ b/server/db/migrations/2.5.284.js
@@ -0,0 +1,12 @@
+exports.up = async knex => {
+  await knex.schema
+    .alterTable('pages', table => {
+      table.json('tocOptions').notNullable().defaultTo(JSON.stringify({
+        min: 1,
+        max: 2,
+        useDefault: true
+      }))
+    })
+}
+
+exports.down = knex => { }
diff --git a/server/graph/resolvers/theming.js b/server/graph/resolvers/theming.js
index d5384389d9427bdcf8327a467747bf3a01618fae..faebc91e4f1cdbb957d978fd5caf194a7ac656a8 100644
--- a/server/graph/resolvers/theming.js
+++ b/server/graph/resolvers/theming.js
@@ -24,9 +24,7 @@ module.exports = {
         theme: WIKI.config.theming.theme,
         iconset: WIKI.config.theming.iconset,
         darkMode: WIKI.config.theming.darkMode,
-        minTocLevel: WIKI.config.theming.minTocLevel,
-        tocLevel: WIKI.config.theming.tocLevel,
-        tocCollapseLevel: WIKI.config.theming.tocCollapseLevel,
+        tocDepth: WIKI.config.theming.tocDepth,
         injectCSS: new CleanCSS({ format: 'beautify' }).minify(WIKI.config.theming.injectCSS).styles,
         injectHead: WIKI.config.theming.injectHead,
         injectBody: WIKI.config.theming.injectBody
@@ -47,9 +45,7 @@ module.exports = {
           theme: args.theme,
           iconset: args.iconset,
           darkMode: args.darkMode,
-          minTocLevel: args.minTocLevel,
-          tocLevel: args.tocLevel,
-          tocCollapseLevel: args.tocCollapseLevel,
+          tocDepth: args.tocDepth,
           injectCSS: args.injectCSS || '',
           injectHead: args.injectHead || '',
           injectBody: args.injectBody || ''
diff --git a/server/graph/schemas/common.graphql b/server/graph/schemas/common.graphql
index 50e9cbdc64684859e2cac684417353caa81c9067..3909ddf222a047fd165e8567cd563089be16c7c3 100644
--- a/server/graph/schemas/common.graphql
+++ b/server/graph/schemas/common.graphql
@@ -21,6 +21,17 @@ input KeyValuePairInput {
   value: String!
 }
 
+# Generic Range Value
+type Range {
+  min: Int
+  max: Int
+}
+
+input RangeInput {
+  min: Int!
+  max: Int!
+}
+
 # Generic Mutation Response
 type DefaultResponse {
   responseResult: ResponseStatus
diff --git a/server/graph/schemas/page.graphql b/server/graph/schemas/page.graphql
index ee8d219e8feb19c8e64446eb3d53b66cbfe3790e..0a8561c4cd3d3897a1c6a5c45cb03ce9dec5fd81 100644
--- a/server/graph/schemas/page.graphql
+++ b/server/graph/schemas/page.graphql
@@ -93,10 +93,8 @@ type PageMutation {
     scriptJs: String
     tags: [String]!
     title: String!
-    minTocLevel: Int
-    tocLevel: Int
-    tocCollapseLevel: Int
-    doUseTocDefault: Boolean
+    tocDepth: RangeInput
+    useDefaultTocDepth: Boolean
   ): PageResponse @auth(requires: ["write:pages", "manage:pages", "manage:system"])
 
   update(
@@ -114,10 +112,8 @@ type PageMutation {
     scriptJs: String
     tags: [String]
     title: String
-    minTocLevel: Int
-    tocLevel: Int
-    tocCollapseLevel: Int
-    doUseTocDefault: Boolean
+    tocDepth: RangeInput
+    useDefaultTocDepth: Boolean
   ): PageResponse @auth(requires: ["write:pages", "manage:pages", "manage:system"])
 
   convert(
@@ -183,37 +179,35 @@ type PageMigrationResponse {
 }
 
 type Page {
-  id: Int!
-  path: String!
-  hash: String!
-  title: String!
-  description: String!
-  isPrivate: Boolean! @auth(requires: ["write:pages", "manage:system"])
-  isPublished: Boolean! @auth(requires: ["write:pages", "manage:system"])
+  id: Int
+  path: String
+  hash: String
+  title: String
+  description: String
+  isPrivate: Boolean @auth(requires: ["write:pages", "manage:system"])
+  isPublished: Boolean @auth(requires: ["write:pages", "manage:system"])
   privateNS: String @auth(requires: ["write:pages", "manage:system"])
-  publishStartDate: Date! @auth(requires: ["write:pages", "manage:system"])
-  publishEndDate: Date! @auth(requires: ["write:pages", "manage:system"])
-  tags: [PageTag]!
-  content: String! @auth(requires: ["read:source", "write:pages", "manage:system"])
+  publishStartDate: Date @auth(requires: ["write:pages", "manage:system"])
+  publishEndDate: Date @auth(requires: ["write:pages", "manage:system"])
+  tags: [PageTag]
+  content: String @auth(requires: ["read:source", "write:pages", "manage:system"])
   render: String
   toc: String
-  minTocLevel: Int!
-  tocLevel: Int!
-  tocCollapseLevel: Int!
-  doUseTocDefault: Boolean!
-  contentType: String!
-  createdAt: Date!
-  updatedAt: Date!
-  editor: String! @auth(requires: ["write:pages", "manage:system"])
-  locale: String!
+  tocDepth: Range
+  useDefaultTocDepth: Boolean
+  contentType: String
+  createdAt: Date
+  updatedAt: Date
+  editor: String @auth(requires: ["write:pages", "manage:system"])
+  locale: String
   scriptCss: String
   scriptJs: String
-  authorId: Int! @auth(requires: ["write:pages", "manage:system"])
-  authorName: String! @auth(requires: ["write:pages", "manage:system"])
-  authorEmail: String! @auth(requires: ["write:pages", "manage:system"])
-  creatorId: Int! @auth(requires: ["write:pages", "manage:system"])
-  creatorName: String! @auth(requires: ["write:pages", "manage:system"])
-  creatorEmail: String! @auth(requires: ["write:pages", "manage:system"])
+  authorId: Int @auth(requires: ["write:pages", "manage:system"])
+  authorName: String @auth(requires: ["write:pages", "manage:system"])
+  authorEmail: String @auth(requires: ["write:pages", "manage:system"])
+  creatorId: Int @auth(requires: ["write:pages", "manage:system"])
+  creatorName: String @auth(requires: ["write:pages", "manage:system"])
+  creatorEmail: String @auth(requires: ["write:pages", "manage:system"])
 }
 
 type PageTag {
diff --git a/server/graph/schemas/theming.graphql b/server/graph/schemas/theming.graphql
index aa5454ab4edede4ba9e1066e8ce9d475bda06af6..610e3fd5c232200a9081b68c2f836f8294cb8905 100644
--- a/server/graph/schemas/theming.graphql
+++ b/server/graph/schemas/theming.graphql
@@ -28,9 +28,7 @@ type ThemingMutation {
     theme: String!
     iconset: String!
     darkMode: Boolean!
-    minTocLevel: Int!
-    tocLevel: Int!
-    tocCollapseLevel: Int!
+    tocDepth: RangeInput!
     injectCSS: String
     injectHead: String
     injectBody: String
@@ -42,12 +40,10 @@ type ThemingMutation {
 # -----------------------------------------------
 
 type ThemingConfig {
-  theme: String!
-  iconset: String!
-  darkMode: Boolean!
-  minTocLevel: Int!
-  tocLevel: Int!
-  tocCollapseLevel: Int!
+  theme: String
+  iconset: String
+  darkMode: Boolean
+  tocDepth: Range
   injectCSS: String
   injectHead: String
   injectBody: String
diff --git a/server/models/pages.js b/server/models/pages.js
index 3e854972f7ff4b86d25c85107b95da4fcf4c6ebf..28dcc12f3ac0f5dfaf25810945f5484679e2cff8 100644
--- a/server/models/pages.js
+++ b/server/models/pages.js
@@ -47,10 +47,6 @@ module.exports = class Page extends Model {
         publishEndDate: {type: 'string'},
         content: {type: 'string'},
         contentType: {type: 'string'},
-        minTocLevel: {type: 'integer'},
-        tocLevel: {type: 'integer'},
-        tocCollapseLevel: {type: 'integer'},
-        doUseTocDefault: {type: 'boolean'},
         createdAt: {type: 'string'},
         updatedAt: {type: 'string'}
       }
@@ -58,7 +54,7 @@ module.exports = class Page extends Model {
   }
 
   static get jsonAttributes() {
-    return ['extra']
+    return ['extra', 'tocOptions']
   }
 
   static get relationMappings() {
@@ -164,10 +160,11 @@ module.exports = class Page extends Model {
       },
       title: 'string',
       toc: 'string',
-      minTocLevel: 'uint',
-      tocLevel: 'uint',
-      tocCollapseLevel: 'uint',
-      doUseTocDefault: 'boolean',
+      tocOptions: {
+        min: 'uint',
+        max: 'uint',
+        useDefault: 'boolean'
+      },
       updatedAt: 'string'
     })
   }
@@ -318,10 +315,11 @@ module.exports = class Page extends Model {
       publishStartDate: opts.publishStartDate || '',
       title: opts.title,
       toc: '[]',
-      minTocLevel: opts.minTocLevel || 0,
-      tocLevel: opts.tocLevel || 1,
-      tocCollapseLevel: opts.tocCollapseLevel || 0,
-      doUseTocDefault: opts.doUseTocDefault || true,
+      tocOptions: JSON.stringify({
+        min: _.get(opts, 'tocDepth.min', 1),
+        max: _.get(opts, 'tocDepth.max', 2),
+        useDefault: opts.useDefaultTocDepth !== false
+      }),
       extra: JSON.stringify({
         js: scriptJs,
         css: scriptCss
@@ -441,10 +439,11 @@ module.exports = class Page extends Model {
       publishEndDate: opts.publishEndDate || '',
       publishStartDate: opts.publishStartDate || '',
       title: opts.title,
-      minTocLevel: opts.minTocLevel || 0,
-      tocLevel: opts.tocLevel || 1,
-      tocCollapseLevel: opts.tocCollapseLevel || 0,
-      doUseTocDefault: opts.doUseTocDefault === true || opts.doUseTocDefault === 1,
+      tocOptions: JSON.stringify({
+        min: _.get(opts, 'tocDepth.min', ogPage.tocOptions.min || 1),
+        max: _.get(opts, 'tocDepth.max', ogPage.tocOptions.max || 2),
+        useDefault: _.get(opts, 'useDefaultTocDepth', ogPage.tocOptions.useDefault !== false)
+      }),
       extra: JSON.stringify({
         ...ogPage.extra,
         js: scriptJs,
@@ -802,7 +801,7 @@ module.exports = class Page extends Model {
    * @returns {Promise} Promise with no value
    */
   static async deletePage(opts) {
-    const page = await WIKI.models.pages.getPageFromDb(_.has(opts, 'id') ? opts.id : opts);
+    const page = await WIKI.models.pages.getPageFromDb(_.has(opts, 'id') ? opts.id : opts)
     if (!page) {
       throw new WIKI.Error.PageNotFound()
     }
@@ -1006,10 +1005,7 @@ module.exports = class Page extends Model {
           'pages.content',
           'pages.render',
           'pages.toc',
-          'pages.minTocLevel',
-          'pages.tocLevel',
-          'pages.tocCollapseLevel',
-          'pages.doUseTocDefault',
+          'pages.tocOptions',
           'pages.contentType',
           'pages.createdAt',
           'pages.updatedAt',
@@ -1090,10 +1086,7 @@ module.exports = class Page extends Model {
       tags: page.tags.map(t => _.pick(t, ['tag', 'title'])),
       title: page.title,
       toc: _.isString(page.toc) ? page.toc : JSON.stringify(page.toc),
-      minTocLevel: page.minTocLevel,
-      tocLevel: page.tocLevel,
-      tocCollapseLevel: page.tocCollapseLevel,
-      doUseTocDefault: page.doUseTocDefault,
+      tocOptions: page.tocOptions,
       updatedAt: page.updatedAt
     }))
   }
diff --git a/server/modules/storage/disk/common.js b/server/modules/storage/disk/common.js
index 157ab927ee8b62a9089e391b61b941f067a3a758..9ed0b9863d99f74d39709226b36047c85adfc553 100644
--- a/server/modules/storage/disk/common.js
+++ b/server/modules/storage/disk/common.js
@@ -92,10 +92,6 @@ module.exports = {
         isPublished: _.get(pageData, 'isPublished', currentPage.isPublished),
         isPrivate: false,
         content: pageData.content,
-        minTocLevel: pageData.minTocLevel,
-        tocLevel: pageData.tocLevel,
-        tocCollapseLevel: pageData.tocCollapseLevel,
-        doUseTocDefault: pageData.doUseTocDefault,
         user: user,
         skipStorage: true
       })
@@ -114,10 +110,7 @@ module.exports = {
         content: pageData.content,
         user: user,
         editor: pageEditor,
-        skipStorage: true,
-        tocLevel: pageData.tocLevel,
-        tocCollapseLevel: pageData.tocCollapseLevel,
-        doUseTocDefault: pageData.doUseTocDefault
+        skipStorage: true
       })
     }
   },
diff --git a/server/setup.js b/server/setup.js
index c56d85c03e06887f2960662f0ed5db7ad1da2383..124549a98cf2d1d2709eeb9c7a38e21c9bced39e 100644
--- a/server/setup.js
+++ b/server/setup.js
@@ -126,11 +126,11 @@ module.exports = () => {
       _.set(WIKI.config, 'theming', {
         theme: 'default',
         darkMode: false,
-        minTocLevel: 0,
-        tocLevel: 2,
-        tocCollapseLevel: 2,
-        doUseTocDefault: true,
         iconset: 'mdi',
+        tocDepth: {
+          min: 1,
+          max: 2
+        },
         injectCSS: '',
         injectHead: '',
         injectBody: ''
diff --git a/server/views/editor.pug b/server/views/editor.pug
index 47d0a1c0476d520f9a6f38847febed92e461c53f..2ea9b19f8c5576a185d6e9e845a26c438871ab30 100644
--- a/server/views/editor.pug
+++ b/server/views/editor.pug
@@ -19,10 +19,7 @@ block body
       script-css=page.extra.css
       script-js=page.extra.js
       init-mode=page.mode
-      :min-toc-level=page.minTocLevel
-      :toc-level=page.tocLevel
-      :toc-collapse-level=page.tocCollapseLevel
-      :do-use-toc-default=page.doUseTocDefault.toString()
+      toc-options=Buffer.from(JSON.stringify(page.tocOptions)).toString('base64')
       init-editor=page.editorKey
       init-content=page.content
       checkout-date=page.updatedAt
diff --git a/server/views/page.pug b/server/views/page.pug
index 1f81969afb58245e2ec86dfa0f9ad82e0226aaf4..e7414508cb8a233ee98792facec2fd6dacfffe39 100644
--- a/server/views/page.pug
+++ b/server/views/page.pug
@@ -25,14 +25,11 @@ block body
       toc=Buffer.from(page.toc).toString('base64')
       :page-id=page.id
       sidebar=Buffer.from(JSON.stringify(sidebar)).toString('base64')
+      toc-options=Buffer.from(JSON.stringify(tocOptions)).toString('base64')
       nav-mode=config.nav.mode
       comments-enabled=config.features.featurePageComments
       effective-permissions=Buffer.from(JSON.stringify(effectivePermissions)).toString('base64')
       comments-external=comments.codeTemplate
-      :min-toc-level=minTocLevel
-      :toc-level=tocLevel
-      :toc-collapse-level=tocCollapseLevel
-      :do-use-toc-default=doUseTocDefault.toString()
       )
       template(slot='contents')
         div!= page.render