From 6816d7547699ac63a34aab2eb6c6ae3b3200830e Mon Sep 17 00:00:00 2001 From: Dominion Gbadamosi Date: Thu, 12 Jun 2025 14:16:35 +0100 Subject: [PATCH 01/13] add: added the class constructor for the difficulty dropdown component --- options/difficulyDropdown.js | 9 +++++++++ options/options.html | 1 + 2 files changed, 10 insertions(+) create mode 100644 options/difficulyDropdown.js diff --git a/options/difficulyDropdown.js b/options/difficulyDropdown.js new file mode 100644 index 0000000..8dc662f --- /dev/null +++ b/options/difficulyDropdown.js @@ -0,0 +1,9 @@ +class DifficultyDropdown { + constructor(container, difficulties, onChange) { + this.container = container; + this.difficulties = difficulties; + this.onChange = onChange; + this.selectedDifficulty = 'all'; + this.filteredDifficulties = ['all', ...difficulties]; + } +} \ No newline at end of file diff --git a/options/options.html b/options/options.html index 2a2cae0..67e12de 100644 --- a/options/options.html +++ b/options/options.html @@ -35,6 +35,7 @@

All Solved Problems

+
From e32aebfc2b0ef27f85157e0eeb0d82058bf631c2 Mon Sep 17 00:00:00 2001 From: Dominion Gbadamosi Date: Fri, 13 Jun 2025 07:46:33 +0100 Subject: [PATCH 02/13] add: progress made on difficulty dropdown class --- options/difficulyDropdown.js | 54 +++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/options/difficulyDropdown.js b/options/difficulyDropdown.js index 8dc662f..db23429 100644 --- a/options/difficulyDropdown.js +++ b/options/difficulyDropdown.js @@ -5,5 +5,57 @@ class DifficultyDropdown { this.onChange = onChange; this.selectedDifficulty = 'all'; this.filteredDifficulties = ['all', ...difficulties]; + this.createDropdown(); } -} \ No newline at end of file + + createDropdown() { + this.container.innerHTML = ''; + this.dropdown = document.createElement('div'); + this.dropdown.className = 'difficulty-dropdown'; + + this.selected = document.createElement('div'); + this.selected.className = 'difficulty-dropdown-selected'; + this.selected.tabIndex = 0; + + const selectedText = document.createElement('span'); + selectedText.className = 'difficulty-dropdown-selected-text'; + selectedText.textContent = 'All Difficulties'; + this.selected.appendChild(selectedText); + const chevron = document.createElement('i'); + chevron.className = 'ri-arrow-down-s-line difficulty-dropdown-chevron' + this.selected.appendChild(chevron); + this.selected.addEventListener('click', () => this.toggleList()); + this.selected.addEventListener('keydown', (e) => { + if (e.key == 'Enter' || e.key == ' ') this.toggleList(); + }); + this.dropdown.appendChild(this.selected); + + this.list = document.createElement('div'); + } + + renderOptions() { + // TODO: Finish function + } + + filterDifficulties() { + // TODO: Finish function + } + + selectDifficulty(tag) { + // TODO: Finish function + } + + toggleList() { + // TODO: Finish function + } + + closeList() { + + } + + selectDifficulty() { + + } + +} +window.DifficultyDropdown = DifficultyDropdown; \ No newline at end of file From e5a3fdc647394a168019c9bb814425b1e4bc54e7 Mon Sep 17 00:00:00 2001 From: Dominion Gbadamosi Date: Fri, 13 Jun 2025 11:36:09 +0100 Subject: [PATCH 03/13] add: finished createDropdown function - need to finish implementation of all the other functions --- options/difficulyDropdown.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/options/difficulyDropdown.js b/options/difficulyDropdown.js index db23429..a0c8506 100644 --- a/options/difficulyDropdown.js +++ b/options/difficulyDropdown.js @@ -31,10 +31,24 @@ class DifficultyDropdown { this.dropdown.appendChild(this.selected); this.list = document.createElement('div'); + this.list.className = 'difficulty-dropdown-list' + this.list.style.display = 'none' + + this.optionsContainer = document.createElement('div'); + this.optionsContainer.className = 'difficulty-dropdown-options'; + this.list.appendChild(this.optionsContainer); + + this.dropdown.appendChild(this.list); + this.container.appendChild(this.dropdown); + + this.renderOptions(); + document.addEventListener('click', (e) => { + if (!this.dropdown.contains(e.target)) this.closeList(); + }); } renderOptions() { - // TODO: Finish function + } filterDifficulties() { From 2037981aae903241e5bda3bdc647cf2512863490 Mon Sep 17 00:00:00 2001 From: Dominion Gbadamosi Date: Fri, 13 Jun 2025 11:48:56 +0100 Subject: [PATCH 04/13] add: added renderOptions function and filterDifficulties functions --- options/difficulyDropdown.js | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/options/difficulyDropdown.js b/options/difficulyDropdown.js index a0c8506..0aa8f42 100644 --- a/options/difficulyDropdown.js +++ b/options/difficulyDropdown.js @@ -34,6 +34,13 @@ class DifficultyDropdown { this.list.className = 'difficulty-dropdown-list' this.list.style.display = 'none' + this.searchInput = document.createElement('input'); + this.searchInput.type = 'text'; + this.searchInput.className = 'difficulty-dropdown-search'; + this.searchInput.placeholder = 'Search Difficulties...'; + this.searchInput.addEventListener('input', () => this.filterDifficulties()); + this.list.appendChild(this.searchInput); + this.optionsContainer = document.createElement('div'); this.optionsContainer.className = 'difficulty-dropdown-options'; this.list.appendChild(this.optionsContainer); @@ -48,14 +55,28 @@ class DifficultyDropdown { } renderOptions() { - + this.optionsContainer.innerHTML = ''; + this.filteredDifficulties.forEach(difficulty => { + const opt = document.createElement('div'); + opt.className = 'difficulty-dropdown-option'; + opt.textContent = difficulty === 'all' ? 'All Difficulties' : difficulty; + if (difficulty === this.selectedDifficulty) opt.classList.add('selected'); + opt.addEventListener('click', () => this.selectDifficulty(difficulty)); + this.optionsContainer.appendChild(opt); + }); } filterDifficulties() { - // TODO: Finish function + const val = this.searchInput.value.toLowerCase(); + this.filteredDifficulties = ['all', ...this.difficulties + .filter(difficulty => difficulty + .toLowerCase() + .includes(val) + )]; + this.renderOptions(); } - selectDifficulty(tag) { + selectDifficulty(difficulty) { // TODO: Finish function } From d9a3cfc3ce18bd18a67547e4f3418eba95a4efc6 Mon Sep 17 00:00:00 2001 From: Dominion Gbadamosi Date: Fri, 13 Jun 2025 11:57:22 +0100 Subject: [PATCH 05/13] add: completed selectDifficulty function --- options/difficulyDropdown.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/options/difficulyDropdown.js b/options/difficulyDropdown.js index 0aa8f42..a5d8496 100644 --- a/options/difficulyDropdown.js +++ b/options/difficulyDropdown.js @@ -77,11 +77,15 @@ class DifficultyDropdown { } selectDifficulty(difficulty) { - // TODO: Finish function + this.selectedDifficulty = difficulty; + + const textSpan = this.selected.querySelector('.difficulty-dropdown-selected-text'); + if (textSpan) textSpan.textContent = difficulty === 'all' ? 'All Difficulties' : difficulty; + this.closeList(); } toggleList() { - // TODO: Finish function + } closeList() { @@ -93,4 +97,4 @@ class DifficultyDropdown { } } -window.DifficultyDropdown = DifficultyDropdown; \ No newline at end of file +window.DifficultyDropdown = DifficultyDropdown; From 31bd06834560d0e076fa6fb396bc299847266deb Mon Sep 17 00:00:00 2001 From: Dominion Gbadamosi Date: Fri, 13 Jun 2025 12:03:54 +0100 Subject: [PATCH 06/13] add completed closeList, setDifficulty --- options/difficulyDropdown.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/options/difficulyDropdown.js b/options/difficulyDropdown.js index a5d8496..42234ee 100644 --- a/options/difficulyDropdown.js +++ b/options/difficulyDropdown.js @@ -85,16 +85,22 @@ class DifficultyDropdown { } toggleList() { - + this.list.style.display = this.list.style.display === 'none' ? 'block' : 'none'; + if (this.list.style.display === 'block') { + this.searchInput.value = ''; + this.filterTags(); + this.searchInput.focus(); + } } closeList() { - + this.list.style.display = 'none'; } - selectDifficulty() { - + setDifficulty(difficulties) { + this.difficulties = difficulties; + this.filterDifficulties = ['all', ...difficulties]; + this.renderOptions(); } - } window.DifficultyDropdown = DifficultyDropdown; From b287e7cc93aaab435a87c52568cd9eed3b61c580 Mon Sep 17 00:00:00 2001 From: Dominion Gbadamosi Date: Fri, 13 Jun 2025 12:07:31 +0100 Subject: [PATCH 07/13] fix: was not calling onCHange for difficulties in the selectDifficulty function --- options/difficulyDropdown.js | 1 + 1 file changed, 1 insertion(+) diff --git a/options/difficulyDropdown.js b/options/difficulyDropdown.js index 42234ee..e012291 100644 --- a/options/difficulyDropdown.js +++ b/options/difficulyDropdown.js @@ -82,6 +82,7 @@ class DifficultyDropdown { const textSpan = this.selected.querySelector('.difficulty-dropdown-selected-text'); if (textSpan) textSpan.textContent = difficulty === 'all' ? 'All Difficulties' : difficulty; this.closeList(); + if (this.onChange) this.onChange(difficulty); } toggleList() { From 5d76533413eb8eaaa35dea65b57ce7f3fcfcdf7f Mon Sep 17 00:00:00 2001 From: Dominion Gbadamosi Date: Fri, 13 Jun 2025 12:08:15 +0100 Subject: [PATCH 08/13] fix: fixed typo in toggleList function --- options/difficulyDropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/difficulyDropdown.js b/options/difficulyDropdown.js index e012291..8a70f20 100644 --- a/options/difficulyDropdown.js +++ b/options/difficulyDropdown.js @@ -89,7 +89,7 @@ class DifficultyDropdown { this.list.style.display = this.list.style.display === 'none' ? 'block' : 'none'; if (this.list.style.display === 'block') { this.searchInput.value = ''; - this.filterTags(); + this.filterDifficulties(); this.searchInput.focus(); } } From b5610f1ebe7eda197f35df97903f0f5226be8d57 Mon Sep 17 00:00:00 2001 From: Dominion Gbadamosi Date: Fri, 13 Jun 2025 12:09:23 +0100 Subject: [PATCH 09/13] fix: fixed typo in the setDifficulty function --- options/difficulyDropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/difficulyDropdown.js b/options/difficulyDropdown.js index 8a70f20..4a6c9b0 100644 --- a/options/difficulyDropdown.js +++ b/options/difficulyDropdown.js @@ -100,7 +100,7 @@ class DifficultyDropdown { setDifficulty(difficulties) { this.difficulties = difficulties; - this.filterDifficulties = ['all', ...difficulties]; + this.filteredDifficulties = ['all', ...difficulties]; this.renderOptions(); } } From c9b0027face145e800bb69f28b056a3bb519628c Mon Sep 17 00:00:00 2001 From: Dominion Gbadamosi Date: Fri, 13 Jun 2025 12:11:11 +0100 Subject: [PATCH 10/13] fix: fixed incorrect file name difficultyDropdown.js was named difficulyDropdown.js --- options/{difficulyDropdown.js => difficultyDropdown.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename options/{difficulyDropdown.js => difficultyDropdown.js} (100%) diff --git a/options/difficulyDropdown.js b/options/difficultyDropdown.js similarity index 100% rename from options/difficulyDropdown.js rename to options/difficultyDropdown.js From 984bb2c30ad99a143a33165673d245e8f04a2151 Mon Sep 17 00:00:00 2001 From: Dominion Gbadamosi Date: Fri, 13 Jun 2025 12:12:51 +0100 Subject: [PATCH 11/13] added difficultyDropdown script to options.html --- options/options.html | 1 + 1 file changed, 1 insertion(+) diff --git a/options/options.html b/options/options.html index 67e12de..86b4f52 100644 --- a/options/options.html +++ b/options/options.html @@ -65,6 +65,7 @@

FAQ / About

+ From 324c35be971f47ac1d9d7dce22adf06a55a1a948 Mon Sep 17 00:00:00 2001 From: Dominion Gbadamosi Date: Fri, 13 Jun 2025 12:21:13 +0100 Subject: [PATCH 12/13] add: integrated DifficultyDropdown class into options.js --- options/options.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/options/options.js b/options/options.js index eaa0c25..90628ed 100644 --- a/options/options.js +++ b/options/options.js @@ -20,6 +20,8 @@ document.addEventListener('DOMContentLoaded', () => { const searchInput = document.getElementById('searchInput'); const tagDropdownContainer = document.getElementById('tagDropdownContainer'); let tagDropdownInstance = null; + const difficultyDropdownContainer = document.getElementById('difficultyDropdownContainer'); + let difficultyDropdownInstance = null; function renderProblems(problems, filterTag, searchTerm, sortOrder = 'recent-desc') { problemsList.innerHTML = ''; @@ -27,6 +29,11 @@ document.addEventListener('DOMContentLoaded', () => { if (filterTag && filterTag !== 'all') { filtered = filtered.filter(p => Array.isArray(p.tags) && p.tags.includes(filterTag)); } + + if (filterDifficulty && filterDifficulty == 'all') { + filtered = filtered.filter(p => difficulty === filterDifficulty); + } + if (searchTerm) { filtered = filtered.filter(p => p.title.toLowerCase().includes(searchTerm.toLowerCase())); } @@ -81,20 +88,30 @@ document.addEventListener('DOMContentLoaded', () => { } }); const allTags = Array.from(tagSet).sort((a, b) => a.localeCompare(b)); - let currentProblems = problems; // Store for re-sorting/filtering + const allDifficulties = ['Easy', 'Medium', 'Hard']; + let currentProblems = problems; function rerender() { renderProblems( currentProblems, tagDropdownInstance ? tagDropdownInstance.selectedTag : 'all', + difficultyDropdownInstance ? difficultyDropdownInstance.selectedDifficulty : 'all', searchInput.value, sortDropdown.value ); } + if (tagDropdownInstance) { tagDropdownInstance.setTags(allTags); } else { tagDropdownInstance = new window.TagDropdown(tagDropdownContainer, allTags, () => rerender()); } + + if (difficultyDropdownInstance) { + difficultyDropdownInstance.setDifficulty(allDifficulties); + } else { + difficultyDropdownInstance = new window.DifficultyDropdown(difficultyDropdownContainer, allDifficulties, () => rerender()); + } + // Initial render rerender(); // Event listeners From 24583537f2aded3b168950f1355804eb6291222a Mon Sep 17 00:00:00 2001 From: Dominion Gbadamosi Date: Fri, 13 Jun 2025 12:27:13 +0100 Subject: [PATCH 13/13] updated version, css for difficulty filter --- content.js | 3 -- manifest.json | 4 +-- options/options.css | 67 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/content.js b/content.js index 3a47e21..881daf7 100644 --- a/content.js +++ b/content.js @@ -1,6 +1,3 @@ -// Import fetchLeetCodeTags from leetcodeApi.js -// (Assumes leetcodeApi.js is loaded before this script as per manifest) - async function getProblemData() { const titleEl = document.querySelector('div[class*="text-title-large"]'); const title = titleEl ? titleEl.textContent.trim() : "Unknown Title"; diff --git a/manifest.json b/manifest.json index 51d2c1f..466bbbc 100644 --- a/manifest.json +++ b/manifest.json @@ -1,8 +1,8 @@ { "manifest_version": 2, "name": "KeepCode", - "version": "0.3.0", - "description": "Prep smarter for coding interviews: KeepCode tracks your LeetCode progress so you can focus on solving.", + "version": "0.3.5", + "description": "Prep smarter for coding interviews! KeepCode tracks your LeetCode progress so you can focus on solving.", "permissions": ["storage", "tabs", "activeTab", "https://leetcode.com/*"], "background": { "scripts": ["background.js"], diff --git a/options/options.css b/options/options.css index 2d6c4ec..92129e7 100644 --- a/options/options.css +++ b/options/options.css @@ -274,3 +274,70 @@ a:hover { outline: none; border-color: #8868bd; } + +/* Difficulty Dropdown Styles (to match Tag Dropdown) */ +.difficulty-dropdown, +.difficulty-dropdown-selected, +.difficulty-dropdown-list { + position: relative; + font-size: 1em; +} +.difficulty-dropdown-selected { + background: #fff; + border: 1px solid #d1d5db; + border-radius: 5px; + padding: 7px 12px; + cursor: pointer; + user-select: none; + min-width: 120px; + transition: border-color 0.15s; +} +.difficulty-dropdown-selected:focus { + outline: none; + border-color: #8868bd; +} +.difficulty-dropdown-list { + position: absolute; + top: 110%; + left: 0; + right: 0; + background: #fff; + border: 1px solid #d1d5db; + border-radius: 5px; + box-shadow: 0 2px 8px rgba(0,0,0,0.08); + z-index: 10; + padding: 0; +} +.difficulty-dropdown-search { + width: 100%; + margin: 0; + border-radius: 5px 5px 0 0; + border-bottom: 1px solid #e5e7eb; + border-top: none; + border-left: none; + border-right: none; + box-sizing: border-box; + padding: 10px 12px; + font-size: 1em; + background: #fafbfc; +} +.difficulty-dropdown-options { + max-height: 180px; + overflow-y: auto; + padding-top: 4px; +} +.difficulty-dropdown-list { + border-radius: 5px; + overflow: hidden; +} +.difficulty-dropdown-option { + padding: 7px 16px; + cursor: pointer; + transition: background 0.13s; + color: #374151; +} +.difficulty-dropdown-option.selected, +.difficulty-dropdown-option:hover { + background: #f3f4f6; + color: #8868bd; +}