feat: added Modal and router function

This commit is contained in:
Philippe Torrel
2026-07-22 11:26:14 +02:00
parent f0e074dc9f
commit 3ec02626a6
11 changed files with 5341 additions and 17 deletions

View File

@@ -12207,7 +12207,10 @@ figure.logo-main figcaption {
}
.product-manager table .th-actions {
width: 150px;
width: 200px;
}
.product-manager table tbody td {
vertical-align: middle;
}
.product-manager table tbody td button {
margin: 3px;

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,5 @@
// import 'bootstrap'; // ohne Pfadangabe (Modul auslesen aus node_modules) funktioniert nur mit JS-Bundler (esbuild, rollup & co.)
import ProductManager from './modules/ProductManager'; // Dateiendung kann weggelassen werden, wenn ein Bundler eingesetzt wird (esbuild, webpack, rollup, etc.)
(() => {
@@ -6,9 +8,8 @@ import ProductManager from './modules/ProductManager'; // Dateiendung kann wegge
// === INIT =============
const init = () => {
// TODO: routing
const pm = ProductManager();
console.log('init');
router();
};
// === EVENTHANDLER =====
@@ -16,6 +17,26 @@ import ProductManager from './modules/ProductManager'; // Dateiendung kann wegge
// === XHR/FETCH ========
// === FUNCTIONS ========
const router = () => {
const path = window.location.pathname;
console.log(path);
switch (path) {
case '/':
case '/index.html':
console.log('HOME');
// nur Skripte, die für Home relevant ausführen
break;
case '/projects/product-manager.html':
console.log('PRODUCT_MANAGER');
const pm = ProductManager();
break;
default:
console.warn('Page not found');
}
};
init();
})();

View File

@@ -1,3 +1,8 @@
import { Modal } from 'bootstrap'; // ohne Pfadangabe (Modul auslesen aus node_modules) funktioniert nur mit JS-Bundler (esbuild, rollup & co.)
// import 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js'; // würde auch ohne Bundler funktionieren
// import '../../../node_modules/bootstrap/dist/js/bootstrap.esm.js'; // würde auch ohne Bundler funktionieren
// Factory Function
const ProductManager = (el = null) => {
// === DOM & VARS =======
@@ -14,8 +19,15 @@ const ProductManager = (el = null) => {
inputPrice: module.querySelector('.input-product-price'),
btnAdd: module.querySelector('.button-product-add'),
templateRow: module.querySelector('.template-row'),
modalEdit: module.querySelector('.modal-edit'),
};
const bsModalEdit = new Modal(DOM.modalEdit, {
backdrop: 'static', // true
keyboard: true,
});
console.log(DOM);
// === INIT =============
@@ -102,7 +114,8 @@ const ProductManager = (el = null) => {
const currentRowEl = e.currentTarget; // tr <- aktuelle Zeie, die bewegt wird
const idx = [...currentRowEl.parentNode.children].indexOf(currentRowEl);
e.dataTransfer.setData('text/plain', idx); // e.dataTransfer.setData('application/json', JSON.stringify({idx, name: sourceElement}));
e.dataTransfer.setData('text/plain', idx);
// e.dataTransfer.setData('application/json', JSON.stringify({idx, name: sourceElement}));
console.log('tr index:', idx);
};
@@ -111,7 +124,7 @@ const ProductManager = (el = null) => {
};
const onDrop = (e) => {
const currentRowEl = e.currentTarget; // tr <- Zielezeile, auf die gedroppt wird.
const currentRowEl = e.currentTarget; // tr <- Zielzeile, auf die gedroppt wird.
const targetIdx = [...currentRowEl.parentNode.children].indexOf(currentRowEl);
const sourceIdx = parseInt(e.dataTransfer.getData('text/plain'));
// const { sourceIdx } = JSON.parse(e.dataTransfer.getData('application/json'));
@@ -124,6 +137,7 @@ const ProductManager = (el = null) => {
}
const draggedEl = DOM.tBody.querySelector(`tr:nth-child(${sourceIdx + 1})`);
// const draggedEl = DOM.tBody.children[sourceIdx]
// Verschiebe das Element im DOM
if (sourceIdx > targetIdx) {

View File

@@ -1,10 +1,11 @@
.product-manager {
table {
.th-actions {
width: 150px;
width: 200px;
}
tbody {
td {
vertical-align: middle;
button {
margin: 3px;
}

View File

@@ -8,6 +8,9 @@
"name": "webseite-sass",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"bootstrap": "^5.3.8"
},
"devDependencies": {
"browser-sync": "^3.0.4",
"esbuild": "^0.28.1",
@@ -777,6 +780,17 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"license": "MIT",
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@socket.io/component-emitter": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
@@ -990,6 +1004,25 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/bootstrap": {
"version": "5.3.8",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz",
"integrity": "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/twbs"
},
{
"type": "opencollective",
"url": "https://opencollective.com/bootstrap"
}
],
"license": "MIT",
"peerDependencies": {
"@popperjs/core": "^2.11.8"
}
},
"node_modules/brace-expansion": {
"version": "1.1.16",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",

View File

@@ -20,9 +20,7 @@
"npm-run-all": "^4.1.5",
"sass": "^1.101.3"
},
"allowScripts": {
"fsevents@2.3.3": true,
"esbuild@0.28.1": true,
"@parcel/watcher@2.6.0": true
"dependencies": {
"bootstrap": "^5.3.8"
}
}

View File

@@ -12,6 +12,7 @@
<link rel="manifest" href="/favicon/site.webmanifest" />
<!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" /> -->
<link rel="stylesheet" href="/assets/css/main.css" />
<!-- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script> -->
<script src="/assets/js/build.js" defer></script>
</head>
<body>
@@ -111,6 +112,13 @@
<td class="td-name">[PRODUCT_NAME]</td>
<td class="td-price">[PRODUCT_PRICE]</td>
<td class="td-actions">
<button
class="btn btn-sm btn-primary button-product-edit"
data-bs-toggle="modal"
data-bs-target="#modal-edit">
<i class="fas fa-file-pen"></i>
<span class="visually-hidden">Edit Product</span>
</button>
<button class="btn btn-sm btn-danger button-product-remove">
<i class="fas fa-trash-can"></i>
<span class="visually-hidden">Remove Product</span>
@@ -126,6 +134,56 @@
</td>
</tr>
</template>
<!-- Modal Edit -->
<div
class="modal modal-edit fade"
id="modal-edit"
tabindex="-1"
aria-labelledby="modal-edit-label"
aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="modal-edit-label">Edit Product</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form class="form-product-edit">
<div class="modal-body">
<div class="row">
<div class="col-12 col-sm-8">
<div class="mb-3">
<label for="input-edit-name" class="form-label">Product Name</label>
<input type="text" id="input-edit-name" class="form-control input-edit-name" name="name" />
</div>
</div>
<div class="col-12 col-sm">
<div class="mb-3">
<label for="input-edit-price" class="form-label">Product Price</label>
<div class="input-group">
<input
type="number"
name="price"
id="input-edit-price"
class="form-control input-edit-price" />
<span class="input-group-text">&euro;</span>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary button-product-update">
<i class="fas fa-arrow-rotate-right"></i>
Update Product
</button>
</div>
</form>
</div>
</div>
</div>
<!-- ▲ /Modal ▲ -->
</div>
<!-- ▲ /product-manager ▲ -->
</main>