MagicalGirlCardACG.tsx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. import React, { useRef } from 'react';
  2. import { snapdom } from '@zumer/snapdom';
  3. interface MagicalGirlCardACGProps {
  4. magicalGirl: {
  5. codename: string;
  6. appearance: {
  7. outfit: string;
  8. accessories: string;
  9. colorScheme: string;
  10. overallLook: string;
  11. };
  12. magicWeapon: {
  13. name: string;
  14. form: string;
  15. basicAbilities: string[];
  16. description: string;
  17. };
  18. specialMove: {
  19. name: string;
  20. chant: string;
  21. description: string;
  22. };
  23. awakening: {
  24. name: string;
  25. evolvedAbilities: string[];
  26. evolvedForm: string;
  27. evolvedOutfit: string;
  28. };
  29. analysis: {
  30. personalityAnalysis: string;
  31. abilityReasoning: string;
  32. coreTraits: string[];
  33. predictionBasis: string;
  34. };
  35. };
  36. gradientStyle: string;
  37. onSaveImage?: (imageUrl: string) => void;
  38. }
  39. const MagicalGirlCardACG: React.FC<MagicalGirlCardACGProps> = ({
  40. magicalGirl,
  41. gradientStyle,
  42. onSaveImage
  43. }) => {
  44. const resultRef = useRef<HTMLDivElement>(null);
  45. const handleSaveImage = async () => {
  46. if (!resultRef.current) return;
  47. try {
  48. const saveButton = resultRef.current.querySelector('.save-button') as HTMLElement;
  49. const logoPlaceholder = resultRef.current.querySelector('.logo-placeholder') as HTMLElement;
  50. if (saveButton) saveButton.style.display = 'none';
  51. if (logoPlaceholder) logoPlaceholder.style.display = 'flex';
  52. const result = await snapdom(resultRef.current, {
  53. scale: 1,
  54. });
  55. if (saveButton) saveButton.style.display = 'block';
  56. if (logoPlaceholder) logoPlaceholder.style.display = 'none';
  57. const imgElement = await result.toPng();
  58. const imageUrl = imgElement.src;
  59. if (onSaveImage) {
  60. onSaveImage(imageUrl);
  61. }
  62. } catch {
  63. alert('生成图片失败,请重试');
  64. const saveButton = resultRef.current?.querySelector('.save-button') as HTMLElement;
  65. const logoPlaceholder = resultRef.current?.querySelector('.logo-placeholder') as HTMLElement;
  66. if (saveButton) saveButton.style.display = 'block';
  67. if (logoPlaceholder) logoPlaceholder.style.display = 'none';
  68. }
  69. };
  70. return (
  71. <div
  72. ref={resultRef}
  73. className="result-card"
  74. style={{ background: gradientStyle }}
  75. >
  76. <div className="result-content">
  77. <div className="flex justify-center items-center" style={{ marginBottom: '1rem', background: 'transparent' }}>
  78. <img src="/questionnaire-title.svg" width={300} height={70} alt="Logo" style={{ display: 'block', background: 'transparent' }} />
  79. </div>
  80. {/* 基本信息 */}
  81. <div className="result-item">
  82. <div className="result-label">💖 魔法少女代号</div>
  83. <div className="result-value">{magicalGirl.codename}</div>
  84. </div>
  85. {/* 外观描述 */}
  86. <div className="result-item">
  87. <div className="result-label">🎀 魔法少女外观</div>
  88. <div className="result-value">
  89. <div><strong>战斗服:</strong>{magicalGirl.appearance.outfit}</div>
  90. <div><strong>饰品:</strong>{magicalGirl.appearance.accessories}</div>
  91. <div><strong>主色调:</strong>{magicalGirl.appearance.colorScheme}</div>
  92. <div><strong>整体气质:</strong>{magicalGirl.appearance.overallLook}</div>
  93. </div>
  94. </div>
  95. {/* 魔法武器 */}
  96. <div className="result-item">
  97. <div className="result-label">🌟 魔法武器</div>
  98. <div className="result-value">
  99. <div><strong>名称:</strong>{magicalGirl.magicWeapon.name}</div>
  100. <div><strong>形态:</strong>{magicalGirl.magicWeapon.form}</div>
  101. <div><strong>核心能力:</strong></div>
  102. <ul style={{ marginLeft: '1rem', marginTop: '0.5rem' }}>
  103. {magicalGirl.magicWeapon.basicAbilities.map((ability: string, index: number) => (
  104. <li key={index}>✨ {ability}</li>
  105. ))}
  106. </ul>
  107. <div style={{ marginTop: '0.5rem' }}><strong>背景:</strong>{magicalGirl.magicWeapon.description}</div>
  108. </div>
  109. </div>
  110. {/* 必杀技 */}
  111. <div className="result-item">
  112. <div className="result-label">🌠 必杀技</div>
  113. <div className="result-value">
  114. <div><strong>名称:</strong>{magicalGirl.specialMove.name}</div>
  115. <div style={{ marginTop: '0.5rem' }}><strong>咏唱:</strong><span style={{ fontStyle: 'italic' }}>「{magicalGirl.specialMove.chant}」</span></div>
  116. <div style={{ marginTop: '0.5rem' }}><strong>效果:</strong>{magicalGirl.specialMove.description}</div>
  117. </div>
  118. </div>
  119. {/* 觉醒形态 */}
  120. <div className="result-item">
  121. <div className="result-label">🌌 觉醒形态</div>
  122. <div className="result-value">
  123. <div><strong>形态名称:</strong>{magicalGirl.awakening.name}</div>
  124. <div><strong>进化能力:</strong></div>
  125. <ul style={{ marginLeft: '1rem', marginTop: '0.5rem' }}>
  126. {magicalGirl.awakening.evolvedAbilities.map((ability: string, index: number) => (
  127. <li key={index}>🌠 {ability}</li>
  128. ))}
  129. </ul>
  130. <div><strong>武器进化:</strong>{magicalGirl.awakening.evolvedForm}</div>
  131. <div><strong>服装进化:</strong>{magicalGirl.awakening.evolvedOutfit}</div>
  132. </div>
  133. </div>
  134. {/* 综合分析 */}
  135. <div className="result-item">
  136. <div className="result-label">🧠 综合分析</div>
  137. <div className="result-value">
  138. <div><strong>性格分析:</strong>{magicalGirl.analysis.personalityAnalysis}</div>
  139. <div><strong>能力设定思路:</strong>{magicalGirl.analysis.abilityReasoning}</div>
  140. <div><strong>核心萌属性:</strong>{magicalGirl.analysis.coreTraits.join('、')}</div>
  141. <div><strong>创作依据:</strong>{magicalGirl.analysis.predictionBasis}</div>
  142. </div>
  143. </div>
  144. <button onClick={handleSaveImage} className="save-button">
  145. 📱 保存为图片
  146. </button>
  147. <div className="logo-placeholder" style={{ display: 'none', justifyContent: 'center', marginTop: '1rem' }}>
  148. <img
  149. src="/logo-white-qrcode.svg"
  150. width={320}
  151. height={80}
  152. alt="Logo"
  153. style={{
  154. display: 'block',
  155. maxWidth: '100%',
  156. height: 'auto'
  157. }}
  158. />
  159. </div>
  160. </div>
  161. </div>
  162. );
  163. };
  164. export default MagicalGirlCardACG;