diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/main.jsx b/06_react/unterricht/tag40/01_react-app-with-tests/src/main.jsx index 38d3e9b..6897480 100644 --- a/06_react/unterricht/tag40/01_react-app-with-tests/src/main.jsx +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/main.jsx @@ -2,7 +2,8 @@ import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import 'bootstrap'; -import 'bootstrap/dist/css/bootstrap.min.css'; +// import 'bootstrap/dist/css/bootstrap.min.css'; +import './styles/main.scss'; import App from './App.jsx'; diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/abstracts/_colors.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/abstracts/_colors.scss new file mode 100644 index 0000000..452a8e5 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/abstracts/_colors.scss @@ -0,0 +1,14 @@ +/* Color Theme Swatches in Hex */ +$color-1: #5c4b51; +$color-2: #8cbeb2; +$color-3: #f2ebbf; +$color-4: #f3b562; +$color-5: #f06060; + +$color-red: $color-5; +$color-white: white; // falls weiß geändert wird z.B.: #f8f8f8 + +$color-dark-blue: #283e4a; +$linear-gradient-dark: linear-gradient(180deg, rgba(40, 62, 74, 1) 0%, rgba(24, 32, 38, 1) 100%); + +$color-link: $color-2; diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/abstracts/_index.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/abstracts/_index.scss new file mode 100644 index 0000000..2201c9a --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/abstracts/_index.scss @@ -0,0 +1,3 @@ +@forward 'colors'; +@forward 'typography'; +@forward 'variables'; diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/abstracts/_typography.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/abstracts/_typography.scss new file mode 100644 index 0000000..f633381 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/abstracts/_typography.scss @@ -0,0 +1,9 @@ +$fallback-serif: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif; +$fallback-sans-serif: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + +$font-headline: 'Playfair Display', $fallback-serif; +$font-subclaim: $fallback-sans-serif; + +$font-menu: $fallback-sans-serif; +$font-copy: 'Source Sans 3', $fallback-sans-serif; +$font-quote: $fallback-serif; diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/abstracts/_variables.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/abstracts/_variables.scss new file mode 100644 index 0000000..e69de29 diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/base/_index.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/base/_index.scss new file mode 100644 index 0000000..26fa81a --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/base/_index.scss @@ -0,0 +1,2 @@ +@forward 'theme'; +@forward 'utils'; diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/base/_theme.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/base/_theme.scss new file mode 100644 index 0000000..d3e0ab2 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/base/_theme.scss @@ -0,0 +1,53 @@ +@use '../abstracts' as *; + +// Allgemeine Formatierungen für die ganze Webanwendung + +*, +html { + box-sizing: border-box; +} + +html, +body, +#root { + height: 100%; + padding: 0; + margin: 0; +} + +body { + font-family: $font-copy; +} + +// Sticky footer +body, +#root { + display: flex; + flex-direction: column; +} + +main, +#main { + flex: 1 0 auto; +} + +body > footer, +.footer-main { + flex-shrink: 0; +} +// /Sticky footer + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: $font-headline; + font-weight: 700; +} + +a { + color: $color-link; + text-decoration: none; +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/base/_utils.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/base/_utils.scss new file mode 100644 index 0000000..e69de29 diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_button.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_button.scss new file mode 100644 index 0000000..f91b983 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_button.scss @@ -0,0 +1,13 @@ +.btn-custom { + &:hover, + &:focus { + background-color: #e0e0e0; + color: #333; + border: 1px solid #ccc; + } + background-color: steelblue; + color: white; + border: 1px solid #ccc; + padding: 8px 16px; + border-radius: 0px; +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_footer-main.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_footer-main.scss new file mode 100644 index 0000000..b2a2a52 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_footer-main.scss @@ -0,0 +1,59 @@ +@use '../abstracts' as *; + +.m-footer-main { + background: $color-dark-blue; // Fallback für ältere Browser + background: $linear-gradient-dark; + padding: 3rem 0; + [class^='col'] { + color: $color-white; + + display: flex; + justify-content: center; + @media (min-width: 768px) { + justify-content: flex-start; + } + h2, + h3, + h4, + h5 { + font-size: 1.5rem; + color: $color-5; + padding: 0.5rem 0; + margin-bottom: 1rem; + letter-spacing: 2px; + text-align: center; + } + } + + @media (min-width: 576px) { + h1, + h2, + h3, + h4, + h5, + h6 { + text-align: left; + } + } + + .row { + flex-direction: column; + > div { + &:nth-child(1) { + order: 3; + } + &:nth-child(2) { + order: 2; + } + &:nth-child(3) { + order: 1; + } + } + } + + @media (min-width: 576px) { + .row { + flex-direction: row-reverse; + } + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_header-main.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_header-main.scss new file mode 100644 index 0000000..f810d50 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_header-main.scss @@ -0,0 +1,85 @@ +@use '../abstracts' as *; + +.header-main { + position: relative; + + width: 100%; + min-height: 400px; + .content-box { + position: relative; + z-index: 2; + display: flex; + justify-content: center; + align-items: center; + width: auto; + margin: 0 auto; + height: 100%; + max-width: 360px; + max-height: 380px; + } + + background: $color-3 url('/img/header-bg.jpg') center no-repeat; + background-size: cover; + + &--min { + height: 150px; + background-color: $color-2; + display: flex; + justify-content: center; + align-items: center; + .content-box { + figure { + width: 150px; + } + } + } + + .splide { + position: absolute; + z-index: 1; + height: 100%; + width: 100%; + top: 0; + overflow: hidden; + .splide__track { + height: 100%; + .splide__slide img { + object-fit: cover; + width: 100%; + height: 100%; + } + .splider-content { + &::after { + content: ''; + position: absolute; + z-index: 1; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.2); + } + + height: 100%; + padding: 0; + } + } + } + + // .content-box { + // figure { + // width: 280px; + // figcaption { + // position: absolute; + // clip: rect(1px, 1px, 1px, 1px); + // clip-path: inset(0 0 99.9% 99.9%); + // overflow: hidden; + // height: 1px; + // width: 1px; + + // padding: 0; + // border: 0; + // } + // } + // } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_index.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_index.scss new file mode 100644 index 0000000..6e3f1d3 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_index.scss @@ -0,0 +1,11 @@ +@forward 'button'; +@forward 'footer-main'; +@forward 'header-main'; +@forward 'inputAmount'; +@forward 'inputPrice'; +@forward 'logo-main'; +@forward 'nav-main'; +@forward 'nav-social'; +@forward 'table-products'; +// @forward 'menu-main'; +// @forward 'product-manager'; diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_inputAmount.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_inputAmount.scss new file mode 100644 index 0000000..928b429 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_inputAmount.scss @@ -0,0 +1,29 @@ +// Input Amount Component +.m-input-amount { + .input-group { + .input-group-text { + padding: 0; + display: inline-block; + overflow: hidden; + button { + border-radius: 0; + } + } + } + .input-amount { + max-width: 80px; + text-align: center; + } + + /* Chrome, Safari, Edge, Opera */ + input::-webkit-outer-spin-button, + input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + + /* Firefox */ + input[type='number'] { + appearance: textfield; + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_inputPrice.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_inputPrice.scss new file mode 100644 index 0000000..a72534a --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_inputPrice.scss @@ -0,0 +1,5 @@ +.m-input-price { + .input-price { + max-width: 120px; + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_logo-main.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_logo-main.scss new file mode 100644 index 0000000..9d5cce9 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_logo-main.scss @@ -0,0 +1,14 @@ +figure.logo-main { + width: 280px; + figcaption { + position: absolute; + clip: rect(1px, 1px, 1px, 1px); + clip-path: inset(0 0 99.9% 99.9%); + overflow: hidden; + height: 1px; + width: 1px; + + padding: 0; + border: 0; + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_menu-main.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_menu-main.scss new file mode 100644 index 0000000..63103a0 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_menu-main.scss @@ -0,0 +1,62 @@ +@use '../abstracts' as *; + +.menu-main { + background-color: $color-5; + + ul { + padding: 0; + margin: 0; + list-style: none; + } + + ul ul { + display: none; // TODO: change to not visible + } + ul > li:hover, + ul > li:focus, + ul > li:focus-within { + ul { + display: block; + } + } + + ul.list { + display: flex; + + justify-content: center; + li { + a { + display: inline-block; + text-decoration: none; + text-transform: uppercase; + color: $color-white; + padding: 0.5rem 1rem; + transition: all 0.4s ease-out; + &:hover, + &:focus { + background-color: $color-white; + color: $color-5; + } + } + } + } + + ul.sublist { + position: absolute; + background-color: rgba($color-5, 0.8); + li { + a { + display: inline-block; + background-color: $color-5; + color: $color-white; + padding: 0.5rem 1rem; + transition: all 0.4s ease-out; + &:hover, + &:focus { + background-color: $color-white; + color: $color-5; + } + } + } + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_nav-main.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_nav-main.scss new file mode 100644 index 0000000..2ba6a93 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_nav-main.scss @@ -0,0 +1,8 @@ +@use '../abstracts' as *; + +.m-nav-main { + .navbar-nav .nav-link.active, + .navbar-nav .nav-link.show { + color: $color-5; + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_nav-social.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_nav-social.scss new file mode 100644 index 0000000..def42a0 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_nav-social.scss @@ -0,0 +1,75 @@ +@use 'sass:color'; +@use '../abstracts' as *; + +.nav-social { + ul { + list-style: none; + padding: 0; + margin: 0; + display: flex; + justify-content: flex-start; + align-items: center; + li { + a { + color: $color-white; + display: inline-block; + padding: 0.5rem; + margin: 3px; + background-color: color.scale($color-dark-blue, $lightness: 10%); + // background-color: lighten($color-dark-blue, 5%); // deprecated + border-radius: 50%; + width: 48px; + height: 48px; + display: flex; + align-items: center; + justify-content: center; + text-decoration: none; + transition: all 0.4s ease-out; + &:hover, + &:focus { + background-color: color.scale($color-dark-blue, $lightness: 20%); + } + + &[aria-label='Youtube'] { + &:hover, + &:focus { + background-color: #f00; + } + } + &[aria-label='Meta'] { + &:hover, + &:focus { + background-color: #0064e0; + } + } + &[aria-label^='X '] { + &:hover, + &:focus { + background-color: #000; + } + } + &[aria-label^='X '] { + &:hover, + &:focus { + background-color: #000; + } + } + &[aria-label^='Instagram'] { + &:hover, + &:focus { + // background: linear-gradient( + // 9deg, + // rgba(254, 218, 117, 1) 10%, + // rgba(250, 126, 30, 1) 30%, + // rgba(239, 100, 57, 1) 43%, + // rgba(214, 41, 118, 1) 55%, + // rgba(150, 47, 191, 1) 67%, + // rgba(79, 91, 213, 1) 81% + // ); + background-color: #405de6; + } + } + } + } + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_product-manager.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_product-manager.scss new file mode 100644 index 0000000..906cc1b --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_product-manager.scss @@ -0,0 +1,37 @@ +.product-manager { + .nav-products-actions { + margin: 1rem 0; + display: flex; + justify-content: flex-end; + .list { + list-style: none; + margin: 0; + padding: 0; + display: flex; + gap: 1rem; + } + } + + table { + .th-actions { + width: 200px; + } + tbody { + td { + vertical-align: middle; + button { + margin: 3px; + } + } + } + + tfoot { + .row > * { + margin-bottom: 1rem; + @media (min-width: 992px) { + margin-bottom: 0; + } + } + } + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_table-products.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_table-products.scss new file mode 100644 index 0000000..f384994 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/components/_table-products.scss @@ -0,0 +1,13 @@ +.m-table-products { + table { + tr { + td { + vertical-align: middle; + input, + .input-group { + margin-bottom: 0 !important; + } + } + } + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/fonts/_index.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/fonts/_index.scss new file mode 100644 index 0000000..6bb01ea --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/fonts/_index.scss @@ -0,0 +1,2 @@ +// @forward 'playfair-display-v40-latin'; +// @forward 'source-sans-3-v19-latin'; diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/fonts/_playfair-display-v40-latin.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/fonts/_playfair-display-v40-latin.scss new file mode 100644 index 0000000..a410d7c --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/fonts/_playfair-display-v40-latin.scss @@ -0,0 +1,96 @@ +// playfair-display-regular - latin +@font-face { + font-display: swap; + font-family: 'Playfair Display'; + font-style: normal; + font-weight: 400; + src: url('./playfair-display-v40-latin/playfair-display-v40-latin-regular.woff2') format('woff2'); +} +// playfair-display-italic - latin +@font-face { + font-display: swap; + font-family: 'Playfair Display'; + font-style: italic; + font-weight: 400; + src: url('./playfair-display-v40-latin/playfair-display-v40-latin-italic.woff2') format('woff2'); +} +// playfair-display-500 - latin +@font-face { + font-display: swap; + font-family: 'Playfair Display'; + font-style: normal; + font-weight: 500; + src: url('./playfair-display-v40-latin/playfair-display-v40-latin-500.woff2') format('woff2'); +} +// playfair-display-500italic - latin +@font-face { + font-display: swap; + font-family: 'Playfair Display'; + font-style: italic; + font-weight: 500; + src: url('./playfair-display-v40-latin/playfair-display-v40-latin-500italic.woff2') format('woff2'); +} +// playfair-display-600 - latin +@font-face { + font-display: swap; + font-family: 'Playfair Display'; + font-style: normal; + font-weight: 600; + src: url('./playfair-display-v40-latin/playfair-display-v40-latin-600.woff2') format('woff2'); +} +// playfair-display-600italic - latin +@font-face { + font-display: swap; + font-family: 'Playfair Display'; + font-style: italic; + font-weight: 600; + src: url('./playfair-display-v40-latin/playfair-display-v40-latin-600italic.woff2') format('woff2'); +} +// playfair-display-700 - latin +@font-face { + font-display: swap; + font-family: 'Playfair Display'; + font-style: normal; + font-weight: 700; + src: url('./playfair-display-v40-latin/playfair-display-v40-latin-700.woff2') format('woff2'); +} +// playfair-display-700italic - latin +@font-face { + font-display: swap; + font-family: 'Playfair Display'; + font-style: italic; + font-weight: 700; + src: url('./playfair-display-v40-latin/playfair-display-v40-latin-700italic.woff2') format('woff2'); +} +// playfair-display-800 - latin +@font-face { + font-display: swap; + font-family: 'Playfair Display'; + font-style: normal; + font-weight: 800; + src: url('./playfair-display-v40-latin/playfair-display-v40-latin-800.woff2') format('woff2'); +} +// playfair-display-800italic - latin +@font-face { + font-display: swap; + font-family: 'Playfair Display'; + font-style: italic; + font-weight: 800; + src: url('./playfair-display-v40-latin/playfair-display-v40-latin-800italic.woff2') format('woff2'); +} +// playfair-display-900 - latin +@font-face { + font-display: swap; + font-family: 'Playfair Display'; + font-style: normal; + font-weight: 900; + src: url('./playfair-display-v40-latin/playfair-display-v40-latin-900.woff2') format('woff2'); +} +// playfair-display-900italic - latin +@font-face { + font-display: swap; + font-family: 'Playfair Display'; + font-style: italic; + font-weight: 900; + src: url('./playfair-display-v40-latin/playfair-display-v40-latin-900italic.woff2') format('woff2'); +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/fonts/_source-sans-3-v19-latin.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/fonts/_source-sans-3-v19-latin.scss new file mode 100644 index 0000000..b8a2b40 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/fonts/_source-sans-3-v19-latin.scss @@ -0,0 +1,134 @@ +// source-sans-3-200 - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: normal; + font-weight: 200; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-200.woff2') format('woff2'); +} + +// source-sans-3-200italic - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: italic; + font-weight: 200; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-200italic.woff2') format('woff2'); +} + +// source-sans-3-300 - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: normal; + font-weight: 300; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-300.woff2') format('woff2'); +} + +// source-sans-3-300italic - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: italic; + font-weight: 300; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-300italic.woff2') format('woff2'); +} + +// source-sans-3-regular - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: normal; + font-weight: 400; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-regular.woff2') format('woff2'); +} + +// source-sans-3-italic - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: italic; + font-weight: 400; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-italic.woff2') format('woff2'); +} +// source-sans-3-500 - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: normal; + font-weight: 500; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-500.woff2') format('woff2'); +} +// source-sans-3-500italic - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: italic; + font-weight: 500; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-500italic.woff2') format('woff2'); +} + +// source-sans-3-600 - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: normal; + font-weight: 600; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-600.woff2') format('woff2'); +} +// source-sans-3-600italic - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: italic; + font-weight: 600; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-600italic.woff2') format('woff2'); +} +// source-sans-3-700 - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: normal; + font-weight: 700; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-700.woff2') format('woff2'); +} +// source-sans-3-700italic - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: italic; + font-weight: 700; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-700italic.woff2') format('woff2'); +} +// source-sans-3-800 - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: normal; + font-weight: 800; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-800.woff2') format('woff2'); +} +// source-sans-3-800italic - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: italic; + font-weight: 800; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-800italic.woff2') format('woff2'); +} +// source-sans-3-900 - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: normal; + font-weight: 900; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-900.woff2') format('woff2'); +} +// source-sans-3-900italic - latin +@font-face { + font-display: swap; + font-family: 'Source Sans 3'; + font-style: italic; + font-weight: 900; + src: url('./source-sans-3-v19-latin/source-sans-3-v19-latin-900italic.woff2') format('woff2'); +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/icons/_index.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/icons/_index.scss new file mode 100644 index 0000000..f8043dc --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/icons/_index.scss @@ -0,0 +1 @@ +@forward 'fontawesome-7.3.0/index.scss'; diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/icons/fontawesome-7.3.0/index.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/icons/fontawesome-7.3.0/index.scss new file mode 100644 index 0000000..703a9e5 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/icons/fontawesome-7.3.0/index.scss @@ -0,0 +1 @@ +@import 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.3.0/css/all.min.css'; diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/_index.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/_index.scss new file mode 100644 index 0000000..ffb1c8f --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/_index.scss @@ -0,0 +1,3 @@ +// @forward 'bootstrap-5.3.8/bootstrap-grid'; +@forward 'bootstrap-5.3.8/bootstrap'; +// @forward 'bulma-1.04/index'; diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_accordion.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_accordion.scss new file mode 100644 index 0000000..e9f267f --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_accordion.scss @@ -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)}; + } + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_alert.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_alert.scss new file mode 100644 index 0000000..b8cff9b --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_alert.scss @@ -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 diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_badge.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_badge.scss new file mode 100644 index 0000000..cc3d269 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_badge.scss @@ -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; +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_breadcrumb.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_breadcrumb.scss new file mode 100644 index 0000000..b8252ff --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_breadcrumb.scss @@ -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); + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_button-group.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_button-group.scss new file mode 100644 index 0000000..78e1252 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_button-group.scss @@ -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); + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_buttons.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_buttons.scss new file mode 100644 index 0000000..caa4518 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_buttons.scss @@ -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); +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_card.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_card.scss new file mode 100644 index 0000000..dcebe6a --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_card.scss @@ -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 + 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; + } + } + } + } + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_carousel.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_carousel.scss new file mode 100644 index 0000000..5ebf6b1 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_carousel.scss @@ -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(); + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_close.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_close.scss new file mode 100644 index 0000000..d53c96f --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_close.scss @@ -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 '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(); + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_containers.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_containers.scss new file mode 100644 index 0000000..83b3138 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_containers.scss @@ -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; + } + } + } + } + } +} diff --git a/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_dropdown.scss b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_dropdown.scss new file mode 100644 index 0000000..587ebb4 --- /dev/null +++ b/06_react/unterricht/tag40/01_react-app-with-tests/src/styles/libraries/bootstrap-5.3.8/_dropdown.scss @@ -0,0 +1,250 @@ +// The dropdown wrapper (`
`) +.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 `
`) 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
element +} + +// Links, buttons, and more within the dropdown menu +// +// `