1- // options.js
2- // Handles navigation and basic filtering for the options page
3-
41document . addEventListener ( 'DOMContentLoaded' , ( ) => {
52 // Sidebar navigation
63 const navItems = document . querySelectorAll ( '.nav-item' ) ;
@@ -16,12 +13,15 @@ document.addEventListener('DOMContentLoaded', () => {
1613 } ) ;
1714 } ) ;
1815
16+ const sortDropdown = document . getElementById ( 'sortDropdown' ) ;
17+
1918 // All Problems: load and render problems
2019 const problemsList = document . getElementById ( 'problemsList' ) ;
2120 const searchInput = document . getElementById ( 'searchInput' ) ;
22- const tagFilter = document . getElementById ( 'tagFilter' ) ;
21+ const tagDropdownContainer = document . getElementById ( 'tagDropdownContainer' ) ;
22+ let tagDropdownInstance = null ;
2323
24- function renderProblems ( problems , filterTag , searchTerm ) {
24+ function renderProblems ( problems , filterTag , searchTerm , sortOrder = 'recent-desc' ) {
2525 problemsList . innerHTML = '' ;
2626 let filtered = problems ;
2727 if ( filterTag && filterTag !== 'all' ) {
@@ -30,31 +30,33 @@ document.addEventListener('DOMContentLoaded', () => {
3030 if ( searchTerm ) {
3131 filtered = filtered . filter ( p => p . title . toLowerCase ( ) . includes ( searchTerm . toLowerCase ( ) ) ) ;
3232 }
33+ // Sorting
34+ if ( sortOrder === 'recent-desc' ) {
35+ filtered . sort ( ( a , b ) => ( b . solvedAt || 0 ) - ( a . solvedAt || 0 ) ) ;
36+ } else if ( sortOrder === 'recent-asc' ) {
37+ filtered . sort ( ( a , b ) => ( a . solvedAt || 0 ) - ( b . solvedAt || 0 ) ) ;
38+ }
3339 if ( filtered . length === 0 ) {
3440 problemsList . innerHTML = '<p>No problems found.</p>' ;
3541 }
3642 filtered . forEach ( problem => {
3743 const item = document . createElement ( 'div' ) ;
3844 item . className = 'problem-item' ;
3945 const difficultyClass = problem . difficulty ? problem . difficulty . toLowerCase ( ) : '' ;
40- // Use DOM methods instead of innerHTML for safety
4146 const link = document . createElement ( 'a' ) ;
4247 link . href = problem . url ;
4348 link . target = '_blank' ;
4449 link . textContent = problem . title ;
45-
4650 const diffSpan = document . createElement ( 'span' ) ;
4751 diffSpan . className = `difficulty ${ difficultyClass } ` ;
4852 diffSpan . textContent = problem . difficulty ;
49-
5053 const tagsSpan = document . createElement ( 'span' ) ;
5154 tagsSpan . style . fontSize = '0.85em' ;
5255 tagsSpan . style . color = problem . tags && problem . tags . length > 0 ? '#666' : '#bbb' ;
5356 tagsSpan . style . marginLeft = '8px' ;
5457 tagsSpan . textContent = problem . tags && problem . tags . length > 0
5558 ? `[${ problem . tags . join ( ', ' ) } ]`
5659 : '[No tags]' ;
57-
5860 item . appendChild ( link ) ;
5961 item . appendChild ( diffSpan ) ;
6062 item . appendChild ( tagsSpan ) ;
@@ -78,21 +80,31 @@ document.addEventListener('DOMContentLoaded', () => {
7880 p . tags . forEach ( tag => tagSet . add ( tag ) ) ;
7981 }
8082 } ) ;
81- tagFilter . innerHTML = '<option value="all">All Tags</option>' ;
82- Array . from ( tagSet ) . forEach ( tag => {
83- const opt = document . createElement ( 'option' ) ;
84- opt . value = tag ;
85- opt . textContent = tag ;
86- tagFilter . appendChild ( opt ) ;
87- } ) ;
83+ const allTags = Array . from ( tagSet ) . sort ( ( a , b ) => a . localeCompare ( b ) ) ;
84+ let currentProblems = problems ; // Store for re-sorting/filtering
85+ function rerender ( ) {
86+ renderProblems (
87+ currentProblems ,
88+ tagDropdownInstance ? tagDropdownInstance . selectedTag : 'all' ,
89+ searchInput . value ,
90+ sortDropdown . value
91+ ) ;
92+ }
93+ if ( tagDropdownInstance ) {
94+ tagDropdownInstance . setTags ( allTags ) ;
95+ } else {
96+ tagDropdownInstance = new window . TagDropdown ( tagDropdownContainer , allTags , ( ) => rerender ( ) ) ;
97+ }
8898 // Initial render
89- renderProblems ( problems , tagFilter . value , searchInput . value ) ;
99+ rerender ( ) ;
90100 // Event listeners
91- tagFilter . addEventListener ( 'change' , ( ) => {
92- renderProblems ( problems , tagFilter . value , searchInput . value ) ;
93- } ) ;
94- searchInput . addEventListener ( 'input' , ( ) => {
95- renderProblems ( problems , tagFilter . value , searchInput . value ) ;
96- } ) ;
101+ searchInput . addEventListener ( 'input' , rerender ) ;
102+ sortDropdown . addEventListener ( 'change' , rerender ) ;
103+
104+ const extVersionElem = document . getElementById ( 'extVersion' ) ;
105+ if ( extVersionElem && browser . runtime . getManifest ) {
106+ const manifest = browser . runtime . getManifest ( ) ;
107+ extVersionElem . textContent = manifest . version ;
108+ }
97109 } ) ;
98110} ) ;
0 commit comments