Merge branch 'dev' into staging
This commit is contained in:
commit
dc17446248
@ -0,0 +1,39 @@
|
||||
@import "@Themes/constants.scss";
|
||||
|
||||
.root {
|
||||
display: flex;
|
||||
max-width: 357px;
|
||||
width: 100%;
|
||||
gap: var(--spacing-sm, 8px);
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
gap: var(--spacing-sm, 8px);
|
||||
align-items: center;
|
||||
|
||||
.file-name {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 277px;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
min-width: var(--spacing-3, 24px);
|
||||
min-height: var(--spacing-3, 24px);
|
||||
width: var(--spacing-3, 24px);
|
||||
height: var(--spacing-3, 24px);
|
||||
stroke: var(--color-primary-500);
|
||||
}
|
||||
|
||||
.error{
|
||||
min-width: var(--spacing-3, 24px);
|
||||
min-height: var(--spacing-3, 24px);
|
||||
width: var(--spacing-3, 24px);
|
||||
height: var(--spacing-3, 24px);
|
||||
stroke: var(--color-error-500);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||
import { CheckCircleIcon, XCircleIcon, XMarkIcon } from "@heroicons/react/24/outline";
|
||||
import React from "react";
|
||||
|
||||
import IconButton, { EIconButtonVariant } from "../../IconButton";
|
||||
import Loader from "../../Loader";
|
||||
import classes from "./classes.module.scss";
|
||||
|
||||
type IProps = {
|
||||
isLoading: boolean;
|
||||
file: File | null;
|
||||
onRemove: () => void;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
export default function DocumentElement(props: IProps) {
|
||||
const { isLoading, onRemove, file, error } = props;
|
||||
|
||||
return (
|
||||
<div className={classes["root"]}>
|
||||
<div className={classes["content"]}>
|
||||
{isLoading ? <Loader /> : !error ? <CheckCircleIcon /> : <XCircleIcon className={classes["error"]} />}
|
||||
{error && (
|
||||
<Typography typo={ETypo.TEXT_MD_LIGHT} color={ETypoColor.COLOR_ERROR_500} className={classes["file-name"]}>
|
||||
{error}
|
||||
</Typography>
|
||||
)}
|
||||
{file && !error && (
|
||||
<Typography typo={ETypo.TEXT_LG_REGULAR} color={ETypoColor.TEXT_SECONDARY} className={classes["file-name"]}>
|
||||
{file.name}
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
<IconButton onClick={onRemove} icon={<XMarkIcon />} variant={error ? EIconButtonVariant.ERROR : EIconButtonVariant.NEUTRAL} />
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
@import "@Themes/constants.scss";
|
||||
|
||||
.root {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-3, 24px);
|
||||
|
||||
width: fit-content;
|
||||
padding: var(--spacing-2, 16px) var(--Radius-2xl, 32px) var(--spacing-2, 16px) var(--spacing-xl, 32px);
|
||||
|
||||
border-radius: var(--Radius-md, 8px);
|
||||
border: 1px dashed var(--dropdown-input-border-hovered, #b4bec5);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--dropdown-input-border-expanded);
|
||||
background: var(--primary-weak-higlight, #e5eefa);
|
||||
}
|
||||
|
||||
.content {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-4, 32px);
|
||||
|
||||
.browse-document-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-sm, 8px);
|
||||
|
||||
.browse-document {
|
||||
display: flex;
|
||||
gap: var(--spacing-sm, 8px);
|
||||
|
||||
&.desktop {
|
||||
@media screen and (max-width: $screen-s) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.mobile {
|
||||
display: none;
|
||||
@media screen and (max-width: $screen-s) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.documents {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-sm, 8px);
|
||||
}
|
||||
|
||||
svg {
|
||||
min-width: var(--spacing-3, 24px);
|
||||
min-height: var(--spacing-3, 24px);
|
||||
width: var(--spacing-3, 24px);
|
||||
height: var(--spacing-3, 24px);
|
||||
stroke: var(--color-primary-500);
|
||||
}
|
||||
}
|
161
src/front/Components/DesignSystem/DragAndDrop/index.tsx
Normal file
161
src/front/Components/DesignSystem/DragAndDrop/index.tsx
Normal file
@ -0,0 +1,161 @@
|
||||
import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||
import { DocumentPlusIcon } from "@heroicons/react/24/outline";
|
||||
import classNames from "classnames";
|
||||
import React, { useCallback, useRef, useState } from "react";
|
||||
|
||||
import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "../Button";
|
||||
import Separator, { ESeperatorColor, ESeperatorDirection } from "../Separator";
|
||||
import classes from "./classes.module.scss";
|
||||
import DocumentElement from "./DocumentElement";
|
||||
|
||||
type IProps = {
|
||||
name?: string;
|
||||
title: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
type IMimeTypes = {
|
||||
extension: string;
|
||||
size: number;
|
||||
};
|
||||
|
||||
const mimeTypesAccepted: { [key: string]: IMimeTypes } = {
|
||||
"application/pdf": {
|
||||
extension: "pdf",
|
||||
size: 41943040,
|
||||
},
|
||||
"image/jpeg": {
|
||||
extension: "jpeg",
|
||||
size: 41943040,
|
||||
},
|
||||
"image/png": {
|
||||
extension: "png",
|
||||
size: 41943040,
|
||||
},
|
||||
"image/jpg": {
|
||||
extension: "jpg",
|
||||
size: 41943040,
|
||||
},
|
||||
};
|
||||
|
||||
type IDocument = {
|
||||
id: string;
|
||||
file: File | null;
|
||||
isLoading: boolean;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
export default function DragAndDrop(props: IProps) {
|
||||
const { name, title, description } = props;
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const [documents, setDocuments] = useState<IDocument[]>([]);
|
||||
|
||||
const handleFiles = useCallback((files: File[]) => {
|
||||
files.forEach((file) => {
|
||||
setDocuments((prevDocs) => [...prevDocs, { id: file.name, file: file, isLoading: true }]);
|
||||
setTimeout(() => {
|
||||
if (mimeTypesAccepted[file.type]) {
|
||||
const newDoc: IDocument = { id: file.name, file, isLoading: false };
|
||||
setDocuments((prevDocs) => prevDocs.map((doc) => (doc.id === newDoc.id ? newDoc : doc)));
|
||||
} else {
|
||||
const errorDoc: IDocument = { id: file.name, file: null, isLoading: false, error: "Type de fichier non accepté" };
|
||||
setDocuments((prevDocs) => prevDocs.map((doc) => (doc.id === errorDoc.id ? errorDoc : doc)));
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleDrop = useCallback(
|
||||
(event: React.DragEvent<HTMLDivElement>) => {
|
||||
event.preventDefault();
|
||||
const files = Array.from(event.dataTransfer.files);
|
||||
handleFiles(files);
|
||||
},
|
||||
[handleFiles],
|
||||
);
|
||||
|
||||
const handleRemove = useCallback((id: string) => {
|
||||
setDocuments((prevDocs) => prevDocs.filter((doc) => doc.id !== id));
|
||||
}, []);
|
||||
|
||||
const handleBrowse = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const files = Array.from(event.target.files || []);
|
||||
handleFiles(files);
|
||||
},
|
||||
[handleFiles],
|
||||
);
|
||||
|
||||
const triggerFileInput = () => {
|
||||
if (fileInputRef.current) {
|
||||
fileInputRef.current.click();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classNames(classes["root"])} onDrop={handleDrop} onDragOver={(e) => e.preventDefault()}>
|
||||
<div className={classes["content"]}>
|
||||
<DocumentPlusIcon />
|
||||
<Separator direction={ESeperatorDirection.VERTICAL} color={ESeperatorColor.STRONG} size={64} />
|
||||
<div className={classes["browse-document-container"]}>
|
||||
<div className={classNames(classes["browse-document"], classes["desktop"])}>
|
||||
<Typography typo={ETypo.TEXT_LG_SEMIBOLD} color={ETypoColor.TEXT_PRIMARY}>
|
||||
{title}
|
||||
</Typography>
|
||||
<Button
|
||||
variant={EButtonVariant.PRIMARY}
|
||||
styletype={EButtonstyletype.TEXT}
|
||||
size={EButtonSize.SM}
|
||||
onClick={triggerFileInput}>
|
||||
{inputFile()}
|
||||
parcourir
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className={classNames(classes["browse-document"], classes["mobile"])}>
|
||||
<Button
|
||||
variant={EButtonVariant.PRIMARY}
|
||||
styletype={EButtonstyletype.TEXT}
|
||||
size={EButtonSize.SM}
|
||||
onClick={triggerFileInput}>
|
||||
{inputFile()}
|
||||
Ajouter un document
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Typography typo={ETypo.TEXT_MD_LIGHT} color={ETypoColor.TEXT_SECONDARY}>
|
||||
{description}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
{documents.length > 0 && (
|
||||
<div className={classes["documents"]}>
|
||||
{documents.map((doc) => (
|
||||
<DocumentElement
|
||||
key={doc.id}
|
||||
isLoading={doc.isLoading}
|
||||
file={doc.file}
|
||||
onRemove={() => handleRemove(doc.id)}
|
||||
error={doc.error}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
function inputFile() {
|
||||
return (
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
name={name}
|
||||
type="file"
|
||||
multiple
|
||||
accept={Object.keys(mimeTypesAccepted).join(",")}
|
||||
onChange={handleBrowse}
|
||||
hidden
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
@import "@Themes/constants.scss";
|
||||
|
||||
.root {
|
||||
height: 2px;
|
||||
width: 100%;
|
||||
background-color: var(--separator-stroke-default);
|
||||
|
||||
&.vertical {
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&.light {
|
||||
background-color: var(--separator-stroke-light);
|
||||
}
|
||||
|
||||
&.strong {
|
||||
background-color: var(--separator-stroke-strong);
|
||||
}
|
||||
|
||||
&.contrast {
|
||||
background-color: var(--separator-stroke-contrast);
|
||||
}
|
||||
}
|
33
src/front/Components/DesignSystem/Separator/index.tsx
Normal file
33
src/front/Components/DesignSystem/Separator/index.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import React from "react";
|
||||
|
||||
import classes from "./classes.module.scss";
|
||||
import classNames from "classnames";
|
||||
|
||||
export enum ESeperatorColor {
|
||||
LIGHT = "light",
|
||||
DEFAULT = "default",
|
||||
STRONG = "strong",
|
||||
CONTRAST = "contrast",
|
||||
}
|
||||
|
||||
export enum ESeperatorDirection {
|
||||
HORIZONTAL = "horizontal",
|
||||
VERTICAL = "vertical",
|
||||
}
|
||||
|
||||
type IProps = {
|
||||
color?: ESeperatorColor;
|
||||
direction?: ESeperatorDirection;
|
||||
size?: number;
|
||||
};
|
||||
|
||||
export default function Separator(props: IProps) {
|
||||
const { color = ESeperatorColor.DEFAULT, direction = ESeperatorDirection.HORIZONTAL, size } = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(classes["root"], classes[color], classes[direction])}
|
||||
style={direction === ESeperatorDirection.HORIZONTAL ? { width: size } : { height: size }}
|
||||
/>
|
||||
);
|
||||
}
|
@ -149,6 +149,8 @@ export enum ETypoColor {
|
||||
INPUT_ERROR = "--input-error",
|
||||
|
||||
TEXT_ACCENT = "--text-accent",
|
||||
TEXT_PRIMARY = "--text-primary",
|
||||
TEXT_SECONDARY = "--text-secondary",
|
||||
|
||||
CONTRAST_DEFAULT = "--contrast-default",
|
||||
CONTRAST_HOVERED = "--contrast-hovered",
|
||||
|
@ -3,15 +3,16 @@
|
||||
flex-direction: column;
|
||||
gap: 32px;
|
||||
.components {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 32px;
|
||||
max-width: 600px;
|
||||
|
||||
.inputs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
|
||||
.rows {
|
||||
display: flex;
|
||||
|
@ -36,6 +36,8 @@ import classes from "./classes.module.scss";
|
||||
import CheckboxesInputElement from "@Front/Components/DesignSystem/CheckBox";
|
||||
import RadioBox from "@Front/Components/DesignSystem/RadioBox";
|
||||
import Toggle, { EToggleSize } from "@Front/Components/DesignSystem/Toggle";
|
||||
import Separator, { ESeperatorColor, ESeperatorDirection } from "@Front/Components/DesignSystem/Separator";
|
||||
import DragAndDrop from "@Front/Components/DesignSystem/DragAndDrop";
|
||||
|
||||
export default function DesignSystem() {
|
||||
const { isOpen, open, close } = useOpenable();
|
||||
@ -83,78 +85,95 @@ export default function DesignSystem() {
|
||||
|
||||
return (
|
||||
<DefaultTemplate title={"DesignSystem"}>
|
||||
<Typography typo={ETypo.DISPLAY_LARGE}>DesignSystem</Typography>
|
||||
<Newsletter isOpen={false} />
|
||||
<div className={classes["root"]}>
|
||||
<div />
|
||||
<div className={classes["rows"]}>
|
||||
<CheckboxesInputElement
|
||||
option={{
|
||||
label: "Default",
|
||||
value: "all",
|
||||
description: "Description",
|
||||
}}
|
||||
toolTip="test"
|
||||
/>
|
||||
<CheckboxesInputElement
|
||||
option={{
|
||||
label: "Checked",
|
||||
value: "all",
|
||||
description: "Description",
|
||||
}}
|
||||
toolTip="test"
|
||||
checked={true}
|
||||
/>
|
||||
<CheckboxesInputElement
|
||||
option={{
|
||||
label: "Disabled",
|
||||
value: "all",
|
||||
description: "Description",
|
||||
}}
|
||||
toolTip="test"
|
||||
disabled={true}
|
||||
/>
|
||||
<CheckboxesInputElement
|
||||
option={{
|
||||
label: "Checked & Disabled",
|
||||
value: "all",
|
||||
description: "Description",
|
||||
}}
|
||||
toolTip="test"
|
||||
checked={true}
|
||||
disabled={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={classes["rows"]}>
|
||||
<RadioBox name="document" value={"new client"} description="Test" label="Créer un document" toolTip="test" />
|
||||
<RadioBox
|
||||
name="document"
|
||||
value={"new client"}
|
||||
description="Test"
|
||||
label="Créer un document"
|
||||
toolTip="test"
|
||||
defaultChecked={true}
|
||||
/>
|
||||
<RadioBox
|
||||
name="document"
|
||||
value={"new client"}
|
||||
description="Test"
|
||||
label="Créer un document"
|
||||
toolTip="test"
|
||||
disabled={true}
|
||||
/>
|
||||
<RadioBox
|
||||
name="document"
|
||||
value={"new client"}
|
||||
description="Test"
|
||||
label="Créer un document"
|
||||
toolTip="test"
|
||||
checked={true}
|
||||
disabled={true}
|
||||
/>
|
||||
</div>
|
||||
<Typography typo={ETypo.DISPLAY_LARGE}>DesignSystem</Typography>
|
||||
<div className={classes["components"]}>
|
||||
<Typography typo={ETypo.TEXT_LG_BOLD}>Drag and Drop</Typography>
|
||||
<DragAndDrop name="test" title="Upload de document" description="Description" />
|
||||
<Typography typo={ETypo.TEXT_LG_BOLD}>Separators</Typography>
|
||||
<div className={classes["rows"]}>
|
||||
<Separator color={ESeperatorColor.DEFAULT} direction={ESeperatorDirection.HORIZONTAL} />
|
||||
<Separator color={ESeperatorColor.LIGHT} direction={ESeperatorDirection.HORIZONTAL} />
|
||||
<Separator color={ESeperatorColor.STRONG} direction={ESeperatorDirection.HORIZONTAL} />
|
||||
<Separator color={ESeperatorColor.CONTRAST} direction={ESeperatorDirection.HORIZONTAL} />
|
||||
</div>
|
||||
<div className={classes["rows"]} style={{ height: 70, justifyContent: "space-around" }}>
|
||||
<Separator color={ESeperatorColor.DEFAULT} direction={ESeperatorDirection.VERTICAL} />
|
||||
<Separator color={ESeperatorColor.LIGHT} direction={ESeperatorDirection.VERTICAL} />
|
||||
<Separator color={ESeperatorColor.STRONG} direction={ESeperatorDirection.VERTICAL} />
|
||||
<Separator color={ESeperatorColor.CONTRAST} direction={ESeperatorDirection.VERTICAL} />
|
||||
</div>
|
||||
|
||||
<Typography typo={ETypo.TEXT_LG_BOLD}>Checkboxes</Typography>
|
||||
<div className={classes["rows"]}>
|
||||
<CheckboxesInputElement
|
||||
option={{
|
||||
label: "Default",
|
||||
value: "all",
|
||||
description: "Description",
|
||||
}}
|
||||
toolTip="test"
|
||||
/>
|
||||
<CheckboxesInputElement
|
||||
option={{
|
||||
label: "Checked",
|
||||
value: "all",
|
||||
description: "Description",
|
||||
}}
|
||||
toolTip="test"
|
||||
checked={true}
|
||||
/>
|
||||
<CheckboxesInputElement
|
||||
option={{
|
||||
label: "Disabled",
|
||||
value: "all",
|
||||
description: "Description",
|
||||
}}
|
||||
toolTip="test"
|
||||
disabled={true}
|
||||
/>
|
||||
<CheckboxesInputElement
|
||||
option={{
|
||||
label: "Checked & Disabled",
|
||||
value: "all",
|
||||
description: "Description",
|
||||
}}
|
||||
toolTip="test"
|
||||
checked={true}
|
||||
disabled={true}
|
||||
/>
|
||||
</div>
|
||||
<Typography typo={ETypo.TEXT_LG_BOLD}>Radio boxes</Typography>
|
||||
<div className={classes["rows"]}>
|
||||
<RadioBox name="document" value={"new client"} description="Test" label="Créer un document" toolTip="test" />
|
||||
<RadioBox
|
||||
name="document"
|
||||
value={"new client"}
|
||||
description="Test"
|
||||
label="Créer un document"
|
||||
toolTip="test"
|
||||
defaultChecked={true}
|
||||
/>
|
||||
<RadioBox
|
||||
name="document"
|
||||
value={"new client"}
|
||||
description="Test"
|
||||
label="Créer un document"
|
||||
toolTip="test"
|
||||
disabled={true}
|
||||
/>
|
||||
<RadioBox
|
||||
name="document"
|
||||
value={"new client"}
|
||||
description="Test"
|
||||
label="Créer un document"
|
||||
toolTip="test"
|
||||
checked={true}
|
||||
disabled={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Typography typo={ETypo.TEXT_LG_BOLD}>Toggle</Typography>
|
||||
<div className={classes["rows"]}>
|
||||
<Toggle size={EToggleSize.MD} />
|
||||
|
Loading…
x
Reference in New Issue
Block a user