jhh6576 commited on
Commit
6a1d185
·
verified ·
1 Parent(s): 3ab7038

Update app_enhanced.py

Browse files
Files changed (1) hide show
  1. app_enhanced.py +50 -50
app_enhanced.py CHANGED
@@ -562,22 +562,17 @@ 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
- /* <<< THIN "SHARK FIN" TAIL (EXPORT SAFE) >>> */
566
- /*
567
- We replicate the visual result of the Mask CSS using a "Crescent Shadow" trick.
568
- This creates the thin, curved thorn shape using box-shadow on a rounded element,
569
- which IS supported by html2canvas (unlike masks).
570
- */
571
  .speech-bubble.speech {
572
  --bubble-fill-color: #4ECDC4;
573
  --bubble-text-color: #ffffff;
574
- --bubble-border-color: #333333; /* Only used if borders enabled */
575
  --tail-pos: 50%;
576
 
577
- /* The original variables from your CSS */
578
- --b: 3em; /* base */
579
- --h: 1.8em; /* height */
580
- --t: .6; /* thickness */
581
  --r: 1.2em; /* radius */
582
 
583
  background: var(--bubble-fill-color);
@@ -585,72 +580,77 @@ class EnhancedComicGenerator:
585
  padding: 1em;
586
  position: absolute;
587
 
588
- /* The exact border-radius logic from your CSS */
589
  border-radius: var(--r) var(--r)
590
  min(var(--r), calc(100% - var(--tail-pos) - (1 - var(--t)) * var(--b) / 2))
591
  min(var(--r), calc(var(--tail-pos) - (1 - var(--t)) * var(--b) / 2))
592
  / var(--r);
593
  }
594
 
 
 
 
 
 
 
595
  .speech-bubble.speech:before {
596
  content: "";
597
  position: absolute;
598
  pointer-events: none;
599
-
600
- /*
601
- CRESCENT TRICK:
602
- 1. Create a transparent box.
603
- 2. Round one corner significantly.
604
- 3. Use box-shadow to "paint" the shape outside the transparent box.
605
- This creates a sharp, thin, concave curve exactly like the mask.
606
- */
607
- width: 1.5em; /* Controls fin thinness width */
608
- height: 1.8em; /* Controls fin height */
609
- background: transparent;
610
  z-index: 1;
 
 
611
  }
612
 
613
  /* BOTTOM TAIL */
614
  .speech-bubble.speech.tail-bottom:before {
615
- top: 90%; /* Slight overlap to seal gap */
616
- /* Exact positioning logic */
617
  left: clamp(0%, calc(var(--tail-pos) - (1 - var(--t)) * var(--b) / 2), calc(100% - (1 - var(--t)) * var(--b)));
618
 
619
- /* The Crescent Shape Construction */
620
- border-radius: 0 0 100% 0; /* Bottom-right curve */
621
- /* Using thinner shadow values (-6px vs -10px) makes the tail thinner */
622
- box-shadow: inset -6px -6px 0px -2px var(--bubble-fill-color);
623
- transform: rotate(-10deg);
624
- transform-origin: top left;
625
  }
626
 
627
- /* TOP TAIL (Reflected) */
 
 
 
 
 
 
628
  .speech-bubble.speech.tail-top:before {
629
- bottom: 90%;
630
  left: clamp(0%, calc(var(--tail-pos) - (1 - var(--t)) * var(--b) / 2), calc(100% - (1 - var(--t)) * var(--b)));
631
- border-radius: 0 100% 0 0;
632
- box-shadow: inset -6px 6px 0px -2px var(--bubble-fill-color);
633
- transform: rotate(10deg);
634
- transform-origin: bottom left;
635
  }
636
 
637
- /* LEFT TAIL */
 
 
 
638
  .speech-bubble.speech.tail-left:before {
639
- right: 90%;
640
  top: clamp(0%, calc(var(--tail-pos) - (1 - var(--t)) * var(--b) / 2), calc(100% - (1 - var(--t)) * var(--b)));
641
- border-radius: 0 0 0 100%;
642
- box-shadow: inset 6px -6px 0px -2px var(--bubble-fill-color);
643
- transform: rotate(10deg);
644
  transform-origin: top right;
645
  }
646
 
647
- /* RIGHT TAIL */
 
 
 
648
  .speech-bubble.speech.tail-right:before {
649
- left: 90%;
650
  top: clamp(0%, calc(var(--tail-pos) - (1 - var(--t)) * var(--b) / 2), calc(100% - (1 - var(--t)) * var(--b)));
651
- border-radius: 0 0 100% 0;
652
- box-shadow: inset -6px -6px 0px -2px var(--bubble-fill-color);
653
- transform: rotate(-10deg);
654
  transform-origin: top left;
655
  }
656
 
@@ -1083,7 +1083,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 (Prevents size reset bug)
1087
  const bubbles = document.querySelectorAll('.speech-bubble');
1088
  bubbles.forEach(b => {
1089
  const rect = b.getBoundingClientRect();
@@ -1106,7 +1106,7 @@ class EnhancedComicGenerator:
1106
  } catch (err) { alert(`Failed to export page ${i + 1}.`); }
1107
  }
1108
 
1109
- // 2. UNFREEZE DIMENSIONS (Restore normal behavior)
1110
  bubbles.forEach(b => {
1111
  b.style.minWidth = '50px';
1112
  b.style.minHeight = '30px';
@@ -1271,7 +1271,7 @@ class EnhancedComicGenerator:
1271
  </script>
1272
  </body>
1273
  </html>'''
1274
- # Fixed indentation for the write operation
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
+ /* <<< 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);
 
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
 
 
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
  } 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
  </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!")