Я случайно наткнулся на статью автора Lucas Neves Pereira под названием «Build your own LinkTree with Go and GitHub Pages«. В статье описано, как создать подобие LinkTree (аналог Taplink) на языке Go и GitHub Pages. Я, как любитель языка Python, решил реализовать проект на этом языке.
Шаг 1: Подготовка файловой структуры проекта
Первым делом создадим файловую структуру для нашего проекта. Мы организуем наш проект таким образом, чтобы он был легко поддерживаемым и удобным для развертывания на GitHub Pages.
Файловая структура:
/ (root) |-- /docs | |-- index.html | |-- /assets | |-- (файлы стилей, скриптов, иконок и т.д.) |-- config.yml |-- generate_site.py |-- /themes
-
/docs: В этой папке будут храниться сгенерированные HTML-файлы и все необходимые ассеты (изображения, стили, скрипты). Эта папка будет использоваться для развертывания сайта на GitHub Pages.
-
config.yml: Файл конфигурации, который содержит все данные для персонализации сайта.
-
generate_site.py: Скрипт на Python, который будет генерировать сайт на основе данных из config.yml.
-
/themes: Папка с темами для сайта. В нашем случае, здесь хранится единственная тема custom, которая включает в себя шаблон HTML, стили, скрипты и изображения.
Шаг 2: Настройка файла конфигурации (config.yml)
Файл config.yml содержит данные о пользователе и ссылки, которые будут отображаться на сайте. Вот его содержимое:
name: "King Triton" picture: "assets/img/picture.jpg" bio: "Programmer python and php/laravel" meta: lang: "en" description: "Programmer python and php/laravel" title: "King Triton" author: "King Triton" siteUrl: "https://king-tri-ton.github.io/pythonpagelink/" links: - name: "Github" url: "https://github.com/king-tri-ton" - name: "Dev.to" url: "https://dev.to/king_triton" - name: "Patreon" url: "https://www.patreon.com/king_triton" - name: "Telegram" url: "https://t.me/king_triton" - name: "Instagram" url: "https://www.instagram.com/king_tri_ton" theme: "custom"
-
name: Имя пользователя, которое будет отображаться на сайте.
-
picture: Путь к изображению пользователя.
-
bio: Краткая биография пользователя.
-
meta: Метаинформация сайта (язык, описание, заголовок, автор, URL сайта).
-
links: Список ссылок, которые будут отображаться на сайте. Каждый элемент содержит название и URL.
-
theme: Тема сайта, которую следует использовать.
Шаг 3: Разработка Python-скрипта для генерации сайта (generate_site.py)
Далее мы напишем скрипт на Python, который будет использовать шаблон из темы, данные из config.yml и генерировать готовый HTML-файл.
import os import shutil from jinja2 import Environment, FileSystemLoader import yaml # Загрузка конфигурации with open('config.yml', 'r') as config_file: config = yaml.safe_load(config_file) # Создание выходной директории output_dir = 'docs' os.makedirs(output_dir, exist_ok=True) # Настройка Jinja2 env = Environment(loader=FileSystemLoader('themes/custom')) template = env.get_template('index.html') # Генерация HTML файла output_html = template.render(config=config) with open(os.path.join(output_dir, 'index.html'), 'w') as fh: fh.write(output_html) # Копирование папки assets в выходной каталог assets_source = os.path.join('themes', config['theme'], 'assets') assets_dest = os.path.join(output_dir, 'assets') if os.path.exists(assets_source): shutil.copytree(assets_source, assets_dest, dirs_exist_ok=True) print("Site generated successfully.")
-
Загрузка конфигурации: Скрипт загружает данные из файла config.yml.
-
Создание выходной директории: Папка docs создается автоматически, если она не существует.
-
Настройка Jinja2: Используется Jinja2 для загрузки шаблона HTML и рендеринга контента.
-
Генерация HTML-файла: Скрипт генерирует файл index.html с использованием данных из конфигурации и сохраняет его в папке docs.
-
Копирование ассетов: Все ассеты (CSS, изображения, скрипты) копируются в папку docs/assets.
Шаг 4: Создание темы и ассетов
Теперь создадим тему, которая будет использоваться для нашего сайта. В папке themes/custom/ должны находиться следующие файлы:
themes/custom/index.html
Это основной HTML-шаблон сайта. Он использует переменные из файла конфигурации.
<!DOCTYPE html> <html lang="{{ config.meta.lang }}"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="{{ config.meta.description }}"> <title>{{ config.meta.title }}</title> <meta name="author" content="{{ config.meta.author }}"> <link rel="canonical" href="{{ config.meta.siteUrl }}"> <link rel="icon" type="image/x-icon" href="assets/icons/favicon.ico"> <link rel="stylesheet" href="assets/css/styles.css"> <meta property="og:title" content="{{ config.meta.title }}"> <meta property="og:site_name" content="{{ config.meta.title }}"> <meta property="og:description" content="{{ config.meta.description }}"> <meta property="og:locale" content="{{ config.meta.lang }}"> <meta name="twitter:title" content="{{ config.meta.title }}"> <meta name="twitter:description" content="{{ config.meta.description }}"> </head> <body> <header> <img src="{{ config.picture }}" alt="Picture" class="avatar"> <h1>{{ config.name }}</h1> <small class="bio">{{ config.bio }}</small> </header> <main> <section class="links"> {% for link in config.links %} <a class="link-item" href="{{ link.url }}" target="_blank" rel="noopener noreferrer"> <p>{{ link.name }}</p> </a> {% endfor %} </section> </main> <footer> <small>© <span class="year"></span> {{ config.meta.author }}</small> </footer> <script src="assets/js/script.js"></script> </body> </html>
themes/custom/assets/styles.css
Файл CSS для стилизации страницы.
/* CSS Reset */ * { margin: 0; padding: 0; box-sizing: border-box; } /* Variables */ :root { --max-width: 600px; --font-family: 'Inter', sans-serif; --padding: 1rem; --header-margin-bottom: 1rem; --line-height: 2; --font-size: 16px; --primary-color-light: #ffffff; --background-color-light: #f0f0f0; --text-color-light: #333; --link-color-light: #1a73e8; --bio-color-light: #666; --primary-color-dark: #1e1e1e; --background-color-dark: #121212; --text-color-dark: #e0e0e0; --link-color-dark: #8ab4f8; --bio-color-dark: #aaa; } /* Light Theme */ @media (prefers-color-scheme: light) { :root { --primary-color: var(--primary-color-light); --background-color: var(--background-color-light); --text-color: var(--text-color-light); --link-color: var(--link-color-light); --bio-color: var(--bio-color-light); } } /* Dark Theme */ @media (prefers-color-scheme: dark) { :root { --primary-color: var(--primary-color-dark); --background-color: var(--background-color-dark); --text-color: var(--text-color-dark); --link-color: var(--link-color-dark); --bio-color: var(--bio-color-dark); } } /* Global Styles */ html { font-family: var(--font-family); font-size: var(--font-size); line-height: var(--line-height); } body { max-width: var(--max-width); min-height: 100vh; margin: 0 auto; display: flex; flex-direction: column; align-items: center; background-color: var(--background-color); color: var(--text-color); padding: var(--padding); } /* Header Styles */ header { padding: var(--padding) 0; margin-bottom: var(--header-margin-bottom); width: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; } .avatar { width: 100px; height: 100px; border-radius: 50%; object-fit: cover; border: 2px solid var(--primary-color); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } h1 { font-size: 24px; margin-bottom: 0.5rem; } .bio { font-size: 14px; color: var(--bio-color); margin-bottom: 1rem; } /* Main Content Styles */ main { width: 100%; flex: 1; } .links { display: flex; flex-direction: column; gap: 1rem; text-align: center; overflow-y: auto; max-height: 400px; } .link-item { display: block; padding: 16px 20px; text-decoration: none; color: var(--link-color); background: var(--primary-color); border-radius: 12px; border: 1px solid var(--link-color); transition: background-color 0.25s, color 0.25s; } .link-item:hover, .link-item:focus { background-color: var(--link-color); color: var(--primary-color); } .link-item p { line-height: 1.5; font-weight: 500; } /* Footer Styles */ footer { width: 100%; text-align: center; padding: 1rem 0; font-size: 14px; gap: 1rem; display: flex; justify-content: center; align-items: center; } /* ScrollBar */ ::-webkit-scrollbar { width: 5px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background: transparent; } ::-webkit-scrollbar-thumb:hover { background: transparent; }
themes/custom/assets/js/script.js
Файл JavaScript для базовых функциональностей.
console.log("scripts loaded"); const yearDate = new Date().getFullYear().toString(); document.querySelector(".year").innerText = yearDate;
themes/custom/assets/img/picture.jpg
Фотография, которая будет использоваться в качестве аватара.
Шаг 5: Генерация сайта
После того как все файлы созданы, запустите скрипт generate_site.py, чтобы сгенерировать сайт:
python generate_site.py
Сайт будет сгенерирован в папке docs.
Шаг 6: Развертывание на GitHub Pages
-
Создайте новый репозиторий на GitHub.
-
Загрузите все файлы, включая папку docs, в репозиторий.
-
Перейдите в раздел Settings репозитория.
-
В разделе Pages выберите ветку master и папку /docs как источник.
-
Сохраните изменения и подождите, пока GitHub Pages развернет ваш сайт.
Теперь ваш сайт будет доступен по адресу https://[username].github.io/[repository-name]/
Вот и все! Теперь у вас есть собственный сайт в стиле Taplink, созданный на Python и развернутый на GitHub Pages. Вы можешь посмотреть мой готовый результат по адресу https://king-tri-ton.github.io/pythonpagelink/.
Благодарю за внимание!
ссылка на оригинал статьи https://habr.com/ru/articles/839574/
Добавить комментарий