优化模板选择的交互逻辑, 支持直接预览选择

This commit is contained in:
puke
2025-12-08 15:39:46 +08:00
parent f111ffc427
commit fb98254549
59 changed files with 234 additions and 112 deletions

View File

@@ -22,7 +22,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![blur_card](../../images/1080x1920/blur_card_en.jpg)
![blur_card](../../images/1080x1920/image_blur_card_en.jpg)
Blurred background card style, suitable for graphic content display
@@ -30,7 +30,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![cartoon](../../images/1080x1920/cartoon_en.jpg)
![cartoon](../../images/1080x1920/image_cartoon_en.jpg)
Cartoon style, suitable for light and lively content
@@ -38,7 +38,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![default](../../images/1080x1920/default_en.jpg)
![default](../../images/1080x1920/image_default_en.jpg)
Default template, simple and versatile
@@ -46,7 +46,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![elegant](../../images/1080x1920/elegant_en.jpg)
![elegant](../../images/1080x1920/image_elegant_en.jpg)
Elegant style, suitable for artistic and intellectual content
@@ -54,7 +54,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![fashion_vintage](../../images/1080x1920/fashion_vintage_en.jpg)
![fashion_vintage](../../images/1080x1920/image_fashion_vintage_en.jpg)
Retro fashion style, suitable for nostalgic themes
@@ -62,7 +62,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![life_insights](../../images/1080x1920/life_insights_en.jpg)
![life_insights](../../images/1080x1920/image_life_insights_en.jpg)
Life insight style, suitable for inspirational content
@@ -70,7 +70,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![modern](../../images/1080x1920/modern_en.jpg)
![modern](../../images/1080x1920/image_modern_en.jpg)
Modern minimalist style, suitable for business and tech content
@@ -78,7 +78,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![neon](../../images/1080x1920/neon_en.jpg)
![neon](../../images/1080x1920/image_neon_en.jpg)
Neon style, suitable for fashion and trendy content
@@ -86,7 +86,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![psychology_card](../../images/1080x1920/psychology_card_en.jpg)
![psychology_card](../../images/1080x1920/image_psychology_card_en.jpg)
Psychology card style, suitable for knowledge popularization
@@ -94,7 +94,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![purple](../../images/1080x1920/purple_en.jpg)
![purple](../../images/1080x1920/image_purple_en.jpg)
Purple theme, suitable for dreamy and mysterious styles
@@ -102,7 +102,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![simple](../../images/1080x1920/simple_en.jpg)
![simple](../../images/1080x1920/image_simple_en.jpg)
Minimalist style, highlighting the content itself
@@ -110,7 +110,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![satirical_cartoon](../../images/1080x1920/satirical_cartoon_en.jpg)
![satirical_cartoon](../../images/1080x1920/image_satirical_cartoon_en.jpg)
80s satirical cartoon style for spiritual tales
@@ -118,7 +118,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![simple_black](../../images/1080x1920/simple_black_en.jpg)
![simple_black](../../images/1080x1920/image_simple_black_en.jpg)
Simple black background, suitable for inspirational content
@@ -126,7 +126,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![simple_line_drawing](../../images/1080x1920/simple_line_drawing_en.jpg)
![simple_line_drawing](../../images/1080x1920/image_simple_line_drawing_en.jpg)
Simple line drawing style for cognitive growth content
@@ -134,7 +134,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![book](../../images/1080x1920/book_en.jpg)
![book](../../images/1080x1920/image_book_en.jpg)
Book style, suitable for book lists
@@ -142,7 +142,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![long_text](../../images/1080x1920/long_text_en.jpg)
![long_text](../../images/1080x1920/image_long_text_en.jpg)
Long text style, suitable for inspirational content
@@ -150,7 +150,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![excerpt](../../images/1080x1920/excerpt_en.jpg)
![excerpt](../../images/1080x1920/image_excerpt_en.jpg)
Excerpt style, suitable for quotes and book excerpts
@@ -158,7 +158,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![health_preservation](../../images/1080x1920/health_preservation_en.jpg)
![health_preservation](../../images/1080x1920/image_health_preservation_en.jpg)
Health preserving tips, suitable for wellness explainers.
@@ -166,7 +166,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![life_insights_light](../../images/1080x1920/life_insights_light_en.jpg)
![life_insights_light](../../images/1080x1920/image_life_insights_light_en.jpg)
Life insights, conveying warmth and strength
@@ -174,7 +174,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![full](../../images/1080x1920/full_en.jpg)
![full](../../images/1080x1920/image_full_en.jpg)
Full screen display, suitable for book lists
@@ -182,7 +182,7 @@ Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
---
![healing](../../images/1080x1920/healing_en.jpg)
![healing](../../images/1080x1920/image_healing_en.jpg)
Healing style, suitable for therapeutic content
</div>
@@ -199,7 +199,7 @@ Suitable for YouTube, Bilibili, and other video platforms.
---
![ultrawide_minimal](../../images/1920x1080/ultrawide_minimal_en.jpg)
![ultrawide_minimal](../../images/1920x1080/image_ultrawide_minimal_en.jpg)
Ultrawide minimalist style, suitable for desktop viewing
@@ -207,7 +207,7 @@ Suitable for YouTube, Bilibili, and other video platforms.
---
![wide_darktech](../../images/1920x1080/wide_darktech_en.jpg)
![wide_darktech](../../images/1920x1080/image_wide_darktech_en.jpg)
Dark tech style, suitable for technology and gaming content
@@ -215,7 +215,7 @@ Suitable for YouTube, Bilibili, and other video platforms.
---
![film](../../images/1920x1080/film_en.jpg)
![film](../../images/1920x1080/image_film_en.jpg)
Film style, immersive experience
@@ -223,7 +223,7 @@ Suitable for YouTube, Bilibili, and other video platforms.
---
![full](../../images/1920x1080/full_en.jpg)
![full](../../images/1920x1080/image_full_en.jpg)
Full screen display, suitable for book lists
@@ -231,7 +231,7 @@ Suitable for YouTube, Bilibili, and other video platforms.
---
![book](../../images/1920x1080/book_en.jpg)
![book](../../images/1920x1080/image_book_en.jpg)
Book style, suitable for book lists
@@ -249,7 +249,7 @@ Suitable for Instagram, WeChat Moments, and other platforms.
---
![minimal_framed](../../images/1080x1080/minimal_framed_en.jpg)
![minimal_framed](../../images/1080x1080/image_minimal_framed_en.jpg)
Minimalist framed style, suitable for social media sharing

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 201 KiB

After

Width:  |  Height:  |  Size: 201 KiB

View File

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 94 KiB

View File

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

View File

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

Before

Width:  |  Height:  |  Size: 390 KiB

After

Width:  |  Height:  |  Size: 390 KiB

View File

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 144 KiB

View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

View File

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 91 KiB

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View File

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

View File

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

View File

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

View File

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

View File

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 107 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

View File

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

View File

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 91 KiB

View File

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 105 KiB

View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

View File

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 125 KiB

View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

Before

Width:  |  Height:  |  Size: 202 KiB

After

Width:  |  Height:  |  Size: 202 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

Before

Width:  |  Height:  |  Size: 201 KiB

After

Width:  |  Height:  |  Size: 201 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

View File

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 104 KiB

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

View File

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

View File

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

View File

@@ -22,7 +22,7 @@
---
![blur_card](../../images/1080x1920/blur_card.png)
![blur_card](../../images/1080x1920/image_blur_card.png)
模糊背景卡片风格,适合图文内容展示
@@ -30,7 +30,7 @@
---
![cartoon](../../images/1080x1920/cartoon.png)
![cartoon](../../images/1080x1920/image_cartoon.png)
卡通风格,适合轻松活泼的内容
@@ -38,7 +38,7 @@
---
![default](../../images/1080x1920/default.jpg)
![default](../../images/1080x1920/image_default.jpg)
默认模板,简洁通用
@@ -46,7 +46,7 @@
---
![elegant](../../images/1080x1920/elegant.jpg)
![elegant](../../images/1080x1920/image_elegant.jpg)
优雅风格,适合文艺、知性内容
@@ -54,7 +54,7 @@
---
![fashion_vintage](../../images/1080x1920/fashion_vintage.jpg)
![fashion_vintage](../../images/1080x1920/image_fashion_vintage.jpg)
复古时尚风格,适合怀旧主题
@@ -62,7 +62,7 @@
---
![life_insights](../../images/1080x1920/life_insights.jpg)
![life_insights](../../images/1080x1920/image_life_insights.jpg)
生活感悟风格,适合心灵鸡汤类内容
@@ -70,7 +70,7 @@
---
![modern](../../images/1080x1920/modern.jpg)
![modern](../../images/1080x1920/image_modern.jpg)
现代简约风格,适合商务、科技内容
@@ -78,7 +78,7 @@
---
![neon](../../images/1080x1920/neon.jpg)
![neon](../../images/1080x1920/image_neon.jpg)
霓虹灯风格,适合时尚、潮流内容
@@ -86,7 +86,7 @@
---
![psychology_card](../../images/1080x1920/psychology_card.jpg)
![psychology_card](../../images/1080x1920/image_psychology_card.jpg)
心理学卡片风格,适合知识科普
@@ -94,7 +94,7 @@
---
![purple](../../images/1080x1920/purple.jpg)
![purple](../../images/1080x1920/image_purple.jpg)
紫色主题,适合梦幻、神秘风格
@@ -102,7 +102,7 @@
---
![simple](../../images/1080x1920/simple.jpg)
![simple](../../images/1080x1920/image_simple.jpg)
极简风格,突出内容本身
@@ -110,7 +110,7 @@
---
![satirical_cartoon](../../images/1080x1920/satirical_cartoon.jpg)
![satirical_cartoon](../../images/1080x1920/image_satirical_cartoon.jpg)
80年代讽刺漫画风格适合精神类小故事
@@ -118,7 +118,7 @@
---
![simple_black](../../images/1080x1920/simple_black.jpg)
![simple_black](../../images/1080x1920/image_simple_black.jpg)
极简黑色背景,适合心灵鸡汤类内容
@@ -126,7 +126,7 @@
---
![simple_line_drawing](../../images/1080x1920/simple_line_drawing.jpg)
![simple_line_drawing](../../images/1080x1920/image_simple_line_drawing.jpg)
简笔画,适合认知成长类内容
@@ -134,7 +134,7 @@
---
![book](../../images/1080x1920/book.jpg)
![book](../../images/1080x1920/image_book.jpg)
图书解读,适合科普类内容
@@ -142,7 +142,7 @@
---
![long_text](../../images/1080x1920/long_text.jpg)
![long_text](../../images/1080x1920/image_long_text.jpg)
长文本,适合励志鸡汤类内容
@@ -150,7 +150,7 @@
---
![excerpt](../../images/1080x1920/excerpt.jpg)
![excerpt](../../images/1080x1920/image_excerpt.jpg)
图文摘抄,适合图文摘抄,名人名言
@@ -158,7 +158,7 @@
---
![health_preservation](../../images/1080x1920/health_preservation.jpg)
![health_preservation](../../images/1080x1920/image_health_preservation.jpg)
养生窍门,适合养生科普内容
@@ -166,7 +166,7 @@
---
![life_insights_light](../../images/1080x1920/life_insights_light.jpg)
![life_insights_light](../../images/1080x1920/image_life_insights_light.jpg)
人生感悟,传递温暖与力量
@@ -174,7 +174,7 @@
---
![full](../../images/1080x1920/full.jpg)
![full](../../images/1080x1920/image_full.jpg)
全屏模版,适合书单号
@@ -182,7 +182,7 @@
---
![healing](../../images/1080x1920/healing.jpg)
![healing](../../images/1080x1920/image_healing.jpg)
治愈模版,适合疗愈类内容
</div>
@@ -199,7 +199,7 @@
---
![ultrawide_minimal](../../images/1920x1080/ultrawide_minimal.jpg)
![ultrawide_minimal](../../images/1920x1080/image_ultrawide_minimal.jpg)
超宽屏极简风格,适合桌面端观看
@@ -207,7 +207,7 @@
---
![wide_darktech](../../images/1920x1080/wide_darktech.jpg)
![wide_darktech](../../images/1920x1080/image_wide_darktech.jpg)
暗黑科技风格,适合技术、游戏内容
@@ -215,7 +215,7 @@
---
![film](../../images/1920x1080/film.jpg)
![film](../../images/1920x1080/image_film.jpg)
电影风格,沉浸式体验
@@ -223,7 +223,7 @@
---
![full](../../images/1920x1080/full.jpg)
![full](../../images/1920x1080/image_full.jpg)
全屏显示,适合书单号
@@ -231,7 +231,7 @@
---
![book](../../images/1920x1080/book.jpg)
![book](../../images/1920x1080/image_book.jpg)
图书解读,适合科普类内容
</div>
@@ -248,7 +248,7 @@
---
![minimal_framed](../../images/1080x1080/minimal_framed.jpg)
![minimal_framed](../../images/1080x1080/image_minimal_framed.jpg)
极简边框风格,适合社交媒体分享

View File

@@ -228,6 +228,46 @@ def render_style_config(pixelle_video):
# ====================================================================
# Storyboard Template Section
# ====================================================================
def get_template_preview_path(template_path: str, language: str = "zh_CN") -> str:
"""
Get the preview image path for a template based on language.
Args:
template_path: Template path like "1080x1920/image_default.html"
language: Language code, either "zh_CN" or "en"
Returns:
Path to preview image in docs/images/
"""
# Extract size and template name from path
# e.g., "1080x1920/image_default.html" -> size="1080x1920", name="image_default"
path_parts = template_path.split('/')
if len(path_parts) >= 2:
size = path_parts[0] # e.g., "1080x1920"
template_file = path_parts[1] # e.g., "image_default.html"
template_name = template_file.replace('.html', '') # e.g., "image_default"
# Build preview image path
# Format: docs/images/{size}/{template_name}.jpg or {template_name}_en.jpg
# Chinese uses Chinese preview, all other languages use English preview for better i18n
suffix = "" if language == "zh_CN" else "_en"
# Try different image extensions
for ext in ['.jpg', '.png']:
preview_path = f"docs/images/{size}/{template_name}{suffix}{ext}"
if os.path.exists(preview_path):
return preview_path
# Fallback: try without language suffix (for templates with only one version)
for ext in ['.jpg', '.png']:
preview_path = f"docs/images/{size}/{template_name}{ext}"
if os.path.exists(preview_path):
return preview_path
# If no preview found, return empty string
return ""
with st.container(border=True):
st.markdown(f"**{tr('section.template')}**")
@@ -284,18 +324,13 @@ def render_style_config(pixelle_video):
st.warning(f"No {template_type_options[selected_template_type]} templates found. Please select a different type or add templates.")
st.stop()
# Build display options with group separators
# Build orientation i18n mapping
ORIENTATION_I18N = {
'portrait': tr('orientation.portrait'),
'landscape': tr('orientation.landscape'),
'square': tr('orientation.square')
}
display_options = []
template_paths_ordered = [] # Use ordered list instead of dict to avoid key conflicts
default_index = 0
current_index = 0
# Get default template from config
template_config = pixelle_video.config.get("template", {})
config_default_template = template_config.get("default_template", "1080x1920/image_default.html")
@@ -312,68 +347,145 @@ def render_style_config(pixelle_video):
}
type_specific_default = type_default_templates.get(selected_template_type, config_default_template)
# Initialize selected template in session state if not exists
if 'selected_template' not in st.session_state:
st.session_state['selected_template'] = type_specific_default
# Collect size groups and prepare tabs
size_groups = []
size_labels = []
for size, templates in grouped_templates.items():
if not templates:
continue
# Filter templates to only include those with proper naming convention
# Only show templates starting with static_, image_, or video_
valid_templates = []
for template in templates:
template_name = template.display_info.name
if template_name.startswith(('static_', 'image_', 'video_')):
valid_templates.append(template)
# Skip if no valid templates after filtering
if not valid_templates:
continue
# Separate templates into two groups: with preview and without preview
templates_with_preview = []
templates_without_preview = []
for template in valid_templates:
preview_path = get_template_preview_path(template.template_path, current_lang)
if preview_path and os.path.exists(preview_path):
templates_with_preview.append(template)
else:
templates_without_preview.append(template)
# Skip this group if no templates at all
if not templates_with_preview and not templates_without_preview:
continue
# Combine: templates with preview first, then without preview
all_templates = templates_with_preview + templates_without_preview
# Get orientation from first template in group
orientation = ORIENTATION_I18N.get(
templates[0].display_info.orientation,
templates[0].display_info.orientation
all_templates[0].display_info.orientation,
all_templates[0].display_info.orientation
)
width = templates[0].display_info.width
height = templates[0].display_info.height
width = all_templates[0].display_info.width
height = all_templates[0].display_info.height
# Add group separator
separator = f"─── {orientation} {width}×{height} ───"
display_options.append(separator)
template_paths_ordered.append(None) # Separator has no template path
current_index += 1
# Create tab label
tab_label = f"{orientation} {width}×{height}"
size_labels.append(tab_label)
size_groups.append(all_templates)
# Create tabs for each size group (wrapped in expander)
with st.expander(tr("template.gallery_view"), expanded=True):
if size_groups:
tabs = st.tabs(size_labels)
for tab, all_templates in zip(tabs, size_groups):
with tab:
# Create grid layout (5 columns)
num_cols = 5
cols = st.columns(num_cols)
for idx, template in enumerate(all_templates):
col_idx = idx % num_cols
with cols[col_idx]:
# Get preview image path
preview_path = get_template_preview_path(template.template_path, current_lang)
# Display preview image or placeholder
if preview_path and os.path.exists(preview_path):
st.image(preview_path, use_container_width=True)
else:
# Placeholder for templates without preview (fixed height, compact layout)
st.markdown(
f"""
<div style="
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
height: 150px;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
border-radius: 8px;
color: white;
margin-bottom: 15px;
padding: 10px;
">
<div style="
font-size: 14px;
opacity: 0.95;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 5;
-webkit-box-orient: vertical;
word-break: break-all;
">{template.display_info.name}</div>
</div>
""",
unsafe_allow_html=True
)
# Select button (unified label)
is_selected = (st.session_state['selected_template'] == template.template_path)
button_label = f"{tr('template.selected')}" if is_selected else tr('template.select_button')
button_type = "primary" if is_selected else "secondary"
if st.button(
button_label,
key=f"template_{template.template_path}",
use_container_width=True,
type=button_type,
):
st.session_state['selected_template'] = template.template_path
st.rerun()
else:
st.warning(tr("template.no_templates_with_preview"))
# Add templates in this group
for t in templates:
display_name = f" {t.display_info.name}"
display_options.append(display_name)
template_paths_ordered.append(t.template_path) # Add to ordered list
# Set default: priority is config > type-specific default > first in portrait
if t.template_path == config_default_template:
default_index = current_index
elif default_index == 0 and t.template_path == type_specific_default:
default_index = current_index
elif default_index == 0 and t.display_info.orientation == 'portrait':
default_index = current_index
current_index += 1
# Dropdown with grouped display
# Create unique display strings by appending hidden unique identifier
# This ensures Streamlit doesn't confuse templates with same name in different groups
unique_display_options = []
for i, option in enumerate(display_options):
# Add zero-width space characters as unique identifier (invisible to users)
unique_option = option + ("\u200B" * i) # \u200B is zero-width space
unique_display_options.append(unique_option)
selected_unique_option = st.selectbox(
tr("template.select"),
unique_display_options,
index=default_index,
label_visibility="collapsed",
help=tr("template.select_help")
)
# Get index from selected unique option
selected_index = unique_display_options.index(selected_unique_option)
# Check if separator is selected (shouldn't happen, but handle it)
if display_options[selected_index].startswith("───"):
st.warning(tr("template.separator_selected"))
st.stop()
# Get full template path directly by index
frame_template = template_paths_ordered[selected_index]
# Display selected template name (inside expander, below tabs)
frame_template = st.session_state['selected_template']
# Find the selected template's display name
selected_template_name = None
for size, templates in grouped_templates.items():
for template in templates:
if template.template_path == frame_template:
selected_template_name = template.display_info.name
break
if selected_template_name:
break
if selected_template_name:
st.info(f"📋 {tr('template.selected_template')}: **{selected_template_name}**")
# Display video size from template
from pixelle_video.utils.template_util import parse_template_size
video_width, video_height = parse_template_size(frame_template)

View File

@@ -103,6 +103,11 @@
"template.preview_image_help": "Supports local path or URL",
"template.preview_caption": "Template Preview: {template}",
"template.custom_parameters": "Custom Parameters",
"template.gallery_view": "Template Gallery",
"template.select_button": "Check",
"template.selected": "Checked",
"template.selected_template": "Current Template",
"template.no_templates_with_preview": "⚠️ No templates available for this type",
"image.not_required": "Current template does not require image generation",
"image.not_required_hint": "The selected template is text-only and does not need images. Benefits: ⚡ Faster generation 💰 Lower cost",
"video.title": "🎬 Video Settings",

View File

@@ -103,6 +103,11 @@
"template.preview_image_help": "支持本地路径或 URL",
"template.preview_caption": "模板预览:{template}",
"template.custom_parameters": "自定义参数",
"template.gallery_view": "模板库",
"template.select_button": "选择",
"template.selected": "已选",
"template.selected_template": "当前模板",
"template.no_templates_with_preview": "⚠️ 该类型暂无可用模板",
"image.not_required": "当前模板不需要插图生成",
"image.not_required_hint": "您选择的模板是纯文本模板,无需生成图片。这将:⚡ 加快生成速度 💰 降低生成成本",
"video.title": "🎬 视频设置",