Skip to content

Commit

Permalink
Category Management Component
Browse files Browse the repository at this point in the history
  • Loading branch information
shehanm95 committed Nov 13, 2024
0 parents commit d7b4fbe
Show file tree
Hide file tree
Showing 4 changed files with 308 additions and 0 deletions.
26 changes: 26 additions & 0 deletions description.css
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);
}
84 changes: 84 additions & 0 deletions index.html
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>
153 changes: 153 additions & 0 deletions main.js
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);
}
}
45 changes: 45 additions & 0 deletions style.css
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;
}

0 comments on commit d7b4fbe

Please sign in to comment.