Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files- index.html +37 -98
index.html
CHANGED
|
@@ -201,14 +201,13 @@
|
|
| 201 |
box-shadow: var(--shadow-md);
|
| 202 |
}
|
| 203 |
|
| 204 |
-
/* Distribution Preview
|
| 205 |
.dist-preview {
|
| 206 |
background: #f8fafc;
|
| 207 |
border-radius: 8px;
|
| 208 |
padding: 1rem;
|
| 209 |
border: 1px solid var(--border-color);
|
| 210 |
display: none;
|
| 211 |
-
/* Hidden by default */
|
| 212 |
animation: slideDown 0.3s ease;
|
| 213 |
}
|
| 214 |
|
|
@@ -366,7 +365,6 @@
|
|
| 366 |
gap: 0.3rem;
|
| 367 |
}
|
| 368 |
|
| 369 |
-
/* Specific style for single color badge to make it pop */
|
| 370 |
.assigned-color.single-color-highlight {
|
| 371 |
background-color: #ecfdf5;
|
| 372 |
color: var(--success-color);
|
|
@@ -374,7 +372,7 @@
|
|
| 374 |
border-radius: 4px;
|
| 375 |
border: 1px solid #a7f3d0;
|
| 376 |
}
|
| 377 |
-
|
| 378 |
.assigned-color.single-color-highlight::before {
|
| 379 |
content: '';
|
| 380 |
display: block;
|
|
@@ -459,32 +457,18 @@
|
|
| 459 |
|
| 460 |
/* Animations */
|
| 461 |
@keyframes slideDown {
|
| 462 |
-
from {
|
| 463 |
-
|
| 464 |
-
transform: translateY(-10px);
|
| 465 |
-
}
|
| 466 |
-
|
| 467 |
-
to {
|
| 468 |
-
opacity: 1;
|
| 469 |
-
transform: translateY(0);
|
| 470 |
-
}
|
| 471 |
}
|
| 472 |
|
| 473 |
@keyframes fadeIn {
|
| 474 |
-
from {
|
| 475 |
-
|
| 476 |
-
}
|
| 477 |
-
|
| 478 |
-
to {
|
| 479 |
-
opacity: 1;
|
| 480 |
-
}
|
| 481 |
}
|
| 482 |
|
| 483 |
/* Responsive */
|
| 484 |
@media (max-width: 1024px) {
|
| 485 |
-
main {
|
| 486 |
-
grid-template-columns: 1fr;
|
| 487 |
-
}
|
| 488 |
}
|
| 489 |
</style>
|
| 490 |
</head>
|
|
@@ -512,16 +496,14 @@
|
|
| 512 |
<form id="generatorForm">
|
| 513 |
<div class="form-group">
|
| 514 |
<label for="productName">Product Name</label>
|
| 515 |
-
<input type="text" id="productName" placeholder="e.g. Bermuda Linho Feminina" required autocomplete="off">
|
| 516 |
-
<div class="helper-text"><i class="fa-solid fa-tag"></i> Include material, gender, and
|
| 517 |
</div>
|
| 518 |
|
| 519 |
<div class="form-group">
|
| 520 |
<label for="colors">Color Variants (Comma or Slash separated)</label>
|
| 521 |
-
<!-- Updated placeholder to show slash support -->
|
| 522 |
<input type="text" id="colors" placeholder="e.g. Black, Grey / Dark Blue, Army Green" required autocomplete="off">
|
| 523 |
-
<div class="helper-text"><i class="fa-solid fa-palette"></i> List all available colors. Use commas or slashes
|
| 524 |
-
</div>
|
| 525 |
</div>
|
| 526 |
|
| 527 |
<button type="submit" class="btn-generate">
|
|
@@ -570,12 +552,13 @@
|
|
| 570 |
* SHOOT COORDINATOR LOGIC
|
| 571 |
* Role: Asset Coordinator
|
| 572 |
* Goal: Distribute colors strictly across two categories.
|
| 573 |
-
* FIX: Improved parsing to handle comma OR slash separation.
|
|
|
|
| 574 |
*/
|
| 575 |
|
| 576 |
const TEMPLATES = {
|
| 577 |
// --- CATEGORY A: MULTI-COLOR SHOTS ---
|
| 578 |
-
// Constraint: Must depict ALL colors.
|
| 579 |
AVALIACAO_ESPELHO: {
|
| 580 |
title: "Review Mirror",
|
| 581 |
type: "multi",
|
|
@@ -598,11 +581,11 @@
|
|
| 598 |
},
|
| 599 |
|
| 600 |
// --- CATEGORY B: SINGLE-COLOR SHOTS ---
|
| 601 |
-
// Constraint: Pick ONE color per shot.
|
| 602 |
DETALHE_1: {
|
| 603 |
title: "Detail Shot 1 (Hand)",
|
| 604 |
type: "single",
|
| 605 |
-
text: `DETALHE DO PRODUTO STRICT VISUAL MATCH TAKEN WITH IPHONE. 1:1 Square format. The subject is the EXACT "{{PRODUCT_NAME}}" in color {{ACTIVE_COLOR}}. A hand is gently pinching the fabric to display the texture and authentic stitching details. Extreme close-up focus on the material weave and construction. Natural sunlight, casual atmosphere, amateur raw photo style. DO NOT ALTER THE SILHOUETTE. --ar 1:1 --style raw --v 6.0`
|
| 606 |
},
|
| 607 |
DETALHE_2: {
|
| 608 |
title: "Detail Shot 2 (Macro)",
|
|
@@ -623,7 +606,7 @@
|
|
| 623 |
// Utility
|
| 624 |
TEXTO_FOTO_PRINCIPAL: {
|
| 625 |
title: "Main Photo Text Overlay",
|
| 626 |
-
type: "multi",
|
| 627 |
text: `TEXTO FOTO PRINCIPAL Ensure the promotional text "Pague 3, Leve 5". Preserve exact original image position. Maintain flat lighting, no visible JPEG artifacts, Ultra-realistic, 8k resolution, photographic clarity, sharp focus. Simple composition, use of symmetry, shallow depth of field. Add bold, sharp graphic text overlays seamlessly integrated.`
|
| 628 |
}
|
| 629 |
};
|
|
@@ -665,8 +648,7 @@
|
|
| 665 |
variables.TARGET_AUDIENCE = "Male";
|
| 666 |
}
|
| 667 |
|
| 668 |
-
// Color Analysis -
|
| 669 |
-
// Now splits by comma OR forward slash to handle inputs like "Red/Blue"
|
| 670 |
const colorsArray = colorsStr.split(/[,\/]/).map(c => c.trim()).filter(c => c.length > 0);
|
| 671 |
variables.COLORS_ARRAY = colorsArray;
|
| 672 |
variables.COLOR_LIST = colorsArray.join(', ');
|
|
@@ -685,17 +667,23 @@
|
|
| 685 |
|
| 686 |
// --- STRING SUBSTITUTION ---
|
| 687 |
|
| 688 |
-
function applySubstitutions(templateStr, variables, activeColor) {
|
| 689 |
let result = templateStr;
|
| 690 |
|
| 691 |
// Core Data
|
| 692 |
result = result.replace(/{{PRODUCT_NAME}}/g, variables.PRODUCT_NAME);
|
| 693 |
result = result.replace(/{{MATERIAL}}/g, variables.MATERIAL);
|
| 694 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 695 |
|
| 696 |
// Color Logic
|
| 697 |
result = result.replace(/{{ALL_COLORS}}/g, variables.COLOR_LIST);
|
| 698 |
-
// IMPORTANT: This replaces the placeholder with ONLY the specific single color assigned
|
| 699 |
result = result.replace(/{{ACTIVE_COLOR}}/g, activeColor);
|
| 700 |
|
| 701 |
// Legacy Cleanup
|
|
@@ -745,10 +733,9 @@
|
|
| 745 |
// Assign Single Colors (Cycle Logic)
|
| 746 |
let colorPointer = 0;
|
| 747 |
const singleColorKeys = ['DETALHE_1', 'DETALHE_2', 'PESSOA_USANDO_1', 'PESSOA_USANDO_2'];
|
| 748 |
-
const singleColorAssignments = {};
|
| 749 |
|
| 750 |
singleColorKeys.forEach(key => {
|
| 751 |
-
// Use modulo to cycle through colors if there are fewer colors than shots
|
| 752 |
const assignedColor = vars.COLORS_ARRAY[colorPointer % vars.COLORS_ARRAY.length];
|
| 753 |
singleColorAssignments[key] = assignedColor;
|
| 754 |
distributionPlan.single.push({ key, color: assignedColor });
|
|
@@ -768,12 +755,14 @@
|
|
| 768 |
<span class="dist-label">Multi-Variant Shots</span>
|
| 769 |
<div class="color-chips">
|
| 770 |
<span class="chip multi">${vars.COLORS_ARRAY.length} Colors</span>
|
|
|
|
| 771 |
</div>
|
| 772 |
</div>
|
| 773 |
<div class="dist-row">
|
| 774 |
<span class="dist-label">Single-Variant Shots</span>
|
| 775 |
<div class="color-chips">
|
| 776 |
-
|
|
|
|
| 777 |
</div>
|
| 778 |
</div>
|
| 779 |
`;
|
|
@@ -791,11 +780,14 @@
|
|
| 791 |
const badgeText = type === 'multi' ? 'Full Spectrum' : 'Single Variant';
|
| 792 |
|
| 793 |
let colorDisplay;
|
|
|
|
|
|
|
| 794 |
if (type === 'multi') {
|
| 795 |
colorDisplay = `<span class="assigned-color" style="color:var(--accent-color)"><i class="fa-solid fa-palette"></i> ${vars.COLORS_ARRAY.length} Variants</span>`;
|
|
|
|
| 796 |
} else {
|
| 797 |
-
// Highlight the single color specifically
|
| 798 |
colorDisplay = `<span class="assigned-color single-color-highlight">${colorLabel}</span>`;
|
|
|
|
| 799 |
}
|
| 800 |
|
| 801 |
card.innerHTML = `
|
|
@@ -804,6 +796,7 @@
|
|
| 804 |
<span class="variant-badge ${badgeClass}">${badgeText}</span>
|
| 805 |
<span class="card-title">${title}</span>
|
| 806 |
${colorDisplay}
|
|
|
|
| 807 |
</div>
|
| 808 |
<button class="btn-copy-single" onclick="copyToClipboard(this)" data-text="${encodeURIComponent(text)}">
|
| 809 |
<i class="fa-regular fa-copy"></i> Copy
|
|
@@ -814,65 +807,11 @@
|
|
| 814 |
return card;
|
| 815 |
};
|
| 816 |
|
| 817 |
-
// Group 1: Multi-Variant
|
| 818 |
const group1 = document.createElement('div');
|
| 819 |
group1.className = 'section-group';
|
| 820 |
group1.innerHTML = `<div class="section-header"><i class="fa-solid fa-layer-group"></i> Phase 1: Full Spectrum Shots</div>`;
|
| 821 |
|
| 822 |
multiColorKeys.forEach(key => {
|
| 823 |
if(TEMPLATES[key]) {
|
| 824 |
-
//
|
| 825 |
-
const processed = applySubstitutions(TEMPLATES[key].text, vars, vars.COLOR_LIST);
|
| 826 |
-
group1.appendChild(createCard(key, TEMPLATES[key].title, processed, 'multi', vars.COLOR_LIST));
|
| 827 |
-
allGeneratedText.push(processed);
|
| 828 |
-
}
|
| 829 |
-
});
|
| 830 |
-
resultsContainer.appendChild(group1);
|
| 831 |
-
|
| 832 |
-
// Group 2: Single-Variant
|
| 833 |
-
const group2 = document.createElement('div');
|
| 834 |
-
group2.className = 'section-group';
|
| 835 |
-
group2.innerHTML = `<div class="section-header"><i class="fa-solid fa-user-tag"></i> Phase 2: Individual Variant Focus</div>`;
|
| 836 |
-
|
| 837 |
-
singleColorKeys.forEach(key => {
|
| 838 |
-
if(TEMPLATES[key]) {
|
| 839 |
-
// CRITICAL FIX: Pass the specific single color assigned to this key
|
| 840 |
-
const activeColor = singleColorAssignments[key];
|
| 841 |
-
const processed = applySubstitutions(TEMPLATES[key].text, vars, activeColor);
|
| 842 |
-
group2.appendChild(createCard(key, TEMPLATES[key].title, processed, 'single', activeColor));
|
| 843 |
-
allGeneratedText.push(processed);
|
| 844 |
-
}
|
| 845 |
-
});
|
| 846 |
-
resultsContainer.appendChild(group2);
|
| 847 |
-
|
| 848 |
-
// Setup Copy All
|
| 849 |
-
copyAllBtn.style.display = 'flex';
|
| 850 |
-
copyAllBtn.onclick = () => {
|
| 851 |
-
const allText = allGeneratedText.join('\n\n---\n\n');
|
| 852 |
-
navigator.clipboard.writeText(allText).then(() => showToast('All prompts copied!'));
|
| 853 |
-
};
|
| 854 |
-
});
|
| 855 |
-
|
| 856 |
-
// Utils
|
| 857 |
-
window.copyToClipboard = function(btn) {
|
| 858 |
-
const text = decodeURIComponent(btn.getAttribute('data-text'));
|
| 859 |
-
navigator.clipboard.writeText(text).then(() => {
|
| 860 |
-
const originalHTML = btn.innerHTML;
|
| 861 |
-
btn.innerHTML = `<i class="fa-solid fa-check"></i> Copied`;
|
| 862 |
-
setTimeout(() => {
|
| 863 |
-
btn.innerHTML = originalHTML;
|
| 864 |
-
}, 2000);
|
| 865 |
-
});
|
| 866 |
-
};
|
| 867 |
-
|
| 868 |
-
function showToast(msg) {
|
| 869 |
-
const toastMsg = document.getElementById('toastMessage');
|
| 870 |
-
toastMsg.textContent = msg;
|
| 871 |
-
const toast = document.getElementById('toast');
|
| 872 |
-
toast.classList.add('show');
|
| 873 |
-
setTimeout(() => toast.classList.remove('show'), 3000);
|
| 874 |
-
}
|
| 875 |
-
</script>
|
| 876 |
-
</body>
|
| 877 |
-
|
| 878 |
-
</html>
|
|
|
|
| 201 |
box-shadow: var(--shadow-md);
|
| 202 |
}
|
| 203 |
|
| 204 |
+
/* Distribution Preview */
|
| 205 |
.dist-preview {
|
| 206 |
background: #f8fafc;
|
| 207 |
border-radius: 8px;
|
| 208 |
padding: 1rem;
|
| 209 |
border: 1px solid var(--border-color);
|
| 210 |
display: none;
|
|
|
|
| 211 |
animation: slideDown 0.3s ease;
|
| 212 |
}
|
| 213 |
|
|
|
|
| 365 |
gap: 0.3rem;
|
| 366 |
}
|
| 367 |
|
|
|
|
| 368 |
.assigned-color.single-color-highlight {
|
| 369 |
background-color: #ecfdf5;
|
| 370 |
color: var(--success-color);
|
|
|
|
| 372 |
border-radius: 4px;
|
| 373 |
border: 1px solid #a7f3d0;
|
| 374 |
}
|
| 375 |
+
|
| 376 |
.assigned-color.single-color-highlight::before {
|
| 377 |
content: '';
|
| 378 |
display: block;
|
|
|
|
| 457 |
|
| 458 |
/* Animations */
|
| 459 |
@keyframes slideDown {
|
| 460 |
+
from { opacity: 0; transform: translateY(-10px); }
|
| 461 |
+
to { opacity: 1; transform: translateY(0); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 462 |
}
|
| 463 |
|
| 464 |
@keyframes fadeIn {
|
| 465 |
+
from { opacity: 0; }
|
| 466 |
+
to { opacity: 1; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 467 |
}
|
| 468 |
|
| 469 |
/* Responsive */
|
| 470 |
@media (max-width: 1024px) {
|
| 471 |
+
main { grid-template-columns: 1fr; }
|
|
|
|
|
|
|
| 472 |
}
|
| 473 |
</style>
|
| 474 |
</head>
|
|
|
|
| 496 |
<form id="generatorForm">
|
| 497 |
<div class="form-group">
|
| 498 |
<label for="productName">Product Name</label>
|
| 499 |
+
<input type="text" id="productName" placeholder="e.g. Bermuda Linho Feminina (Leve 3)" required autocomplete="off">
|
| 500 |
+
<div class="helper-text"><i class="fa-solid fa-tag"></i> Include material, gender, and bundle info.</div>
|
| 501 |
</div>
|
| 502 |
|
| 503 |
<div class="form-group">
|
| 504 |
<label for="colors">Color Variants (Comma or Slash separated)</label>
|
|
|
|
| 505 |
<input type="text" id="colors" placeholder="e.g. Black, Grey / Dark Blue, Army Green" required autocomplete="off">
|
| 506 |
+
<div class="helper-text"><i class="fa-solid fa-palette"></i> List all available colors. Use commas or slashes.</div>
|
|
|
|
| 507 |
</div>
|
| 508 |
|
| 509 |
<button type="submit" class="btn-generate">
|
|
|
|
| 552 |
* SHOOT COORDINATOR LOGIC
|
| 553 |
* Role: Asset Coordinator
|
| 554 |
* Goal: Distribute colors strictly across two categories.
|
| 555 |
+
* FIX 1: Improved parsing to handle comma OR slash separation.
|
| 556 |
+
* FIX 2: Force quantity to 1 for Single Variant shots (Phase 2), regardless of bundle size.
|
| 557 |
*/
|
| 558 |
|
| 559 |
const TEMPLATES = {
|
| 560 |
// --- CATEGORY A: MULTI-COLOR SHOTS ---
|
| 561 |
+
// Constraint: Must depict ALL colors. Uses TOTAL_QUANTITY.
|
| 562 |
AVALIACAO_ESPELHO: {
|
| 563 |
title: "Review Mirror",
|
| 564 |
type: "multi",
|
|
|
|
| 581 |
},
|
| 582 |
|
| 583 |
// --- CATEGORY B: SINGLE-COLOR SHOTS ---
|
| 584 |
+
// Constraint: Pick ONE color per shot. QUANTITY FORCED TO 1.
|
| 585 |
DETALHE_1: {
|
| 586 |
title: "Detail Shot 1 (Hand)",
|
| 587 |
type: "single",
|
| 588 |
+
text: `DETALHE DO PRODUTO STRICT VISUAL MATCH TAKEN WITH IPHONE. 1:1 Square format. The subject is the EXACT "{{PRODUCT_NAME}}" in color {{ACTIVE_COLOR}} (Qty: 1). A hand is gently pinching the fabric to display the texture and authentic stitching details. Extreme close-up focus on the material weave and construction. Natural sunlight, casual atmosphere, amateur raw photo style. DO NOT ALTER THE SILHOUETTE. --ar 1:1 --style raw --v 6.0`
|
| 589 |
},
|
| 590 |
DETALHE_2: {
|
| 591 |
title: "Detail Shot 2 (Macro)",
|
|
|
|
| 606 |
// Utility
|
| 607 |
TEXTO_FOTO_PRINCIPAL: {
|
| 608 |
title: "Main Photo Text Overlay",
|
| 609 |
+
type: "multi",
|
| 610 |
text: `TEXTO FOTO PRINCIPAL Ensure the promotional text "Pague 3, Leve 5". Preserve exact original image position. Maintain flat lighting, no visible JPEG artifacts, Ultra-realistic, 8k resolution, photographic clarity, sharp focus. Simple composition, use of symmetry, shallow depth of field. Add bold, sharp graphic text overlays seamlessly integrated.`
|
| 611 |
}
|
| 612 |
};
|
|
|
|
| 648 |
variables.TARGET_AUDIENCE = "Male";
|
| 649 |
}
|
| 650 |
|
| 651 |
+
// Color Analysis - Split by comma OR slash
|
|
|
|
| 652 |
const colorsArray = colorsStr.split(/[,\/]/).map(c => c.trim()).filter(c => c.length > 0);
|
| 653 |
variables.COLORS_ARRAY = colorsArray;
|
| 654 |
variables.COLOR_LIST = colorsArray.join(', ');
|
|
|
|
| 667 |
|
| 668 |
// --- STRING SUBSTITUTION ---
|
| 669 |
|
| 670 |
+
function applySubstitutions(templateStr, variables, activeColor, type) {
|
| 671 |
let result = templateStr;
|
| 672 |
|
| 673 |
// Core Data
|
| 674 |
result = result.replace(/{{PRODUCT_NAME}}/g, variables.PRODUCT_NAME);
|
| 675 |
result = result.replace(/{{MATERIAL}}/g, variables.MATERIAL);
|
| 676 |
+
|
| 677 |
+
// Quantity Logic Override
|
| 678 |
+
// CRITICAL: If type is 'single', we force quantity to 1 to avoid showing piles/bundles in detail shots
|
| 679 |
+
let quantityToUse = variables.TOTAL_QUANTITY;
|
| 680 |
+
if (type === 'single') {
|
| 681 |
+
quantityToUse = 1;
|
| 682 |
+
}
|
| 683 |
+
result = result.replace(/{{QUANTITY}}/g, quantityToUse);
|
| 684 |
|
| 685 |
// Color Logic
|
| 686 |
result = result.replace(/{{ALL_COLORS}}/g, variables.COLOR_LIST);
|
|
|
|
| 687 |
result = result.replace(/{{ACTIVE_COLOR}}/g, activeColor);
|
| 688 |
|
| 689 |
// Legacy Cleanup
|
|
|
|
| 733 |
// Assign Single Colors (Cycle Logic)
|
| 734 |
let colorPointer = 0;
|
| 735 |
const singleColorKeys = ['DETALHE_1', 'DETALHE_2', 'PESSOA_USANDO_1', 'PESSOA_USANDO_2'];
|
| 736 |
+
const singleColorAssignments = {};
|
| 737 |
|
| 738 |
singleColorKeys.forEach(key => {
|
|
|
|
| 739 |
const assignedColor = vars.COLORS_ARRAY[colorPointer % vars.COLORS_ARRAY.length];
|
| 740 |
singleColorAssignments[key] = assignedColor;
|
| 741 |
distributionPlan.single.push({ key, color: assignedColor });
|
|
|
|
| 755 |
<span class="dist-label">Multi-Variant Shots</span>
|
| 756 |
<div class="color-chips">
|
| 757 |
<span class="chip multi">${vars.COLORS_ARRAY.length} Colors</span>
|
| 758 |
+
<span class="chip" style="border:none; background:transparent;">(${vars.TOTAL_QUANTITY} units/shot)</span>
|
| 759 |
</div>
|
| 760 |
</div>
|
| 761 |
<div class="dist-row">
|
| 762 |
<span class="dist-label">Single-Variant Shots</span>
|
| 763 |
<div class="color-chips">
|
| 764 |
+
<span class="chip single-color-highlight" style="border-color:var(--success-color); color:var(--success-color);">1 Unit/Shot</span>
|
| 765 |
+
<span class="chip" style="border:none; background:transparent;">(Forced Qty)</span>
|
| 766 |
</div>
|
| 767 |
</div>
|
| 768 |
`;
|
|
|
|
| 780 |
const badgeText = type === 'multi' ? 'Full Spectrum' : 'Single Variant';
|
| 781 |
|
| 782 |
let colorDisplay;
|
| 783 |
+
let qtyInfo = "";
|
| 784 |
+
|
| 785 |
if (type === 'multi') {
|
| 786 |
colorDisplay = `<span class="assigned-color" style="color:var(--accent-color)"><i class="fa-solid fa-palette"></i> ${vars.COLORS_ARRAY.length} Variants</span>`;
|
| 787 |
+
qtyInfo = `<span style="font-size:0.7rem; color:var(--text-secondary); margin-left:8px;">(${vars.TOTAL_QUANTITY} units)</span>`;
|
| 788 |
} else {
|
|
|
|
| 789 |
colorDisplay = `<span class="assigned-color single-color-highlight">${colorLabel}</span>`;
|
| 790 |
+
qtyInfo = `<span style="font-size:0.7rem; color:var(--success-color); margin-left:8px; font-weight:600;">(Qty: 1)</span>`;
|
| 791 |
}
|
| 792 |
|
| 793 |
card.innerHTML = `
|
|
|
|
| 796 |
<span class="variant-badge ${badgeClass}">${badgeText}</span>
|
| 797 |
<span class="card-title">${title}</span>
|
| 798 |
${colorDisplay}
|
| 799 |
+
${qtyInfo}
|
| 800 |
</div>
|
| 801 |
<button class="btn-copy-single" onclick="copyToClipboard(this)" data-text="${encodeURIComponent(text)}">
|
| 802 |
<i class="fa-regular fa-copy"></i> Copy
|
|
|
|
| 807 |
return card;
|
| 808 |
};
|
| 809 |
|
| 810 |
+
// Group 1: Multi-Variant (Pass 'multi' type)
|
| 811 |
const group1 = document.createElement('div');
|
| 812 |
group1.className = 'section-group';
|
| 813 |
group1.innerHTML = `<div class="section-header"><i class="fa-solid fa-layer-group"></i> Phase 1: Full Spectrum Shots</div>`;
|
| 814 |
|
| 815 |
multiColorKeys.forEach(key => {
|
| 816 |
if(TEMPLATES[key]) {
|
| 817 |
+
// Pass 'multi' as
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|