Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Trading Dictionary App</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script> | |
| <link href="https://cdn.jsdelivr.net/npm/daisyui@3.9.4/dist/full.css" rel="stylesheet" type="text/css" /> | |
| <script src="https://kit.fontawesome.com/1f7e5e05ce.js" crossorigin="anonymous"></script> | |
| <script> | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| 'trading-green': '#00c853', | |
| 'trading-red': '#d50000', | |
| 'trading-blue': '#0077ff', | |
| 'trading-bg': '#1a2a4a', | |
| 'trading-panel': '#1e2d4d', | |
| 'trading-dark': '#162447' | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| </head> | |
| <body class="bg-trading-bg min-h-screen text-gray-200"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <!-- Header --> | |
| <header class="text-center mb-10"> | |
| <h1 class="text-4xl font-bold mb-2"> | |
| <i class="fas fa-exchange-alt mr-3 text-trading-green"></i>Trading Dictionary | |
| </h1> | |
| <p class="text-gray-300">Master trading terminology with this comprehensive dictionary</p> | |
| </header> | |
| <!-- Main Tabs --> | |
| <div class="tabs tabs-lifted w-full max-w-6xl mx-auto mb-6 bg-trading-dark rounded-lg overflow-hidden"> | |
| <a class="tab tab-lg" id="input-tab">➕ Add Term</a> | |
| <a class="tab tab-lg" id="search-tab">🔍 Search</a> | |
| <a class="tab tab-lg" id="records-tab">📊 Terms List</a> | |
| <a class="tab tab-lg" id="import-tab">📤 Import/Export</a> | |
| </div> | |
| <!-- Input Tab Content --> | |
| <div id="input-content" class="tab-content bg-trading-panel rounded-xl shadow-xl p-8 mb-8 transition-all duration-300"> | |
| <h2 class="text-2xl font-semibold mb-6 flex items-center text-white"> | |
| <i class="fas fa-plus-circle mr-3 text-trading-green"></i>Add New Trading Term | |
| </h2> | |
| <form id="dictionary-form" class="space-y-6"> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div class="form-control"> | |
| <label class="label"> | |
| <span class="label-text font-medium text-gray-200">Term</span> | |
| <span class="label-text-alt text-red-400">*</span> | |
| </label> | |
| <input type="text" id="term" placeholder="Enter trading term" class="input input-bordered input-primary w-full bg-gray-800 border-gray-600 text-white" required /> | |
| </div> | |
| <div class="form-control"> | |
| <label class="label"> | |
| <span class="label-text font-medium text-gray-200">Category</span> | |
| </label> | |
| <select id="category" class="select select-bordered select-primary w-full bg-gray-800 border-gray-600 text-white"> | |
| <option value="">Select category...</option> | |
| <option value="technical-analysis">Technical Analysis</option> | |
| <option value="fundamental-analysis">Fundamental Analysis</option> | |
| <option value="trading-strategy">Trading Strategy</option> | |
| <option value="risk-management">Risk Management</option> | |
| <option value="market-structure">Market Structure</option> | |
| <option value="indicators">Indicators</option> | |
| <option value="candlestick-patterns">Candlestick Patterns</option> | |
| <option value="crypto-trading">Crypto Trading</option> | |
| <option value="options-trading">Options Trading</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="form-control"> | |
| <label class="label"> | |
| <span class="label-text font-medium text-gray-200">Definition</span> | |
| <span class="label-text-alt text-red-400">*</span> | |
| </label> | |
| <textarea id="definition" placeholder="Enter definition" class="textarea textarea-bordered textarea-primary h-24 bg-gray-800 border-gray-600 text-white" required></textarea> | |
| </div> | |
| <div class="form-control"> | |
| <label class="label"> | |
| <span class="label-text font-medium text-gray-200">How to Use / Application</span> | |
| </label> | |
| <textarea id="application" placeholder="Describe how this term is used in trading" class="textarea textarea-bordered textarea-primary h-24 bg-gray-800 border-gray-600 text-white"></textarea> | |
| </div> | |
| <div class="form-control"> | |
| <label class="label"> | |
| <span class="label-text font-medium text-gray-200">Method / Implementation</span> | |
| </label> | |
| <textarea id="method" placeholder="Explain the method or implementation details" class="textarea textarea-bordered textarea-primary h-24 bg-gray-800 border-gray-600 text-white"></textarea> | |
| </div> | |
| <div class="form-control"> | |
| <label class="label"> | |
| <span class="label-text font-medium text-gray-200">Example</span> | |
| </label> | |
| <textarea id="example" placeholder="Provide an example of how this term is applied" class="textarea textarea-bordered textarea-primary h-24 bg-gray-800 border-gray-600 text-white"></textarea> | |
| </div> | |
| <div class="form-control"> | |
| <label class="label"> | |
| <span class="label-text font-medium text-gray-200">Synonyms / Related Terms</span> | |
| </label> | |
| <input type="text" id="synonyms" placeholder="Comma separated related terms" class="input input-bordered input-primary w-full bg-gray-800 border-gray-600 text-white" /> | |
| </div> | |
| <div class="flex flex-wrap gap-4 pt-4"> | |
| <button type="submit" class="btn btn-primary btn-lg flex-1 md:flex-none bg-trading-green hover:bg-green-600 border-0 text-white"> | |
| <i class="fas fa-save mr-2"></i>Save Term | |
| </button> | |
| <button type="button" id="clear-form" class="btn btn-outline btn-lg flex-1 md:flex-none border-gray-500 text-gray-300 hover:bg-gray-700 hover:border-gray-400"> | |
| <i class="fas fa-times mr-2"></i>Clear | |
| </button> | |
| </div> | |
| </form> | |
| </div> | |
| <!-- Search Tab Content --> | |
| <div id="search-content" class="tab-content bg-trading-panel rounded-xl shadow-xl p-8 mb-8 hidden transition-all duration-300"> | |
| <h2 class="text-2xl font-semibold mb-6 flex items-center text-white"> | |
| <i class="fas fa-search mr-3 text-trading-blue"></i>Search Trading Terms | |
| </h2> | |
| <div class="form-control mb-6"> | |
| <label class="label"> | |
| <span class="label-text font-medium text-gray-200">Search Term</span> | |
| </label> | |
| <div class="relative"> | |
| <input type="text" id="search-input" placeholder="Search for terms, definitions, applications..." class="input input-bordered input-primary w-full pr-12 bg-gray-800 border-gray-600 text-white" /> | |
| <button id="search-btn" class="btn btn-square btn-ghost absolute right-1 top-1 border-0 hover:bg-gray-700 text-trading-blue"> | |
| <i class="fas fa-search"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="form-control mb-6"> | |
| <div class="flex flex-wrap gap-2"> | |
| <label class="label cursor-pointer"> | |
| <span class="label-text text-gray-200">Category: </span> | |
| </label> | |
| <select id="search-category" class="select select-sm select-bordered bg-gray-800 border-gray-600 text-gray-200"> | |
| <option value="">All Categories</option> | |
| <option value="technical-analysis">Technical Analysis</option> | |
| <option value="fundamental-analysis">Fundamental Analysis</option> | |
| <option value="trading-strategy">Trading Strategy</option> | |
| <option value="risk-management">Risk Management</option> | |
| <option value="market-structure">Market Structure</option> | |
| <option value="indicators">Indicators</option> | |
| <option value="candlestick-patterns">Candlestick Patterns</option> | |
| <option value="crypto-trading">Crypto Trading</option> | |
| <option value="options-trading">Options Trading</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div id="search-results" class="mt-6 space-y-4"></div> | |
| </div> | |
| <!-- Records Tab Content --> | |
| <div id="records-content" class="tab-content bg-trading-panel rounded-xl shadow-xl p-8 mb-8 hidden transition-all duration-300"> | |
| <h2 class="text-2xl font-semibold mb-6 flex items-center text-white"> | |
| <i class="fas fa-database mr-3 text-purple-400"></i>All Trading Terms | |
| <span id="record-count" class="badge badge-primary ml-3 bg-trading-green text-white"></span> | |
| </h2> | |
| <div class="overflow-x-auto"> | |
| <table id="records-table" class="table table-zebra w-full"> | |
| <thead> | |
| <tr class="text-gray-300"> | |
| <th class="text-white">Term</th> | |
| <th class="text-white">Category</th> | |
| <th class="text-white">Definition</th> | |
| <th class="text-white">Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody></tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <!-- Import/Export Tab Content --> | |
| <div id="import-content" class="tab-content bg-trading-panel rounded-xl shadow-xl p-8 hidden transition-all duration-300"> | |
| <h2 class="text-2xl font-semibold mb-6 flex items-center text-white"> | |
| <i class="fas fa-file-import mr-3 text-orange-400"></i>Import/Export Data | |
| </h2> | |
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-8"> | |
| <!-- Import Section --> | |
| <div class="p-6 border-2 border-dashed border-trading-blue rounded-xl bg-opacity-50 bg-trading-dark"> | |
| <h3 class="text-xl font-semibold mb-4 text-trading-blue flex items-center"> | |
| <i class="fas fa-upload mr-3"></i>Import Data | |
| </h3> | |
| <p class="text-gray-300 mb-4">Import your trading dictionary data from Excel (XLS/XLSX) file.</p> | |
| <div class="form-control"> | |
| <label class="label"> | |
| <span class="label-text text-gray-200">Upload Excel File</span> | |
| </label> | |
| <input type="file" id="import-file" accept=".xlsx, .xls" class="file-input file-input-bordered w-full bg-gray-800 border-gray-500 text-gray-200" /> | |
| </div> | |
| <button id="import-btn" class="btn btn-primary mt-4 w-full bg-trading-blue hover:bg-blue-600 border-0 text-white"> | |
| <i class="fas fa-download mr-2"></i>Import Data | |
| </button> | |
| <div class="mt-4 text-sm text-gray-400"> | |
| <p><strong>File format requirements:</strong></p> | |
| <ul class="list-disc list-inside mt-1"> | |
| <li>Must be in XLS or XLSX format</li> | |
| <li>First row should contain headers: Term, Category, Definition, Application, Method, Example, Synonyms</li> | |
| <li>All fields except "Application", "Method", "Example" and "Synonyms" are required</li> | |
| </ul> | |
| </div> | |
| </div> | |
| <!-- Export Section --> | |
| <div class="p-6 border-2 border-dashed border-trading-green rounded-xl bg-opacity-50 bg-trading-dark"> | |
| <h3 class="text-xl font-semibold mb-4 text-trading-green flex items-center"> | |
| <i class="fas fa-download mr-3"></i>Export Data | |
| </h3> | |
| <p class="text-gray-300 mb-4">Export your trading dictionary data to Excel for backup or sharing.</p> | |
| <button id="export-btn" class="btn btn-success w-full text-lg py-4 bg-trading-green hover:bg-green-600 border-0 text-white"> | |
| <i class="fas fa-file-excel mr-2"></i>Export to Excel | |
| </button> | |
| <div class="mt-4 text-sm text-gray-400"> | |
| <p><strong>Export options:</strong></p> | |
| <ul class="list-disc list-inside mt-1"> | |
| <li>Exports all trading dictionary entries</li> | |
| <li>Creates an XLSX file compatible with Excel and Google Sheets</li> | |
| <li>Includes all data fields</li> | |
| </ul> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mt-8 p-4 bg-yellow-900 bg-opacity-30 border-l-4 border-yellow-500 rounded"> | |
| <p class="text-sm text-yellow-200 flex items-start"> | |
| <i class="fas fa-exclamation-triangle mr-2 mt-1"></i> | |
| <strong>Warning:</strong> Importing a new file will overwrite any existing entries with the same terms. Please backup your data before importing. | |
| </p> | |
| </div> | |
| </div> | |
| <!-- Toast Notification --> | |
| <div id="toast" class="toast toast-top toast-end hidden"> | |
| <div id="toast-content" class="alert rounded-lg shadow-lg"> | |
| <span id="toast-message"></span> | |
| </div> | |
| </div> | |
| <!-- Detail Modal --> | |
| <input type="checkbox" id="detail-modal" class="modal-toggle" /> | |
| <div class="modal modal-bottom sm:modal-middle"> | |
| <div class="modal-box bg-trading-panel max-w-3xl"> | |
| <h3 id="detail-modal-title" class="font-bold text-xl mb-4 text-trading-green"></h3> | |
| <div id="detail-content" class="space-y-4 text-gray-200"> | |
| <!-- Content will be filled dynamically --> | |
| </div> | |
| <div class="modal-action"> | |
| <label for="detail-modal" class="btn bg-gray-700 hover:bg-gray-600 border-0 text-white">Close</label> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Edit Modal --> | |
| <input type="checkbox" id="edit-modal" class="modal-toggle" /> | |
| <div class="modal modal-bottom sm:modal-middle"> | |
| <div class="modal-box bg-trading-panel max-w-3xl"> | |
| <h3 id="edit-modal-title" class="font-bold text-xl mb-4 text-trading-green">Edit Entry</h3> | |
| <form id="edit-form" class="space-y-4"> | |
| <input type="hidden" id="edit-id" /> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> | |
| <div class="form-control"> | |
| <label class="label"> | |
| <span class="label-text font-medium text-gray-200">Term</span> | |
| </label> | |
| <input type="text" id="edit-term" class="input input-bordered input-primary w-full bg-gray-800 border-gray-600 text-white" required /> | |
| </div> | |
| <div class="form-control"> | |
| <label class="label"> | |
| <span class="label-text font-medium text-gray-200">Category</span> | |
| </label> | |
| <select id="edit-category" class="select select-bordered select-primary w-full bg-gray-800 border-gray-600 text-white"> | |
| <option value="">Select category...</option> | |
| <option value="technical-analysis">Technical Analysis</option> | |
| <option value="fundamental-analysis">Fundamental Analysis</option> | |
| <option value="trading-strategy">Trading Strategy</option> | |
| <option value="risk-management">Risk Management</option> | |
| <option value="market-structure">Market Structure</option> | |
| <option value="indicators">Indicators</option> | |
| <option value="candlestick-patterns">Candlestick Patterns</option> | |
| <option value="crypto-trading">Crypto Trading</option> | |
| <option value="options-trading">Options Trading</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="form-control"> | |
| <label class="label"> | |
| <span class="label-text font-medium text-gray-200">Definition</span> | |
| </label> | |
| <textarea id="edit-definition" class="textarea textarea-bordered textarea-primary h-20 bg-gray-800 border-gray-600 text-white" required></textarea> | |
| </div> | |
| <div class="form-control"> | |
| <label class="label"> | |
| <span class="label-text font-medium text-gray-200">How to Use / Application</span> | |
| </label> | |
| <textarea id="edit-application" class="textarea textarea-bordered textarea-primary h-20 bg-gray-800 border-gray-600 text-white"></textarea> | |
| </div> | |
| <div class="form-control"> | |
| <label class="label"> | |
| <span class="label-text font-medium text-gray-200">Method / Implementation</span> | |
| </label> | |
| <textarea id="edit-method" class="textarea textarea-bordered textarea-primary h-20 bg-gray-800 border-gray-600 text-white"></textarea> | |
| </div> | |
| <div class="form-control"> | |
| <label class="label"> | |
| <span class="label-text font-medium text-gray-200">Example</span> | |
| </label> | |
| <textarea id="edit-example" class="textarea textarea-bordered textarea-primary h-20 bg-gray-800 border-gray-600 text-white"></textarea> | |
| </div> | |
| <div class="form-control"> | |
| <label class="label"> | |
| <span class="label-text font-medium text-gray-200">Synonyms / Related Terms</span> | |
| </label> | |
| <input type="text" id="edit-synonyms" class="input input-bordered input-primary w-full bg-gray-800 border-gray-600 text-white" /> | |
| </div> | |
| <div class="modal-action"> | |
| <button type="submit" class="btn btn-primary bg-trading-green hover:bg-green-600 border-0 text-white">Save Changes</button> | |
| <label for="edit-modal" class="btn bg-gray-700 hover:bg-gray-600 border-0 text-white">Cancel</label> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| <!-- Delete Confirmation Modal --> | |
| <input type="checkbox" id="delete-modal" class="modal-toggle" /> | |
| <div class="modal"> | |
| <div class="modal-box bg-trading-panel"> | |
| <h3 id="delete-modal-title" class="font-bold text-xl text-red-400">Delete Confirmation</h3> | |
| <p id="delete-modal-body" class="py-4 text-gray-300">Are you sure you want to delete this entry? This action cannot be undone.</p> | |
| <div class="modal-action"> | |
| <button id="confirm-delete" class="btn btn-error text-white">Yes, Delete</button> | |
| <label for="delete-modal" class="btn bg-gray-700 hover:bg-gray-600 border-0 text-white">Cancel</label> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Trading Dictionary App Main Logic | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Initialize local storage if not exists | |
| if (!localStorage.getItem('tradingDictionaryEntries')) { | |
| // Load some default trading terms | |
| const defaultTerms = [ | |
| { | |
| id: 1, | |
| term: "Support", | |
| category: "technical-analysis", | |
| definition: "A price level where a downtrend can be expected to pause due to a concentration of demand.", | |
| application: "Support levels are used to identify potential entry points for long positions. Traders watch for price to bounce off support levels with confirmation from other indicators.", | |
| method: "Identify support by examining previous price lows on a chart. Horizontal lines are drawn at these levels. Multiple touches of a support level increase its significance.", | |
| example: "In the ETH/USD chart, $1,800 has acted as strong support three times in the past month, making it a high-probability bounce level.", | |
| synonyms: "Floor, Demand zone" | |
| }, | |
| { | |
| id: 2, | |
| term: "Resistance", | |
| category: "technical-analysis", | |
| definition: "A price level where an uptrend can be expected to pause due to a concentration of supply.", | |
| application: "Resistance levels help identify potential take-profit points or entry points for short positions. They are often used in conjunction with overbought indicators.", | |
| method: "Identify resistance by examining previous price highs on a chart. Draw horizontal lines at these levels. The more times price fails to break above a resistance level, the stronger it becomes.", | |
| example: "For BTC/USD, $45,000 has been a strong resistance level, preventing price from moving higher on three separate occasions in the past two months.", | |
| synonyms: "Ceiling, Supply zone" | |
| }, | |
| { | |
| id: 3, | |
| term: "Moving Average", | |
| category: "indicators", | |
| definition: "An indicator that shows the average value of a security's price over a set period of time.", | |
| application: "Used to identify trends, generate buy/sell signals, and determine support/resistance levels. Crossovers of different moving averages can signal trend changes.", | |
| method: "Calculate by taking the average closing price over a specified number of periods. Common types include Simple Moving Average (SMA), Exponential Moving Average (EMA), and Weighted Moving Average (WMA).", | |
| example: "A trader might use a 50-day EMA crossover above a 200-day EMA as a buy signal, indicating a potential bullish trend change.", | |
| synonyms: "MA, Average" | |
| }, | |
| { | |
| id: 4, | |
| term: "Risk/Reward Ratio", | |
| category: "risk-management", | |
| definition: "A measure of the potential profit of a trade compared to its potential loss.", | |
| application: "Used to evaluate whether a trade is worth taking based on the potential return versus the potential risk. Helps traders maintain consistency in their trading approach.", | |
| method: "Calculate by dividing the potential profit (distance from entry to take-profit) by the potential loss (distance from entry to stop-loss). A ratio of 2:1 means the potential profit is twice the potential risk.", | |
| example: "A trader entering a position at $100 with a take-profit at $120 and a stop-loss at $90 has a risk/reward ratio of 2:1 (potential profit of $20 vs potential risk of $10).", | |
| synonyms: "R:R, Profit/risk ratio" | |
| } | |
| ]; | |
| localStorage.setItem('tradingDictionaryEntries', JSON.stringify(defaultTerms)); | |
| } | |
| // Tab functionality | |
| const tabs = document.querySelectorAll('.tab'); | |
| const tabContents = document.querySelectorAll('.tab-content'); | |
| tabs.forEach(tab => { | |
| tab.addEventListener('click', () => { | |
| // Remove active class from all tabs and contents | |
| tabs.forEach(t => t.classList.remove('tab-active')); | |
| tabContents.forEach(content => content.classList.add('hidden')); | |
| // Add active class to clicked tab and corresponding content | |
| tab.classList.add('tab-active'); | |
| const tabId = tab.id.replace('-tab', '-content'); | |
| document.getElementById(tabId).classList.remove('hidden'); | |
| // Special handling for records tab - refresh table when shown | |
| if (tabId === 'records-content') { | |
| displayAllRecords(); | |
| } else if (tabId === 'search-content') { | |
| // Clear search results when entering search tab | |
| document.getElementById('search-results').innerHTML = ''; | |
| document.getElementById('search-input').value = ''; | |
| } | |
| }); | |
| }); | |
| // Show input tab by default | |
| document.getElementById('input-tab').click(); | |
| // Dictionary data functions | |
| function getEntries() { | |
| return JSON.parse(localStorage.getItem('tradingDictionaryEntries')) || []; | |
| } | |
| function saveEntries(entries) { | |
| localStorage.setItem('tradingDictionaryEntries', JSON.stringify(entries)); | |
| } | |
| function addEntry(entry) { | |
| const entries = getEntries(); | |
| // Check if term already exists and update if it does | |
| const existingIndex = entries.findIndex(e => e.term.toLowerCase() === entry.term.toLowerCase()); | |
| if (existingIndex > -1) { | |
| entries[existingIndex] = { ...entries[existingIndex], ...entry }; | |
| } else { | |
| entry.id = Date.now(); // Simple ID generation | |
| entries.push(entry); | |
| } | |
| saveEntries(entries); | |
| } | |
| function updateEntry(id, updatedEntry) { | |
| const entries = getEntries(); | |
| const index = entries.findIndex(e => e.id == id); | |
| if (index > -1) { | |
| entries[index] = { ...entries[index], ...updatedEntry }; | |
| saveEntries(entries); | |
| } | |
| } | |
| function deleteEntry(id) { | |
| let entries = getEntries(); | |
| entries = entries.filter(e => e.id != id); | |
| saveEntries(entries); | |
| } | |
| function searchEntries(term, category = '', searchInAllFields = true) { | |
| const entries = getEntries(); | |
| const searchTerm = term.toLowerCase(); | |
| return entries.filter(entry => { | |
| // Check category filter first | |
| if (category && entry.category !== category) { | |
| return false; | |
| } | |
| if (entry.term.toLowerCase().includes(searchTerm)) { | |
| return true; | |
| } | |
| if (searchInAllFields && entry.definition.toLowerCase().includes(searchTerm)) { | |
| return true; | |
| } | |
| if (searchInAllFields && entry.application && entry.application.toLowerCase().includes(searchTerm)) { | |
| return true; | |
| } | |
| if (searchInAllFields && entry.method && entry.method.toLowerCase().includes(searchTerm)) { | |
| return true; | |
| } | |
| if (searchInAllFields && entry.example && entry.example.toLowerCase().includes(searchTerm)) { | |
| return true; | |
| } | |
| if (searchInAllFields && entry.synonyms && entry.synonyms.toLowerCase().includes(searchTerm)) { | |
| return true; | |
| } | |
| return false; | |
| }); | |
| } | |
| // Form submission | |
| const dictionaryForm = document.getElementById('dictionary-form'); | |
| dictionaryForm.addEventListener('submit', function(e) { | |
| e.preventDefault(); | |
| const entry = { | |
| term: document.getElementById('term').value.trim(), | |
| category: document.getElementById('category').value, | |
| definition: document.getElementById('definition').value.trim(), | |
| application: document.getElementById('application').value.trim(), | |
| method: document.getElementById('method').value.trim(), | |
| example: document.getElementById('example').value.trim(), | |
| synonyms: document.getElementById('synonyms').value.trim() | |
| }; | |
| // Validation | |
| if (!entry.term) { | |
| showNotification('Term is required', 'error'); | |
| return; | |
| } | |
| if (!entry.definition) { | |
| showNotification('Definition is required', 'error'); | |
| return; | |
| } | |
| addEntry(entry); | |
| showNotification('Trading term added successfully!', 'success'); | |
| // Reset form | |
| dictionaryForm.reset(); | |
| }); | |
| // Clear form | |
| document.getElementById('clear-form').addEventListener('click', function() { | |
| dictionaryForm.reset(); | |
| }); | |
| // Search functionality | |
| const searchBtn = document.getElementById('search-btn'); | |
| const searchInput = document.getElementById('search-input'); | |
| const searchCategory = document.getElementById('search-category'); | |
| const searchResults = document.getElementById('search-results'); | |
| function performSearch() { | |
| const term = searchInput.value.trim(); | |
| const category = searchCategory.value; | |
| if (!term && !category) { | |
| searchResults.innerHTML = '<div class="alert alert-info text-gray-300 bg-gray-700 border-0">Enter a search term or select a category above.</div>'; | |
| return; | |
| } | |
| const results = searchEntries(term, category, true); | |
| if (results.length === 0) { | |
| searchResults.innerHTML = '<div class="alert alert-warning text-gray-300 bg-gray-700 border-0">No entries found matching your search.</div>'; | |
| return; | |
| } | |
| searchResults.innerHTML = ` | |
| <div class="alert alert-info mb-4 text-gray-300 bg-gray-700 border-0"> | |
| Found ${results.length} result${results.length !== 1 ? 's' : ''} ${term ? `for "${term}"` : ''}${term && category ? ' with' : category ? ' for' : ''} ${category ? `"${searchCategory.options[searchCategory.selectedIndex].text}" category` : ''} | |
| </div> | |
| ${results.map(renderEntryCard).join('')} | |
| `; | |
| // Add event listeners to view, edit and delete buttons | |
| document.querySelectorAll('.view-btn').forEach(btn => { | |
| btn.addEventListener('click', handleViewClick); | |
| }); | |
| document.querySelectorAll('.edit-btn').forEach(btn => { | |
| btn.addEventListener('click', handleEditClick); | |
| }); | |
| document.querySelectorAll('.delete-btn').forEach(btn => { | |
| btn.addEventListener('click', handleDeleteClick); | |
| }); | |
| } | |
| searchBtn.addEventListener('click', performSearch); | |
| searchInput.addEventListener('keypress', function(e) { | |
| if (e.key === 'Enter') { | |
| performSearch(); | |
| } | |
| }); | |
| searchCategory.addEventListener('change', performSearch); | |
| // Display all records | |
| function displayAllRecords() { | |
| const entries = getEntries(); | |
| const tableBody = document.querySelector('#records-table tbody'); | |
| const recordCount = document.getElementById('record-count'); | |
| if (entries.length === 0) { | |
| tableBody.innerHTML = ` | |
| <tr> | |
| <td colspan="4" class="text-center py-8 text-gray-500"> | |
| <i class="fas fa-inbox text-4xl mb-2 opacity-50"></i> | |
| <div>No entries yet. Start by adding your first trading term!</div> | |
| </td> | |
| </tr> | |
| `; | |
| recordCount.textContent = '0 entries'; | |
| return; | |
| } | |
| tableBody.innerHTML = entries.map(entry => { | |
| const categoryLabel = { | |
| 'technical-analysis': 'Technical', | |
| 'fundamental-analysis': 'Fundamental', | |
| 'trading-strategy': 'Strategy', | |
| 'risk-management': 'Risk Mgmt', | |
| 'market-structure': 'Market', | |
| 'indicators': 'Indicators', | |
| 'candlestick-patterns': 'Candlestick', | |
| 'crypto-trading': 'Crypto', | |
| 'options-trading': 'Options' | |
| }[entry.category] || entry.category; | |
| return ` | |
| <tr class="hover:bg-gray-700 transition-colors"> | |
| <td class="font-medium text-trading-green">${entry.term}</td> | |
| <td> | |
| <span class="badge bg-gray-700 border border-gray-600 text-xs">${categoryLabel}</span> | |
| </td> | |
| <td>${truncateText(entry.definition, 80)}</td> | |
| <td> | |
| <div class="join join-vertical md:join-horizontal"> | |
| <button class="btn btn-xs btn-outline join-item view-btn text-blue-400 border-gray-600 hover:bg-gray-700" data-id="${entry.id}"> | |
| <i class="fas fa-eye"></i> | |
| </button> | |
| <button class="btn btn-xs btn-outline join-item edit-btn text-green-400 border-gray-600 hover:bg-gray-700" data-id="${entry.id}"> | |
| <i class="fas fa-edit"></i> | |
| </button> | |
| <button class="btn btn-xs btn-outline join-item delete-btn text-red-400 border-gray-600 hover:bg-gray-700" data-id="${entry.id}"> | |
| <i class="fas fa-trash"></i> | |
| </button> | |
| </div> | |
| </td> | |
| </tr> | |
| `; | |
| }).join(''); | |
| recordCount.textContent = `${entries.length} entries`; | |
| // Add event listeners to view, edit and delete buttons | |
| document.querySelectorAll('.view-btn').forEach(btn => { | |
| btn.addEventListener('click', handleViewClick); | |
| }); | |
| document.querySelectorAll('.edit-btn').forEach(btn => { | |
| btn.addEventListener('click', handleEditClick); | |
| }); | |
| document.querySelectorAll('.delete-btn').forEach(btn => { | |
| btn.addEventListener('click', handleDeleteClick); | |
| }); | |
| } | |
| // View entry | |
| function handleViewClick(e) { | |
| const entryId = e.target.closest('.view-btn').dataset.id; | |
| const entries = getEntries(); | |
| const entry = entries.find(e => e.id == entryId); | |
| // Fill the modal content | |
| document.getElementById('detail-modal-title').textContent = entry.term; | |
| const categoryLabels = { | |
| 'technical-analysis': 'Technical Analysis', | |
| 'fundamental-analysis': 'Fundamental Analysis', | |
| 'trading-strategy': 'Trading Strategy', | |
| 'risk-management': 'Risk Management', | |
| 'market-structure': 'Market Structure', | |
| 'indicators': 'Indicators', | |
| 'candlestick-patterns': 'Candlestick Patterns', | |
| 'crypto-trading': 'Crypto Trading', | |
| 'options-trading': 'Options Trading' | |
| }; | |
| const categoryLabel = categoryLabels[entry.category] || entry.category; | |
| document.getElementById('detail-content').innerHTML = ` | |
| <div class="bg-gray-700 rounded-lg p-4"> | |
| <div class="flex justify-between items-start"> | |
| <div> | |
| <span class="text-trading-blue font-medium">${categoryLabel}</span> | |
| </div> | |
| </div> | |
| <div class="mt-3"> | |
| <h4 class="font-semibold text-trading-green text-lg mb-2">Definition</h4> | |
| <p class="text-gray-200">${entry.definition}</p> | |
| </div> | |
| ${entry.application ? ` | |
| <div class="mt-4"> | |
| <h4 class="font-semibold text-trading-blue text-lg mb-2">How to Use / Application</h4> | |
| <p class="text-gray-200">${entry.application}</p> | |
| </div>` : ''} | |
| ${entry.method ? ` | |
| <div class="mt-4"> | |
| <h4 class="font-semibold text-trading-blue text-lg mb-2">Method / Implementation</h4> | |
| <p class="text-gray-200">${entry.method}</p> | |
| </div>` : ''} | |
| ${entry.example ? ` | |
| <div class="mt-4"> | |
| <h4 class="font-semibold text-trading-blue text-lg mb-2">Example</h4> | |
| <p class="text-gray-200">${entry.example}</p> | |
| </div>` : ''} | |
| ${entry.synonyms ? ` | |
| <div class="mt-4"> | |
| <h4 class="font-semibold text-trading-blue text-lg mb-2">Synonyms / Related Terms</h4> | |
| <div class="flex flex-wrap gap-2 mt-2"> | |
| ${entry.synonyms.split(',').map(synonym => | |
| `<span class="badge bg-gray-600 text-gray-200">${synonym.trim()}</span>` | |
| ).join('')} | |
| </div> | |
| </div>` : ''} | |
| </div> | |
| `; | |
| // Show modal | |
| document.getElementById('detail-modal').checked = true; | |
| } | |
| // Edit entry | |
| let currentEditId = null; | |
| function handleEditClick(e) { | |
| currentEditId = e.target.closest('.edit-btn').dataset.id; | |
| const entries = getEntries(); | |
| const entry = entries.find(e => e.id == currentEditId); | |
| // Fill the form | |
| document.getElementById('edit-id').value = entry.id; | |
| document.getElementById('edit-term').value = entry.term; | |
| document.getElementById('edit-category').value = entry.category || ''; | |
| document.getElementById('edit-definition').value = entry.definition; | |
| document.getElementById('edit-application').value = entry.application || ''; | |
| document.getElementById('edit-method').value = entry.method || ''; | |
| document.getElementById('edit-example').value = entry.example || ''; | |
| document.getElementById('edit-synonyms').value = entry.synonyms || ''; | |
| // Show modal | |
| document.getElementById('edit-modal').checked = true; | |
| } | |
| document.getElementById('edit-form').addEventListener('submit', function(e) { | |
| e.preventDefault(); | |
| const updatedEntry = { | |
| term: document.getElementById('edit-term').value.trim(), | |
| category: document.getElementById('edit-category').value, | |
| definition: document.getElementById('edit-definition').value.trim(), | |
| application: document.getElementById('edit-application').value.trim(), | |
| method: document.getElementById('edit-method').value.trim(), | |
| example: document.getElementById('edit-example').value.trim(), | |
| synonyms: document.getElementById('edit-synonyms').value.trim() | |
| }; | |
| // Validation | |
| if (!updatedEntry.term) { | |
| showNotification('Term is required', 'error'); | |
| return; | |
| } | |
| if (!updatedEntry.definition) { | |
| showNotification('Definition is required', 'error'); | |
| return; | |
| } | |
| updateEntry(currentEditId, updatedEntry); | |
| showNotification('Entry updated successfully!', 'success'); | |
| // Close modal | |
| document.getElementById('edit-modal').checked = false; | |
| // Refresh views if needed | |
| if (!document.getElementById('search-content').classList.contains('hidden')) { | |
| performSearch(); | |
| } | |
| if (!document.getElementById('records-content').classList.contains('hidden')) { | |
| displayAllRecords(); | |
| } | |
| }); | |
| // Delete entry | |
| let currentDeleteId = null; | |
| function handleDeleteClick(e) { | |
| currentDeleteId = e.target.closest('.delete-btn').dataset.id; | |
| // Update modal content | |
| const entries = getEntries(); | |
| const entry = entries.find(e => e.id == currentDeleteId); | |
| document.getElementById('delete-modal-body').textContent = | |
| `Are you sure you want to delete "${entry.term}"? This action cannot be undone.`; | |
| // Show modal | |
| document.getElementById('delete-modal').checked = true; | |
| } | |
| document.getElementById('confirm-delete').addEventListener('click', function() { | |
| deleteEntry(currentDeleteId); | |
| showNotification('Entry deleted successfully!', 'success'); | |
| // Close modal | |
| document.getElementById('delete-modal').checked = false; | |
| // Refresh views if needed | |
| if (!document.getElementById('search-content').classList.contains('hidden')) { | |
| performSearch(); | |
| } | |
| if (!document.getElementById('records-content').classList.contains('hidden')) { | |
| displayAllRecords(); | |
| } | |
| }); | |
| // Import/Export functionality | |
| document.getElementById('import-btn').addEventListener('click', function() { | |
| const fileInput = document.getElementById('import-file'); | |
| const file = fileInput.files[0]; | |
| if (!file) { | |
| showNotification('Please select a file to import', 'error'); | |
| return; | |
| } | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| try { | |
| const data = new Uint8Array(e.target.result); | |
| const workbook = XLSX.read(data, { type: 'array' }); | |
| const firstSheet = workbook.Sheets[workbook.SheetNames[0]]; | |
| const jsonData = XLSX.utils.sheet_to_json(firstSheet); | |
| // Validate data structure | |
| const requiredFields = ['Term', 'Definition']; | |
| const missingFields = requiredFields.filter(field => !jsonData[0] || !jsonData[0].hasOwnProperty(field)); | |
| if (missingFields.length > 0) { | |
| showNotification(`Required column(s) missing: ${missingFields.join(', ')}`, 'error'); | |
| return; | |
| } | |
| // Process data | |
| const entries = getEntries(); | |
| let importedCount = 0; | |
| jsonData.forEach(row => { | |
| // Skip empty rows | |
| if (!row.Term || !row.Definition) return; | |
| const entry = { | |
| term: row.Term.trim(), | |
| category: row.Category || '', | |
| definition: row.Definition.trim(), | |
| application: row.Application || '', | |
| method: row.Method || '', | |
| example: row.Example || '', | |
| synonyms: row.Synonyms || '', | |
| id: Date.now() + Math.floor(Math.random() * 1000) // Generate unique ID | |
| }; | |
| // Check if term already exists and update if needed | |
| const existingIndex = entries.findIndex(e => e.term.toLowerCase() === entry.term.toLowerCase()); | |
| if (existingIndex > -1) { | |
| entries[existingIndex] = { ...entries[existingIndex], ...entry }; | |
| } else { | |
| entries.push(entry); | |
| } | |
| importedCount++; | |
| }); | |
| saveEntries(entries); | |
| showNotification(`Successfully imported ${importedCount} trading terms!`, 'success'); | |
| // Clear file input | |
| fileInput.value = ''; | |
| // Refresh views | |
| if (!document.getElementById('records-content').classList.contains('hidden')) { | |
| displayAllRecords(); | |
| } | |
| } catch (error) { | |
| console.error(error); | |
| showNotification('Error processing file. Please check the format and try again.', 'error'); | |
| } | |
| }; | |
| reader.readAsArrayBuffer(file); | |
| }); | |
| document.getElementById('export-btn').addEventListener('click', function() { | |
| const entries = getEntries(); | |
| if (entries.length === 0) { | |
| showNotification('No data to export', 'warning'); | |
| return; | |
| } | |
| // Transform data for export | |
| const exportData = entries.map(entry => { | |
| const categoryLabels = { | |
| 'technical-analysis': 'Technical Analysis', | |
| 'fundamental-analysis': 'Fundamental Analysis', | |
| 'trading-strategy': 'Trading Strategy', | |
| 'risk-management': 'Risk Management', | |
| 'market-structure': 'Market Structure', | |
| 'indicators': 'Indicators', | |
| 'candlestick-patterns': 'Candlestick Patterns', | |
| 'crypto-trading': 'Crypto Trading', | |
| 'options-trading': 'Options Trading' | |
| }; | |
| return { | |
| 'Term': entry.term, | |
| 'Category': categoryLabels[entry.category] || entry.category, | |
| 'Definition': entry.definition, | |
| 'Application': entry.application || '', | |
| 'Method': entry.method || '', | |
| 'Example': entry.example || '', | |
| 'Synonyms': entry.synonyms || '' | |
| }; | |
| }); | |
| // Create worksheet | |
| const worksheet = XLSX.utils.json_to_sheet(exportData); | |
| // Create workbook | |
| const workbook = XLSX.utils.book_new(); | |
| XLSX.utils.book_append_sheet(workbook, worksheet, 'Trading Dictionary'); | |
| // Generate file | |
| XLSX.writeFile(workbook, `trading_dictionary_export_${new Date().toISOString().split('T')[0]}.xlsx`); | |
| showNotification('Data exported successfully!', 'success'); | |
| }); | |
| // Helper functions | |
| function renderEntryCard(entry) { | |
| const categoryLabels = { | |
| 'technical-analysis': 'Technical Analysis', | |
| 'fundamental-analysis': 'Fundamental Analysis', | |
| 'trading-strategy': 'Trading Strategy', | |
| 'risk-management': 'Risk Management', | |
| 'market-structure': 'Market Structure', | |
| 'indicators': 'Indicators', | |
| 'candlestick-patterns': 'Candlestick Patterns', | |
| 'crypto-trading': 'Crypto Trading', | |
| 'options-trading': 'Options Trading' | |
| }; | |
| const categoryLabel = categoryLabels[entry.category] || entry.category; | |
| return ` | |
| <div class="card bg-gray-700 shadow-md border border-gray-600 mb-4 transition-all duration-200 hover:shadow-lg"> | |
| <div class="card-body p-6"> | |
| <div class="flex justify-between items-start"> | |
| <h3 class="card-title text-xl font-bold text-trading-green"> | |
| ${entry.term} | |
| </h3> | |
| <span class="badge bg-gray-600 text-trading-blue">${categoryLabel}</span> | |
| </div> | |
| <div class="mt-4"> | |
| <h4 class="font-semibold text-trading-green mb-2">Definition</h4> | |
| <p class="text-gray-200">${entry.definition}</p> | |
| </div> | |
| ${entry.application ? ` | |
| <div class="mt-4"> | |
| <h4 class="font-semibold text-trading-blue mb-2">How to Use / Application</h4> | |
| <p class="text-gray-200">${entry.application}</p> | |
| </div>` : ''} | |
| ${entry.synonyms ? ` | |
| <div class="mt-4"> | |
| <h4 class="font-semibold text-trading-blue mb-2">Related Terms</h4> | |
| <div class="flex flex-wrap gap-1 mt-1"> | |
| ${entry.synonyms.split(',').map(synonym => | |
| `<span class="badge bg-gray-600 text-gray-200">${synonym.trim()}</span>` | |
| ).join('')} | |
| </div> | |
| </div>` : ''} | |
| <div class="card-actions justify-end mt-6 space-x-2"> | |
| <button class="btn btn-outline btn-sm view-btn text-trading-blue border-trading-blue hover:bg-gray-600" data-id="${entry.id}"> | |
| <i class="fas fa-eye mr-1"></i>View Details | |
| </button> | |
| <button class="btn btn-outline btn-sm edit-btn text-green-400 border-green-400 hover:bg-gray-600" data-id="${entry.id}"> | |
| <i class="fas fa-edit mr-1"></i>Edit | |
| </button> | |
| <button class="btn btn-outline btn-error btn-sm delete-btn border-red-400 hover:bg-gray-600" data-id="${entry.id}"> | |
| <i class="fas fa-trash mr-1"></i>Delete | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| } | |
| function truncateText(text, maxLength) { | |
| if (text.length <= maxLength) { | |
| return text; | |
| } | |
| return text.substring(0, maxLength) + '...'; | |
| } | |
| function showNotification(message, type = 'success') { | |
| const toast = document.getElementById('toast'); | |
| const toastContent = document.getElementById('toast-content'); | |
| const toastMessage = document.getElementById('toast-message'); | |
| // Set message and style | |
| toastMessage.textContent = message; | |
| // Remove previous classes | |
| toastContent.className = 'alert rounded-lg shadow-lg'; | |
| // Add appropriate class based on type | |
| if (type === 'error') { | |
| toastContent.classList.add('bg-red-600', 'text-white'); | |
| } else if (type === 'warning') { | |
| toastContent.classList.add('bg-yellow-600', 'text-white'); | |
| } else { | |
| toastContent.classList.add('bg-trading-green', 'text-white'); | |
| } | |
| // Show toast | |
| toast.classList.remove('hidden'); | |
| // Hide after 3 seconds | |
| setTimeout(() => { | |
| toast.classList.add('hidden'); | |
| }, 3000); | |
| } | |
| // Initialize the app | |
| displayAllRecords(); | |
| }); | |
| </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-qwensite.hf.space/logo.svg" alt="qwensite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-qwensite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >QwenSite</a> - 🧬 <a href="https://enzostvs-qwensite.hf.space?remix=alterzick/trading-dictionary" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |