fix: 🎨 update layout for multiple brands and single brand

This commit is contained in:
Alexis Gousseau 2025-07-09 11:30:28 +02:00
parent 889ead5101
commit ce5e29cbbd
No known key found for this signature in database
GPG key ID: 4A614CB3DBBA2406
8 changed files with 101 additions and 508 deletions

21
app.vue
View file

@ -86,6 +86,7 @@ export default defineComponent({
this.loading = false;
this.setTimeout();
dataJson.fonts.forEach(font => this.injectFontFace(font.font_name, font.font));
this.redirectIfOneBrand(dataJson.items);
});
},
mounted() {
@ -103,6 +104,9 @@ export default defineComponent({
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);
},
injectFontFace(fontName: string, fontPath: string|null) {
const newStyle = document.createElement("style");
if(fontPath) {
@ -113,7 +117,18 @@ export default defineComponent({
}
document.head.appendChild(newStyle);
},
/** Prolong le timer pour revenir au home screen */
/** Redirect to ranges.index if there is only one brand. */
redirectIfOneBrand(brands: Array<TypeBrand>): void {
if (brands.length === 1) {
useAppStore().setActiveBrand(brands[0]);
this.activeBrand = brands[0];
navigateTo(useLocaleRoute()({"name": "brands-slug", "params": {"slug": this.transField(brands[0], "slug")}}));
} else {
useAppStore().setActiveBrand(null);
this.activeBrand = null;
}
},
/** Prolong le timer pour revenir au home screen. */
setTimeout(): void {
if(this.timeout) {
clearTimeout(this.timeout);
@ -121,7 +136,9 @@ export default defineComponent({
this.$nextTick(() => {
this.timeout = setTimeout(() => {
useAppStore().setActiveRange(null);
useAppStore().setActiveBrand(null);
window.ipcRendererObject.getJsonData().then((dataJson) => {
this.redirectIfOneBrand(dataJson.items);
});
navigateTo(useLocaleRoute()({"name": "index"}));
}, useAppStore().getSettings().home_timeout * 1000);
});

View file

@ -170,7 +170,6 @@ export default defineComponent({
return ToolboxHelper.getContrastYIQ(hexcolor);
},
gotoBrand(brand: TypeBrand) {
useAppStore().setActiveBrand(null);
useAppStore().setActiveRange(null);
useAppStore().setActiveBrand(brand);
navigateTo(useLocaleRoute()({"name": "brands-slug", "params": {"slug": this.transField(brand, "slug")}}));

View file

@ -1,289 +0,0 @@
<template>
<nav
id="top-navbar"
class="navbar navbar-expand-lg position-relative p-0"
:style="`background-color: ${activeRange && brandWithMultipleRanges ? activeRange.color : activeBrand?.color} !important`"
>
<div class="container-fluid">
<!-- UNE MARQUE EST SELECTIONNEE -->
<div
v-if="activeBrand"
:class="{
'd-flex flex-row flex-grow-1 justify-content-center align-items-center': true,
'mx-auto': !activeRange,
}"
>
<NuxtLinkLocale
:to="`/brands/${transField(activeBrand, 'slug')}`"
:class="{
'd-inline-block py-3 px-2 text-center': true,
'flex-grow-1': !activeRange
}"
data-bs-toggle="tooltip"
:title="t('view_brand_ranges', {'brand_name': transField(activeBrand, 'name')})"
>
<img
class="img-fluid main-logo"
:src="`/data/${activeBrand.picture}`"
:alt="`Marque ${transField(activeBrand, 'name')}`"
:title="t('brands_logo', {'brand_name': transField(activeBrand, 'name')})"
data-bs-toggle="tooltip"
>
</NuxtLinkLocale>
<div v-if="activeRange && brandWithMultipleRanges" class="flex-grow-1 text-center">
<span
:class="{...{
'title': true,
'ps-md-5 d-inline-block px-5 py-3 rounded text-capitalize': true,
'text-dark': getContrastYIQ(activeRange.color) === '#000000',
'text-light': getContrastYIQ(activeRange.color) === '#FFFFFF',
}, ...rangeFont(activeRange.font_id)}"
:style="{
'text-shadow': `0 0 0.2rem ${toRGBA(getContrastYIQ(activeRange.color), 0.8)}`
}"
>
{{ transField(activeRange, 'name') }}
</span>
</div>
</div>
<!-- HOME (PAS DE MARQUE) -->
<div v-else class="row text-bg-light">
<div class="col-12 g-0 pb-5">
<img
src="assets/pictures/layout/top-hr.png"
alt="Top bar"
class="img-fluid d-block"
>
</div>
<div class="col-12 mx-auto text-center mb-3 mt-3 pb-5">
<div class="d-inline-block bg-white p-4 rounded">
<img :src="`/data/${settings.logo}`" alt="Logo" class="img-fluid main-logo d-inline-block">
</div>
</div>
</div>
<button
class="navbar-toggler"
data-bs-toggle="collapse"
data-bs-target="#navbar-menu"
type="button"
aria-controls="navbar-menu"
aria-expanded="false"
:aria-label="t('show_hide_languages')"
>
<span class="navbar-toggler-icon" />
</button>
<div id="navbar-menu" class="lang-bar navbar-collapse collapse flex-grow-0">
<div class="btn-group z-1">
<button
v-for="(localeObject,localeIndex) of locales"
:key="localeIndex"
:class="{
'btn ms-3 px-4 mx-0 shadow fw-bold': true,
'btn-white bg-white': locale !== localeObject.iso,
'btn-secondary': locale === localeObject.iso,
}"
:title="localeObject.label"
data-bs-toggle="tooltip"
@click.prevent="switchLocale(localeObject)"
>
<span class="text-uppercase fs-5">{{ localeObject.flag }}</span>
<!-- <span :class="`fi fi-${localeObject.flag}`" /> -->
</button>
</div>
</div>
</div>
</nav>
</template>
<script lang="ts">
import log from "electron-log";
import { defineComponent } from "vue";
import type { RouteLocationNormalizedLoaded } from "vue-router";
import ToolboxHelper from "~/classes/ToolboxHelper";
import { useAppStore } from "~/stores/useAppStore";
import { Tooltips } from "~/vueModules/bsTooltips";
type LocaleParams = {
iso: string,
flag: string,
label: string,
};
export default defineComponent({
name: "AppHeader",
props: {
activeBrand: {
type: Object as PropType<TypeBrand|null>,
required: false,
default: null
},
activeRange: {
type: Object as PropType<TypeRange|null>,
required: false,
default: null
},
},
data(): {
versions: typeof window.versions;
settings: TypeSettings;
locales: Array<LocaleParams>,
locale: string;
route: RouteLocationNormalizedLoaded;
tooltips: Tooltips|null;
} {
return {
versions: window.versions,
settings: {} as TypeSettings,
locales: [],
locale: "",
route: useRoute(),
tooltips: null
};
},
computed: {
brandWithMultipleRanges(): boolean {
if(!this.activeBrand) {
return false;
}
return this.activeBrand.ranges.length > 1;
}
},
watch: {
$route(to: RouteLocationNormalizedLoaded) {
log.debug(`Swithing to route ${String(to.name)}`);
if(to.name?.toString().startsWith("index")) {
// * Reset active Brand on main page
useAppStore().setActiveBrand(null);
}
const { locale } = useAppStore().getI18n();
this.locale = locale;
},
},
beforeMount() {
this.settings = useAppStore().data.settings();
const { locale, availableLocales } = useI18n({ useScope: "global"});
this.locale = locale.value;
let localeSortArr = [] as Array<string>;
window.ipcRendererObject.getJsonData().then((dataJson) => {
localeSortArr = dataJson.settings.locales;
});
this.locales = availableLocales.sort((LocA, LocB) => localeSortArr.indexOf(LocA) - localeSortArr.indexOf(LocB)).map(localeStr => {
return {
iso: localeStr,
flag: this.t("_flag", {}, localeStr),
label: this.t("_lang", {}, localeStr),
};
});
},
mounted() {
this.$nextTick(() => {this.tooltips = Tooltips.make({type:"parent", parentSelector: "#top-navbar"});});
},
beforeUnmount() {
this.tooltips?.closeBootstrapTooltip();
},
methods: {
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);
},
switchLocale(localeToSwitch:LocaleParams) {
const switchLocalePath = useSwitchLocalePath();
// Toast.toast(localeToSwitch.label, ToastTypeEnum.default);
useAppStore().switchLocale(localeToSwitch.iso);
navigateTo(switchLocalePath(localeToSwitch.iso));
},
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());
},
getContrastYIQ(hexcolor: string): string {
return ToolboxHelper.getContrastYIQ(hexcolor);
},
toRGBA(hexcolor: string, alpha: number = 1): string {
return ToolboxHelper.toRGBA(hexcolor, alpha);
},
}
});
</script>
<style lang="postcss">
@import "flag-icons/sass/flag-icons.scss";
</style>
<style lang="scss" scoped>
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/vendor/rfs";
#top-navbar {
.title {
@include rfs(2rem, font-size);
@include media-breakpoint-up(md) {
@include rfs(3rem, font-size);
}
@include media-breakpoint-up(xxl) {
@include rfs(5rem, font-size);
}
}
.sub-title {
@include rfs(1.2rem, font-size);
@include media-breakpoint-up(md) {
@include rfs(1.8rem, font-size);
}
@include media-breakpoint-up(xxl) {
@include rfs(3.2rem, font-size);
}
}
.main-logo {
@include rfs(7rem, max-height);
& {
height: 20vh;
}
@include media-breakpoint-up(md) {
@include rfs(15rem, max-height);
}
@include media-breakpoint-up(xxl) {
@include rfs(30rem, max-height);
}
}
.fi {
@include media-breakpoint-up(md) {
@include rfs(2em, line-height);
@include rfs(4em, width);
}
@include media-breakpoint-up(xxl) {
@include rfs(3em, line-height);
@include rfs(5em, width);
}
}
.lang-bar {
position: absolute;
right: 1rem;
top: 0;
}
.lang-bar .btn-group {
border-radius: 0;
}
.lang-bar .btn-group button {
border-top-left-radius: 0;
border-top-right-radius: 0;
border-bottom-left-radius: 1rem;
border-bottom-right-radius: 1rem;
}
}
</style>

View file

@ -14,14 +14,14 @@
'mx-auto': !activeRange,
}"
>
<NuxtLinkLocale
:to="`/brands/${transField(activeBrand, 'slug')}`"
<button
:class="{
'd-inline-block py-3 px-2 text-center': true,
'd-inline-block py-3 px-2 text-center bg-transparent border-0': true,
'flex-grow-1': !activeRange
}"
data-bs-toggle="tooltip"
:title="t('view_brand_ranges', {'brand_name': transField(activeBrand, 'name')})"
@click="goToBrand(activeBrand)"
>
<img
class="img-fluid main-logo"
@ -30,7 +30,7 @@
:title="t('brands_logo', {'brand_name': transField(activeBrand, 'name')})"
data-bs-toggle="tooltip"
>
</NuxtLinkLocale>
</button>
<div v-if="activeRange && brandWithMultipleRanges" class="flex-grow-1 text-center">
<span
:class="{...{
@ -47,6 +47,21 @@
</span>
</div>
</div>
<!-- HOME (PAS DE MARQUE) -->
<div v-else class="row text-bg-light">
<div class="col-12 g-0 pb-5">
<img
src="assets/pictures/layout/top-hr.png"
alt="Top bar"
class="img-fluid d-block"
>
</div>
<div class="col-12 mx-auto text-center mb-3 mt-3 pb-5">
<div class="d-inline-block bg-white p-4 rounded">
<img :src="`/data/${settings.logo}`" alt="Logo" class="img-fluid main-logo d-inline-block">
</div>
</div>
</div>
<button
class="navbar-toggler"
@ -60,15 +75,15 @@
<span class="navbar-toggler-icon" />
</button>
<div v-if="activeBrand" id="navbar-menu" class="lang-bar navbar-collapse collapse flex-grow-0">
<div id="navbar-menu" class="lang-bar navbar-collapse collapse flex-grow-0">
<div class="btn-group z-1">
<button
v-for="(localeObject, localeIndex) of locales"
:key="localeIndex"
:class="{
'btn ms-3 px-2 mx-0 shadow fw-bold': true,
'btn-secondary': locale !== localeObject.iso,
'btn-white bg-white': locale === localeObject.iso,
'btn ms-3 px-4 mx-0 shadow fw-bold': true,
'btn-secondary': locale === localeObject.iso,
'btn-white bg-white': locale !== localeObject.iso,
}"
:title="localeObject.label"
data-bs-toggle="tooltip"
@ -76,7 +91,7 @@
@click.prevent="switchLocale(localeObject)"
>
<span class="text-uppercase fs-5">{{ localeObject.flag }}</span>
<!-- <span :class="`fi fi-${localeObject.flag}`" /> -->
<span :class="`fi fi-${localeObject.flag}`" />
</button>
</div>
</div>
@ -178,11 +193,10 @@ export default defineComponent({
return ToolboxHelper.getTranslatableField(model, field);
},
switchLocale(localeToSwitch:LocaleParams) {
// const switchLocalePath = useSwitchLocalePath();
const switchLocalePath = useSwitchLocalePath();
// Toast.toast(localeToSwitch.label, ToastTypeEnum.default);
useAppStore().switchLocale(localeToSwitch.iso);
this.locale = localeToSwitch.iso;
// navigateTo(switchLocalePath(localeToSwitch.iso));
navigateTo(switchLocalePath(localeToSwitch.iso));
},
rangeFont(fontId: number) {
const font = useAppStore().getFont(fontId);
@ -198,6 +212,13 @@ export default defineComponent({
toRGBA(hexcolor: string, alpha: number = 1): string {
return ToolboxHelper.toRGBA(hexcolor, alpha);
},
goToBrand(activeBrand: TypeBrand): void {
if(!activeBrand) {
return;
}
useAppStore().setActiveRange(null);
navigateTo(useLocaleRoute()({"name": "brands-slug", "params": {"slug": activeBrand.slug[this.locale]}}));
}
}
});
</script>

View file

@ -71,13 +71,14 @@ app.whenReady().then(() => {
// width: 1280,
// height: 900,
center: true,
kiosk: false,
kiosk: process.env.NODE_ENV !== "development",
closable: false,
alwaysOnTop: true,
fullscreen: false,
fullscreen: process.env.NODE_ENV !== "development",
autoHideMenuBar: true,
webPreferences: {
preload: path.join(__dirname, "preload.js")
preload: path.join(__dirname, "preload.js"),
devTools: process.env.NODE_ENV === "development",
}
});

View file

@ -1,5 +1,5 @@
export default {
"_flag": "en",
"_flag": "us",
"_lang": "English",
"error_occured": "An error has occured",
"loading": "Loading",

View file

@ -1,189 +0,0 @@
<template>
<div class="page-home d-flex text-bg-light">
<div class="container-fluid justify-content-center d-flex flex-column">
<div class="row">
<div class="col-12 text-center overflow-hidden pb-5">
<div class="home-title">
{{ t('welcome_to_ldc') }}
</div>
</div>
<div class="col-12 text-center pb-5">
<video
class="object-fit-contain w-100"
playsinline
autoplay
muted
loop
controls
controlsList="nodownload noremoteplayback nofullscreen"
>
<source src="assets/videos/groupe-ldc-presentation-groupe-V7.webm" type="video/webm">
<!-- <source src="assets/videos/groupe-ldc-presentation-groupe-V7.mp4" type="video/mp4"> -->
</video>
</div>
</div>
<div v-if="appState.brands" class="row">
<div class="col-12 text-center overflow-hidden pb-5">
<div class="home-title">
{{ t('discover_our_brands') }}
</div>
</div>
<div
v-for="(brand, brandIndex) of appState.brands()"
:key="brandIndex"
:class="{
'col-12 col-md-6 px-5 my-3': true,
}"
>
<div
:class="{
'd-flex align-items-center h-100 my-2': true,
'justify-content-start': brandIndex %2 !== 0,
'justify-content-end': brandIndex %2 === 0,
}"
>
<div
class="d-inline-block text-center"
role="button"
:title="t('view_brand_ranges', {'brand_name': transField(brand, 'name')})"
data-bs-toggle="tooltip"
@click="gotoBrand(brand)"
>
<div class="d-inline-block brand-picture-wrapper">
<img
class="img-fluid"
:src="`/data/${brand.picture}`"
:alt="t('brands_logo', {'brand_name': transField(brand, 'name')})"
:title="t('brands_logo', {'brand_name': transField(brand, 'name')})"
>
</div>
<!-- :class="{...{'brand-title fw-bold text-capitalize fs-1 animate__animated p-3 mt-5 d-inline-block': true}, ...titleAnimations(brandIndex)}" -->
<span
class="d-none"
:style="{
'color': getContrastYIQ(brand.color),
'background-color': brand.color
}"
>
{{ transField(brand, 'name') }}
</span>
</div>
</div>
</div>
</div>
<div v-else class="row">
<div class="col">
<span class="h4">{{ t('no_brands_available') }}</span>
</div>
</div>
<div class="row my-5 pb-5">
<div class="col py-5 my-5 pb-5">
<img
src="assets/pictures/layout/home-bottom-banner.png"
alt="Bottom Banner"
class="img-fluid"
>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import type AppState from "~/classes/AppState";
import ToolboxHelper from "~/classes/ToolboxHelper";
import { useAppStore } from "~/stores/useAppStore";
import { Tooltips } from "~/vueModules/bsTooltips";
export default defineComponent({
name: "HomePage",
data() : {
appState: AppState;
animateTimeout: NodeJS.Timeout|undefined;
animateIndex: number|null;
animations: Array<string>;
tooltips: Tooltips|null;
} {
return {
appState: {} as AppState,
animateTimeout: undefined,
animateIndex: null,
animations: ["heartBeat", "tada", "shakeX", "rubberBand"],
tooltips: null
};
},
mounted() {
this.$nextTick(() => {this.tooltips = Tooltips.make({type:"parent", parentSelector: ".page-home"});});
this.appState = useAppStore().data;
// * ANIMATIONS
clearTimeout(this.animateTimeout);
this.$nextTick(() => {
[...document.getElementsByClassName("brand-title")].forEach(el => {
el.classList.add("animate__bounce");
});
this.animateTimeout = setTimeout(() => {
[...document.getElementsByClassName("brand-title")].forEach(el => {
el.classList.remove("animate__bounce");
});
this.setBrandToAnimate();
}, ToolboxHelper.randomInteger(4000, 8000));
});
},
beforeUnmount() {
this.tooltips?.closeBootstrapTooltip();
clearTimeout(this.animateTimeout);
},
methods: {
getContrastYIQ(hexcolor: string): string {
return ToolboxHelper.getContrastYIQ(hexcolor);
},
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);
},
setBrandToAnimate(): void {
clearTimeout(this.animateTimeout);
this.animateIndex = ToolboxHelper.randomInteger(0, this.appState.brands().length -1);
this.animateTimeout = setTimeout(this.setBrandToAnimate, ToolboxHelper.randomInteger(2000, 6000));
},
titleAnimations(brandIndex: 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 === brandIndex);
return Object.fromEntries(out.entries());
},
gotoBrand(brand: TypeBrand) {
useAppStore().setActiveBrand(brand);
navigateTo(useLocaleRoute()({"name": "brands-slug", "params": {"slug": this.transField(brand, "slug")}}));
}
},
});
</script>
<style lang="scss" scoped>
@import "../assets/scss/variables";
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/vendor/rfs";
.page-home, .page-home>div {
min-height: 100%;
.brand-picture-wrapper {
@include rfs(5rem, border-radius);
@include rfs(3rem, padding-top);
@include rfs(3rem, padding-bottom);
@include rfs(8rem, padding-right);
@include rfs(8rem, padding-left);
background-color: $color-white;
}
}
</style>

View file

@ -1,32 +1,53 @@
<template>
<div class="page-home d-flex">
<div class="container-fluid">
<div :class="{'page-home d-flex': true, 'text-bg-light': multipleBrands}">
<div class="container-fluid justify-content-center d-flex flex-column">
<div v-if="multipleBrands" class="row">
<div class="col-12 text-center overflow-hidden pb-5">
<div class="home-title">
{{ t('welcome_to_ldc') }}
</div>
</div>
<div class="col-12 text-center pb-5">
<video
class="object-fit-contain w-100"
playsinline
autoplay
muted
loop
controls
controlsList="nodownload noremoteplayback nofullscreen"
>
<source src="assets/videos/groupe-ldc-presentation-groupe-V7.webm" type="video/webm">
<!-- <source src="assets/videos/groupe-ldc-presentation-groupe-V7.mp4" type="video/mp4"> -->
</video>
</div>
</div>
<div v-if="appState.brands" class="row h-100 align-items-center">
<div
v-for="(brand, brandIndex) of appState.brands()"
:key="brandIndex"
:class="{
'align-items-center': true,
'col-12': appState.brands().length == 1,
'col-12 col-md-6 px-5 my-3': appState.brands().length > 1,
'col-12': !multipleBrands,
'col-12 col-md-6 px-5 my-3': multipleBrands,
}"
>
<div
:class="{
'd-flex h-100 my-2': true,
'justify-content-start': brandIndex %2 !== 0 && appState.brands().length > 1,
'justify-content-end': brandIndex %2 === 0 && appState.brands().length > 1,
'justify-content-center': appState.brands().length === 1,
'justify-content-start': brandIndex %2 !== 0 && multipleBrands,
'justify-content-end': brandIndex %2 === 0 && multipleBrands,
'justify-content-center': !multipleBrands,
}"
>
<div
class="brand d-inline-block text-center shadow"
class="d-inline-block text-center"
role="button"
:title="t('view_brand_ranges', {'brand_name': transField(brand, 'name')})"
data-bs-toggle="tooltip"
@click="gotoBrand(brand)"
>
<div class="d-inline-block brand-picture-wrapper">
<div class="d-inline-block brand-picture-wrapper shadow">
<img
class="img-fluid"
:src="`/data/${brand.picture}`"
@ -53,6 +74,15 @@
<span class="h4">{{ t('no_brands_available') }}</span>
</div>
</div>
<div v-if="multipleBrands" class="row my-5 pb-5">
<div class="col py-5 my-5 pb-5">
<img
src="assets/pictures/layout/home-bottom-banner.png"
alt="Bottom Banner"
class="img-fluid"
>
</div>
</div>
</div>
</div>
</template>
@ -72,18 +102,21 @@ export default defineComponent({
animateIndex: number|null;
animations: Array<string>;
tooltips: Tooltips|null;
multipleBrands: boolean;
} {
return {
appState: {} as AppState,
animateTimeout: undefined,
animateIndex: null,
animations: ["heartBeat", "tada", "shakeX", "rubberBand"],
tooltips: null
tooltips: null,
multipleBrands: false,
};
},
mounted() {
this.$nextTick(() => {this.tooltips = Tooltips.make({type:"parent", parentSelector: ".page-home"});});
this.appState = useAppStore().data;
this.multipleBrands = this.appState.brands().length > 1;
// * ANIMATIONS
clearTimeout(this.animateTimeout);
@ -115,7 +148,7 @@ export default defineComponent({
},
setBrandToAnimate(): void {
clearTimeout(this.animateTimeout);
this.animateIndex = ToolboxHelper.randomInteger(0, this.appState.brands().length -1);
this.animateIndex = ToolboxHelper.randomInteger(0, this.appState.brands().length - 1);
this.animateTimeout = setTimeout(this.setBrandToAnimate, ToolboxHelper.randomInteger(2000, 6000));
},
titleAnimations(brandIndex: number) {