numclassify 0.3.1__tar.gz → 0.3.2__tar.gz

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 (39) hide show
  1. {numclassify-0.3.1 → numclassify-0.3.2}/CHANGELOG.md +11 -0
  2. {numclassify-0.3.1 → numclassify-0.3.2}/PKG-INFO +1 -1
  3. {numclassify-0.3.1 → numclassify-0.3.2}/docs/playground.css +155 -0
  4. {numclassify-0.3.1 → numclassify-0.3.2}/docs/playground.html +16 -2
  5. {numclassify-0.3.1 → numclassify-0.3.2}/docs/playground.js +142 -18
  6. {numclassify-0.3.1 → numclassify-0.3.2}/pyproject.toml +1 -1
  7. {numclassify-0.3.1 → numclassify-0.3.2}/.github/workflows/ci.yml +0 -0
  8. {numclassify-0.3.1 → numclassify-0.3.2}/.github/workflows/docs.yml +0 -0
  9. {numclassify-0.3.1 → numclassify-0.3.2}/.github/workflows/publish.yml +0 -0
  10. {numclassify-0.3.1 → numclassify-0.3.2}/.gitignore +0 -0
  11. {numclassify-0.3.1 → numclassify-0.3.2}/CONTRIBUTING.md +0 -0
  12. {numclassify-0.3.1 → numclassify-0.3.2}/LICENSE +0 -0
  13. {numclassify-0.3.1 → numclassify-0.3.2}/README.md +0 -0
  14. {numclassify-0.3.1 → numclassify-0.3.2}/docs/api.md +0 -0
  15. {numclassify-0.3.1 → numclassify-0.3.2}/docs/changelog.md +0 -0
  16. {numclassify-0.3.1 → numclassify-0.3.2}/docs/cli.md +0 -0
  17. {numclassify-0.3.1 → numclassify-0.3.2}/docs/index.md +0 -0
  18. {numclassify-0.3.1 → numclassify-0.3.2}/examples/basic_usage.py +0 -0
  19. {numclassify-0.3.1 → numclassify-0.3.2}/examples/custom_type.py +0 -0
  20. {numclassify-0.3.1 → numclassify-0.3.2}/examples/find_perfect_numbers.py +0 -0
  21. {numclassify-0.3.1 → numclassify-0.3.2}/examples/random_classify.py +0 -0
  22. {numclassify-0.3.1 → numclassify-0.3.2}/examples/stream_large_range.py +0 -0
  23. {numclassify-0.3.1 → numclassify-0.3.2}/mkdocs.yml +0 -0
  24. {numclassify-0.3.1 → numclassify-0.3.2}/numclassify/__init__.py +0 -0
  25. {numclassify-0.3.1 → numclassify-0.3.2}/numclassify/__main__.py +0 -0
  26. {numclassify-0.3.1 → numclassify-0.3.2}/numclassify/_core/__init__.py +0 -0
  27. {numclassify-0.3.1 → numclassify-0.3.2}/numclassify/_core/combinatorial.py +0 -0
  28. {numclassify-0.3.1 → numclassify-0.3.2}/numclassify/_core/digital.py +0 -0
  29. {numclassify-0.3.1 → numclassify-0.3.2}/numclassify/_core/divisors.py +0 -0
  30. {numclassify-0.3.1 → numclassify-0.3.2}/numclassify/_core/figurate.py +0 -0
  31. {numclassify-0.3.1 → numclassify-0.3.2}/numclassify/_core/number_theory.py +0 -0
  32. {numclassify-0.3.1 → numclassify-0.3.2}/numclassify/_core/powers.py +0 -0
  33. {numclassify-0.3.1 → numclassify-0.3.2}/numclassify/_core/primes.py +0 -0
  34. {numclassify-0.3.1 → numclassify-0.3.2}/numclassify/_core/recreational.py +0 -0
  35. {numclassify-0.3.1 → numclassify-0.3.2}/numclassify/_core/sequences.py +0 -0
  36. {numclassify-0.3.1 → numclassify-0.3.2}/numclassify/_registry.py +0 -0
  37. {numclassify-0.3.1 → numclassify-0.3.2}/numclassify/cli.py +0 -0
  38. {numclassify-0.3.1 → numclassify-0.3.2}/numclassify/py.typed +0 -0
  39. {numclassify-0.3.1 → numclassify-0.3.2}/tests/test_registry.py +0 -0
@@ -6,6 +6,17 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
6
6
 
7
7
  ---
8
8
 
9
+ ## [0.3.2] - 2026-06-12
10
+
11
+ ### Added
12
+ - Search autocomplete dropdown — suggests property names as you type in the search field
13
+ - Confetti celebration burst when a number scores >50 properties
14
+ - Keyboard shortcuts: `C` (classify), `S` (search), `N` (Number of the Day), `?`/`H` (show shortcuts overlay)
15
+ - `prefers-reduced-motion` support — disables all animations for accessibility
16
+
17
+ ### Fixed
18
+ - No bugs reported since v0.3.1
19
+
9
20
  ## [0.3.1] - 2026-06-12
10
21
 
11
22
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: numclassify
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: The most comprehensive Python library for number classification - 3000+ number types
5
5
  Project-URL: Homepage, https://github.com/aratrikghosh2011-tech/numclassify
6
6
  Project-URL: Repository, https://github.com/aratrikghosh2011-tech/numclassify
@@ -999,3 +999,158 @@ footer a:hover {
999
999
  .tabs { gap: 2px; }
1000
1000
  .tab { font-size: 12px; padding: 8px 6px; }
1001
1001
  }
1002
+
1003
+ /* ── Search Autocomplete ────────────────────────────────────────────── */
1004
+
1005
+ .autocomplete-wrap {
1006
+ position: relative;
1007
+ flex: 1;
1008
+ min-width: 180px;
1009
+ }
1010
+
1011
+ #ac-dropdown {
1012
+ position: absolute;
1013
+ top: calc(100% + 4px);
1014
+ left: 0;
1015
+ right: 0;
1016
+ background: var(--bg-elevated);
1017
+ border: 1px solid var(--border);
1018
+ border-radius: 8px;
1019
+ max-height: 220px;
1020
+ overflow-y: auto;
1021
+ z-index: 50;
1022
+ display: none;
1023
+ box-shadow: 0 8px 24px rgba(0,0,0,0.3);
1024
+ }
1025
+
1026
+ #ac-dropdown.open { display: block; }
1027
+
1028
+ .ac-item {
1029
+ padding: 8px 14px;
1030
+ font-family: 'JetBrains Mono', monospace;
1031
+ font-size: 12px;
1032
+ cursor: pointer;
1033
+ transition: background 0.15s ease;
1034
+ color: var(--text);
1035
+ }
1036
+
1037
+ .ac-item:first-child { border-radius: 7px 7px 0 0; }
1038
+ .ac-item:last-child { border-radius: 0 0 7px 7px; }
1039
+
1040
+ .ac-item:hover, .ac-item.selected {
1041
+ background: var(--saffron-faint);
1042
+ color: var(--saffron);
1043
+ }
1044
+
1045
+ .ac-item .ac-cat {
1046
+ float: right;
1047
+ font-size: 10px;
1048
+ color: var(--text-muted);
1049
+ font-family: 'Inter', sans-serif;
1050
+ }
1051
+
1052
+ /* ── Confetti ────────────────────────────────────────────────────────── */
1053
+
1054
+ .confetti-container {
1055
+ position: fixed;
1056
+ inset: 0;
1057
+ pointer-events: none;
1058
+ z-index: 9999;
1059
+ overflow: hidden;
1060
+ }
1061
+
1062
+ .confetti-piece {
1063
+ position: absolute;
1064
+ width: 8px;
1065
+ height: 8px;
1066
+ top: -10px;
1067
+ animation: confettiFall linear forwards;
1068
+ }
1069
+
1070
+ @keyframes confettiFall {
1071
+ 0% {
1072
+ transform: translateY(0) rotate(0deg) scale(1);
1073
+ opacity: 1;
1074
+ }
1075
+ 100% {
1076
+ transform: translateY(100vh) rotate(720deg) scale(0.3);
1077
+ opacity: 0;
1078
+ }
1079
+ }
1080
+
1081
+ /* ── Keyboard Shortcuts Overlay ──────────────────────────────────────── */
1082
+
1083
+ .shortcuts-overlay {
1084
+ position: fixed;
1085
+ inset: 0;
1086
+ background: rgba(0,0,0,0.6);
1087
+ backdrop-filter: blur(4px);
1088
+ z-index: 9998;
1089
+ display: none;
1090
+ align-items: center;
1091
+ justify-content: center;
1092
+ }
1093
+
1094
+ .shortcuts-overlay.open { display: flex; }
1095
+
1096
+ .shortcuts-panel {
1097
+ background: var(--bg-card);
1098
+ border: 1px solid var(--border);
1099
+ border-radius: 16px;
1100
+ padding: 32px 40px;
1101
+ max-width: 400px;
1102
+ width: 90%;
1103
+ animation: slideUp 0.3s ease both;
1104
+ }
1105
+
1106
+ .shortcuts-panel h2 {
1107
+ font-size: 16px;
1108
+ font-weight: 700;
1109
+ color: var(--saffron);
1110
+ margin-bottom: 20px;
1111
+ text-transform: uppercase;
1112
+ letter-spacing: 0.08em;
1113
+ }
1114
+
1115
+ .shortcut-row {
1116
+ display: flex;
1117
+ align-items: center;
1118
+ justify-content: space-between;
1119
+ padding: 8px 0;
1120
+ border-bottom: 1px solid rgba(255,153,51,0.06);
1121
+ }
1122
+
1123
+ .shortcut-row:last-child { border-bottom: none; }
1124
+
1125
+ .shortcut-row .sk-key {
1126
+ background: var(--bg-input);
1127
+ border: 1px solid var(--border);
1128
+ border-radius: 4px;
1129
+ padding: 2px 8px;
1130
+ font-family: 'JetBrains Mono', monospace;
1131
+ font-size: 12px;
1132
+ color: var(--saffron);
1133
+ min-width: 28px;
1134
+ text-align: center;
1135
+ }
1136
+
1137
+ .shortcut-row .sk-desc {
1138
+ font-size: 13px;
1139
+ color: var(--text-muted);
1140
+ }
1141
+
1142
+ .shortcuts-close {
1143
+ margin-top: 20px;
1144
+ width: 100%;
1145
+ }
1146
+
1147
+ /* ── Reduced Motion ──────────────────────────────────────────────────── */
1148
+
1149
+ @media (prefers-reduced-motion: reduce) {
1150
+ *, *::before, *::after {
1151
+ animation-duration: 0.01ms !important;
1152
+ animation-iteration-count: 1 !important;
1153
+ transition-duration: 0.01ms !important;
1154
+ scroll-behavior: auto !important;
1155
+ }
1156
+ }
@@ -60,7 +60,7 @@
60
60
  </div>
61
61
  </div>
62
62
  <div class="tags-wrap" id="classify-tags"></div>
63
- <div class="btn-row">
63
+ <div class="btn-row" id="batch-actions">
64
64
  <button class="btn btn-icon" onclick="copyResults()">Copy</button>
65
65
  <button class="btn btn-icon" onclick="shareURL()">Share</button>
66
66
  <button class="btn btn-icon" onclick="downloadJSON()">Download</button>
@@ -88,7 +88,10 @@
88
88
  <div class="card">
89
89
  <div class="card-title">Search by Property</div>
90
90
  <div class="input-row">
91
- <input type="text" id="input-property" placeholder="Property name (e.g. prime, perfect, triangular)..." />
91
+ <div class="autocomplete-wrap">
92
+ <input type="text" id="input-property" placeholder="Property name (e.g. prime, perfect, triangular)..." autocomplete="off" />
93
+ <div id="ac-dropdown"></div>
94
+ </div>
92
95
  </div>
93
96
  <div class="input-row" style="margin-top:10px;">
94
97
  <input type="number" id="input-range-start" placeholder="From" value="1" />
@@ -166,6 +169,17 @@
166
169
  <button id="scroll-top" onclick="scrollToTop()" title="Scroll to top">&uarr;</button>
167
170
  <div id="toast"></div>
168
171
 
172
+ <div class="shortcuts-overlay" id="shortcuts-overlay" onclick="closeShortcuts()">
173
+ <div class="shortcuts-panel" onclick="event.stopPropagation()">
174
+ <h2>Keyboard Shortcuts</h2>
175
+ <div class="shortcut-row"><span class="sk-key">C</span><span class="sk-desc">Classify tab</span></div>
176
+ <div class="shortcut-row"><span class="sk-key">S</span><span class="sk-desc">Search tab</span></div>
177
+ <div class="shortcut-row"><span class="sk-key">N</span><span class="sk-desc">Number of the Day</span></div>
178
+ <div class="shortcut-row"><span class="sk-key">?</span><span class="sk-desc">Toggle this panel</span></div>
179
+ <button class="btn shortcuts-close" onclick="closeShortcuts()">Close</button>
180
+ </div>
181
+ </div>
182
+
169
183
  <script src="playground.js"></script>
170
184
  </body>
171
185
  </html>
@@ -5,6 +5,7 @@ let allProperties = [];
5
5
  let searchPage = 0;
6
6
  const SEARCH_PAGE_SIZE = 50;
7
7
  let searchResultsAll = [];
8
+ let batchMode = false;
8
9
 
9
10
  // ── Utility ──────────────────────────────────────────────────────────────
10
11
 
@@ -166,20 +167,22 @@ function makeTags(props, container, delayBase = 0) {
166
167
 
167
168
  // ── Score Counter Animation ──────────────────────────────────────────────
168
169
 
169
- function animateScore(el, target, duration = 400) {
170
+ function animateScore(target, duration = 400) {
171
+ const counter = document.querySelector('#classify-score .score-count');
172
+ if (!counter) return;
170
173
  const start = performance.now();
171
- const startVal = 0;
172
174
  function step(now) {
173
175
  const t = Math.min((now - start) / duration, 1);
174
176
  const ease = 1 - Math.pow(1 - t, 3);
175
- const current = Math.round(startVal + (target - startVal) * ease);
176
- el.textContent = current + ' properties';
177
+ const current = Math.round(target * ease);
178
+ counter.textContent = current;
177
179
  if (t < 1) requestAnimationFrame(step);
178
180
  else {
179
- el.textContent = target + ' properties';
180
- el.classList.remove('pulse');
181
- void el.offsetWidth;
182
- el.classList.add('pulse');
181
+ counter.textContent = target;
182
+ const badge = $('classify-score');
183
+ badge.classList.remove('pulse');
184
+ void badge.offsetWidth;
185
+ badge.classList.add('pulse');
183
186
  }
184
187
  }
185
188
  requestAnimationFrame(step);
@@ -230,7 +233,7 @@ json.dumps(m)
230
233
  const ver = await pyodide.runPythonAsync('nc.__version__');
231
234
  $('version-text').textContent = ver;
232
235
  } catch(e) {
233
- $('version-text').textContent = '0.3.0';
236
+ $('version-text').textContent = '?';
234
237
  }
235
238
 
236
239
  setProgress(100, 'Ready!');
@@ -256,6 +259,13 @@ json.dumps(m)
256
259
 
257
260
  async function doClassify(n = null) {
258
261
  if (!requireReady()) return;
262
+ // If no explicit number and input contains commas/spaces, go to batch mode
263
+ if (n === null) {
264
+ const raw = $('input-classify').value.trim();
265
+ if (raw.includes(',') || /\s/.test(raw)) {
266
+ return doBatchClassify();
267
+ }
268
+ }
259
269
  const val = n !== null ? n : parseInt($('input-classify').value);
260
270
  if (isNaN(val)) { toast('Enter a valid integer.'); return; }
261
271
 
@@ -271,9 +281,12 @@ json.dumps({"number": r["number"], "score": r["score"], "props": r["true_propert
271
281
  `);
272
282
  const data = JSON.parse(result);
273
283
 
284
+ batchMode = false;
274
285
  renderNumber($('classify-number'), data.number);
275
- animateScore($('classify-score'), data.score);
286
+ animateScore(data.score);
276
287
  makeTags(data.props, $('classify-tags'));
288
+ $('batch-actions').style.display = '';
289
+ if (data.score > 50) burstConfetti();
277
290
 
278
291
  const res = $('result-classify');
279
292
  res.style.display = 'block';
@@ -327,6 +340,7 @@ json.dumps(results)
327
340
  `);
328
341
  const results = JSON.parse(result);
329
342
 
343
+ batchMode = true;
330
344
  const res = $('result-classify');
331
345
  res.style.display = 'block';
332
346
  res.classList.remove('show');
@@ -334,7 +348,8 @@ json.dumps(results)
334
348
  res.classList.add('show');
335
349
 
336
350
  $('classify-number').innerHTML = `<span style="font-size:24px;background:none;-webkit-text-fill-color:var(--saffron);color:var(--saffron)">Batch (${results.length})</span>`;
337
- $('classify-score').textContent = '';
351
+ $('classify-score').innerHTML = '<span class="score-count"></span>';
352
+ $('batch-actions').style.display = 'none';
338
353
 
339
354
  let html = '<table class="batch-table"><thead><tr><th>Number</th><th>Score</th><th>Properties</th></tr></thead><tbody>';
340
355
  results.forEach(r => {
@@ -538,6 +553,7 @@ json.dumps({"only_a": only_a, "only_b": only_b, "shared": shared})
538
553
  // ── Number of the Day ────────────────────────────────────────────────────
539
554
 
540
555
  async function computeNOTD(dateStr) {
556
+ if (!pyReady) return;
541
557
  try {
542
558
  if ($('notd-content')) $('notd-content').style.display = 'none';
543
559
  if ($('notd-loading')) $('notd-loading').style.display = 'block';
@@ -580,6 +596,7 @@ function onNotdDateChange(input) {
580
596
  // ── Copy & Share & Download ──────────────────────────────────────────────
581
597
 
582
598
  async function copyResults() {
599
+ if (batchMode) { toast('Cannot copy batch results — classify a single number first.'); return; }
583
600
  const num = $('classify-number').textContent;
584
601
  const score = $('classify-score').textContent;
585
602
  const tags = [...$('classify-tags').querySelectorAll('.tag')].map(t => t.textContent).join(', ');
@@ -606,10 +623,12 @@ function shareURL() {
606
623
  }
607
624
 
608
625
  function downloadJSON() {
626
+ if (batchMode) { toast('Cannot download batch results — classify a single number first.'); return; }
609
627
  const num = $('classify-number').textContent;
610
- const score = $('classify-score').textContent.replace(' properties', '');
628
+ const scoreEl = document.querySelector('#classify-score .score-count');
629
+ const score = scoreEl ? parseInt(scoreEl.textContent) || 0 : 0;
611
630
  const tags = [...$('classify-tags').querySelectorAll('.tag')].map(t => t.textContent);
612
- const data = { number: parseInt(num) || num, score: parseInt(score) || 0, properties: tags };
631
+ const data = { number: parseInt(num) || num, score, properties: tags };
613
632
  const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
614
633
  const url = URL.createObjectURL(blob);
615
634
  const a = document.createElement('a');
@@ -643,16 +662,119 @@ function scrollToTop() {
643
662
  window.scrollTo({ top: 0, behavior: 'smooth' });
644
663
  }
645
664
 
665
+ // ── Search Autocomplete ───────────────────────────────────────────────────
666
+
667
+ function setupAutocomplete() {
668
+ const input = $('input-property');
669
+ if (!input) return;
670
+ const dropdown = $('ac-dropdown');
671
+ let selectedIdx = -1;
672
+
673
+ input.addEventListener('input', () => {
674
+ const val = input.value.trim().toLowerCase();
675
+ if (!val) { dropdown.classList.remove('open'); return; }
676
+ const matches = allProperties
677
+ .filter(p => p.includes(val))
678
+ .slice(0, 10);
679
+ if (!matches.length) { dropdown.classList.remove('open'); return; }
680
+ selectedIdx = -1;
681
+ dropdown.innerHTML = matches.map((p, i) =>
682
+ `<div class="ac-item${i === 0 ? ' selected' : ''}" data-prop="${p}" onclick="pickAutocomplete('${p}')">
683
+ ${p.replace(/_/g, ' ')}
684
+ <span class="ac-cat">${(categoryMap[p] || '').replace(/_/g, ' ')}</span>
685
+ </div>`
686
+ ).join('');
687
+ dropdown.classList.add('open');
688
+ });
689
+
690
+ input.addEventListener('keydown', e => {
691
+ const items = dropdown.querySelectorAll('.ac-item');
692
+ if (!items.length) return;
693
+ if (e.key === 'ArrowDown') {
694
+ e.preventDefault();
695
+ selectedIdx = Math.min(selectedIdx + 1, items.length - 1);
696
+ } else if (e.key === 'ArrowUp') {
697
+ e.preventDefault();
698
+ selectedIdx = Math.max(selectedIdx - 1, -1);
699
+ } else if (e.key === 'Enter' && selectedIdx >= 0) {
700
+ e.preventDefault();
701
+ items[selectedIdx].click();
702
+ return;
703
+ } else return;
704
+ items.forEach((el, i) => el.classList.toggle('selected', i === selectedIdx));
705
+ });
706
+
707
+ document.addEventListener('click', e => {
708
+ if (!input.contains(e.target) && !dropdown.contains(e.target)) {
709
+ dropdown.classList.remove('open');
710
+ }
711
+ });
712
+ }
713
+
714
+ function pickAutocomplete(prop) {
715
+ $('input-property').value = prop;
716
+ $('ac-dropdown').classList.remove('open');
717
+ doSearch();
718
+ }
719
+
720
+ // ── Confetti ──────────────────────────────────────────────────────────────
721
+
722
+ function burstConfetti() {
723
+ const container = document.createElement('div');
724
+ container.className = 'confetti-container';
725
+ const colors = ['#FF9933', '#FF6B6B', '#4ECDC4', '#45B7D1', '#F7DC6F', '#DDA0DD', '#98D8C8', '#BB8FCE', '#FFEAA7', '#4CAF7D'];
726
+ for (let i = 0; i < 80; i++) {
727
+ const piece = document.createElement('div');
728
+ piece.className = 'confetti-piece';
729
+ const size = 4 + Math.random() * 8;
730
+ piece.style.width = size + 'px';
731
+ piece.style.height = size + 'px';
732
+ piece.style.background = colors[Math.floor(Math.random() * colors.length)];
733
+ piece.style.left = Math.random() * 100 + '%';
734
+ piece.style.borderRadius = Math.random() > 0.5 ? '50%' : '2px';
735
+ piece.style.animationDuration = (1.5 + Math.random() * 2) + 's';
736
+ piece.style.animationDelay = Math.random() * 0.5 + 's';
737
+ container.appendChild(piece);
738
+ }
739
+ document.body.appendChild(container);
740
+ setTimeout(() => container.remove(), 3500);
741
+ }
742
+
743
+ // ── Keyboard Shortcuts ────────────────────────────────────────────────────
744
+
745
+ const SHORTCUT_MAP = {
746
+ c: 'classify',
747
+ s: 'search',
748
+ n: 'notd',
749
+ };
750
+
751
+ function setupShortcuts() {
752
+ document.addEventListener('keydown', e => {
753
+ if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
754
+ const key = e.key.toLowerCase();
755
+ if (key === '?' || key === 'h') {
756
+ e.preventDefault();
757
+ $('shortcuts-overlay').classList.toggle('open');
758
+ return;
759
+ }
760
+ const tab = SHORTCUT_MAP[key];
761
+ if (tab) {
762
+ e.preventDefault();
763
+ switchTab(tab);
764
+ }
765
+ });
766
+ }
767
+
768
+ function closeShortcuts() {
769
+ $('shortcuts-overlay').classList.remove('open');
770
+ }
771
+
646
772
  // ── Init ─────────────────────────────────────────────────────────────────
647
773
 
648
774
  document.addEventListener('DOMContentLoaded', () => {
649
775
  // Enter key support
650
776
  $('input-classify')?.addEventListener('keydown', e => {
651
- if (e.key === 'Enter') {
652
- const raw = e.target.value.trim();
653
- if (raw.includes(',') || raw.includes(' ')) doBatchClassify();
654
- else doClassify();
655
- }
777
+ if (e.key === 'Enter') doClassify();
656
778
  });
657
779
  $('input-property')?.addEventListener('keydown', e => {
658
780
  if (e.key === 'Enter') doSearch();
@@ -668,5 +790,7 @@ document.addEventListener('DOMContentLoaded', () => {
668
790
  if ($('theme-icon')) $('theme-icon').textContent = savedTheme === 'light' ? '☀️' : '🌙';
669
791
  }
670
792
 
793
+ setupAutocomplete();
794
+ setupShortcuts();
671
795
  initPyodide();
672
796
  });
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "numclassify"
7
- version = "0.3.1"
7
+ version = "0.3.2"
8
8
  description = "The most comprehensive Python library for number classification - 3000+ number types"
9
9
  authors = [{name = "Aratrik Ghosh", email = "aratrikghosh2011@gmail.com"}]
10
10
  readme = "README.md"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes