Skip to content

Repository files navigation

Tile Store NYC — Sample Room Inventory

A zero-dependency web application for managing tile sample inventory at the NYC Tile Store showroom. Built as a direct replacement for the NYC Showroom.xlsx spreadsheet, with all 2,731 sample records embedded directly in the HTML — no server, no database, no internet connection required.


Features

  • Full inventory search — partial match across SKU, collection, description, and bin location simultaneously
  • Barcode scanner support — plug in any USB/Bluetooth scanner; items are found by partial SKU and their edit modal opens automatically
  • Add & subtract quantity — quick ± buttons on every row, or a full edit modal with large buttons and a direct number input
  • Change history log — collapsible audit trail inside the edit modal showing every quantity and field change, when it happened, and how it was made
  • Threshold / Alerts Settings — configurable global or per-item reorder thresholds; toast notifications fire when stock hits the limit
  • Multi-contact alerts — send reorder emails to multiple recipients and SMS alerts to multiple phone numbers, all managed through the UI with no code editing required
  • Reorder panel — consolidated view of all low/out-of-stock items; one-click sends a single email to all configured addresses
  • Collection color coding — each collection family is assigned a unique, consistent accent color so staff can visually group tiles at a glance; colors adapt correctly between light and dark mode
  • Zebra-striped table — alternating white/gray rows for easy row tracking; out-of-stock rows highlighted in rose red
  • Dark / Light mode — toggle in the header, preference persisted across sessions; collection colors update instantly on switch
  • Bilingual UI — full English and Spanish translations, switchable at runtime
  • LocalStorage persistence — all quantity, contact, and history changes survive page refresh without a backend
  • CSV export — downloads the current filtered view
  • Mobile responsive — works on phones and tablets; stats collapse to 2-column grid on small screens
  • Pagination scroll — changing pages returns to the very top of the page so the stats bar and controls are always visible

Tech Stack

Layer Technology
Markup HTML5 + inline SVG (logo)
Styling CSS3 (custom properties, CSS Grid, Flexbox, @media queries)
Logic Vanilla JavaScript (ES2020, no frameworks or libraries)
Data JSON embedded in <script type="application/json"> in index.html
Persistence Browser localStorage
Email alerts Native mailto: protocol (multi-recipient)
SMS alerts Native sms: protocol (opens device messaging app)
Source data Microsoft Excel (NYC Showroom.xlsx) extracted via PowerShell + OpenXML

No npm. No build step. No CDN dependency. Open the file and it works.


Project Structure

Claude test/
├── index.html            # HTML shell + all 2,731 inventory records (embedded JSON)
├── styles.css            # All CSS — variables, layout, components, dark mode, responsive
├── script.js             # All JavaScript — i18n, data, search, render, modals, contacts, history
├── NYC Showroom.xlsx     # Original spreadsheet (source of truth for initial data import)
├── inventory.html        # Legacy single-file version (kept for reference)
├── Screenshot *.png      # UI reference screenshot used during development
└── README.md             # This file

All three files must be in the same folder. index.html references styles.css and script.js as relative paths. Opening index.html directly from the filesystem (file://) works fine — no local server needed.


Installation

No installation required.

  1. Place index.html, styles.css, and script.js in the same folder
  2. Double-click index.html — it opens directly in any modern browser
  3. All 2,731 sample records load instantly from the embedded JSON

Browsers supported: Chrome 80+, Firefox 75+, Safari 13+, Edge 80+


How to Run

Open locally

Double-click index.html
  — or —
Drag index.html into a browser window

Serve over a local network (tablets, phones, other workstations on the same Wi-Fi)

Using Python:

cd "path/to/Claude test"
python -m http.server 8080

Then open http://<your-computer-ip>:8080/index.html on any device on the same network.

Using Node.js:

npx serve "path/to/Claude test"

Configuration

All user-configurable values are managed through the UI — no code editing required. The defaults are:

Setting Default Where to change
Alert emails jay@tilestore.com ⚙️ Threshold/Alerts Settings → Alert Emails
Alert phones (none) ⚙️ Threshold/Alerts Settings → Alert Phones
Global reorder threshold 2 ⚙️ Threshold/Alerts Settings → Global Default Threshold
Default language English ES / EN toggle in header
Items per page 50 Per-page dropdown in table footer

For developers who need to change compile-time defaults, the relevant variables in script.js are:

Variable Purpose
contacts Default emails and phones array
globalThreshold Default reorder quantity threshold
lang Default UI language ('en' or 'es')
perPage Default rows per page
COLL_HUES Array of 20 hues used for collection color assignment
SK / TK / GK / CK / HK localStorage key names

Usage Examples

Searching for a tile sample

Type in the header search bar. Search is partial and instant across all fields:

"MKTB5888"     → matches SKU SMP-MKTB0000005888SAMPLE
"calacatta"    → shows all Calacatta collection samples
"17-10"        → shows all samples in bin aisle 17-10
"penny round"  → matches by description keyword
"overflow"     → matches items flagged on the overflow rack

Adjusting quantity

Quick update (inline): Click or + on any row. The status badge, stats bar, and reorder panel all update immediately and a change is recorded in the audit log.

Full edit modal:

  1. Click Edit ✏️ on any row
  2. Use the large ± buttons, or type a number directly into the manual input field
  3. Optionally update Notes, Order #, and a per-item Reorder Threshold
  4. Click Save Changes — only fields that actually changed are written to the history log

Viewing change history

Every item carries an audit trail of up to 50 entries (oldest dropped automatically):

  1. Click Edit ✏️ on any row
  2. At the bottom of the modal, click 🕐 Change History — the panel expands with a smooth animation
  3. Each entry shows:
    • Date and time of the change
    • Source label: Quick update, Edit modal, Scanner, or Item created
    • Per-field diff: old valuenew value in red and green
  4. Click the toggle again to collapse

Changes are recorded for: quantity, notes, order number, reorder threshold, and item creation.

Adding a new sample

  1. Click + Add Item in the toolbar
  2. Enter a full or partial SKU — partial entries are automatically normalized:
    "MKTB0000005999"    →    SMP-MKTB0000005999SAMPLE
    
  3. Fill in Description (required), Collection, Bin, and initial Quantity
  4. Optionally set a custom Reorder Threshold for this item
  5. Click Add Sample — an "Item created" entry is added to the history log

Using a barcode scanner

  1. Click 📷 in the header — the orange scanner banner appears
  2. Scan any barcode with a USB or Bluetooth scanner
  3. The app matches the scan against SKUs using partial matching (strips SMP- prefix and SAMPLE suffix automatically)
  4. If a match is found, the edit modal opens for that item; subsequent save is recorded as Scanner in the history
  5. Press Escape or click Stop to exit scanner mode

Configuring alert contacts

Open ⚙️ Threshold/Alerts Settings in the header:

Emails:

  • The list starts with jay@tilestore.com as the default
  • Click + Add to add another recipient — a blank input appears and is focused automatically
  • Edit any address directly in its input field — changes save instantly to localStorage
  • All configured addresses are combined into one mailto: so a single email thread reaches everyone
  • The remove button (✕) is disabled when only one email remains to prevent accidental lock-out

Phones:

  • Click + Add to add a phone number (any format — +1 (555) 000-0000, 5551234567, etc.)
  • When an alert fires, the app opens one SMS compose window per number, staggered by 600 ms to avoid browser popup blocking
  • SMS uses the device's native messaging app via the sms: protocol — works reliably on iOS and Android; on Windows it opens the Phone Link app if paired

Setting reorder thresholds

Global threshold (applies to all items without an individual override):

  1. Click ⚙️ in the header to open Threshold/Alerts Settings
  2. Enter a number in Global Default Threshold
  3. Click Apply to All — clears all per-item overrides

Per-item threshold:

  1. Click Edit ✏️ on any row
  2. Set a value in the Reorder Threshold field
  3. Save — this item uses its own threshold and ignores the global value

Sending reorder alerts

Single item — in the Reorder panel, click 📧 next to any item. Your email client opens with that item's details pre-filled, addressed to all configured emails.

All low-stock items at once:

  1. Click 🔔 Reorder in the toolbar to open the Reorder panel, or click 📧 Send All Alerts in ⚙️ settings
  2. One email opens addressed to all configured email recipients with every flagged item listed
  3. One SMS compose window opens per configured phone number

Exporting to CSV

Click ⬇️ Export CSV — downloads tilebar-nyc-inventory.csv containing the current filtered view with columns:

SKU, Collection, Description, Bin, Qty, Overflow, OrderNum, Notes, Status, Threshold


Collection Color Coding

Each collection is assigned a unique color derived deterministically from its name using a hash function mapped to a palette of 20 perceptually-spread hues:

"Calacatta"  →  hash → hue index → HSL color pair (always the same)
"Bond"       →  hash → different index → different color (always the same)
  • Colors are consistent — the same collection always gets the same color across sessions and devices
  • Colors adapt to theme — light mode uses soft pastel backgrounds with deep text; dark mode uses muted deep backgrounds with bright text
  • Switching between light and dark mode instantly re-renders all collection chips with the correct palette
  • Colors appear in the table row chips and in the Collection field inside the edit modal

Table Appearance

Row type Light mode Dark mode
Odd rows (1, 3, 5…) White #ffffff #1c1e26
Even rows (2, 4, 6…) Light gray #f4f5f7 #21232e
Low-stock rows Soft yellow Muted yellow-brown
Out-of-stock rows Rose red #fde8e6 Deep red #3b1212
Hovered row Blue tint (overrides all above) Blue tint

Column headers use font-weight: 700 with full-contrast text for clear readability.


Data Persistence Model

First visit:
  index.html (embedded JSON) ──► localStorage

Subsequent visits:
  localStorage ──► app state        (user edits take priority)
  embedded JSON ──► merged in       (new SKUs added without overwriting existing)

On every change:
  app state ──► localStorage        (instant, no round-trip)

Five localStorage keys are used:

Key Contains
tilebar-inv-nyc Full inventory array with current quantities
tilebar-thr-nyc Per-item threshold overrides { sku: number }
tilebar-gthr-nyc Global threshold number
tilebar-contacts-nyc { emails: [...], phones: [...] }
tilebar-history-nyc { [sku]: [{ts, src, changes}] } — audit log, max 50 entries per item

Re-importing Data from the Spreadsheet

If NYC Showroom.xlsx is updated and you need to refresh the embedded records:

  1. Run the PowerShell extraction scripts (saved in %TEMP% from the original build):
    • export_v2.ps1 — reads the Excel XML and writes inventory_v2.json
    • inject_json.ps1 — injects the JSON into html_template.txt and writes index.html
  2. Or paste the updated JSON array directly into the <script type="application/json" id="inventory-data"> block inside index.html

Existing browser-side quantity changes are preserved after a re-import — the merge logic keeps localStorage values for known SKUs and only adds new ones from the embedded JSON.


Resetting to Factory State

Paste in the browser console (DevTools → Console) to wipe all saved changes and reload from the embedded spreadsheet data:

localStorage.removeItem('tilebar-inv-nyc');
localStorage.removeItem('tilebar-thr-nyc');
localStorage.removeItem('tilebar-gthr-nyc');
localStorage.removeItem('tilebar-contacts-nyc');
localStorage.removeItem('tilebar-history-nyc');
location.reload();

To reset individual stores without touching others:

// Contacts only
localStorage.removeItem('tilebar-contacts-nyc');

// History/audit log only
localStorage.removeItem('tilebar-history-nyc');

// Inventory quantities only (reverts to embedded spreadsheet data)
localStorage.removeItem('tilebar-inv-nyc');

location.reload();

Do I Need a Backend Database?

Short answer: No — the current version works fine on any computer, including machines 5–7 years old.

Why the current version is solid

Concern Reality
Browser compatibility Chrome 80+ (released 2020) runs on any Windows 7+ machine. A 5–7 year old PC running Windows 10 handles this with ease
Performance 2,731 records in memory is tiny — filtering and sorting happens in microseconds. Even a 2015 Intel Core i3 with 4 GB RAM won't break a sweat
No install, no network Nothing to configure, no IT department needed, works offline — plug in a USB scanner and go
Data safety localStorage survives browser restarts and Windows updates. Only clears if someone explicitly wipes browser data
File size 805 KB HTML + 30 KB JS + 17 KB CSS — loads instantly even on a spinning hard drive

When you SHOULD consider moving to a backend database

Consider it only if you hit one of these real problems:

  1. Multiple people editing at the same time — if two staff members update the same item from different computers, neither sees the other's change. Changes don't sync between machines
  2. Inventory grows beyond ~10,000 items — embedded JSON starts to feel slow to load at that scale
  3. You need a central audit trail — currently history is per-browser. If Jay updates from the front desk PC and someone else updates from a tablet, the histories are siloed
  4. Management wants reports or dashboards — pulling data from a database into charts is straightforward; pulling from scattered localStorage instances is not

The middle-ground option (no database needed)

If the only problem is sync between computers, you can solve it without a database at all:

  • Shared network folder — save the exported JSON to a shared drive (or OneDrive / SharePoint) and load it from there; every computer reads the same file
  • Google Sheets as a backend — use the free Google Sheets API to keep the spreadsheet workflow your team already knows, with real-time sync added on top

Recommendation

Stay with the current version unless you have two or more people actively editing inventory simultaneously on different machines. For a single showroom where one person at a time manages the sample room, this setup is more reliable than a database — fewer moving parts, nothing that can go down, and it runs comfortably on hardware from 2015.

About

Tile store inventory portal

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages