280 lines
9.8 KiB
JavaScript
280 lines
9.8 KiB
JavaScript
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
|
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
|
const { Box, Button, EventBox, Label, Overlay, Stack } = Widget;
|
|
import { MaterialIcon } from './materialicon.js';
|
|
import { NavigationIndicator } from './cairo_navigationindicator.js';
|
|
import { setupCursorHover } from '../.widgetutils/cursorhover.js';
|
|
import { DoubleRevealer } from '../.widgethacks/advancedrevealers.js';
|
|
|
|
export const TabContainer = ({ icons, names, children, className = '', setup = () => { }, ...rest }) => {
|
|
const shownIndex = Variable(0);
|
|
let previousShownIndex = 0;
|
|
const count = Math.min(icons.length, names.length, children.length);
|
|
const tabs = Box({
|
|
homogeneous: true,
|
|
children: Array.from({ length: count }, (_, i) => Button({ // Tab button
|
|
className: 'tab-btn',
|
|
onClicked: () => shownIndex.value = i,
|
|
setup: setupCursorHover,
|
|
child: Box({
|
|
hpack: 'center',
|
|
vpack: 'center',
|
|
className: 'spacing-h-5 txt-small',
|
|
children: [
|
|
MaterialIcon(icons[i], 'norm'),
|
|
Label({
|
|
label: names[i],
|
|
})
|
|
]
|
|
})
|
|
})),
|
|
setup: (self) => self.hook(shownIndex, (self) => {
|
|
self.children[previousShownIndex].toggleClassName('tab-btn-active', false);
|
|
self.children[shownIndex.value].toggleClassName('tab-btn-active', true);
|
|
previousShownIndex = shownIndex.value;
|
|
}),
|
|
});
|
|
const tabIndicatorLine = Box({
|
|
vertical: true,
|
|
homogeneous: true,
|
|
setup: (self) => self.hook(shownIndex, (self) => {
|
|
self.children[0].css = `font-size: ${shownIndex.value}px;`;
|
|
}),
|
|
children: [NavigationIndicator({
|
|
className: 'tab-indicator',
|
|
count: count,
|
|
css: `font-size: ${shownIndex.value}px;`,
|
|
})],
|
|
});
|
|
const tabSection = Box({
|
|
homogeneous: true,
|
|
children: [EventBox({
|
|
onScrollUp: () => mainBox.prevTab(),
|
|
onScrollDown: () => mainBox.nextTab(),
|
|
child: Box({
|
|
vertical: true,
|
|
children: [
|
|
tabs,
|
|
tabIndicatorLine
|
|
]
|
|
})
|
|
})]
|
|
});
|
|
const contentStack = Stack({
|
|
transition: 'slide_left_right',
|
|
children: children.reduce((acc, currentValue, index) => {
|
|
acc[index] = currentValue;
|
|
return acc;
|
|
}, {}),
|
|
setup: (self) => self.hook(shownIndex, (self) => {
|
|
self.shown = `${shownIndex.value}`;
|
|
}),
|
|
});
|
|
const mainBox = Box({
|
|
attribute: {
|
|
children: children,
|
|
shown: shownIndex,
|
|
names: names,
|
|
},
|
|
vertical: true,
|
|
className: `spacing-v-5 ${className}`,
|
|
setup: (self) => {
|
|
self.pack_start(tabSection, false, false, 0);
|
|
self.pack_end(contentStack, true, true, 0);
|
|
setup(self);
|
|
},
|
|
...rest,
|
|
});
|
|
mainBox.nextTab = () => shownIndex.value = Math.min(shownIndex.value + 1, count - 1);
|
|
mainBox.prevTab = () => shownIndex.value = Math.max(shownIndex.value - 1, 0);
|
|
mainBox.cycleTab = () => shownIndex.value = (shownIndex.value + 1) % count;
|
|
|
|
return mainBox;
|
|
}
|
|
|
|
|
|
export const IconTabContainer = ({
|
|
iconWidgets, names, children, className = '',
|
|
setup = () => { }, onChange = () => { },
|
|
tabsHpack = 'center', tabSwitcherClassName = '',
|
|
...rest
|
|
}) => {
|
|
const shownIndex = Variable(0);
|
|
let previousShownIndex = 0;
|
|
const count = Math.min(iconWidgets.length, names.length, children.length);
|
|
const tabs = Box({
|
|
hpack: tabsHpack,
|
|
className: `spacing-h-5 ${tabSwitcherClassName}`,
|
|
children: iconWidgets.map((icon, i) => Button({
|
|
className: 'tab-icon',
|
|
tooltipText: names[i],
|
|
child: icon,
|
|
setup: setupCursorHover,
|
|
onClicked: () => shownIndex.value = i,
|
|
})),
|
|
setup: (self) => self.hook(shownIndex, (self) => {
|
|
self.children[previousShownIndex].toggleClassName('tab-icon-active', false);
|
|
self.children[shownIndex.value].toggleClassName('tab-icon-active', true);
|
|
previousShownIndex = shownIndex.value;
|
|
}),
|
|
});
|
|
const tabSection = Box({
|
|
homogeneous: true,
|
|
children: [EventBox({
|
|
onScrollUp: () => mainBox.prevTab(),
|
|
onScrollDown: () => mainBox.nextTab(),
|
|
child: Box({
|
|
vertical: true,
|
|
hexpand: true,
|
|
children: [
|
|
tabs,
|
|
]
|
|
})
|
|
})]
|
|
});
|
|
const contentStack = Stack({
|
|
transition: 'slide_left_right',
|
|
children: children.reduce((acc, currentValue, index) => {
|
|
acc[index] = currentValue;
|
|
return acc;
|
|
}, {}),
|
|
setup: (self) => self.hook(shownIndex, (self) => {
|
|
self.shown = `${shownIndex.value}`;
|
|
}),
|
|
});
|
|
const mainBox = Box({
|
|
attribute: {
|
|
children: children,
|
|
shown: shownIndex,
|
|
names: names,
|
|
},
|
|
vertical: true,
|
|
className: `spacing-v-5 ${className}`,
|
|
setup: (self) => {
|
|
self.pack_start(tabSection, false, false, 0);
|
|
self.pack_end(contentStack, true, true, 0);
|
|
setup(self);
|
|
self.hook(shownIndex, (self) => onChange(self, shownIndex.value));
|
|
},
|
|
...rest,
|
|
});
|
|
mainBox.nextTab = () => shownIndex.value = Math.min(shownIndex.value + 1, count - 1);
|
|
mainBox.prevTab = () => shownIndex.value = Math.max(shownIndex.value - 1, 0);
|
|
mainBox.cycleTab = () => shownIndex.value = (shownIndex.value + 1) % count;
|
|
mainBox.shown = shownIndex;
|
|
|
|
return mainBox;
|
|
}
|
|
|
|
export const ExpandingIconTabContainer = ({
|
|
icons, names, children, className = '',
|
|
setup = () => { }, onChange = () => { },
|
|
tabsHpack = 'center', tabSwitcherClassName = '',
|
|
transitionDuration = userOptions.animations.durationLarge,
|
|
...rest
|
|
}) => {
|
|
const shownIndex = Variable(0);
|
|
let previousShownIndex = 0;
|
|
const count = Math.min(icons.length, names.length, children.length);
|
|
const tabs = Box({
|
|
hpack: tabsHpack,
|
|
className: `spacing-h-5 ${tabSwitcherClassName}`,
|
|
children: icons.map((icon, i) => {
|
|
const tabIcon = MaterialIcon(icon, 'norm', { hexpand: true });
|
|
const tabName = DoubleRevealer({
|
|
transition1: 'slide_right',
|
|
transition2: 'crossfade',
|
|
duration1: 0,
|
|
duration2: 0,
|
|
// duration1: userOptions.animations.durationSmall,
|
|
// duration2: userOptions.animations.durationSmall,
|
|
child: Label({
|
|
className: 'margin-left-5 txt-small',
|
|
label: names[i],
|
|
}),
|
|
revealChild: i === shownIndex.value,
|
|
})
|
|
const button = Button({
|
|
className: 'tab-icon-expandable',
|
|
tooltipText: names[i],
|
|
child: Box({
|
|
homogeneous: true,
|
|
children: [Box({
|
|
hpack: 'center',
|
|
children: [
|
|
tabIcon,
|
|
tabName,
|
|
]
|
|
})],
|
|
}),
|
|
setup: setupCursorHover,
|
|
onClicked: () => shownIndex.value = i,
|
|
});
|
|
button.toggleFocus = (value) => {
|
|
tabIcon.hexpand = !value;
|
|
button.toggleClassName('tab-icon-expandable-active', value);
|
|
tabName.toggleRevealChild(value);
|
|
}
|
|
return button;
|
|
}),
|
|
setup: (self) => self.hook(shownIndex, (self) => {
|
|
self.children[previousShownIndex].toggleFocus(false);
|
|
self.children[shownIndex.value].toggleFocus(true);
|
|
previousShownIndex = shownIndex.value;
|
|
}),
|
|
});
|
|
const tabSection = Box({
|
|
homogeneous: true,
|
|
children: [EventBox({
|
|
onScrollUp: () => mainBox.prevTab(),
|
|
onScrollDown: () => mainBox.nextTab(),
|
|
child: Box({
|
|
vertical: true,
|
|
hexpand: true,
|
|
children: [
|
|
tabs,
|
|
]
|
|
})
|
|
})]
|
|
});
|
|
const contentStack = Stack({
|
|
transition: 'slide_left_right',
|
|
transitionDuration: transitionDuration,
|
|
children: children.reduce((acc, currentValue, index) => {
|
|
acc[index] = currentValue;
|
|
return acc;
|
|
}, {}),
|
|
setup: (self) => self.hook(shownIndex, (self) => {
|
|
self.shown = `${shownIndex.value}`;
|
|
}),
|
|
});
|
|
const mainBox = Box({
|
|
attribute: {
|
|
children: children,
|
|
shown: shownIndex,
|
|
names: names,
|
|
},
|
|
vertical: true,
|
|
className: `spacing-v-5 ${className}`,
|
|
setup: (self) => {
|
|
self.pack_start(tabSection, false, false, 0);
|
|
self.pack_end(contentStack, true, true, 0);
|
|
setup(self);
|
|
self.hook(shownIndex, (self) => onChange(self, shownIndex.value));
|
|
},
|
|
...rest,
|
|
});
|
|
mainBox.nextTab = () => shownIndex.value = Math.min(shownIndex.value + 1, count - 1);
|
|
mainBox.prevTab = () => shownIndex.value = Math.max(shownIndex.value - 1, 0);
|
|
mainBox.cycleTab = () => shownIndex.value = (shownIndex.value + 1) % count;
|
|
mainBox.focusName = (name) => {
|
|
const focusIndex = names.indexOf(name);
|
|
if (focusIndex !== -1) {
|
|
shownIndex.value = focusIndex;
|
|
}
|
|
}
|
|
mainBox.shown = shownIndex;
|
|
|
|
return mainBox;
|
|
}
|