<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;
padding: 20px;
background: #f5f5f5;
color: #333;
}
body.dark-mode {
background: #1a1a1a;
color: #e0e0e0;
}
.target-logo {
width: 48px;
height: 48px;
background: linear-gradient(135deg, #cc0000 0%, #ff0000 100%);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 8px rgba(204, 0, 0, 0.3);
position: relative;
}
.target-logo::before {
content: '';
position: absolute;
width: 33px;
height: 33px;
border-radius: 50%;
background: white;
}
.target-logo::after {
content: '';
position: absolute;
width: 18px;
height: 18px;
border-radius: 50%;
background: #cc0000;
}
.header {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 20px;
}
.header-content {
flex: 1;
}
.header h1 {
font-size: 24px;
color: #cc0000;
margin-bottom: 4px;
}
.header p {
color: #666;
font-size: 14px;
}
body.dark-mode .header p {
color: #999;
}
.carousel-container {
position: relative;
overflow: hidden;
padding: 0 40px;
}
.carousel {
display: flex;
gap: 16px;
overflow-x: auto;
scroll-behavior: smooth;
scrollbar-width: thin;
padding: 8px 0;
}
.carousel::-webkit-scrollbar {
height: 6px;
}
.carousel::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
.carousel::-webkit-scrollbar-thumb {
background: #cc0000;
border-radius: 3px;
}
.product-card {
min-width: 280px;
background: white;
border-radius: 12px;
padding: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.2s, box-shadow 0.2s;
cursor: pointer;
}
body.dark-mode .product-card {
background: #2a2a2a;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.product-card:hover {
transform: translateY(-4px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
body.dark-mode .product-card:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
}
.product-image {
width: 100%;
height: 200px;
object-fit: contain;
border-radius: 8px;
background: #f9f9f9;
margin-bottom: 12px;
}
body.dark-mode .product-image {
background: #1a1a1a;
}
.product-title {
font-size: 14px;
font-weight: 600;
color: #333;
margin-bottom: 8px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
min-height: 40px;
}
body.dark-mode .product-title {
color: #e0e0e0;
}
.product-price {
font-size: 20px;
font-weight: 700;
color: #cc0000;
margin-bottom: 8px;
}
.product-rating {
display: flex;
align-items: center;
gap: 4px;
font-size: 12px;
color: #666;
margin-bottom: 8px;
}
body.dark-mode .product-rating {
color: #999;
}
.stars {
color: #ffa500;
font-weight: bold;
}
.product-link {
display: block;
text-align: center;
background: #cc0000;
color: white;
padding: 8px 16px;
border-radius: 6px;
text-decoration: none;
font-size: 13px;
font-weight: 600;
margin-top: 12px;
transition: background 0.2s;
}
.product-link:hover {
background: #aa0000;
}
.nav-button {
position: absolute;
top: 50%;
transform: translateY(-50%);
background: white;
border: none;
width: 36px;
height: 36px;
border-radius: 50%;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
color: #333;
z-index: 10;
transition: transform 0.2s;
}
body.dark-mode .nav-button {
background: #2a2a2a;
color: #e0e0e0;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
}
.nav-button:hover {
transform: translateY(-50%) scale(1.1);
}
.nav-button.prev {
left: 0;
}
.nav-button.next {
right: 0;
}
.no-results {
text-align: center;
padding: 40px;
color: #666;
}
body.dark-mode .no-results {
color: #999;
}
.loading {
text-align: center;
padding: 40px;
color: #666;
}
body.dark-mode .loading {
color: #999;
}
.loading-spinner {
display: inline-block;
width: 40px;
height: 40px;
border: 4px solid rgba(204, 0, 0, 0.2);
border-top-color: #cc0000;
border-radius: 50%;
animation: spin 0.8s linear infinite;
margin-bottom: 16px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.results-count {
text-align: center;
color: #666;
font-size: 14px;
margin-bottom: 16px;
}
body.dark-mode .results-count {
color: #999;
}
.hidden {
display: none !important;
}
/* Product Detail Page */
.product-detail {
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
body.dark-mode .product-detail {
background: #2a2a2a;
}
.back-button {
display: inline-flex;
align-items: center;
gap: 8px;
background: #f5f5f5;
border: none;
padding: 10px 16px;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
font-weight: 600;
color: #333;
margin-bottom: 20px;
transition: background 0.2s;
}
body.dark-mode .back-button {
background: #1a1a1a;
color: #e0e0e0;
}
.back-button:hover {
background: #e0e0e0;
}
body.dark-mode .back-button:hover {
background: #333;
}
.product-detail-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 32px;
margin-bottom: 24px;
}
.product-detail-image {
width: 100%;
max-height: 400px;
object-fit: contain;
border-radius: 8px;
background: #f9f9f9;
}
body.dark-mode .product-detail-image {
background: #1a1a1a;
}
.product-detail-info h2 {
font-size: 24px;
margin-bottom: 16px;
color: #333;
}
body.dark-mode .product-detail-info h2 {
color: #e0e0e0;
}
.product-detail-price {
font-size: 32px;
font-weight: 700;
color: #cc0000;
margin-bottom: 16px;
}
.product-detail-description {
color: #666;
line-height: 1.6;
margin-bottom: 20px;
}
body.dark-mode .product-detail-description {
color: #999;
}
.buy-button {
display: inline-block;
background: #cc0000;
color: white;
padding: 14px 32px;
border-radius: 8px;
text-decoration: none;
font-size: 16px;
font-weight: 600;
transition: background 0.2s;
}
.buy-button:hover {
background: #aa0000;
}
</style>
</head>
<body>
<div class="header">
<div class="target-logo"></div>
<div class="header-content">
<h1>Target Shopping</h1>
<p id="query-text">Loading results...</p>
</div>
</div>
<div id="results-count" class="results-count"></div>
<div id="loading" class="loading">
<div class="loading-spinner"></div>
<p>Loading products...</p>
</div>
<div id="no-results" class="no-results" style="display: none;">
<p>No products found. Try a different search!</p>
</div>
<div id="carousel-wrapper" style="display: none;">
<div class="carousel-container">
<button class="nav-button prev" onclick="scrollCarousel(-1)">‹</button>
<div id="carousel" class="carousel"></div>
<button class="nav-button next" onclick="scrollCarousel(1)">›</button>
</div>
</div>
<div id="product-detail-wrapper" style="display: none;">
<div class="product-detail">
<button class="back-button" onclick="showCarousel()">
← Back to Results
</button>
<div class="product-detail-grid">
<div>
<img id="detail-image" class="product-detail-image" src="" alt="">
</div>
<div class="product-detail-info">
<h2 id="detail-title"></h2>
<div id="detail-rating" class="product-rating"></div>
<div id="detail-price" class="product-detail-price"></div>
<div id="detail-description" class="product-detail-description"></div>
<a id="detail-link" href="#" target="_blank" class="buy-button">View on Target.com</a>
</div>
</div>
</div>
</div>
<script>
// Apply dark mode
const theme = window.openai?.theme || 'light';
if (theme === 'dark') {
document.body.classList.add('dark-mode');
}
console.log('Theme:', theme);
// Wait for toolOutput to be available
let productsData = [];
let checkInterval;
function initializeCarousel() {
const toolOutput = window.openai?.toolOutput || {};
const products = toolOutput.products || [];
const query = toolOutput.query || '';
const totalResults = toolOutput.total_results || 0;
// If we have data, proceed
if (products.length > 0 || query) {
clearInterval(checkInterval);
productsData = products;
console.log('Product carousel loaded with:', { query, totalResults, products });
// Update query text
document.getElementById('query-text').textContent = `Results for "${query}"`;
// Hide loading
document.getElementById('loading').style.display = 'none';
if (products.length === 0) {
document.getElementById('no-results').style.display = 'block';
} else {
document.getElementById('carousel-wrapper').style.display = 'block';
document.getElementById('results-count').textContent = `Showing ${products.length} products`;
renderCarousel(products);
}
}
}
function renderCarousel(products) {
const carousel = document.getElementById('carousel');
carousel.innerHTML = '';
products.forEach((product, index) => {
const card = document.createElement('div');
card.className = 'product-card';
const imageUrl = product.thumbnail || product.image || product.img || 'https://via.placeholder.com/280x200?text=No+Image';
const title = product.title || product.name || product.product_title || 'Product';
const price = product.price || product.current_price || 'N/A';
const rating = product.rating || product.stars || 0;
const reviewCount = product.reviews_count || product.reviews || product.review_count || product.number_of_reviews || 0;
card.innerHTML = `
<img src="${imageUrl}" alt="${title}" class="product-image" onerror="this.src='https://via.placeholder.com/280x200?text=No+Image'">
<div class="product-title">${title}</div>
<div class="product-price">$${price}</div>
${rating > 0 ? `
<div class="product-rating">
<span class="stars">${'★'.repeat(Math.round(rating))}${'☆'.repeat(5 - Math.round(rating))}</span>
${reviewCount > 0 ? `<span>(${reviewCount} reviews)</span>` : ''}
</div>
` : ''}
`;
// Add click handler to show product detail
card.addEventListener('click', () => showProductDetail(product));
carousel.appendChild(card);
});
}
function showProductDetail(product) {
// Hide carousel
document.getElementById('carousel-wrapper').style.display = 'none';
document.getElementById('results-count').style.display = 'none';
// Show detail page
document.getElementById('product-detail-wrapper').style.display = 'block';
// Populate detail page
const imageUrl = product.thumbnail || product.image || product.img || 'https://via.placeholder.com/400x400?text=No+Image';
const title = product.title || product.name || product.product_title || 'Product';
const price = product.price || product.current_price || 'N/A';
const rating = product.rating || product.stars || 0;
const reviewCount = product.reviews_count || product.reviews || product.review_count || product.number_of_reviews || 0;
const description = product.description || product.features || 'No description available.';
const productUrl = product.url || product.link || '#';
document.getElementById('detail-image').src = imageUrl;
document.getElementById('detail-image').alt = title;
document.getElementById('detail-title').textContent = title;
document.getElementById('detail-price').textContent = `$${price}`;
// Rating
if (rating > 0) {
document.getElementById('detail-rating').innerHTML = `
<span class="stars">${'★'.repeat(Math.round(rating))}${'☆'.repeat(5 - Math.round(rating))}</span>
${reviewCount > 0 ? `<span>(${reviewCount} reviews)</span>` : ''}
`;
document.getElementById('detail-rating').style.display = 'flex';
} else {
document.getElementById('detail-rating').style.display = 'none';
}
// Description
if (Array.isArray(description)) {
document.getElementById('detail-description').innerHTML = '<ul>' + description.map(item => `<li>${item}</li>`).join('') + '</ul>';
} else {
document.getElementById('detail-description').textContent = description;
}
document.getElementById('detail-link').href = productUrl;
}
function showCarousel() {
// Hide detail page
document.getElementById('product-detail-wrapper').style.display = 'none';
// Show carousel
document.getElementById('carousel-wrapper').style.display = 'block';
document.getElementById('results-count').style.display = 'block';
}
// Scroll carousel
function scrollCarousel(direction) {
const carousel = document.getElementById('carousel');
const scrollAmount = 300;
carousel.scrollBy({
left: direction * scrollAmount,
behavior: 'smooth'
});
}
// Check for data every 200ms
checkInterval = setInterval(initializeCarousel, 200);
// Also try immediately
initializeCarousel();
</script>
</body>
</html>