add radio & check boxes (#2)
solve partially this ticket : https://app.ora.pm/p/fb56ed95daa7456b888d266a050b9afa?v=86662&s=28293&t=k&c=657791f3b1c64e6cbbf22f9378c0bdae --------- Co-authored-by: OxSaitama <arnaud.daubernatali@smart-chain.fr> Co-authored-by: Massi <massi.hamidouche@smart-chain.fr>
This commit is contained in:
parent
676db99cb8
commit
205e1f0580
@ -5,7 +5,3 @@ WEB_ROOT_URL=/
|
|||||||
API_LABEL=Api
|
API_LABEL=Api
|
||||||
API_PORT=3001
|
API_PORT=3001
|
||||||
API_ROOT_URL=/api/v1
|
API_ROOT_URL=/api/v1
|
||||||
|
|
||||||
RPC_GATEWAY_LABEL=Rpc gateway
|
|
||||||
RPC_GATEWAY_PORT=3002
|
|
||||||
RPC_GATEWAY_ROOT_URL=/rpc/v1
|
|
@ -0,0 +1,39 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
appearance: none;
|
||||||
|
background-color: transparent;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border: 1px solid $green-flash;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin-right: 16px;
|
||||||
|
display: grid;
|
||||||
|
place-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]::before {
|
||||||
|
content: url("../../../assets/icons/check.svg");
|
||||||
|
place-content: center;
|
||||||
|
display: grid;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background-color: $green-flash;
|
||||||
|
border-radius: 2px;
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:checked::before {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip {
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
30
src/front/Components/DesignSystem/CheckBox/index.tsx
Normal file
30
src/front/Components/DesignSystem/CheckBox/index.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import React from "react";
|
||||||
|
import Tooltip from "../ToolTip";
|
||||||
|
import Typography, { ITypo, ITypoColor } from "../Typography";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
name: string;
|
||||||
|
toolTip?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class CheckBox extends React.Component<IProps> {
|
||||||
|
static defaultProps = {
|
||||||
|
toolTip: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
public override render(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Typography typo={ITypo.P_ERR_16} color={ITypoColor.BLACK}>
|
||||||
|
<label className={classes["root"]}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name={this.props.name}
|
||||||
|
/>
|
||||||
|
{this.props.name}
|
||||||
|
{this.props.toolTip && <Tooltip className={classes["tooltip"]} text={this.props.toolTip}/>}
|
||||||
|
</label>
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
154
src/front/Components/DesignSystem/Form/Elements/BaseField.tsx
Normal file
154
src/front/Components/DesignSystem/Form/Elements/BaseField.tsx
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
import { ChangeEvent, Component, createRef } from "react";
|
||||||
|
|
||||||
|
import { FormContext, IFormContext } from "..";
|
||||||
|
// elements
|
||||||
|
import Validators, { IValidationTypes } from "../Validators/Validators";
|
||||||
|
|
||||||
|
export type IError = {
|
||||||
|
message: string;
|
||||||
|
validator: string;
|
||||||
|
value: string | number | readonly string[];
|
||||||
|
args: any[];
|
||||||
|
isErrored?: (hasError: boolean) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type INewBasefieldProps = {
|
||||||
|
onChange?: (event: ChangeEvent<HTMLInputElement & HTMLSelectElement & HTMLTextAreaElement>) => void;
|
||||||
|
name: string;
|
||||||
|
regex?: RegExp;
|
||||||
|
onCancel?: () => void;
|
||||||
|
disableValidation?: boolean;
|
||||||
|
onErrors?: (errors: IError[]) => void;
|
||||||
|
fieldRef?: React.RefObject<any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type IProps = IValidationTypes & React.InputHTMLAttributes<HTMLInputElement> & INewBasefieldProps;
|
||||||
|
|
||||||
|
type IState = {
|
||||||
|
value?: string | number | readonly string[] ;
|
||||||
|
errors: IError[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export default abstract class BaseField<P extends IProps> extends Component<P, IState> {
|
||||||
|
public static override contextType = FormContext;
|
||||||
|
public override context: IFormContext | null = null;
|
||||||
|
public fieldRef: React.RefObject<any> = createRef();
|
||||||
|
|
||||||
|
static defaultProps: Partial<IProps> = {
|
||||||
|
disableValidation: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props: P) {
|
||||||
|
super(props);
|
||||||
|
this.onChange = this.onChange.bind(this);
|
||||||
|
this.validate = this.validate.bind(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
value: this.props.value ?? this.props.defaultValue ?? "",
|
||||||
|
errors: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override componentDidMount() {
|
||||||
|
this.context?.setField(this.props.name, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override componentDidUpdate(prevProps: P) {
|
||||||
|
if (prevProps.value !== this.props.value || prevProps.defaultValue !== this.props.defaultValue) {
|
||||||
|
this.setState({ value: this.props.value ?? this.props.defaultValue ?? "" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override componentWillUnmount() {
|
||||||
|
this.context?.unSetField(this.props.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async onBlur(event: React.FocusEvent<HTMLInputElement, Element>) {
|
||||||
|
// this.validate();
|
||||||
|
// if (this.props.onBlur) {
|
||||||
|
// this.props.onBlur(event);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
public async validate(isOnSubmit?: boolean) {
|
||||||
|
if (this.props.disableValidation) return;
|
||||||
|
if (this.props.readOnly) return;
|
||||||
|
|
||||||
|
const errorArray: IError[] = [];
|
||||||
|
const props: { [key: string]: any } = this.props;
|
||||||
|
const validators = Object.entries(Validators).filter(([key]) => props[key]);
|
||||||
|
|
||||||
|
const isValidable = isOnSubmit
|
||||||
|
? this.props.required || (this.state.value && this.state.value !== "")
|
||||||
|
: this.state.value && this.state.value !== "";
|
||||||
|
|
||||||
|
if (isValidable) {
|
||||||
|
const validations = await Promise.all(
|
||||||
|
validators.map(async ([key, validator]) => {
|
||||||
|
const validation = await (validator.validate as any)(this.state.value, ...(props[key].args ?? []));
|
||||||
|
if (props[key].isErrored) {
|
||||||
|
props[key].isErrored(!validation);
|
||||||
|
}
|
||||||
|
return [key, validator, validation];
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const unValidateds = validations.filter(([key, validator, validation]) => !validation);
|
||||||
|
const errors: IError[] = unValidateds.map(([key, unValidated]) => {
|
||||||
|
let message = unValidated.message;
|
||||||
|
if (typeof props[key] === "object" && props[key].message) message = props[key].message;
|
||||||
|
return { message, validator: key, value: this.state.value!, args: props[key].args ?? [] };
|
||||||
|
});
|
||||||
|
|
||||||
|
errorArray.push(...errors);
|
||||||
|
} else {
|
||||||
|
validators.forEach(async ([key]) => {
|
||||||
|
if (props[key].isErrored) {
|
||||||
|
props[key].isErrored(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ errors: errorArray });
|
||||||
|
this.onErrors(errorArray);
|
||||||
|
return errorArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setErrors(errors: IError[]) {
|
||||||
|
this.setState({ ...this.state, errors });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It is automatically called by the parent form when the user cancelled the
|
||||||
|
* form and all of its changes.
|
||||||
|
*
|
||||||
|
* Override the method for custom cancelling logic, or pass a custom onCancel
|
||||||
|
* callback.
|
||||||
|
*/
|
||||||
|
public cancel() {
|
||||||
|
if (this.props.onCancel) {
|
||||||
|
this.props.onCancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public onErrors(errors: IError[]) {
|
||||||
|
if (this.props.onErrors) {
|
||||||
|
this.props.onErrors(errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onChange(event: ChangeEvent<HTMLInputElement & HTMLSelectElement & HTMLTextAreaElement>) {
|
||||||
|
if (this.props.regex) {
|
||||||
|
if (!this.props.regex.test(event.currentTarget.value)) {
|
||||||
|
event.currentTarget.value = event.currentTarget.value.substring(0, event.currentTarget.value.length - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setState({ value: event.currentTarget.value }, () => {
|
||||||
|
this.validate();
|
||||||
|
this.context?.onFieldChange(this.props.name, this);
|
||||||
|
});
|
||||||
|
if (this.props.onChange) {
|
||||||
|
this.props.onChange(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.input {
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
padding: 24px;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
width: 530px;
|
||||||
|
height: 70px;
|
||||||
|
border: 1px solid $grey-medium;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
~ .fake-placeholder {
|
||||||
|
transform: translateY(-35px);
|
||||||
|
transition: transform 0.5s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:not([value=""]) {
|
||||||
|
~ .fake-placeholder {
|
||||||
|
transform: translateY(-35px);
|
||||||
|
transition: transform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[type="number"] {
|
||||||
|
&:focus {
|
||||||
|
~ .fake-placeholder {
|
||||||
|
transform: translateY(-35px);
|
||||||
|
transition: transform 0.5s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:not([value=""]) {
|
||||||
|
~ .fake-placeholder {
|
||||||
|
transform: translateY(-35px);
|
||||||
|
transition: transform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not([value=""]) {
|
||||||
|
~ .fake-placeholder {
|
||||||
|
transform: translateY(-35px);
|
||||||
|
transition: transform 0.5s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~ .fake-placeholder {
|
||||||
|
z-index: 2;
|
||||||
|
top: 35%;
|
||||||
|
margin-left: 8px;
|
||||||
|
padding: 0 16px;
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
background: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea {
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
padding: 24px;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
width: 530px;
|
||||||
|
height: 70px;
|
||||||
|
border: 1px solid $grey-medium;
|
||||||
|
|
||||||
|
~ .fake-placeholder {
|
||||||
|
z-index: 2;
|
||||||
|
top: 35%;
|
||||||
|
margin-left: 8px;
|
||||||
|
padding: 0 16px;
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
background: $white;
|
||||||
|
transform: translateY(-35px);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import { ReactNode } from "react";
|
||||||
|
|
||||||
|
import Validators from "../../Validators/Validators";
|
||||||
|
import BaseField, { IProps as IBaseFieldProps } from "../BaseField";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
export type IProps = IBaseFieldProps & {
|
||||||
|
fakeplaceholder: string;
|
||||||
|
large?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
// @ts-ignore TODO: typing error on IProps (validator class?? cf Massi 22/02/23)
|
||||||
|
export default class InputField extends BaseField<IProps> {
|
||||||
|
public override render(): ReactNode {
|
||||||
|
let pattern;
|
||||||
|
|
||||||
|
if (this.props.type === "number") {
|
||||||
|
pattern = "(^[0-9]*)(\\.{0,1})([0-9]*)$";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.pattern) {
|
||||||
|
pattern = this.props.pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.fieldRef) {
|
||||||
|
this.fieldRef = this.props.fieldRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we always need to control the input so we need to set the value as "" by default
|
||||||
|
const value = this.state.value ?? "";
|
||||||
|
|
||||||
|
if (this.props.large === true) {
|
||||||
|
return (
|
||||||
|
<Typography typo={ITypo.NAV_INPUT_16} color={ITypoColor.GREY}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<textarea
|
||||||
|
maxLength={this.props.maxLength}
|
||||||
|
name={this.props.name}
|
||||||
|
required={this.props.required}
|
||||||
|
ref={this.props.fieldRef}
|
||||||
|
rows={4}
|
||||||
|
value={value}
|
||||||
|
onChange={this.onChange}
|
||||||
|
data-has-validation-errors={this.state.errors.length > 0}
|
||||||
|
className={this.props.className ? [classes["textarea"], classes[this.props.className]].join(" ") : classes["textarea"]}
|
||||||
|
/>
|
||||||
|
<div className={classes["fake-placeholder"]}>{this.props.fakeplaceholder}</div>
|
||||||
|
</div>
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<Typography typo={ITypo.NAV_INPUT_16} color={ITypoColor.GREY}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<input
|
||||||
|
{...this.getHtmlAttributes()}
|
||||||
|
ref={this.props.fieldRef}
|
||||||
|
pattern={pattern}
|
||||||
|
onChange={this.onChange}
|
||||||
|
onBlur={this.onBlur}
|
||||||
|
value={value}
|
||||||
|
data-has-validation-errors={this.state.errors.length > 0}
|
||||||
|
className={this.props.className ? [classes["input"], classes[this.props.className]].join(" ") : classes["input"]}
|
||||||
|
/>
|
||||||
|
<div className={classes["fake-placeholder"]}>{this.props.fakeplaceholder}</div>
|
||||||
|
</div>
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We filter the props we'll pass to the primitive input as they're useless for it
|
||||||
|
// It also avoids the console warning because of passing useless props to a primitive DOM element
|
||||||
|
private getHtmlAttributes() {
|
||||||
|
const htmlAttributes = { ...this.props };
|
||||||
|
|
||||||
|
delete htmlAttributes.disableValidation;
|
||||||
|
delete htmlAttributes.onErrors;
|
||||||
|
delete htmlAttributes.fieldRef;
|
||||||
|
delete htmlAttributes.className;
|
||||||
|
delete htmlAttributes.defaultValue;
|
||||||
|
|
||||||
|
for (const validator in Validators) {
|
||||||
|
delete (htmlAttributes as { [key: string]: any })[validator];
|
||||||
|
}
|
||||||
|
|
||||||
|
return htmlAttributes;
|
||||||
|
}
|
||||||
|
}
|
77
src/front/Components/DesignSystem/Form/InputField/index.tsx
Normal file
77
src/front/Components/DesignSystem/Form/InputField/index.tsx
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import { ReactNode } from "react";
|
||||||
|
|
||||||
|
import Validators from "../Validators/Validators";
|
||||||
|
//import { IProps as IBaseFieldProps } from "../.";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import BaseField, { IProps as IBaseFieldProps } from "../Elements/BaseField";
|
||||||
|
|
||||||
|
export type IProps = IBaseFieldProps & {
|
||||||
|
large?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class InputField extends BaseField<IProps> {
|
||||||
|
public override render(): ReactNode {
|
||||||
|
let pattern;
|
||||||
|
|
||||||
|
if (this.props.type === "number") {
|
||||||
|
pattern = "(^[0-9]*)(\\.{0,1})([0-9]*)$";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.pattern) {
|
||||||
|
pattern = this.props.pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.fieldRef) {
|
||||||
|
this.fieldRef = this.props.fieldRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we always need to control the input so we need to set the value as "" by default
|
||||||
|
const value = this.state.value ?? "";
|
||||||
|
|
||||||
|
if (this.props.large === true) {
|
||||||
|
return (
|
||||||
|
<textarea
|
||||||
|
maxLength={this.props.maxLength}
|
||||||
|
name={this.props.name}
|
||||||
|
required={this.props.required}
|
||||||
|
ref={this.props.fieldRef}
|
||||||
|
rows={4}
|
||||||
|
value={value}
|
||||||
|
onChange={this.onChange}
|
||||||
|
data-has-validation-errors={this.state.errors.length > 0}
|
||||||
|
className={this.props.className ? [classes["textarea"], classes[this.props.className]].join(" ") : classes["textarea"]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
{...this.getHtmlAttributes()}
|
||||||
|
ref={this.props.fieldRef}
|
||||||
|
pattern={pattern}
|
||||||
|
onChange={this.onChange}
|
||||||
|
value={value}
|
||||||
|
data-has-validation-errors={this.state.errors.length > 0}
|
||||||
|
className={this.props.className ? [classes["input"], classes[this.props.className]].join(" ") : classes["input"]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We filter the props we'll pass to the primitive input as they're useless for it
|
||||||
|
// It also avoids the console warning because of passing useless props to a primitive DOM element
|
||||||
|
private getHtmlAttributes() {
|
||||||
|
const htmlAttributes = { ...this.props };
|
||||||
|
|
||||||
|
delete htmlAttributes.disableValidation;
|
||||||
|
delete htmlAttributes.onErrors;
|
||||||
|
delete htmlAttributes.fieldRef;
|
||||||
|
delete htmlAttributes.className;
|
||||||
|
delete htmlAttributes.defaultValue;
|
||||||
|
|
||||||
|
for (const validator in Validators) {
|
||||||
|
delete (htmlAttributes as { [key: string]: any })[validator];
|
||||||
|
}
|
||||||
|
|
||||||
|
return htmlAttributes;
|
||||||
|
}
|
||||||
|
}
|
180
src/front/Components/DesignSystem/Form/Validators/Validators.ts
Normal file
180
src/front/Components/DesignSystem/Form/Validators/Validators.ts
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
import { isEmail, isNotEmpty, isNumberString, isString, max, maxLength, min, minLength } from "class-validator";
|
||||||
|
|
||||||
|
const Validators = {
|
||||||
|
/**
|
||||||
|
* **Parameters** : boolean
|
||||||
|
*
|
||||||
|
* This validator verifies the value is not empty
|
||||||
|
*/
|
||||||
|
required: { validate: isNotEmpty, message: "validation_messages.field_required" },
|
||||||
|
|
||||||
|
/**
|
||||||
|
* **Parameters** : boolean
|
||||||
|
*
|
||||||
|
* This validator verifies the value is a number
|
||||||
|
*/
|
||||||
|
numbersOnly: { validate: isNumberString, message: "validation_messages.only_numbers" },
|
||||||
|
|
||||||
|
/**
|
||||||
|
* **Parameters** : boolean
|
||||||
|
*
|
||||||
|
* This validator verifies the value is a number
|
||||||
|
*/
|
||||||
|
intOnly: {
|
||||||
|
validate: function (value: string) {
|
||||||
|
const regex = /^[0-9]*$/;
|
||||||
|
return regex.test(value);
|
||||||
|
},
|
||||||
|
message: "validation_messages.only_integers",
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* **Parameters** : number
|
||||||
|
*
|
||||||
|
* This validator verifies the number is not below the parameter
|
||||||
|
*/
|
||||||
|
minNumber: { validate: (value: string, minVal: number) => min(Number(value), minVal), message: "validation_messages.below_min" },
|
||||||
|
|
||||||
|
/**
|
||||||
|
* **Parameters** : number
|
||||||
|
*
|
||||||
|
* This validator verifies the number is not above the parameter
|
||||||
|
*/
|
||||||
|
maxNumber: { validate: (value: string, maxVal: number) => max(Number(value), maxVal), message: "validation_messages.above_max" },
|
||||||
|
|
||||||
|
/**
|
||||||
|
* **Parameters** : number
|
||||||
|
*
|
||||||
|
* This validator verifies the string minimum length is conform to the parameter
|
||||||
|
*/
|
||||||
|
minLength: {
|
||||||
|
validate: minLength,
|
||||||
|
message: "validation_messages.min_string_length",
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* **Parameters** : number
|
||||||
|
*
|
||||||
|
* This validator verifies the string maximum length is conform to the parameter
|
||||||
|
*/
|
||||||
|
maxLength: {
|
||||||
|
validate: maxLength,
|
||||||
|
message: "validation_messages.max_string_length",
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* **Parameters** : boolean
|
||||||
|
*
|
||||||
|
* This validator verifies the input's value is a string.
|
||||||
|
*/
|
||||||
|
isString: { validate: (value: string) => isString(value), message: "validation_messages.only_letters" },
|
||||||
|
|
||||||
|
/**
|
||||||
|
* **Parameters** : boolean
|
||||||
|
*
|
||||||
|
* This validator verifies the input's value is conform to the tag regex.
|
||||||
|
*/
|
||||||
|
isTag: {
|
||||||
|
validate: function (value: string) {
|
||||||
|
const regex = /^[a-zA-Z0-9][a-zA-Z0-9 ]*(,[a-zA-Z0-9][a-zA-Z0-9 ]*)*$/;
|
||||||
|
const isValid = regex.test(value);
|
||||||
|
if (!isValid) return false;
|
||||||
|
|
||||||
|
const splittedTag = value.split(",");
|
||||||
|
if (splittedTag.length !== new Set(splittedTag).size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
message: "validation_messages.not_valid_tag",
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* **Parameters** : boolean
|
||||||
|
*
|
||||||
|
* This validator verifies the input's value is a valid email.
|
||||||
|
*
|
||||||
|
* If the **input is empty, it is considered valid**. If you do not wish this
|
||||||
|
* to happen please refer to the `required` validator.
|
||||||
|
*/
|
||||||
|
isEmail: {
|
||||||
|
validate: (value: string) => (Boolean(value) ? isEmail(value) : true),
|
||||||
|
message: "validation_messages.invalid_email",
|
||||||
|
},
|
||||||
|
|
||||||
|
isPseudo: {
|
||||||
|
validate: (value: string) => {
|
||||||
|
const pseudoRegex = /^[a-zA-Z][a-zA-Z0-9_-]{2,19}$/;
|
||||||
|
return pseudoRegex.test(value);
|
||||||
|
},
|
||||||
|
message: "validation_messages.is_pseudo",
|
||||||
|
},
|
||||||
|
|
||||||
|
noSpaceInString: {
|
||||||
|
validate: (value: string) => {
|
||||||
|
const regex = /^\S*$/;
|
||||||
|
return regex.test(value);
|
||||||
|
},
|
||||||
|
message: "validation_messages.no_space_in_string",
|
||||||
|
},
|
||||||
|
|
||||||
|
isPositiveNumber: {
|
||||||
|
validate: (value: string) => {
|
||||||
|
let nbr = parseFloat(value);
|
||||||
|
return !(isNaN(nbr) || nbr <= 0);
|
||||||
|
},
|
||||||
|
message: "validation_messages.positive_number",
|
||||||
|
},
|
||||||
|
|
||||||
|
floatPrecision: {
|
||||||
|
validate: (value: string, precision: number) => {
|
||||||
|
// If value is not a float
|
||||||
|
if (isNaN(parseFloat(value))) return false;
|
||||||
|
let splittedValue = value.split(".");
|
||||||
|
// If there is no decimals
|
||||||
|
if (!splittedValue[1]) return true;
|
||||||
|
// If there is more decimals than the required precision
|
||||||
|
if (splittedValue[1].length > precision) return false;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
message: "validation_messages.float_precision",
|
||||||
|
},
|
||||||
|
|
||||||
|
isUrl: {
|
||||||
|
validate: (value: string, root: string | string[]) => {
|
||||||
|
try {
|
||||||
|
const url = new URL(value);
|
||||||
|
if (root) {
|
||||||
|
if (typeof root === "string") {
|
||||||
|
return url.hostname === root || url.hostname === `www.${root}`;
|
||||||
|
} else {
|
||||||
|
return root.some((r) => url.hostname === r || url.hostname === `www.${r}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
message: "validation_messages.invalid_url",
|
||||||
|
},
|
||||||
|
|
||||||
|
// isUniqueEmail: { TODO : uncomment and implement DB request
|
||||||
|
// validate: async (value: string, actual: string) => {
|
||||||
|
// try {
|
||||||
|
// const users = await AppUser.getInstance().getUsers({email: value});
|
||||||
|
// if (!users.metadata.count) return true;
|
||||||
|
// if (users.data.length > 1) return false;
|
||||||
|
// if (users.data[0]?.email === actual) return true;
|
||||||
|
// return false;
|
||||||
|
// } catch {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// message: "validation_messages.unique_email",
|
||||||
|
// },
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Validators;
|
||||||
|
export type IValidationTypes = Partial<
|
||||||
|
Record<keyof typeof Validators, boolean | Partial<{ message: string; args: any[]; isErrored: (errored: boolean) => void }>>
|
||||||
|
>;
|
162
src/front/Components/DesignSystem/Form/index.tsx
Normal file
162
src/front/Components/DesignSystem/Form/index.tsx
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
import React, { ReactNode } from "react";
|
||||||
|
import BaseField, { IError, IProps as IBaseFieldProps } from "./Elements/BaseField";
|
||||||
|
|
||||||
|
export type IBaseField = BaseField<IBaseFieldProps>;
|
||||||
|
|
||||||
|
export type IFormContext = {
|
||||||
|
setField: (name: string, field: IBaseField) => void;
|
||||||
|
unSetField: (name: string) => void;
|
||||||
|
onFieldChange: (name: string, field: IBaseField) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
type IFields = {
|
||||||
|
[key: string]: IBaseField;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type IApiFormErrors = {
|
||||||
|
[fieldName: string]: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type IFormErrors = {
|
||||||
|
[key: string]: {
|
||||||
|
field: IBaseField;
|
||||||
|
errors: IError[] | undefined;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type IState = {};
|
||||||
|
export type IProps = {
|
||||||
|
onFieldChange?: (name: string, field: IBaseField, errors: IFormErrors | null) => void;
|
||||||
|
onSubmit?: (
|
||||||
|
e: React.FormEvent<HTMLFormElement> | null,
|
||||||
|
values: { [key: string]: string },
|
||||||
|
onApiErrors: (apiFormErrors: IApiFormErrors | null) => void,
|
||||||
|
) => void;
|
||||||
|
onValidated?: () => void;
|
||||||
|
onErrors?: (errors: IFormErrors) => void;
|
||||||
|
/**
|
||||||
|
* @description Url, No redirection without action
|
||||||
|
*/
|
||||||
|
action?: string;
|
||||||
|
className?: string;
|
||||||
|
children?: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FormContext = React.createContext<IFormContext>({ setField: () => {}, unSetField: () => {}, onFieldChange: () => {} });
|
||||||
|
|
||||||
|
export default class Form extends React.Component<IProps, IState> {
|
||||||
|
protected fields: IFields = {};
|
||||||
|
private formRef: React.RefObject<HTMLFormElement>;
|
||||||
|
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {};
|
||||||
|
this.setField = this.setField.bind(this);
|
||||||
|
this.unSetField = this.unSetField.bind(this);
|
||||||
|
this.onFieldChange = this.onFieldChange.bind(this);
|
||||||
|
this.onSubmit = this.onSubmit.bind(this);
|
||||||
|
this.onSubmitErrorApi = this.onSubmitErrorApi.bind(this);
|
||||||
|
this.formRef = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override render() {
|
||||||
|
return (
|
||||||
|
<FormContext.Provider
|
||||||
|
value={{
|
||||||
|
setField: this.setField,
|
||||||
|
unSetField: this.unSetField,
|
||||||
|
onFieldChange: this.onFieldChange,
|
||||||
|
}}>
|
||||||
|
<form className={this.props.className} ref={this.formRef} onSubmit={this.onSubmit} action={this.props.action ?? ""}>
|
||||||
|
{this.props.children}
|
||||||
|
</form>
|
||||||
|
</FormContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async onSubmit(e: React.FormEvent<HTMLFormElement> | null) {
|
||||||
|
if (!this.props.action) e?.preventDefault();
|
||||||
|
|
||||||
|
const errors = await this.validate();
|
||||||
|
|
||||||
|
if (errors) {
|
||||||
|
e?.preventDefault();
|
||||||
|
|
||||||
|
this.onErrors(errors);
|
||||||
|
|
||||||
|
return { errors };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.onValidated) this.props.onValidated();
|
||||||
|
|
||||||
|
const elementsValues = this.getAllChildrenFields(e).reduce(
|
||||||
|
(obj, element) => ({ ...obj, [element.getAttribute("name") ?? ""]: (element as any).value }),
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.props.onSubmit) {
|
||||||
|
this.props.onSubmit(e, elementsValues, this.onSubmitErrorApi);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { values: elementsValues };
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onSubmitErrorApi(apiFormErrors: IApiFormErrors | null) {
|
||||||
|
if (!apiFormErrors) return;
|
||||||
|
const errors: IFormErrors = {};
|
||||||
|
for (const [key, message] of Object.entries(apiFormErrors)) {
|
||||||
|
if (!this.fields[key]) continue;
|
||||||
|
this.fields[key]?.setErrors([
|
||||||
|
{
|
||||||
|
message,
|
||||||
|
validator: "",
|
||||||
|
value: this.fields[key]?.state.value ?? "",
|
||||||
|
args: [],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
this.onErrors(errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async validate() {
|
||||||
|
const errors = (
|
||||||
|
await Promise.all(
|
||||||
|
Object.entries(this.fields).map(async ([name, field]) => {
|
||||||
|
return { name, validation: await field.validate(true), field };
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
).filter(({ validation }) => validation?.length);
|
||||||
|
|
||||||
|
if (!errors.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorsObject: IFormErrors = {};
|
||||||
|
errors.forEach(({ name, validation, field }) => (errorsObject[name] = { errors: validation, field }));
|
||||||
|
return errorsObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onErrors(errors: IFormErrors) {
|
||||||
|
if (this.props.onErrors) this.props.onErrors(errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected setField(name: string, field: IBaseField) {
|
||||||
|
this.fields[name] = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected unSetField(name: string) {
|
||||||
|
delete this.fields[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async onFieldChange(name: string, field: IBaseField) {
|
||||||
|
if (this.props.onFieldChange) {
|
||||||
|
const errors = await this.validate();
|
||||||
|
this.props.onFieldChange(name, field, errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getAllChildrenFields(e: React.FormEvent<HTMLFormElement> | null): Element[] {
|
||||||
|
return Array.from(((e?.target as HTMLFormElement) ?? this.formRef.current).elements);
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,6 @@ class HeaderLinkClass extends React.Component<IPropsClass, IStateClass> {
|
|||||||
{this.props.isActive && <div className={classes["underline"]} />}
|
{this.props.isActive && <div className={classes["underline"]} />}
|
||||||
</Link>;
|
</Link>;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function HeaderLink(props: IPropsClass) {
|
export default function HeaderLink(props: IPropsClass) {
|
@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import LogoIcon from "@Assets/logo.png"
|
import LogoIcon from "@Assets/logo.svg"
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Navigation from "./Navigation";
|
import Navigation from "./Navigation";
|
||||||
import Notifications from "./Notifications";
|
import Notifications from "./Notifications";
|
@ -0,0 +1,39 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
input[type="radio"] {
|
||||||
|
appearance: none;
|
||||||
|
background-color: transparent;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border: 1px solid $green-flash;
|
||||||
|
border-radius: 100px;
|
||||||
|
margin-right: 16px;
|
||||||
|
display: grid;
|
||||||
|
place-content: center;
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"]::before {
|
||||||
|
content: "";
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background-color: $green-flash;
|
||||||
|
border-radius: 100px;
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"]:checked::before {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip {
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
}
|
28
src/front/Components/DesignSystem/RadioBox/index.tsx
Normal file
28
src/front/Components/DesignSystem/RadioBox/index.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import React from "react";
|
||||||
|
import Tooltip from "../ToolTip";
|
||||||
|
import Typography, { ITypo, ITypoColor } from "../Typography";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
children: React.ReactNode;
|
||||||
|
name: string;
|
||||||
|
toolTip?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class RadioBox extends React.Component<IProps> {
|
||||||
|
|
||||||
|
public override render(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Typography typo={ITypo.P_ERR_16} color={ITypoColor.BLACK}>
|
||||||
|
<label className={classes["root"]}>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name={this.props.name}
|
||||||
|
/>
|
||||||
|
{this.props.children}
|
||||||
|
{this.props.toolTip && <Tooltip className={classes["tooltip"]} text={this.props.toolTip}/>}
|
||||||
|
</label>
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
min-width: 100px;
|
||||||
|
max-width: 320px;
|
||||||
|
background: $white;
|
||||||
|
border-radius: 5px !important;
|
||||||
|
position: fixed;
|
||||||
|
transition: opacity 0.2s ease-in-out;
|
||||||
|
text-align: left;
|
||||||
|
filter: drop-shadow(0px 9px 18px $shadow-tooltip);
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
img {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.root-content {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carrot {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
margin-top: -4px;
|
||||||
|
fill: $white;
|
||||||
|
}
|
42
src/front/Components/DesignSystem/ToolTip/Content/index.tsx
Normal file
42
src/front/Components/DesignSystem/ToolTip/Content/index.tsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import classNames from "classnames";
|
||||||
|
import React, { ReactNode } from "react";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
display: boolean;
|
||||||
|
title?: React.ReactNode;
|
||||||
|
event: React.MouseEvent<HTMLElement> | null;
|
||||||
|
children?: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class TooltipContent extends React.Component<IProps> {
|
||||||
|
public override render(): JSX.Element {
|
||||||
|
const mousePositionX = this.props.event?.clientX;
|
||||||
|
const mousePositionY = this.props.event?.clientY;
|
||||||
|
let right = 0;
|
||||||
|
let bottom = 0;
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
right = window.innerWidth - (mousePositionX ?? 0) - 35;
|
||||||
|
bottom = window.innerHeight - (mousePositionY ?? 0) + 15;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{ bottom: bottom + "px", right: right + "px" }}
|
||||||
|
className={classNames(classes["root"], { [classes["show"]!]: this.props.display })}>
|
||||||
|
<div className={classes["root-content"]}>
|
||||||
|
{this.props.title && <div>{this.props.title}</div>}
|
||||||
|
{this.props.children}
|
||||||
|
</div>
|
||||||
|
<svg
|
||||||
|
className={classes["carrot"]}
|
||||||
|
width="25"
|
||||||
|
height="15"
|
||||||
|
viewBox="0 0 25 15"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12.5 14.4231L1.26091e-06 4.49015e-06L25 6.67572e-06L12.5 14.4231Z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
66
src/front/Components/DesignSystem/ToolTip/index.tsx
Normal file
66
src/front/Components/DesignSystem/ToolTip/index.tsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import React from "react";
|
||||||
|
import Image from "next/image";
|
||||||
|
import ToolTipIcon from "@Assets/icons/tool-tip.svg";
|
||||||
|
import TooltipContent from "./Content";
|
||||||
|
import Typography, { ITypo } from "../Typography";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
title?: string | JSX.Element;
|
||||||
|
text?: string | JSX.Element;
|
||||||
|
className?: string;
|
||||||
|
isNotFlex?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
type IState = {
|
||||||
|
showContent: boolean;
|
||||||
|
event: React.MouseEvent<HTMLElement> | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class Tooltip extends React.Component<IProps, IState> {
|
||||||
|
static defaultProps: Partial<IProps> = {
|
||||||
|
isNotFlex: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
public constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
showContent: false,
|
||||||
|
event: null,
|
||||||
|
};
|
||||||
|
this.togglePopup = this.togglePopup.bind(this);
|
||||||
|
this.moovePopup = this.moovePopup.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override render(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span
|
||||||
|
className={this.props.className}
|
||||||
|
style={!this.props.isNotFlex ? { display: "flex" } : {}}
|
||||||
|
onMouseEnter={this.togglePopup}
|
||||||
|
onMouseLeave={this.togglePopup}
|
||||||
|
onMouseMove={this.moovePopup}>
|
||||||
|
<Image src={ToolTipIcon} alt="toolTip icon"/>
|
||||||
|
</span>
|
||||||
|
<Typography typo={ITypo.CAPTION_14}>
|
||||||
|
<TooltipContent title={this.props.title} event={this.state.event} display={this.state.showContent}>
|
||||||
|
{this.props.text}
|
||||||
|
</TooltipContent>
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private togglePopup(e: React.MouseEvent<HTMLSpanElement>): void {
|
||||||
|
this.setState({
|
||||||
|
showContent: !this.state.showContent,
|
||||||
|
event: e,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private moovePopup(e: React.MouseEvent<HTMLSpanElement>): void {
|
||||||
|
this.setState({
|
||||||
|
event: e,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -120,4 +120,8 @@
|
|||||||
&.grey {
|
&.grey {
|
||||||
color: $grey;
|
color: $grey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.black {
|
||||||
|
color: $black;
|
||||||
|
}
|
||||||
}
|
}
|
@ -32,6 +32,7 @@ export enum ITypo {
|
|||||||
export enum ITypoColor {
|
export enum ITypoColor {
|
||||||
RE_HOVER = "re-hover",
|
RE_HOVER = "re-hover",
|
||||||
GREY = "grey",
|
GREY = "grey",
|
||||||
|
BLACK = 'black'
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Typography extends React.Component<IProps, IState> {
|
export default class Typography extends React.Component<IProps, IState> {
|
@ -1,4 +1,6 @@
|
|||||||
.root {
|
.root {
|
||||||
|
margin-left: 35px;
|
||||||
|
margin-right: 35px;
|
||||||
.section {
|
.section {
|
||||||
margin-bottom: 32px;
|
margin-bottom: 32px;
|
||||||
}
|
}
|
141
src/front/Components/Layouts/DesignSystem/index.tsx
Normal file
141
src/front/Components/Layouts/DesignSystem/index.tsx
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
import BasePage from "@Front/Components/Layouts/Base";
|
||||||
|
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
|
import Toasts, { IToast } from "@Front/Stores/Toasts";
|
||||||
|
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
|
||||||
|
import HeaderLink from "@Front/Components/DesignSystem/Header/HeaderLink";
|
||||||
|
import CheckBox from "@Front/Components/DesignSystem/CheckBox";
|
||||||
|
import ToolTip from "@Front/Components/DesignSystem/ToolTip";
|
||||||
|
import RadioBox from "@Front/Components/DesignSystem/RadioBox";
|
||||||
|
// import Input from "@Front/Components/DesignSystem/Input";
|
||||||
|
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
|
||||||
|
|
||||||
|
type IState = {
|
||||||
|
isModalDisplayed: boolean;
|
||||||
|
};
|
||||||
|
type IProps = {};
|
||||||
|
|
||||||
|
export default class DesignSystem extends BasePage<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isModalDisplayed: false,
|
||||||
|
};
|
||||||
|
this.openModal = this.openModal.bind(this);
|
||||||
|
this.closeModal = this.closeModal.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override render(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<DefaultTemplate title={"HomePage"}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["section"]}>
|
||||||
|
<div className={classes["sub-section"]}>
|
||||||
|
<Typography typo={ITypo.H1}>Website design System</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["sub-section"]}>
|
||||||
|
<Typography typo={ITypo.P_18}>
|
||||||
|
This page allows to gather all the design system of the site. A Design System is a library of components, visuals and principles with reusable code. This evolving kit offers a UX and UI repository for
|
||||||
|
designers and developers of digital products and services. The construction of a design system offers many advantages. This solution facilitates the work of the teams and reduces the "design debt" and the
|
||||||
|
"technical debt". The result is a coherent ecosystem and therefore a better experience for users and customers.
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classes["section"]}>
|
||||||
|
<div className={classes["sub-section"]}>
|
||||||
|
<Typography typo={ITypo.H3}>Button components</Typography>
|
||||||
|
</div>
|
||||||
|
<Button variant={EButtonVariant.PRIMARY}>Primary</Button>
|
||||||
|
<Button variant={EButtonVariant.SECONDARY}>Secondary</Button>
|
||||||
|
<Button variant={EButtonVariant.GHOST}>Ghost</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classes["section"]}>
|
||||||
|
<div className={classes["sub-section"]}>
|
||||||
|
<Typography typo={ITypo.H3}>Toaster component</Typography>
|
||||||
|
</div>
|
||||||
|
<Button variant={EButtonVariant.PRIMARY} onClick={this.spawnToast}>
|
||||||
|
Spawn a toast
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className={classes["section"]}>
|
||||||
|
<div className={classes["sub-section"]}>
|
||||||
|
<Typography typo={ITypo.H3}>Modal components</Typography>
|
||||||
|
</div>
|
||||||
|
<Button variant={EButtonVariant.PRIMARY} onClick={this.openModal}>
|
||||||
|
Show Modal
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Confirm isOpen={this.state.isModalDisplayed} onClose={this.closeModal} closeBtn header={"Title"} cancelText={"Cancel"} confirmText={"Confirmer"}>
|
||||||
|
Lorem ipsum dolor sit amet consectetur. Aliquam nunc lobortis lacus vulputate sagittis sed tempor eget feugiat. Elementum malesuada at sit elit.
|
||||||
|
</Confirm>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classes["section"]}>
|
||||||
|
<div className={classes["sub-section"]}>
|
||||||
|
<Typography typo={ITypo.H3}>HeaderLink components</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["inline-flex"]}>
|
||||||
|
<HeaderLink text={"Home"} path={"/"} />
|
||||||
|
<HeaderLink text={"Design-system"} path={"/design-system"} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["section"]}>
|
||||||
|
<div className={classes["sub-section"]}>
|
||||||
|
<Typography typo={ITypo.H3}>CheckBox component</Typography>
|
||||||
|
</div>
|
||||||
|
<CheckBox name="Check Box 1" toolTip="Checkbox with tooltip"/>
|
||||||
|
<CheckBox name="Check Box 2" />
|
||||||
|
</div>
|
||||||
|
<div className={classes["section"]}>
|
||||||
|
<div className={classes["sub-section"]}>
|
||||||
|
<Typography typo={ITypo.H3}>RadioBox component</Typography>
|
||||||
|
</div>
|
||||||
|
<RadioBox name="RadioBox" toolTip="Radiobox with tooltip">Radio Box 1</RadioBox>
|
||||||
|
<RadioBox name="RadioBox">Radio Box 2</RadioBox>
|
||||||
|
</div>
|
||||||
|
<div className={classes["section"]}>
|
||||||
|
<div className={classes["sub-section"]}>
|
||||||
|
<Typography typo={ITypo.H3}>Tool tip component</Typography>
|
||||||
|
</div>
|
||||||
|
<ToolTip title="toolTip" text="tooltip content" isNotFlex={true} />
|
||||||
|
</div>
|
||||||
|
<div className={classes["section"]}>
|
||||||
|
<div className={classes["sub-section"]}>
|
||||||
|
<Typography typo={ITypo.H3}>Input component</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["sub-section"]}>
|
||||||
|
<InputField name="input field" fakeplaceholder="input place hodler" />
|
||||||
|
</div>
|
||||||
|
<div className={classes["sub-section"]}>
|
||||||
|
<InputField name="input field" fakeplaceholder="text area place hodler" large={true} />
|
||||||
|
</div>
|
||||||
|
<div className={classes["sub-section"]}>
|
||||||
|
<InputField name="input field" fakeplaceholder="number place hodler" type="number" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaultTemplate>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
private openModal() {
|
||||||
|
this.setState({
|
||||||
|
isModalDisplayed: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private closeModal() {
|
||||||
|
this.setState({
|
||||||
|
isModalDisplayed: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private spawnToast() {
|
||||||
|
const toast: IToast = {
|
||||||
|
title: "Un collaborateur veut rejoindre votre office",
|
||||||
|
text: "12:00 - 1 fev 2023",
|
||||||
|
};
|
||||||
|
Toasts.getInstance().open(toast);
|
||||||
|
}
|
||||||
|
}
|
3
src/front/assets/icons/check.svg
Normal file
3
src/front/assets/icons/check.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="10" height="8" viewBox="0 0 10 8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9.81353 0.144344C10.0429 0.354011 10.0635 0.715195 9.85967 0.95107L3.93375 7.80821C3.82832 7.9302 3.67721 8 3.51852 8C3.35983 8 3.20872 7.9302 3.10329 7.80821L0.140334 4.37964C-0.0635092 4.14376 -0.0428533 3.78258 0.18647 3.57291C0.415794 3.36324 0.766945 3.38449 0.970788 3.62037L3.51852 6.56846L9.02921 0.191798C9.23306 -0.0440776 9.58421 -0.0653237 9.81353 0.144344Z" fill="white"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 497 B |
12
src/front/assets/icons/tool-tip.svg
Normal file
12
src/front/assets/icons/tool-tip.svg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_2395_56631)">
|
||||||
|
<path d="M10.9999 20.1667C16.0625 20.1667 20.1666 16.0627 20.1666 11C20.1666 5.93743 16.0625 1.83337 10.9999 1.83337C5.93731 1.83337 1.83325 5.93743 1.83325 11C1.83325 16.0627 5.93731 20.1667 10.9999 20.1667Z" stroke="#101010" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M11 14.6667V11" stroke="#101010" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M11 7.33337H11.0092" stroke="#101010" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_2395_56631">
|
||||||
|
<rect width="22" height="22" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 765 B |
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
38
src/front/assets/logo.svg
Normal file
38
src/front/assets/logo.svg
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<svg width="174" height="39" viewBox="0 0 174 39" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_2800_16209)">
|
||||||
|
<path d="M25.5273 5.84731C25.5401 5.51025 25.3462 5.16586 24.929 4.98634L14.1634 0.368254C13.2979 -0.0036107 12.2788 -0.0036107 11.4116 0.368254L0.706259 4.96069C0.281779 5.14204 0.0823469 5.4901 0.0933248 5.83448V26.9282L2.49932 28.0621L3.93743 27.3733L10.7474 30.1852V31.6159L12.8332 32.5978L14.9391 31.5902V30.1999L21.7381 27.3916L23.1689 28.0621L25.5328 26.93V5.84731H25.5273Z" fill="#C5B2D4"/>
|
||||||
|
<path d="M12.8314 32.7L10.6541 31.676V30.249L3.93741 27.4756L2.49748 28.1644L0 26.9865L0.00365931 5.74256C0.0311041 5.3707 0.279937 5.04463 0.669653 4.8761L11.3768 0.283662C12.2605 -0.0955304 13.3162 -0.0955304 14.1999 0.283662L24.9656 4.90175C25.3517 5.06661 25.5932 5.38902 25.6188 5.75539H25.6206V26.9883L23.1671 28.1625L21.7344 27.4921L15.0306 30.2618V31.6485L12.8332 32.7H12.8314ZM10.837 31.5588L12.8314 32.4967L14.8458 31.5331V30.1391L14.9025 30.1153L21.7381 27.2924L23.1652 27.961L25.4377 26.8729V5.93857H25.434V5.84331C25.4486 5.50992 25.2456 5.22232 24.8924 5.07028L14.1267 0.452192C13.2888 0.0931497 12.2861 0.0931497 11.4481 0.452192L0.741009 5.04463C0.382398 5.1985 0.173817 5.4916 0.182965 5.83049V5.92392V26.8692L2.49748 27.9592L3.93192 27.2723L3.97035 27.2869L10.837 30.1226V31.5551V31.5588Z" fill="#4E1480"/>
|
||||||
|
<path d="M10.5187 28.7051C10.1985 28.7051 9.87462 28.641 9.56907 28.5109L2.57614 25.5305C1.68144 25.1495 1.10327 24.2739 1.10327 23.3011L1.09778 10.187C1.09778 9.36812 1.50579 8.61157 2.18825 8.16094C2.87071 7.7103 3.72699 7.6352 4.47898 7.96127L11.4774 10.9856C12.3648 11.3685 12.9393 12.2423 12.9393 13.2113V26.2816C12.9393 27.0967 12.5331 27.8533 11.8543 28.3039C11.4518 28.5714 10.9871 28.7069 10.5205 28.7069L10.5187 28.7051ZM9.78497 28.0053C10.365 28.2526 11.0255 28.1922 11.5506 27.8441C12.0757 27.4961 12.3904 26.9117 12.3904 26.2797V13.2095C12.3904 12.4603 11.9476 11.7862 11.2597 11.4894L4.26125 8.46502C3.68125 8.21406 3.01891 8.27268 2.49014 8.62073C1.96137 8.96878 1.64667 9.55497 1.64667 10.187L1.65216 23.3011C1.65216 24.054 2.0986 24.73 2.79021 25.0249L9.78314 28.0053H9.78497Z" fill="white"/>
|
||||||
|
<path d="M13.0509 15.5434V14.8564C13.0509 14.8381 13.0399 14.8235 13.0235 14.8161L12.1763 14.4498C12.1471 14.4369 12.1141 14.4589 12.1141 14.4901V15.177C12.1141 15.1953 12.1251 15.21 12.1416 15.2173L12.9887 15.5837C13.018 15.5965 13.0509 15.5745 13.0509 15.5434Z" fill="white"/>
|
||||||
|
<path d="M13.007 15.862C12.9631 15.862 12.921 15.8529 12.879 15.8345L12.0337 15.4682C11.9166 15.4187 11.8416 15.3033 11.8416 15.1751V14.4881C11.8416 14.38 11.8946 14.2811 11.9843 14.2207C12.0739 14.1621 12.1874 14.1529 12.2862 14.195L13.1333 14.5614C13.2504 14.6109 13.3254 14.7263 13.3254 14.8545V15.5414C13.3254 15.6495 13.2723 15.7484 13.1809 15.8089C13.1278 15.8437 13.0674 15.862 13.007 15.862ZM12.3904 15.0249L12.7765 15.1916V15.0084L12.3904 14.8417V15.0249Z" fill="white"/>
|
||||||
|
<path d="M13.0819 26.2944V25.6074C13.0819 25.5891 13.0709 25.5744 13.0545 25.5671L12.2074 25.2007C12.1781 25.1879 12.1451 25.2099 12.1451 25.241V25.928C12.1451 25.9463 12.1561 25.961 12.1726 25.9683L13.0197 26.3347C13.049 26.3475 13.0819 26.3255 13.0819 26.2944Z" fill="white"/>
|
||||||
|
<path d="M13.038 26.6149C12.996 26.6149 12.9539 26.6057 12.9118 26.5892L12.0647 26.2229C11.9476 26.1716 11.8726 26.0562 11.8726 25.9298V25.2428C11.8726 25.1348 11.9256 25.0358 12.0153 24.9754C12.1049 24.9149 12.2184 24.9076 12.3172 24.9497L13.1643 25.3161C13.2814 25.3656 13.3564 25.481 13.3564 25.6092V26.2961C13.3564 26.4042 13.3033 26.5031 13.2137 26.5618C13.1606 26.5966 13.1003 26.6149 13.038 26.6149ZM12.4215 25.7777L12.8075 25.9444V25.7594L12.4215 25.5927V25.7777Z" fill="white"/>
|
||||||
|
<path d="M4.94739 14.1675C3.52575 14.7207 3.18726 17.2596 4.18808 19.8352C5.1889 22.4126 7.15395 24.0521 8.57559 23.4971C9.99723 22.942 10.3357 20.4049 9.33489 17.8293C8.33407 15.2538 6.36903 13.6124 4.94739 14.1675ZM7.34606 18.8845C7.32959 18.824 7.30947 18.7636 7.28568 18.7031C7.23811 18.5786 7.17773 18.465 7.11187 18.3642L7.45218 15.818C7.99925 16.3529 8.50057 17.1167 8.8537 18.0235C9.19584 18.9028 9.34221 19.7766 9.31294 20.5258L7.34423 18.8826L7.34606 18.8845ZM5.31515 15.0706C5.79269 14.8837 6.34707 15.0065 6.89048 15.3618L6.5465 17.9228C6.48612 17.9154 6.42758 17.9209 6.37269 17.9411C6.33975 17.9539 6.30865 17.9722 6.2812 17.996L4.3436 16.3785C4.50095 15.7355 4.82846 15.2592 5.31332 15.0706H5.31515ZM4.70221 19.6447C4.35458 18.7489 4.20821 17.8605 4.2448 17.1021L6.10373 18.6537C6.11836 18.802 6.15496 18.9614 6.21717 19.1208C6.25559 19.2197 6.30133 19.3113 6.35073 19.3956L6.03237 21.7751C5.51275 21.2439 5.0407 20.5093 4.70404 19.6429L4.70221 19.6447ZM6.59224 22.2587L6.90877 19.8938C6.98562 19.9121 7.06064 19.9121 7.12833 19.8847C7.21616 19.8499 7.28385 19.7784 7.33142 19.6813L9.22146 21.2585C9.06776 21.918 8.7366 22.4089 8.24259 22.6013C7.74127 22.7955 7.15761 22.6544 6.59224 22.2587Z" fill="white"/>
|
||||||
|
<path d="M6.96733 18.639C7.22714 19.0585 7.22531 19.5293 6.9783 19.6795C6.7313 19.8297 6.31048 19.6099 6.07995 19.1739C5.83477 18.7104 5.82928 18.2928 6.05799 18.1462C6.32512 17.9777 6.7002 18.2104 6.96733 18.639Z" fill="#3FA79E"/>
|
||||||
|
<path d="M92.3262 11.9142C92.4908 11.2914 92.7653 10.7015 93.1495 10.1428C93.5337 9.58411 94.0003 9.095 94.5492 8.67185C95.0981 8.25052 95.7165 7.92079 96.4008 7.68265C97.0869 7.44451 97.8151 7.32544 98.5818 7.32544H102.589L102.04 9.60609H100.283C99.3685 9.60609 98.6092 9.8314 98.0054 10.2784C97.4016 10.7272 97.0266 11.2731 96.8802 11.9124L96.3038 14.193H99.7893L99.213 16.4737H95.7275L92.9007 27.9319H88.3448L92.3243 11.9124L92.3262 11.9142Z" fill="#4E1480"/>
|
||||||
|
<path d="M102.838 11.9142C103.002 11.2914 103.277 10.7015 103.661 10.1428C104.045 9.58411 104.512 9.095 105.061 8.67185C105.609 8.25052 106.228 7.92079 106.912 7.68265C107.598 7.44451 108.326 7.32544 109.093 7.32544H113.1L112.551 9.60609H110.795C109.88 9.60609 109.121 9.8314 108.517 10.2784C107.913 10.7272 107.538 11.2731 107.392 11.9124L106.815 14.193H110.301L109.724 16.4737H106.239L103.412 27.9319H98.8562L102.836 11.9124L102.838 11.9142Z" fill="#4E1480"/>
|
||||||
|
<path d="M122.872 11.9143L122.296 14.195H120.567C119.652 14.195 118.893 14.4203 118.289 14.8672C117.685 15.316 117.301 15.8619 117.136 16.5013L114.309 27.932H109.726L112.553 16.5287C112.699 15.9242 112.959 15.3435 113.336 14.783C113.711 14.2243 114.174 13.7297 114.723 13.2992C115.272 12.8687 115.894 12.5298 116.589 12.2825C117.284 12.0352 118.035 11.9106 118.84 11.9106H122.874L122.872 11.9143Z" fill="#4E1480"/>
|
||||||
|
<path d="M126.33 27.9338C124.976 27.9338 123.946 27.6041 123.242 26.9446C122.537 26.2851 122.184 25.4516 122.184 24.4441C122.184 24.1327 122.23 23.7663 122.322 23.345L124.023 16.4756C124.188 15.8528 124.462 15.2629 124.846 14.7042C125.231 14.1455 125.697 13.6601 126.246 13.2479C126.795 12.8357 127.417 12.5115 128.112 12.2715C128.808 12.0334 129.54 11.9143 130.308 11.9143H133.766C135.12 11.9143 136.145 12.2404 136.84 12.8907C137.535 13.541 137.883 14.3708 137.883 15.3783C137.883 15.7081 137.837 16.0836 137.746 16.5049L136.62 21.0662H127.481L126.905 23.3743C126.74 24.0155 126.844 24.5559 127.221 24.9955C127.596 25.4352 128.24 25.655 129.157 25.655H133.768L133.219 27.9356H126.33V27.9338ZM128.059 18.7837H132.643L133.192 16.4903C133.338 15.8528 133.246 15.3105 132.917 14.8654C132.588 14.4184 132.103 14.1968 131.463 14.1968C131.151 14.1968 130.84 14.2554 130.529 14.3745C130.218 14.4935 129.935 14.6566 129.679 14.8654C129.422 15.0742 129.199 15.3197 129.007 15.6018C128.815 15.8839 128.681 16.1807 128.61 16.4903L128.061 18.7837H128.059Z" fill="#4E1480"/>
|
||||||
|
<path d="M140.684 27.9337V23.345H145.267V27.9337H140.684Z" fill="#4E1480"/>
|
||||||
|
<path d="M152.099 11.9142H156.682L152.703 27.9337H148.12L152.099 11.9142ZM153.224 7.32544H157.808L157.259 9.60609H152.675L153.224 7.32544Z" fill="#3FA79E"/>
|
||||||
|
<path d="M162.446 27.9338C161.092 27.9338 160.062 27.6041 159.357 26.9446C158.653 26.2851 158.3 25.4516 158.3 24.4441C158.3 24.1327 158.346 23.7664 158.437 23.345L160.139 16.4756C160.303 15.8528 160.578 15.2629 160.962 14.7042C161.346 14.1455 161.813 13.6601 162.362 13.2479C162.911 12.8357 163.533 12.5115 164.228 12.2715C164.923 12.0334 165.655 11.9143 166.423 11.9143H169.882C171.235 11.9143 172.26 12.244 172.955 12.9035C173.651 13.563 173.998 14.3873 173.998 15.3765C173.998 15.6879 173.952 16.0543 173.861 16.4756L172.159 23.345C171.995 23.9862 171.72 24.5815 171.336 25.1311C170.952 25.6806 170.485 26.1661 169.936 26.5874C169.387 27.0087 168.769 27.3384 168.085 27.5766C167.399 27.8147 166.67 27.9338 165.902 27.9338H162.444H162.446ZM169.28 16.5031C169.444 15.8619 169.362 15.3179 169.033 14.8691C168.703 14.4203 168.218 14.1968 167.578 14.1968C166.938 14.1968 166.343 14.4221 165.794 14.8691C165.245 15.3179 164.888 15.8638 164.724 16.5031L163.022 23.345C162.857 23.9862 162.94 24.5321 163.269 24.979C163.598 25.4278 164.083 25.6513 164.724 25.6513C165.035 25.6513 165.346 25.5927 165.657 25.4736C165.968 25.3546 166.251 25.1897 166.508 24.979C166.764 24.7684 166.983 24.5266 167.166 24.2518C167.349 23.977 167.486 23.6748 167.578 23.345L169.28 16.5031Z" fill="#3FA79E"/>
|
||||||
|
<path d="M83.5749 13.4C80.0821 12.5042 76.4393 14.9497 75.4385 18.8607C74.4376 22.7717 76.4576 26.6699 79.9522 27.5657C83.445 28.4614 87.0879 26.0159 88.0887 22.1049C89.0895 18.1939 87.0696 14.2958 83.5749 13.4ZM82.876 21.1597C82.9126 21.0754 82.9437 20.9875 82.9675 20.8959C83.015 20.7072 83.0297 20.5185 83.0132 20.3372L86.667 17.8844C87.1391 19.0567 87.2507 20.4325 86.8994 21.81C86.5573 23.1454 85.8345 24.2665 84.8996 25.0652L82.8742 21.1597H82.876ZM83.2584 14.7867C84.433 15.0871 85.4009 15.8107 86.0724 16.7797L82.3966 19.2472C82.285 19.174 82.1624 19.119 82.027 19.0842C81.9447 19.0622 81.8624 19.0512 81.78 19.0476L79.7875 15.2025C80.8524 14.6585 82.0655 14.4808 83.2584 14.7867ZM76.6918 19.1941C77.0394 17.8349 77.7822 16.6973 78.741 15.8968L80.653 19.5843C80.5084 19.762 80.3968 19.9782 80.3346 20.22C80.2962 20.3702 80.2797 20.5204 80.2815 20.6669L76.8638 22.9604C76.4429 21.8228 76.3551 20.5094 76.6918 19.1941ZM77.4273 24.0888L80.8231 21.81C80.9549 21.9126 81.1067 21.9914 81.2751 22.0335C81.4928 22.0884 81.7123 22.0811 81.9191 22.0243L83.8622 25.7741C82.7845 26.342 81.5477 26.5307 80.3346 26.2193C79.1051 25.9042 78.1006 25.1275 77.4273 24.0888Z" fill="#3FA79E"/>
|
||||||
|
<path d="M81.4104 27.8405C80.9183 27.8405 80.4224 27.78 79.9303 27.6536C78.2159 27.214 76.7942 26.0526 75.9306 24.3856C75.0689 22.7223 74.8621 20.7512 75.3525 18.837C75.841 16.9227 76.9681 15.2942 78.5233 14.25C80.0821 13.204 81.8843 12.8706 83.6005 13.3103C87.1373 14.217 89.1901 18.172 88.1802 22.127C87.3093 25.5305 84.4477 27.8405 81.4123 27.8405H81.4104ZM82.1075 13.3048C80.9055 13.3048 79.7052 13.6785 78.6257 14.4039C77.1071 15.4224 76.0075 17.0143 75.5299 18.8846C75.0524 20.7549 75.2518 22.6783 76.0935 24.3032C76.9333 25.9244 78.3128 27.051 79.976 27.4778C83.4139 28.3607 87.0147 25.939 88.0009 22.083C88.987 18.227 86.9927 14.3709 83.553 13.4898C83.0754 13.3671 82.5906 13.3066 82.1057 13.3066L82.1075 13.3048ZM81.5074 26.4574C81.1049 26.4574 80.7042 26.408 80.3127 26.3072C79.1106 25.9995 78.0585 25.2283 77.3504 24.1383L77.301 24.0632L80.8268 21.6965L80.8798 21.7368C81.0079 21.8357 81.147 21.9053 81.2988 21.9438C81.4946 21.9932 81.694 21.9914 81.8953 21.9346L81.9667 21.9145L83.9866 25.8108L83.9061 25.8529C83.1468 26.2523 82.3253 26.4556 81.5074 26.4556V26.4574ZM77.5535 24.1145C78.236 25.1257 79.2277 25.8401 80.3584 26.1314C81.4855 26.4208 82.6528 26.2834 83.7396 25.7357L81.8715 22.1324C81.6629 22.1782 81.4562 22.1764 81.2531 22.1251C81.0994 22.0867 80.9549 22.0189 80.8213 21.9236L77.5554 24.1163L77.5535 24.1145ZM84.874 25.2099L82.7754 21.1634L82.7937 21.1231C82.8303 21.0388 82.8595 20.9564 82.8815 20.874C82.9254 20.7018 82.94 20.5241 82.9254 20.3464L82.9199 20.2933L86.7128 17.747L86.7549 17.8514C87.2489 19.0806 87.333 20.4948 86.9909 21.8339C86.6542 23.1473 85.9535 24.2904 84.9618 25.1348L84.874 25.2099ZM82.9785 21.1561L84.9307 24.9205C85.8474 24.1072 86.4969 23.0264 86.8134 21.7881C87.1373 20.5241 87.0696 19.1923 86.6268 18.0236L83.1102 20.383C83.1193 20.5644 83.1029 20.7439 83.0571 20.9179C83.037 20.9967 83.0114 21.0755 82.9785 21.1542V21.1561ZM76.818 23.1015L76.7778 22.9934C76.3332 21.7881 76.2728 20.4673 76.6021 19.1722C76.9388 17.8533 77.678 16.6644 78.6806 15.8272L78.7684 15.754L80.7609 19.5953L80.7225 19.6411C80.5798 19.817 80.4792 20.0185 80.4224 20.242C80.3877 20.3812 80.3694 20.5223 80.373 20.6633V20.7128L76.8198 23.0997L76.818 23.1015ZM76.6918 19.1942L76.7796 19.2161C76.4686 20.4362 76.5125 21.6781 76.9095 22.8194L80.1882 20.6193C80.1882 20.4783 80.2084 20.3372 80.2431 20.1998C80.3017 19.9709 80.4023 19.762 80.5414 19.577L78.7099 16.0434C77.7804 16.8512 77.0961 17.9742 76.7778 19.218L76.6899 19.196L76.6918 19.1942ZM82.3985 19.3572L82.3472 19.3242C82.2411 19.2546 82.1277 19.2033 82.0051 19.1722C81.9337 19.1539 81.8587 19.1429 81.7764 19.1392H81.7233L79.6631 15.1641L79.7455 15.122C80.8798 14.5431 82.1021 14.3966 83.2804 14.6988C84.4422 14.9956 85.432 15.699 86.1474 16.7285L86.2005 16.8054L82.3966 19.359L82.3985 19.3572ZM81.8386 18.9597C81.9136 18.9652 81.9831 18.978 82.0508 18.9945C82.1716 19.0256 82.2868 19.0733 82.3948 19.1374L85.9425 16.756C85.2582 15.8034 84.3233 15.1549 83.2346 14.8747C82.1277 14.5907 80.9805 14.719 79.9101 15.2429L81.8368 18.9597H81.8386Z" fill="#3FA79E"/>
|
||||||
|
<path d="M34.8329 7.37695H39.4162L34.8603 25.7046H41.7215L41.1726 27.9852H29.7281L34.8329 7.37695Z" fill="#4E1480"/>
|
||||||
|
<path d="M49.1572 7.37695H60.6017L60.0528 9.6576H53.1916L51.4626 16.5545H57.72L57.1711 18.8351H50.9137L49.1847 25.7046H56.0459L55.497 27.9852H44.0525L49.1572 7.37695Z" fill="#4E1480"/>
|
||||||
|
<path d="M65.7887 23.3964C65.6241 24.0376 65.7064 24.5835 66.0357 25.0304C66.3651 25.4792 66.8499 25.7027 67.4903 25.7027C68.826 25.7027 69.7865 24.9333 70.372 23.3946H72.6499C72.1742 24.9333 71.4424 26.0837 70.4544 26.844C69.4663 27.6042 68.1124 27.9834 66.3925 27.9834H65.2124C63.8585 27.9834 62.8284 27.6536 62.1239 26.9942C61.4195 26.3347 61.0664 25.5012 61.0664 24.4937C61.0664 24.1823 61.1121 23.8159 61.2036 23.3946L62.9052 16.5252C63.0699 15.9023 63.3443 15.3125 63.7285 14.7538C64.1128 14.1951 64.5793 13.7096 65.1282 13.2975C65.6771 12.8853 66.2992 12.561 66.9945 12.3211C67.6897 12.0829 68.4216 11.9639 69.1901 11.9639H70.3702C71.8522 11.9639 72.9134 12.2258 73.5538 12.7479C74.1942 13.27 74.5144 14.0522 74.5144 15.0982C74.5144 15.5378 74.4595 16.0141 74.3497 16.527H72.0718C72.273 15.0066 71.6967 14.2463 70.3427 14.2463C69.7024 14.2463 69.1077 14.4717 68.5588 14.9186C68.0099 15.3674 67.6532 15.9133 67.4885 16.5526L65.7869 23.3946L65.7887 23.3964Z" fill="#4E1480"/>
|
||||||
|
<path d="M134.897 37.6811C134.613 37.6811 134.251 37.5895 134.081 37.3844V37.5749H133.599V32.6948H134.093V34.6128C134.331 34.2574 134.666 33.9863 135.134 33.9863C135.925 33.9863 136.424 34.7502 136.424 35.7595C136.424 36.7689 135.905 37.6774 134.897 37.6774V37.6811ZM134.97 34.4571C134.62 34.4571 134.397 34.6476 134.245 34.8454C134.121 35.0103 134.093 35.0836 134.093 35.2612V36.778C134.093 37.0619 134.344 37.2799 134.818 37.2799C135.542 37.2799 135.91 36.6461 135.91 35.8694C135.91 35.0927 135.601 34.4589 134.968 34.4589L134.97 34.4571Z" fill="#320756"/>
|
||||||
|
<path d="M138.481 37.8203C138.283 38.4065 137.954 38.9341 137.085 39L137.045 38.5586C137.584 38.5512 137.921 38.2087 138.066 37.6884L136.794 34.0889H137.334L138.033 36.212C138.164 36.6077 138.276 36.9832 138.316 37.1096H138.329C138.375 36.9246 138.481 36.582 138.6 36.1937L139.246 34.0907H139.714L138.483 37.8222L138.481 37.8203Z" fill="#320756"/>
|
||||||
|
<path d="M144.455 37.5766V33.6637C144.455 32.8504 143.983 32.3778 143.137 32.3778C142.599 32.3778 142.127 32.6196 141.798 33.0482C141.589 33.301 141.556 33.4219 141.556 33.7517V37.5766H140.733V31.7623H141.502V32.6855C141.941 32.0371 142.555 31.5974 143.401 31.5974C144.51 31.5974 145.278 32.2789 145.278 33.5318V37.5766H144.455Z" fill="#059C8C"/>
|
||||||
|
<path d="M149.219 37.7854C147.408 37.7854 146.65 36.2247 146.65 34.6529C146.65 33.0812 147.485 31.5645 149.263 31.5645C151.041 31.5645 151.832 33.0812 151.832 34.6639C151.832 36.2467 150.998 37.7854 149.219 37.7854ZM149.263 32.2789C147.957 32.2789 147.507 33.5868 147.507 34.6529C147.507 35.7191 147.891 37.06 149.219 37.06C150.547 37.06 150.976 35.6971 150.976 34.6639C150.976 33.6308 150.591 32.2789 149.263 32.2789Z" fill="#059C8C"/>
|
||||||
|
<path d="M154.873 37.7635C153.841 37.7635 153.391 37.0491 153.391 36.1808V32.5647H152.414V31.8723H153.391V30.5973L154.214 30.3005V31.8723H155.795V32.5647H154.214V36.0818C154.214 36.7193 154.532 37.0491 155.136 37.0491C155.389 37.0491 155.608 36.9721 155.773 36.8842L155.927 37.5656C155.663 37.6755 155.257 37.7635 154.873 37.7635Z" fill="#059C8C"/>
|
||||||
|
<path d="M157.661 37.6426C157.321 37.6426 157.09 37.4008 157.09 37.0601C157.09 36.7193 157.31 36.4775 157.65 36.4775C157.991 36.4775 158.221 36.7193 158.221 37.0601C158.221 37.4008 158.001 37.6426 157.661 37.6426Z" fill="#25124B"/>
|
||||||
|
<path d="M159.418 37.5766V29.8169H160.318V37.5766H159.418Z" fill="#25124B"/>
|
||||||
|
<path d="M164.127 30.6412V37.5766H163.216V30.6412H160.658V29.8169H166.718V30.6412H164.127Z" fill="#25124B"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_2800_16209">
|
||||||
|
<rect width="174" height="39" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 17 KiB |
@ -1,112 +0,0 @@
|
|||||||
import BasePage from "@Front/Components/Layouts/Base";
|
|
||||||
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
|
|
||||||
import classes from "./classes.module.scss";
|
|
||||||
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
|
||||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
|
||||||
import Toasts, { IToast } from "@Front/Stores/Toasts";
|
|
||||||
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
|
|
||||||
import HeaderLink from "@Front/Components/DesignSystem/Header/HeaderLink";
|
|
||||||
|
|
||||||
type IState = {
|
|
||||||
isModalDisplayed: boolean
|
|
||||||
}
|
|
||||||
type IProps = {
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class DesignSystem extends BasePage<IProps, IState> {
|
|
||||||
constructor(props: IProps) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
isModalDisplayed: false
|
|
||||||
}
|
|
||||||
this.openModal = this.openModal.bind(this);
|
|
||||||
this.closeModal = this.closeModal.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
|
||||||
return (
|
|
||||||
<DefaultTemplate title={"HomePage"}>
|
|
||||||
<div className={classes["root"]}>
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H1}>Website design System</Typography>
|
|
||||||
</div>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.P_18}>
|
|
||||||
This page allows to gather all the design system of the site. A
|
|
||||||
Design System is a library of components, visuals and principles
|
|
||||||
with reusable code. This evolving kit offers a UX and UI
|
|
||||||
repository for designers and developers of digital products and
|
|
||||||
services. The construction of a design system offers many
|
|
||||||
advantages. This solution facilitates the work of the teams and
|
|
||||||
reduces the "design debt" and the "technical debt". The result
|
|
||||||
is a coherent ecosystem and therefore a better experience for
|
|
||||||
users and customers.
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>Button components</Typography>
|
|
||||||
</div>
|
|
||||||
<Button variant={EButtonVariant.PRIMARY}>Primary</Button>
|
|
||||||
<Button variant={EButtonVariant.SECONDARY}>Secondary</Button>
|
|
||||||
<Button variant={EButtonVariant.GHOST}>Ghost</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>Toaster component</Typography>
|
|
||||||
</div>
|
|
||||||
<Button variant={EButtonVariant.PRIMARY} onClick={this.spawnToast}>Spawn a toast</Button>
|
|
||||||
</div>
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>Modal components</Typography>
|
|
||||||
</div>
|
|
||||||
<Button variant={EButtonVariant.PRIMARY} onClick={this.openModal}>Show Modal</Button>
|
|
||||||
|
|
||||||
<Confirm
|
|
||||||
isOpen={this.state.isModalDisplayed}
|
|
||||||
onClose={this.closeModal}
|
|
||||||
closeBtn
|
|
||||||
header={"Title"}
|
|
||||||
cancelText={"Cancel"}
|
|
||||||
confirmText={"Confirmer"}>
|
|
||||||
Lorem ipsum dolor sit amet consectetur. Aliquam nunc lobortis lacus vulputate sagittis sed tempor eget feugiat. Elementum malesuada at sit elit.
|
|
||||||
</Confirm>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>HeaderLink components</Typography>
|
|
||||||
</div>
|
|
||||||
<div className={classes["inline-flex"]}>
|
|
||||||
<HeaderLink text={"Home"} path={"/"} />
|
|
||||||
<HeaderLink text={"Design-system"} path={"/design-system"} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</DefaultTemplate>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
private openModal() {
|
|
||||||
this.setState({
|
|
||||||
isModalDisplayed: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
private closeModal() {
|
|
||||||
this.setState({
|
|
||||||
isModalDisplayed: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private spawnToast() {
|
|
||||||
const toast: IToast = { title: "Un collaborateur veut rejoindre votre office", text: "12:00 - 1 fev 2023" }
|
|
||||||
Toasts.getInstance().open(toast)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user