This commit is contained in:
24
02_advanced/projekte/js-advanced-dashboard-template/.gitignore
vendored
Normal file
24
02_advanced/projekte/js-advanced-dashboard-template/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -0,0 +1,17 @@
|
||||
## License and terms of use
|
||||
|
||||
© Web Professional Institute Inc. All rights reserved.
|
||||
|
||||
This material is provided solely for students enrolled in courses offered by Web Professional Institute Inc. By accessing or using this code, you acknowledge that it is strictly for educational use within the context of Web Professional Institute Inc. programs.
|
||||
|
||||
**Usage Restrictions:**
|
||||
|
||||
- Redistribution, sharing, or copying of this material outside the course environment is strictly prohibited.
|
||||
- The content is designed to support your learning objectives and is not authorized for commercial projects, public repositories, or applications beyond the course scope.
|
||||
- Unauthorized commercial use or open-source distribution is strictly prohibited and may result in expulsion from the program and legal action.
|
||||
|
||||
**Agreement & Rights:**
|
||||
|
||||
As a student, you have agreed to these terms as part of your enrollment agreement, which includes additional details on permitted uses, restrictions, and policies. The author and Web Professional Institute Inc. retain all rights to this material, including the code base and instructional content.
|
||||
|
||||
For any questions regarding these terms, please contact Web Professional Institute Inc. for clarification.
|
||||
@@ -0,0 +1,62 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Recipe Explorer Dashboard</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Recipe Explorer Dashboard</h1>
|
||||
|
||||
<div id="search-container">
|
||||
<input
|
||||
type="text"
|
||||
id="search-input"
|
||||
placeholder="Search for recipes by name..."
|
||||
/>
|
||||
<button id="search-button">Search</button>
|
||||
</div>
|
||||
|
||||
<div id="loading">Loading...</div>
|
||||
<div id="error-message"></div>
|
||||
|
||||
<table id="recipes-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Recipe Name</th>
|
||||
<th>Cuisine</th>
|
||||
<th>Preparation Time (mins)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Recipe data will be populated here -->
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Modal for Recipe Details -->
|
||||
<div id="recipe-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close">×</span>
|
||||
<h2 id="modal-title">Recipe Name</h2>
|
||||
<img
|
||||
id="modal-image"
|
||||
src=""
|
||||
alt="Recipe Image"
|
||||
style="border-radius: 10px; max-height: 200px"
|
||||
/>
|
||||
<p><strong>Cuisine:</strong> <span id="modal-category"></span></p>
|
||||
<p>
|
||||
<strong>Preparation Time:</strong> <span id="modal-time"></span> mins
|
||||
</p>
|
||||
<p><strong>Ingredients:</strong></p>
|
||||
<ul id="modal-ingredients">
|
||||
<!-- Ingredients will be populated here -->
|
||||
</ul>
|
||||
<p><strong>Instructions:</strong></p>
|
||||
<p id="modal-instructions"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="scripts.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
122
02_advanced/projekte/js-advanced-dashboard-template/scripts.js
Normal file
122
02_advanced/projekte/js-advanced-dashboard-template/scripts.js
Normal file
@@ -0,0 +1,122 @@
|
||||
(() => {
|
||||
// ===== DOM & VARIABLES =====
|
||||
const RECIPES_URL = 'https://dummyjson.com/recipes';
|
||||
|
||||
const searchInput = document.querySelector('#search-input');
|
||||
const searchButton = document.querySelector('#search-button');
|
||||
const recipesTableBody = document.querySelector('#recipes-table tbody');
|
||||
const loadingIndicator = document.querySelector('#loading');
|
||||
const errorMessage = document.querySelector('#error-message');
|
||||
|
||||
const modal = document.querySelector('#recipe-modal');
|
||||
const modalTitle = document.querySelector('#modal-title');
|
||||
const modalImage = document.querySelector('#modal-image');
|
||||
const modalCategory = document.querySelector('#modal-category');
|
||||
const modalTime = document.querySelector('#modal-time');
|
||||
const modalIngredients = document.querySelector('#modal-ingredients');
|
||||
const modalInstructions = document.querySelector('#modal-instructions');
|
||||
const closeModal = document.querySelector('.close');
|
||||
|
||||
let allRecipes = [];
|
||||
|
||||
// ===== INIT =====
|
||||
const init = () => {
|
||||
// TODO: Fetch and display all recipes on initial load
|
||||
|
||||
// Event Listeners
|
||||
closeModal.addEventListener('click', closeModalEvent);
|
||||
window.addEventListener('click', windowClickEvent);
|
||||
};
|
||||
|
||||
// ===== EVENT LISTENERS =====
|
||||
const searchButtonEvent = () => {
|
||||
const query = searchInput.value.trim().toLowerCase();
|
||||
if (query !== '') {
|
||||
// TODO: Implement search functionality
|
||||
} else {
|
||||
// TODO: Display all recipes if search input is empty
|
||||
}
|
||||
};
|
||||
|
||||
// Close Modal Event
|
||||
const closeModalEvent = () => {
|
||||
modal.style.display = 'none';
|
||||
};
|
||||
|
||||
// Close Modal when clicking outside the modal content
|
||||
const windowClickEvent = (event) => {
|
||||
if (event.target == modal) {
|
||||
modal.style.display = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
// ===== FUNCTIONS =====
|
||||
// Fetches all recipes from the API and displays them.
|
||||
const fetchAndDisplayRecipes = async () => {
|
||||
showLoading(true);
|
||||
showError(false, '');
|
||||
|
||||
try {
|
||||
// TODO: Fetch data from API
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
showError(true, 'An error occurred while fetching recipes.');
|
||||
} finally {
|
||||
showLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Searches for recipes by name and displays the results.
|
||||
const searchRecipes = async (query) => {
|
||||
showLoading(true);
|
||||
showError(false, '');
|
||||
|
||||
try {
|
||||
// TODO: Search for recipes by name
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
showError(true, 'An error occurred while searching for recipes.');
|
||||
} finally {
|
||||
showLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Displays a list of recipes in the table.
|
||||
const displayRecipes = (recipes) => {
|
||||
clearTable();
|
||||
|
||||
// TODO: Iterate over the recipes and display them in the table
|
||||
};
|
||||
|
||||
// Displays detailed information about a selected recipe in a modal.
|
||||
const showRecipeDetails = (recipe) => {
|
||||
// TODO: Calculate total preparation time
|
||||
// TODO: Set image source
|
||||
// TODO: Populate ingredients
|
||||
// TODO: Show modal
|
||||
};
|
||||
|
||||
// Shows or hides the loading indicator.
|
||||
const showLoading = (show) => {
|
||||
loadingIndicator.style.display = show ? 'block' : 'none';
|
||||
};
|
||||
|
||||
// Displays or hides an error message.
|
||||
const showError = (show, message) => {
|
||||
if (show) {
|
||||
errorMessage.textContent = message;
|
||||
errorMessage.style.display = 'block';
|
||||
} else {
|
||||
errorMessage.textContent = '';
|
||||
errorMessage.style.display = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
// Clears the recipes table.
|
||||
const clearTable = () => {
|
||||
recipesTableBody.innerHTML = '';
|
||||
};
|
||||
|
||||
// ===== CALL INIT =====
|
||||
init();
|
||||
})();
|
||||
124
02_advanced/projekte/js-advanced-dashboard-template/styles.css
Normal file
124
02_advanced/projekte/js-advanced-dashboard-template/styles.css
Normal file
@@ -0,0 +1,124 @@
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: #4d7c0f;
|
||||
}
|
||||
|
||||
#search-container {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#search-input {
|
||||
width: 300px;
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
border: 2px solid #65a30d;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#search-button {
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
background-color: #4d7c0f;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
#search-button:hover {
|
||||
background-color: #65a30d;
|
||||
transition: 0.1s;
|
||||
}
|
||||
|
||||
#recipes-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 20px;
|
||||
max-width: 1000px;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
#recipes-table th,
|
||||
#recipes-table td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#recipes-table th {
|
||||
background-color: #4d7c0f;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#recipes-table tr:nth-child(even) {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
#recipes-table tr:hover {
|
||||
background-color: #ecfccb;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Modal styling */
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
padding-top: 100px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: #fff;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #888;
|
||||
width: 60%;
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.close {
|
||||
color: #aaa;
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 25px;
|
||||
font-size: 30px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.close:hover,
|
||||
.close:focus {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Loading Indicator */
|
||||
#loading {
|
||||
display: none;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
color: #4d7c0f;
|
||||
}
|
||||
|
||||
/* Error Message */
|
||||
#error-message {
|
||||
display: none;
|
||||
text-align: center;
|
||||
color: red;
|
||||
font-size: 18px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
Reference in New Issue
Block a user