206 lines
6.9 KiB
Vue
206 lines
6.9 KiB
Vue
<template>
|
|
<div class="page-brands-show d-flex">
|
|
<div class="container justify-content-center d-flex flex-column">
|
|
<template v-if="brand.ranges">
|
|
<div
|
|
v-for="(rangePair, rangePairIndex) of chunkInefficientCustom(brand.ranges, 2)"
|
|
:key="rangePairIndex"
|
|
:class="{'row justify-content-center mt-5 pt-5 mb-5 pb-5': true}"
|
|
>
|
|
<div
|
|
v-for="(range, rangeIndex) of rangePair"
|
|
:key="rangeIndex"
|
|
class="col text-center"
|
|
>
|
|
<button
|
|
:class="{
|
|
'd-inline-block btn position-relative': true,
|
|
}"
|
|
:title="t('view_range_products', {'range_name': transField(range, 'name')})"
|
|
data-bs-toggle="tooltip"
|
|
@click.stop="gotoRange(range)"
|
|
>
|
|
<div>
|
|
<img
|
|
class="img-fluid"
|
|
:src="`/data/${range.picture}`"
|
|
:alt="t('ranges_logo', {'range_name': transField(range, 'name')})"
|
|
:title="t('ranges_logo', {'range_name': transField(range, 'name')})"
|
|
>
|
|
</div>
|
|
<span
|
|
:class="{
|
|
...{
|
|
'range-title fs-2 fw-bold mt-5 d-inline-block px-5 py-3 rounded shadow text-capitalize animate__animated': true,
|
|
'text-dark': getContrastYIQ(range.color) === '#000000',
|
|
'text-light': getContrastYIQ(range.color) === '#FFFFFF',
|
|
},
|
|
...titleAnimations(rangeIndex),
|
|
...rangeFont(range.font_id)
|
|
}"
|
|
:style="{
|
|
'background-color': range.color,
|
|
'text-shadow': `0 0 0.2rem ${toRGBA(getContrastYIQ(range.color), 0.8)}`,
|
|
}"
|
|
>
|
|
{{ transField(range, 'name') }}
|
|
</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<div v-else class="row">
|
|
<div class="col">
|
|
<span>{{ t('no_ranges_available') }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import log from "electron-log";
|
|
import { defineComponent } from "vue";
|
|
import { useRoute, type RouteLocationNormalizedLoaded } from "vue-router";
|
|
import type AppState from "~/classes/AppState";
|
|
import Toast, { ToastTypeEnum } from "~/classes/Toast";
|
|
import ToolboxHelper from "~/classes/ToolboxHelper";
|
|
import { useAppStore } from "~/stores/useAppStore";
|
|
import { Tooltips } from "~/vueModules/bsTooltips";
|
|
|
|
export default defineComponent({
|
|
name: "BrandShow",
|
|
data(): {
|
|
appState: AppState;
|
|
route: RouteLocationNormalizedLoaded;
|
|
brand: TypeBrand;
|
|
animateTimeout: NodeJS.Timeout|undefined;
|
|
animateIndex: number|null;
|
|
animations: Array<string>;
|
|
tooltips: Tooltips|null;
|
|
} {
|
|
return {
|
|
appState: {} as AppState,
|
|
route: useRoute(),
|
|
brand: {} as TypeBrand,
|
|
animateTimeout: undefined,
|
|
animateIndex: null,
|
|
animations: ["heartBeat", "tada", "shakeX", "rubberBand"],
|
|
tooltips: null
|
|
};
|
|
},
|
|
beforeMount() {
|
|
this.appState = useAppStore().data;
|
|
|
|
const brand = useAppStore().activeBrand;
|
|
if(!brand) {
|
|
Toast.toast("brand", ToastTypeEnum.error, this.t("error_occured"));
|
|
log.error("No active brand found to display brands-slug");
|
|
return ;
|
|
}
|
|
this.brand = brand;
|
|
|
|
const firstRange = this.brand.ranges.at(0);
|
|
|
|
// * Goto products view directly if there is only one range
|
|
if(this.brand.ranges.length === 1 && firstRange) {
|
|
this.gotoRange(firstRange);
|
|
}
|
|
},
|
|
mounted() {
|
|
this.$nextTick(() => {this.tooltips = Tooltips.make({type:"parent", parentSelector: ".page-brands-show"});});
|
|
|
|
// * ANIMATIONS
|
|
clearTimeout(this.animateTimeout);
|
|
this.$nextTick(() => {
|
|
[...document.getElementsByClassName("range-title")].forEach(el => {
|
|
el.classList.add("animate__bounce");
|
|
});
|
|
this.animateTimeout = setTimeout(() => {
|
|
[...document.getElementsByClassName("range-title")].forEach(el => {
|
|
el.classList.remove("animate__bounce");
|
|
});
|
|
this.setRangeToAnimate();
|
|
}, ToolboxHelper.randomInteger(4000, 8000));
|
|
});
|
|
},
|
|
beforeUnmount() {
|
|
this.tooltips?.closeBootstrapTooltip();
|
|
clearTimeout(this.animateTimeout);
|
|
},
|
|
methods: {
|
|
chunkInefficientCustom(ranges: Array<TypeRange>, chunkSize: number):Array<Array<TypeRange>> {
|
|
const out: Array<Array<TypeRange>> = [];
|
|
let row: Array<TypeRange> = [];
|
|
ranges
|
|
.sort((a, b) => a.order - b.order)
|
|
.forEach((range, _i) => {
|
|
// Handle special width=2 case immediately
|
|
if (range.width === 2) {
|
|
if (row.length > 0) {
|
|
out.push(row);
|
|
row = [];
|
|
}
|
|
out.push([range]);
|
|
return;
|
|
}
|
|
|
|
// Add to current row
|
|
row.push(range);
|
|
|
|
// Push row if it reaches chunk size
|
|
if (row.length === chunkSize) {
|
|
out.push(row);
|
|
row = [];
|
|
}
|
|
});
|
|
// Push any remaining elements
|
|
if (row.length > 0) {
|
|
out.push(row);
|
|
}
|
|
return out;
|
|
},
|
|
t(text: string, params: Record<string,string> = {}, localeToUse: string|null = null): string {
|
|
return ToolboxHelper.trans(text, params, localeToUse);
|
|
},
|
|
transField(model: Typei18nModel, field: Typei18nFieldList) {
|
|
return ToolboxHelper.getTranslatableField(model, field);
|
|
},
|
|
titleAnimations(rangeIndex: number) {
|
|
const animation = this.animations.at(ToolboxHelper.randomInteger(0, this.animations.length -1));
|
|
const out: Map<string, boolean> = new Map<string, boolean>();
|
|
out.set(`animate__${animation}`, this.animateIndex === rangeIndex);
|
|
return Object.fromEntries(out.entries());
|
|
},
|
|
rangeFont(fontId: number) {
|
|
const font = useAppStore().getFont(fontId);
|
|
const out: Map<string, boolean> = new Map<string, boolean>();
|
|
if(font) {
|
|
out.set(`f-${font.font_name}`, true);
|
|
}
|
|
return Object.fromEntries(out.entries());
|
|
},
|
|
setRangeToAnimate(): void {
|
|
clearTimeout(this.animateTimeout);
|
|
this.animateIndex = Math.ceil(Math.random() * this.brand.ranges.length) -1;
|
|
this.animateTimeout = setTimeout(this.setRangeToAnimate, ToolboxHelper.randomInteger(2000, 6000));
|
|
},
|
|
getContrastYIQ(hexcolor: string): string {
|
|
return ToolboxHelper.getContrastYIQ(hexcolor);
|
|
},
|
|
toRGBA(hexcolor: string, alpha: number = 1): string {
|
|
return ToolboxHelper.toRGBA(hexcolor, alpha);
|
|
},
|
|
gotoRange(range: TypeRange) {
|
|
useAppStore().setActiveRange(range);
|
|
navigateTo(useLocaleRoute()({"name": "ranges-slug", "params": {"slug": this.transField(range, "slug")}}));
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.page-brands-show, .page-brands-show>div {
|
|
min-height: 100%;
|
|
}
|
|
</style>
|