Branch: refs/heads/master Author: Enrico Tröger enrico.troeger@uvena.de Committer: GitHub noreply@github.com Date: Sun, 30 Jun 2019 12:11:17 UTC Commit: 1ab6c22629c745106a4debb44f3903ef0a7e5b5b https://github.com/geany/www.geany.org/commit/1ab6c22629c745106a4debb44f3903...
Log Message: ----------- Merge pull request #8 from geany/issue5_geany_themes_preview
Add Geany-Themes page with theme preview
Modified Paths: -------------- geany/templates/home.html page_content/download/themes.md static_docs/github_client.py static_docs/templates/pages/download/themes.html static_docs/urls.py static_docs/views.py
Modified: geany/templates/home.html 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -151,7 +151,7 @@ <h2 class="text-center">Great Community</h2> <h2 class="text-center">Easily Customizable</h2> <p> Many parts of Geany are heavily customizable like color themes - (<a href="https://github.com/geany/geany-themes">Geany Themes project</a>) or + (<a href="{% url "page" "download/themes" %}">Geany Themes</a>) or adding new filetypes. </p> <p>
Modified: page_content/download/themes.md 10 lines changed, 10 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,10 @@ +## Geany Themes + +Geany-Themes is a collection of color schemes for Geany, either written originally by the Geany community or ported from color schemes for other editors. +These schemes are compatible with Geany 1.22 and greater. + +To use one the themes below, download the configuration file and save it to the folder `colorschemes` in your Geany configuration directory (usually `~/.config/geany/colorschemes/`). + +For more information and detailed configuration instructions, see https://github.com/geany/geany-themes. + +
Modified: static_docs/github_client.py 17 lines changed, 14 insertions(+), 3 deletions(-) =================================================================== @@ -30,15 +30,18 @@ class GitHubApiClient: """"""
# ---------------------------------------------------------------------- - def get_file_contents(self, filename): - url_parameters = dict(user=GITHUB_USER, - repository=GITHUB_REPOSITORY, + def get_file_contents(self, filename, user=None, repository=None): + user = user or GITHUB_USER + repository = repository or GITHUB_REPOSITORY + url_parameters = dict(user=user, + repository=repository, filename=filename) url = 'https://api.github.com/repos/%(user)s/%(repository)s/contents/%(filename)s' % \ url_parameters with requests.get(url, timeout=HTTP_REQUEST_TIMEOUT, stream=False) as response: response_json = response.json() self._log_rate_limit(response) + self._log_request(response)
# parse response return self._parse_fetch_file_response(response_json) @@ -49,6 +52,14 @@ def _log_rate_limit(self, response): rate_limit = response.headers['X-RateLimit-Limit'] logger.info('Github rate limits: %s/%s', rate_limit_remaining, rate_limit)
+ # ---------------------------------------------------------------------- + def _log_request(self, response): + logger.info( + 'Requesting "{} {}" took {}s'.format( + response.request.method, + response.request.url, + response.elapsed.total_seconds())) + # ---------------------------------------------------------------------- def _parse_fetch_file_response(self, response_json): content = response_json['content']
Modified: static_docs/templates/pages/download/themes.html 63 lines changed, 63 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,63 @@ +{% extends "pages/richtextpage.html" %} + +{% load mezzanine_tags pages_tags static %} + +{% block extra_css %} +<link rel="stylesheet" href="{% static "mezzanine/css/magnific-popup.css" %}"> +<style> + .img-thumbnail { + cursor: zoom-in; + } +</style> +{% endblock %} + +{% block richtext_content %} +{{ block.super }} + +<h3>Available Themes</h3> + +<div class="row"> + +{% for theme in theme_index.values|dictsort:"name" %} + <div class="col-md-4"> + <div class="panel panel-default"> + <div class="panel-heading"> + <strong>{{ theme.name }}</strong> + <span class="pull-right"><a href="{{ theme.colorscheme }}">Download</a></span> + </div> + <div class="panel-body gallery"> + <a href="{{ theme.screenshot }}" title="{{ theme.name }} - {{ theme.description }}"> + <img + src="data:image/png;base64,{{ theme.thumbnail }}" + class="img-responsive img-thumbnail center-block" + alt="Thumbnail of colorscheme {{ theme.name }}" /> + </a> + <div class="text-center">{{ theme.description }}</div> + </div> + </div> + </div> + + {% if forloop.counter|divisibleby:3 %} + </div> + <div class="row"> + {% endif %} +{% endfor %} +</div> + +{% endblock %} + +{% block extra_js %} +{{ block.super }} +<script src="{% static "mezzanine/js/magnific-popup.js" %}"></script> +<script> +$(document).ready(function() { + $('.gallery').magnificPopup({ + delegate: 'a', + type: 'image', + gallery: { + enabled: true, + } + }); +}); +</script> +{% endblock %}
Modified: static_docs/urls.py 4 lines changed, 3 insertions(+), 1 deletions(-) =================================================================== @@ -14,10 +14,12 @@
from django.conf.urls import url
-from static_docs.views import I18NStatisticsView, ReleaseNotesView, ToDoView +from static_docs.views import I18NStatisticsView, ReleaseNotesView, ThemesView, ToDoView
urlpatterns = ( # pylint: disable=invalid-name + url(r'^download/themes/$', ThemesView.as_view(), name='themes'), + url(r'^documentation/todo/$', ToDoView.as_view(), name='todo'),
url(r'^documentation/releasenotes/$', ReleaseNotesView.as_view(), name='releasenotes'),
Modified: static_docs/views.py 64 lines changed, 62 insertions(+), 2 deletions(-) =================================================================== @@ -19,6 +19,7 @@ import re
from django.conf import settings +from django.core.cache import cache from django.http import Http404 from django.views.generic.base import TemplateView from mezzanine_pagedown.filters import plain as markdown_plain @@ -30,6 +31,9 @@ RELEASE_REGEXP = re.compile(r'^Geany (?P<version>[0-9.]+) ((?P<date>.*))$') DATE_PATTERNS_TO_BE_IGNORED = ('TBD', 'TBA', 'unreleased')
+CACHE_KEY_THEME_INDEX_MD5_HASH = 'THEME_INDEX_MD5_HASH' +CACHE_KEY_THEME_INDEX = 'THEME_INDEX' + logger = logging.getLogger(__name__) # pylint: disable=invalid-name
@@ -56,9 +60,9 @@ def __init__(self, *args, **kwargs): self._file_contents = None
# ---------------------------------------------------------------------- - def _fetch_file_via_github_api(self, filename): + def _fetch_file_via_github_api(self, filename, user=None, repository=None): client = GitHubApiClient() - self._file_contents = client.get_file_contents(filename) + self._file_contents = client.get_file_contents(filename, user=user, repository=repository)
class ReleaseNotesView(StaticDocsView): @@ -240,3 +244,59 @@ def _get_i18n_statistics(self): settings.STATIC_DOCS_GEANY_I18N_STATISTICS_FILENAME) with open(filename) as input_file: return json.load(input_file) + + +class ThemesView(StaticDocsView): + """ + Fetch the Geany-Themes index from https://github.com/geany/geany-themes/tree/master/index + """ + + template_name = "pages/download/themes.html" + + # ---------------------------------------------------------------------- + def get_context_data(self, **kwargs): + theme_index = self._get_theme_index() + context = super(ThemesView, self).get_context_data(**kwargs) + context['theme_index'] = theme_index + return context + + # ---------------------------------------------------------------------- + def _get_theme_index(self): + """ + Refresh the theme index by: + - querying the MD5 hash from Github + - compare the freshly retrieved MD5 hash against the cached one + - load the whole theme index if: + - the MD5 hashes differ + - the MD5 hash was not retrieved yet or has been expired from cache + - the theme index was not retrieved yet or has been expired from cache + - after loading the whole theme index cache it long (24 hours) + - store the freshly retrieved MD5 hash in the cache + """ + theme_index_md5_hash = self._query_theme_index_md5_hash() + cached_theme_index_md5_hash = cache.get(CACHE_KEY_THEME_INDEX_MD5_HASH) + theme_index = cache.get(CACHE_KEY_THEME_INDEX) + + # theme index has been changed remotely? + if theme_index_md5_hash != cached_theme_index_md5_hash or theme_index is None: + logger.debug('Refresh theme index from Github (MD5: {})'.format(theme_index_md5_hash)) + # query whole theme index + theme_index = self._query_parse_themes_index() + # cache it for later + cache.set(CACHE_KEY_THEME_INDEX, theme_index, CACHE_TIMEOUT_24HOURS) + + # cache MD5 hash + cache.set(CACHE_KEY_THEME_INDEX_MD5_HASH, theme_index_md5_hash, CACHE_TIMEOUT_24HOURS) + + return theme_index + + # ---------------------------------------------------------------------- + def _query_theme_index_md5_hash(self): + self._fetch_file_via_github_api('index/index.json.md5', repository='geany-themes') + return self._file_contents.strip() + + # ---------------------------------------------------------------------- + def _query_parse_themes_index(self): + self._fetch_file_via_github_api('index/index.json', repository='geany-themes') + theme_index = json.loads(self._file_contents) + return theme_index
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).