tracks select : track selection inside groups working without comparison mode enabled

This commit is contained in:
isUnknown 2025-06-05 18:41:01 +02:00
parent 1de315cbcd
commit 0c5c10791e
4 changed files with 101 additions and 41 deletions

View file

@ -34,6 +34,7 @@ tabs:
type: pages type: pages
layout: cards layout: cards
template: track template: track
info: "{{ page.group }}"
- width: 1/2 - width: 1/2
sections: sections:
fieldsSection: fieldsSection:

View file

@ -110,7 +110,11 @@ class ProjectPage extends NotificationsPage {
$trackData['files'][] = getFileData($view); $trackData['files'][] = getFileData($view);
} }
$files['dynamic'][] = $trackData; if ($track->group()->isNotEmpty()) {
$files['dynamic'][$track->group()->value()][] = $trackData;
} else {
$files['dynamic']['independantTracks'][] = $trackData;
}
} }
} }

View file

@ -2,53 +2,91 @@
<div <div
id="selector-dropdown" id="selector-dropdown"
class="flex flex-col" class="flex flex-col"
:style="'--image: url(\'' + getFrontViewUrl(current) + '\')'" :style="'--image: url(\'' + getFrontViewUrl(currentValue) + '\')'"
> >
<label for="selector-select" class="text-sm">Choisir une {{ label }}</label> <label for="selector-select" class="text-sm">{{ label }}</label>
<Select
<component
:is="isCompareModeEnabled ? 'MultiSelect' : 'Select'"
id="selector-select" id="selector-select"
v-model="current" v-model="currentValue"
:options="items" :options="items"
optionLabel="title" optionLabel="title"
class="font-serif" class="font-serif"
data-icon="chevron-single-down" data-icon="chevron-single-down"
checkmark checkmark
:display="isCompareModeEnabled ? 'chip' : undefined"
> >
<template #value="slotProps"> <template #value="slotProps">
<p>{{ current.title }}</p> <p v-if="isCompareModeEnabled && Array.isArray(currentValue)">
{{ currentValue.length }} selected
</p>
<!-- Sinon, simple select : afficher le titre s'il y a une sélection -->
<p v-else-if="currentValue && !Array.isArray(currentValue)">
{{ currentValue.title }}
</p>
<p v-else>Select...</p>
</template> </template>
<template #option="slotProps"> <template #option="slotProps">
<img alt="" :src="getFrontViewUrl(slotProps.option)" width="28" height="28"> <img
alt=""
:src="getFrontViewUrl(slotProps.option)"
width="28"
height="28"
/>
<p>{{ slotProps.option.title }}</p> <p>{{ slotProps.option.title }}</p>
</template> </template>
</Select> </component>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { storeToRefs } from 'pinia';
import { useDialogStore } from '../stores/dialog';
const { items, label } = defineProps({ const { items, label, isCompareModeEnabled } = defineProps({
label: String, label: String,
items: Array, items: Array,
}); isCompareModeEnabled: {
type: Boolean,
const current = ref(items[0]); default: false,
},
watch(current, (newValue) => {
changeCurrent(newValue);
}); });
const emit = defineEmits(['update:selectedItems']); const emit = defineEmits(['update:selectedItems']);
const currentValue = ref(isCompareModeEnabled ? [] : null);
const { activeTracks } = storeToRefs(useDialogStore());
watch(currentValue, (newValue) => {
if (
newValue !== null &&
(Array.isArray(newValue) ? newValue.length > 0 : true)
) {
changeCurrent(newValue);
}
});
watch(activeTracks, (newValue) => {
if (newValue[newValue.length - 1] !== currentValue.value) {
currentValue.value = isCompareModeEnabled ? [] : null;
}
});
function changeCurrent(item) { function changeCurrent(item) {
emit('update:selectedItems', item); emit('update:selectedItems', item);
} }
function getFrontViewUrl(item) { function getFrontViewUrl(item) {
// if (!item) return; if (!item) return '';
if (Array.isArray(item)) {
return item.length > 0 ? getFrontViewUrl(item[0]) : '';
}
if (item.files.length > 1) { if (item.files.length > 1) {
return item.files[7].url; return item.files[7]?.url || item.files[0].url;
} else { } else {
return item.files[0].url; return item.files[0].url;
} }
@ -184,7 +222,7 @@ function getFrontViewUrl(item) {
height: 1.75rem; height: 1.75rem;
mix-blend-mode: multiply; mix-blend-mode: multiply;
} }
#selector-select_list [aria-selected="true"] img { #selector-select_list [aria-selected='true'] img {
display: none; display: none;
} }
</style> </style>

View file

@ -3,14 +3,11 @@
<header class="tracks-header | flex"> <header class="tracks-header | flex">
<div class="tracks"> <div class="tracks">
<Selector <Selector
:label="'piste'" v-for="track in tracks"
:items="tracks" :key="track.slug"
@update:selectedItems="selectTrack" :label="track.title"
/> :items="track.variations"
<Selector :isCompareModeEnabled="isCompareModeEnabled"
v-if="isCompareModeEnabled"
:label="'piste'"
:items="tracks"
@update:selectedItems="selectTrack" @update:selectedItems="selectTrack"
/> />
</div> </div>
@ -46,7 +43,7 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, computed, watch, onMounted, onBeforeMount } from 'vue'; import { computed, watch, onMounted, onBeforeMount } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { usePageStore } from '../../../stores/page'; import { usePageStore } from '../../../stores/page';
import { useDialogStore } from '../../../stores/dialog'; import { useDialogStore } from '../../../stores/dialog';
@ -55,6 +52,7 @@ import { useRoute } from 'vue-router';
import Interactive360 from './Interactive360.vue'; import Interactive360 from './Interactive360.vue';
import SingleImage from './SingleImage.vue'; import SingleImage from './SingleImage.vue';
import Selector from '../../Selector.vue'; import Selector from '../../Selector.vue';
import slugify from 'slugify';
const route = useRoute(); const route = useRoute();
@ -64,15 +62,21 @@ const { isCommentsOpen, isCommentPanelEnabled, activeTracks, openedFile } =
const { isCompareModeEnabled } = storeToRefs(useVirtualSampleStore()); const { isCompareModeEnabled } = storeToRefs(useVirtualSampleStore());
const rawTracks = page.value.steps.find(
(step) => step.slug === 'virtual-sample'
).files.dynamic;
onBeforeMount(() => { onBeforeMount(() => {
if (route.hash.length > 0) { activeTracks.value = [rawTracks[Object.keys(rawTracks)[0]][0]];
const trackToOpen = tracks.value.find(
(track) => track.slug === route.hash.substring(1) // if (route.hash.length > 0) {
); // const trackToOpen = tracks.value.find(
activeTracks.value = [trackToOpen]; // (track) => track.slug === route.hash.substring(1)
} else { // );
activeTracks.value = [tracks.value[0]]; // activeTracks.value = [trackToOpen];
} // } else {
// activeTracks.value = [tracks.value[0]];
// }
}); });
onMounted(() => { onMounted(() => {
@ -82,16 +86,29 @@ onMounted(() => {
} }
}); });
const tracks = computed( const tracks = computed(() => {
() => const rawTracks = page.value.steps.find(
page.value.steps.find((step) => step.slug === 'virtual-sample').files (step) => step.slug === 'virtual-sample'
.dynamic ).files.dynamic;
);
const tracks = [];
for (const key in rawTracks) {
tracks.push({
title: key,
slug: slugify(key),
variations: rawTracks[key],
});
}
return tracks;
});
const isSingleImage = computed(() => { const isSingleImage = computed(() => {
console.log(activeTracks.value);
return ( return (
activeTracks.value?.length === 1 && activeTracks.value?.length === 1 &&
activeTracks.value[0]?.files.length === 1 activeTracks.value[0]?.files?.length === 1
); );
}); });