feat(lite/component): New multicolor modal (#6394)

This commit is contained in:
Thierry Goettelmann 2022-09-20 13:51:37 +02:00 committed by Julien Fontanet
parent 5218d6df1a
commit 4b3728e8d8
5 changed files with 188 additions and 79 deletions

View File

@ -14,46 +14,44 @@
</UiActionButton> </UiActionButton>
</UiFilterGroup> </UiFilterGroup>
<UiModal v-if="isOpen"> <UiModal v-if="isOpen" :icon="faFilter" @submit.prevent="handleSubmit">
<form @submit.prevent="handleSubmit"> <div class="rows">
<div class="rows"> <CollectionFilterRow
<CollectionFilterRow v-for="(newFilter, index) in newFilters"
v-for="(newFilter, index) in newFilters" :key="newFilter.id"
:key="newFilter.id" v-model="newFilters[index]"
v-model="newFilters[index]" :available-filters="availableFilters"
:available-filters="availableFilters" @remove="removeNewFilter"
@remove="removeNewFilter" />
/> </div>
</div>
<div <div
v-if="newFilters.some((filter) => filter.isAdvanced)" v-if="newFilters.some((filter) => filter.isAdvanced)"
class="available-properties" class="available-properties"
> >
{{ $t("available-properties-for-advanced-filter") }} {{ $t("available-properties-for-advanced-filter") }}
<div class="properties"> <div class="properties">
<UiBadge <UiBadge
v-for="(filter, property) in availableFilters" v-for="(filter, property) in availableFilters"
:key="property" :key="property"
:icon="getFilterIcon(filter)" :icon="getFilterIcon(filter)"
> >
{{ property }} {{ property }}
</UiBadge> </UiBadge>
</div>
</div> </div>
</div>
<UiButtonGroup> <template #buttons>
<UiButton color="secondary" @click="addNewFilter"> <UiButton transparent @click="addNewFilter">
{{ $t("add-or") }} {{ $t("add-or") }}
</UiButton> </UiButton>
<UiButton :disabled="!isFilterValid" type="submit"> <UiButton :disabled="!isFilterValid" type="submit">
{{ $t(editedFilter ? "update" : "add") }} {{ $t(editedFilter ? "update" : "add") }}
</UiButton> </UiButton>
<UiButton color="secondary" @click="handleCancel"> <UiButton outlined @click="handleCancel">
{{ $t("cancel") }} {{ $t("cancel") }}
</UiButton> </UiButton>
</UiButtonGroup> </template>
</form>
</UiModal> </UiModal>
</template> </template>
@ -61,12 +59,11 @@
import { Or, parse } from "complex-matcher"; import { Or, parse } from "complex-matcher";
import { computed, ref } from "vue"; import { computed, ref } from "vue";
import type { Filters, NewFilter } from "@/types/filter"; import type { Filters, NewFilter } from "@/types/filter";
import { faPlus } from "@fortawesome/free-solid-svg-icons"; import { faFilter, faPlus } from "@fortawesome/free-solid-svg-icons";
import CollectionFilterRow from "@/components/CollectionFilterRow.vue"; import CollectionFilterRow from "@/components/CollectionFilterRow.vue";
import UiActionButton from "@/components/ui/UiActionButton.vue"; import UiActionButton from "@/components/ui/UiActionButton.vue";
import UiBadge from "@/components/ui/UiBadge.vue"; import UiBadge from "@/components/ui/UiBadge.vue";
import UiButton from "@/components/ui/UiButton.vue"; import UiButton from "@/components/ui/UiButton.vue";
import UiButtonGroup from "@/components/ui/UiButtonGroup.vue";
import UiFilter from "@/components/ui/UiFilter.vue"; import UiFilter from "@/components/ui/UiFilter.vue";
import UiFilterGroup from "@/components/ui/UiFilterGroup.vue"; import UiFilterGroup from "@/components/ui/UiFilterGroup.vue";
import UiModal from "@/components/ui/UiModal.vue"; import UiModal from "@/components/ui/UiModal.vue";

View File

@ -17,35 +17,33 @@
</UiActionButton> </UiActionButton>
</UiFilterGroup> </UiFilterGroup>
<UiModal v-if="isOpen"> <UiModal v-if="isOpen" @submit.prevent="handleSubmit" :icon="faSort">
<form @submit.prevent="handleSubmit"> <div class="form-widgets">
<div class="form-widgets"> <FormWidget :label="$t('sort-by')">
<FormWidget :label="$t('sort-by')"> <select v-model="newSortProperty">
<select v-model="newSortProperty"> <option v-if="!newSortProperty"></option>
<option v-if="!newSortProperty"></option> <option
<option v-for="(sort, property) in availableSorts"
v-for="(sort, property) in availableSorts" :key="property"
:key="property" :value="property"
:value="property" >
> {{ sort.label ?? property }}
{{ sort.label ?? property }} </option>
</option> </select>
</select> </FormWidget>
</FormWidget> <FormWidget>
<FormWidget> <select v-model="newSortIsAscending">
<select v-model="newSortIsAscending"> <option :value="true">{{ $t("ascending") }}</option>
<option :value="true">{{ $t("ascending") }}</option> <option :value="false">{{ $t("descending") }}</option>
<option :value="false">{{ $t("descending") }}</option> </select>
</select> </FormWidget>
</FormWidget> </div>
</div> <template #buttons>
<UiButtonGroup> <UiButton type="submit">{{ $t("add") }}</UiButton>
<UiButton type="submit">{{ $t("add") }}</UiButton> <UiButton outlined @click="handleCancel">
<UiButton color="secondary" @click="handleCancel">
{{ $t("cancel") }} {{ $t("cancel") }}
</UiButton> </UiButton>
</UiButtonGroup> </template>
</form>
</UiModal> </UiModal>
</template> </template>
@ -56,11 +54,11 @@ import {
faCaretDown, faCaretDown,
faCaretUp, faCaretUp,
faPlus, faPlus,
faSort,
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import FormWidget from "@/components/FormWidget.vue"; import FormWidget from "@/components/FormWidget.vue";
import UiButton from "@/components/ui/UiButton.vue"; import UiButton from "@/components/ui/UiButton.vue";
import UiActionButton from "@/components/ui/UiActionButton.vue"; import UiActionButton from "@/components/ui/UiActionButton.vue";
import UiButtonGroup from "@/components/ui/UiButtonGroup.vue";
import UiFilter from "@/components/ui/UiFilter.vue"; import UiFilter from "@/components/ui/UiFilter.vue";
import UiFilterGroup from "@/components/ui/UiFilterGroup.vue"; import UiFilterGroup from "@/components/ui/UiFilterGroup.vue";
import UiModal from "@/components/ui/UiModal.vue"; import UiModal from "@/components/ui/UiModal.vue";

View File

@ -9,6 +9,7 @@
<style lang="postcss" scoped> <style lang="postcss" scoped>
.ui-filter-group { .ui-filter-group {
display: flex; display: flex;
align-items: center;
padding: 1rem; padding: 1rem;
background-color: var(--background-color-primary); background-color: var(--background-color-primary);
gap: 1rem; gap: 1rem;

View File

@ -1,38 +1,151 @@
<template> <template>
<Teleport to="body"> <Teleport to="body">
<div class="ui-modal"> <form
<div class="content"> :class="className"
<slot /> class="ui-modal"
v-bind="$attrs"
@click.self="emit('close')"
>
<div class="container">
<span v-if="onClose" class="close-icon" @click="emit('close')">
<FontAwesomeIcon :icon="faXmark" />
</span>
<div v-if="icon || $slots.icon" class="modal-icon">
<slot name="icon">
<FontAwesomeIcon :icon="icon" />
</slot>
</div>
<UiTitle v-if="$slots.title" type="h4">
<slot name="title" />
</UiTitle>
<div v-if="$slots.subtitle" class="subtitle">
<slot name="subtitle" />
</div>
<div v-if="$slots.default" class="content">
<slot />
</div>
<UiButtonGroup :color="color">
<slot name="buttons" />
</UiButtonGroup>
</div> </div>
</div> </form>
</Teleport> </Teleport>
</template> </template>
<script lang="ts" setup></script> <script lang="ts" setup>
import { computed } from "vue";
import type { IconDefinition } from "@fortawesome/fontawesome-common-types";
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import { useMagicKeys, whenever } from "@vueuse/core";
import UiButtonGroup from "@/components/ui/UiButtonGroup.vue";
import UiTitle from "@/components/ui/UiTitle.vue";
const props = withDefaults(
defineProps<{
icon?: IconDefinition;
color?: "info" | "warning" | "error" | "success";
onClose?: () => void;
}>(),
{ color: "info" }
);
const emit = defineEmits<{
(event: "close"): void;
}>();
const { escape } = useMagicKeys();
whenever(escape, () => emit("close"));
const className = computed(() => {
return [`color-${props.color}`, { "has-icon": props.icon !== undefined }];
});
</script>
<style lang="postcss" scoped> <style lang="postcss" scoped>
.ui-modal { .ui-modal {
position: fixed; position: fixed;
top: 0; top: 0;
right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0;
background-color: #00000080;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background-color: #00000080;
} }
.content { .color-success {
background-color: var(--background-color-primary); --modal-color: var(--color-green-infra-base);
--modal-background-color: var(--background-color-green-infra);
}
.color-info {
--modal-color: var(--color-extra-blue-base);
--modal-background-color: var(--background-color-extra-blue);
}
.color-warning {
--modal-color: var(--color-orange-world-base);
--modal-background-color: var(--background-color-orange-world);
}
.color-error {
--modal-color: var(--color-red-vates-base);
--modal-background-color: var(--background-color-red-vates);
}
.container {
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
min-width: 40rem; min-width: 40rem;
padding: 2rem; padding: 4.2rem;
text-align: center;
border-radius: 1rem; border-radius: 1rem;
background-color: var(--modal-background-color);
box-shadow: var(--shadow-400); box-shadow: var(--shadow-400);
} }
:slotted(.ui-button-group) { .close-icon {
justify-content: center; font-size: 2rem;
margin-top: 1rem; position: absolute;
top: 1.5rem;
right: 2rem;
padding: 0.2rem 0.5rem;
cursor: pointer;
color: var(--modal-color);
}
.container :slotted(.accent) {
color: var(--modal-color);
}
.modal-icon {
font-size: 4.8rem;
margin: 2rem 0;
color: var(--modal-color);
}
.ui-title {
margin-top: 4rem;
.has-icon & {
margin-top: 0;
}
}
.subtitle {
font-size: 1.6rem;
font-weight: 400;
color: var(--color-blue-scale-200);
}
.content {
margin-top: 2rem;
}
.ui-button-group {
margin-top: 4rem;
} }
</style> </style>

View File

@ -1,10 +1,10 @@
import { ref } from "vue"; import { ref } from "vue";
export default function useModal() { export default function useModal<T>() {
const $payload = ref(); const $payload = ref<T>();
const $isOpen = ref(false); const $isOpen = ref(false);
const open = (payload?: any) => { const open = (payload?: T) => {
$isOpen.value = true; $isOpen.value = true;
$payload.value = payload; $payload.value = payload;
}; };