Skip to content

Instantly share code, notes, and snippets.

@deeplook
Last active March 26, 2020 20:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save deeplook/20c7a64eda8fc77fe020f5c644466b27 to your computer and use it in GitHub Desktop.
Save deeplook/20c7a64eda8fc77fe020f5c644466b27 to your computer and use it in GitHub Desktop.
Create custom SVG badges with shields.io
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Create custom SVG badges with shields.io\n",
"\n",
"- https://shields.io\n",
"- https://mybinder.readthedocs.io/en/latest/howto/badges.html"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import SVG\n",
"import base64\n",
"import re\n",
"import textwrap\n",
"import urllib\n",
"\n",
"import requests\n",
"from ipywidgets import Checkbox, ColorPicker, Dropdown, HBox, \\\n",
" HTML, Layout, VBox, Text, Textarea, Output"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"class BadgeCreator:\n",
" \"\"\"A class to help create SVG badges with shields.io interactively.\n",
" \"\"\"\n",
" def __init__(self, fields={}, dry=False, verbose=False):\n",
" \"\"\"Create instance.\n",
" \n",
" Accepted field names are: name, label, label_color, message, message_color, \n",
" logo, logo_color, style. Other field names are ignored.\n",
" \"\"\"\n",
" \n",
" l100px = Layout(width=\"100px\")\n",
" l200px = Layout(width=\"200px\")\n",
" l500px = Layout(width=\"500px\")\n",
" \n",
" # input\n",
" self.name = Text(\n",
" description=\"Name\", \n",
" placeholder='Badge name', \n",
" value=fields.get(\"name\"))\n",
" \n",
" self.label = Text(\n",
" description=\"Label\", \n",
" placeholder='Text', \n",
" value=fields.get(\"label\"))\n",
" \n",
" self.label_color = ColorPicker(layout=l100px)\n",
" col = fields.get(\"label_color\")\n",
" if col:\n",
" self.label_color.value = col\n",
" \n",
" self.use_label_color = Checkbox(\n",
" description=\"Use color\", \n",
" value=fields.get(\"label_color\") is not None, \n",
" layout=l200px)\n",
" \n",
" self.message = Text(\n",
" description=\"Message\", \n",
" placeholder='Text', \n",
" value=fields.get(\"message\"))\n",
" \n",
" self.message_color = ColorPicker(\n",
" value=fields.get(\"message_color\", \"black\"),\n",
" layout=l100px)\n",
"\n",
" self.logo = Text(\n",
" description=\"Logo\", \n",
" placeholder='Name', \n",
" value=fields.get(\"logo\"))\n",
" \n",
" self.logo_color = ColorPicker(layout=l100px)\n",
" col = fields.get(\"logo_color\")\n",
" if col:\n",
" self.logo_color.value = col\n",
" \n",
" self.use_logo_color = Checkbox(\n",
" description=\"Use color\", \n",
" value=fields.get(\"logo_color\") is not None, \n",
" layout=l200px)\n",
"\n",
" style_options = [\"\", \"flat\", \"flat-square\", \"for-the-badge\", \"plastic\", \"social\"]\n",
" self.style = Dropdown(\n",
" description=\"Style\", \n",
" options=style_options, \n",
" value=fields.get(\"style\", style_options[0]))\n",
"\n",
" # output\n",
" self.url = Textarea(description=\"URL\", layout=l500px)\n",
" self.md = Textarea(description=\"Markdown\", layout=l500px)\n",
" self.rst = Textarea(description=\"ReST\", layout=l500px)\n",
" self.html = HTML(description=\"Badge\", value=\"\")\n",
" self.raw = Textarea(description=\"Raw\", value=\"\", layout=l500px)\n",
" self.status = Output()\n",
"\n",
" cb = self.changed\n",
" for el in [self.name, self.label, self.logo, self.message]:\n",
" el.on_submit(cb)\n",
" for el in [self.label_color, self.use_label_color,\n",
" self.message_color,\n",
" self.logo_color, self.use_logo_color,\n",
" self.style]:\n",
" el.observe(cb)\n",
" \n",
" children = [\n",
" self.name,\n",
" HBox([self.label, self.label_color, self.use_label_color]), \n",
" HBox([self.message, self.message_color]), \n",
" HBox([self.logo, self.logo_color, self.use_logo_color]), \n",
" self.style, \n",
" self.html,\n",
" self.raw,\n",
" self.url,\n",
" self.md,\n",
" self.rst]\n",
" if verbose:\n",
" children.append(self.status)\n",
" self.ui = VBox(children=children)\n",
" \n",
" if not dry:\n",
" self.changed(self.label)\n",
"\n",
" def changed(self, change):\n",
" \"\"\"Callback sending a request to shields.io to create a badge SVG code.\n",
" \"\"\"\n",
" if self.status:\n",
" with self.status:\n",
" print(change)\n",
" svg = self.create()\n",
" self.html.value = svg\n",
" self.raw.value = svg\n",
" \n",
" def create(self):\n",
" \"\"\"Request a badge from shields.io and return its SVG code.\n",
" \"\"\"\n",
" lbl = self.label.value\n",
" msg = urllib.parse.quote(self.message.value)\n",
" col = self.message_color.value\n",
" if msg:\n",
" if col[0] == \"#\":\n",
" col = col[1:]\n",
" else:\n",
" col = \"\"\n",
" url_ = f\"https://img.shields.io/badge/{lbl}-{msg}-{col}\"\n",
"\n",
" params = {}\n",
" # if urllib.parse.quote_plus(self.label.value) != self.label.value:\n",
" # params[\"label\"] = urllib.parse.quote_plus(self.label.value)\n",
" if self.style.value:\n",
" params[\"style\"] = self.style.value\n",
" if self.logo.value:\n",
" if re.match(\"$http[s]?://.*\", self.logo.value):\n",
" logo_value = requests.get(self.logo.value)\n",
" else:\n",
" logo_value = self.logo.value\n",
" params[\"logo\"] = logo_value\n",
" if self.label_color.value and self.use_label_color.value:\n",
" params[\"labelColor\"] = self.label_color.value\n",
" # with self.status:\n",
" # print(self.logo.value, self.use_logo_color.value)\n",
" if self.logo.value and self.use_logo_color.value:\n",
" params[\"logoColor\"] = self.logo_color.value\n",
" \n",
" if params:\n",
" url_ += (\"?\" + urllib.parse.urlencode(params))\n",
" self.url.value = url_\n",
"\n",
" # html.value = f\"\"\"<img alt=\"{self.name.value}\" src=\"{url_}\">\"\"\"\n",
" self.md.value = f\"\"\"![{self.name.value}]({url_})\"\"\"\n",
" self.rst.value = textwrap.dedent(f\"\"\"\\\n",
" .. image:: {url_}\n",
" :alt: {self.name.value}\n",
" \"\"\")\n",
"\n",
" svg = requests.get(url_).text\n",
" return svg"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"fields = dict(\n",
" name=\"Mac support\",\n",
" label=\"mac\", # label_color=\"black\",\n",
" message=\"mojave | catalina\", message_color=\"blue\",\n",
" logo=\"apple\", logo_color=\"white\",\n",
" # style=\"social\",\n",
")\n",
"bc = BadgeCreator(fields=fields)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "892f004dec2d4a02b01a45b74750c021",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Text(value='Mac support', description='Name', placeholder='Badge name'), HBox(children=(Text(va…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# This will not show directly on GitHub:\n",
"bc.ui"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"<svg height=\"20\" width=\"157\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"><linearGradient id=\"b\" x2=\"0\" y2=\"100%\"><stop offset=\"0\" stop-color=\"#bbb\" stop-opacity=\".1\"/><stop offset=\"1\" stop-opacity=\".1\"/></linearGradient><clipPath id=\"a\"><rect fill=\"#fff\" height=\"20\" rx=\"3\" width=\"157\"/></clipPath><g clip-path=\"url(#a)\"><path d=\"M0 0h50v20H0z\" fill=\"#555\"/><path d=\"M50 0h107v20H50z\" fill=\"#007ec6\"/><path d=\"M0 0h157v20H0z\" fill=\"url(#b)\"/></g><g fill=\"#fff\" font-family=\"DejaVu Sans,Verdana,Geneva,sans-serif\" font-size=\"110\" text-anchor=\"middle\"><image height=\"14\" width=\"14\" x=\"5\" xlink:href=\"data:image/svg+xml;base64,PHN2ZyBmaWxsPSJ3aGl0ZSIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHRpdGxlPkFwcGxlIGljb248L3RpdGxlPjxwYXRoIGQ9Ik03LjA3OCAyMy41NWMtLjQ3My0uMzE2LS44OTMtLjcwMy0xLjI0NC0xLjE1LS4zODMtLjQ2My0uNzM4LS45NS0xLjA2NC0xLjQ1NC0uNzY2LTEuMTItMS4zNjUtMi4zNDUtMS43OC0zLjYzNi0uNS0xLjUwMi0uNzQzLTIuOTQtLjc0My00LjM0NyAwLTEuNTcuMzQtMi45NCAxLjAwMi00LjA5LjQ5LS45IDEuMjItMS42NTMgMi4xLTIuMTgyLjg1LS41MyAxLjg0LS44MiAyLjg0LS44NC4zNSAwIC43My4wNSAxLjEzLjE1LjI5LjA4LjY0LjIxIDEuMDcuMzcuNTUuMjEuODUuMzQuOTUuMzcuMzIuMTIuNTkuMTcuOC4xNy4xNiAwIC4zOS0uMDUuNjQ1LS4xMy4xNDUtLjA1LjQyLS4xNC44MS0uMzEuMzg2LS4xNC42OTItLjI2LjkzNS0uMzUuMzctLjExLjcyOC0uMjEgMS4wNS0uMjYuMzktLjA2Ljc3Ny0uMDggMS4xNDgtLjA1LjcxLjA1IDEuMzYuMiAxLjk0LjQyIDEuMDIuNDEgMS44NDMgMS4wNSAyLjQ1NyAxLjk2LS4yNi4xNi0uNS4zNDYtLjcyNS41NS0uNDg3LjQzLS45Ljk0LTEuMjMgMS41MDUtLjQzLjc3LS42NSAxLjY0LS42NDQgMi41Mi4wMTUgMS4wODMuMjkgMi4wMzUuODQgMi44Ni4zODcuNi45MDQgMS4xMTQgMS41MzQgMS41MzYuMzEuMjEuNTgyLjM1NS44NC40NS0uMTIuMzc1LS4yNTIuNzQtLjQwNSAxLjEtLjM0Ny44MDctLjc2IDEuNTgtMS4yNSAyLjMxLS40MzIuNjMtLjc3MiAxLjEtMS4wMyAxLjQxLS40MDIuNDgtLjc5Ljg0LTEuMTggMS4wOTctLjQzLjI4NS0uOTM1LjQzNi0xLjQ1Mi40MzYtLjM1LjAxNS0uNy0uMDMtMS4wMzQtLjEyNy0uMjktLjA5NS0uNTc2LS4yMDItLjg1Ni0uMzIzLS4yOTMtLjEzNC0uNTk2LS4yNDgtLjkwNS0uMzQtLjM4LS4xLS43Ny0uMTQ4LTEuMTY0LS4xNDctLjQgMC0uNzkuMDUtMS4xNi4xNDUtLjMxLjA4OC0uNjEuMTk2LS45MDcuMzI1LS40Mi4xNzUtLjY5NS4yOS0uODU1LjM0LS4zMjQuMDk2LS42NTYuMTU0LS45OS4xNzUtLjUyIDAtMS4wMDQtLjE1LTEuNDg2LS40NXptNi44NTQtMTguNDZjLS42OC4zNC0xLjMyNi40ODQtMS45NzMuNDM2LS4xLS42NDYgMC0xLjMxLjI3LTIuMDM3LjI0LS42Mi41Ni0xLjE4IDEtMS42OC40Ni0uNTIgMS4wMS0uOTUgMS42My0xLjI2LjY2LS4zNCAxLjI5LS41MiAxLjg5LS41NS4wOC42OCAwIDEuMzUtLjI1IDIuMDctLjIyOC42NC0uNTY4IDEuMjMtMSAxLjc2LS40MzUuNTItLjk3NS45NS0xLjU4NiAxLjI2eiIvPjwvc3ZnPg==\" y=\"3\"/> <text fill=\"#010101\" fill-opacity=\".3\" textLength=\"230\" transform=\"scale(.1)\" x=\"345\" y=\"150\">mac</text><text textLength=\"230\" transform=\"scale(.1)\" x=\"345\" y=\"140\">mac</text><text fill=\"#010101\" fill-opacity=\".3\" textLength=\"970\" transform=\"scale(.1)\" x=\"1025\" y=\"150\">mojave | catalina</text><text textLength=\"970\" transform=\"scale(.1)\" x=\"1025\" y=\"140\">mojave | catalina</text></g> </svg>"
],
"text/plain": [
"<IPython.core.display.SVG object>"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# But this will:\n",
"SVG(bc.raw.value)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment