“Item Hunt” is a comprehensive collectible item tracking system that provides visual management for a collection of 100 numbered items. The application features Firebase Firestore integration for real-time data synchronization, responsive grid layout, and intelligent status tracking with temporal indicators. Designed for collectors, traders, or inventory management, it offers an intuitive interface for monitoring item discovery and acquisition status.
itemhunt/
├── index.html # Complete item tracking application
├── 001.jpg - 100.jpg # Individual item images (referenced but not analyzed)
└── Firebase Firestore # Cloud database for item status tracking
// Firebase Firestore configuration
const firebaseConfig = {
apiKey: "AIzaSyCiN_rH3ekJXC_W7MU2xZ77Vu7CYrS6uYQ",
authDomain: "item-hunt.firebaseapp.com",
projectId: "item-hunt",
storageBucket: "item-hunt.firebasestorage.app",
messagingSenderId: "995765553615",
appId: "1:995765553615:web:a253fff364374039bbeaba",
measurementId: "G-5ER7MBLZZ7"
};
// Initialize Firebase and Firestore
firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
// Firestore collection: "items"
// Document structure for each item:
{
"001": { // Document ID (item code)
"found": true, // Boolean: item discovery status
"dateFound": "2024-01-15" // ISO date string: discovery date
},
"002": {
"found": false, // Not yet discovered
"dateFound": null // No discovery date
}
// ... continues for items 001-100
}
async function loadItems() {
let itemsData = {};
try {
// Fetch all items from Firestore
const snapshot = await db.collection("items").get();
snapshot.forEach(doc => {
itemsData[doc.id] = doc.data();
});
} catch (error) {
console.error("Error fetching items:", error);
}
// Process and render grid with fetched data
renderItemGrid(itemsData);
}
function calculateStatusText(dateFound) {
const foundDate = new Date(dateFound);
const today = new Date();
// Normalize dates to midnight for accurate day calculation
foundDate.setHours(0, 0, 0, 0);
today.setHours(0, 0, 0, 0);
// Calculate difference in days
const diffTime = today - foundDate;
const diffDays = diffTime / (1000 * 60 * 60 * 24);
// Return contextual status messages
if (diffDays === 0) {
return "item found today";
} else if (diffDays === 1) {
return "item found yesterday";
} else {
return `item found ${diffDays} days ago`;
}
}
.grid-container {
display: grid;
grid-gap: 16px;
padding: 16px;
}
/* Mobile-first responsive design */
@media (max-width: 767px) {
.grid-container {
grid-template-columns: repeat(2, 1fr); /* 2 columns on mobile */
}
}
@media (min-width: 768px) {
.grid-container {
grid-template-columns: repeat(5, 1fr); /* 5 columns on desktop */
}
}
/* Outer container with aesthetic border and shadow */
.grid-item {
border: 4px solid #f8f8f8; /* Off-white outer border */
border-radius: 20px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Subtle drop shadow */
overflow: hidden;
}
/* Inner container with status-dependent colored border */
.grid-inner {
margin: 4px; /* Gap between borders */
padding: 10px;
border: 6px solid; /* Thick status border */
border-radius: 16px;
}
/* Dynamic border coloring based on item status */
gridInner.style.borderColor = found ? '#0F9D58' : '#DB4437';
/* Status color system using Google's design palette */
.red-color {
color: #DB4437; /* Google Red for unfound items */
}
.green-color {
color: #0F9D58; /* Google Green for found items */
}
.item-number, .status {
font-weight: bold;
font-size: 1.44em; /* Proportional scaling */
margin: 5px 0;
}
.info {
display: flex;
justify-content: space-between; /* Item number left, status right */
align-items: center;
margin-top: 10px;
}
.grid-inner img {
width: 100%; /* Full container width */
display: block;
border-radius: 10px; /* Rounded image corners */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Soft image shadow */
}
// Generate 100 item grid dynamically
for (let i = 1; i <= 100; i++) {
let code = ("000" + i).slice(-3); // Zero-padded 3-digit codes (001-100)
let data = itemsData[code] || { found: false }; // Default to unfound
let found = data.found;
// Calculate appropriate status text
let statusText = "item not found";
if (found && data.dateFound) {
statusText = calculateStatusText(data.dateFound);
}
// Create complete grid item structure
const gridItem = createGridItem(code, found, statusText);
container.appendChild(gridItem);
}
function createGridItem(code, found, statusText) {
// Outer container creation
const gridItem = document.createElement('div');
gridItem.classList.add('grid-item');
// Inner container with status-based styling
const gridInner = document.createElement('div');
gridInner.classList.add('grid-inner');
gridInner.style.borderColor = found ? '#0F9D58' : '#DB4437';
// Image element configuration
const img = document.createElement('img');
img.src = code + ".jpg"; // Expected: 001.jpg, 002.jpg, etc.
img.alt = `Item ${code}`;
gridInner.appendChild(img);
// Information display section
const infoDiv = document.createElement('div');
infoDiv.classList.add('info');
// Item number display
const numberDiv = document.createElement('div');
numberDiv.classList.add('item-number');
numberDiv.textContent = code;
infoDiv.appendChild(numberDiv);
// Status display with color coding
const statusDiv = document.createElement('div');
statusDiv.classList.add('status');
statusDiv.textContent = statusText;
statusDiv.classList.add(found ? 'green-color' : 'red-color');
infoDiv.appendChild(statusDiv);
gridInner.appendChild(infoDiv);
gridItem.appendChild(gridInner);
return gridItem;
}
// Efficient item data processing
let itemsData = {};
snapshot.forEach(doc => {
itemsData[doc.id] = doc.data(); // Simple object mapping
});
// Zero-padded code generation
let code = ("000" + i).slice(-3); // Efficient string padding
try {
const snapshot = await db.collection("items").get();
snapshot.forEach(doc => {
itemsData[doc.id] = doc.data();
});
} catch (error) {
console.error("Error fetching items:", error);
// Graceful degradation: continues with empty itemsData object
}
// Potential analytics calculations
function calculateCollectionStats(itemsData) {
const totalItems = 100;
const foundItems = Object.values(itemsData).filter(item => item.found).length;
const completionRate = (foundItems / totalItems) * 100;
const recentFinds = Object.values(itemsData)
.filter(item => item.found && item.dateFound)
.map(item => new Date(item.dateFound))
.filter(date => (new Date() - date) <= 7 * 24 * 60 * 60 * 1000); // Last 7 days
return {
totalItems,
foundItems,
completionRate,
recentFinds: recentFinds.length,
missingItems: totalItems - foundItems
};
}
// Validate item data structure
function validateItemData(data) {
return data &&
typeof data.found === 'boolean' &&
(data.dateFound === null || typeof data.dateFound === 'string');
}
Item Hunt represents an elegant solution for collectible item tracking that successfully combines modern web technologies with practical collection management needs. The Firebase integration, responsive design, and intelligent status system create a professional tool for collectors and inventory managers.
Technical Rating: 8.4/10
The application successfully demonstrates how simple concepts can be elevated through thoughtful technical implementation, creating a valuable tool for collection enthusiasts and inventory management scenarios.