newWebsite2.0
@@ -1,374 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<link rel="icon" href="/img/favicon.jpg" type="image/png">
|
||||
<meta charset="UTF-8">
|
||||
<title>BR0TCRAFT</title>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Orbitron';
|
||||
src: url('/fonts/Orbitron-Black.ttf') format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('/fonts/Roboto-Regular.ttf') format('truetype');
|
||||
}
|
||||
body {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
background-color: #120000;
|
||||
color: #ffeded;
|
||||
margin: 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.header {
|
||||
background-color: #330000;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-bottom: 5px solid #660000;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 2.5em;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
h2 {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center; /* Zentriert alle Elemente innerhalb von .container */
|
||||
}
|
||||
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: left;
|
||||
width: 80%;
|
||||
margin: 20px auto;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0px 5px 15px rgba(255, 0, 0, 0.3);
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 2em;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
margin-left: 10px;
|
||||
width: calc(100% - 0px);
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.buttonsklein {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
margin-left: 46%;
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
padding: 10px 0px;
|
||||
border: none;
|
||||
border-radius: 0px;
|
||||
margin-bottom: 0px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.buttonklein {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
padding: 10px 0px;
|
||||
border: none;
|
||||
border-radius: 0px;
|
||||
margin-bottom: 0px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.buttonklein:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
.description {
|
||||
margin-top: 20px; /* Space from the carousel */
|
||||
padding: 15px;
|
||||
background-color: rgba(0, 0, 0, 0.3); /* Semi-transparent background */
|
||||
border-radius: 10px;
|
||||
border: 2px solid #660000; /* Red border */
|
||||
}
|
||||
.description p {
|
||||
color: #ffffff; /* Light red text color */
|
||||
font-size: 1.1em;
|
||||
line-height: 1.6;
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
.content {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.buttons {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.carousel-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
perspective: 1200px;
|
||||
position: relative;
|
||||
height: 250px;
|
||||
overflow: hidden;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.carousel {
|
||||
display: flex;
|
||||
transition: transform 0.5s ease;
|
||||
transform-style: preserve-3d;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.carousel-item {
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
transition: transform 0.5s ease, opacity 0.5s ease;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
opacity: 1;
|
||||
}
|
||||
.carousel-item:nth-child(1) {
|
||||
transform: translateX(-150%) translateY(20px) scale(0.8) rotateY(-30deg);
|
||||
}
|
||||
.carousel-item:nth-child(2) {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.carousel-item:nth-child(3) {
|
||||
transform: translateX(50%) translateY(20px) scale(0.8) rotateY(30deg);
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.7em;
|
||||
justify-items: left;
|
||||
}
|
||||
|
||||
.carousel-item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
.carousel-controls {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translateY(-50%);
|
||||
width: 100%;
|
||||
padding: 0; /* Remove padding */
|
||||
}
|
||||
.carousel-button {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.5em;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
margin: 0 10px; /* Add margin */
|
||||
}
|
||||
.carousel-button:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<a href="/" style="text-decoration: none; color: inherit;">
|
||||
<h1>BR0TCRAFT</h1>
|
||||
</a>
|
||||
</div>
|
||||
<div class="container">
|
||||
|
||||
<h2>Gamename</h2>
|
||||
<div class="section">
|
||||
|
||||
|
||||
|
||||
|
||||
<p>Datum</p>
|
||||
<div class="section-title">Update: 12.10.2024</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<p>ein Button zum Interaktieren</p>
|
||||
<div class="content">
|
||||
<div class="buttons">
|
||||
<a href="/play/Tiny-Snake/snake.html" class="button">Spielen</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<p>ein kleiner Button zum Interaktieren</p>
|
||||
<div class="content">
|
||||
<div class="buttonsklein">
|
||||
<a href="/play/Tiny-Snake/snake.html" class="buttonklein">Spielen</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Unter Überschrift:</h5>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
<p>Eine simple zwischennotiz</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<p>Karusell zur Bilder implementierung</p>
|
||||
<div class="carousel-container">
|
||||
<div class="carousel">
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/Snake/snake1.PNG" alt="App 1 Image 1">
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/snake.jpg" alt="App 1 Image 2">
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/Snake/Snake2.png" alt="App 1 Image 3">
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-controls">
|
||||
<button class="carousel-button prev"><</button>
|
||||
<button class="carousel-button next">></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class=" section">
|
||||
<p>Noch eine Kategorie für weiteres Datum</p>
|
||||
</div>
|
||||
<script>
|
||||
const carousel = document.querySelector('.carousel');
|
||||
const items = document.querySelectorAll('.carousel-item');
|
||||
const prevButton = document.querySelector('.prev');
|
||||
const nextButton = document.querySelector('.next');
|
||||
|
||||
let currentItem = 2; // Start with the middle item
|
||||
|
||||
function updateCarousel() {
|
||||
items.forEach((item, index) => {
|
||||
if (index === currentItem - 1) {
|
||||
// Center item
|
||||
item.style.transform = 'translateX(-50%)';
|
||||
} else if (index < currentItem - 1) {
|
||||
// Items to the left
|
||||
item.style.transform = `translateX(${-150 - (currentItem - index - 2) * 100}%) translateY(20px) scale(0.8) rotateY(-30deg)`;
|
||||
} else {
|
||||
// Items to the right
|
||||
item.style.transform = `translateX(${50 + (index - currentItem) * 100}%) translateY(20px) scale(0.8) rotateY(30deg)`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
prevButton.addEventListener('click', () => {
|
||||
currentItem--;
|
||||
if (currentItem < 1) {
|
||||
currentItem = items.length;
|
||||
}
|
||||
updateCarousel();
|
||||
});
|
||||
|
||||
nextButton.addEventListener('click', () => {
|
||||
currentItem++;
|
||||
if (currentItem > items.length) {
|
||||
currentItem = 1;
|
||||
}
|
||||
updateCarousel();
|
||||
});
|
||||
|
||||
// Initial setup
|
||||
updateCarousel();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Br0tcraft</title>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="header-container">
|
||||
</div>
|
||||
<div class="Background-Leiste"></div>
|
||||
<div class="Leiste"></div>
|
||||
<div class="container">
|
||||
|
||||
<a class="menu-link-home" href="">BR0TCRAFT</a>
|
||||
<div class="mobile-menu-icon" onclick="toggleMenu()">
|
||||
|
||||
<div class="hamburger-icon"></div>
|
||||
<div class="hamburger-icon"></div>
|
||||
<div class="hamburger-icon"></div>
|
||||
</div>
|
||||
<div class="menu-links">
|
||||
|
||||
<a class="menu-link" href="">Spiele</a>
|
||||
<a class="menu-link" href="">Tutorials</a>
|
||||
<a class="menu-link" href="">Extensions</a>
|
||||
<a class="menu-link" href="">Kontakt</a>
|
||||
<a class="menu-link" href="">funny-Seiten</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mobile-menu" onclick="toggleMenu()">
|
||||
<a class="menu-link-home" href="">BR0TCRAFT</a>
|
||||
<br><br><br>
|
||||
<a class="menu-link-mobile" href="">Spiele</a>
|
||||
<a class="menu-link-mobile" href="">Tutorials</a>
|
||||
<a class="menu-link-mobile" href="">Turbowarp-Extensions</a>
|
||||
<a class="menu-link-mobile" href="">Kontakt</a>
|
||||
<a class="menu-link-mobile" href="">funny-Seiten</a>
|
||||
</div>
|
||||
<h1 class="headline">Example</h1>
|
||||
Dies wird genutzt für weitere Websiten als Template
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
function toggleMenu() {
|
||||
var menuLinks = document.querySelector(".menu-links");
|
||||
var mobileMenu = document.querySelector(".mobile-menu");
|
||||
var body = document.body;
|
||||
|
||||
menuLinks.classList.toggle("show");
|
||||
mobileMenu.classList.toggle("show");
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,172 +0,0 @@
|
||||
@font-face {
|
||||
font-family: "Roboto";
|
||||
src: url("/fonts/Roboto/Roboto-Regular.ttf");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Orbitron";
|
||||
src: url("/fonts/Orbitron/Orbitron-Black.ttf");
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Orbitron";
|
||||
background-color: white;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.Leiste {
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 7vw;
|
||||
position: fixed;
|
||||
background-color: rgb(77, 0, 0);
|
||||
z-index: 0;
|
||||
}
|
||||
.Background-Leiste {
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 7vw;
|
||||
object-fit: cover;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.header-container {
|
||||
top: 3vw;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
position: fixed;
|
||||
right: 32px;
|
||||
left: 10px;
|
||||
top: 0px;
|
||||
font-family: Orbitron;
|
||||
font-size: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.menu-link-home {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-left: 0px;
|
||||
font-size: 6vw;
|
||||
|
||||
}
|
||||
|
||||
.menu-link {
|
||||
font-size: 1.5vw;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.menu-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.headline {
|
||||
text-align: center;
|
||||
color: rgb(0, 0, 0);
|
||||
font-size: 4vw;
|
||||
text-shadow: 5px 5px 3px rgba(5, 0, 0, 0.26);
|
||||
}
|
||||
|
||||
.mobile-menu-icon {
|
||||
display: none; /* Standardmäßig ausblenden */
|
||||
cursor: pointer;
|
||||
position: fixed;
|
||||
top: 0.5vw;
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
.hamburger-icon {
|
||||
width: 30px;
|
||||
height: 3px;
|
||||
background-color: white;
|
||||
margin: 6px 0;
|
||||
}
|
||||
|
||||
.menu-links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end; /* Rechts ausrichten */
|
||||
}
|
||||
|
||||
.menu-links.show {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.menu {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #333; /* Hintergrundfarbe des Menüs */
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.menu-link-mobile {
|
||||
color: white;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
font-size: 250%;
|
||||
margin: 20px; /* Abstand zwischen den Links hinzufügen */
|
||||
}
|
||||
|
||||
.mobile-menu {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: transparent;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.Inhalt {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
top: 10vw;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 937px) {
|
||||
.mobile-menu-icon {
|
||||
display: block; /* Bei kleinen Bildschirmen anzeigen */
|
||||
}
|
||||
|
||||
.hamburger-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.menu-links {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
top: 80px;
|
||||
right: 0; /* Rechts ausrichten */
|
||||
background-color: #333;
|
||||
width: 100%;
|
||||
justify-content: flex-start; /* Links oben ausrichten */
|
||||
}
|
||||
|
||||
.menu-links.show {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.mobile-menu.show {
|
||||
display: block;
|
||||
background-color: rgb(104, 0, 0);
|
||||
}
|
||||
}
|
||||
309
about.html
Normal file
@@ -0,0 +1,309 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>BR0TCRAFT | About</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;600&family=Inter:wght@300;400;600;800&family=Orbitron:wght@700&display=swap"
|
||||
rel="stylesheet">
|
||||
<style>
|
||||
.about-prose {
|
||||
max-width: 680px;
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.about-prose p {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.about-prose strong {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.trait-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 1rem;
|
||||
margin-top: 1.25rem;
|
||||
}
|
||||
|
||||
.trait-box {
|
||||
border: 1px solid #222;
|
||||
border-radius: var(--radius);
|
||||
padding: 1.25rem 1.5rem;
|
||||
}
|
||||
|
||||
.trait-box .trait-label {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.72rem;
|
||||
color: var(--accent-primary);
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
.trait-box ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.trait-box ul li {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.7;
|
||||
padding-left: 1rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.trait-box ul li::before {
|
||||
content: '–';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
/* Journey Timeline */
|
||||
.timeline {
|
||||
position: relative;
|
||||
max-width: 680px;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.timeline::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 7px;
|
||||
top: 6px;
|
||||
bottom: 0;
|
||||
width: 1px;
|
||||
background: #2a2a2a;
|
||||
}
|
||||
|
||||
.tl-item {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tl-dot {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
border-radius: 50%;
|
||||
background: #1a1a1a;
|
||||
border: 1px solid #444;
|
||||
flex-shrink: 0;
|
||||
margin-top: 4px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.tl-item:hover .tl-dot {
|
||||
border-color: var(--accent-primary);
|
||||
}
|
||||
|
||||
.tl-label {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.75rem;
|
||||
color: #555;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.tl-body h4 {
|
||||
color: #fff;
|
||||
font-size: 0.95rem;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.tl-body p {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
.tl-tag {
|
||||
display: inline-block;
|
||||
font-size: 0.72rem;
|
||||
font-family: var(--font-code);
|
||||
color: var(--accent-primary);
|
||||
background: rgba(255, 77, 77, 0.07);
|
||||
padding: 1px 6px;
|
||||
border-radius: 3px;
|
||||
margin-top: 0.4rem;
|
||||
}
|
||||
|
||||
/* Plans */
|
||||
.plan-list {
|
||||
max-width: 600px;
|
||||
margin-top: 1.25rem;
|
||||
}
|
||||
|
||||
.plan-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 1rem;
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid #1e1e1e;
|
||||
}
|
||||
|
||||
.plan-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.plan-index {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.75rem;
|
||||
color: #444;
|
||||
min-width: 28px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.plan-item h4 {
|
||||
color: #fff;
|
||||
font-size: 0.95rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.plan-item p {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.88rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.section-divider {
|
||||
height: 1px;
|
||||
background: #1e1e1e;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav class="navbar">
|
||||
<div class="brand">BR0TCRAFT</div>
|
||||
<div class="nav-links">
|
||||
<a href="index.html">Home</a>
|
||||
<a href="projects.html">Projects</a>
|
||||
<a href="tutorials.html">Dev Notes</a>
|
||||
<a href="about.html" class="active">About</a>
|
||||
<a href="assets.html">Assets</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
<section class="section">
|
||||
<h1 style="font-family: var(--font-display); margin-bottom: 2rem; color: #fff;">About me</h1>
|
||||
|
||||
<div class="about-prose">
|
||||
<p>
|
||||
Für mich ist Programmieren wie ein aufgeräumter Schreibtisch: Es arbeitet sich einfach besser, wenn die
|
||||
Struktur
|
||||
stimmt. Während ich Python nutze, um Ideen schnell und verständlich in Prototypen zu verwandeln, reizt mich an
|
||||
C++ die Nähe zur Hardware. Es ist für mich der Schlüssel, um nicht nur Code zu schreiben, sondern auch den
|
||||
Computer dahinter besser zu begreifen.
|
||||
<br><br>
|
||||
Aktuell probiere ich mich viel in der 3DS-Homebrew-Szene aus. Dabei liegt mein Fokus nicht auf maximaler
|
||||
High-End-
|
||||
Performance, sondern auf Handwerk: Ich achte auf Cache-Effizienz bei Iterationen, ein sauberes Error-Handling
|
||||
und
|
||||
eine Logik, die auch nach Monaten noch nachvollziehbar ist. Ich optimiere lieber Daten im Vorfeld, statt
|
||||
später
|
||||
Ladezeiten zu flicken.
|
||||
<br><br>
|
||||
In der Open-Source-Welt trage ich dort bei, wo mich die Themen persönlich packen. Ich muss nicht das nächste
|
||||
große Framework erfinden, mir geht es darum, sinnvolle Verbesserungen beizusteuern und durch eigene
|
||||
Nischenprojekte zu lernen. Am Ende ist jedes Tool für mich ein Erfolg, wenn es ein echtes Problem löst und
|
||||
sich der Code dabei „richtig“ anfühlt.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section-divider"></div>
|
||||
<section class="section">
|
||||
<h2 style="font-family: var(--font-display); margin-bottom: 0.5rem; color: #fff;">Journey</h2>
|
||||
<p style="color: var(--text-muted); font-size: 0.9rem; margin-bottom: 2rem;">Was ich bisher so ausprobiert hatte
|
||||
</p>
|
||||
|
||||
<div class="timeline">
|
||||
|
||||
<div class="tl-item">
|
||||
<div class="tl-dot"></div>
|
||||
<div class="tl-body">
|
||||
<div class="tl-label">Anfang</div>
|
||||
<h4>Scratch</h4>
|
||||
<p>Wie wahrscheinlich viele andere auch. Logik verstehen, Konzepte ausprobieren, ohne dass ein Compiler
|
||||
sich
|
||||
beschwert. Es war für mich ein wohl sinnvoller Einstieg in die Welt der Programmierung.</p>
|
||||
<span class="tl-tag">Scratch</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tl-item">
|
||||
<div class="tl-dot"></div>
|
||||
<div class="tl-body">
|
||||
<div class="tl-label">Erstes echtes Projekt</div>
|
||||
<h4>Unity & C#</h4>
|
||||
<p>Mein erstes richtiges Projekt war ein Mobile Game, das ich tatsächlich bis zum Release gebracht habe.
|
||||
Es
|
||||
war zwar nicht das innovativste Spiel der Welt, aber meine Freunde haben es gespielt und es hat mir
|
||||
bewiesen, dass ich Projekte zu Ende bringen kann. C# und Unity waren ein guter Einstieg, aber nach dem
|
||||
Projekt wusste ich, das ich tiefer in die Softwareentwicklung eintauchen will. Reinen
|
||||
Spielelogik lag mir leider nicht so.</p>
|
||||
<span class="tl-tag">C#</span>
|
||||
<span class="tl-tag">Unity</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tl-item">
|
||||
<div class="tl-dot"></div>
|
||||
<div class="tl-body">
|
||||
<div class="tl-label">Alternative</div>
|
||||
<h4>Godot ausprobiert</h4>
|
||||
<p>Schnellere Iterationen, leichtgewichtiger und GDScript war herrlich unkompliziert. Als Unity Ende 2023
|
||||
die Lizenzpolitik änderte, fiel der Wechsel leicht. Auch wenn hier kein fertiges Spiel entstanden ist,
|
||||
habe ich bei den Experimenten extrem viel über Architektur und sauberen Code gelernt. </p>
|
||||
<span class="tl-tag">GDScript</span>
|
||||
<span class="tl-tag">Godot</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tl-item">
|
||||
<div class="tl-dot"></div>
|
||||
<div class="tl-body">
|
||||
<div class="tl-label">Parallel</div>
|
||||
<h4>Python & JavaScript</h4>
|
||||
<p>Python nutze ich vor allem für Backends und Automatisierungen, es ist nach wie vor meine erste Wahl,
|
||||
wenn es darum geht, schnell produktiv zu sein. JavaScript war ein kurzer Ausflug, nicht unbedingt meine
|
||||
Lieblingssprache, aber ein notwendiges und brauchbares Werkzeug für alles, was im Browser stattfindet.
|
||||
</p>
|
||||
<span class="tl-tag">Python</span>
|
||||
<span class="tl-tag">JavaScript</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tl-item">
|
||||
<div class="tl-dot" style="border-color: var(--accent-primary);"></div>
|
||||
<div class="tl-body">
|
||||
<div class="tl-label">Aktuell</div>
|
||||
<h4>C++</h4>
|
||||
<p>Hier bin ich momentan. Und das nicht weil es einfach ist, sondern weil ich wissen will, was unter
|
||||
der Oberfläche passiert. C++ ist oft frustrierend, aber genau deshalb so lehrreich.</p>
|
||||
<span class="tl-tag">C++</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,346 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<link rel="icon" href="/img/favicon.jpg" type="image/png">
|
||||
<meta charset="UTF-8">
|
||||
<title>BR0TCRAFT</title>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Orbitron';
|
||||
src: url('/fonts/Orbitron-Black.ttf') format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('/fonts/Roboto-Regular.ttf') format('truetype');
|
||||
}
|
||||
body {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
background-color: #120000;
|
||||
color: #ffb3b3;
|
||||
margin: 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.header {
|
||||
background-color: #330000;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-bottom: 5px solid #660000;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 2.5em;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.container {
|
||||
padding-top: 80px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
perspective: 1000px;
|
||||
}
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 80%;
|
||||
margin: 20px auto;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0px 5px 15px rgba(255, 0, 0, 0.3);
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 2em;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.item {
|
||||
background-color: #220000;
|
||||
color: #ffcccc;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
.item-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.item-content img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
margin-left: 20px;
|
||||
width: calc(100% - 220px);
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
padding: 10px 0px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
.description {
|
||||
margin-top: 20px; /* Space from the carousel */
|
||||
padding: 15px;
|
||||
background-color: rgba(0, 0, 0, 0.3); /* Semi-transparent background */
|
||||
border-radius: 10px;
|
||||
border: 2px solid #660000; /* Red border */
|
||||
}
|
||||
.description p {
|
||||
color: #ffcccc; /* Light red text color */
|
||||
font-size: 1.1em;
|
||||
line-height: 1.6;
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
.content {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.item {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.buttons {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.carousel-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
perspective: 1200px;
|
||||
position: relative;
|
||||
height: 250px;
|
||||
overflow: hidden;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.carousel {
|
||||
display: flex;
|
||||
transition: transform 0.5s ease;
|
||||
transform-style: preserve-3d;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.carousel-item {
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
transition: transform 0.5s ease, opacity 0.5s ease;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
opacity: 1;
|
||||
}
|
||||
.carousel-item:nth-child(1) {
|
||||
transform: translateX(-150%) translateY(20px) scale(0.8) rotateY(-30deg);
|
||||
}
|
||||
.carousel-item:nth-child(2) {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.carousel-item:nth-child(3) {
|
||||
transform: translateX(50%) translateY(20px) scale(0.8) rotateY(30deg);
|
||||
}
|
||||
|
||||
.carousel-item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
.carousel-controls {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translateY(-50%);
|
||||
width: 100%;
|
||||
padding: 0; /* Remove padding */
|
||||
}
|
||||
.carousel-button {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.5em;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
margin: 0 10px; /* Add margin */
|
||||
}
|
||||
.carousel-button:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<a href="/" style="text-decoration: none; color: inherit;">
|
||||
<h1>BR0TCRAFT</h1>
|
||||
</a>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="section">
|
||||
<div class="section-title">Br0tbot (in Entwicklung, kann noch nicht alles)</div>
|
||||
<div class="content">
|
||||
<div class="item">
|
||||
<div class="item-content">
|
||||
<img src="/img/Apps/TigerBr0tbot.jpg" alt="App 1 Image">
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<a href="#" class="button">Spielen</a>
|
||||
<a href="#" class="button">Herunterladen</a>
|
||||
<a href="#" class="button">Github-Repository</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p>
|
||||
Dies ist der Python-Code für einen Discord-Bot, der als vielseitiger Allrounder entwickelt wurde. Der Bot beherrscht die wichtigsten Funktionen, die man von einem Discord-Bot erwartet. Dazu gehören beispielsweise das Akzeptieren von Regeln, das Begrüßen und Verabschieden von Mitgliedern, das Zuweisen von Rollen, das Erstellen von Tickets, ein Levelsystem, die Kontrolle des Servers sowie das Erstellen von Statistiken.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Zusätzlich gibt es auch unterhaltsame Funktionen zur Zeitvertreibung, wie etwa einen "Counting"-Kanal, einen "Coins"-Kanal und vieles mehr. Über den Button "Spielen" gelangt man zu einer Seite, auf der der Bot eingerichtet werden kann.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Der Bot ist Open Source und für das Selbst-Hosting gedacht.
|
||||
</p>
|
||||
<p>
|
||||
Ps: Der Bot ist noch in Entwicklung und es stehen evtl noch nicht alle versprochenen funktionen zur Verfügunng
|
||||
</p>
|
||||
</div>
|
||||
<div class="carousel-container">
|
||||
<div class="carousel">
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/Snake/snake1.PNG" alt="App 1 Image 1">
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/TigerBr0tbot.jpg" alt="App 1 Image 2">
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/Snake/Snake2.png" alt="App 1 Image 3">
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-controls">
|
||||
<button class="carousel-button prev"><</button>
|
||||
<button class="carousel-button next">></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const carousel = document.querySelector('.carousel');
|
||||
const items = document.querySelectorAll('.carousel-item');
|
||||
const prevButton = document.querySelector('.prev');
|
||||
const nextButton = document.querySelector('.next');
|
||||
|
||||
let currentItem = 2; // Start with the middle item
|
||||
|
||||
function updateCarousel() {
|
||||
items.forEach((item, index) => {
|
||||
if (index === currentItem - 1) {
|
||||
// Center item
|
||||
item.style.transform = 'translateX(-50%)';
|
||||
} else if (index < currentItem - 1) {
|
||||
// Items to the left
|
||||
item.style.transform = `translateX(${-150 - (currentItem - index - 2) * 100}%) translateY(20px) scale(0.8) rotateY(-30deg)`;
|
||||
} else {
|
||||
// Items to the right
|
||||
item.style.transform = `translateX(${50 + (index - currentItem) * 100}%) translateY(20px) scale(0.8) rotateY(30deg)`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
prevButton.addEventListener('click', () => {
|
||||
currentItem--;
|
||||
if (currentItem < 1) {
|
||||
currentItem = items.length;
|
||||
}
|
||||
updateCarousel();
|
||||
});
|
||||
|
||||
nextButton.addEventListener('click', () => {
|
||||
currentItem++;
|
||||
if (currentItem > items.length) {
|
||||
currentItem = 1;
|
||||
}
|
||||
updateCarousel();
|
||||
});
|
||||
|
||||
// Initial setup
|
||||
updateCarousel();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,345 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<link rel="icon" href="/img/favicon.jpg" type="image/png">
|
||||
<meta charset="UTF-8">
|
||||
<title>BR0TCRAFT</title>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Orbitron';
|
||||
src: url('/fonts/Orbitron-Black.ttf') format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('/fonts/Roboto-Regular.ttf') format('truetype');
|
||||
}
|
||||
body {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
background-color: #120000;
|
||||
color: #ffb3b3;
|
||||
margin: 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.header {
|
||||
background-color: #330000;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-bottom: 5px solid #660000;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 2.5em;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.container {
|
||||
padding-top: 80px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
perspective: 1000px;
|
||||
}
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 80%;
|
||||
margin: 20px auto;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0px 5px 15px rgba(255, 0, 0, 0.3);
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 2em;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.item {
|
||||
background-color: #220000;
|
||||
color: #ffcccc;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
.item-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.item-content img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
margin-left: 20px;
|
||||
width: calc(100% - 220px);
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
padding: 10px 0px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
.description {
|
||||
margin-top: 20px; /* Space from the carousel */
|
||||
padding: 15px;
|
||||
background-color: rgba(0, 0, 0, 0.3); /* Semi-transparent background */
|
||||
border-radius: 10px;
|
||||
border: 2px solid #660000; /* Red border */
|
||||
}
|
||||
.description p {
|
||||
color: #ffcccc; /* Light red text color */
|
||||
font-size: 1.1em;
|
||||
line-height: 1.6;
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
.content {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.item {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.buttons {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.carousel-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
perspective: 1200px;
|
||||
position: relative;
|
||||
height: 250px;
|
||||
overflow: hidden;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.carousel {
|
||||
display: flex;
|
||||
transition: transform 0.5s ease;
|
||||
transform-style: preserve-3d;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.carousel-item {
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
transition: transform 0.5s ease, opacity 0.5s ease;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
opacity: 1;
|
||||
}
|
||||
.carousel-item:nth-child(1) {
|
||||
transform: translateX(-150%) translateY(20px) scale(0.8) rotateY(-30deg);
|
||||
}
|
||||
.carousel-item:nth-child(2) {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.carousel-item:nth-child(3) {
|
||||
transform: translateX(50%) translateY(20px) scale(0.8) rotateY(30deg);
|
||||
}
|
||||
|
||||
.carousel-item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
.carousel-controls {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translateY(-50%);
|
||||
width: 100%;
|
||||
padding: 0; /* Remove padding */
|
||||
}
|
||||
.carousel-button {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.5em;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
margin: 0 10px; /* Add margin */
|
||||
}
|
||||
.carousel-button:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<a href="/" style="text-decoration: none; color: inherit;">
|
||||
<h1>BR0TCRAFT</h1>
|
||||
</a>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="section">
|
||||
<div class="section-title">Br0tkabeln (beta)</div>
|
||||
<div class="content">
|
||||
<div class="item">
|
||||
<div class="item-content">
|
||||
<img src="/img/Apps/Br0tkabeln.jpg" alt="App 1 Image">
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<a href="https://vocabulary.br0tcraft.de/" class="button">Starten</a>
|
||||
<a href="#" class="button">Github-Repository</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p>
|
||||
Ein simpler und hoffentlich auch einfach zu verstehender Vokabeltrainer
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Der Vokabeltrainer wurde mit Python, Html, Css, Javascript und Flask erstellt. Deine Vokabeln werden kostenlos auf dem Server gespeichert
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Es werden jediglich Benutzername, Vokabeln(English & Deutsch) und deren Level in Klartext auf dem Server gespeichert. Das Passwort wiederum wird zur Sicherheit gehasht.
|
||||
</p>
|
||||
<p>
|
||||
Es gehen keine Daten an Dritte weiter und nur ich (und der jeweilge Besitzer seiner bzw mit ihm geteilten Acountdaten) haben Zugriff auf diese oben genannten Informationen
|
||||
</p>
|
||||
</div>
|
||||
<div class="carousel-container">
|
||||
<div class="carousel">
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/Br0tkabeln/Vocabbild.PNG" alt="App 1 Image 1">
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/Br0tkabeln.jpg" alt="App 1 Image 2">
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/Br0tkabeln/Vocabbild2.PNG" alt="App 1 Image 3">
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-controls">
|
||||
<button class="carousel-button prev"><</button>
|
||||
<button class="carousel-button next">></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const carousel = document.querySelector('.carousel');
|
||||
const items = document.querySelectorAll('.carousel-item');
|
||||
const prevButton = document.querySelector('.prev');
|
||||
const nextButton = document.querySelector('.next');
|
||||
|
||||
let currentItem = 2; // Start with the middle item
|
||||
|
||||
function updateCarousel() {
|
||||
items.forEach((item, index) => {
|
||||
if (index === currentItem - 1) {
|
||||
// Center item
|
||||
item.style.transform = 'translateX(-50%)';
|
||||
} else if (index < currentItem - 1) {
|
||||
// Items to the left
|
||||
item.style.transform = `translateX(${-150 - (currentItem - index - 2) * 100}%) translateY(20px) scale(0.8) rotateY(-30deg)`;
|
||||
} else {
|
||||
// Items to the right
|
||||
item.style.transform = `translateX(${50 + (index - currentItem) * 100}%) translateY(20px) scale(0.8) rotateY(30deg)`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
prevButton.addEventListener('click', () => {
|
||||
currentItem--;
|
||||
if (currentItem < 1) {
|
||||
currentItem = items.length;
|
||||
}
|
||||
updateCarousel();
|
||||
});
|
||||
|
||||
nextButton.addEventListener('click', () => {
|
||||
currentItem++;
|
||||
if (currentItem > items.length) {
|
||||
currentItem = 1;
|
||||
}
|
||||
updateCarousel();
|
||||
});
|
||||
|
||||
// Initial setup
|
||||
updateCarousel();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,274 +0,0 @@
|
||||
!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<link rel="icon" href="/img/favicon.jpg" type="image/png">
|
||||
<meta charset="UTF-8">
|
||||
<title>BR0TCRAFT</title>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Orbitron';
|
||||
src: url('/fonts/Orbitron-Black.ttf') format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('/fonts/Roboto-Regular.ttf') format('truetype');
|
||||
}
|
||||
body {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
background-color: #120000;
|
||||
color: #ffb3b3;
|
||||
margin: 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.header {
|
||||
background-color: #330000;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-bottom: 5px solid #660000;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 2.5em;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.container {
|
||||
padding-top: 80px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
perspective: 1000px;
|
||||
}
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 80%;
|
||||
margin: 20px auto;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0px 5px 15px rgba(255, 0, 0, 0.3);
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 2em;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.item {
|
||||
background-color: #220000;
|
||||
color: #ffcccc;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
.item-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.item-content img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
margin-left: 20px;
|
||||
width: calc(100% - 220px);
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
padding: 10px 0px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
.description {
|
||||
margin-top: 20px; /* Space from the carousel */
|
||||
padding: 15px;
|
||||
background-color: rgba(0, 0, 0, 0.3); /* Semi-transparent background */
|
||||
border-radius: 10px;
|
||||
border: 2px solid #660000; /* Red border */
|
||||
}
|
||||
.description p {
|
||||
color: #ffcccc; /* Light red text color */
|
||||
font-size: 1.1em;
|
||||
line-height: 1.6;
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
.content {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.item {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.buttons {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.carousel-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
perspective: 1200px;
|
||||
position: relative;
|
||||
height: 250px;
|
||||
overflow: hidden;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.carousel {
|
||||
display: flex;
|
||||
transition: transform 0.5s ease;
|
||||
transform-style: preserve-3d;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.carousel-item {
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
transition: transform 0.5s ease, opacity 0.5s ease;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
opacity: 1;
|
||||
}
|
||||
.carousel-item:nth-child(1) {
|
||||
transform: translateX(-150%) translateY(20px) scale(0.8) rotateY(-30deg);
|
||||
}
|
||||
.carousel-item:nth-child(2) {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.carousel-item:nth-child(3) {
|
||||
transform: translateX(50%) translateY(20px) scale(0.8) rotateY(30deg);
|
||||
}
|
||||
|
||||
.carousel-item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
.carousel-controls {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translateY(-50%);
|
||||
width: 100%;
|
||||
padding: 0; /* Remove padding */
|
||||
}
|
||||
.carousel-button {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.5em;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
margin: 0 10px; /* Add margin */
|
||||
}
|
||||
.carousel-button:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<a href="/" style="text-decoration: none; color: inherit;">
|
||||
<h1>BR0TCRAFT</h1>
|
||||
</a>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="section">
|
||||
<div class="section-title">Sensor data</div>
|
||||
<div class="content">
|
||||
<div class="item">
|
||||
<div class="item-content">
|
||||
<img src="/img/Apps/PocketCode/Sensor/Sensor.png" alt="App 1 Image">
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<a href="https://share.catrob.at/app/project/445cff43-cbda-401a-bae7-924ec0dc6384" class="button">Spielen/Herunterladen</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p>Diese App ist dazu gedacht Programmteile in sein eigenes Pocket Code Projekt einzufügen. Es hat einfach schon bestimmte komplizierte programme erstellt bei denen es evtl. sinvoll ist diese auch in sein Spiel hinzuzufügen, ohne daran ewig zu arbeiten</p>
|
||||
|
||||
<p>Diese App erlaubt dir herauszufinden ob und wie lange die App im Hintergrund lief. Wie lange es her ist das die App das letzte mal geöffnet wurde. Eine automatische Update erkennen für dein Spiel, um zu checken obn das game sich aktualisieren soll und zu guter letzt noch die funktion eine Liste anzuzeigen (praktisch zum debuggen von Spielen). Benutzt diese App wie ihr wollt, sie gehört ganz euch (Lizenz: CC0)</p>
|
||||
|
||||
<p> Spielbar nur am Handy mit der App <a href="/enviroments/PocketCode/index.html">Pocket Code</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,334 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<link rel="icon" href="/img/favicon.jpg" type="image/png">
|
||||
<meta charset="UTF-8">
|
||||
<title>BR0TCRAFT</title>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Orbitron';
|
||||
src: url('/fonts/Orbitron-Black.ttf') format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('/fonts/Roboto-Regular.ttf') format('truetype');
|
||||
}
|
||||
body {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
background-color: #120000;
|
||||
color: #ffb3b3;
|
||||
margin: 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.header {
|
||||
background-color: #330000;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-bottom: 5px solid #660000;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 2.5em;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.container {
|
||||
padding-top: 80px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
perspective: 1000px;
|
||||
}
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 80%;
|
||||
margin: 20px auto;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0px 5px 15px rgba(255, 0, 0, 0.3);
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 2em;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.item {
|
||||
background-color: #220000;
|
||||
color: #ffcccc;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
.item-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.item-content img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
margin-left: 20px;
|
||||
width: calc(100% - 220px);
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
padding: 10px 0px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
.description {
|
||||
margin-top: 20px; /* Space from the carousel */
|
||||
padding: 15px;
|
||||
background-color: rgba(0, 0, 0, 0.3); /* Semi-transparent background */
|
||||
border-radius: 10px;
|
||||
border: 2px solid #660000; /* Red border */
|
||||
}
|
||||
.description p {
|
||||
color: #ffcccc; /* Light red text color */
|
||||
font-size: 1.1em;
|
||||
line-height: 1.6;
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
.content {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.item {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.buttons {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.carousel-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
perspective: 1200px;
|
||||
position: relative;
|
||||
height: 250px;
|
||||
overflow: hidden;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.carousel {
|
||||
display: flex;
|
||||
transition: transform 0.5s ease;
|
||||
transform-style: preserve-3d;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.carousel-item {
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
transition: transform 0.5s ease, opacity 0.5s ease;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
opacity: 1;
|
||||
}
|
||||
.carousel-item:nth-child(1) {
|
||||
transform: translateX(-150%) translateY(20px) scale(0.8) rotateY(-30deg);
|
||||
}
|
||||
.carousel-item:nth-child(2) {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.carousel-item:nth-child(3) {
|
||||
transform: translateX(50%) translateY(20px) scale(0.8) rotateY(30deg);
|
||||
}
|
||||
|
||||
.carousel-item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
.carousel-controls {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translateY(-50%);
|
||||
width: 100%;
|
||||
padding: 0; /* Remove padding */
|
||||
}
|
||||
.carousel-button {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.5em;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
margin: 0 10px; /* Add margin */
|
||||
}
|
||||
.carousel-button:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<a href="/" style="text-decoration: none; color: inherit;">
|
||||
<h1>BR0TCRAFT</h1>
|
||||
</a>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="section">
|
||||
<div class="section-title">Tower defense (Beta)</div>
|
||||
<div class="content">
|
||||
<div class="item">
|
||||
<div class="item-content">
|
||||
<img src="/img/Apps/PocketCode/Tower/Tower.png" alt="App 1 Image">
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<a href="https://share.catrob.at/app/project/ef0b260c-a0a6-4e87-9eab-d7759de1f092" class="button">Spielen/Herunterladen</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p>Ein kleines unvertiges Tower-Defense-game, welches Leider überhaupt nicht mehr funktioniert. Immerhin sind die Assets recht schön geworden die kann man/irgendjemand ja noch verwenden(Lizenz: CC0). Ich hab jedenfalls momentan keine Lust daran weiter zu arbeiten </p>
|
||||
|
||||
<p>In dem Spiel gibt es Münzen mit denen kannst du dir Verteidigungsposten kaufen bzw Verbessern. Geld bekommst du von den Angriffen von Gegnern die du starten kannst, welche auch immer stärker werden</p>
|
||||
|
||||
<p> Spielbar nur am Handy mit der App <a href="/enviroments/PocketCode/index.html">Pocket Code</a></p>
|
||||
</div>
|
||||
<div class="carousel-container">
|
||||
<div class="carousel">
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/PocketCode/Tower/Tower1.jpg" alt="App 1 Image 1">
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/PocketCode/Tower/Tower.png" alt="App 1 Image 2">
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/PocketCode/Tower/Tower2.jpg" alt="App 1 Image 3">
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-controls">
|
||||
<button class="carousel-button prev"><</button>
|
||||
<button class="carousel-button next">></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const carousel = document.querySelector('.carousel');
|
||||
const items = document.querySelectorAll('.carousel-item');
|
||||
const prevButton = document.querySelector('.prev');
|
||||
const nextButton = document.querySelector('.next');
|
||||
|
||||
let currentItem = 2; // Start with the middle item
|
||||
|
||||
function updateCarousel() {
|
||||
items.forEach((item, index) => {
|
||||
if (index === currentItem - 1) {
|
||||
// Center item
|
||||
item.style.transform = 'translateX(-50%)';
|
||||
} else if (index < currentItem - 1) {
|
||||
// Items to the left
|
||||
item.style.transform = `translateX(${-150 - (currentItem - index - 2) * 100}%) translateY(20px) scale(0.8) rotateY(-30deg)`;
|
||||
} else {
|
||||
// Items to the right
|
||||
item.style.transform = `translateX(${50 + (index - currentItem) * 100}%) translateY(20px) scale(0.8) rotateY(30deg)`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
prevButton.addEventListener('click', () => {
|
||||
currentItem--;
|
||||
if (currentItem < 1) {
|
||||
currentItem = items.length;
|
||||
}
|
||||
updateCarousel();
|
||||
});
|
||||
|
||||
nextButton.addEventListener('click', () => {
|
||||
currentItem++;
|
||||
if (currentItem > items.length) {
|
||||
currentItem = 1;
|
||||
}
|
||||
updateCarousel();
|
||||
});
|
||||
|
||||
// Initial setup
|
||||
updateCarousel();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,334 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<link rel="icon" href="/img/favicon.jpg" type="image/png">
|
||||
<meta charset="UTF-8">
|
||||
<title>BR0TCRAFT</title>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Orbitron';
|
||||
src: url('/fonts/Orbitron-Black.ttf') format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('/fonts/Roboto-Regular.ttf') format('truetype');
|
||||
}
|
||||
body {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
background-color: #120000;
|
||||
color: #ffb3b3;
|
||||
margin: 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.header {
|
||||
background-color: #330000;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-bottom: 5px solid #660000;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 2.5em;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.container {
|
||||
padding-top: 80px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
perspective: 1000px;
|
||||
}
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 80%;
|
||||
margin: 20px auto;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0px 5px 15px rgba(255, 0, 0, 0.3);
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 2em;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.item {
|
||||
background-color: #220000;
|
||||
color: #ffcccc;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
.item-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.item-content img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
margin-left: 20px;
|
||||
width: calc(100% - 220px);
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
padding: 10px 0px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
.description {
|
||||
margin-top: 20px; /* Space from the carousel */
|
||||
padding: 15px;
|
||||
background-color: rgba(0, 0, 0, 0.3); /* Semi-transparent background */
|
||||
border-radius: 10px;
|
||||
border: 2px solid #660000; /* Red border */
|
||||
}
|
||||
.description p {
|
||||
color: #ffcccc; /* Light red text color */
|
||||
font-size: 1.1em;
|
||||
line-height: 1.6;
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
.content {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.item {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.buttons {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.carousel-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
perspective: 1200px;
|
||||
position: relative;
|
||||
height: 250px;
|
||||
overflow: hidden;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.carousel {
|
||||
display: flex;
|
||||
transition: transform 0.5s ease;
|
||||
transform-style: preserve-3d;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.carousel-item {
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
transition: transform 0.5s ease, opacity 0.5s ease;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
opacity: 1;
|
||||
}
|
||||
.carousel-item:nth-child(1) {
|
||||
transform: translateX(-150%) translateY(20px) scale(0.8) rotateY(-30deg);
|
||||
}
|
||||
.carousel-item:nth-child(2) {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.carousel-item:nth-child(3) {
|
||||
transform: translateX(50%) translateY(20px) scale(0.8) rotateY(30deg);
|
||||
}
|
||||
|
||||
.carousel-item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
.carousel-controls {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translateY(-50%);
|
||||
width: 100%;
|
||||
padding: 0; /* Remove padding */
|
||||
}
|
||||
.carousel-button {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.5em;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
margin: 0 10px; /* Add margin */
|
||||
}
|
||||
.carousel-button:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<a href="/" style="text-decoration: none; color: inherit;">
|
||||
<h1>BR0TCRAFT</h1>
|
||||
</a>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="section">
|
||||
<div class="section-title">auto-clicker</div>
|
||||
<div class="content">
|
||||
<div class="item">
|
||||
<div class="item-content">
|
||||
<img src="/img/Apps/PocketCode/auto-clicker/auto-clicker.png" alt="App 1 Image">
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<a href="https://share.catrob.at/app/project/13f85a59-ae25-416f-a9b8-33ad1ab3a430" class="button">Spielen/Herunterladen</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p>Ein meiner Meinung nach sehr einfach zu bedienender auto-clicker</p>
|
||||
|
||||
<p>Es ist an sich ganz einfach. Die App besteht nur aus einem ObjeKt, dieses Objekt kopierst du dir und fügst es in das Spiel deiner Wahl ein und schon hast du einen automatischen Klicker immer an deiner Seite</p>
|
||||
|
||||
<p> Spielbar nur am Handy mit der App <a href="/enviroments/PocketCode/index.html">Pocket Code</a></p>
|
||||
</div>
|
||||
<div class="carousel-container">
|
||||
<div class="carousel">
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/PocketCode/auto-clicker/clicker1.jpg" alt="App 1 Image 1">
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/PocketCode/auto-clicker/auto-clicker.png" alt="App 1 Image 2">
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/PocketCode/auto-clicker/clicker2.jpg" alt="App 1 Image 3">
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-controls">
|
||||
<button class="carousel-button prev"><</button>
|
||||
<button class="carousel-button next">></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const carousel = document.querySelector('.carousel');
|
||||
const items = document.querySelectorAll('.carousel-item');
|
||||
const prevButton = document.querySelector('.prev');
|
||||
const nextButton = document.querySelector('.next');
|
||||
|
||||
let currentItem = 2; // Start with the middle item
|
||||
|
||||
function updateCarousel() {
|
||||
items.forEach((item, index) => {
|
||||
if (index === currentItem - 1) {
|
||||
// Center item
|
||||
item.style.transform = 'translateX(-50%)';
|
||||
} else if (index < currentItem - 1) {
|
||||
// Items to the left
|
||||
item.style.transform = `translateX(${-150 - (currentItem - index - 2) * 100}%) translateY(20px) scale(0.8) rotateY(-30deg)`;
|
||||
} else {
|
||||
// Items to the right
|
||||
item.style.transform = `translateX(${50 + (index - currentItem) * 100}%) translateY(20px) scale(0.8) rotateY(30deg)`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
prevButton.addEventListener('click', () => {
|
||||
currentItem--;
|
||||
if (currentItem < 1) {
|
||||
currentItem = items.length;
|
||||
}
|
||||
updateCarousel();
|
||||
});
|
||||
|
||||
nextButton.addEventListener('click', () => {
|
||||
currentItem++;
|
||||
if (currentItem > items.length) {
|
||||
currentItem = 1;
|
||||
}
|
||||
updateCarousel();
|
||||
});
|
||||
|
||||
// Initial setup
|
||||
updateCarousel();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,332 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<link rel="icon" href="/img/favicon.jpg" type="image/png">
|
||||
<meta charset="UTF-8">
|
||||
<title>BR0TCRAFT</title>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Orbitron';
|
||||
src: url('/fonts/Orbitron-Black.ttf') format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('/fonts/Roboto-Regular.ttf') format('truetype');
|
||||
}
|
||||
body {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
background-color: #120000;
|
||||
color: #ffb3b3;
|
||||
margin: 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.header {
|
||||
background-color: #330000;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-bottom: 5px solid #660000;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 2.5em;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.container {
|
||||
padding-top: 80px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
perspective: 1000px;
|
||||
}
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 80%;
|
||||
margin: 20px auto;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0px 5px 15px rgba(255, 0, 0, 0.3);
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 2em;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.item {
|
||||
background-color: #220000;
|
||||
color: #ffcccc;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
.item-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.item-content img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
margin-left: 20px;
|
||||
width: calc(100% - 220px);
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
padding: 10px 0px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
.description {
|
||||
margin-top: 20px; /* Space from the carousel */
|
||||
padding: 15px;
|
||||
background-color: rgba(0, 0, 0, 0.3); /* Semi-transparent background */
|
||||
border-radius: 10px;
|
||||
border: 2px solid #660000; /* Red border */
|
||||
}
|
||||
.description p {
|
||||
color: #ffcccc; /* Light red text color */
|
||||
font-size: 1.1em;
|
||||
line-height: 1.6;
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
.content {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.item {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.buttons {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.carousel-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
perspective: 1200px;
|
||||
position: relative;
|
||||
height: 250px;
|
||||
overflow: hidden;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.carousel {
|
||||
display: flex;
|
||||
transition: transform 0.5s ease;
|
||||
transform-style: preserve-3d;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.carousel-item {
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
transition: transform 0.5s ease, opacity 0.5s ease;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
opacity: 1;
|
||||
}
|
||||
.carousel-item:nth-child(1) {
|
||||
transform: translateX(-150%) translateY(20px) scale(0.8) rotateY(-30deg);
|
||||
}
|
||||
.carousel-item:nth-child(2) {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.carousel-item:nth-child(3) {
|
||||
transform: translateX(50%) translateY(20px) scale(0.8) rotateY(30deg);
|
||||
}
|
||||
|
||||
.carousel-item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
.carousel-controls {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translateY(-50%);
|
||||
width: 100%;
|
||||
padding: 0; /* Remove padding */
|
||||
}
|
||||
.carousel-button {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.5em;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
margin: 0 10px; /* Add margin */
|
||||
}
|
||||
.carousel-button:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<a href="/" style="text-decoration: none; color: inherit;">
|
||||
<h1>BR0TCRAFT</h1>
|
||||
</a>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="section">
|
||||
<div class="section-title">Tiny Snake</div>
|
||||
<div class="content">
|
||||
<div class="item">
|
||||
<div class="item-content">
|
||||
<img src="/img/Apps/snake.jpg" alt="App 1 Image">
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<a href="/play/Tiny-Snake/snake.html" class="button">Spielen</a>
|
||||
<a href="#" class="button">Herunterladen</a>
|
||||
<a href="#" class="button">Github-Repository</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p>Hier ist das nächste große AAA-game. Naja nicht wirklich. Also eigentlich ist es ein super einfaches Snake game, ohne vielen funktionen. Das erstaunliche dabei ist das es so kompakt wie (für mich) möglich ist. Funktioniert leider nur am PC. Man bewegt die Schlange mit den Pfeiltasten</p>
|
||||
</div>
|
||||
<div class="carousel-container">
|
||||
<div class="carousel">
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/Snake/snake1.PNG" alt="App 1 Image 1">
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/snake.jpg" alt="App 1 Image 2">
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="/img/Apps/Snake/Snake2.png" alt="App 1 Image 3">
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-controls">
|
||||
<button class="carousel-button prev"><</button>
|
||||
<button class="carousel-button next">></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const carousel = document.querySelector('.carousel');
|
||||
const items = document.querySelectorAll('.carousel-item');
|
||||
const prevButton = document.querySelector('.prev');
|
||||
const nextButton = document.querySelector('.next');
|
||||
|
||||
let currentItem = 2; // Start with the middle item
|
||||
|
||||
function updateCarousel() {
|
||||
items.forEach((item, index) => {
|
||||
if (index === currentItem - 1) {
|
||||
// Center item
|
||||
item.style.transform = 'translateX(-50%)';
|
||||
} else if (index < currentItem - 1) {
|
||||
// Items to the left
|
||||
item.style.transform = `translateX(${-150 - (currentItem - index - 2) * 100}%) translateY(20px) scale(0.8) rotateY(-30deg)`;
|
||||
} else {
|
||||
// Items to the right
|
||||
item.style.transform = `translateX(${50 + (index - currentItem) * 100}%) translateY(20px) scale(0.8) rotateY(30deg)`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
prevButton.addEventListener('click', () => {
|
||||
currentItem--;
|
||||
if (currentItem < 1) {
|
||||
currentItem = items.length;
|
||||
}
|
||||
updateCarousel();
|
||||
});
|
||||
|
||||
nextButton.addEventListener('click', () => {
|
||||
currentItem++;
|
||||
if (currentItem > items.length) {
|
||||
currentItem = 1;
|
||||
}
|
||||
updateCarousel();
|
||||
});
|
||||
|
||||
// Initial setup
|
||||
updateCarousel();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
378
article.html
Normal file
@@ -0,0 +1,378 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>BR0TCRAFT | Artikel</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;600&family=Inter:wght@300;400;600;800&family=Orbitron:wght@700&display=swap"
|
||||
rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav class="navbar">
|
||||
<div class="brand">BR0TCRAFT</div>
|
||||
<div class="nav-links">
|
||||
<a href="index.html">Home</a>
|
||||
<a href="projects.html">Projekte</a>
|
||||
<a href="tutorials.html" class="active">Dev Notes</a>
|
||||
<a href="about.html">About</a>
|
||||
<a href="assets.html">Assets</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="sidebar-overlay" id="overlay"></div>
|
||||
|
||||
<button class="mobile-menu-btn" id="menuToggle">
|
||||
<span></span>
|
||||
</button>
|
||||
|
||||
<div class="container-docs">
|
||||
<div class="docs-layout">
|
||||
|
||||
<aside class="docs-sidebar" id="sidebar">
|
||||
<button class="sidebar-toggle-desktop" id="sidebarCollapseBtn">
|
||||
<span>←</span> Sidebar einklappen
|
||||
</button>
|
||||
<div class="sidebar-group">
|
||||
<h4>Kapitel</h4>
|
||||
<div id="auto-toc"></div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<button class="sidebar-collapsed-trigger" id="sidebarExpandBtn" title="Sidebar zeigen">
|
||||
→
|
||||
</button>
|
||||
|
||||
<main class="section">
|
||||
<div id="markdown-content">
|
||||
<p style="color: #444; font-family: var(--font-code); font-size: 0.85rem;">Lade Inhalt...</p>
|
||||
</div>
|
||||
|
||||
<div id="doc-nav" class="doc-pagination"></div>
|
||||
|
||||
<div style="margin-top: 4rem; border-top: 1px solid #1e1e1e; padding-top: 2rem; display: flex; gap: 0.75rem;">
|
||||
<a href="tutorials.html" class="btn">← Dev Notes</a>
|
||||
<a href="index.html" class="btn"
|
||||
style="background: transparent; border: 1px solid #222; color: var(--text-muted);">Home</a>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const fileParam = urlParams.get('file');
|
||||
const docParam = urlParams.get('doc');
|
||||
const partParam = urlParams.get('part');
|
||||
const contentDiv = document.getElementById('markdown-content');
|
||||
const toc = document.getElementById('auto-toc');
|
||||
|
||||
let docManifest = null;
|
||||
|
||||
// --- 1. Tabs System ---
|
||||
function initTabs() {
|
||||
document.querySelectorAll('.code-tabs').forEach((group, gIdx) => {
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'tab-wrapper';
|
||||
|
||||
const headerRow = document.createElement('div');
|
||||
headerRow.className = 'tab-header-row';
|
||||
wrapper.appendChild(headerRow);
|
||||
|
||||
const children = Array.from(group.children);
|
||||
let tabCount = 0;
|
||||
|
||||
children.forEach((child) => {
|
||||
if (child.tagName.startsWith('H')) {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'tab-trigger';
|
||||
btn.textContent = child.textContent;
|
||||
btn.dataset.target = `panel-${gIdx}-${tabCount}`;
|
||||
if (tabCount === 0) btn.classList.add('active');
|
||||
|
||||
btn.onclick = (e) => {
|
||||
wrapper.querySelectorAll('.tab-trigger').forEach(b => b.classList.remove('active'));
|
||||
wrapper.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
|
||||
e.target.classList.add('active');
|
||||
wrapper.querySelector(`#${e.target.dataset.target}`).classList.add('active');
|
||||
};
|
||||
headerRow.appendChild(btn);
|
||||
} else if (child.tagName === 'PRE') {
|
||||
const panel = document.createElement('div');
|
||||
panel.className = 'tab-panel';
|
||||
panel.id = `panel-${gIdx}-${tabCount}`;
|
||||
if (tabCount === 0) panel.classList.add('active');
|
||||
panel.appendChild(child.cloneNode(true));
|
||||
wrapper.appendChild(panel);
|
||||
tabCount++;
|
||||
}
|
||||
});
|
||||
group.parentNode.replaceChild(wrapper, group);
|
||||
});
|
||||
}
|
||||
|
||||
// --- 2. Code Headers & Copy Button ---
|
||||
function enhanceCodeBlocks() {
|
||||
hljs.highlightAll();
|
||||
document.querySelectorAll('pre code').forEach((block) => {
|
||||
const parent = block.parentElement;
|
||||
if (parent.querySelector('.code-header')) return;
|
||||
|
||||
let lang = "CODE";
|
||||
block.classList.forEach(c => { if (c.startsWith('language-')) lang = c.split('-')[1].toUpperCase(); });
|
||||
|
||||
const header = document.createElement('div');
|
||||
header.className = 'code-header';
|
||||
|
||||
const copyBtn = document.createElement('button');
|
||||
copyBtn.className = 'copy-btn';
|
||||
copyBtn.innerHTML = `<span>Copy</span>`;
|
||||
copyBtn.onclick = () => {
|
||||
navigator.clipboard.writeText(block.innerText);
|
||||
copyBtn.innerHTML = `<span style="color:var(--accent-primary)">Copied!</span>`;
|
||||
setTimeout(() => copyBtn.innerHTML = `<span>Copy</span>`, 2000);
|
||||
};
|
||||
|
||||
header.innerHTML = `<span class="lang-tag">${lang}</span>`;
|
||||
header.appendChild(copyBtn);
|
||||
parent.insertBefore(header, block);
|
||||
});
|
||||
}
|
||||
|
||||
// --- 3. Sidebar Generators ---
|
||||
|
||||
// Auto-generate TOC from headers (for single-file mode)
|
||||
function generateAutoTOC() {
|
||||
const headers = contentDiv.querySelectorAll('h2, h3');
|
||||
headers.forEach(h => {
|
||||
const link = document.createElement('a');
|
||||
link.className = 'sidebar-link';
|
||||
link.href = '#' + h.id;
|
||||
link.textContent = h.textContent.replace('#', '').trim();
|
||||
if (h.tagName === 'H3') link.style.paddingLeft = '25px';
|
||||
toc.appendChild(link);
|
||||
});
|
||||
}
|
||||
|
||||
// Generate Sidebar from Document Manifest
|
||||
function renderDocSidebar(chapters, container, depth = 0) {
|
||||
chapters.forEach(chapter => {
|
||||
if (chapter.children) {
|
||||
const groupTitle = document.createElement('div');
|
||||
groupTitle.className = 'sidebar-category';
|
||||
groupTitle.textContent = chapter.title;
|
||||
groupTitle.style.paddingLeft = (depth * 15) + 'px';
|
||||
|
||||
const childGroup = document.createElement('div');
|
||||
childGroup.className = 'sidebar-child-group';
|
||||
|
||||
// Check if current part is in this group to keep it open
|
||||
const hasActiveChild = (list) => list.some(c => c.id === partParam || (c.children && hasActiveChild(c.children)));
|
||||
if (!hasActiveChild(chapter.children)) {
|
||||
// groupTitle.classList.add('collapsed');
|
||||
// childGroup.classList.add('collapsed');
|
||||
}
|
||||
|
||||
groupTitle.onclick = () => {
|
||||
groupTitle.classList.toggle('collapsed');
|
||||
childGroup.classList.toggle('collapsed');
|
||||
};
|
||||
|
||||
container.appendChild(groupTitle);
|
||||
container.appendChild(childGroup);
|
||||
renderDocSidebar(chapter.children, childGroup, depth + 1);
|
||||
} else {
|
||||
const link = document.createElement('a');
|
||||
link.className = 'sidebar-link';
|
||||
if (partParam === chapter.id || (!partParam && depth === 0 && chapters.indexOf(chapter) === 0)) {
|
||||
link.classList.add('active');
|
||||
}
|
||||
link.href = `?doc=${docParam}&part=${chapter.id}`;
|
||||
link.textContent = chapter.title;
|
||||
link.style.paddingLeft = (depth * 15 + 15) + 'px';
|
||||
container.appendChild(link);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- Anchor Links ---
|
||||
function addAnchorLinks() {
|
||||
contentDiv.querySelectorAll('h1, h2, h3').forEach(h => {
|
||||
const slug = h.textContent.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)+/g, '');
|
||||
h.id = slug;
|
||||
const a = document.createElement('a');
|
||||
a.className = 'anchor-link';
|
||||
a.href = '#' + slug;
|
||||
a.innerHTML = '#';
|
||||
h.insertBefore(a, h.firstChild);
|
||||
});
|
||||
}
|
||||
|
||||
// --- Navigation ---
|
||||
const menuBtn = document.getElementById('menuToggle');
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const overlay = document.getElementById('overlay');
|
||||
const docsLayout = document.querySelector('.docs-layout');
|
||||
|
||||
function toggleMenu() {
|
||||
menuBtn.classList.toggle('active');
|
||||
sidebar.classList.toggle('active');
|
||||
overlay.classList.toggle('active');
|
||||
}
|
||||
|
||||
menuBtn.addEventListener('click', toggleMenu);
|
||||
overlay.addEventListener('click', toggleMenu);
|
||||
|
||||
// Desktop Toggle
|
||||
document.getElementById('sidebarCollapseBtn')?.addEventListener('click', () => {
|
||||
docsLayout.classList.add('sidebar-collapsed');
|
||||
});
|
||||
|
||||
document.getElementById('sidebarExpandBtn')?.addEventListener('click', () => {
|
||||
docsLayout.classList.remove('sidebar-collapsed');
|
||||
});
|
||||
|
||||
document.addEventListener('click', (e) => {
|
||||
if (e.target.classList.contains('sidebar-link') && window.innerWidth <= 1024) {
|
||||
toggleMenu();
|
||||
}
|
||||
});
|
||||
|
||||
// --- Update page title ---
|
||||
function updateTitle() {
|
||||
const h1 = contentDiv.querySelector('h1');
|
||||
if (h1) {
|
||||
document.title = 'BR0TCRAFT | ' + h1.textContent.replace('#', '').trim();
|
||||
}
|
||||
}
|
||||
|
||||
// --- Loading Logic ---
|
||||
|
||||
function loadMarkdown(path) {
|
||||
fetch(path)
|
||||
.then(r => {
|
||||
if (!r.ok) throw new Error('Datei nicht gefunden');
|
||||
return r.text();
|
||||
})
|
||||
.then(md => {
|
||||
contentDiv.innerHTML = marked.parse(md);
|
||||
updateTitle();
|
||||
addAnchorLinks();
|
||||
initTabs();
|
||||
enhanceCodeBlocks();
|
||||
if (!docParam) generateAutoTOC();
|
||||
window.scrollTo(0, 0);
|
||||
})
|
||||
.catch(() => {
|
||||
contentDiv.innerHTML = `<p style="color:#555; font-family:var(--font-code); font-size:0.85rem;">
|
||||
Inhalt konnte nicht geladen werden.
|
||||
</p>`;
|
||||
});
|
||||
}
|
||||
|
||||
// --- Navigation Footer ---
|
||||
function renderPagination() {
|
||||
if (!docManifest) return;
|
||||
|
||||
const nav = document.getElementById('doc-nav');
|
||||
nav.innerHTML = '';
|
||||
|
||||
// Flatten structure to get linear sequence
|
||||
const flat = [];
|
||||
const flatten = (list) => {
|
||||
list.forEach(item => {
|
||||
if (item.file) flat.push(item);
|
||||
if (item.children) flatten(item.children);
|
||||
});
|
||||
};
|
||||
flatten(docManifest.chapters);
|
||||
|
||||
const currentIndex = flat.findIndex(item => item.id === (partParam || flat[0].id));
|
||||
|
||||
if (currentIndex > 0) {
|
||||
const prev = flat[currentIndex - 1];
|
||||
const a = document.createElement('a');
|
||||
a.href = `?doc=${docParam}&part=${prev.id}`;
|
||||
a.className = 'nav-page-btn prev';
|
||||
a.innerHTML = `<span class="nav-label">Zurück</span><span class="nav-title">${prev.title}</span>`;
|
||||
nav.appendChild(a);
|
||||
} else {
|
||||
nav.appendChild(document.createElement('div')); // Spacer
|
||||
}
|
||||
|
||||
if (currentIndex < flat.length - 1) {
|
||||
const next = flat[currentIndex + 1];
|
||||
const a = document.createElement('a');
|
||||
a.href = `?doc=${docParam}&part=${next.id}`;
|
||||
a.className = 'nav-page-btn next';
|
||||
a.innerHTML = `<span class="nav-label">Weiter</span><span class="nav-title">${next.title}</span>`;
|
||||
nav.appendChild(a);
|
||||
}
|
||||
}
|
||||
|
||||
if (docParam) {
|
||||
const manifestPath = `content/${docParam}/index.json`;
|
||||
fetch(manifestPath)
|
||||
.then(r => {
|
||||
if (!r.ok) throw new Error('Manifest nicht gefunden');
|
||||
return r.json();
|
||||
})
|
||||
.then(data => {
|
||||
docManifest = data;
|
||||
document.querySelector('#sidebar h4').textContent = data.title || "Kapitel";
|
||||
renderDocSidebar(data.chapters, toc);
|
||||
|
||||
let targetFile = null;
|
||||
const findPart = (list) => {
|
||||
for (const item of list) {
|
||||
if (item.id === partParam) { targetFile = item.file; break; }
|
||||
if (item.children) findPart(item.children);
|
||||
if (targetFile) break;
|
||||
}
|
||||
};
|
||||
|
||||
if (partParam) {
|
||||
findPart(data.chapters);
|
||||
} else {
|
||||
const first = data.chapters[0];
|
||||
targetFile = first.children ? first.children[0].file : first.file;
|
||||
}
|
||||
|
||||
if (targetFile) {
|
||||
loadMarkdown(`content/${docParam}/${targetFile}`);
|
||||
renderPagination();
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
contentDiv.innerHTML = `<div style="background: rgba(255,77,77,0.05); border: 1px solid var(--accent-primary); padding: 2rem; border-radius: 12px; margin-top: 2rem;">
|
||||
<h3 style="color: var(--accent-primary); margin-top: 0;">Ladefehler</h3>
|
||||
<p style="color:#aaa; font-size:0.9rem;">Die Dokumentation <b>${docParam}</b> konnte nicht geladen werden.</p>
|
||||
<ul style="color:#777; font-size:0.8rem; margin-top: 1rem;">
|
||||
<li>Prüfe, ob du die Seite über einen <b>Webserver</b> aufrufst (nicht nur lokal öffnen).</li>
|
||||
<li>Prüfe, ob die Datei <code>content/${docParam}/index.json</code> existiert.</li>
|
||||
</ul>
|
||||
</div>`;
|
||||
});
|
||||
|
||||
} else if (fileParam) {
|
||||
loadMarkdown(fileParam);
|
||||
} else {
|
||||
contentDiv.innerHTML = `<p style="color:#555; font-family:var(--font-code); font-size:0.85rem;">
|
||||
Kein Artikel angegeben.
|
||||
</p>`;
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
290
assets.html
Normal file
@@ -0,0 +1,290 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>BR0TCRAFT | Assets</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;600&family=Inter:wght@300;400;600;800&family=Orbitron:wght@700&display=swap"
|
||||
rel="stylesheet">
|
||||
<style>
|
||||
.license-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
background: rgba(255, 77, 77, 0.07);
|
||||
border: 1px solid rgba(255, 77, 77, 0.2);
|
||||
border-radius: 6px;
|
||||
padding: 0.4rem 0.9rem;
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.78rem;
|
||||
color: var(--accent-primary);
|
||||
margin-bottom: 1.75rem;
|
||||
}
|
||||
|
||||
.assets-intro {
|
||||
max-width: 600px;
|
||||
color: var(--text-muted);
|
||||
line-height: 1.75;
|
||||
font-size: 0.95rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.assets-intro p {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
/* Asset grid */
|
||||
.asset-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
||||
gap: 0.75rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.asset-item {
|
||||
border: 1px solid #1f1f1f;
|
||||
border-radius: var(--radius);
|
||||
overflow: hidden;
|
||||
background: rgba(255, 255, 255, 0.015);
|
||||
transition: border-color 0.2s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.asset-item:hover {
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
.asset-preview {
|
||||
height: 100px;
|
||||
background: #111;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.asset-preview img {
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
object-fit: contain;
|
||||
filter: brightness(0.9);
|
||||
}
|
||||
|
||||
.asset-meta {
|
||||
padding: 0.6rem 0.8rem;
|
||||
border-top: 1px solid #1a1a1a;
|
||||
}
|
||||
|
||||
.asset-name {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.75rem;
|
||||
color: #888;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.asset-type {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.65rem;
|
||||
color: #444;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* Category filter */
|
||||
.filter-row {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.filter-btn {
|
||||
background: none;
|
||||
border: 1px solid #222;
|
||||
border-radius: 4px;
|
||||
color: #555;
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.75rem;
|
||||
padding: 0.3rem 0.8rem;
|
||||
cursor: pointer;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.filter-btn.active,
|
||||
.filter-btn:hover {
|
||||
border-color: var(--accent-primary);
|
||||
color: var(--accent-primary);
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
color: #444;
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.85rem;
|
||||
padding: 3rem 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-state span {
|
||||
display: block;
|
||||
font-size: 2rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
/* Info box */
|
||||
.info-box {
|
||||
border: 1px solid #1e1e1e;
|
||||
border-radius: var(--radius);
|
||||
padding: 1.25rem 1.5rem;
|
||||
background: rgba(255, 255, 255, 0.015);
|
||||
max-width: 600px;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.info-box h4 {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.78rem;
|
||||
color: var(--accent-primary);
|
||||
margin-bottom: 0.6rem;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.info-box p {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.65;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav class="navbar">
|
||||
<div class="brand">BR0TCRAFT</div>
|
||||
<div class="nav-links">
|
||||
<a href="index.html">Home</a>
|
||||
<a href="projects.html">Projekte</a>
|
||||
<a href="tutorials.html">Dev Notes</a>
|
||||
<a href="about.html">About</a>
|
||||
<a href="assets.html" class="active">Assets</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
<section class="section">
|
||||
<h1 style="font-family: var(--font-display); margin-bottom: 1.25rem; color: #fff;">Assets</h1>
|
||||
|
||||
<div class="license-badge">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="M12 8v4m0 4h.01" />
|
||||
</svg>
|
||||
CC0 Public Domain
|
||||
</div>
|
||||
|
||||
<div class="assets-intro">
|
||||
<p>
|
||||
Icons, Grafiken und kleine UI-Assets, die ich für eigene Projekte erstellt oder gesammelt habe.
|
||||
Alles steht unter <strong style="color:#fff">CC0</strong>,
|
||||
keine Namensnennung erforderlich, keine Einschränkungen bei der Nutzung.
|
||||
</p>
|
||||
<p>
|
||||
Der Grund ist eigentlich ganz einfach. Ich nutze selbst viele freie Ressourcen anderer Leute.
|
||||
Durch die Assets möchte ich auch etwas zurückgeben und das so unkompliziert wie möglich.
|
||||
</p>
|
||||
<p>
|
||||
Mitnehmen, anpassen, verwenden.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="filter-row">
|
||||
<button class="filter-btn active" onclick="filterAssets('all', this)">Alle</button>
|
||||
<button class="filter-btn" onclick="filterAssets('icon', this)">Icons</button>
|
||||
<button class="filter-btn" onclick="filterAssets('texture', this)">Texturen</button>
|
||||
<button class="filter-btn" onclick="filterAssets('ui', this)">UI</button>
|
||||
</div>
|
||||
|
||||
<div class="asset-grid" id="assetGrid">
|
||||
|
||||
<div class="asset-item" data-category="icon">
|
||||
<div class="asset-preview">🔧</div>
|
||||
<div class="asset-meta">
|
||||
<div class="asset-name">tool.svg</div>
|
||||
<div class="asset-type">SVG · Icon</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="asset-item" data-category="icon">
|
||||
<div class="asset-preview">⚙️</div>
|
||||
<div class="asset-meta">
|
||||
<div class="asset-name">settings.svg</div>
|
||||
<div class="asset-type">SVG · Icon</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="asset-item" data-category="ui">
|
||||
<div class="asset-preview">🎨</div>
|
||||
<div class="asset-meta">
|
||||
<div class="asset-name">button-set.png</div>
|
||||
<div class="asset-type">PNG · UI</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="asset-item" data-category="texture">
|
||||
<div class="asset-preview"
|
||||
style="background: repeating-linear-gradient(45deg, #111 0px, #111 2px, #0d0d0d 2px, #0d0d0d 8px);"></div>
|
||||
<div class="asset-meta">
|
||||
<div class="asset-name">noise-dark.png</div>
|
||||
<div class="asset-type">PNG · Textur</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="asset-item" data-category="icon">
|
||||
<div class="asset-preview">📁</div>
|
||||
<div class="asset-meta">
|
||||
<div class="asset-name">folder.svg</div>
|
||||
<div class="asset-type">SVG · Icon</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="asset-item" data-category="ui">
|
||||
<div class="asset-preview" style="background: linear-gradient(135deg, #1a0000, #220000);">
|
||||
<div style="width:60%; height:8px; background:#ff4d4d22; border-radius:4px;"></div>
|
||||
</div>
|
||||
<div class="asset-meta">
|
||||
<div class="asset-name">progress-bar.svg</div>
|
||||
<div class="asset-type">SVG · UI</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<h4>// Eigene Assets beisteuern?</h4>
|
||||
<p>
|
||||
Wenn du selbst freie Assets beisteuern willst, meld dich per
|
||||
<a href="mailto:info@br0tcraft.de" style="color: var(--accent-primary); text-decoration: none;">Email</a>
|
||||
oder über GitHub. CC0 ist Bedingung.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function filterAssets(category, btn) {
|
||||
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
document.querySelectorAll('.asset-item').forEach(item => {
|
||||
const show = category === 'all' || item.dataset.category === category;
|
||||
item.style.display = show ? '' : 'none';
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
25
content/3ds/index.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"title": "3ds Homebrew Dev Notes",
|
||||
"chapters": [
|
||||
{
|
||||
"title": "Introduction",
|
||||
"file": "intro.md",
|
||||
"id": "intro"
|
||||
},
|
||||
{
|
||||
"title": "DevkitPro Setup",
|
||||
"file": "devkitpro.md",
|
||||
"id": "devkitpro"
|
||||
},
|
||||
{
|
||||
"title": "Specs",
|
||||
"children": [
|
||||
{
|
||||
"title": "RAM Allocation",
|
||||
"file": "specs/ram-allocation.md",
|
||||
"id": "ram-allocation"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
32
content/3ds/intro copy.md
Normal file
@@ -0,0 +1,32 @@
|
||||
## A little overview about 3ds specs that should be known when working on homebrew for it
|
||||
|
||||
### Hardware
|
||||
#### New 3DS
|
||||
(New 3DS, New 3DS XL, New 2DS XL)
|
||||
CPU
|
||||
ARM11 @ 804 MHz (Quad-core)
|
||||
GPU
|
||||
Custom PICA200 @ 268 MHz
|
||||
RAM
|
||||
256 MB (more infos here: )
|
||||
VRAM
|
||||
10 MB
|
||||
Display
|
||||
Top: 400x240
|
||||
Bottom: 320x240
|
||||
|
||||
#### Old 3DS
|
||||
(Old 3DS, Old 3DS XL, Old 2DS)
|
||||
CPU
|
||||
ARM11 @ 268 MHz (Dual-core)
|
||||
GPU
|
||||
Custom PICA200 @ 134 MHz
|
||||
RAM
|
||||
128 MB
|
||||
VRAM
|
||||
10 MB
|
||||
Display
|
||||
Top: 400x240
|
||||
Bottom: 320x240
|
||||
|
||||
### Homebrew
|
||||
30
content/3ds/intro.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# 3DS Homebrew Development Wiki & Lookup Table
|
||||
Welcome to the ultimate resource for Nintendo 3DS homebrew development using devkitPro. This guide covers everything from setting up your toolchain to advanced hardware specifications and CIA deployment.
|
||||
|
||||
🗺️ Documentation Roadmap
|
||||
1. Toolchain & Environment Setup
|
||||
Part 1: Installing devkitPro — Step-by-step installation for Windows, Arch Linux, and Debian using the dkp-pacman package manager.
|
||||
|
||||
Part 2: Modern VS Code Integration — Configuring C/C++ IntelliSense, include paths, and automated build tasks for seamless auto-completion.
|
||||
|
||||
2. Core Development & Compilation
|
||||
Part 3: Anatomy of a 3DS Makefile — Customizing your application's metadata (Name, Author, Description, and Icon).
|
||||
|
||||
Part 4: The Build Pipeline (.3dsx) — Understanding how source code becomes an executable homebrew file.
|
||||
|
||||
3. OS Services & Hardware Interfacing
|
||||
Part 5: Storage & File Systems — Working with sdmc:/ (SD Card) and compiling assets into romfs:/.
|
||||
|
||||
Part 6: System APIs & Services — Interfacing with the OS: Battery status, System Clock, Notifications, and Mii data.
|
||||
|
||||
Part 7: Networking & Threads — Implementing multi-threading via libctru and managing Wi-Fi/Network sockets.
|
||||
|
||||
4. Advanced Deployment & Assets
|
||||
Part 8: Creating .cia Files — Packaging your app for direct installation onto the 3DS Home Menu.
|
||||
|
||||
Part 9: Crafting App Banners (2D & 3D) — Designing and compiling custom 2D icons and 3D top-screen banners.
|
||||
|
||||
5. Hardware Architecture & Technical Specifications
|
||||
Part 10: Memory (RAM) Restrictions — Navigating the strict memory layouts of Old 3DS vs. New 3DS.
|
||||
|
||||
Part 11: CPU & GPU Architecture — Understanding the ARM11/PICA200 limits and graphic rendering options.
|
||||
26
content/3ds/specs/ram-allocation.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# RAM Allocation Guide
|
||||
|
||||
When developing homebrew for the Nintendo 3DS, available RAM depends heavily on two factors: how your application is packaged (.3dsx vs. .cia) and the console hardware (Old 3DS vs. New 3DS).
|
||||
|
||||
## 1. Homebrew Launcher (.3dsx) vs. Installed CIA (.cia)
|
||||
|
||||
### .3dsx (Launched via Homebrew Launcher)
|
||||
When launching a .3dsx file, your application inherits the memory constraints of the host application used to exploit the system (usually the Nintendo 3DS Sound app or the internet browser via safehax).
|
||||
* **Available RAM**: You are generally limited to roughly 32 MB to 64 MB of linear memory, as the system allocates the rest to the operating system and the host applet.
|
||||
* **Limitation**: You cannot request extended memory modes or access New 3DS-exclusive RAM via a .3dsx file.
|
||||
|
||||
### .cia (Installed to Home Menu)
|
||||
An installed .cia acts like a native retail game. It uses a Result Spec File (.rsf) during compilation to explicitly tell the 3DS OS how much memory to allocate and which CPU mode to use.
|
||||
|
||||
## 2. Memory Modes & .rsf Flags (Old 3DS vs. New 3DS)
|
||||
|
||||
The Old 3DS has 128 MB of total RAM, while the New 3DS has 256 MB. How you configure your .rsf file determines how much of this memory your app can touch.
|
||||
|
||||
| Memory Mode | Available RAM | O3DS Behavior | N3DS Behavior |
|
||||
|-------------|---------------|---------------|---------------|
|
||||
| **Application (Default)** | **64 MB** | Standard mode. System applets (Friends list, Browser) remain suspended in the background. Quick launch/exit. | Standard mode. Works identically to O3DS. |
|
||||
| **SystemMode32** | **32 MB** | Limits the app to 32 MB. Historically used by simple tools to slightly decrease boot times. | Works identically, but rarely used for homebrew. |
|
||||
| **SystemMode4 (Extended Memory)** | **80 MB** | **Requires App Reboot**: The OS terminates background applets to free up an extra 16 MB. Exiting to the Home Menu forces a console soft-reboot. | **No Reboot Needed**: Because the N3DS has 256 MB of RAM, it can grant 80 MB easily without closing background applets. |
|
||||
| **SystemMode5 (Extended Memory)** | **96 MB** | **Requires App Reboot**: Used by late-generation heavy games (e.g., Super Smash Bros.). Frees up 32 MB by completely shutting down the Home Menu/OS applets. Exiting forces a long soft-reboot. | **No Reboot Needed**: The N3DS handles this natively without needing a soft-reboot. |
|
||||
|
||||
**Example of Extended Memory Usage:** Super Smash Bros. 3DS and Monster Hunter 4 Ultimate use SystemMode5 (96MB) on an Old 3DS, causing the famous "soft-reboot" when you close them.
|
||||
1
content/demo-doc/01-intro.md
Normal file
@@ -0,0 +1 @@
|
||||
# Einleitung\nDas ist der erste Teil einer strukturierten Dokumentation.
|
||||
1
content/demo-doc/02-install.md
Normal file
@@ -0,0 +1 @@
|
||||
# Installation\nHier steht, wie man alles installiert.
|
||||
1
content/demo-doc/adv/performance.md
Normal file
@@ -0,0 +1 @@
|
||||
# Performance\nOptimierungstipps für Profis.
|
||||
13
content/demo-doc/index.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"title": "Struktur-Demo",
|
||||
"chapters": [
|
||||
{ "title": "Einleitung", "file": "01-intro.md", "id": "intro" },
|
||||
{ "title": "Installation", "file": "02-install.md", "id": "install" },
|
||||
{
|
||||
"title": "Fortgeschritten",
|
||||
"children": [
|
||||
{ "title": "Performance", "file": "adv/performance.md", "id": "perf" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,311 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<link rel="icon" href="/img/favicon.jpg" type="image/png">
|
||||
<meta charset="UTF-8">
|
||||
<title>BR0TCRAFT</title>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Orbitron';
|
||||
src: url('/fonts/Orbitron-Black.ttf') format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('/fonts/Roboto-Regular.ttf') format('truetype');
|
||||
}
|
||||
body {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
background-color: #120000;
|
||||
color: #ffb3b3;
|
||||
margin: 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.header {
|
||||
background-color: #330000;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-bottom: 5px solid #660000;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 2.5em;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.container {
|
||||
padding-top: 80px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
perspective: 1000px;
|
||||
}
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 80%;
|
||||
margin: 20px auto;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0px 5px 15px rgba(255, 0, 0, 0.3);
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 2em;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.item {
|
||||
background-color: #220000;
|
||||
color: #ffcccc;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
.item-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.item-content img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
margin-left: 20px;
|
||||
width: calc(100% - 220px);
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: #660000;
|
||||
color: #ffffff;
|
||||
padding: 10px 0px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: #ff6666;
|
||||
box-shadow: 0px 4px 10px rgba(255, 0, 0, 0.4);
|
||||
}
|
||||
.description {
|
||||
margin-top: 20px; /* Space from the carousel */
|
||||
padding: 15px;
|
||||
background-color: rgba(0, 0, 0, 0.3); /* Semi-transparent background */
|
||||
border-radius: 10px;
|
||||
border: 2px solid #660000; /* Red border */
|
||||
}
|
||||
.description p {
|
||||
color: #ffcccc; /* Light red text color */
|
||||
font-size: 1.1em;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.item-content {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px; /* Spacing around the content */
|
||||
}
|
||||
|
||||
.item-content2 img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 25%;
|
||||
width: 50%;
|
||||
margin: auto;
|
||||
height: auto;
|
||||
max-height: calc(100% - 0px); /* Adjust image height here */
|
||||
top: 5px;
|
||||
object-fit: contain;/* Cover the area and maintain aspect ratio */
|
||||
border-radius: 10px; /* Round all corners of the image */
|
||||
}
|
||||
.devvlog-item {
|
||||
height: 200px;
|
||||
}
|
||||
.item-text {
|
||||
position: absolute;
|
||||
bottom: 10px; /* Space from the bottom */
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
.item:hover {
|
||||
box-shadow: 0px 5px 15px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.item::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
left: -1px;
|
||||
right: -1px;
|
||||
bottom: -1px;
|
||||
border: 1px solid #ff6666;
|
||||
border-radius: 11px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
.item:hover::before {
|
||||
opacity: 1;
|
||||
}
|
||||
.item2 {
|
||||
background-color: #220000;
|
||||
color: #ffcccc;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
margin: 10px;
|
||||
box-shadow: 0px 2px 5px rgba(255, 0, 0, 0.2);
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
.section2 {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
width: 80%;
|
||||
margin: 20px auto;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0px 5px 15px rgba(255, 0, 0, 0.3);
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
.section-title2 {
|
||||
font-size: 2em;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-family: 'Orbitron', sans-serif;
|
||||
color: #ff6666;
|
||||
text-shadow: 0px 2px 5px rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
.content {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.item {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.buttons {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<a href="/" style="text-decoration: none; color: inherit;">
|
||||
<h1>BR0TCRAFT</h1>
|
||||
</a>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="section">
|
||||
<div class="section-title">Pocket Code</div>
|
||||
<div class="content">
|
||||
<div class="item">
|
||||
<div class="item-content">
|
||||
<img src="/img/developmentEnvironment/PocketCodetiny.png" alt="App 1 Image">
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<a href="https://play.google.com/store/apps/details?id=org.catrobat.catroid&hl=de&pli=1" class="button">Herunterladen</a>
|
||||
<a href="https://share.catrob.at/app/user/3a747897-7a83-11eb-a92d-005056a36f47" class="button">Mein Catrobat-Acount</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p>Pocket Code ist eine von Catroabt programmierte Entwicklungsumgebung fürs Handy. Darin lassen sich Spiele fürs Handy am Handy entwickeln. Ich selber habe dort auch schon das ein oder andere gemacht, von denen auch ein paar Apps online zu finden sind.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section2">
|
||||
<div class="section-title2">Meine Apps</div>
|
||||
<a href="/" class="item devvlog-item">
|
||||
<div class="item-content2">
|
||||
<img src="img/Apps/Earthlarge.png" alt="App 1 Image">
|
||||
<div class="item-text">Ki-Chatbot</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="/apps/PocketCode/Tower-defense/index.html" class="item devvlog-item">
|
||||
<div class="item-content2">
|
||||
<img src="/img/Apps/PocketCode/Tower/Tower.png" alt="App 1 Image">
|
||||
<div class="item-text">Tower defense (Beta)</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="/apps/PocketCode/auto-clicker/index.html" class="item devvlog-item">
|
||||
<div class="item-content2">
|
||||
<img src="/img/Apps/PocketCode/auto-clicker/auto-clicker.png" alt="App 1 Image">
|
||||
<div class="item-text">auto-clicker</div>
|
||||
</div>
|
||||
<a href="/apps/PocketCode/Sensor-datas/index.html" class="item devvlog-item">
|
||||
<div class="item-content2">
|
||||
<img src="/img/Apps/PocketCode/Sensor/Sensor.png" alt="App 1 Image">
|
||||
<div class="item-text">Sensor Datas</div>
|
||||
</div>
|
||||
</a>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
617
ext/scene-manager.js
Normal file
@@ -0,0 +1,617 @@
|
||||
(function (Scratch) {
|
||||
'use strict';
|
||||
|
||||
if (!Scratch.extensions.unsandboxed) {
|
||||
throw new Error('SceneManager must run unsandboxed!');
|
||||
}
|
||||
|
||||
let rootDirectoryHandle = null;
|
||||
let currentFileHandle = null;
|
||||
|
||||
const styleEl = document.createElement('style');
|
||||
styleEl.textContent = `
|
||||
/* ── Overlay & Box ───────────────────────────────────────────── */
|
||||
.sm-ov {
|
||||
position: fixed; inset: 0;
|
||||
background: rgba(0,0,0,.6);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
z-index: 99999;
|
||||
animation: smFade .14s ease;
|
||||
}
|
||||
@keyframes smFade { from { opacity:0 } to { opacity:1 } }
|
||||
|
||||
.sm-box {
|
||||
background: #1e1e2e;
|
||||
border: 1px solid #383860;
|
||||
border-radius: 14px;
|
||||
padding: 26px 28px 22px;
|
||||
max-width: 540px;
|
||||
width: calc(100% - 40px);
|
||||
color: #cdd6f4;
|
||||
box-shadow: 0 28px 70px rgba(0,0,0,.55);
|
||||
animation: smSlide .18s ease;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
@keyframes smSlide { from { transform:translateY(-10px);opacity:0 } to { transform:none;opacity:1 } }
|
||||
|
||||
/* ── Typography ──────────────────────────────────────────────── */
|
||||
.sm-box h2 {
|
||||
margin: 0 0 14px;
|
||||
font: 600 17px/1.3 system-ui, sans-serif;
|
||||
color: #89b4fa;
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
}
|
||||
.sm-box p {
|
||||
margin: 0 0 12px;
|
||||
font: 400 13.5px/1.65 system-ui, sans-serif;
|
||||
color: #bac2de;
|
||||
}
|
||||
.sm-box p:last-child { margin-bottom: 0; }
|
||||
.sm-box code {
|
||||
background: #313244;
|
||||
border-radius: 4px;
|
||||
padding: 1px 5px;
|
||||
font-size: 12px;
|
||||
font-family: monospace;
|
||||
color: #a6e3a1;
|
||||
}
|
||||
|
||||
/* ── Note / Info block ───────────────────────────────────────── */
|
||||
.sm-note {
|
||||
background: #252538;
|
||||
border-left: 3px solid #89b4fa;
|
||||
border-radius: 0 8px 8px 0;
|
||||
padding: 10px 14px;
|
||||
font: 400 13px/1.6 system-ui, sans-serif;
|
||||
color: #bac2de;
|
||||
margin: 12px 0;
|
||||
}
|
||||
.sm-note strong { color: #cdd6f4; font-weight: 600; }
|
||||
|
||||
/* ── Path display ────────────────────────────────────────────── */
|
||||
.sm-path {
|
||||
background: #181825;
|
||||
border: 1px solid #45475a;
|
||||
border-radius: 7px;
|
||||
padding: 9px 13px;
|
||||
font: 400 12.5px/1.5 monospace;
|
||||
color: #a6e3a1;
|
||||
margin: 12px 0;
|
||||
word-break: break-all;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/* ── Buttons ─────────────────────────────────────────────────── */
|
||||
.sm-row {
|
||||
display: flex; gap: 10px; justify-content: flex-end;
|
||||
margin-top: 22px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.sm-btn {
|
||||
padding: 8px 20px;
|
||||
border-radius: 7px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font: 600 13px system-ui, sans-serif;
|
||||
transition: filter .12s, transform .1s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.sm-btn:hover { filter: brightness(1.13); }
|
||||
.sm-btn:active { transform: scale(.97); }
|
||||
.sm-btn-primary { background: #89b4fa; color: #1e1e2e; }
|
||||
.sm-btn-ghost { background: #313244; color: #cdd6f4; }
|
||||
.sm-btn-warn { background: #f38ba8; color: #1e1e2e; }
|
||||
.sm-btn:disabled { opacity: .4; cursor: default; filter: none; }
|
||||
|
||||
/* ── Project tree ────────────────────────────────────────────── */
|
||||
.sm-tree {
|
||||
background: #181825;
|
||||
border: 1px solid #45475a;
|
||||
border-radius: 8px;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
margin: 12px 0;
|
||||
}
|
||||
.sm-tree-empty {
|
||||
padding: 28px 16px;
|
||||
text-align: center;
|
||||
color: #585b70;
|
||||
font: italic 13px system-ui, sans-serif;
|
||||
}
|
||||
.sm-folder-row {
|
||||
padding: 7px 14px;
|
||||
background: #1e1e2e;
|
||||
border-bottom: 1px solid #2a2a42;
|
||||
font: 600 12.5px system-ui, sans-serif;
|
||||
color: #fab387;
|
||||
display: flex; align-items: center; gap: 7px;
|
||||
user-select: none;
|
||||
}
|
||||
.sm-file-row {
|
||||
padding: 8px 14px 8px 30px;
|
||||
border-bottom: 1px solid #252538;
|
||||
font: 400 13px system-ui, sans-serif;
|
||||
color: #cdd6f4;
|
||||
cursor: pointer;
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
transition: background .1s;
|
||||
}
|
||||
.sm-file-row:last-child { border-bottom: none; }
|
||||
.sm-file-row:hover { background: #313244; }
|
||||
.sm-file-row.sm-sel { background: #3a3a5c; color: #89b4fa; }
|
||||
|
||||
/* ── Toast ───────────────────────────────────────────────────── */
|
||||
.sm-toast {
|
||||
position: fixed; bottom: 24px; right: 24px;
|
||||
background: #313244;
|
||||
border: 1px solid #45475a;
|
||||
border-radius: 8px;
|
||||
padding: 10px 16px;
|
||||
font: 400 13px system-ui, sans-serif;
|
||||
color: #cdd6f4;
|
||||
z-index: 100000;
|
||||
opacity: 0;
|
||||
transform: translateY(8px);
|
||||
transition: opacity .22s ease, transform .22s ease;
|
||||
max-width: 320px;
|
||||
box-shadow: 0 8px 24px rgba(0,0,0,.4);
|
||||
}
|
||||
.sm-toast.sm-toast-in { opacity: 1; transform: none; }
|
||||
.sm-toast.sm-ok { border-left: 3px solid #a6e3a1; }
|
||||
.sm-toast.sm-err { border-left: 3px solid #f38ba8; }
|
||||
|
||||
/* ── Divider ─────────────────────────────────────────────────── */
|
||||
.sm-sep {
|
||||
border: none; border-top: 1px solid #313244;
|
||||
margin: 14px 0;
|
||||
}
|
||||
|
||||
/* ── Loading spinner ─────────────────────────────────────────── */
|
||||
.sm-spin {
|
||||
display: inline-block; width: 14px; height: 14px;
|
||||
border: 2px solid #45475a;
|
||||
border-top-color: #89b4fa;
|
||||
border-radius: 50%;
|
||||
animation: smSpin .7s linear infinite;
|
||||
}
|
||||
@keyframes smSpin { to { transform: rotate(360deg); } }
|
||||
`;
|
||||
document.head.appendChild(styleEl);
|
||||
|
||||
/** Opens a modal. `buildFn(box, close)` populates .sm-box and calls close(value) to resolve. */
|
||||
function openModal(buildFn) {
|
||||
return new Promise(resolve => {
|
||||
const overlay = document.createElement('div');
|
||||
overlay.className = 'sm-ov';
|
||||
const box = document.createElement('div');
|
||||
box.className = 'sm-box';
|
||||
overlay.appendChild(box);
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
let closed = false;
|
||||
const close = val => {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
document.removeEventListener('keydown', onKey);
|
||||
overlay.remove();
|
||||
resolve(val);
|
||||
};
|
||||
const onKey = e => { if (e.key === 'Escape') close(null); };
|
||||
document.addEventListener('keydown', onKey);
|
||||
overlay.addEventListener('click', e => { if (e.target === overlay) close(null); });
|
||||
|
||||
buildFn(box, close);
|
||||
});
|
||||
}
|
||||
|
||||
function showToast(msg, type = 'ok') {
|
||||
const t = document.createElement('div');
|
||||
t.className = `sm-toast sm-${type}`;
|
||||
t.textContent = msg;
|
||||
document.body.appendChild(t);
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => t.classList.add('sm-toast-in')));
|
||||
setTimeout(() => {
|
||||
t.classList.remove('sm-toast-in');
|
||||
t.addEventListener('transitionend', () => t.remove(), { once: true });
|
||||
}, 2800);
|
||||
}
|
||||
|
||||
class SceneManager {
|
||||
|
||||
getInfo() {
|
||||
return {
|
||||
id: 'sceneManager',
|
||||
name: 'Scene Manager',
|
||||
color1: '#4A90E2',
|
||||
color2: '#357ABD',
|
||||
color3: '#285A8F',
|
||||
blocks: [
|
||||
// ── Folder management ──
|
||||
{
|
||||
blockType: Scratch.BlockType.LABEL,
|
||||
text: 'Root Folder'
|
||||
},
|
||||
{
|
||||
opcode: 'selectFolder',
|
||||
blockType: Scratch.BlockType.BUTTON,
|
||||
text: 'Set Root Folder',
|
||||
func: 'selectFolder'
|
||||
},
|
||||
{
|
||||
opcode: 'browseProjects',
|
||||
blockType: Scratch.BlockType.BUTTON,
|
||||
text: 'Browse & Switch Project',
|
||||
func: 'browseProjects'
|
||||
},
|
||||
{
|
||||
opcode: 'showHelp',
|
||||
blockType: Scratch.BlockType.BUTTON,
|
||||
text: 'How does this work?',
|
||||
func: 'showHelp'
|
||||
},
|
||||
// ── Scene blocks ──
|
||||
{
|
||||
blockType: Scratch.BlockType.LABEL,
|
||||
text: 'Scene Blocks'
|
||||
},
|
||||
{
|
||||
opcode: 'openSB3',
|
||||
blockType: Scratch.BlockType.COMMAND,
|
||||
text: 'open [arg0].sb3',
|
||||
arguments: {
|
||||
arg0: { type: Scratch.ArgumentType.STRING, defaultValue: 'MyGame/Level2' }
|
||||
}
|
||||
},
|
||||
{
|
||||
opcode: 'openSB3withData',
|
||||
blockType: Scratch.BlockType.COMMAND,
|
||||
text: 'open [arg0].sb3 with data [arg1]',
|
||||
arguments: {
|
||||
arg0: { type: Scratch.ArgumentType.STRING, defaultValue: 'MyGame/Level2' },
|
||||
arg1: { type: Scratch.ArgumentType.STRING, defaultValue: 'score=100' }
|
||||
}
|
||||
},
|
||||
{
|
||||
opcode: 'receivedData',
|
||||
blockType: Scratch.BlockType.REPORTER,
|
||||
text: 'received data'
|
||||
}, {
|
||||
blockType: Scratch.BlockType.LABEL,
|
||||
text: 'SE Support: Coming in v1.0'
|
||||
}
|
||||
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
async selectFolder() {
|
||||
const handle = await this._pickDirectory();
|
||||
if (!handle) return;
|
||||
rootDirectoryHandle = handle;
|
||||
currentFileHandle = null;
|
||||
this._showFolderSetModal(handle.name);
|
||||
}
|
||||
|
||||
async browseProjects() {
|
||||
if (!rootDirectoryHandle) {
|
||||
const ok = await this._requireFolder('Open the project browser');
|
||||
if (!ok) return;
|
||||
}
|
||||
|
||||
const files = await this._scanSb3(rootDirectoryHandle);
|
||||
|
||||
await openModal((box, close) => {
|
||||
let selectedPath = null;
|
||||
|
||||
// Build tree HTML
|
||||
const grouped = {};
|
||||
for (const f of files) {
|
||||
const parts = f.path.split('/');
|
||||
const dir = parts.length > 1 ? parts.slice(0, -1).join('/') : '';
|
||||
(grouped[dir] = grouped[dir] || []).push(f);
|
||||
}
|
||||
|
||||
let treeHtml = '';
|
||||
if (files.length === 0) {
|
||||
treeHtml = '<div class="sm-tree-empty">No .sb3 files found in this folder.</div>';
|
||||
} else {
|
||||
for (const [dir, items] of Object.entries(grouped)) {
|
||||
if (dir) treeHtml += `<div class="sm-folder-row">📁 ${this._esc(dir)}/</div>`;
|
||||
for (const item of items) {
|
||||
const name = item.path.split('/').pop().replace(/\.sb3$/i, '');
|
||||
treeHtml += `<div class="sm-file-row" data-path="${this._esc(item.path)}">📄 ${this._esc(name)}.sb3</div>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
box.innerHTML = `
|
||||
<h2>Browse Projects</h2>
|
||||
<p>Root folder: <code>${this._esc(rootDirectoryHandle.name)}/</code></p>
|
||||
<div class="sm-tree" id="sm-tree">${treeHtml}</div>
|
||||
<p id="sm-sel-label" style="font-size:12.5px;color:#585b70;min-height:18px;margin-bottom:0"></p>
|
||||
<div class="sm-row">
|
||||
<button class="sm-btn sm-btn-ghost" id="sm-cancel-btn">Cancel</button>
|
||||
<button class="sm-btn sm-btn-primary" id="sm-switch-btn" disabled>Switch →</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const tree = box.querySelector('#sm-tree');
|
||||
const switchBtn = box.querySelector('#sm-switch-btn');
|
||||
const selLabel = box.querySelector('#sm-sel-label');
|
||||
|
||||
tree.addEventListener('click', e => {
|
||||
const row = e.target.closest('.sm-file-row');
|
||||
if (!row) return;
|
||||
tree.querySelectorAll('.sm-sel').forEach(el => el.classList.remove('sm-sel'));
|
||||
row.classList.add('sm-sel');
|
||||
selectedPath = row.dataset.path;
|
||||
selLabel.textContent = `Selected: ${selectedPath}`;
|
||||
selLabel.style.color = '#89b4fa';
|
||||
switchBtn.disabled = false;
|
||||
});
|
||||
|
||||
box.querySelector('#sm-cancel-btn').onclick = () => close(null);
|
||||
|
||||
switchBtn.onclick = () => {
|
||||
if (!selectedPath) return;
|
||||
close(selectedPath);
|
||||
};
|
||||
|
||||
}).then(async path => {
|
||||
if (!path) return;
|
||||
await this._loadScene(path, '', /* saveFirst */ true);
|
||||
});
|
||||
}
|
||||
|
||||
async showHelp() {
|
||||
await openModal((box, close) => {
|
||||
box.innerHTML = `
|
||||
<h2>How the Scene Manager works</h2>
|
||||
|
||||
<p>
|
||||
<strong style="color:#cdd6f4">Scene Manager</strong> lets you split your Scratch project
|
||||
into multiple <code>.sb3</code> files and seamlessly switch between them at runtime —
|
||||
just like loading a new level or screen.
|
||||
</p>
|
||||
|
||||
<div class="sm-note">
|
||||
<strong>Scratch Everywhere</strong><br>
|
||||
All <code>.sb3</code> files directly inside the scratch-everywhere folder appear in the SE! menu.<br><br>
|
||||
<strong>Set Root Folder</strong> tells Scene Manager which folder acts as that root folder while
|
||||
you're developing in Scratch/Turbowarp/ScratchBox/Mistwarp or any other SE! compatible editor.
|
||||
</div>
|
||||
|
||||
<hr class="sm-sep">
|
||||
<p><strong style="color:#cdd6f4">Recommended project structure</strong></p>
|
||||
<div class="sm-path">📁 scratch-everywhere/
|
||||
MyGame.sb3 ← launcher (appears in menu)
|
||||
📁 MyGameName-Scenes/
|
||||
Level1.sb3
|
||||
Level2.sb3
|
||||
BossLevel.sb3</div>
|
||||
|
||||
<p>
|
||||
Only <code>MyGame.sb3</code> is visible in the game-selection menu.
|
||||
It uses Scene Manager blocks to load the actual levels from the
|
||||
<code>scenes/</code> subfolder, those files stay private inside the SE! menu.
|
||||
</p>
|
||||
|
||||
<div class="sm-note">
|
||||
Use <strong>subfolder-prefixed paths</strong> in the scene blocks:<br>
|
||||
<code>open scenes/Level1.sb3</code><br>
|
||||
Scene Manager navigates into the subfolder automatically.
|
||||
</div>
|
||||
|
||||
<div class="sm-row">
|
||||
<button class="sm-btn sm-btn-primary" id="sm-ok-btn">Got it!</button>
|
||||
</div>
|
||||
`;
|
||||
box.querySelector('#sm-ok-btn').onclick = () => close(null);
|
||||
});
|
||||
}
|
||||
|
||||
async openSB3(args) {
|
||||
await this._loadScene(args.arg0, '');
|
||||
}
|
||||
|
||||
async openSB3withData(args) {
|
||||
await this._loadScene(args.arg0, args.arg1);
|
||||
}
|
||||
|
||||
receivedData() {
|
||||
return sessionStorage.getItem('scenemanager_data') || '';
|
||||
}
|
||||
|
||||
/** Opens a directory picker. Returns null if cancelled. */
|
||||
async _pickDirectory() {
|
||||
try {
|
||||
return await window.showDirectoryPicker({ id: 'scenemanager-root', mode: 'readwrite', startIn: 'documents' });
|
||||
} catch (e) {
|
||||
if (e.name !== 'AbortError') console.error('[SceneManager] Directory picker failed:', e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Shows the "folder has been set" confirmation modal. */
|
||||
_showFolderSetModal(name) {
|
||||
openModal((box, close) => {
|
||||
box.innerHTML = `
|
||||
<h2>Root folder set</h2>
|
||||
<p>Scene Manager will now load projects from:</p>
|
||||
<div class="sm-path">📁 ${this._esc(name)}/</div>
|
||||
<div class="sm-note">
|
||||
In <strong>Scratch Everywhere</strong> this corresponds to the
|
||||
<code>scratch-everywhere/</code> folder, where all your .sb3 files are located.
|
||||
Put your launcher project in the root and keep scene files in a subfolder.
|
||||
You theoretically don't have to put all your scenes inside a subfolder, but it is recommended.
|
||||
</div>
|
||||
<div class="sm-row">
|
||||
<button class="sm-btn sm-btn-primary" id="sm-ok-btn">Got it!</button>
|
||||
</div>
|
||||
`;
|
||||
box.querySelector('#sm-ok-btn').onclick = () => close(null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* If no root folder is set, prompts the user to select one.
|
||||
* Returns true if a folder is now available, false if cancelled.
|
||||
*/
|
||||
async _requireFolder(action) {
|
||||
return openModal((box, close) => {
|
||||
box.innerHTML = `
|
||||
<h2>Root folder required</h2>
|
||||
<p>
|
||||
<strong style="color:#cdd6f4">${this._esc(action)}</strong> needs to know
|
||||
where your <code>.sb3</code> files are stored.
|
||||
</p>
|
||||
<div class="sm-note">
|
||||
Select your <code>scratch-everywhere/</code> folder (or any folder containing your projects).
|
||||
After selecting, the action will continue automatically.
|
||||
</div>
|
||||
<div class="sm-row">
|
||||
<button class="sm-btn sm-btn-ghost" id="sm-cancel-btn">Cancel</button>
|
||||
<button class="sm-btn sm-btn-primary" id="sm-select-btn">Select folder…</button>
|
||||
</div>
|
||||
`;
|
||||
box.querySelector('#sm-cancel-btn').onclick = () => close(false);
|
||||
box.querySelector('#sm-select-btn').onclick = async () => {
|
||||
const handle = await this._pickDirectory();
|
||||
if (handle) { rootDirectoryHandle = handle; currentFileHandle = null; close(true); }
|
||||
else close(false);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/** Recursively scans a directory for .sb3 files. Returns [{path, handle}]. */
|
||||
async _scanSb3(dirHandle, prefix = '') {
|
||||
const results = [];
|
||||
for await (const [name, handle] of dirHandle.entries()) {
|
||||
const rel = prefix ? `${prefix}/${name}` : name;
|
||||
if (handle.kind === 'file' && name.toLowerCase().endsWith('.sb3')) {
|
||||
results.push({ path: rel, handle });
|
||||
} else if (handle.kind === 'directory') {
|
||||
results.push(...await this._scanSb3(handle, rel));
|
||||
}
|
||||
}
|
||||
return results.sort((a, b) => a.path.localeCompare(b.path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a relative path (e.g. "scenes/Level2" or "scenes/Level2.sb3")
|
||||
* to a FileSystemFileHandle inside rootDirectoryHandle.
|
||||
*/
|
||||
async _getFileHandle(relativePath) {
|
||||
if (!rootDirectoryHandle) {
|
||||
const ok = await this._requireFolder('A scene block tried to load a file');
|
||||
if (!ok) return null;
|
||||
}
|
||||
// Normalise: strip trailing .sb3, then re-add
|
||||
const clean = relativePath.replace(/\.sb3$/i, '');
|
||||
const parts = clean.split('/').filter(Boolean);
|
||||
const fileName = parts[parts.length - 1] + '.sb3';
|
||||
let handle = rootDirectoryHandle;
|
||||
try {
|
||||
for (let i = 0; i < parts.length - 1; i++) {
|
||||
handle = await handle.getDirectoryHandle(parts[i]);
|
||||
}
|
||||
return await handle.getFileHandle(fileName);
|
||||
} catch {
|
||||
await this._showError(`File not found: ${clean}.sb3`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Core loading routine used by both the scene blocks and the project browser. */
|
||||
async _loadScene(filePath, dataToPass, fromBrowser = false) {
|
||||
const display = filePath.replace(/\.sb3$/i, '') + '.sb3';
|
||||
|
||||
// Confirm
|
||||
const confirmed = await openModal((box, close) => {
|
||||
const saveRow = currentFileHandle
|
||||
? `<button class="sm-btn sm-btn-primary" id="sm-save-btn">Save current & switch</button>`
|
||||
: `<button class="sm-btn sm-btn-primary" id="sm-switch-btn">Switch</button>`;
|
||||
|
||||
box.innerHTML = `
|
||||
<h2>Switch scene</h2>
|
||||
<p>Load <code>${this._esc(display)}</code>?</p>
|
||||
<div class="sm-note">
|
||||
Unsaved changes in the current project will be lost.
|
||||
${currentFileHandle ? 'You can save first using the button below.' : ''}
|
||||
</div>
|
||||
<div class="sm-row">
|
||||
<button class="sm-btn sm-btn-ghost" id="sm-cancel-btn">Cancel</button>
|
||||
${saveRow}
|
||||
${currentFileHandle ? `<button class="sm-btn sm-btn-warn" id="sm-switch-btn">Switch without saving</button>` : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
box.querySelector('#sm-cancel-btn').onclick = () => close('cancel');
|
||||
|
||||
const switchBtn = box.querySelector('#sm-switch-btn');
|
||||
if (switchBtn) switchBtn.onclick = () => close('switch');
|
||||
|
||||
const saveBtn = box.querySelector('#sm-save-btn');
|
||||
if (saveBtn) saveBtn.onclick = () => close('save-and-switch');
|
||||
});
|
||||
|
||||
if (!confirmed || confirmed === 'cancel') return;
|
||||
|
||||
// Optionally save current project back to its file
|
||||
if (confirmed === 'save-and-switch' && currentFileHandle) {
|
||||
try {
|
||||
const blob = await Scratch.vm.saveProjectSb3();
|
||||
const writable = await currentFileHandle.createWritable();
|
||||
await writable.write(blob);
|
||||
await writable.close();
|
||||
showToast(`Saved: ${currentFileHandle.name}`, 'ok');
|
||||
} catch (e) {
|
||||
console.error('[SceneManager] Save failed:', e);
|
||||
showToast('Save failed — switching anyway.', 'err');
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve file
|
||||
const fh = await this._getFileHandle(filePath);
|
||||
if (!fh) return;
|
||||
|
||||
// Load
|
||||
try {
|
||||
const file = await fh.getFile();
|
||||
const buf = await file.arrayBuffer();
|
||||
sessionStorage.setItem('scenemanager_data', dataToPass);
|
||||
currentFileHandle = fh;
|
||||
await Scratch.vm.loadProject(buf);
|
||||
Scratch.vm.greenFlag();
|
||||
} catch (e) {
|
||||
console.error('[SceneManager] Load failed:', e);
|
||||
await this._showError('Could not load the project. Is it a valid .sb3 file?');
|
||||
}
|
||||
}
|
||||
|
||||
async _showError(msg) {
|
||||
await openModal((box, close) => {
|
||||
box.innerHTML = `
|
||||
<h2>Error</h2>
|
||||
<p>${this._esc(msg)}</p>
|
||||
<div class="sm-row">
|
||||
<button class="sm-btn sm-btn-primary" id="sm-ok-btn">OK</button>
|
||||
</div>
|
||||
`;
|
||||
box.querySelector('#sm-ok-btn').onclick = () => close(null);
|
||||
});
|
||||
}
|
||||
|
||||
_esc(str) {
|
||||
return String(str)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"');
|
||||
}
|
||||
}
|
||||
|
||||
Scratch.extensions.register(new SceneManager());
|
||||
|
||||
})(Scratch);
|
||||
388
extensions.html
Normal file
@@ -0,0 +1,388 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>BR0TCRAFT | Extensions</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;600&family=Inter:wght@300;400;600;800&family=Orbitron:wght@700&display=swap"
|
||||
rel="stylesheet">
|
||||
<style>
|
||||
/* Search & Filter Bar */
|
||||
.controls-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
border: 1px solid #2a2a2a;
|
||||
border-radius: var(--radius);
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
background: #111;
|
||||
border: 1px solid #333;
|
||||
color: #fff;
|
||||
font-family: var(--font-code);
|
||||
padding: 10px 15px;
|
||||
border-radius: 6px;
|
||||
font-size: 0.9rem;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent-primary);
|
||||
box-shadow: 0 0 10px rgba(255, 77, 77, 0.1);
|
||||
}
|
||||
|
||||
.filter-tags {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.filter-tag {
|
||||
background: transparent;
|
||||
border: 1px solid #333;
|
||||
color: var(--text-muted);
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.75rem;
|
||||
padding: 4px 10px;
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.filter-tag:hover {
|
||||
border-color: #555;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.filter-tag.active {
|
||||
background: rgba(255, 77, 77, 0.1);
|
||||
border-color: var(--accent-primary);
|
||||
color: var(--accent-primary);
|
||||
}
|
||||
|
||||
/* Extension Card Styles */
|
||||
.ext-status {
|
||||
display: inline-block;
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.65rem;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
margin-left: 0.5rem;
|
||||
vertical-align: middle;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.ext-status-new {
|
||||
background: rgba(77, 255, 128, 0.1);
|
||||
color: #4dff80;
|
||||
border: 1px solid rgba(77, 255, 128, 0.2);
|
||||
}
|
||||
|
||||
.ext-status-updated {
|
||||
background: rgba(0, 180, 255, 0.1);
|
||||
color: #00b4ff;
|
||||
border: 1px solid rgba(0, 180, 255, 0.2);
|
||||
}
|
||||
|
||||
.ext-tags {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
.ext-tag {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.65rem;
|
||||
color: #aaa;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.ext-author {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.7rem;
|
||||
color: #ffb400;
|
||||
margin-top: 0.5rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ext-actions {
|
||||
display: flex;
|
||||
gap: 0.6rem;
|
||||
margin-top: 1rem;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid #222;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.ext-btn {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.75rem;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
transition: 0.2s;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.btn-copy {
|
||||
background: rgba(255, 77, 77, 0.1);
|
||||
border: 1px solid rgba(255, 77, 77, 0.3);
|
||||
color: var(--accent-primary);
|
||||
}
|
||||
|
||||
.btn-copy:hover {
|
||||
background: rgba(255, 77, 77, 0.2);
|
||||
box-shadow: 0 0 10px rgba(255, 77, 77, 0.1);
|
||||
}
|
||||
|
||||
.btn-docs {
|
||||
background: transparent;
|
||||
border: 1px solid #444;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.btn-docs:hover {
|
||||
border-color: #777;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Toast Notification */
|
||||
.toast {
|
||||
position: fixed;
|
||||
bottom: -60px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: var(--accent-primary);
|
||||
color: #000;
|
||||
font-weight: 600;
|
||||
font-family: var(--font-code);
|
||||
padding: 10px 20px;
|
||||
border-radius: 20px;
|
||||
opacity: 0;
|
||||
transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.toast.show {
|
||||
bottom: 30px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 4rem 1rem;
|
||||
color: #555;
|
||||
font-family: var(--font-code);
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav class="navbar">
|
||||
<div class="brand">BR0TCRAFT</div>
|
||||
<div class="nav-links">
|
||||
<a href="index.html">Home</a>
|
||||
<a href="projects.html" class="active">Projekte</a> <!-- Active, as Extensions are a subset -->
|
||||
<a href="tutorials.html">Dev Notes</a>
|
||||
<a href="about.html">About</a>
|
||||
<a href="assets.html">Assets</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
<section class="section">
|
||||
<div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 0.5rem;">
|
||||
<a href="projects.html" style="color: var(--text-muted); text-decoration: none; font-size: 1.2rem;">←</a>
|
||||
<h1 style="font-family: var(--font-display); color: #fff; margin: 0;">Scratch Extensions</h1>
|
||||
</div>
|
||||
<p style="color: var(--text-muted); font-size: 0.9rem; margin-bottom: 2.5rem;">
|
||||
Eine Sammlung von mir erstellter Erweiterungen für TurboWarp, PenguinMod und Scratch Everywhere.
|
||||
</p>
|
||||
|
||||
<div class="controls-container">
|
||||
<input type="text" id="searchInput" class="search-input"
|
||||
placeholder="Suche nach Extensions (z.B. Audio, Visuals)...">
|
||||
<div class="filter-tags" id="filterTags">
|
||||
<button class="filter-tag active" data-filter="all">Alle</button>
|
||||
<button class="filter-tag" data-filter="TurboWarp">TurboWarp</button>
|
||||
<button class="filter-tag" data-filter="PenguinMod">PenguinMod</button>
|
||||
<button class="filter-tag" data-filter="SE!">SE!</button>
|
||||
<button class="filter-tag" data-filter="Costume">Costume</button>
|
||||
<button class="filter-tag" data-filter="Operator">Operator</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid" id="extensionGrid">
|
||||
<!-- Extensions will be injected here via JS -->
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast">Link kopiert!</div>
|
||||
|
||||
<!-- SVG Icons -->
|
||||
<svg style="display: none;">
|
||||
<defs>
|
||||
<symbol id="icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
||||
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-docs" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path>
|
||||
<path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path>
|
||||
</symbol>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
<script>
|
||||
// --- Customise Extensions Here ---
|
||||
const extensions = [
|
||||
{
|
||||
id: "scene-manager",
|
||||
name: "Scene Manager",
|
||||
description: "Ein Tool, um verschiedene Projekte als einzelne Szenen zu verwalten (gedacht für Scratch Everywhere!). ",
|
||||
imagePath: "img/extensions/scene-manager.png",
|
||||
tags: ["SE!"],
|
||||
status: "new", // 'new', 'updated', or null
|
||||
authors: "Br0tcraft",
|
||||
link: "ext/scene-manager.js",
|
||||
docs: "article.html?file=content/ext-scene-manager.md" // Optional documentation link
|
||||
},
|
||||
{
|
||||
id: "penguin-physics",
|
||||
name: "2D Physics Core",
|
||||
description: "Eine Portierung von Box2D in Scratch via PenguinMod. Perfekt für Platformer und Puzzle.",
|
||||
imageBg: "linear-gradient(135deg, #001a33, #0066cc)",
|
||||
tags: ["PenguinMod", "Operator"],
|
||||
status: null,
|
||||
authors: null,
|
||||
link: "https://example.com/ext/physics.js",
|
||||
docs: "article.html?file=content/physics.md"
|
||||
}
|
||||
];
|
||||
|
||||
const grid = document.getElementById('extensionGrid');
|
||||
const searchInput = document.getElementById('searchInput');
|
||||
const filterButtons = document.querySelectorAll('.filter-tag');
|
||||
let currentFilter = 'all';
|
||||
|
||||
function renderExtensions() {
|
||||
grid.innerHTML = '';
|
||||
const query = searchInput.value.toLowerCase();
|
||||
|
||||
const filtered = extensions.filter(ext => {
|
||||
const matchesSearch = ext.name.toLowerCase().includes(query) || ext.description.toLowerCase().includes(query) || ext.tags.some(t => t.toLowerCase().includes(query));
|
||||
const matchesFilter = currentFilter === 'all' || ext.tags.includes(currentFilter);
|
||||
return matchesSearch && matchesFilter;
|
||||
});
|
||||
|
||||
if (filtered.length === 0) {
|
||||
grid.innerHTML = '<div class="empty-state">Keine Extensions gefunden.</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
filtered.forEach(ext => {
|
||||
let statusHtml = '';
|
||||
if (ext.status === 'new') statusHtml = '<span class="ext-status ext-status-new">[NEW]</span>';
|
||||
if (ext.status === 'updated') statusHtml = '<span class="ext-status ext-status-updated">[UPDATED]</span>';
|
||||
|
||||
const tagsHtml = ext.tags.map(t => `<span class="ext-tag">${t}</span>`).join('');
|
||||
const authorHtml = ext.authors ? `<span class="ext-author">${ext.authors}</span>` : '';
|
||||
|
||||
let docsBtn = '';
|
||||
if (ext.docs) {
|
||||
docsBtn = `<a href="${ext.docs}" class="ext-btn btn-docs"><svg width="14" height="14"><use href="#icon-docs"></use></svg> Docs</a>`;
|
||||
}
|
||||
|
||||
let mediaHtml = '';
|
||||
if (ext.imagePath) {
|
||||
mediaHtml = `<img src="${ext.imagePath}" style="width:100%; height:100%; object-fit: cover;" alt="${ext.name}">`;
|
||||
} else {
|
||||
mediaHtml = `<div style="width:100%; height:100%; background: ${ext.imageBg}; display: flex; align-items: center; justify-content: center;">
|
||||
<span style="font-family: var(--font-code); color: rgba(255,255,255,0.2); font-size: 2rem;">{ }</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
const card = document.createElement('article');
|
||||
card.className = 'card';
|
||||
card.innerHTML = `
|
||||
<div style="height: 140px; overflow: hidden;">
|
||||
${mediaHtml}
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3 class="card-title" style="margin-bottom: 0.2rem;">${ext.name}${statusHtml}</h3>
|
||||
${authorHtml}
|
||||
<div class="ext-tags">${tagsHtml}</div>
|
||||
<p class="card-desc" style="margin-top: 1rem;">${ext.description}</p>
|
||||
|
||||
<div class="ext-actions">
|
||||
<button class="ext-btn btn-copy" onclick="copyLink('${ext.link}')">
|
||||
<svg width="14" height="14"><use href="#icon-copy"></use></svg> Link kopieren
|
||||
</button>
|
||||
${docsBtn}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
grid.appendChild(card);
|
||||
});
|
||||
}
|
||||
|
||||
// Events
|
||||
searchInput.addEventListener('input', renderExtensions);
|
||||
|
||||
filterButtons.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
filterButtons.forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
currentFilter = btn.dataset.filter;
|
||||
renderExtensions();
|
||||
});
|
||||
});
|
||||
|
||||
// Copy to clipboard
|
||||
window.copyLink = function (link) {
|
||||
navigator.clipboard.writeText(link).then(() => {
|
||||
showToast("Link kopiert!");
|
||||
}).catch(err => {
|
||||
console.error("Copy failed", err);
|
||||
showToast("Fehler beim Kopieren!");
|
||||
});
|
||||
};
|
||||
|
||||
function showToast(msg) {
|
||||
const toast = document.getElementById('toast');
|
||||
toast.innerText = msg;
|
||||
toast.classList.add('show');
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show');
|
||||
}, 2500);
|
||||
}
|
||||
|
||||
// Initial render
|
||||
renderExtensions();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
Before Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 7.3 KiB |
BIN
img/Apps/Zynk/Banner.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
img/Apps/Zynk/Logo.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
49
img/Apps/Zynk/Logo.svg
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0.188 455.904 131.961" xmlns:bx="https://boxy-svg.com">
|
||||
<defs>
|
||||
<linearGradient x1="336.42148" y1="180.2661" x2="182.42881" y2="180.2661" gradientUnits="userSpaceOnUse" id="color-1">
|
||||
<stop offset="0" stop-color="#019bc8"/>
|
||||
<stop offset="1" stop-color="#3cd8e7"/>
|
||||
</linearGradient>
|
||||
<linearGradient x1="147.35625" y1="93.33003" x2="351.99218" y2="93.33003" gradientUnits="userSpaceOnUse" id="color-2">
|
||||
<stop offset="0" stop-color="#1bc6dd"/>
|
||||
<stop offset="0.4882" stop-color="#38d4e5"/>
|
||||
<stop offset="0.99" stop-color="#3ed9e8"/>
|
||||
</linearGradient>
|
||||
<linearGradient x1="125.80128" y1="264.46344" x2="330.4372" y2="264.46344" gradientUnits="userSpaceOnUse" id="color-3">
|
||||
<stop offset="0" stop-color="#1bc6dd"/>
|
||||
<stop offset="0.4882" stop-color="#38d4e5"/>
|
||||
<stop offset="0.99" stop-color="#3ed9e8"/>
|
||||
</linearGradient>
|
||||
<linearGradient x1="134.2437" y1="180.15041" x2="288.23637" y2="180.15041" gradientUnits="userSpaceOnUse" id="color-4">
|
||||
<stop offset="0" stop-color="#019bc8"/>
|
||||
<stop offset="1" stop-color="#3cd8e7"/>
|
||||
</linearGradient>
|
||||
<view id="view-1">
|
||||
<title>View 1</title>
|
||||
</view>
|
||||
<style bx:fonts="Alan Sans">@import url(https://fonts.googleapis.com/css2?family=Alan+Sans%3Aital%2Cwght%400%2C300..900&display=swap);</style>
|
||||
<bx:export>
|
||||
<bx:file format="png" href="#object-0" path="Unbetitelt.png"/>
|
||||
<bx:file format="html" path="Unbetitelt.html" excluded="true"/>
|
||||
<bx:file format="svg" path="Unbetitelt.svg" excluded="true"/>
|
||||
<bx:file format="jpeg" path="Unbetitelt.jpeg" excluded="true"/>
|
||||
<bx:file format="gif" path="Unbetitelt.gif" excluded="true"/>
|
||||
<bx:file format="png" path="Logo.png" dpi="400" antialiasing="false"/>
|
||||
</bx:export>
|
||||
</defs>
|
||||
<rect x="3.777" y="0.128" width="441.573" height="132.608" style="paint-order: fill; stroke-opacity: 0; stroke-width: 0px; stroke: rgb(2, 119, 151); fill: rgb(0, 119, 153);" id="object-0"/>
|
||||
<g transform="matrix(0.522704, 0, 0, 0.61619, -60.055473, -45.021687)" style="">
|
||||
<g stroke-width="0" stroke-miterlimit="10">
|
||||
<path d="M138.17337,281.74035c-5.37056,0 -9.72425,-4.59731 -9.72425,-10.26836v-9.60405c0,-5.67106 4.3537,-10.26836 9.72425,-10.26836h185.18742c5.37056,0 9.72425,4.59731 9.72425,10.26836v9.60405c0,5.67106 -4.3537,10.26836 -9.72425,10.26836z" fill="#008ec0" stroke="#27c7d3"/>
|
||||
<path d="M159.28705,110.60695c-5.37056,0 -9.72425,-4.59731 -9.72425,-10.26836v-9.60405c0,-5.67106 4.3537,-10.26836 9.72425,-10.26836h185.18742c5.37056,0 9.72425,4.59731 9.72425,10.26836v9.60405c0,5.67106 -4.3537,10.26836 -9.72425,10.26836z" fill="#008ec0" stroke="#27c7d3"/>
|
||||
<path d="M142.66363,221.90843c23.25511,-19.01391 114.30793,-94.07711 114.30793,-94.07711l-7.14549,-6.85484l39.94877,0.55401l-9.89989,28.90364l-7.14549,-8.27088c0,0 -92.86371,78.88336 -115.21023,97.17507c-8.34511,6.83087 -16.77168,5.96334 -19.25286,2.92872c-2.57888,-3.15411 -5.46447,-12.29544 4.39726,-20.35862z" fill="#008ec0" stroke="none"/>
|
||||
<path d="M331.81274,144.69689c-23.25511,19.01391 -114.30793,94.07711 -114.30793,94.07711l7.14549,6.85484l-39.94877,-0.55401l9.89989,-28.90364l7.14549,8.27088c0,0 92.86371,-78.88336 115.21023,-97.17507c8.34511,-6.83087 16.77168,-5.96334 19.25286,-2.92872c1.38768,1.69722 2.86418,5.12801 2.3956,9.19157c-0.40222,3.48818 -2.23769,7.44263 -6.79287,11.16705z" fill="#008ec0" stroke="none"/>
|
||||
<path d="M329.54002,141.96962c-23.25511,19.01391 -114.30793,94.07711 -114.30793,94.07711l7.14549,6.85484l-39.94877,-0.55401l9.89989,-28.90364l7.14549,8.27088c0,0 92.86371,-78.88336 115.21023,-97.17507c8.34511,-6.83087 16.77168,-5.96334 19.25286,-2.92872c1.38768,1.69721 2.86418,5.12801 2.3956,9.19157c-0.40223,3.48818 -2.23769,7.44263 -6.79286,11.16705z" fill="url(#color-1)" stroke="none"/>
|
||||
<path d="M157.08051,108.40042c-5.37056,0 -9.72425,-4.59731 -9.72425,-10.26836v-9.60405c0,-5.67106 4.3537,-10.26836 9.72425,-10.26836h185.18742c5.37056,0 9.72425,4.59731 9.72425,10.26836v9.60405c0,5.67106 -4.3537,10.26836 -9.72425,10.26836z" fill="url(#color-2)" stroke="#27c7d3"/>
|
||||
<path d="M135.52553,279.53382c-5.37056,0 -9.72425,-4.59731 -9.72425,-10.26836v-9.60405c0,-5.67106 4.3537,-10.26836 9.72425,-10.26836h185.18742c5.37056,0 9.72425,4.59731 9.72425,10.26836v9.60405c0,5.67106 -4.3537,10.26836 -9.72425,10.26836z" fill="url(#color-3)" stroke="#27c7d3"/>
|
||||
<path d="M141.12516,218.44689c23.25511,-19.01391 114.30793,-94.07711 114.30793,-94.07711l-7.14549,-6.85484l39.94877,0.55401l-9.89989,28.90364l-7.14549,-8.27088c0,0 -92.86371,78.88336 -115.21023,97.17507c-8.34511,6.83087 -16.77168,5.96334 -19.25286,2.92872c-2.57888,-3.15411 -5.46447,-12.29544 4.39726,-20.35862z" fill="url(#color-4)" stroke="none"/>
|
||||
</g>
|
||||
</g>
|
||||
<text style="fill: rgb(61, 216, 232); font-family: "Alan Sans"; font-size: 28px; letter-spacing: -1.1px; white-space: pre;" transform="matrix(5.874275, 0, 0, 6.425704, -902.711975, -230.758133)" x="175.446" y="55.849" dx="-0.072" dy="-0.11">YNK</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
53
img/Apps/Zynk/Logo2.svg
Normal file
|
After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 276 KiB |
|
Before Width: | Height: | Size: 418 KiB |
BIN
img/Logo.png
|
Before Width: | Height: | Size: 2.5 KiB |
BIN
img/avatar.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 282 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 1.4 MiB |
BIN
img/extensions/scene-manager.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
353
index.html
@@ -1,99 +1,266 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="de">
|
||||
|
||||
<head>
|
||||
<link rel="icon" href="img/favicon.jpg" type="image/png">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<meta charset="UTF-8">
|
||||
<title>BR0TCRAFT</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>BR0TCRAFT</h1>
|
||||
</div>
|
||||
<div class="header-image">
|
||||
<img src="img/Background3.jpg" alt="Header Image">
|
||||
</div>
|
||||
<div class="contact-icons">
|
||||
<a href="your discord link" target="_blank"><img src="img/contact/discord.png" alt="Discord"></a>
|
||||
<a href="mailto:info.br0tcraft.de"><img src="img/contact/email.png" alt="Email"></a>
|
||||
<a href="https://github.com/Br0tcraft"><img src="img/contact/github.png" alt="Email"></a>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="section">
|
||||
<div class="section-title">Apps</div>
|
||||
<a href="apps/Br0tbot/index.html" class="item">
|
||||
<div class="item-content">
|
||||
<img src="img/Apps/TigerBr0tbot-large.png" alt="App 1 Image">
|
||||
<div class="item-text">Br0tbot</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="apps/Tiny-Snake/index.html" class="item">
|
||||
<div class="item-content">
|
||||
<img src="img/Apps/snake-large.png" alt="App 1 Image">
|
||||
<div class="item-text">Tiny Snake</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="apps/Br0tkabeln/index.html" class="item">
|
||||
<div class="item-content">
|
||||
<img src="img/Apps/Br0tkabelnlarge.png" alt="App 1 Image">
|
||||
<div class="item-text">Br0tkabeln</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="section-title">Entwicklungsumgebungen</div>
|
||||
<a href="/enviroments/PocketCode/index.html" class="item devvlog-item">
|
||||
<div class="item-content">
|
||||
<img src="img/developmentEnvironment/PocketCode.jpeg" alt="App 1 Image">
|
||||
<div class="item-text">Pocket Code</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="" class="item devvlog-item">
|
||||
<div class="item-content">
|
||||
<img src="img/Background3.jpg" alt="App 1 Image">
|
||||
<div class="item-text">bald kommt mehr</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="section-title">Devvlogs</div>
|
||||
<a href="apps/Tiny-Snake/index.html" class="item devvlog-item">
|
||||
<div class="item-content">
|
||||
<img src="img/Apps/Earthlarge.png" alt="App 1 Image">
|
||||
<div class="item-text">The Simulation</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="" class="item devvlog-item">
|
||||
<div class="item-content">
|
||||
<img src="img/Background3.jpg" alt="App 1 Image">
|
||||
<div class="item-text">Bald kommt mehr</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="section-title">Anleitungen</div>
|
||||
<a href="/" class="item anleitung-item">
|
||||
<div class="item-content">
|
||||
<img src="/img/developmentEnvironment/PocketCode.jpeg" alt="App 1 Image">
|
||||
<div class="item-text">Erstes Handy game (Pocket Code) kommt bald</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="/" class="item anleitung-item">
|
||||
<div class="item-content">
|
||||
<img src="/img/Background3.jpg" alt="App 1 Image">
|
||||
<div class="item-text">mehr kommt bald ... irgendwann ... vielleicht ...</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener("visibilitychange", (event) => {
|
||||
if (document.visibilityState == "visible") {
|
||||
document.title = "BR0TCRAFT";
|
||||
} else {
|
||||
document.title = "Come back, please";
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>BR0TCRAFT | Home</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;600&family=Inter:wght@300;400;600;800&family=Orbitron:wght@700&display=swap"
|
||||
rel="stylesheet">
|
||||
<style>
|
||||
.hero-short {
|
||||
font-size: 1.15rem;
|
||||
color: var(--text-muted);
|
||||
line-height: 1.7;
|
||||
max-width: 560px;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
.hero-short strong {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.expand-toggle {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--accent-primary);
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.85rem;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
margin-top: 0.75rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.expand-toggle:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.hero-long {
|
||||
display: none;
|
||||
font-size: 1rem;
|
||||
color: var(--text-muted);
|
||||
line-height: 1.75;
|
||||
max-width: 600px;
|
||||
margin-top: 1rem;
|
||||
animation: fadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
.hero-long.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(4px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Current section */
|
||||
.current-block {
|
||||
border-left: 2px solid var(--accent-primary);
|
||||
padding: 1.5rem 2rem;
|
||||
background: rgba(255, 77, 77, 0.04);
|
||||
border-radius: 0 var(--radius) var(--radius) 0;
|
||||
}
|
||||
|
||||
.current-label {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.75rem;
|
||||
color: var(--accent-primary);
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.current-block h3 {
|
||||
font-family: var(--font-display);
|
||||
font-size: 1.1rem;
|
||||
color: #fff;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.current-block p {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
.current-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 1rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
/* Pinned article */
|
||||
.pinned-card {
|
||||
border: 1px solid #2a2a2a;
|
||||
border-radius: var(--radius);
|
||||
padding: 1.5rem;
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.pinned-card:hover {
|
||||
border-color: var(--accent-primary);
|
||||
}
|
||||
|
||||
.pinned-tag {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.75rem;
|
||||
color: var(--accent-primary);
|
||||
margin-bottom: 0.6rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.pinned-card h3 {
|
||||
color: #fff;
|
||||
font-size: 1rem;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.pinned-card p {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav class="navbar">
|
||||
<div class="brand">BR0TCRAFT</div>
|
||||
<div class="nav-links">
|
||||
<a href="index.html" class="active">Home</a>
|
||||
<a href="projects.html">Projects</a>
|
||||
<a href="tutorials.html">Dev Notes</a>
|
||||
<a href="about.html">About</a>
|
||||
<a href="assets.html">Assets</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<!-- Hero -->
|
||||
<section class="section hero">
|
||||
<div class="hero-content">
|
||||
|
||||
<div class="text-col">
|
||||
<div class="social-row">
|
||||
<a href="https://discord.gg/deinlink" target="_blank" class="social-link" title="Discord">
|
||||
<img src="https://cdn.simpleicons.org/discord/ff4d4d" alt="Discord">
|
||||
</a>
|
||||
<a href="mailto:info@br0tcraft.de" class="social-link" title="Email">
|
||||
<img src="https://cdn.simpleicons.org/gmail/ff4d4d" alt="Email">
|
||||
</a>
|
||||
<a href="https://github.com/Br0tcraft" target="_blank" class="social-link" title="GitHub">
|
||||
<img src="https://cdn.simpleicons.org/github/ff4d4d" alt="Github">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<h1><span style="color:var(--accent-primary)">Br0tcraft</span></h1>
|
||||
|
||||
<p class="hero-short">
|
||||
Ich baue Software, um zu verstehen, wie sie im Kern funktioniert. Am liebsten mit C++, Python oder Dart. Ob
|
||||
technische Spielerei oder Nischen-Tools, ich mag Projekte, die nicht nur laufen, sondern auch eine saubere
|
||||
Struktur unter der Haube haben.
|
||||
<br>
|
||||
<strong>Work in progress, mit Liebe zum Detail.</strong>
|
||||
</p>
|
||||
|
||||
<div class="tech-stack" style="margin-top: 1.25rem;">
|
||||
<span class="tech-tag">C++</span>
|
||||
<span class="tech-tag">C#</span>
|
||||
<span class="tech-tag">GDScript</span>
|
||||
<span class="tech-tag">Python</span>
|
||||
<span class="tech-tag">JavaScript</span>
|
||||
<span class="tech-tag">Dart</span>
|
||||
<span class="tech-tag">Scratch</span>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 1.25rem; display: flex; gap: 0.75rem; flex-wrap: wrap;">
|
||||
<a href="projects.html" class="btn">Meine Projekte</a>
|
||||
<a href="about.html" class="btn"
|
||||
style="background: transparent; border: 1px solid #333; color: var(--text-muted);">Über mich</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="avatar-wrapper">
|
||||
<img src="img/avatar.png" alt="Br0tcraft Avatar" class="avatar">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<h2 style="font-family: var(--font-display); margin-bottom: 0.5rem; color: #fff;">
|
||||
Contributions & Open Source
|
||||
</h2>
|
||||
<p style="color: var(--text-muted); margin-bottom: 2.5rem; max-width: 650px; font-size: 1.05rem;">
|
||||
Ich bin definitiv kein Profi. Oft sitze ich vor dem Code und raufe mir die Haare, aber genau das macht den
|
||||
Reiz aus. Sich an Projekte wagen, die eigentlich eine Nummer zu groß sind.
|
||||
</p>
|
||||
|
||||
<div class="contribution-grid">
|
||||
|
||||
<div class="contribution-card">
|
||||
<div class="contribution-header">
|
||||
<img src="https://github.com/ScratchEverywhere/ScratchEverywhere/blob/main/gfx/icon.png?raw=true"
|
||||
alt="Scratch Everywhere" class="contribution-logo">
|
||||
<div class="contribution-title-area">
|
||||
<h3>Scratch Everywhere</h3>
|
||||
<div class="contribution-links">
|
||||
<a href="https://github.com/ScratchEverywhere/ScratchEverywhere" target="_blank"
|
||||
class="contribution-link">
|
||||
<img src="https://cdn.simpleicons.org/github/a0a0a0" alt="GitHub"> Code
|
||||
</a>
|
||||
<a href="https://github.com/ScratchEverywhere/ScratchEverywhere" target="_blank"
|
||||
class="contribution-link">
|
||||
<img src="https://cdn.simpleicons.org/planetscale/a0a0a0" alt="Web"> Website
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="contribution-body">
|
||||
<p>
|
||||
Es ist ein Projekt, das Scratch auf Plattformen wie die Wii, den 3DS oder Linux
|
||||
bringt.
|
||||
Ich lerne hier mehr über C++ und Teamwork als in jedem Tutorial ... auch wenn meine Pull Requests manchmal
|
||||
zehn Anläufe brauchen, bis sie passen.
|
||||
</p>
|
||||
<ul class="contribution-points">
|
||||
<li>Arbeit am C++ Kern und der UI-Logik</li>
|
||||
<li>Fixing von Bugs (die ich oft erst selbst eingebaut habe)</li>
|
||||
<li>Alte Hardware mit modernem Code zum Leben erwecken</li>
|
||||
</ul>
|
||||
<div class="contribution-status">
|
||||
<span class="status-tag">Aktiv dabei</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
1
mini/assets/icons/arrow_down.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="6.163" height="4.265" viewBox="0 0 6.163 4.265"><path fill="none" stroke="#000" stroke-linecap="round" stroke-miterlimit="10" stroke-width=".5" d="m.25.25 2.831 3.765m0 0L5.913.25"/></svg>
|
||||
|
After Width: | Height: | Size: 235 B |
1
mini/assets/icons/arrow_left.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="4.265" height="6.163" viewBox="0 0 4.265 6.163"><path fill="none" stroke="#000" stroke-linecap="round" stroke-miterlimit="10" stroke-width=".5" d="M4.015.25.25 3.081m0 0 3.765 2.832"/></svg>
|
||||
|
After Width: | Height: | Size: 237 B |
1
mini/assets/icons/arrow_right.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="4.265" height="6.163" viewBox="0 0 4.265 6.163"><path fill="none" stroke="#000" stroke-linecap="round" stroke-miterlimit="10" stroke-width=".5" d="m.25.25 3.765 2.831m0 0L.25 5.913"/></svg>
|
||||
|
After Width: | Height: | Size: 236 B |
1
mini/assets/icons/book.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="21.052" height="16.147" viewBox="0 0 21.052 16.147"><g fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="1.5"><path d="M1.47 14.706a.72.72 0 0 1-.72-.72V1.47a.72.72 0 0 1 .72-.72h7.596c.577 0 .983.625 1.448.625.44 0 1.075-.625 1.613-.625h7.455a.72.72 0 0 1 .72.72v12.516a.72.72 0 0 1-.72.72H12.03c-.527 0-1.018.691-1.449.691-.456 0-.983-.69-1.547-.69z"/><path stroke-linecap="round" d="m10.416 1.433.098 13.561"/></g></svg>
|
||||
|
After Width: | Height: | Size: 483 B |
1
mini/assets/icons/church.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="5.339" height="5.067" viewBox="0 0 5.339 5.067"><g fill="none" stroke="#000" stroke-linecap="round" stroke-miterlimit="10" stroke-width=".5"><path d="M.25 4.817V2.56l.893-.438v-.624L2.626.25M2.12 2.024h.506"/><path d="M1.146 2.12v2.697H.219h2.494-.556s.043-.16.028-.504c-.013-.31.098-.548.443-.575M2.713.25l1.483 1.247v.624l.893.438v2.258M2.644 1.59v1.062m.488-.628h-.506"/><path d="M4.194 2.12v2.697h.927-2.495.557s-.044-.16-.029-.504c.014-.31-.098-.548-.442-.575"/></g></svg>
|
||||
|
After Width: | Height: | Size: 524 B |
1
mini/assets/icons/download.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8.138" height="8.863" viewBox="0 0 8.138 8.863"><g fill="none" stroke="#000" stroke-miterlimit="10" stroke-width=".5"><path d="M1.268 8.6C.715 8.6.208 8.017.253 7.524l.015-2.007c0-.071-.06 1.188-.006 2.014.028.288.163 1.074 1.036 1.055.93-.02 3.957.057 5.584.026.863-.016.99-.772 1-1.023.033-.794.006-2.148.006-2.072v2.081c0 .553-.447 1.015-.985 1z"/><path stroke-linecap="round" stroke-linejoin="round" d="M4.062.25v6.477L.475 2.877m7.188 0-3.6 3.85V.25"/></g></svg>
|
||||
|
After Width: | Height: | Size: 514 B |
1
mini/assets/icons/file.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="9.444" height="12.174" viewBox="0 0 9.444 12.174"><g fill="none" stroke="#000" stroke-miterlimit="10" stroke-width=".5"><path d="M1.415 11.924c-.643 0-1.165-.448-1.165-1V1.25c0-.552.522-1 1.165-1h5.474l2.305 2.266v8.408c0 .552-.522 1-1.165 1z"/><path stroke-linecap="round" d="M8.977 2.482H6.89V.284M2.143 6.087H7.3M2.143 3.892H7.3M2.143 1.697h3.363M2.143 8.282H7.3m-5.157 2.195H7.3"/></g></svg>
|
||||
|
After Width: | Height: | Size: 442 B |
1
mini/assets/icons/list.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="21.951" height="21.08" viewBox="0 0 21.951 21.08"><g fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="1.5"><path d="M.75 3.19A2.44 2.44 0 0 1 3.188.753c1.346 0 12.76.065 12.76.065S19.135.74 18.99 3.821c-.016.35.005 10.811.005 10.811s.606.062 1.466.014c1.453-.081 1.49 1.304 1.49 1.304s.05.572.038 1.214c-.054 2.806-2.626 3.165-2.626 3.165s-10.042-.132-11.893-.09c-2.904.066-2.93-2.738-2.93-2.738L4.486 7.185s-1.174-.021-1.298-.021c-1.181 0-2.211-.591-2.435-1.706C.72 5.302.75 3.355.75 3.19z"/><path stroke-linecap="round" d="M2.204.93c2.225-.94 2.249 2.106 2.249 2.106l.044 4.003m3.856-1.328h6.718m-6.718 4.688h6.718m4.037 4.201s-8.07.071-9.791.062c-.84-.004 1.256 5.853-2.865 5.407"/></g></svg>
|
||||
|
After Width: | Height: | Size: 756 B |
1
mini/assets/icons/settings.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="9.952" height="9.714" viewBox="0 0 9.952 9.714"><g fill="none" stroke="#000" stroke-miterlimit="10" stroke-width=".5"><path stroke-linecap="round" stroke-linejoin="round" d="M3.73 1.824V.25h2.492v1.481m-.007.125L7.369.702l1.826 1.827L8.11 3.614m.019-.005h1.573V6.1h-1.48M1.843 3.614.757 2.53 2.584.702l1.154 1.154M1.731 6.1H.25V3.61h1.574M6.23 7.983v1.481H3.737V7.891M8.117 6.1l1.085 1.086-1.826 1.826L6.222 7.86M3.73 7.859 2.577 9.012.75 7.186 1.836 6.1"/><path d="M3.404 4.854a1.572 1.572 0 1 1 3.145 0 1.572 1.572 0 0 1-3.145 0z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 591 B |
1
mini/assets/icons/shirt.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="15.471" height="18.719" viewBox="0 0 15.471 18.719"><g fill="none" stroke="#000" stroke-linecap="round" stroke-miterlimit="10"><path stroke-linejoin="round" d="m4.09 8.1-.954 6.067L.5 8.348l1.94-6.181L5.257.5 6.56 2.59h1.818"/><path d="M8.742 18.22H3.106v-4.185"/><path d="M12.316 14.035v4.184H6.679"/><path stroke-linejoin="round" d="M7.092 2.59H8.91L10.213.5l2.818 1.667 1.94 6.181-2.637 5.819-.953-6.066"/></g></svg>
|
||||
|
After Width: | Height: | Size: 466 B |
1
mini/assets/icons/sun.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17.973" height="18.286" viewBox="0 0 17.973 18.286"><g fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="1.5"><path d="M5.795 9.1a3.192 3.192 0 1 1 6.384 0 3.192 3.192 0 0 1-6.384 0z"/><path stroke-linecap="round" d="M8.987.75v3.17m8.236 5.18h-3.17m1.126-6.191L12.938 5.15m2.241 10.143-2.241-2.241M3.92 8.922H.75m4.286-3.951-2.242-2.24m2.242 10.142-2.242 2.242m6.193 2.421v-3.17"/></g></svg>
|
||||
|
After Width: | Height: | Size: 451 B |
1
mini/assets/icons/users.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8.296" height="8.83" viewBox="0 0 8.296 8.83"><path fill="none" stroke="#000" stroke-miterlimit="10" stroke-width=".5" d="M.25 8.58v-.914a2 2 0 0 1 2-2h3.796a2 2 0 0 1 2 2v.914zm1.62-6.053a2.277 2.277 0 1 1 4.555 0 2.277 2.277 0 0 1-4.554 0z"/></svg>
|
||||
|
After Width: | Height: | Size: 297 B |
1
mini/assets/icons/x.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="7.623" height="7.623" viewBox="0 0 7.623 7.623"><path fill="none" stroke="#000" stroke-linecap="round" stroke-miterlimit="10" stroke-width=".5" d="m.25.25 7.123 7.123m-7.123 0L7.373.25"/></svg>
|
||||
|
After Width: | Height: | Size: 240 B |
1
mini/assets/images/placement/background.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="64.338" height="41.66" viewBox="0 0 64.338 41.66"><g stroke-miterlimit="10"><path fill="#faeccb" d="M.283 41.35V.37h63.783v40.98z"/><path fill="none" stroke="#000" stroke-linecap="round" stroke-width=".5" d="M32.194 29.421h-4.238c-3.81 0-17.322-3.704-23.964-3.704-2.272 0-3.74.146-3.74.146V5.05H15.83V.257h16.339"/><path fill="none" stroke="#000" stroke-linecap="round" stroke-width=".5" d="M32.168.257h16.34V5.05h15.576v20.813s-1.467-.146-3.74-.146c-6.641 0-20.154 3.704-23.964 3.704h-4.237"/><path fill="#fff" stroke="#000" stroke-width=".5" d="M25.76 24.947a1.5 1.5 0 0 1-1.5-1.5v-4.189a1.5 1.5 0 0 1 1.5-1.5h12.685a1.5 1.5 0 0 1 1.5 1.5v4.19a1.5 1.5 0 0 1-1.5 1.5z"/><path fill="#d86161" stroke="#000" stroke-width=".5" d="M17.109 23.66a1.237 1.237 0 0 1-1.238-1.238v-2.138c0-.684.554-1.238 1.238-1.238h2.138c.683 0 1.237.554 1.237 1.238v2.138c0 .683-.554 1.237-1.237 1.237z"/><path fill="none" stroke="#000" stroke-width=".5" d="M21.965 19.827a.69.69 0 1 1 1.38 0 .69.69 0 0 1-1.38 0zm0 3.052a.69.69 0 1 1 1.38 0 .69.69 0 0 1-1.38 0z"/><path fill="#ffcd48" stroke="#000" stroke-width=".5" d="M21.965 19.827a.69.69 0 1 1 1.38 0 .69.69 0 0 1-1.38 0zm0 3.052a.69.69 0 1 1 1.38 0 .69.69 0 0 1-1.38 0zm19.108-3.052a.69.69 0 1 1 1.38 0 .69.69 0 0 1-1.38 0zm0 3.052a.69.69 0 1 1 1.38 0 .69.69 0 0 1-1.38 0z"/><path fill="none" stroke="#000" stroke-linecap="round" stroke-width=".5" d="M32.194 33.125h-4.238c-3.81 0-17.322-3.704-23.964-3.704-2.272 0-3.74.145-3.74.145v-5.01"/><path fill="none" stroke="#000" stroke-linecap="round" stroke-width=".5" d="M64.084 24.549v5.01s-1.467-.146-3.74-.146c-6.641 0-20.154 3.704-23.964 3.704h-4.237"/><path fill="#bc2d2d" stroke="#000" stroke-width=".5" d="M18.127 30.68a.426.426 0 0 1-.328-.506l.257-1.207a.426.426 0 0 1 .505-.328l6.07 1.29c.23.05.377.275.328.505l-.256 1.207a.426.426 0 0 1-.505.328zm20.496 1.436a.426.426 0 0 1-.505-.329l-.256-1.206a.426.426 0 0 1 .328-.505l6.07-1.29a.426.426 0 0 1 .505.328l.257 1.207a.426.426 0 0 1-.328.505z"/><path fill="#fff" stroke="#000" stroke-width=".5" d="M47.58 19.551c-.463-.47-.52-1.165-.126-1.553l1.23-1.214c.394-.388 1.089-.321 1.552.149l1.45 1.47c.463.47.52 1.165.126 1.553L50.58 21.17c-.394.388-1.088.322-1.552-.148zM4.134 17.685a.597.597 0 0 1-.844 0l-2.165-2.166a.597.597 0 0 1 0-.843L9.839 5.96a.597.597 0 0 1 .844 0l2.165 2.165a.597.597 0 0 1 0 .844z"/><path fill="#bc2d2d" stroke="#000" stroke-width=".5" d="M6.082 21.666a.5.5 0 0 1-.708 0L3.61 19.902a.5.5 0 0 1 0-.707l1.764-1.765a.5.5 0 0 1 .708 0l1.764 1.765a.5.5 0 0 1 0 .707zm2.97-2.97a.5.5 0 0 1-.707 0L6.58 16.93a.5.5 0 0 1 0-.707l1.765-1.765a.5.5 0 0 1 .707 0l1.765 1.765a.5.5 0 0 1 0 .707zm2.97-2.971a.5.5 0 0 1-.707 0l-1.764-1.764a.5.5 0 0 1 0-.707l1.764-1.765a.5.5 0 0 1 .707 0l1.765 1.765a.5.5 0 0 1 0 .707z"/><path fill="#fff" stroke="#000" stroke-width=".5" d="M51.567 9.007a.597.597 0 0 1 0-.844l2.165-2.165a.597.597 0 0 1 .844 0l8.714 8.714a.597.597 0 0 1 0 .844l-2.165 2.165a.597.597 0 0 1-.844 0z"/><path fill="#bc2d2d" stroke="#000" stroke-width=".5" d="M14.993 12.755a.5.5 0 0 1-.707 0L12.52 10.99a.5.5 0 0 1 0-.707l1.765-1.764a.5.5 0 0 1 .707 0l1.764 1.764a.5.5 0 0 1 0 .707zm36.011 1.085a.5.5 0 0 1-.707 0l-1.765-1.764a.5.5 0 0 1 0-.707l1.765-1.764a.5.5 0 0 1 .707 0l1.765 1.764a.5.5 0 0 1 0 .707zm6.758 6.684a.5.5 0 0 1-.707 0L55.29 18.76a.5.5 0 0 1 0-.707l1.765-1.765a.5.5 0 0 1 .707 0l1.764 1.765a.5.5 0 0 1 0 .707zm-3.615-2.456a.64.64 0 0 1-.904 0l-2.255-2.255a.64.64 0 0 1 0-.903l2.255-2.255c.25-.25.654-.25.904 0l2.255 2.255c.25.25.25.654 0 .903z"/><path fill="#fff" stroke="#000" stroke-width=".5" d="M20.507 4.86a.5.5 0 0 1-.5-.5V.29L44.233.252V4.36a.5.5 0 0 1-.5.5z"/><path fill="none" stroke="#000" stroke-linecap="round" stroke-width=".5" d="M32.856 41.41H.25V29.428"/><path fill="none" stroke="#000" stroke-linecap="round" stroke-width=".5" d="M64.071 29.417v11.982H31.465"/><path stroke="#000" stroke-width=".5" d="M.253 5.033V.25h15.602v4.783zm48.232.007V.256h15.603V5.04z"/><path fill="#ffcd48" stroke="#d8ca2d" stroke-width=".5" d="M19.16 26.924a.277.277 0 1 1 .553 0 .277.277 0 0 1-.553 0zm.955.272a.277.277 0 1 1 .553 0 .277.277 0 0 1-.553 0zm-.698-1.182a.277.277 0 1 1 .554 0 .277.277 0 0 1-.554 0zm.983.271a.277.277 0 1 1 .554 0 .277.277 0 0 1-.553 0zm23.224 1.245a.277.277 0 1 1 0-.554.277.277 0 0 1 0 .553zm-.954.27a.277.277 0 1 1 0-.553.277.277 0 0 1 0 .554zm.697-1.181a.277.277 0 1 1 0-.554.277.277 0 0 1 0 .554zm-.984.271a.277.277 0 1 1 0-.554.277.277 0 0 1 0 .554z"/><path fill="#ffcd48" stroke="#000" stroke-width=".5" d="M4.487 14.548a.69.69 0 1 1 1.38 0 .69.69 0 0 1-1.38 0zM9.008 10a.69.69 0 1 1 1.38 0 .69.69 0 0 1-1.38 0z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
1
mini/assets/images/placement/entrance.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="64.327" height="41.52" viewBox="0 0 64.327 41.52"><g stroke="#000" stroke-miterlimit="10"><path fill="#b38969" stroke-width=".25" d="M.97 36.476a2.413 2.413 0 1 1 4.825 0 2.413 2.413 0 0 1-4.826 0z"/><path fill="#b38969" stroke-width=".25" d="M.97 31.65a2.413 2.413 0 1 1 4.825 0 2.413 2.413 0 0 1-4.826 0z"/><path fill="none" stroke-width=".25" d="M1.53 36.618a.17.17 0 0 1-.173-.172v-.224c0-.095.077-.172.172-.172h3.706c.095 0 .172.077.172.172v.224a.17.17 0 0 1-.172.172z"/><path fill="none" stroke-width=".25" d="M5.351 36.734c0 .734-.881 1.328-1.969 1.328-1.087 0-1.969-.594-1.969-1.328 0-.043.01-.128.01-.128l3.92.003s.008.083.008.125z"/><path fill="none" stroke-linecap="round" stroke-width=".25" d="m2.086 36.665 1.238 1.379m-.568-1.379 1.181 1.315m-.511-1.315 1.036 1.154m.448-.249-.814-.905m1.14.523-.47-.523M2.525 37.9l-1.109-1.235"/><path fill="none" stroke-width=".25" d="M1.53 31.792a.17.17 0 0 1-.173-.171v-.224c0-.095.077-.172.172-.172h3.706c.095 0 .172.077.172.172v.224a.17.17 0 0 1-.172.171z"/><path fill="none" stroke-width=".25" d="M5.351 31.908c0 .734-.881 1.329-1.969 1.329-1.087 0-1.969-.595-1.969-1.329 0-.043.01-.127.01-.127l3.92.002s.008.083.008.125z"/><path fill="none" stroke-linecap="round" stroke-width=".25" d="m2.086 31.84 1.238 1.378m-.568-1.378 1.181 1.314m-.511-1.314 1.036 1.153m.448-.248-.814-.905m1.14.522-.47-.522m-2.241 1.234L1.416 31.84"/><path fill="#cede59" stroke-width=".25" d="M5.795 31.65a2.413 2.413 0 1 1 4.826 0 2.413 2.413 0 0 1-4.826 0z"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width=".25" d="M8.593 29.977s-.116.282.038.544c.166.282.574.563.739.949.06.141.16.573.054.907-.023.074-.124.406-.388.61s-.691.281-.866.276a1.5 1.5 0 0 1-.739-.256 1.2 1.2 0 0 1-.409-.546c-.103-.315-.074-.713.042-1.071.155-.477.43-.878.43-.878s.011.163.073.339c.081.232.213.343.25.402.03.046.103-.565.324-.858.208-.276.452-.418.452-.418"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width=".25" d="M8.517 32.153a.55.55 0 0 1 .192.388c0 .201-.164.49-.504.486-.323-.005-.494-.314-.486-.495a1 1 0 0 1 .214-.526c.148-.18.32-.272.32-.272a1 1 0 0 0 .264.42"/><path fill="#cede59" stroke-width=".25" d="M5.795 36.476a2.413 2.413 0 1 1 4.826 0 2.413 2.413 0 0 1-4.826 0z"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width=".25" d="M8.593 34.803s-.116.281.038.544c.166.282.574.563.739.948.06.142.16.574.054.908-.023.074-.124.405-.388.61s-.691.28-.866.276a1.5 1.5 0 0 1-.739-.257 1.2 1.2 0 0 1-.409-.546c-.103-.314-.074-.713.042-1.07.155-.477.43-.878.43-.878s.011.162.073.339c.081.232.213.343.25.402.03.046.103-.566.324-.858.208-.276.452-.418.452-.418"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width=".25" d="M8.517 36.979a.55.55 0 0 1 .192.388c0 .2-.164.49-.504.485-.323-.004-.494-.314-.486-.495a1 1 0 0 1 .214-.525c.148-.18.32-.272.32-.272a1 1 0 0 0 .264.419"/><path fill="none" stroke-width=".25" d="M.97 31.65a2.413 2.413 0 1 1 4.825 0 2.413 2.413 0 0 1-4.826 0z"/><path fill="none" stroke-width=".25" d="M.97 36.476a2.413 2.413 0 1 1 4.825 0 2.413 2.413 0 0 1-4.826 0z"/><path fill="#5997de" stroke-width=".25" d="M10.62 31.65a2.413 2.413 0 1 1 4.826 0 2.413 2.413 0 0 1-4.825 0z"/><path fill="none" stroke-linejoin="round" stroke-width=".25" d="M11.196 31.87h3.675s-.823 1.28-1.837 1.28-1.838-1.28-1.838-1.28z"/><path fill="none" stroke-width=".25" d="M11.854 31.33a1.18 1.18 0 0 1 2.359 0c0 .185-.119.516-.119.516l-2.108.027s-.132-.347-.132-.543z"/><path fill="#5997de" stroke-width=".25" d="M10.62 36.476a2.413 2.413 0 1 1 4.826 0 2.413 2.413 0 0 1-4.825 0z"/><path fill="none" stroke-linejoin="round" stroke-width=".25" d="M11.196 36.695h3.675s-.823 1.28-1.837 1.28-1.838-1.28-1.838-1.28z"/><path fill="none" stroke-width=".25" d="M11.854 36.156a1.18 1.18 0 0 1 2.359 0c0 .185-.119.516-.119.516l-2.108.027s-.132-.347-.132-.543z"/><path fill="none" stroke-width=".5" d="M.25 41.27V.25h63.827v41.02z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
1
mini/assets/images/placement/entrance_incense.svg
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
1
mini/assets/images/placement/kneel.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="64.327" height="41.52" viewBox="0 0 64.327 41.52"><g stroke="#000" stroke-miterlimit="10"><path fill="#b38969" stroke-width=".25" d="M33.184 36.008a2.413 2.413 0 1 1 4.825 0 2.413 2.413 0 0 1-4.825 0z"/><path fill="none" stroke-width=".25" d="M33.743 36.15a.17.17 0 0 1-.171-.172v-.224c0-.095.077-.172.171-.172h3.707c.094 0 .171.077.171.172v.224a.17.17 0 0 1-.171.171z"/><path fill="none" stroke-width=".25" d="M37.565 36.266c0 .733-.881 1.328-1.968 1.328-1.088 0-1.97-.595-1.97-1.328 0-.044.01-.128.01-.128l3.92.002s.008.083.008.126z"/><path fill="none" stroke-linecap="round" stroke-width=".25" d="m34.3 36.197 1.239 1.378m-.569-1.378 1.181 1.314m-.511-1.314 1.037 1.153m.447-.248-.813-.905m1.139.523-.47-.523m-2.24 1.235-1.11-1.235"/><path fill="#b38969" stroke-width=".25" d="M23.864 35.69a2.413 2.413 0 1 1 4.826 0 2.413 2.413 0 0 1-4.826 0z"/><path fill="none" stroke-width=".25" d="M24.424 35.832a.17.17 0 0 1-.172-.171v-.225c0-.094.077-.171.172-.171h3.706c.095 0 .172.077.172.171v.225a.17.17 0 0 1-.172.171z"/><path fill="none" stroke-width=".25" d="M28.246 35.948c0 .734-.882 1.329-1.97 1.329-1.087 0-1.968-.595-1.968-1.329 0-.043.009-.127.009-.127l3.92.002s.009.083.009.125z"/><path fill="none" stroke-linecap="round" stroke-width=".25" d="m24.98 35.88 1.239 1.378m-.569-1.378 1.182 1.314m-.512-1.314 1.037 1.153m.447-.248-.813-.905m1.139.522-.469-.522m-2.241 1.234-1.11-1.234"/><path fill="#cede59" stroke-width=".25" d="M38.01 35.222a2.413 2.413 0 1 1 4.825 0 2.413 2.413 0 0 1-4.826 0z"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width=".25" d="M40.808 33.549s-.117.281.037.543c.166.283.574.563.739.949.06.142.16.573.054.908-.023.074-.123.405-.388.61-.263.204-.69.28-.866.276a1.5 1.5 0 0 1-.738-.257 1.2 1.2 0 0 1-.41-.546c-.102-.314-.074-.713.042-1.07.155-.477.43-.878.43-.878s.012.162.073.338c.082.233.213.344.25.402.03.047.103-.565.324-.857.208-.276.453-.418.453-.418"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width=".25" d="M40.731 35.725a.55.55 0 0 1 .192.388c0 .2-.164.49-.504.485-.322-.005-.494-.314-.485-.495a1 1 0 0 1 .213-.526c.148-.18.32-.271.32-.271a1 1 0 0 0 .264.419"/><path fill="#cede59" stroke-width=".25" d="M19.038 34.69a2.413 2.413 0 1 1 4.826 0 2.413 2.413 0 0 1-4.826 0z"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width=".25" d="M21.837 33.017s-.117.282.037.544c.166.282.574.563.739.948.06.142.16.574.054.908-.023.074-.123.406-.388.61-.263.204-.69.281-.866.276a1.5 1.5 0 0 1-.738-.256 1.2 1.2 0 0 1-.41-.547c-.102-.314-.074-.712.042-1.07.155-.477.43-.878.43-.878s.012.163.073.339c.082.232.213.343.25.402.03.046.103-.565.324-.858.208-.276.453-.418.453-.418"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width=".25" d="M21.76 35.193a.55.55 0 0 1 .192.388c0 .201-.164.49-.504.486-.322-.005-.494-.315-.485-.495a1 1 0 0 1 .213-.526c.148-.18.32-.272.32-.272a1 1 0 0 0 .264.42"/><path fill="none" stroke-width=".25" d="M33.184 36.008a2.413 2.413 0 1 1 4.825 0 2.413 2.413 0 0 1-4.825 0zm-9.32-.318a2.413 2.413 0 1 1 4.826 0 2.413 2.413 0 0 1-4.826 0z"/><path fill="#5997de" stroke-width=".25" d="M14.213 33.508a2.413 2.413 0 1 1 4.825 0 2.413 2.413 0 0 1-4.825 0z"/><path fill="none" stroke-linejoin="round" stroke-width=".25" d="M14.788 33.726h3.675s-.823 1.281-1.837 1.281-1.838-1.28-1.838-1.28z"/><path fill="none" stroke-width=".25" d="M15.446 33.187a1.18 1.18 0 0 1 2.359 0c0 .185-.119.516-.119.516l-2.108.027s-.132-.347-.132-.543z"/><path fill="#5997de" stroke-width=".25" d="M42.835 33.72a2.413 2.413 0 1 1 4.826 0 2.413 2.413 0 0 1-4.826 0z"/><path fill="none" stroke-linejoin="round" stroke-width=".25" d="M43.41 33.939h3.675s-.823 1.28-1.837 1.28-1.837-1.28-1.837-1.28z"/><path fill="none" stroke-width=".25" d="M44.069 33.4a1.18 1.18 0 0 1 2.358 0c0 .185-.118.515-.118.515l-2.108.027s-.132-.347-.132-.542z"/><path fill="none" stroke-width=".5" d="M.25 41.27V.25h63.827v41.02z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
1
mini/assets/images/placement/kneel_incense.svg
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
1
mini/assets/images/placement/sit.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="64.327" height="41.52" viewBox="0 0 64.327 41.52"><g stroke="#000" stroke-miterlimit="10"><path fill="#b38969" stroke-width=".25" d="M55.12 18.47a2.413 2.413 0 1 1 4.825 0 2.413 2.413 0 0 1-4.825 0z"/><path fill="none" stroke-width=".25" d="M55.68 18.612a.17.17 0 0 1-.172-.172v-.224c0-.095.077-.172.172-.172h3.706c.095 0 .171.077.171.172v.224a.17.17 0 0 1-.171.172z"/><path fill="none" stroke-width=".25" d="M59.502 18.728c0 .734-.882 1.328-1.97 1.328-1.087 0-1.968-.594-1.968-1.328 0-.043.009-.128.009-.128l3.92.003s.009.083.009.125z"/><path fill="none" stroke-linecap="round" stroke-width=".25" d="m56.237 18.66 1.238 1.378m-.568-1.378 1.18 1.314m.526-.162-1.036-1.153m1.483.906-.813-.906m1.139.523-.47-.523m-2.24 1.235-1.11-1.235"/><path fill="#b38969" stroke-width=".25" d="M47.605 11.386a2.413 2.413 0 1 1 4.825 0 2.413 2.413 0 0 1-4.825 0z"/><path fill="none" stroke-width=".25" d="M48.164 11.528a.17.17 0 0 1-.171-.172v-.224c0-.095.076-.172.171-.172h3.707c.094 0 .171.077.171.172v.224a.17.17 0 0 1-.171.172z"/><path fill="none" stroke-width=".25" d="M51.986 11.644c0 .733-.881 1.328-1.969 1.328-1.087 0-1.968-.595-1.968-1.328 0-.043.008-.128.008-.128l3.92.002s.01.084.01.126z"/><path fill="none" stroke-linecap="round" stroke-width=".25" d="m49.96 12.953-1.239-1.378m.67 0 1.181 1.315m.525-.162-1.035-1.153m1.483.905-.813-.905m1.138.522-.468-.522M49.16 12.81l-1.109-1.235"/><path fill="#cede59" stroke-width=".25" d="M13.31 9.902a2.413 2.413 0 1 1 4.826 0 2.413 2.413 0 0 1-4.826 0z"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width=".25" d="M16.109 8.23s-.117.28.037.543c.166.282.574.563.739.948.06.142.16.574.054.908-.023.074-.124.406-.388.61s-.691.281-.866.276a1.5 1.5 0 0 1-.739-.256 1.2 1.2 0 0 1-.409-.547c-.103-.314-.074-.712.042-1.07.155-.477.43-.878.43-.878s.011.163.073.339c.082.232.213.343.25.402.03.046.103-.565.324-.858.208-.276.453-.418.453-.418"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width=".25" d="M16.032 10.405a.55.55 0 0 1 .192.388c0 .2-.164.49-.504.485-.322-.004-.494-.314-.486-.494a1 1 0 0 1 .214-.526c.148-.18.32-.272.32-.272a1 1 0 0 0 .264.42"/><path fill="#cede59" stroke-width=".25" d="M2.629 20.198a2.413 2.413 0 1 1 4.825 0 2.413 2.413 0 0 1-4.825 0z"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width=".25" d="M5.427 18.525s-.117.281.037.543c.166.283.575.563.74.949.06.142.159.573.053.908-.023.074-.123.405-.388.61-.263.204-.69.28-.866.276a1.5 1.5 0 0 1-.738-.257 1.2 1.2 0 0 1-.41-.546c-.102-.314-.074-.713.043-1.07.154-.477.43-.878.43-.878s.01.162.073.338c.081.233.212.344.25.402.029.047.103-.565.323-.857.209-.276.453-.418.453-.418"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width=".25" d="M5.35 20.7a.55.55 0 0 1 .192.389c0 .2-.164.49-.504.485-.322-.005-.494-.314-.485-.495a1 1 0 0 1 .214-.526c.147-.18.32-.271.32-.271a1 1 0 0 0 .264.419"/><path fill="none" stroke-width=".25" d="M55.12 18.47a2.413 2.413 0 1 1 4.825 0 2.413 2.413 0 0 1-4.825 0zm-7.515-7.084a2.413 2.413 0 1 1 4.825 0 2.413 2.413 0 0 1-4.825 0z"/><path fill="#5997de" stroke-width=".25" d="M6.089 16.79a2.413 2.413 0 1 1 4.825 0 2.413 2.413 0 0 1-4.825 0z"/><path fill="none" stroke-linejoin="round" stroke-width=".25" d="M6.664 17.008h3.675s-.823 1.28-1.838 1.28c-1.014 0-1.837-1.28-1.837-1.28z"/><path fill="none" stroke-width=".25" d="M7.322 16.47a1.18 1.18 0 0 1 2.359 0c0 .184-.119.515-.119.515l-2.108.027s-.132-.347-.132-.543z"/><path fill="#5997de" stroke-width=".25" d="M9.688 13.238a2.413 2.413 0 1 1 4.826 0 2.413 2.413 0 0 1-4.826 0z"/><path fill="none" stroke-linejoin="round" stroke-width=".25" d="M10.264 13.457h3.674s-.822 1.28-1.837 1.28-1.837-1.28-1.837-1.28z"/><path fill="none" stroke-width=".25" d="M10.922 12.918a1.18 1.18 0 0 1 2.358 0c0 .185-.118.516-.118.516l-2.108.027s-.132-.347-.132-.543z"/><path fill="none" stroke-width=".5" d="M.25 41.27V.25h63.827v41.02z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
1
mini/assets/images/placement/sit_incense.svg
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
1
mini/assets/images/tasks/basket.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12.295" height="6.36" viewBox="0 0 12.295 6.36"><g fill="none" stroke="#000" stroke-miterlimit="10" stroke-width=".5"><path d="M.75 1.903a.5.5 0 0 1-.5-.5V.75a.5.5 0 0 1 .5-.5h10.795a.5.5 0 0 1 .5.5v.653a.5.5 0 0 1-.5.5z"/><path d="M11.882 2.24c0 2.138-2.568 3.87-5.735 3.87S.413 4.378.413 2.24c0-.125.026-.371.026-.371l11.418.007s.025.242.025.365z"/><path stroke-linecap="round" d="M5.978 6.055 2.372 2.041M7.763 5.87 4.324 2.04M9.293 5.4 6.276 2.04m4.32 2.638L8.227 2.041m3.319 1.521L10.179 2.04M3.651 5.637.421 2.041"/></g></svg>
|
||||
|
After Width: | Height: | Size: 579 B |
1
mini/assets/images/tasks/bread-wine.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8.88" height="7.339" viewBox="0 0 8.88 7.339"><g fill="none" stroke="#000" stroke-miterlimit="10" stroke-width=".5"><path stroke-linejoin="round" d="M.25 4.169h8.38s-1.876 2.92-4.19 2.92S.25 4.17.25 4.17z"/><path d="M1.75 2.94a2.69 2.69 0 0 1 5.38 0c0 .421-.27 1.175-.27 1.175l-4.808.062S1.75 3.386 1.75 2.94z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 369 B |
1
mini/assets/images/tasks/candle.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8.235" height="10.812" viewBox="0 0 8.235 10.812"><g fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width=".5"><path d="M5.38.25s-.768.445-1.42 1.311c-.693.919-.926 2.837-1.017 2.692-.117-.183-.529-.533-.784-1.261-.194-.554-.228-1.063-.228-1.063S1.065 3.188.58 4.683C.215 5.806.126 7.056.449 8.043.586 8.46 1 9.206 1.732 9.757c.32.241 1.327.778 2.318.805.55.015 1.891-.226 2.718-.866.83-.642 1.144-1.683 1.217-1.914.332-1.05.02-2.404-.17-2.85-.516-1.21-1.798-2.09-2.318-2.976C5.013 1.133 5.38.25 5.38.25"/><path d="M4.311 5.764s-.54.287-1.004.852c-.419.511-.642 1.17-.67 1.65-.027.568.511 1.539 1.523 1.553 1.066.015 1.583-.893 1.581-1.523-.02-.375-.146-.785-.601-1.217a3.13 3.13 0 0 1-.829-1.315"/></g></svg>
|
||||
|
After Width: | Height: | Size: 812 B |
1
mini/assets/images/tasks/incense.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="5.89" height="8.112" viewBox="0 0 5.89 8.112"><g fill="none" stroke="#000" stroke-miterlimit="10" stroke-width=".5"><path d="M5.454 3.707c0 1.37-1.123 2.482-2.509 2.482S.435 5.078.435 3.707c0-1.37 1.124-2.481 2.51-2.481s2.51 1.11 2.51 2.481z"/><path d="M1.867 1.43V.75a.5.5 0 0 1 .5-.5h1.156a.5.5 0 0 1 .5.5v.662c0 .046-.545-.263-1.023-.257-.589.008-1.133.321-1.133.275zM5.64 7.862c0 .23-5.39.077-5.39 0 0-.627.831-1.154 1.965-1.316.232-.033.496-.33.749-.33.29 0 .55.303.812.346 1.082.177 1.864.692 1.864 1.3z"/><path stroke-linecap="round" d="M.547 3.707h4.796"/></g></svg>
|
||||
|
After Width: | Height: | Size: 621 B |
11
mini/data/knowledge/Ambo.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<p>
|
||||
Der <a href="https://de.wikipedia.org/wiki/Ambo" title="Ambo auf Wikipedia">Ambo</a> ist das feststehende, leicht
|
||||
erhöhte Lesepult in der Kirche.
|
||||
</p>
|
||||
<p>
|
||||
An dem Ambo findet das Lektorat statt, dies sind die Lesungen aus der Bibel und die
|
||||
Fürbitten.
|
||||
</p>
|
||||
<p>
|
||||
In unserer Gemeinde ist der Ambo (vom Pfarrer aus gesehen) rechts neben dem Altar platziert.
|
||||
</p>
|
||||
4
mini/data/knowledge/Kollekte.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<p>Die <a href="https://de.wikipedia.org/wiki/Kollekte" title="Kollekte auf Wikipedia">Kollekte</a> ist eine
|
||||
Geldsammlung während oder am Ende eines Gottesdienstes.</p>
|
||||
<p>Sie dient dazu, Geld für kirchliche, soziale oder wohltätige Zwecke zu sammeln.</p>
|
||||
<p>Der Begriff kommt aus dem Lateinischen und bedeutet "sammeln".</p>
|
||||
7
mini/data/knowledge/Liturgische_Farben.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<p>Die Farben der Gewänder folgen dem Kirchenjahr:</p>
|
||||
<ul>
|
||||
<li><strong>Grün</strong> – Zeit im Jahreskreis</li>
|
||||
<li><strong>Lila</strong> – Fastenzeit und Advent</li>
|
||||
<li><strong>Rot</strong> – Feste des Heiligen Geistes und der Märtyrer</li>
|
||||
<li><strong>Weiß/Gold</strong> – Hochfeste wie Weihnachten und Ostern</li>
|
||||
</ul>
|
||||
13
mini/data/knowledge/Praefation.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<p>Der Pfarrer wendet sich zur Gemeinde:</p>
|
||||
<div class="dialog-box">
|
||||
<p><span class="dialog-speaker">Pfarrer:</span> Der Herr sei mit euch.<br>
|
||||
<span class="dialog-speaker">Gemeinde:</span> Und mit deinem Geist.
|
||||
</p>
|
||||
<p><span class="dialog-speaker">Pfarrer:</span> Erhebet die Herzen.<br>
|
||||
<span class="dialog-speaker">Gemeinde:</span> Wir haben sie beim Herrn.
|
||||
</p>
|
||||
<p><span class="dialog-speaker">Pfarrer:</span> Lasset uns danken dem Herrn, unserm Gott.<br>
|
||||
<span class="dialog-speaker">Gemeinde:</span> Das ist würdig und recht.
|
||||
</p>
|
||||
</div>
|
||||
<p>„In Wahrheit ist es würdig und recht, dir, Herr, heiliger Vater, immer und überall zu danken…“</p>
|
||||
22
mini/data/knowledge/knowledge.json
Normal file
@@ -0,0 +1,22 @@
|
||||
[
|
||||
{
|
||||
"title": "Liturgische Farben",
|
||||
"category": "Tradition",
|
||||
"file": "Liturgische_Farben.html"
|
||||
},
|
||||
{
|
||||
"title": "Ambo",
|
||||
"category": "Gegenstand",
|
||||
"file": "Ambo.html"
|
||||
},
|
||||
{
|
||||
"title": "Kollekte",
|
||||
"category": "Tradition",
|
||||
"file": "Kollekte.html"
|
||||
},
|
||||
{
|
||||
"title": "Präfation (Dialog)",
|
||||
"category": "Ablauf",
|
||||
"file": "Praefation.html"
|
||||
}
|
||||
]
|
||||
30
mini/data/placements.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"standard": [
|
||||
{
|
||||
"label": "Einzug",
|
||||
"image": "assets/images/placement/entrance.svg"
|
||||
},
|
||||
{
|
||||
"label": "Hinknien",
|
||||
"image": "assets/images/placement/kneel.svg"
|
||||
},
|
||||
{
|
||||
"label": "Hinsetzen",
|
||||
"image": "assets/images/placement/sit.svg"
|
||||
}
|
||||
],
|
||||
"withWeihrauch": [
|
||||
{
|
||||
"label": "Einzug (mit Weihrauch)",
|
||||
"image": "assets/images/placement/entrance_incense.svg"
|
||||
},
|
||||
{
|
||||
"label": "Hinknien (mit Weihrauch)",
|
||||
"image": "assets/images/placement/kneel_incense.svg"
|
||||
},
|
||||
{
|
||||
"label": "Hinsetzen (mit Weihrauch)",
|
||||
"image": "assets/images/placement/sit_incense.svg"
|
||||
}
|
||||
]
|
||||
}
|
||||
13
mini/data/prayers/Vater_unser.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<p>Vater unser im Himmel,<br>
|
||||
geheiligt werde dein Name.<br>
|
||||
Dein Reich komme.<br>
|
||||
Dein Wille geschehe,<br>
|
||||
wie im Himmel so auf Erden.<br>
|
||||
Unser tägliches Brot gib uns heute.<br>
|
||||
Und vergib uns unsere Schuld,<br>
|
||||
wie auch wir vergeben unsern Schuldigern.<br>
|
||||
Und führe uns nicht in Versuchung,<br>
|
||||
sondern erlöse uns von dem Bösen.<br>
|
||||
Denn dein ist das Reich und die Kraft<br>
|
||||
und die Herrlichkeit in Ewigkeit.<br>
|
||||
Amen.</p>
|
||||
6
mini/data/prayers/prayers.json
Normal file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"title": "Vater unser",
|
||||
"file": "Vater_unser.html"
|
||||
}
|
||||
]
|
||||
9
mini/data/sequence/00-Vorbereitung.html
Normal file
@@ -0,0 +1,9 @@
|
||||
Bespricht kurz, wer welche Aufgabe übernimmt.<br><br>
|
||||
Sollten nur 4 Minis anwesend sein, entfällt der Weihrauchdienst, die beiden Minis, die sich um die Kerze kümmern,
|
||||
übernehmen dann zusätzlich die Körbe.<br>
|
||||
Der Kollekte-Dienst ist nicht immer vorgesehen, fragt daher sicherheitshalber beim Pfarrer nach, falls ihr unsicher
|
||||
seid.
|
||||
<br><br>
|
||||
Stellt euch nun vor dem Kreuz in der Sakristei auf (so wie ihr später auch beim Einzug gehen werdet).<br>
|
||||
Der Pfarrer sagt: "Unsere Hilfe ist im Namen des Herrn."<br>
|
||||
Ihr antwortet: "Der Himmel und Erde erschaffen hat." und macht dabei das Kreuzzeichen.
|
||||
6
mini/data/sequence/01-Einzug.html
Normal file
@@ -0,0 +1,6 @@
|
||||
Die Minis, die für die Gabenbereitung zuständig sind, bleiben beim Einzug kurz neben der Glocke bei der Tür stehen.<br>
|
||||
Stoßt die Glocke so an, dass sie etwa zweimal läutet.<br><br>
|
||||
|
||||
Danach geht ihr zu euren Knieplätzen auf der Stufe vor dem Altar.<br>
|
||||
Sobald der Pfarrer ein Zeichen gibt (Handzeichen o. Ä.), macht ihr gemeinsam eine kurze Kniebeuge,<br>
|
||||
geht dann hoch auf eure Sitzplätze und setzt euch möglichst synchron hin.
|
||||
1
mini/data/sequence/02-Eroeffnung.html
Normal file
@@ -0,0 +1 @@
|
||||
EMPTY
|
||||
31
mini/data/sequence/sequence.json
Normal file
@@ -0,0 +1,31 @@
|
||||
[
|
||||
{
|
||||
"title": "Vorbereitung",
|
||||
"categories": [
|
||||
"gabenbereitung",
|
||||
"kerze",
|
||||
"koerbchen",
|
||||
"weihrauch"
|
||||
],
|
||||
"file": "00-Vorbereitung.html"
|
||||
},
|
||||
{
|
||||
"title": "Einzug",
|
||||
"categories": [
|
||||
"allgemein",
|
||||
"gabenbereitung",
|
||||
"kerze",
|
||||
"koerbchen",
|
||||
"weihrauch"
|
||||
],
|
||||
"file": "01-Einzug.html"
|
||||
},
|
||||
{
|
||||
"title": "Eröffnung",
|
||||
"categories": [
|
||||
"kerze",
|
||||
"weihrauch"
|
||||
],
|
||||
"file": "02-Eroeffnung.html"
|
||||
}
|
||||
]
|
||||
72
mini/data/tasks.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"gabenbereitung": {
|
||||
"icon": "assets/images/tasks/bread-wine.svg",
|
||||
"title": "Gabenbereitung",
|
||||
"description": "Vorbereitung der Gaben für die Eucharistie und Handwaschung des Priesters",
|
||||
"steps": [
|
||||
{
|
||||
"title": "Vorbereitung",
|
||||
"steps": [
|
||||
"Sobald der Pfarrer euch ein Zeichen gibt, geht ihr gemeinsam zum Gabentisch.",
|
||||
"Ein Mini nimmt Kelch und Schale, der andere übernimmt Wasser und Wein.",
|
||||
"Achtet darauf, dass die Henkel der Gläser zum Pfarrer zeigen, so kann er sie leichter greifen.",
|
||||
"Macht ein leichtes Kopfnicken, dreht euch zueinander und geht zurück zum Gabentisch.",
|
||||
"Dort nimmt einer die Karaffe mit Wasser und das Auffangschälchen, der andere das Handtuch.",
|
||||
"Ihr geht wieder zum Pfarrer und wascht ihm die Hände (in der Regel genügen ein paar Tropfen Wasser).",
|
||||
"Legt Handtuch und Karaffe zurück auf den Tisch, ihr könnt nun mit den anderen Ministranten zur Stufe gehen und euch dort gemeinsam hinknien."
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Klingeln",
|
||||
"steps": [
|
||||
"Nach der Wandlung läutet ihr mit der Schelle.",
|
||||
"Einmal, wenn der Pfarrer die Hostie hochhebt, und einmal, wenn er den Kelch hochhebt.",
|
||||
"Zuerst läutet der Mini, der rechts neben dem Altar kniet, dann der links neben dem Altar.",
|
||||
"Jedes Läuten sollte etwa 2–3 Sekunden dauern."
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Abtragen",
|
||||
"steps": [
|
||||
"Nach dem Kommunionganges geht ihr zurück zum Gabentisch.",
|
||||
"Nehmt das kleine Wasserschälchen und geht damit zum Pfarrer.",
|
||||
"Er reicht euch den Kelch, und ihr könnt das restliche Wasser darin ausleeren.",
|
||||
"Der Pfarrer trinkt das Wasser, reinigt Kelch und Schale mit einem Tuch und gibt sie euch zurück.",
|
||||
"Stellt die Gefäße wieder auf den Gabentisch und kehrt auf eure Plätze zurück."
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"kerze": {
|
||||
"icon": "assets/images/tasks/candle.svg",
|
||||
"title": "Kerze",
|
||||
"description": "Die Kerze für das Evangelium tragen",
|
||||
"steps": [
|
||||
"Hinter euren Sitzplätzen stehen zwei kleinere Kerzen, nicht zu verwechseln mit den großen Kerzen weiter hinten.",
|
||||
"Normalerweise sind sie bereits entzündet. Falls nicht, gebt der Mesnerin kurz ein Zeichen.",
|
||||
"Nehmt die Kerzen und stellt euch hinter den Pfarrer. Folgt ihm mit etwa einem Schritt Abstand.",
|
||||
"Geht vorsichtig mit den Kerzen um, heißes Wachs kann tropfen (Achtet auf die Kleidung!).",
|
||||
"Während der Pfarrer am Ambo das Evangelium liest, stellt ihr euch gut sichtbar hinter ihn.",
|
||||
"Macht das Kreuzzeichen mit, sobald der Pfarrer es auf seiner Stirn macht (dazu müsst ihr die Kerze kurz mit einer Hand halten).",
|
||||
"Danach bleibt ihr still stehen, bis der Pfarrer fertig ist oder euch ein Zeichen zum Gehen gibt.",
|
||||
"Dann geht ihr gemeinsam zurück und stellt die Kerzen ab.",
|
||||
"WICHTIG: Falls es keinen separaten Kollekte-Dienst gibt, übernehmt ihr zusätzlich während der Gabenbereitung das Sammeln der Spenden mit den Körben."
|
||||
]
|
||||
},
|
||||
"kollekte": {
|
||||
"icon": "assets/images/tasks/basket.svg",
|
||||
"title": "Kollekte",
|
||||
"description": "Die Körbe für die Kollekte austeilen und wieder einsammeln",
|
||||
"steps": [
|
||||
"Sobald die Gabenbereitung beginnt, nehmt ihr die Körbe. Sie liegen entweder hinter euch oder auf der anderen Seite bei den anderen Mini-Plätzen.",
|
||||
"Gemeinsam geht ihr nach vorne zum Altar, macht dort eine Kniebeuge und dreht euch dann zu den Bänken um.",
|
||||
"Der Mini mit den drei Körben schaut am besten schon vorher, ob oben in der Kirche auch Leute sitzen.",
|
||||
"Danach gebt ihr links und rechts jeweils ein Korb her, einmal zu Beginn und einmal nach dem ersten Durchgang.",
|
||||
"Die Person mit dem zusätzlichen Korb geht dann noch nach oben (falls dort jemand steht. Besser einmal zu viel hochgehen, als jemanden zu vergessen).",
|
||||
"Die andere Person wartet hinten in der Kirche, bis sie die Körbe von oben zurückbekommt.",
|
||||
"Anschließend geht ihr nach vorne und sammelt die gefüllten Körbe ein.",
|
||||
"Legt sie dann hinter der Altarstufe auf den Boden und kniet euch auf eure Plätze.",
|
||||
"Dort wartet ihr, bis die anderen Minis mit der Gabenbereitung fertig sind und ebenfalls zu euch nach unten kommen."
|
||||
]
|
||||
}
|
||||
}
|
||||
100
mini/index.html
Normal file
@@ -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, viewport-fit=cover">
|
||||
<title>Ministranten Guide</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="top-bar">
|
||||
<div class="brand">
|
||||
<div class="header-icon">
|
||||
<img src="assets/icons/church.svg" alt="Ministranten Guide Icon">
|
||||
</div>
|
||||
<div>
|
||||
<div class="header-title">Ministranten-Guide</div>
|
||||
<div class="header-subtitle"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="desktop-nav">
|
||||
<a href="#" class="tab-btn active" data-file="pages/today.html">Heute</a>
|
||||
<a href="#" class="tab-btn" data-file="pages/sequence.html">Ablauf</a>
|
||||
<a href="#" class="tab-btn" data-file="pages/knowledge.html">Wissen</a>
|
||||
</nav>
|
||||
|
||||
<button class="settings-btn" id="settingsBtn" aria-label="Einstellungen">
|
||||
<img src="assets/icons/settings.svg" alt="Einstellungen">
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<main class="content" id="content-container">
|
||||
</main>
|
||||
|
||||
<nav class="bottom-nav">
|
||||
<a href="#" class="bottom-tab active" data-file="pages/today.html">
|
||||
<img src="assets/icons/sun.svg" alt="Heute Icon">
|
||||
<span>Heute</span>
|
||||
</a>
|
||||
<a href="#" class="bottom-tab" data-file="pages/sequence.html">
|
||||
<img src="assets/icons/list.svg" alt="Ablauf Icon">
|
||||
<span>Ablauf</span>
|
||||
</a>
|
||||
<a href="#" class="bottom-tab" data-file="pages/knowledge.html">
|
||||
<img src="assets/icons/book.svg" alt="Wissen Icon">
|
||||
<span>Wissen</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<div class="modal-overlay" id="settingsModal">
|
||||
<div class="modal-content settings-modal">
|
||||
<div class="modal-top-row">
|
||||
<div class="modal-icon">
|
||||
<img src="assets/icons/settings.svg" alt="Einstellungen Icon">
|
||||
</div>
|
||||
<button class="modal-close" id="closeSettingsBtn" aria-label="Schließen">
|
||||
<img src="assets/icons/x.svg" alt="Schließen">
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h2 class="modal-title">Einstellungen</h2>
|
||||
|
||||
<div class="setting-item">
|
||||
<div class="setting-label">
|
||||
<span>Dark Mode</span>
|
||||
</div>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="darkModeToggle">
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<hr class="settings-divider">
|
||||
|
||||
<div class="settings-info">
|
||||
<p><strong>Ministranten-Guide</strong> v0.1.0-beta</p>
|
||||
<p>Entwickelt von <strong></strong></p>
|
||||
<p>
|
||||
<a href="https://github.com/dein-repo/ministranten-guide" target="_blank" rel="noopener">
|
||||
GitHub Repository
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://github.com/dein-repo/ministranten-guide/issues/new" target="_blank" rel="noopener">
|
||||
Problem melden (Issue)
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="module" src="js/main.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
102
mini/js/main.js
Normal file
@@ -0,0 +1,102 @@
|
||||
import { initTodayPage } from './modules/today.js';
|
||||
import { initSequencePage } from './modules/sequence.js';
|
||||
import { initKnowledgePage } from './modules/knowledge.js';
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const container = document.getElementById("content-container");
|
||||
const triggers = document.querySelectorAll("[data-file]");
|
||||
const settingsBtn = document.getElementById('settingsBtn');
|
||||
const settingsModal = document.getElementById('settingsModal');
|
||||
const closeSettingsBtn = document.getElementById('closeSettingsBtn');
|
||||
const darkModeToggle = document.getElementById('darkModeToggle');
|
||||
|
||||
settingsBtn.addEventListener('click', () => {
|
||||
settingsModal.classList.add('active');
|
||||
});
|
||||
|
||||
closeSettingsBtn.addEventListener('click', () => {
|
||||
settingsModal.classList.remove('active');
|
||||
});
|
||||
|
||||
settingsModal.addEventListener('click', (e) => {
|
||||
if (e.target === settingsModal) {
|
||||
settingsModal.classList.remove('active');
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && settingsModal.classList.contains('active')) {
|
||||
settingsModal.classList.remove('active');
|
||||
}
|
||||
});
|
||||
|
||||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
const systemPrefersDark = mediaQuery.matches;
|
||||
|
||||
const storedDarkMode = localStorage.getItem('darkMode');
|
||||
|
||||
let isDark;
|
||||
if (storedDarkMode !== null) {
|
||||
isDark = storedDarkMode === 'true';
|
||||
} else {
|
||||
isDark = systemPrefersDark;
|
||||
}
|
||||
|
||||
function applyDarkMode(enable) {
|
||||
document.body.classList.toggle('dark-mode', enable);
|
||||
if (darkModeToggle) {
|
||||
darkModeToggle.checked = enable;
|
||||
}
|
||||
}
|
||||
|
||||
applyDarkMode(isDark);
|
||||
|
||||
darkModeToggle.addEventListener('change', () => {
|
||||
const isDarkNow = darkModeToggle.checked;
|
||||
applyDarkMode(isDarkNow);
|
||||
localStorage.setItem('darkMode', isDarkNow);
|
||||
});
|
||||
|
||||
function handleSystemChange(e) {
|
||||
if (localStorage.getItem('darkMode') === null) {
|
||||
applyDarkMode(e.matches);
|
||||
}
|
||||
}
|
||||
|
||||
if (mediaQuery.addEventListener) {
|
||||
mediaQuery.addEventListener('change', handleSystemChange);
|
||||
} else {
|
||||
mediaQuery.addListener(handleSystemChange);
|
||||
}
|
||||
|
||||
|
||||
async function loadPage(file) {
|
||||
try {
|
||||
const response = await fetch(file);
|
||||
if (!response.ok) throw new Error("Error loading page: " + response.statusText);
|
||||
|
||||
container.innerHTML = await response.text();
|
||||
|
||||
triggers.forEach(item => {
|
||||
item.classList.toggle("active", item.getAttribute("data-file") === file);
|
||||
});
|
||||
|
||||
if (file.includes("today")) initTodayPage();
|
||||
if (file.includes("sequence")) initSequencePage();
|
||||
if (file.includes("knowledge")) initKnowledgePage();
|
||||
|
||||
} catch (error) {
|
||||
container.innerHTML = "<p>Error loading content.</p>";
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
loadPage("pages/today.html");
|
||||
|
||||
triggers.forEach(trigger => {
|
||||
trigger.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
loadPage(trigger.getAttribute("data-file"));
|
||||
});
|
||||
});
|
||||
});
|
||||
95
mini/js/modules/knowledge.js
Normal file
@@ -0,0 +1,95 @@
|
||||
export async function initKnowledgePage() {
|
||||
const wissenList = document.getElementById('wissen-list');
|
||||
const gebeteList = document.getElementById('gebete-list');
|
||||
|
||||
if (wissenList) {
|
||||
try {
|
||||
const knowledgeResponse = await fetch('data/knowledge/knowledge.json');
|
||||
const knowledgeItems = await knowledgeResponse.json();
|
||||
renderKnowledgeList(wissenList, knowledgeItems);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Wissens-Übersicht:', error);
|
||||
}
|
||||
}
|
||||
|
||||
if (gebeteList) {
|
||||
try {
|
||||
const gebeteResponse = await fetch('data/prayers/prayers.json');
|
||||
const gebeteItems = await gebeteResponse.json();
|
||||
renderGebeteList(gebeteList, gebeteItems);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Gebete:', error);
|
||||
}
|
||||
}
|
||||
|
||||
const tabs = document.querySelectorAll('.wissen-tab');
|
||||
const panelGebete = document.getElementById('panel-gebete');
|
||||
const panelWissen = document.getElementById('panel-wissen');
|
||||
|
||||
tabs.forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
tabs.forEach(t => t.classList.remove('active'));
|
||||
tab.classList.add('active');
|
||||
|
||||
const target = tab.dataset.tab;
|
||||
if (panelGebete) panelGebete.classList.toggle('active', target === 'gebete');
|
||||
if (panelWissen) panelWissen.classList.toggle('active', target === 'wissen');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createAccordionItem(title, filename, basePath) {
|
||||
const element = document.createElement('div');
|
||||
element.className = 'wissen-item';
|
||||
|
||||
element.innerHTML = `
|
||||
<button class="wissen-header">
|
||||
<span class="wissen-title">${title}</span>
|
||||
<img src="assets/icons/arrow_down.svg" alt="Pfeil nach unten" class="wissen-arrow">
|
||||
</button>
|
||||
<div class="wissen-content">
|
||||
<p class="loading">Loading...</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const header = element.querySelector('.wissen-header');
|
||||
const contentDiv = element.querySelector('.wissen-content');
|
||||
let isLoaded = false;
|
||||
|
||||
header.addEventListener('click', async () => {
|
||||
element.classList.toggle('active');
|
||||
|
||||
if (element.classList.contains('active') && !isLoaded) {
|
||||
try {
|
||||
const contentResponse = await fetch(`${basePath}/${filename}`);
|
||||
if (!contentResponse.ok) throw new Error('Failed to load file');
|
||||
|
||||
const htmlContent = await contentResponse.text();
|
||||
contentDiv.innerHTML = htmlContent;
|
||||
isLoaded = true;
|
||||
} catch (err) {
|
||||
contentDiv.innerHTML = '<p>Failed to load content.</p>';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
function renderKnowledgeList(container, items) {
|
||||
container.innerHTML = '';
|
||||
items.forEach(item => {
|
||||
const title = item.titel || item.title;
|
||||
const element = createAccordionItem(title, item.file, 'data/knowledge');
|
||||
container.appendChild(element);
|
||||
});
|
||||
}
|
||||
|
||||
function renderGebeteList(container, items) {
|
||||
container.innerHTML = '';
|
||||
items.forEach(item => {
|
||||
const title = item.title || item.titel;
|
||||
const element = createAccordionItem(title, item.file, 'data/prayers');
|
||||
container.appendChild(element);
|
||||
});
|
||||
}
|
||||
120
mini/js/modules/sequence.js
Normal file
@@ -0,0 +1,120 @@
|
||||
export async function initSequencePage() {
|
||||
|
||||
const listContainer = document.getElementById('sequence-list') || document.getElementById('ablauf-list');
|
||||
const filterChips = document.querySelectorAll('.filter-chip');
|
||||
|
||||
if (!listContainer) {
|
||||
console.warn('Sequence container not found.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('data/sequence/sequence.json');
|
||||
if (!response.ok) throw new Error('Sequence data could not be loaded.');
|
||||
|
||||
const sequenceSteps = await response.json();
|
||||
|
||||
renderSequenceList(listContainer, sequenceSteps);
|
||||
setupFilterLogic(filterChips);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading sequence:', error);
|
||||
listContainer.innerHTML = '<p>Sequence could not be loaded.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
function renderSequenceList(container, steps) {
|
||||
container.innerHTML = '';
|
||||
|
||||
steps.forEach(step => {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'ablauf-item';
|
||||
item.dataset.categories = step.categories.join(',');
|
||||
|
||||
item.innerHTML = `
|
||||
<button class="sequence-header">
|
||||
<span class="sequence-title">${step.title}</span>
|
||||
<i data-lucide="chevron-down" class="ablauf-arrow"></i>
|
||||
</button>
|
||||
<div class="sequence-content">
|
||||
<p class="loading">Loading...</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const header = item.querySelector('.sequence-header');
|
||||
const contentDiv = item.querySelector('.sequence-content');
|
||||
let isLoaded = false;
|
||||
|
||||
header.addEventListener('click', async () => {
|
||||
item.classList.toggle('active');
|
||||
|
||||
if (item.classList.contains('active') && !isLoaded) {
|
||||
try {
|
||||
const contentResponse = await fetch(`data/sequence/${step.file}`);
|
||||
if (!contentResponse.ok) throw new Error('Content not found.');
|
||||
|
||||
const htmlContent = await contentResponse.text();
|
||||
contentDiv.innerHTML = htmlContent;
|
||||
isLoaded = true;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
contentDiv.innerHTML = '<p>Content could not be loaded.</p>';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
container.appendChild(item);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function setupFilterLogic(filterChips) {
|
||||
if (!filterChips || filterChips.length === 0) return;
|
||||
|
||||
let activeFilters = new Set(['alle']);
|
||||
|
||||
function applyFilters() {
|
||||
document.querySelectorAll('.ablauf-item').forEach(item => {
|
||||
const categories = item.dataset.categories ? item.dataset.categories.split(',') : [];
|
||||
|
||||
const isVisible = activeFilters.has('alle') ||
|
||||
categories.some(cat => activeFilters.has(cat));
|
||||
|
||||
item.style.display = isVisible ? '' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
filterChips.forEach(chip => {
|
||||
chip.addEventListener('click', () => {
|
||||
const filter = chip.dataset.filter;
|
||||
|
||||
if (filter === 'alle') {
|
||||
activeFilters = new Set(['alle']);
|
||||
filterChips.forEach(c => c.classList.remove('active'));
|
||||
chip.classList.add('active');
|
||||
} else {
|
||||
if (activeFilters.has('alle')) {
|
||||
activeFilters.delete('alle');
|
||||
document.querySelector('.filter-chip[data-filter="alle"]')?.classList.remove('active');
|
||||
}
|
||||
|
||||
if (activeFilters.has(filter)) {
|
||||
activeFilters.delete(filter);
|
||||
chip.classList.remove('active');
|
||||
} else {
|
||||
activeFilters.add(filter);
|
||||
chip.classList.add('active');
|
||||
}
|
||||
|
||||
if (activeFilters.size === 0) {
|
||||
activeFilters.add('alle');
|
||||
document.querySelector('.filter-chip[data-filter="alle"]')?.classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
applyFilters();
|
||||
});
|
||||
});
|
||||
|
||||
applyFilters();
|
||||
}
|
||||
227
mini/js/modules/today.js
Normal file
@@ -0,0 +1,227 @@
|
||||
export async function initTodayPage() {
|
||||
|
||||
const today = new Date();
|
||||
document.getElementById('weekday').textContent = today.toLocaleDateString('de-DE', { weekday: 'long' });
|
||||
document.getElementById('date').textContent = today.toLocaleDateString('de-DE', { day: '2-digit', month: 'long', year: 'numeric' });
|
||||
|
||||
const miniColor = getMiniColor(today);
|
||||
const miniAmount = getMiniAmount(today);
|
||||
|
||||
document.getElementById('summary-color').textContent = miniColor;
|
||||
document.getElementById('summary-count').textContent = miniAmount;
|
||||
|
||||
const modal = document.getElementById('task-modal');
|
||||
if (!modal) return;
|
||||
|
||||
try {
|
||||
const [tasksResponse, placementsResponse] = await Promise.all([
|
||||
fetch('data/tasks.json'),
|
||||
fetch('data/placements.json')
|
||||
]);
|
||||
|
||||
const taskData = await tasksResponse.json();
|
||||
const placementData = await placementsResponse.json();
|
||||
|
||||
setupTaskModal(modal, taskData);
|
||||
setupPlacementViewer(placementData);
|
||||
} catch (error) {
|
||||
console.error('Error while loading data:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function setupTaskModal(modal, taskData) {
|
||||
const modalIcon = document.getElementById('modal-icon');
|
||||
const modalTitle = document.getElementById('modal-title');
|
||||
const modalDescription = document.getElementById('modal-description');
|
||||
const modalSteps = document.getElementById('modal-steps');
|
||||
const closeBtn = modal.querySelector('.modal-close');
|
||||
const segContainer = document.getElementById('task-segmented-control');
|
||||
|
||||
document.querySelectorAll('.task-card').forEach(card => {
|
||||
card.addEventListener('click', () => {
|
||||
const data = taskData[card.dataset.task];
|
||||
if (!data) return;
|
||||
|
||||
modalIcon.src = data.icon;
|
||||
modalTitle.textContent = data.title;
|
||||
|
||||
if (data.description) {
|
||||
modalDescription.textContent = data.description;
|
||||
modalDescription.style.display = '';
|
||||
} else {
|
||||
modalDescription.style.display = 'none';
|
||||
}
|
||||
|
||||
const steps = data.steps;
|
||||
let sections = [];
|
||||
let isFlat = false;
|
||||
|
||||
if (Array.isArray(steps) && steps.length > 0) {
|
||||
if (typeof steps[0] === 'object' && steps[0].steps && Array.isArray(steps[0].steps)) {
|
||||
sections = steps;
|
||||
} else {
|
||||
sections = [{ title: null, steps: steps }];
|
||||
isFlat = true;
|
||||
}
|
||||
} else {
|
||||
sections = [{ title: null, steps: [] }];
|
||||
isFlat = true;
|
||||
}
|
||||
|
||||
const renderSteps = (stepsArray) => {
|
||||
modalSteps.innerHTML = stepsArray.map(step => `<li>${step}</li>`).join('');
|
||||
};
|
||||
|
||||
if (sections.length > 1 && !isFlat) {
|
||||
segContainer.style.display = 'flex';
|
||||
segContainer.innerHTML = '';
|
||||
|
||||
sections.forEach((section, index) => {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'segmented-btn' + (index === 0 ? ' active' : '');
|
||||
btn.textContent = section.title;
|
||||
btn.dataset.index = index;
|
||||
btn.addEventListener('click', () => {
|
||||
segContainer.querySelectorAll('.segmented-btn').forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
renderSteps(sections[index].steps);
|
||||
});
|
||||
segContainer.appendChild(btn);
|
||||
});
|
||||
|
||||
renderSteps(sections[0].steps);
|
||||
} else {
|
||||
segContainer.style.display = 'none';
|
||||
if (sections.length === 1) {
|
||||
renderSteps(sections[0].steps);
|
||||
} else {
|
||||
renderSteps(steps); // Fallback
|
||||
}
|
||||
}
|
||||
|
||||
modal.classList.add('active');
|
||||
});
|
||||
});
|
||||
|
||||
// Schließen
|
||||
closeBtn?.addEventListener('click', () => modal.classList.remove('active'));
|
||||
modal.addEventListener('click', (e) => {
|
||||
if (e.target === modal) modal.classList.remove('active');
|
||||
});
|
||||
}
|
||||
function setupPlacementViewer(placementData) {
|
||||
let currentIndex = 0;
|
||||
let showIncense = false;
|
||||
|
||||
const placementImage = document.getElementById('placement-image');
|
||||
const placementLabel = document.getElementById('placement-label');
|
||||
const prevBtn = document.getElementById('placement-prev');
|
||||
const nextBtn = document.getElementById('placement-next');
|
||||
const weihrauchToggle = document.getElementById('incense-toggle');
|
||||
const koerbchenLegend = document.getElementById('basket-toggle');
|
||||
const weihrauchLegend = document.getElementById('incense-legend');
|
||||
const kerzeLabel = document.getElementById('kerze-label');
|
||||
|
||||
function updatePlacement() {
|
||||
const dataset = showIncense ? placementData.withWeihrauch : placementData.standard;
|
||||
const currentItem = dataset[currentIndex];
|
||||
|
||||
if (!currentItem) return;
|
||||
|
||||
placementImage.src = currentItem.image;
|
||||
placementLabel.textContent = currentItem.label;
|
||||
kerzeLabel.textContent = showIncense ? 'Kerze & Kollekte' : 'Kerze';
|
||||
|
||||
const isEntranceWithIncense = showIncense && currentIndex === 0;
|
||||
koerbchenLegend.style.display = isEntranceWithIncense ? 'none' : '';
|
||||
weihrauchLegend.style.display = isEntranceWithIncense ? '' : 'none';
|
||||
}
|
||||
|
||||
prevBtn?.addEventListener('click', () => {
|
||||
currentIndex = (currentIndex - 1 + 3) % 3;
|
||||
updatePlacement();
|
||||
});
|
||||
|
||||
nextBtn?.addEventListener('click', () => {
|
||||
currentIndex = (currentIndex + 1) % 3;
|
||||
updatePlacement();
|
||||
});
|
||||
|
||||
weihrauchToggle?.addEventListener('click', () => {
|
||||
showIncense = !showIncense;
|
||||
weihrauchToggle.classList.toggle('active', showIncense);
|
||||
updatePlacement();
|
||||
});
|
||||
|
||||
updatePlacement();
|
||||
}
|
||||
|
||||
function getOstern(jahr) {
|
||||
const a = jahr % 19;
|
||||
const b = jahr % 4;
|
||||
const c = jahr % 7;
|
||||
const k = Math.floor(jahr / 100);
|
||||
const p = Math.floor((13 + 8 * k) / 25);
|
||||
const q = Math.floor(k / 4);
|
||||
const M = (15 - p + k - q) % 30;
|
||||
const N = (4 + k - q) % 7;
|
||||
const d = (19 * a + M) % 30;
|
||||
const e = (2 * b + 4 * c + 6 * d + N) % 7;
|
||||
const days = 22 + d + e;
|
||||
|
||||
if (days <= 31) {
|
||||
return new Date(jahr, 2, days);
|
||||
} else {
|
||||
return new Date(jahr, 3, days - 31);
|
||||
}
|
||||
}
|
||||
|
||||
function tageDifferenz(datum1, datum2) {
|
||||
const day = 24 * 60 * 60 * 1000;
|
||||
return Math.round((datum1 - datum2) / day);
|
||||
}
|
||||
|
||||
function getMiniColor(targetDate) {
|
||||
const year = targetDate.getFullYear();
|
||||
const easter = getOstern(year);
|
||||
const diffToEaster = tageDifferenz(targetDate, easter);
|
||||
|
||||
const month = targetDate.getMonth();
|
||||
const day = targetDate.getDate();
|
||||
const wochentag = targetDate.getDay();
|
||||
|
||||
if ((month === 11 && day >= 24) || (month === 0 && day <= 10)) {
|
||||
return "GRÜN";
|
||||
}
|
||||
|
||||
if (diffToEaster >= -46 && diffToEaster <= -1) {
|
||||
if (diffToEaster === -7 || diffToEaster === -2) {
|
||||
return "ROT";
|
||||
}
|
||||
return "LILA";
|
||||
}
|
||||
|
||||
if (diffToEaster >= 0 && diffToEaster <= 50) {
|
||||
if (diffToEaster === 50) {
|
||||
return "ROT";
|
||||
}
|
||||
return "GRÜN";
|
||||
}
|
||||
|
||||
let holyEvening = new Date(year, 11, 24);
|
||||
let fourthAdvent = new Date(year, 11, 24 - holyEvening.getDay());
|
||||
let firstAdvent = new Date(fourthAdvent);
|
||||
firstAdvent.setDate(fourthAdvent.getDate() - 21);
|
||||
|
||||
if (targetDate >= firstAdvent && targetDate < holyEvening) {
|
||||
return "LILA";
|
||||
}
|
||||
|
||||
return "GRÜN";
|
||||
}
|
||||
|
||||
function getMiniAmount(targetDate) {
|
||||
const amount = (targetDate.getDay() === 0 || targetDate.getDay() === 6) ? 6 : 4;
|
||||
|
||||
return amount;
|
||||
}
|
||||
13
mini/pages/knowledge.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<section class="wissen-page">
|
||||
<div class="wissen-tabs">
|
||||
<button class="wissen-tab active" data-tab="gebete">Gebete</button>
|
||||
<button class="wissen-tab" data-tab="wissen">Wissen & Traditionen</button>
|
||||
</div>
|
||||
<div class="wissen-panel active" id="panel-gebete">
|
||||
<div class="wissen-list" id="gebete-list"></div>
|
||||
</div>
|
||||
|
||||
<div class="wissen-panel" id="panel-wissen">
|
||||
<div class="wissen-list" id="wissen-list"></div>
|
||||
</div>
|
||||
</section>
|
||||
20
mini/pages/sequence.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<section class="ablauf-page">
|
||||
<div class="filter-bar">
|
||||
<span class="filter-label">Aufgaben:</span>
|
||||
<div class="filter-chips">
|
||||
<button class="filter-chip active" data-filter="alle">Alle</button>
|
||||
<button class="filter-chip" data-filter="allgemein">Allgemein</button>
|
||||
<button class="filter-chip" data-filter="gabenbereitung">Gabenbereitung</button>
|
||||
<button class="filter-chip" data-filter="kerze">Kerze</button>
|
||||
<button class="filter-chip" data-filter="koerbchen">Kollekte</button>
|
||||
<button class="filter-chip" data-filter="weihrauch">Weihrauch</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sequence-list" id="sequence-list"></div>
|
||||
|
||||
<div class="ablauf-download-bar">
|
||||
<a href="pdf/ablauf-uebersicht.pdf" download class="btn-download btn-download-large">
|
||||
<img src="assets/icons/download.svg" alt="Download Icon"> Gesamten Ablauf als PDF herunterladen
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
161
mini/pages/today.html
Normal file
@@ -0,0 +1,161 @@
|
||||
<section class="today-dashboard">
|
||||
<article class="card today-summary-card">
|
||||
<div class="summary-date">
|
||||
<span id="weekday">Sonntag</span>
|
||||
<span id="date">15. August 2026</span>
|
||||
</div>
|
||||
<div class="summary-details">
|
||||
<div class="summary-item">
|
||||
<img src="assets/icons/shirt.svg" alt="Shirt Icon">
|
||||
<div>
|
||||
<strong>Gewand</strong>
|
||||
<span id="summary-color">Grün</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<img src="assets/icons/users.svg" alt="Users Icon">
|
||||
<div>
|
||||
<strong>Ministranten</strong>
|
||||
<span id="summary-count">4</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<article class="card liturgical-card">
|
||||
<div class="liturgical-title-row">
|
||||
<h3>Gewand</h3>
|
||||
</div>
|
||||
<p class="card-hint">
|
||||
Die Gewandfarbe richtet sich nach dem Kirchenjahr. Ihr übernehmt einfach die Farbe, die auch der Pfarrer
|
||||
trägt.<br>
|
||||
<small>(Bei Weiß oder Gold zieht ihr stattdessen Grün an.)</small>
|
||||
</p>
|
||||
<div class="info-stack">
|
||||
<div class="info-line">
|
||||
<div class="info-line-icon info-line-icon-green">
|
||||
<img src="assets/icons/shirt.svg" alt="Shirt Icon">
|
||||
</div>
|
||||
<div>
|
||||
<strong>Grünes Gewand</strong>
|
||||
<span>An Tagen im Jahreskreis</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-line">
|
||||
<div class="info-line-icon info-line-icon-lilac">
|
||||
<img src="assets/icons/shirt.svg" alt="Shirt Icon">
|
||||
</div>
|
||||
<div>
|
||||
<strong>Lilanes Gewand</strong>
|
||||
<span>An Tagen der Buße und Fastenzeit</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-line">
|
||||
<div class="info-line-icon info-line-icon-red">
|
||||
<img src="assets/icons/shirt.svg" alt="Shirt Icon">
|
||||
</div>
|
||||
<div>
|
||||
<strong>Rotes Gewand</strong>
|
||||
<span>An Festtagen des Heiligen Geistes und der Märtyrer</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card placement-card">
|
||||
<div class="placement-header">
|
||||
<h3>Sitzordnung</h3>
|
||||
<button class="placement-toggle" id="incense-toggle">
|
||||
<img src="assets/images/tasks/incense.svg" alt="Weihrauch Icon" class="task-icon"> Weihrauch
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="placement-stage">
|
||||
<img id="placement-background" src="assets/images/placement/background.svg" alt="Platzierung Altar">
|
||||
<img id="placement-image" src="assets/images/placement/entrance.svg" alt="Platzierung Einzug">
|
||||
</div>
|
||||
|
||||
<div class="placement-controls">
|
||||
<button id="placement-prev"><img src="assets/icons/arrow_left.svg" alt="Pfeil Links Icon"></button>
|
||||
<span id="placement-label">Einzug</span>
|
||||
<button id="placement-next"><img src="assets/icons/arrow_right.svg" alt="Pfeil Rechts Icon"></button>
|
||||
</div>
|
||||
|
||||
<div class="placement-legend">
|
||||
<div class="legend-item"><img src="assets/images/tasks/bread-wine.svg" alt="Gabenbereitung Icon"
|
||||
class="task-icon"> Gabenbereitung</div>
|
||||
<div class="legend-item"><img src="assets/images/tasks/candle.svg" alt="Kerze Icon" class="task-icon">
|
||||
<p id="kerze-label">Kerze</p>
|
||||
</div>
|
||||
<div class="legend-item" id="basket-toggle"><img src="assets/images/tasks/basket.svg" alt="Kollekte Icon"
|
||||
class="task-icon">
|
||||
Kollekte</div>
|
||||
<div class="legend-item" id="incense-legend"><img src="assets/images/tasks/incense.svg" alt="Weihrauch Icon"
|
||||
class="task-icon"> Weihrauch</div>
|
||||
</div>
|
||||
</article>
|
||||
<div class="card pdf-download-card">
|
||||
<div class="pdf-download-content">
|
||||
<img src="assets/icons/file.svg" alt="File Icon">
|
||||
<div>
|
||||
<strong>Kurzübersicht</strong>
|
||||
<span>Gewand, Platzierungen & Aufgaben als PDF</span>
|
||||
</div>
|
||||
</div>
|
||||
<a href="pdf/heute-kurzuebersicht.pdf" download class="btn-download">
|
||||
<img src="assets/icons/download.svg" alt="Download Icon"> PDF herunterladen
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="tasks-section">
|
||||
<h2>Deine Aufgaben</h2>
|
||||
<div class="tasks-grid">
|
||||
<button class="task-card" data-task="gabenbereitung">
|
||||
<image src="assets/images/tasks/bread-wine.svg" alt="Gabenbereitung Icon">
|
||||
<span class="task-name">Gabenbereitung</span>
|
||||
<span class="task-arrow"><img src="assets/icons/arrow_right.svg" alt="Pfeil Icon"></span>
|
||||
</button>
|
||||
<button class="task-card" data-task="kerze">
|
||||
<img src="assets/images/tasks/candle.svg" alt="Kerze Icon">
|
||||
<span class="task-name">Kerze</span>
|
||||
<span class="task-arrow"><img src="assets/icons/arrow_right.svg" alt="Pfeil Icon"></span>
|
||||
</button>
|
||||
<button class="task-card" data-task="kollekte">
|
||||
<img src="assets/images/tasks/basket.svg" alt="Kollekte Icon">
|
||||
<span class="task-name">Kollekte</span>
|
||||
<span class="task-arrow"><img src="assets/icons/arrow_right.svg" alt="Pfeil Icon"></span>
|
||||
</button>
|
||||
<button class="task-card" data-task="weihrauch">
|
||||
<img src="assets/images/tasks/incense.svg" alt="Weihrauch Icon">
|
||||
<span class="task-name">Weihrauch</span>
|
||||
<span class="task-arrow"><img src="assets/icons/arrow_right.svg" alt="Pfeil Icon"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-overlay" id="task-modal">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<div class="modal-top-row">
|
||||
<div class="modal-icon">
|
||||
<img id="modal-icon" src="" alt="Aufgaben Icon">
|
||||
</div>
|
||||
<button class="modal-close" aria-label="Schließen">
|
||||
<img src="assets/icons/x.svg" alt="Schließen Icon">
|
||||
</button>
|
||||
</div>
|
||||
<h3 class="modal-title" id="modal-title">Titel</h3>
|
||||
<p class="modal-description" id="modal-description">
|
||||
Hier steht eine kurze Erklärung.
|
||||
</p>
|
||||
</div>
|
||||
<div id="task-segmented-control" class="segmented-control" style="display:none;"></div>
|
||||
<ol class="modal-steps" id="modal-steps">
|
||||
<li>Schritt 1</li>
|
||||
<li>Schritt 2</li>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
1538
mini/style.css
Normal file
@@ -1,7 +0,0 @@
|
||||
<!DOCTYPE html><html lang="de"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Snake</title><style>body{margin:0;display:flex;justify-content:center;align-items:center;height:100vh;background:#000;}canvas{background:#222}</style>
|
||||
</head><body><canvas id="c"></canvas><script>let c=document.getElementById('c'),x=c.getContext('2d'),p=20,t=[{x:200,y:200}],f={x:60,y:60},d=39;c.width=c.height=400;
|
||||
setInterval(()=>{t.unshift({x:(t[0].x+(d==37?-p:d==39?p:0)+c.width)%c.width,y:(t[0].y+(d==38?-p:d==40?p:0)+c.height)%c.height});
|
||||
if(t[0].x==f.x&&t[0].y==f.y)f={x:~~(Math.random()*20)*p,y:~~(Math.random()*20)*p};else t.pop();x.fillStyle='lime';x.clearRect(0,0,c.width,c.height);t.forEach(e=>x.fillRect(e.x,e.y,p,p));
|
||||
x.fillStyle='red';x.fillRect(f.x,f.y,p,p);if(t.slice(1).some(e=>e.x==t[0].x&&e.y==t[0].y))t=[{x:200,y:200}],f={x:60,y:60},d=39;},100);onkeydown=e=>d=e.keyCode-32&&e.keyCode;
|
||||
</script></body></html>
|
||||
175
projects.html
Normal file
@@ -0,0 +1,175 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>BR0TCRAFT | Projekte</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;600&family=Inter:wght@300;400;600;800&family=Orbitron:wght@700&display=swap"
|
||||
rel="stylesheet">
|
||||
<style>
|
||||
.project-status {
|
||||
display: inline-block;
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.68rem;
|
||||
padding: 2px 7px;
|
||||
border-radius: 3px;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.status-active {
|
||||
background: rgba(77, 255, 128, 0.08);
|
||||
color: #4dff80;
|
||||
border: 1px solid rgba(77, 255, 128, 0.15);
|
||||
}
|
||||
|
||||
.status-wip {
|
||||
background: rgba(255, 180, 0, 0.08);
|
||||
color: #ffb400;
|
||||
border: 1px solid rgba(255, 180, 0, 0.15);
|
||||
}
|
||||
|
||||
.status-done {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
color: #555;
|
||||
border: 1px solid #222;
|
||||
}
|
||||
|
||||
.card-stack {
|
||||
font-size: 0.78rem;
|
||||
font-family: var(--font-code);
|
||||
color: var(--accent-primary);
|
||||
margin-top: auto;
|
||||
padding-top: 0.75rem;
|
||||
}
|
||||
|
||||
.project-links {
|
||||
display: flex;
|
||||
gap: 0.6rem;
|
||||
margin-top: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.link-btn {
|
||||
font-size: 0.78rem;
|
||||
font-family: var(--font-code);
|
||||
color: var(--text-muted);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid #222;
|
||||
border-radius: 4px;
|
||||
padding: 3px 10px;
|
||||
text-decoration: none;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.link-btn:hover {
|
||||
color: #fff;
|
||||
border-color: #444;
|
||||
}
|
||||
|
||||
.link-btn.primary {
|
||||
color: var(--accent-primary);
|
||||
border-color: rgba(255, 77, 77, 0.25);
|
||||
}
|
||||
|
||||
.link-btn.primary:hover {
|
||||
background: rgba(255, 77, 77, 0.08);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav class="navbar">
|
||||
<div class="brand">BR0TCRAFT</div>
|
||||
<div class="nav-links">
|
||||
<a href="index.html">Home</a>
|
||||
<a href="projects.html" class="active">Projects</a>
|
||||
<a href="tutorials.html">Dev Notes</a>
|
||||
<a href="about.html">About</a>
|
||||
<a href="assets.html">Assets</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
<section class="section">
|
||||
<h1 style="font-family: var(--font-display); margin-bottom: 0.5rem; color: #fff;">Projects</h1>
|
||||
<p style="color: var(--text-muted); font-size: 0.9rem; margin-bottom: 3rem;">
|
||||
Dinge, die ich gebaut habe oder noch baue.
|
||||
</p>
|
||||
|
||||
<div class="grid">
|
||||
|
||||
<article class="card">
|
||||
<a href="extensions.html" class="card-image-link">
|
||||
<div
|
||||
style="height: 150px; background: linear-gradient(135deg, #1a0000, #ff4d4d22); display: flex; align-items: center; justify-content: center;">
|
||||
<h2
|
||||
style="font-family: var(--font-display); color: var(--accent-primary); letter-spacing: 1px; font-size: 1.5rem;">
|
||||
EXTENSIONS</h2>
|
||||
</div>
|
||||
</a>
|
||||
<div class="card-content">
|
||||
<span class="project-status status-active">aktiv</span>
|
||||
<h3 class="card-title"><a href="extensions.html">Scratch Extensions</a></h3>
|
||||
<p class="card-desc">Meine Sammlung an Erweiterungen für TurboWarp, PenguinMod und SE!.</p>
|
||||
<div class="card-stack">JS · TurboWarp API</div>
|
||||
<div class="project-links">
|
||||
<a href="extensions.html" class="link-btn primary">→ öffnen</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card">
|
||||
<a href="/br0tkabeln/" class="card-image-link">
|
||||
<div style="height: 150px; background: #1a0000; overflow: hidden;">
|
||||
<img src="img/Apps/Br0tkabeln.jpg" style="width:100%; height:100%; object-fit: cover;" alt="Br0tkabeln">
|
||||
</div>
|
||||
</a>
|
||||
<div class="card-content">
|
||||
<span class="project-status status-active">aktiv</span>
|
||||
<h3 class="card-title"><a href="/br0tkabeln/">Br0tkabeln</a></h3>
|
||||
<p class="card-desc">Simpler Vokabeltrainer mit Fokus auf Privacy. Keine Accounts, keine Cloud.</p>
|
||||
<div class="card-stack">Python · Flask · JS</div>
|
||||
<div class="project-links">
|
||||
<a href="/br0tkabeln/" class="link-btn primary">→ öffnen</a>
|
||||
<a href="https://github.com/Br0tcraft" target="_blank" class="link-btn">GitHub</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card">
|
||||
<div style="height: 150px; background: #1a0000; overflow: hidden;">
|
||||
<img src="img/Apps/snake-large.png" style="width:100%; height:100%; object-fit: cover;" alt="Snake">
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<span class="project-status status-done">abgeschlossen</span>
|
||||
<h3 class="card-title">Tiny Snake</h3>
|
||||
<p class="card-desc">Ein Rewrite des Klassikers. Hauptsächlich um C++ besser zu lernen.</p>
|
||||
<div class="card-stack">C++</div>
|
||||
<div class="project-links">
|
||||
<a href="https://github.com/Br0tcraft" target="_blank" class="link-btn">GitHub</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card">
|
||||
<div style="height: 150px; background: #111; display: flex; align-items: center; justify-content: center;">
|
||||
<span style="font-family: var(--font-code); font-size: 0.75rem; color: #2a2a2a;">in Arbeit</span>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<span class="project-status status-wip">⧖ in Arbeit</span>
|
||||
<h3 class="card-title">Demnächst</h3>
|
||||
<p class="card-desc">Weitere Projekte folgen. Kein ETA.</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
438
tutorials.html
Normal file
@@ -0,0 +1,438 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>BR0TCRAFT | Dev Notes</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;600&family=Inter:wght@300;400;600;800&family=Orbitron:wght@700&display=swap"
|
||||
rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
||||
<style>
|
||||
.search-wrapper {
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
width: 100%;
|
||||
padding: 1rem 1.5rem;
|
||||
border-radius: var(--radius);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid #2a2a2a;
|
||||
color: #fff;
|
||||
font-family: var(--font-body);
|
||||
font-size: 1rem;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.search-bar:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent-primary);
|
||||
box-shadow: 0 0 15px var(--accent-glow);
|
||||
}
|
||||
|
||||
.search-bar::placeholder {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
/* Tabs: Notes / Tutorials */
|
||||
.tab-switcher {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
margin-bottom: 2.5rem;
|
||||
border-bottom: 1px solid #222;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #555;
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.6rem 1.2rem;
|
||||
cursor: pointer;
|
||||
border-bottom: 2px solid transparent;
|
||||
margin-bottom: -1px;
|
||||
transition: color 0.2s, border-color 0.2s;
|
||||
}
|
||||
|
||||
.tab-btn.active {
|
||||
color: #fff;
|
||||
border-bottom-color: var(--accent-primary);
|
||||
}
|
||||
|
||||
.tab-btn:hover:not(.active) {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.tab-panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tab-panel.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Dev Note card */
|
||||
.note-card {
|
||||
border: 1px solid #1f1f1f;
|
||||
border-radius: var(--radius);
|
||||
padding: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
background: rgba(255, 255, 255, 0.015);
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.note-card:hover {
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
.note-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
margin-bottom: 0.8rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.note-index {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.72rem;
|
||||
color: #444;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.note-card h3 {
|
||||
color: #fff;
|
||||
font-size: 1rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.note-tag {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.72rem;
|
||||
color: var(--accent-primary);
|
||||
background: rgba(255, 77, 77, 0.07);
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.note-problem,
|
||||
.note-solution {
|
||||
font-size: 0.88rem;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.note-problem {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.note-problem strong,
|
||||
.note-solution strong {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.78rem;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.note-problem strong {
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.note-solution strong {
|
||||
color: var(--accent-primary);
|
||||
}
|
||||
|
||||
.note-solution {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.note-card pre {
|
||||
margin: 0.75rem 0 0;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
.note-card pre code {
|
||||
font-family: var(--font-code);
|
||||
}
|
||||
|
||||
/* Tutorial cards (same as before but slimmer) */
|
||||
.meta-tags {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.meta-tag {
|
||||
font-size: 0.78rem;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
background: #1e1e1e;
|
||||
color: #555;
|
||||
font-family: var(--font-code);
|
||||
}
|
||||
|
||||
.notes-count {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.78rem;
|
||||
color: #444;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav class="navbar">
|
||||
<div class="brand">BR0TCRAFT</div>
|
||||
<div class="nav-links">
|
||||
<a href="index.html">Home</a>
|
||||
<a href="projects.html">Projects</a>
|
||||
<a href="tutorials.html" class="active">Dev Notes</a>
|
||||
<a href="about.html">About</a>
|
||||
<a href="assets.html">Assets</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
<section class="section">
|
||||
<h1 style="font-family: var(--font-display); margin-bottom: 0.5rem; color: #fff;">Dev Notes</h1>
|
||||
<p style="color: var(--text-muted); margin-bottom: 2rem; font-size: 0.95rem;">
|
||||
Notizen, Quick Tips und längere Artikel.
|
||||
</p>
|
||||
|
||||
<div class="search-wrapper">
|
||||
<input type="text" id="searchInput" class="search-bar" placeholder="Suche (C++, Python, Git ...)">
|
||||
</div>
|
||||
|
||||
<div class="tab-switcher">
|
||||
<button class="tab-btn active" onclick="switchTab('notes', this)">Quick Tips</button>
|
||||
<button class="tab-btn" onclick="switchTab('tutorials', this)">Tutorials</button>
|
||||
</div>
|
||||
|
||||
<div class="tab-panel active" id="tab-notes">
|
||||
<div class="notes-count" id="notesCount"></div>
|
||||
|
||||
<div class="note-card searchable" data-keywords="c++ string string_view performance copy">
|
||||
<div class="note-header">
|
||||
<div class="note-title-group">
|
||||
<div class="note-index">#01</div>
|
||||
<h3>std::string vs. std::string_view</h3>
|
||||
</div>
|
||||
<span class="note-tag">C++</span>
|
||||
</div>
|
||||
<p class="note-problem"><strong>PROBLEM</strong> Unnötige Kopien beim Übergeben von Strings als
|
||||
Funktionsparameter.</p>
|
||||
<p class="note-solution"><strong>LÖSUNG</strong> Wenn der String nur gelesen wird,
|
||||
<code>std::string_view</code> statt <code>const std::string&</code> nutzen. Kein Ownership, kein
|
||||
Copy-Overhead.
|
||||
</p>
|
||||
<pre><code class="language-cpp">void log(std::string_view msg) {
|
||||
std::cout << msg;
|
||||
}</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="note-card searchable" data-keywords="python dict keyerror get default">
|
||||
<div class="note-header">
|
||||
<div class="note-title-group">
|
||||
<div class="note-index">#02</div>
|
||||
<h3>dict.get() statt dict[]</h3>
|
||||
</div>
|
||||
<span class="note-tag">Python</span>
|
||||
</div>
|
||||
<p class="note-problem"><strong>PROBLEM</strong> <code>KeyError</code> beim Zugriff auf einen Key, der
|
||||
nicht existieren könnte.</p>
|
||||
<p class="note-solution"><strong>LÖSUNG</strong> <code>.get()</code> gibt <code>None</code> (oder einen
|
||||
Default) zurück, statt zu crashen.</p>
|
||||
<pre><code class="language-python">val = data.get("key", "default")</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="note-card searchable" data-keywords="git commit message amend fix">
|
||||
<div class="note-header">
|
||||
<div class="note-title-group">
|
||||
<div class="note-index">#03</div>
|
||||
<h3>Falschen Commit-Message fixen</h3>
|
||||
</div>
|
||||
<span class="note-tag">Git</span>
|
||||
</div>
|
||||
<p class="note-problem"><strong>PROBLEM</strong> Commit abgeschickt, Message falsch.</p>
|
||||
<p class="note-solution"><strong>LÖSUNG</strong> <code>--amend</code> vor dem Push. Danach wird's
|
||||
komplizierter.</p>
|
||||
<pre><code class="language-bash">git commit --amend -m "Richtige Message"</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="note-card searchable" data-keywords="c++ destructor virtual base class memory leak">
|
||||
<div class="note-header">
|
||||
<div class="note-title-group">
|
||||
<div class="note-index">#04</div>
|
||||
<h3>Vergessenes virtual im Destruktor</h3>
|
||||
</div>
|
||||
<span class="note-tag">C++</span>
|
||||
</div>
|
||||
<p class="note-problem"><strong>PROBLEM</strong> Basisklassen-Destruktor ist nicht <code>virtual</code>
|
||||
→ Derived-Objekte werden nicht korrekt zerstört.</p>
|
||||
<p class="note-solution"><strong>LÖSUNG</strong> Sobald eine Klasse als Basisklasse gedacht ist:</p>
|
||||
<pre><code class="language-cpp">class Base {
|
||||
public:
|
||||
virtual ~Base() = default;
|
||||
};</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="note-card searchable" data-keywords="javascript optional chaining nullish coalescing">
|
||||
<div class="note-header">
|
||||
<div class="note-title-group">
|
||||
<div class="note-index">#05</div>
|
||||
<h3>Optional Chaining statt verschachteltem if</h3>
|
||||
</div>
|
||||
<span class="note-tag">JavaScript</span>
|
||||
</div>
|
||||
<p class="note-problem"><strong>PROBLEM</strong> Tief verschachtelte Objekte ohne Garantie, dass jede
|
||||
Ebene existiert.</p>
|
||||
<p class="note-solution"><strong>LÖSUNG</strong> <code>?.</code> und <code>??</code> kombinieren.
|
||||
Kürzer, kein <code>TypeError</code>, kein 3-stöckiges <code>if</code>.</p>
|
||||
<pre><code class="language-javascript">const city = user?.address?.city ?? "Unbekannt";</code></pre>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tab-panel" id="tab-tutorials">
|
||||
<div class="grid" id="tutorialGrid">
|
||||
|
||||
<article class="card tutorial-card searchable" data-keywords="3ds devkitpro homebrew cia 3dsx rsf">
|
||||
<div class="card-content">
|
||||
<span
|
||||
style="color:var(--accent-primary); font-family:var(--font-code); font-size:0.78rem;">#Nintendo3DS</span>
|
||||
<h3 class="card-title" style="margin-top:0.5rem;">Introduction to 3DS Homebrew Development</h3>
|
||||
<p class="card-desc">How to start programming homebrew for the Nintendo 3DS.</p>
|
||||
<div class="meta-tags">
|
||||
<span class="meta-tag">homebrew</span>
|
||||
<span class="meta-tag">3DS</span>
|
||||
<span class="meta-tag">C++</span>
|
||||
</div>
|
||||
<a href="article.html?doc=3ds/" class="btn" style="margin-top:auto; font-size:0.85rem;">Read
|
||||
More</a>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card tutorial-card searchable" data-keywords="server account verwaltung passwort sicherheit">
|
||||
<div class="card-content">
|
||||
<span
|
||||
style="color:var(--accent-primary); font-family:var(--font-code); font-size:0.78rem;">#Backend</span>
|
||||
<h3 class="card-title" style="margin-top:0.5rem;">Account-Verwaltung</h3>
|
||||
<p class="card-desc">Accounts handhaben, ohne Angst zu haben, Passwörter zu leaken.</p>
|
||||
<div class="meta-tags">
|
||||
<span class="meta-tag">Python</span>
|
||||
<span class="meta-tag">Security</span>
|
||||
<span class="meta-tag">Webserver</span>
|
||||
</div>
|
||||
<a href="article.html?file=content/account-management.md" class="btn"
|
||||
style="margin-top:auto; font-size:0.85rem;">Lesen</a>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card tutorial-card searchable"
|
||||
data-keywords="email verifikation authentifizierung backend login">
|
||||
<div class="card-content">
|
||||
<span
|
||||
style="color:var(--accent-primary); font-family:var(--font-code); font-size:0.78rem;">#Backend</span>
|
||||
<h3 class="card-title" style="margin-top:0.5rem;">Email-Authentifizierung</h3>
|
||||
<p class="card-desc">Emails im Backend verschicken, Benutzer über Login-Code verifizieren.</p>
|
||||
<div class="meta-tags">
|
||||
<span class="meta-tag">Python</span>
|
||||
<span class="meta-tag">Backends</span>
|
||||
<span class="meta-tag">Webserver</span>
|
||||
</div>
|
||||
<a href="article.html?file=content/email-auth.md" class="btn"
|
||||
style="margin-top:auto; font-size:0.85rem;">Lesen</a>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card tutorial-card searchable" data-keywords="passwort salting hashing datenbank sicherheit">
|
||||
<div class="card-content">
|
||||
<span
|
||||
style="color:var(--accent-primary); font-family:var(--font-code); font-size:0.78rem;">#Backend</span>
|
||||
<h3 class="card-title" style="margin-top:0.5rem;">Passwörter hashen & salzen</h3>
|
||||
<p class="card-desc">Auswirkung eines Datenbankleaks minimieren, so geht's richtig.</p>
|
||||
<div class="meta-tags">
|
||||
<span class="meta-tag">Python</span>
|
||||
<span class="meta-tag">Security</span>
|
||||
<span class="meta-tag">Backends</span>
|
||||
</div>
|
||||
<a href="article.html?file=content/password-salting.md" class="btn"
|
||||
style="margin-top:auto; font-size:0.85rem;">Lesen</a>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card tutorial-card searchable" data-keywords="datenbanken speichern benutzer accounts sql">
|
||||
<div class="card-content">
|
||||
<span
|
||||
style="color:var(--accent-primary); font-family:var(--font-code); font-size:0.78rem;">#Backend</span>
|
||||
<h3 class="card-title" style="margin-top:0.5rem;">Datenbanken</h3>
|
||||
<p class="card-desc">Daten, Benutzer und Accounts in einer Datenbank speichern.</p>
|
||||
<div class="meta-tags">
|
||||
<span class="meta-tag">Python</span>
|
||||
<span class="meta-tag">Backends</span>
|
||||
<span class="meta-tag">Webserver</span>
|
||||
</div>
|
||||
<a href="article.html?file=content/databases.md" class="btn"
|
||||
style="margin-top:auto; font-size:0.85rem;">Lesen</a>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function switchTab(name, btn) {
|
||||
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
||||
document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
document.getElementById('tab-' + name).classList.add('active');
|
||||
filterSearch(document.getElementById('searchInput').value);
|
||||
}
|
||||
|
||||
const input = document.getElementById('searchInput');
|
||||
|
||||
function filterSearch(term) {
|
||||
const t = term.toLowerCase();
|
||||
const activePanel = document.querySelector('.tab-panel.active');
|
||||
const items = activePanel.querySelectorAll('.searchable');
|
||||
let visible = 0;
|
||||
items.forEach(item => {
|
||||
const text = item.innerText.toLowerCase();
|
||||
const kw = (item.getAttribute('data-keywords') || '').toLowerCase();
|
||||
const show = !t || text.includes(t) || kw.includes(t);
|
||||
item.style.display = show ? '' : 'none';
|
||||
if (show) visible++;
|
||||
});
|
||||
|
||||
const countEl = document.getElementById('notesCount');
|
||||
if (countEl && document.getElementById('tab-notes').classList.contains('active')) {
|
||||
countEl.textContent = visible + ' Einträge';
|
||||
}
|
||||
}
|
||||
|
||||
input.addEventListener('input', e => filterSearch(e.target.value));
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
hljs.highlightAll();
|
||||
const notes = document.querySelectorAll('#tab-notes .searchable');
|
||||
document.getElementById('notesCount').textContent = notes.length + ' Einträge';
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||