jhh6576 commited on
Commit
347e87f
·
verified ·
1 Parent(s): 6a1d185

Update app_enhanced.py

Browse files
Files changed (1) hide show
  1. app_enhanced.py +55 -74
app_enhanced.py CHANGED
@@ -562,96 +562,78 @@ class EnhancedComicGenerator:
562
  .speech-bubble.selected { outline: 2px dashed #4CAF50; }
563
  .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; }
564
 
565
- /* <<< VARIANT #85: "SHARK FIN" SHAPE (EXPORT SAFE: BOX-SHADOW METHOD) >>> */
566
  .speech-bubble.speech {
567
- --bubble-fill-color: #4ECDC4;
568
- --bubble-text-color: #ffffff;
569
- --bubble-border-color: #333333;
570
- --tail-pos: 50%;
571
-
572
- /* Variables from your specific CSS */
573
- --b: 3em; /* tail base */
574
- --h: 1.8em; /* tail height */
575
- --t: 0.6; /* thickness */
576
  --r: 1.2em; /* radius */
 
 
 
 
577
 
578
- background: var(--bubble-fill-color);
579
- color: var(--bubble-text-color);
580
  padding: 1em;
581
- position: absolute;
 
582
 
583
- /* EXACT border-radius logic from your requested CSS */
584
- border-radius: var(--r) var(--r)
585
- min(var(--r), calc(100% - var(--tail-pos) - (1 - var(--t)) * var(--b) / 2))
586
- min(var(--r), calc(var(--tail-pos) - (1 - var(--t)) * var(--b) / 2))
587
- / var(--r);
 
 
 
 
 
 
588
  }
589
 
590
  /*
591
- EXPORT SAFE TRICK:
592
- Instead of 'mask' (which fails export), we use a transparent box
593
- with a curved border-radius and an INSET BOX-SHADOW.
594
- This paints the "meat" of the fin inside the curve, mimicking the mask.
595
  */
596
- .speech-bubble.speech:before {
597
- content: "";
598
- position: absolute;
599
- pointer-events: none;
600
- background: transparent;
601
- z-index: 1;
602
- /* Fin Dimensions */
603
- width: 3em; height: 1.8em;
604
- }
605
 
606
- /* BOTTOM TAIL */
607
- .speech-bubble.speech.tail-bottom:before {
608
- top: 95%; /* Slight overlap */
609
- /* Position Logic */
610
- left: clamp(0%, calc(var(--tail-pos) - (1 - var(--t)) * var(--b) / 2), calc(100% - (1 - var(--t)) * var(--b)));
611
-
612
- /* The Fin Shape via Shadow */
613
- border-bottom-left-radius: 100%;
614
- box-shadow: inset 1.5em -0.8em 0 0 var(--bubble-fill-color);
615
- }
616
 
617
- /* TOP TAIL (Flip) */
618
  .speech-bubble.speech.tail-top {
619
- /* Flip Main Radius Logic for top */
620
- border-radius: min(var(--r), calc(var(--tail-pos) - (1 - var(--t)) * var(--b) / 2))
621
- min(var(--r), calc(100% - var(--tail-pos) - (1 - var(--t)) * var(--b) / 2))
622
- var(--r) var(--r) / var(--r);
623
- }
624
- .speech-bubble.speech.tail-top:before {
625
- bottom: 95%;
626
- left: clamp(0%, calc(var(--tail-pos) - (1 - var(--t)) * var(--b) / 2), calc(100% - (1 - var(--t)) * var(--b)));
627
- border-top-left-radius: 100%;
628
- box-shadow: inset 1.5em 0.8em 0 0 var(--bubble-fill-color);
629
  }
630
 
631
- /* LEFT TAIL (Rotate) */
632
  .speech-bubble.speech.tail-left {
 
 
 
 
 
633
  border-radius: var(--r);
634
  }
635
- .speech-bubble.speech.tail-left:before {
636
- right: 95%;
637
- top: clamp(0%, calc(var(--tail-pos) - (1 - var(--t)) * var(--b) / 2), calc(100% - (1 - var(--t)) * var(--b)));
638
- border-top-left-radius: 100%;
639
- box-shadow: inset 0.8em 1.5em 0 0 var(--bubble-fill-color);
640
- transform: rotate(-90deg);
641
- transform-origin: top right;
642
- }
643
 
644
- /* RIGHT TAIL (Rotate) */
645
  .speech-bubble.speech.tail-right {
646
- border-radius: var(--r);
647
- }
648
- .speech-bubble.speech.tail-right:before {
649
- left: 95%;
650
- top: clamp(0%, calc(var(--tail-pos) - (1 - var(--t)) * var(--b) / 2), calc(100% - (1 - var(--t)) * var(--b)));
651
- border-top-right-radius: 100%;
652
- box-shadow: inset -0.8em 1.5em 0 0 var(--bubble-fill-color);
653
- transform: rotate(90deg);
654
- transform-origin: top left;
655
  }
656
 
657
  .speech-bubble.thought { background: white; border: 2px dashed #555; color: #333; border-radius: 50%; }
@@ -1083,7 +1065,7 @@ class EnhancedComicGenerator:
1083
  const pages = document.querySelectorAll('.comic-page');
1084
  if (pages.length === 0) return alert("No pages found.");
1085
 
1086
- // 1. FREEZE DIMENSIONS BEFORE EXPORT
1087
  const bubbles = document.querySelectorAll('.speech-bubble');
1088
  bubbles.forEach(b => {
1089
  const rect = b.getBoundingClientRect();
@@ -1106,7 +1088,7 @@ class EnhancedComicGenerator:
1106
  } catch (err) { alert(`Failed to export page ${i + 1}.`); }
1107
  }
1108
 
1109
- // 2. UNFREEZE DIMENSIONS
1110
  bubbles.forEach(b => {
1111
  b.style.minWidth = '50px';
1112
  b.style.minHeight = '30px';
@@ -1271,7 +1253,6 @@ class EnhancedComicGenerator:
1271
  </script>
1272
  </body>
1273
  </html>'''
1274
- # Corrected Indentation here
1275
  with open(os.path.join(self.output_dir, 'page.html'), 'w', encoding='utf-8') as f:
1276
  f.write(template_html)
1277
  print("📄 Template files copied successfully!")
 
562
  .speech-bubble.selected { outline: 2px dashed #4CAF50; }
563
  .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; }
564
 
565
+ /* <<< NEW CSS FROM USER: Clip-Path and Border-Image Tail >>> */
566
  .speech-bubble.speech {
567
+ /* tail dimension */
568
+ --b: 2em; /* base */
569
+ --h: 1.5em; /* height */
570
+
571
+ /* slider position mapped to --p */
572
+ --p: var(--tail-pos, 50%);
573
+ --x: 1.8em; /* tail skew offset */
 
 
574
  --r: 1.2em; /* radius */
575
+
576
+ /* Colors */
577
+ --c: var(--bubble-fill-color, #4ECDC4);
578
+ color: var(--bubble-text-color, #fff);
579
 
 
 
580
  padding: 1em;
581
+ background: var(--c);
582
+ position: absolute; /* Ensure it floats */
583
 
584
+ /* The user's exact border-radius logic */
585
+ border-radius: var(--r) var(--r) min(var(--r),100% - var(--p) - var(--b)/2) min(var(--r),var(--p) - var(--b)/2)/var(--r);
586
+
587
+ /* The user's exact clip-path logic */
588
+ clip-path: polygon(0 100%,0 0,100% 0,100% 100%,
589
+ clamp(var(--b),var(--p) + var(--b)/2,100%) 100%,
590
+ calc(var(--p) + var(--x)) calc(100% + var(--h)),
591
+ clamp(0%,var(--p) - var(--b)/2,100% - var(--b)) 100%);
592
+
593
+ /* The user's exact border-image logic */
594
+ border-image: conic-gradient(var(--c) 0 0) 0 0 1 0/0 0 var(--h) 0/0 999px var(--h) 999px;
595
  }
596
 
597
  /*
598
+ ROTATION LOGIC FOR OTHER SIDES
599
+ Since the user's CSS is hardcoded for "Bottom Tail",
600
+ we adapt it for Top/Left/Right by calculating the correct polygon/border-image values
601
+ derived from the same logic.
602
  */
 
 
 
 
 
 
 
 
 
603
 
604
+ /* BOTTOM (Default) - No changes needed */
605
+ .speech-bubble.speech.tail-bottom { }
 
 
 
 
 
 
 
 
606
 
607
+ /* TOP TAIL */
608
  .speech-bubble.speech.tail-top {
609
+ border-image: conic-gradient(var(--c) 0 0) 1 0 0 0 / var(--h) 0 0 0 / var(--h) 999px 0 999px;
610
+ /* Invert Y axis logic for polygon */
611
+ clip-path: polygon(0 0, 0 100%, 100% 100%, 100% 0,
612
+ clamp(var(--b), var(--p) + var(--b)/2, 100%) 0,
613
+ calc(var(--p) + var(--x)) calc(0% - var(--h)),
614
+ clamp(0%, var(--p) - var(--b)/2, 100% - var(--b)) 0);
615
+ /* Adjust border radius for top tail */
616
+ border-radius: min(var(--r),var(--p) - var(--b)/2) min(var(--r),100% - var(--p) - var(--b)/2) var(--r) var(--r)/var(--r);
 
 
617
  }
618
 
619
+ /* LEFT TAIL */
620
  .speech-bubble.speech.tail-left {
621
+ border-image: conic-gradient(var(--c) 0 0) 0 0 0 1 / 0 0 0 var(--h) / 0 999px 999px var(--h);
622
+ clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%,
623
+ 0 clamp(var(--b), var(--p) + var(--b)/2, 100%),
624
+ calc(0% - var(--h)) calc(var(--p) + var(--x)),
625
+ 0 clamp(0%, var(--p) - var(--b)/2, 100% - var(--b)));
626
  border-radius: var(--r);
627
  }
 
 
 
 
 
 
 
 
628
 
629
+ /* RIGHT TAIL */
630
  .speech-bubble.speech.tail-right {
631
+ border-image: conic-gradient(var(--c) 0 0) 0 1 0 0 / 0 var(--h) 0 0 / 0 var(--h) 999px 999px;
632
+ clip-path: polygon(100% 0, 0 0, 0 100%, 100% 100%,
633
+ 100% clamp(var(--b), var(--p) + var(--b)/2, 100%),
634
+ calc(100% + var(--h)) calc(var(--p) + var(--x)),
635
+ 100% clamp(0%, var(--p) - var(--b)/2, 100% - var(--b)));
636
+ border-radius: var(--r);
 
 
 
637
  }
638
 
639
  .speech-bubble.thought { background: white; border: 2px dashed #555; color: #333; border-radius: 50%; }
 
1065
  const pages = document.querySelectorAll('.comic-page');
1066
  if (pages.length === 0) return alert("No pages found.");
1067
 
1068
+ // 1. FREEZE DIMENSIONS BEFORE EXPORT (Prevents size reset bug)
1069
  const bubbles = document.querySelectorAll('.speech-bubble');
1070
  bubbles.forEach(b => {
1071
  const rect = b.getBoundingClientRect();
 
1088
  } catch (err) { alert(`Failed to export page ${i + 1}.`); }
1089
  }
1090
 
1091
+ // 2. UNFREEZE DIMENSIONS (Restore normal behavior)
1092
  bubbles.forEach(b => {
1093
  b.style.minWidth = '50px';
1094
  b.style.minHeight = '30px';
 
1253
  </script>
1254
  </body>
1255
  </html>'''
 
1256
  with open(os.path.join(self.output_dir, 'page.html'), 'w', encoding='utf-8') as f:
1257
  f.write(template_html)
1258
  print("📄 Template files copied successfully!")