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/difficultyDropdown.js b/options/difficultyDropdown.js new file mode 100644 index 0000000..4a6c9b0 --- /dev/null +++ b/options/difficultyDropdown.js @@ -0,0 +1,107 @@ +class DifficultyDropdown { + constructor(container, difficulties, onChange) { + this.container = container; + this.difficulties = difficulties; + this.onChange = onChange; + this.selectedDifficulty = 'all'; + this.filteredDifficulties = ['all', ...difficulties]; + this.createDropdown(); + } + + 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'); + 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); + + 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() { + 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() { + const val = this.searchInput.value.toLowerCase(); + this.filteredDifficulties = ['all', ...this.difficulties + .filter(difficulty => difficulty + .toLowerCase() + .includes(val) + )]; + this.renderOptions(); + } + + selectDifficulty(difficulty) { + this.selectedDifficulty = difficulty; + + 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() { + this.list.style.display = this.list.style.display === 'none' ? 'block' : 'none'; + if (this.list.style.display === 'block') { + this.searchInput.value = ''; + this.filterDifficulties(); + this.searchInput.focus(); + } + } + + closeList() { + this.list.style.display = 'none'; + } + + setDifficulty(difficulties) { + this.difficulties = difficulties; + this.filteredDifficulties = ['all', ...difficulties]; + this.renderOptions(); + } +} +window.DifficultyDropdown = DifficultyDropdown; 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; +} diff --git a/options/options.html b/options/options.html index 2a2cae0..86b4f52 100644 --- a/options/options.html +++ b/options/options.html @@ -35,6 +35,7 @@