Skip to content

Commit

Permalink
👌 IMPROVE: Make octicon's size variable (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisjsewell authored Jul 29, 2021
1 parent 694848d commit 7c8c266
Show file tree
Hide file tree
Showing 16 changed files with 114 additions and 88 deletions.
28 changes: 13 additions & 15 deletions docs/badges_buttons.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Badges, Buttons & Icons
# Badges, Buttons & Icons {octicon}`rocket`

(badges)=

Expand Down Expand Up @@ -152,29 +152,27 @@ class

Inline icon roles are available for both the [GitHub octicon](https://octicons-git-v2.primer.now.sh/octicons/) or [FontAwesome](https://fontawesome.com/icons?d=gallery&m=free) libraries.

Octicon icons are added as SVG's directly into the page, for either 16px (`octicon-16`) or 24px (`octicon-24`) sizes.
Additional CSS classes can be added to the SVG after a semi-colon (`;`) delimiter.
Octicon icons are added as SVG's directly into the page with the `octicon` role.

A coloured icon: {octicon-16}`report;sd-text-info`, some more text.
By default the icon will be of height `1em` (i.e. the height of the font).
A specific height can be set after a semi-colon (`;`) with units of either `px`, `em` or `rem`.
Additional CSS classes can also be added to the SVG after a second semi-colon (`;`) delimiter.

A coloured icon: {octicon}`report;1em;sd-text-info`, some more text.

````{tab-set-code}
```markdown
A coloured icon: {octicon-16}`report;sd-text-info`, some more text.
```{literalinclude} ./snippets/myst/icon-octicon.txt
:language: markdown
```
```rst
A coloured icon: :octicon-16:`report;sd-text-info`, some more text.
```{literalinclude} ./snippets/rst/icon-octicon.txt
:language: rst
```
````

````{dropdown} All Octicons (16px)
```{_all-octicon}
:size: 16
```
````
````{dropdown} All Octicons
:open:
````{dropdown} All Octicons (24px)
```{_all-octicon}
:size: 24
```
````

Expand Down
2 changes: 2 additions & 0 deletions docs/cards.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ Content
Content
:::

(cards:options)=

## `card` options

width
Expand Down
19 changes: 19 additions & 0 deletions docs/grids.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,22 @@ text-align

class
: Additional CSS classes for the grid item element.

## `grid-item-card` options

columns
: The number of columns (out of 12) a grid-item will take up.
One or four integers (for "xs sm md lg") between 1 and 12 (or `auto` to adapt to the content).

margin
: Outer margin of grid item.
One (all) or four (top bottom left right) values from: 0, 1, 2, 3, 4, 5, auto.

padding
: Inner padding of grid item.
One (all) or four (top bottom left right) values from: 0, 1, 2, 3, 4, 5.

class-item
: Additional CSS classes for the grid item element.

Plus all options from [](cards:options).
12 changes: 6 additions & 6 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,42 +57,42 @@ furo <https://sphinx-design.readthedocs.io/en/furo-theme>
:margin: 4 4 0 0
:gutter: 1

:::{grid-item-card} {octicon-16}`table` Grids
:::{grid-item-card} {octicon}`table` Grids
:link: grids
:link-type: doc

Screen size adaptable grid layouts.
:::

:::{grid-item-card} {octicon-16}`note` Cards
:::{grid-item-card} {octicon}`note` Cards
:link: cards
:link-type: doc

Flexible and extensible content containers.
:::

:::{grid-item-card} {octicon-16}`chevron-down` Dropdowns
:::{grid-item-card} {octicon}`chevron-down` Dropdowns
:link: dropdowns
:link-type: doc

Hide content in expandable containers.
:::

:::{grid-item-card} {octicon-16}`duplicate` Tabs
:::{grid-item-card} {octicon}`duplicate` Tabs
:link: tabs
:link-type: doc

Synchronisable, tabbed content sets.
:::

:::{grid-item-card} {octicon-16}`plus-circle` Badges, Buttons & Icons
:::{grid-item-card} {octicon}`plus-circle` Badges, Buttons & Icons
:link: badges_buttons
:link-type: doc

Roles and directives for {bdg-primary}`badges` and other components.
:::

:::{grid-item-card} {octicon-16}`image` CSS Styling
:::{grid-item-card} {octicon}`image` CSS Styling
:link: css_variables
:link-type: doc

Expand Down
2 changes: 1 addition & 1 deletion docs/snippets/myst/icon-octicon.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
A coloured icon: {octicon-16}`report;sd-text-info`, some more text.
A coloured icon: {octicon}`report;1em;sd-text-info`, some more text.
2 changes: 1 addition & 1 deletion docs/snippets/rst/icon-octicon.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
A coloured icon: :octicon-16:`report;sd-text-info`, some more text.
A coloured icon: :octicon:`report;1em;sd-text-info`, some more text.
4 changes: 2 additions & 2 deletions sphinx_design/article_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def run(self) -> List[nodes.Node]:
self.set_source_info(date_column)
date_icon = nodes.raw(
"",
nodes.Text(get_octicon("calendar", size=16)),
nodes.Text(get_octicon("calendar", height="16px")),
classes=["sd-pr-2"],
format="html",
)
Expand All @@ -171,7 +171,7 @@ def run(self) -> List[nodes.Node]:
self.set_source_info(read_time_column)
read_time_icon = nodes.raw(
"",
nodes.Text(get_octicon("clock", size=16)),
nodes.Text(get_octicon("clock", height="16px")),
classes=["sd-pr-2"],
format="html",
)
Expand Down
2 changes: 1 addition & 1 deletion sphinx_design/compiled/style.min.css

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions sphinx_design/dropdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def run(self):


# Note the custom octicon here has thicker dots than:
# get_octicon("kebab-horizontal", classes="no-title", size=24)
# get_octicon("kebab-horizontal", classes=["no-title"])
KEBAB = """\
<svg viewBox="0 0 36 24" width="36" height="16" xmlns="http://www.w3.org/2000/svg"
class="octicon no-title" aria-hidden="true">
Expand Down Expand Up @@ -165,7 +165,7 @@ def run(self):
children=[
nodes.raw(
"",
nodes.Text(get_octicon("chevron-up", size=24)),
nodes.Text(get_octicon("chevron-up", height="24px")),
format="html",
)
],
Expand All @@ -176,7 +176,7 @@ def run(self):
children=[
nodes.raw(
"",
nodes.Text(get_octicon("chevron-down", size=24)),
nodes.Text(get_octicon("chevron-down", height="24px")),
format="html",
)
],
Expand Down Expand Up @@ -206,7 +206,7 @@ def run(self):
0,
nodes.raw(
"",
nodes.Text(get_octicon(node["icon"], size=16)),
nodes.Text(get_octicon(node["icon"], height="1em")),
classes=["sd-summary-icon"],
format="html",
),
Expand Down
93 changes: 48 additions & 45 deletions sphinx_design/icons.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json
import re
from functools import lru_cache
from typing import Any, Dict, List, Optional, Tuple, Union
from typing import Any, Dict, List, Optional, Sequence, Tuple

try:
import importlib.resources as resources
Expand All @@ -14,7 +15,6 @@
from sphinx.util.docutils import SphinxDirective, SphinxRole

from . import compiled
from .shared import make_choice

OCTICON_VERSION = "0.0.0-dd899ea"

Expand All @@ -27,8 +27,7 @@


def setup_icons(app: Sphinx) -> None:
app.add_role("octicon-16", OcticonRole(16))
app.add_role("octicon-24", OcticonRole(24))
app.add_role("octicon", OcticonRole())
app.add_directive("_all-octicon", AllOcticons)
for style in ["fa", "fas", "fab"]:
# note: fa is deprecated in v5, fas is the default and fab is the other free option
Expand All @@ -52,50 +51,57 @@ def get_octicon_data() -> Dict[str, Any]:
return json.loads(content)


def list_octicons(size: int = 16) -> List[str]:
def list_octicons() -> List[str]:
"""List available octicon names."""
return [
key
for key, data in get_octicon_data().items()
if str(size) in data.get("heights", [])
]
return list(get_octicon_data().keys())


HEIGHT_REGEX = re.compile(r"^(?P<value>\d+)(?P<unit>px|em|rem)$")


def get_octicon(
name: str,
classes: Optional[str] = None,
width: Optional[Union[int, float]] = None,
height: Optional[Union[int, float]] = None,
height: str = "1em",
classes: Sequence[str] = (),
aria_label: Optional[str] = None,
size: int = 16,
) -> str:
"""Return the HTML for an GitHub octicon SVG icon."""
assert size in [16, 24], "size must be 16 or 24"
"""Return the HTML for an GitHub octicon SVG icon.
:height: the height of the octicon, with suffix unit 'px', 'em' or 'rem'.
"""
try:
data = get_octicon_data()[name]
except KeyError:
raise KeyError(f"Unrecognised octicon: {name}")

content = data["heights"][str(size)]["path"]
match = HEIGHT_REGEX.match(height)
if not match:
raise ValueError(
f"Invalid height: '{height}', must be format <integer><px|em|rem>"
)
height_value = int(match.group("value"))
height_unit = match.group("unit")

original_height = 16
if "16" not in data["heights"]:
original_height = int(list(data["heights"].keys())[0])
elif "24" in data["heights"]:
if height_unit == "px":
if height_value >= 24:
original_height = 24
elif height_value >= 1.5:
original_height = 24
original_width = data["heights"][str(original_height)]["width"]
width_value = round(original_width * height_value / original_height, 2)
content = data["heights"][str(original_height)]["path"]
options = {
"version": "1.1",
"width": data["heights"][str(size)]["width"],
"height": int(size),
"class": f"sd-octicon sd-octicon-{name}",
"width": f"{width_value}{height_unit}",
"height": f"{height_value}{height_unit}",
"class": " ".join(("sd-octicon", f"sd-octicon-{name}", *classes)),
}

if width is not None or height is not None:
if width is None and height is not None:
width = round((int(height) * options["width"]) / options["height"], 2)
if height is None and width is not None:
height = round((int(width) * options["height"]) / options["width"], 2)
options["width"] = width
options["height"] = height

options["viewBox"] = f'0 0 {options["width"]} {options["height"]}'

if classes is not None:
options["class"] += " " + classes.strip()
options["viewBox"] = f"0 0 {original_width} {original_height}"

if aria_label is not None:
options["aria-label"] = aria_label
Expand All @@ -113,19 +119,18 @@ class OcticonRole(SphinxRole):
Additional classes can be added to the element after a semicolon.
"""

def __init__(self, size: int) -> None:
super().__init__()
self.size = size

def run(self) -> Tuple[List[nodes.Node], List[nodes.system_message]]:
"""Run the role."""
icon, classes = self.text.split(";", 1) if ";" in self.text else [self.text, ""]
values = self.text.split(";") if ";" in self.text else [self.text]
icon = values[0]
height = "1em" if len(values) < 2 else values[1]
classes = "" if len(values) < 3 else values[2]
icon = icon.strip()
try:
svg = get_octicon(icon, size=self.size, classes=classes)
except KeyError:
svg = get_octicon(icon, height=height, classes=classes.split())
except Exception as exc:
msg = self.inliner.reporter.error(
f"Unknown octicon name: {icon}",
f"Invalid octicon content: {exc}",
line=self.lineno,
)
prb = self.inliner.problematic(self.rawtext, self.rawtext, msg)
Expand All @@ -142,24 +147,22 @@ class AllOcticons(SphinxDirective):
"""

option_spec = {
"size": make_choice(["16", "24"]),
"class": directives.class_option,
}

def run(self) -> List[nodes.Node]:
"""Run the directive."""
size = int(self.options.get("size", "16"))
classes = " ".join(self.options.get("class", []))
classes = self.options.get("class", [])
list_node = nodes.bullet_list()
for icon in list_octicons(size):
for icon in list_octicons():
item_node = nodes.list_item()
item_node.extend(
(
nodes.literal(icon, icon),
nodes.Text(": "),
nodes.raw(
"",
nodes.Text(get_octicon(icon, size=size, classes=classes)),
nodes.Text(get_octicon(icon, classes=classes)),
format="html",
),
)
Expand Down
6 changes: 5 additions & 1 deletion style/_dropdown.scss
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ details.sd-dropdown {
}

.sd-summary-icon {
margin-right: 0.5rem;
margin-right: 0.5em;
}

.sd-summary-icon svg {
Expand Down Expand Up @@ -107,6 +107,10 @@ details.sd-dropdown {
width: 100%;
}

.sd-summary-content > .sd-tab-set:first-child {
margin-top: 0;
}

@keyframes sd-fade-in {
0% {
opacity: 0;
Expand Down
4 changes: 2 additions & 2 deletions tests/test_snippets/snippet_post_article-info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
<container classes="sd-col sd-col-auto sd-d-flex sd-align-items-center" design_component="grid-item" is_div="True">
<paragraph classes="sd-p-0 sd-m-0">
<raw classes="sd-pr-2" format="html" xml:space="preserve">
<svg version="1.1" width="16" height="16" class="sd-octicon sd-octicon-calendar" viewBox="0 0 16 16" aria-hidden="true"><path fill-rule="evenodd" d="M4.75 0a.75.75 0 01.75.75V2h5V.75a.75.75 0 011.5 0V2h1.25c.966 0 1.75.784 1.75 1.75v10.5A1.75 1.75 0 0113.25 16H2.75A1.75 1.75 0 011 14.25V3.75C1 2.784 1.784 2 2.75 2H4V.75A.75.75 0 014.75 0zm0 3.5h8.5a.25.25 0 01.25.25V6h-11V3.75a.25.25 0 01.25-.25h2zm-2.25 4v6.75c0 .138.112.25.25.25h10.5a.25.25 0 00.25-.25V7.5h-11z"></path></svg>
<svg version="1.1" width="16.0px" height="16px" class="sd-octicon sd-octicon-calendar" viewBox="0 0 16 16" aria-hidden="true"><path fill-rule="evenodd" d="M4.75 0a.75.75 0 01.75.75V2h5V.75a.75.75 0 011.5 0V2h1.25c.966 0 1.75.784 1.75 1.75v10.5A1.75 1.75 0 0113.25 16H2.75A1.75 1.75 0 011 14.25V3.75C1 2.784 1.784 2 2.75 2H4V.75A.75.75 0 014.75 0zm0 3.5h8.5a.25.25 0 01.25.25V6h-11V3.75a.25.25 0 01.25-.25h2zm-2.25 4v6.75c0 .138.112.25.25.25h10.5a.25.25 0 00.25-.25V7.5h-11z"></path></svg>
Jul 24, 2021
<container classes="sd-col sd-col-auto sd-d-flex sd-align-items-center" design_component="grid-item" is_div="True">
<paragraph classes="sd-p-0 sd-m-0">
<raw classes="sd-pr-2" format="html" xml:space="preserve">
<svg version="1.1" width="16" height="16" class="sd-octicon sd-octicon-clock" viewBox="0 0 16 16" aria-hidden="true"><path fill-rule="evenodd" d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.5 4.75a.75.75 0 00-1.5 0v3.5a.75.75 0 00.471.696l2.5 1a.75.75 0 00.557-1.392L8.5 7.742V4.75z"></path></svg>
<svg version="1.1" width="16.0px" height="16px" class="sd-octicon sd-octicon-clock" viewBox="0 0 16 16" aria-hidden="true"><path fill-rule="evenodd" d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.5 4.75a.75.75 0 00-1.5 0v3.5a.75.75 0 00.471.696l2.5 1a.75.75 0 00.557-1.392L8.5 7.742V4.75z"></path></svg>
5 min read
Loading

0 comments on commit 7c8c266

Please sign in to comment.