markdown-badges 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- markdown_badges-1.0.0/.gitignore +6 -0
- markdown_badges-1.0.0/CHANGELOG.md +49 -0
- markdown_badges-1.0.0/LICENSE +21 -0
- markdown_badges-1.0.0/MIGRATING.md +55 -0
- markdown_badges-1.0.0/PKG-INFO +207 -0
- markdown_badges-1.0.0/README.md +176 -0
- markdown_badges-1.0.0/docs/badges.md +62 -0
- markdown_badges-1.0.0/docs/img/catalogue.png +0 -0
- markdown_badges-1.0.0/docs/img/inline-badges.png +0 -0
- markdown_badges-1.0.0/docs/img/showcase.png +0 -0
- markdown_badges-1.0.0/docs/img/todo-badges.png +0 -0
- markdown_badges-1.0.0/pyproject.toml +71 -0
- markdown_badges-1.0.0/src/markdown_badges/__init__.py +161 -0
- markdown_badges-1.0.0/src/markdown_badges/catalogue.py +163 -0
- markdown_badges-1.0.0/src/markdown_badges/parsing.py +132 -0
- markdown_badges-1.0.0/src/markdown_badges/py.typed +0 -0
- markdown_badges-1.0.0/src/markdown_badges/styling.py +94 -0
- markdown_badges-1.0.0/tests/test_catalogue.py +69 -0
- markdown_badges-1.0.0/tests/test_extension.py +122 -0
- markdown_badges-1.0.0/tests/test_rendering.py +86 -0
- markdown_badges-1.0.0/tests/test_scanning.py +83 -0
- markdown_badges-1.0.0/tests/test_shorthand.py +67 -0
- markdown_badges-1.0.0/tests/test_shorthand_re.py +44 -0
- markdown_badges-1.0.0/tests/test_styling.py +56 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0 - 2026-09-08
|
|
4
|
+
|
|
5
|
+
Renamed from `markdown-priority-badges`. Breaking release: see [MIGRATING.md](MIGRATING.md).
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- A 20-badge catalogue ships in the package and is active with no config: 6 priority, 9 status, 5 branding. `catalogue` narrows which types load, `[]` disables it.
|
|
10
|
+
- `shorthand` maps any task-list marker to any badge, so anyone can invent their own markers.
|
|
11
|
+
- Extended badge values: anything after a `;` in a value becomes a further CSS declaration, so a badge can carry an icon, a gradient or a shadow with no site CSS.
|
|
12
|
+
- `badges_in(text)` returns every badge on a line, of any type, in document order.
|
|
13
|
+
- Public API: `Badge`, `BadgeType`, `CATALOGUE`, `catalogue_for`, `resolve_badges`, `badges_in`, `priority_of`, `rank_of`.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Import path and config key are now `markdown_badges`; the CSS class prefix is `badge` instead of `task-prio`.
|
|
18
|
+
- Badges are declared under `badges`, keyed by type (`priority`, `status`, `branding`), replacing the flat `levels` map.
|
|
19
|
+
- `priority_of` and `rank_of` consider only `priority` badges, so a status or branding badge can no longer be reported as a severity.
|
|
20
|
+
- The scanning API takes a `Mapping[str, Badge]` rather than a sequence of level names.
|
|
21
|
+
|
|
22
|
+
### Removed
|
|
23
|
+
|
|
24
|
+
- The `levels` option. A leftover `levels` key raises a `ValueError` pointing at the migration guide.
|
|
25
|
+
- The built-in `!` / `!!` task-list shorthand. Three lines of `shorthand` config restore it.
|
|
26
|
+
- `LEVELS`, `DEFAULT_LEVELS`, `level_rank`, `MARKER_RE`, `PriorityBadgesExtension`, `PriorityInlineProcessor`, `TasklistShorthandTreeprocessor`.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- A backslash-escaped keyword (`\!high`) renders as literal text instead of a badge with a stray backslash.
|
|
31
|
+
- The text-contrast calculation reads a badge value up to its first `;`, so a value carrying extra declarations contrasts against its real background instead of falling back to white text.
|
|
32
|
+
- Every invalid config raises a `ValueError` naming the offending key and the fix, instead of failing silently or with an `AttributeError`.
|
|
33
|
+
- README links are absolute, so they resolve on the PyPI project page.
|
|
34
|
+
|
|
35
|
+
## 0.2.0 - 2026-07-01
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- Public parsing API: `LEVELS`, `level_rank(level, levels=LEVELS)`, and `priority_of(text, levels=LEVELS)` for tools that aggregate or filter task items by priority.
|
|
40
|
+
|
|
41
|
+
## 0.1.0 - 2026-07-01
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
|
|
45
|
+
- Inline keywords: `!low` / `!medium` / `!high` / `!critical` (and any custom level) render a badge anywhere in prose, headings, or table cells. Only configured level keywords match, so an ordinary `!` in text is untouched.
|
|
46
|
+
- Task-list shorthand: a leading `!` (high) / `!!` (critical) after a checkbox renders a priority badge, via a Treeprocessor running just before `pymdownx.tasklist`.
|
|
47
|
+
- Configurable `levels` map (name -> color), merged over the built-in `low` / `medium` / `high` / `critical`, so levels can be recolored or added from config.
|
|
48
|
+
- Self-contained styling: badges ship inline styles (no external CSS), with the text color auto-contrasted (black or white) against each background.
|
|
49
|
+
- Colors accept 3- or 6-digit hex and common CSS names.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Antoine Keranflec'h
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Migrating from markdown-priority-badges 0.2.0 to markdown-badges 1.0
|
|
2
|
+
|
|
3
|
+
## Install
|
|
4
|
+
|
|
5
|
+
Replace the dependency. The old project stays on PyPI at 0.2.0 and receives no further releases.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
uv remove markdown-priority-badges && uv add markdown-badges
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Config
|
|
12
|
+
|
|
13
|
+
The extension key changes, `levels` becomes `badges.priority`, and the catalogue is active by default.
|
|
14
|
+
|
|
15
|
+
```toml
|
|
16
|
+
# before
|
|
17
|
+
[project.markdown_extensions.markdown_priority_badges.levels]
|
|
18
|
+
blocker = "#7b1fa2"
|
|
19
|
+
|
|
20
|
+
# after
|
|
21
|
+
[project.markdown_extensions.markdown_badges.badges.priority]
|
|
22
|
+
blocker = "#7b1fa2"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Leaving a `levels` key in place raises a `ValueError` naming this file, rather than being silently ignored.
|
|
26
|
+
|
|
27
|
+
## Restoring the `!` / `!!` shorthand
|
|
28
|
+
|
|
29
|
+
It is no longer built in. Three lines bring it back, and you can pick different markers.
|
|
30
|
+
|
|
31
|
+
```toml
|
|
32
|
+
[project.markdown_extensions.markdown_badges.shorthand]
|
|
33
|
+
"!" = "high"
|
|
34
|
+
"!!" = "critical"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## API
|
|
38
|
+
|
|
39
|
+
| 0.2.0 | 1.0 |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| `from markdown_priority_badges import ...` | `from markdown_badges import ...` |
|
|
42
|
+
| `LEVELS` | `catalogue_for(BadgeType.PRIORITY)` |
|
|
43
|
+
| `DEFAULT_LEVELS` | `CATALOGUE` |
|
|
44
|
+
| `level_rank(name, levels)` | `rank_of(name, badges)` |
|
|
45
|
+
| `priority_of(text, levels)` | `priority_of(text, badges)` |
|
|
46
|
+
| `PriorityBadgesExtension` | `MarkdownBadgesExtension` |
|
|
47
|
+
| no equivalent | `badges_in(text, badges)` for every badge type |
|
|
48
|
+
|
|
49
|
+
The second argument changes from a sequence of names to a `Mapping[str, Badge]`, which is what `catalogue_for` returns.
|
|
50
|
+
|
|
51
|
+
`priority_of` now considers only `priority` badges, and no longer looks at a leading `!` / `!!`, because that shorthand is no longer built in.
|
|
52
|
+
|
|
53
|
+
## CSS classes
|
|
54
|
+
|
|
55
|
+
The class prefix changes from `task-prio` to `badge`: `class="badge badge--high"`. Update any site CSS that targeted `.task-prio`.
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: markdown-badges
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python-Markdown extension rendering inline !name badges, with a catalogue of priority, status and branding badges
|
|
5
|
+
Project-URL: Homepage, https://github.com/antoinekh/markdown-priority-badges
|
|
6
|
+
Project-URL: Repository, https://github.com/antoinekh/markdown-priority-badges
|
|
7
|
+
Project-URL: Issues, https://github.com/antoinekh/markdown-priority-badges/issues
|
|
8
|
+
Project-URL: Documentation, https://github.com/antoinekh/markdown-priority-badges/blob/master/docs/badges.md
|
|
9
|
+
Project-URL: Changelog, https://github.com/antoinekh/markdown-priority-badges/blob/master/CHANGELOG.md
|
|
10
|
+
Author: Antoine Keranflec'h
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: badge,badges,branding,catalogue,documentation,markdown,mkdocs,priority,status,tasklist,zensical
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
+
Classifier: Framework :: MkDocs
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Topic :: Documentation
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
|
+
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
27
|
+
Classifier: Typing :: Typed
|
|
28
|
+
Requires-Python: >=3.10
|
|
29
|
+
Requires-Dist: markdown>=3.5
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# markdown-badges
|
|
33
|
+
|
|
34
|
+
[](https://github.com/antoinekh/markdown-priority-badges/actions/workflows/ci.yml)
|
|
35
|
+
[](https://pypi.org/project/markdown-badges/)
|
|
36
|
+
[](https://pypi.org/project/markdown-badges/)
|
|
37
|
+
[](https://github.com/antoinekh/markdown-priority-badges/blob/master/LICENSE)
|
|
38
|
+
|
|
39
|
+
A Python-Markdown extension that renders small inline **badges** from a `!name` keyword: priority, status, or brand. Works in Zensical, MkDocs, or plain Python-Markdown. The badge ships its own inline styles, so no external CSS is required.
|
|
40
|
+
|
|
41
|
+
## Why?
|
|
42
|
+
|
|
43
|
+
This is not a replacement for admonitions / callouts (`!!! warning`, `> [!NOTE]`). Those wrap a block of explanatory text. Badges are the opposite: tiny inline pills you can drop anywhere, but that fit especially nicely into a **list item, todo, or table cell**, so status or severity is scannable at a glance without turning the line into a block. The intended usage is exactly that split: reach for a callout when you have a paragraph to say, and reach for a badge to mark some rows.
|
|
44
|
+
|
|
45
|
+
## Badges
|
|
46
|
+
|
|
47
|
+
Write `!name` anywhere (prose, headings, table cells, list items) and it renders as a small inline pill:
|
|
48
|
+
|
|
49
|
+
```markdown
|
|
50
|
+
This migration is !critical and blocks the release.
|
|
51
|
+
|
|
52
|
+
## !high Rotate the keys
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+

|
|
56
|
+
|
|
57
|
+
Only a name in scope matches, so an ordinary `!`, `!important`, or `!highest` in text is never touched. To write a name literally, escape it (`\!high`) or put it in a code span (`` `!high` ``).
|
|
58
|
+
|
|
59
|
+
## Badge types
|
|
60
|
+
|
|
61
|
+
Every badge belongs to one of three types.
|
|
62
|
+
|
|
63
|
+
| Type | Meaning | Examples |
|
|
64
|
+
| --- | --- | --- |
|
|
65
|
+
| `priority` | Carries a severity rank, from least to most severe. Only this type is considered by `priority_of` and `rank_of`. | `!trivial` `!low` `!medium` `!high` `!critical` `!blocker` |
|
|
66
|
+
| `status` | Says where an item sits in a workflow. No rank. | `!todo` `!wip` `!review` `!blocked` `!approved` `!done` `!onhold` `!experimental` `!deprecated` |
|
|
67
|
+
| `branding` | A brand mark. Most carry a logo inlined as a `data:` URI, so a page makes no network request for it; `aws` is a plain colour with no logo, because no CC0 AWS mark exists and the badge text already reads AWS. | `!gitlab` `!github` `!claude` `!docker` `!aws` |
|
|
68
|
+
|
|
69
|
+
## Catalogue
|
|
70
|
+
|
|
71
|
+
Every badge above ships with the package and is active out of the box, no config required.
|
|
72
|
+
|
|
73
|
+

|
|
74
|
+
|
|
75
|
+
Full list with keyword, value, and resolved text colour: **[docs/badges.md](https://github.com/antoinekh/markdown-priority-badges/blob/master/docs/badges.md)**.
|
|
76
|
+
|
|
77
|
+
## Narrowing the catalogue
|
|
78
|
+
|
|
79
|
+
The `catalogue` option is a list of type names, defaulting to all three (`priority`, `status`, `branding`). Pass a subset to load fewer of them, or `[]` to disable the catalogue entirely.
|
|
80
|
+
|
|
81
|
+
```toml
|
|
82
|
+
# zensical.toml
|
|
83
|
+
[project.markdown_extensions.markdown_badges]
|
|
84
|
+
catalogue = ["priority", "status"] # drop the branding badges
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
# plain Python-Markdown
|
|
89
|
+
from markdown_badges import MarkdownBadgesExtension
|
|
90
|
+
markdown.markdown(text, extensions=[MarkdownBadgesExtension(catalogue=["priority", "status"])])
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Adding and recolouring badges
|
|
94
|
+
|
|
95
|
+
The `badges` option is a mapping of type name to a name -> value map, merged over the catalogue: an existing name is recoloured in place, keeping its position and its type, and a new name is inserted after the last badge of its own type, so a new priority outranks every catalogue priority.
|
|
96
|
+
|
|
97
|
+
```toml
|
|
98
|
+
[project.markdown_extensions.markdown_badges.badges.priority]
|
|
99
|
+
showstopper = "#000000" # a new priority, ranked above every catalogue one
|
|
100
|
+
critical = "#8e0000" # an existing name: recolours it, keeping its rank
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from markdown_badges import MarkdownBadgesExtension
|
|
105
|
+
markdown.markdown(text, extensions=[MarkdownBadgesExtension(badges={"priority": {"blocker": "#7b1fa2"}})])
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Colors may be 3-, 4-, 6-, or 8-digit hex (`#7b1fa2`, `#eee`, `#eeeeeeff`) or a common CSS name (`red`, `yellow`, `rebeccapurple`); the badge text color auto-contrasts against them. Any alpha channel is ignored for the contrast calculation.
|
|
109
|
+
|
|
110
|
+
## Extended values
|
|
111
|
+
|
|
112
|
+
A badge value becomes the badge's `background-color`, so anything after a `;` becomes a further declaration on that badge. Use it to give a badge an icon, a gradient, or a shadow, with no site CSS:
|
|
113
|
+
|
|
114
|
+
```toml
|
|
115
|
+
[project.markdown_extensions.markdown_badges.badges.status]
|
|
116
|
+
# A background image, plus the padding that makes room for it.
|
|
117
|
+
icon = "#b71c1c;background-image:url('data:image/svg+xml,…');background-repeat:no-repeat;background-position:0.4em center;background-size:0.85em;padding-left:1.7em"
|
|
118
|
+
# A gradient instead of a flat fill.
|
|
119
|
+
gradient = "#4a148c;background-image:linear-gradient(90deg,#4a148c,#c2185b)"
|
|
120
|
+
# A colored ring and halo.
|
|
121
|
+
glow = "#111;box-shadow:0 0 0 2px #ff1744,0 0 10px #ff1744"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The contrast calculation reads the leading colour, up to the first `;`, so the badge text stays legible against the base you picked.
|
|
125
|
+
|
|
126
|
+
### Custom logo badges
|
|
127
|
+
|
|
128
|
+
Inline a single-path logo as a `data:` URI and you get a brand badge that costs no network request. Pick the base colour and the logo fill together: the badge text colour is chosen from the base, so a white mark needs a base dark enough to resolve to white text, and a dark mark needs a light one.
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
import urllib.parse
|
|
132
|
+
|
|
133
|
+
svg = "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='#fff'><path d='M0 0h24v24H0z'/></svg>"
|
|
134
|
+
uri = "data:image/svg+xml," + urllib.parse.quote(svg, safe="")
|
|
135
|
+
value = f"#0052cc;background-image:url('{uri}');background-repeat:no-repeat;background-position:0.45em center;background-size:0.8em;padding-left:1.75em"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Put the resulting `value` under `badges.branding` (or any type) with the name you want the keyword to use, for example `badges={"branding": {"jira": value}}`. For the recipe used to build the shipped branding badges, including the SVG-encoding helper, see `_icon_value` in `src/markdown_badges/catalogue.py`.
|
|
139
|
+
|
|
140
|
+
## Task-list shorthand
|
|
141
|
+
|
|
142
|
+
Not built in by default. The `shorthand` option maps any task-list marker to any badge name, so you can pick your own markers, or restore the old `!` / `!!` behaviour:
|
|
143
|
+
|
|
144
|
+
```toml
|
|
145
|
+
[project.markdown_extensions.markdown_badges.shorthand]
|
|
146
|
+
"!" = "high"
|
|
147
|
+
"!!" = "critical"
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
```markdown
|
|
151
|
+
- [ ] !blocker Waiting on vendor API access
|
|
152
|
+
- [ ] !! Ship the security patch today
|
|
153
|
+
- [ ] ! Review the migration PR
|
|
154
|
+
- [ ] !medium Update the runbook
|
|
155
|
+
- [ ] !low Tidy up log formatting
|
|
156
|
+
- [x] !! Rotate the leaked credentials
|
|
157
|
+
- [ ] Weekly backup check
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
<img alt="Todo list with badges" src="https://raw.githubusercontent.com/antoinekh/markdown-priority-badges/master/docs/img/todo-badges.png" width="560">
|
|
161
|
+
|
|
162
|
+
The marker must come right after the checkbox and be followed by a space, so `- [ ] !important note` is left untouched. Works with `-`, `*`, `+` bullets and both `[ ]` / `[x]` states. Requires `pymdownx.tasklist` to be enabled alongside this extension.
|
|
163
|
+
|
|
164
|
+
## Reusing the parser
|
|
165
|
+
|
|
166
|
+
`badges_in`, `priority_of`, and `rank_of` are exposed for tools that aggregate or filter task items (for example a todo dashboard). Each takes an optional `Mapping[str, Badge]` argument, defaulting to the whole catalogue; pass the result of `resolve_badges` or `catalogue_for` to match your own config instead.
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
from markdown_badges import badges_in, priority_of, rank_of
|
|
170
|
+
|
|
171
|
+
badges_in("!blocker vendor waiting !wip") # -> [Badge(name="blocker", ...), Badge(name="wip", ...)]
|
|
172
|
+
priority_of("ping !high vendor") # -> "high"
|
|
173
|
+
priority_of("weekly backup") # -> None (no priority badge)
|
|
174
|
+
rank_of("blocker") # -> 5 (severity index among priority badges)
|
|
175
|
+
rank_of("wip") # -> -1 (not a priority badge)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`badges_in` returns every badge found in the text, of any type, in document order. `priority_of` returns the name of the highest-ranked `priority` badge found, or `None`; `status` and `branding` badges are ignored. `rank_of` gives a badge's severity index among the priority badges, or `-1` if it has none.
|
|
179
|
+
|
|
180
|
+
> [!NOTE]
|
|
181
|
+
> These are plain-text scans, not a Markdown parse. Unlike the rendered badge, a keyword inside a code span or escaped as `\!high` still counts.
|
|
182
|
+
|
|
183
|
+
## Install & enable
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
uv add markdown-badges
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
(or `pip install markdown-badges`)
|
|
190
|
+
|
|
191
|
+
Zensical (`zensical.toml`):
|
|
192
|
+
|
|
193
|
+
```toml
|
|
194
|
+
[project.markdown_extensions.markdown_badges]
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Plain Python-Markdown:
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
markdown.markdown(text, extensions=["markdown_badges"])
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Add `pymdownx.tasklist` to `extensions` too if you enable the `shorthand` option. The badge renders as `<span class="badge badge--<name>" style="...">...</span>`. The `badge` classes are kept for optional site-side overriding, but no CSS is needed by default.
|
|
204
|
+
|
|
205
|
+
## Migrating from 0.2.0
|
|
206
|
+
|
|
207
|
+
The package was renamed from `markdown-priority-badges` to `markdown-badges`, and the config and API changed along with it: see **[MIGRATING.md](https://github.com/antoinekh/markdown-priority-badges/blob/master/MIGRATING.md)**.
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# markdown-badges
|
|
2
|
+
|
|
3
|
+
[](https://github.com/antoinekh/markdown-priority-badges/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/markdown-badges/)
|
|
5
|
+
[](https://pypi.org/project/markdown-badges/)
|
|
6
|
+
[](https://github.com/antoinekh/markdown-priority-badges/blob/master/LICENSE)
|
|
7
|
+
|
|
8
|
+
A Python-Markdown extension that renders small inline **badges** from a `!name` keyword: priority, status, or brand. Works in Zensical, MkDocs, or plain Python-Markdown. The badge ships its own inline styles, so no external CSS is required.
|
|
9
|
+
|
|
10
|
+
## Why?
|
|
11
|
+
|
|
12
|
+
This is not a replacement for admonitions / callouts (`!!! warning`, `> [!NOTE]`). Those wrap a block of explanatory text. Badges are the opposite: tiny inline pills you can drop anywhere, but that fit especially nicely into a **list item, todo, or table cell**, so status or severity is scannable at a glance without turning the line into a block. The intended usage is exactly that split: reach for a callout when you have a paragraph to say, and reach for a badge to mark some rows.
|
|
13
|
+
|
|
14
|
+
## Badges
|
|
15
|
+
|
|
16
|
+
Write `!name` anywhere (prose, headings, table cells, list items) and it renders as a small inline pill:
|
|
17
|
+
|
|
18
|
+
```markdown
|
|
19
|
+
This migration is !critical and blocks the release.
|
|
20
|
+
|
|
21
|
+
## !high Rotate the keys
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
Only a name in scope matches, so an ordinary `!`, `!important`, or `!highest` in text is never touched. To write a name literally, escape it (`\!high`) or put it in a code span (`` `!high` ``).
|
|
27
|
+
|
|
28
|
+
## Badge types
|
|
29
|
+
|
|
30
|
+
Every badge belongs to one of three types.
|
|
31
|
+
|
|
32
|
+
| Type | Meaning | Examples |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| `priority` | Carries a severity rank, from least to most severe. Only this type is considered by `priority_of` and `rank_of`. | `!trivial` `!low` `!medium` `!high` `!critical` `!blocker` |
|
|
35
|
+
| `status` | Says where an item sits in a workflow. No rank. | `!todo` `!wip` `!review` `!blocked` `!approved` `!done` `!onhold` `!experimental` `!deprecated` |
|
|
36
|
+
| `branding` | A brand mark. Most carry a logo inlined as a `data:` URI, so a page makes no network request for it; `aws` is a plain colour with no logo, because no CC0 AWS mark exists and the badge text already reads AWS. | `!gitlab` `!github` `!claude` `!docker` `!aws` |
|
|
37
|
+
|
|
38
|
+
## Catalogue
|
|
39
|
+
|
|
40
|
+
Every badge above ships with the package and is active out of the box, no config required.
|
|
41
|
+
|
|
42
|
+

|
|
43
|
+
|
|
44
|
+
Full list with keyword, value, and resolved text colour: **[docs/badges.md](https://github.com/antoinekh/markdown-priority-badges/blob/master/docs/badges.md)**.
|
|
45
|
+
|
|
46
|
+
## Narrowing the catalogue
|
|
47
|
+
|
|
48
|
+
The `catalogue` option is a list of type names, defaulting to all three (`priority`, `status`, `branding`). Pass a subset to load fewer of them, or `[]` to disable the catalogue entirely.
|
|
49
|
+
|
|
50
|
+
```toml
|
|
51
|
+
# zensical.toml
|
|
52
|
+
[project.markdown_extensions.markdown_badges]
|
|
53
|
+
catalogue = ["priority", "status"] # drop the branding badges
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
# plain Python-Markdown
|
|
58
|
+
from markdown_badges import MarkdownBadgesExtension
|
|
59
|
+
markdown.markdown(text, extensions=[MarkdownBadgesExtension(catalogue=["priority", "status"])])
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Adding and recolouring badges
|
|
63
|
+
|
|
64
|
+
The `badges` option is a mapping of type name to a name -> value map, merged over the catalogue: an existing name is recoloured in place, keeping its position and its type, and a new name is inserted after the last badge of its own type, so a new priority outranks every catalogue priority.
|
|
65
|
+
|
|
66
|
+
```toml
|
|
67
|
+
[project.markdown_extensions.markdown_badges.badges.priority]
|
|
68
|
+
showstopper = "#000000" # a new priority, ranked above every catalogue one
|
|
69
|
+
critical = "#8e0000" # an existing name: recolours it, keeping its rank
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from markdown_badges import MarkdownBadgesExtension
|
|
74
|
+
markdown.markdown(text, extensions=[MarkdownBadgesExtension(badges={"priority": {"blocker": "#7b1fa2"}})])
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Colors may be 3-, 4-, 6-, or 8-digit hex (`#7b1fa2`, `#eee`, `#eeeeeeff`) or a common CSS name (`red`, `yellow`, `rebeccapurple`); the badge text color auto-contrasts against them. Any alpha channel is ignored for the contrast calculation.
|
|
78
|
+
|
|
79
|
+
## Extended values
|
|
80
|
+
|
|
81
|
+
A badge value becomes the badge's `background-color`, so anything after a `;` becomes a further declaration on that badge. Use it to give a badge an icon, a gradient, or a shadow, with no site CSS:
|
|
82
|
+
|
|
83
|
+
```toml
|
|
84
|
+
[project.markdown_extensions.markdown_badges.badges.status]
|
|
85
|
+
# A background image, plus the padding that makes room for it.
|
|
86
|
+
icon = "#b71c1c;background-image:url('data:image/svg+xml,…');background-repeat:no-repeat;background-position:0.4em center;background-size:0.85em;padding-left:1.7em"
|
|
87
|
+
# A gradient instead of a flat fill.
|
|
88
|
+
gradient = "#4a148c;background-image:linear-gradient(90deg,#4a148c,#c2185b)"
|
|
89
|
+
# A colored ring and halo.
|
|
90
|
+
glow = "#111;box-shadow:0 0 0 2px #ff1744,0 0 10px #ff1744"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The contrast calculation reads the leading colour, up to the first `;`, so the badge text stays legible against the base you picked.
|
|
94
|
+
|
|
95
|
+
### Custom logo badges
|
|
96
|
+
|
|
97
|
+
Inline a single-path logo as a `data:` URI and you get a brand badge that costs no network request. Pick the base colour and the logo fill together: the badge text colour is chosen from the base, so a white mark needs a base dark enough to resolve to white text, and a dark mark needs a light one.
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
import urllib.parse
|
|
101
|
+
|
|
102
|
+
svg = "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='#fff'><path d='M0 0h24v24H0z'/></svg>"
|
|
103
|
+
uri = "data:image/svg+xml," + urllib.parse.quote(svg, safe="")
|
|
104
|
+
value = f"#0052cc;background-image:url('{uri}');background-repeat:no-repeat;background-position:0.45em center;background-size:0.8em;padding-left:1.75em"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Put the resulting `value` under `badges.branding` (or any type) with the name you want the keyword to use, for example `badges={"branding": {"jira": value}}`. For the recipe used to build the shipped branding badges, including the SVG-encoding helper, see `_icon_value` in `src/markdown_badges/catalogue.py`.
|
|
108
|
+
|
|
109
|
+
## Task-list shorthand
|
|
110
|
+
|
|
111
|
+
Not built in by default. The `shorthand` option maps any task-list marker to any badge name, so you can pick your own markers, or restore the old `!` / `!!` behaviour:
|
|
112
|
+
|
|
113
|
+
```toml
|
|
114
|
+
[project.markdown_extensions.markdown_badges.shorthand]
|
|
115
|
+
"!" = "high"
|
|
116
|
+
"!!" = "critical"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```markdown
|
|
120
|
+
- [ ] !blocker Waiting on vendor API access
|
|
121
|
+
- [ ] !! Ship the security patch today
|
|
122
|
+
- [ ] ! Review the migration PR
|
|
123
|
+
- [ ] !medium Update the runbook
|
|
124
|
+
- [ ] !low Tidy up log formatting
|
|
125
|
+
- [x] !! Rotate the leaked credentials
|
|
126
|
+
- [ ] Weekly backup check
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
<img alt="Todo list with badges" src="https://raw.githubusercontent.com/antoinekh/markdown-priority-badges/master/docs/img/todo-badges.png" width="560">
|
|
130
|
+
|
|
131
|
+
The marker must come right after the checkbox and be followed by a space, so `- [ ] !important note` is left untouched. Works with `-`, `*`, `+` bullets and both `[ ]` / `[x]` states. Requires `pymdownx.tasklist` to be enabled alongside this extension.
|
|
132
|
+
|
|
133
|
+
## Reusing the parser
|
|
134
|
+
|
|
135
|
+
`badges_in`, `priority_of`, and `rank_of` are exposed for tools that aggregate or filter task items (for example a todo dashboard). Each takes an optional `Mapping[str, Badge]` argument, defaulting to the whole catalogue; pass the result of `resolve_badges` or `catalogue_for` to match your own config instead.
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from markdown_badges import badges_in, priority_of, rank_of
|
|
139
|
+
|
|
140
|
+
badges_in("!blocker vendor waiting !wip") # -> [Badge(name="blocker", ...), Badge(name="wip", ...)]
|
|
141
|
+
priority_of("ping !high vendor") # -> "high"
|
|
142
|
+
priority_of("weekly backup") # -> None (no priority badge)
|
|
143
|
+
rank_of("blocker") # -> 5 (severity index among priority badges)
|
|
144
|
+
rank_of("wip") # -> -1 (not a priority badge)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`badges_in` returns every badge found in the text, of any type, in document order. `priority_of` returns the name of the highest-ranked `priority` badge found, or `None`; `status` and `branding` badges are ignored. `rank_of` gives a badge's severity index among the priority badges, or `-1` if it has none.
|
|
148
|
+
|
|
149
|
+
> [!NOTE]
|
|
150
|
+
> These are plain-text scans, not a Markdown parse. Unlike the rendered badge, a keyword inside a code span or escaped as `\!high` still counts.
|
|
151
|
+
|
|
152
|
+
## Install & enable
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
uv add markdown-badges
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
(or `pip install markdown-badges`)
|
|
159
|
+
|
|
160
|
+
Zensical (`zensical.toml`):
|
|
161
|
+
|
|
162
|
+
```toml
|
|
163
|
+
[project.markdown_extensions.markdown_badges]
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Plain Python-Markdown:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
markdown.markdown(text, extensions=["markdown_badges"])
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Add `pymdownx.tasklist` to `extensions` too if you enable the `shorthand` option. The badge renders as `<span class="badge badge--<name>" style="...">...</span>`. The `badge` classes are kept for optional site-side overriding, but no CSS is needed by default.
|
|
173
|
+
|
|
174
|
+
## Migrating from 0.2.0
|
|
175
|
+
|
|
176
|
+
The package was renamed from `markdown-priority-badges` to `markdown-badges`, and the config and API changed along with it: see **[MIGRATING.md](https://github.com/antoinekh/markdown-priority-badges/blob/master/MIGRATING.md)**.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Badge catalogue
|
|
2
|
+
|
|
3
|
+
Every badge below ships with the package and is active out of the box. Nothing here needs config. Use `catalogue` to narrow the set, and `badges` to recolour an entry or add your own.
|
|
4
|
+
|
|
5
|
+
Generated from `CATALOGUE` in `src/markdown_badges/catalogue.py` by `scripts/gen_badges.py`. Edit the catalogue, not this file.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
> [!NOTE]
|
|
10
|
+
> Only `priority` badges carry a severity rank. `priority_of` and `rank_of` ignore `status` and `branding` badges entirely; use `badges_in` to get every badge on a line whatever its type.
|
|
11
|
+
|
|
12
|
+
## Priority
|
|
13
|
+
|
|
14
|
+
| Keyword | Value | Text | Notes |
|
|
15
|
+
| --- | --- | --- | --- |
|
|
16
|
+
| `!trivial` | `#78909c` | `#000` | Nice to have. |
|
|
17
|
+
| `!low` | `#2e7d32` | `#fff` | Green. |
|
|
18
|
+
| `!medium` | `#f9a825` | `#000` | Amber. |
|
|
19
|
+
| `!high` | `#ef6c00` | `#000` | Orange. |
|
|
20
|
+
| `!critical` | `#d32f2f` | `#fff` | Red. |
|
|
21
|
+
| `!blocker` | `#7b1fa2` | `#fff` | Work that cannot start. |
|
|
22
|
+
|
|
23
|
+
## Status
|
|
24
|
+
|
|
25
|
+
| Keyword | Value | Text | Notes |
|
|
26
|
+
| --- | --- | --- | --- |
|
|
27
|
+
| `!todo` | `#1565c0` | `#fff` | Not started. |
|
|
28
|
+
| `!wip` | `#0277bd` | `#fff` | In progress. |
|
|
29
|
+
| `!review` | `#6a1b9a` | `#fff` | Waiting on a reviewer. |
|
|
30
|
+
| `!blocked` | `#b71c1c` | `#fff` | Waiting on someone else. |
|
|
31
|
+
| `!approved` | `#2e7d32` | `#fff` | Signed off, not yet shipped. |
|
|
32
|
+
| `!done` | `#37474f` | `#fff` | Finished. |
|
|
33
|
+
| `!onhold` | `#8d6e63` | `#fff` | Paused on purpose. |
|
|
34
|
+
| `!experimental` | `#00838f` | `#000` | Not stable yet. |
|
|
35
|
+
| `!deprecated` | `#5d4037` | `#fff` | On the way out. |
|
|
36
|
+
|
|
37
|
+
## Branding
|
|
38
|
+
|
|
39
|
+
| Keyword | Value | Text | Notes |
|
|
40
|
+
| --- | --- | --- | --- |
|
|
41
|
+
| `!gitlab` | `#7759c2 plus icon CSS` | `#fff` | GitLab purple. |
|
|
42
|
+
| `!github` | `#181717 plus icon CSS` | `#fff` | GitHub near-black. |
|
|
43
|
+
| `!claude` | `#d97757 plus icon CSS` | `#000` | Claude coral, dark mark. |
|
|
44
|
+
| `!docker` | `#1d63ed plus icon CSS` | `#fff` | Docker blue, white whale. |
|
|
45
|
+
| `!aws` | `#232f3e` | `#fff` | AWS squid ink. No mark. |
|
|
46
|
+
|
|
47
|
+
## Narrowing the catalogue
|
|
48
|
+
|
|
49
|
+
```toml
|
|
50
|
+
[project.markdown_extensions.markdown_badges]
|
|
51
|
+
catalogue = ["priority", "status"] # drop the branding badges
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Adding your own
|
|
55
|
+
|
|
56
|
+
```toml
|
|
57
|
+
[project.markdown_extensions.markdown_badges.badges.priority]
|
|
58
|
+
showstopper = "#000000" # a new priority, ranked above every catalogue one
|
|
59
|
+
critical = "#8e0000" # an existing name: recolours it, keeping its rank
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
For a logo badge, add the mark as a single-path SVG to `ICONS` in `src/markdown_badges/catalogue.py` and build the value with `_icon_value`. Pick the base colour and the icon fill together: the badge text colour comes from the base, so a white mark needs a base that resolves to white text.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "markdown-badges"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Python-Markdown extension rendering inline !name badges, with a catalogue of priority, status and branding badges"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
authors = [{ name = "Antoine Keranflec'h" }]
|
|
8
|
+
requires-python = ">=3.10"
|
|
9
|
+
dependencies = ["markdown>=3.5"]
|
|
10
|
+
keywords = ["markdown", "mkdocs", "zensical", "badge", "badges", "priority", "status", "branding", "catalogue", "tasklist", "documentation"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 5 - Production/Stable",
|
|
13
|
+
"Intended Audience :: Developers",
|
|
14
|
+
"Framework :: MkDocs",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
17
|
+
"Programming Language :: Python :: 3.10",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Programming Language :: Python :: 3.14",
|
|
22
|
+
"Topic :: Documentation",
|
|
23
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
24
|
+
"Topic :: Text Processing :: Markup :: Markdown",
|
|
25
|
+
"Typing :: Typed",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/antoinekh/markdown-priority-badges"
|
|
30
|
+
Repository = "https://github.com/antoinekh/markdown-priority-badges"
|
|
31
|
+
Issues = "https://github.com/antoinekh/markdown-priority-badges/issues"
|
|
32
|
+
Documentation = "https://github.com/antoinekh/markdown-priority-badges/blob/master/docs/badges.md"
|
|
33
|
+
Changelog = "https://github.com/antoinekh/markdown-priority-badges/blob/master/CHANGELOG.md"
|
|
34
|
+
|
|
35
|
+
[dependency-groups]
|
|
36
|
+
dev = ["pytest>=8.0", "pymdown-extensions>=10.0", "ruff>=0.8", "mypy>=1.11", "types-Markdown"]
|
|
37
|
+
|
|
38
|
+
[build-system]
|
|
39
|
+
requires = ["hatchling"]
|
|
40
|
+
build-backend = "hatchling.build"
|
|
41
|
+
|
|
42
|
+
[tool.hatch.build.targets.wheel]
|
|
43
|
+
packages = ["src/markdown_badges"]
|
|
44
|
+
|
|
45
|
+
[tool.hatch.build.targets.sdist]
|
|
46
|
+
include = [
|
|
47
|
+
"src/**",
|
|
48
|
+
"tests/**",
|
|
49
|
+
"README.md",
|
|
50
|
+
"LICENSE",
|
|
51
|
+
"CHANGELOG.md",
|
|
52
|
+
"MIGRATING.md",
|
|
53
|
+
"pyproject.toml",
|
|
54
|
+
"docs/img/*.png",
|
|
55
|
+
"docs/badges.md",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
testpaths = ["tests"]
|
|
60
|
+
|
|
61
|
+
[tool.ruff]
|
|
62
|
+
line-length = 100
|
|
63
|
+
|
|
64
|
+
[tool.ruff.lint]
|
|
65
|
+
select = ["E", "F", "I", "UP", "B"]
|
|
66
|
+
|
|
67
|
+
[tool.mypy]
|
|
68
|
+
# The package ships py.typed, so the shipped code is checked strictly.
|
|
69
|
+
files = ["src"]
|
|
70
|
+
python_version = "3.10"
|
|
71
|
+
strict = true
|