Update app_enhanced.py
Browse files- app_enhanced.py +39 -18
app_enhanced.py
CHANGED
|
@@ -543,13 +543,14 @@ class EnhancedComicGenerator:
|
|
| 543 |
.speech-bubble.selected { outline: 2px dashed #4CAF50; }
|
| 544 |
.speech-bubble textarea { position: absolute; top: 0; left: 0; width: 100%; height: 100%; box-sizing: border-box; border: 1px solid #4CAF50; background: rgba(255,255,255,0.95); font: inherit; text-align: center; resize: none; padding: 8px; z-index: 102; }
|
| 545 |
|
| 546 |
-
/* <<<
|
| 547 |
.speech-bubble.speech {
|
| 548 |
background: var(--bubble-fill-color, white);
|
| 549 |
color: var(--bubble-text-color, #333);
|
| 550 |
border: 2px solid var(--bubble-border-color, #333);
|
| 551 |
border-radius: 10px;
|
| 552 |
padding: 0;
|
|
|
|
| 553 |
}
|
| 554 |
|
| 555 |
.speech-bubble.speech:after, .speech-bubble.speech:before {
|
|
@@ -557,16 +558,16 @@ class EnhancedComicGenerator:
|
|
| 557 |
position: absolute;
|
| 558 |
display: block;
|
| 559 |
width: 0;
|
|
|
|
| 560 |
}
|
| 561 |
|
| 562 |
-
/*
|
| 563 |
-
/* BOTTOM */
|
| 564 |
.speech-bubble.speech.tail-bottom:after {
|
| 565 |
border-style: solid;
|
| 566 |
border-width: 15px 15px 0 0;
|
| 567 |
border-color: var(--bubble-fill-color, white) transparent transparent transparent;
|
| 568 |
bottom: -15px;
|
| 569 |
-
left:
|
| 570 |
transform: translateX(-50%);
|
| 571 |
z-index: 1;
|
| 572 |
}
|
|
@@ -575,18 +576,18 @@ class EnhancedComicGenerator:
|
|
| 575 |
border-width: 17px 17px 0 0;
|
| 576 |
border-color: var(--bubble-border-color, #333) transparent transparent transparent;
|
| 577 |
bottom: -19px;
|
| 578 |
-
left:
|
| 579 |
transform: translateX(-50%);
|
| 580 |
z-index: 0;
|
| 581 |
}
|
| 582 |
|
| 583 |
-
/* TOP */
|
| 584 |
.speech-bubble.speech.tail-top:after {
|
| 585 |
border-style: solid;
|
| 586 |
border-width: 0 15px 15px 0;
|
| 587 |
border-color: transparent var(--bubble-fill-color, white) transparent transparent;
|
| 588 |
top: -15px;
|
| 589 |
-
left:
|
| 590 |
transform: translateX(-50%) rotate(180deg);
|
| 591 |
z-index: 1;
|
| 592 |
}
|
|
@@ -595,17 +596,17 @@ class EnhancedComicGenerator:
|
|
| 595 |
border-width: 0 17px 17px 0;
|
| 596 |
border-color: transparent var(--bubble-border-color, #333) transparent transparent;
|
| 597 |
top: -19px;
|
| 598 |
-
left:
|
| 599 |
transform: translateX(-50%) rotate(180deg);
|
| 600 |
z-index: 0;
|
| 601 |
}
|
| 602 |
|
| 603 |
-
/* RIGHT */
|
| 604 |
-
|
| 605 |
border-style: solid;
|
| 606 |
border-width: 15px 15px 0 0;
|
| 607 |
border-color: var(--bubble-fill-color, white) transparent transparent transparent;
|
| 608 |
-
top:
|
| 609 |
right: -15px;
|
| 610 |
transform: translateY(-50%) rotate(90deg);
|
| 611 |
z-index: 1;
|
|
@@ -614,18 +615,18 @@ class EnhancedComicGenerator:
|
|
| 614 |
border-style: solid;
|
| 615 |
border-width: 17px 17px 0 0;
|
| 616 |
border-color: var(--bubble-border-color, #333) transparent transparent transparent;
|
| 617 |
-
top:
|
| 618 |
right: -19px;
|
| 619 |
transform: translateY(-50%) rotate(90deg);
|
| 620 |
z-index: 0;
|
| 621 |
}
|
| 622 |
|
| 623 |
-
/* LEFT */
|
| 624 |
.speech-bubble.speech.tail-left:after {
|
| 625 |
border-style: solid;
|
| 626 |
border-width: 15px 15px 0 0;
|
| 627 |
border-color: var(--bubble-fill-color, white) transparent transparent transparent;
|
| 628 |
-
top:
|
| 629 |
left: -15px;
|
| 630 |
transform: translateY(-50%) rotate(-90deg);
|
| 631 |
z-index: 1;
|
|
@@ -634,12 +635,11 @@ class EnhancedComicGenerator:
|
|
| 634 |
border-style: solid;
|
| 635 |
border-width: 17px 17px 0 0;
|
| 636 |
border-color: var(--bubble-border-color, #333) transparent transparent transparent;
|
| 637 |
-
top:
|
| 638 |
left: -19px;
|
| 639 |
transform: translateY(-50%) rotate(-90deg);
|
| 640 |
z-index: 0;
|
| 641 |
}
|
| 642 |
-
/* <<< MODIFICATION END >>> */
|
| 643 |
|
| 644 |
.speech-bubble.thought { background: white; border: 2px dashed #555; color: #333; border-radius: 50%; }
|
| 645 |
.speech-bubble.reaction { background: #FFD700; border: 3px solid #E53935; color: #D32F2F; font-weight: 900; text-transform: uppercase; width: 180px; clip-path: polygon(0% 25%, 17% 21%, 17% 0%, 31% 16%, 50% 4%, 69% 16%, 83% 0%, 83% 21%, 100% 25%, 85% 45%, 95% 62%, 82% 79%, 100% 97%, 79% 89%, 60% 98%, 46% 82%, 27% 95%, 15% 78%, 5% 62%, 15% 45%); }
|
|
@@ -676,6 +676,9 @@ class EnhancedComicGenerator:
|
|
| 676 |
.color-picker-grid div { text-align: center; }
|
| 677 |
.color-picker-grid label { font-size: 11px; }
|
| 678 |
.color-picker-grid input[type="color"] { height: 25px; padding: 2px; }
|
|
|
|
|
|
|
|
|
|
| 679 |
</style>
|
| 680 |
</head>
|
| 681 |
<body>
|
|
@@ -711,8 +714,12 @@ class EnhancedComicGenerator:
|
|
| 711 |
<button onclick="deleteBubble()" class="reset-button">🗑️ Delete Bubble</button>
|
| 712 |
</div>
|
| 713 |
<div class="control-group" id="tail-controls" style="display: none;">
|
| 714 |
-
<label>Tail
|
| 715 |
-
<button onclick="rotateBubbleTail()" class="secondary-button">🔄 Rotate
|
|
|
|
|
|
|
|
|
|
|
|
|
| 716 |
</div>
|
| 717 |
<div class="control-group">
|
| 718 |
<label>Panel Tools (Select Panel):</label>
|
|
@@ -902,6 +909,11 @@ class EnhancedComicGenerator:
|
|
| 902 |
alert("Tail rotation is only available for Speech and Thought bubbles.");
|
| 903 |
}
|
| 904 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 905 |
|
| 906 |
function selectPanel(panel) {
|
| 907 |
document.querySelectorAll('.panel.selected').forEach(p => p.classList.remove('selected'));
|
|
@@ -915,6 +927,7 @@ class EnhancedComicGenerator:
|
|
| 915 |
currentlySelectedBubble = bubble;
|
| 916 |
const bubbleControls = ['bubble-text-color', 'bubble-fill-color', 'bubble-type-select', 'font-select'];
|
| 917 |
const tailControls = document.getElementById('tail-controls');
|
|
|
|
| 918 |
|
| 919 |
if (currentlySelectedBubble) {
|
| 920 |
currentlySelectedBubble.classList.add('selected');
|
|
@@ -934,6 +947,14 @@ class EnhancedComicGenerator:
|
|
| 934 |
document.getElementById('bubble-type-select').value = currentlySelectedBubble.dataset.type || 'speech';
|
| 935 |
document.getElementById('font-select').value = styles.fontFamily.split(',')[0].replace(/"/g, "").replace(/'/g, "").trim();
|
| 936 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 937 |
document.getElementById('zoom-slider').disabled = true;
|
| 938 |
bubbleControls.forEach(id => document.getElementById(id).disabled = false);
|
| 939 |
|
|
|
|
| 543 |
.speech-bubble.selected { outline: 2px dashed #4CAF50; }
|
| 544 |
.speech-bubble textarea { position: absolute; top: 0; left: 0; width: 100%; height: 100%; box-sizing: border-box; border: 1px solid #4CAF50; background: rgba(255,255,255,0.95); font: inherit; text-align: center; resize: none; padding: 8px; z-index: 102; }
|
| 545 |
|
| 546 |
+
/* <<< FIXED BUBBLE CSS WITH DYNAMIC TAIL SLIDER >>> */
|
| 547 |
.speech-bubble.speech {
|
| 548 |
background: var(--bubble-fill-color, white);
|
| 549 |
color: var(--bubble-text-color, #333);
|
| 550 |
border: 2px solid var(--bubble-border-color, #333);
|
| 551 |
border-radius: 10px;
|
| 552 |
padding: 0;
|
| 553 |
+
--tail-pos: 50%; /* Default centered tail */
|
| 554 |
}
|
| 555 |
|
| 556 |
.speech-bubble.speech:after, .speech-bubble.speech:before {
|
|
|
|
| 558 |
position: absolute;
|
| 559 |
display: block;
|
| 560 |
width: 0;
|
| 561 |
+
pointer-events: none;
|
| 562 |
}
|
| 563 |
|
| 564 |
+
/* BOTTOM TAIL */
|
|
|
|
| 565 |
.speech-bubble.speech.tail-bottom:after {
|
| 566 |
border-style: solid;
|
| 567 |
border-width: 15px 15px 0 0;
|
| 568 |
border-color: var(--bubble-fill-color, white) transparent transparent transparent;
|
| 569 |
bottom: -15px;
|
| 570 |
+
left: var(--tail-pos);
|
| 571 |
transform: translateX(-50%);
|
| 572 |
z-index: 1;
|
| 573 |
}
|
|
|
|
| 576 |
border-width: 17px 17px 0 0;
|
| 577 |
border-color: var(--bubble-border-color, #333) transparent transparent transparent;
|
| 578 |
bottom: -19px;
|
| 579 |
+
left: var(--tail-pos);
|
| 580 |
transform: translateX(-50%);
|
| 581 |
z-index: 0;
|
| 582 |
}
|
| 583 |
|
| 584 |
+
/* TOP TAIL */
|
| 585 |
.speech-bubble.speech.tail-top:after {
|
| 586 |
border-style: solid;
|
| 587 |
border-width: 0 15px 15px 0;
|
| 588 |
border-color: transparent var(--bubble-fill-color, white) transparent transparent;
|
| 589 |
top: -15px;
|
| 590 |
+
left: var(--tail-pos);
|
| 591 |
transform: translateX(-50%) rotate(180deg);
|
| 592 |
z-index: 1;
|
| 593 |
}
|
|
|
|
| 596 |
border-width: 0 17px 17px 0;
|
| 597 |
border-color: transparent var(--bubble-border-color, #333) transparent transparent;
|
| 598 |
top: -19px;
|
| 599 |
+
left: var(--tail-pos);
|
| 600 |
transform: translateX(-50%) rotate(180deg);
|
| 601 |
z-index: 0;
|
| 602 |
}
|
| 603 |
|
| 604 |
+
/* RIGHT TAIL */
|
| 605 |
+
.speech-bubble.speech.tail-right:after {
|
| 606 |
border-style: solid;
|
| 607 |
border-width: 15px 15px 0 0;
|
| 608 |
border-color: var(--bubble-fill-color, white) transparent transparent transparent;
|
| 609 |
+
top: var(--tail-pos);
|
| 610 |
right: -15px;
|
| 611 |
transform: translateY(-50%) rotate(90deg);
|
| 612 |
z-index: 1;
|
|
|
|
| 615 |
border-style: solid;
|
| 616 |
border-width: 17px 17px 0 0;
|
| 617 |
border-color: var(--bubble-border-color, #333) transparent transparent transparent;
|
| 618 |
+
top: var(--tail-pos);
|
| 619 |
right: -19px;
|
| 620 |
transform: translateY(-50%) rotate(90deg);
|
| 621 |
z-index: 0;
|
| 622 |
}
|
| 623 |
|
| 624 |
+
/* LEFT TAIL */
|
| 625 |
.speech-bubble.speech.tail-left:after {
|
| 626 |
border-style: solid;
|
| 627 |
border-width: 15px 15px 0 0;
|
| 628 |
border-color: var(--bubble-fill-color, white) transparent transparent transparent;
|
| 629 |
+
top: var(--tail-pos);
|
| 630 |
left: -15px;
|
| 631 |
transform: translateY(-50%) rotate(-90deg);
|
| 632 |
z-index: 1;
|
|
|
|
| 635 |
border-style: solid;
|
| 636 |
border-width: 17px 17px 0 0;
|
| 637 |
border-color: var(--bubble-border-color, #333) transparent transparent transparent;
|
| 638 |
+
top: var(--tail-pos);
|
| 639 |
left: -19px;
|
| 640 |
transform: translateY(-50%) rotate(-90deg);
|
| 641 |
z-index: 0;
|
| 642 |
}
|
|
|
|
| 643 |
|
| 644 |
.speech-bubble.thought { background: white; border: 2px dashed #555; color: #333; border-radius: 50%; }
|
| 645 |
.speech-bubble.reaction { background: #FFD700; border: 3px solid #E53935; color: #D32F2F; font-weight: 900; text-transform: uppercase; width: 180px; clip-path: polygon(0% 25%, 17% 21%, 17% 0%, 31% 16%, 50% 4%, 69% 16%, 83% 0%, 83% 21%, 100% 25%, 85% 45%, 95% 62%, 82% 79%, 100% 97%, 79% 89%, 60% 98%, 46% 82%, 27% 95%, 15% 78%, 5% 62%, 15% 45%); }
|
|
|
|
| 676 |
.color-picker-grid div { text-align: center; }
|
| 677 |
.color-picker-grid label { font-size: 11px; }
|
| 678 |
.color-picker-grid input[type="color"] { height: 25px; padding: 2px; }
|
| 679 |
+
|
| 680 |
+
.slider-container { display: flex; align-items: center; gap: 5px; margin-top: 5px;}
|
| 681 |
+
.slider-container label { font-size: 11px; min-width: 50px;}
|
| 682 |
</style>
|
| 683 |
</head>
|
| 684 |
<body>
|
|
|
|
| 714 |
<button onclick="deleteBubble()" class="reset-button">🗑️ Delete Bubble</button>
|
| 715 |
</div>
|
| 716 |
<div class="control-group" id="tail-controls" style="display: none;">
|
| 717 |
+
<label>Tail Adjustment</label>
|
| 718 |
+
<button onclick="rotateBubbleTail()" class="secondary-button">🔄 Rotate Side</button>
|
| 719 |
+
<div class="slider-container">
|
| 720 |
+
<label>Pos:</label>
|
| 721 |
+
<input type="range" id="tail-slider" min="10" max="90" value="50" oninput="slideTail(this.value)">
|
| 722 |
+
</div>
|
| 723 |
</div>
|
| 724 |
<div class="control-group">
|
| 725 |
<label>Panel Tools (Select Panel):</label>
|
|
|
|
| 909 |
alert("Tail rotation is only available for Speech and Thought bubbles.");
|
| 910 |
}
|
| 911 |
}
|
| 912 |
+
|
| 913 |
+
function slideTail(value) {
|
| 914 |
+
if(!currentlySelectedBubble) return;
|
| 915 |
+
currentlySelectedBubble.style.setProperty('--tail-pos', value + '%');
|
| 916 |
+
}
|
| 917 |
|
| 918 |
function selectPanel(panel) {
|
| 919 |
document.querySelectorAll('.panel.selected').forEach(p => p.classList.remove('selected'));
|
|
|
|
| 927 |
currentlySelectedBubble = bubble;
|
| 928 |
const bubbleControls = ['bubble-text-color', 'bubble-fill-color', 'bubble-type-select', 'font-select'];
|
| 929 |
const tailControls = document.getElementById('tail-controls');
|
| 930 |
+
const tailSlider = document.getElementById('tail-slider');
|
| 931 |
|
| 932 |
if (currentlySelectedBubble) {
|
| 933 |
currentlySelectedBubble.classList.add('selected');
|
|
|
|
| 947 |
document.getElementById('bubble-type-select').value = currentlySelectedBubble.dataset.type || 'speech';
|
| 948 |
document.getElementById('font-select').value = styles.fontFamily.split(',')[0].replace(/"/g, "").replace(/'/g, "").trim();
|
| 949 |
|
| 950 |
+
// Read current tail pos
|
| 951 |
+
const currentTailPos = styles.getPropertyValue('--tail-pos').trim();
|
| 952 |
+
if(currentTailPos.includes('%')) {
|
| 953 |
+
tailSlider.value = parseInt(currentTailPos);
|
| 954 |
+
} else {
|
| 955 |
+
tailSlider.value = 50;
|
| 956 |
+
}
|
| 957 |
+
|
| 958 |
document.getElementById('zoom-slider').disabled = true;
|
| 959 |
bubbleControls.forEach(id => document.getElementById(id).disabled = false);
|
| 960 |
|