A Trie (prefix tree) data structure utility powering real-time autocomplete search across the portfolio projects index. Each keypress traverses the Trie for O(n) prefix-matched results.

This page was auto-generated by Claude — it parsed the portfolio codebase, surfaced a Medium article written in 2022, and assembled this project page from the code and article context.

Project Type: tech / Data Structures & Algorithms

Role: Full-Stack Developer

Tech Stack: Next.js, TypeScript, JavaScript, TailwindCSS

Status: Deployed, 05/2022

Article: medium

Live: chrislee.wtf/projects

1// --------------------------
2// utils/Autocomplete.js
3// --------------------------
4
5function Node(character) {
6  this.character = character
7  this.terminal = false // terminal = true marks end of word
8  this.children = {} // dict-map: key = letter, value = node
9}
10
11class Trie {
12  constructor() {
13    // Root is null — all results available when nothing is typed
14    this.root = new Node(null)
15  }
16
17  insert(word) {
18    let current = this.root
19    for (let character of word) {
20      if (current.children[character] === undefined) {
21        current.children[character] = new Node(character)
22      }
23      current = current.children[character]
24    }
25    current.terminal = true
26  }
27
28  traverse(node, prefix, visit) {
29    if (node.terminal) {
30      visit.push(prefix)
31    }
32    for (let key in node.children) {
33      this.traverse(node.children[key], prefix + key, visit)
34    }
35    return visit
36  }
37
38  search(word) {
39    let searchResultsArr = []
40    let current = this.root
41    for (let character of word) {
42      if (current.children[character] === undefined) {
43        return []
44      }
45      current = current.children[character]
46    }
47    return this.traverse(current, word, searchResultsArr)
48  }
49}
50
51export default Trie
52
53// --------------------------
54// Consumer (pages/projects.tsx)
55// --------------------------
56
57// Memoized so the Trie is built once and reused across renders.
58// data is a static import, so the empty dep array is correct.
59const trie = useMemo(() => {
60  const t = new Trie()
61  data.forEach((project) => t.insert(project.title))
62  return t
63}, [])