BIN
05_react/unterricht/tag55/react-app-advanced.zip
Normal file
@@ -1,3 +1,4 @@
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import FooterMain from './components/footers/FooterMain';
|
||||
import HeaderMain from './components/headers/HeaderMain';
|
||||
import NavMain from './components/navs/NavMain';
|
||||
@@ -5,10 +6,12 @@ import Router from './routes/Router';
|
||||
|
||||
function App(props) {
|
||||
// const { } = props;
|
||||
const { pathname: path } = useLocation();
|
||||
|
||||
console.log(path);
|
||||
return (
|
||||
<>
|
||||
<HeaderMain />
|
||||
{path === '/' && <HeaderMain />}
|
||||
<NavMain />
|
||||
<main id="main">
|
||||
<Router />
|
||||
|
||||
@@ -1,82 +1,21 @@
|
||||
import { useCallback, useMemo, useReducer, useState } from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import RowProduct from './content/RowProduct';
|
||||
import { ProductsProvider, useProductsState } from '../../stores/products';
|
||||
|
||||
// Reducer (bei größerer Applikaitonsstuktur ausgelagert)
|
||||
const initialState = (props) => {
|
||||
// Validierung und Error Checks
|
||||
return { items: props.items || [] };
|
||||
};
|
||||
const TableProductsView = (props) => {
|
||||
const { items } = useProductsState();
|
||||
// const dispatch = useProductsDispatch()
|
||||
|
||||
const reducer = (state, action) => {
|
||||
const { type, payload } = action;
|
||||
switch (type) {
|
||||
case 'UPDATE_AMOUNT':
|
||||
return {
|
||||
...state,
|
||||
items: state.items.map((item) =>
|
||||
item._id === payload.id
|
||||
? { ...item, stock: payload.amount } //
|
||||
: item,
|
||||
),
|
||||
};
|
||||
case 'UPDATE_PRICE':
|
||||
return {
|
||||
...state,
|
||||
items: state.items.map((item) =>
|
||||
item._id === payload.id
|
||||
? { ...item, price: payload.price } //
|
||||
: item,
|
||||
),
|
||||
};
|
||||
default:
|
||||
console.warn('no action found');
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
const TableProducts = (props) => {
|
||||
// const {
|
||||
// items = [
|
||||
// {
|
||||
// _id: '1',
|
||||
// title: 'Example Product 1',
|
||||
// sku: 'ABC1234',
|
||||
// stock: 2,
|
||||
// price: 15.2,
|
||||
// },
|
||||
// ],
|
||||
// } = props;
|
||||
|
||||
const [{ items }, dispatch] = useReducer(reducer, initialState(props));
|
||||
|
||||
// const [items, setItems] = useState(
|
||||
// props.items || [
|
||||
// {
|
||||
// _id: '1',
|
||||
// title: 'Example Product 1',
|
||||
// sku: 'ABC1234',
|
||||
// stock: 2,
|
||||
// price: 15.2,
|
||||
// },
|
||||
// ],
|
||||
// );
|
||||
//const [{ items }, dispatch] = useReducer(reducer, initialState(props));
|
||||
|
||||
// EventHandler ============
|
||||
const handleAmount = useCallback((amount, id) => {
|
||||
dispatch({ type: 'UPDATE_AMOUNT', payload: { amount, id } });
|
||||
// const handleAmount = useCallback((amount, id) => {
|
||||
// dispatch({ type: PRODUCTS_ACTIONS.UPDATE_AMOUNT, payload: { amount, id } });
|
||||
// }, []);
|
||||
|
||||
// setItems((prevItems) => {
|
||||
// return prevItems.map((item) => (item._id === id ? { ...item, stock: amount } : item));
|
||||
// });
|
||||
}, []);
|
||||
|
||||
const handlePrice = useCallback((price, id) => {
|
||||
dispatch({ type: 'UPDATE_PRICE', payload: { price, id } });
|
||||
|
||||
// setItems((prevItems) => {
|
||||
// return prevItems.map((item) => (item._id === id ? { ...item, price: price } : item));
|
||||
// });
|
||||
}, []);
|
||||
// const handlePrice = useCallback((price, id) => {
|
||||
// dispatch({ type: PRODUCTS_ACTIONS.UPDATE_PRICE, payload: { price, id } });
|
||||
// }, []);
|
||||
|
||||
// Functions ===============
|
||||
const totalPrice = useMemo(() => {
|
||||
@@ -91,13 +30,6 @@ const TableProducts = (props) => {
|
||||
if (el) console.log(el);
|
||||
}, []);
|
||||
|
||||
// const getTotalPrice = () => {
|
||||
// // [0, {stock: 2, price, 15.2}, {...}]
|
||||
// return items.reduce((sum, obj) => {
|
||||
// return sum + Number(obj.stock) * Number(obj.price);
|
||||
// }, 0);
|
||||
// };
|
||||
|
||||
return (
|
||||
<div className="m-table-products table-products">
|
||||
<div className="container py-2">
|
||||
@@ -117,8 +49,8 @@ const TableProducts = (props) => {
|
||||
<RowProduct
|
||||
key={`row-product-${idx}`}
|
||||
{...product}
|
||||
onHandleAmount={handleAmount}
|
||||
onHandlePrice={handlePrice}
|
||||
// onHandleAmount={handleAmount}
|
||||
// onHandlePrice={handlePrice}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
@@ -133,4 +65,14 @@ const TableProducts = (props) => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const TableProducts = (props) => {
|
||||
// const { } = props;
|
||||
|
||||
return (
|
||||
<ProductsProvider items={props.items}>
|
||||
<TableProductsView />
|
||||
</ProductsProvider>
|
||||
);
|
||||
};
|
||||
export default TableProducts;
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
// import { useState } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useProductsActions } from '../../../stores/products'; // /index.js muss nicht angegeben werden (wg. Bundler)
|
||||
// import { useProductsDispatch } from '../../../stores/products';
|
||||
// import { PRODUCTS_ACTIONS } from '../../../stores/products';
|
||||
|
||||
import InputAmount from '../../inputs/InputAmount';
|
||||
import InputPrice from '../../inputs/InputPrice';
|
||||
|
||||
@@ -6,19 +10,35 @@ const RowProduct = (props) => {
|
||||
const { _id, sku = '', stock: amount = 0, price = 0, title = '' } = props;
|
||||
//const { sku = '', title = '' } = props;
|
||||
|
||||
// const [amount, setAmount] = useState(props.stock || 0);
|
||||
// const [price, setPrice] = useState(props.price || 0);
|
||||
const { updateAmount, updatePrice } = useProductsActions();
|
||||
// const dispatch = useProductsDispatch();
|
||||
|
||||
// Eventhandler
|
||||
const handleAmount = (val) => {
|
||||
// setAmount(val);
|
||||
props.onHandleAmount(val, _id);
|
||||
};
|
||||
// const handleAmount = useCallback((val) => {
|
||||
// // setAmount(val);
|
||||
// // props.onHandleAmount(val, _id);
|
||||
// dispatch({ type: PRODUCTS_ACTIONS.UPDATE_AMOUNT, payload: { amount: val, id: _id } });
|
||||
// }, []);
|
||||
|
||||
const handlePrice = (val) => {
|
||||
// setPrice(val);
|
||||
props.onHandlePrice(val, _id);
|
||||
};
|
||||
const handleAmount = useCallback(
|
||||
(val) => {
|
||||
updateAmount(val, _id);
|
||||
},
|
||||
[updateAmount, _id],
|
||||
);
|
||||
|
||||
// const handlePrice = (val) => {
|
||||
// // setPrice(val);
|
||||
// // props.onHandlePrice(val, _id);
|
||||
// dispatch({ type: PRODUCTS_ACTIONS.UPDATE_PRICE, payload: { price: val, id: _id } });
|
||||
// };
|
||||
|
||||
const handlePrice = useCallback(
|
||||
(val) => {
|
||||
updatePrice(val, _id);
|
||||
},
|
||||
[updatePrice, _id],
|
||||
);
|
||||
|
||||
return (
|
||||
<tr className="row-product">
|
||||
@@ -34,4 +54,4 @@ const RowProduct = (props) => {
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
export default RowProduct;
|
||||
export default memo(RowProduct);
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import { createContext, useCallback, useContext, useReducer } from 'react';
|
||||
import { PRODUCTS_ACTIONS, productsReducer } from './reducer';
|
||||
import { createInitialState } from './initialState';
|
||||
|
||||
const ProductsStateContext = createContext(null);
|
||||
const ProductsDispatchContext = createContext(null);
|
||||
|
||||
// const ProductsContext = createContext(null);
|
||||
|
||||
export const ProductsProvider = (props) => {
|
||||
const { children, items = [] } = props;
|
||||
|
||||
const [state, dispatch] = useReducer(productsReducer, items, createInitialState);
|
||||
|
||||
return (
|
||||
// <ProductsContext.Provider value={{state, dispatch}}>
|
||||
// {children}
|
||||
// </ProductsContext.Provider>
|
||||
|
||||
<ProductsStateContext.Provider value={state}>
|
||||
<ProductsDispatchContext.Provider value={dispatch}>{children}</ProductsDispatchContext.Provider>
|
||||
</ProductsStateContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
// eigene Hooks mit ErrorHandler
|
||||
export const useProductsState = () => {
|
||||
const state = useContext(ProductsStateContext);
|
||||
|
||||
if (state == null) {
|
||||
throw Error('useProductsState muss innerhalb von ProductsProvider verwendet werden.');
|
||||
}
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
export const useProductsDispatch = () => {
|
||||
const dispatch = useContext(ProductsDispatchContext);
|
||||
|
||||
if (dispatch == null) {
|
||||
throw Error('useProductsDispatch muss innerhalb von ProductsProvider verwendet werden.');
|
||||
}
|
||||
|
||||
return dispatch;
|
||||
};
|
||||
|
||||
export const useProductsActions = () => {
|
||||
const dispatch = useProductsDispatch();
|
||||
|
||||
const updateAmount = useCallback(
|
||||
(amount, id) => {
|
||||
dispatch({ type: PRODUCTS_ACTIONS.UPDATE_AMOUNT, payload: { id, amount } });
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const updatePrice = useCallback(
|
||||
(price, id) => {
|
||||
dispatch({ type: PRODUCTS_ACTIONS.UPDATE_PRICE, payload: { id, price } });
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
return {
|
||||
updateAmount,
|
||||
updatePrice,
|
||||
};
|
||||
};
|
||||
3
05_react/unterricht/tag55/react-app-advanced/src/stores/products/index.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export { createInitialState } from './initialState';
|
||||
export { PRODUCTS_ACTIONS, productsReducer } from './reducer';
|
||||
export { ProductsProvider, useProductsActions, useProductsDispatch, useProductsState } from './ProductsStore';
|
||||
7
05_react/unterricht/tag55/react-app-advanced/src/stores/products/initialState.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// import mit {}
|
||||
export const createInitialState = (items) => {
|
||||
// validation and sanitizing
|
||||
return { items: items || [] };
|
||||
};
|
||||
|
||||
export default createInitialState; // import mit eigener Benennung möglich
|
||||
36
05_react/unterricht/tag55/react-app-advanced/src/stores/products/reducer.js
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// in ts enum
|
||||
export const PRODUCTS_ACTIONS = {
|
||||
UPDATE_AMOUNT: 'UPDATE_AMOUNT',
|
||||
UPDATE_PRICE: 'UPDATE_PRICE',
|
||||
};
|
||||
|
||||
export const productsReducer = (state, action) => {
|
||||
const { type, payload } = action;
|
||||
|
||||
console.log(state);
|
||||
|
||||
switch (type) {
|
||||
case PRODUCTS_ACTIONS.UPDATE_AMOUNT:
|
||||
return {
|
||||
...state,
|
||||
items: state.items.map((item) =>
|
||||
item._id === payload.id //
|
||||
? { ...item, stock: payload.amount }
|
||||
: item,
|
||||
),
|
||||
};
|
||||
|
||||
case PRODUCTS_ACTIONS.UPDATE_PRICE:
|
||||
return {
|
||||
...state,
|
||||
items: state.items.map((item) =>
|
||||
item._id === payload.id //
|
||||
? { ...item, price: payload.price }
|
||||
: item,
|
||||
),
|
||||
};
|
||||
default:
|
||||
console.warn('no action found');
|
||||
return state;
|
||||
}
|
||||
};
|
||||
BIN
webseite-react-php.zip
Normal file
24
webseite-react-php/react-app/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
8
webseite-react-php/react-app/.oxlintrc.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["react", "oxc"],
|
||||
"rules": {
|
||||
"react/rules-of-hooks": "error",
|
||||
"react/only-export-components": ["warn", { "allowConstantExport": true }]
|
||||
}
|
||||
}
|
||||
16
webseite-react-php/react-app/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# React + Vite
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some Oxlint rules.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
|
||||
|
||||
## React Compiler
|
||||
|
||||
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
|
||||
|
||||
## Expanding the Oxlint configuration
|
||||
|
||||
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and Oxlint's TypeScript related rules in your project.
|
||||
13
webseite-react-php/react-app/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>react-app</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
2611
webseite-react-php/react-app/package-lock.json
generated
Normal file
29
webseite-react-php/react-app/package.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "react-app",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"lint": "oxlint",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@splidejs/react-splide": "^0.7.12",
|
||||
"axios": "^1.20.0",
|
||||
"bootstrap": "^5.3.8",
|
||||
"react": "^19.2.8",
|
||||
"react-dom": "^19.2.8",
|
||||
"react-icons": "^5.7.0",
|
||||
"react-router-dom": "^7.18.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.2.18",
|
||||
"@types/react-dom": "^19.2.5",
|
||||
"@vitejs/plugin-react": "^6.1.1",
|
||||
"oxlint": "^1.80.0",
|
||||
"sass-embedded": "^1.103.1",
|
||||
"vite": "^8.2.2"
|
||||
}
|
||||
}
|
||||
119
webseite-react-php/react-app/public/data/nerdshop-products.json
Normal file
@@ -0,0 +1,119 @@
|
||||
[
|
||||
{
|
||||
"_id": "675bee96bb39023b77e6cd92",
|
||||
"title": "Smart Coffee Mug with LCD Level Indicator",
|
||||
"sku": "MUG0007",
|
||||
"stock": 25,
|
||||
"price": 49.99,
|
||||
"description": "Know exactly how much coffee you have left with this LCD-equipped mug.",
|
||||
"tagline": "Never face an empty mug again."
|
||||
},
|
||||
{
|
||||
"_id": "675bee96bb39023b77e6cd93",
|
||||
"title": "Bluetooth Coffee Mug with Fortune Telling Scanner",
|
||||
"sku": "MUG0013",
|
||||
"stock": 15,
|
||||
"price": 99.99,
|
||||
"description": "Get your daily fortune with every sip using this Bluetooth-connected mug.",
|
||||
"tagline": "Coffee reading, made smart."
|
||||
},
|
||||
{
|
||||
"_id": "675bee96bb39023b77e6cd94",
|
||||
"title": "South Pole Tested Pre-Warmed Ink Pen",
|
||||
"sku": "OFF3145",
|
||||
"stock": 34,
|
||||
"price": 29.95,
|
||||
"description": "Write smoothly even in the coldest conditions with this pre-warmed ink pen.",
|
||||
"tagline": "The pen that conquers the cold."
|
||||
},
|
||||
{
|
||||
"_id": "675bee96bb39023b77e6cd95",
|
||||
"title": "Ambidextrous Computer Mouse",
|
||||
"sku": "COM1001",
|
||||
"stock": 50,
|
||||
"price": 19.9,
|
||||
"description": "Finally, a mouse designed for both left and right-handed users.",
|
||||
"tagline": "End the left-right struggle."
|
||||
},
|
||||
{
|
||||
"_id": "675bee96bb39023b77e6cd96",
|
||||
"title": "Easter Egg Themed Webcam",
|
||||
"sku": "COM0404",
|
||||
"stock": 8,
|
||||
"price": 14.99,
|
||||
"description": "Add some festive flair to your video calls with this Easter egg webcam.",
|
||||
"tagline": "Happy Easter, every day."
|
||||
},
|
||||
{
|
||||
"_id": "675bee96bb39023b77e6cd97",
|
||||
"title": "Vulcan Language vi Cheatsheet",
|
||||
"sku": "COM0001",
|
||||
"stock": 6,
|
||||
"price": 9.9,
|
||||
"description": "Master the Vulcan language and vi editor simultaneously with this handy cheatsheet.",
|
||||
"tagline": "Learn vi and Vulcan, live long and prosper."
|
||||
},
|
||||
{
|
||||
"_id": "675bee96bb39023b77e6cd98",
|
||||
"title": "Klingon Language emacs Cheatsheet",
|
||||
"sku": "COM1536",
|
||||
"stock": 33,
|
||||
"price": 9.9,
|
||||
"description": "Conquer the Klingon language and emacs with this comprehensive cheatsheet.",
|
||||
"tagline": "Learn emacs and Klingon, qapla'!"
|
||||
},
|
||||
{
|
||||
"_id": "675bee96bb39023b77e6cda0",
|
||||
"title": "Self-Folding Laundry Basket",
|
||||
"sku": "HME0023",
|
||||
"stock": 15,
|
||||
"price": 79.99,
|
||||
"description": "Say goodbye to laundry clutter with this self-folding basket.",
|
||||
"tagline": "Laundry day just got easier."
|
||||
},
|
||||
{
|
||||
"_id": "675bee96bb39023b77e6cda1",
|
||||
"title": "Noise-Cancelling Headphones for Cats",
|
||||
"sku": "PET0112",
|
||||
"stock": 39,
|
||||
"price": 39.95,
|
||||
"description": "Give your cat the gift of silence with these noise-canceling headphones.",
|
||||
"tagline": "Purrfect tranquility for your feline friend."
|
||||
},
|
||||
{
|
||||
"_id": "675bee96bb39023b77e6cda2",
|
||||
"title": "Glow-in-the-Dark Toilet Paper",
|
||||
"sku": "HME0221",
|
||||
"stock": 65,
|
||||
"price": 12.5,
|
||||
"description": "Navigate your midnight bathroom trips with ease using this glow-in-the-dark toilet paper.",
|
||||
"tagline": "A guiding light in the darkness."
|
||||
},
|
||||
{
|
||||
"_id": "675bee96bb39023b77e6cda3",
|
||||
"title": "Automatic Plant Waterer with Compliment Dispenser",
|
||||
"sku": "GRD0334",
|
||||
"stock": 17,
|
||||
"price": 69.99,
|
||||
"description": "Keep your plants happy and hydrated with automatic watering and daily compliments.",
|
||||
"tagline": "Nurture your plants, boost their self-esteem."
|
||||
},
|
||||
{
|
||||
"_id": "675bee96bb39023b77e6cda4",
|
||||
"title": "Self-Stirring Cereal Bowl",
|
||||
"sku": "KIT0445",
|
||||
"stock": 55,
|
||||
"price": 24.95,
|
||||
"description": "Enjoy perfectly crunchy cereal every time with this self-stirring bowl.",
|
||||
"tagline": "No more soggy surprises."
|
||||
},
|
||||
{
|
||||
"_id": "675bee96bb39023b77e6cda5",
|
||||
"title": "Polygon Planet Lamp",
|
||||
"sku": "LMP0556",
|
||||
"stock": 4,
|
||||
"price": 39.9,
|
||||
"description": "Transform your space with the enchanting glow of a planetarium-inspired lamp.",
|
||||
"tagline": "Bring the cosmos into your home."
|
||||
}
|
||||
]
|
||||
1
webseite-react-php/react-app/public/favicon.svg
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
24
webseite-react-php/react-app/public/icons.svg
Normal file
@@ -0,0 +1,24 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<symbol id="bluesky-icon" viewBox="0 0 16 17">
|
||||
<g clip-path="url(#bluesky-clip)"><path fill="#08060d" d="M7.75 7.735c-.693-1.348-2.58-3.86-4.334-5.097-1.68-1.187-2.32-.981-2.74-.79C.188 2.065.1 2.812.1 3.251s.241 3.602.398 4.13c.52 1.744 2.367 2.333 4.07 2.145-2.495.37-4.71 1.278-1.805 4.512 3.196 3.309 4.38-.71 4.987-2.746.608 2.036 1.307 5.91 4.93 2.746 2.72-2.746.747-4.143-1.747-4.512 1.702.189 3.55-.4 4.07-2.145.156-.528.397-3.691.397-4.13s-.088-1.186-.575-1.406c-.42-.19-1.06-.395-2.741.79-1.755 1.24-3.64 3.752-4.334 5.099"/></g>
|
||||
<defs><clipPath id="bluesky-clip"><path fill="#fff" d="M.1.85h15.3v15.3H.1z"/></clipPath></defs>
|
||||
</symbol>
|
||||
<symbol id="discord-icon" viewBox="0 0 20 19">
|
||||
<path fill="#08060d" d="M16.224 3.768a14.5 14.5 0 0 0-3.67-1.153c-.158.286-.343.67-.47.976a13.5 13.5 0 0 0-4.067 0c-.128-.306-.317-.69-.476-.976A14.4 14.4 0 0 0 3.868 3.77C1.546 7.28.916 10.703 1.231 14.077a14.7 14.7 0 0 0 4.5 2.306q.545-.748.965-1.587a9.5 9.5 0 0 1-1.518-.74q.191-.14.372-.293c2.927 1.369 6.107 1.369 8.999 0q.183.152.372.294-.723.437-1.52.74.418.838.963 1.588a14.6 14.6 0 0 0 4.504-2.308c.37-3.911-.63-7.302-2.644-10.309m-9.13 8.234c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.894 0 1.614.82 1.599 1.82.001 1-.705 1.82-1.6 1.82m5.91 0c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.893 0 1.614.82 1.599 1.82 0 1-.706 1.82-1.6 1.82"/>
|
||||
</symbol>
|
||||
<symbol id="documentation-icon" viewBox="0 0 21 20">
|
||||
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="m15.5 13.333 1.533 1.322c.645.555.967.833.967 1.178s-.322.623-.967 1.179L15.5 18.333m-3.333-5-1.534 1.322c-.644.555-.966.833-.966 1.178s.322.623.966 1.179l1.534 1.321"/>
|
||||
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M17.167 10.836v-4.32c0-1.41 0-2.117-.224-2.68-.359-.906-1.118-1.621-2.08-1.96-.599-.21-1.349-.21-2.848-.21-2.623 0-3.935 0-4.983.369-1.684.591-3.013 1.842-3.641 3.428C3 6.449 3 7.684 3 10.154v2.122c0 2.558 0 3.838.706 4.726q.306.383.713.671c.76.536 1.79.64 3.581.66"/>
|
||||
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M3 10a2.78 2.78 0 0 1 2.778-2.778c.555 0 1.209.097 1.748-.047.48-.129.854-.503.982-.982.145-.54.048-1.194.048-1.749a2.78 2.78 0 0 1 2.777-2.777"/>
|
||||
</symbol>
|
||||
<symbol id="github-icon" viewBox="0 0 19 19">
|
||||
<path fill="#08060d" fill-rule="evenodd" d="M9.356 1.85C5.05 1.85 1.57 5.356 1.57 9.694a7.84 7.84 0 0 0 5.324 7.44c.387.079.528-.168.528-.376 0-.182-.013-.805-.013-1.454-2.165.467-2.616-.935-2.616-.935-.349-.91-.864-1.143-.864-1.143-.71-.48.051-.48.051-.48.787.051 1.2.805 1.2.805.695 1.194 1.817.857 2.268.649.064-.507.27-.857.49-1.052-1.728-.182-3.545-.857-3.545-3.87 0-.857.31-1.558.8-2.104-.078-.195-.349-1 .077-2.078 0 0 .657-.208 2.14.805a7.5 7.5 0 0 1 1.946-.26c.657 0 1.328.092 1.946.26 1.483-1.013 2.14-.805 2.14-.805.426 1.078.155 1.883.078 2.078.502.546.799 1.247.799 2.104 0 3.013-1.818 3.675-3.558 3.87.284.247.528.714.528 1.454 0 1.052-.012 1.896-.012 2.156 0 .208.142.455.528.377a7.84 7.84 0 0 0 5.324-7.441c.013-4.338-3.48-7.844-7.773-7.844" clip-rule="evenodd"/>
|
||||
</symbol>
|
||||
<symbol id="social-icon" viewBox="0 0 20 20">
|
||||
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M12.5 6.667a4.167 4.167 0 1 0-8.334 0 4.167 4.167 0 0 0 8.334 0"/>
|
||||
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M2.5 16.667a5.833 5.833 0 0 1 8.75-5.053m3.837.474.513 1.035c.07.144.257.282.414.309l.93.155c.596.1.736.536.307.965l-.723.73a.64.64 0 0 0-.152.531l.207.903c.164.715-.213.991-.84.618l-.872-.52a.63.63 0 0 0-.577 0l-.872.52c-.624.373-1.003.094-.84-.618l.207-.903a.64.64 0 0 0-.152-.532l-.723-.729c-.426-.43-.289-.864.306-.964l.93-.156a.64.64 0 0 0 .412-.31l.513-1.034c.28-.562.735-.562 1.012 0"/>
|
||||
</symbol>
|
||||
<symbol id="x-icon" viewBox="0 0 19 19">
|
||||
<path fill="#08060d" fill-rule="evenodd" d="M1.893 1.98c.052.072 1.245 1.769 2.653 3.77l2.892 4.114c.183.261.333.48.333.486s-.068.089-.152.183l-.522.593-.765.867-3.597 4.087c-.375.426-.734.834-.798.905a1 1 0 0 0-.118.148c0 .01.236.017.664.017h.663l.729-.83c.4-.457.796-.906.879-.999a692 692 0 0 0 1.794-2.038c.034-.037.301-.34.594-.675l.551-.624.345-.392a7 7 0 0 1 .34-.374c.006 0 .93 1.306 2.052 2.903l2.084 2.965.045.063h2.275c1.87 0 2.273-.003 2.266-.021-.008-.02-1.098-1.572-3.894-5.547-2.013-2.862-2.28-3.246-2.273-3.266.008-.019.282-.332 2.085-2.38l2-2.274 1.567-1.782c.022-.028-.016-.03-.65-.03h-.674l-.3.342a871 871 0 0 1-1.782 2.025c-.067.075-.405.458-.75.852a100 100 0 0 1-.803.91c-.148.172-.299.344-.99 1.127-.304.343-.32.358-.345.327-.015-.019-.904-1.282-1.976-2.808L6.365 1.85H1.8zm1.782.91 8.078 11.294c.772 1.08 1.413 1.973 1.425 1.984.016.017.241.02 1.05.017l1.03-.004-2.694-3.766L7.796 5.75 5.722 2.852l-1.039-.004-1.039-.004z" clip-rule="evenodd"/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
BIN
webseite-react-php/react-app/public/img/header-bg.jpg
Normal file
|
After Width: | Height: | Size: 210 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
1923
webseite-react-php/react-app/public/img/logo-react.svg
Normal file
|
After Width: | Height: | Size: 150 KiB |
BIN
webseite-react-php/react-app/public/img/slides/slide-01.jpg
Normal file
|
After Width: | Height: | Size: 153 KiB |
BIN
webseite-react-php/react-app/public/img/slides/slide-02.jpg
Normal file
|
After Width: | Height: | Size: 150 KiB |
BIN
webseite-react-php/react-app/public/img/slides/slide-03.jpg
Normal file
|
After Width: | Height: | Size: 159 KiB |
23
webseite-react-php/react-app/src/App.jsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import FooterMain from './components/footers/FooterMain';
|
||||
import HeaderMain from './components/headers/HeaderMain';
|
||||
import NavMain from './components/navs/NavMain';
|
||||
import Router from './routes/Router';
|
||||
|
||||
function App(props) {
|
||||
// const { } = props;
|
||||
const { pathname: path } = useLocation();
|
||||
|
||||
console.log(path);
|
||||
return (
|
||||
<>
|
||||
{path === '/' && <HeaderMain />}
|
||||
<NavMain />
|
||||
<main id="main">
|
||||
<Router />
|
||||
</main>
|
||||
<FooterMain />
|
||||
</>
|
||||
);
|
||||
}
|
||||
export default App;
|
||||
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
1923
webseite-react-php/react-app/src/assets/img/logo-react.svg
Normal file
|
After Width: | Height: | Size: 150 KiB |
1
webseite-react-php/react-app/src/assets/react.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
1
webseite-react-php/react-app/src/assets/vite.svg
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
@@ -0,0 +1,18 @@
|
||||
import { useContext } from 'react';
|
||||
import ThemeContext from './theme-switcher/ThemeContext';
|
||||
|
||||
const ExampleUseContext = (props) => {
|
||||
// const { } = props;
|
||||
|
||||
const theme = useContext(ThemeContext);
|
||||
|
||||
return (
|
||||
<div className={`example-use-context ${theme === 'light' ? 'text-bg-light' : 'text-bg-dark'} p-3`}>
|
||||
<h4>useContext</h4>
|
||||
<p>
|
||||
The theme of this component is: <strong>{theme}</strong>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default ExampleUseContext;
|
||||
@@ -0,0 +1,24 @@
|
||||
import { useId } from 'react';
|
||||
// import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
const ExampleUseId = (props) => {
|
||||
// const { } = props;
|
||||
const id = useId().replaceAll(/[_r.]/g, '');
|
||||
// const id2 = uuidv4(); // -> 'b18794e8-5d0d-417c-b361-ba38e78411b4'
|
||||
|
||||
return (
|
||||
<div className="example-use-id">
|
||||
<p>
|
||||
<strong>ID: {id}</strong>
|
||||
</p>
|
||||
|
||||
<div className="mb-3">
|
||||
<label htmlFor={`input-date-${id}`} className="form-label">
|
||||
Datum:
|
||||
</label>
|
||||
<input type="date" name="date" id={`input-date-${id}`} className="form-control w-25" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default ExampleUseId;
|
||||
@@ -0,0 +1,77 @@
|
||||
import { useReducer } from 'react';
|
||||
import { FaMinus, FaPlus } from 'react-icons/fa6';
|
||||
|
||||
const initialState = {
|
||||
counter: 0,
|
||||
//more props...
|
||||
};
|
||||
|
||||
// Reducer Funktion verwaltet das state Objekt. Über die Funktion lässt sich das state-Objekt gezielt verändern
|
||||
function reducer(state, action) {
|
||||
// action Objekt hat immer folgende Eigenschaften: {type: 'ACTION_NAME', payload: changeValue}
|
||||
const { type, payload = 1 } = action;
|
||||
switch (type) {
|
||||
case 'INCREASE':
|
||||
return { ...state, counter: state.counter + 1 };
|
||||
case 'DECREASE':
|
||||
return { ...state, counter: state.counter - 1 };
|
||||
case 'DOUBLE':
|
||||
return { ...state, counter: state.counter * 2 };
|
||||
case 'INC_VALUE':
|
||||
return { ...state, counter: state.counter + payload };
|
||||
|
||||
default:
|
||||
console.warn('Action Type not found');
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
const ExampleUseReducer = (props) => {
|
||||
// const { } = props;
|
||||
|
||||
// Hook - Toplevel
|
||||
// const [counter, setCounter] = useState(0);
|
||||
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
|
||||
// EventHandler ============
|
||||
const handeClickInc = (e) => {
|
||||
//setCounter(counter + 1);
|
||||
dispatch({ type: 'INCREASE' });
|
||||
};
|
||||
const handeClickDec = (e) => {
|
||||
// setCounter(counter - 1);
|
||||
|
||||
// dispatch(action_object)
|
||||
dispatch({ type: 'DECREASE' });
|
||||
};
|
||||
|
||||
const handleClickDouble = (e) => {
|
||||
// dispatch(action_object)
|
||||
dispatch({ type: 'DOUBLE' });
|
||||
};
|
||||
|
||||
const handleClickIncValue = (e) => {
|
||||
dispatch({ type: 'INC_VALUE', payload: 5 });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="example-use-reducer">
|
||||
Counter: {state.counter}
|
||||
<button className="btn btn-dark button-inc mx-1" aria-label="Increase" onClick={handeClickInc}>
|
||||
<FaPlus />
|
||||
</button>
|
||||
<button className="btn btn-dark button-dec mx-1" aria-label="Decrease" onClick={handeClickDec}>
|
||||
<FaMinus />
|
||||
</button>
|
||||
<button className="btn btn-dark button-double mx-1" aria-label="Double" onClick={handleClickDouble}>
|
||||
<FaPlus />
|
||||
<FaPlus />
|
||||
</button>
|
||||
<button className="btn btn-dark button-inc-value mx-1" aria-label="Inc by value" onClick={handleClickIncValue}>
|
||||
<FaPlus /> 5
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default ExampleUseReducer;
|
||||
@@ -0,0 +1,41 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { FaPlus, FaMinus } from 'react-icons/fa6';
|
||||
|
||||
const ExampleUseState = (props) => {
|
||||
// const { } = props;
|
||||
|
||||
const [counter, setCounter] = useState(0);
|
||||
|
||||
// let counter = 0;
|
||||
|
||||
// EventHandler =======
|
||||
const handleClick = (e) => {
|
||||
console.log('click');
|
||||
const btn = e.currentTarget;
|
||||
const label = btn.ariaLabel;
|
||||
|
||||
switch (label) {
|
||||
case 'Increase':
|
||||
// setCounter(counter + 1); // setter(value)
|
||||
setCounter((prevState) => prevState + 1); // setter(fn(prevValue) => newValue )
|
||||
break;
|
||||
case 'Decrease':
|
||||
setCounter(counter - 1);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="example-use-state">
|
||||
Counter: {counter}
|
||||
<button className="btn btn-dark button-inc mx-1" aria-label="Increase" onClick={handleClick}>
|
||||
<FaPlus />
|
||||
</button>
|
||||
<button className="btn btn-dark button-inc mx-1" aria-label="Decrease" onClick={handleClick}>
|
||||
<FaMinus />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default ExampleUseState;
|
||||
@@ -0,0 +1,8 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
export const THEME_DEFAULT_VALUE = 'light';
|
||||
|
||||
const ThemeContext = createContext(THEME_DEFAULT_VALUE); // standard theme is light;
|
||||
// ThemeContext wird durch createContext() zu einem JSX-Element
|
||||
|
||||
export default ThemeContext;
|
||||
@@ -0,0 +1,26 @@
|
||||
import { useState } from 'react';
|
||||
import ThemeContext, { THEME_DEFAULT_VALUE } from './ThemeContext';
|
||||
|
||||
const ThemeProvider = (props) => {
|
||||
const { children } = props;
|
||||
|
||||
console.log(ThemeContext._currentValue); // 'light' <- _currentValue beinhaltet initialWert. Soll aber in production Umgebung nicht verwendet werden, da kein offizieller Standard.
|
||||
|
||||
const [theme, setTheme] = useState(THEME_DEFAULT_VALUE);
|
||||
|
||||
// EventHandler ==============
|
||||
const handleToggleTheme = () => {
|
||||
console.log('click');
|
||||
setTheme((prevState) => (prevState === 'light' ? 'dark' : 'light'));
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeContext.Provider value={theme}>
|
||||
<button className="btn btn-dark button-theme-toggle my-3" onClick={handleToggleTheme}>
|
||||
Change Theme
|
||||
</button>
|
||||
{children}
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
export default ThemeProvider;
|
||||
@@ -0,0 +1,48 @@
|
||||
import NavSocial from '../navs/NavSocial';
|
||||
|
||||
const FooterMain = (props) => {
|
||||
// const { } = props;
|
||||
|
||||
return (
|
||||
<footer className="m-footer-main footer-main">
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-12 col-md-4">
|
||||
<div className="box">
|
||||
<h2>Contact</h2>
|
||||
<address>
|
||||
John Smith
|
||||
<br />
|
||||
1 Example Street
|
||||
<br />
|
||||
Anytown, AB1 2CD
|
||||
</address>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-md-4">
|
||||
<div className="box">
|
||||
<h2>More Information</h2>
|
||||
<nav className="nav-footer">
|
||||
<ul className="list">
|
||||
<li>
|
||||
<a href="#">Imprint</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Our Privacy Policy</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-md-4">
|
||||
<div className="box">
|
||||
<h2>Social Media</h2>
|
||||
<NavSocial />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
export default FooterMain;
|
||||
@@ -0,0 +1,21 @@
|
||||
import LogoMain from '../logos/LogoMain';
|
||||
import SliderSplide from '../sliders/SliderSplide';
|
||||
|
||||
const HeaderMain = () => {
|
||||
const images = [
|
||||
{ path: '/img/slides/slide-01.jpg', title: 'Classroom' },
|
||||
{ path: '/img/slides/slide-02.jpg', title: 'Mountains' },
|
||||
{ path: '/img/slides/slide-03.jpg', title: 'Canyons' },
|
||||
];
|
||||
|
||||
return (
|
||||
<header className="m-header-main header-main">
|
||||
<SliderSplide images={images} />
|
||||
<div className="content-box">
|
||||
<LogoMain />
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeaderMain;
|
||||
@@ -0,0 +1,67 @@
|
||||
// import { useState } from 'react';
|
||||
import { FaMinus, FaPlus } from 'react-icons/fa6';
|
||||
// npm install react-icons | Auf der npm Seite mit --save, ist nicht mehr nötig
|
||||
const InputAmount = (props) => {
|
||||
const { amount = 0, max = 100, min = -100 } = props;
|
||||
// const [amount, setAmount] = useState(props.amount || 0);
|
||||
|
||||
// EventHandlers ================
|
||||
const handleChange = (e) => {
|
||||
const inputValue = e.target.value;
|
||||
const numericRegExp = new RegExp(/^-?\d*$/); // regular expression for numbers (including optional minus sign)
|
||||
|
||||
if (!numericRegExp.test(inputValue)) return;
|
||||
// setAmount(inputValue);
|
||||
props.onHandleAmount(inputValue);
|
||||
};
|
||||
const handleClickDec = (e) => {
|
||||
// Guard
|
||||
if (amount < min) return;
|
||||
|
||||
props.onHandleAmount(amount - 1);
|
||||
// setAmount((prevState) => prevState - 1);
|
||||
};
|
||||
|
||||
const handleClickInc = (e) => {
|
||||
// Guard
|
||||
if (amount > max) return;
|
||||
|
||||
// setAmount((prevState) => prevState + 1);
|
||||
props.onHandleAmount(amount + 1);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="m-input-amount input-amount">
|
||||
<div className="input-group mb-3">
|
||||
<span className="input-group-text">
|
||||
<button
|
||||
className="btn btn-dark button-decrease"
|
||||
aria-label="Decrease Amount"
|
||||
onClick={handleClickDec}
|
||||
disabled={amount <= min}>
|
||||
<FaMinus />
|
||||
</button>
|
||||
</span>
|
||||
<input
|
||||
type="number"
|
||||
name="amount"
|
||||
placeholder="0"
|
||||
aria-label="Amount"
|
||||
value={amount}
|
||||
className="form-control input-amount"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<span className="input-group-text">
|
||||
<button
|
||||
className="btn btn-dark button-increase"
|
||||
aria-label="Increase Amount"
|
||||
onClick={handleClickInc}
|
||||
disabled={amount >= max}>
|
||||
<FaPlus />
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default InputAmount;
|
||||
@@ -0,0 +1,49 @@
|
||||
// import { useState } from 'react';
|
||||
import { FaDollarSign, FaEuroSign, FaYenSign } from 'react-icons/fa6';
|
||||
|
||||
const InputPrice = (props) => {
|
||||
const { currency = '$', price = 0 } = props;
|
||||
|
||||
// const [price, setPrice] = useState(0);
|
||||
|
||||
//Evenhandler
|
||||
const handleChange = (e) => {
|
||||
console.log(`Preis: ${e.target.value}`);
|
||||
|
||||
props.onHandlePrice(e.target.value);
|
||||
//setPrice(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="m-input-price input-price">
|
||||
<div className="input-group mb-3">
|
||||
{currency === '$' && (
|
||||
<span className="input-group-text">
|
||||
<FaDollarSign />
|
||||
</span>
|
||||
)}
|
||||
<input
|
||||
type="number"
|
||||
name="price"
|
||||
placeholder="0.00"
|
||||
aria-label="Price"
|
||||
className="form-control input-price"
|
||||
step="0.01"
|
||||
value={price}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
{currency === '€' && (
|
||||
<span className="input-group-text">
|
||||
<FaEuroSign />
|
||||
</span>
|
||||
)}
|
||||
{currency === '¥' && (
|
||||
<span className="input-group-text">
|
||||
<FaYenSign />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default InputPrice;
|
||||
@@ -0,0 +1,12 @@
|
||||
import Logo from '../../assets/img/logo-react.min.svg';
|
||||
|
||||
const LogoMain = (props) => {
|
||||
// const { } = props;
|
||||
|
||||
return (
|
||||
<figure className="m-logo-main logo-main">
|
||||
<img src={Logo} alt="React" />
|
||||
</figure>
|
||||
);
|
||||
};
|
||||
export default LogoMain;
|
||||
73
webseite-react-php/react-app/src/components/navs/NavMain.jsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
const NavMain = () => {
|
||||
return (
|
||||
<nav className="m-nav-main nav-main navbar navbar-expand-lg bg-light" data-bs-theme="light">
|
||||
<div className="container-fluid">
|
||||
<button
|
||||
className="navbar-toggler"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarNav"
|
||||
aria-controls="navbarNav"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation">
|
||||
<span className="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div className="collapse navbar-collapse" id="navbarNav">
|
||||
<ul className="navbar-nav">
|
||||
<li className="nav-item">
|
||||
<NavLink className={({ isActive }) => `nav-link ${isActive ? 'active' : ''}`} to="/">
|
||||
Home
|
||||
</NavLink>
|
||||
</li>
|
||||
<li className="nav-item dropdown">
|
||||
<NavLink
|
||||
className="nav-link dropdown-toggle"
|
||||
to="/projects"
|
||||
role="button"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false">
|
||||
Projects
|
||||
</NavLink>
|
||||
<ul className="dropdown-menu">
|
||||
<li>
|
||||
<NavLink
|
||||
className={({ isActive }) => `dropdown-item ${isActive ? 'active' : ''}`}
|
||||
to="/projects/fibonacci">
|
||||
Fibonacci
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<NavLink
|
||||
className={({ isActive }) => `dropdown-item ${isActive ? 'active' : ''}`}
|
||||
to="/projects/examples">
|
||||
Examples
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<NavLink
|
||||
className={({ isActive }) => `dropdown-item ${isActive ? 'active' : ''}`}
|
||||
to="/projects/table-products">
|
||||
Table Products
|
||||
</NavLink>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<NavLink className={({ isActive }) => `nav-link ${isActive ? 'active' : ''}`} to="/about">
|
||||
About
|
||||
</NavLink>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<NavLink className={({ isActive }) => `nav-link ${isActive ? 'active' : ''}`} to="/contact">
|
||||
Contact
|
||||
</NavLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
export default NavMain;
|
||||
@@ -0,0 +1,33 @@
|
||||
import { FaInstagram, FaXTwitter, FaYoutube, FaMeta } from 'react-icons/fa6';
|
||||
|
||||
const NavSocial = (props) => {
|
||||
// const { } = props;
|
||||
|
||||
return (
|
||||
<nav className="m-nav-social nav-social">
|
||||
<ul className="list">
|
||||
<li>
|
||||
<a href="#" aria-label="X (Twitter)">
|
||||
<FaXTwitter />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.youtube.com/@GFNde" target="_blank" aria-label="Youtube">
|
||||
<FaYoutube />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" aria-label="Meta">
|
||||
<FaMeta />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" aria-label="Instagram">
|
||||
<FaInstagram />
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
export default NavSocial;
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Splide, SplideSlide } from '@splidejs/react-splide';
|
||||
|
||||
const SliderSplide = (props) => {
|
||||
const {
|
||||
images = [],
|
||||
label = 'Slides',
|
||||
options = {
|
||||
rewind: true,
|
||||
height: '100%',
|
||||
autoplay: true,
|
||||
speed: 800,
|
||||
type: 'fade',
|
||||
},
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
{images.length > 0 && (
|
||||
<div className="m-slider-splide slider-splide">
|
||||
<Splide aria-label={label} options={options}>
|
||||
{images.map(({ path, title }, idx) => (
|
||||
// <SplideSlide key={`splide-slide-${idx}`} style={{ backgroundImage: `url(${path})` }}>
|
||||
<SplideSlide key={`splide-slide-${idx}`}>
|
||||
<img src={path} alt={title} />
|
||||
</SplideSlide>
|
||||
))}
|
||||
</Splide>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default SliderSplide;
|
||||
@@ -0,0 +1,78 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import RowProduct from './content/RowProduct';
|
||||
import { ProductsProvider, useProductsState } from '../../stores/products';
|
||||
|
||||
const TableProductsView = (props) => {
|
||||
const { items } = useProductsState();
|
||||
// const dispatch = useProductsDispatch()
|
||||
|
||||
//const [{ items }, dispatch] = useReducer(reducer, initialState(props));
|
||||
|
||||
// EventHandler ============
|
||||
// const handleAmount = useCallback((amount, id) => {
|
||||
// dispatch({ type: PRODUCTS_ACTIONS.UPDATE_AMOUNT, payload: { amount, id } });
|
||||
// }, []);
|
||||
|
||||
// const handlePrice = useCallback((price, id) => {
|
||||
// dispatch({ type: PRODUCTS_ACTIONS.UPDATE_PRICE, payload: { price, id } });
|
||||
// }, []);
|
||||
|
||||
// Functions ===============
|
||||
const totalPrice = useMemo(() => {
|
||||
// [0, {stock: 2, price, 15.2}, {...}]
|
||||
return items.reduce((sum, obj) => {
|
||||
return sum + Number(obj.stock) * Number(obj.price);
|
||||
}, 0);
|
||||
}, [items]);
|
||||
|
||||
// useCallback weiter Einsatzbereich in Kombination mit ref- Attribut
|
||||
const theadRef = useCallback((el) => {
|
||||
if (el) console.log(el);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="m-table-products table-products">
|
||||
<div className="container py-2">
|
||||
<table className="table table-striped">
|
||||
<thead className="table-dark" ref={theadRef}>
|
||||
<tr>
|
||||
<th>SKU</th>
|
||||
<th>Stock</th>
|
||||
<th>Title</th>
|
||||
<th>Price</th>
|
||||
<th>Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{items.length > 0 &&
|
||||
items.map((product, idx) => (
|
||||
<RowProduct
|
||||
key={`row-product-${idx}`}
|
||||
{...product}
|
||||
// onHandleAmount={handleAmount}
|
||||
// onHandlePrice={handlePrice}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colSpan={4}>Total:</td>
|
||||
<td>{totalPrice.toFixed(2)}</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const TableProducts = (props) => {
|
||||
// const { } = props;
|
||||
|
||||
return (
|
||||
<ProductsProvider items={props.items}>
|
||||
<TableProductsView />
|
||||
</ProductsProvider>
|
||||
);
|
||||
};
|
||||
export default TableProducts;
|
||||
@@ -0,0 +1,57 @@
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useProductsActions } from '../../../stores/products'; // /index.js muss nicht angegeben werden (wg. Bundler)
|
||||
// import { useProductsDispatch } from '../../../stores/products';
|
||||
// import { PRODUCTS_ACTIONS } from '../../../stores/products';
|
||||
|
||||
import InputAmount from '../../inputs/InputAmount';
|
||||
import InputPrice from '../../inputs/InputPrice';
|
||||
|
||||
const RowProduct = (props) => {
|
||||
const { _id, sku = '', stock: amount = 0, price = 0, title = '' } = props;
|
||||
//const { sku = '', title = '' } = props;
|
||||
|
||||
const { updateAmount, updatePrice } = useProductsActions();
|
||||
// const dispatch = useProductsDispatch();
|
||||
|
||||
// Eventhandler
|
||||
// const handleAmount = useCallback((val) => {
|
||||
// // setAmount(val);
|
||||
// // props.onHandleAmount(val, _id);
|
||||
// dispatch({ type: PRODUCTS_ACTIONS.UPDATE_AMOUNT, payload: { amount: val, id: _id } });
|
||||
// }, []);
|
||||
|
||||
const handleAmount = useCallback(
|
||||
(val) => {
|
||||
updateAmount(val, _id);
|
||||
},
|
||||
[updateAmount, _id],
|
||||
);
|
||||
|
||||
// const handlePrice = (val) => {
|
||||
// // setPrice(val);
|
||||
// // props.onHandlePrice(val, _id);
|
||||
// dispatch({ type: PRODUCTS_ACTIONS.UPDATE_PRICE, payload: { price: val, id: _id } });
|
||||
// };
|
||||
|
||||
const handlePrice = useCallback(
|
||||
(val) => {
|
||||
updatePrice(val, _id);
|
||||
},
|
||||
[updatePrice, _id],
|
||||
);
|
||||
|
||||
return (
|
||||
<tr className="row-product">
|
||||
<td>{sku}</td>
|
||||
<td>
|
||||
<InputAmount amount={amount} max={1000} min={0} onHandleAmount={(value) => handleAmount(value)} />
|
||||
</td>
|
||||
<td>{title}</td>
|
||||
<td>
|
||||
<InputPrice price={price} onHandlePrice={handlePrice} />
|
||||
</td>
|
||||
<td>{(amount * price).toFixed(2)}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
export default memo(RowProduct);
|
||||
18
webseite-react-php/react-app/src/main.jsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import { StrictMode } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
|
||||
// eigene separate Gestaltung mit main.scss (beinhaltet boostrap)
|
||||
import './styles/main.scss';
|
||||
|
||||
import 'bootstrap'; // bootstrap JS wird über esbuild aus node_modules ausgelesen und eingebunden (bundled)
|
||||
|
||||
import App from './App.jsx';
|
||||
|
||||
createRoot(document.getElementById('root')).render(
|
||||
<StrictMode>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</StrictMode>,
|
||||
);
|
||||
13
webseite-react-php/react-app/src/pages/About.jsx
Normal file
@@ -0,0 +1,13 @@
|
||||
const About = (props) => {
|
||||
// const { } = props;
|
||||
|
||||
return (
|
||||
<div className="page page-about">
|
||||
<div className="container py-3">
|
||||
<h1>About</h1>
|
||||
<p>Welcome to the Single-Page-Application (SPA) with React. This is the About page.</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default About;
|
||||
16
webseite-react-php/react-app/src/pages/Contact.jsx
Normal file
@@ -0,0 +1,16 @@
|
||||
const Contact = (props) => {
|
||||
// const { } = props;
|
||||
|
||||
return (
|
||||
<div className="page page-contact">
|
||||
<div className="container py-3">
|
||||
<h1>Contact</h1>
|
||||
<p>
|
||||
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Iste suscipit eos autem iure soluta laboriosam in
|
||||
perferendis atque explicabo, possimus eius? Ea magnam sed atque exercitationem officiis ipsum, deserunt iste.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default Contact;
|
||||
13
webseite-react-php/react-app/src/pages/Home.jsx
Normal file
@@ -0,0 +1,13 @@
|
||||
const Home = (props) => {
|
||||
// const { } = props;
|
||||
|
||||
return (
|
||||
<div className="page page-home">
|
||||
<div className="container py-3">
|
||||
<h1>Hello, Spa!</h1>
|
||||
<p>Welcome to the Single-Page-Application (SPA) with React. This is the Home page.</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default Home;
|
||||
18
webseite-react-php/react-app/src/pages/projects/Examples.jsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import ExampleUseContext from '../../components/examples/ExampleUseContext';
|
||||
import ThemeProvider from '../../components/examples/theme-switcher/ThemeProvider';
|
||||
|
||||
const Examples = () => {
|
||||
return (
|
||||
<div className="page page-examples">
|
||||
<div className="container py-5">
|
||||
<h2>Examples</h2>
|
||||
<hr />
|
||||
<h3>useContext</h3>
|
||||
<ThemeProvider>
|
||||
<ExampleUseContext />
|
||||
</ThemeProvider>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default Examples;
|
||||
@@ -0,0 +1,45 @@
|
||||
import { useState, useMemo } from 'react';
|
||||
import { FaMinus, FaPlus } from 'react-icons/fa6';
|
||||
|
||||
const Fibonacci = () => {
|
||||
const [num, setNum] = useState(5);
|
||||
|
||||
const fibonacci = useMemo(() => {
|
||||
console.log('Fibonacci number is being calculated...');
|
||||
function fib(n) {
|
||||
// Define a recursive function within the callback
|
||||
if (n <= 1) {
|
||||
return n;
|
||||
}
|
||||
return fib(n - 1) + fib(n - 2);
|
||||
}
|
||||
return fib(num); // Call the inner function
|
||||
}, [num]);
|
||||
|
||||
return (
|
||||
<div className="page page-fibonacci">
|
||||
<div className="container py-5">
|
||||
<div className="mb-3">
|
||||
<button
|
||||
className="btn btn-dark button-dec"
|
||||
onClick={() => setNum(num - 1)}
|
||||
aria-label="previous Fibonacci number">
|
||||
<FaMinus />
|
||||
</button>
|
||||
<span> {num} </span>
|
||||
<button
|
||||
className="btn btn-dark button-dec"
|
||||
onClick={() => setNum(num + 1)}
|
||||
aria-label="next Fibonacci number">
|
||||
<FaPlus />
|
||||
</button>
|
||||
</div>
|
||||
<p>
|
||||
The {num}th Fibonacci number is: {fibonacci}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Fibonacci;
|
||||
@@ -0,0 +1,36 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
|
||||
import Table from '../../components/tables/TableProducts';
|
||||
|
||||
const TableProducts = (props) => {
|
||||
// const { } = props;
|
||||
|
||||
const [items, setItems] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const getItems = async () => {
|
||||
const { data } = await axios.get('/data/nerdshop-products.json');
|
||||
setItems(data);
|
||||
};
|
||||
getItems();
|
||||
|
||||
// axios.get('/data/nerdshop-products.json').then((res) => {
|
||||
// // console.log(res.data);
|
||||
// setItems(res.data);
|
||||
// });
|
||||
|
||||
return () => {};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="page page-table-products">
|
||||
<div className="container pt-3">
|
||||
<h2>Table products</h2>
|
||||
<p>A inventory table of products</p>
|
||||
</div>
|
||||
{items.length > 0 && <Table items={items} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default TableProducts;
|
||||
28
webseite-react-php/react-app/src/routes/Router.jsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
import Home from '../pages/Home';
|
||||
import About from '../pages/About';
|
||||
import Contact from '../pages/Contact';
|
||||
|
||||
// Projects
|
||||
import Fibonacci from '../pages/projects/Fibonacci';
|
||||
import TableProducts from '../pages/projects/TableProducts';
|
||||
import Examples from '../pages/projects/Examples';
|
||||
|
||||
const Router = (props) => {
|
||||
// const { } = props;
|
||||
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/about" element={<About />} />
|
||||
<Route path="/contact" element={<Contact />} />
|
||||
|
||||
<Route path="/projects" element="">
|
||||
<Route path="examples" element={<Examples />} />
|
||||
<Route path="fibonacci" element={<Fibonacci />} />
|
||||
<Route path="table-products" element={<TableProducts />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
);
|
||||
};
|
||||
export default Router;
|
||||
@@ -0,0 +1,68 @@
|
||||
import { createContext, useCallback, useContext, useReducer } from 'react';
|
||||
import { PRODUCTS_ACTIONS, productsReducer } from './reducer';
|
||||
import { createInitialState } from './initialState';
|
||||
|
||||
const ProductsStateContext = createContext(null);
|
||||
const ProductsDispatchContext = createContext(null);
|
||||
|
||||
// const ProductsContext = createContext(null);
|
||||
|
||||
export const ProductsProvider = (props) => {
|
||||
const { children, items = [] } = props;
|
||||
|
||||
const [state, dispatch] = useReducer(productsReducer, items, createInitialState);
|
||||
|
||||
return (
|
||||
// <ProductsContext.Provider value={{state, dispatch}}>
|
||||
// {children}
|
||||
// </ProductsContext.Provider>
|
||||
|
||||
<ProductsStateContext.Provider value={state}>
|
||||
<ProductsDispatchContext.Provider value={dispatch}>{children}</ProductsDispatchContext.Provider>
|
||||
</ProductsStateContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
// eigene Hooks mit ErrorHandler
|
||||
export const useProductsState = () => {
|
||||
const state = useContext(ProductsStateContext);
|
||||
|
||||
if (state == null) {
|
||||
throw Error('useProductsState muss innerhalb von ProductsProvider verwendet werden.');
|
||||
}
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
export const useProductsDispatch = () => {
|
||||
const dispatch = useContext(ProductsDispatchContext);
|
||||
|
||||
if (dispatch == null) {
|
||||
throw Error('useProductsDispatch muss innerhalb von ProductsProvider verwendet werden.');
|
||||
}
|
||||
|
||||
return dispatch;
|
||||
};
|
||||
|
||||
export const useProductsActions = () => {
|
||||
const dispatch = useProductsDispatch();
|
||||
|
||||
const updateAmount = useCallback(
|
||||
(amount, id) => {
|
||||
dispatch({ type: PRODUCTS_ACTIONS.UPDATE_AMOUNT, payload: { id, amount } });
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const updatePrice = useCallback(
|
||||
(price, id) => {
|
||||
dispatch({ type: PRODUCTS_ACTIONS.UPDATE_PRICE, payload: { id, price } });
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
return {
|
||||
updateAmount,
|
||||
updatePrice,
|
||||
};
|
||||
};
|
||||
3
webseite-react-php/react-app/src/stores/products/index.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export { createInitialState } from './initialState';
|
||||
export { PRODUCTS_ACTIONS, productsReducer } from './reducer';
|
||||
export { ProductsProvider, useProductsActions, useProductsDispatch, useProductsState } from './ProductsStore';
|
||||
7
webseite-react-php/react-app/src/stores/products/initialState.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// import mit {}
|
||||
export const createInitialState = (items) => {
|
||||
// validation and sanitizing
|
||||
return { items: items || [] };
|
||||
};
|
||||
|
||||
export default createInitialState; // import mit eigener Benennung möglich
|
||||
36
webseite-react-php/react-app/src/stores/products/reducer.js
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// in ts enum
|
||||
export const PRODUCTS_ACTIONS = {
|
||||
UPDATE_AMOUNT: 'UPDATE_AMOUNT',
|
||||
UPDATE_PRICE: 'UPDATE_PRICE',
|
||||
};
|
||||
|
||||
export const productsReducer = (state, action) => {
|
||||
const { type, payload } = action;
|
||||
|
||||
console.log(state);
|
||||
|
||||
switch (type) {
|
||||
case PRODUCTS_ACTIONS.UPDATE_AMOUNT:
|
||||
return {
|
||||
...state,
|
||||
items: state.items.map((item) =>
|
||||
item._id === payload.id //
|
||||
? { ...item, stock: payload.amount }
|
||||
: item,
|
||||
),
|
||||
};
|
||||
|
||||
case PRODUCTS_ACTIONS.UPDATE_PRICE:
|
||||
return {
|
||||
...state,
|
||||
items: state.items.map((item) =>
|
||||
item._id === payload.id //
|
||||
? { ...item, price: payload.price }
|
||||
: item,
|
||||
),
|
||||
};
|
||||
default:
|
||||
console.warn('no action found');
|
||||
return state;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
// @import 'bootstrap-5.3.8/bootstrap-grid';
|
||||
@import 'bootstrap-5.3.8/bootstrap';
|
||||
// @import 'bulma-1.04/index'
|
||||
153
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_accordion.scss
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
//
|
||||
// Base styles
|
||||
//
|
||||
|
||||
.accordion {
|
||||
// scss-docs-start accordion-css-vars
|
||||
--#{$prefix}accordion-color: #{$accordion-color};
|
||||
--#{$prefix}accordion-bg: #{$accordion-bg};
|
||||
--#{$prefix}accordion-transition: #{$accordion-transition};
|
||||
--#{$prefix}accordion-border-color: #{$accordion-border-color};
|
||||
--#{$prefix}accordion-border-width: #{$accordion-border-width};
|
||||
--#{$prefix}accordion-border-radius: #{$accordion-border-radius};
|
||||
--#{$prefix}accordion-inner-border-radius: #{$accordion-inner-border-radius};
|
||||
--#{$prefix}accordion-btn-padding-x: #{$accordion-button-padding-x};
|
||||
--#{$prefix}accordion-btn-padding-y: #{$accordion-button-padding-y};
|
||||
--#{$prefix}accordion-btn-color: #{$accordion-button-color};
|
||||
--#{$prefix}accordion-btn-bg: #{$accordion-button-bg};
|
||||
--#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon)};
|
||||
--#{$prefix}accordion-btn-icon-width: #{$accordion-icon-width};
|
||||
--#{$prefix}accordion-btn-icon-transform: #{$accordion-icon-transform};
|
||||
--#{$prefix}accordion-btn-icon-transition: #{$accordion-icon-transition};
|
||||
--#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon)};
|
||||
--#{$prefix}accordion-btn-focus-box-shadow: #{$accordion-button-focus-box-shadow};
|
||||
--#{$prefix}accordion-body-padding-x: #{$accordion-body-padding-x};
|
||||
--#{$prefix}accordion-body-padding-y: #{$accordion-body-padding-y};
|
||||
--#{$prefix}accordion-active-color: #{$accordion-button-active-color};
|
||||
--#{$prefix}accordion-active-bg: #{$accordion-button-active-bg};
|
||||
// scss-docs-end accordion-css-vars
|
||||
}
|
||||
|
||||
.accordion-button {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: var(--#{$prefix}accordion-btn-padding-y) var(--#{$prefix}accordion-btn-padding-x);
|
||||
@include font-size($font-size-base);
|
||||
color: var(--#{$prefix}accordion-btn-color);
|
||||
text-align: left; // Reset button style
|
||||
background-color: var(--#{$prefix}accordion-btn-bg);
|
||||
border: 0;
|
||||
@include border-radius(0);
|
||||
overflow-anchor: none;
|
||||
@include transition(var(--#{$prefix}accordion-transition));
|
||||
|
||||
&:not(.collapsed) {
|
||||
color: var(--#{$prefix}accordion-active-color);
|
||||
background-color: var(--#{$prefix}accordion-active-bg);
|
||||
box-shadow: inset 0 calc(-1 * var(--#{$prefix}accordion-border-width)) 0 var(--#{$prefix}accordion-border-color); // stylelint-disable-line function-disallowed-list
|
||||
|
||||
&::after {
|
||||
background-image: var(--#{$prefix}accordion-btn-active-icon);
|
||||
transform: var(--#{$prefix}accordion-btn-icon-transform);
|
||||
}
|
||||
}
|
||||
|
||||
// Accordion icon
|
||||
&::after {
|
||||
flex-shrink: 0;
|
||||
width: var(--#{$prefix}accordion-btn-icon-width);
|
||||
height: var(--#{$prefix}accordion-btn-icon-width);
|
||||
margin-left: auto;
|
||||
content: "";
|
||||
background-image: var(--#{$prefix}accordion-btn-icon);
|
||||
background-repeat: no-repeat;
|
||||
background-size: var(--#{$prefix}accordion-btn-icon-width);
|
||||
@include transition(var(--#{$prefix}accordion-btn-icon-transition));
|
||||
}
|
||||
|
||||
&:hover {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
z-index: 3;
|
||||
outline: 0;
|
||||
box-shadow: var(--#{$prefix}accordion-btn-focus-box-shadow);
|
||||
}
|
||||
}
|
||||
|
||||
.accordion-header {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.accordion-item {
|
||||
color: var(--#{$prefix}accordion-color);
|
||||
background-color: var(--#{$prefix}accordion-bg);
|
||||
border: var(--#{$prefix}accordion-border-width) solid var(--#{$prefix}accordion-border-color);
|
||||
|
||||
&:first-of-type {
|
||||
@include border-top-radius(var(--#{$prefix}accordion-border-radius));
|
||||
|
||||
> .accordion-header .accordion-button {
|
||||
@include border-top-radius(var(--#{$prefix}accordion-inner-border-radius));
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:first-of-type) {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
// Only set a border-radius on the last item if the accordion is collapsed
|
||||
&:last-of-type {
|
||||
@include border-bottom-radius(var(--#{$prefix}accordion-border-radius));
|
||||
|
||||
> .accordion-header .accordion-button {
|
||||
&.collapsed {
|
||||
@include border-bottom-radius(var(--#{$prefix}accordion-inner-border-radius));
|
||||
}
|
||||
}
|
||||
|
||||
> .accordion-collapse {
|
||||
@include border-bottom-radius(var(--#{$prefix}accordion-border-radius));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.accordion-body {
|
||||
padding: var(--#{$prefix}accordion-body-padding-y) var(--#{$prefix}accordion-body-padding-x);
|
||||
}
|
||||
|
||||
|
||||
// Flush accordion items
|
||||
//
|
||||
// Remove borders and border-radius to keep accordion items edge-to-edge.
|
||||
|
||||
.accordion-flush {
|
||||
> .accordion-item {
|
||||
border-right: 0;
|
||||
border-left: 0;
|
||||
@include border-radius(0);
|
||||
|
||||
&:first-child { border-top: 0; }
|
||||
&:last-child { border-bottom: 0; }
|
||||
|
||||
// stylelint-disable selector-max-class
|
||||
> .accordion-collapse,
|
||||
> .accordion-header .accordion-button,
|
||||
> .accordion-header .accordion-button.collapsed {
|
||||
@include border-radius(0);
|
||||
}
|
||||
// stylelint-enable selector-max-class
|
||||
}
|
||||
}
|
||||
|
||||
@if $enable-dark-mode {
|
||||
@include color-mode(dark) {
|
||||
.accordion-button::after {
|
||||
--#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon-dark)};
|
||||
--#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon-dark)};
|
||||
}
|
||||
}
|
||||
}
|
||||
68
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_alert.scss
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// Base styles
|
||||
//
|
||||
|
||||
.alert {
|
||||
// scss-docs-start alert-css-vars
|
||||
--#{$prefix}alert-bg: transparent;
|
||||
--#{$prefix}alert-padding-x: #{$alert-padding-x};
|
||||
--#{$prefix}alert-padding-y: #{$alert-padding-y};
|
||||
--#{$prefix}alert-margin-bottom: #{$alert-margin-bottom};
|
||||
--#{$prefix}alert-color: inherit;
|
||||
--#{$prefix}alert-border-color: transparent;
|
||||
--#{$prefix}alert-border: #{$alert-border-width} solid var(--#{$prefix}alert-border-color);
|
||||
--#{$prefix}alert-border-radius: #{$alert-border-radius};
|
||||
--#{$prefix}alert-link-color: inherit;
|
||||
// scss-docs-end alert-css-vars
|
||||
|
||||
position: relative;
|
||||
padding: var(--#{$prefix}alert-padding-y) var(--#{$prefix}alert-padding-x);
|
||||
margin-bottom: var(--#{$prefix}alert-margin-bottom);
|
||||
color: var(--#{$prefix}alert-color);
|
||||
background-color: var(--#{$prefix}alert-bg);
|
||||
border: var(--#{$prefix}alert-border);
|
||||
@include border-radius(var(--#{$prefix}alert-border-radius));
|
||||
}
|
||||
|
||||
// Headings for larger alerts
|
||||
.alert-heading {
|
||||
// Specified to prevent conflicts of changing $headings-color
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
// Provide class for links that match alerts
|
||||
.alert-link {
|
||||
font-weight: $alert-link-font-weight;
|
||||
color: var(--#{$prefix}alert-link-color);
|
||||
}
|
||||
|
||||
|
||||
// Dismissible alerts
|
||||
//
|
||||
// Expand the right padding and account for the close button's positioning.
|
||||
|
||||
.alert-dismissible {
|
||||
padding-right: $alert-dismissible-padding-r;
|
||||
|
||||
// Adjust close link position
|
||||
.btn-close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: $stretched-link-z-index + 1;
|
||||
padding: $alert-padding-y * 1.25 $alert-padding-x;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// scss-docs-start alert-modifiers
|
||||
// Generate contextual modifier classes for colorizing the alert
|
||||
@each $state in map-keys($theme-colors) {
|
||||
.alert-#{$state} {
|
||||
--#{$prefix}alert-color: var(--#{$prefix}#{$state}-text-emphasis);
|
||||
--#{$prefix}alert-bg: var(--#{$prefix}#{$state}-bg-subtle);
|
||||
--#{$prefix}alert-border-color: var(--#{$prefix}#{$state}-border-subtle);
|
||||
--#{$prefix}alert-link-color: var(--#{$prefix}#{$state}-text-emphasis);
|
||||
}
|
||||
}
|
||||
// scss-docs-end alert-modifiers
|
||||
38
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_badge.scss
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
// Base class
|
||||
//
|
||||
// Requires one of the contextual, color modifier classes for `color` and
|
||||
// `background-color`.
|
||||
|
||||
.badge {
|
||||
// scss-docs-start badge-css-vars
|
||||
--#{$prefix}badge-padding-x: #{$badge-padding-x};
|
||||
--#{$prefix}badge-padding-y: #{$badge-padding-y};
|
||||
@include rfs($badge-font-size, --#{$prefix}badge-font-size);
|
||||
--#{$prefix}badge-font-weight: #{$badge-font-weight};
|
||||
--#{$prefix}badge-color: #{$badge-color};
|
||||
--#{$prefix}badge-border-radius: #{$badge-border-radius};
|
||||
// scss-docs-end badge-css-vars
|
||||
|
||||
display: inline-block;
|
||||
padding: var(--#{$prefix}badge-padding-y) var(--#{$prefix}badge-padding-x);
|
||||
@include font-size(var(--#{$prefix}badge-font-size));
|
||||
font-weight: var(--#{$prefix}badge-font-weight);
|
||||
line-height: 1;
|
||||
color: var(--#{$prefix}badge-color);
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: baseline;
|
||||
@include border-radius(var(--#{$prefix}badge-border-radius));
|
||||
@include gradient-bg();
|
||||
|
||||
// Empty badges collapse automatically
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Quick fix for badges in buttons
|
||||
.btn .badge {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
||||
40
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_breadcrumb.scss
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
.breadcrumb {
|
||||
// scss-docs-start breadcrumb-css-vars
|
||||
--#{$prefix}breadcrumb-padding-x: #{$breadcrumb-padding-x};
|
||||
--#{$prefix}breadcrumb-padding-y: #{$breadcrumb-padding-y};
|
||||
--#{$prefix}breadcrumb-margin-bottom: #{$breadcrumb-margin-bottom};
|
||||
@include rfs($breadcrumb-font-size, --#{$prefix}breadcrumb-font-size);
|
||||
--#{$prefix}breadcrumb-bg: #{$breadcrumb-bg};
|
||||
--#{$prefix}breadcrumb-border-radius: #{$breadcrumb-border-radius};
|
||||
--#{$prefix}breadcrumb-divider-color: #{$breadcrumb-divider-color};
|
||||
--#{$prefix}breadcrumb-item-padding-x: #{$breadcrumb-item-padding-x};
|
||||
--#{$prefix}breadcrumb-item-active-color: #{$breadcrumb-active-color};
|
||||
// scss-docs-end breadcrumb-css-vars
|
||||
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: var(--#{$prefix}breadcrumb-padding-y) var(--#{$prefix}breadcrumb-padding-x);
|
||||
margin-bottom: var(--#{$prefix}breadcrumb-margin-bottom);
|
||||
@include font-size(var(--#{$prefix}breadcrumb-font-size));
|
||||
list-style: none;
|
||||
background-color: var(--#{$prefix}breadcrumb-bg);
|
||||
@include border-radius(var(--#{$prefix}breadcrumb-border-radius));
|
||||
}
|
||||
|
||||
.breadcrumb-item {
|
||||
// The separator between breadcrumbs (by default, a forward-slash: "/")
|
||||
+ .breadcrumb-item {
|
||||
padding-left: var(--#{$prefix}breadcrumb-item-padding-x);
|
||||
|
||||
&::before {
|
||||
float: left; // Suppress inline spacings and underlining of the separator
|
||||
padding-right: var(--#{$prefix}breadcrumb-item-padding-x);
|
||||
color: var(--#{$prefix}breadcrumb-divider-color);
|
||||
content: var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)) #{"/* rtl:"} var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped)) #{"*/"};
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: var(--#{$prefix}breadcrumb-item-active-color);
|
||||
}
|
||||
}
|
||||
147
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_button-group.scss
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
// Make the div behave like a button
|
||||
.btn-group,
|
||||
.btn-group-vertical {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
vertical-align: middle; // match .btn alignment given font-size hack above
|
||||
|
||||
> .btn {
|
||||
position: relative;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
// Bring the hover, focused, and "active" buttons to the front to overlay
|
||||
// the borders properly
|
||||
> .btn-check:checked + .btn,
|
||||
> .btn-check:focus + .btn,
|
||||
> .btn:hover,
|
||||
> .btn:focus,
|
||||
> .btn:active,
|
||||
> .btn.active {
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Optional: Group multiple button groups together for a toolbar
|
||||
.btn-toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
|
||||
.input-group {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
@include border-radius($btn-border-radius);
|
||||
|
||||
// Prevent double borders when buttons are next to each other
|
||||
> :not(.btn-check:first-child) + .btn,
|
||||
> .btn-group:not(:first-child) {
|
||||
margin-left: calc(-1 * #{$btn-border-width}); // stylelint-disable-line function-disallowed-list
|
||||
}
|
||||
|
||||
// Reset rounded corners
|
||||
> .btn:not(:last-child):not(.dropdown-toggle),
|
||||
> .btn.dropdown-toggle-split:first-child,
|
||||
> .btn-group:not(:last-child) > .btn {
|
||||
@include border-end-radius(0);
|
||||
}
|
||||
|
||||
// The left radius should be 0 if the button is:
|
||||
// - the "third or more" child
|
||||
// - the second child and the previous element isn't `.btn-check` (making it the first child visually)
|
||||
// - part of a btn-group which isn't the first child
|
||||
> .btn:nth-child(n + 3),
|
||||
> :not(.btn-check) + .btn,
|
||||
> .btn-group:not(:first-child) > .btn {
|
||||
@include border-start-radius(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Sizing
|
||||
//
|
||||
// Remix the default button sizing classes into new ones for easier manipulation.
|
||||
|
||||
.btn-group-sm > .btn { @extend .btn-sm; }
|
||||
.btn-group-lg > .btn { @extend .btn-lg; }
|
||||
|
||||
|
||||
//
|
||||
// Split button dropdowns
|
||||
//
|
||||
|
||||
.dropdown-toggle-split {
|
||||
padding-right: $btn-padding-x * .75;
|
||||
padding-left: $btn-padding-x * .75;
|
||||
|
||||
&::after,
|
||||
.dropup &::after,
|
||||
.dropend &::after {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.dropstart &::before {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-sm + .dropdown-toggle-split {
|
||||
padding-right: $btn-padding-x-sm * .75;
|
||||
padding-left: $btn-padding-x-sm * .75;
|
||||
}
|
||||
|
||||
.btn-lg + .dropdown-toggle-split {
|
||||
padding-right: $btn-padding-x-lg * .75;
|
||||
padding-left: $btn-padding-x-lg * .75;
|
||||
}
|
||||
|
||||
|
||||
// The clickable button for toggling the menu
|
||||
// Set the same inset shadow as the :active state
|
||||
.btn-group.show .dropdown-toggle {
|
||||
@include box-shadow($btn-active-box-shadow);
|
||||
|
||||
// Show no shadow for `.btn-link` since it has no other button styles.
|
||||
&.btn-link {
|
||||
@include box-shadow(none);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Vertical button groups
|
||||
//
|
||||
|
||||
.btn-group-vertical {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
|
||||
> .btn,
|
||||
> .btn-group {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
> .btn:not(:first-child),
|
||||
> .btn-group:not(:first-child) {
|
||||
margin-top: calc(-1 * #{$btn-border-width}); // stylelint-disable-line function-disallowed-list
|
||||
}
|
||||
|
||||
// Reset rounded corners
|
||||
> .btn:not(:last-child):not(.dropdown-toggle),
|
||||
> .btn-group:not(:last-child) > .btn {
|
||||
@include border-bottom-radius(0);
|
||||
}
|
||||
|
||||
// The top radius should be 0 if the button is:
|
||||
// - the "third or more" child
|
||||
// - the second child and the previous element isn't `.btn-check` (making it the first child visually)
|
||||
// - part of a btn-group which isn't the first child
|
||||
> .btn:nth-child(n + 3),
|
||||
> :not(.btn-check) + .btn,
|
||||
> .btn-group:not(:first-child) > .btn {
|
||||
@include border-top-radius(0);
|
||||
}
|
||||
}
|
||||
216
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_buttons.scss
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
//
|
||||
// Base styles
|
||||
//
|
||||
|
||||
.btn {
|
||||
// scss-docs-start btn-css-vars
|
||||
--#{$prefix}btn-padding-x: #{$btn-padding-x};
|
||||
--#{$prefix}btn-padding-y: #{$btn-padding-y};
|
||||
--#{$prefix}btn-font-family: #{$btn-font-family};
|
||||
@include rfs($btn-font-size, --#{$prefix}btn-font-size);
|
||||
--#{$prefix}btn-font-weight: #{$btn-font-weight};
|
||||
--#{$prefix}btn-line-height: #{$btn-line-height};
|
||||
--#{$prefix}btn-color: #{$btn-color};
|
||||
--#{$prefix}btn-bg: transparent;
|
||||
--#{$prefix}btn-border-width: #{$btn-border-width};
|
||||
--#{$prefix}btn-border-color: transparent;
|
||||
--#{$prefix}btn-border-radius: #{$btn-border-radius};
|
||||
--#{$prefix}btn-hover-border-color: transparent;
|
||||
--#{$prefix}btn-box-shadow: #{$btn-box-shadow};
|
||||
--#{$prefix}btn-disabled-opacity: #{$btn-disabled-opacity};
|
||||
--#{$prefix}btn-focus-box-shadow: 0 0 0 #{$btn-focus-width} rgba(var(--#{$prefix}btn-focus-shadow-rgb), .5);
|
||||
// scss-docs-end btn-css-vars
|
||||
|
||||
display: inline-block;
|
||||
padding: var(--#{$prefix}btn-padding-y) var(--#{$prefix}btn-padding-x);
|
||||
font-family: var(--#{$prefix}btn-font-family);
|
||||
@include font-size(var(--#{$prefix}btn-font-size));
|
||||
font-weight: var(--#{$prefix}btn-font-weight);
|
||||
line-height: var(--#{$prefix}btn-line-height);
|
||||
color: var(--#{$prefix}btn-color);
|
||||
text-align: center;
|
||||
text-decoration: if($link-decoration == none, null, none);
|
||||
white-space: $btn-white-space;
|
||||
vertical-align: middle;
|
||||
cursor: if($enable-button-pointers, pointer, null);
|
||||
user-select: none;
|
||||
border: var(--#{$prefix}btn-border-width) solid var(--#{$prefix}btn-border-color);
|
||||
@include border-radius(var(--#{$prefix}btn-border-radius));
|
||||
@include gradient-bg(var(--#{$prefix}btn-bg));
|
||||
@include box-shadow(var(--#{$prefix}btn-box-shadow));
|
||||
@include transition($btn-transition);
|
||||
|
||||
&:hover {
|
||||
color: var(--#{$prefix}btn-hover-color);
|
||||
text-decoration: if($link-hover-decoration == underline, none, null);
|
||||
background-color: var(--#{$prefix}btn-hover-bg);
|
||||
border-color: var(--#{$prefix}btn-hover-border-color);
|
||||
}
|
||||
|
||||
.btn-check + &:hover {
|
||||
// override for the checkbox/radio buttons
|
||||
color: var(--#{$prefix}btn-color);
|
||||
background-color: var(--#{$prefix}btn-bg);
|
||||
border-color: var(--#{$prefix}btn-border-color);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
color: var(--#{$prefix}btn-hover-color);
|
||||
@include gradient-bg(var(--#{$prefix}btn-hover-bg));
|
||||
border-color: var(--#{$prefix}btn-hover-border-color);
|
||||
outline: 0;
|
||||
// Avoid using mixin so we can pass custom focus shadow properly
|
||||
@if $enable-shadows {
|
||||
box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow);
|
||||
} @else {
|
||||
box-shadow: var(--#{$prefix}btn-focus-box-shadow);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-check:focus-visible + & {
|
||||
border-color: var(--#{$prefix}btn-hover-border-color);
|
||||
outline: 0;
|
||||
// Avoid using mixin so we can pass custom focus shadow properly
|
||||
@if $enable-shadows {
|
||||
box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow);
|
||||
} @else {
|
||||
box-shadow: var(--#{$prefix}btn-focus-box-shadow);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-check:checked + &,
|
||||
:not(.btn-check) + &:active,
|
||||
&:first-child:active,
|
||||
&.active,
|
||||
&.show {
|
||||
color: var(--#{$prefix}btn-active-color);
|
||||
background-color: var(--#{$prefix}btn-active-bg);
|
||||
// Remove CSS gradients if they're enabled
|
||||
background-image: if($enable-gradients, none, null);
|
||||
border-color: var(--#{$prefix}btn-active-border-color);
|
||||
@include box-shadow(var(--#{$prefix}btn-active-shadow));
|
||||
|
||||
&:focus-visible {
|
||||
// Avoid using mixin so we can pass custom focus shadow properly
|
||||
@if $enable-shadows {
|
||||
box-shadow: var(--#{$prefix}btn-active-shadow), var(--#{$prefix}btn-focus-box-shadow);
|
||||
} @else {
|
||||
box-shadow: var(--#{$prefix}btn-focus-box-shadow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-check:checked:focus-visible + & {
|
||||
// Avoid using mixin so we can pass custom focus shadow properly
|
||||
@if $enable-shadows {
|
||||
box-shadow: var(--#{$prefix}btn-active-shadow), var(--#{$prefix}btn-focus-box-shadow);
|
||||
} @else {
|
||||
box-shadow: var(--#{$prefix}btn-focus-box-shadow);
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled,
|
||||
&.disabled,
|
||||
fieldset:disabled & {
|
||||
color: var(--#{$prefix}btn-disabled-color);
|
||||
pointer-events: none;
|
||||
background-color: var(--#{$prefix}btn-disabled-bg);
|
||||
background-image: if($enable-gradients, none, null);
|
||||
border-color: var(--#{$prefix}btn-disabled-border-color);
|
||||
opacity: var(--#{$prefix}btn-disabled-opacity);
|
||||
@include box-shadow(none);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Alternate buttons
|
||||
//
|
||||
|
||||
// scss-docs-start btn-variant-loops
|
||||
@each $color, $value in $theme-colors {
|
||||
.btn-#{$color} {
|
||||
@if $color == "light" {
|
||||
@include button-variant(
|
||||
$value,
|
||||
$value,
|
||||
$hover-background: shade-color($value, $btn-hover-bg-shade-amount),
|
||||
$hover-border: shade-color($value, $btn-hover-border-shade-amount),
|
||||
$active-background: shade-color($value, $btn-active-bg-shade-amount),
|
||||
$active-border: shade-color($value, $btn-active-border-shade-amount)
|
||||
);
|
||||
} @else if $color == "dark" {
|
||||
@include button-variant(
|
||||
$value,
|
||||
$value,
|
||||
$hover-background: tint-color($value, $btn-hover-bg-tint-amount),
|
||||
$hover-border: tint-color($value, $btn-hover-border-tint-amount),
|
||||
$active-background: tint-color($value, $btn-active-bg-tint-amount),
|
||||
$active-border: tint-color($value, $btn-active-border-tint-amount)
|
||||
);
|
||||
} @else {
|
||||
@include button-variant($value, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@each $color, $value in $theme-colors {
|
||||
.btn-outline-#{$color} {
|
||||
@include button-outline-variant($value);
|
||||
}
|
||||
}
|
||||
// scss-docs-end btn-variant-loops
|
||||
|
||||
|
||||
//
|
||||
// Link buttons
|
||||
//
|
||||
|
||||
// Make a button look and behave like a link
|
||||
.btn-link {
|
||||
--#{$prefix}btn-font-weight: #{$font-weight-normal};
|
||||
--#{$prefix}btn-color: #{$btn-link-color};
|
||||
--#{$prefix}btn-bg: transparent;
|
||||
--#{$prefix}btn-border-color: transparent;
|
||||
--#{$prefix}btn-hover-color: #{$btn-link-hover-color};
|
||||
--#{$prefix}btn-hover-border-color: transparent;
|
||||
--#{$prefix}btn-active-color: #{$btn-link-hover-color};
|
||||
--#{$prefix}btn-active-border-color: transparent;
|
||||
--#{$prefix}btn-disabled-color: #{$btn-link-disabled-color};
|
||||
--#{$prefix}btn-disabled-border-color: transparent;
|
||||
--#{$prefix}btn-box-shadow: 0 0 0 #000; // Can't use `none` as keyword negates all values when used with multiple shadows
|
||||
--#{$prefix}btn-focus-shadow-rgb: #{$btn-link-focus-shadow-rgb};
|
||||
|
||||
text-decoration: $link-decoration;
|
||||
@if $enable-gradients {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
text-decoration: $link-hover-decoration;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
color: var(--#{$prefix}btn-color);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--#{$prefix}btn-hover-color);
|
||||
}
|
||||
|
||||
// No need for an active state here
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Button Sizes
|
||||
//
|
||||
|
||||
.btn-lg {
|
||||
@include button-size($btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-border-radius-lg);
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
@include button-size($btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-border-radius-sm);
|
||||
}
|
||||
238
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_card.scss
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
//
|
||||
// Base styles
|
||||
//
|
||||
|
||||
.card {
|
||||
// scss-docs-start card-css-vars
|
||||
--#{$prefix}card-spacer-y: #{$card-spacer-y};
|
||||
--#{$prefix}card-spacer-x: #{$card-spacer-x};
|
||||
--#{$prefix}card-title-spacer-y: #{$card-title-spacer-y};
|
||||
--#{$prefix}card-title-color: #{$card-title-color};
|
||||
--#{$prefix}card-subtitle-color: #{$card-subtitle-color};
|
||||
--#{$prefix}card-border-width: #{$card-border-width};
|
||||
--#{$prefix}card-border-color: #{$card-border-color};
|
||||
--#{$prefix}card-border-radius: #{$card-border-radius};
|
||||
--#{$prefix}card-box-shadow: #{$card-box-shadow};
|
||||
--#{$prefix}card-inner-border-radius: #{$card-inner-border-radius};
|
||||
--#{$prefix}card-cap-padding-y: #{$card-cap-padding-y};
|
||||
--#{$prefix}card-cap-padding-x: #{$card-cap-padding-x};
|
||||
--#{$prefix}card-cap-bg: #{$card-cap-bg};
|
||||
--#{$prefix}card-cap-color: #{$card-cap-color};
|
||||
--#{$prefix}card-height: #{$card-height};
|
||||
--#{$prefix}card-color: #{$card-color};
|
||||
--#{$prefix}card-bg: #{$card-bg};
|
||||
--#{$prefix}card-img-overlay-padding: #{$card-img-overlay-padding};
|
||||
--#{$prefix}card-group-margin: #{$card-group-margin};
|
||||
// scss-docs-end card-css-vars
|
||||
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106
|
||||
height: var(--#{$prefix}card-height);
|
||||
color: var(--#{$prefix}body-color);
|
||||
word-wrap: break-word;
|
||||
background-color: var(--#{$prefix}card-bg);
|
||||
background-clip: border-box;
|
||||
border: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color);
|
||||
@include border-radius(var(--#{$prefix}card-border-radius));
|
||||
@include box-shadow(var(--#{$prefix}card-box-shadow));
|
||||
|
||||
> hr {
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
> .list-group {
|
||||
border-top: inherit;
|
||||
border-bottom: inherit;
|
||||
|
||||
&:first-child {
|
||||
border-top-width: 0;
|
||||
@include border-top-radius(var(--#{$prefix}card-inner-border-radius));
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom-width: 0;
|
||||
@include border-bottom-radius(var(--#{$prefix}card-inner-border-radius));
|
||||
}
|
||||
}
|
||||
|
||||
// Due to specificity of the above selector (`.card > .list-group`), we must
|
||||
// use a child selector here to prevent double borders.
|
||||
> .card-header + .list-group,
|
||||
> .list-group + .card-footer {
|
||||
border-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card-body {
|
||||
// Enable `flex-grow: 1` for decks and groups so that card blocks take up
|
||||
// as much space as possible, ensuring footers are aligned to the bottom.
|
||||
flex: 1 1 auto;
|
||||
padding: var(--#{$prefix}card-spacer-y) var(--#{$prefix}card-spacer-x);
|
||||
color: var(--#{$prefix}card-color);
|
||||
}
|
||||
|
||||
.card-title {
|
||||
margin-bottom: var(--#{$prefix}card-title-spacer-y);
|
||||
color: var(--#{$prefix}card-title-color);
|
||||
}
|
||||
|
||||
.card-subtitle {
|
||||
margin-top: calc(-.5 * var(--#{$prefix}card-title-spacer-y)); // stylelint-disable-line function-disallowed-list
|
||||
margin-bottom: 0;
|
||||
color: var(--#{$prefix}card-subtitle-color);
|
||||
}
|
||||
|
||||
.card-text:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.card-link {
|
||||
&:hover {
|
||||
text-decoration: if($link-hover-decoration == underline, none, null);
|
||||
}
|
||||
|
||||
+ .card-link {
|
||||
margin-left: var(--#{$prefix}card-spacer-x);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Optional textual caps
|
||||
//
|
||||
|
||||
.card-header {
|
||||
padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x);
|
||||
margin-bottom: 0; // Removes the default margin-bottom of <hN>
|
||||
color: var(--#{$prefix}card-cap-color);
|
||||
background-color: var(--#{$prefix}card-cap-bg);
|
||||
border-bottom: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color);
|
||||
|
||||
&:first-child {
|
||||
@include border-radius(var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius) 0 0);
|
||||
}
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x);
|
||||
color: var(--#{$prefix}card-cap-color);
|
||||
background-color: var(--#{$prefix}card-cap-bg);
|
||||
border-top: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color);
|
||||
|
||||
&:last-child {
|
||||
@include border-radius(0 0 var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Header navs
|
||||
//
|
||||
|
||||
.card-header-tabs {
|
||||
margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
|
||||
margin-bottom: calc(-1 * var(--#{$prefix}card-cap-padding-y)); // stylelint-disable-line function-disallowed-list
|
||||
margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
|
||||
border-bottom: 0;
|
||||
|
||||
.nav-link.active {
|
||||
background-color: var(--#{$prefix}card-bg);
|
||||
border-bottom-color: var(--#{$prefix}card-bg);
|
||||
}
|
||||
}
|
||||
|
||||
.card-header-pills {
|
||||
margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
|
||||
margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
|
||||
}
|
||||
|
||||
// Card image
|
||||
.card-img-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
padding: var(--#{$prefix}card-img-overlay-padding);
|
||||
@include border-radius(var(--#{$prefix}card-inner-border-radius));
|
||||
}
|
||||
|
||||
.card-img,
|
||||
.card-img-top,
|
||||
.card-img-bottom {
|
||||
width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
|
||||
}
|
||||
|
||||
.card-img,
|
||||
.card-img-top {
|
||||
@include border-top-radius(var(--#{$prefix}card-inner-border-radius));
|
||||
}
|
||||
|
||||
.card-img,
|
||||
.card-img-bottom {
|
||||
@include border-bottom-radius(var(--#{$prefix}card-inner-border-radius));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Card groups
|
||||
//
|
||||
|
||||
.card-group {
|
||||
// The child selector allows nested `.card` within `.card-group`
|
||||
// to display properly.
|
||||
> .card {
|
||||
margin-bottom: var(--#{$prefix}card-group-margin);
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
// The child selector allows nested `.card` within `.card-group`
|
||||
// to display properly.
|
||||
> .card {
|
||||
flex: 1 0 0;
|
||||
margin-bottom: 0;
|
||||
|
||||
+ .card {
|
||||
margin-left: 0;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
// Handle rounded corners
|
||||
@if $enable-rounded {
|
||||
&:not(:last-child) {
|
||||
@include border-end-radius(0);
|
||||
|
||||
> .card-img-top,
|
||||
> .card-header {
|
||||
// stylelint-disable-next-line property-disallowed-list
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
> .card-img-bottom,
|
||||
> .card-footer {
|
||||
// stylelint-disable-next-line property-disallowed-list
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
@include border-start-radius(0);
|
||||
|
||||
> .card-img-top,
|
||||
> .card-header {
|
||||
// stylelint-disable-next-line property-disallowed-list
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
> .card-img-bottom,
|
||||
> .card-footer {
|
||||
// stylelint-disable-next-line property-disallowed-list
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
226
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_carousel.scss
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
// Notes on the classes:
|
||||
//
|
||||
// 1. .carousel.pointer-event should ideally be pan-y (to allow for users to scroll vertically)
|
||||
// even when their scroll action started on a carousel, but for compatibility (with Firefox)
|
||||
// we're preventing all actions instead
|
||||
// 2. The .carousel-item-start and .carousel-item-end is used to indicate where
|
||||
// the active slide is heading.
|
||||
// 3. .active.carousel-item is the current slide.
|
||||
// 4. .active.carousel-item-start and .active.carousel-item-end is the current
|
||||
// slide in its in-transition state. Only one of these occurs at a time.
|
||||
// 5. .carousel-item-next.carousel-item-start and .carousel-item-prev.carousel-item-end
|
||||
// is the upcoming slide in transition.
|
||||
|
||||
.carousel {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.carousel.pointer-event {
|
||||
touch-action: pan-y;
|
||||
}
|
||||
|
||||
.carousel-inner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
@include clearfix();
|
||||
}
|
||||
|
||||
.carousel-item {
|
||||
position: relative;
|
||||
display: none;
|
||||
float: left;
|
||||
width: 100%;
|
||||
margin-right: -100%;
|
||||
backface-visibility: hidden;
|
||||
@include transition($carousel-transition);
|
||||
}
|
||||
|
||||
.carousel-item.active,
|
||||
.carousel-item-next,
|
||||
.carousel-item-prev {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.carousel-item-next:not(.carousel-item-start),
|
||||
.active.carousel-item-end {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.carousel-item-prev:not(.carousel-item-end),
|
||||
.active.carousel-item-start {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Alternate transitions
|
||||
//
|
||||
|
||||
.carousel-fade {
|
||||
.carousel-item {
|
||||
opacity: 0;
|
||||
transition-property: opacity;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.carousel-item.active,
|
||||
.carousel-item-next.carousel-item-start,
|
||||
.carousel-item-prev.carousel-item-end {
|
||||
z-index: 1;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.active.carousel-item-start,
|
||||
.active.carousel-item-end {
|
||||
z-index: 0;
|
||||
opacity: 0;
|
||||
@include transition(opacity 0s $carousel-transition-duration);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Left/right controls for nav
|
||||
//
|
||||
|
||||
.carousel-control-prev,
|
||||
.carousel-control-next {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
// Use flex for alignment (1-3)
|
||||
display: flex; // 1. allow flex styles
|
||||
align-items: center; // 2. vertically center contents
|
||||
justify-content: center; // 3. horizontally center contents
|
||||
width: $carousel-control-width;
|
||||
padding: 0;
|
||||
color: $carousel-control-color;
|
||||
text-align: center;
|
||||
background: none;
|
||||
filter: var(--#{$prefix}carousel-control-icon-filter);
|
||||
border: 0;
|
||||
opacity: $carousel-control-opacity;
|
||||
@include transition($carousel-control-transition);
|
||||
|
||||
// Hover/focus state
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $carousel-control-color;
|
||||
text-decoration: none;
|
||||
outline: 0;
|
||||
opacity: $carousel-control-hover-opacity;
|
||||
}
|
||||
}
|
||||
.carousel-control-prev {
|
||||
left: 0;
|
||||
background-image: if($enable-gradients, linear-gradient(90deg, rgba($black, .25), rgba($black, .001)), null);
|
||||
}
|
||||
.carousel-control-next {
|
||||
right: 0;
|
||||
background-image: if($enable-gradients, linear-gradient(270deg, rgba($black, .25), rgba($black, .001)), null);
|
||||
}
|
||||
|
||||
// Icons for within
|
||||
.carousel-control-prev-icon,
|
||||
.carousel-control-next-icon {
|
||||
display: inline-block;
|
||||
width: $carousel-control-icon-width;
|
||||
height: $carousel-control-icon-width;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50%;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.carousel-control-prev-icon {
|
||||
background-image: escape-svg($carousel-control-prev-icon-bg) #{"/*rtl:" + escape-svg($carousel-control-next-icon-bg) + "*/"};
|
||||
}
|
||||
.carousel-control-next-icon {
|
||||
background-image: escape-svg($carousel-control-next-icon-bg) #{"/*rtl:" + escape-svg($carousel-control-prev-icon-bg) + "*/"};
|
||||
}
|
||||
|
||||
// Optional indicator pips/controls
|
||||
//
|
||||
// Add a container (such as a list) with the following class and add an item (ideally a focusable control,
|
||||
// like a button) with data-bs-target for each slide your carousel holds.
|
||||
|
||||
.carousel-indicators {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
// Use the .carousel-control's width as margin so we don't overlay those
|
||||
margin-right: $carousel-control-width;
|
||||
margin-bottom: 1rem;
|
||||
margin-left: $carousel-control-width;
|
||||
|
||||
[data-bs-target] {
|
||||
box-sizing: content-box;
|
||||
flex: 0 1 auto;
|
||||
width: $carousel-indicator-width;
|
||||
height: $carousel-indicator-height;
|
||||
padding: 0;
|
||||
margin-right: $carousel-indicator-spacer;
|
||||
margin-left: $carousel-indicator-spacer;
|
||||
text-indent: -999px;
|
||||
cursor: pointer;
|
||||
background-color: var(--#{$prefix}carousel-indicator-active-bg);
|
||||
background-clip: padding-box;
|
||||
border: 0;
|
||||
// Use transparent borders to increase the hit area by 10px on top and bottom.
|
||||
border-top: $carousel-indicator-hit-area-height solid transparent;
|
||||
border-bottom: $carousel-indicator-hit-area-height solid transparent;
|
||||
opacity: $carousel-indicator-opacity;
|
||||
@include transition($carousel-indicator-transition);
|
||||
}
|
||||
|
||||
.active {
|
||||
opacity: $carousel-indicator-active-opacity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Optional captions
|
||||
//
|
||||
//
|
||||
|
||||
.carousel-caption {
|
||||
position: absolute;
|
||||
right: (100% - $carousel-caption-width) * .5;
|
||||
bottom: $carousel-caption-spacer;
|
||||
left: (100% - $carousel-caption-width) * .5;
|
||||
padding-top: $carousel-caption-padding-y;
|
||||
padding-bottom: $carousel-caption-padding-y;
|
||||
color: var(--#{$prefix}carousel-caption-color);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
// Dark mode carousel
|
||||
|
||||
@mixin carousel-dark() {
|
||||
--#{$prefix}carousel-indicator-active-bg: #{$carousel-indicator-active-bg-dark};
|
||||
--#{$prefix}carousel-caption-color: #{$carousel-caption-color-dark};
|
||||
--#{$prefix}carousel-control-icon-filter: #{$carousel-control-icon-filter-dark};
|
||||
}
|
||||
|
||||
.carousel-dark {
|
||||
@include carousel-dark();
|
||||
}
|
||||
|
||||
:root,
|
||||
[data-bs-theme="light"] {
|
||||
--#{$prefix}carousel-indicator-active-bg: #{$carousel-indicator-active-bg};
|
||||
--#{$prefix}carousel-caption-color: #{$carousel-caption-color};
|
||||
--#{$prefix}carousel-control-icon-filter: #{$carousel-control-icon-filter};
|
||||
}
|
||||
|
||||
@if $enable-dark-mode {
|
||||
@include color-mode(dark, true) {
|
||||
@include carousel-dark();
|
||||
}
|
||||
}
|
||||
66
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_close.scss
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// Transparent background and border properties included for button version.
|
||||
// iOS requires the button element instead of an anchor tag.
|
||||
// If you want the anchor version, it requires `href="#"`.
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
|
||||
|
||||
.btn-close {
|
||||
// scss-docs-start close-css-vars
|
||||
--#{$prefix}btn-close-color: #{$btn-close-color};
|
||||
--#{$prefix}btn-close-bg: #{ escape-svg($btn-close-bg) };
|
||||
--#{$prefix}btn-close-opacity: #{$btn-close-opacity};
|
||||
--#{$prefix}btn-close-hover-opacity: #{$btn-close-hover-opacity};
|
||||
--#{$prefix}btn-close-focus-shadow: #{$btn-close-focus-shadow};
|
||||
--#{$prefix}btn-close-focus-opacity: #{$btn-close-focus-opacity};
|
||||
--#{$prefix}btn-close-disabled-opacity: #{$btn-close-disabled-opacity};
|
||||
// scss-docs-end close-css-vars
|
||||
|
||||
box-sizing: content-box;
|
||||
width: $btn-close-width;
|
||||
height: $btn-close-height;
|
||||
padding: $btn-close-padding-y $btn-close-padding-x;
|
||||
color: var(--#{$prefix}btn-close-color);
|
||||
background: transparent var(--#{$prefix}btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements
|
||||
filter: var(--#{$prefix}btn-close-filter);
|
||||
border: 0; // for button elements
|
||||
@include border-radius();
|
||||
opacity: var(--#{$prefix}btn-close-opacity);
|
||||
|
||||
// Override <a>'s hover style
|
||||
&:hover {
|
||||
color: var(--#{$prefix}btn-close-color);
|
||||
text-decoration: none;
|
||||
opacity: var(--#{$prefix}btn-close-hover-opacity);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: 0;
|
||||
box-shadow: var(--#{$prefix}btn-close-focus-shadow);
|
||||
opacity: var(--#{$prefix}btn-close-focus-opacity);
|
||||
}
|
||||
|
||||
&:disabled,
|
||||
&.disabled {
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
opacity: var(--#{$prefix}btn-close-disabled-opacity);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin btn-close-white() {
|
||||
--#{$prefix}btn-close-filter: #{$btn-close-filter-dark};
|
||||
}
|
||||
|
||||
.btn-close-white {
|
||||
@include btn-close-white();
|
||||
}
|
||||
|
||||
:root,
|
||||
[data-bs-theme="light"] {
|
||||
--#{$prefix}btn-close-filter: #{$btn-close-filter};
|
||||
}
|
||||
|
||||
@if $enable-dark-mode {
|
||||
@include color-mode(dark, true) {
|
||||
@include btn-close-white();
|
||||
}
|
||||
}
|
||||
41
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_containers.scss
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
// Container widths
|
||||
//
|
||||
// Set the container width, and override it for fixed navbars in media queries.
|
||||
|
||||
@if $enable-container-classes {
|
||||
// Single container class with breakpoint max-widths
|
||||
.container,
|
||||
// 100% wide container at all breakpoints
|
||||
.container-fluid {
|
||||
@include make-container();
|
||||
}
|
||||
|
||||
// Responsive containers that are 100% wide until a breakpoint
|
||||
@each $breakpoint, $container-max-width in $container-max-widths {
|
||||
.container-#{$breakpoint} {
|
||||
@extend .container-fluid;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up($breakpoint, $grid-breakpoints) {
|
||||
%responsive-container-#{$breakpoint} {
|
||||
max-width: $container-max-width;
|
||||
}
|
||||
|
||||
// Extend each breakpoint which is smaller or equal to the current breakpoint
|
||||
$extend-breakpoint: true;
|
||||
|
||||
@each $name, $width in $grid-breakpoints {
|
||||
@if ($extend-breakpoint) {
|
||||
.container#{breakpoint-infix($name, $grid-breakpoints)} {
|
||||
@extend %responsive-container-#{$breakpoint};
|
||||
}
|
||||
|
||||
// Once the current breakpoint is reached, stop extending
|
||||
@if ($breakpoint == $name) {
|
||||
$extend-breakpoint: false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
250
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_dropdown.scss
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
// The dropdown wrapper (`<div>`)
|
||||
.dropup,
|
||||
.dropend,
|
||||
.dropdown,
|
||||
.dropstart,
|
||||
.dropup-center,
|
||||
.dropdown-center {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dropdown-toggle {
|
||||
white-space: nowrap;
|
||||
|
||||
// Generate the caret automatically
|
||||
@include caret();
|
||||
}
|
||||
|
||||
// The dropdown menu
|
||||
.dropdown-menu {
|
||||
// scss-docs-start dropdown-css-vars
|
||||
--#{$prefix}dropdown-zindex: #{$zindex-dropdown};
|
||||
--#{$prefix}dropdown-min-width: #{$dropdown-min-width};
|
||||
--#{$prefix}dropdown-padding-x: #{$dropdown-padding-x};
|
||||
--#{$prefix}dropdown-padding-y: #{$dropdown-padding-y};
|
||||
--#{$prefix}dropdown-spacer: #{$dropdown-spacer};
|
||||
@include rfs($dropdown-font-size, --#{$prefix}dropdown-font-size);
|
||||
--#{$prefix}dropdown-color: #{$dropdown-color};
|
||||
--#{$prefix}dropdown-bg: #{$dropdown-bg};
|
||||
--#{$prefix}dropdown-border-color: #{$dropdown-border-color};
|
||||
--#{$prefix}dropdown-border-radius: #{$dropdown-border-radius};
|
||||
--#{$prefix}dropdown-border-width: #{$dropdown-border-width};
|
||||
--#{$prefix}dropdown-inner-border-radius: #{$dropdown-inner-border-radius};
|
||||
--#{$prefix}dropdown-divider-bg: #{$dropdown-divider-bg};
|
||||
--#{$prefix}dropdown-divider-margin-y: #{$dropdown-divider-margin-y};
|
||||
--#{$prefix}dropdown-box-shadow: #{$dropdown-box-shadow};
|
||||
--#{$prefix}dropdown-link-color: #{$dropdown-link-color};
|
||||
--#{$prefix}dropdown-link-hover-color: #{$dropdown-link-hover-color};
|
||||
--#{$prefix}dropdown-link-hover-bg: #{$dropdown-link-hover-bg};
|
||||
--#{$prefix}dropdown-link-active-color: #{$dropdown-link-active-color};
|
||||
--#{$prefix}dropdown-link-active-bg: #{$dropdown-link-active-bg};
|
||||
--#{$prefix}dropdown-link-disabled-color: #{$dropdown-link-disabled-color};
|
||||
--#{$prefix}dropdown-item-padding-x: #{$dropdown-item-padding-x};
|
||||
--#{$prefix}dropdown-item-padding-y: #{$dropdown-item-padding-y};
|
||||
--#{$prefix}dropdown-header-color: #{$dropdown-header-color};
|
||||
--#{$prefix}dropdown-header-padding-x: #{$dropdown-header-padding-x};
|
||||
--#{$prefix}dropdown-header-padding-y: #{$dropdown-header-padding-y};
|
||||
// scss-docs-end dropdown-css-vars
|
||||
|
||||
position: absolute;
|
||||
z-index: var(--#{$prefix}dropdown-zindex);
|
||||
display: none; // none by default, but block on "open" of the menu
|
||||
min-width: var(--#{$prefix}dropdown-min-width);
|
||||
padding: var(--#{$prefix}dropdown-padding-y) var(--#{$prefix}dropdown-padding-x);
|
||||
margin: 0; // Override default margin of ul
|
||||
@include font-size(var(--#{$prefix}dropdown-font-size));
|
||||
color: var(--#{$prefix}dropdown-color);
|
||||
text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)
|
||||
list-style: none;
|
||||
background-color: var(--#{$prefix}dropdown-bg);
|
||||
background-clip: padding-box;
|
||||
border: var(--#{$prefix}dropdown-border-width) solid var(--#{$prefix}dropdown-border-color);
|
||||
@include border-radius(var(--#{$prefix}dropdown-border-radius));
|
||||
@include box-shadow(var(--#{$prefix}dropdown-box-shadow));
|
||||
|
||||
&[data-bs-popper] {
|
||||
top: 100%;
|
||||
left: 0;
|
||||
margin-top: var(--#{$prefix}dropdown-spacer);
|
||||
}
|
||||
|
||||
@if $dropdown-padding-y == 0 {
|
||||
> .dropdown-item:first-child,
|
||||
> li:first-child .dropdown-item {
|
||||
@include border-top-radius(var(--#{$prefix}dropdown-inner-border-radius));
|
||||
}
|
||||
> .dropdown-item:last-child,
|
||||
> li:last-child .dropdown-item {
|
||||
@include border-bottom-radius(var(--#{$prefix}dropdown-inner-border-radius));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// scss-docs-start responsive-breakpoints
|
||||
// We deliberately hardcode the `bs-` prefix because we check
|
||||
// this custom property in JS to determine Popper's positioning
|
||||
|
||||
@each $breakpoint in map-keys($grid-breakpoints) {
|
||||
@include media-breakpoint-up($breakpoint) {
|
||||
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
|
||||
|
||||
.dropdown-menu#{$infix}-start {
|
||||
--bs-position: start;
|
||||
|
||||
&[data-bs-popper] {
|
||||
right: auto;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu#{$infix}-end {
|
||||
--bs-position: end;
|
||||
|
||||
&[data-bs-popper] {
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// scss-docs-end responsive-breakpoints
|
||||
|
||||
// Allow for dropdowns to go bottom up (aka, dropup-menu)
|
||||
// Just add .dropup after the standard .dropdown class and you're set.
|
||||
.dropup {
|
||||
.dropdown-menu[data-bs-popper] {
|
||||
top: auto;
|
||||
bottom: 100%;
|
||||
margin-top: 0;
|
||||
margin-bottom: var(--#{$prefix}dropdown-spacer);
|
||||
}
|
||||
|
||||
.dropdown-toggle {
|
||||
@include caret(up);
|
||||
}
|
||||
}
|
||||
|
||||
.dropend {
|
||||
.dropdown-menu[data-bs-popper] {
|
||||
top: 0;
|
||||
right: auto;
|
||||
left: 100%;
|
||||
margin-top: 0;
|
||||
margin-left: var(--#{$prefix}dropdown-spacer);
|
||||
}
|
||||
|
||||
.dropdown-toggle {
|
||||
@include caret(end);
|
||||
&::after {
|
||||
vertical-align: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropstart {
|
||||
.dropdown-menu[data-bs-popper] {
|
||||
top: 0;
|
||||
right: 100%;
|
||||
left: auto;
|
||||
margin-top: 0;
|
||||
margin-right: var(--#{$prefix}dropdown-spacer);
|
||||
}
|
||||
|
||||
.dropdown-toggle {
|
||||
@include caret(start);
|
||||
&::before {
|
||||
vertical-align: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Dividers (basically an `<hr>`) within the dropdown
|
||||
.dropdown-divider {
|
||||
height: 0;
|
||||
margin: var(--#{$prefix}dropdown-divider-margin-y) 0;
|
||||
overflow: hidden;
|
||||
border-top: 1px solid var(--#{$prefix}dropdown-divider-bg);
|
||||
opacity: 1; // Revisit in v6 to de-dupe styles that conflict with <hr> element
|
||||
}
|
||||
|
||||
// Links, buttons, and more within the dropdown menu
|
||||
//
|
||||
// `<button>`-specific styles are denoted with `// For <button>s`
|
||||
.dropdown-item {
|
||||
display: block;
|
||||
width: 100%; // For `<button>`s
|
||||
padding: var(--#{$prefix}dropdown-item-padding-y) var(--#{$prefix}dropdown-item-padding-x);
|
||||
clear: both;
|
||||
font-weight: $font-weight-normal;
|
||||
color: var(--#{$prefix}dropdown-link-color);
|
||||
text-align: inherit; // For `<button>`s
|
||||
text-decoration: if($link-decoration == none, null, none);
|
||||
white-space: nowrap; // prevent links from randomly breaking onto new lines
|
||||
background-color: transparent; // For `<button>`s
|
||||
border: 0; // For `<button>`s
|
||||
@include border-radius(var(--#{$prefix}dropdown-item-border-radius, 0));
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: var(--#{$prefix}dropdown-link-hover-color);
|
||||
text-decoration: if($link-hover-decoration == underline, none, null);
|
||||
@include gradient-bg(var(--#{$prefix}dropdown-link-hover-bg));
|
||||
}
|
||||
|
||||
&.active,
|
||||
&:active {
|
||||
color: var(--#{$prefix}dropdown-link-active-color);
|
||||
text-decoration: none;
|
||||
@include gradient-bg(var(--#{$prefix}dropdown-link-active-bg));
|
||||
}
|
||||
|
||||
&.disabled,
|
||||
&:disabled {
|
||||
color: var(--#{$prefix}dropdown-link-disabled-color);
|
||||
pointer-events: none;
|
||||
background-color: transparent;
|
||||
// Remove CSS gradients if they're enabled
|
||||
background-image: if($enable-gradients, none, null);
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
// Dropdown section headers
|
||||
.dropdown-header {
|
||||
display: block;
|
||||
padding: var(--#{$prefix}dropdown-header-padding-y) var(--#{$prefix}dropdown-header-padding-x);
|
||||
margin-bottom: 0; // for use with heading elements
|
||||
@include font-size($font-size-sm);
|
||||
color: var(--#{$prefix}dropdown-header-color);
|
||||
white-space: nowrap; // as with > li > a
|
||||
}
|
||||
|
||||
// Dropdown text
|
||||
.dropdown-item-text {
|
||||
display: block;
|
||||
padding: var(--#{$prefix}dropdown-item-padding-y) var(--#{$prefix}dropdown-item-padding-x);
|
||||
color: var(--#{$prefix}dropdown-link-color);
|
||||
}
|
||||
|
||||
// Dark dropdowns
|
||||
.dropdown-menu-dark {
|
||||
// scss-docs-start dropdown-dark-css-vars
|
||||
--#{$prefix}dropdown-color: #{$dropdown-dark-color};
|
||||
--#{$prefix}dropdown-bg: #{$dropdown-dark-bg};
|
||||
--#{$prefix}dropdown-border-color: #{$dropdown-dark-border-color};
|
||||
--#{$prefix}dropdown-box-shadow: #{$dropdown-dark-box-shadow};
|
||||
--#{$prefix}dropdown-link-color: #{$dropdown-dark-link-color};
|
||||
--#{$prefix}dropdown-link-hover-color: #{$dropdown-dark-link-hover-color};
|
||||
--#{$prefix}dropdown-divider-bg: #{$dropdown-dark-divider-bg};
|
||||
--#{$prefix}dropdown-link-hover-bg: #{$dropdown-dark-link-hover-bg};
|
||||
--#{$prefix}dropdown-link-active-color: #{$dropdown-dark-link-active-color};
|
||||
--#{$prefix}dropdown-link-active-bg: #{$dropdown-dark-link-active-bg};
|
||||
--#{$prefix}dropdown-link-disabled-color: #{$dropdown-dark-link-disabled-color};
|
||||
--#{$prefix}dropdown-header-color: #{$dropdown-dark-header-color};
|
||||
// scss-docs-end dropdown-dark-css-vars
|
||||
}
|
||||
9
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_forms.scss
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
@import "forms/labels";
|
||||
@import "forms/form-text";
|
||||
@import "forms/form-control";
|
||||
@import "forms/form-select";
|
||||
@import "forms/form-check";
|
||||
@import "forms/form-range";
|
||||
@import "forms/floating-labels";
|
||||
@import "forms/input-group";
|
||||
@import "forms/validation";
|
||||
302
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_functions.scss
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
// Bootstrap functions
|
||||
//
|
||||
// Utility mixins and functions for evaluating source code across our variables, maps, and mixins.
|
||||
|
||||
// Ascending
|
||||
// Used to evaluate Sass maps like our grid breakpoints.
|
||||
@mixin _assert-ascending($map, $map-name) {
|
||||
$prev-key: null;
|
||||
$prev-num: null;
|
||||
@each $key, $num in $map {
|
||||
@if $prev-num == null or unit($num) == "%" or unit($prev-num) == "%" {
|
||||
// Do nothing
|
||||
} @else if not comparable($prev-num, $num) {
|
||||
@warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !";
|
||||
} @else if $prev-num >= $num {
|
||||
@warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !";
|
||||
}
|
||||
$prev-key: $key;
|
||||
$prev-num: $num;
|
||||
}
|
||||
}
|
||||
|
||||
// Starts at zero
|
||||
// Used to ensure the min-width of the lowest breakpoint starts at 0.
|
||||
@mixin _assert-starts-at-zero($map, $map-name: "$grid-breakpoints") {
|
||||
@if length($map) > 0 {
|
||||
$values: map-values($map);
|
||||
$first-value: nth($values, 1);
|
||||
@if $first-value != 0 {
|
||||
@warn "First breakpoint in #{$map-name} must start at 0, but starts at #{$first-value}.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Colors
|
||||
@function to-rgb($value) {
|
||||
@return red($value), green($value), blue($value);
|
||||
}
|
||||
|
||||
// stylelint-disable scss/dollar-variable-pattern
|
||||
@function rgba-css-var($identifier, $target) {
|
||||
@if $identifier == "body" and $target == "bg" {
|
||||
@return rgba(var(--#{$prefix}#{$identifier}-bg-rgb), var(--#{$prefix}#{$target}-opacity));
|
||||
} @if $identifier == "body" and $target == "text" {
|
||||
@return rgba(var(--#{$prefix}#{$identifier}-color-rgb), var(--#{$prefix}#{$target}-opacity));
|
||||
} @else {
|
||||
@return rgba(var(--#{$prefix}#{$identifier}-rgb), var(--#{$prefix}#{$target}-opacity));
|
||||
}
|
||||
}
|
||||
|
||||
@function map-loop($map, $func, $args...) {
|
||||
$_map: ();
|
||||
|
||||
@each $key, $value in $map {
|
||||
// allow to pass the $key and $value of the map as an function argument
|
||||
$_args: ();
|
||||
@each $arg in $args {
|
||||
$_args: append($_args, if($arg == "$key", $key, if($arg == "$value", $value, $arg)));
|
||||
}
|
||||
|
||||
$_map: map-merge($_map, ($key: call(get-function($func), $_args...)));
|
||||
}
|
||||
|
||||
@return $_map;
|
||||
}
|
||||
// stylelint-enable scss/dollar-variable-pattern
|
||||
|
||||
@function varify($list) {
|
||||
$result: null;
|
||||
@each $entry in $list {
|
||||
$result: append($result, var(--#{$prefix}#{$entry}), space);
|
||||
}
|
||||
@return $result;
|
||||
}
|
||||
|
||||
// Internal Bootstrap function to turn maps into its negative variant.
|
||||
// It prefixes the keys with `n` and makes the value negative.
|
||||
@function negativify-map($map) {
|
||||
$result: ();
|
||||
@each $key, $value in $map {
|
||||
@if $key != 0 {
|
||||
$result: map-merge($result, ("n" + $key: (-$value)));
|
||||
}
|
||||
}
|
||||
@return $result;
|
||||
}
|
||||
|
||||
// Get multiple keys from a sass map
|
||||
@function map-get-multiple($map, $values) {
|
||||
$result: ();
|
||||
@each $key, $value in $map {
|
||||
@if (index($values, $key) != null) {
|
||||
$result: map-merge($result, ($key: $value));
|
||||
}
|
||||
}
|
||||
@return $result;
|
||||
}
|
||||
|
||||
// Merge multiple maps
|
||||
@function map-merge-multiple($maps...) {
|
||||
$merged-maps: ();
|
||||
|
||||
@each $map in $maps {
|
||||
$merged-maps: map-merge($merged-maps, $map);
|
||||
}
|
||||
@return $merged-maps;
|
||||
}
|
||||
|
||||
// Replace `$search` with `$replace` in `$string`
|
||||
// Used on our SVG icon backgrounds for custom forms.
|
||||
//
|
||||
// @author Kitty Giraudel
|
||||
// @param {String} $string - Initial string
|
||||
// @param {String} $search - Substring to replace
|
||||
// @param {String} $replace ('') - New value
|
||||
// @return {String} - Updated string
|
||||
@function str-replace($string, $search, $replace: "") {
|
||||
$index: str-index($string, $search);
|
||||
|
||||
@if $index {
|
||||
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
|
||||
}
|
||||
|
||||
@return $string;
|
||||
}
|
||||
|
||||
// See https://codepen.io/kevinweber/pen/dXWoRw
|
||||
//
|
||||
// Requires the use of quotes around data URIs.
|
||||
|
||||
@function escape-svg($string) {
|
||||
@if str-index($string, "data:image/svg+xml") {
|
||||
@each $char, $encoded in $escaped-characters {
|
||||
// Do not escape the url brackets
|
||||
@if str-index($string, "url(") == 1 {
|
||||
$string: url("#{str-replace(str-slice($string, 6, -3), $char, $encoded)}");
|
||||
} @else {
|
||||
$string: str-replace($string, $char, $encoded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@return $string;
|
||||
}
|
||||
|
||||
// Color contrast
|
||||
// See https://github.com/twbs/bootstrap/pull/30168
|
||||
|
||||
// A list of pre-calculated numbers of pow(divide((divide($value, 255) + .055), 1.055), 2.4). (from 0 to 255)
|
||||
// stylelint-disable-next-line scss/dollar-variable-default, scss/dollar-variable-pattern
|
||||
$_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003 .0033 .0037 .004 .0044 .0048 .0052 .0056 .006 .0065 .007 .0075 .008 .0086 .0091 .0097 .0103 .011 .0116 .0123 .013 .0137 .0144 .0152 .016 .0168 .0176 .0185 .0194 .0203 .0212 .0222 .0232 .0242 .0252 .0262 .0273 .0284 .0296 .0307 .0319 .0331 .0343 .0356 .0369 .0382 .0395 .0409 .0423 .0437 .0452 .0467 .0482 .0497 .0513 .0529 .0545 .0561 .0578 .0595 .0612 .063 .0648 .0666 .0685 .0704 .0723 .0742 .0762 .0782 .0802 .0823 .0844 .0865 .0887 .0908 .0931 .0953 .0976 .0999 .1022 .1046 .107 .1095 .1119 .1144 .117 .1195 .1221 .1248 .1274 .1301 .1329 .1356 .1384 .1413 .1441 .147 .15 .1529 .1559 .159 .162 .1651 .1683 .1714 .1746 .1779 .1812 .1845 .1878 .1912 .1946 .1981 .2016 .2051 .2086 .2122 .2159 .2195 .2232 .227 .2307 .2346 .2384 .2423 .2462 .2502 .2542 .2582 .2623 .2664 .2705 .2747 .2789 .2831 .2874 .2918 .2961 .3005 .305 .3095 .314 .3185 .3231 .3278 .3325 .3372 .3419 .3467 .3515 .3564 .3613 .3663 .3712 .3763 .3813 .3864 .3916 .3968 .402 .4072 .4125 .4179 .4233 .4287 .4342 .4397 .4452 .4508 .4564 .4621 .4678 .4735 .4793 .4851 .491 .4969 .5029 .5089 .5149 .521 .5271 .5333 .5395 .5457 .552 .5583 .5647 .5711 .5776 .5841 .5906 .5972 .6038 .6105 .6172 .624 .6308 .6376 .6445 .6514 .6584 .6654 .6724 .6795 .6867 .6939 .7011 .7084 .7157 .7231 .7305 .7379 .7454 .7529 .7605 .7682 .7758 .7835 .7913 .7991 .807 .8148 .8228 .8308 .8388 .8469 .855 .8632 .8714 .8796 .8879 .8963 .9047 .9131 .9216 .9301 .9387 .9473 .956 .9647 .9734 .9823 .9911 1;
|
||||
|
||||
@function color-contrast($background, $color-contrast-dark: $color-contrast-dark, $color-contrast-light: $color-contrast-light, $min-contrast-ratio: $min-contrast-ratio) {
|
||||
$foregrounds: $color-contrast-light, $color-contrast-dark, $white, $black;
|
||||
$max-ratio: 0;
|
||||
$max-ratio-color: null;
|
||||
|
||||
@each $color in $foregrounds {
|
||||
$contrast-ratio: contrast-ratio($background, $color);
|
||||
@if $contrast-ratio >= $min-contrast-ratio {
|
||||
@return $color;
|
||||
} @else if $contrast-ratio > $max-ratio {
|
||||
$max-ratio: $contrast-ratio;
|
||||
$max-ratio-color: $color;
|
||||
}
|
||||
}
|
||||
|
||||
@warn "Found no color leading to #{$min-contrast-ratio}:1 contrast ratio against #{$background}...";
|
||||
|
||||
@return $max-ratio-color;
|
||||
}
|
||||
|
||||
@function contrast-ratio($background, $foreground: $color-contrast-light) {
|
||||
$l1: luminance($background);
|
||||
$l2: luminance(opaque($background, $foreground));
|
||||
|
||||
@return if($l1 > $l2, divide($l1 + .05, $l2 + .05), divide($l2 + .05, $l1 + .05));
|
||||
}
|
||||
|
||||
// Return WCAG2.2 relative luminance
|
||||
// See https://www.w3.org/TR/WCAG/#dfn-relative-luminance
|
||||
// See https://www.w3.org/TR/WCAG/#dfn-contrast-ratio
|
||||
@function luminance($color) {
|
||||
$rgb: (
|
||||
"r": red($color),
|
||||
"g": green($color),
|
||||
"b": blue($color)
|
||||
);
|
||||
|
||||
@each $name, $value in $rgb {
|
||||
$value: if(divide($value, 255) < .04045, divide(divide($value, 255), 12.92), nth($_luminance-list, $value + 1));
|
||||
$rgb: map-merge($rgb, ($name: $value));
|
||||
}
|
||||
|
||||
@return (map-get($rgb, "r") * .2126) + (map-get($rgb, "g") * .7152) + (map-get($rgb, "b") * .0722);
|
||||
}
|
||||
|
||||
// Return opaque color
|
||||
// opaque(#fff, rgba(0, 0, 0, .5)) => #808080
|
||||
@function opaque($background, $foreground) {
|
||||
@return mix(rgba($foreground, 1), $background, opacity($foreground) * 100%);
|
||||
}
|
||||
|
||||
// scss-docs-start color-functions
|
||||
// Tint a color: mix a color with white
|
||||
@function tint-color($color, $weight) {
|
||||
@return mix(white, $color, $weight);
|
||||
}
|
||||
|
||||
// Shade a color: mix a color with black
|
||||
@function shade-color($color, $weight) {
|
||||
@return mix(black, $color, $weight);
|
||||
}
|
||||
|
||||
// Shade the color if the weight is positive, else tint it
|
||||
@function shift-color($color, $weight) {
|
||||
@return if($weight > 0, shade-color($color, $weight), tint-color($color, -$weight));
|
||||
}
|
||||
// scss-docs-end color-functions
|
||||
|
||||
// Return valid calc
|
||||
@function add($value1, $value2, $return-calc: true) {
|
||||
@if $value1 == null {
|
||||
@return $value2;
|
||||
}
|
||||
|
||||
@if $value2 == null {
|
||||
@return $value1;
|
||||
}
|
||||
|
||||
@if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {
|
||||
@return $value1 + $value2;
|
||||
}
|
||||
|
||||
@return if($return-calc == true, calc(#{$value1} + #{$value2}), $value1 + unquote(" + ") + $value2);
|
||||
}
|
||||
|
||||
@function subtract($value1, $value2, $return-calc: true) {
|
||||
@if $value1 == null and $value2 == null {
|
||||
@return null;
|
||||
}
|
||||
|
||||
@if $value1 == null {
|
||||
@return -$value2;
|
||||
}
|
||||
|
||||
@if $value2 == null {
|
||||
@return $value1;
|
||||
}
|
||||
|
||||
@if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {
|
||||
@return $value1 - $value2;
|
||||
}
|
||||
|
||||
@if type-of($value2) != number {
|
||||
$value2: unquote("(") + $value2 + unquote(")");
|
||||
}
|
||||
|
||||
@return if($return-calc == true, calc(#{$value1} - #{$value2}), $value1 + unquote(" - ") + $value2);
|
||||
}
|
||||
|
||||
@function divide($dividend, $divisor, $precision: 10) {
|
||||
$sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);
|
||||
$dividend: abs($dividend);
|
||||
$divisor: abs($divisor);
|
||||
@if $dividend == 0 {
|
||||
@return 0;
|
||||
}
|
||||
@if $divisor == 0 {
|
||||
@error "Cannot divide by 0";
|
||||
}
|
||||
$remainder: $dividend;
|
||||
$result: 0;
|
||||
$factor: 10;
|
||||
@while ($remainder > 0 and $precision >= 0) {
|
||||
$quotient: 0;
|
||||
@while ($remainder >= $divisor) {
|
||||
$remainder: $remainder - $divisor;
|
||||
$quotient: $quotient + 1;
|
||||
}
|
||||
$result: $result * 10 + $quotient;
|
||||
$factor: $factor * .1;
|
||||
$remainder: $remainder * 10;
|
||||
$precision: $precision - 1;
|
||||
@if ($precision < 0 and $remainder >= $divisor * 5) {
|
||||
$result: $result + 1;
|
||||
}
|
||||
}
|
||||
$result: $result * $factor * $sign;
|
||||
$dividend-unit: unit($dividend);
|
||||
$divisor-unit: unit($divisor);
|
||||
$unit-map: (
|
||||
"px": 1px,
|
||||
"rem": 1rem,
|
||||
"em": 1em,
|
||||
"%": 1%
|
||||
);
|
||||
@if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {
|
||||
$result: $result * map-get($unit-map, $dividend-unit);
|
||||
}
|
||||
@return $result;
|
||||
}
|
||||
39
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_grid.scss
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
// Row
|
||||
//
|
||||
// Rows contain your columns.
|
||||
|
||||
:root {
|
||||
@each $name, $value in $grid-breakpoints {
|
||||
--#{$prefix}breakpoint-#{$name}: #{$value};
|
||||
}
|
||||
}
|
||||
|
||||
@if $enable-grid-classes {
|
||||
.row {
|
||||
@include make-row();
|
||||
|
||||
> * {
|
||||
@include make-col-ready();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@if $enable-cssgrid {
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-rows: repeat(var(--#{$prefix}rows, 1), 1fr);
|
||||
grid-template-columns: repeat(var(--#{$prefix}columns, #{$grid-columns}), 1fr);
|
||||
gap: var(--#{$prefix}gap, #{$grid-gutter-width});
|
||||
|
||||
@include make-cssgrid();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Columns
|
||||
//
|
||||
// Common styles for small and large grid columns
|
||||
|
||||
@if $enable-grid-classes {
|
||||
@include make-grid-columns();
|
||||
}
|
||||
12
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_helpers.scss
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
@import "helpers/clearfix";
|
||||
@import "helpers/color-bg";
|
||||
@import "helpers/colored-links";
|
||||
@import "helpers/focus-ring";
|
||||
@import "helpers/icon-link";
|
||||
@import "helpers/ratio";
|
||||
@import "helpers/position";
|
||||
@import "helpers/stacks";
|
||||
@import "helpers/visually-hidden";
|
||||
@import "helpers/stretched-link";
|
||||
@import "helpers/text-truncation";
|
||||
@import "helpers/vr";
|
||||
42
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_images.scss
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// Responsive images (ensure images don't scale beyond their parents)
|
||||
//
|
||||
// This is purposefully opt-in via an explicit class rather than being the default for all `<img>`s.
|
||||
// We previously tried the "images are responsive by default" approach in Bootstrap v2,
|
||||
// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)
|
||||
// which weren't expecting the images within themselves to be involuntarily resized.
|
||||
// See also https://github.com/twbs/bootstrap/issues/18178
|
||||
.img-fluid {
|
||||
@include img-fluid();
|
||||
}
|
||||
|
||||
|
||||
// Image thumbnails
|
||||
.img-thumbnail {
|
||||
padding: $thumbnail-padding;
|
||||
background-color: $thumbnail-bg;
|
||||
border: $thumbnail-border-width solid $thumbnail-border-color;
|
||||
@include border-radius($thumbnail-border-radius);
|
||||
@include box-shadow($thumbnail-box-shadow);
|
||||
|
||||
// Keep them at most 100% wide
|
||||
@include img-fluid();
|
||||
}
|
||||
|
||||
//
|
||||
// Figures
|
||||
//
|
||||
|
||||
.figure {
|
||||
// Ensures the caption's text aligns with the image.
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.figure-img {
|
||||
margin-bottom: $spacer * .5;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.figure-caption {
|
||||
@include font-size($figure-caption-font-size);
|
||||
color: $figure-caption-color;
|
||||
}
|
||||
199
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_list-group.scss
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
// Base class
|
||||
//
|
||||
// Easily usable on <ul>, <ol>, or <div>.
|
||||
|
||||
.list-group {
|
||||
// scss-docs-start list-group-css-vars
|
||||
--#{$prefix}list-group-color: #{$list-group-color};
|
||||
--#{$prefix}list-group-bg: #{$list-group-bg};
|
||||
--#{$prefix}list-group-border-color: #{$list-group-border-color};
|
||||
--#{$prefix}list-group-border-width: #{$list-group-border-width};
|
||||
--#{$prefix}list-group-border-radius: #{$list-group-border-radius};
|
||||
--#{$prefix}list-group-item-padding-x: #{$list-group-item-padding-x};
|
||||
--#{$prefix}list-group-item-padding-y: #{$list-group-item-padding-y};
|
||||
--#{$prefix}list-group-action-color: #{$list-group-action-color};
|
||||
--#{$prefix}list-group-action-hover-color: #{$list-group-action-hover-color};
|
||||
--#{$prefix}list-group-action-hover-bg: #{$list-group-hover-bg};
|
||||
--#{$prefix}list-group-action-active-color: #{$list-group-action-active-color};
|
||||
--#{$prefix}list-group-action-active-bg: #{$list-group-action-active-bg};
|
||||
--#{$prefix}list-group-disabled-color: #{$list-group-disabled-color};
|
||||
--#{$prefix}list-group-disabled-bg: #{$list-group-disabled-bg};
|
||||
--#{$prefix}list-group-active-color: #{$list-group-active-color};
|
||||
--#{$prefix}list-group-active-bg: #{$list-group-active-bg};
|
||||
--#{$prefix}list-group-active-border-color: #{$list-group-active-border-color};
|
||||
// scss-docs-end list-group-css-vars
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
// No need to set list-style: none; since .list-group-item is block level
|
||||
padding-left: 0; // reset padding because ul and ol
|
||||
margin-bottom: 0;
|
||||
@include border-radius(var(--#{$prefix}list-group-border-radius));
|
||||
}
|
||||
|
||||
.list-group-numbered {
|
||||
list-style-type: none;
|
||||
counter-reset: section;
|
||||
|
||||
> .list-group-item::before {
|
||||
// Increments only this instance of the section counter
|
||||
content: counters(section, ".") ". ";
|
||||
counter-increment: section;
|
||||
}
|
||||
}
|
||||
|
||||
// Individual list items
|
||||
//
|
||||
// Use on `li`s or `div`s within the `.list-group` parent.
|
||||
|
||||
.list-group-item {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: var(--#{$prefix}list-group-item-padding-y) var(--#{$prefix}list-group-item-padding-x);
|
||||
color: var(--#{$prefix}list-group-color);
|
||||
text-decoration: if($link-decoration == none, null, none);
|
||||
background-color: var(--#{$prefix}list-group-bg);
|
||||
border: var(--#{$prefix}list-group-border-width) solid var(--#{$prefix}list-group-border-color);
|
||||
|
||||
&:first-child {
|
||||
@include border-top-radius(inherit);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
@include border-bottom-radius(inherit);
|
||||
}
|
||||
|
||||
&.disabled,
|
||||
&:disabled {
|
||||
color: var(--#{$prefix}list-group-disabled-color);
|
||||
pointer-events: none;
|
||||
background-color: var(--#{$prefix}list-group-disabled-bg);
|
||||
}
|
||||
|
||||
// Include both here for `<a>`s and `<button>`s
|
||||
&.active {
|
||||
z-index: 2; // Place active items above their siblings for proper border styling
|
||||
color: var(--#{$prefix}list-group-active-color);
|
||||
background-color: var(--#{$prefix}list-group-active-bg);
|
||||
border-color: var(--#{$prefix}list-group-active-border-color);
|
||||
}
|
||||
|
||||
// stylelint-disable-next-line scss/selector-no-redundant-nesting-selector
|
||||
& + .list-group-item {
|
||||
border-top-width: 0;
|
||||
|
||||
&.active {
|
||||
margin-top: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list
|
||||
border-top-width: var(--#{$prefix}list-group-border-width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Interactive list items
|
||||
//
|
||||
// Use anchor or button elements instead of `li`s or `div`s to create interactive
|
||||
// list items. Includes an extra `.active` modifier class for selected items.
|
||||
|
||||
.list-group-item-action {
|
||||
width: 100%; // For `<button>`s (anchors become 100% by default though)
|
||||
color: var(--#{$prefix}list-group-action-color);
|
||||
text-align: inherit; // For `<button>`s (anchors inherit)
|
||||
|
||||
&:not(.active) {
|
||||
// Hover state
|
||||
&:hover,
|
||||
&:focus {
|
||||
z-index: 1; // Place hover/focus items above their siblings for proper border styling
|
||||
color: var(--#{$prefix}list-group-action-hover-color);
|
||||
text-decoration: none;
|
||||
background-color: var(--#{$prefix}list-group-action-hover-bg);
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: var(--#{$prefix}list-group-action-active-color);
|
||||
background-color: var(--#{$prefix}list-group-action-active-bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Horizontal
|
||||
//
|
||||
// Change the layout of list group items from vertical (default) to horizontal.
|
||||
|
||||
@each $breakpoint in map-keys($grid-breakpoints) {
|
||||
@include media-breakpoint-up($breakpoint) {
|
||||
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
|
||||
|
||||
.list-group-horizontal#{$infix} {
|
||||
flex-direction: row;
|
||||
|
||||
> .list-group-item {
|
||||
&:first-child:not(:last-child) {
|
||||
@include border-bottom-start-radius(var(--#{$prefix}list-group-border-radius));
|
||||
@include border-top-end-radius(0);
|
||||
}
|
||||
|
||||
&:last-child:not(:first-child) {
|
||||
@include border-top-end-radius(var(--#{$prefix}list-group-border-radius));
|
||||
@include border-bottom-start-radius(0);
|
||||
}
|
||||
|
||||
&.active {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
+ .list-group-item {
|
||||
border-top-width: var(--#{$prefix}list-group-border-width);
|
||||
border-left-width: 0;
|
||||
|
||||
&.active {
|
||||
margin-left: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list
|
||||
border-left-width: var(--#{$prefix}list-group-border-width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Flush list items
|
||||
//
|
||||
// Remove borders and border-radius to keep list group items edge-to-edge. Most
|
||||
// useful within other components (e.g., cards).
|
||||
|
||||
.list-group-flush {
|
||||
@include border-radius(0);
|
||||
|
||||
> .list-group-item {
|
||||
border-width: 0 0 var(--#{$prefix}list-group-border-width);
|
||||
|
||||
&:last-child {
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// scss-docs-start list-group-modifiers
|
||||
// List group contextual variants
|
||||
//
|
||||
// Add modifier classes to change text and background color on individual items.
|
||||
// Organizationally, this must come after the `:hover` states.
|
||||
|
||||
@each $state in map-keys($theme-colors) {
|
||||
.list-group-item-#{$state} {
|
||||
--#{$prefix}list-group-color: var(--#{$prefix}#{$state}-text-emphasis);
|
||||
--#{$prefix}list-group-bg: var(--#{$prefix}#{$state}-bg-subtle);
|
||||
--#{$prefix}list-group-border-color: var(--#{$prefix}#{$state}-border-subtle);
|
||||
--#{$prefix}list-group-action-hover-color: var(--#{$prefix}emphasis-color);
|
||||
--#{$prefix}list-group-action-hover-bg: var(--#{$prefix}#{$state}-border-subtle);
|
||||
--#{$prefix}list-group-action-active-color: var(--#{$prefix}emphasis-color);
|
||||
--#{$prefix}list-group-action-active-bg: var(--#{$prefix}#{$state}-border-subtle);
|
||||
--#{$prefix}list-group-active-color: var(--#{$prefix}#{$state}-bg-subtle);
|
||||
--#{$prefix}list-group-active-bg: var(--#{$prefix}#{$state}-text-emphasis);
|
||||
--#{$prefix}list-group-active-border-color: var(--#{$prefix}#{$state}-text-emphasis);
|
||||
}
|
||||
}
|
||||
// scss-docs-end list-group-modifiers
|
||||
174
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_maps.scss
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
// Re-assigned maps
|
||||
//
|
||||
// Placed here so that others can override the default Sass maps and see automatic updates to utilities and more.
|
||||
|
||||
// scss-docs-start theme-colors-rgb
|
||||
$theme-colors-rgb: map-loop($theme-colors, to-rgb, "$value") !default;
|
||||
// scss-docs-end theme-colors-rgb
|
||||
|
||||
// scss-docs-start theme-text-map
|
||||
$theme-colors-text: (
|
||||
"primary": $primary-text-emphasis,
|
||||
"secondary": $secondary-text-emphasis,
|
||||
"success": $success-text-emphasis,
|
||||
"info": $info-text-emphasis,
|
||||
"warning": $warning-text-emphasis,
|
||||
"danger": $danger-text-emphasis,
|
||||
"light": $light-text-emphasis,
|
||||
"dark": $dark-text-emphasis,
|
||||
) !default;
|
||||
// scss-docs-end theme-text-map
|
||||
|
||||
// scss-docs-start theme-bg-subtle-map
|
||||
$theme-colors-bg-subtle: (
|
||||
"primary": $primary-bg-subtle,
|
||||
"secondary": $secondary-bg-subtle,
|
||||
"success": $success-bg-subtle,
|
||||
"info": $info-bg-subtle,
|
||||
"warning": $warning-bg-subtle,
|
||||
"danger": $danger-bg-subtle,
|
||||
"light": $light-bg-subtle,
|
||||
"dark": $dark-bg-subtle,
|
||||
) !default;
|
||||
// scss-docs-end theme-bg-subtle-map
|
||||
|
||||
// scss-docs-start theme-border-subtle-map
|
||||
$theme-colors-border-subtle: (
|
||||
"primary": $primary-border-subtle,
|
||||
"secondary": $secondary-border-subtle,
|
||||
"success": $success-border-subtle,
|
||||
"info": $info-border-subtle,
|
||||
"warning": $warning-border-subtle,
|
||||
"danger": $danger-border-subtle,
|
||||
"light": $light-border-subtle,
|
||||
"dark": $dark-border-subtle,
|
||||
) !default;
|
||||
// scss-docs-end theme-border-subtle-map
|
||||
|
||||
$theme-colors-text-dark: null !default;
|
||||
$theme-colors-bg-subtle-dark: null !default;
|
||||
$theme-colors-border-subtle-dark: null !default;
|
||||
|
||||
@if $enable-dark-mode {
|
||||
// scss-docs-start theme-text-dark-map
|
||||
$theme-colors-text-dark: (
|
||||
"primary": $primary-text-emphasis-dark,
|
||||
"secondary": $secondary-text-emphasis-dark,
|
||||
"success": $success-text-emphasis-dark,
|
||||
"info": $info-text-emphasis-dark,
|
||||
"warning": $warning-text-emphasis-dark,
|
||||
"danger": $danger-text-emphasis-dark,
|
||||
"light": $light-text-emphasis-dark,
|
||||
"dark": $dark-text-emphasis-dark,
|
||||
) !default;
|
||||
// scss-docs-end theme-text-dark-map
|
||||
|
||||
// scss-docs-start theme-bg-subtle-dark-map
|
||||
$theme-colors-bg-subtle-dark: (
|
||||
"primary": $primary-bg-subtle-dark,
|
||||
"secondary": $secondary-bg-subtle-dark,
|
||||
"success": $success-bg-subtle-dark,
|
||||
"info": $info-bg-subtle-dark,
|
||||
"warning": $warning-bg-subtle-dark,
|
||||
"danger": $danger-bg-subtle-dark,
|
||||
"light": $light-bg-subtle-dark,
|
||||
"dark": $dark-bg-subtle-dark,
|
||||
) !default;
|
||||
// scss-docs-end theme-bg-subtle-dark-map
|
||||
|
||||
// scss-docs-start theme-border-subtle-dark-map
|
||||
$theme-colors-border-subtle-dark: (
|
||||
"primary": $primary-border-subtle-dark,
|
||||
"secondary": $secondary-border-subtle-dark,
|
||||
"success": $success-border-subtle-dark,
|
||||
"info": $info-border-subtle-dark,
|
||||
"warning": $warning-border-subtle-dark,
|
||||
"danger": $danger-border-subtle-dark,
|
||||
"light": $light-border-subtle-dark,
|
||||
"dark": $dark-border-subtle-dark,
|
||||
) !default;
|
||||
// scss-docs-end theme-border-subtle-dark-map
|
||||
}
|
||||
|
||||
// Utilities maps
|
||||
//
|
||||
// Extends the default `$theme-colors` maps to help create our utilities.
|
||||
|
||||
// Come v6, we'll de-dupe these variables. Until then, for backward compatibility, we keep them to reassign.
|
||||
// scss-docs-start utilities-colors
|
||||
$utilities-colors: $theme-colors-rgb !default;
|
||||
// scss-docs-end utilities-colors
|
||||
|
||||
// scss-docs-start utilities-text-colors
|
||||
$utilities-text: map-merge(
|
||||
$utilities-colors,
|
||||
(
|
||||
"black": to-rgb($black),
|
||||
"white": to-rgb($white),
|
||||
"body": to-rgb($body-color)
|
||||
)
|
||||
) !default;
|
||||
$utilities-text-colors: map-loop($utilities-text, rgba-css-var, "$key", "text") !default;
|
||||
|
||||
$utilities-text-emphasis-colors: (
|
||||
"primary-emphasis": var(--#{$prefix}primary-text-emphasis),
|
||||
"secondary-emphasis": var(--#{$prefix}secondary-text-emphasis),
|
||||
"success-emphasis": var(--#{$prefix}success-text-emphasis),
|
||||
"info-emphasis": var(--#{$prefix}info-text-emphasis),
|
||||
"warning-emphasis": var(--#{$prefix}warning-text-emphasis),
|
||||
"danger-emphasis": var(--#{$prefix}danger-text-emphasis),
|
||||
"light-emphasis": var(--#{$prefix}light-text-emphasis),
|
||||
"dark-emphasis": var(--#{$prefix}dark-text-emphasis)
|
||||
) !default;
|
||||
// scss-docs-end utilities-text-colors
|
||||
|
||||
// scss-docs-start utilities-bg-colors
|
||||
$utilities-bg: map-merge(
|
||||
$utilities-colors,
|
||||
(
|
||||
"black": to-rgb($black),
|
||||
"white": to-rgb($white),
|
||||
"body": to-rgb($body-bg)
|
||||
)
|
||||
) !default;
|
||||
$utilities-bg-colors: map-loop($utilities-bg, rgba-css-var, "$key", "bg") !default;
|
||||
|
||||
$utilities-bg-subtle: (
|
||||
"primary-subtle": var(--#{$prefix}primary-bg-subtle),
|
||||
"secondary-subtle": var(--#{$prefix}secondary-bg-subtle),
|
||||
"success-subtle": var(--#{$prefix}success-bg-subtle),
|
||||
"info-subtle": var(--#{$prefix}info-bg-subtle),
|
||||
"warning-subtle": var(--#{$prefix}warning-bg-subtle),
|
||||
"danger-subtle": var(--#{$prefix}danger-bg-subtle),
|
||||
"light-subtle": var(--#{$prefix}light-bg-subtle),
|
||||
"dark-subtle": var(--#{$prefix}dark-bg-subtle)
|
||||
) !default;
|
||||
// scss-docs-end utilities-bg-colors
|
||||
|
||||
// scss-docs-start utilities-border-colors
|
||||
$utilities-border: map-merge(
|
||||
$utilities-colors,
|
||||
(
|
||||
"black": to-rgb($black),
|
||||
"white": to-rgb($white)
|
||||
)
|
||||
) !default;
|
||||
$utilities-border-colors: map-loop($utilities-border, rgba-css-var, "$key", "border") !default;
|
||||
|
||||
$utilities-border-subtle: (
|
||||
"primary-subtle": var(--#{$prefix}primary-border-subtle),
|
||||
"secondary-subtle": var(--#{$prefix}secondary-border-subtle),
|
||||
"success-subtle": var(--#{$prefix}success-border-subtle),
|
||||
"info-subtle": var(--#{$prefix}info-border-subtle),
|
||||
"warning-subtle": var(--#{$prefix}warning-border-subtle),
|
||||
"danger-subtle": var(--#{$prefix}danger-border-subtle),
|
||||
"light-subtle": var(--#{$prefix}light-border-subtle),
|
||||
"dark-subtle": var(--#{$prefix}dark-border-subtle)
|
||||
) !default;
|
||||
// scss-docs-end utilities-border-colors
|
||||
|
||||
$utilities-links-underline: map-loop($utilities-colors, rgba-css-var, "$key", "link-underline") !default;
|
||||
|
||||
$negative-spacers: if($enable-negative-margins, negativify-map($spacers), null) !default;
|
||||
|
||||
$gutters: $spacers !default;
|
||||
42
webseite-react-php/react-app/src/styles/01_frameworks/bootstrap-5.3.8/_mixins.scss
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// Toggles
|
||||
//
|
||||
// Used in conjunction with global variables to enable certain theme features.
|
||||
|
||||
// Vendor
|
||||
@import "vendor/rfs";
|
||||
|
||||
// Deprecate
|
||||
@import "mixins/deprecate";
|
||||
|
||||
// Helpers
|
||||
@import "mixins/breakpoints";
|
||||
@import "mixins/color-mode";
|
||||
@import "mixins/color-scheme";
|
||||
@import "mixins/image";
|
||||
@import "mixins/resize";
|
||||
@import "mixins/visually-hidden";
|
||||
@import "mixins/reset-text";
|
||||
@import "mixins/text-truncate";
|
||||
|
||||
// Utilities
|
||||
@import "mixins/utilities";
|
||||
|
||||
// Components
|
||||
@import "mixins/backdrop";
|
||||
@import "mixins/buttons";
|
||||
@import "mixins/caret";
|
||||
@import "mixins/pagination";
|
||||
@import "mixins/lists";
|
||||
@import "mixins/forms";
|
||||
@import "mixins/table-variants";
|
||||
|
||||
// Skins
|
||||
@import "mixins/border-radius";
|
||||
@import "mixins/box-shadow";
|
||||
@import "mixins/gradients";
|
||||
@import "mixins/transition";
|
||||
|
||||
// Layout
|
||||
@import "mixins/clearfix";
|
||||
@import "mixins/container";
|
||||
@import "mixins/grid";
|
||||