Skip to content

Commit

Permalink
feat: rework active class functions
Browse files Browse the repository at this point in the history
  • Loading branch information
BrocksiNet committed Nov 20, 2023
1 parent 6692b49 commit 072180c
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 107 deletions.
7 changes: 0 additions & 7 deletions packages/composables/src/mocks/Menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ const Menu: StoreNavigationElement[] = [
path: "|525abe8981214bd2ba94fd33942333ec|0208fc353bdb492aba4bbd910ea5cc5a|",
level: 3,
active: true,
activeClass: false,
childCount: 3,
visibleChildCount: 2,
displayNestedProducts: true,
Expand Down Expand Up @@ -83,7 +82,6 @@ const Menu: StoreNavigationElement[] = [
path: "|525abe8981214bd2ba94fd33942333ec|0208fc353bdb492aba4bbd910ea5cc5a|c568b6d678014d9bbc5e1e4b684b79c7|",
level: 4,
active: true,
activeClass: false,
childCount: 0,
visibleChildCount: 0,
displayNestedProducts: true,
Expand Down Expand Up @@ -174,7 +172,6 @@ const Menu: StoreNavigationElement[] = [
path: "|525abe8981214bd2ba94fd33942333ec|0208fc353bdb492aba4bbd910ea5cc5a|c568b6d678014d9bbc5e1e4b684b79c7|",
level: 4,
active: true,
activeClass: false,
childCount: 0,
visibleChildCount: 0,
displayNestedProducts: true,
Expand Down Expand Up @@ -298,7 +295,6 @@ const Menu: StoreNavigationElement[] = [
path: "|525abe8981214bd2ba94fd33942333ec|0208fc353bdb492aba4bbd910ea5cc5a|",
level: 3,
active: true,
activeClass: false,
childCount: 3,
visibleChildCount: 3,
displayNestedProducts: true,
Expand Down Expand Up @@ -347,7 +343,6 @@ const Menu: StoreNavigationElement[] = [
path: "|525abe8981214bd2ba94fd33942333ec|0208fc353bdb492aba4bbd910ea5cc5a|162cd978ddaa498790e70be6dc75d089|",
level: 4,
active: true,
activeClass: false,
childCount: 0,
visibleChildCount: 0,
displayNestedProducts: true,
Expand Down Expand Up @@ -428,7 +423,6 @@ const Menu: StoreNavigationElement[] = [
path: "|525abe8981214bd2ba94fd33942333ec|0208fc353bdb492aba4bbd910ea5cc5a|162cd978ddaa498790e70be6dc75d089|",
level: 4,
active: true,
activeClass: false,
childCount: 0,
visibleChildCount: 0,
displayNestedProducts: true,
Expand Down Expand Up @@ -509,7 +503,6 @@ const Menu: StoreNavigationElement[] = [
path: "|525abe8981214bd2ba94fd33942333ec|0208fc353bdb492aba4bbd910ea5cc5a|162cd978ddaa498790e70be6dc75d089|",
level: 4,
active: true,
activeClass: false,
childCount: 0,
visibleChildCount: 0,
displayNestedProducts: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export type Category = Entity & {
breadcrumb: string[];
level: number;
active: boolean;
activeClass: boolean;
childCount: number;
displayNestedProducts: boolean;
parent: Category | null;
Expand Down
171 changes: 75 additions & 96 deletions templates/vue-demo-store/components/layout/LayoutTopNavigation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
import {
getCategoryRoute,
getTranslatedProperty,
getSmallestThumbnailUrl,
} from "@shopware-pwa/helpers-next";
import type { Category } from "@shopware-pwa/types";
type NavigationElement = Category & {
activeClass?: boolean;
};
const { navigationElements } = useNavigation();
const currentMenuPosition = ref<string | null>(null);
const resetActiveClass = ref<boolean>(true);
Expand All @@ -14,77 +17,99 @@ const localePath = useLocalePath();
const { formatLink } = useInternationalization(localePath);
onMounted(() => {
const currentNaviagtionElement = findNavigationElement(route.path.slice(1));
let currentNaviagtionElement: NavigationElement | undefined;
if (navigationElements.value) {
currentNaviagtionElement = findNavigationElement(
route.path.slice(1),
navigationElements.value,
);
}
if (currentNaviagtionElement) {
updateActiveClass(
currentNaviagtionElement.id,
currentNaviagtionElement.parentId,
);
}
});
// only works with 2 level navigation
const findNavigationElement = (routePath: string): Category | undefined => {
let navigationElement;
const navigation = navigationElements.value;
if (navigation) {
// we do not loop through the top level
for (let ni = 0; ni < navigation.length; ++ni) {
const children = navigation[ni].children;
if (children) {
for (let ci = 0; ci < children.length; ++ci) {
const seoUrls = children[ci].seoUrls;
if (seoUrls) {
for (let si = 0; si < seoUrls.length; ++si) {
if (seoUrls[si].seoPathInfo == routePath) {
navigationElement = children[ci];
break;
}
}
}
if (navigationElement) {
break;
}
const findNavigationElement = (
routePath: string,
navigation: NavigationElement[],
): NavigationElement | undefined => {
for (let i = 0; i < navigation.length; i++) {
const navigationElement = navigation[i];
const seoUrls = navigationElement.seoUrls;
if (seoUrls) {
for (let j = 0; j < seoUrls.length; j++) {
if (seoUrls[j].seoPathInfo === routePath) {
return navigationElement;
}
}
if (navigationElement) {
break;
}
const children = navigationElement.children;
if (children) {
const foundElement = findNavigationElement(routePath, children);
if (foundElement) {
return foundElement;
}
}
}
return undefined;
};
return navigationElement;
const onUpdateActiveClass = (navigationId: string, parentId: string | null) => {
updateActiveClass(navigationId, parentId);
};
// only works with 2 level navigation, timeout needed to be executed after watch
const resetNavigationActiveClass = (navigation: NavigationElement[]) => {
for (let ni = 0; ni < navigation.length; ++ni) {
navigation[ni].activeClass = false;
const children = navigation[ni].children;
if (children) {
resetNavigationActiveClass(children);
}
}
};
const updateActiveClass = (navigationId: string, parentId: string | null) => {
resetActiveClass.value = false;
const navigation = navigationElements.value;
if (navigation) {
const setNavigationActiveClass = (
navigation: NavigationElement[],
navigationId: string,
parentId: string | null,
) => {
for (let ni = 0; ni < navigation.length; ++ni) {
navigation[ni].activeClass = false;
if (
(parentId && navigation[ni].id == parentId) ||
navigation[ni].id == navigationId
) {
if (navigation[ni].id === navigationId) {
navigation[ni].activeClass = true;
}
if (navigation[ni].id == parentId) {
navigation[ni].activeClass = true;
if (navigationElements.value) {
setNavigationActiveClass(
navigationElements.value,
navigationId,
navigation[ni].parentId,
);
}
}
const children = navigation[ni].children;
if (children) {
for (let ci = 0; ci < children.length; ++ci) {
children[ci].activeClass = false;
if (children[ci].id == navigationId) {
children[ci].activeClass = true;
}
}
setNavigationActiveClass(children, navigationId, parentId);
}
}
};
if (navigationElements.value) {
resetNavigationActiveClass(navigationElements.value);
setNavigationActiveClass(navigationElements.value, navigationId, parentId);
resetActiveClass.value = false;
}
};
// reset when route.path changes
watch(
() => route.path,
() => {
if (resetActiveClass.value == true) {
updateActiveClass("", "");
if (resetActiveClass.value == true && navigationElements.value) {
resetNavigationActiveClass(navigationElements.value);
}
resetActiveClass.value = true;
},
Expand Down Expand Up @@ -113,7 +138,7 @@ watch(
"
:to="formatLink(getCategoryRoute(navigationElement))"
:class="{
'link-active': navigationElement.activeClass,
'link-active': (navigationElement as NavigationElement).activeClass,
}"
class="text-base font-medium text-gray-500 hover:text-gray-900 p-2 inline-block"
@click="
Expand Down Expand Up @@ -145,57 +170,11 @@ watch(
<div
class="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 overflow-hidden"
>
<template
v-for="(childElement, index) in navigationElement.children"
:key="childElement.id"
>
<div
:class="{
'sm:pb-0': index !== navigationElement.children.length - 1,
}"
class="relative grid gap-6 bg-white px-3 py-2 sm:gap-6 sm:p-3"
>
<NuxtLink
:to="formatLink(getCategoryRoute(childElement))"
:target="
childElement.externalLink || childElement.linkNewTab
? '_blank'
: ''
"
:class="{
'link-active': childElement.activeClass,
}"
class="flex justify-between rounded-lg hover:bg-gray-50 p-2"
@click="
updateActiveClass(childElement.id, childElement.parentId)
"
>
<div
class="flex flex-col flex-grow pl-2"
:class="{
'max-w-200px md:max-w-300px': !!childElement.media,
}"
>
<p class="text-base font-medium text-gray-900">
{{ getTranslatedProperty(childElement, "name") }}
</p>
<p
v-if="getTranslatedProperty(childElement, 'description')"
class="mt-1 text-sm text-gray-500"
v-html="
getTranslatedProperty(childElement, 'description')
"
/>
</div>
<div v-if="childElement.media" class="flex">
<img
:src="getSmallestThumbnailUrl(childElement.media)"
class="object-scale-down h-48 w-px-200 rounded-md"
alt="Category image"
/>
</div>
</NuxtLink>
</div>
<template v-if="navigationElement.children.length > 0">
<LayoutTopNavigationRecursive
:navigation-element-children="navigationElement.children"
@update-active-class="onUpdateActiveClass"
/>
</template>
<div
class="px-5 py-5 bg-gray-50 space-y-6 sm:flex sm:space-y-0 sm:space-x-10 sm:px-8"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<script setup lang="ts">
import {
getCategoryRoute,
getTranslatedProperty,
getSmallestThumbnailUrl,
} from "@shopware-pwa/helpers-next";
import type { Category } from "@shopware-pwa/types";
type NavigationElement = Category & {
activeClass?: boolean;
};
const localePath = useLocalePath();
const { formatLink } = useInternationalization(localePath);
defineProps<{
navigationElementChildren: Array<NavigationElement>;
}>();
const emits = defineEmits<{
(e: "updateActiveClass", navigationId: string, parentId: string | null): void;
}>();
const emitUpdateActiveClass = (
navigationId: string,
parentId: string | null,
) => {
emits("updateActiveClass", navigationId, parentId);
};
</script>

<template>
<template
v-for="(childElement, index) in navigationElementChildren"
:key="childElement.id"
>
<div
:class="{
'sm:pb-0': index !== navigationElementChildren.length - 1,
}"
class="relative grid gap-6 bg-white px-3 py-2 sm:gap-6 sm:p-3"
>
<NuxtLink
:to="formatLink(getCategoryRoute(childElement))"
:target="
childElement.externalLink || childElement.linkNewTab ? '_blank' : ''
"
:class="{
'link-active': childElement.activeClass,
}"
class="flex justify-between rounded-lg hover:bg-gray-50 p-2"
@click="emitUpdateActiveClass(childElement.id, childElement.parentId)"
>
<div
class="flex flex-col flex-grow pl-2"
:class="{
'max-w-200px md:max-w-300px': !!childElement.media,
}"
>
<p class="text-base font-medium text-gray-900">
{{ getTranslatedProperty(childElement, "name") }}
</p>
<!-- eslint-disable vue/no-v-html -->
<p
v-if="getTranslatedProperty(childElement, 'description')"
class="mt-1 text-sm text-gray-500"
v-html="getTranslatedProperty(childElement, 'description')"
/>
<!-- eslint-enable vue/no-v-html -->
</div>
<div v-if="childElement.media" class="flex">
<img
:src="getSmallestThumbnailUrl(childElement.media)"
class="object-scale-down h-48 w-px-200 rounded-md"
alt="Category image"
/>
</div>
</NuxtLink>
<template
v-if="childElement.children && childElement.children.length > 0"
>
<LayoutTopNavigationRecursive
:navigation-element-children="childElement.children"
@update-active-class="
emitUpdateActiveClass(childElement.id, childElement.parentId)
"
/>
</template>
</div>
</template>
</template>

<style scoped>
nav .link-active {
@apply text-gray-900 bg-brand-primary bg-opacity-10 rounded-lg;
}
</style>
Loading

0 comments on commit 072180c

Please sign in to comment.