Colour language tag using GitHub's linguist colours
This commit is contained in:
parent
e504da0bcf
commit
d85065d914
6 changed files with 67 additions and 10 deletions
|
@ -17,3 +17,4 @@ flake8-mutable==1.2.0
|
|||
flake8-print==5.0.0
|
||||
flake8-tuple==0.4.1
|
||||
djlint==1.19.2
|
||||
types-pyyaml==6.0.12.9
|
||||
|
|
|
@ -80,6 +80,14 @@ div.block-tangent {
|
|||
div.block-code {
|
||||
position: relative;
|
||||
|
||||
.highlight {
|
||||
pre,
|
||||
span,
|
||||
& {
|
||||
@include dark-mode;
|
||||
}
|
||||
}
|
||||
|
||||
.code-header {
|
||||
position: absolute;
|
||||
font-family: $family-code;
|
||||
|
@ -103,19 +111,17 @@ div.block-code {
|
|||
|
||||
.language-tag {
|
||||
background-color: $primary-light;
|
||||
font-weight: $weight-medium;
|
||||
|
||||
@include dark-mode {
|
||||
background-color: $primary-dark;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.highlight {
|
||||
pre,
|
||||
span,
|
||||
& {
|
||||
@include dark-mode;
|
||||
&.linguist-color span {
|
||||
// HACK: Naive inverse threshold of the colour for optimum contrast
|
||||
filter: contrast(1000) grayscale(100) invert(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,4 +22,4 @@ $code-padding: 0;
|
|||
$code: inherit;
|
||||
$pre: unset;
|
||||
$content-heading-weight: $weight-medium;
|
||||
$content-pre-padding: 1.5em 1.25em 1.25em;
|
||||
$content-pre-padding: 1.5em;
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
from typing import Iterator
|
||||
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.safestring import mark_safe
|
||||
from pygments import highlight
|
||||
from pygments.formatters.html import HtmlFormatter
|
||||
from pygments.lexers import find_lexer_class, get_all_lexers
|
||||
from pygments.lexers.python import PythonConsoleLexer, PythonLexer
|
||||
from pygments.lexers.shell import BashLexer, BashSessionLexer
|
||||
from pygments.lexers.special import TextLexer
|
||||
from wagtail.blocks import CharBlock, ChoiceBlock, StructBlock, StructValue, TextBlock
|
||||
|
||||
from .utils import get_linguist_colours
|
||||
|
||||
|
||||
def get_language_choices() -> Iterator[tuple[str, str]]:
|
||||
for name, _, _, _ in sorted(get_all_lexers()):
|
||||
|
@ -17,6 +21,8 @@ def get_language_choices() -> Iterator[tuple[str, str]]:
|
|||
class CodeStructValue(StructValue):
|
||||
LANGUAGE_DISPLAY_MAPPING = {PythonConsoleLexer.name: PythonLexer.name}
|
||||
|
||||
LINGUIST_MAPPING = {BashLexer.name: "Shell", BashSessionLexer.name: "Shell"}
|
||||
|
||||
def code(self) -> str:
|
||||
lexer = find_lexer_class(self["language"])()
|
||||
formatter = HtmlFormatter(
|
||||
|
@ -39,6 +45,25 @@ class CodeStructValue(StructValue):
|
|||
"""
|
||||
return self.LANGUAGE_DISPLAY_MAPPING.get(self["language"], self["language"])
|
||||
|
||||
@cached_property
|
||||
def colour(self) -> str | None:
|
||||
"""
|
||||
Expose the colour denoted by GitHub's linguist.
|
||||
"""
|
||||
linguist_colours = get_linguist_colours()
|
||||
|
||||
language = self.LINGUIST_MAPPING.get(self["language"], self["language"])
|
||||
|
||||
if exact_match := linguist_colours.get(language.lower()):
|
||||
return exact_match
|
||||
|
||||
if language_display_match := linguist_colours.get(
|
||||
self.LANGUAGE_DISPLAY_MAPPING.get(language, "").lower()
|
||||
):
|
||||
return language_display_match
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class CodeBlock(StructBlock):
|
||||
filename = CharBlock(max_length=128, required=False)
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
{% if value.header_text %}
|
||||
<div class="code-header tags">
|
||||
{% if value.header_text %}<span class="tag ml-auto mr-5 language-tag" title="{{ value.language }}">{{ value.header_text }}</span>{% endif %}
|
||||
<div class="code-header">
|
||||
{% if value.header_text %}
|
||||
<span class="tag ml-auto mr-5 language-tag {% if value.colour %}linguist-color{% endif %}" title="{{ value.language }}" {% if value.colour %}style="background-color: {{ value.colour }}"{% endif %}>
|
||||
<span {% if value.colour %}style="color: {{ value.colour }}"{% endif %}>{{ value.header_text }}</span>
|
||||
</span>
|
||||
{% endif %}
|
||||
<span class="tag code-copy-tag">
|
||||
<i class="fa-regular fa-clipboard is-clickable code-copy" title="Copy to clipboard"></i>
|
||||
</span>
|
||||
|
|
|
@ -1,4 +1,25 @@
|
|||
from importlib.metadata import version
|
||||
|
||||
import requests
|
||||
import yaml
|
||||
from django_cache_decorator import django_cache_decorator
|
||||
|
||||
PYGMENTS_VERSION = version("pygments")
|
||||
PYGMENTS_VERSION_SLUG = PYGMENTS_VERSION.replace(".", "-")
|
||||
|
||||
LINGUIST_DATA_URL = "https://raw.githubusercontent.com/github/linguist/master/lib/linguist/languages.yml"
|
||||
|
||||
|
||||
@django_cache_decorator(time=21600)
|
||||
def get_linguist_colours() -> dict[str, str]:
|
||||
response = requests.get(LINGUIST_DATA_URL)
|
||||
|
||||
response.raise_for_status()
|
||||
|
||||
linguist_data = yaml.safe_load(response.text)
|
||||
|
||||
return {
|
||||
language.lower(): l["color"]
|
||||
for language, l in linguist_data.items()
|
||||
if l.get("color")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue