-
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adapte les fiches de sorties aux listes des événements (#338)
* Adapte les fiches de sorties aux listes des événements (#290) * Corrige selon review * Corrige le dernier point (vu ensemble) * Corrige selon review * Utilise le component `Button` dans `ButtonDropdown` * Corrige un test * Corrige un snapshot de PDF * Trie les listes par ID (et pas par nom) dans les fiches de sortie * Dernière petites corrections * Apply suggestions from code review * Corrige selon review * Corrige l'ordre du matériel dans les fiches de sorties --------- Co-authored-by: Donovan <donovan@pulsanova.com>
- Loading branch information
Showing
44 changed files
with
2,290 additions
and
1,963 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
21 changes: 21 additions & 0 deletions
21
client/src/themes/default/components/ButtonDropdown/_variables.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
@use '~@/themes/default/style/globals'; | ||
|
||
/// Padding vertical des boutons. | ||
/// @type Number | ||
$padding-y: 0.396rem !default; | ||
|
||
/// Padding horizontal des boutons. | ||
/// @type Number | ||
$padding-x: 0.626rem !default; | ||
|
||
/// Marge entre l'icône et le texte des boutons (si icône présente) | ||
/// @type Number | ||
$icon-margin: 0.385rem !default; | ||
|
||
/// Largeur de la bordure des boutons. | ||
/// @type Number | ||
$border-width: 2px !default; | ||
|
||
/// Border radius des boutons. | ||
/// @type Number | ||
$border-radius: 4px !default; |
75 changes: 75 additions & 0 deletions
75
client/src/themes/default/components/ButtonDropdown/index.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
@use '~@/themes/default/components/Button/variables' as button; | ||
@use '~@/themes/default/style/globals'; | ||
@use 'sass:color'; | ||
|
||
.ButtonDropdown { | ||
$block: &; | ||
|
||
position: relative; | ||
display: flex; | ||
|
||
// | ||
// - Bouton principal | ||
// | ||
|
||
&__main-button { | ||
border-top-right-radius: 0; | ||
border-bottom-right-radius: 0; | ||
} | ||
|
||
// | ||
// - Bouton toggle | ||
// | ||
|
||
&__toggle { | ||
// - Important, pour surcharger la définition de .Button + .Button | ||
// stylelint-disable-next-line declaration-no-important | ||
margin-left: -(button.$border-width) !important; | ||
border-top-left-radius: 0; | ||
border-bottom-left-radius: 0; | ||
} | ||
|
||
&__action-button { | ||
width: 100%; | ||
} | ||
|
||
// | ||
// - Menu | ||
// | ||
|
||
&__menu { | ||
position: absolute; | ||
z-index: 1; | ||
top: 100%; | ||
right: 0; | ||
margin: 2px 0 0; | ||
padding: 0; | ||
background: globals.$bg-color-dropdown-menu; | ||
box-shadow: -2px 6px 6px rgba(0, 0, 0, 0.25); | ||
transform-origin: 50% 0%; | ||
transform: scaleY(0); | ||
transition: transform 150ms ease-in-out; | ||
white-space: nowrap; | ||
|
||
&__item { | ||
flex: 0 0 auto; | ||
margin: 0; | ||
white-space: nowrap; | ||
list-style: none; | ||
|
||
& + & { | ||
margin-top: 2px; | ||
} | ||
} | ||
} | ||
|
||
// | ||
// - Open | ||
// | ||
|
||
&--open { | ||
#{$block}__menu { | ||
transform: none; | ||
} | ||
} | ||
} |
249 changes: 249 additions & 0 deletions
249
client/src/themes/default/components/ButtonDropdown/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,249 @@ | ||
import './index.scss'; | ||
import { defineComponent } from '@vue/composition-api'; | ||
import ClickOutside from 'vue-click-outside'; | ||
import Icon from '@/themes/default/components/Icon'; | ||
import Button from '@/themes/default/components/Button'; | ||
|
||
import type { PropType } from '@vue/composition-api'; | ||
import type { Props as IconProps } from '@/themes/default/components/Icon'; | ||
|
||
type Action = { | ||
/** Le contenu à afficher dans le bouton d'action secondaire. */ | ||
label: string, | ||
|
||
/** Le type de bouton d'action secondaire à utiliser. */ | ||
type?: string, | ||
|
||
/** | ||
* Si l'action secondaire est un lien, la cible du lien sous forme de chaîne, | ||
* ou d'objet `Location` compatible avec Vue-Router. | ||
* | ||
* Si non définie, un élément HTML `<button>` sera utilisé et | ||
* vous devriez écouter l'événement `onClick` pour réagir au click. | ||
*/ | ||
target?: string | Location, | ||
|
||
/** | ||
* Si l'action secondaire est un lien, permet d'indiquer que c'est un lien externe. | ||
* | ||
* Si c'est le cas, le fonctionnement sera le suivant : | ||
* - Le routing interne ("Vue Router"), ne sera pas utilisé. | ||
* (Il ne faut donc pas passer d'objet à `target` mais bien une chaîne) | ||
* - Si c'est une URL absolue, celle-ci s'ouvrira dans une autre fenêtre / onglet. | ||
*/ | ||
external?: boolean, | ||
|
||
/** | ||
* L'éventuel icône à utiliser avant le texte de l'action secondaire. | ||
* | ||
* Doit contenir une chaîne de caractère avec les composantes suivantes séparées par `:` : | ||
* - Le nom de l'icône sous forme de chaîne (e.g. `plus`, `wrench`) | ||
* Pour une liste exhaustive des codes, voir: https://fontawesome.com/v5.15/icons?m=free | ||
* - La variante à utiliser de l'icône à utiliser (`solid`, `regular`, ...). | ||
* | ||
* @example | ||
* - `wrench` | ||
* - `wrench:solid` | ||
*/ | ||
icon?: string | `${string}:${Required<IconProps>['variant']}`, | ||
|
||
/** | ||
* Fonction à utiliser lors d'un clic sur le bouton d'action secondaire. | ||
* | ||
* N'est utile que quand l'action secondaire n'est pas un lien. | ||
*/ | ||
onClick?(e: MouseEvent): void, | ||
}; | ||
|
||
type Props = { | ||
/** Le contenu à afficher dans le bouton principal. */ | ||
label: string, | ||
|
||
/** | ||
* Si le bouton principal est un lien, la cible du lien sous forme de chaîne, | ||
* ou d'objet `Location` compatible avec Vue-Router. | ||
* | ||
* Si non définie, un élément HTML `<button>` sera utilisé et | ||
* vous devriez écouter l'événement `onClick` pour réagir au click. | ||
*/ | ||
to?: string | Location, | ||
|
||
/** | ||
* Si le bouton principal est un lien, permet d'indiquer que c'est un lien externe. | ||
* | ||
* Si c'est le cas, le component fonctionnera comme suit: | ||
* - Le routing interne ("Vue Router"), ne sera pas utilisé. | ||
* (Il ne faut donc pas passer d'objet à `to` mais bien une chaîne) | ||
* - Si c'est une URL absolue, celle-ci s'ouvrira dans une autre fenêtre / onglet. | ||
*/ | ||
external?: boolean, | ||
|
||
/** | ||
* L'éventuel icône à utiliser avant le texte du bouton principal. | ||
* | ||
* Doit contenir une chaîne de caractère avec les composantes suivantes séparées par `:`: | ||
* - Le nom de l'icône sous forme de chaîne (e.g. `plus`, `wrench`) | ||
* Pour une liste exhaustive des codes, voir: https://fontawesome.com/v5.15/icons?m=free | ||
* - La variante à utiliser de l'icône à utiliser (`solid`, `regular`, ...). | ||
* | ||
* @example | ||
* - `wrench` | ||
* - `wrench:solid` | ||
*/ | ||
icon?: string | `${string}:${Required<IconProps>['variant']}`, | ||
|
||
/** | ||
* Permet d'indiquer si le bouton principal et les actions secondaires sont désactivés. | ||
* | ||
* Si c'est le cas (true), le bouton principal et toutes les actions secondaires seront | ||
* affichés grisés et ne seront pas cliquables. | ||
*/ | ||
disabled?: boolean, | ||
|
||
/** | ||
* Un tableau d'objets décrivant toutes les actions présentes dans le dropdown. | ||
* | ||
* Voir le type {@link Action} pour plus de détails. | ||
*/ | ||
actions: Action[], | ||
}; | ||
|
||
type Data = { | ||
isOpen: boolean, | ||
}; | ||
|
||
/** | ||
* ButtonDropdown | ||
* | ||
* Affiche un bouton qui permet de déclencher une action principale, et un menu | ||
* déroulant contenant des actions secondaires. | ||
* | ||
* Le bouton principal peut être soit un lien (externe ou non), soit un button. | ||
* Dans le premier cas, il faut passer les props `to` et éventuellement `external`, | ||
* et dans le second cas il suffit d'utiliser l'événement `onClick`. | ||
* | ||
* Pour les actions secondaires, chaque item de la liste `actions` doit être du | ||
* type `Action` (voir documentation). | ||
*/ | ||
const ButtonDropdown = defineComponent({ | ||
name: 'ButtonDropdown', | ||
directives: { ClickOutside }, | ||
props: { | ||
label: { | ||
type: String as PropType<Props['label']>, | ||
required: true, | ||
}, | ||
to: { | ||
type: [String, Object] as PropType<Props['to']>, | ||
default: undefined, | ||
}, | ||
external: { | ||
type: Boolean as PropType<Required<Props>['external']>, | ||
default: false, | ||
}, | ||
icon: { | ||
type: String as PropType<Props['icon']>, | ||
default: undefined, | ||
}, | ||
disabled: { | ||
type: Boolean as PropType<Required<Props>['disabled']>, | ||
default: false, | ||
}, | ||
actions: { | ||
type: Array as PropType<Props['actions']>, | ||
required: true, | ||
validator: (values: unknown) => ( | ||
Array.isArray(values) && values.length > 0 | ||
), | ||
}, | ||
}, | ||
emits: ['click'], | ||
data: (): Data => ({ | ||
isOpen: false, | ||
}), | ||
methods: { | ||
// ------------------------------------------------------ | ||
// - | ||
// - Handlers | ||
// - | ||
// ------------------------------------------------------ | ||
|
||
handleClose() { | ||
this.isOpen = false; | ||
}, | ||
|
||
handleToggle() { | ||
this.isOpen = !this.isOpen; | ||
}, | ||
|
||
handleClick(e: MouseEvent) { | ||
if (this.disabled) { | ||
return; | ||
} | ||
|
||
this.isOpen = false; | ||
this.$emit('click', e); | ||
}, | ||
}, | ||
render() { | ||
const { | ||
isOpen, | ||
disabled, | ||
handleClose, | ||
icon, | ||
label, | ||
to, | ||
external, | ||
handleClick, | ||
handleToggle, | ||
actions, | ||
} = this; | ||
|
||
const classNames = ['ButtonDropdown', { | ||
'ButtonDropdown--open': isOpen, | ||
}]; | ||
|
||
return ( | ||
<div class={classNames} v-clickOutside={handleClose}> | ||
<Button | ||
type="secondary" | ||
to={to} | ||
icon={icon} | ||
external={external} | ||
onClick={handleClick} | ||
disabled={disabled} | ||
class="ButtonDropdown__main-button" | ||
> | ||
{label} | ||
</Button> | ||
<Button | ||
type="secondary" | ||
onClick={handleToggle} | ||
class="ButtonDropdown__toggle" | ||
disabled={disabled} | ||
> | ||
<Icon name="ellipsis-h" /> | ||
</Button> | ||
<ul class="ButtonDropdown__menu"> | ||
{actions.map((action: Action) => ( | ||
<li class="ButtonDropdown__menu__item" key={action.label}> | ||
<Button | ||
type={action.type} | ||
to={action.target} | ||
icon={action.icon} | ||
external={action.external} | ||
onClick={action.onClick ?? (() => {})} | ||
disabled={disabled} | ||
class="ButtonDropdown__action-button" | ||
> | ||
{action.label} | ||
</Button> | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
); | ||
}, | ||
}); | ||
|
||
export default ButtonDropdown; |
Oops, something went wrong.