@keenmate/pure-admin-core 1.0.0-rc01

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +172 -0
  3. package/dist/css/main.css +11542 -0
  4. package/dist/fonts/Delivery/Delivery_W_Bd.woff2 +0 -0
  5. package/dist/fonts/Delivery/Delivery_W_BdIt.woff2 +0 -0
  6. package/dist/fonts/Delivery/Delivery_W_CdBlk.woff2 +0 -0
  7. package/dist/fonts/Delivery/Delivery_W_CdLt.woff2 +0 -0
  8. package/dist/fonts/Delivery/Delivery_W_It.woff2 +0 -0
  9. package/dist/fonts/Delivery/Delivery_W_Lt.woff2 +0 -0
  10. package/dist/fonts/Delivery/Delivery_W_LtIt.woff2 +0 -0
  11. package/dist/fonts/Delivery/Delivery_W_Rg.woff2 +0 -0
  12. package/dist/fonts/google/3y976aknfjLm_3lMKjiMgmUUYBs04Y8UH-qVHQ.woff2 +0 -0
  13. package/dist/fonts/google/3y976aknfjLm_3lMKjiMgmUUYBs04Y8UH-qVHQ.woff2.1 +0 -0
  14. package/dist/fonts/google/3y976aknfjLm_3lMKjiMgmUUYBs04Y8UH-qVHQ.woff2.2 +0 -0
  15. package/dist/fonts/google/3y976aknfjLm_3lMKjiMgmUUYBs04Y8VH-qVHQ.woff2 +0 -0
  16. package/dist/fonts/google/3y976aknfjLm_3lMKjiMgmUUYBs04Y8VH-qVHQ.woff2.1 +0 -0
  17. package/dist/fonts/google/3y976aknfjLm_3lMKjiMgmUUYBs04Y8VH-qVHQ.woff2.2 +0 -0
  18. package/dist/fonts/google/3y976aknfjLm_3lMKjiMgmUUYBs04Y8bH-o.woff2 +0 -0
  19. package/dist/fonts/google/3y976aknfjLm_3lMKjiMgmUUYBs04Y8bH-o.woff2.1 +0 -0
  20. package/dist/fonts/google/3y976aknfjLm_3lMKjiMgmUUYBs04Y8fH-qVHQ.woff2 +0 -0
  21. package/dist/fonts/google/3y976aknfjLm_3lMKjiMgmUUYBs04Y8fH-qVHQ.woff2.1 +0 -0
  22. package/dist/fonts/google/3y976aknfjLm_3lMKjiMgmUUYBs04Y8fH-qVHQ.woff2.2 +0 -0
  23. package/dist/fonts/google/6aez4K2oVqwIvtE2H68T.woff2 +0 -0
  24. package/dist/fonts/google/6aez4K2oVqwIvtU2Hw.woff2 +0 -0
  25. package/dist/fonts/google/6aez4K2oVqwIvtY2H68T.woff2 +0 -0
  26. package/dist/fonts/google/6aez4K2oVqwIvtg2H68T.woff2 +0 -0
  27. package/dist/fonts/google/6aez4K2oVqwIvto2H68T.woff2 +0 -0
  28. package/dist/fonts/google/6aez4K2oVqwIvts2H68T.woff2 +0 -0
  29. package/dist/fonts/google/7Auup_AqnyWWAxW2Wk3swUz56MS91Eww8SX21nejog.woff2 +0 -0
  30. package/dist/fonts/google/7Auup_AqnyWWAxW2Wk3swUz56MS91Eww8SX21nijogp5.woff2 +0 -0
  31. package/dist/fonts/google/7Auup_AqnyWWAxW2Wk3swUz56MS91Eww8SX21nmjogp5.woff2 +0 -0
  32. package/dist/fonts/google/PN_xRfK9oXHga0XdZ8g_vT0.woff2 +0 -0
  33. package/dist/fonts/google/PN_xRfK9oXHga0XdZsg_.woff2 +0 -0
  34. package/dist/fonts/google/PN_xRfK9oXHga0XdaMg_vT0.woff2 +0 -0
  35. package/dist/fonts/google/TK3tWkYFABsmjsphPho.woff2 +0 -0
  36. package/dist/fonts/google/TK3tWkYFABsmjspuPho7vA.woff2 +0 -0
  37. package/dist/fonts/google/TK3tWkYFABsmjspvPho7vA.woff2 +0 -0
  38. package/dist/fonts/google/dg45_pLmvrkcOkBnKsOzXyGWTBcmg-X6VjTYJwQj.woff2 +0 -0
  39. package/dist/fonts/google/dg45_pLmvrkcOkBnKsOzXyGWTBcmg-X6VjXYJwQj.woff2 +0 -0
  40. package/dist/fonts/google/dg45_pLmvrkcOkBnKsOzXyGWTBcmg-X6Vj_YJwQj.woff2 +0 -0
  41. package/dist/fonts/google/dg45_pLmvrkcOkBnKsOzXyGWTBcmg-X6VjbYJwQj.woff2 +0 -0
  42. package/dist/fonts/google/dg45_pLmvrkcOkBnKsOzXyGWTBcmg-X6VjvYJw.woff2 +0 -0
  43. package/dist/fonts/google/fonts-tracklist.txt +48 -0
  44. package/dist/fonts/google/vEFO2_JTCgwQ5ejvMV0O96D01E8J0tJXHKbBjM4.woff2 +0 -0
  45. package/dist/fonts/google/vEFO2_JTCgwQ5ejvMV0O96D01E8J0tJXHKbOjM7sfA.woff2 +0 -0
  46. package/dist/fonts/google/vEFO2_JTCgwQ5ejvMV0O96D01E8J0tJXHKbPjM7sfA.woff2 +0 -0
  47. package/dist/fonts/google/wEOhEADFm8hSaQTFG18FErVhsC9x-tarUfLtrftV.woff2 +0 -0
  48. package/dist/fonts/google/wEOhEADFm8hSaQTFG18FErVhsC9x-tarUfXtrftV.woff2 +0 -0
  49. package/dist/fonts/google/wEOhEADFm8hSaQTFG18FErVhsC9x-tarUfbtrQ.woff2 +0 -0
  50. package/dist/fonts/google/wEOhEADFm8hSaQTFG18FErVhsC9x-tarUfjtrftV.woff2 +0 -0
  51. package/dist/fonts/google/wEOhEADFm8hSaQTFG18FErVhsC9x-tarUfntrftV.woff2 +0 -0
  52. package/dist/fonts/google/wEOhEADFm8hSaQTFG18FErVhsC9x-tarUfrtrftV.woff2 +0 -0
  53. package/dist/fonts/google/wEOhEADFm8hSaQTFG18FErVhsC9x-tarUfvtrftV.woff2 +0 -0
  54. package/dist/fonts/google/xn7_YHE41ni1AdIRqAuZuw1Bx9mbZk79FN_B-bnBeA.woff2 +0 -0
  55. package/dist/fonts/google/xn7_YHE41ni1AdIRqAuZuw1Bx9mbZk79FN_C-bk.woff2 +0 -0
  56. package/dist/fonts/google/xn7_YHE41ni1AdIRqAuZuw1Bx9mbZk79FN_G-bnBeA.woff2 +0 -0
  57. package/dist/fonts/google/xn7_YHE41ni1AdIRqAuZuw1Bx9mbZk79FN_M-bnBeA.woff2 +0 -0
  58. package/dist/fonts/google/xn7_YHE41ni1AdIRqAuZuw1Bx9mbZk79FN_N-bnBeA.woff2 +0 -0
  59. package/dist/fonts/google/xn7_YHE41ni1AdIRqAuZuw1Bx9mbZk79FN_P-bnBeA.woff2 +0 -0
  60. package/package.json +60 -0
  61. package/snippets/alerts.html +281 -0
  62. package/snippets/badges.html +212 -0
  63. package/snippets/buttons.html +287 -0
  64. package/snippets/cards.html +393 -0
  65. package/snippets/checkbox-lists.html +490 -0
  66. package/snippets/code.html +225 -0
  67. package/snippets/command-palette.html +210 -0
  68. package/snippets/comparison.html +428 -0
  69. package/snippets/customization.html +142 -0
  70. package/snippets/forms.html +477 -0
  71. package/snippets/grid.html +338 -0
  72. package/snippets/layout.html +598 -0
  73. package/snippets/lists.html +232 -0
  74. package/snippets/loaders.html +183 -0
  75. package/snippets/manifest.json +388 -0
  76. package/snippets/modal-dialogs.html +411 -0
  77. package/snippets/modals.html +310 -0
  78. package/snippets/popconfirm.html +253 -0
  79. package/snippets/profile.html +264 -0
  80. package/snippets/tables.html +317 -0
  81. package/snippets/tabs.html +930 -0
  82. package/snippets/timeline.html +364 -0
  83. package/snippets/toasts.html +154 -0
  84. package/snippets/tooltips.html +411 -0
  85. package/snippets/typography.html +101 -0
  86. package/snippets/utilities.html +595 -0
  87. package/snippets/virtual-scroll.html +322 -0
  88. package/snippets/web-daterangepicker.html +634 -0
  89. package/snippets/web-multiselect.html +362 -0
  90. package/src/scss/.claude/settings.local.json +11 -0
  91. package/src/scss/_base-css-variables.scss +348 -0
  92. package/src/scss/_core.scss +99 -0
  93. package/src/scss/_fonts.scss +67 -0
  94. package/src/scss/_purecss-grid-responsive.scss +138 -0
  95. package/src/scss/_purecss-grid.scss +58 -0
  96. package/src/scss/_variables.scss +14 -0
  97. package/src/scss/core-components/_alerts.scss +212 -0
  98. package/src/scss/core-components/_badges.scss +16 -0
  99. package/src/scss/core-components/_base.scss +124 -0
  100. package/src/scss/core-components/_buttons.scss +473 -0
  101. package/src/scss/core-components/_cards.scss +285 -0
  102. package/src/scss/core-components/_checkbox-lists.scss +289 -0
  103. package/src/scss/core-components/_code.scss +141 -0
  104. package/src/scss/core-components/_command-palette.scss +518 -0
  105. package/src/scss/core-components/_comparison.scss +172 -0
  106. package/src/scss/core-components/_file-selector.scss +780 -0
  107. package/src/scss/core-components/_forms.scss +16 -0
  108. package/src/scss/core-components/_grid.scss +264 -0
  109. package/src/scss/core-components/_layout.scss +15 -0
  110. package/src/scss/core-components/_lists.scss +211 -0
  111. package/src/scss/core-components/_loaders.scss +277 -0
  112. package/src/scss/core-components/_logic-tree.scss +280 -0
  113. package/src/scss/core-components/_modals.scss +209 -0
  114. package/src/scss/core-components/_notifications.scss +253 -0
  115. package/src/scss/core-components/_pagers.scss +141 -0
  116. package/src/scss/core-components/_popconfirm.scss +170 -0
  117. package/src/scss/core-components/_profile.scss +281 -0
  118. package/src/scss/core-components/_settings-panel.scss +128 -0
  119. package/src/scss/core-components/_statistics.scss +200 -0
  120. package/src/scss/core-components/_tables.scss +555 -0
  121. package/src/scss/core-components/_tabs.scss +438 -0
  122. package/src/scss/core-components/_timeline.scss +589 -0
  123. package/src/scss/core-components/_toasts.scss +281 -0
  124. package/src/scss/core-components/_tooltips.scss +503 -0
  125. package/src/scss/core-components/_utilities.scss +241 -0
  126. package/src/scss/core-components/_web-components-theme.scss +294 -0
  127. package/src/scss/core-components/badges/_badge-base.scss +131 -0
  128. package/src/scss/core-components/badges/_badge-group.scss +25 -0
  129. package/src/scss/core-components/badges/_composite-badge-variants.scss +396 -0
  130. package/src/scss/core-components/badges/_composite-badge.scss +70 -0
  131. package/src/scss/core-components/badges/_index.scss +10 -0
  132. package/src/scss/core-components/badges/_labels.scss +155 -0
  133. package/src/scss/core-components/forms/_checkboxes-radios.scss +205 -0
  134. package/src/scss/core-components/forms/_form-inputs.scss +100 -0
  135. package/src/scss/core-components/forms/_form-layout.scss +66 -0
  136. package/src/scss/core-components/forms/_form-states.scss +89 -0
  137. package/src/scss/core-components/forms/_index.scss +12 -0
  138. package/src/scss/core-components/forms/_input-groups.scss +149 -0
  139. package/src/scss/core-components/forms/_input-wrapper.scss +89 -0
  140. package/src/scss/core-components/forms/_query-editor.scss +313 -0
  141. package/src/scss/core-components/layout/_index.scss +11 -0
  142. package/src/scss/core-components/layout/_layout-container.scss +105 -0
  143. package/src/scss/core-components/layout/_layout-responsive.scss +100 -0
  144. package/src/scss/core-components/layout/_navbar-elements.scss +238 -0
  145. package/src/scss/core-components/layout/_navbar.scss +71 -0
  146. package/src/scss/core-components/layout/_sidebar-states.scss +228 -0
  147. package/src/scss/core-components/layout/_sidebar.scss +177 -0
  148. package/src/scss/main.scss +7 -0
  149. package/src/scss/themes/_dark-base.scss +207 -0
  150. package/src/scss/themes/audi-light.scss +311 -0
  151. package/src/scss/themes/audi.scss +288 -0
  152. package/src/scss/themes/corporate.scss +203 -0
  153. package/src/scss/themes/dark-blue.scss +152 -0
  154. package/src/scss/themes/dark-green.scss +156 -0
  155. package/src/scss/themes/dark-red.scss +160 -0
  156. package/src/scss/themes/dark.scss +145 -0
  157. package/src/scss/themes/express.scss +281 -0
  158. package/src/scss/themes/minimal.scss +121 -0
  159. package/src/scss/utilities.scss +481 -0
  160. package/src/scss/variables/_base.scss +81 -0
  161. package/src/scss/variables/_colors.scss +148 -0
  162. package/src/scss/variables/_components.scss +509 -0
  163. package/src/scss/variables/_index.scss +13 -0
  164. package/src/scss/variables/_layout.scss +65 -0
  165. package/src/scss/variables/_spacing.scss +66 -0
  166. package/src/scss/variables/_system.scss +80 -0
  167. package/src/scss/variables/_typography.scss +37 -0
@@ -0,0 +1,322 @@
1
+ <!-- Virtual Scroll & Infinite Scroll Snippets -->
2
+ <!-- Clean HTML and JavaScript examples for efficient large dataset rendering -->
3
+
4
+ <!-- ========================================
5
+ Virtual Scroll (True Virtualization)
6
+ Constant DOM size, handles millions of items
7
+ ======================================== -->
8
+
9
+ <!-- Timeline Virtual Scroll -->
10
+ <div id="timeline-virtual-container" style="height: 400px; overflow-y: auto;">
11
+ <ul class="pa-timeline pa-timeline--feed" id="timeline-virtual-list"></ul>
12
+ </div>
13
+
14
+ <script>
15
+ const timelineContainer = document.getElementById('timeline-virtual-container');
16
+ const timelineList = document.getElementById('timeline-virtual-list');
17
+
18
+ let scrollTop = 0;
19
+ const itemHeight = 50; // Fixed height per item
20
+ const totalItems = 5000; // Total dataset size
21
+ const bufferSize = 10; // Extra items above/below viewport
22
+ const viewportHeight = 400; // Container height
23
+
24
+ function renderTimelineItems() {
25
+ // Calculate visible range
26
+ const startIndex = Math.floor(scrollTop / itemHeight);
27
+ const endIndex = Math.ceil((scrollTop + viewportHeight) / itemHeight);
28
+ const visibleStart = Math.max(0, startIndex - bufferSize);
29
+ const visibleEnd = Math.min(totalItems, endIndex + bufferSize);
30
+
31
+ // Set list height to maintain scroll
32
+ timelineList.style.height = `${totalItems * itemHeight}px`;
33
+ timelineList.style.position = 'relative';
34
+
35
+ // Clear and render visible items only
36
+ timelineList.innerHTML = '';
37
+
38
+ for (let i = visibleStart; i < visibleEnd; i++) {
39
+ const li = document.createElement('li');
40
+ li.className = 'pa-timeline__item';
41
+
42
+ // Absolute positioning at calculated offset
43
+ li.style.position = 'absolute';
44
+ li.style.top = `${i * itemHeight}px`;
45
+ li.style.left = '0';
46
+ li.style.right = '0';
47
+
48
+ // Render item content
49
+ li.innerHTML = `
50
+ <div class="pa-timeline__time">09:30</div>
51
+ <div class="pa-timeline__content">
52
+ <div class="pa-timeline__avatar">
53
+ <img src="avatar.jpg" alt="User">
54
+ </div>
55
+ <span>Action #${i}</span>
56
+ </div>
57
+ `;
58
+
59
+ timelineList.appendChild(li);
60
+ }
61
+ }
62
+
63
+ // Listen to scroll events
64
+ timelineContainer.addEventListener('scroll', () => {
65
+ scrollTop = timelineContainer.scrollTop;
66
+ renderTimelineItems();
67
+ });
68
+
69
+ // Initial render
70
+ renderTimelineItems();
71
+ </script>
72
+
73
+ <!-- ========================================
74
+ Table Virtual Scroll (with spacer rows)
75
+ Preserves table structure
76
+ ======================================== -->
77
+
78
+ <div id="table-virtual-container" style="height: 400px; overflow-y: auto;">
79
+ <table class="pa-table pa-table--striped">
80
+ <thead style="position: sticky; top: 0; background: var(--base-primary-bg); z-index: 10;">
81
+ <tr>
82
+ <th>#</th>
83
+ <th>Name</th>
84
+ <th>Email</th>
85
+ <th>Status</th>
86
+ </tr>
87
+ </thead>
88
+ <tbody id="table-virtual-body"></tbody>
89
+ </table>
90
+ </div>
91
+
92
+ <script>
93
+ const tableContainer = document.getElementById('table-virtual-container');
94
+ const tableBody = document.getElementById('table-virtual-body');
95
+
96
+ let tableScrollTop = 0;
97
+ const tableItemHeight = 38; // Table row height
98
+ const tableTotalItems = 10000; // Total rows
99
+ const tableBufferSize = 10;
100
+ const tableViewportHeight = 400;
101
+
102
+ function renderTableRows() {
103
+ // Calculate visible range
104
+ const startIndex = Math.floor(tableScrollTop / tableItemHeight);
105
+ const endIndex = Math.ceil((tableScrollTop + tableViewportHeight) / tableItemHeight);
106
+ const visibleStart = Math.max(0, startIndex - tableBufferSize);
107
+ const visibleEnd = Math.min(tableTotalItems, endIndex + tableBufferSize);
108
+
109
+ // Clear tbody
110
+ tableBody.innerHTML = '';
111
+
112
+ // Top spacer row (pushes content down)
113
+ if (visibleStart > 0) {
114
+ const topSpacer = document.createElement('tr');
115
+ topSpacer.style.height = `${visibleStart * tableItemHeight}px`;
116
+ topSpacer.innerHTML = '<td colspan="4"></td>';
117
+ tableBody.appendChild(topSpacer);
118
+ }
119
+
120
+ // Visible rows
121
+ for (let i = visibleStart; i < visibleEnd; i++) {
122
+ const tr = document.createElement('tr');
123
+ tr.innerHTML = `
124
+ <td>${i + 1}</td>
125
+ <td>John Doe</td>
126
+ <td>john.doe@example.com</td>
127
+ <td><span class="pa-badge pa-badge--success">Active</span></td>
128
+ `;
129
+ tableBody.appendChild(tr);
130
+ }
131
+
132
+ // Bottom spacer row (maintains scroll height)
133
+ if (visibleEnd < tableTotalItems) {
134
+ const bottomSpacer = document.createElement('tr');
135
+ bottomSpacer.style.height = `${(tableTotalItems - visibleEnd) * tableItemHeight}px`;
136
+ bottomSpacer.innerHTML = '<td colspan="4"></td>';
137
+ tableBody.appendChild(bottomSpacer);
138
+ }
139
+ }
140
+
141
+ // Listen to scroll events
142
+ tableContainer.addEventListener('scroll', () => {
143
+ tableScrollTop = tableContainer.scrollTop;
144
+ renderTableRows();
145
+ });
146
+
147
+ // Initial render
148
+ renderTableRows();
149
+ </script>
150
+
151
+ <!-- ========================================
152
+ Infinite Scroll (Lazy Loading)
153
+ Growing DOM, good for thousands of items
154
+ ======================================== -->
155
+
156
+ <!-- Infinite Scroll Timeline -->
157
+ <div class="pa-timeline__scroll-container" id="infinite-scroll-container" style="max-height: 400px; overflow-y: auto;">
158
+ <ul class="pa-timeline pa-timeline--feed" id="infinite-scroll-timeline"></ul>
159
+ </div>
160
+ <div class="pa-timeline__loader" id="infinite-scroll-loader">
161
+ <div class="pa-loader pa-loader--sm d-none" id="infinite-scroll-spinner">
162
+ <div class="pa-spinner"></div>
163
+ </div>
164
+ <div class="pa-timeline__loader-text d-none" id="infinite-scroll-text">
165
+ Loading more entries...
166
+ </div>
167
+ </div>
168
+
169
+ <script>
170
+ let infinitePage = 0;
171
+ let isLoadingInfinite = false;
172
+ const infiniteContainer = document.getElementById('infinite-scroll-container');
173
+ const infiniteTimeline = document.getElementById('infinite-scroll-timeline');
174
+ const infiniteSpinner = document.getElementById('infinite-scroll-spinner');
175
+ const infiniteText = document.getElementById('infinite-scroll-text');
176
+
177
+ function loadInfiniteItems() {
178
+ if (isLoadingInfinite || infinitePage >= 100) {
179
+ return; // Stop at 100 pages (2000 items)
180
+ }
181
+
182
+ isLoadingInfinite = true;
183
+ infiniteSpinner.style.display = 'block';
184
+ infiniteText.style.display = 'block';
185
+
186
+ // Simulate async data loading
187
+ setTimeout(() => {
188
+ // Load 20 items per page
189
+ for (let i = 0; i < 20; i++) {
190
+ const index = infinitePage * 20 + i;
191
+ const li = document.createElement('li');
192
+ li.className = 'pa-timeline__item';
193
+ li.innerHTML = `
194
+ <div class="pa-timeline__time">09:30</div>
195
+ <div class="pa-timeline__content">
196
+ <div class="pa-timeline__avatar">
197
+ <img src="avatar.jpg" alt="User">
198
+ </div>
199
+ <span>Action #${index}</span>
200
+ </div>
201
+ `;
202
+ infiniteTimeline.appendChild(li); // Append, never remove
203
+ }
204
+
205
+ infinitePage++;
206
+ infiniteSpinner.style.display = 'none';
207
+ infiniteText.style.display = 'none';
208
+ isLoadingInfinite = false;
209
+ }, 500);
210
+ }
211
+
212
+ // Load initial items
213
+ loadInfiniteItems();
214
+
215
+ // Listen to scroll events
216
+ infiniteContainer.addEventListener('scroll', () => {
217
+ const scrollTop = infiniteContainer.scrollTop;
218
+ const scrollHeight = infiniteContainer.scrollHeight;
219
+ const clientHeight = infiniteContainer.clientHeight;
220
+
221
+ // Check if scrolled near bottom (50px threshold)
222
+ if (scrollTop + clientHeight >= scrollHeight - 50 && !isLoadingInfinite) {
223
+ loadInfiniteItems();
224
+ }
225
+ });
226
+ </script>
227
+
228
+ <!-- ========================================
229
+ Using VirtualScroll Class (General Purpose)
230
+ ======================================== -->
231
+
232
+ <script src="/dist/js/virtual-scroll.js"></script>
233
+
234
+ <div id="my-container" style="height: 400px; overflow-y: auto;"></div>
235
+
236
+ <script>
237
+ const vs = new VirtualScroll({
238
+ container: document.getElementById('my-container'),
239
+ itemHeight: 50, // Fixed height per item (required)
240
+ totalItems: 10000, // Total dataset size
241
+ bufferSize: 10, // Extra items above/below (optional)
242
+ renderItem: (index) => {
243
+ // Return DOM element for this item
244
+ const div = document.createElement('div');
245
+ div.textContent = `Item ${index}`;
246
+ return div;
247
+ },
248
+ onScroll: (scrollTop) => {
249
+ // Optional: callback on scroll
250
+ console.log('Scrolled to:', scrollTop);
251
+ }
252
+ });
253
+
254
+ // API methods
255
+ vs.setTotalItems(20000); // Update total items
256
+ vs.scrollToItem(5000); // Scroll to specific item
257
+ const range = vs.getVisibleRange(); // Get current visible range
258
+ vs.destroy(); // Cleanup
259
+ </script>
260
+
261
+ <!-- ========================================
262
+ Performance Comparison
263
+ ======================================== -->
264
+ <!--
265
+ VIRTUAL SCROLL (Constant DOM):
266
+ - DOM size: ~20-30 elements regardless of dataset
267
+ - Performance: Handles millions of items smoothly
268
+ - Requirements: Fixed item heights, uniform layout
269
+ - Best for: Tables, logs, file lists, data grids
270
+ - Strategy: Items added/removed dynamically as you scroll
271
+
272
+ INFINITE SCROLL (Growing DOM):
273
+ - DOM size: Grows with each load (e.g., 2000 elements for 2000 items)
274
+ - Performance: Good for hundreds/low thousands
275
+ - Requirements: Works with variable heights
276
+ - Best for: Social feeds, news lists, image galleries
277
+ - Strategy: Items appended, never removed
278
+
279
+ WHEN TO USE WHAT:
280
+ - 10,000+ uniform items → Virtual Scroll
281
+ - Rich variable content → Infinite Scroll
282
+ - Complex nested layouts → Infinite Scroll
283
+ - Simple repeating rows → Virtual Scroll
284
+ -->
285
+
286
+ <!-- ========================================
287
+ Configuration Guidelines
288
+ ======================================== -->
289
+ <!--
290
+ VIRTUAL SCROLL SETTINGS:
291
+
292
+ itemHeight:
293
+ - Must be exact and consistent
294
+ - Measure with: element.offsetHeight
295
+ - Examples:
296
+ - Timeline item: 50px
297
+ - Table row: 38px
298
+ - List item: 44px
299
+
300
+ bufferSize:
301
+ - Recommended: 5-15 items
302
+ - Larger = smoother scroll, more DOM
303
+ - Smaller = less DOM, potential flicker
304
+
305
+ totalItems:
306
+ - Can be updated dynamically
307
+ - Example: vs.setTotalItems(newCount)
308
+
309
+ INFINITE SCROLL SETTINGS:
310
+
311
+ Threshold:
312
+ - Recommended: 50-100px from bottom
313
+ - Trigger early for smooth experience
314
+
315
+ Page size:
316
+ - Recommended: 20-50 items per load
317
+ - Balance between requests and UX
318
+
319
+ Max pages:
320
+ - Set a limit to prevent memory issues
321
+ - Example: 100 pages = 2000 items max
322
+ -->