after 9000 hours it finally works
This commit is contained in:
parent
5958c32acf
commit
e6f025bf6e
7 changed files with 131 additions and 49 deletions
|
|
@ -88,6 +88,12 @@ const SettingsModalContent = {
|
||||||
// Clear the state of target tab, so that next time settings is opened
|
// Clear the state of target tab, so that next time settings is opened
|
||||||
// it doesn't force it.
|
// it doesn't force it.
|
||||||
useInterfaceStore().clearSettingsModalTargetTab()
|
useInterfaceStore().clearSettingsModalTargetTab()
|
||||||
|
},
|
||||||
|
nestedTooBig () {
|
||||||
|
this.$refs.tabSwitcher.showNav()
|
||||||
|
},
|
||||||
|
nestedTooSmall () {
|
||||||
|
this.$refs.tabSwitcher.hideNav()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,33 @@
|
||||||
<vertical-tab-switcher
|
<vertical-tab-switcher
|
||||||
ref="tabSwitcher"
|
ref="tabSwitcher"
|
||||||
class="settings_tab-switcher"
|
class="settings_tab-switcher"
|
||||||
:side-tab-bar="true"
|
|
||||||
:scrollable-tabs="true"
|
:scrollable-tabs="true"
|
||||||
:body-scroll-lock="bodyLock"
|
:body-scroll-lock="bodyLock"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
:full-width="true"
|
||||||
:label="$t('settings.general')"
|
:label="$t('settings.general')"
|
||||||
icon="wrench"
|
icon="wrench"
|
||||||
data-tab-name="general"
|
data-tab-name="general"
|
||||||
>
|
>
|
||||||
<GeneralTab />
|
<GeneralTab
|
||||||
|
class="inner-tab -middle"
|
||||||
|
@too-small="() => nestedTooSmall()"
|
||||||
|
@too-big="() => nestedTooBig()"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
:full-width="true"
|
||||||
:label="$t('settings.appearance')"
|
:label="$t('settings.appearance')"
|
||||||
icon="window-restore"
|
icon="window-restore"
|
||||||
data-tab-name="appearance"
|
data-tab-name="appearance"
|
||||||
:delay-render="true"
|
:delay-render="true"
|
||||||
>
|
>
|
||||||
<AppearanceTab />
|
<AppearanceTab
|
||||||
|
class="inner-tab -middle"
|
||||||
|
@too-small="() => nestedTooSmall()"
|
||||||
|
@too-big="() => nestedTooBig()"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="expertLevel > 0"
|
v-if="expertLevel > 0"
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
ref="tabSwitcher"
|
ref="tabSwitcher"
|
||||||
:side-tab-bar="true"
|
:side-tab-bar="true"
|
||||||
:scrollable-tabs="true"
|
:scrollable-tabs="true"
|
||||||
|
@too-small="() => console.log('small') || $emit('tooSmall')"
|
||||||
|
@too-big="() => $emit('tooBig')"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
:label="$t('settings.interface')"
|
:label="$t('settings.interface')"
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
:label="$t('settings.general')"
|
:label="$t('settings.general')"
|
||||||
ref="tabSwitcher"
|
ref="tabSwitcher"
|
||||||
class="settings_tab-switcher"
|
class="settings_tab-switcher"
|
||||||
|
@too-small="() => $emit('tooSmall')"
|
||||||
|
@too-big="() => $emit('tooBig')"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
:label="$t('settings.behavior')"
|
:label="$t('settings.behavior')"
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,10 @@ export default {
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="tab-switcher top-tabs">
|
<div
|
||||||
|
class="tab-switcher top-tabs"
|
||||||
|
ref="root"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
class="tabs"
|
class="tabs"
|
||||||
role="tablist"
|
role="tablist"
|
||||||
|
|
@ -170,6 +173,7 @@ export default {
|
||||||
role="tabpanel"
|
role="tabpanel"
|
||||||
class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')}
|
class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')}
|
||||||
v-body-scroll-lock={this.bodyScrollLock}
|
v-body-scroll-lock={this.bodyScrollLock}
|
||||||
|
ref="content"
|
||||||
>
|
>
|
||||||
{contents}
|
{contents}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,12 @@ export default {
|
||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
emits: ['tooBig', 'tooSmall'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
active: findFirstUsable(this.slots()),
|
active: findFirstUsable(this.slots()),
|
||||||
resizeHandler: null
|
resizeHandler: null,
|
||||||
|
navMode: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -59,6 +61,16 @@ export default {
|
||||||
mobileLayout: store => store.layoutType === 'mobile'
|
mobileLayout: store => store.layoutType === 'mobile'
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
created () {
|
||||||
|
this.resizeHandler = throttle(this.onResize, 200)
|
||||||
|
window.addEventListener('resize', this.resizeHandler)
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.resizeHandler()
|
||||||
|
},
|
||||||
|
unmounted () {
|
||||||
|
window.removeEventListener('resize', this.resizeHandler)
|
||||||
|
},
|
||||||
beforeUpdate () {
|
beforeUpdate () {
|
||||||
const currentSlot = this.slots()[this.active]
|
const currentSlot = this.slots()[this.active]
|
||||||
if (!currentSlot.props) {
|
if (!currentSlot.props) {
|
||||||
|
|
@ -70,7 +82,20 @@ export default {
|
||||||
return (e) => {
|
return (e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
this.setTab(index)
|
this.setTab(index)
|
||||||
console.log(index)
|
}
|
||||||
|
},
|
||||||
|
onResize (index) {
|
||||||
|
const tabContent = this.$refs.contents?.querySelector('.tab-content-wrapper.-active .tab-content')
|
||||||
|
const tabContentWidth = tabContent.clientWidth
|
||||||
|
const rootWidth = this.$refs.root?.clientWidth
|
||||||
|
const navWidth = this.$refs.nav?.clientWidth
|
||||||
|
const contentsWidth = this.$refs.contents?.clientWidth
|
||||||
|
|
||||||
|
|
||||||
|
if (contentsWidth < tabContentWidth) {
|
||||||
|
this.$emit('tooSmall')
|
||||||
|
} else if (contentsWidth - navWidth >= tabContentWidth){
|
||||||
|
this.$emit('tooBig')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// DO NOT put it to computed, it doesn't work (caching?)
|
// DO NOT put it to computed, it doesn't work (caching?)
|
||||||
|
|
@ -85,7 +110,12 @@ export default {
|
||||||
this.onSwitch.call(null, this.slots()[index].key)
|
this.onSwitch.call(null, this.slots()[index].key)
|
||||||
}
|
}
|
||||||
this.active = index
|
this.active = index
|
||||||
this.$refs.contents.scrollTop = 0
|
},
|
||||||
|
showNav () {
|
||||||
|
this.navMode = false
|
||||||
|
},
|
||||||
|
hideNav () {
|
||||||
|
this.navMode = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render () {
|
render () {
|
||||||
|
|
@ -93,7 +123,7 @@ export default {
|
||||||
.map((slot, index) => {
|
.map((slot, index) => {
|
||||||
const props = slot.props
|
const props = slot.props
|
||||||
if (!props) return
|
if (!props) return
|
||||||
const classesTab = ['vertical-tab menu-item']
|
const classesTab = ['vertical-tab', 'menu-item']
|
||||||
if (this.activeIndex === index) {
|
if (this.activeIndex === index) {
|
||||||
classesTab.push('-active')
|
classesTab.push('-active')
|
||||||
}
|
}
|
||||||
|
|
@ -104,6 +134,7 @@ export default {
|
||||||
class={classesTab.join(' ')}
|
class={classesTab.join(' ')}
|
||||||
type="button"
|
type="button"
|
||||||
role="tab"
|
role="tab"
|
||||||
|
title={props.label}
|
||||||
>
|
>
|
||||||
{!props.icon ? '' : (<FAIcon class="tab-icon" size="1x" fixed-width icon={props.icon}/>)}
|
{!props.icon ? '' : (<FAIcon class="tab-icon" size="1x" fixed-width icon={props.icon}/>)}
|
||||||
<span class="text">
|
<span class="text">
|
||||||
|
|
@ -117,9 +148,9 @@ export default {
|
||||||
const props = slot.props
|
const props = slot.props
|
||||||
if (!props) return
|
if (!props) return
|
||||||
const active = this.activeIndex === index
|
const active = this.activeIndex === index
|
||||||
const classes = [ active ? 'active' : 'hidden' ]
|
const classes = ['tab-content-wrapper', active ? '-active' : '-hidden' ]
|
||||||
if (props.fullHeight) {
|
if (props.fullHeight) {
|
||||||
classes.push('full-height')
|
classes.push('-full-height')
|
||||||
}
|
}
|
||||||
let delayRender = slot.props['delay-render']
|
let delayRender = slot.props['delay-render']
|
||||||
if (delayRender && active) {
|
if (delayRender && active) {
|
||||||
|
|
@ -137,17 +168,25 @@ export default {
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref="contents" class={classes}>
|
<div class={classes} >
|
||||||
{header}
|
{header}
|
||||||
|
<div class={ ['tab-content', props['full-width'] ? '-full-width' : null].join(' ') } >
|
||||||
{renderSlot}
|
{renderSlot}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const rootClasses = ['vertical-tab-switcher']
|
||||||
|
if (this.navMode) {
|
||||||
|
rootClasses.push('-nav-mode')
|
||||||
|
rootClasses.push('-nav-content')
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref="root" class="vertical-tab-switcher">
|
<div ref="root" class={ rootClasses.join(' ') }>
|
||||||
<div
|
<div
|
||||||
class="tabs -navigation-mode -tabs"
|
class="tabs"
|
||||||
role="tablist"
|
role="tablist"
|
||||||
ref="nav"
|
ref="nav"
|
||||||
>
|
>
|
||||||
|
|
@ -157,6 +196,7 @@ export default {
|
||||||
role="tabpanel"
|
role="tabpanel"
|
||||||
class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')}
|
class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')}
|
||||||
v-body-scroll-lock={this.bodyScrollLock}
|
v-body-scroll-lock={this.bodyScrollLock}
|
||||||
|
ref="contents"
|
||||||
>
|
>
|
||||||
{contents}
|
{contents}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,13 @@
|
||||||
|
|
||||||
> .tabs {
|
> .tabs {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
overflow: hidden auto;
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
overflow: hidden auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 15em;
|
||||||
border-right: 1px solid;
|
border-right: 1px solid;
|
||||||
border-right-color: var(--border);
|
border-right-color: var(--border);
|
||||||
min-width: 10em;
|
|
||||||
|
|
||||||
> .menu-item {
|
> .menu-item {
|
||||||
padding: 0.5em 1em;
|
padding: 0.5em 1em;
|
||||||
|
|
@ -21,13 +23,37 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
> .contents {
|
> .contents {
|
||||||
flex: 1 0 auto;
|
flex: 1 1 auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
|
||||||
.hidden {
|
.tab-content {
|
||||||
|
align-self: center;
|
||||||
|
|
||||||
|
&:not(.-full-width) {
|
||||||
|
width: 30em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.-full-width {
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.tab-content-label {
|
||||||
|
font-size: 1.5em;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
margin: 0;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.-hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.full-height:not(.hidden) {
|
&.-full-height:not(.-hidden) {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -36,37 +62,30 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-content-label {
|
|
||||||
font-size: 1.5em;
|
|
||||||
padding: 0.5em 1em;
|
|
||||||
margin: 0;
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .tabs,
|
&.-nav-mode {
|
||||||
> .content {
|
&.-nav-tabs {
|
||||||
transition: width 2s ease-in;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.-tabs {
|
|
||||||
> .tabs {
|
> .tabs {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .content {
|
> .nav-content {
|
||||||
width: 0%;
|
width: 0%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.-content {
|
&.-nav-content {
|
||||||
> .tabs {
|
> .tabs {
|
||||||
width: 0%;
|
position: absolute;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .content {
|
> .nav-content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue