diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2d54d6c --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Dependencies +node_modules/ + +# IDE +.vscode/ +.idea/ + +# OS +.DS_Store +Thumbs.db + +# Temporary files +*.tmp +*.temp + +# Personal files +theme.scss +_variables.scss +reference.png +better.png +START_PROMPT.md +CLAUDE.md +CLAUDE_V2.md +math.md +vetcalculators/ +*.js.backup* +backup/ diff --git a/build.js b/build.js index 06945c3..43223b6 100644 --- a/build.js +++ b/build.js @@ -77,14 +77,21 @@ function readSourceComponents() { * Backup existing files */ function backupFiles() { + const backupDir = 'backup'; + + // Create backup directory if it doesn't exist + if (!fs.existsSync(backupDir)) { + fs.mkdirSync(backupDir); + } + const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const filesToBackup = ['iframe.html', 'sundog-dog-food-calculator.js']; filesToBackup.forEach(file => { if (fs.existsSync(file)) { - const backupName = `${file}.backup-${timestamp}`; + const backupName = path.join(backupDir, `${file}.backup-${timestamp}`); fs.copyFileSync(file, backupName); - console.log(`📦 Backed up ${file} to: ${backupName}`); + console.log(` 📦 Backed up ${file}`); } }); } diff --git a/dog-food-calculator-widget.js b/dog-food-calculator-widget.js deleted file mode 100644 index ed8c4d0..0000000 --- a/dog-food-calculator-widget.js +++ /dev/null @@ -1,1729 +0,0 @@ -/** - * Dog Calorie Calculator Widget - * Embeddable JavaScript widget for calculating dog's daily calorie requirements - * by Canine Nutrition and Wellness - https://caninenutritionandwellness.com - * - * Basic Usage: - * - *
- * - * Advanced Usage with theme and scale options: - * - *
- * - * Or with JavaScript: - * new DogCalorieCalculatorWidget(container, { theme: 'light', scale: 1.2 }); // theme: 'light', 'dark', 'system' | scale: 0.5-2.0 - */ - -(function() { - 'use strict'; - - // Widget styles - Using Shadow DOM for better isolation where supported - const widgetStyles = ` - .dog-calc-widget { - max-width: 600px; - margin: 0 auto; - padding: 24px; - font-family: 'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; - line-height: 1.5; - color: #6f3f6d; - box-sizing: border-box; - } - - .dog-calc-widget *, - .dog-calc-widget *::before, - .dog-calc-widget *::after { - box-sizing: border-box; - } - - .dog-calc-section { - background: #fdfcfe; - border: 1px solid #e8e3ed; - border-radius: 8px 8px 0 0; - padding: 24px; - margin-bottom: 0; - box-shadow: 0 3px 6px rgba(0, 0, 0, 0.08); - } - - .dog-calc-section-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 24px; - flex-wrap: wrap; - gap: 16px; - } - - .dog-calc-section h2 { - margin: 0; - color: #6f3f6d; - font-size: 1.5rem; - font-weight: 600; - } - - /* Unit Switch */ - .dog-calc-unit-switch { - display: flex; - align-items: center; - gap: 12px; - } - - .dog-calc-unit-label { - font-size: 0.9rem; - font-weight: 500; - color: #635870; - transition: color 0.2s ease; - } - - .dog-calc-unit-label.active { - color: #6f3f6d; - font-weight: 600; - } - - .dog-calc-switch { - position: relative; - display: inline-block; - width: 48px; - height: 24px; - } - - .dog-calc-switch input { - opacity: 0; - width: 0; - height: 0; - } - - .dog-calc-slider { - position: absolute; - cursor: pointer; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: #e8e3ed; - transition: 0.3s; - border-radius: 24px; - } - - .dog-calc-slider:before { - position: absolute; - content: ""; - height: 18px; - width: 18px; - left: 3px; - bottom: 3px; - background-color: white; - transition: 0.3s; - border-radius: 50%; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); - } - - .dog-calc-switch input:checked + .dog-calc-slider { - background-color: #f19a5f; - } - - .dog-calc-switch input:checked + .dog-calc-slider:before { - transform: translateX(24px); - } - - .dog-calc-form-group { - margin-bottom: 20px; - } - - .dog-calc-form-group label { - display: block; - margin-bottom: 8px; - font-weight: 500; - color: #6f3f6d; - font-size: 1rem; - } - - .dog-calc-form-group select, - .dog-calc-form-group input[type="number"], - .dog-calc-form-group input[type="text"] { - width: 100%; - padding: 12px 16px; - border: 1px solid #e8e3ed; - border-radius: 6px; - font-size: 1rem; - font-family: inherit; - background-color: #ffffff; - color: #6f3f6d; - transition: all 0.2s ease; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236f3f6d' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e"); - background-repeat: no-repeat; - background-position: right 12px center; - background-size: 20px; - padding-right: 40px; - } - - .dog-calc-form-group select option { - background-color: #ffffff; - color: #6f3f6d; - } - - .dog-calc-form-group input[type="number"], - .dog-calc-form-group input[type="text"] { - background-image: none; - padding-right: 16px; - } - - .dog-calc-form-group select:focus, - .dog-calc-form-group input[type="number"]:focus, - .dog-calc-form-group input[type="text"]:focus { - outline: none; - border-color: #f19a5f; - background-color: #ffffff; - box-shadow: 0 0 0 3px rgba(241, 154, 95, 0.1); - } - - .dog-calc-form-group input[readonly] { - background-color: #f8f5fa; - cursor: not-allowed; - color: #635870; - } - - .dog-calc-results { - background: linear-gradient(135deg, rgba(241, 154, 95, 0.08) 0%, rgba(241, 154, 95, 0.04) 100%); - border: 1px solid rgba(241, 154, 95, 0.2); - border-radius: 6px; - padding: 20px; - margin-top: 24px; - } - - .dog-calc-result-item { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 12px; - } - - .dog-calc-result-item:last-child { - margin-bottom: 0; - } - - .dog-calc-result-label { - font-weight: 500; - color: #6f3f6d; - font-size: 0.95rem; - } - - .dog-calc-result-value { - font-weight: 600; - color: #6f3f6d; - font-size: 1.1rem; - padding: 4px 12px; - background: rgba(241, 154, 95, 0.15); - border-radius: 4px; - } - - .dog-calc-collapsible { - background: #ffffff; - border: 1px solid #e8e3ed; - border-top: none; - margin-bottom: 0; - overflow: hidden; - box-shadow: 0 3px 6px rgba(0, 0, 0, 0.08); - } - - .dog-calc-collapsible-header { - background: #f8f5fa; - padding: 20px 24px; - border-bottom: 1px solid #e8e3ed; - } - - .dog-calc-collapsible-header h3 { - margin: 0; - font-size: 1.25rem; - color: #6f3f6d; - font-weight: 600; - } - - .dog-calc-collapsible-content { - display: block; - } - - .dog-calc-collapsible-inner { - padding: 24px; - } - - /* Action Buttons */ - .dog-calc-action-buttons { - display: flex; - justify-content: center; - gap: 16px; - padding: 20px; - background: #f8f5fa; - border-left: 1px solid #e8e3ed; - border-right: 1px solid #e8e3ed; - margin-top: -1px; - box-shadow: 0 3px 6px rgba(0, 0, 0, 0.08); - } - - .dog-calc-btn { - padding: 8px 16px; - border: 1px solid #e8e3ed; - border-radius: 6px; - font-size: 0.9rem; - font-weight: 500; - font-family: inherit; - cursor: pointer; - transition: all 0.2s ease; - display: inline-flex; - align-items: center; - gap: 6px; - background: white; - color: #6f3f6d; - } - - .dog-calc-btn:hover { - transform: translateY(-1px); - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - } - - .dog-calc-btn-share:hover { - border-color: #9f5999; - color: #9f5999; - } - - .dog-calc-btn-embed:hover { - border-color: #7fa464; - color: #7fa464; - } - - .dog-calc-input-group { - display: flex; - gap: 16px; - align-items: flex-end; - } - - .dog-calc-input-group .dog-calc-form-group { - flex: 1; - margin-bottom: 0; - } - - .dog-calc-unit-select { - min-width: 120px; - } - - .dog-calc-error { - color: #e87159; - font-size: 0.875rem; - margin-top: 6px; - font-weight: 500; - } - - .dog-calc-hidden { - display: none !important; - } - - .dog-calc-footer { - text-align: center; - padding: 20px; - background: #fdfcfe; - border: 1px solid #e8e3ed; - border-radius: 0 0 8px 8px; - border-top: none; - margin-top: -1px; - box-shadow: 0 3px 6px rgba(0, 0, 0, 0.08); - } - - .dog-calc-footer a { - color: #9f5999; - text-decoration: none; - font-size: 0.9rem; - font-weight: 500; - transition: color 0.2s ease; - } - - .dog-calc-footer a:hover { - color: #f19a5f; - text-decoration: underline; - } - - @media (max-width: 576px) { - .dog-calc-widget { - padding: 16px; - } - - .dog-calc-section, - .dog-calc-collapsible-inner { - padding: 20px; - } - - .dog-calc-section h2, - .dog-calc-collapsible-header h3 { - font-size: 1.3rem; - } - - .dog-calc-input-group { - flex-direction: column; - gap: 20px; - } - - .dog-calc-input-group .dog-calc-form-group { - margin-bottom: 20px; - } - - .dog-calc-result-item { - flex-direction: column; - align-items: flex-start; - gap: 8px; - } - - .dog-calc-result-value { - align-self: stretch; - text-align: center; - } - - .dog-calc-collapsible-header { - padding: 16px 20px; - } - - .dog-calc-section-header { - flex-direction: column; - align-items: stretch; - gap: 12px; - } - - .dog-calc-section h2 { - text-align: center; - } - - .dog-calc-unit-switch { - justify-content: center; - } - - .dog-calc-action-buttons { - flex-direction: column; - padding: 16px; - } - - .dog-calc-btn { - width: 100%; - justify-content: center; - } - } - - /* Dark theme - manual override */ - .dog-calc-widget.dog-calc-theme-dark { - color: #f5f3f7; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-section, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-collapsible { - background: #24202d; - border-color: #433c4f; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-collapsible-header { - background: #312b3b; - border-color: #433c4f; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-collapsible-header:hover { - background: #3a3446; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-section h2, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-collapsible-header h3, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-form-group label, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-result-label { - color: #f5f3f7; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-form-group select, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-form-group input[type="number"], - .dog-calc-widget.dog-calc-theme-dark .dog-calc-form-group input[type="text"] { - background-color: #312b3b; - border-color: #433c4f; - color: #f5f3f7; - background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f5f3f7' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e"); - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-form-group select option { - background-color: #312b3b; - color: #f5f3f7; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-form-group select:focus, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-form-group input[type="number"]:focus, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-form-group input[type="text"]:focus { - background-color: #312b3b; - border-color: #f19a5f; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-form-group input[readonly] { - background-color: #433c4f; - color: #b8b0c2; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-results { - background: linear-gradient(135deg, rgba(241, 154, 95, 0.15) 0%, rgba(241, 154, 95, 0.08) 100%); - border-color: rgba(241, 154, 95, 0.3); - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-result-value { - color: #f5f3f7; - background: rgba(241, 154, 95, 0.2); - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-footer { - background: #24202d; - border-color: #433c4f; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-unit-label { - color: #b8b0c2; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-unit-label.active { - color: #f5f3f7; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-slider { - background-color: #433c4f; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-action-buttons { - background: #312b3b; - border-color: #433c4f; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-btn { - background: #433c4f; - border-color: #433c4f; - color: #f5f3f7; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-btn:hover { - background: #524a5f; - border-color: #524a5f; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-btn-share:hover { - border-color: #9f5999; - color: #f19a5f; - } - - .dog-calc-widget.dog-calc-theme-dark .dog-calc-btn-embed:hover { - border-color: #7fa464; - color: #7fa464; - } - - /* System theme - follows user's OS preference */ - @media (prefers-color-scheme: dark) { - .dog-calc-widget.dog-calc-theme-system { - color: #f5f3f7; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-section, - .dog-calc-widget.dog-calc-theme-system .dog-calc-collapsible { - background: #24202d; - border-color: #433c4f; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-collapsible-header { - background: #312b3b; - border-color: #433c4f; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-collapsible-header:hover { - background: #3a3446; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-section h2, - .dog-calc-widget.dog-calc-theme-system .dog-calc-collapsible-header h3, - .dog-calc-widget.dog-calc-theme-system .dog-calc-form-group label, - .dog-calc-widget.dog-calc-theme-system .dog-calc-result-label { - color: #f5f3f7; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-unit-label { - color: #b8b0c2; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-unit-label.active { - color: #f5f3f7; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-slider { - background-color: #433c4f; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-form-group select, - .dog-calc-widget.dog-calc-theme-system .dog-calc-form-group input[type="number"], - .dog-calc-widget.dog-calc-theme-system .dog-calc-form-group input[type="text"] { - background-color: #312b3b; - border-color: #433c4f; - color: #f5f3f7; - background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f5f3f7' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e"); - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-form-group select option { - background-color: #312b3b; - color: #f5f3f7; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-form-group select:focus, - .dog-calc-widget.dog-calc-theme-system .dog-calc-form-group input[type="number"]:focus, - .dog-calc-widget.dog-calc-theme-system .dog-calc-form-group input[type="text"]:focus { - background-color: #312b3b; - border-color: #f19a5f; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-form-group input[readonly] { - background-color: #433c4f; - color: #b8b0c2; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-results { - background: linear-gradient(135deg, rgba(241, 154, 95, 0.15) 0%, rgba(241, 154, 95, 0.08) 100%); - border-color: rgba(241, 154, 95, 0.3); - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-result-value { - color: #f5f3f7; - background: rgba(241, 154, 95, 0.2); - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-footer { - background: #24202d; - border-color: #433c4f; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-action-buttons { - background: #312b3b; - border-color: #433c4f; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-btn { - background: #433c4f; - border-color: #433c4f; - color: #f5f3f7; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-btn:hover { - background: #524a5f; - border-color: #524a5f; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-btn-share:hover { - border-color: #9f5999; - color: #f19a5f; - } - - .dog-calc-widget.dog-calc-theme-system .dog-calc-btn-embed:hover { - border-color: #7fa464; - color: #7fa464; - } - } - - /* Modal Styles */ - .dog-calc-modal { - display: none; - position: fixed; - z-index: 10000; - left: 0; - top: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.5); - animation: fadeIn 0.3s ease; - } - - @keyframes fadeIn { - from { opacity: 0; } - to { opacity: 1; } - } - - .dog-calc-modal-content { - position: relative; - background-color: #ffffff; - margin: 5% auto; - padding: 30px; - border: 1px solid #e8e3ed; - border-radius: 12px; - width: 90%; - max-width: 500px; - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); - animation: slideIn 0.3s ease; - } - - .dog-calc-modal-embed { - max-width: 700px; - } - - @keyframes slideIn { - from { - opacity: 0; - transform: translateY(-20px); - } - to { - opacity: 1; - transform: translateY(0); - } - } - - .dog-calc-modal-close { - position: absolute; - right: 20px; - top: 20px; - font-size: 28px; - font-weight: 300; - color: #6f3f6d; - cursor: pointer; - transition: color 0.2s ease; - } - - .dog-calc-modal-close:hover { - color: #f19a5f; - } - - .dog-calc-modal h3 { - margin: 0 0 24px 0; - color: #6f3f6d; - font-size: 1.5rem; - } - - /* Share Modal */ - .dog-calc-share-buttons { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); - gap: 12px; - margin-bottom: 20px; - } - - .dog-calc-share-btn { - padding: 12px 16px; - border: none; - border-radius: 6px; - font-size: 0.9rem; - font-weight: 500; - color: white; - cursor: pointer; - transition: all 0.2s ease; - display: flex; - align-items: center; - justify-content: center; - gap: 8px; - font-family: inherit; - } - - .dog-calc-share-facebook { background: #1877f2; } - .dog-calc-share-facebook:hover { background: #1664d1; transform: translateY(-1px); } - .dog-calc-share-twitter { background: #1da1f2; } - .dog-calc-share-twitter:hover { background: #1991da; transform: translateY(-1px); } - .dog-calc-share-linkedin { background: #0a66c2; } - .dog-calc-share-linkedin:hover { background: #084d95; transform: translateY(-1px); } - .dog-calc-share-email { background: #6f3f6d; } - .dog-calc-share-email:hover { background: #5a3357; transform: translateY(-1px); } - .dog-calc-share-copy { background: #f19a5f; } - .dog-calc-share-copy:hover { background: #e87741; transform: translateY(-1px); } - - .dog-calc-share-url { - display: flex; - width: 100%; - } - - .dog-calc-share-url input { - flex: 1; - width: 100%; - padding: 10px 16px; - border: 1px solid #e8e3ed; - border-radius: 6px; - font-size: 0.9rem; - font-family: monospace; - background: #f8f5fa; - color: #6f3f6d; - } - - /* Embed Modal */ - .dog-calc-embed-options { - display: flex; - flex-direction: column; - gap: 24px; - } - - .dog-calc-embed-option h4 { - margin: 0 0 8px 0; - color: #6f3f6d; - font-size: 1.1rem; - } - - .dog-calc-embed-option p { - margin: 0 0 16px 0; - color: #635870; - font-size: 0.9rem; - } - - /* Default (light theme) code containers */ - .dog-calc-code-container { - position: relative; - background: #ffffff; - border: 1px solid #e8e3ed; - border-radius: 6px; - overflow: hidden; - } - - .dog-calc-code-container pre { - margin: 0; - padding: 16px 60px 16px 16px; - overflow-x: auto; - } - - .dog-calc-code-container code { - color: #312b3b; - font-family: 'Consolas', 'Monaco', 'Courier New', monospace; - font-size: 0.85rem; - line-height: 1.4; - } - - .dog-calc-copy-btn { - position: absolute; - top: 8px; - right: 8px; - padding: 6px 10px; - background: #f19a5f; - color: white; - border: none; - border-radius: 4px; - font-size: 0.8rem; - font-weight: 500; - cursor: pointer; - transition: all 0.2s ease; - font-family: inherit; - z-index: 1; - } - - /* Better container backgrounds for contrast */ - .dog-calc-embed-option { - border: 1px solid #e8e3ed; - border-radius: 8px; - padding: 20px; - background: #fcfafd; - } - - .dog-calc-copy-btn:hover { background: #e87741; } - .dog-calc-copy-btn.copied { background: #7fa464; } - .dog-calc-copy-btn.copied:hover { background: #7fa464; } - - /* Dark theme modal styles */ - .dog-calc-theme-dark .dog-calc-modal-content, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-modal-content { - background-color: #24202d; - border-color: #433c4f; - } - - .dog-calc-theme-dark .dog-calc-modal h3, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-modal h3 { - color: #f5f3f7; - } - - .dog-calc-theme-dark .dog-calc-modal-close, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-modal-close { - color: #f5f3f7; - } - - .dog-calc-theme-dark .dog-calc-modal-close:hover, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-modal-close:hover { - color: #f19a5f; - } - - .dog-calc-theme-dark .dog-calc-share-url input, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-share-url input { - background: #312b3b; - border-color: #433c4f; - color: #f5f3f7; - } - - .dog-calc-theme-dark .dog-calc-embed-option, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-embed-option { - background: #312b3b; - border-color: #433c4f; - } - - .dog-calc-theme-dark .dog-calc-embed-option h4, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-embed-option h4 { - color: #f5f3f7; - } - - .dog-calc-theme-dark .dog-calc-embed-option p, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-embed-option p { - color: #b8b0c2; - } - - /* Dark theme code containers - different from embed option background */ - .dog-calc-theme-dark .dog-calc-code-container, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-code-container { - background: #1a1621; - border-color: #2a2330; - } - - .dog-calc-theme-dark .dog-calc-code-container code, - .dog-calc-widget.dog-calc-theme-dark .dog-calc-code-container code { - color: #f5f3f7; - } - - /* System theme modal styles */ - @media (prefers-color-scheme: dark) { - .dog-calc-theme-system .dog-calc-modal-content, - .dog-calc-widget.dog-calc-theme-system .dog-calc-modal-content { - background-color: #24202d; - border-color: #433c4f; - } - - .dog-calc-theme-system .dog-calc-modal h3, - .dog-calc-widget.dog-calc-theme-system .dog-calc-modal h3 { - color: #f5f3f7; - } - - .dog-calc-theme-system .dog-calc-modal-close, - .dog-calc-widget.dog-calc-theme-system .dog-calc-modal-close { - color: #f5f3f7; - } - - .dog-calc-theme-system .dog-calc-modal-close:hover, - .dog-calc-widget.dog-calc-theme-system .dog-calc-modal-close:hover { - color: #f19a5f; - } - - .dog-calc-theme-system .dog-calc-share-url input, - .dog-calc-widget.dog-calc-theme-system .dog-calc-share-url input { - background: #312b3b; - border-color: #433c4f; - color: #f5f3f7; - } - - .dog-calc-theme-system .dog-calc-embed-option, - .dog-calc-widget.dog-calc-theme-system .dog-calc-embed-option { - background: #312b3b; - border-color: #433c4f; - } - - .dog-calc-theme-system .dog-calc-embed-option h4, - .dog-calc-widget.dog-calc-theme-system .dog-calc-embed-option h4 { - color: #f5f3f7; - } - - .dog-calc-theme-system .dog-calc-embed-option p, - .dog-calc-widget.dog-calc-theme-system .dog-calc-embed-option p { - color: #b8b0c2; - } - - /* System theme code containers - different from embed option background */ - .dog-calc-theme-system .dog-calc-code-container, - .dog-calc-widget.dog-calc-theme-system .dog-calc-code-container { - background: #1a1621; - border-color: #2a2330; - } - - .dog-calc-theme-system .dog-calc-code-container code, - .dog-calc-widget.dog-calc-theme-system .dog-calc-code-container code { - color: #f5f3f7; - } - } - `; - - // Widget HTML template - const widgetTemplate = ` -
-
-
-

Dog's Characteristics

-
- Metric - - Imperial -
-
- -
- - -
- -
- - -
Please enter a valid weight (minimum 0.1 kg)
-
- - -
- -
-
-

How much should I feed?

-
-
-
-
-
- - -
Please enter a valid energy content
-
-
- - -
-
- - - -
- - -
Please enter a valid number of days (minimum 1)
-
- -
-
- - -
-
- - -
-
-
-
-
- -
- - -
- - -
- - - - - - - `; - - // Calculator class - class DogCalorieCalculatorWidget { - constructor(container, options = {}) { - this.container = container; - this.currentMER = 0; - this.isImperial = false; - this.theme = options.theme || 'system'; // 'light', 'dark', 'system' - this.scale = options.scale || 1.0; // 0.5 to 2.0 - this.init(); - } - - init() { - this.injectStyles(); - this.injectHTML(); - this.applyTheme(); - this.applyScale(); - this.bindEvents(); - this.updateUnitLabels(); - } - - injectStyles() { - if (!document.getElementById('dog-calc-widget-styles')) { - const style = document.createElement('style'); - style.id = 'dog-calc-widget-styles'; - style.textContent = widgetStyles; - document.head.appendChild(style); - } - } - - injectHTML() { - this.container.innerHTML = widgetTemplate; - // Move modals to document body for proper positioning and theme inheritance - this.moveModalsToBody(); - } - - moveModalsToBody() { - const shareModal = this.container.querySelector('#shareModal'); - const embedModal = this.container.querySelector('#embedModal'); - - if (shareModal) { - shareModal.remove(); - shareModal.classList.add(`dog-calc-theme-${this.theme}`); - document.body.appendChild(shareModal); - } - - if (embedModal) { - embedModal.remove(); - embedModal.classList.add(`dog-calc-theme-${this.theme}`); - document.body.appendChild(embedModal); - } - - // Bind events for modal elements now that they're in the document - this.bindModalEvents(); - } - - applyTheme() { - const widget = this.container.querySelector('.dog-calc-widget'); - if (!widget) return; - - // Remove existing theme classes - widget.classList.remove('dog-calc-theme-light', 'dog-calc-theme-dark', 'dog-calc-theme-system'); - - // Apply new theme class - widget.classList.add(`dog-calc-theme-${this.theme}`); - - // Also apply theme to modals if they exist - const shareModal = document.querySelector('#shareModal'); - const embedModal = document.querySelector('#embedModal'); - - if (shareModal) { - shareModal.classList.remove('dog-calc-theme-light', 'dog-calc-theme-dark', 'dog-calc-theme-system'); - shareModal.classList.add(`dog-calc-theme-${this.theme}`); - } - - if (embedModal) { - embedModal.classList.remove('dog-calc-theme-light', 'dog-calc-theme-dark', 'dog-calc-theme-system'); - embedModal.classList.add(`dog-calc-theme-${this.theme}`); - } - } - - applyScale() { - const widget = this.container.querySelector('.dog-calc-widget'); - if (!widget) return; - - // Clamp scale between 0.5 and 2.0 for usability - const clampedScale = Math.max(0.5, Math.min(2.0, this.scale)); - - if (clampedScale !== 1.0) { - widget.style.transform = `scale(${clampedScale})`; - widget.style.transformOrigin = 'top center'; - - // Adjust container to account for scaling - const actualHeight = widget.offsetHeight * clampedScale; - widget.style.marginBottom = `${(clampedScale - 1) * widget.offsetHeight}px`; - } - } - - bindEvents() { - const weightInput = this.container.querySelector('#weight'); - const dogTypeSelect = this.container.querySelector('#dogType'); - const foodEnergyInput = this.container.querySelector('#foodEnergy'); - const daysInput = this.container.querySelector('#days'); - const unitSelect = this.container.querySelector('#unit'); - const unitToggle = this.container.querySelector('#unitToggle'); - - if (weightInput) { - weightInput.addEventListener('input', () => this.updateCalorieCalculations()); - weightInput.addEventListener('blur', () => this.validateWeight()); - } - - if (dogTypeSelect) dogTypeSelect.addEventListener('change', () => this.updateCalorieCalculations()); - - if (foodEnergyInput) { - foodEnergyInput.addEventListener('input', () => this.updateFoodCalculations()); - foodEnergyInput.addEventListener('blur', () => this.validateFoodEnergy()); - } - - const energyUnitSelect = this.container.querySelector('#energyUnit'); - if (energyUnitSelect) energyUnitSelect.addEventListener('change', () => this.updateFoodCalculations()); - - if (daysInput) { - daysInput.addEventListener('input', () => this.updateFoodCalculations()); - daysInput.addEventListener('blur', () => this.validateDays()); - } - - if (unitSelect) unitSelect.addEventListener('change', () => this.updateFoodCalculations()); - - if (unitToggle) unitToggle.addEventListener('change', () => this.toggleUnits()); - - // Modal event listeners - buttons are in widget, modals are in document - const shareBtn = this.container.querySelector('#shareBtn'); - const embedBtn = this.container.querySelector('#embedBtn'); - - if (shareBtn) shareBtn.addEventListener('click', () => this.showShareModal()); - if (embedBtn) embedBtn.addEventListener('click', () => this.showEmbedModal()); - } - - bindModalEvents() { - // Modal elements are in document body, so we need to set up their events after moving them - const shareModalClose = document.querySelector('#shareModalClose'); - const embedModalClose = document.querySelector('#embedModalClose'); - - if (shareModalClose) shareModalClose.addEventListener('click', () => this.hideShareModal()); - if (embedModalClose) embedModalClose.addEventListener('click', () => this.hideEmbedModal()); - - // Share buttons - const shareFacebook = document.querySelector('#shareFacebook'); - const shareTwitter = document.querySelector('#shareTwitter'); - const shareLinkedIn = document.querySelector('#shareLinkedIn'); - const shareEmail = document.querySelector('#shareEmail'); - const shareCopy = document.querySelector('#shareCopy'); - - if (shareFacebook) shareFacebook.addEventListener('click', () => this.shareToFacebook()); - if (shareTwitter) shareTwitter.addEventListener('click', () => this.shareToTwitter()); - if (shareLinkedIn) shareLinkedIn.addEventListener('click', () => this.shareToLinkedIn()); - if (shareEmail) shareEmail.addEventListener('click', () => this.shareViaEmail()); - if (shareCopy) shareCopy.addEventListener('click', () => this.copyShareLink()); - - // Copy buttons - const copyWidget = document.querySelector('#copyWidget'); - const copyIframe = document.querySelector('#copyIframe'); - - if (copyWidget) copyWidget.addEventListener('click', () => this.copyEmbedCode('widget')); - if (copyIframe) copyIframe.addEventListener('click', () => this.copyEmbedCode('iframe')); - - // Close modals on outside click - const shareModal = document.querySelector('#shareModal'); - const embedModal = document.querySelector('#embedModal'); - - if (shareModal) { - shareModal.addEventListener('click', (e) => { - if (e.target === shareModal) this.hideShareModal(); - }); - } - - if (embedModal) { - embedModal.addEventListener('click', (e) => { - if (e.target === embedModal) this.hideEmbedModal(); - }); - } - } - - toggleUnits() { - const toggle = this.container.querySelector('#unitToggle'); - this.isImperial = toggle.checked; - - this.updateUnitLabels(); - this.convertExistingValues(); - this.updateCalorieCalculations(); - } - - updateUnitLabels() { - const metricLabel = this.container.querySelector('#metricLabel'); - const imperialLabel = this.container.querySelector('#imperialLabel'); - const weightLabel = this.container.querySelector('#weightLabel'); - const weightInput = this.container.querySelector('#weight'); - const unitSelect = this.container.querySelector('#unit'); - const energyUnitSelect = this.container.querySelector('#energyUnit'); - - if (metricLabel && imperialLabel) { - metricLabel.classList.toggle('active', !this.isImperial); - imperialLabel.classList.toggle('active', this.isImperial); - } - - if (this.isImperial) { - if (weightLabel) weightLabel.textContent = "Dog's Weight (lbs):"; - if (weightInput) { - weightInput.placeholder = "Enter weight in lbs"; - weightInput.min = "0.2"; - weightInput.step = "0.1"; - } - if (unitSelect) { - unitSelect.innerHTML = ` - - - - - `; - } - // Set energy unit to kcal/cup for imperial - if (energyUnitSelect && energyUnitSelect.value === 'kcal100g') { - energyUnitSelect.value = 'kcalcup'; - } - } else { - if (weightLabel) weightLabel.textContent = "Dog's Weight (kg):"; - if (weightInput) { - weightInput.placeholder = "Enter weight in kg"; - weightInput.min = "0.1"; - weightInput.step = "0.1"; - } - if (unitSelect) { - unitSelect.innerHTML = ` - - - - - `; - } - // Set energy unit to kcal/100g for metric - if (energyUnitSelect && energyUnitSelect.value === 'kcalcup') { - energyUnitSelect.value = 'kcal100g'; - } - } - } - - convertExistingValues() { - const weightInput = this.container.querySelector('#weight'); - - if (weightInput && weightInput.value) { - const currentWeight = parseFloat(weightInput.value); - if (!isNaN(currentWeight)) { - if (this.isImperial) { - weightInput.value = this.formatNumber(currentWeight * 2.20462, 1); - } else { - weightInput.value = this.formatNumber(currentWeight / 2.20462, 1); - } - } - } - } - - getWeightInKg() { - const weightInput = this.container.querySelector('#weight'); - if (!weightInput || !weightInput.value) return null; - - const weight = parseFloat(weightInput.value); - if (isNaN(weight)) return null; - - return this.isImperial ? weight / 2.20462 : weight; - } - - getFoodEnergyPer100g() { - const foodEnergyInput = this.container.querySelector('#foodEnergy'); - const energyUnitSelect = this.container.querySelector('#energyUnit'); - if (!foodEnergyInput || !foodEnergyInput.value || !energyUnitSelect) return null; - - const energy = parseFloat(foodEnergyInput.value); - if (isNaN(energy)) return null; - - const unit = energyUnitSelect.value; - - // Convert all units to kcal/100g for internal calculations - switch (unit) { - case 'kcal100g': - return energy; - case 'kcalkg': - return energy / 10; // 1 kg = 10 × 100g - case 'kcalcup': - return energy / 1.2; // Assume 1 cup ≈ 120g for dry dog food - case 'kcalcan': - return energy / 4.5; // Assume 1 can ≈ 450g for wet dog food - default: - return energy; - } - } - - calculateRER(weightKg) { - return 70 * Math.pow(weightKg, 0.75); - } - - calculateMER(rer, factor) { - return rer * factor; - } - - validateInput(value, min = 0, isInteger = false) { - const num = parseFloat(value); - if (isNaN(num) || num < min) return false; - if (isInteger && !Number.isInteger(num)) return false; - return true; - } - - showError(elementId, show = true) { - const errorElement = this.container.querySelector('#' + elementId); - if (errorElement) { - if (show) { - errorElement.classList.remove('dog-calc-hidden'); - } else { - errorElement.classList.add('dog-calc-hidden'); - } - } - } - - convertUnits(grams, unit) { - switch (unit) { - case 'kg': return grams / 1000; - case 'oz': return grams / 28.3495; - case 'lb': return grams / 453.592; - default: return grams; - } - } - - formatNumber(num, decimals = 0) { - if (decimals === 0) { - return Math.round(num).toString(); - } - return num.toFixed(decimals).replace(/\.?0+$/, ''); - } - - validateWeight() { - const weight = this.container.querySelector('#weight')?.value; - if (weight && !this.validateInput(weight, 0.1)) { - this.showError('weightError', true); - } else { - this.showError('weightError', false); - } - } - - validateFoodEnergy() { - const energyInput = this.container.querySelector('#foodEnergy'); - const energyUnitSelect = this.container.querySelector('#energyUnit'); - - if (!energyInput || !energyInput.value) { - this.showError('foodEnergyError', false); - return; - } - - const energy = parseFloat(energyInput.value); - const unit = energyUnitSelect?.value || 'kcal100g'; - - let minValue = 1; - switch (unit) { - case 'kcal100g': - minValue = 1; - break; - case 'kcalkg': - minValue = 10; - break; - case 'kcalcup': - minValue = 50; - break; - case 'kcalcan': - minValue = 100; - break; - } - - if (!this.validateInput(energy, minValue)) { - this.showError('foodEnergyError', true); - } else { - this.showError('foodEnergyError', false); - } - } - - validateDays() { - const days = this.container.querySelector('#days')?.value; - if (days && !this.validateInput(days, 1, true)) { - this.showError('daysError', true); - } else { - this.showError('daysError', false); - } - } - - updateCalorieCalculations() { - const dogTypeSelect = this.container.querySelector('#dogType'); - const calorieResults = this.container.querySelector('#calorieResults'); - const rerValue = this.container.querySelector('#rerValue'); - const merValue = this.container.querySelector('#merValue'); - - if (!dogTypeSelect || !calorieResults || !rerValue || !merValue) { - return; - } - - const weightKg = this.getWeightInKg(); - const dogTypeFactor = dogTypeSelect.value; - - this.showError('weightError', false); - - if (!weightKg || weightKg < 0.1) { - const weightInput = this.container.querySelector('#weight'); - if (weightInput && weightInput.value) this.showError('weightError', true); - calorieResults.style.display = 'none'; - return; - } - - if (!dogTypeFactor) { - calorieResults.style.display = 'none'; - return; - } - - const factor = parseFloat(dogTypeFactor); - - const rer = this.calculateRER(weightKg); - const mer = this.calculateMER(rer, factor); - - this.currentMER = mer; - - rerValue.textContent = this.formatNumber(rer, 0) + ' cal/day'; - merValue.textContent = this.formatNumber(mer, 0) + ' cal/day'; - calorieResults.style.display = 'block'; - - this.updateFoodCalculations(); - } - - updateFoodCalculations() { - if (this.currentMER === 0) return; - - const daysInput = this.container.querySelector('#days'); - const unitSelect = this.container.querySelector('#unit'); - const dailyFoodResults = this.container.querySelector('#dailyFoodResults'); - const dailyFoodValue = this.container.querySelector('#dailyFoodValue'); - const totalFoodDisplay = this.container.querySelector('#totalFoodDisplay'); - - if (!daysInput || !unitSelect || !dailyFoodResults || !dailyFoodValue || !totalFoodDisplay) { - return; - } - - const energyPer100g = this.getFoodEnergyPer100g(); - const days = daysInput.value; - const unit = unitSelect.value; - - this.showError('foodEnergyError', false); - this.showError('daysError', false); - - if (!energyPer100g || energyPer100g < 0.1) { - const foodEnergyInput = this.container.querySelector('#foodEnergy'); - if (foodEnergyInput && foodEnergyInput.value) this.showError('foodEnergyError', true); - dailyFoodResults.style.display = 'none'; - totalFoodDisplay.value = ''; - return; - } - - if (!days || !this.validateInput(days, 1, true)) { - if (days) this.showError('daysError', true); - totalFoodDisplay.value = ''; - return; - } - - const numDays = parseInt(days); - - const dailyFoodGrams = (this.currentMER / energyPer100g) * 100; - const totalFoodGrams = dailyFoodGrams * numDays; - - dailyFoodValue.textContent = this.formatNumber(dailyFoodGrams, 1) + ' g/day'; - dailyFoodResults.style.display = 'block'; - - const convertedAmount = this.convertUnits(totalFoodGrams, unit); - const unitLabel = unit === 'g' ? 'g' : unit === 'kg' ? 'kg' : unit === 'oz' ? 'oz' : 'lb'; - const decimals = unit === 'g' ? 0 : unit === 'kg' ? 2 : 1; - - totalFoodDisplay.value = this.formatNumber(convertedAmount, decimals) + ' ' + unitLabel; - } - - // Modal functionality - showShareModal() { - const modal = document.querySelector('#shareModal'); - const shareUrl = document.querySelector('#shareUrl'); - if (modal && shareUrl) { - shareUrl.value = window.location.href; - modal.style.display = 'block'; - } - } - - hideShareModal() { - const modal = document.querySelector('#shareModal'); - if (modal) modal.style.display = 'none'; - } - - showEmbedModal() { - const modal = document.querySelector('#embedModal'); - const widgetCode = document.querySelector('#widgetCode'); - const iframeCode = document.querySelector('#iframeCode'); - - if (modal && widgetCode && iframeCode) { - // Extract domain from current URL to build embed subdomain - const hostname = window.location.hostname; - const protocol = window.location.protocol; - const embedUrl = `${protocol}//embed.${hostname}`; - const theme = this.theme !== 'system' ? ` data-theme="${this.theme}"` : ''; - - widgetCode.textContent = ` -
`; - - iframeCode.textContent = ``; - - modal.style.display = 'block'; - } - } - - hideEmbedModal() { - const modal = document.querySelector('#embedModal'); - if (modal) modal.style.display = 'none'; - } - - shareToFacebook() { - const url = encodeURIComponent(window.location.href); - window.open(`https://www.facebook.com/sharer/sharer.php?u=${url}`, '_blank', 'width=600,height=400'); - } - - shareToTwitter() { - const url = encodeURIComponent(window.location.href); - const text = encodeURIComponent('Check out this useful dog calorie calculator!'); - window.open(`https://twitter.com/intent/tweet?url=${url}&text=${text}`, '_blank', 'width=600,height=400'); - } - - shareToLinkedIn() { - const url = encodeURIComponent(window.location.href); - window.open(`https://www.linkedin.com/sharing/share-offsite/?url=${url}`, '_blank', 'width=600,height=400'); - } - - shareViaEmail() { - const subject = encodeURIComponent('Dog Calorie Calculator'); - const body = encodeURIComponent(`Check out this useful dog calorie calculator: ${window.location.href}`); - window.location.href = `mailto:?subject=${subject}&body=${body}`; - } - - async copyShareLink() { - const shareUrl = document.querySelector('#shareUrl'); - const copyBtn = document.querySelector('#shareCopy'); - - if (shareUrl && copyBtn) { - try { - await navigator.clipboard.writeText(shareUrl.value); - const originalText = copyBtn.textContent; - copyBtn.textContent = 'Copied!'; - copyBtn.classList.add('copied'); - - setTimeout(() => { - copyBtn.textContent = originalText; - copyBtn.classList.remove('copied'); - }, 2000); - } catch (err) { - // Fallback for older browsers - shareUrl.select(); - document.execCommand('copy'); - } - } - } - - async copyEmbedCode(type) { - const codeElement = document.querySelector(type === 'widget' ? '#widgetCode' : '#iframeCode'); - const copyBtn = document.querySelector(type === 'widget' ? '#copyWidget' : '#copyIframe'); - - if (codeElement && copyBtn) { - try { - await navigator.clipboard.writeText(codeElement.textContent); - const originalText = copyBtn.textContent; - copyBtn.textContent = 'Copied!'; - copyBtn.classList.add('copied'); - - setTimeout(() => { - copyBtn.textContent = originalText; - copyBtn.classList.remove('copied'); - }, 2000); - } catch (err) { - // Fallback for older browsers - console.log('Copy fallback needed'); - } - } - } - } - - // Auto-initialize widget - function initDogCalorieCalculator() { - const containers = document.querySelectorAll('#dog-calorie-calculator, .dog-calorie-calculator'); - containers.forEach(container => { - if (!container.dataset.initialized) { - const theme = container.dataset.theme || 'system'; - const scale = parseFloat(container.dataset.scale) || 1.0; - new DogCalorieCalculatorWidget(container, { theme, scale }); - container.dataset.initialized = 'true'; - } - }); - } - - // Initialize when DOM is ready - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', initDogCalorieCalculator); - } else { - initDogCalorieCalculator(); - } - - // Expose for manual initialization - window.DogCalorieCalculatorWidget = DogCalorieCalculatorWidget; - -})(); \ No newline at end of file