designtopack/src/components/project/ClientBrief/Images.vue
2024-10-08 17:30:56 +02:00

430 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<section class="h-full | flex flex-col" style="--row-gap: var(--space-32)">
<header
class="project-details | flex items-start | bg-white | rounded-2xl | p-16 | w-full"
>
<div class="project-details__description | flex-1">
<label
for="project-description"
class="flex | text-sm text-grey-700 | mb-8"
>Description du projet</label
>
<textarea
name="project-description"
id="project-description"
placeholder="Ajoutez une description générale de votre projet…"
rows="3"
class="border border-grey-200 | rounded-xl | p-16 | w-full"
v-model="page.content.description"
@input="savePage()"
></textarea>
</div>
<fieldset class="project-details__filters | flex-1">
<legend class="text-sm text-grey-700 | mb-8">Filtrer par tags</legend>
<div class="flex" style="gap: var(--space-8)">
<button
class="btn btn--sm btn--grey"
id="all"
:aria-pressed="selectedTags.length === 0"
@click="selectedTags = []"
>
Voir tout
</button>
<template v-for="(tag, index) in page.tags" :key="index">
<input
class="sr-only"
type="checkbox"
:id="tag + '-page'"
:name="tag + '-page'"
:value="tag + '-page'"
v-model="selectedTags"
/>
<label class="btn btn--sm btn--primary" :for="tag + '-page'">{{
toPascalCase(tag)
}}</label>
</template>
</div>
</fieldset>
</header>
<div class="h-full | masonry">
<button
data-icon="upload"
class="flex flex-col | bg-white | border border-grey-200 | text-grey-800 | font-medium | rounded-2xl"
@click="addImages = true"
>
Ajouter une ou plusieurs images
</button>
<figure
v-for="image in images"
class="image"
@click="imageDetails = true"
>
<span class="tag | btn btn--sm">Tag</span>
<img :src="image.url" alt="" />
</figure>
</div>
<Dialog
id="add-images"
v-model:visible="addImages"
modal
header="Ajouter des images"
class="bg-white | text-grey-800 | rounded-2xl | overflow-hidden | p-32"
>
<div class="with-sidebar | h-full">
<nav>
<ul>
<li class="active">Mes Images</li>
<li>Matériauthèque</li>
<li>Réalisations</li>
<li>Inspirations</li>
</ul>
</nav>
<div
class="auto-grid | bg-grey-50 | border border-grey-200 | rounded-2xl | w-full | p-8"
style="--min: 15rem; --gap: 0.5rem"
>
<FileUpload
mode="basic"
name="images[]"
:url="'/upload-images.json?pageUri=' + page.uri"
@upload="onAdvancedUpload($event)"
:auto="true"
:multiple="true"
accept="image/*"
:maxFileSize="1000000"
invalidFileSizeMessage="Fichier trop lourd"
chooseLabel="Ajouter une ou plusieurs images"
class="flex flex-col justify-center | bg-white | border border-grey-200 | text-grey-800 | font-medium | rounded-xl"
>
<template #chooseicon>
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0.714355 15.0001V16.4286C0.714355 17.1864 1.01538 17.9131 1.55119 18.4489C2.08701 18.9848 2.81374 19.2858 3.5715 19.2858H16.4286C17.1864 19.2858 17.9131 18.9848 18.4489 18.4489C18.9848 17.9131 19.2858 17.1864 19.2858 16.4286V15.0001M5.71436 5.71436L10.0001 0.714355M10.0001 0.714355L14.2858 5.71436M10.0001 0.714355V13.5715"
stroke="currentColor"
stroke-width="1.25"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</template>
<template
#content="{
files,
uploadedFiles,
removeUploadedFileCallback,
removeFileCallback,
}"
>
<div v-if="files.length > 0">Fichiers importés</div>
</template>
</FileUpload>
<figure class="image">
<img
src="https://images.unsplash.com/photo-1541643600914-78b084683601?q=80&w=2008&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt=""
/>
</figure>
<figure class="image">
<img
src="https://images.unsplash.com/photo-1541643600914-78b084683601?q=80&w=2008&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt=""
/>
</figure>
<figure class="image">
<img
src="https://images.unsplash.com/photo-1541643600914-78b084683601?q=80&w=2008&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt=""
/>
</figure>
<figure class="image">
<img
src="https://images.unsplash.com/photo-1541643600914-78b084683601?q=80&w=2008&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt=""
/>
</figure>
<figure class="image">
<img
src="https://images.unsplash.com/photo-1541643600914-78b084683601?q=80&w=2008&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt=""
/>
</figure>
<Toast />
</div>
</div>
</Dialog>
<Dialog
id="image-details"
v-model:visible="imageDetails"
modal
header="Détails de limage"
class="bg-white | text-grey-800 | rounded-2xl | overflow-hidden"
>
<img :src="modal.url" alt="" class="bg-grey-200" loading="lazy" />
<div class="flex flex-col | p-32" style="--row-gap: var(--space-32)">
<fieldset class="image__tags">
<legend class="text-sm text-grey-700 | mb-8">Tags</legend>
<div class="flex" style="gap: var(--space-8)">
<template v-for="(tag, index) in modal.tags" :key="index">
<input
class="sr-only"
type="checkbox"
:id="tag + '-image'"
:name="tag + '-image'"
:value="tag + '-image'"
v-model="modal.selectedTags"
/>
<label class="btn btn--sm btn--primary" :for="tag + '-image'">{{
toPascalCase(tag)
}}</label>
</template>
</div>
</fieldset>
<div class="image__description | w-full">
<label
for="image-description"
class="flex | text-sm text-grey-700 | mb-8"
>Description de limage</label
>
<textarea
name="image-description"
id="image-description"
placeholder="Ajoutez une description à limage…"
class="border border-grey-200 | rounded-xl | p-16 | w-full"
></textarea>
</div>
<button
data-icon="delete"
class="btn btn--black-10 | ml-auto mt-auto"
@click="imageDetails = false"
>
Supprimer cette image
</button>
</div>
</Dialog>
</section>
</template>
<script setup>
import Toast from "primevue/toast";
import FileUpload from "primevue/fileupload";
import Dialog from "primevue/dialog";
import { useToast } from "primevue/usetoast";
import { usePageStore } from "../../../stores/page";
import { ref, watch } from "vue";
import { toPascalCase } from "../../../helpers";
const { page } = usePageStore();
const toast = useToast();
const selectedTags = ref([]);
const modal = ref(null);
watch(modal, (newValue) => {
if (newValue) {
newValue.selectedTags = newValue.selectedTags.map((tag) => {
if (!tag.includes("image")) {
return tag + "-image";
} else {
return tag;
}
});
}
});
const images = ref(page.images);
const isWaitingForSave = ref(false);
function savePage() {
if (!isWaitingForSave.value) {
isWaitingForSave.value = true;
setTimeout(() => {
const headers = {
method: "POST",
body: JSON.stringify({
pageUri: page.uri,
properties: [
{
name: "description",
value: page.content.description,
},
],
}),
};
fetch("/save-page.json", headers)
.then((res) => res.json())
.then((json) => {
isWaitingForSave.value = false;
console.log(json);
});
}, 3000);
}
}
function onAdvancedUpload(event) {
if (event.xhr.status === 200) {
toast.add({
severity: "success",
summary: "Upload réussi",
detail: event.xhr.response.success,
life: 3000,
});
const response = JSON.parse(event.xhr.response);
console.log(response);
images.value = response.images;
} else {
toast.add({
severity: "error",
summary: "Échec de l'upload",
detail: event.xhr.response.error,
life: 3000,
});
console.error(JSON.parse(event.xhr.response));
}
}
function beforeSend(event) {
const formData = event.formData;
formData.append(
"pageUri",
"projects/miss-dior-blooming-bouquet/client-brief"
);
}
</script>
<style>
fieldset {
appearance: none;
padding: 0;
margin: 0;
border: none;
}
button[data-icon="upload"] {
padding: 6.875rem 4.875rem;
}
[data-pc-name="fileupload"] button:hover {
background: var(--color-primary-10);
border-color: var(--color-primary-20);
color: var(--color-primary-100);
}
input[type="file"] {
display: none;
}
[role="dialog"] {
position: relative;
}
[data-pc-section="mask"] {
background-color: var(--color-black-50);
}
[data-pc-section="header"] {
height: var(--space-40);
}
[data-pc-section="title"] {
font-weight: 500;
font-size: var(--text-lg);
}
[data-pc-name="pcclosebutton"] {
position: absolute;
top: var(--space-16);
right: var(--space-16);
padding: 0.625rem;
width: var(--space-40);
height: var(--space-40);
}
[data-pc-name="pcclosebutton"] svg {
width: 1.25rem;
height: 1.25rem;
}
[data-pc-name="pcclosebutton"] span {
display: none;
}
[data-pc-section="content"] {
flex-grow: 1;
}
#add-images {
--sidebar-width: 12.5rem;
counter-set: selected-images;
width: min(100vw - var(--gutter) * 2, 100rem);
height: min(100vh - var(--gutter) * 2, 60rem);
padding-top: var(--space-16);
row-gap: var(--space-32);
}
#add-images nav li {
position: relative;
height: var(--space-48);
border-left: 1px solid var(--color-grey-400);
padding: var(--space-12) var(--space-16);
color: var(--color-grey-400);
font-weight: 500;
cursor: pointer;
}
#add-images nav li:hover,
#add-images nav li.active {
color: var(--color-grey-800);
border-left-color: var(--color-grey-800);
}
#add-images nav li.active::before {
content: "";
width: 2px;
position: absolute;
top: 0;
left: -1px;
bottom: 0;
background: var(--color-grey-800);
}
#add-images [data-pc-name="fileupload"] button {
padding: 3rem;
aspect-ratio: 1/1;
}
#add-images .image {
counter-increment: selected-images;
aspect-ratio: 1/1;
border-radius: var(--rounded-xl);
}
#add-images .image::after {
content: counter(selected-images);
top: var(--space-12);
right: var(--space-12);
border-radius: 50%;
color: var(--color-white);
font-weight: 700;
background: var(--color-grey-800);
mask: none;
display: grid;
place-items: center;
text-align: center;
width: 1.5rem;
height: 1.5rem;
}
#image-details {
width: min(100vw - var(--gutter) * 2, 62.5rem);
height: min(100vh - var(--gutter) * 2, 50rem);
flex-direction: row !important;
}
#image-details [data-pc-section="header"] {
position: absolute;
left: 50%;
right: 0;
z-index: 1102;
padding: 1.5rem var(--space-32);
}
#image-details [data-pc-section="content"] {
display: flex;
}
#image-details [data-pc-section="content"] > * {
width: 50%;
}
#image-details [data-pc-section="content"] > div {
padding-top: 5rem;
}
</style>