mirror of
https://github.com/kevinveenbirkenbach/homepage.veen.world.git
synced 2025-04-22 13:12:25 +02:00
Replaced German by English comments
This commit is contained in:
parent
45969feaed
commit
ae775916b0
12
Dockerfile
12
Dockerfile
@ -1,18 +1,18 @@
|
|||||||
# Basis-Image für Python
|
# Base image for Python
|
||||||
FROM python:slim
|
FROM python:slim
|
||||||
|
|
||||||
# Arbeitsverzeichnis festlegen
|
# Set the working directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Abhängigkeiten kopieren und installieren
|
# Copy and install dependencies
|
||||||
COPY app/requirements.txt requirements.txt
|
COPY app/requirements.txt requirements.txt
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
# Anwendungscode kopieren
|
# Copy application code
|
||||||
COPY app/ .
|
COPY app/ .
|
||||||
|
|
||||||
# Port freigeben
|
# Expose port
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
|
||||||
# Startbefehl
|
# Start command
|
||||||
CMD ["python", "app.py"]
|
CMD ["python", "app.py"]
|
||||||
|
@ -15,7 +15,6 @@ cache_manager.clear_cache()
|
|||||||
|
|
||||||
def load_config(app):
|
def load_config(app):
|
||||||
"""Load and resolve the configuration."""
|
"""Load and resolve the configuration."""
|
||||||
# Lade die Konfigurationsdatei
|
|
||||||
with open("config.yaml", "r") as f:
|
with open("config.yaml", "r") as f:
|
||||||
config = yaml.safe_load(f)
|
config = yaml.safe_load(f)
|
||||||
|
|
||||||
@ -28,7 +27,7 @@ def load_config(app):
|
|||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
load_config(app)
|
load_config(app)
|
||||||
|
|
||||||
# Hole die Umgebungsvariable FLASK_ENV oder setze einen Standardwert
|
# Get the environment variable FLASK_ENV or set a default value
|
||||||
FLASK_ENV = os.getenv("FLASK_ENV", "production")
|
FLASK_ENV = os.getenv("FLASK_ENV", "production")
|
||||||
|
|
||||||
@app.before_request
|
@app.before_request
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
/* Den scroll-container so einstellen, dass er nur vertikal scrollt */
|
/* Set the scroll container to only scroll vertically */
|
||||||
.scroll-container {
|
.scroll-container {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
/* Native Scrollbar ausblenden */
|
/* Hide native scrollbar */
|
||||||
scrollbar-width: none; /* Firefox */
|
scrollbar-width: none; /* Firefox */
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll-container::-webkit-scrollbar {
|
.scroll-container::-webkit-scrollbar {
|
||||||
display: none; /* WebKit */
|
display: none; /* WebKit */
|
||||||
}
|
}
|
||||||
@ -14,13 +15,13 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
width: 8px;
|
width: 8px;
|
||||||
/* height: 100vh; <-- diese Zeile entfernen oder anpassen */
|
/* height: 100vh; <-- remove or adjust this line */
|
||||||
background: transparent;
|
background: transparent;
|
||||||
transition: opacity 0.3s ease;
|
transition: opacity 0.3s ease;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Der Thumb der Scrollbar */
|
/* The scrollbar thumb */
|
||||||
#scroll-thumb {
|
#scroll-thumb {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@ -28,4 +29,3 @@
|
|||||||
background-color: rgba(0, 0, 0, 0.2);
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
@ -24,7 +24,7 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Subtle shadow effect */
|
/* Subtle shadow effect */
|
||||||
.navbar, .card, .dropdown-menu{
|
.navbar, .card, .dropdown-menu {
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,26 +85,26 @@ h3.footer-title {
|
|||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-img-top i{
|
.card-img-top i {
|
||||||
font-size: 100px;
|
font-size: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div#navbarNavheader li.nav-item{
|
div#navbarNavheader li.nav-item {
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div#navbarNavfooter li.nav-item{
|
div#navbarNavfooter li.nav-item {
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
position: relative;
|
position: relative;
|
||||||
box-shadow:
|
box-shadow:
|
||||||
/* Innerer Schatten */
|
/* Inner shadow */
|
||||||
inset 10px 0 10px -10px rgba(0, 0, 0, 0.3), /* linker innerer Schatten */
|
inset 10px 0 10px -10px rgba(0, 0, 0, 0.3), /* Left inner shadow */
|
||||||
inset -10px 0 10px -10px rgba(0, 0, 0, 0.3), /* rechter innerer Schatten */
|
inset -10px 0 10px -10px rgba(0, 0, 0, 0.3), /* Right inner shadow */
|
||||||
/* Äußerer Schatten */
|
/* Outer shadow */
|
||||||
10px 0 10px -10px rgba(0, 0, 0, 0.3), /* rechter äußerer Schatten */
|
10px 0 10px -10px rgba(0, 0, 0, 0.3), /* Right outer shadow */
|
||||||
-10px 0 10px -10px rgba(0, 0, 0, 0.3); /* linker äußerer Schatten */
|
-10px 0 10px -10px rgba(0, 0, 0, 0.3); /* Left outer shadow */
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
/* Top-Level Dropdown-Menü */
|
/* Top-level dropdown menu */
|
||||||
.nav-item .dropdown-menu {
|
.nav-item .dropdown-menu {
|
||||||
position: absolute; /* Wichtig für Positionierung */
|
position: absolute; /* Important for positioning */
|
||||||
top: 100%; /* Standardmäßige Öffnung nach unten */
|
top: 100%; /* Default opening direction: downwards */
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 1050; /* Damit das Menü über anderen Elementen liegt */
|
z-index: 1050; /* Ensures the menu appears above other elements */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Submenu-Position */
|
/* Submenu position */
|
||||||
.dropdown-submenu > .dropdown-menu {
|
.dropdown-submenu > .dropdown-menu {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 100%; /* Öffnen nach rechts */
|
left: 100%; /* Opens to the right */
|
||||||
z-index: 1050;
|
z-index: 1050;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sicherstellen, dass der Übergang smooth ist */
|
/* Ensure a smooth transition */
|
||||||
.dropdown-menu {
|
.dropdown-menu {
|
||||||
transition: all 0.3s ease-in-out;
|
transition: all 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
@ -22,7 +22,7 @@
|
|||||||
nav.navbar.menu-header {
|
nav.navbar.menu-header {
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav.navbar.menu-footer {
|
nav.navbar.menu-footer {
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
|
@ -15,25 +15,24 @@ function adjustScrollContainerHeight() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Berechne die verfügbare Höhe für den Scrollbereich
|
// Calculate the available height for the scroll area
|
||||||
const availableHeight = window.innerHeight - siblingsHeight;
|
const availableHeight = window.innerHeight - siblingsHeight;
|
||||||
scrollContainer.style.maxHeight = availableHeight + 'px';
|
scrollContainer.style.maxHeight = availableHeight + 'px';
|
||||||
scrollContainer.style.overflowY = 'auto';
|
scrollContainer.style.overflowY = 'auto';
|
||||||
scrollContainer.style.overflowX = 'hidden';
|
scrollContainer.style.overflowX = 'hidden';
|
||||||
|
|
||||||
// Hole die aktuelle Position und Höhe des Scrollbereichs
|
// Get the current position and height of the scroll container
|
||||||
const scrollContainerRect = scrollContainer.getBoundingClientRect();
|
const scrollContainerRect = scrollContainer.getBoundingClientRect();
|
||||||
|
|
||||||
// Setze die Position (top) und die Höhe des benutzerdefinierten Scrollbar-Tracks
|
// Set the position (top) and height of the custom scrollbar track
|
||||||
scrollbarContainer.style.top = scrollContainerRect.top + 'px';
|
scrollbarContainer.style.top = scrollContainerRect.top + 'px';
|
||||||
scrollbarContainer.style.height = scrollContainerRect.height + 'px';
|
scrollbarContainer.style.height = scrollContainerRect.height + 'px';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
window.addEventListener('load', adjustScrollContainerHeight);
|
window.addEventListener('load', adjustScrollContainerHeight);
|
||||||
window.addEventListener('resize', adjustScrollContainerHeight);
|
window.addEventListener('resize', adjustScrollContainerHeight);
|
||||||
|
|
||||||
// 2. Aktualisiert den Thumb (Größe und Position) der benutzerdefinierten Scrollbar
|
// 2. Updates the thumb (size and position) of the custom scrollbar
|
||||||
function updateCustomScrollbar() {
|
function updateCustomScrollbar() {
|
||||||
const scrollContainer = document.querySelector('.scroll-container');
|
const scrollContainer = document.querySelector('.scroll-container');
|
||||||
const thumb = document.getElementById('scroll-thumb');
|
const thumb = document.getElementById('scroll-thumb');
|
||||||
@ -44,22 +43,22 @@ function updateCustomScrollbar() {
|
|||||||
const containerHeight = scrollContainer.clientHeight;
|
const containerHeight = scrollContainer.clientHeight;
|
||||||
const scrollTop = scrollContainer.scrollTop;
|
const scrollTop = scrollContainer.scrollTop;
|
||||||
|
|
||||||
// Berechne die Thumb-Höhe (mindestens 20px)
|
// Calculate the thumb height (minimum 20px)
|
||||||
let thumbHeight = (containerHeight / contentHeight) * containerHeight;
|
let thumbHeight = (containerHeight / contentHeight) * containerHeight;
|
||||||
thumbHeight = Math.max(thumbHeight, 20);
|
thumbHeight = Math.max(thumbHeight, 20);
|
||||||
thumb.style.height = thumbHeight + 'px';
|
thumb.style.height = thumbHeight + 'px';
|
||||||
|
|
||||||
// Berechne die Position des Thumbs
|
// Calculate the thumb position
|
||||||
const maxScrollTop = contentHeight - containerHeight;
|
const maxScrollTop = contentHeight - containerHeight;
|
||||||
const maxThumbTop = containerHeight - thumbHeight;
|
const maxThumbTop = containerHeight - thumbHeight;
|
||||||
const thumbTop = maxScrollTop ? (scrollTop / maxScrollTop) * maxThumbTop : 0;
|
const thumbTop = maxScrollTop ? (scrollTop / maxScrollTop) * maxThumbTop : 0;
|
||||||
thumb.style.top = thumbTop + 'px';
|
thumb.style.top = thumbTop + 'px';
|
||||||
|
|
||||||
// Zeige die Scrollbar, falls der Inhalt überläuft, sonst ggf. ausblenden
|
// Show the scrollbar if content overflows, otherwise hide it
|
||||||
customScrollbar.style.opacity = contentHeight > containerHeight ? '1' : '0';
|
customScrollbar.style.opacity = contentHeight > containerHeight ? '1' : '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aktualisiere den Thumb bei Scrollen des Containers
|
// Update the thumb when the container is scrolled
|
||||||
const scrollContainer = document.querySelector('.scroll-container');
|
const scrollContainer = document.querySelector('.scroll-container');
|
||||||
if (scrollContainer) {
|
if (scrollContainer) {
|
||||||
scrollContainer.addEventListener('scroll', updateCustomScrollbar);
|
scrollContainer.addEventListener('scroll', updateCustomScrollbar);
|
||||||
@ -67,7 +66,7 @@ if (scrollContainer) {
|
|||||||
window.addEventListener('resize', updateCustomScrollbar);
|
window.addEventListener('resize', updateCustomScrollbar);
|
||||||
window.addEventListener('load', updateCustomScrollbar);
|
window.addEventListener('load', updateCustomScrollbar);
|
||||||
|
|
||||||
// 3. Interaktivität: Ermögliche Drag & Drop des Scroll-Thumbs
|
// 3. Interactivity: Enable drag & drop for the scroll thumb
|
||||||
let isDragging = false;
|
let isDragging = false;
|
||||||
let dragStartY = 0;
|
let dragStartY = 0;
|
||||||
let scrollStartY = 0;
|
let scrollStartY = 0;
|
||||||
@ -93,11 +92,11 @@ document.addEventListener('mousemove', function(e) {
|
|||||||
const maxThumbTop = containerHeight - thumbHeight;
|
const maxThumbTop = containerHeight - thumbHeight;
|
||||||
|
|
||||||
const deltaY = e.clientY - dragStartY;
|
const deltaY = e.clientY - dragStartY;
|
||||||
// Berechne neuen Thumb-Top-Wert
|
// Calculate the new thumb top position
|
||||||
let newThumbTop = (scrollStartY / maxScrollTop) * maxThumbTop + deltaY;
|
let newThumbTop = (scrollStartY / maxScrollTop) * maxThumbTop + deltaY;
|
||||||
newThumbTop = Math.max(0, Math.min(newThumbTop, maxThumbTop));
|
newThumbTop = Math.max(0, Math.min(newThumbTop, maxThumbTop));
|
||||||
|
|
||||||
// Berechne den neuen Scrollwert anhand der Thumb-Position
|
// Calculate the new scroll position based on the thumb position
|
||||||
const newScrollTop = (newThumbTop / maxThumbTop) * maxScrollTop;
|
const newScrollTop = (newThumbTop / maxThumbTop) * maxScrollTop;
|
||||||
scrollContainer.scrollTop = newScrollTop;
|
scrollContainer.scrollTop = newScrollTop;
|
||||||
});
|
});
|
||||||
|
@ -17,15 +17,15 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Öffnen beim Hovern
|
// Open on hover
|
||||||
item.addEventListener('mouseenter', onMouseEnter);
|
item.addEventListener('mouseenter', onMouseEnter);
|
||||||
|
|
||||||
// Verzögertes Schließen beim Verlassen
|
// Delayed close on mouse leave
|
||||||
item.addEventListener('mouseleave', onMouseLeave);
|
item.addEventListener('mouseleave', onMouseLeave);
|
||||||
|
|
||||||
// Öffnen und Position anpassen beim Klicken
|
// Open and adjust position on click
|
||||||
item.addEventListener('click', (e) => {
|
item.addEventListener('click', (e) => {
|
||||||
e.stopPropagation(); // Verhindert das Schließen von Menüs bei Klick
|
e.stopPropagation(); // Prevents menus from closing when clicking inside
|
||||||
if (item.classList.contains('open')) {
|
if (item.classList.contains('open')) {
|
||||||
closeMenu(item);
|
closeMenu(item);
|
||||||
} else {
|
} else {
|
||||||
@ -44,7 +44,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
addAllMenuEventListeners();
|
addAllMenuEventListeners();
|
||||||
|
|
||||||
// Globale Klick-Listener, um Menüs zu schließen, wenn außerhalb geklickt wird
|
// Global click listener to close menus when clicking outside
|
||||||
document.addEventListener('click', () => {
|
document.addEventListener('click', () => {
|
||||||
[...menuItems, ...subMenuItems].forEach(item => closeMenu(item));
|
[...menuItems, ...subMenuItems].forEach(item => closeMenu(item));
|
||||||
});
|
});
|
||||||
@ -70,11 +70,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSmallScreen() {
|
function isSmallScreen() {
|
||||||
return window.innerWidth < 992; // Bootstrap-Breakpoint für 'lg'
|
return window.innerWidth < 992; // Bootstrap breakpoint for 'lg'
|
||||||
}
|
}
|
||||||
|
|
||||||
function adjustMenuPosition(submenu, parent, isTopLevel) {
|
function adjustMenuPosition(submenu, parent, isTopLevel) {
|
||||||
const rect = submenu.getBoundingClientRect();
|
const rect = submenu.getBoundingClientRect();
|
||||||
const parentRect = parent.getBoundingClientRect();
|
const parentRect = parent.getBoundingClientRect();
|
||||||
|
|
||||||
@ -89,33 +89,33 @@ function adjustMenuPosition(submenu, parent, isTopLevel) {
|
|||||||
submenu.style.right = '';
|
submenu.style.right = '';
|
||||||
|
|
||||||
if (isTopLevel) {
|
if (isTopLevel) {
|
||||||
if (isSmallScreen && spaceBelow < spaceAbove) {
|
if (isSmallScreen() && spaceBelow < spaceAbove) {
|
||||||
// Für kleine Bildschirme: Menü direkt über dem Eltern-Element öffnen
|
// For small screens: Open menu directly above the parent element
|
||||||
submenu.style.top = 'auto';
|
submenu.style.top = 'auto';
|
||||||
submenu.style.bottom = `${parentRect.height}px`; // Direkt über dem Eltern-Element
|
submenu.style.bottom = `${parentRect.height}px`; // Directly above the parent element
|
||||||
|
}
|
||||||
|
// Top-level menu
|
||||||
|
else if (spaceBelow < spaceAbove) {
|
||||||
|
submenu.style.bottom = `${window.innerHeight - parentRect.bottom - parentRect.height}px`;
|
||||||
|
submenu.style.top = 'auto';
|
||||||
|
} else {
|
||||||
|
submenu.style.top = `${parentRect.height}px`;
|
||||||
|
submenu.style.bottom = 'auto';
|
||||||
}
|
}
|
||||||
// Top-Level-Menü
|
|
||||||
else if (spaceBelow < spaceAbove) {
|
|
||||||
submenu.style.bottom = `${window.innerHeight - parentRect.bottom - parentRect.height}px`;
|
|
||||||
submenu.style.top = 'auto';
|
|
||||||
} else {
|
|
||||||
submenu.style.top = `${parentRect.height}px`;
|
|
||||||
submenu.style.bottom = 'auto';
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Submenü
|
// Submenu
|
||||||
const prefersRight = spaceRight >= spaceLeft;
|
const prefersRight = spaceRight >= spaceLeft;
|
||||||
submenu.style.left = prefersRight ? '100%' : 'auto';
|
submenu.style.left = prefersRight ? '100%' : 'auto';
|
||||||
submenu.style.right = prefersRight ? 'auto' : '100%';
|
submenu.style.right = prefersRight ? 'auto' : '100%';
|
||||||
|
|
||||||
// Nach oben öffnen, wenn unten kein Platz ist
|
// Open upwards if there's no space below
|
||||||
if (spaceBelow < spaceAbove) {
|
if (spaceBelow < spaceAbove) {
|
||||||
submenu.style.bottom = `0`;
|
submenu.style.bottom = `0`;
|
||||||
submenu.style.top = `auto`;
|
submenu.style.top = `auto`;
|
||||||
} else {
|
} else {
|
||||||
submenu.style.top = `0`;
|
submenu.style.top = `0`;
|
||||||
submenu.style.bottom = '${parentRect.height}px';
|
submenu.style.bottom = `${parentRect.height}px`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Initialisiert alle Tooltips auf der Seite
|
// Initializes all tooltips on the page
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||||
tooltipTriggerList.forEach(function (tooltipTriggerEl) {
|
tooltipTriggerList.forEach(function (tooltipTriggerEl) {
|
||||||
|
@ -29,7 +29,6 @@
|
|||||||
{% include "moduls/navigation.html.j2"%}
|
{% include "moduls/navigation.html.j2"%}
|
||||||
<main id="main">
|
<main id="main">
|
||||||
<div class="scroll-container">
|
<div class="scroll-container">
|
||||||
<!-- Hier kommt dein Hauptinhalt -->
|
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
@ -13,7 +13,7 @@ def compute_card_classes(cards):
|
|||||||
elif num_cards % 2 == 0:
|
elif num_cards % 2 == 0:
|
||||||
lg_classes = ["col-lg-6"] * num_cards
|
lg_classes = ["col-lg-6"] * num_cards
|
||||||
else:
|
else:
|
||||||
# Für komplexe Fälle (z. B. 5, 7, 11) – Stelle sicher, dass mindestens 3 pro Zeile erscheinen
|
# For complex cases (e.g., 5, 7, 11) – Ensure at least 3 per row
|
||||||
for i in range(num_cards):
|
for i in range(num_cards):
|
||||||
if num_cards % 4 == 3:
|
if num_cards % 4 == 3:
|
||||||
if i < 3:
|
if i < 3:
|
||||||
@ -32,7 +32,7 @@ def compute_card_classes(cards):
|
|||||||
lg_classes.append("col-lg-6")
|
lg_classes.append("col-lg-6")
|
||||||
else:
|
else:
|
||||||
lg_classes.append("col-lg-4")
|
lg_classes.append("col-lg-4")
|
||||||
# md-Klassen: Wenn die Anzahl der Karten gerade ist oder wenn nicht die letzte Karte, ansonsten "col-md-12"
|
# md classes: If the number of cards is even or if not the last card, otherwise "col-md-12"
|
||||||
md_classes = []
|
md_classes = []
|
||||||
for i in range(num_cards):
|
for i in range(num_cards):
|
||||||
if num_cards % 2 == 0 or i < num_cards - 1:
|
if num_cards % 2 == 0 or i < num_cards - 1:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user