import os import markdown import shutil from pathlib import Path TEMPLATE = """ {title} | ФМИ

Физико-математический институт

{content}
""" def parse_front_matter(text): if text.strip().startswith('---'): parts = text.split('---', 2) if len(parts) >= 3: meta = {} for line in parts[1].strip().split('\n'): if ':' in line: key, val = line.split(':', 1) meta[key.strip()] = val.strip().strip('"') return meta, parts[2].strip() return {}, text.strip() def build_page(md_path, html_path, title): with open(md_path, 'r', encoding='utf-8') as f: meta, md_text = parse_front_matter(f.read()) html_content = markdown.markdown(md_text, extensions=['fenced_code', 'tables']) with open(html_path, 'w', encoding='utf-8') as f: f.write(TEMPLATE.format(title=title, content=html_content)) # Улучшенная навигация с "хлебными крошками" def build_breadcrumbs(current_path): """Создает навигационную цепочку (хлебные крошки)""" crumbs = ['') return ''.join(crumbs) # ------------------------------------------------------------------------ def main(): Path('public').mkdir(exist_ok=True) Path('public/news').mkdir(exist_ok=True) Path('public/staff').mkdir(exist_ok=True) # 1. Главная страница if Path('content/index.md').exists(): build_page(Path('content/index.md'), 'public/index.html', 'Главная') # 2. Страница новостей (с карточками) news_files = sorted(Path('content/news').glob('*.md'), reverse=True) news_cards = [] for md_file in news_files: with open(md_file, 'r', encoding='utf-8') as f: meta, body = parse_front_matter(f.read()) title = meta.get('title', md_file.stem.replace('-', ' ').title()) date = meta.get('date', '') # Берем первые 200 символов как анонс excerpt = body[:200].strip() if len(body) > 200: excerpt += '...' # Конвертируем в HTML (только первый абзац) first_paragraph = body.split('\n\n')[0] if '\n\n' in body else body[:150] excerpt_html = markdown.markdown(first_paragraph, extensions=['fenced_code']) # Форматируем дату if date: try: from datetime import datetime date_obj = datetime.strptime(date, '%Y-%m-%d') date_formatted = date_obj.strftime('%d.%m.%Y') except: date_formatted = date else: date_formatted = md_file.stem.replace('-', '.') card_html = f'''

{title}

{date_formatted}
{excerpt_html}
Читать далее
''' news_cards.append(card_html) breadcrumbs = build_breadcrumbs('/news.html') news_content = breadcrumbs + "

Последние новости

" + "".join(news_cards) with open('public/news.html', 'w', encoding='utf-8') as f: f.write(TEMPLATE.format(title="Новости", content=news_content)) # 3. Страница сотрудников staff_by_lab = {} unassigned = [] for md_file in sorted(Path('content/staff').glob('*.md')): with open(md_file, 'r', encoding='utf-8') as f: meta, _ = parse_front_matter(f.read()) name = meta.get('name', md_file.stem.replace('-', ' ').title()) degree = meta.get('degree', '') position = meta.get('position', '') lab = meta.get('lab', 'Без подразделения') details = [] if degree: details.append(degree) if position: details.append(position) details_str = ", ".join(details) person_html = f'''
{name}
{details_str}
''' if lab == 'Без подразделения' or not lab: unassigned.append(person_html) else: if lab not in staff_by_lab: staff_by_lab[lab] = [] staff_by_lab[lab].append(person_html) staff_html = "

Наши сотрудники

" lab_order = [ "Лаборатория математики и телекоммуникаций", "Лаборатория теоретической и вычислительной физики", "Лаборатория экспериментальной физики" ] for lab in lab_order: if lab in staff_by_lab: staff_html += f"

{lab}

" for p in staff_by_lab[lab]: staff_html += p for lab, people in staff_by_lab.items(): if lab not in lab_order: staff_html += f"

{lab}

" for p in people: staff_html += p if unassigned: staff_html += "

Сотрудники (без привязки к лаборатории)

" for p in unassigned: staff_html += p with open('public/staff.html', 'w', encoding='utf-8') as f: f.write(TEMPLATE.format(title="Сотрудники", content=staff_html)) # 4. Персональные страницы сотрудников for md_file in Path('content/staff').glob('*.md'): with open(md_file, 'r', encoding='utf-8') as f: meta, body = parse_front_matter(f.read()) name = meta.get('name', md_file.stem.replace('-', ' ').title()) full_content = f'← Назад к списку сотрудников\n{body}' html_content = markdown.markdown(full_content, extensions=['fenced_code', 'tables']) with open(Path(f'public/staff/{md_file.stem}.html'), 'w', encoding='utf-8') as f: f.write(TEMPLATE.format(title=name, content=html_content)) # 5. Страница с публикациями (PDF-файлы) pdf_files = sorted(Path('static/pdf').glob('*.pdf')) if pdf_files: pdf_list_html = "

Научные публикации и документы

" with open('public/publications.html', 'w', encoding='utf-8') as f: f.write(TEMPLATE.format(title="Публикации", content=pdf_list_html)) else: # Если PDF пока нет, создаем заглушку with open('public/publications.html', 'w', encoding='utf-8') as f: f.write(TEMPLATE.format(title="Публикации", content="

Публикации

В этом разделе скоро появятся научные публикации и документы.

")) # 6. Копирование статических файлов (картинки, PDF, CSS) if Path('static').exists(): shutil.rmtree('public/static', ignore_errors=True) shutil.copytree('static', 'public/static') print("✅ Статические файлы скопированы (включая PDF)") print("✅ Сайт успешно собран!") if __name__ == '__main__': main()