Last active
March 26, 2020 20:45
-
-
Save deeplook/20c7a64eda8fc77fe020f5c644466b27 to your computer and use it in GitHub Desktop.
Create custom SVG badges with shields.io
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"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