Compare commits
170
Commits
6a665c6e9a
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1fc7aea2c3 | ||
|
|
cf5e373303 | ||
|
|
d918c197ae | ||
|
|
6c9b06b983 | ||
|
|
38867d737c | ||
|
|
24dacde5a9 | ||
|
|
00be33abcc | ||
|
|
21ad1ceb30 | ||
|
|
2f1b79a86a | ||
|
|
1dcec632d8 | ||
|
|
7cd82c0954 | ||
|
|
3ae7bb13b8 | ||
|
|
2cd098e5a2 | ||
|
|
6b58d09ec9 | ||
|
|
c356167f97 | ||
|
|
f475f40350 | ||
|
|
ed2c0b9906 | ||
|
|
baf557f666 | ||
|
|
a885cd9550 | ||
|
|
c5806140ae | ||
|
|
c322bf1edf | ||
|
|
6c7b9a0032 | ||
|
|
5c5e64aac9 | ||
|
|
3e77bd3f49 | ||
|
|
b21be6c1d1 | ||
|
|
50c1e85931 | ||
|
|
c936a7f00c | ||
|
|
7936f3387b | ||
|
|
da7fd3f7eb | ||
|
|
451e19b3a1 | ||
|
|
cd9acfb9eb | ||
|
|
7828535330 | ||
|
|
e91c11346e | ||
|
|
e9211c0a92 | ||
|
|
2426cd56bc | ||
|
|
e955f3fc4f | ||
|
|
f65a30752f | ||
|
|
ce35a827c3 | ||
|
|
cdb30b2ea3 | ||
|
|
d823a35ac1 | ||
|
|
b00bf0c183 | ||
|
|
5ca16567d2 | ||
|
|
3370aa2caa | ||
|
|
a2b463d491 | ||
|
|
c623e6f9d6 | ||
|
|
34172beb12 | ||
|
|
3367fea887 | ||
|
|
acf2deaea3 | ||
|
|
6985789ef7 | ||
|
|
75a26bda91 | ||
|
|
2efeba53f2 | ||
|
|
3b5f77b95e | ||
|
|
72d02ee501 | ||
|
|
b2577c249a | ||
|
|
12a7bc895c | ||
|
|
a1a85e4743 | ||
|
|
688ad6e2cf | ||
|
|
f8fc579c6f | ||
|
|
778d1f2929 | ||
|
|
7927009320 | ||
|
|
4036beca67 | ||
|
|
4a81288194 | ||
|
|
5739309790 | ||
|
|
72ee23c158 | ||
|
|
7489f4288c | ||
|
|
62b63ff196 | ||
|
|
fd7a5a03ca | ||
|
|
5b6dc89bb5 | ||
|
|
5d11cf5541 | ||
|
|
a385afacf9 | ||
|
|
f115c02ed5 | ||
|
|
e54f22a25c | ||
|
|
eda043f0c6 | ||
|
|
0526e28413 | ||
|
|
017583b8c8 | ||
|
|
6ec63fb1ec | ||
|
|
e3547acc13 | ||
|
|
fe8fc15363 | ||
|
|
9f316103e9 | ||
|
|
490de9179b | ||
|
|
8e7c8112a3 | ||
|
|
bcb589d15e | ||
|
|
16416a0239 | ||
|
|
73de568a05 | ||
|
|
f474ba8ea0 | ||
|
|
141a2ab609 | ||
|
|
a51aa72cc9 | ||
|
|
864b3f27d9 | ||
|
|
5a14dd3f10 | ||
|
|
42583441cc | ||
|
|
5b04511a91 | ||
|
|
64ff587b2c | ||
|
|
e797e9e8dd | ||
|
|
5bf1292c21 | ||
|
|
2a541fcdb1 | ||
|
|
64722b9dd2 | ||
|
|
34a9abfe23 | ||
|
|
7964b5e15c | ||
|
|
69655e8ef6 | ||
|
|
42356cfd31 | ||
|
|
707e3bebe9 | ||
|
|
bc06824ab6 | ||
|
|
36c0c2c7ea | ||
|
|
c41a126ea6 | ||
|
|
7e46647b86 | ||
|
|
11044693c9 | ||
|
|
29d4c7504f | ||
|
|
d83afa36d9 | ||
|
|
b9eb9f8f70 | ||
|
|
2c4aba89a9 | ||
|
|
87773ffa50 | ||
|
|
ff82f5a054 | ||
|
|
b8fe2dfafe | ||
|
|
588960732e | ||
|
|
7fd7301202 | ||
|
|
80c664c78a | ||
|
|
df640e0af2 | ||
|
|
19dc8aed74 | ||
|
|
e3d489e247 | ||
|
|
ebe9ab0e34 | ||
|
|
a064006966 | ||
|
|
7e6ec5b9ef | ||
|
|
1fe62103a8 | ||
|
|
fc5c2ad59e | ||
|
|
31a58172b5 | ||
|
|
723c95a3f9 | ||
|
|
7763aa89dc | ||
|
|
68ec935f9a | ||
|
|
7d06d95ab6 | ||
|
|
c1af899035 | ||
|
|
057001ad03 | ||
|
|
e8c2fc145f | ||
|
|
7e1d20d0ec | ||
|
|
1bd81120cc | ||
|
|
7ba49fc673 | ||
|
|
6c4bc185b3 | ||
|
|
2a2bdc3c63 | ||
|
|
6f4f54522c | ||
|
|
967bd5c7ea | ||
|
|
0987345152 | ||
|
|
78b97c124a | ||
|
|
643fdfc410 | ||
|
|
c388855bf9 | ||
|
|
c612d6d873 | ||
|
|
4582633d83 | ||
|
|
39962434d0 | ||
|
|
5a688bc7ea | ||
|
|
4dec8a5680 | ||
|
|
7b234167fa | ||
|
|
6972ee5e4f | ||
|
|
af025ac50c | ||
|
|
366a821a0e | ||
|
|
02b3745b88 | ||
|
|
58bdd6018f | ||
|
|
7a4748b549 | ||
|
|
8c7380fde9 | ||
|
|
9dad0f06a2 | ||
|
|
635c23d5e8 | ||
|
|
102a818a83 | ||
|
|
9e243cbaf2 | ||
|
|
ef9a956a2c | ||
|
|
6ceab20458 | ||
|
|
4fe074b619 | ||
|
|
8791cf065a | ||
|
|
6a8f9bc60a | ||
|
|
10ef70e872 | ||
|
|
6b7d61dbc4 | ||
|
|
0c2ff6cf9d | ||
|
|
18049a4c64 | ||
|
|
ad6782538b |
Vendored
+3
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"terminal.explorerKind": "external",
|
||||
"terminal.external.osxExec": "iTerm.app",
|
||||
"terminal.external.windowsExec": "wt.exe",
|
||||
"workbench.iconTheme": "vscode-icons",
|
||||
"workbench.colorTheme": "One Dark Pro",
|
||||
"prettier.printWidth": 120,
|
||||
|
||||
+28
-26
@@ -267,11 +267,7 @@ Abschlussquiz - JS Grundlagen
|
||||
**Inhalt:**
|
||||
|
||||
- **Exkurs: Statische Webseite mit Sass und HTML Part II**
|
||||
- fetch in der Praxis: Joke API auslesen
|
||||
- XML-HttpRequest und AJAX mit jQuery
|
||||
- Wetter API auslesen
|
||||
- Node Standardbib
|
||||
- fs
|
||||
- Node Module: HTTP-Server, npm-run-all und SVGO
|
||||
|
||||
**Übungen:**
|
||||
|
||||
@@ -283,15 +279,32 @@ Projektarbeit + Wetter API Key besorgen
|
||||
|
||||
**Inhalt:**
|
||||
|
||||
- Node Standardbib
|
||||
- zlib (stream)
|
||||
- Crypto
|
||||
- Abschluss von JS für Fortgeschrittene
|
||||
- Projektvorstellung 1 + 2
|
||||
- XML-HttpRequest und AJAX mit jQuery
|
||||
- Node Module für die Projekt-Entwicklungsumgebung
|
||||
- Wetter API auslesen
|
||||
- fetch in der Praxis: Joke API auslesen
|
||||
- Was ist Node.js? (Wiederholung)
|
||||
|
||||
**Übungen:**
|
||||
|
||||
Projektarbeit
|
||||
Übungen Public API auslesen
|
||||
|
||||
---
|
||||
|
||||
#### Tag 18
|
||||
|
||||
**Inhalt:**
|
||||
|
||||
- Node Standardbib (fs, zlib (stream), Crypto)
|
||||
- Import vs. require (Teil II)
|
||||
- NPM Befehle
|
||||
- Abschluss von JS für Fortgeschrittene
|
||||
- Projektvorstellung 1 + 2 JS Advanced
|
||||
|
||||
|
||||
**Übungen:**
|
||||
|
||||
Übungen 25 - 31
|
||||
|
||||
---
|
||||
@@ -300,23 +313,12 @@ Projektarbeit
|
||||
|
||||
---
|
||||
|
||||
#### Tag 18
|
||||
|
||||
**Inhalt:**
|
||||
|
||||
- Einführung in JS DOM
|
||||
- DOM Selection (querySelector, querySelectorAll)
|
||||
- $ & $$ Helper
|
||||
- CSS Selektoren
|
||||
|
||||
**Übungen:**
|
||||
|
||||
Übungen 01 - 05
|
||||
|
||||
---
|
||||
|
||||
#### Tag 19
|
||||
|
||||
- Einführung in JS DOM
|
||||
- DOM Selection (querySelector, querySelectorAll, $ & $$ Helper)
|
||||
- CSS Selektoren
|
||||
- Defer & Async
|
||||
- JS Dateien auslagern
|
||||
- Chat Gestaltung (DOMTokenList Objekt)
|
||||
@@ -325,7 +327,7 @@ Projektarbeit
|
||||
|
||||
**Übungen:**
|
||||
|
||||
Übungen 06 - 07
|
||||
Übungen 01 - 06
|
||||
|
||||
---
|
||||
|
||||
@@ -340,4 +342,4 @@ Projektarbeit
|
||||
|
||||
**Übungen:**
|
||||
|
||||
Übung 08 - 10
|
||||
Übung 07 - 10
|
||||
@@ -0,0 +1,114 @@
|
||||
## NVM - Node Version Manager
|
||||
|
||||
nvm ist ein Versionsmanager für node.js. Über nvm können mehrere unterschiedliche Node Versionen installiert werden. NVM wird über die Konsole aufgerufen und ist mit verschiedenen Shells kompatibel (sh, dash, ksh, zsh, bash).
|
||||
|
||||
#### Links
|
||||
|
||||
- <https://github.com/coreybutler/nvm-windows> (Win)
|
||||
- <https://github.com/nvm-sh/nvm> (Mac OS)
|
||||
|
||||
#### Installation Windows
|
||||
|
||||
1. Lade den NVM-Installer über folgenden Link herunter: <https://github.com/coreybutler/nvm-windows/releases>
|
||||
2. Installiere NVM über den [Installer](https://github.com/coreybutler/nvm-windows/releases/download/1.2.2/nvm-setup.zip)
|
||||
3. Sollte vorher bereits NodeJS global ohne NVM installiert worden sein, wird empfohlen die vorherige NodeJS Version zu [deinstallieren](https://stackoverflow.com/a/55300310).
|
||||
|
||||
### Installation Mac OS
|
||||
|
||||
- Installiere NVM über die Konsole mit:
|
||||
|
||||
```bash
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
|
||||
```
|
||||
|
||||
- Füge den Pfad zum NVM Ordner zur Shell-Config hinzu. (`~/.bash_profile`, `~/.zshrc`, `~/.profile`, or `~/.bashrc`).
|
||||
|
||||
```bash
|
||||
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
|
||||
```
|
||||
|
||||
- Aktuelle Informationen zur Installation findet man unter folgendem Link: <https://github.com/nvm-sh/nvm>
|
||||
|
||||
#### Erste Schritte
|
||||
|
||||
Sobald NVM erfolgreich installiert wurde kann man über nvm in der Konsole eine neue Node Version mit folgendem Befehl installieren:
|
||||
|
||||
```bash
|
||||
nvm install [NODE VERSIONSNUMMER]
|
||||
```
|
||||
|
||||
> Hinweis: Die aktuellste Versionsnummer von NodeJS findet man am einfachsten auf der [NodeJS-Seite](https://nodejs.org/en/)
|
||||
|
||||
Installierte Node Versionen auflisten
|
||||
|
||||
```bash
|
||||
nvm list
|
||||
```
|
||||
|
||||
Node Version verwenden/wechseln
|
||||
|
||||
```bash
|
||||
nvm use [NODE VERSIONSNUMMER]
|
||||
```
|
||||
|
||||
Node Version als Standard einrichten
|
||||
|
||||
```bash
|
||||
nvm alias default [NODE VERSIONSNUMMER]
|
||||
```
|
||||
|
||||
## Node.js
|
||||
|
||||
### Definition
|
||||
|
||||
Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.
|
||||
|
||||
## Neues Projekt erstellen
|
||||
|
||||
- Über die Konsole in den Projektordner gehen.
|
||||
|
||||
Projektordner wechsel über "change directory" (cd)
|
||||
|
||||
```bash
|
||||
cd [projektpfad]
|
||||
```
|
||||
|
||||
- Eigene Package.json Datei generieren (nur einmalig bei einem neuen Projekt notwendig.)
|
||||
|
||||
```bash
|
||||
npm init
|
||||
```
|
||||
|
||||
- Module installieren, die nur für die Entwicklung benötigt werden. (devDependicies)
|
||||
|
||||
| Befehl | Zweck |
|
||||
| ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `npm install Modul@Version` | installiere Modul in der Version Version (semantic versioning) |
|
||||
| `npm install Modul@Version --save`<br>`npm install Modul@Version -S` | Modul wird in der Datei `package.json` unter dependencies hinzugefügt (Mittlerweile default) |
|
||||
| `npm install Modul@Version --save-dev`<br>`npm install Modul@Version -D` | Modul wird in der Datei `package.json` unter devdependencies hinzugefügt |
|
||||
| `npm install Modul@Version --global`<br>`npm install Modul@Version -g` | Modul wird global installiert. (Von jedem Ordner aus anwendbar) |
|
||||
| `npm uninstall Modul@Version` | entfernt Modul aus `node_modules` |
|
||||
| `npm uninstall Modul@Version --save` | entfernt Modul aus `node_modules` und aus der dependencies- Eigenschaft in der `package.json`. |
|
||||
| `npm update Modul` | Aktualisiert Modul auf die neueste Version |
|
||||
| `npm update Modul --save` | Aktualisiert Modul auf die neueste Version und auch die Versionsnummer der dependencies- Eigenschaft in der `package.json`. |
|
||||
| `npm init` | erstellt eine package.json-Datei (der Befehl fragt die Eigenschaften ab) |
|
||||
| `npm init --yes` | erstellt eine package.json-Datei (der Befehl setzt Default-Werte ein) |
|
||||
| `npm list` | listet alle installierten Module auf. |
|
||||
| `npm search` | Suchbegriff sucht Module, deren Namen den Suchbegriff enthält |
|
||||
|
||||
# Globale Module
|
||||
|
||||
## SASS
|
||||
|
||||
### Definition
|
||||
|
||||
> Sass is the most mature, stable, and powerful professional grade CSS extension language in the world.
|
||||
|
||||
Sass ist eine CSS-Preprocessor Sprache.
|
||||
|
||||
```bash
|
||||
npm install sass -g
|
||||
```
|
||||
|
||||
## Liste von verwendeten Modulen
|
||||
Binary file not shown.
@@ -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?
|
||||
@@ -0,0 +1,17 @@
|
||||
## License and terms of use
|
||||
|
||||
© Web Professional Institute Inc. All rights reserved.
|
||||
|
||||
This material is provided solely for students enrolled in courses offered by Web Professional Institute Inc. By accessing or using this code, you acknowledge that it is strictly for educational use within the context of Web Professional Institute Inc. programs.
|
||||
|
||||
**Usage Restrictions:**
|
||||
|
||||
- Redistribution, sharing, or copying of this material outside the course environment is strictly prohibited.
|
||||
- The content is designed to support your learning objectives and is not authorized for commercial projects, public repositories, or applications beyond the course scope.
|
||||
- Unauthorized commercial use or open-source distribution is strictly prohibited and may result in expulsion from the program and legal action.
|
||||
|
||||
**Agreement & Rights:**
|
||||
|
||||
As a student, you have agreed to these terms as part of your enrollment agreement, which includes additional details on permitted uses, restrictions, and policies. The author and Web Professional Institute Inc. retain all rights to this material, including the code base and instructional content.
|
||||
|
||||
For any questions regarding these terms, please contact Web Professional Institute Inc. for clarification.
|
||||
@@ -0,0 +1,62 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Recipe Explorer Dashboard</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Recipe Explorer Dashboard</h1>
|
||||
|
||||
<div id="search-container">
|
||||
<input
|
||||
type="text"
|
||||
id="search-input"
|
||||
placeholder="Search for recipes by name..."
|
||||
/>
|
||||
<button id="search-button">Search</button>
|
||||
</div>
|
||||
|
||||
<div id="loading">Loading...</div>
|
||||
<div id="error-message"></div>
|
||||
|
||||
<table id="recipes-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Recipe Name</th>
|
||||
<th>Cuisine</th>
|
||||
<th>Preparation Time (mins)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Recipe data will be populated here -->
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Modal for Recipe Details -->
|
||||
<div id="recipe-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close">×</span>
|
||||
<h2 id="modal-title">Recipe Name</h2>
|
||||
<img
|
||||
id="modal-image"
|
||||
src=""
|
||||
alt="Recipe Image"
|
||||
style="border-radius: 10px; max-height: 200px"
|
||||
/>
|
||||
<p><strong>Cuisine:</strong> <span id="modal-category"></span></p>
|
||||
<p>
|
||||
<strong>Preparation Time:</strong> <span id="modal-time"></span> mins
|
||||
</p>
|
||||
<p><strong>Ingredients:</strong></p>
|
||||
<ul id="modal-ingredients">
|
||||
<!-- Ingredients will be populated here -->
|
||||
</ul>
|
||||
<p><strong>Instructions:</strong></p>
|
||||
<p id="modal-instructions"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="scripts.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,122 @@
|
||||
(() => {
|
||||
// ===== DOM & VARIABLES =====
|
||||
const RECIPES_URL = 'https://dummyjson.com/recipes';
|
||||
|
||||
const searchInput = document.querySelector('#search-input');
|
||||
const searchButton = document.querySelector('#search-button');
|
||||
const recipesTableBody = document.querySelector('#recipes-table tbody');
|
||||
const loadingIndicator = document.querySelector('#loading');
|
||||
const errorMessage = document.querySelector('#error-message');
|
||||
|
||||
const modal = document.querySelector('#recipe-modal');
|
||||
const modalTitle = document.querySelector('#modal-title');
|
||||
const modalImage = document.querySelector('#modal-image');
|
||||
const modalCategory = document.querySelector('#modal-category');
|
||||
const modalTime = document.querySelector('#modal-time');
|
||||
const modalIngredients = document.querySelector('#modal-ingredients');
|
||||
const modalInstructions = document.querySelector('#modal-instructions');
|
||||
const closeModal = document.querySelector('.close');
|
||||
|
||||
let allRecipes = [];
|
||||
|
||||
// ===== INIT =====
|
||||
const init = () => {
|
||||
// TODO: Fetch and display all recipes on initial load
|
||||
|
||||
// Event Listeners
|
||||
closeModal.addEventListener('click', closeModalEvent);
|
||||
window.addEventListener('click', windowClickEvent);
|
||||
};
|
||||
|
||||
// ===== EVENT LISTENERS =====
|
||||
const searchButtonEvent = () => {
|
||||
const query = searchInput.value.trim().toLowerCase();
|
||||
if (query !== '') {
|
||||
// TODO: Implement search functionality
|
||||
} else {
|
||||
// TODO: Display all recipes if search input is empty
|
||||
}
|
||||
};
|
||||
|
||||
// Close Modal Event
|
||||
const closeModalEvent = () => {
|
||||
modal.style.display = 'none';
|
||||
};
|
||||
|
||||
// Close Modal when clicking outside the modal content
|
||||
const windowClickEvent = (event) => {
|
||||
if (event.target == modal) {
|
||||
modal.style.display = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
// ===== FUNCTIONS =====
|
||||
// Fetches all recipes from the API and displays them.
|
||||
const fetchAndDisplayRecipes = async () => {
|
||||
showLoading(true);
|
||||
showError(false, '');
|
||||
|
||||
try {
|
||||
// TODO: Fetch data from API
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
showError(true, 'An error occurred while fetching recipes.');
|
||||
} finally {
|
||||
showLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Searches for recipes by name and displays the results.
|
||||
const searchRecipes = async (query) => {
|
||||
showLoading(true);
|
||||
showError(false, '');
|
||||
|
||||
try {
|
||||
// TODO: Search for recipes by name
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
showError(true, 'An error occurred while searching for recipes.');
|
||||
} finally {
|
||||
showLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Displays a list of recipes in the table.
|
||||
const displayRecipes = (recipes) => {
|
||||
clearTable();
|
||||
|
||||
// TODO: Iterate over the recipes and display them in the table
|
||||
};
|
||||
|
||||
// Displays detailed information about a selected recipe in a modal.
|
||||
const showRecipeDetails = (recipe) => {
|
||||
// TODO: Calculate total preparation time
|
||||
// TODO: Set image source
|
||||
// TODO: Populate ingredients
|
||||
// TODO: Show modal
|
||||
};
|
||||
|
||||
// Shows or hides the loading indicator.
|
||||
const showLoading = (show) => {
|
||||
loadingIndicator.style.display = show ? 'block' : 'none';
|
||||
};
|
||||
|
||||
// Displays or hides an error message.
|
||||
const showError = (show, message) => {
|
||||
if (show) {
|
||||
errorMessage.textContent = message;
|
||||
errorMessage.style.display = 'block';
|
||||
} else {
|
||||
errorMessage.textContent = '';
|
||||
errorMessage.style.display = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
// Clears the recipes table.
|
||||
const clearTable = () => {
|
||||
recipesTableBody.innerHTML = '';
|
||||
};
|
||||
|
||||
// ===== CALL INIT =====
|
||||
init();
|
||||
})();
|
||||
@@ -0,0 +1,124 @@
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: #4d7c0f;
|
||||
}
|
||||
|
||||
#search-container {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#search-input {
|
||||
width: 300px;
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
border: 2px solid #65a30d;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#search-button {
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
background-color: #4d7c0f;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
#search-button:hover {
|
||||
background-color: #65a30d;
|
||||
transition: 0.1s;
|
||||
}
|
||||
|
||||
#recipes-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 20px;
|
||||
max-width: 1000px;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
#recipes-table th,
|
||||
#recipes-table td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#recipes-table th {
|
||||
background-color: #4d7c0f;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#recipes-table tr:nth-child(even) {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
#recipes-table tr:hover {
|
||||
background-color: #ecfccb;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Modal styling */
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
padding-top: 100px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: #fff;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #888;
|
||||
width: 60%;
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.close {
|
||||
color: #aaa;
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 25px;
|
||||
font-size: 30px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.close:hover,
|
||||
.close:focus {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Loading Indicator */
|
||||
#loading {
|
||||
display: none;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
color: #4d7c0f;
|
||||
}
|
||||
|
||||
/* Error Message */
|
||||
#error-message {
|
||||
display: none;
|
||||
text-align: center;
|
||||
color: red;
|
||||
font-size: 18px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@@ -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?
|
||||
@@ -0,0 +1,17 @@
|
||||
## License and terms of use
|
||||
|
||||
© Web Professional Institute Inc. All rights reserved.
|
||||
|
||||
This material is provided solely for students enrolled in courses offered by Web Professional Institute Inc. By accessing or using this code, you acknowledge that it is strictly for educational use within the context of Web Professional Institute Inc. programs.
|
||||
|
||||
**Usage Restrictions:**
|
||||
|
||||
- Redistribution, sharing, or copying of this material outside the course environment is strictly prohibited.
|
||||
- The content is designed to support your learning objectives and is not authorized for commercial projects, public repositories, or applications beyond the course scope.
|
||||
- Unauthorized commercial use or open-source distribution is strictly prohibited and may result in expulsion from the program and legal action.
|
||||
|
||||
**Agreement & Rights:**
|
||||
|
||||
As a student, you have agreed to these terms as part of your enrollment agreement, which includes additional details on permitted uses, restrictions, and policies. The author and Web Professional Institute Inc. retain all rights to this material, including the code base and instructional content.
|
||||
|
||||
For any questions regarding these terms, please contact Web Professional Institute Inc. for clarification.
|
||||
@@ -0,0 +1,76 @@
|
||||
'use strict';
|
||||
|
||||
const menu = [
|
||||
{
|
||||
category: 'Beverages',
|
||||
items: [
|
||||
{ name: 'Coffee', price: 3.5 },
|
||||
{ name: 'Tea', price: 2.5 },
|
||||
{ name: 'Juice', price: 4 },
|
||||
],
|
||||
},
|
||||
{
|
||||
category: 'Pastries',
|
||||
items: [
|
||||
{ name: 'Croissant', price: 2.75 },
|
||||
{ name: 'Muffin', price: 2.5 },
|
||||
{ name: 'Bagel', price: 2.25 },
|
||||
],
|
||||
},
|
||||
{
|
||||
category: 'Sandwiches',
|
||||
items: [
|
||||
{ name: 'Ham Sandwich', price: 5.5 },
|
||||
{ name: 'Veggie Sandwich', price: 5 },
|
||||
{ name: 'Turkey Sandwich', price: 6 },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
// ADD YOUR CODE BELOW
|
||||
const listMenuItems = (menu) => {};
|
||||
|
||||
const calculateAveragePrice = (menu) => {};
|
||||
|
||||
const findItemsByCategory = (menu, categoryName) => {};
|
||||
|
||||
// ===== TEST CASES (DO NOT MODIFY) =====
|
||||
|
||||
// 1. List All Menu Items
|
||||
const menuItems = listMenuItems(menu);
|
||||
console.log('All Menu Items:\n', menuItems);
|
||||
|
||||
// 2. Calculate Average Price
|
||||
const averagePrice = calculateAveragePrice(menu);
|
||||
console.log('Average Price of All Items:', averagePrice);
|
||||
|
||||
// 3. Find Items by Category
|
||||
const searchCategory = 'Pastries';
|
||||
const pastries = findItemsByCategory(menu, searchCategory);
|
||||
console.log(`Items in "${searchCategory}" \nItems:`, pastries);
|
||||
|
||||
/*
|
||||
===== EXPECTED OUTPUT =====
|
||||
|
||||
All Menu Items:
|
||||
[
|
||||
'Coffee',
|
||||
'Tea',
|
||||
'Juice',
|
||||
'Croissant',
|
||||
'Muffin',
|
||||
'Bagel',
|
||||
'Ham Sandwich',
|
||||
'Veggie Sandwich',
|
||||
'Turkey Sandwich'
|
||||
]
|
||||
|
||||
Average Price of All Items: 3.78
|
||||
|
||||
Items in "Pastries"
|
||||
Items: [
|
||||
{ name: 'Croissant', price: 2.75 },
|
||||
{ name: 'Muffin', price: 2.5 },
|
||||
{ name: 'Bagel', price: 2.25 }
|
||||
]
|
||||
*/
|
||||
@@ -0,0 +1,100 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>GeoLocation API auslesen</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container py-5">
|
||||
<h1>GeoLocation API auslesen</h1>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
(() => {
|
||||
// === DOM & VARS =======
|
||||
const DOM = {};
|
||||
|
||||
// === INIT =============
|
||||
const init = () => {
|
||||
getGeoLocation().then((dataGeolocation) => {
|
||||
// console.log('Geo Location:' + dataGeolocation);
|
||||
console.log(setGeoLocation(dataGeolocation));
|
||||
// getWeather().then((data) => {
|
||||
// console.log('Weather Data:' + data);
|
||||
// setWeather(data);
|
||||
// });
|
||||
});
|
||||
|
||||
getCoordinates().then((data) => {
|
||||
console.log(data);
|
||||
});
|
||||
};
|
||||
|
||||
// === EVENTHANDLER =====
|
||||
|
||||
// === XHR/FETCH ========
|
||||
|
||||
// === FUNCTIONS ========
|
||||
const setGeoLocation = (data) => {
|
||||
const { longitude, latitude } = data;
|
||||
console.log(`LON: ${data.longitude} LAT: ${data.latitude}`);
|
||||
return { longitude, latitude };
|
||||
};
|
||||
|
||||
const getGeoLocation = async () => {
|
||||
try {
|
||||
const res = await fetch('https://myiprightnow.com/api/ip');
|
||||
if (!res.ok) {
|
||||
throw Error('Fetch Error Geolocation');
|
||||
}
|
||||
const data = await res.json();
|
||||
console.log(data);
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const getCoordinates = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Prüfen, ob der Browser Geolocation unterstützt
|
||||
if (!navigator.geolocation) {
|
||||
reject(new Error('Geolocation wird von diesem Browser nicht unterstützt.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Optionen für die Abfrage (optional)
|
||||
const options = {
|
||||
enableHighAccuracy: true, // Bestmögliche Genauigkeit erzwingen
|
||||
timeout: 5000, // Max. Wartezeit in Millisekunden
|
||||
maximumAge: 0, // Kein Cache, frische Daten anfordern
|
||||
};
|
||||
|
||||
// Erfolg-Callback
|
||||
const success = (position) => {
|
||||
const { latitude, longitude } = position.coords;
|
||||
resolve({ latitude, longitude });
|
||||
};
|
||||
|
||||
// Fehler-Callback
|
||||
const error = (err) => {
|
||||
reject(new Error(`Standortabfrage fehlgeschlagen: ${err.message}`));
|
||||
};
|
||||
|
||||
// API-Aufruf starten
|
||||
// https://developer.mozilla.org/de/docs/Web/API/Geolocation/getCurrentPosition
|
||||
navigator.geolocation.getCurrentPosition(success, error, options);
|
||||
});
|
||||
};
|
||||
|
||||
init();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,62 @@
|
||||
// Übung 25
|
||||
const quotedCSV = '"very big, soft computer mouse","the cutest peripheral ever","10","39.90"';
|
||||
|
||||
// Übung 26
|
||||
// In der Praxis finden sich auch CSV-Datensätze, in denen manche Felder mit Anführungszeichen umgeben sind und manche nicht.
|
||||
|
||||
// Schreibe ein Programm, das auch mit diesen Fällen zurechtkommt. Folgender Datensatz soll korrekt zerlegt werden:
|
||||
|
||||
const mixedCSV = '"very big, soft computer mouse","the cutest peripheral ever",10,39.90';
|
||||
|
||||
const parseCSVRecord = (record) => {
|
||||
const fields = [];
|
||||
let field = '';
|
||||
let inQuotes = false;
|
||||
|
||||
for (const character of record) {
|
||||
if (character === '"') {
|
||||
inQuotes = !inQuotes;
|
||||
} else if (character === ',' && !inQuotes) {
|
||||
fields.push(field);
|
||||
field = '';
|
||||
} else {
|
||||
field += character;
|
||||
}
|
||||
}
|
||||
|
||||
fields.push(field);
|
||||
return fields;
|
||||
};
|
||||
|
||||
console.log(parseCSVRecord(quotedCSV));
|
||||
console.log(parseCSVRecord(mixedCSV));
|
||||
/*
|
||||
Übung 25: CSV-Datensätze mit Anführungszeichen
|
||||
Bisher haben wir die Felder in einem CSV-Datensatz einfach mit der Anweisung:
|
||||
|
||||
|
||||
record.split(',')
|
||||
|
||||
|
||||
in einzelne Felder zerlegt. In der Praxis kann es aber vorkommen, dass ein einzelnes Feld ein Komma enthält. Das Problem wird üblicherweise gelöst, indem die einzelnen Felder noch mit Anführungszeichen umgeben werden. Hier ist ein Beispiel:
|
||||
|
||||
'very big, soft computer mouse', 'the cutest peripheral ever', '10', '39.90'
|
||||
|
||||
|
||||
Das erste Feld enthält ein Komma (very big, soft computer mouse), trotzdem ist die Unterteilung eindeutig. Schreibe ein kurzes Programm, das diesen Datensatz korrekt zerlegt und die einzelnen Felder ausgibt:
|
||||
|
||||
|
||||
const quotedCSV =
|
||||
'"very big, soft computer mouse","the cutest peripheral ever","10","39.90"'
|
||||
*/
|
||||
|
||||
/*
|
||||
Übung 26: CSV-Datensätze mit Anführungszeichen — Teil 2
|
||||
In der Praxis finden sich auch CSV-Datensätze, in denen manche Felder mit Anführungszeichen umgeben sind und manche nicht.
|
||||
|
||||
Schreibe ein Programm, das auch mit diesen Fällen zurechtkommt. Folgender Datensatz soll korrekt zerlegt werden:
|
||||
|
||||
const mixedCSV =
|
||||
'"very big, soft computer mouse","the cutest peripheral ever",10,39.90'
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,51 @@
|
||||
# Regex Beispiel
|
||||
|
||||
Am besten löst man das mit einem regulären Ausdruck, der entweder nach **Inhalten in Anführungszeichen** sucht _oder_ nach **Inhalten ohne Kommas**.
|
||||
|
||||
Hier ist der passende Reguläre Ausdruck:
|
||||
|
||||
`/"([^"\\]*(?:\\.[^"\\]*)*)"|([^,]+)/g`
|
||||
|
||||
---
|
||||
|
||||
### Wie der Regex funktioniert
|
||||
|
||||
Der Ausdruck nutzt das **ODER-Prinzip (`|`)**, um zwei Szenarien zu matchen:
|
||||
|
||||
1. **`"([^"\\]*(?:\\.[^"\\]*)*)"` (Gruppe 1):** Matcht alles, was in doppelten Anführungszeichen steht. Er erlaubt sogar escaped Anführungszeichen (`\"`) im Text.
|
||||
2. **`([^,]+)` (Gruppe 2):** Wenn keine Anführungszeichen da sind, matcht er alles bis zum nächsten Komma.
|
||||
|
||||
---
|
||||
|
||||
### Anwendung in JavaScript (Beispiel)
|
||||
|
||||
Da du das Ergebnis sicherlich in einem Array von einzelnen Werten brauchst, kannst du den Regex wie folgt anwenden. Hierbei nutzen wir `matchAll`, um die Treffer sauber zu trennen und die Anführungszeichen direkt zu entfernen:
|
||||
|
||||
```javascript
|
||||
const input = '"very big, soft computer mouse","the cutest peripheral ever",10,39.90';
|
||||
const regex = /"([^"\\]*(?:\\.[^"\\]*)*)"|([^,]+)/g;
|
||||
|
||||
const matches = [...input.matchAll(regex)];
|
||||
|
||||
const result = matches.map((match) => {
|
||||
// Wenn Gruppe 1 existiert, war es ein String in Anführungszeichen
|
||||
// Wenn Gruppe 2 existiert, war es ein unberührter Wert (Zahl)
|
||||
const value = match[1] !== undefined ? match[1] : match[2].trim();
|
||||
|
||||
// Optional: Datentypen konvertieren
|
||||
if (!isNaN(value) && value !== '') {
|
||||
return Number(value);
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
### Das Ergebnis (Output)
|
||||
|
||||
Nach dem Parsen erhältst du ein sauberes Array, bei dem die Kommas innerhalb der Strings ignoriert wurden und die Zahlen einsatzbereit sind:
|
||||
|
||||
```json
|
||||
["very big, soft computer mouse", "the cutest peripheral ever", 10, 39.9]
|
||||
```
|
||||
@@ -0,0 +1 @@
|
||||
"very big, soft computer mouse","the cutest peripheral ever",10,39.90
|
||||
|
@@ -0,0 +1,11 @@
|
||||
Code,Short Description,Tagline,Quantity,Price
|
||||
MUG0007,coffee mug with LCD level indicator,never again reach for the empty mug,20,49.90
|
||||
MUG0013,coffee mug with bluetooth-connected coffee grounds scanner for automatized fortune telling,put the smart into coffee reading,20,99.90
|
||||
OFF3145,pen with pre-warmed ink (tested on the South Pole),the pen is mightier than the cold,50,29.90
|
||||
COM1001,ambidextrous computer mouse,end the dictate of left and right,10,19.90
|
||||
COM0404,Easter egg themed webcam for your monitor,put an Easter egg on hardware too,20,149.90
|
||||
COM0001,Vulcan language vi cheatsheet,learn vi and Vulcan at the same time,3,9.90
|
||||
COM1536,Klingon language emacs cheatsheet,learn emacs and Klingon at the same time,50,9.90
|
||||
MOB0555,smartphone case with built-in screen,never miss a message,20,39.90
|
||||
|
||||
|
||||
|
Binary file not shown.
@@ -0,0 +1,57 @@
|
||||
import fs from 'node:fs';
|
||||
import zlib from 'node:zlib';
|
||||
import color from 'chalk';
|
||||
|
||||
const data = fs.readFileSync('data/products.csv', 'utf-8');
|
||||
const products = data.split('\n');
|
||||
const header = products.shift().split(',');
|
||||
// console.log('header', header); // => Code,Short Description,Tagline,Quantity,Price
|
||||
|
||||
const convertCsvToJson = (productRow) => {
|
||||
// console.log('products', products);
|
||||
// console.log('ar', ar);
|
||||
|
||||
const cols = productRow.split(/\s*,\s*/);
|
||||
// console.log(product);
|
||||
// let obj = {};
|
||||
|
||||
// for (let i = 0; i < header.length; i++) {
|
||||
// obj[header[i]] = cols[i];
|
||||
// }
|
||||
|
||||
const product = header.reduce((obj, str, idx) => {
|
||||
obj[str] = cols[idx];
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
return product;
|
||||
};
|
||||
|
||||
const entries = products
|
||||
.filter((row) => row !== '') //
|
||||
.map(convertCsvToJson);
|
||||
console.log(entries);
|
||||
|
||||
// fs.writeFile('a.json', JSON.stringify(entries), 'UTF-8', (err) => {
|
||||
// console.warn(err);
|
||||
// });
|
||||
|
||||
const compressedData = zlib.gzipSync(JSON.stringify(entries));
|
||||
try {
|
||||
fs.writeFileSync('data/products.json.gz', compressedData);
|
||||
console.log('compressed file');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
/*
|
||||
Übung 27: Ohne Umwege
|
||||
|
||||
Die Datei products.csv soll in eine products.json umgewandelt werden und in products.json.gz komprimiert werden.
|
||||
*/
|
||||
|
||||
/*
|
||||
Übung 27: Ohne Umwege
|
||||
|
||||
Die Datei products.csv soll in eine products.json umgewandelt werden und in products.json.gz komprimiert werden.
|
||||
*/
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "u27_zlib",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "u27_zlib",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"chalk": "^6.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-6.0.1.tgz",
|
||||
"integrity": "sha512-/Ce6KNm3vIbWdMlNna6RVIZ/ICQxnJxCicet5LBKK9ZffBkqzDw0xh9EiKSljdRtiIQ1S1z4YgcscUUGzNCWrA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "u27_zlib",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"chalk": "^6.0.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// const crypto = require('node:crypto');
|
||||
import crypto from 'node:crypto';
|
||||
import _ from 'lodash';
|
||||
|
||||
const PASSWORD_LENGTH = 10;
|
||||
const s = '23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ!.,;#$%/+*';
|
||||
|
||||
const buf = crypto.randomBytes(PASSWORD_LENGTH);
|
||||
|
||||
console.log('s.length:', s.length); // => 64
|
||||
console.log('buf:', buf); // => <Buffer 9a 28 4f d6 32 7a 6d 44 f0 3e>
|
||||
console.log('Array:', Array.from(buf)); // => [ 17, 181, 126, 182, 190, 212, 137, 233, 140, 75]
|
||||
const password = Array.from(buf)
|
||||
.map((byte) => s.charAt(byte % s.length)) // => kZ+!+pbMed
|
||||
.join('');
|
||||
|
||||
console.log(password);
|
||||
|
||||
const generatePassword = (length) => {
|
||||
const chars = '23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ!.,;#$%/+*'.split('');
|
||||
return _.shuffle(chars)
|
||||
.slice(0, length + 1)
|
||||
.join('');
|
||||
};
|
||||
|
||||
const pwd = generatePassword(10);
|
||||
console.log('Password: ', pwd);
|
||||
|
||||
// Übung 28: Passwortgenerator
|
||||
|
||||
// Was macht der folgende Code?
|
||||
|
||||
// OK: Der Titel verrät es schon. Versuche dennoch, das Programm zu verstehen! Benutze die Dokumentation der Standardbibliothek, um nachzuschlagen, was crypto.randomBytes(…) genau macht!
|
||||
|
||||
// Bonusfrage: Warum sind in den Zeichen «1», «i» und «l» nicht enthalten, genau so wenig wie «0» und «o»?
|
||||
|
||||
// const asciiLetters = Array.from({ length: 26 }, (_, i) =>
|
||||
// String.fromCharCode(65 + i) + String.fromCharCode(97 + i)
|
||||
// ).join(''); // "AaBbCc..." oder getrennt sortieren
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "u28_password-generator",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "u28_password-generator",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"lodash": "^4.18.1"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
|
||||
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "u28_password-generator",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"lodash": "^4.18.1"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,37 @@
|
||||
// const fs = require('node:fs');
|
||||
// const zlib = require('node:zlib');
|
||||
import fs from 'node:fs';
|
||||
import zlib from 'node:zlib';
|
||||
|
||||
const gzipCompressor = zlib.createGzip();
|
||||
|
||||
const inputStream = fs.createReadStream('data/products.html');
|
||||
const outputStream = fs.createWriteStream('data/products.html.gz');
|
||||
|
||||
inputStream.on('data', (chunk) => {
|
||||
console.log('Pakete (data chunks) werden geladen: ', chunk.length);
|
||||
// outputStream.write(zlib.gzipSync(data));
|
||||
});
|
||||
|
||||
outputStream.on('finish', () => {
|
||||
console.log('Process finished');
|
||||
});
|
||||
|
||||
inputStream.pipe(gzipCompressor).pipe(outputStream);
|
||||
|
||||
// Übung 29: Datenströme
|
||||
// Schreibe Codebeispiel 239 um, ohne die Funktion pipe(…) zu verwenden!
|
||||
|
||||
// TIPP: Um eine Datei päckchenweise lesen- und schreiben zu können, gibt es für das fs Modul die Methoden createReadStream und createWriteStream.
|
||||
|
||||
// ÜBUNG BEREITS GELÖST!!!
|
||||
|
||||
// Die wichtigsten WritableStream-Events im Überblick
|
||||
|
||||
// - 'finish': Feuert, nachdem stream.end() aufgerufen wurde und alle gepufferten Daten erfolgreich auf das Ziellaufwerk geschrieben wurden.
|
||||
|
||||
// - 'close': Feuert, wenn der zugrundeliegende File Descriptor / die Ressource vollständig geschlossen wurde.
|
||||
|
||||
// - 'drain': Feuert, wenn der interne Puffer voll war (write() gab false zurück) und nun wieder bereit für neue Daten ist.
|
||||
|
||||
// - 'error': Feuert, wenn beim Schreiben ein Fehler auftritt (z. B. fehlende Schreibrechte oder volle Festplatte).
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "03_stream",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"type": "module"
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import os from 'node:os';
|
||||
|
||||
console.log(os.platform());
|
||||
console.log(os.cpus().length);
|
||||
|
||||
console.log(`I am running on a machine with ${os.platform()} and ${os.cpus().length} cores.`);
|
||||
console.log(`I am running on a machine with ${os.type()} and ${os.cpus().length} cores.`);
|
||||
console.log(`I am running on a machine with ${os.version()} and ${os.cpus().length} cores.`);
|
||||
|
||||
// Weitere Informationen zum Betriebssystem
|
||||
console.log('\n--- Betriebssystem ---');
|
||||
console.log('Systemtyp:', os.type());
|
||||
console.log('Systemversion:', os.release());
|
||||
console.log('Architektur von Node.js:', os.arch());
|
||||
console.log('Computername:', os.hostname());
|
||||
|
||||
// os.cpus() liefert Informationen zu den logischen CPU-Kernen.
|
||||
const cpus = os.cpus();
|
||||
console.log('\n--- Prozessor ---');
|
||||
console.log('Logische CPU-Kerne:', cpus.length);
|
||||
console.log('CPU-Modell:', cpus[0]?.model ?? 'Unbekannt');
|
||||
|
||||
// Die Speicherangaben kommen in Bytes. 1024 ** 3 Bytes entsprechen einem GiB.
|
||||
const totalMemory = os.totalmem();
|
||||
const freeMemory = os.freemem();
|
||||
const usedMemory = totalMemory - freeMemory;
|
||||
|
||||
function formatMemory(bytes) {
|
||||
return `${(bytes / 1024 ** 3).toFixed(2)} GiB`;
|
||||
}
|
||||
|
||||
console.log('\n--- Arbeitsspeicher ---');
|
||||
console.log('Gesamt:', formatMemory(totalMemory));
|
||||
console.log('Frei:', formatMemory(freeMemory));
|
||||
console.log('Belegt:', formatMemory(usedMemory));
|
||||
|
||||
// os.uptime() gibt die Laufzeit des Betriebssystems in Sekunden zurück.
|
||||
const uptime = os.uptime();
|
||||
const hours = Math.floor(uptime / 3600);
|
||||
const minutes = Math.floor((uptime % 3600) / 60);
|
||||
console.log(`\nSystemlaufzeit: ${hours} Stunden und ${minutes} Minuten`);
|
||||
|
||||
console.log('\n--- Benutzer und Verzeichnisse ---');
|
||||
console.log('Benutzername:', os.userInfo().username);
|
||||
console.log('Home-Verzeichnis:', os.homedir());
|
||||
console.log('Temporäres Verzeichnis:', os.tmpdir());
|
||||
|
||||
// Jede Netzwerkschnittstelle kann mehrere IPv4- und IPv6-Adressen haben.
|
||||
console.log('\n--- Netzwerkschnittstellen ---');
|
||||
for (const [name, addresses] of Object.entries(os.networkInterfaces())) {
|
||||
for (const address of addresses ?? []) {
|
||||
console.log(`${name}: ${address.address} (${address.family}${address.internal ? ', intern' : ''})`);
|
||||
}
|
||||
}
|
||||
|
||||
// Übung 32: Information zum Betriebssystem und der Anzahl der vorhandenen CPUs
|
||||
|
||||
// Im Kontext einer Monitoring-Lösung benötigt ein Kunde eine kleine CLI (Command Line Interface)-Anwendung, die es erlaubt, das aktuelle Betriebssystem und die Anzahl der CPUs auf dem jeweiligen Rechner zu ermitteln.
|
||||
|
||||
// Vorgehensweise
|
||||
|
||||
// 1.Schau dir die Online-Dokumentation zum os-Modul der Standardbibliothek an.
|
||||
// 2.Erstelle dann ein kurzes Node.js-Programm, das ausgibt, auf welcher Plattform es gerade läuft (also etwa »linux«, »darwin« (OS X) oder »win32«) und wie viele Kerne der Rechner hat.
|
||||
|
||||
// Hier eine mögliche Beispielausgabe:
|
||||
|
||||
// I am running on a machine with linux and 2 cores.
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "u32_os-info",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"type": "module"
|
||||
}
|
||||
Binary file not shown.
@@ -4,5 +4,6 @@
|
||||
"titleBar.activeBackground": "#6bd0ab",
|
||||
"titleBar.inactiveForeground": "#ddd",
|
||||
"titleBar.inactiveBackground": "#6ca38f"
|
||||
}
|
||||
},
|
||||
"editor.tabSize": 2
|
||||
}
|
||||
|
||||
@@ -12087,14 +12087,22 @@ blockquote {
|
||||
.header-main {
|
||||
width: 100%;
|
||||
height: 30vh; /* viewport height */
|
||||
height: 300px;
|
||||
background-color: #ddd;
|
||||
height: 400px;
|
||||
background: black url("../img/header-bg.webp") center no-repeat border-box;
|
||||
background-size: cover;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 20px solid rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
.logo-main img,
|
||||
.logo-main svg {
|
||||
width: 320px;
|
||||
height: auto;
|
||||
max-width: 320px;
|
||||
}
|
||||
.logo-main figcaption {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
@@ -12147,55 +12155,4 @@ blockquote {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.box {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 0.5rem solid #333;
|
||||
background-color: salmon;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.header-main {
|
||||
width: 100%;
|
||||
height: 30vh; /* viewport height */
|
||||
height: 300px;
|
||||
background-color: #ddd;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.logo-main figcaption {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.menu-main {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.menu-main ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.menu-main ul.list {
|
||||
display: flex;
|
||||
}
|
||||
.menu-main ul.list li a {
|
||||
display: inline-block;
|
||||
color: #333;
|
||||
background-color: salmon;
|
||||
padding: 0.5rem 1rem;
|
||||
text-decoration: none;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=main.css.map */
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
@@ -5,6 +5,14 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Webseite mit HTML & CSS (SCSS)</title>
|
||||
<!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" /> -->
|
||||
|
||||
<link rel="icon" type="image/png" href="/favicon/favicon-96x96.png" sizes="96x96" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon/favicon.svg" />
|
||||
<link rel="shortcut icon" href="/favicon/favicon.ico" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" />
|
||||
<meta name="apple-mobile-web-app-title" content="JS Course" />
|
||||
<link rel="manifest" href="/favicon/site.webmanifest" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css" />
|
||||
<script src="assets/js/build.js" defer></script>
|
||||
</head>
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
.header-main {
|
||||
width: 100%;
|
||||
height: 30vh; /* viewport height */
|
||||
height: 300px;
|
||||
height: 400px;
|
||||
|
||||
// https://cssreference.io/property/background/
|
||||
background: black url('../img/header-bg.webp') center no-repeat border-box;
|
||||
|
||||
background-size: cover;
|
||||
|
||||
background-color: #ddd;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
border: 20px solid rgba(white, 0.25);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
.logo-main figcaption {
|
||||
.logo-main {
|
||||
img,
|
||||
svg {
|
||||
width: 320px;
|
||||
height: auto;
|
||||
max-width: 320px;
|
||||
}
|
||||
figcaption {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
@@ -7,4 +14,5 @@
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,59 +10,3 @@
|
||||
@import '04_plugins/index';
|
||||
// 05 Modules
|
||||
@import '05_modules/index';
|
||||
|
||||
.box {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 0.5rem solid #333;
|
||||
background-color: salmon;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.header-main {
|
||||
width: 100%;
|
||||
height: 30vh; /* viewport height */
|
||||
height: 300px;
|
||||
|
||||
background-color: #ddd;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.logo-main figcaption {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.menu-main {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
ul.list {
|
||||
display: flex;
|
||||
li {
|
||||
a {
|
||||
display: inline-block;
|
||||
color: #333;
|
||||
background-color: salmon;
|
||||
padding: 0.5rem 1rem;
|
||||
text-decoration: none;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
<header class="header-main">
|
||||
<div class="content-box">
|
||||
<figure class="logo-main">
|
||||
<img src="https://dummyimage.com/280x160/555/000.jpg" alt="Logo" />
|
||||
<figcaption>Logo - Slogan</figcaption>
|
||||
<img src="/assets/img/logo-js.min.svg" alt="Logo - JS Course" />
|
||||
<figcaption>JS course</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"server": "npx http-server -p 3000 -c-1",
|
||||
"css": "npx sass dev/scss/main.scss:assets/css/main.css -w -q",
|
||||
"js": "npx esbuild dev/js/main.js --watch --bundle --sourcemap --outfile=assets/js/build.js",
|
||||
"dev": "run-p css js"
|
||||
"dev": "run-p css js server"
|
||||
},
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.28.2",
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"workbench.colorCustomizations": {
|
||||
"titleBar.activeForeground": "#333",
|
||||
"titleBar.activeBackground": "#6bd0ab",
|
||||
"titleBar.inactiveForeground": "#ddd",
|
||||
"titleBar.inactiveBackground": "#6ca38f"
|
||||
},
|
||||
"editor.tabSize": 2
|
||||
}
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 849 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 642 483">
|
||||
<path d="M803.541 858.114h641.02v489.042h-641.02z" fill="none" transform="matrix(1 0 0 .98569 -803.541 -845.831)"/>
|
||||
<path d="m200.993 79.566-1.106 1.106c-4.992 4.992-13.087 4.992-18.08 0L159.18 58.044c-4.992-4.993-4.992-13.087 0-18.08l1.106-1.105c4.993-4.993 13.087-4.993 18.08 0l22.627 22.627c4.992 4.993 4.992 13.088 0 18.08" fill="#75cbcc" fill-rule="nonzero" transform="translate(-222.359 -66.506)scale(3.5623)"/>
|
||||
<path d="m178.918 101.6 21.522-21.522c5.298-5.298 5.298-13.887 0-19.185a13 13 0 0 0-.618-.577l-17.95-17.95c4.525 5.117 4.525 12.829.003 17.947q-.317.278-.621.58l-21.522 21.521c-5.298 5.298-5.298 13.888 0 19.186 5.299 5.298 13.888 5.298 19.186 0" fill="#ace0e0" fill-rule="nonzero" transform="translate(-222.359 -66.506)scale(3.5623)"/>
|
||||
<path d="m99.555 61.446 1.106-1.106c4.992-4.993 13.087-4.993 18.08 0l22.628 22.628c4.992 4.993 4.992 13.087 0 18.08l-1.106 1.105c-4.993 4.993-13.087 4.993-18.08 0L99.555 79.525c-4.992-4.993-4.992-13.087 0-18.079" fill="#75cbcc" fill-rule="nonzero" transform="translate(-222.359 -66.506)scale(3.5623)"/>
|
||||
<path d="m121.63 39.411-21.522 21.522c-5.298 5.298-5.298 13.888 0 19.185q.302.299.617.577l17.95 17.949c-4.524-5.117-4.525-12.829-.003-17.947a13 13 0 0 0 .621-.58l21.522-21.522c5.298-5.298 5.298-13.887 0-19.186-5.297-5.295-13.887-5.295-19.185.002" fill="#ace0e0" fill-rule="nonzero" transform="translate(-222.359 -66.506)scale(3.5623)"/>
|
||||
<path d="M206.166 330.121q0 5-1.229 8.958t-3.625 6.688q-2.395 2.729-5.896 4.187t-8.041 1.458q-4.125 0-8.417-1.166.084-1.208.208-2.396.125-1.187.209-2.354.083-.708.52-1.146.438-.438 1.355-.438.75 0 1.979.375 1.228.375 3.312.375 2.751 0 4.917-.833a8.7 8.7 0 0 0 3.625-2.583q1.458-1.75 2.229-4.479t.771-6.48v-39.25h8.083zM251.333 300.371q-.375.625-.813.937-.436.313-1.062.313-.708 0-1.667-.709a29 29 0 0 0-2.396-1.562q-1.437-.853-3.458-1.563-2.02-.708-4.896-.708-2.708 0-4.771.729-2.062.73-3.458 1.979a8.1 8.1 0 0 0-2.104 2.938q-.708 1.687-.708 3.646 0 2.499 1.229 4.146 1.229 1.645 3.25 2.812t4.583 2.021a790 790 0 0 1 5.25 1.771 61 61 0 0 1 5.25 2.062 18.5 18.5 0 0 1 4.583 2.896q2.022 1.75 3.25 4.292 1.23 2.542 1.23 6.25 0 3.916-1.334 7.354a16.9 16.9 0 0 1-3.896 5.979q-2.562 2.542-6.291 4t-8.479 1.458q-5.834 0-10.584-2.104t-8.125-5.687l2.334-3.834a3.1 3.1 0 0 1 .812-.77q.48-.313 1.063-.313.541 0 1.229.438.687.436 1.562 1.104.876.666 2 1.458t2.563 1.458q1.437.667 3.271 1.105t4.125.437q2.875 0 5.125-.792 2.25-.79 3.812-2.229a9.66 9.66 0 0 0 2.396-3.437q.834-2 .833-4.459 0-2.707-1.229-4.437t-3.229-2.896-4.583-1.979a978 978 0 0 1-5.25-1.667 56 56 0 0 1-5.25-1.979 17 17 0 0 1-4.584-2.917q-2-1.791-3.229-4.479-1.229-2.687-1.229-6.646 0-3.166 1.229-6.125a15.7 15.7 0 0 1 3.583-5.25q2.355-2.291 5.792-3.666 3.438-1.375 7.896-1.375 5 0 9.104 1.583a21.5 21.5 0 0 1 7.229 4.583zM329.25 338.412q.666 0 1.166.542l3.209 3.458q-3.667 4.25-8.896 6.625t-12.646 2.375q-6.417 0-11.667-2.229t-8.958-6.25q-3.708-4.02-5.75-9.646-2.042-5.625-2.042-12.375t2.125-12.375 5.979-9.666q3.855-4.042 9.23-6.271 5.374-2.229 11.875-2.229 6.375 0 11.25 2.041 4.875 2.043 8.583 5.542l-2.667 3.708a2.2 2.2 0 0 1-.646.688q-.395.271-1.062.271-.75 0-1.833-.813-1.084-.812-2.834-1.812t-4.375-1.813-6.458-.812q-4.625 0-8.458 1.604a18.5 18.5 0 0 0-6.605 4.646q-2.77 3.042-4.312 7.416-1.542 4.376-1.542 9.875 0 5.584 1.604 9.959t4.375 7.396a18.5 18.5 0 0 0 6.542 4.604q3.77 1.583 8.146 1.583 2.667 0 4.812-.312a19.7 19.7 0 0 0 3.959-.98 16.6 16.6 0 0 0 3.375-1.687 24 24 0 0 0 3.104-2.438q.708-.625 1.417-.625M397 320.912q0 6.71-2.125 12.313t-6 9.646-9.313 6.271-12.021 2.229-12-2.229-9.291-6.271q-3.876-4.042-6-9.646t-2.125-12.313q0-6.708 2.125-12.312t6-9.667q3.875-4.062 9.291-6.312t12-2.25 12.021 2.25 9.313 6.312 6 9.667Q397 314.204 397 320.912m-8.292 0q0-5.5-1.5-9.875-1.5-4.374-4.25-7.395t-6.667-4.646q-3.916-1.625-8.75-1.625-4.791 0-8.708 1.625t-6.688 4.646q-2.77 3.021-4.27 7.395-1.5 4.376-1.5 9.875 0 5.5 1.5 9.855 1.5 4.353 4.27 7.375 2.772 3.02 6.688 4.625t8.708 1.604q4.834 0 8.75-1.604t6.667-4.625q2.75-3.022 4.25-7.375 1.5-4.355 1.5-9.855M431.583 344.329q3.708 0 6.625-1.25t4.937-3.5q2.021-2.25 3.084-5.375 1.062-3.125 1.062-6.875v-36.292h8.042v36.292q0 5.167-1.646 9.583-1.646 4.418-4.708 7.646-3.063 3.23-7.479 5.063t-9.917 1.833-9.917-1.833-7.5-5.063q-3.083-3.228-4.729-7.646-1.646-4.416-1.646-9.583v-36.292h8.042v36.25q0 3.75 1.062 6.875t3.084 5.375q2.02 2.25 4.958 3.521 2.938 1.272 6.646 1.271M486.375 319.954q3.5 0 6.187-.854t4.5-2.417a10 10 0 0 0 2.729-3.729q.917-2.166.917-4.792 0-5.333-3.5-8.041t-10.5-2.709h-8.833v22.542zm27.583 30.792h-7.167q-2.208 0-3.25-1.709l-15.5-21.333q-.708-1-1.521-1.437t-2.52-.438h-6.125v24.917h-8.042v-59.709h16.875q5.667 0 9.792 1.146t6.812 3.313 3.979 5.229 1.292 6.854q0 3.166-1 5.917a15.6 15.6 0 0 1-2.896 4.937q-1.896 2.188-4.625 3.729-2.729 1.542-6.187 2.334 1.54.875 2.666 2.541zM552.583 300.371q-.375.625-.813.937t-1.062.313q-.708 0-1.667-.709a29 29 0 0 0-2.396-1.562q-1.437-.853-3.458-1.563-2.02-.708-4.896-.708-2.708 0-4.771.729-2.062.73-3.458 1.979a8.1 8.1 0 0 0-2.104 2.938q-.708 1.687-.708 3.646 0 2.499 1.229 4.146 1.229 1.645 3.25 2.812t4.583 2.021a790 790 0 0 1 5.25 1.771 61 61 0 0 1 5.25 2.062 18.5 18.5 0 0 1 4.583 2.896q2.022 1.75 3.25 4.292 1.23 2.542 1.23 6.25 0 3.916-1.334 7.354a16.9 16.9 0 0 1-3.896 5.979q-2.562 2.542-6.291 4t-8.479 1.458q-5.834 0-10.584-2.104t-8.125-5.687l2.334-3.834a3.1 3.1 0 0 1 .812-.77q.48-.313 1.063-.313.541 0 1.229.438.687.436 1.562 1.104.875.666 2 1.458t2.563 1.458q1.437.667 3.271 1.105t4.125.437q2.875 0 5.125-.792 2.25-.79 3.812-2.229a9.66 9.66 0 0 0 2.396-3.437q.833-2 .833-4.459 0-2.707-1.229-4.437t-3.229-2.896-4.583-1.979a978 978 0 0 1-5.25-1.667 56 56 0 0 1-5.25-1.979 17 17 0 0 1-4.584-2.917q-2-1.791-3.229-4.479-1.229-2.687-1.229-6.646 0-3.166 1.229-6.125a15.7 15.7 0 0 1 3.583-5.25q2.355-2.291 5.792-3.666 3.438-1.375 7.896-1.375 5 0 9.104 1.583a21.5 21.5 0 0 1 7.229 4.583zM604.083 344.162l-.042 6.584H567.25v-59.709h36.791v6.584h-28.708v19.833h23.25v6.333h-23.25v20.375z" fill-rule="nonzero" transform="translate(-78.559 53)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.1 KiB |
@@ -0,0 +1,42 @@
|
||||
"use strict";
|
||||
(() => {
|
||||
// dev/js/main.js
|
||||
(() => {
|
||||
const DOM = {
|
||||
chuckNorrisJoke: document.querySelector(".chuck-norris-joke"),
|
||||
jokeText: document.querySelector(".joke-text"),
|
||||
buttonGetJoke: document.querySelector(".button-get-joke")
|
||||
};
|
||||
console.log(DOM);
|
||||
const init = () => {
|
||||
console.log("init...");
|
||||
DOM.buttonGetJoke.addEventListener("click", onClickGetJoke);
|
||||
getJoke().then((data) => {
|
||||
generateJoke(data.value);
|
||||
});
|
||||
};
|
||||
const onClickGetJoke = (e) => {
|
||||
getJoke().then((data) => {
|
||||
generateJoke(data.value);
|
||||
});
|
||||
};
|
||||
const getJoke = async () => {
|
||||
try {
|
||||
const response = await fetch("https://api.chucknorris.io/jokes/random");
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP-Request went wrong.");
|
||||
}
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Error: ", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
const generateJoke = (joke) => {
|
||||
DOM.jokeText.textContent = joke;
|
||||
};
|
||||
init();
|
||||
})();
|
||||
})();
|
||||
//# sourceMappingURL=build.js.map
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../dev/js/main.js"],
|
||||
"sourcesContent": ["'use strict';\n\n(() => {\n // === DOM & VARS =======\n const DOM = {\n chuckNorrisJoke: document.querySelector('.chuck-norris-joke'),\n jokeText: document.querySelector('.joke-text'),\n buttonGetJoke: document.querySelector('.button-get-joke'),\n };\n\n console.log(DOM);\n\n // === INIT =============\n const init = () => {\n console.log('init...');\n DOM.buttonGetJoke.addEventListener('click', onClickGetJoke);\n\n // Funktionaufrufe\n getJoke().then((data) => {\n generateJoke(data.value);\n });\n };\n\n // === EVENTHANDLER =====\n const onClickGetJoke = (e) => {\n getJoke().then((data) => {\n generateJoke(data.value);\n });\n };\n\n // === XHR/FETCH ========\n const getJoke = async () => {\n try {\n const response = await fetch('https://api.chucknorris.io/jokes/random');\n if (!response.ok) {\n throw new Error('HTTP-Request went wrong.');\n }\n const data = await response.json();\n return data; // -> Promise\n } catch (error) {\n console.error('Error: ', error);\n\n throw error;\n }\n };\n\n // === FUNCTIONS ========\n const generateJoke = (joke) => {\n DOM.jokeText.textContent = joke;\n };\n\n init();\n})();\n"],
|
||||
"mappings": ";;;AAEA,GAAC,MAAM;AAEL,UAAM,MAAM;AAAA,MACV,iBAAiB,SAAS,cAAc,oBAAoB;AAAA,MAC5D,UAAU,SAAS,cAAc,YAAY;AAAA,MAC7C,eAAe,SAAS,cAAc,kBAAkB;AAAA,IAC1D;AAEA,YAAQ,IAAI,GAAG;AAGf,UAAM,OAAO,MAAM;AACjB,cAAQ,IAAI,SAAS;AACrB,UAAI,cAAc,iBAAiB,SAAS,cAAc;AAG1D,cAAQ,EAAE,KAAK,CAAC,SAAS;AACvB,qBAAa,KAAK,KAAK;AAAA,MACzB,CAAC;AAAA,IACH;AAGA,UAAM,iBAAiB,CAAC,MAAM;AAC5B,cAAQ,EAAE,KAAK,CAAC,SAAS;AACvB,qBAAa,KAAK,KAAK;AAAA,MACzB,CAAC;AAAA,IACH;AAGA,UAAM,UAAU,YAAY;AAC1B,UAAI;AACF,cAAM,WAAW,MAAM,MAAM,yCAAyC;AACtE,YAAI,CAAC,SAAS,IAAI;AAChB,gBAAM,IAAI,MAAM,0BAA0B;AAAA,QAC5C;AACA,cAAM,OAAO,MAAM,SAAS,KAAK;AACjC,eAAO;AAAA,MACT,SAAS,OAAO;AACd,gBAAQ,MAAM,WAAW,KAAK;AAE9B,cAAM;AAAA,MACR;AAAA,IACF;AAGA,UAAM,eAAe,CAAC,SAAS;AAC7B,UAAI,SAAS,cAAc;AAAA,IAC7B;AAEA,SAAK;AAAA,EACP,GAAG;",
|
||||
"names": []
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Webseite mit HTML & CSS (SCSS)</title>
|
||||
<!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" /> -->
|
||||
|
||||
<link rel="icon" type="image/png" href="/favicon/favicon-96x96.png" sizes="96x96" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon/favicon.svg" />
|
||||
<link rel="shortcut icon" href="/favicon/favicon.ico" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" />
|
||||
<meta name="apple-mobile-web-app-title" content="JS Course" />
|
||||
<link rel="manifest" href="/favicon/site.webmanifest" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css" />
|
||||
<script src="assets/js/build.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- header.header-main>.content-box>figure.logo-main>img+figc -->
|
||||
<header class="header-main">
|
||||
<div class="content-box">
|
||||
<figure class="logo-main">
|
||||
<img src="https://dummyimage.com/280x160/555/000.jpg" alt="Logo" />
|
||||
<figcaption>Logo - Slogan</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</header>
|
||||
<!-- nav.menu-main>ul.list>li*4>a[href="#"]{Link $} -->
|
||||
<nav class="menu-main">
|
||||
<ul class="list">
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/about.html">About</a></li>
|
||||
<li>
|
||||
<a href="#dropdown">Projects</a>
|
||||
<!-- ul.sublist>li*3>a[href="#"]{Project $} -->
|
||||
<ul class="sublist">
|
||||
<li><a href="/projects/01_jokes.html">01 Chuck Norris Jokes</a></li>
|
||||
<li><a href="#">Project 2</a></li>
|
||||
<li><a href="#">Project 3</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="/contact.html">Contact</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<main>
|
||||
<div class="container py-5">
|
||||
<h1>Kontakt</h1>
|
||||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Amet, iste?</p>
|
||||
<form class="form-contact">
|
||||
<div class="row">
|
||||
<!-- .col>.mb-3>label.form-label -->
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="input-firstname" class="form-label">First name:</label>
|
||||
<input
|
||||
type="text"
|
||||
name="firstname"
|
||||
id="input-firstname"
|
||||
class="form-control input-firstname"
|
||||
required />
|
||||
</div>
|
||||
</div>
|
||||
<!-- ▲ /col ▲ -->
|
||||
<!-- .col>.mb-3>label.form-label -->
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="input-lastname" class="form-label">Last name:</label>
|
||||
<input type="text" name="lastname" id="input-lastname" class="form-control input-lastname" required />
|
||||
</div>
|
||||
</div>
|
||||
<!-- ▲ /col ▲ -->
|
||||
</div>
|
||||
<!-- .row>.col>.mb-3>label.form-label+input:email.form-control -->
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="mb-3">
|
||||
<label for="input-email" class="form-label">E-mail</label>
|
||||
<input type="email" name="email" id="input-email" class="form-control input-email" required />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="mb-3">
|
||||
<label for="input-subject" class="form-label">Subject</label>
|
||||
<input type="text" name="subject" id="input-subject" class="form-control input-subject" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- .row>.col>.mb-3>label.form-label+textarea.form-control -->
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="mb-3">
|
||||
<label for="textarea-message" class="form-label">Message</label>
|
||||
|
||||
<textarea
|
||||
name="message"
|
||||
id="textarea-message"
|
||||
cols="12"
|
||||
rows="8"
|
||||
class="form-control textarea-message"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- .row>.col>.mb-3>button:submit.btn.btn-dark.button-submit -->
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="mb-3">
|
||||
<button type="submit" class="btn btn-dark button-submit">Send</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,53 @@
|
||||
'use strict';
|
||||
|
||||
(() => {
|
||||
// === DOM & VARS =======
|
||||
const DOM = {
|
||||
chuckNorrisJoke: document.querySelector('.chuck-norris-joke'),
|
||||
jokeText: document.querySelector('.joke-text'),
|
||||
buttonGetJoke: document.querySelector('.button-get-joke'),
|
||||
};
|
||||
|
||||
console.log(DOM);
|
||||
|
||||
// === INIT =============
|
||||
const init = () => {
|
||||
console.log('init...');
|
||||
DOM.buttonGetJoke.addEventListener('click', onClickGetJoke);
|
||||
|
||||
// Funktionaufrufe
|
||||
getJoke().then((data) => {
|
||||
generateJoke(data.value);
|
||||
});
|
||||
};
|
||||
|
||||
// === EVENTHANDLER =====
|
||||
const onClickGetJoke = (e) => {
|
||||
getJoke().then((data) => {
|
||||
generateJoke(data.value);
|
||||
});
|
||||
};
|
||||
|
||||
// === XHR/FETCH ========
|
||||
const getJoke = async () => {
|
||||
try {
|
||||
const response = await fetch('https://api.chucknorris.io/jokes/random');
|
||||
if (!response.ok) {
|
||||
throw new Error('HTTP-Request went wrong.');
|
||||
}
|
||||
const data = await response.json();
|
||||
return data; // -> Promise
|
||||
} catch (error) {
|
||||
console.error('Error: ', error);
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// === FUNCTIONS ========
|
||||
const generateJoke = (joke) => {
|
||||
DOM.jokeText.textContent = joke;
|
||||
};
|
||||
|
||||
init();
|
||||
})();
|
||||
@@ -0,0 +1,4 @@
|
||||
@import 'bootstrap-5.3.8/bootstrap';
|
||||
// @import 'bootstrap-5.3.8/bootstrap-grid';
|
||||
// @import 'bootstrap-5.3.8/bootstrap-reboot';
|
||||
// @import 'bootstrap-5.3.8/bootstrap-utilities';
|
||||
+153
@@ -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)};
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+68
@@ -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
|
||||
Vendored
+38
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
Vendored
+216
@@ -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);
|
||||
}
|
||||
Vendored
+238
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
02_advanced/unterricht/tag17/01_website-static/dev/scss/01_frameworks/bootstrap-5.3.8/_carousel.scss
Vendored
+226
@@ -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();
|
||||
}
|
||||
}
|
||||
Vendored
+66
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
02_advanced/unterricht/tag17/01_website-static/dev/scss/01_frameworks/bootstrap-5.3.8/_dropdown.scss
Vendored
+250
@@ -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
|
||||
}
|
||||
Vendored
+9
@@ -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
@@ -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;
|
||||
}
|
||||
Vendored
+39
@@ -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();
|
||||
}
|
||||
Vendored
+12
@@ -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";
|
||||
Vendored
+42
@@ -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
@@ -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
|
||||
Vendored
+174
@@ -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;
|
||||
Vendored
+42
@@ -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";
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user