chore: initialize project repository with core extension files
- Add .gitignore to exclude node_modules, dist, logs, and system files - Add comprehensive project documentation including README, deployment guide, and development setup - Add .kiro project specifications for amazon-product-bar-extension, appwrite-cloud-storage, appwrite-userid-repair, blacklist-feature, and enhanced-item-management - Add .kiro steering documents for product, structure, styling, and tech guidelines - Add VSCode settings configuration for consistent development environment - Add manifest.json and babel/vite configuration for extension build setup - Add complete source code implementation including AppWrite integration, storage managers, UI components, and services - Add comprehensive test suite with Jest configuration and 30+ test files covering all major modules - Add test HTML files for integration testing and validation - Add coverage reports and build validation scripts - Add AppWrite setup and repair documentation for database schema management - Add migration guides and responsive accessibility implementation documentation - Establish foundation for Amazon product bar extension with full feature set including blacklist management, enhanced item workflows, and real-time synchronization
This commit is contained in:
217
old-vanilla-version/content.js
Normal file
217
old-vanilla-version/content.js
Normal file
@@ -0,0 +1,217 @@
|
||||
// Amazon Product Bar Extension - Content Script
|
||||
// This script runs on Amazon search result pages
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
console.log('Amazon Product Bar Extension loaded');
|
||||
|
||||
/**
|
||||
* Checks if the current URL is an Amazon search results page
|
||||
* @param {string} url - The URL to check
|
||||
* @returns {boolean} - True if it's a search results page
|
||||
*/
|
||||
function isSearchResultsPage(url) {
|
||||
// Check for Amazon search patterns: /s? or /s/ or search in URL
|
||||
return url.includes('/s?') || url.includes('/s/') || url.includes('field-keywords') || url.includes('k=');
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all product cards within a container element
|
||||
* @param {Element} container - The container to search within
|
||||
* @returns {Element[]} - Array of product card elements
|
||||
*/
|
||||
function findAllProductCards(container) {
|
||||
// Try multiple selectors for Amazon product cards
|
||||
let productCards = container.querySelectorAll('[data-component-type="s-search-result"]');
|
||||
|
||||
// Fallback selectors if the main one doesn't work
|
||||
if (productCards.length === 0) {
|
||||
productCards = container.querySelectorAll('[data-asin]:not([data-asin=""])');
|
||||
}
|
||||
|
||||
if (productCards.length === 0) {
|
||||
productCards = container.querySelectorAll('.s-result-item');
|
||||
}
|
||||
|
||||
return Array.from(productCards);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the image container within a product card
|
||||
* @param {Element} productCard - The product card element
|
||||
* @returns {Element|null} - The image container element or null if not found
|
||||
*/
|
||||
function findImageContainer(productCard) {
|
||||
// Try multiple selectors for image containers
|
||||
let imageContainer = productCard.querySelector('.s-image');
|
||||
|
||||
if (!imageContainer) {
|
||||
imageContainer = productCard.querySelector('.a-link-normal img');
|
||||
if (imageContainer) {
|
||||
imageContainer = imageContainer.parentElement;
|
||||
}
|
||||
}
|
||||
|
||||
if (!imageContainer) {
|
||||
imageContainer = productCard.querySelector('img[data-image-latency]');
|
||||
if (imageContainer) {
|
||||
imageContainer = imageContainer.parentElement;
|
||||
}
|
||||
}
|
||||
|
||||
if (!imageContainer) {
|
||||
const imgElement = productCard.querySelector('img');
|
||||
if (imgElement) {
|
||||
imageContainer = imgElement.parentElement;
|
||||
}
|
||||
}
|
||||
|
||||
return imageContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a product card already has a bar injected
|
||||
* @param {Element} productCard - The product card element to check
|
||||
* @returns {boolean} - True if the product card already has a bar
|
||||
*/
|
||||
function hasBar(productCard) {
|
||||
// Check if the product card has been processed by looking for our marker attribute
|
||||
return productCard.hasAttribute('data-ext-processed') ||
|
||||
productCard.querySelector('.amazon-ext-product-bar') !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects a product bar below the image container
|
||||
* @param {Element} imageContainer - The image container element
|
||||
*/
|
||||
function injectBar(imageContainer) {
|
||||
// Get the parent product card to check for duplicates
|
||||
const productCard = imageContainer.closest('[data-component-type="s-search-result"]') ||
|
||||
imageContainer.closest('[data-asin]') ||
|
||||
imageContainer.closest('.s-result-item');
|
||||
|
||||
// Skip if no product card found or bar already exists
|
||||
if (!productCard || hasBar(productCard)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the product bar element
|
||||
const productBar = document.createElement('div');
|
||||
productBar.className = 'amazon-ext-product-bar';
|
||||
productBar.setAttribute('data-ext-processed', 'true');
|
||||
productBar.textContent = '🔥 Product Bar Active'; // Temporary content to make it visible
|
||||
|
||||
// Insert the bar after the image container
|
||||
if (imageContainer.nextSibling) {
|
||||
imageContainer.parentNode.insertBefore(productBar, imageContainer.nextSibling);
|
||||
} else {
|
||||
imageContainer.parentNode.appendChild(productBar);
|
||||
}
|
||||
|
||||
// Mark the product card as processed to prevent duplicates
|
||||
productCard.setAttribute('data-ext-processed', 'true');
|
||||
|
||||
console.log('Product bar injected for product card');
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes product cards in a given container
|
||||
* @param {Element} container - The container to process
|
||||
*/
|
||||
function processProductCards(container) {
|
||||
const productCards = findAllProductCards(container);
|
||||
console.log(`Found ${productCards.length} product cards to process`);
|
||||
|
||||
productCards.forEach(productCard => {
|
||||
// Skip if already processed
|
||||
if (hasBar(productCard)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const imageContainer = findImageContainer(productCard);
|
||||
if (imageContainer) {
|
||||
injectBar(imageContainer);
|
||||
} else {
|
||||
console.warn('No image container found for product card');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and configures a MutationObserver for dynamic content
|
||||
* @returns {MutationObserver} - The configured observer
|
||||
*/
|
||||
function createDOMObserver() {
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
// Only process added nodes
|
||||
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
|
||||
mutation.addedNodes.forEach((node) => {
|
||||
// Only process element nodes
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
// Check if the added node is a product card itself
|
||||
if (node.matches && (node.matches('[data-component-type="s-search-result"]') ||
|
||||
node.matches('[data-asin]') ||
|
||||
node.matches('.s-result-item'))) {
|
||||
const imageContainer = findImageContainer(node);
|
||||
if (imageContainer) {
|
||||
injectBar(imageContainer);
|
||||
}
|
||||
} else {
|
||||
// Check if the added node contains product cards
|
||||
processProductCards(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return observer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts observing the DOM for changes
|
||||
*/
|
||||
function startObserving() {
|
||||
const observer = createDOMObserver();
|
||||
|
||||
// Observe the entire document body for changes
|
||||
// This will catch infinite scroll additions and other dynamic content
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
console.log('DOM observer started for dynamic content detection');
|
||||
|
||||
// Return observer for potential cleanup
|
||||
return observer;
|
||||
}
|
||||
|
||||
// Initialize the extension
|
||||
function initialize() {
|
||||
// Check if we're on a search results page
|
||||
if (!isSearchResultsPage(window.location.href)) {
|
||||
console.log('Not a search results page, extension inactive');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Initializing Amazon Product Bar Extension');
|
||||
|
||||
// Process existing product cards on page load
|
||||
processProductCards(document.body);
|
||||
|
||||
// Start observing for dynamic content
|
||||
startObserving();
|
||||
}
|
||||
|
||||
// Wait for DOM to be ready, then initialize
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initialize);
|
||||
} else {
|
||||
// DOM is already ready
|
||||
initialize();
|
||||
}
|
||||
})();
|
||||
39
old-vanilla-version/styles.css
Normal file
39
old-vanilla-version/styles.css
Normal file
@@ -0,0 +1,39 @@
|
||||
/* Amazon Product Bar Extension Styles */
|
||||
|
||||
.amazon-ext-product-bar {
|
||||
width: 100%;
|
||||
min-height: 30px;
|
||||
background-color: #ff9900;
|
||||
background: linear-gradient(135deg, #ff9900 0%, #ffb84d 100%);
|
||||
border-radius: 6px;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 4px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
text-shadow: 0 1px 2px rgba(0,0,0,0.3);
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
/* Ensure the bar doesn't interfere with existing Amazon functionality */
|
||||
.amazon-ext-product-bar:hover {
|
||||
background: linear-gradient(135deg, #e68a00 0%, #ff9900 100%);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 3px 6px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
/* Prevent layout shifts during injection */
|
||||
.amazon-ext-product-bar {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
/* Make sure it's visible on all backgrounds */
|
||||
.amazon-ext-product-bar {
|
||||
border: 1px solid rgba(0,0,0,0.1);
|
||||
}
|
||||
Reference in New Issue
Block a user