pmi-site/build.py

150 lines
6.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import markdown
from pathlib import Path
TEMPLATE = """<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{title} | ФМИ</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
<style>
body {{ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; max-width: 900px; margin: 0 auto; padding: 20px; line-height: 1.6; color: #333; }}
header {{ border-bottom: 2px solid #003366; padding-bottom: 10px; margin-bottom: 30px; }}
h1 {{ color: #003366; }}
h2 {{ color: #004080; border-bottom: 1px solid #eee; padding-bottom: 5px; margin-top: 30px; }}
h3 {{ color: #0055a4; margin-top: 25px; }}
nav {{ margin-bottom: 30px; }}
nav a {{ margin-right: 20px; text-decoration: none; color: #003366; font-weight: bold; font-size: 1.1em; }}
nav a:hover {{ text-decoration: underline; }}
.person {{ margin-bottom: 15px; padding-bottom: 15px; border-bottom: 1px dashed #ddd; }}
.person-name {{ font-weight: bold; font-size: 1.1em; color: #222; }}
.person-details {{ color: #555; font-size: 0.95em; }}
</style>
</head>
<body>
<header>
<h1>Физико-математический институт</h1>
<nav>
<a href="/">Главная</a>
<a href="/news.html">Новости</a>
<a href="/staff.html">Сотрудники</a>
</nav>
</header>
<main>
{content}
</main>
<footer style="margin-top: 50px; border-top: 1px solid #ccc; padding-top: 20px; font-size: 0.8em; color: #666;">
© 2026 Физико-математический институт Коми НЦ УрО РАН
</footer>
</body>
</html>"""
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 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_links = "".join([f'<li><a href="news/{f.stem}.html">{f.stem.replace("-", " ").title()}</a></li>' for f in news_files])
with open('public/news.html', 'w', encoding='utf-8') as f:
f.write(TEMPLATE.format(title="Новости", content=f"<h2>Последние новости</h2><ul>{news_links}</ul>"))
for md_file in news_files:
build_page(md_file, Path(f'public/news/{md_file.stem}.html'), md_file.stem.replace('-', ' ').title())
# 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'<div class="person"><div class="person-name">{name}</div><div class="person-details">{details_str}</div></div>'
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)
# Формируем HTML для страницы сотрудников
staff_html = "<h2>Наши сотрудники</h2>"
# Сначала лаборатории в заданном порядке (можно отсортировать)
lab_order = [
"Лаборатория математики и телекоммуникаций",
"Лаборатория теоретической и вычислительной физики",
"Лаборатория экспериментальной физики"
]
for lab in lab_order:
if lab in staff_by_lab:
staff_html += f"<h3>{lab}</h3>"
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"<h3>{lab}</h3>"
for p in people:
staff_html += p
if unassigned:
staff_html += "<h3>Сотрудники (без привязки к лаборатории)</h3>"
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))
# Создаем индивидуальные страницы для каждого сотрудника
for md_file in Path('content/staff').glob('*.md'):
build_page(md_file, Path(f'public/staff/{md_file.stem}.html'), meta.get('name', md_file.stem))
print("✅ Сайт успешно собран! Сотрудники сгруппированы.")
if __name__ == '__main__':
main()