📦 NEW: frontend: Modifier info et Article
This commit is contained in:
		
							
								
								
									
										129
									
								
								website/components/AddEditFunction.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								website/components/AddEditFunction.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,129 @@ | ||||
| import { Fragment, useState, useEffect } from 'react'; | ||||
| import htmlParser from 'html-react-parser'; | ||||
| import Loader from '../components/Loader'; | ||||
| import useAPI from '../hooks/useAPI'; | ||||
| import api from '../utils/api'; | ||||
| import '../public/css/pages/admin.css'; | ||||
|  | ||||
| const AddEditFunction = (props) => { | ||||
|  | ||||
|     const [, categories]              = useAPI('/categories'); | ||||
|     const [inputState, setInputState] = useState(props.defaultInputState); | ||||
|     const [message, setMessage]       = useState(""); | ||||
|     const [isLoading, setIsLoading]   = useState(false); | ||||
|  | ||||
|     useEffect(() => { | ||||
|         if (categories.length > 0 && !props.isEditing) { | ||||
|             handleChange({ | ||||
|                 target: { | ||||
|                     name: "categorieId", | ||||
|                     value: categories[0].id | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|     }, [categories]); | ||||
|  | ||||
|     const apiCallFunction = (formData) => { | ||||
|         if (props.isEditing) return api.put(`/admin/functions/${inputState.id}`, formData, { headers: { 'Authorization': props.user.token } }); | ||||
|         return api.post('/admin/functions', formData, { headers: { 'Authorization': props.user.token } }); | ||||
|     } | ||||
|  | ||||
|     const handleChange = (event, isTypeCheck = false) => { | ||||
|         const inputStateNew = { ...inputState }; | ||||
|         inputStateNew[event.target.name] = (event.target.files != undefined) ? event.target.files[0] : (isTypeCheck) ? event.target.checked : event.target.value; | ||||
|         setInputState(inputStateNew); | ||||
|     } | ||||
|  | ||||
|     const handleSubmit = (event) => { | ||||
|         event.preventDefault(); | ||||
|         setIsLoading(true); | ||||
|         const formData = new FormData(); | ||||
|         formData.append('type', inputState.type); | ||||
|         formData.append('categorieId', inputState.categorieId); | ||||
|         formData.append('title', inputState.title); | ||||
|         formData.append('slug', inputState.slug); | ||||
|         formData.append('description', inputState.description); | ||||
|         formData.append('image', inputState.image); | ||||
|  | ||||
|         if (props.isEditing) { | ||||
|             formData.append('isOnline', inputState.isOnline); | ||||
|         } | ||||
|  | ||||
|         apiCallFunction(formData) | ||||
|             .then(() => { | ||||
|                 setIsLoading(false); | ||||
|                 window.location.reload(true); | ||||
|             }) | ||||
|             .catch((error) => { | ||||
|                 setMessage(`<p class="form-error"><b>Erreur:</b> ${error.response.data.message}</p>`); | ||||
|                 setIsLoading(false); | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     return ( | ||||
|         <Fragment> | ||||
|             <form onSubmit={handleSubmit}> | ||||
|                 <div className="form-group"> | ||||
|                     <label className="form-label" htmlFor="title">Titre :</label> | ||||
|                     <input value={inputState.title} onChange={handleChange} type="text" name="title" id="title" className="form-control" placeholder="(e.g : Nombre aléatoire)" /> | ||||
|                 </div> | ||||
|  | ||||
|                 <div className="form-group"> | ||||
|                     <label className="form-label" htmlFor="slug">Slug :</label> | ||||
|                     <input value={inputState.slug} onChange={handleChange} type="text" name="slug" id="slug" className="form-control" placeholder="(e.g : randomNumber)" /> | ||||
|                 </div> | ||||
|  | ||||
|                 <div className="form-group"> | ||||
|                     <label className="form-label" htmlFor="description">Description :</label> | ||||
|                     <textarea style={{ height: 'auto' }} value={inputState.description} onChange={handleChange} name="description" id="description" className="form-control" rows="5"></textarea> | ||||
|                 </div> | ||||
|  | ||||
|                 <div className="form-group"> | ||||
|                     <label className="form-label" htmlFor="type">Type :</label> | ||||
|                     <select onChange={handleChange} name="type" id="type" className="form-control" { ...(props.isEditing) && { value: inputState.type } }> | ||||
|                         <option value="form">Formulaire</option> | ||||
|                         <option value="article">Article</option> | ||||
|                         <option value="page">Page</option> | ||||
|                     </select> | ||||
|                 </div> | ||||
|  | ||||
|                 <div className="form-group"> | ||||
|                     <label className="form-label" htmlFor="categorieId">Catégorie :</label> | ||||
|                     <select onChange={handleChange} name="categorieId" id="categorieId" className="form-control" { ...(props.isEditing) && { value: inputState.categorieId } }> | ||||
|                         {categories.map((category) => ( | ||||
|                             <option key={category.id} value={category.id} className="Admin__Modal-select-option" style={{ backgroundColor: category.color }}>{category.name}</option> | ||||
|                         ))} | ||||
|                     </select> | ||||
|                 </div> | ||||
|  | ||||
|                 <div className="form-group"> | ||||
|                     <label className="form-label" htmlFor="image">Image <em>(150x150 recommandé)</em> :</label> | ||||
|                     <br/> | ||||
|                     <input onChange={handleChange} accept="image/jpeg,image/jpg,image/png" type="file" name="image" id="image" /> | ||||
|                 </div> | ||||
|  | ||||
|                 {(props.isEditing) &&                  | ||||
|                     <div className="form-group custom-control custom-switch"> | ||||
|                         <input onChange={(event) => handleChange(event, true)} type="checkbox" name="isOnline" checked={inputState.isOnline} className="custom-control-input" id="isOnline" /> | ||||
|                         <label className="custom-control-label" htmlFor="isOnline">isOnline</label> | ||||
|                     </div> | ||||
|                 } | ||||
|  | ||||
|                 <div className="form-group text-center"> | ||||
|                     <button type="submit" className="btn btn-dark">Envoyer</button> | ||||
|                 </div> | ||||
|             </form> | ||||
|  | ||||
|             <div className="form-result text-center"> | ||||
|                 { | ||||
|                     (isLoading) ?  | ||||
|                         <Loader /> | ||||
|                     : | ||||
|                         htmlParser(message) | ||||
|                 } | ||||
|             </div> | ||||
|         </Fragment> | ||||
|     ); | ||||
| } | ||||
|  | ||||
| export default AddEditFunction; | ||||
							
								
								
									
										46
									
								
								website/components/EditArticleFunction.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								website/components/EditArticleFunction.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| import { useState } from 'react'; | ||||
| import 'suneditor/dist/css/suneditor.min.css'; | ||||
| import dynamic from 'next/dynamic'; | ||||
| import htmlParser from 'html-react-parser'; | ||||
| import { complex } from '../utils/sunEditorConfig'; | ||||
| import api from '../utils/api'; | ||||
| import 'notyf/notyf.min.css'; // for React and Vue | ||||
|  | ||||
| const SunEditor = dynamic( | ||||
|     () => import('suneditor-react'), | ||||
|     { ssr: false } | ||||
| ); | ||||
|  | ||||
| const EditArticleFunction = (props) => { | ||||
|  | ||||
|     const [htmlContent, setHtmlContent] = useState(""); | ||||
|  | ||||
|     const handleEditorChange = (content) => { | ||||
|         setHtmlContent(content); | ||||
|     } | ||||
|  | ||||
|     const handleSave = async (content) => { | ||||
|         let Notyf; | ||||
|         if (typeof window != 'undefined') { | ||||
|             Notyf = require('notyf'); | ||||
|         } | ||||
|         const notyf = new Notyf.Notyf({ | ||||
|             duration: 5000 | ||||
|         }); | ||||
|         try { | ||||
|             await api.put(`/admin/functions/article/${props.functionInfo.id}`, { article: content }, { headers: { 'Authorization': props.user.token } }); | ||||
|             notyf.success('Sauvegardé!'); | ||||
|         } catch {} | ||||
|     } | ||||
|  | ||||
|     return ( | ||||
|         <div className="container-fluid"> | ||||
|             <SunEditor setContents={props.functionInfo.article} lang="fr" onChange={handleEditorChange} setOptions={{ buttonList: complex, callBackSave: handleSave }} /> | ||||
|             <div className="container-fluid"> | ||||
|                 {htmlParser(htmlContent)} | ||||
|             </div> | ||||
|         </div> | ||||
|     ); | ||||
| } | ||||
|  | ||||
| export default EditArticleFunction; | ||||
| @@ -1,7 +1,16 @@ | ||||
| import htmlParser from 'html-react-parser'; | ||||
| import FunctionTabs from './FunctionTabs/FunctionTabs'; | ||||
| import FunctionForm from './FunctionForm'; | ||||
| import FunctionComments from './FunctionComments/FunctionComments'; | ||||
|  | ||||
| const Article = ({ article }) => { | ||||
|     return ( | ||||
|         <div className="container-fluid"> | ||||
|             {(article != undefined) && htmlParser(article)} | ||||
|         </div> | ||||
|     ); | ||||
| } | ||||
|  | ||||
| const FunctionTabManager = (props) => { | ||||
|     if (props.type === "form") { | ||||
|         return ( | ||||
| @@ -9,7 +18,9 @@ const FunctionTabManager = (props) => { | ||||
|                 <div className="FunctionComponent__slide"> | ||||
|                     <FunctionForm inputArray={ [...props.utilizationForm || []] } slug={props.slug} /> | ||||
|                 </div> | ||||
|                 <div className="FunctionComponent__slide text-center">Article</div> | ||||
|                 <div className="FunctionComponent__slide"> | ||||
|                     <Article article={props.article} /> | ||||
|                 </div> | ||||
|                 <div className="FunctionComponent__slide"> | ||||
|                     <FunctionComments functionId={props.id} /> | ||||
|                 </div> | ||||
| @@ -19,7 +30,9 @@ const FunctionTabManager = (props) => { | ||||
|  | ||||
|     return ( | ||||
|         <FunctionTabs type={props.type}> | ||||
|             <div className="FunctionComponent__slide text-center">Article</div> | ||||
|             <div className="FunctionComponent__slide"> | ||||
|                 <Article article={props.article} /> | ||||
|             </div> | ||||
|             <div className="FunctionComponent__slide"> | ||||
|                 <FunctionComments functionId={props.id} /> | ||||
|             </div> | ||||
|   | ||||
							
								
								
									
										19
									
								
								website/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										19
									
								
								website/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -5862,6 +5862,11 @@ | ||||
|         "sort-keys": "^1.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "notyf": { | ||||
|       "version": "3.6.0", | ||||
|       "resolved": "https://registry.npmjs.org/notyf/-/notyf-3.6.0.tgz", | ||||
|       "integrity": "sha512-TqirJJOj5xTrkUGbat94aeFdBCMuJqlxvFAeySV08WRhcZDVzegIsQrYgek1ZN/Vhc+Ux3BgUmndS4ii1W2TJg==" | ||||
|     }, | ||||
|     "nprogress": { | ||||
|       "version": "0.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", | ||||
| @@ -9537,6 +9542,20 @@ | ||||
|       "resolved": "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz", | ||||
|       "integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw==" | ||||
|     }, | ||||
|     "suneditor": { | ||||
|       "version": "2.28.4", | ||||
|       "resolved": "https://registry.npmjs.org/suneditor/-/suneditor-2.28.4.tgz", | ||||
|       "integrity": "sha512-KLmKMq1QrBT9GT+/yv0d/a6YGEQ5+QUSmzZYJaIXGJ8QNNRV0BqfQP0gBnWY8s35HFKiU5meXWuzrI03AmubRg==" | ||||
|     }, | ||||
|     "suneditor-react": { | ||||
|       "version": "2.9.1", | ||||
|       "resolved": "https://registry.npmjs.org/suneditor-react/-/suneditor-react-2.9.1.tgz", | ||||
|       "integrity": "sha512-O26aLQ4dRWbdJv+d78pPaL/mLwWgVMiz64uo531+kHjBlNlREpV2dvvIYVH7TNxKi6LboeDZybJ5rm8kPMchAQ==", | ||||
|       "requires": { | ||||
|         "prop-types": "^15.7.2", | ||||
|         "suneditor": "^2.28.4" | ||||
|       } | ||||
|     }, | ||||
|     "supports-color": { | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", | ||||
|   | ||||
| @@ -18,12 +18,14 @@ | ||||
|     "html-react-parser": "^0.10.2", | ||||
|     "next": "9.3.2", | ||||
|     "next-fonts": "^1.0.3", | ||||
|     "notyf": "^3.6.0", | ||||
|     "nprogress": "^0.2.0", | ||||
|     "react": "16.13.0", | ||||
|     "react-color": "^2.18.0", | ||||
|     "react-dom": "16.13.0", | ||||
|     "react-swipeable-views": "^0.13.9", | ||||
|     "react-swipeable-views-utils": "^0.13.9", | ||||
|     "suneditor-react": "^2.9.1", | ||||
|     "universal-cookie": "^4.0.3" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|   | ||||
| @@ -1,31 +1,76 @@ | ||||
| import { Fragment } from 'react'; | ||||
| import { Fragment, useState } from 'react'; | ||||
| import Cookies from "universal-cookie"; | ||||
| import SwipeableViews from 'react-swipeable-views'; | ||||
| import HeadTag from '../../components/HeadTag'; | ||||
| import AddEditFunction from '../../components/AddEditFunction'; | ||||
| import EditArticleFunction from '../../components/EditArticleFunction'; | ||||
| import redirect from '../../utils/redirect'; | ||||
| import api from '../../utils/api'; | ||||
| import { API_URL } from '../../utils/config'; | ||||
| import '../../components/FunctionTabs/FunctionTabs.css'; | ||||
| import '../../public/css/pages/admin.css'; | ||||
|  | ||||
| const AdminFunctionComponent = (props) => { | ||||
|  | ||||
|     if (!props.user.isAdmin && typeof window != 'undefined') { | ||||
|         return redirect({}, '/404'); | ||||
|     } | ||||
|     const [slideIndex, setSlideIndex] = useState(0); | ||||
|  | ||||
|     return ( | ||||
|         <Fragment> | ||||
|             <HeadTag /> | ||||
|             <p>{props.slug}</p> | ||||
|             <HeadTag title={props.functionInfo.title} description={props.functionInfo.description} image={API_URL + props.functionInfo.image} /> | ||||
|  | ||||
|             <div className="container-fluid"> | ||||
|                 <div className="container"> | ||||
|                     <div className="row justify-content-center"> | ||||
|                         <ul className="FunctionTabs__nav"> | ||||
|                             <li className="FunctionTabs__nav-item"> | ||||
|                                 <a onClick={() => setSlideIndex(0)} className={`FunctionTabs__nav-link ${(slideIndex === 0) && "FunctionTabs__nav-link-active"}`}>✒️ Modifier</a> | ||||
|                             </li> | ||||
|                             <li className="FunctionTabs__nav-item"> | ||||
|                                 <a onClick={() => setSlideIndex(1)} className={`FunctionTabs__nav-link ${(slideIndex === 1) && "FunctionTabs__nav-link-active"}`}>📝 Article</a> | ||||
|                             </li> | ||||
|                             <li className="FunctionTabs__nav-item"> | ||||
|                                 <a onClick={() => setSlideIndex(2)} className={`FunctionTabs__nav-link ${(slideIndex === 2) && "FunctionTabs__nav-link-active"}`}>⚙️ Utilisation</a> | ||||
|                             </li> | ||||
|                         </ul> | ||||
|                     </div> | ||||
|                 </div> | ||||
|  | ||||
|                 <div className="container-fluid"> | ||||
|                     <SwipeableViews onChangeIndex={(index) => setSlideIndex(index)} index={slideIndex}> | ||||
|                         <div className="Admin__Function-slide"> | ||||
|                             <AddEditFunction  | ||||
|                                 defaultInputState={{ ...props.functionInfo }}  | ||||
|                                 user={props.user}  | ||||
|                                 isEditing | ||||
|                             /> | ||||
|                         </div> | ||||
|                         <div className="Admin__Function-slide"> | ||||
|                             <EditArticleFunction { ...props } /> | ||||
|                         </div> | ||||
|                     </SwipeableViews> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </Fragment> | ||||
|     ); | ||||
| } | ||||
|  | ||||
| export async function getServerSideProps({ req, params }) { | ||||
|     const cookies = new Cookies(req.headers.cookie); | ||||
|     const { slug } = params; | ||||
|     return { | ||||
|         props: { | ||||
|             user: { ...cookies.get('user') }, | ||||
|             slug | ||||
|         } | ||||
|     }; | ||||
| export async function getServerSideProps(context) { | ||||
|     const cookies  = new Cookies(context.req.headers.cookie); | ||||
|     const user     = { ...cookies.get('user') }; | ||||
|     const { slug } = context.params; | ||||
|     if (!user.isAdmin) { | ||||
|         return redirect(context, '/404'); | ||||
|     } | ||||
|     return api.get(`/admin/functions/${slug}`, { headers: { 'Authorization': user.token } }) | ||||
|         .then((response) => { | ||||
|             return { | ||||
|                 props: { | ||||
|                     user, | ||||
|                     functionInfo: response.data | ||||
|                 } | ||||
|             }; | ||||
|         }) | ||||
|         .catch(() => redirect(context, '/404')); | ||||
| } | ||||
|  | ||||
| export default AdminFunctionComponent; | ||||
| @@ -1,67 +1,21 @@ | ||||
| import Link from 'next/link'; | ||||
| import { Fragment, useState, useEffect } from 'react'; | ||||
| import { Fragment, useState } from 'react'; | ||||
| import Cookies from "universal-cookie"; | ||||
| import HeadTag from '../../components/HeadTag'; | ||||
| import FunctionsList from '../../components/FunctionsList/FunctionsList'; | ||||
| import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; | ||||
| import { faTimes } from '@fortawesome/free-solid-svg-icons'; | ||||
| import Modal from '../../components/Modal'; | ||||
| import FunctionsList from '../../components/FunctionsList/FunctionsList'; | ||||
| import AddEditFunction from '../../components/AddEditFunction'; | ||||
| import redirect from '../../utils/redirect'; | ||||
| import htmlParser from 'html-react-parser'; | ||||
| import Loader from '../../components/Loader'; | ||||
| import useAPI from '../../hooks/useAPI'; | ||||
| import api from '../../utils/api'; | ||||
| import '../../public/css/pages/admin.css'; | ||||
|  | ||||
| const Admin = (props) => { | ||||
|  | ||||
|     const [, categories]              = useAPI('/categories'); | ||||
|     const [isOpen, setIsOpen]         = useState(false); | ||||
|     const [inputState, setInputState] = useState({ type: 'form' }); | ||||
|     const [message, setMessage]       = useState(""); | ||||
|     const [isLoading, setIsLoading]   = useState(false); | ||||
|  | ||||
|     useEffect(() => { | ||||
|         if (categories.length > 0) { | ||||
|             handleChange({ | ||||
|                 target: { | ||||
|                     name: "categorieId", | ||||
|                     value: categories[0].id | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|     }, [categories]); | ||||
|  | ||||
|     const toggleModal = () => setIsOpen(!isOpen); | ||||
|  | ||||
|     const handleChange = (event, isTypeCheck = false) => { | ||||
|         const inputStateNew = { ...inputState }; | ||||
|         inputStateNew[event.target.name] = (event.target.files != undefined) ? event.target.files[0] : (isTypeCheck) ? event.target.checked : event.target.value; | ||||
|         setInputState(inputStateNew); | ||||
|     } | ||||
|  | ||||
|     const handleSubmit = (event) => { | ||||
|         event.preventDefault(); | ||||
|         setIsLoading(true); | ||||
|         const formData = new FormData(); | ||||
|         formData.append('type', inputState.type); | ||||
|         formData.append('categorieId', inputState.categorieId); | ||||
|         formData.append('title', inputState.title); | ||||
|         formData.append('slug', inputState.slug); | ||||
|         formData.append('description', inputState.description); | ||||
|         formData.append('image', inputState.image); | ||||
|  | ||||
|         api.post('/admin/functions', formData, { headers: { 'Authorization': props.user.token } }) | ||||
|             .then((response) => { | ||||
|                 setMessage(`<p class="form-success"><b>Succès:</b> ${response.data.message}</p>`); | ||||
|                 setIsLoading(false); | ||||
|             }) | ||||
|             .catch((error) => { | ||||
|                 setMessage(`<p class="form-error"><b>Erreur:</b> ${error.response.data.message}</p>`); | ||||
|                 setIsLoading(false); | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     if (!props.user.isAdmin && typeof window != 'undefined') { | ||||
|         return redirect({}, '/404'); | ||||
|     } | ||||
| @@ -87,58 +41,7 @@ const Admin = (props) => { | ||||
|                                 </div> | ||||
|  | ||||
|                                 <div className="col-24"> | ||||
|                                     <form onSubmit={handleSubmit}> | ||||
|                                         <div className="form-group"> | ||||
|                                             <label className="form-label" htmlFor="title">Titre :</label> | ||||
|                                             <input value={inputState.title} onChange={handleChange} type="text" name="title" id="title" className="form-control" placeholder="(e.g : Nombre aléatoire)" /> | ||||
|                                         </div> | ||||
|  | ||||
|                                         <div className="form-group"> | ||||
|                                             <label className="form-label" htmlFor="slug">Slug :</label> | ||||
|                                             <input value={inputState.slug} onChange={handleChange} type="text" name="slug" id="slug" className="form-control" placeholder="(e.g : randomNumber)" /> | ||||
|                                         </div> | ||||
|  | ||||
|                                         <div className="form-group"> | ||||
|                                             <label className="form-label" htmlFor="description">Description :</label> | ||||
|                                             <textarea style={{ height: 'auto' }} value={inputState.biography} onChange={handleChange} name="description" id="description" className="form-control" rows="5"></textarea> | ||||
|                                         </div> | ||||
|  | ||||
|                                         <div className="form-group"> | ||||
|                                             <label className="form-label" htmlFor="type">Type :</label> | ||||
|                                             <select onChange={handleChange} name="type" id="type" className="form-control"> | ||||
|                                                 <option value="form">Formulaire</option> | ||||
|                                                 <option value="article">Article</option> | ||||
|                                                 <option value="page">Page</option> | ||||
|                                             </select> | ||||
|                                         </div> | ||||
|  | ||||
|                                         <div className="form-group"> | ||||
|                                             <label className="form-label" htmlFor="categorieId">Catégorie :</label> | ||||
|                                             <select onChange={handleChange} name="categorieId" id="categorieId" className="form-control"> | ||||
|                                                 {categories.map((category) => ( | ||||
|                                                     <option key={category.id} value={category.id} className="Admin__Modal-select-option" style={{ backgroundColor: category.color }}>{category.name}</option> | ||||
|                                                 ))} | ||||
|                                             </select> | ||||
|                                         </div> | ||||
|  | ||||
|                                         <div className="form-group"> | ||||
|                                             <label className="form-label" htmlFor="image">Image <em>(150x150 recommandé)</em> :</label> | ||||
|                                             <br/> | ||||
|                                             <input onChange={handleChange} accept="image/jpeg,image/jpg,image/png" type="file" name="image" id="image" /> | ||||
|                                         </div> | ||||
|  | ||||
|                                         <div className="form-group text-center"> | ||||
|                                             <button type="submit" className="btn btn-dark">Envoyer</button> | ||||
|                                         </div> | ||||
|                                     </form> | ||||
|                                     <div className="form-result text-center"> | ||||
|                                         { | ||||
|                                             (isLoading) ?  | ||||
|                                                 <Loader /> | ||||
|                                             : | ||||
|                                                 htmlParser(message) | ||||
|                                         } | ||||
|                                     </div> | ||||
|                                     <AddEditFunction defaultInputState={{ type: 'form' }} { ...props } /> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         </div> | ||||
|   | ||||
| @@ -44,6 +44,9 @@ a:hover { | ||||
| div[aria-hidden="true"] > * { | ||||
|     display: none; | ||||
| } | ||||
| .notyf__message { | ||||
|     font-family: sans-serif; | ||||
| } | ||||
|  | ||||
| /* LOADING */ | ||||
| .isLoading { | ||||
| @@ -135,4 +138,67 @@ a, .important { | ||||
|     color: #fff; | ||||
|     background-color: #343a40; | ||||
|     border-color: #343a40; | ||||
| } | ||||
| .custom-control { | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
| } | ||||
| .custom-control-input { | ||||
|     position: absolute; | ||||
|     z-index: -1; | ||||
|     opacity: 0; | ||||
| } | ||||
| .custom-control-label { | ||||
|     position: relative; | ||||
|     margin-bottom: 0; | ||||
|     vertical-align: top; | ||||
| } | ||||
| .custom-control-input:checked~.custom-control-label::before { | ||||
|     color: #fff; | ||||
|     border-color: #007bff; | ||||
|     background-color: #007bff; | ||||
| } | ||||
| .custom-switch .custom-control-label::before { | ||||
|     left: -2.25rem; | ||||
|     width: 1.75rem; | ||||
|     pointer-events: all; | ||||
|     border-radius: .5rem; | ||||
| } | ||||
| .custom-control-label::before { | ||||
|     position: absolute; | ||||
|     top: .25rem; | ||||
|     left: -1.5rem; | ||||
|     display: block; | ||||
|     width: 1rem; | ||||
|     height: 1rem; | ||||
|     pointer-events: none; | ||||
|     content: ""; | ||||
|     background-color: #fff; | ||||
|     border: #adb5bd solid 1px; | ||||
| } | ||||
| .custom-switch .custom-control-input:checked~.custom-control-label::after { | ||||
|     background-color: #fff; | ||||
|     -webkit-transform: translateX(.75rem); | ||||
|     transform: translateX(.75rem); | ||||
| } | ||||
| .custom-switch .custom-control-label::after { | ||||
|     top: calc(.25rem + 2px); | ||||
|     left: calc(-2.25rem + 2px); | ||||
|     width: calc(1rem - 4px); | ||||
|     height: calc(1rem - 4px); | ||||
|     background-color: #adb5bd; | ||||
|     border-radius: .5rem; | ||||
|     transition: background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out; | ||||
|     transition: transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; | ||||
|     transition: transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out; | ||||
| } | ||||
| .custom-control-label::after { | ||||
|     position: absolute; | ||||
|     top: .25rem; | ||||
|     left: -1.5rem; | ||||
|     display: block; | ||||
|     width: 1rem; | ||||
|     height: 1rem; | ||||
|     content: ""; | ||||
|     background: no-repeat 50%/50% 50%; | ||||
| } | ||||
| @@ -7,7 +7,7 @@ | ||||
|     box-shadow: 0px 0px 6px 6px rgba(0, 0, 0, .25); | ||||
|     border: 1px solid black; | ||||
|     border-radius: 1rem; | ||||
|     margin-top: 30px; | ||||
|     margin-top: 40px; | ||||
| } | ||||
| .FunctionComponent__title { | ||||
|     margin: 0; | ||||
|   | ||||
| @@ -29,4 +29,7 @@ | ||||
| } | ||||
| .Admin__table-row { | ||||
|     padding: 15px; | ||||
| } | ||||
| .Admin__Function-slide { | ||||
|     margin-top: 40px; | ||||
| } | ||||
| @@ -25,67 +25,4 @@ | ||||
| } | ||||
| .Profile__Modal-top-container { | ||||
|     margin: 20px 0; | ||||
| } | ||||
| .custom-control { | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
| } | ||||
| .custom-control-input { | ||||
|     position: absolute; | ||||
|     z-index: -1; | ||||
|     opacity: 0; | ||||
| } | ||||
| .custom-control-label { | ||||
|     position: relative; | ||||
|     margin-bottom: 0; | ||||
|     vertical-align: top; | ||||
| } | ||||
| .custom-control-input:checked~.custom-control-label::before { | ||||
|     color: #fff; | ||||
|     border-color: #007bff; | ||||
|     background-color: #007bff; | ||||
| } | ||||
| .custom-switch .custom-control-label::before { | ||||
|     left: -2.25rem; | ||||
|     width: 1.75rem; | ||||
|     pointer-events: all; | ||||
|     border-radius: .5rem; | ||||
| } | ||||
| .custom-control-label::before { | ||||
|     position: absolute; | ||||
|     top: .25rem; | ||||
|     left: -1.5rem; | ||||
|     display: block; | ||||
|     width: 1rem; | ||||
|     height: 1rem; | ||||
|     pointer-events: none; | ||||
|     content: ""; | ||||
|     background-color: #fff; | ||||
|     border: #adb5bd solid 1px; | ||||
| } | ||||
| .custom-switch .custom-control-input:checked~.custom-control-label::after { | ||||
|     background-color: #fff; | ||||
|     -webkit-transform: translateX(.75rem); | ||||
|     transform: translateX(.75rem); | ||||
| } | ||||
| .custom-switch .custom-control-label::after { | ||||
|     top: calc(.25rem + 2px); | ||||
|     left: calc(-2.25rem + 2px); | ||||
|     width: calc(1rem - 4px); | ||||
|     height: calc(1rem - 4px); | ||||
|     background-color: #adb5bd; | ||||
|     border-radius: .5rem; | ||||
|     transition: background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out; | ||||
|     transition: transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; | ||||
|     transition: transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out; | ||||
| } | ||||
| .custom-control-label::after { | ||||
|     position: absolute; | ||||
|     top: .25rem; | ||||
|     left: -1.5rem; | ||||
|     display: block; | ||||
|     width: 1rem; | ||||
|     height: 1rem; | ||||
|     content: ""; | ||||
|     background: no-repeat 50%/50% 50%; | ||||
| } | ||||
							
								
								
									
										14
									
								
								website/utils/sunEditorConfig.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								website/utils/sunEditorConfig.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| export const complex = [ | ||||
|     ["undo", "redo"], | ||||
|     ["font", "fontSize", "formatBlock"], | ||||
|     ["bold", "underline", "italic", "strike", "subscript", "superscript"], | ||||
|     ["removeFormat"], | ||||
|     "/", | ||||
|     ["fontColor", "hiliteColor"], | ||||
|     ["outdent", "indent"], | ||||
|     ["align", "horizontalRule", "list", "table"], | ||||
|     ["link", "image", "video"], | ||||
|     ["fullScreen", "showBlocks", "codeView"], | ||||
|     ["preview", "print"], | ||||
|     ["save", "template"] | ||||
| ]; | ||||
		Reference in New Issue
	
	Block a user