Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/PunctuOwlity/llms.txt

Use this file to discover all available pages before exploring further.

The web app’s events screen provides two complementary tools for narrowing down a long list of events: a live search box that filters by title and a row of category tabs that restrict events to a specific type. Both controls work together — only events that satisfy both the active category tab and the current search query are shown at the same time. A search input sits at the top of the events screen, above the category tabs. As you type, the grid updates immediately on every keystroke — there is no submit button to press.
  • Element ID: #eventSearch (an <input type="search">)
  • Trigger: the native input event, fired on every character change
  • Match logic: the query is trimmed and lowercased, then checked against the lowercased event title using String.includes()
  • Scope: title only — date, time, and category are not searched
// Live search handler (app.js)
document.querySelector('#eventSearch').addEventListener('input', render);

// Inside render()
const q = document.querySelector('#eventSearch').value.trim().toLowerCase();
const rows = getEvents().filter(e =>
  (category === 'all' || e.category === category) &&
  e.title.toLowerCase().includes(q)
);
Clearing the search field immediately restores the full list for the active category tab.

Category Tabs

Below the search input, four tab buttons let you filter events by their assigned category. Clicking a tab highlights it as active and re-renders the grid.
Tab labeldata-category valueShows
All EventsallEvery event regardless of category
BirthdaysbirthdayEvents categorised as birthday
AppointmentsappointmentEvents categorised as appointment
TripstripEvents categorised as trip
Only one tab can be active at a time. The currently selected tab is marked with the CSS class active. Switching tabs resets only the category filter — any text typed into the search box remains in place and continues to apply.
// Tab click handler (app.js)
document.querySelectorAll('.tabs button').forEach(t =>
  t.addEventListener('click', () => {
    document.querySelector('.tabs .active').classList.remove('active');
    t.classList.add('active');
    category = t.dataset.category;
    render();
  })
);

Combined Filtering

The category tab and the search query are evaluated together with a logical AND: an event must match both conditions to appear in the grid. For example, if the Appointments tab is active and you type "den", the grid shows only appointment-category events whose titles contain the substring "den" (such as "Dentist" or "Dental Checkup"). Events in other categories are excluded even if their titles also contain "den".
// AND filter in render() (app.js)
const rows = getEvents().filter(e =>
  (category === 'all' || e.category === category) &&   // category condition
  e.title.toLowerCase().includes(q)                    // search condition
);

Empty State

When no events match the combined filter, the events grid displays a plain paragraph instead of cards:
<p class="empty-state">No events found.</p>
This message appears whether the result set is empty because there are genuinely no events, because the search query produced no matches, or because a category tab contains no events.

Auto-Category Detection Reference

Categories are assigned automatically when an event is saved, based on keywords in the title. Understanding these rules helps you predict which tab an event will appear under.
Title pattern (case-insensitive)Category assigned
Contains birthdaybirthday
Matches /(appointment|dentist|dental|doctor)/appointment
Matches /(trip|travel|vacation)/trip
No matchgeneral
Events with category general appear only under the All Events tab, since there is no dedicated General tab. To ensure an event surfaces under a specific tab, include one of the recognised keywords in its title, or rely on the category field if you are importing data directly.
The Android version of PunctuOwlity does not include search or category-filter functionality in the current source. MainActivity calls db.getAllEvents() and renders every event unconditionally — no search input or tab navigation is present in the Android UI.

Build docs developers (and LLMs) love