@@ -4,7 +4,7 @@ title: Document Analyses
4
4
---
5
5
6
6
<h1 >Document Analyses</h1 >
7
- <p class =" subtitle" >AI-generated summaries for {{ analyses .length }} documents</p >
7
+ <p class =" subtitle" >AI-generated summaries for < span id = " total-count " > {{ analyses .length }} </ span > documents</p >
8
8
9
9
<div class =" search-box" >
10
10
<input type =" text" id =" search" placeholder =" Search analyses..." >
@@ -17,6 +17,22 @@ title: Document Analyses
17
17
{% endfor %}
18
18
</div >
19
19
20
+ <div class =" pagination-controls" >
21
+ <button id =" prev-page" disabled >← Previous</button >
22
+ <span id =" page-info" >Page 1</span >
23
+ <button id =" next-page" >Next →</button >
24
+ <span class =" page-size-selector" >
25
+ Show:
26
+ <select id =" page-size" >
27
+ <option value =" 50" >50</option >
28
+ <option value =" 100" selected >100</option >
29
+ <option value =" 250" >250</option >
30
+ <option value =" 500" >500</option >
31
+ </select >
32
+ per page
33
+ </span >
34
+ </div >
35
+
20
36
<div class =" table-container" >
21
37
<table class =" analyses-table" >
22
38
<thead >
@@ -29,7 +45,7 @@ title: Document Analyses
29
45
</thead >
30
46
<tbody id =" results" >
31
47
{% for item in analyses %}
32
- <tr class =" analysis-row" data-content = " {{ [item.document_number, item.analysis.document_type, item.analysis.summary, item.analysis.significance, item.analysis.key_topics | join(' ')] | join(' ') | lower }} " data- type =" {{ item.analysis.document_type | lower }}" >
48
+ <tr class =" analysis-row" data-type =" {{ item.analysis.document_type | lower }}" >
33
49
<td class =" doc-number" >
34
50
<a href =" /document/{{ item.document_id | slugify }}/" >{{ item .document_number }} </a >
35
51
</td >
@@ -75,6 +91,56 @@ title: Document Analyses
75
91
color : white ;
76
92
}
77
93
94
+ .pagination-controls {
95
+ display : flex ;
96
+ align-items : center ;
97
+ gap : 1rem ;
98
+ margin-bottom : 1.5rem ;
99
+ padding : 1rem ;
100
+ background : white ;
101
+ border : 1px solid #e0e0e0 ;
102
+ border-radius : 6px ;
103
+ }
104
+
105
+ .pagination-controls button {
106
+ padding : 0.5rem 1rem ;
107
+ background : white ;
108
+ border : 1px solid #e0e0e0 ;
109
+ border-radius : 4px ;
110
+ cursor : pointer ;
111
+ font-size : 0.875rem ;
112
+ transition : all 0.2s ;
113
+ }
114
+
115
+ .pagination-controls button :hover:not (:disabled ) {
116
+ border-color : #3498db ;
117
+ color : #3498db ;
118
+ }
119
+
120
+ .pagination-controls button :disabled {
121
+ opacity : 0.5 ;
122
+ cursor : not-allowed ;
123
+ }
124
+
125
+ #page-info {
126
+ font-size : 0.875rem ;
127
+ color : #666 ;
128
+ margin : 0 0.5rem ;
129
+ }
130
+
131
+ .page-size-selector {
132
+ margin-left : auto ;
133
+ font-size : 0.875rem ;
134
+ color : #666 ;
135
+ }
136
+
137
+ .page-size-selector select {
138
+ padding : 0.25rem 0.5rem ;
139
+ border : 1px solid #e0e0e0 ;
140
+ border-radius : 4px ;
141
+ margin : 0 0.5rem ;
142
+ }
143
+
78
144
.table-container {
79
145
overflow-x : auto ;
80
146
background : white ;
@@ -188,7 +254,33 @@ title: Document Analyses
188
254
}
189
255
}
190
256
257
+ @media (max-width : 900px ) {
258
+ .pagination-controls {
259
+ flex-wrap : wrap ;
260
+ }
261
+
262
+ .page-size-selector {
263
+ margin-left : 0 ;
264
+ width : 100% ;
265
+ text-align : center ;
266
+ }
267
+ }
268
+
191
269
@media (max-width : 600px ) {
270
+ .pagination-controls {
271
+ padding : 0.75rem ;
272
+ gap : 0.5rem ;
273
+ }
274
+
275
+ .pagination-controls button {
276
+ font-size : 0.8rem ;
277
+ padding : 0.4rem 0.75rem ;
278
+ }
279
+
280
+ #page-info {
281
+ font-size : 0.75rem ;
282
+ }
283
+
192
284
/* Stack table on mobile */
193
285
.analyses-table thead {
194
286
display : none ;
@@ -251,35 +343,97 @@ title: Document Analyses
251
343
const results = document .getElementById (' results' );
252
344
const allRows = Array .from (results .querySelectorAll (' .analysis-row' ));
253
345
const filterButtons = document .querySelectorAll (' .filter-btn' );
346
+ const prevButton = document .getElementById (' prev-page' );
347
+ const nextButton = document .getElementById (' next-page' );
348
+ const pageInfo = document .getElementById (' page-info' );
349
+ const pageSizeSelect = document .getElementById (' page-size' );
350
+ const totalCount = document .getElementById (' total-count' );
254
351
255
352
let currentFilter = ' all' ;
256
353
let currentSearch = ' ' ;
257
-
258
- // Filter function that applies both type filter and search
259
- function applyFilters () {
260
- allRows .forEach (row => {
354
+ let currentPage = 1 ;
355
+ let pageSize = 100 ;
356
+ let filteredRows = allRows;
357
+
358
+ // Filter and pagination function
359
+ function applyFiltersAndPagination () {
360
+ // First, filter rows based on type and search
361
+ filteredRows = allRows .filter (row => {
261
362
const matchesType = currentFilter === ' all' || row .dataset .type === currentFilter;
262
- const matchesSearch = currentSearch === ' ' || row .dataset .content .includes (currentSearch);
263
- row .style .display = (matchesType && matchesSearch) ? ' ' : ' none' ;
363
+
364
+ let matchesSearch = true ;
365
+ if (currentSearch !== ' ' ) {
366
+ const rowText = row .textContent .toLowerCase ();
367
+ matchesSearch = rowText .includes (currentSearch);
368
+ }
369
+
370
+ return matchesType && matchesSearch;
264
371
});
372
+
373
+ // Update total count
374
+ totalCount .textContent = filteredRows .length ;
375
+
376
+ // Calculate pagination
377
+ const totalPages = Math .ceil (filteredRows .length / pageSize);
378
+ const startIndex = (currentPage - 1 ) * pageSize;
379
+ const endIndex = startIndex + pageSize;
380
+
381
+ // Hide all rows first
382
+ allRows .forEach (row => row .style .display = ' none' );
383
+
384
+ // Show only current page rows
385
+ filteredRows .slice (startIndex, endIndex).forEach (row => {
386
+ row .style .display = ' ' ;
387
+ });
388
+
389
+ // Update pagination controls
390
+ pageInfo .textContent = ` Page ${ currentPage} of ${ totalPages || 1 } (${ filteredRows .length } total)` ;
391
+ prevButton .disabled = currentPage <= 1 ;
392
+ nextButton .disabled = currentPage >= totalPages;
265
393
}
266
394
267
395
// Search handler
268
396
search .addEventListener (' input' , (e ) => {
269
397
currentSearch = e .target .value .toLowerCase ().trim ();
270
- applyFilters ();
398
+ currentPage = 1 ; // Reset to first page on search
399
+ applyFiltersAndPagination ();
271
400
});
272
401
273
402
// Filter button handlers
274
403
filterButtons .forEach (btn => {
275
404
btn .addEventListener (' click' , () => {
276
- // Update active state
277
405
filterButtons .forEach (b => b .classList .remove (' active' ));
278
406
btn .classList .add (' active' );
279
-
280
- // Update filter and apply
281
407
currentFilter = btn .dataset .type ;
282
- applyFilters ();
408
+ currentPage = 1 ; // Reset to first page on filter change
409
+ applyFiltersAndPagination ();
283
410
});
284
411
});
412
+
413
+ // Pagination handlers
414
+ prevButton .addEventListener (' click' , () => {
415
+ if (currentPage > 1 ) {
416
+ currentPage-- ;
417
+ applyFiltersAndPagination ();
418
+ window .scrollTo ({ top: 0 , behavior: ' smooth' });
419
+ }
420
+ });
421
+
422
+ nextButton .addEventListener (' click' , () => {
423
+ const totalPages = Math .ceil (filteredRows .length / pageSize);
424
+ if (currentPage < totalPages) {
425
+ currentPage++ ;
426
+ applyFiltersAndPagination ();
427
+ window .scrollTo ({ top: 0 , behavior: ' smooth' });
428
+ }
429
+ });
430
+
431
+ pageSizeSelect .addEventListener (' change' , (e ) => {
432
+ pageSize = parseInt (e .target .value );
433
+ currentPage = 1 ; // Reset to first page on page size change
434
+ applyFiltersAndPagination ();
435
+ });
436
+
437
+ // Initial render
438
+ applyFiltersAndPagination ();
285
439
</script >
0 commit comments