From e1e5aaf130ecd328433d21f7a9c1b814198a788c Mon Sep 17 00:00:00 2001 From: puke <1129090915@qq.com> Date: Tue, 6 Jan 2026 11:49:18 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96web=E9=A1=B5=E9=9D=A2FAQ?= =?UTF-8?q?=E7=9A=84=E5=B1=95=E7=A4=BA=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/components/faq.py | 58 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/web/components/faq.py b/web/components/faq.py index 22a1f5f..a890e2f 100644 --- a/web/components/faq.py +++ b/web/components/faq.py @@ -14,6 +14,7 @@ FAQ component for displaying frequently asked questions """ +import re from pathlib import Path from typing import Optional @@ -57,6 +58,50 @@ def load_faq_content(language: str) -> Optional[str]: return None +def parse_faq_sections(content: str) -> list[tuple[str, str]]: + """ + Parse FAQ content into sections by ### headings + + Args: + content: Raw markdown content + + Returns: + List of (question, answer) tuples + """ + # Remove the first main heading (starts with #, not ###) + lines = content.split('\n') + if lines and lines[0].startswith('#') and not lines[0].startswith('##'): + content = '\n'.join(lines[1:]) + + # Split by ### headings (top-level questions) + # Pattern matches ### at start of line followed by question text + pattern = r'^###\s+(.+?)$' + + sections = [] + current_question = None + current_answer_lines = [] + + for line in content.split('\n'): + match = re.match(pattern, line) + if match: + # Save previous section if exists + if current_question is not None: + answer = '\n'.join(current_answer_lines).strip() + sections.append((current_question, answer)) + # Start new section + current_question = match.group(1).strip() + current_answer_lines = [] + else: + current_answer_lines.append(line) + + # Save last section + if current_question is not None: + answer = '\n'.join(current_answer_lines).strip() + sections.append((current_question, answer)) + + return sections + + def render_faq_sidebar(): """ Render FAQ in the sidebar @@ -77,14 +122,13 @@ def render_faq_sidebar(): if faq_content: # Display FAQ in an expander, expanded by default with st.expander(tr('faq.expand_to_view', fallback='FAQ'), expanded=True): - # Remove the first heading from FAQ content since we already show it above - lines = faq_content.split('\n') - # Skip the first line if it's a heading - if lines and lines[0].startswith('#'): - faq_content = '\n'.join(lines[1:]) + # Parse FAQ into sections + sections = parse_faq_sections(faq_content) - # Display FAQ content - st.markdown(faq_content, unsafe_allow_html=True) + # Display each question in its own collapsible expander + for question, answer in sections: + with st.expander(question, expanded=False): + st.markdown(answer, unsafe_allow_html=True) # Add a link to GitHub issues for more help st.markdown(