trying-selection-list / index.html
sunole's picture
Add 1 files
3fa1641 verified
Raw History Blame Contribute Delete
17.7 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interactive Selectable List with Buy/Sell</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.fade-in {
animation: fadeIn 0.3s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
.item-selected {
transform: scale(0.98);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.checkbox-custom {
appearance: none;
-webkit-appearance: none;
width: 20px;
height: 20px;
border: 2px solid #4f46e5;
border-radius: 4px;
outline: none;
cursor: pointer;
position: relative;
transition: all 0.2s;
}
.checkbox-custom:checked {
background-color: #4f46e5;
}
.checkbox-custom:checked::after {
content: '\f00c';
font-family: 'Font Awesome 6 Free';
font-weight: 900;
position: absolute;
color: white;
font-size: 12px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.bounce {
animation: bounce 0.5s;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-5px); }
}
.action-btn {
padding: 0.25rem 0.75rem;
border-radius: 0.375rem;
font-size: 0.75rem;
font-weight: 500;
transition: all 0.2s;
cursor: pointer;
user-select: none;
}
.buy-btn {
background-color: #10b981;
color: white;
}
.buy-btn:hover {
background-color: #059669;
}
.sell-btn {
background-color: #ef4444;
color: white;
}
.sell-btn:hover {
background-color: #dc2626;
}
.close-btn {
background-color: #3b82f6;
color: white;
}
.close-btn:hover {
background-color: #2563eb;
}
.action-container {
display: flex;
gap: 0.5rem;
margin-left: 1rem;
}
</style>
</head>
<body class="bg-gray-50 min-h-screen flex items-center justify-center p-4">
<div class="w-full max-w-md mx-auto">
<div class="bg-white rounded-xl shadow-lg overflow-hidden transition-all duration-300">
<div class="p-6">
<h2 class="text-2xl font-bold text-indigo-600 mb-4 flex items-center">
<i class="fas fa-list-check mr-2"></i> Selectable Items
</h2>
<div class="mb-4 relative">
<input
type="text"
id="searchInput"
placeholder="Search items..."
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none transition"
>
<i class="fas fa-search absolute right-3 top-3 text-gray-400"></i>
</div>
<div class="flex justify-between items-center mb-3">
<span class="text-sm text-gray-600" id="selectedCount">0 selected</span>
<button
id="clearAllBtn"
class="text-sm text-indigo-600 hover:text-indigo-800 transition hidden"
>
Clear all
</button>
</div>
<div class="border border-gray-200 rounded-lg overflow-hidden">
<div id="itemsContainer" class="max-h-96 overflow-y-auto">
<!-- Items will be inserted here by JavaScript -->
</div>
</div>
<div class="mt-4 flex justify-between items-center">
<div class="text-sm text-gray-500" id="totalItems">Total: 0 items</div>
<button
id="submitBtn"
class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition disabled:opacity-50 disabled:cursor-not-allowed"
disabled
>
Confirm Selection
</button>
</div>
</div>
</div>
<div class="mt-8 bg-white rounded-xl shadow-lg p-6">
<h3 class="text-lg font-semibold text-gray-800 mb-3">Add Custom Items</h3>
<div class="flex gap-2">
<input
type="text"
id="newItemInput"
placeholder="Enter new item"
class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none transition"
>
<button
id="addItemBtn"
class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition"
>
<i class="fas fa-plus"></i> Add
</button>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Sample initial data
const initialItems = [
"Apple", "Banana", "Cherry", "Date", "Elderberry",
"Fig", "Grape", "Honeydew", "Kiwi", "Lemon",
"Mango", "Nectarine", "Orange", "Peach", "Quince"
];
// Load data from localStorage or initialize
const savedData = localStorage.getItem('selectableListData');
let items, selectedItems, itemActions;
if (savedData) {
const parsedData = JSON.parse(savedData);
items = parsedData.items || [...initialItems];
selectedItems = parsedData.selectedItems || [];
itemActions = parsedData.itemActions || {};
} else {
items = [...initialItems];
selectedItems = [];
itemActions = {};
}
// Initialize item actions for any new items
items.forEach(item => {
if (!itemActions.hasOwnProperty(item)) {
itemActions[item] = null;
}
});
// Save data to localStorage
function saveToLocalStorage() {
const dataToSave = {
items: items,
selectedItems: selectedItems,
itemActions: itemActions
};
localStorage.setItem('selectableListData', JSON.stringify(dataToSave));
}
// DOM elements
const itemsContainer = document.getElementById('itemsContainer');
const searchInput = document.getElementById('searchInput');
const selectedCount = document.getElementById('selectedCount');
const clearAllBtn = document.getElementById('clearAllBtn');
const submitBtn = document.getElementById('submitBtn');
const totalItems = document.getElementById('totalItems');
const newItemInput = document.getElementById('newItemInput');
const addItemBtn = document.getElementById('addItemBtn');
// Render items
function renderItems(itemsToRender = items) {
itemsContainer.innerHTML = '';
if (itemsToRender.length === 0) {
itemsContainer.innerHTML = `
<div class="p-4 text-center text-gray-500">
<i class="fas fa-inbox text-3xl mb-2 text-gray-300"></i>
<p>No items found</p>
</div>
`;
return;
}
itemsToRender.forEach((item, index) => {
const isSelected = selectedItems.includes(item);
const action = itemActions[item];
const itemElement = document.createElement('div');
itemElement.className = `p-3 border-b border-gray-100 flex items-center justify-between cursor-pointer transition ${isSelected ? 'bg-indigo-50 item-selected' : 'hover:bg-gray-50'} fade-in`;
// Create action buttons based on current state
let actionButtons = '';
if (action === 'buy' || action === 'sell') {
actionButtons = `
<div class="action-container">
<div class="action-btn close-btn" data-item="${item}" data-action="close">
Close ${action === 'buy' ? 'Buy' : 'Sell'}
</div>
</div>
`;
} else {
actionButtons = `
<div class="action-container">
<div class="action-btn buy-btn" data-item="${item}" data-action="buy">
Buy
</div>
<div class="action-btn sell-btn" data-item="${item}" data-action="sell">
Sell
</div>
</div>
`;
}
itemElement.innerHTML = `
<span class="flex-1 ${isSelected ? 'font-medium text-indigo-700' : 'text-gray-700'}">${item}</span>
${actionButtons}
<input
type="checkbox"
class="checkbox-custom"
${isSelected ? 'checked' : ''}
data-item="${item}"
>
`;
// Add click handler for the item row
itemElement.addEventListener('click', (e) => {
// Don't toggle selection if clicking on action buttons
if (!e.target.closest('.action-btn')) {
toggleSelection(item);
}
});
// Add click handlers for action buttons
const actionBtns = itemElement.querySelectorAll('.action-btn');
actionBtns.forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
const action = btn.dataset.action;
handleItemAction(item, action);
});
});
itemsContainer.appendChild(itemElement);
});
updateUI();
}
// Handle buy/sell/close actions
function handleItemAction(item, action) {
if (action === 'buy' || action === 'sell') {
itemActions[item] = action;
} else if (action === 'close') {
itemActions[item] = null;
}
// Add animation to the changed element
const itemElement = document.querySelector(`[data-item="${item}"]`).closest('div');
if (itemElement) {
itemElement.classList.add('bounce');
setTimeout(() => {
itemElement.classList.remove('bounce');
}, 500);
}
saveToLocalStorage();
renderItems(getFilteredItems());
}
// Toggle item selection
function toggleSelection(item) {
const index = selectedItems.indexOf(item);
if (index === -1) {
selectedItems.push(item);
} else {
selectedItems.splice(index, 1);
}
saveToLocalStorage();
renderItems(getFilteredItems());
// Add bounce animation to the checkbox
const checkbox = document.querySelector(`input[data-item="${item}"]`);
if (checkbox) {
checkbox.parentElement.classList.add('bounce');
setTimeout(() => {
checkbox.parentElement.classList.remove('bounce');
}, 500);
}
}
// Filter items based on search input
function getFilteredItems() {
const searchTerm = searchInput.value.toLowerCase();
return items.filter(item =>
item.toLowerCase().includes(searchTerm)
);
}
// Update UI elements
function updateUI() {
selectedCount.textContent = `${selectedItems.length} selected`;
totalItems.textContent = `Total: ${items.length} items`;
// Toggle clear all button
if (selectedItems.length > 0) {
clearAllBtn.classList.remove('hidden');
submitBtn.disabled = false;
} else {
clearAllBtn.classList.add('hidden');
submitBtn.disabled = true;
}
}
// Clear all selections
function clearAllSelections() {
selectedItems = [];
saveToLocalStorage();
renderItems(getFilteredItems());
}
// Add new item
function addNewItem() {
const newItem = newItemInput.value.trim();
if (newItem && !items.includes(newItem)) {
items.unshift(newItem);
itemActions[newItem] = null; // Initialize action for new item
newItemInput.value = '';
saveToLocalStorage();
renderItems(getFilteredItems());
// Highlight the newly added item
setTimeout(() => {
const firstItem = itemsContainer.firstChild;
if (firstItem) {
firstItem.classList.add('bg-green-50');
setTimeout(() => {
firstItem.classList.remove('bg-green-50');
}, 2000);
}
}, 100);
}
}
// Event listeners
searchInput.addEventListener('input', () => {
renderItems(getFilteredItems());
});
clearAllBtn.addEventListener('click', clearAllSelections);
submitBtn.addEventListener('click', () => {
// Prepare action summary
let actionSummary = [];
for (const item in itemActions) {
if (itemActions[item]) {
actionSummary.push(`${item} (${itemActions[item]})`);
}
}
alert(`Selected items: ${selectedItems.join(', ')}\n\nActions:\n${actionSummary.join('\n')}`);
});
newItemInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
addNewItem();
}
});
addItemBtn.addEventListener('click', addNewItem);
// Initialize
renderItems();
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=sunole/trying-selection-list" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>