initial commit

This commit is contained in:
Mathieu Jaumotte 2021-05-17 09:26:09 +02:00
commit 5a9c6947bc
13 changed files with 2089 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
yarn-error.log
.yarncache
node_modules
# compiled sass
css

39
README.md Normal file
View File

@ -0,0 +1,39 @@
## Objectif
Rendre un tableau sans utiliser de balises <table>,
en utilisant des balises <div> + du positionnement flexbox
et qui adopte un positionnement responsive
avec basculement pour les 3 tailles large (L), medium (M) et small (S).
Taille par défaut: Large.
La solution prévoit de gérer avec du javascript l'entête (thead) qui se déploie différemment pour les tailles M et S
## Nodejs
* mise en place de sass
* bash docker-node.sh
* yarn install
* compiler les fichiers sass
* yarn run scss
## Let's go
* lancer un serveur web
* bash run.sh
* http://localhost:8000/index3.html
## TODO
* prévoir plusieurs tableaux sur une seule page
* se rapprocher davantage de la structure html d'un tableau (ajouter thead et tbody)
* BUG: js l.57: la règle 'not small' est jouée pour écran L, alors qu'elle est prévue pour le basculement de S vers M
## Limites
* En taille par défaut (L), la largeur des colonnes du tableau est déterminée par des propriétés flex côté css, pour personnaliser il faut donc surcharger en insérant dans le html :
```html
<style>
#my-table .td:nth-child(1) { flex: 1; }
#my-table .td:nth-child(2) { flex: 4; }
#my-table .td:nth-child(3) { flex: 6; }
#my-table .td:nth-child(4) { flex: 2; }
</style>
```

20
docker-node.sh Normal file
View File

@ -0,0 +1,20 @@
#!/bin/bash
cd $(dirname $0)
if [ $# -eq 0 ]
then
cmd=bash
else
cmd="${@}"
fi
docker run \
--rm \
--interactive \
--tty \
--user $(id -u):$(id -g) \
--volume ${PWD}:/app \
--workdir /app \
--env YARN_CACHE_FOLDER=/app/.yarncache \
node:14 ${cmd}

104
index.html Normal file
View File

@ -0,0 +1,104 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="css/styles.css">
<title>Flexbox test 1</title>
</head>
<body>
<h1>Flexbox test 1</h1>
<div id="t1" class="test">
<table>
<thead>
<tr>
<th>Prénom</th>
<th>Nom</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td>Marcel</td>
<td>Aimé</td>
<td>Voir | Editer</td>
</tr>
<tr>
<td>Robert</td>
<td>Pirate</td>
<td>Voir | Editer</td>
</tr>
</tbody>
</table>
</div>
<div id="t2" class="test">
<div class="table">
<div class="row">
<div class="cell">ID </div>
<div class="cell">Nr </div>
<div class="cell">Header 1 </div>
<div class="cell span4-5"> Header 2 </div>
</div>
<div class="row">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">Content</div>
<div class="cell">Content</div>
<div class="cell">Content</div>
</div>
<div class="row">
<div class="cell">2</div>
<div class="cell">3</div>
<div class="cell span3-5">Content</div>
</div>
<div class="row">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell span3-4">Content</div>
<div class="cell">Content</div>
</div>
</div>
</div>
<div id="t3" class="test">
<div class="container">
<div class="item">Left<br>high</div>
<div class="item">Middle/Left&nbsp;-&nbsp;&nbsp;is&nbsp;wider</div>
<div class="item">Middle/Right</div>
<div class="item">Right</div>
<div class="item">Left</div>
<div class="item">Middle/Left</div>
<div class="item">Middle/Right</div>
<div class="item">Right</div>
<div class="item">Left</div>
<div class="item">Middle/Left</div>
<div class="item">Middle/Right<br>higher<br>higher</div>
<div class="item">Right</div>
</div>
</div>
<div id="t4" class="test">
<div class="thegrid">
<!-- [HEAD] -->
<div class="head">Column 1</div>
<div class="head">Column 2</div>
<div class="head">Column 3</div>
<div class="head">Column 4</div>
<!-- [ROWS] -->
<div class="cell">Row 1 col 1</div>
<div class="cell">Row 1 col 2</div>
<div class="cell">Row 1 col 3</div>
<div class="cell">Row 1 col 4</div>
<!-- [ROWS] -->
<div class="cell">Row 2 col 1</div>
<div class="cell">Row 2 col 2</div>
<div class="cell">Row 2 col 3</div>
<div class="cell">Row 2 col 4</div>
</div>
</div>
</body>
</html>

93
index2.html Normal file
View File

@ -0,0 +1,93 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="css/styles2.css">
<title>Flexbox test 2</title>
</head>
<body>
<h1>Flexbox test 2</h1>
<div class="test">
<table role="table">
<thead role="rowgroup">
<tr role="row">
<th role="columnheader">First Name</th>
<th role="columnheader">Last Name</th>
<th role="columnheader">Job Title</th>
<th role="columnheader">Favorite Color</th>
<th role="columnheader">Wars or Trek?</th>
<th role="columnheader">Secret Alias</th>
<th role="columnheader">Date of Birth</th>
<th role="columnheader">Dream Vacation City</th>
<th role="columnheader">GPA</th>
<th role="columnheader">Arbitrary Data</th>
</tr>
</thead>
<tbody role="rowgroup">
<tr role="row">
<td role="cell" data-header="First Name">James</td>
<td role="cell" data-header="Last Name">Matman</td>
<td role="cell" data-header="Job Title">Chief Sandwich Eater</td>
<td role="cell" data-header="Favorite Color">Lettuce Green</td>
<td role="cell" data-header="Wars or Trek?">Trek</td>
<td role="cell" data-header="Secret Alias">Digby Green</td>
<td role="cell" data-header="Date of Birth">January 13, 1979</td>
<td role="cell" data-header="Dream Vacation City">Gotham City</td>
<td role="cell" data-header="GPA">3.1</td>
<td role="cell" data-header="Arbitrary Data">RBX-12</td>
</tr>
<tr role="row">
<td role="cell">The</td>
<td role="cell">Tick</td>
<td role="cell">Crimefighter Sorta</td>
<td role="cell">Blue</td>
<td role="cell">Wars</td>
<td role="cell">John Smith</td>
<td role="cell">July 19, 1968</td>
<td role="cell">Athens</td>
<td role="cell">N/A</td>
<td role="cell">Edlund, Ben (July 1996).</td>
</tr>
<tr role="row">
<td role="cell">Jokey</td>
<td role="cell">Smurf</td>
<td role="cell">Giving Exploding Presents</td>
<td role="cell">Smurflow</td>
<td role="cell">Smurf</td>
<td role="cell">Smurflane Smurfmutt</td>
<td role="cell">Smurfuary Smurfteenth, 1945</td>
<td role="cell">New Smurf City</td>
<td role="cell">4.Smurf</td>
<td role="cell">One</td>
</tr>
<tr role="row">
<td role="cell">Cindy</td>
<td role="cell">Beyler</td>
<td role="cell">Sales Representative</td>
<td role="cell">Red</td>
<td role="cell">Wars</td>
<td role="cell">Lori Quivey</td>
<td role="cell">July 5, 1956</td>
<td role="cell">Paris</td>
<td role="cell">3.4</td>
<td role="cell">3451</td>
</tr>
<tr role="row">
<td role="cell">Captain</td>
<td role="cell">Cool</td>
<td role="cell">Tree Crusher</td>
<td role="cell">Blue</td>
<td role="cell">Wars</td>
<td role="cell">Steve 42nd</td>
<td role="cell">December 13, 1982</td>
<td role="cell">Las Vegas</td>
<td role="cell">1.9</td>
<td role="cell">Under the couch</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>

100
index3.html Normal file
View File

@ -0,0 +1,100 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="css/styles3.css">
<title>Flexbox test 3</title>
</head>
<body>
<h1>Flexbox test 3</h1>
<div class="table" id="my-table">
<div class="tr header">
<div class="td">ID</div>
<div class="td">Column 1</div>
<div class="td">Column 2</div>
<div class="td">Column 3</div>
<div class="td">Action</div>
</div>
<div class="tr">
<div class="td">1</div>
<div class="td">Content Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
<div class="td">Content sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
<div class="td">Content Posuere morbi leo urna molestie.</div>
<div class="td">show | edit</div>
</div>
<div class="tr">
<div class="td">2</div>
<div class="td">Content Posuere morbi leo urna molestie.</div>
<div class="td">Content sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
<div class="td">Dolor sit amet, consectetur adipiscing elit.</div>
<div class="td">show | edit</div>
</div>
<div class="tr">
<div class="td">3</div>
<div class="td">Content sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
<div class="td">Content Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
<div class="td">Leo urna molestie.</div>
<div class="td">show | edit</div>
</div>
<div class="tr">
<div class="td">4</div>
<div class="td">Content Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
<div class="td">Content morbi leo urna molestie. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
<div class="td">Content Posuere </div>
<div class="td">show | edit</div>
</div>
<div class="tr">
<div class="td">5</div>
<div class="td">Content Posuere morbi leo urna molestie.</div>
<div class="td">Content sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
<div class="td">Dolor sit amet, consectetur adipiscing elit.</div>
<div class="td">show | edit</div>
</div>
<div class="tr">
<div class="td">6</div>
<div class="td">Content Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
<div class="td">Content sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
<div class="td">Content Posuere morbi leo urna molestie.</div>
<div class="td">show | edit</div>
</div>
<div class="tr">
<div class="td">7</div>
<div class="td">Content Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
<div class="td">Content morbi leo urna molestie. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
<div class="td">Content Posuere </div>
<div class="td">show | edit</div>
</div>
</div>
<!-- ajouter une autre
div class="table" id="other-table">
<div class="tr header">
<div class="td">ID</div>
<div class="td">Column 1</div>
<div class="td">Column 2</div>
<div class="td">Column 3</div>
<div class="td">Action</div>
</div>
</div>
<div class="tr">
<div class="td">6</div>
<div class="td">Content</div>
<div class="td">Content</div>
<div class="td">Content</div>
<div class="td">show | edit</div>
</div>
<div class="tr">
<div class="td">7</div>
<div class="td">Content</div>
<div class="td">Content</div>
<div class="td">Content</div>
<div class="td">show | edit</div>
</div>
</div-->
<script type="text/javascript">
const table = document.querySelector("#my-table");
</script>
<script src="js/index3.js"></script>
</body>
</html>

78
js/index3.js Normal file
View File

@ -0,0 +1,78 @@
const max800 = window.matchMedia("(max-width: 800px)");
const max450 = window.matchMedia("(max-width: 450px)");
const theadContent = i => {
const header = table.querySelectorAll(".header .td");
let content;
header.forEach((item, j) => {
if (i === j) {
content = item.textContent;
}
}, i);
return content;
};
const createThead = (cell, i) => {
const elem = document.createElement("div");
elem.classList.add("thead");
elem.innerHTML = theadContent(i);
cell.appendChild(elem);
}
const mediumScreen = rule => {
if (rule.matches) {
console.log('medium');
const rows = [...table.querySelectorAll(".tr")];
rows.shift();
rows.forEach(row => {;
const cells = row.querySelectorAll(".td");
cells.forEach((cell, i) => {
createThead(cell, i);
});
});
} else {
console.log('not medium');
const theads = table.querySelectorAll(".thead");
theads.forEach(element => {
element.parentNode.removeChild(element);
});
}
};
const smallScreen = (rule) => {
if (rule.matches) {
console.log('small');
const rows = [...table.querySelectorAll(".tr")];
rows.shift();
rows.forEach(row => {;
const cells = row.querySelectorAll(".td");
cells.forEach((cell, i) => {
let thead = cell.querySelector('.thead');
thead.classList.add("td");
row.insertBefore(thead, cell);
});
});
} else {
console.log('not small'); // large is not small, donc il passe ici !! pas normal
const rows = [...table.querySelectorAll(".tr")];
rows.shift();
rows.forEach(row => {;
const theads = row.querySelectorAll(".thead");
theads.forEach((thead) => {
thead.classList.remove("td");
thead.parentNode.removeChild(thead);
});
const cells = row.querySelectorAll(".td");
cells.forEach((cell, i) => {
createThead(cell, i);
});
});
}
};
mediumScreen(max800);
max800.addListener(mediumScreen);
smallScreen(max450);
max450.addListener(smallScreen);

9
package.json Normal file
View File

@ -0,0 +1,9 @@
{
"dependencies": {
"node-sass": "^6.0.0",
"sass-loader": "^11.1.1"
},
"scripts": {
"scss": "node-sass --watch scss -o css"
}
}

2
run.sh Normal file
View File

@ -0,0 +1,2 @@
#/bin/bash
python3 -m http.server

107
scss/styles.scss Normal file
View File

@ -0,0 +1,107 @@
body {
padding: 1em;
div.test {
border: 1px solid grey;
padding: 1em;
margin: 0 2em 1em;
}
}
div#t1 {
table,
td,
th {
border: 1px solid lightgrey;
padding: 0.5em;
border-collapse: collapse;
}
}
div#t2 {
div.table {
display: flex;
flex-direction: column;
}
div.row {
display: flex;
min-height: 50px;
}
div.cell {
flex: 4;
border: 1px solid lightgrey;
}
div.cell:nth-child(1) {
flex: 1;
}
div.cell:nth-child(2) {
flex: 2;
}
div.cell.span4-5 {
flex: 8 24px; /* col 4,5 flex-grow/border/padding */
}
div.cell.span3-4 {
flex: 8 24px; /* col 3,4 flex-grow/border/padding */
}
div.cell.span3-5 {
flex: 12 36px; /* col 3,4,5 flex-grow/border/padding */
}
div.row:first-child div.cell {
display: flex;
justify-content: center; /* center horiz. */
align-items: center; /* center vert. */
font-weight: bold;
}
div.row div.cell {
padding: 5px;
box-sizing: border-box;
}
}
div#t3 {
.container {
display: flex;
flex-wrap: wrap; /* allow items to wrap */
justify-content: space-between; /* vertical */
align-items: stretch; /* horizontal, is default and can be omitted */
}
.item {
flex-basis: 25%; /* give each item a width */
border: 1px solid lightgrey;
box-sizing: border-box;
flex-shrink: 0; /* prevent from "shrink to fit" */
min-width: 0; /* allow to shrink past content width */
overflow: hidden; /* hide overflowed content */
}
.item:nth-child(n+5) {
margin-top: 10px; /* from 5th item, add top margin */
}
}
div#t4 {
/* (A1) CONTAINER - BIG SCREEN */
.thegrid {
display: grid;
grid-template-columns: auto auto auto auto;
/* OR SPECIFY WIDTH
*/
grid-template-columns: 40% 20% 20% 20%;
grid-gap: 5px;
}
/* (A2) CONTAINER - SMOL SCREEN */
@media screen and (max-width:768px) {
.thegrid { grid-template-columns: auto auto; }
}
/* (B) CELLS */
.thegrid .head, .thegrid .cell {
padding: 10px;
}
/* (C) HEADER CELLS */
.thegrid .head {
font-weight: bold;
background: #ffe4d1;
}
/* (D) DATA CELLS */
.thegrid .cell {
background: #d1f2ff;
}
}

110
scss/styles2.scss Normal file
View File

@ -0,0 +1,110 @@
body {
padding: 1em;
div.test {
border: 1px solid grey;
padding: 1em;
margin: 0 2em 1em;
table,
tbody,
td,
th,
thead,
tr {
border: 1px solid lightgrey;
border-collapse: collapse;
}
}
}
@media only screen
and (max-width: 760px), (min-device-width: 768px)
and (max-device-width: 1024px) {
table,
tbody,
td,
th,
thead,
tr {
display: block;
border: 0;
}
/* Hide table headers (but not display: none;, for accessibility) */
thead tr {
position: absolute;
top: -9999px;
left: -9999px;
}
tr {
margin: 0 0 1rem;
}
tr:nth-child(odd) {
background: #ccc;
}
td {
/* Behave like a "row" */
border: none;
border-bottom: 1px solid #eee;
position: relative;
padding-left: 50%;
}
td:before {
/* Now like a table header */
position: absolute;
/* Top/left values mimic padding */
top: 0;
left: 6px;
width: 45%;
padding-right: 10px;
white-space: nowrap;
}
/*
Label the data
You could also use a data-* attribute and content for this. That way "bloats" the HTML, this way means you need to keep HTML and CSS in sync. Lea Verou has a clever way to handle with text-shadow.
*/
td:nth-of-type(1):before {
content: "First Name";
}
td:nth-of-type(2):before {
content: "Last Name";
}
td:nth-of-type(3):before {
content: "Job Title";
}
td:nth-of-type(4):before {
content: "Favorite Color";
}
td:nth-of-type(5):before {
content: "Wars of Trek?";
}
td:nth-of-type(6):before {
content: "Secret Alias";
}
td:nth-of-type(7):before {
content: "Date of Birth";
}
td:nth-of-type(8):before {
content: "Dream Vacation City";
}
td:nth-of-type(9):before {
content: "GPA";
}
td:nth-of-type(10):before {
content: "Arbitrary Data";
}
}

96
scss/styles3.scss Normal file
View File

@ -0,0 +1,96 @@
div.table {
display: flex;
flex-direction: column;
div.tr {
display: flex;
min-height: 50px;
&:nth-child(1) {
border-top: 1px solid grey;
}
&:nth-child(odd) {
background: #dedede;
}
div.td {
display: flex;
align-items: center;
flex: 4;
border: 1px solid grey;
border-top: 0;
border-left: 0;
&:nth-child(1) {
border-left: 1px solid grey;
}
&:nth-child(1) { flex: 1; } // les largeurs de colonnes
&:nth-child(2) { flex: 4; }
&:nth-child(3) { flex: 6; }
&:nth-child(4) { flex: 2; }
&:last-child { flex: 2; }
div.thead { // TODO affiché par erreur en grand écran,
// car le script applique ici la l.57 du script js
// commenter pour voir le problème
display: none;
}
}
&.header div.td {
justify-content: center;
font-weight: bold;
}
div.td,
div.thead {
padding: 5px;
box-sizing: border-box;
}
}
}
@media only screen
and (max-width: 800px) {
div.table {
margin-right: 0.5em;
div.tr {
flex-direction: column;
padding-left: 37%;
&.header {
position: absolute;
top: -9999px;
left: -9999px;
}
div.td {
position: relative;
border-left: 1px solid grey;
div.thead { // idem l.28
display: block;
position: absolute;
top: 0;
left: -57%;
width: 52%;
padding-right: 10px;
white-space: nowrap;
}
&:nth-child(1) {
//border-left: 0;
}
}
&:nth-child(2) {
div.td:nth-child(1) {
border-top: 1px solid grey;
}
}
}
}
@media only screen
and (max-width: 450px) {
div.table {
div.tr {
padding-left: 0;
div.td {
padding-left: 1.5em;
&.thead {
font-weight: bold;
padding-left: 0.5em;
}
}
}
}
}
}

1326
yarn.lock Normal file

File diff suppressed because it is too large Load Diff