-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit d7b4fbe
Showing
4 changed files
with
308 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
.project-container { | ||
|
||
margin: 20px auto; | ||
padding: 20px; | ||
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); | ||
border-radius: 8px; | ||
background-color: #f8f9fa; | ||
} | ||
|
||
.project-header { | ||
color: #0d6efd; | ||
} | ||
|
||
.feature-item { | ||
margin-bottom: 15px; | ||
} | ||
|
||
.btn-clone { | ||
margin-top: 20px; | ||
} | ||
|
||
.screenshot { | ||
max-width: 100%; | ||
border-radius: 8px; | ||
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
|
||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Add Category Component</title> | ||
<link rel="stylesheet" href="style.css"> | ||
<link rel="stylesheet" href="description.css"> | ||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" | ||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"> | ||
</head> | ||
|
||
<body> | ||
|
||
|
||
<div class="addCategoryComp container m-auto mt-5"> | ||
<h3>Add Category</h3> | ||
<div class="input-group mt-2 mb-3"> | ||
<input type="text" id="categoryInput" class="form-control w-75" placeholder="Enter category"> | ||
<button class="btn btn-primary ms-1" id="addCategoryButton">Add</button> | ||
</div> | ||
<div id="categoriesContainer" class="mt-3"></div> | ||
|
||
<hr class="m-3"> | ||
|
||
<!-- Sub-category section --> | ||
<h4 id="subCategoryTitle">Add Sub Category for: <span id="selectedCategoryName"></span></h4> | ||
<div class="input-group mt-2 mb-3"> | ||
<input type="text" id="subCategoryInput" class="form-control w-75" placeholder="Enter sub category" | ||
disabled> | ||
<button class="btn btn-primary ms-1" id="addSubCategoryButton" disabled>Add</button> | ||
</div> | ||
<div id="subCategoriesContainer" class="mt-3"></div> | ||
</div> | ||
|
||
<div class="div"> | ||
<div class="project-container container"> | ||
<h2 class="project-header">Category and Subcategory Management Component</h2> | ||
<p class="lead">A Bootstrap-based UI component for managing categories and their respective sub-categories | ||
with | ||
options to add, select, and delete, plus keyboard shortcuts for quick actions.</p> | ||
|
||
<h4>Features</h4> | ||
<ul class="list-group list-group-flush"> | ||
<li class="list-group-item feature-item"><strong>Add Categories:</strong> Enter a category name and add | ||
it to the list.</li> | ||
<li class="list-group-item feature-item"><strong>Select and Add Subcategories:</strong> Select a | ||
category to enable adding related sub-categories.</li> | ||
<li class="list-group-item feature-item"><strong>Move Deleted Subcategories:</strong> If a category is | ||
deleted, its sub-categories are moved to the default "Others" section.</li> | ||
<li class="list-group-item feature-item"><strong>Quick Actions:</strong> Each category and sub-category | ||
tag has a cross (<code>×</code>) button for deletion.</li> | ||
<li class="list-group-item feature-item"><strong>Keyboard Support:</strong> Press "Enter" to quickly | ||
submit category or sub-category input.</li> | ||
</ul> | ||
|
||
|
||
<h4>Code Summary</h4> | ||
<p>This component includes:</p> | ||
<ul class="list-group list-group-flush"> | ||
<li class="list-group-item feature-item"><strong>Category Input Field:</strong> For entering and | ||
submitting new categories.</li> | ||
<li class="list-group-item feature-item"><strong>Category Tags:</strong> Displayed in a container with | ||
each category selectable and removable.</li> | ||
<li class="list-group-item feature-item"><strong>Subcategory Input Field:</strong> Enabled only when a | ||
category is selected.</li> | ||
<li class="list-group-item feature-item"><strong>Subcategory Tags:</strong> Displayed with delete | ||
options and associated with the selected category.</li> | ||
</ul> | ||
|
||
|
||
</div> | ||
</div> | ||
|
||
|
||
|
||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" | ||
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" | ||
crossorigin="anonymous"></script> | ||
<script src="main.js"></script> | ||
</body> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
const addCategoryButton = document.getElementById("addCategoryButton"); | ||
const categoryInput = document.getElementById("categoryInput"); | ||
const categoriesContainer = document.getElementById("categoriesContainer"); | ||
const subCategoryInput = document.getElementById("subCategoryInput"); | ||
const addSubCategoryButton = document.getElementById("addSubCategoryButton"); | ||
const subCategoriesContainer = document.getElementById("subCategoriesContainer"); | ||
const selectedCategoryName = document.getElementById("selectedCategoryName"); | ||
|
||
let categories = {}; // Object to store categories and their sub-categories | ||
let selectedCategory = null; // Track currently selected category | ||
|
||
addCategoryButton.addEventListener("click", addCategory); | ||
addSubCategoryButton.addEventListener("click", addSubCategory); | ||
categoryInput.addEventListener("keypress", (e) => { if (e.key === "Enter") addCategory(); }); | ||
subCategoryInput.addEventListener("keypress", (e) => { if (e.key === "Enter") addSubCategory(); }); | ||
|
||
function addCategory() { | ||
const categoryText = categoryInput.value.trim(); | ||
if (categoryText && !categories[categoryText]) { // Avoid duplicates | ||
categories[categoryText] = ["Others"]; // Initialize with default "Others" sub-category | ||
|
||
const categoryTag = document.createElement("span"); | ||
categoryTag.classList.add("category-tag"); | ||
categoryTag.textContent = categoryText; | ||
|
||
// Cross button for removing category | ||
const removeBtn = document.createElement("span"); | ||
removeBtn.classList.add("remove-btn"); | ||
removeBtn.textContent = "×"; | ||
removeBtn.addEventListener("click", (e) => { | ||
e.stopPropagation(); | ||
confirmCategoryDeletion(categoryText); | ||
}); | ||
categoryTag.appendChild(removeBtn); | ||
|
||
// Click event to select category | ||
categoryTag.addEventListener("click", () => { | ||
document.querySelectorAll(".category-tag").forEach(tag => { | ||
tag.classList.remove("selected"); | ||
}); | ||
categoryTag.classList.add("selected"); | ||
|
||
selectedCategory = categoryText; // Set the selected category | ||
selectedCategoryName.textContent = categoryText; // Display selected category name | ||
|
||
// Enable sub-category input and button | ||
subCategoryInput.disabled = false; | ||
addSubCategoryButton.disabled = false; | ||
|
||
displaySubCategories(); // Show its sub-categories | ||
}); | ||
|
||
categoriesContainer.appendChild(categoryTag); | ||
categoryInput.value = ""; | ||
} | ||
} | ||
|
||
function addSubCategory() { | ||
const subCategoryText = subCategoryInput.value.trim(); | ||
if (subCategoryText && selectedCategory && !categories[selectedCategory].includes(subCategoryText)) { | ||
// Add sub-category to the selected category | ||
categories[selectedCategory].push(subCategoryText); | ||
subCategoryInput.value = ""; | ||
displaySubCategories(); // Refresh sub-categories display | ||
} | ||
} | ||
|
||
function displaySubCategories() { | ||
// Clear the current sub-categories display | ||
subCategoriesContainer.innerHTML = ""; | ||
|
||
// Display sub-categories for the selected category | ||
categories[selectedCategory].forEach(subCategory => { | ||
const subCategoryTag = document.createElement("span"); | ||
subCategoryTag.classList.add("subcategory-tag"); | ||
subCategoryTag.textContent = subCategory; | ||
|
||
// Add "Others" class if it's the default category | ||
if (subCategory === "Others") { | ||
subCategoryTag.classList.add("others-tag"); | ||
} | ||
|
||
// Cross button for removing sub-category | ||
const removeBtn = document.createElement("span"); | ||
removeBtn.classList.add("remove-btn"); | ||
removeBtn.textContent = "×"; | ||
removeBtn.addEventListener("click", () => { | ||
moveToOthers(subCategory); | ||
}); | ||
subCategoryTag.appendChild(removeBtn); | ||
|
||
subCategoriesContainer.appendChild(subCategoryTag); | ||
}); | ||
} | ||
|
||
function confirmCategoryDeletion(category) { | ||
const confirmDelete = confirm(`If you delete the category "${category}", all sub-categories will move to "Others". Are you sure?`); | ||
if (confirmDelete) { | ||
// Move sub-categories to "Others" before deletion | ||
categories["Others"] = (categories["Others"] || []).concat(categories[category].filter(sub => sub !== "Others")); | ||
delete categories[category]; | ||
if (selectedCategory === category) { | ||
selectedCategory = null; // Clear selected category | ||
selectedCategoryName.textContent = ""; // Clear display of selected category name | ||
subCategoryInput.disabled = true; | ||
addSubCategoryButton.disabled = true; | ||
} | ||
categoriesContainer.innerHTML = ""; // Clear all categories | ||
subCategoriesContainer.innerHTML = ""; // Clear sub-categories display | ||
renderCategories(); | ||
} | ||
} | ||
|
||
function moveToOthers(subCategory) { | ||
if (selectedCategory && subCategory !== "Others") { | ||
categories[selectedCategory] = categories[selectedCategory].filter(sub => sub !== subCategory); | ||
if (!categories["Others"]) categories["Others"] = []; | ||
categories["Others"].push(subCategory); | ||
displaySubCategories(); | ||
} | ||
} | ||
|
||
function renderCategories() { | ||
for (const category in categories) { | ||
const categoryTag = document.createElement("span"); | ||
categoryTag.classList.add("category-tag"); | ||
categoryTag.textContent = category; | ||
|
||
// Cross button for each category | ||
const removeBtn = document.createElement("span"); | ||
removeBtn.classList.add("remove-btn"); | ||
removeBtn.textContent = "×"; | ||
removeBtn.addEventListener("click", (e) => { | ||
e.stopPropagation(); | ||
confirmCategoryDeletion(category); | ||
}); | ||
categoryTag.appendChild(removeBtn); | ||
|
||
categoryTag.addEventListener("click", () => { | ||
document.querySelectorAll(".category-tag").forEach(tag => { | ||
tag.classList.remove("selected"); | ||
}); | ||
categoryTag.classList.add("selected"); | ||
selectedCategory = category; | ||
selectedCategoryName.textContent = category; | ||
subCategoryInput.disabled = false; | ||
addSubCategoryButton.disabled = false; | ||
displaySubCategories(); | ||
}); | ||
|
||
categoriesContainer.appendChild(categoryTag); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
.addCategoryComp { | ||
margin: 10px; | ||
padding: 20px; | ||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); | ||
border-radius: 10px; | ||
background-color: #f9f9f9; | ||
} | ||
|
||
.category-tag, | ||
.subcategory-tag { | ||
display: inline-flex; | ||
align-items: center; | ||
padding: 5px 10px; | ||
margin: 5px 5px 0 0; | ||
border-radius: 15px; | ||
font-weight: bold; | ||
font-size: 0.9rem; | ||
cursor: pointer; | ||
background-color: #e7f1ff; | ||
color: #0d6efd; | ||
} | ||
|
||
.category-tag .remove-btn, | ||
.subcategory-tag .remove-btn { | ||
font-weight: bold; | ||
font-size: 0.8rem; | ||
color: #dc3545; | ||
margin-left: 8px; | ||
cursor: pointer; | ||
} | ||
|
||
.category-tag.selected { | ||
background-color: #0d6efd; | ||
color: white; | ||
} | ||
|
||
.subcategory-tag { | ||
background-color: #f1f3f5; | ||
color: #495057; | ||
} | ||
|
||
.others-tag { | ||
font-style: italic; | ||
opacity: 0.8; | ||
} |