working prototype

This commit is contained in:
Henry Jameson 2025-11-24 20:05:38 +02:00
commit 7c57be22e4
15 changed files with 266 additions and 215 deletions

View file

@ -37,19 +37,13 @@ export default {
required: false,
type: Boolean,
default: null
},
hideHeader: {
required: false,
type: Boolean,
default: null
}
},
data () {
return {
active: findFirstUsable(this.slots()),
resizeHandler: null,
navMode: false,
navSide: 'content'
navSide: 'tabs'
}
},
computed: {
@ -71,16 +65,6 @@ export default {
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 () {
const currentSlot = this.slots()[this.active]
if (!currentSlot.props) {
@ -92,7 +76,6 @@ export default {
return (e) => {
e.preventDefault()
this.setTab(index)
this.onResize()
}
},
setTab (index) {
@ -105,30 +88,6 @@ export default {
changeNavSide (side) {
if (this.navSide !== side) {
this.navSide = side
this.onResize()
}
},
getNavMode () {
return this.navMode
},
onResize () {
// All other tabs are hidden and their width is most likely 0
const activeTab = this.$refs.root.querySelector('.tab-content-wrapper.-active')
const tabContent = activeTab.querySelector('.tab-content')
const tabContentWidth = tabContent.clientWidth
const rootWidth = this.$refs.root.clientWidth
const navWidth = this.$refs.nav.clientWidth
const contentsWidth = rootWidth - navWidth
// if contents takes more space than its container
if (contentsWidth < tabContentWidth) {
this.hideNav()
// If we (theoretically) have enough space to fit it in
} else if (contentsWidth - navWidth >= tabContentWidth){
// First expand the inner layer, then outer
// if use same logic as above order will be reversed
this.showNav()
}
},
// DO NOT put it to computed, it doesn't work (caching?)
@ -145,7 +104,7 @@ export default {
const props = slot.props
if (!props) return
const classesTab = ['vertical-tab', 'menu-item']
if (this.activeIndex === index) {
if (this.activeIndex === index && useInterfaceStore().layoutType !== 'mobile') {
classesTab.push('-active')
}
return (
@ -183,14 +142,21 @@ export default {
: ''
const headerClasses = ['tab-content-label']
if (this.hideHeader === true) {
headerClasses.push('-hidden')
}
const header = (
<h1 class={headerClasses}>
<button type="button" onClick={() => this.changeNavSide('tabs')}>LOL</button>
<h2 class={headerClasses}>
<button
type="button"
onClick={() => this.changeNavSide('tabs')}
class="button-unstyled"
>
<FAIcon
size="lg"
class="back-button-icon"
icon="chevron-left"
/>
</button>
{props.label}
</h1>
</h2>
)
return (
@ -204,13 +170,14 @@ export default {
})
const rootClasses = ['vertical-tab-switcher']
if (this.navMode) {
rootClasses.push('-nav-mode')
if (this.navSide === 'content') {
rootClasses.push('-nav-content')
} else {
rootClasses.push('-nav-tabs')
}
if (useInterfaceStore().layoutType === 'mobile') {
rootClasses.push('-mobile')
}
if (this.navSide === 'tabs') {
rootClasses.push('-nav-tabs')
} else {
rootClasses.push('-nav-contents')
}
return (

View file

@ -1,16 +1,19 @@
.vertical-tab-switcher {
display: flex;
flex-direction: row;
container-type: inline-size;
> .tabs {
flex: 0 0 auto;
flex: 0 0 15em;
flex-direction: column;
overflow: hidden auto;
white-space: nowrap;
text-overflow: ellipsis;
width: 15em;
min-width: 15em;
border-right: 1px solid;
border-right-color: var(--border);
box-sizing: border-box;
> .menu-item {
padding: 0.5em 1em;
@ -23,18 +26,13 @@
}
> .contents {
flex: 1 1 auto;
overflow-x: hidden;
.tab-content-label {
display: none
}
flex: 1 0 35em;
.tab-content {
align-self: center;
&:not(.-full-width) {
width: 30em;
max-width: 40em;
}
&.-full-width {
@ -42,16 +40,23 @@
}
}
.tab-content-label {
box-sizing: border-box;
margin: 0;
border-bottom: 1px solid var(--border);
display: none;
button {
box-sizing: border-box;
padding: 0.5em;
}
}
.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);
}
overflow-y: auto;
height: 100%;
&.-hidden {
display: none;
@ -69,38 +74,104 @@
}
}
&.-nav-mode {
&.-nav-tabs {
> .tabs {
width: 100%;
}
> .nav-content {
width: 0%;
&.-mobile {
> .contents {
.tab-content-label {
display: block
}
}
&.-nav-content {
&.-nav-contents {
> .contents {
> .tab-content-wrapper {
> .tab-content-label {
display: block;
display: block;
flex-grow: 1;
}
&.-hidden {
display: none;
}
> .tabs {
display: none;
flex-grow: 0;
flex-shrink: 1;
}
}
&.-nav-tabs {
> .tabs {
display: block;
flex-grow: 1;
}
> .contents {
display: none;
flex-grow: 0;
flex-shrink: 1;
}
}
}
@supports (container-type: inline-size) {
&,
&.-mobile {
&.-nav-contents,
&.-nav-tabs {
/* I THINK it's a false positive and eslint doesn't understand the @-rule */
/* stylelint-disable no-descending-specificity */
> .contents {
display: block;
flex-grow: 1;
}
> .tabs {
display: block;
flex-grow: 0;
}
/* stylelint-enable no-descending-specificity */
}
}
@container (width < 50em) {
> .contents {
.tab-content-label {
display: block
}
}
&.-mobile {
> .contents {
.tab-content-label {
display: block
}
}
}
> .tabs {
position: absolute;
pointer-events: none;
opacity: 0;
}
&,
&.-mobile {
&.-nav-contents {
> .contents {
display: block;
flex-grow: 1;
}
> .nav-content {
width: 100%;
> .tabs {
display: none;
flex-grow: 0;
flex-shrink: 1;
}
}
&.-nav-tabs {
/* stylelint-disable no-descending-specificity */
> .tabs {
display: block;
flex-grow: 1;
}
> .contents {
display: none;
flex-grow: 0;
flex-shrink: 1;
}
/* stylelint-enable no-descending-specificity */
}
}
}
}