Compare commits

..

14 Commits

8843 changed files with 1274275 additions and 1 deletions

44
.env Normal file
View File

@ -0,0 +1,44 @@
# In all environments, the following files are loaded if they exist,
# the latter taking precedence over the former:
#
# * .env contains default values for the environment variables needed by the app
# * .env.local uncommitted file with local overrides
# * .env.$APP_ENV committed environment-specific defaults
# * .env.$APP_ENV.local uncommitted environment-specific overrides
#
# Real environment variables win over .env files.
#
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
# https://symfony.com/doc/current/configuration/secrets.html
#
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=f08b2e4bf7a8fab7311394b405a6c2c3
###< symfony/framework-bundle ###
###> symfony/webapp-pack ###
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
###< symfony/webapp-pack ###
###> doctrine/doctrine-bundle ###
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
#
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8&charset=utf8mb4"
DATABASE_URL="mysql://ethik:ethik@mariadb:3306/ethik?serverVersion=5.7"
###< doctrine/doctrine-bundle ###
###> symfony/messenger ###
# Choose one of the transports below
# MESSENGER_TRANSPORT_DSN=doctrine://default
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
###< symfony/messenger ###
###> symfony/mailer ###
# MAILER_DSN=null://null
###< symfony/mailer ###

6
.env.test Normal file
View File

@ -0,0 +1,6 @@
# define your env variables for the test env here
KERNEL_CLASS='App\Kernel'
APP_SECRET='$ecretf0rt3st'
SYMFONY_DEPRECATIONS_HELPER=999999
PANTHER_APP_ENV=panther
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots

34
.gitignore vendored Normal file
View File

@ -0,0 +1,34 @@
###> symfony/framework-bundle ###
/.env.local
/.env.local.php
/.env.*.local
/config/secrets/prod/prod.decrypt.private.php
/public/bundles/
/public/build/
/var/
###< symfony/framework-bundle ###
###> phpunit/phpunit ###
/phpunit.xml
.phpunit.result.cache
###< phpunit/phpunit ###
###> symfony/phpunit-bridge ###
.phpunit.result.cache
/phpunit.xml
###< symfony/phpunit-bridge ###
###> symfony/webpack-encore-bundle ###
/node_modules/
npm-debug.log
yarn-error.log
/public/build/
###< symfony/webpack-encore-bundle ###
/.cache/
/.composer/
/.yarn/
/.yarnrc/
/.bash_history
/supervisord.log
/supervisord.pid

5
.yarnrc Normal file
View File

@ -0,0 +1,5 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
lastUpdateCheck 1673110672276

9
Makefile Normal file
View File

@ -0,0 +1,9 @@
up:
docker-compose up --build
down:
docker-compose down -v
purge:
docker-compose down -v --remove-orphans --rmi local

View File

@ -1,3 +1,58 @@
# EthikTag
Projet du HH année 2022
Projet du HH année 2022
Le principe de cette application est de faire une assitance à l'étiquetage des poches et tube de sang lors d'un don.
## Situation actuelle
1) le donneur se voit donner un un formulaire à l'accueil avant de voir le médecin.
ce formulaire comporte les données d'identité du donneur ainsi qu'un numéro de don sous la forme d'un code barre.
Attachées à ce formulaire se trouve deux bandes de code barre identiques.
2) Le donneur voit le médecin qui va indiquer le nombre de tubes et de poches qui devront être prélevés, notament au niveau des tubes qui permettront de faire des contrôles selon l'historique du patient.
Le médecin inscrit sur le formulaire d'entrée ces indications, en plus d'une indication sur InLog
3) Le donneur se présente auprès de l'infirmière muni du formulaire, elle se base sur les indications fournies pour choisir le lot de poches ainsi que le nombre de tubes nécessaire.
Les lots de poches peuvent être de 3, 4 ou 5 poches.
Les tubes ont des couleurs différentes et peuvent aller jusqu'à 8 tubes pour un prélèvement.
Théoriquement, l'infirmière doit , au fur et à mesure des prélèvements, coller un code barre sur les poches et tubes.
Cependant, aucune aide ou vérification n'est en place, et c'est uniquement l'organisation de l'infirmière qui permet d'avoir des lots finaux cohérents.
Or, l'infirmière peut avoir 3 patients simultanés, et parfois, des malaises peuvent se produire. Dans ces conditions, il est difficile d'obtenir un taux de réussite de 100%.
Certaines erreurs peuvent arrivées, et sont remarquées plus tard dans la chaîne de collecte, cependant les efforts fournis après la trouvaille d'une erreur sont important et couteux.
## Principe de l'application
Mettre en place un système dynamique qui rappelle à chaque action de scan d'étiquette l'étape en cours et la progression du prélevement, ainsi que l'identité du donneur.
## Monter l'environnement
A la racine du projet
```
monter l'environnement (construction de l'image, des assets et de la base de données vide, monter le conteneur)
make up
descendre le conteneur
make down
descendre le conteneur et supprimer l'image correspondante
make purge
```
## Modification du style
depuis la racine, aller dans le conteneur
```
docker compose exec ethik_tag bash
```
compiler les assets
```
yarn encore dev
ou yarn encore prod (pour minifier)
ou yarn encore dev --watch (détecte les changments et recompile automatiquement)
```

19
assets/app.js Normal file
View File

@ -0,0 +1,19 @@
/*
* Welcome to your app's main JavaScript file!
*
* We recommend including the built version of this JavaScript file
* (and its CSS file) in your base layout (base.html.twig).
*/
// any CSS you import will output into a single css file (app.css in this case)
import 'jquery';
// start the Stimulus application
import GetEvent from './js/getCodeBarre';
$(document).ready(()=>{
setTimeout(()=>{
// utils.init();
GetEvent.init()
}, 200);
})

View File

@ -0,0 +1,16 @@
import { Controller } from '@hotwired/stimulus';
/*
* This is an example Stimulus controller!
*
* Any element with a data-controller="hello" attribute will cause
* this controller to be executed. The name "hello" comes from the filename:
* hello_controller.js -> "hello"
*
* Delete this file or adapt it for your use!
*/
export default class extends Controller {
connect() {
this.element.textContent = 'Hello Stimulus! Edit me in assets/controllers/hello_controller.js';
}
}

View File

@ -0,0 +1 @@
import 'fontawesome-free/js/solid.min';

263
assets/js/getCodeBarre.js Normal file
View File

@ -0,0 +1,263 @@
export default class GetEvent{
static init(){
this.getEvent()
}
static getEvent(){
let saisie = $('#saisie');
saisie.focus();
let value;
let $info = $('.info');
let $infoDon = $('#info-don');
let $infoDonneur = $('#info-donneur');
let $infoPsl = $('#info-psl');
let $don = $('#don');
let $nom = $('#nom');
let $prenom = $('#prenom');
let $naissance = $('#naissance');
let $typeDon = $('#typeDon');
let $typePoche = $('#typePoche');
let $nbreTube = $('#nbreTube');
let $step = $('#step');
let $indication = $('#indication');
let $evolution = $('#evolution');
let $label = $('#label');
let $type = $('#type');
let $current = $('#current');
let $todo = $('#todo');
let $picturePoche = $('#picturePoche');
let $pictureTube = $('#pictureTube');
let $input = $('#inputRange');
let $displayError = $('.error');
let $displaySuccess = $('.displaySuccess');
document.addEventListener('keydown', function (event) {
saisie.focus();
if(event.code == 'Tab'){
value = saisie.val();
saisie.val('')
$.ajax({
url: '/api/get-code-barre-type',
method: "POST",
dataType: "json",
data: {'codeBarre': value},
success: function(response){
switch(response.data.step){
case '0':
if(response.data.status == 'success'){
$don.html(response.data.codeBarre);
$nom.html(response.data.nom);
$prenom.html(response.data.prenom);
$naissance.html(new Date(response.data.birthdate).toLocaleDateString());
$typeDon.html(response.data.type_don);
$nbreTube.html(response.data.nbre_tube);
$step.html('Pour passer à la suite');
$indication.html('Scannez le DMU');
$pictureTube.css('display', 'none');
$picturePoche.css('display', 'flex');
$info.css('visibility', 'visible')
saisie.focus();
}
if(response.data.status == 'init'){
let pochesImg = $('.sang');
[...pochesImg].forEach(sang=>{
sang.remove();
})
$don.html(response.data.codeBarre);
$nom.html(response.data.nom);
$prenom.html(response.data.prenom);
$naissance.html(new Date(response.data.birthdate).toLocaleDateString());
$typeDon.html(response.data.type_don);
$nbreTube.html(response.data.nbre_tube);
$step.html('Pour passer à la suite');
$indication.html('Scannez le DMU');
$typePoche.html('');
$info.css('visibility', 'visible')
$evolution.css('visibility', 'hidden')
saisie.focus();
}
if(response.data.status == 'error'){
saisie.focus();
$displayError.css('display', "flex");
setTimeout(() => {
$displayError.css('display', 'none')
}, 5000);
}
break;
case '1':
if(response.data.status == 'success'){
$typePoche.html(response.data.nbre_poche)
$step.html('ETAPE 1 / 2');
$indication.html('Scannez les étiquettes des poches');
saisie.focus();
$evolution.css('visibility', 'visible');
}
if(response.data.status == 'error_donneur'){
$displayError.html('erreur donneur')
$displayError.css('display', "flex");
setTimeout(() => {
$displayError.css('display', 'none')
}, 5000);
saisie.focus();
}
if(response.data.status == 'error_doublon'){
$displayError.html('erreur doublon')
$displayError.css('display', "flex");
setTimeout(() => {
$displayError.css('display', 'none')
}, 5000);
saisie.focus();
}
case '2':
if(response.data.status == 'success'){
console.log('step 2 success !!')
$typePoche.html(response.data.nbre_poche)
$current.html(response.data.nbre_poche)
$type.html('Poches');
$todo.html(response.data.nbre_poche_max)
$input.attr('max', response.data.nbre_poche_max)
$input.attr('value', response.data.nbre_poche)
if(response.data.nbre_poche !=response.data.nbre_poche_max && response.data.nbre_poche != 0){
$picturePoche.append('<div class="sang"><img src="/poches/Poche_sang2.png"></div>')
}
saisie.focus();
}
if(response.data.status == 'final'){
$typePoche.html(response.data.nbre_poche)
$current.html(response.data.nbre_poche)
$input.attr('max', response.data.nbre_poche_max)
$input.attr('value', response.data.nbre_poche)
$indication.html('validez avec un scan de poche!');
$picturePoche.append('<div class="sang"><img src="/poches/Poche_sang2.png"></div>')
saisie.focus();
}
if(response.data.status == 'error_scan'){
$displayError.html("Mauvais type d'étiquette")
$displayError.css('display', "flex");
setTimeout(() => {
$displayError.css('display', 'none')
}, 5000);
saisie.focus();
}
if(response.data.status == 'error_doublon'){
$displayError.html('Etiquette déjà scannée')
$displayError.css('display', "flex");
setTimeout(() => {
$displayError.css('display', 'none')
}, 5000);
saisie.focus();
}
if(response.data.status == 'error_donneur'){
$displayError.html('Ne correspond pas au donneur')
$displayError.css('display', "flex");
setTimeout(() => {
$displayError.css('display', 'none')
}, 5000);
saisie.focus();
}
break;
case '3':
if(response.data.status == "success"){
$picturePoche.css('display', 'none');
let pochesImg = $('.sang');
[...pochesImg].forEach(sang=>{
sang.remove();
})
$pictureTube.css('display', 'flex');
$indication.html('Scannez les étiquettes de tubes!');
$input.attr('max', response.data.nbre_tube_max)
$todo.html(response.data.nbre_tube_max)
$input.attr('value', 0)
$current.html(0)
$type.html('Tubes')
}
if(response.data.status == "error_scan"){
$displayError.html("Mauvais type d'étiquette")
$displayError.css('display', "flex");
setTimeout(() => {
$displayError.css('display', 'none')
}, 5000);
}
break;
case '4':
if(response.data.status == 'success'){
$step.html('ETAPE 2 / 2');
$nbreTube.html(response.data.nbre_tube)
$current.html(response.data.nbre_tube)
$input.attr('max', response.data.nbre_tube_max)
$type.html('Tubes')
$todo.html(response.data.nbre_tube_max)
$input.attr('value', response.data.nbre_tube)
console.log( response.data.nbre_tube)
$pictureTube.append('<div class="sang"><img src="/tubes/Tube'+response.data.nbre_tube+'_check.png"></div>')
saisie.focus();
}
if(response.data.status == 'final'){
$nbreTube.html(response.data.nbre_tube)
$current.html(response.data.nbre_tube_max)
$input.attr('max', response.data.nbre_tube_max)
$type.html('Tubes')
$todo.html(response.data.nbre_tube_max)
$input.attr('value', response.data.nbre_tube)
$pictureTube.append('<div class="sang"><img src="/tubes/Tube'+response.data.nbre_tube+'_check.png"></div>')
$displaySuccess.html('Patient '+ response.data.prenom+' '+response.data.nom + ' traité avec succès')
$displaySuccess.css('display', 'flex')
setTimeout(() => {
location.reload();
$displaySuccess.css('display', 'none')
}, 5000);
saisie.focus();
}
if(response.data.status == 'error_scan'){
$displayError.html("Mauvais type d'étiquette")
$displayError.css('display', "flex");
setTimeout(() => {
$displayError.css('display', 'none')
}, 5000);
saisie.focus();
}
if(response.data.status == 'error_doublon'){
$displayError.html('Etiquette déjà scannée')
$displayError.css('display', "flex");
setTimeout(() => {
$displayError.css('display', 'none')
}, 5000);
saisie.focus();
}
if(response.data.status == 'error_donneur'){
$displayError.html('Ne correspond pas au donneur')
$displayError.css('display', "flex");
setTimeout(() => {
$displayError.css('display', 'none');
}, 5000);
saisie.focus();
}
break;
}
}
})
}
})
}
}

View File

@ -0,0 +1,24 @@
.add-flash{
&-form-warning{
width: 100%;
background-color: indianred;
color: white;
display: flex;
justify-content: center;
align-items: center;
padding-bottom: 65px !important;
border-radius: 5px;
font-size: 25px;
}
&-success{
width: 100%;
background-color: lightgreen;
color: white;
display: flex;
justify-content: center;
align-items: center;
padding-bottom: 65px !important;
border-radius: 5px;
font-size: 25px;
}
}

View File

@ -0,0 +1,7 @@
.footer{
min-height: 5rem;
display: flex;
justify-content: center;
align-items: center;
background-color: grey;
}

View File

@ -0,0 +1,21 @@
.crud{
&-bool-form{
label{
&:hover{
cursor: pointer;
}
}
}
&-collection{
display: flex;
flex-wrap: wrap;
&-item{
background-color: #333;
color: white;
border-radius: 3px;
padding: 3px;
border: 1px double #333;
margin: 1px;
}
}
}

View File

@ -0,0 +1,43 @@
.header{
display: flex;
justify-content: space-between;
align-items: center;
background-color: rgb(51, 0, 61);
color:white;
min-height : 7rem;
&-logo{
margin:1rem;
a{
img {
width: 200px;
height: 100%;
object-fit: contain;
}
}
&-nav{
display: flex;
flex-direction: row;
justify-content: space-between;
align-content: center;
}
}
&-deconnexion{
float: right;
border-radius: 10px;
border: 2px solid white;
margin-right: 1rem;
&:hover{
background-color: white;
}
a{
color: white;
padding: 0 1rem;
&:hover{
text-decoration: none;
color: steelblue;
}
}
}
}

View File

@ -0,0 +1,73 @@
.sidebar{
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
flex: 0 0 12%;
min-height:100vh;
box-shadow: 5px 0 10px grey;
background-color: #333;
.divider{
height: 2px;
width: 100%;
background-color: dimgray;
margin: 12px 0 ;
}
&-logo{
width: 100%;
height: 100%;
object-fit: cover;
}
&-header{
img{
width: 100%;
}
}
a{
text-decoration: none;
&.active{
background-color: white;
border-radius: 5px;
color: dimgray;
box-shadow: 3px 3px 3px grey;
}
}
&-content{
width: 90%;
p{
color: #313131;
font-weight: 800;
font-size: 1.2em;
width: 100%;
text-align: center;
background-color: white;
border-radius: 0 6px;
}
& ul{
padding-left: 0;
& li {
list-style: none;
&.active{
background-color: rgba(255,255,255,0.5);
border-radius: 3px;
a{
color: #313131;
font-weight: 500;
}
}
& a{
padding:0.5rem 1.5rem;
font-size: 1.1em;
display: block;
color:white;
&:hover{
color: #313131;
background-color: rgba(255,255,255,0.5);
border-radius: 3px;
}
}
}
}
}
}

View File

@ -0,0 +1 @@
@import "~fontawesome-free/css/all.css";

View File

@ -0,0 +1,5 @@
@import url('https://fonts.googleapis.com/css2?family=Oswald:wght@300;400;500;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Merriweather:wght@400;500;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Helvetica:wght@400;500;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Tangerine:wght@700&display=swap');

View File

@ -0,0 +1,13 @@
.login-wrapper{
display: flex;
justify-content: center;
align-items: center;
height: 600px;
}
.login{
border: 1px solid grey;
border-radius: 5px;
box-shadow: 2px 2px 2px grey;
padding: 30px;
}

168
assets/styles/front.scss Normal file
View File

@ -0,0 +1,168 @@
.info{
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
visibility: hidden;
}
#step{
color: #007BFF;
padding: 20px;
font-size: 32px;
font-weight: 800;
}
#indication, #label{
border-radius: 50px;
background-color: #007BFF;
color: white;
padding: 8px 20px;
font-weight: 800;
font-size: 32px;
margin: 30px 0;
}
#evolution{
display: flex;
width: 100%;
justify-content: start;
align-items: center;
visibility: hidden;
input[type=range]{
width: 80%;
margin-left: 20px;
}
#label{
width: auto;
}
}
.displaySuccess{
position: absolute;
display: flex;
justify-content: center;
align-items: center;
font-size: 48px;
font-weight: 800;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: green;
color: white;
display: none;
z-index: 10000;
}
#picturePoche, #pictureTube{
display: flex;
justify-content: start;
align-items: start;
height: 300px;
.sang{
width: auto;
height: 150px;
}
img{
width: 100%;
height: 100%;
object-fit: contain;
}
}
.error{
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 300px;
width: 100%;
background-color: #F44336;
color: white;
display: none;
justify-content: center;
align-items: center;
font-size: 48px;
font-weight: 800;
}
#saisie{
position: absolute;
left:-300px
}
/*Badeau supérieur*/
.page_header {
display: grid;
grid-template-columns: 25% 0.75% 30% 44%;
grid-template-rows: 25vh;
grid-template-areas: "barecode sparebar identity gift_spec";
background-color: rgba(5, 5, 59, 0.952);
}
.gift_cb {
display: grid;
text-align: center;
grid-template-columns: 100%;
// grid-template-rows: 75% 25%;
grid-template-areas:
"cb"
"number_cb";
grid-area: barecode;
background-repeat: no-repeat;
background-size: contain;
background-position: center;
margin: 10px;
background-color: white;
}
/*
.separator {
grid-area: sparebar;
background-color: black;
}*/
li {
list-style: none;
font-size: large;
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
margin: 10px;
}
.page_header .gift_cb .cb_cb {
grid-template-columns: cb;
/*background-color: black;*/
}
.cb_number {
}
.identity {
grid-area: identity;
background-color: white;
margin: 10px;
}
.gift_specificity {
grid-area: gift_spec;
background-color: white;
margin: 10px;
}
/* Bandeau intermédiaire étapes*/
.step {
display: grid;
grid-template-columns: 100%;
grid-template-rows: 15vh 10vh;
grid-template-areas:
"step_number"
"step_message";
background-color: rgba(5, 5, 59, 0.952);
}
.step_state {
grid-area: step_number;
background-color: white;
margin-left: 10px;
margin-right: 10px;
}

View File

@ -0,0 +1,16 @@
@import '~bootstrap/scss/bootstrap';
@import '~bootstrap/scss/bootstrap-utilities';
.login-wrapper{
display: flex;
justify-content: center;
align-items: center;
height: 600px;
}
.login{
border: 1px solid grey;
border-radius: 5px;
box-shadow: 2px 2px 2px grey;
padding: 30px;
}

45
assets/styles/main.scss Normal file
View File

@ -0,0 +1,45 @@
@import './header', './footer', './sidebar', 'common/login', 'common/fonts', 'add-flash', 'front';
@import './global';
@import '~bootstrap/scss/bootstrap';
@import '~bootstrap/scss/bootstrap-utilities';
@import 'tom-select/dist/scss/tom-select.bootstrap5';
.special{
font-size: 50px;
}
.page-container {
display: flex;
flex-direction: row;
width: 100%;
a:hover{
text-decoration: none;
}
&-content{
width: 100%;
margin:2rem;
}
}
label.custom-file-label{
&:after{
content: "Parcourir";
}
}
.breadcrumb{
justify-content: space-between;
align-items: center;
&-first{
&-title{
font-size: 1.4rem;
font-weight: 600;
color: steelblue;
}
}
&-second{
ol{
margin-bottom: 0;
}
}
}

View File

@ -0,0 +1,6 @@
@import "~fontawesome-free/webfonts/fa-solid-900.eot";
@import "~fontawesome-free/webfonts/fa-solid-900.woff2";
@import "~fontawesome-free/webfonts/fa-solid-900.woff";
@import "~fontawesome-free/webfonts/fa-solid-900.ttf";
@import "~fontawesome-free/webfonts/fa-solid-900.svg";
@import "~fontawesome-free/scss/solid.scss";

17
bin/console Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env php
<?php
use App\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
}
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
return new Application($kernel);
};

19
bin/phpunit Executable file
View File

@ -0,0 +1,19 @@
#!/usr/bin/env php
<?php
if (!ini_get('date.timezone')) {
ini_set('date.timezone', 'UTC');
}
if (is_file(dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit')) {
define('PHPUNIT_COMPOSER_INSTALL', dirname(__DIR__).'/vendor/autoload.php');
require PHPUNIT_COMPOSER_INSTALL;
PHPUnit\TextUI\Command::main();
} else {
if (!is_file(dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php')) {
echo "Unable to find the `simple-phpunit.php` script in `vendor/symfony/phpunit-bridge/bin/`.\n";
exit(1);
}
require dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php';
}

108
composer.json Normal file
View File

@ -0,0 +1,108 @@
{
"type": "project",
"license": "proprietary",
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"php": ">=7.2.5",
"ext-ctype": "*",
"ext-iconv": "*",
"doctrine/annotations": "^1.13",
"doctrine/doctrine-bundle": "^2.7",
"doctrine/doctrine-migrations-bundle": "^3.2",
"doctrine/orm": "^2.13",
"knplabs/knp-paginator-bundle": "^5.9",
"phpdocumentor/reflection-docblock": "^5.3",
"phpstan/phpdoc-parser": "^1.11",
"sensio/framework-extra-bundle": "^6.1",
"symfony/asset": "5.4.*",
"symfony/console": "5.4.*",
"symfony/doctrine-messenger": "5.4.*",
"symfony/dotenv": "5.4.*",
"symfony/expression-language": "5.4.*",
"symfony/flex": "^1.17|^2",
"symfony/form": "5.4.*",
"symfony/framework-bundle": "5.4.*",
"symfony/http-client": "5.4.*",
"symfony/intl": "5.4.*",
"symfony/mailer": "5.4.*",
"symfony/mime": "5.4.*",
"symfony/monolog-bundle": "^3.0",
"symfony/notifier": "5.4.*",
"symfony/process": "5.4.*",
"symfony/property-access": "5.4.*",
"symfony/property-info": "5.4.*",
"symfony/proxy-manager-bridge": "5.4.*",
"symfony/runtime": "5.4.*",
"symfony/security-bundle": "5.4.*",
"symfony/serializer": "5.4.*",
"symfony/string": "5.4.*",
"symfony/translation": "5.4.*",
"symfony/twig-bundle": "5.4.*",
"symfony/validator": "5.4.*",
"symfony/web-link": "5.4.*",
"symfony/webpack-encore-bundle": "^1.15",
"symfony/yaml": "5.4.*",
"twig/extra-bundle": "^2.12|^3.0",
"twig/twig": "^2.12|^3.0"
},
"config": {
"allow-plugins": {
"composer/package-versions-deprecated": true,
"symfony/flex": true,
"symfony/runtime": true
},
"optimize-autoloader": true,
"preferred-install": {
"*": "dist"
},
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"replace": {
"symfony/polyfill-ctype": "*",
"symfony/polyfill-iconv": "*",
"symfony/polyfill-php72": "*"
},
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
},
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
]
},
"conflict": {
"symfony/symfony": "*"
},
"extra": {
"symfony": {
"allow-contrib": false,
"require": "5.4.*"
}
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4",
"phpunit/phpunit": "^9.5",
"symfony/browser-kit": "5.4.*",
"symfony/css-selector": "5.4.*",
"symfony/debug-bundle": "5.4.*",
"symfony/maker-bundle": "^1.0",
"symfony/phpunit-bridge": "^6.1",
"symfony/stopwatch": "5.4.*",
"symfony/web-profiler-bundle": "5.4.*"
}
}

10610
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

18
config/bundles.php Normal file
View File

@ -0,0 +1,18 @@
<?php
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
Knp\Bundle\PaginatorBundle\KnpPaginatorBundle::class => ['all' => true],
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
];

View File

@ -0,0 +1,19 @@
framework:
cache:
# Unique name of your app: used to compute stable namespaces for cache keys.
#prefix_seed: your_vendor_name/app_name
# The "app" cache stores to the filesystem by default.
# The data in this cache should persist between deploys.
# Other options include:
# Redis
#app: cache.adapter.redis
#default_redis_provider: redis://localhost
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
#app: cache.adapter.apcu
# Namespaced pools use the above "app" backend by default
#pools:
#my.dedicated.cache: null

View File

@ -0,0 +1,5 @@
when@dev:
debug:
# Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser.
# See the "server:dump" command to start a new server.
dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%"

View File

@ -0,0 +1,42 @@
doctrine:
dbal:
url: '%env(resolve:DATABASE_URL)%'
# IMPORTANT: You MUST configure your server version,
# either here or in the DATABASE_URL env var (see .env file)
#server_version: '13'
orm:
auto_generate_proxy_classes: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
mappings:
App:
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
when@test:
doctrine:
dbal:
# "TEST_TOKEN" is typically set by ParaTest
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
when@prod:
doctrine:
orm:
auto_generate_proxy_classes: false
query_cache_driver:
type: pool
pool: doctrine.system_cache_pool
result_cache_driver:
type: pool
pool: doctrine.result_cache_pool
framework:
cache:
pools:
doctrine.result_cache_pool:
adapter: cache.app
doctrine.system_cache_pool:
adapter: cache.system

View File

@ -0,0 +1,6 @@
doctrine_migrations:
migrations_paths:
# namespace is arbitrary but should be different from App\Migrations
# as migrations classes should NOT be autoloaded
'DoctrineMigrations': '%kernel.project_dir%/migrations'
enable_profiler: false

View File

@ -0,0 +1,24 @@
# see https://symfony.com/doc/current/reference/configuration/framework.html
framework:
secret: '%env(APP_SECRET)%'
#csrf_protection: true
http_method_override: false
# Enables session support. Note that the session will ONLY be started if you read or write from it.
# Remove or comment this section to explicitly disable session support.
session:
handler_id: null
cookie_secure: auto
cookie_samesite: lax
storage_factory_id: session.storage.factory.native
#esi: true
#fragments: true
php_errors:
log: true
when@test:
framework:
test: true
session:
storage_factory_id: session.storage.factory.mock_file

View File

@ -0,0 +1,3 @@
framework:
mailer:
dsn: '%env(MAILER_DSN)%'

View File

@ -0,0 +1,24 @@
framework:
messenger:
failure_transport: failed
transports:
# https://symfony.com/doc/current/messenger.html#transport-configuration
async:
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
options:
use_notify: true
check_delayed_interval: 60000
retry_strategy:
max_retries: 3
multiplier: 2
failed: 'doctrine://default?queue_name=failed'
# sync: 'sync://'
routing:
Symfony\Component\Mailer\Messenger\SendEmailMessage: async
Symfony\Component\Notifier\Message\ChatMessage: async
Symfony\Component\Notifier\Message\SmsMessage: async
# Route your messages to the transports
# 'App\Message\YourMessage': async

View File

@ -0,0 +1,61 @@
monolog:
channels:
- deprecation # Deprecations are logged in the dedicated "deprecation" channel when it exists
when@dev:
monolog:
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
channels: ["!event"]
# uncomment to get logging in your browser
# you may have to allow bigger header sizes in your Web server configuration
#firephp:
# type: firephp
# level: info
#chromephp:
# type: chromephp
# level: info
console:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine", "!console"]
when@test:
monolog:
handlers:
main:
type: fingers_crossed
action_level: error
handler: nested
excluded_http_codes: [404, 405]
channels: ["!event"]
nested:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
when@prod:
monolog:
handlers:
main:
type: fingers_crossed
action_level: error
handler: nested
excluded_http_codes: [404, 405]
buffer_size: 50 # How many messages should be saved? Prevent memory leaks
nested:
type: stream
path: php://stderr
level: debug
formatter: monolog.formatter.json
console:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine"]
deprecation:
type: stream
channels: [deprecation]
path: php://stderr

View File

@ -0,0 +1,16 @@
framework:
notifier:
#chatter_transports:
# slack: '%env(SLACK_DSN)%'
# telegram: '%env(TELEGRAM_DSN)%'
#texter_transports:
# twilio: '%env(TWILIO_DSN)%'
# nexmo: '%env(NEXMO_DSN)%'
channel_policy:
# use chat/slack, chat/telegram, sms/twilio or sms/nexmo
urgent: ['email']
high: ['email']
medium: ['email']
low: ['email']
admin_recipients:
- { email: admin@example.com }

View File

@ -0,0 +1,12 @@
framework:
router:
utf8: true
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
#default_uri: http://localhost
when@prod:
framework:
router:
strict_requirements: null

View File

@ -0,0 +1,53 @@
security:
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
entry_point: form_login
form_login:
login_path: app_login
check_path: app_login
username_parameter: email
password_parameter: password
enable_csrf: true
logout: true
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/front, roles: ROLE_ADMIN }
- { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
when@test:
security:
password_hashers:
# By default, password hashers are resource intensive and take time. This is
# important to generate secure password hashes. In tests however, secure hashes
# are not important, waste resources and increase test times. The following
# reduces the work factor to the lowest possible values.
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon

View File

@ -0,0 +1,3 @@
sensio_framework_extra:
router:
annotations: false

View File

@ -0,0 +1,13 @@
framework:
default_locale: en
translator:
default_path: '%kernel.project_dir%/translations'
fallbacks:
- en
# providers:
# crowdin:
# dsn: '%env(CROWDIN_DSN)%'
# loco:
# dsn: '%env(LOCO_DSN)%'
# lokalise:
# dsn: '%env(LOKALISE_DSN)%'

View File

@ -0,0 +1,7 @@
twig:
default_path: '%kernel.project_dir%/templates'
form_themes:
- 'bootstrap_5_horizontal_layout.html.twig'
when@test:
twig:
strict_variables: true

View File

@ -0,0 +1,13 @@
framework:
validation:
email_validation_mode: html5
# Enables validator auto-mapping support.
# For instance, basic validation constraints will be inferred from Doctrine's metadata.
#auto_mapping:
# App\Entity\: []
when@test:
framework:
validation:
not_compromised_password: false

View File

@ -0,0 +1,15 @@
when@dev:
web_profiler:
toolbar: true
intercept_redirects: false
framework:
profiler: { only_exceptions: false }
when@test:
web_profiler:
toolbar: false
intercept_redirects: false
framework:
profiler: { collect: false }

View File

@ -0,0 +1,49 @@
webpack_encore:
# The path where Encore is building the assets - i.e. Encore.setOutputPath()
output_path: '%kernel.project_dir%/public/build'
# If multiple builds are defined (as shown below), you can disable the default build:
# output_path: false
# Set attributes that will be rendered on all script and link tags
script_attributes:
defer: true
# Uncomment (also under link_attributes) if using Turbo Drive
# https://turbo.hotwired.dev/handbook/drive#reloading-when-assets-change
# 'data-turbo-track': reload
# link_attributes:
# Uncomment if using Turbo Drive
# 'data-turbo-track': reload
# If using Encore.enableIntegrityHashes() and need the crossorigin attribute (default: false, or use 'anonymous' or 'use-credentials')
# crossorigin: 'anonymous'
# Preload all rendered script and link tags automatically via the HTTP/2 Link header
# preload: true
# Throw an exception if the entrypoints.json file is missing or an entry is missing from the data
# strict_mode: false
# If you have multiple builds:
# builds:
# pass "frontend" as the 3rg arg to the Twig functions
# {{ encore_entry_script_tags('entry1', null, 'frontend') }}
# frontend: '%kernel.project_dir%/public/frontend/build'
# Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes)
# Put in config/packages/prod/webpack_encore.yaml
# cache: true
framework:
assets:
json_manifest_path: '%kernel.project_dir%/public/build/manifest.json'
#when@prod:
# webpack_encore:
# # Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes)
# # Available in version 1.2
# cache: true
#when@test:
# webpack_encore:
# strict_mode: false

5
config/preload.php Normal file
View File

@ -0,0 +1,5 @@
<?php
if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) {
require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php';
}

3
config/routes.yaml Normal file
View File

@ -0,0 +1,3 @@
#index:
# path: /
# controller: App\Controller\DefaultController::index

View File

@ -0,0 +1,7 @@
controllers:
resource: ../../src/Controller/
type: annotation
kernel:
resource: ../../src/Kernel.php
type: annotation

View File

@ -0,0 +1,4 @@
when@dev:
_errors:
resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
prefix: /_error

View File

@ -0,0 +1,8 @@
when@dev:
web_profiler_wdt:
resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
prefix: /_wdt
web_profiler_profiler:
resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
prefix: /_profiler

24
config/services.yaml Normal file
View File

@ -0,0 +1,24 @@
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones

View File

@ -0,0 +1,53 @@
FROM php:8.1-apache
RUN a2enmod rewrite
ARG PHP_VERSION="8.1"
ENV PHP_VERSION $PHP_VERSION
RUN export DEBIAN_FRONTEND=noninteractive \
&& apt-get update \
&& apt-get -y upgrade \
&& apt-get --no-install-recommends -yq install supervisor libicu-dev \
libwebp-dev \
libjpeg62-turbo-dev \
libpng-dev libzip-dev libxpm-dev \
libfreetype6-dev \
vim wget git \
apache2
RUN docker-php-ext-install pdo pdo_mysql zip \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install gd \
&& docker-php-ext-configure intl \
&& docker-php-ext-install intl
RUN wget https://getcomposer.org/download/2.0.9/composer.phar \
&& mv composer.phar /usr/bin/composer && chmod +x /usr/bin/composer
RUN wget -O- https://deb.nodesource.com/setup_18.x | bash - \
&& apt-get install -y nodejs \
&& npm install --global yarn
COPY apache.conf /etc/apache2/sites-enabled/000-default.conf
WORKDIR /var/www
RUN wget -O- https://github.com/boxboat/fixuid/releases/download/v0.5.1/fixuid-0.5.1-linux-amd64.tar.gz | tar -C /usr/local/bin -xzf - \
&& chown root:root /usr/local/bin/fixuid \
&& chmod 4755 /usr/local/bin/fixuid \
&& mkdir -p /etc/fixuid
COPY fixuid.yaml /etc/fixuid/config.yaml
COPY supervisor.ini /etc/supervisor/supervisor.ini
RUN chmod +x /etc/supervisor/supervisor.ini
RUN chown www-data:www-data /etc/supervisor/supervisor.ini
COPY init.sh /init.sh
RUN chmod +x /init.sh
RUN chown www-data:www-data /init.sh
ENTRYPOINT ["/usr/local/bin/fixuid"]
USER www-data
CMD ["/init.sh"]

View File

@ -0,0 +1,16 @@
<VirtualHost *:80>
DocumentRoot /var/www/public
<Directory /var/www/public>
AllowOverride None
Order Allow,Deny
Allow from All
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>
</Directory>
CustomLog /dev/stdout combined
ErrorLog /dev/stderr
</VirtualHost>

View File

@ -0,0 +1,4 @@
user: www-data
group: www-data
paths:
- /var/www/var

View File

@ -0,0 +1,7 @@
#!/bin/bash
yarn install
yarn encore dev
bin/console d:s:u -f --complete
bin/console d:f:l -n
/usr/bin/supervisord -c /etc/supervisor/supervisor.ini

View File

@ -0,0 +1,12 @@
[supervisord]
nodaemon=true
[program:apache2]
environment=HOSTNAME="%(ENV_HOSTNAME)s"
command = apache2ctl -D FOREGROUND
user = www-data
autostart = true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

View File

View File

@ -0,0 +1,39 @@
version: "3"
services:
mariadb:
image: mariadb:10.10
environment:
MYSQL_DATABASE: ethik
MYSQL_USER: ethik
MYSQL_PASSWORD: ethik
MYSQL_ROOT_PASSWORD: ethik
TZ: Europe/Paris
volumes:
- ./containers/mariadb/init-db.d:/docker-entrypoint-initdb.d/:ro
- mariadb_data:/var/lib/mysql
- /etc/localtime:/etc/localtime:ro
ethik_tag:
build:
context: ./containers/ethikTag
user: ${FIXUID:-1000}:${FIXGID:-1000}
volumes:
- .:/var/www
ports:
- 8000:80
tmpfs:
- /var/www/var:uid=${FIXUID:-1000},gid=${FIXGID:-1000}
depends_on:
- mariadb
###> doctrine/doctrine-bundle ###
adminer:
image: adminer:latest
ports:
- 8082:8080
volumes:
###> doctrine/doctrine-bundle ###
mariadb_data:
###< doctrine/doctrine-bundle ###

36
docker-compose.yml Normal file
View File

@ -0,0 +1,36 @@
version: "3"
services:
ethik_tag:
build:
context: ./containers/ethikTag
volumes:
- .:/var/www
ports:
- 8000:80
###> doctrine/doctrine-bundle ###
mariadb:
image: mariadb:10.10
environment:
MYSQL_DATABASE: ethik
MYSQL_USER: ethik
MYSQL_PASSWORD: ethik
MYSQL_ROOT_PASSWORD: ethik
TZ: Europe/Paris
volumes:
- ./containers/mariadb/init-db.d:/docker-entrypoint-initdb.d/:ro
- mariadb_data:/var/lib/mysql
- /etc/localtime:/etc/localtime:ro
# You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data!
# - ./docker/db/data:/var/lib/postgresql/data:rw
###< doctrine/doctrine-bundle ###
adminer:
image: adminer:latest
ports:
- 8082:8080
volumes:
###> doctrine/doctrine-bundle ###
mariadb_data:
###< doctrine/doctrine-bundle ###

32
package.json Normal file
View File

@ -0,0 +1,32 @@
{
"devDependencies": {
"@babel/core": "^7.17.0",
"@babel/preset-env": "^7.16.0",
"@hotwired/stimulus": "^3.0.0",
"@symfony/stimulus-bridge": "^3.2.0",
"@symfony/webpack-encore": "^4.0.0",
"core-js": "^3.23.0",
"regenerator-runtime": "^0.13.9",
"sass": "^1.55.0",
"sass-loader": "^13.0.0",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-notifier": "^1.15.0"
},
"license": "UNLICENSED",
"private": true,
"scripts": {
"dev-server": "encore dev-server",
"dev": "encore dev",
"watch": "encore dev --watch",
"build": "encore production --progress"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^6.2.1",
"@popperjs/core": "^2.11.6",
"bootstrap": "^5.2.2",
"fortawesome": "^0.0.1-security",
"jquery": "^3.6.1",
"tom-select": "^2.2.2"
}
}

42
phpunit.xml.dist Normal file
View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="tests/bootstrap.php"
convertDeprecationsToExceptions="false"
>
<php>
<ini name="display_errors" value="1" />
<ini name="error_reporting" value="-1" />
<server name="APP_ENV" value="test" force="true" />
<server name="SHELL_VERBOSITY" value="-1" />
<server name="SYMFONY_PHPUNIT_REMOVE" value="" />
<server name="SYMFONY_PHPUNIT_VERSION" value="9.5" />
</php>
<testsuites>
<testsuite name="Project Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
</listeners>
<!-- Run `composer require symfony/panther` before enabling this extension -->
<!--
<extensions>
<extension class="Symfony\Component\Panther\ServerExtension" />
</extensions>
-->
</phpunit>

70
public/.htaccess Normal file
View File

@ -0,0 +1,70 @@
# Use the front controller as index file. It serves as a fallback solution when
# every other rewrite/redirect fails (e.g. in an aliased environment without
# mod_rewrite). Additionally, this reduces the matching process for the
# start page (path "/") because otherwise Apache will apply the rewriting rules
# to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl).
DirectoryIndex index.php
# By default, Apache does not evaluate symbolic links if you did not enable this
# feature in your server configuration. Uncomment the following line if you
# install assets as symlinks or if you experience problems related to symlinks
# when compiling LESS/Sass/CoffeScript assets.
# Options +FollowSymlinks
# Disabling MultiViews prevents unwanted negotiation, e.g. "/index" should not resolve
# to the front controller "/index.php" but be rewritten to "/index.php/index".
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
<IfModule mod_rewrite.c>
# This Option needs to be enabled for RewriteRule, otherwise it will show an error like
# 'Options FollowSymLinks or SymLinksIfOwnerMatch is off which implies that RewriteRule directive is forbidden'
Options +FollowSymlinks
RewriteEngine On
# Determine the RewriteBase automatically and set it as environment variable.
# If you are using Apache aliases to do mass virtual hosting or installed the
# project in a subdirectory, the base path will be prepended to allow proper
# resolution of the index.php file and to redirect to the correct URI. It will
# work in environments without path prefix as well, providing a safe, one-size
# fits all solution. But as you do not need it in this case, you can comment
# the following 2 lines to eliminate the overhead.
RewriteCond %{REQUEST_URI}::$0 ^(/.+)/(.*)::\2$
RewriteRule .* - [E=BASE:%1]
# Sets the HTTP_AUTHORIZATION header removed by Apache
RewriteCond %{HTTP:Authorization} .+
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0]
# Redirect to URI without front controller to prevent duplicate content
# (with and without `/index.php`). Only do this redirect on the initial
# rewrite by Apache and not on subsequent cycles. Otherwise we would get an
# endless redirect loop (request -> rewrite to front controller ->
# redirect -> request -> ...).
# So in case you get a "too many redirects" error or you always get redirected
# to the start page because your Apache does not expose the REDIRECT_STATUS
# environment variable, you have 2 choices:
# - disable this feature by commenting the following 2 lines or
# - use Apache >= 2.3.9 and replace all L flags by END flags and remove the
# following RewriteCond (best solution)
RewriteCond %{ENV:REDIRECT_STATUS} =""
RewriteRule ^index\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L]
# If the requested filename exists, simply serve it.
# We only want to let Apache serve files and not directories.
# Rewrite all other queries to the front controller.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ %{ENV:BASE}/index.php [L]
</IfModule>
<IfModule !mod_rewrite.c>
<IfModule mod_alias.c>
# When mod_rewrite is not available, we instruct a temporary redirect of
# the start page to the front controller explicitly so that the website
# and the generated links can still be used.
RedirectMatch 307 ^/$ /index.php/
# RedirectTemp cannot be used instead
</IfModule>
</IfModule>

15948
public/build/adminStyle.css Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,22 @@
"use strict";
(self["webpackChunk"] = self["webpackChunk"] || []).push([["adminStyle"],{
/***/ "./assets/styles/main.scss":
/*!*********************************!*\
!*** ./assets/styles/main.scss ***!
\*********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
// extracted by mini-css-extract-plugin
/***/ })
},
/******/ __webpack_require__ => { // webpackRuntimeModules
/******/ var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
/******/ var __webpack_exports__ = (__webpack_exec__("./assets/styles/main.scss"));
/******/ }
]);
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRtaW5TdHlsZS5qcyIsIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7O0FBQUEiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9hc3NldHMvc3R5bGVzL21haW4uc2Nzcz8xZjFhIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIGV4dHJhY3RlZCBieSBtaW5pLWNzcy1leHRyYWN0LXBsdWdpblxuZXhwb3J0IHt9OyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==

380
public/build/app.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,29 @@
{
"entrypoints": {
"app": {
"js": [
"/build/runtime.js",
"/build/vendors-node_modules_core-js_modules_es_array_for-each_js-node_modules_core-js_modules_es_arr-9c7bdc.js",
"/build/app.js"
]
},
"adminStyle": {
"js": [
"/build/runtime.js",
"/build/adminStyle.js"
],
"css": [
"/build/adminStyle.css"
]
},
"frontStyle": {
"js": [
"/build/runtime.js",
"/build/frontStyle.js"
],
"css": [
"/build/frontStyle.css"
]
}
}
}

14967
public/build/frontStyle.css Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,22 @@
"use strict";
(self["webpackChunk"] = self["webpackChunk"] || []).push([["frontStyle"],{
/***/ "./assets/styles/front/front.scss":
/*!****************************************!*\
!*** ./assets/styles/front/front.scss ***!
\****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
// extracted by mini-css-extract-plugin
/***/ })
},
/******/ __webpack_require__ => { // webpackRuntimeModules
/******/ var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
/******/ var __webpack_exports__ = (__webpack_exec__("./assets/styles/front/front.scss"));
/******/ }
]);
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJvbnRTdHlsZS5qcyIsIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7O0FBQUEiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9hc3NldHMvc3R5bGVzL2Zyb250L2Zyb250LnNjc3M/MDc5ZiJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBleHRyYWN0ZWQgYnkgbWluaS1jc3MtZXh0cmFjdC1wbHVnaW5cbmV4cG9ydCB7fTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=

View File

@ -0,0 +1,9 @@
{
"build/app.js": "/build/app.js",
"build/adminStyle.css": "/build/adminStyle.css",
"build/adminStyle.js": "/build/adminStyle.js",
"build/frontStyle.css": "/build/frontStyle.css",
"build/frontStyle.js": "/build/frontStyle.js",
"build/runtime.js": "/build/runtime.js",
"build/vendors-node_modules_core-js_modules_es_array_for-each_js-node_modules_core-js_modules_es_arr-9c7bdc.js": "/build/vendors-node_modules_core-js_modules_es_array_for-each_js-node_modules_core-js_modules_es_arr-9c7bdc.js"
}

175
public/build/runtime.js Normal file

File diff suppressed because one or more lines are too long

10
public/index.php Normal file
View File

@ -0,0 +1,10 @@
<?php
use App\Kernel;
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 800"><defs><style>.cls-1{fill:#bae1ed;}.cls-2{fill:#8cd0e4;}.cls-3{fill:#72bacc;}.cls-4{fill:#e25a5a;}.cls-5{fill:#ce5555;}.cls-6{fill:#eb6570;}.cls-7{fill:#fff;}.cls-8{fill:#222227;}</style></defs><title>Poche_sang</title><g id="Calque_3" data-name="Calque 3"><path class="cls-1" d="M146.7,217.13h-6.83a28.3,28.3,0,0,0,28.3,28.31h13.66a28.29,28.29,0,0,0,28.3-28.31V210.3a28.29,28.29,0,0,0-28.3-28.3H168.17a28.3,28.3,0,0,0-28.3,28.3v6.83h13.66V210.3a14.65,14.65,0,0,1,14.64-14.64h13.66a14.65,14.65,0,0,1,14.64,14.64v6.83a14.63,14.63,0,0,1-14.64,14.64H168.17a14.63,14.63,0,0,1-14.64-14.64Z"/><path class="cls-2" d="M255,220.06H95a46.85,46.85,0,0,0-46.84,46.85V503.09A87.83,87.83,0,0,0,136,590.93H214a87.83,87.83,0,0,0,87.83-87.84V266.91A46.85,46.85,0,0,0,255,220.06Z"/><path class="cls-3" d="M254.5,220.06h-15c-6.05,90.65-37.08,282.42-190.85,296.59a87.86,87.86,0,0,0,86.79,74.28h78.08a87.83,87.83,0,0,0,87.83-87.84V266.91A46.85,46.85,0,0,0,254.5,220.06Z"/><path class="cls-4" d="M292.11,399.19c-1.35.95-16.69,6.1-18.29,6.72C239.45,419.26,198,410.45,163,404.74c-2.28-.37-4.54-.77-6.8-1.2h-108v99.55A87.83,87.83,0,0,0,136,590.93H214a87.83,87.83,0,0,0,87.83-87.84V403.54Z"/><path class="cls-5" d="M273.3,405.91c-24.68,9.58-53,7.75-80,3.83-28.25,55.35-73.2,100.33-144.68,106.91.2,1.32.44,2.64.7,4,.13.65.29,1.3.44,1.95s.31,1.41.49,2.1.36,1.33.54,2,.37,1.33.57,2,.42,1.32.64,2,.42,1.29.65,1.93.47,1.29.72,1.94.49,1.26.74,1.88.53,1.27.8,1.9l.84,1.85c.29.61.58,1.22.88,1.83s.62,1.22.93,1.83.62,1.18.94,1.76.69,1.21,1,1.82.65,1.12,1,1.67.8,1.24,1.2,1.86.65,1,1,1.53c.54.79,1.11,1.58,1.68,2.35q.64.9,1.32,1.77c.58.76,1.15,1.51,1.76,2.23.36.45.74.88,1.12,1.32s1,1.17,1.5,1.74.83.89,1.24,1.33,1,1.07,1.53,1.6.87.87,1.32,1.3,1,1,1.58,1.51.91.83,1.38,1.24,1.09,1,1.65,1.43l1.42,1.18c.58.46,1.16.92,1.75,1.37s1,.74,1.44,1.09l1.87,1.33c.47.33,1,.67,1.43,1,.68.45,1.37.88,2.05,1.32l1.36.85c.83.5,1.67,1,2.51,1.44.34.19.67.39,1,.57,1.18.64,2.38,1.26,3.59,1.84l1,.48c.89.41,1.79.83,2.7,1.21l1.43.59,2.37.93c.53.2,1.07.37,1.6.56.76.27,1.53.54,2.3.78l1.68.52,2.3.65,1.74.44q1.16.28,2.34.54l1.75.37,2.42.43,1.73.28c.85.12,1.7.22,2.55.32.55.07,1.11.14,1.67.19.94.09,1.89.16,2.84.22l1.42.1c1.43.07,2.87.11,4.32.11h78.08a87.83,87.83,0,0,0,87.83-87.84V403.54l-9.76-4.35C290.24,400.14,274.9,405.29,273.3,405.91Z"/><path class="cls-6" d="M55.93,405.49s18.55-16.59,83.94-11.71,139.56,13.74,154.2,5.41c0,0-36.11,34.61-117.12,20.94S61.79,404.52,55.93,405.49Z"/><path class="cls-1" d="M255,233.73a33.21,33.21,0,0,1,33.18,33.18V503.09A74.25,74.25,0,0,1,214,577.26H136a74.25,74.25,0,0,1-74.17-74.17V266.91A33.21,33.21,0,0,1,95,233.73H255m0-13.67H95a46.85,46.85,0,0,0-46.84,46.85V503.09A87.83,87.83,0,0,0,136,590.93H214a87.83,87.83,0,0,0,87.83-87.84V266.91A46.85,46.85,0,0,0,255,220.06Z"/><rect class="cls-1" x="157.92" y="582.14" width="34.16" height="36.11"/><path class="cls-7" d="M100.35,414.81c0,4.7,5.88,8.52,13.14,8.52h123c7.26,0,13.14-3.82,13.14-8.52V379.37c0-4.71-5.88-8.52-13.14-8.52h-123c-7.26,0-13.14,3.81-13.14,8.52Z"/><path class="cls-8" d="M113.19,393.76H236.81a2.39,2.39,0,1,0,0-4.78H113.19a2.39,2.39,0,0,0,0,4.78"/><path class="cls-8" d="M113.19,408.69H236.81a2.39,2.39,0,0,0,0-4.78H113.19a2.39,2.39,0,0,0,0,4.78"/></g></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 800"><defs><style>.cls-1{fill:#bae1ed;}.cls-2{fill:#8cd0e4;}.cls-3{fill:#72bacc;}.cls-4{fill:#e25a5a;}.cls-5{fill:#ce5555;}.cls-6{fill:#eb6570;}.cls-7{fill:#fff;}.cls-8{fill:#222227;}.cls-9{fill:#3aaa35;}</style></defs><title>Poche_sang2</title><g id="Calque_3" data-name="Calque 3"><path class="cls-1" d="M146.7,217.13h-6.83a28.3,28.3,0,0,0,28.3,28.31h13.66a28.29,28.29,0,0,0,28.3-28.31V210.3a28.29,28.29,0,0,0-28.3-28.3H168.17a28.3,28.3,0,0,0-28.3,28.3v6.83h13.66V210.3a14.65,14.65,0,0,1,14.64-14.64h13.66a14.65,14.65,0,0,1,14.64,14.64v6.83a14.63,14.63,0,0,1-14.64,14.64H168.17a14.63,14.63,0,0,1-14.64-14.64Z"/><path class="cls-2" d="M255,220.06H95a46.85,46.85,0,0,0-46.84,46.85V503.09A87.83,87.83,0,0,0,136,590.93H214a87.83,87.83,0,0,0,87.83-87.84V266.91A46.85,46.85,0,0,0,255,220.06Z"/><path class="cls-3" d="M254.5,220.06h-15c-6.05,90.65-37.08,282.42-190.85,296.59a87.86,87.86,0,0,0,86.79,74.28h78.08a87.83,87.83,0,0,0,87.83-87.84V266.91A46.85,46.85,0,0,0,254.5,220.06Z"/><path class="cls-4" d="M292.11,399.19c-1.35.95-16.69,6.1-18.29,6.72C239.45,419.26,198,410.45,163,404.74c-2.28-.37-4.54-.77-6.8-1.2h-108v99.55A87.83,87.83,0,0,0,136,590.93H214a87.83,87.83,0,0,0,87.83-87.84V403.54Z"/><path class="cls-5" d="M273.3,405.91c-24.68,9.58-53,7.75-80,3.83-28.25,55.35-73.2,100.33-144.68,106.91.2,1.32.44,2.64.7,4,.13.65.29,1.3.44,1.95s.31,1.41.49,2.1.36,1.33.54,2,.37,1.33.57,2,.42,1.32.64,2,.42,1.29.65,1.93.47,1.29.72,1.94.49,1.26.74,1.88.53,1.27.8,1.9l.84,1.85c.29.61.58,1.22.88,1.83s.62,1.22.93,1.83.62,1.18.94,1.76.69,1.21,1,1.82.65,1.12,1,1.67.8,1.24,1.2,1.86.65,1,1,1.53c.54.79,1.11,1.58,1.68,2.35q.64.9,1.32,1.77c.58.76,1.15,1.51,1.76,2.23.36.45.74.88,1.12,1.32s1,1.17,1.5,1.74.83.89,1.24,1.33,1,1.07,1.53,1.6.87.87,1.32,1.3,1,1,1.58,1.51.91.83,1.38,1.24,1.09,1,1.65,1.43l1.42,1.18c.58.46,1.16.92,1.75,1.37s1,.74,1.44,1.09l1.87,1.33c.47.33,1,.67,1.43,1,.68.45,1.37.88,2.05,1.32l1.36.85c.83.5,1.67,1,2.51,1.44.34.19.67.39,1,.57,1.18.64,2.38,1.26,3.59,1.84l1,.48c.89.41,1.79.83,2.7,1.21l1.43.59,2.37.93c.53.2,1.07.37,1.6.56.76.27,1.53.54,2.3.78l1.68.52,2.3.65,1.74.44q1.16.28,2.34.54l1.75.37,2.42.43,1.73.28c.85.12,1.7.22,2.55.32.55.07,1.11.14,1.67.19.94.09,1.89.16,2.84.22l1.42.1c1.43.07,2.87.11,4.32.11h78.08a87.83,87.83,0,0,0,87.83-87.84V403.54l-9.76-4.35C290.24,400.14,274.9,405.29,273.3,405.91Z"/><path class="cls-6" d="M55.93,405.49s18.55-16.59,83.94-11.71,139.56,13.74,154.2,5.41c0,0-36.11,34.61-117.12,20.94S61.79,404.52,55.93,405.49Z"/><path class="cls-1" d="M255,233.73a33.21,33.21,0,0,1,33.18,33.18V503.09A74.25,74.25,0,0,1,214,577.26H136a74.25,74.25,0,0,1-74.17-74.17V266.91A33.21,33.21,0,0,1,95,233.73H255m0-13.67H95a46.85,46.85,0,0,0-46.84,46.85V503.09A87.83,87.83,0,0,0,136,590.93H214a87.83,87.83,0,0,0,87.83-87.84V266.91A46.85,46.85,0,0,0,255,220.06Z"/><rect class="cls-1" x="157.92" y="582.14" width="34.16" height="36.11"/><path class="cls-7" d="M100.35,414.81c0,4.7,5.88,8.52,13.14,8.52h123c7.26,0,13.14-3.82,13.14-8.52V379.37c0-4.71-5.88-8.52-13.14-8.52h-123c-7.26,0-13.14,3.81-13.14,8.52Z"/><path class="cls-8" d="M113.19,393.76H236.81a2.39,2.39,0,1,0,0-4.78H113.19a2.39,2.39,0,0,0,0,4.78"/><path class="cls-8" d="M113.19,408.69H236.81a2.39,2.39,0,0,0,0-4.78H113.19a2.39,2.39,0,0,0,0,4.78"/></g><g id="Calque_4" data-name="Calque 4"><path class="cls-9" d="M242.24,618.24A67.24,67.24,0,1,1,175,551,67.24,67.24,0,0,1,242.24,618.24Z"/><polygon class="cls-7" points="166.97 660.02 137.68 633.99 146.53 624.03 164.24 639.78 201.15 582.95 212.32 590.2 166.97 660.02"/></g></svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
public/tubes/Tube1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

1
public/tubes/Tube1.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 800"><defs><style>.cls-1{fill:#c5deed;}.cls-2,.cls-6{fill:#fff;}.cls-2{opacity:0.34;}.cls-3{fill:#773fa9;}.cls-4{opacity:0.17;}.cls-5{opacity:0.72;}</style></defs><title>Tube1</title><g id="Tube1"><path class="cls-1" d="M105.68,143.54V531.75c0,26.92,31,48.75,69.32,48.75h0c38.29,0,69.32-21.83,69.32-48.75V143.54Z"/><path class="cls-2" d="M194.92,568.11c-31.46,0-57-20-57-44.67V175.1H112V530.83c0,24.67,25.5,44.67,57,44.67h0a68.21,68.21,0,0,0,31.83-7.62c-1.92.15-3.88.23-5.85.23Z"/><path class="cls-2" d="M180.93,127V519.7c0,8.73,8.62,15.8,19.26,15.8h0c10.63,0,19.26-7.07,19.26-15.8V127Z"/><path class="cls-3" d="M245.15,45.7a8.2,8.2,0,0,0-8.2-8.2H113.05a8.2,8.2,0,0,0-8.2,8.2V152.83h140.3Z"/><rect class="cls-3" x="98.04" y="152.95" width="153.93" height="23.63"/><rect class="cls-2" x="98.04" y="152.95" width="153.93" height="2.96"/><rect class="cls-4" x="98.04" y="173.62" width="153.93" height="2.96"/><path class="cls-4" d="M123.1,46.33a5.33,5.33,0,0,0-5.33,5.33v87a5.34,5.34,0,0,0,10.67,0v-87A5.33,5.33,0,0,0,123.1,46.33Z"/><path class="cls-4" d="M143.86,46.33a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,0,0,10.66,0v-87A5.32,5.32,0,0,0,143.86,46.33Z"/><path class="cls-4" d="M164.62,46.33a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,0,0,10.66,0v-87A5.32,5.32,0,0,0,164.62,46.33Z"/><path class="cls-4" d="M185.38,46.33a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,0,0,10.66,0v-87A5.33,5.33,0,0,0,185.38,46.33Z"/><path class="cls-4" d="M206.14,46.33a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,0,0,10.66,0v-87A5.33,5.33,0,0,0,206.14,46.33Z"/><path class="cls-4" d="M226.9,46.33a5.33,5.33,0,0,0-5.34,5.33v87a5.34,5.34,0,0,0,10.67,0v-87A5.33,5.33,0,0,0,226.9,46.33Z"/><g class="cls-5"><rect class="cls-6" x="126.16" y="287.8" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="359.72" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="304.26" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="317.75" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="331.24" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="344.72" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="431.65" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="376.18" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="389.67" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="403.16" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="416.65" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="503.57" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="448.11" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="461.6" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="475.09" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="488.58" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="232.9" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="246.39" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="259.88" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="273.37" width="14.01" height="3.41"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 800"><defs><style>.cls-1{fill:#c5deed;}.cls-2,.cls-6{fill:#fff;}.cls-2{opacity:0.34;}.cls-3{fill:#773fa9;}.cls-4{opacity:0.17;}.cls-5{opacity:0.72;}.cls-7{fill:#3aaa35;}</style></defs><title>Tube1_check</title><g id="Calque_17" data-name="Calque 17"><path class="cls-1" d="M110.68,144.54V532.75c0,26.92,31,48.75,69.32,48.75h0c38.29,0,69.32-21.83,69.32-48.75V144.54Z"/><path class="cls-2" d="M199.92,569.11c-31.46,0-57-20-57-44.67V176.1H117V531.83c0,24.67,25.5,44.67,57,44.67h0a68.21,68.21,0,0,0,31.83-7.62c-1.92.15-3.88.23-5.85.23Z"/><path class="cls-2" d="M185.93,128V520.7c0,8.73,8.62,15.8,19.26,15.8h0c10.63,0,19.26-7.07,19.26-15.8V128Z"/><path class="cls-3" d="M250.15,46.7a8.2,8.2,0,0,0-8.2-8.2H118.05a8.2,8.2,0,0,0-8.2,8.2V153.83h140.3Z"/><rect class="cls-3" x="103.04" y="153.95" width="153.93" height="23.63"/><rect class="cls-2" x="103.04" y="153.95" width="153.93" height="2.96"/><rect class="cls-4" x="103.04" y="174.62" width="153.93" height="2.96"/><path class="cls-4" d="M128.1,47.33a5.33,5.33,0,0,0-5.33,5.33v87a5.34,5.34,0,0,0,10.67,0v-87A5.33,5.33,0,0,0,128.1,47.33Z"/><path class="cls-4" d="M148.86,47.33a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,0,0,10.66,0v-87A5.32,5.32,0,0,0,148.86,47.33Z"/><path class="cls-4" d="M169.62,47.33a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,0,0,10.66,0v-87A5.32,5.32,0,0,0,169.62,47.33Z"/><path class="cls-4" d="M190.38,47.33a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,0,0,10.66,0v-87A5.33,5.33,0,0,0,190.38,47.33Z"/><path class="cls-4" d="M211.14,47.33a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,0,0,10.66,0v-87A5.33,5.33,0,0,0,211.14,47.33Z"/><path class="cls-4" d="M231.9,47.33a5.33,5.33,0,0,0-5.34,5.33v87a5.34,5.34,0,0,0,10.67,0v-87A5.33,5.33,0,0,0,231.9,47.33Z"/><g class="cls-5"><rect class="cls-6" x="131.16" y="288.8" width="35.4" height="5.2"/><rect class="cls-6" x="131.16" y="360.72" width="35.4" height="5.2"/><rect class="cls-6" x="131.16" y="305.26" width="14.01" height="3.41"/><rect class="cls-6" x="131.16" y="318.75" width="14.01" height="3.41"/><rect class="cls-6" x="131.16" y="332.24" width="14.01" height="3.41"/><rect class="cls-6" x="131.16" y="345.72" width="14.01" height="3.41"/><rect class="cls-6" x="131.16" y="432.65" width="35.4" height="5.2"/><rect class="cls-6" x="131.16" y="377.18" width="14.01" height="3.41"/><rect class="cls-6" x="131.16" y="390.67" width="14.01" height="3.41"/><rect class="cls-6" x="131.16" y="404.16" width="14.01" height="3.41"/><rect class="cls-6" x="131.16" y="417.65" width="14.01" height="3.41"/><rect class="cls-6" x="131.16" y="504.57" width="35.4" height="5.2"/><rect class="cls-6" x="131.16" y="449.11" width="14.01" height="3.41"/><rect class="cls-6" x="131.16" y="462.6" width="14.01" height="3.41"/><rect class="cls-6" x="131.16" y="476.09" width="14.01" height="3.41"/><rect class="cls-6" x="131.16" y="489.58" width="14.01" height="3.41"/><rect class="cls-6" x="131.16" y="233.9" width="14.01" height="3.41"/><rect class="cls-6" x="131.16" y="247.39" width="14.01" height="3.41"/><rect class="cls-6" x="131.16" y="260.88" width="14.01" height="3.41"/><rect class="cls-6" x="131.16" y="274.37" width="14.01" height="3.41"/></g></g><g id="Calque_24" data-name="Calque 24"><path class="cls-7" d="M262,400a87,87,0,1,1-87-87A87,87,0,0,1,262,400Z"/><polygon class="cls-6" points="169.38 449.86 131.48 416.18 142.92 403.3 165.84 423.67 213.6 350.14 228.05 359.52 169.38 449.86"/></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
public/tubes/Tube2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

1
public/tubes/Tube2.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 800"><defs><style>.cls-1{fill:#c5deed;}.cls-2,.cls-6{fill:#fff;}.cls-2{opacity:0.34;}.cls-3{fill:#203d6d;}.cls-4{opacity:0.17;}.cls-5{opacity:0.72;}</style></defs><title>Tube2</title><g id="tube2"><path class="cls-1" d="M105.68,142.34V694.39A69.32,69.32,0,0,0,175,763.71h0a69.32,69.32,0,0,0,69.32-69.32v-552Z"/><path class="cls-2" d="M206.82,746.92a65.13,65.13,0,0,1-65.13-65.13V173.89H112V692.56a65.13,65.13,0,0,0,65.14,65.13h0a64.9,64.9,0,0,0,36.4-11.11c-2.2.22-4.44.34-6.7.34Z"/><path class="cls-2" d="M180.93,125.81V604.58a19.26,19.26,0,0,0,19.26,19.26h0a19.26,19.26,0,0,0,19.26-19.26V125.81Z"/><path class="cls-3" d="M245.15,44.5a8.2,8.2,0,0,0-8.2-8.21H113.05a8.2,8.2,0,0,0-8.2,8.21V151.62h140.3Z"/><rect class="cls-3" x="98.04" y="151.74" width="153.93" height="23.63"/><rect class="cls-2" x="98.04" y="151.74" width="153.93" height="2.96"/><rect class="cls-4" x="98.04" y="172.41" width="153.93" height="2.96"/><path class="cls-4" d="M123.1,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.34,5.34,0,1,0,10.67,0v-87A5.33,5.33,0,0,0,123.1,45.12Z"/><path class="cls-4" d="M143.86,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.32,5.32,0,0,0,143.86,45.12Z"/><path class="cls-4" d="M164.62,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.32,5.32,0,0,0,164.62,45.12Z"/><path class="cls-4" d="M185.38,45.12a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.33,5.33,0,0,0,185.38,45.12Z"/><path class="cls-4" d="M206.14,45.12a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.33,5.33,0,0,0,206.14,45.12Z"/><path class="cls-4" d="M226.9,45.12a5.33,5.33,0,0,0-5.34,5.33v87a5.34,5.34,0,1,0,10.67,0v-87A5.33,5.33,0,0,0,226.9,45.12Z"/><g class="cls-5"><rect class="cls-6" x="126.16" y="286.59" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="358.51" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="303.05" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="316.54" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="330.03" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="343.51" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="430.44" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="374.97" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="388.46" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="401.95" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="415.44" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="502.36" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="446.9" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="460.39" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="473.88" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="487.37" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="574.29" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="518.82" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="532.31" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="545.8" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="559.29" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="646.21" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="590.75" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="604.24" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="617.73" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="631.22" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="231.69" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="245.18" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="258.67" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="272.16" width="14.01" height="3.41"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 800"><defs><style>.cls-1{fill:#c5deed;}.cls-2,.cls-6{fill:#fff;}.cls-2{opacity:0.34;}.cls-3{fill:#203d6d;}.cls-4{opacity:0.17;}.cls-5{opacity:0.72;}.cls-7{fill:#3aaa35;}</style></defs><title>Tube2_check</title><g id="Calque_18" data-name="Calque 18"><path class="cls-1" d="M105.68,142.34V694.39A69.32,69.32,0,0,0,175,763.71h0a69.32,69.32,0,0,0,69.32-69.32v-552Z"/><path class="cls-2" d="M206.82,746.92a65.13,65.13,0,0,1-65.13-65.13V173.89H112V692.56a65.13,65.13,0,0,0,65.14,65.13h0a64.9,64.9,0,0,0,36.4-11.11c-2.2.22-4.44.34-6.7.34Z"/><path class="cls-2" d="M180.93,125.81V604.58a19.26,19.26,0,0,0,19.26,19.26h0a19.26,19.26,0,0,0,19.26-19.26V125.81Z"/><path class="cls-3" d="M245.15,44.5a8.2,8.2,0,0,0-8.2-8.21H113.05a8.2,8.2,0,0,0-8.2,8.21V151.62h140.3Z"/><rect class="cls-3" x="98.04" y="151.74" width="153.93" height="23.63"/><rect class="cls-2" x="98.04" y="151.74" width="153.93" height="2.96"/><rect class="cls-4" x="98.04" y="172.41" width="153.93" height="2.96"/><path class="cls-4" d="M123.1,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.34,5.34,0,1,0,10.67,0v-87A5.33,5.33,0,0,0,123.1,45.12Z"/><path class="cls-4" d="M143.86,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.32,5.32,0,0,0,143.86,45.12Z"/><path class="cls-4" d="M164.62,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.32,5.32,0,0,0,164.62,45.12Z"/><path class="cls-4" d="M185.38,45.12a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.33,5.33,0,0,0,185.38,45.12Z"/><path class="cls-4" d="M206.14,45.12a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.33,5.33,0,0,0,206.14,45.12Z"/><path class="cls-4" d="M226.9,45.12a5.33,5.33,0,0,0-5.34,5.33v87a5.34,5.34,0,1,0,10.67,0v-87A5.33,5.33,0,0,0,226.9,45.12Z"/><g class="cls-5"><rect class="cls-6" x="126.16" y="286.59" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="358.51" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="303.05" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="316.54" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="330.03" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="343.51" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="430.44" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="374.97" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="388.46" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="401.95" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="415.44" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="502.36" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="446.9" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="460.39" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="473.88" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="487.37" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="574.29" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="518.82" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="532.31" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="545.8" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="559.29" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="646.21" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="590.75" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="604.24" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="617.73" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="631.22" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="231.69" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="245.18" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="258.67" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="272.16" width="14.01" height="3.41"/></g></g><g id="Calque_23" data-name="Calque 23"><path class="cls-7" d="M262,400a87,87,0,1,1-87-87A87,87,0,0,1,262,400Z"/><polygon class="cls-6" points="164.38 449.86 126.48 416.18 137.92 403.3 160.84 423.67 208.6 350.14 223.05 359.52 164.38 449.86"/></g></svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
public/tubes/Tube3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

1
public/tubes/Tube3.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 800"><defs><style>.cls-1{fill:#c5deed;}.cls-2,.cls-6{fill:#fff;}.cls-2{opacity:0.34;}.cls-3{fill:#f39de4;}.cls-4{opacity:0.17;}.cls-5{opacity:0.72;}</style></defs><title>Tube3</title><g id="Calque_13" data-name="Calque 13"><path class="cls-1" d="M105.68,142.34V694.39A69.32,69.32,0,0,0,175,763.71h0a69.32,69.32,0,0,0,69.32-69.32v-552Z"/><path class="cls-2" d="M206.82,746.92a65.13,65.13,0,0,1-65.13-65.13V173.89H112V692.56a65.13,65.13,0,0,0,65.14,65.13h0a64.9,64.9,0,0,0,36.4-11.11c-2.2.22-4.44.34-6.7.34Z"/><path class="cls-2" d="M180.93,125.81V604.58a19.26,19.26,0,0,0,19.26,19.26h0a19.26,19.26,0,0,0,19.26-19.26V125.81Z"/><path class="cls-3" d="M245.15,44.5a8.2,8.2,0,0,0-8.2-8.21H113.05a8.2,8.2,0,0,0-8.2,8.21V151.62h140.3Z"/><rect class="cls-3" x="98.04" y="151.74" width="153.93" height="23.63"/><rect class="cls-2" x="98.04" y="151.74" width="153.93" height="2.96"/><rect class="cls-4" x="98.04" y="172.41" width="153.93" height="2.96"/><path class="cls-4" d="M123.1,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.34,5.34,0,1,0,10.67,0v-87A5.33,5.33,0,0,0,123.1,45.12Z"/><path class="cls-4" d="M143.86,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.32,5.32,0,0,0,143.86,45.12Z"/><path class="cls-4" d="M164.62,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.32,5.32,0,0,0,164.62,45.12Z"/><path class="cls-4" d="M185.38,45.12a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.33,5.33,0,0,0,185.38,45.12Z"/><path class="cls-4" d="M206.14,45.12a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.33,5.33,0,0,0,206.14,45.12Z"/><path class="cls-4" d="M226.9,45.12a5.33,5.33,0,0,0-5.34,5.33v87a5.34,5.34,0,1,0,10.67,0v-87A5.33,5.33,0,0,0,226.9,45.12Z"/><g class="cls-5"><rect class="cls-6" x="126.16" y="286.59" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="358.51" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="303.05" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="316.54" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="330.03" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="343.51" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="430.44" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="374.97" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="388.46" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="401.95" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="415.44" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="502.36" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="446.9" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="460.39" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="473.88" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="487.37" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="574.29" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="518.82" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="532.31" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="545.8" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="559.29" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="646.21" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="590.75" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="604.24" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="617.73" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="631.22" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="231.69" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="245.18" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="258.67" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="272.16" width="14.01" height="3.41"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 800"><defs><style>.cls-1{fill:#c5deed;}.cls-2,.cls-6{fill:#fff;}.cls-2{opacity:0.34;}.cls-3{fill:#f39de4;}.cls-4{opacity:0.17;}.cls-5{opacity:0.72;}.cls-7{fill:#3aaa35;}</style></defs><title>Tube3_check</title><g id="Calque_19" data-name="Calque 19"><path class="cls-1" d="M115.68,142.34V694.39A69.32,69.32,0,0,0,185,763.71h0a69.32,69.32,0,0,0,69.32-69.32v-552Z"/><path class="cls-2" d="M216.82,746.92a65.13,65.13,0,0,1-65.13-65.13V173.89H122V692.56a65.13,65.13,0,0,0,65.14,65.13h0a64.9,64.9,0,0,0,36.4-11.11c-2.2.22-4.44.34-6.7.34Z"/><path class="cls-2" d="M190.93,125.81V604.58a19.26,19.26,0,0,0,19.26,19.26h0a19.26,19.26,0,0,0,19.26-19.26V125.81Z"/><path class="cls-3" d="M255.15,44.5a8.2,8.2,0,0,0-8.2-8.21H123.05a8.2,8.2,0,0,0-8.2,8.21V151.62h140.3Z"/><rect class="cls-3" x="108.04" y="151.74" width="153.93" height="23.63"/><rect class="cls-2" x="108.04" y="151.74" width="153.93" height="2.96"/><rect class="cls-4" x="108.04" y="172.41" width="153.93" height="2.96"/><path class="cls-4" d="M133.1,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.34,5.34,0,1,0,10.67,0v-87A5.33,5.33,0,0,0,133.1,45.12Z"/><path class="cls-4" d="M153.86,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.32,5.32,0,0,0,153.86,45.12Z"/><path class="cls-4" d="M174.62,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.32,5.32,0,0,0,174.62,45.12Z"/><path class="cls-4" d="M195.38,45.12a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.33,5.33,0,0,0,195.38,45.12Z"/><path class="cls-4" d="M216.14,45.12a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.33,5.33,0,0,0,216.14,45.12Z"/><path class="cls-4" d="M236.9,45.12a5.33,5.33,0,0,0-5.34,5.33v87a5.34,5.34,0,1,0,10.67,0v-87A5.33,5.33,0,0,0,236.9,45.12Z"/><g class="cls-5"><rect class="cls-6" x="136.16" y="286.59" width="35.4" height="5.2"/><rect class="cls-6" x="136.16" y="358.51" width="35.4" height="5.2"/><rect class="cls-6" x="136.16" y="303.05" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="316.54" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="330.03" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="343.51" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="430.44" width="35.4" height="5.2"/><rect class="cls-6" x="136.16" y="374.97" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="388.46" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="401.95" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="415.44" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="502.36" width="35.4" height="5.2"/><rect class="cls-6" x="136.16" y="446.9" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="460.39" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="473.88" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="487.37" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="574.29" width="35.4" height="5.2"/><rect class="cls-6" x="136.16" y="518.82" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="532.31" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="545.8" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="559.29" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="646.21" width="35.4" height="5.2"/><rect class="cls-6" x="136.16" y="590.75" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="604.24" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="617.73" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="631.22" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="231.69" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="245.18" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="258.67" width="14.01" height="3.41"/><rect class="cls-6" x="136.16" y="272.16" width="14.01" height="3.41"/></g></g><g id="Calque_25" data-name="Calque 25"><path class="cls-7" d="M262,400a87,87,0,1,1-87-87A87,87,0,0,1,262,400Z"/><polygon class="cls-6" points="164.61 449.86 126.72 416.18 138.16 403.3 161.08 423.67 208.83 350.14 223.28 359.52 164.61 449.86"/></g></svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
public/tubes/Tube4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

1
public/tubes/Tube4.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 800"><defs><style>.cls-1{fill:#c5deed;}.cls-2,.cls-6{fill:#fff;}.cls-2{opacity:0.34;}.cls-3{fill:#eab82d;}.cls-4{opacity:0.17;}.cls-5{opacity:0.72;}</style></defs><title>Tube4</title><g id="Calque_14" data-name="Calque 14"><path class="cls-1" d="M120.91,141V693.1a69.32,69.32,0,0,0,69.32,69.32h0a69.32,69.32,0,0,0,69.32-69.32V141Z"/><path class="cls-2" d="M222.05,745.63a65.13,65.13,0,0,1-65.13-65.14V172.6H127.21V691.27a65.13,65.13,0,0,0,65.14,65.13h0a64.9,64.9,0,0,0,36.4-11.11c-2.2.22-4.44.34-6.7.34Z"/><path class="cls-2" d="M196.16,124.52V603.29a19.26,19.26,0,0,0,19.26,19.26h0a19.26,19.26,0,0,0,19.26-19.26V124.52Z"/><path class="cls-3" d="M260.38,43.2a8.2,8.2,0,0,0-8.21-8.2H128.28a8.2,8.2,0,0,0-8.2,8.2V150.33h140.3Z"/><rect class="cls-3" x="113.27" y="150.45" width="153.93" height="23.63"/><rect class="cls-2" x="113.27" y="150.45" width="153.93" height="2.96"/><rect class="cls-4" x="113.27" y="171.12" width="153.93" height="2.96"/><path class="cls-4" d="M138.33,43.83A5.33,5.33,0,0,0,133,49.16v87a5.34,5.34,0,0,0,10.67,0v-87A5.33,5.33,0,0,0,138.33,43.83Z"/><path class="cls-4" d="M159.09,43.83a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,0,0,10.66,0v-87A5.32,5.32,0,0,0,159.09,43.83Z"/><path class="cls-4" d="M179.85,43.83a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,0,0,10.66,0v-87A5.33,5.33,0,0,0,179.85,43.83Z"/><path class="cls-4" d="M200.61,43.83a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,0,0,10.66,0v-87A5.33,5.33,0,0,0,200.61,43.83Z"/><path class="cls-4" d="M221.37,43.83A5.33,5.33,0,0,0,216,49.16v87a5.34,5.34,0,0,0,10.67,0v-87A5.33,5.33,0,0,0,221.37,43.83Z"/><path class="cls-4" d="M242.12,43.83a5.33,5.33,0,0,0-5.33,5.33v87a5.34,5.34,0,0,0,10.67,0v-87A5.33,5.33,0,0,0,242.12,43.83Z"/><g class="cls-5"><rect class="cls-6" x="141.39" y="285.3" width="35.4" height="5.2"/><rect class="cls-6" x="141.39" y="357.22" width="35.4" height="5.2"/><rect class="cls-6" x="141.39" y="301.76" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="315.25" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="328.74" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="342.22" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="429.15" width="35.4" height="5.2"/><rect class="cls-6" x="141.39" y="373.68" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="387.17" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="400.66" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="414.15" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="501.07" width="35.4" height="5.2"/><rect class="cls-6" x="141.39" y="445.61" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="459.1" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="472.59" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="486.08" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="573" width="35.4" height="5.2"/><rect class="cls-6" x="141.39" y="517.53" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="531.02" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="544.51" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="558" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="644.92" width="35.4" height="5.2"/><rect class="cls-6" x="141.39" y="589.46" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="602.95" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="616.44" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="629.93" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="230.4" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="243.89" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="257.38" width="14.01" height="3.41"/><rect class="cls-6" x="141.39" y="270.87" width="14.01" height="3.41"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 800"><defs><style>.cls-1{fill:#c5deed;}.cls-2,.cls-6{fill:#fff;}.cls-2{opacity:0.34;}.cls-3{fill:#eab82d;}.cls-4{opacity:0.17;}.cls-5{opacity:0.72;}.cls-7{fill:#3aaa35;}</style></defs><title>Tube4_check</title><g id="Calque_20" data-name="Calque 20"><path class="cls-1" d="M105.68,142.34V694.39A69.32,69.32,0,0,0,175,763.71h0a69.32,69.32,0,0,0,69.32-69.32v-552Z"/><path class="cls-2" d="M206.82,746.92a65.13,65.13,0,0,1-65.13-65.13V173.89H112V692.56a65.13,65.13,0,0,0,65.14,65.13h0a64.9,64.9,0,0,0,36.4-11.11c-2.2.22-4.44.34-6.7.34Z"/><path class="cls-2" d="M180.93,125.81V604.58a19.26,19.26,0,0,0,19.26,19.26h0a19.26,19.26,0,0,0,19.26-19.26V125.81Z"/><path class="cls-3" d="M245.15,44.5a8.2,8.2,0,0,0-8.2-8.21H113.05a8.2,8.2,0,0,0-8.2,8.21V151.62h140.3Z"/><rect class="cls-3" x="98.04" y="151.74" width="153.93" height="23.63"/><rect class="cls-2" x="98.04" y="151.74" width="153.93" height="2.96"/><rect class="cls-4" x="98.04" y="172.41" width="153.93" height="2.96"/><path class="cls-4" d="M123.1,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.34,5.34,0,1,0,10.67,0v-87A5.33,5.33,0,0,0,123.1,45.12Z"/><path class="cls-4" d="M143.86,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.32,5.32,0,0,0,143.86,45.12Z"/><path class="cls-4" d="M164.62,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.32,5.32,0,0,0,164.62,45.12Z"/><path class="cls-4" d="M185.38,45.12a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.33,5.33,0,0,0,185.38,45.12Z"/><path class="cls-4" d="M206.14,45.12a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.33,5.33,0,0,0,206.14,45.12Z"/><path class="cls-4" d="M226.9,45.12a5.33,5.33,0,0,0-5.34,5.33v87a5.34,5.34,0,1,0,10.67,0v-87A5.33,5.33,0,0,0,226.9,45.12Z"/><g class="cls-5"><rect class="cls-6" x="126.16" y="286.59" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="358.51" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="303.05" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="316.54" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="330.03" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="343.51" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="430.44" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="374.97" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="388.46" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="401.95" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="415.44" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="502.36" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="446.9" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="460.39" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="473.88" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="487.37" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="574.29" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="518.82" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="532.31" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="545.8" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="559.29" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="646.21" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="590.75" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="604.24" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="617.73" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="631.22" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="231.69" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="245.18" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="258.67" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="272.16" width="14.01" height="3.41"/></g></g><g id="Calque_27" data-name="Calque 27"><path class="cls-7" d="M262,400a87,87,0,1,1-87-87A87,87,0,0,1,262,400Z"/><polygon class="cls-6" points="164.61 449.86 126.72 416.18 138.16 403.3 161.08 423.67 208.83 350.14 223.28 359.52 164.61 449.86"/></g></svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
public/tubes/Tube5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

1
public/tubes/Tube5.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 800"><defs><style>.cls-1{fill:#c5deed;}.cls-2,.cls-6{fill:#fff;}.cls-2{opacity:0.34;}.cls-3{fill:#773fa9;}.cls-4{opacity:0.17;}.cls-5{opacity:0.72;}</style></defs><title>Tube5</title><g id="Calque_15" data-name="Calque 15"><path class="cls-1" d="M105.68,142.34V694.39A69.32,69.32,0,0,0,175,763.71h0a69.32,69.32,0,0,0,69.32-69.32v-552Z"/><path class="cls-2" d="M206.82,746.92a65.13,65.13,0,0,1-65.13-65.13V173.89H112V692.56a65.13,65.13,0,0,0,65.14,65.13h0a64.9,64.9,0,0,0,36.4-11.11c-2.2.22-4.44.34-6.7.34Z"/><path class="cls-2" d="M180.93,125.81V604.58a19.26,19.26,0,0,0,19.26,19.26h0a19.26,19.26,0,0,0,19.26-19.26V125.81Z"/><path class="cls-3" d="M245.15,44.5a8.2,8.2,0,0,0-8.2-8.21H113.05a8.2,8.2,0,0,0-8.2,8.21V151.62h140.3Z"/><rect class="cls-3" x="98.04" y="151.74" width="153.93" height="23.63"/><rect class="cls-2" x="98.04" y="151.74" width="153.93" height="2.96"/><rect class="cls-4" x="98.04" y="172.41" width="153.93" height="2.96"/><path class="cls-4" d="M123.1,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.34,5.34,0,1,0,10.67,0v-87A5.33,5.33,0,0,0,123.1,45.12Z"/><path class="cls-4" d="M143.86,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.32,5.32,0,0,0,143.86,45.12Z"/><path class="cls-4" d="M164.62,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.32,5.32,0,0,0,164.62,45.12Z"/><path class="cls-4" d="M185.38,45.12a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.33,5.33,0,0,0,185.38,45.12Z"/><path class="cls-4" d="M206.14,45.12a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.33,5.33,0,0,0,206.14,45.12Z"/><path class="cls-4" d="M226.9,45.12a5.33,5.33,0,0,0-5.34,5.33v87a5.34,5.34,0,1,0,10.67,0v-87A5.33,5.33,0,0,0,226.9,45.12Z"/><g class="cls-5"><rect class="cls-6" x="126.16" y="286.59" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="358.51" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="303.05" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="316.54" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="330.03" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="343.51" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="430.44" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="374.97" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="388.46" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="401.95" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="415.44" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="502.36" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="446.9" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="460.39" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="473.88" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="487.37" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="574.29" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="518.82" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="532.31" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="545.8" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="559.29" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="646.21" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="590.75" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="604.24" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="617.73" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="631.22" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="231.69" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="245.18" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="258.67" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="272.16" width="14.01" height="3.41"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 800"><defs><style>.cls-1{fill:#c5deed;}.cls-2,.cls-6{fill:#fff;}.cls-2{opacity:0.34;}.cls-3{fill:#773fa9;}.cls-4{opacity:0.17;}.cls-5{opacity:0.72;}.cls-7{fill:#3aaa35;}</style></defs><title>Tube5_check</title><g id="Calque_21" data-name="Calque 21"><path class="cls-1" d="M105.68,142.34V694.39A69.32,69.32,0,0,0,175,763.71h0a69.32,69.32,0,0,0,69.32-69.32v-552Z"/><path class="cls-2" d="M206.82,746.92a65.13,65.13,0,0,1-65.13-65.13V173.89H112V692.56a65.13,65.13,0,0,0,65.14,65.13h0a64.9,64.9,0,0,0,36.4-11.11c-2.2.22-4.44.34-6.7.34Z"/><path class="cls-2" d="M180.93,125.81V604.58a19.26,19.26,0,0,0,19.26,19.26h0a19.26,19.26,0,0,0,19.26-19.26V125.81Z"/><path class="cls-3" d="M245.15,44.5a8.2,8.2,0,0,0-8.2-8.21H113.05a8.2,8.2,0,0,0-8.2,8.21V151.62h140.3Z"/><rect class="cls-3" x="98.04" y="151.74" width="153.93" height="23.63"/><rect class="cls-2" x="98.04" y="151.74" width="153.93" height="2.96"/><rect class="cls-4" x="98.04" y="172.41" width="153.93" height="2.96"/><path class="cls-4" d="M123.1,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.34,5.34,0,1,0,10.67,0v-87A5.33,5.33,0,0,0,123.1,45.12Z"/><path class="cls-4" d="M143.86,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.32,5.32,0,0,0,143.86,45.12Z"/><path class="cls-4" d="M164.62,45.12a5.33,5.33,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.32,5.32,0,0,0,164.62,45.12Z"/><path class="cls-4" d="M185.38,45.12a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.33,5.33,0,0,0,185.38,45.12Z"/><path class="cls-4" d="M206.14,45.12a5.32,5.32,0,0,0-5.33,5.33v87a5.33,5.33,0,1,0,10.66,0v-87A5.33,5.33,0,0,0,206.14,45.12Z"/><path class="cls-4" d="M226.9,45.12a5.33,5.33,0,0,0-5.34,5.33v87a5.34,5.34,0,1,0,10.67,0v-87A5.33,5.33,0,0,0,226.9,45.12Z"/><g class="cls-5"><rect class="cls-6" x="126.16" y="286.59" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="358.51" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="303.05" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="316.54" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="330.03" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="343.51" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="430.44" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="374.97" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="388.46" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="401.95" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="415.44" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="502.36" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="446.9" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="460.39" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="473.88" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="487.37" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="574.29" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="518.82" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="532.31" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="545.8" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="559.29" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="646.21" width="35.4" height="5.2"/><rect class="cls-6" x="126.16" y="590.75" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="604.24" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="617.73" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="631.22" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="231.69" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="245.18" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="258.67" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="272.16" width="14.01" height="3.41"/></g></g><g id="Calque_28" data-name="Calque 28"><path class="cls-7" d="M262,400a87,87,0,1,1-87-87A87,87,0,0,1,262,400Z"/><polygon class="cls-6" points="159.61 449.86 121.72 416.18 133.16 403.3 156.08 423.67 203.83 350.14 218.28 359.52 159.61 449.86"/></g></svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
public/tubes/Tube6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

1
public/tubes/Tube6.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 800"><defs><style>.cls-1{fill:#c5deed;}.cls-2,.cls-6{fill:#fff;}.cls-2{opacity:0.34;}.cls-3{fill:#ac3039;}.cls-4{opacity:0.17;}.cls-5{opacity:0.72;}</style></defs><title>Tube6</title><g id="Calque_16" data-name="Calque 16"><path class="cls-1" d="M105.58,141.51l.18,388.21c0,26.92,31.06,48.73,69.35,48.72h0c38.28,0,69.31-21.86,69.3-48.78l-.18-388.21Z"/><path class="cls-2" d="M195,566c-31.45,0-57-20-57-44.65l-.16-348.33h-26l.16,355.73c0,24.67,25.52,44.65,57,44.64h0a68.16,68.16,0,0,0,31.83-7.64Q198,566,195,566Z"/><path class="cls-2" d="M180.83,125,181,517.64c0,8.72,8.63,15.79,19.26,15.79h0c10.64,0,19.26-7.09,19.26-15.81l-.18-392.69Z"/><path class="cls-3" d="M245,43.61a8.2,8.2,0,0,0-8.21-8.2l-123.89.06a8.2,8.2,0,0,0-8.2,8.2l.05,107.13,140.3-.06Z"/><rect class="cls-3" x="97.95" y="150.89" width="153.93" height="23.63"/><rect class="cls-2" x="97.95" y="150.89" width="153.93" height="2.96"/><rect class="cls-4" x="97.96" y="171.56" width="153.93" height="2.96"/><path class="cls-4" d="M123,44.29a5.33,5.33,0,0,0-5.33,5.33l0,87a5.33,5.33,0,1,0,10.66,0l0-87A5.33,5.33,0,0,0,123,44.29Z"/><path class="cls-4" d="M143.73,44.28a5.33,5.33,0,0,0-5.33,5.33l0,87a5.33,5.33,0,1,0,10.66,0l0-87A5.33,5.33,0,0,0,143.73,44.28Z"/><path class="cls-4" d="M164.48,44.27a5.33,5.33,0,0,0-5.33,5.33l0,87a5.34,5.34,0,1,0,10.67,0l0-87A5.33,5.33,0,0,0,164.48,44.27Z"/><path class="cls-4" d="M185.24,44.26a5.33,5.33,0,0,0-5.33,5.33l0,87a5.34,5.34,0,1,0,10.67,0l0-87A5.33,5.33,0,0,0,185.24,44.26Z"/><path class="cls-4" d="M206,44.25a5.33,5.33,0,0,0-5.33,5.33l0,87a5.33,5.33,0,1,0,10.66,0l0-87A5.32,5.32,0,0,0,206,44.25Z"/><path class="cls-4" d="M226.76,44.24a5.33,5.33,0,0,0-5.33,5.33l0,87a5.33,5.33,0,1,0,10.66,0l0-87A5.33,5.33,0,0,0,226.76,44.24Z"/><g class="cls-5"><rect class="cls-6" x="126.14" y="285.75" width="35.4" height="5.2"/><rect class="cls-6" x="126.17" y="357.67" width="35.4" height="5.2"/><rect class="cls-6" x="126.15" y="302.21" width="14.01" height="3.41"/><rect class="cls-6" x="126.15" y="315.7" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="329.19" width="14.01" height="3.41"/><rect class="cls-6" x="126.16" y="342.68" width="14.01" height="3.41"/><rect class="cls-6" x="126.2" y="429.6" width="35.4" height="5.2"/><rect class="cls-6" x="126.18" y="374.14" width="14.01" height="3.41"/><rect class="cls-6" x="126.18" y="387.63" width="14.01" height="3.41"/><rect class="cls-6" x="126.19" y="401.12" width="14.01" height="3.41"/><rect class="cls-6" x="126.2" y="414.61" width="14.01" height="3.41"/><rect class="cls-6" x="126.24" y="501.52" width="35.4" height="5.2"/><rect class="cls-6" x="126.21" y="446.06" width="14.01" height="3.41"/><rect class="cls-6" x="126.22" y="459.55" width="14.01" height="3.41"/><rect class="cls-6" x="126.22" y="473.04" width="14.01" height="3.41"/><rect class="cls-6" x="126.23" y="486.53" width="14.01" height="3.41"/><rect class="cls-6" x="126.11" y="230.86" width="14.01" height="3.41"/><rect class="cls-6" x="126.12" y="244.35" width="14.01" height="3.41"/><rect class="cls-6" x="126.13" y="257.84" width="14.01" height="3.41"/><rect class="cls-6" x="126.13" y="271.33" width="14.01" height="3.41"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 800"><defs><style>.cls-1{fill:#c5deed;}.cls-2,.cls-6{fill:#fff;}.cls-2{opacity:0.34;}.cls-3{fill:#ac3039;}.cls-4{opacity:0.17;}.cls-5{opacity:0.72;}.cls-7{fill:#3aaa35;}</style></defs><title>Tube6_check</title><g id="Calque_22" data-name="Calque 22"><path class="cls-1" d="M105.67,141.51l.17,388.21c0,26.92,31.06,48.73,69.35,48.72h0c38.29,0,69.31-21.86,69.3-48.78l-.18-388.21Z"/><path class="cls-2" d="M195.1,566c-31.45,0-57-20-57-44.65L138,173.06H112l.16,355.73c0,24.67,25.52,44.65,57,44.64h0A68.22,68.22,0,0,0,201,565.8q-2.9.24-5.86.24Z"/><path class="cls-2" d="M180.91,125l.18,392.69c0,8.72,8.63,15.79,19.27,15.79h0c10.63,0,19.25-7.09,19.25-15.81l-.18-392.69Z"/><path class="cls-3" d="M245.1,43.61a8.21,8.21,0,0,0-8.21-8.2L113,35.47a8.19,8.19,0,0,0-8.2,8.2l0,107.13,140.3-.06Z"/><rect class="cls-3" x="98.04" y="150.89" width="153.93" height="23.63"/><rect class="cls-2" x="98.03" y="150.89" width="153.93" height="2.96"/><rect class="cls-4" x="98.04" y="171.56" width="153.93" height="2.96"/><path class="cls-4" d="M123.05,44.29a5.33,5.33,0,0,0-5.33,5.33l0,87a5.33,5.33,0,1,0,10.66,0l0-87A5.33,5.33,0,0,0,123.05,44.29Z"/><path class="cls-4" d="M143.81,44.28a5.33,5.33,0,0,0-5.33,5.33l0,87a5.33,5.33,0,1,0,10.66,0l0-87A5.33,5.33,0,0,0,143.81,44.28Z"/><path class="cls-4" d="M164.57,44.27a5.33,5.33,0,0,0-5.33,5.33l0,87a5.33,5.33,0,1,0,10.66,0l0-87A5.33,5.33,0,0,0,164.57,44.27Z"/><path class="cls-4" d="M185.32,44.26A5.32,5.32,0,0,0,180,49.59l0,87a5.33,5.33,0,1,0,10.66,0l0-87A5.33,5.33,0,0,0,185.32,44.26Z"/><path class="cls-4" d="M206.08,44.25a5.33,5.33,0,0,0-5.33,5.33l0,87a5.34,5.34,0,1,0,10.67,0l0-87A5.33,5.33,0,0,0,206.08,44.25Z"/><path class="cls-4" d="M226.84,44.24a5.33,5.33,0,0,0-5.33,5.33l0,87a5.34,5.34,0,1,0,10.67,0l0-87A5.34,5.34,0,0,0,226.84,44.24Z"/><g class="cls-5"><rect class="cls-6" x="126.22" y="285.75" width="35.4" height="5.2"/><rect class="cls-6" x="126.25" y="357.67" width="35.4" height="5.2"/><rect class="cls-6" x="126.23" y="302.21" width="14.01" height="3.41"/><rect class="cls-6" x="126.23" y="315.7" width="14.01" height="3.41"/><rect class="cls-6" x="126.24" y="329.19" width="14.01" height="3.41"/><rect class="cls-6" x="126.25" y="342.68" width="14.01" height="3.41"/><rect class="cls-6" x="126.29" y="429.6" width="35.4" height="5.2"/><rect class="cls-6" x="126.26" y="374.14" width="14.01" height="3.41"/><rect class="cls-6" x="126.27" y="387.63" width="14.01" height="3.41"/><rect class="cls-6" x="126.27" y="401.12" width="14.01" height="3.41"/><rect class="cls-6" x="126.28" y="414.61" width="14.01" height="3.41"/><rect class="cls-6" x="126.32" y="501.52" width="35.4" height="5.2"/><rect class="cls-6" x="126.29" y="446.06" width="14.01" height="3.41"/><rect class="cls-6" x="126.3" y="459.55" width="14.01" height="3.41"/><rect class="cls-6" x="126.31" y="473.04" width="14.01" height="3.41"/><rect class="cls-6" x="126.31" y="486.53" width="14.01" height="3.41"/><rect class="cls-6" x="126.2" y="230.86" width="14.01" height="3.41"/><rect class="cls-6" x="126.2" y="244.35" width="14.01" height="3.41"/><rect class="cls-6" x="126.21" y="257.84" width="14.01" height="3.41"/><rect class="cls-6" x="126.21" y="271.33" width="14.01" height="3.41"/></g></g><g id="Calque_29" data-name="Calque 29"><path class="cls-7" d="M262,400a87,87,0,1,1-87-87A87,87,0,0,1,262,400Z"/><polygon class="cls-6" points="164.61 449.86 126.72 416.18 138.16 403.3 161.08 423.67 208.83 350.14 223.28 359.52 164.61 449.86"/></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1,291 @@
<?php
namespace App\Command;
use App\Services\Tools;
use App\Twig\AppExtension;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\MakerBundle\Str;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
class MakeAdminController extends Command
{
private Tools $tools;
protected static $defaultName = 'make:admin-controller';
public function __construct( Tools $tools)
{
$this->tools = $tools;
parent::__construct();
}
protected function configure(): void
{
$this->setDescription('Create Admin Controller')
->setHelp('Create controller for admin')
->addArgument('entityName', InputArgument::REQUIRED, 'Nom de l\'entité')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$className = ucfirst($input->getArgument('entityName'));
$lowerClassName = lcfirst($className);
$instance = '$'.lcfirst($className);
$snakeName = Str::asRouteName($className);
$controllerDir = __DIR__ . '/../Controller/';
$formDir = __DIR__ . '/../Form/';
$handlerDir = __DIR__ . '/../Form/Handler/';
if(!file_exists($formDir) && !mkdir($formDir, 0777) && !is_dir($formDir)) {
throw new \RuntimeException(sprintf('Directory "%s" was not created', $formDir));
}
if(!file_exists($handlerDir) && !mkdir($handlerDir, 0777) && !is_dir($handlerDir)) {
throw new \RuntimeException(sprintf('Directory "%s" was not created', $handlerDir));
}
$metadatas = $this->tools->getProperties("App\Entity\\".$className);
$tabResponse = [];
foreach ($metadatas as $metadata){
$helper = $this->getHelper('question');
$question = new ConfirmationQuestion('Voulez vous ajoutez '.$metadata.' dans les fields ? (default : true) ', true);
if ($helper->ask($input, $output, $question)){
$tabResponse[$metadata]['fields'] = true;
$tabResponse[$metadata]['show'] = $helper->ask($input, $output , new Question('Quel nom afficher pour la propriété? (default : '.$metadata.') ', $metadata));
}
}
$fields = "";
foreach ($tabResponse as $key => $item){
$fields.=$item['fields'] ? "'".ucfirst($item['show'])."' => '".ucfirst($key)."',\n" : "";
}
$controllerContent =
"<?php
namespace App\Controller;
use App\Entity\\".$className.";
use App\Form\\".$className."Type;
use App\Form\Handler\\".$className."Handler;
use App\Repository\\".$className."Repository;
use App\Services\Tools;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Container\ContainerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Knp\Component\Pager\PaginatorInterface;
/**
* Class ".$className."Controller
* @package App\Controller
* @Route(\"/admin/$lowerClassName\", name=\"admin_".$snakeName."_\")
*/
class ".$className."Controller extends AbstractController
{
private EntityManagerInterface \$entityManager;
public function __construct(EntityManagerInterface \$entityManager)
{
\$this->entityManager = \$entityManager;
}
/**
* @Route(\"/\", name=\"index\", methods={\"GET\"})
* @param ".$className."Repository ".$instance."Repository
* PaginatorInterface \$paginator
* Request \$request
*/
public function index(".$className."Repository ".$instance."Repository, PaginatorInterface \$paginator, Request \$request): Response
{
\$els = \$paginator->paginate(
".$instance."Repository->createQueryBuilder('a')->getQuery(),
\$request->query->getInt('page', 1),
10
);
return \$this->render('admin/crud/index.html.twig', [
'els'=>\$els,
'paginator'=>false,
'search'=>false,
'class'=> ".$className."::class,
'route'=> 'admin_". $snakeName ."',
'breadcrumb'=>[
[
'text'=>'tous les éléments'
]
],
'fields' => [
$fields
],
'title' => 'Tous les élements',
'add_button_label'=>'Ajouter un élément'
]);
}
/**
* @Route(\"/new\", name=\"new\", methods={\"GET\",\"POST\"})
* @param Request \$request
* @param ".$className."Handler ".$instance."Handler
* @param Tools \$tools
* @return Response
*/
public function new(Request \$request, Tools \$tools, ".$className."Handler ".$instance."Handler): Response
{
$instance = new ".$className."();
\$form = \$this->createForm(".$className."Type::class, $instance);
if (".$instance."Handler->new(\$form, \$request)) {
return \$this->redirectToRoute('admin_".$snakeName."_index');
}
return \$this->render('admin/crud/_form.html.twig', [
'form'=>\$form->createView(),
'el'=>".$instance.",
'button_label'=>'Créer',
'route'=>'admin_". $snakeName."',
'title'=>'Ajouter un élément',
'breadcrumb'=>[
[
'route'=>'admin_". $snakeName ."_index',
'text'=>'tous les éléments'
],
[
'text'=>'ajouter un élément'
]
],
]);
}
/**
* @Route(\"/edit/{id}\", name=\"edit\")
* @param Request \$request
* @param ".$className." ".$instance."
* @param Tools \$tools
* @return Response
*/
public function edit(Request \$request, ".$className." ".$instance.", Tools \$tools): Response
{
\$form = \$this->createForm(".$className."Type::class, ".$instance.");
if (".$instance."Handler->edit(\$form, \$request)) {
return \$this->redirectToRoute('admin_".$snakeName."_edit', ['id'=>".$instance."->getId()]);
}
return \$this->render('admin/crud/_form.html.twig', [
'el' => ".$instance.",
'route'=> 'admin_".$snakeName."',
'form' => \$form->createView(),
'button_label' => 'Mettre à jour',
'title' => 'Edition',
'breadcrumb'=>[
[
'route'=>'admin_".$snakeName."_index',
'text'=>'".$lowerClassName."s'
],
[
'text'=>'édition '
]
],
]);
}
/**
* @Route(\"/{id}\", name=\"delete\", methods={\"DELETE\"})
* @param Request \$request
* @return Response
*/
public function delete(Request \$request,".$className." ".$instance."): Response
{
if (\$this->isCsrfTokenValid('delete'.".$instance."->getId(), \$request->request->get('_token'))) {
\$this->entityManager->remove(".$instance.");
\$this->entityManager->flush();
}
return \$this->redirectToRoute('admin_".$snakeName."_index');
}
}";
$command = $this->getApplication()->find('make:form');
$arguments = [
'name' => $className,
];
$greetInput = new ArrayInput($arguments);
try {
$command->run($greetInput, $output);
} catch (\Exception $e) {
}
if(!file_exists($controllerDir.$className."Controller.php")){
$output->writeln([
'Création du fichier '.$controllerDir.$className.'Controller.php ...'
]);
file_put_contents($controllerDir.$className.'Controller.php', $controllerContent);
$output->writeln([
'Le dossier a bien été créé'
]);
}
$handlerContent =
"<?php
namespace App\Form\Handler;
use App\Entity\\".$className.";
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\FormInterface;
class ".$className."Handler extends AbstractController
{
private \$entityManager;
public function __construct(EntityManagerInterface \$entityManager)
{
\$this->entityManager = \$entityManager;
}
public function new(FormInterface \$form, Request \$request): bool
{
\$form->handleRequest(\$request);
if (\$form->isSubmitted() && \$form->isValid()) {
".$instance." = \$form->getData();
\$this->entityManager->persist(".$instance.");
\$this->entityManager->flush();
return true;
}
return false;
}
public function edit(FormInterface \$form, Request \$request): bool
{
\$form->handleRequest(\$request);
if (\$form->isSubmitted() && \$form->isValid()) {
\$this->entityManager->flush();
return true;
}
return false;
}
}
";
if(!file_exists($handlerDir.$className."Handler.php")){
$output->writeln([
'Création du fichier '.$handlerDir.$className.'Handler.php ...'
]);
file_put_contents($handlerDir.$className.'Handler.php', $handlerContent);
$output->writeln([
'Le dossier a bien été créé'
]);
}
}
}

0
src/Controller/.gitignore vendored Normal file
View File

Some files were not shown because too many files have changed in this diff Show More