This commit is contained in:
Philippe Torrel
2026-10-14 10:33:34 +02:00
parent 42356cfd31
commit 69655e8ef6
68 changed files with 2129 additions and 127 deletions
@@ -44,7 +44,7 @@ DELETE http://127.0.0.1:8000/api/products/174a2a19-26eb-475e-af47-4f46d2ab62ec
# RESET PRODUCTS
PATCH http://127.0.0.1:8000/api/products/reset
PATCH http://127.0.0.1:8000/api/products/reset?reset=true
Content-Type: application/json
{
@@ -104,6 +104,7 @@ app.delete('/api/products/:id', (req, res) => {
// HTTP - Methode - PATCH
// reseten von Produkten
app.patch('/api/products/reset', (req, res) => {
console.log(req.query.reset);
const reset = req.body.reset;
if (!reset) {
@@ -130,6 +131,7 @@ app.patch('/api/products/save', (req, res) => {
});
app.get('/', (req, res) => {
console.log(req.query.reset);
return res.send('Server is running!');
});
@@ -12205,6 +12205,513 @@ blockquote {
font-family: "Gloria Hallelujah", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;
}
.splide__container {
box-sizing: border-box;
position: relative;
}
.splide__list {
backface-visibility: hidden;
display: flex;
height: 100%;
margin: 0 !important;
padding: 0 !important;
}
.splide.is-initialized:not(.is-active) .splide__list {
display: block;
}
.splide__pagination {
align-items: center;
display: flex;
flex-wrap: wrap;
justify-content: center;
margin: 0;
pointer-events: none;
}
.splide__pagination li {
display: inline-block;
line-height: 1;
list-style-type: none;
margin: 0;
pointer-events: auto;
}
.splide:not(.is-overflow) .splide__pagination {
display: none;
}
.splide__progress__bar {
width: 0;
}
.splide {
position: relative;
visibility: hidden;
}
.splide.is-initialized, .splide.is-rendered {
visibility: visible;
}
.splide__slide {
backface-visibility: hidden;
box-sizing: border-box;
flex-shrink: 0;
list-style-type: none !important;
margin: 0;
position: relative;
}
.splide__slide img {
vertical-align: bottom;
}
.splide__spinner {
animation: splide-loading 1s infinite linear;
border: 2px solid #999;
border-left-color: transparent;
border-radius: 50%;
bottom: 0;
contain: strict;
display: inline-block;
height: 20px;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: 20px;
}
.splide__sr {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.splide__toggle__pause {
display: none;
}
.splide__toggle.is-active .splide__toggle__play {
display: none;
}
.splide__toggle.is-active .splide__toggle__pause {
display: inline;
}
.splide__track {
overflow: hidden;
position: relative;
z-index: 0;
}
@keyframes splide-loading {
0% {
transform: rotateZ(0);
}
100% {
transform: rotateZ(360deg);
}
}
.splide__track--draggable {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
.splide__track--fade > .splide__list > .splide__slide {
margin: 0 !important;
opacity: 0;
z-index: 0;
}
.splide__track--fade > .splide__list > .splide__slide.is-active {
opacity: 1;
z-index: 1;
}
.splide--rtl {
direction: rtl;
}
.splide__track--ttb > .splide__list {
display: block;
}
.splide__arrow {
background: #ccc;
border: 0;
cursor: pointer;
padding: 0;
position: absolute;
top: 50%;
transform: translateY(-50%);
z-index: 1;
opacity: 0.7;
align-items: center;
border-radius: 50%;
display: flex;
justify-content: center;
height: 2em;
width: 2em;
}
.splide__arrow svg {
fill: #000;
height: 1.2em;
width: 1.2em;
}
.splide__arrow:hover:not(:disabled) {
opacity: 0.9;
}
.splide__arrow:disabled {
opacity: 0.3;
}
.splide__arrow:focus-visible {
outline: #0bf 3px solid;
outline-offset: 3px;
}
.splide__arrow--prev {
left: 1em;
}
.splide__arrow--prev svg {
transform: scaleX(-1);
}
.splide__arrow--next {
right: 1em;
}
.splide.is-focus-in .splide__arrow:focus {
outline: #0bf 3px solid;
outline-offset: 3px;
}
.splide__pagination {
bottom: 0.5em;
left: 0;
padding: 0 1em;
position: absolute;
right: 0;
z-index: 1;
}
.splide__pagination__page {
background: #ccc;
border: 0;
border-radius: 50%;
display: inline-block;
height: 8px;
margin: 3px;
padding: 0;
position: relative;
transition: transform 0.2s linear;
width: 8px;
opacity: 0.7;
}
.splide__pagination__page.is-active {
background: #fff;
z-index: 1;
transform: scale(1.4);
}
.splide__pagination__page:hover {
cursor: pointer;
opacity: 0.9;
}
.splide__pagination__page:focus-visible {
outline: #0bf 3px solid;
outline-offset: 3px;
}
.splide.is-focus-in .splide__pagination__page:focus {
outline: #0bf 3px solid;
outline-offset: 3px;
}
.splide__progress__bar {
background: #ccc;
height: 1rem;
}
.splide__slide {
-webkit-tap-highlight-color: transparent;
}
.splide__slide:focus {
outline: 0;
}
@supports (outline-offset: -3px) {
.splide__slide:focus-visible {
outline: #0bf 3px solid;
outline-offset: -3px;
}
}
.splide__slide:focus-visible {
/* IE does not support outline-offset */
}
@media screen and (-ms-high-contrast: none) {
.splide__slide:focus-visible {
border: #0bf 3px solid;
}
}
@supports (outline-offset: -3px) {
.splide.is-focus-in .splide__slide:focus {
outline: #0bf 3px solid;
outline-offset: -3px;
}
}
.splide.is-focus-in .splide__slide:focus {
/* IE does not support outline-offset */
}
@media screen and (-ms-high-contrast: none) {
.splide.is-focus-in .splide__slide:focus {
border: #0bf 3px solid;
}
}
@media screen and (-ms-high-contrast: none) {
.splide.is-focus-in .splide__track > .splide__list > .splide__slide:focus {
border-color: #0bf;
}
}
.splide__toggle {
cursor: pointer;
}
.splide__toggle:focus-visible {
outline: #0bf 3px solid;
outline-offset: 3px;
}
.splide.is-focus-in .splide__toggle:focus {
outline: #0bf 3px solid;
outline-offset: 3px;
}
.splide__track--nav > .splide__list > .splide__slide {
border: 3px solid transparent;
cursor: pointer;
}
.splide__track--nav > .splide__list > .splide__slide.is-active {
border: 3px solid #000;
}
.splide__arrows--rtl .splide__arrow--prev {
left: auto;
right: 1em;
}
.splide__arrows--rtl .splide__arrow--prev svg {
transform: scaleX(1);
}
.splide__arrows--rtl .splide__arrow--next {
left: 1em;
right: auto;
}
.splide__arrows--rtl .splide__arrow--next svg {
transform: scaleX(-1);
}
.splide__arrows--ttb .splide__arrow {
left: 50%;
transform: translate(-50%, 0);
}
.splide__arrows--ttb .splide__arrow--prev {
top: 1em;
}
.splide__arrows--ttb .splide__arrow--prev svg {
transform: rotateZ(-90deg);
}
.splide__arrows--ttb .splide__arrow--next {
bottom: 1em;
top: auto;
}
.splide__arrows--ttb .splide__arrow--next svg {
transform: rotateZ(90deg);
}
.splide__pagination--ttb {
bottom: 0;
display: flex;
flex-direction: column;
left: auto;
padding: 1em 0;
right: 0.5em;
top: 0;
}
@keyframes splide-loading {
0% {
transform: rotateZ(0);
}
100% {
transform: rotateZ(360deg);
}
}
.splide__track--draggable {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
.splide__track--fade > .splide__list > .splide__slide {
margin: 0 !important;
opacity: 0;
z-index: 0;
}
.splide__track--fade > .splide__list > .splide__slide.is-active {
opacity: 1;
z-index: 1;
}
.splide--rtl {
direction: rtl;
}
.splide__track--ttb > .splide__list {
display: block;
}
.splide__container {
box-sizing: border-box;
position: relative;
}
.splide__list {
backface-visibility: hidden;
display: flex;
height: 100%;
margin: 0 !important;
padding: 0 !important;
}
.splide.is-initialized:not(.is-active) .splide__list {
display: block;
}
.splide__pagination {
align-items: center;
display: flex;
flex-wrap: wrap;
justify-content: center;
margin: 0;
pointer-events: none;
}
.splide__pagination li {
display: inline-block;
line-height: 1;
list-style-type: none;
margin: 0;
pointer-events: auto;
}
.splide:not(.is-overflow) .splide__pagination {
display: none;
}
.splide__progress__bar {
width: 0;
}
.splide {
position: relative;
visibility: hidden;
}
.splide.is-initialized, .splide.is-rendered {
visibility: visible;
}
.splide__slide {
backface-visibility: hidden;
box-sizing: border-box;
flex-shrink: 0;
list-style-type: none !important;
margin: 0;
position: relative;
}
.splide__slide img {
vertical-align: bottom;
}
.splide__spinner {
animation: splide-loading 1s infinite linear;
border: 2px solid #999;
border-left-color: transparent;
border-radius: 50%;
bottom: 0;
contain: strict;
display: inline-block;
height: 20px;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: 20px;
}
.splide__sr {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.splide__toggle__pause {
display: none;
}
.splide__toggle.is-active .splide__toggle__play {
display: none;
}
.splide__toggle.is-active .splide__toggle__pause {
display: inline;
}
.splide__track {
overflow: hidden;
position: relative;
z-index: 0;
}
/*!
* Toastify js 1.12.0
* https://github.com/apvarun/toastify-js
@@ -12337,7 +12844,15 @@ blockquote {
flex-direction: row;
align-items: center;
justify-content: center;
border: 20px solid rgba(255, 255, 255, 0.25);
position: relative;
}
.header-main .splide {
position: absolute;
z-index: 1;
height: 100%;
width: 100%;
top: 0;
overflow: hidden;
}
.logo-main img,
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -27,6 +27,24 @@
<figcaption>JS course</figcaption>
</figure>
</div>
<!-- ▼ Slider Splide ▼ -->
<section class="splide my-slider" aria-label="Header Slider">
<div class="splide__track">
<ul class="splide__list">
<li class="splide__slide">
<img src="https://dummyimage.com/1920x600/f90/333.jpg" alt="slide 01" />
</li>
<li class="splide__slide">
<img src="https://dummyimage.com/1920x600/c40/333.jpg" alt="slide 02" />
</li>
<li class="splide__slide">
<img src="https://dummyimage.com/1920x600/fc0/333.jpg" alt="slide 03" />
</li>
</ul>
</div>
</section>
</header>
<!-- nav.menu-main>ul.list>li*4>a[href="#"]{Link $} -->
@@ -6,4 +6,6 @@
<figcaption>JS course</figcaption>
</figure>
</div>
@@include('slider-splide.html')
</header>
@@ -188,25 +188,5 @@
</div>
</div>
<!-- ▲ /Delete Modal ▲ -->
<!-- ▼ Dialog Edit Product ▼ -->
<!-- <button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#slideDownDialog">
Slide down dialog
</button>
<dialog class="dialog dialog-slide-down" id="slideDownDialog">
<div class="dialog-header">
<h1 class="dialog-title">Slide down dialog</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="Close"></button>
</div>
<div class="dialog-body">
<p>This dialog slides down from the top of the viewport.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
<button type="button" class="btn-solid theme-primary">Save changes</button>
</div>
</dialog> -->
<!-- ▲ /Dialog Edit Product ▲ -->
</div>
<!-- ▲ /Product Manager ▲ -->
@@ -0,0 +1,16 @@
<!-- ▼ Slider Splide ▼ -->
<section class="splide my-slider" aria-label="Header Slider">
<div class="splide__track">
<ul class="splide__list">
<li class="splide__slide">
<img src="https://dummyimage.com/1920x600/f90/333.jpg" alt="slide 01" />
</li>
<li class="splide__slide">
<img src="https://dummyimage.com/1920x600/c40/333.jpg" alt="slide 02" />
</li>
<li class="splide__slide">
<img src="https://dummyimage.com/1920x600/fc0/333.jpg" alt="slide 03" />
</li>
</ul>
</div>
</section>
@@ -3,6 +3,9 @@
@@include('head.html', {title: 'Productmanager'})
<body>
@@include('menu-main.html')
<main>@@include('product-manager.html')</main>
<main>
<section class="section-product-manager">@@include('product-manager.html')</section>
<!-- <section class="section-product-manager">@@include('product-manager.html')</section> -->
</main>
</body>
</html>
@@ -1,5 +1,5 @@
import ProductManager from './modules/ProductManager'; // Dateiendung nicht notwendig ?
import Splide from '@splidejs/splide';
(() => {
// === DOM & VARS =======
const DOM = {};
@@ -24,6 +24,12 @@ import ProductManager from './modules/ProductManager'; // Dateiendung nicht notw
case '/':
case '/index.html':
console.log('HOME');
new Splide('.splide', {
cover: true,
autoHeight: true,
height: '100%',
fixedHeight: '100%',
}).mount();
break;
case '/projects/02_product-manager.html':
console.log('PRODUCT_MANAGER');
@@ -1,16 +1,39 @@
import { parents } from '../utils/helpers.js';
import { Modal } from 'bootstrap';
import Toast from './Toast';
import { v4 as id } from 'uuid';
//import * as bootstrap from 'bootstrap';
// import 'bootstrap';
// Factory Function
const ProductManager = (el = null, options = {}) => {
const ProductManager = (target = '.product-manager', options = {}) => {
// === Selektor or Element ===
if (typeof target === 'string') {
const elements = document.querySelectorAll(target);
if (elements.length === 0) {
console.warn('Product Manager not found', target);
return null;
}
if (elements.length > 1) {
return [...elements].map((el) => ProductManager(el, options)); // Rekursion
}
target = elements[0];
} else if (target instanceof NodeList || Array.isArray(target)) {
if (target.length === 0) return null;
if (target.length === 1) {
target = target[0];
} else {
return [...target].map((el) => ProductManager(el, options)); // Rekursion
}
}
// === DOM & VARS =======
const module = el || document.querySelector('.product-manager') || console.warn('Product Manager Element not found');
const uId = id();
const module = target;
if (!module) return;
const DOM = {
@@ -61,8 +84,10 @@ const ProductManager = (el = null, options = {}) => {
// Funktionsaufrufe zu beginn der Anwendung
initProducts();
DOM.btnAdd.disabled = true;
// Event-Lauscher zu beginn der Anwendung
setUIds();
// Event-Lauscher zu beginn der Anwendung
DOM.btnReset.addEventListener('click', onClickReset);
DOM.btnSave.addEventListener('click', onClickSave);
@@ -90,14 +115,14 @@ const ProductManager = (el = null, options = {}) => {
// async API request
resetProducts().then((data) => {
if (data.success) {
// Toast(data.msg, 'success').show();
Toast(data.msg, 'success').show();
// Toast(data.msg, { variant: 'primary', duration: 5000, stopOnFocus: false }).show();
Toast(data.msg, {
variant: 'primary',
duration: 3000,
stopOnFocus: false,
style: { borderRadius: '1rem' },
}).show();
// Toast(data.msg, {
// variant: 'success',
// duration: 3000,
// stopOnFocus: false,
// style: { borderRadius: '1rem' },
// }).show();
loadProducts();
} else {
Toast(data.msg, 'error').show();
@@ -116,7 +141,10 @@ const ProductManager = (el = null, options = {}) => {
// async API request
saveProducts().then((data) => {
if (data.success) {
Toast(data.msg, 'success').show();
Toast(data.msg, {
variant: 'success', //
style: { background: '#f3b562', borderRadius: '1rem', color: 'black' },
}).show();
} else {
Toast(data.msg, 'error').show();
}
@@ -481,8 +509,10 @@ const ProductManager = (el = null, options = {}) => {
const tdNameEl = trEl.querySelector('.td-name');
const tdPriceEl = trEl.querySelector('.td-price');
const btnDragEl = trEl.querySelector('.button-product-drag');
const btnEditEl = trEl.querySelector('.button-product-edit');
const btnRemoveEl = trEl.querySelector('.button-product-remove');
const btnMoveUpEl = trEl.querySelector('.button-product-move-up');
const btnMoveDownEl = trEl.querySelector('.button-product-move-down');
@@ -499,8 +529,11 @@ const ProductManager = (el = null, options = {}) => {
tdNameEl.textContent = name;
tdPriceEl.textContent = Number(price).toFixed(2);
btnEditEl.dataset.bsTarget += `-${uId}`;
btnEditEl.addEventListener('click', onClickEdit);
btnRemoveEl.addEventListener('click', onClickRemove);
btnRemoveEl.dataset.bsTarget += `-${uId}`;
btnMoveUpEl.addEventListener('click', onClickMoveUp);
btnMoveDownEl.addEventListener('click', onClickMoveDown);
@@ -531,6 +564,15 @@ const ProductManager = (el = null, options = {}) => {
DOM.formEdit.reset(); // Modal Formular leeren
};
const setUIds = () => {
DOM.modalEdit.id += `-${uId}`;
DOM.modalEdit.querySelector('.modal-title').id += `-${uId}`;
DOM.modalDelete.id += `-${uId}`;
DOM.modalDelete.querySelector('.modal-title').id += `-${uId}`;
DOM.inputEditName.id += `-${uId}`;
DOM.inputEditPrice.id += `-${uId}`;
};
// Helper
// function parents(el, selector) {
// const parents = [];
@@ -1,4 +1,7 @@
// TODO: change with SASS FontAwesome Version
@import 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.3.1/css/all.css';
@import 'splide-4.1.4/themes/default/index';
@import 'splide-4.1.4/core/index';
@import 'toastify-1.12/toastify';
@@ -0,0 +1,9 @@
@keyframes splide-loading {
0% {
transform: rotateZ( 0 );
}
100% {
transform: rotateZ( 360deg );
}
}
@@ -0,0 +1,3 @@
@forward 'foundation/animations';
@forward 'object/modifiers';
@forward 'object/objects';
@@ -0,0 +1,8 @@
.splide {
$root: &;
&__track--draggable {
-webkit-touch-callout: none;
user-select: none;
}
}
@@ -0,0 +1,18 @@
.splide {
$root: &;
&__track--fade {
> #{ $root }__list {
> #{ $root }__slide {
margin: 0 !important;
opacity: 0;
z-index: 0;
&.is-active {
opacity: 1;
z-index: 1;
}
}
}
}
}
@@ -0,0 +1,4 @@
@forward 'draggable';
@forward 'fade';
@forward 'rtl';
@forward 'ttb';
@@ -0,0 +1,5 @@
.splide {
&--rtl {
direction: rtl;
}
}
@@ -0,0 +1,9 @@
.splide {
$root: &;
&__track--ttb {
> #{ $root }__list {
display: block;
}
}
}
@@ -0,0 +1,6 @@
.splide {
&__container {
box-sizing: border-box;
position: relative;
}
}
@@ -0,0 +1,10 @@
@forward 'container';
@forward 'list';
@forward 'pagination';
@forward 'progress';
@forward 'root';
@forward 'slide';
@forward 'spinner' as spinner-*;
@forward 'sr';
@forward 'toggle';
@forward 'track';
@@ -0,0 +1,17 @@
.splide {
$root: &;
&__list {
backface-visibility: hidden;
display: flex;
height: 100%;
margin: 0 !important;
padding: 0 !important;
}
&.is-initialized:not( .is-active ) {
#{ $root }__list {
display: block;
}
}
}
@@ -0,0 +1,26 @@
.splide {
$root: &;
&__pagination {
align-items: center;
display: flex;
flex-wrap: wrap;
justify-content: center;
margin: 0;
pointer-events: none;
li {
display: inline-block;
line-height: 1;
list-style-type: none;
margin: 0;
pointer-events: auto;
}
}
&:not( .is-overflow ) {
#{ $root }__pagination {
display: none;
}
}
}
@@ -0,0 +1,7 @@
.splide {
&__progress {
&__bar {
width: 0;
}
}
}
@@ -0,0 +1,9 @@
.splide {
position: relative;
visibility: hidden;
&.is-initialized,
&.is-rendered {
visibility: visible;
}
}
@@ -0,0 +1,14 @@
.splide {
&__slide {
backface-visibility: hidden;
box-sizing: border-box;
flex-shrink: 0;
list-style-type: none !important;
margin: 0;
position: relative;
img {
vertical-align: bottom;
}
}
}
@@ -0,0 +1,21 @@
$size: 20px !default;
$border: 2px solid #999 !default;
.splide {
&__spinner {
animation: splide-loading 1s infinite linear;
border: $border;
border-left-color: transparent;
border-radius: 50%;
bottom: 0;
contain: strict;
display: inline-block;
height: $size;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: $size;
}
}
@@ -0,0 +1,12 @@
.splide {
&__sr {
border: 0;
clip: rect( 0 0 0 0 );
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
}
@@ -0,0 +1,22 @@
.splide {
&__toggle {
$parent: &;
&__play {
}
&__pause {
display: none;
}
&.is-active {
#{ $parent }__play {
display: none;
}
#{ $parent }__pause {
display: inline;
}
}
}
}
@@ -0,0 +1,7 @@
.splide {
&__track {
overflow: hidden;
position: relative;
z-index: 0;
}
}
@@ -0,0 +1,8 @@
$main: #000 !default;
$sub01: #333 !default;
$sub02: #999 !default;
$background: #ccc !default;
$background-active: #fff !default;
$focus: #0bf !default;
@@ -0,0 +1,27 @@
@use './colors';
$outline: colors.$focus 3px solid !default;
$outline-offset: 3px !default;
$outline-offset-inset: -3px !default;
@mixin ie-only {
@media screen and (-ms-high-contrast: none) {
@content;
}
}
@mixin focus-outline( $offset: $outline-offset ) {
outline: $outline;
outline-offset: $offset;
}
@mixin focus-outline-inset {
@supports ( outline-offset: $outline-offset-inset ) {
@include focus-outline( $outline-offset-inset );
}
/* IE does not support outline-offset */
@include ie-only {
border: $outline;
}
}
@@ -0,0 +1,13 @@
@use 'foundation/colors';
$spinner-size: 20px !default;
$spinner-border: 2px solid colors.$sub02 !default;
@use '../../core/object/objects' with (
$spinner-size: $spinner-size,
$spinner-border: $spinner-border,
);
@forward '../../core';
@forward 'object/objects';
@forward 'object/modifiers';
@@ -0,0 +1,3 @@
@forward 'nav' as nav-*;
@forward 'rtl' as rtl-*;
@forward 'ttb' as ttb-*;
@@ -0,0 +1,37 @@
@use '../../foundation/colors';
@use '../../foundation/mixins';
$border: 3px solid transparent !default;
$border-active: 3px solid colors.$main !default;
$border-radius: false !default;
$opacity: false !default;
$opacity-active: false !default;
.splide {
$root: &;
&__track--nav {
> #{ $root }__list {
> #{ $root }__slide {
border: $border;
cursor: pointer;
@if $opacity {
opacity: $opacity;
}
@if $border-radius {
border-radius: $border-radius;
}
&.is-active {
border: $border-active;
@if $opacity {
opacity: $opacity-active;
}
}
}
}
}
}
@@ -0,0 +1,28 @@
$arrow-right: 1em !default;
$arrow-left: 1em !default;
.splide {
$root: &;
&__arrows--rtl {
#{ $root }__arrow {
&--prev {
left: auto;
right: $arrow-right;
svg {
transform: scaleX( 1 );
}
}
&--next {
left: $arrow-left;
right: auto;
svg {
transform: scaleX( -1 );
}
}
}
}
}
@@ -0,0 +1,54 @@
$arrow-top: 1em !default;
$arrow-bottom: 1em !default;
$pagination-left: auto !default;
$pagination-right: .5em !default;
$pagination-dot-width: false !default;
$pagination-dot-height: false !default;
.splide {
$root: &;
&__arrows--ttb {
#{ $root }__arrow {
left: 50%;
transform: translate( -50%, 0 );
&--prev {
top: $arrow-top;
svg {
transform: rotateZ( -90deg );
}
}
&--next {
bottom: $arrow-bottom;
top: auto;
svg {
transform: rotateZ( 90deg );
}
}
}
}
&__pagination--ttb {
bottom: 0;
display: flex;
flex-direction: column;
left: $pagination-left;
padding: 1em 0;
right: $pagination-right;
top: 0;
#{ $root }__pagination__page {
@if $pagination-dot-width {
width: $pagination-dot-width;
}
@if $pagination-dot-height {
height: $pagination-dot-height;
}
}
}
}
@@ -0,0 +1,105 @@
@use '../../foundation/colors';
@use '../../foundation/mixins';
$size: 1.2em !default;
$fill: colors.$main !default;
$fill-hover: false !default;
$transition: false !default;
$button-size: 2em !default;
$button-background: colors.$background !default;
$button-background-hover: false !default;
$button-border: 0 !default;
$button-padding: 0 !default;
$button-border-radius: 50% !default;
$button-transition: false !default;
$opacity: .7 !default;
$opacity-hover: .9 !default;
$opacity-disabled: .3 !default;
$left: 1em !default;
$right: 1em !default;
.splide {
$root: &;
&__arrow {
background: $button-background;
border: $button-border;
cursor: pointer;
padding: $button-padding;
position: absolute;
top: 50%;
transform: translateY( -50% );
z-index: 1;
@if $opacity {
opacity: $opacity;
}
@if $button-size {
align-items: center;
border-radius: $button-border-radius;
display: flex;
justify-content: center;
height: $button-size;
width: $button-size;
}
@if $button-transition {
transition: $button-transition;
}
svg {
fill: $fill;
height: $size;
width: $size;
@if $transition {
transition: $transition;
}
}
&:hover:not(:disabled) {
@if $opacity-hover {
opacity: $opacity-hover;
}
@if $button-background-hover {
background: $button-background-hover;
}
@if $fill-hover {
svg {
fill: $fill-hover;
}
}
}
&:disabled {
@if $opacity-disabled {
opacity: $opacity-disabled;
}
}
&:focus-visible {
@include mixins.focus-outline;
}
&--prev {
left: $left;
svg {
transform: scaleX( -1 );
}
}
&--next {
right: $right;
}
}
&.is-focus-in {
#{ $root }__arrow:focus {
@include mixins.focus-outline;
}
}
}
@@ -0,0 +1,5 @@
@forward 'arrow' as arrow-*;
@forward 'pagination' as pagination-*;
@forward 'progress' as progress-*;
@forward 'slide' as slide-*;
@forward 'toggle' as toggle-*;
@@ -0,0 +1,80 @@
@use '../../foundation/colors';
@use '../../foundation/mixins';
$bottom: .5em !default;
$dot-width: 8px !default;
$dot-height: 8px !default;
$dot-background: colors.$background !default;
$dot-background-hover: false !default;
$dot-background-active: colors.$background-active !default;
$dot-border: 0 !default;
$dot-border-radius: 50% !default;
$dot-margin: 3px !default;
$dot-padding: 0 !default;
$dot-opacity: .7 !default;
$dot-opacity-hover: .9 !default;
$dot-transition: transform .2s linear !default;
$dot-transform-active: scale( 1.4 ) !default;
.splide {
$root: &;
&__pagination {
bottom: $bottom;
left: 0;
padding: 0 1em;
position: absolute;
right: 0;
z-index: 1;
&__page {
background: $dot-background;
border: $dot-border;
border-radius: $dot-border-radius;
display: inline-block;
height: $dot-height;
margin: $dot-margin;
padding: $dot-padding;
position: relative;
transition: $dot-transition;
width: $dot-width;
@if $dot-opacity {
opacity: $dot-opacity;
}
&.is-active {
background: $dot-background-active;
z-index: 1;
@if $dot-transform-active {
transform: $dot-transform-active;
}
}
&:hover {
cursor: pointer;
@if $dot-opacity-hover {
opacity: $dot-opacity-hover;
}
@if $dot-background-hover {
background: $dot-background-hover;
}
}
&:focus-visible {
@include mixins.focus-outline;
}
}
}
&.is-focus-in {
#{ $root }__pagination {
&__page:focus {
@include mixins.focus-outline;
}
}
}
}
@@ -0,0 +1,13 @@
@use '../../foundation/colors';
$height: 3px !default;
$background: colors.$background;
.splide {
&__progress {
&__bar {
background: $background;
height: $height;
}
}
}
@@ -0,0 +1,42 @@
@use '../../foundation/colors';
@use '../../foundation/mixins';
$border-radius: false !default;
$outline-offset: -2px !default;
.splide {
$root: &;
&__slide {
-webkit-tap-highlight-color: transparent;
@if $border-radius {
border-radius: $border-radius;
}
// Gets rid of a focus ring in IE and Safari
&:focus {
outline: 0;
}
&:focus-visible {
@include mixins.focus-outline-inset;
}
}
&.is-focus-in {
#{ $root }__slide:focus {
@include mixins.focus-outline-inset;
}
#{ $root }__track {
> #{ $root }__list {
> #{ $root }__slide:focus {
@include mixins.ie-only {
border-color: colors.$focus;
}
}
}
}
}
}
@@ -0,0 +1,19 @@
@use '../../foundation/mixins';
.splide {
$root: &;
&__toggle {
cursor: pointer;
&:focus-visible {
@include mixins.focus-outline;
}
}
&.is-focus-in {
#{ $root }__toggle:focus {
@include mixins.focus-outline;
}
}
}
@@ -0,0 +1,52 @@
$main: #20b2aa !default;
$main-light: lighten( $main, 20% ) !default;
@use '../../template/default/foundation/colors' with (
$main: $main,
$sub01: $main,
$sub02: $main,
$background: #ccc,
$background-active: $main,
$focus: $main,
);
@use '../../template/default/object/modifiers/nav' with (
$border-radius: 4px,
$opacity: .7,
$opacity-active: 1,
);
@use '../../template/default/object/modifiers/ttb' with (
$pagination-dot-width: 5px,
$pagination-dot-height: 20px,
$pagination-right: 1em,
);
@use '../../template/default/object/objects/arrow' with (
$size: 2.5em,
$opacity: false,
$opacity-hover: false,
$fill-hover: $main-light,
$transition: fill .2s linear,
$button-size: 2.5em,
$button-border-radius: 0,
$button-background: transparent,
);
@use '../../template/default/object/objects/pagination' with (
$bottom: 1em,
$dot-width: 20px,
$dot-height: 5px,
$dot-border-radius: 2.5px,
$dot-opacity: false,
$dot-transition: background-color .2s linear,
$dot-background-hover: $main-light,
$dot-transform-active: false,
);
@use '../../template/default/object/objects/slide' with (
$border-radius: 4px,
);
@forward '../../template/default';
@forward 'object/objects';
@@ -0,0 +1,17 @@
.splide {
$root: &;
&__slider {
> #{ $root }__arrows {
#{ $root }__arrow {
&--prev {
left: -2.5em;
}
&--next {
right: -2.5em;
}
}
}
}
}
@@ -0,0 +1,37 @@
$main: #00bfff !default;
$main-light: lighten( $main, 20% ) !default;
@use '../../template/default/foundation/colors' with (
$main: $main,
$sub01: $main,
$sub02: $main,
$background: #ccc,
$background-active: $main,
$focus: $main,
);
@use '../../template/default/object/modifiers/nav' with (
$opacity: .7,
$opacity-active: 1,
);
@use '../../template/default/object/objects/arrow' with (
$size: 2.5em,
$opacity: false,
$opacity-hover: false,
$fill-hover: $main-light,
$transition: fill .2s linear,
$button-size: 2.5em,
$button-border-radius: 0,
$button-background: transparent,
);
@use '../../template/default/object/objects/pagination' with (
$dot-width: 10px,
$dot-height: 10px,
$dot-opacity: false,
$dot-transition: ( background-color .2s linear, transform .2s linear ),
$dot-background-hover: $main-light,
);
@forward '../../template/default';
@@ -13,5 +13,15 @@
align-items: center;
justify-content: center;
border: 20px solid rgba(white, 0.25);
// border: 20px solid rgba(white, 0.25);
position: relative;
.splide {
position: absolute;
z-index: 1;
height: 100%;
width: 100%;
top: 0;
overflow: hidden;
}
}
@@ -27,6 +27,24 @@
<figcaption>JS course</figcaption>
</figure>
</div>
<!-- ▼ Slider Splide ▼ -->
<section class="splide my-slider" aria-label="Header Slider">
<div class="splide__track">
<ul class="splide__list">
<li class="splide__slide">
<img src="https://dummyimage.com/1920x600/f90/333.jpg" alt="slide 01" />
</li>
<li class="splide__slide">
<img src="https://dummyimage.com/1920x600/c40/333.jpg" alt="slide 02" />
</li>
<li class="splide__slide">
<img src="https://dummyimage.com/1920x600/fc0/333.jpg" alt="slide 03" />
</li>
</ul>
</div>
</section>
</header>
<!-- nav.menu-main>ul.list>li*4>a[href="#"]{Link $} -->
@@ -9,8 +9,10 @@
"version": "0.0.1",
"license": "ISC",
"dependencies": {
"@splidejs/splide": "^4.1.4",
"bootstrap": "^5.3.8",
"toastify-js": "^1.12.0"
"toastify-js": "^1.12.0",
"uuid": "^14.0.3"
},
"devDependencies": {
"@babel/core": "^8.0.7",
@@ -2993,6 +2995,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/@splidejs/splide": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/@splidejs/splide/-/splide-4.1.4.tgz",
"integrity": "sha512-5I30evTJcAJQXt6vJ26g2xEkG+l1nXcpEw4xpKh0/FWQ8ozmAeTbtniVtVmz2sH1Es3vgfC4SS8B2X4o5JMptA==",
"license": "MIT"
},
"node_modules/@types/cors": {
"version": "2.8.19",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
@@ -9290,6 +9298,19 @@
"node": ">= 0.4.0"
}
},
"node_modules/uuid": {
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.3.tgz",
"integrity": "sha512-Sc5u1VVln93y1Xnz4R+CunOZc7R9LUcTmhj7Rc7Eg3HVcf7rVn2FOoa812fe0W8p3jD7xeoGSYbfqCGGH2B6xw==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
"uuid": "dist-node/bin/uuid"
}
},
"node_modules/v8flags": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-4.0.1.tgz",
@@ -34,7 +34,9 @@
"vinyl-source-stream": "^2.0.0"
},
"dependencies": {
"@splidejs/splide": "^4.1.4",
"bootstrap": "^5.3.8",
"toastify-js": "^1.12.0"
"toastify-js": "^1.12.0",
"uuid": "^14.0.3"
}
}
@@ -36,7 +36,8 @@
</ul>
</nav>
<main><!-- ▼ Product Manager ▼ -->
<main>
<section class="section-product-manager"><!-- ▼ Product Manager ▼ -->
<div class="product-manager">
<div class="container py-5">
<h1>Productmanager</h1>
@@ -226,28 +227,10 @@
</div>
</div>
<!-- ▲ /Delete Modal ▲ -->
<!-- ▼ Dialog Edit Product ▼ -->
<!-- <button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#slideDownDialog">
Slide down dialog
</button>
<dialog class="dialog dialog-slide-down" id="slideDownDialog">
<div class="dialog-header">
<h1 class="dialog-title">Slide down dialog</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="Close"></button>
</div>
<div class="dialog-body">
<p>This dialog slides down from the top of the viewport.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
<button type="button" class="btn-solid theme-primary">Save changes</button>
</div>
</dialog> -->
<!-- ▲ /Dialog Edit Product ▲ -->
</div>
<!-- ▲ /Product Manager ▲ -->
</main>
</section>
</main>
</body>
</html>