Skip to content

Commit

Permalink
Handle empty icon better, and add more documentation and examples.
Browse files Browse the repository at this point in the history
  • Loading branch information
niyue committed Feb 27, 2022
1 parent 2a7a13a commit 6d07dc5
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 166 deletions.
164 changes: 8 additions & 156 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,162 +38,14 @@ icon = "rocket"
4. Paste the diagram to a mermaid diagram editor, for example, [`https://mermaid-js.github.io/mermaid-live-editor`](https://mermaid-js.github.io/mermaid-live-editor).

# Examples
```mermaid
flowchart TD
url_shortener(fa:fa-hashtag <br/>url shortener)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
subgraph groups.webui[fa:fa-desktop web ui]
groups.webui.skills.url_validator(fa:fa-globe <br/>url validator)
class groups.webui.skills.url_validator newSkill;
groups.webui.skills.react-->groups.webui.skills.url_validator
groups.webui.skills.react(fa:fa-list <br/>react)
class groups.webui.skills.react beingLearnedSkill;
end
class groups.webui normalSkillGroup;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
subgraph groups.native_client[fa:fa-desktop native client]
groups.native_client.skills.react_native(fa:fa-mobile <br/>react native)
class groups.native_client.skills.react_native newSkill;
groups.native_client.skills.other_clients(fa:fa-lock <br/>???)
class groups.native_client.skills.other_clients unknownSkill;
end
class groups.native_client newSkillGroup;
groups.webui-->groups.native_client
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
subgraph groups.backend[fa:fa-server backend]
groups.backend.skills.restapi(fa:fa-send <br/>REST API)
class groups.backend.skills.restapi learnedSkill;
groups.backend.skills.database(fa:fa-database <br/>database)
class groups.backend.skills.database learnedSkill;
end
class groups.backend normalSkillGroup;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
subgraph groups.partitioned_backend[fa:fa-copy partitioned backend]
groups.partitioned_backend.skills.proxy(fa:fa-anchor <br/>proxy)
class groups.partitioned_backend.skills.proxy beingLearnedSkill;
groups.partitioned_backend.skills.database(fa:fa-database <br/>partitioned database)
class groups.partitioned_backend.skills.database beingLearnedSkill;
end
class groups.partitioned_backend normalSkillGroup;
groups.backend-->groups.partitioned_backend
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
subgraph groups.cache[ cache]
groups.cache.skills.memcache(fa:fa-magnet <br/>memcache)
class groups.cache.skills.memcache learnedSkill;
groups.cache.skills.redis(fa:fa-lock <br/>???)
class groups.cache.skills.redis unknownSkill;
end
class groups.cache normalSkillGroup;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
url_shortener-->groups.webui
url_shortener-->groups.backend
url_shortener-->groups.cache
classDef normalSkillGroup stroke:#0096C7,stroke-width:4px,fill:#CAF0F8;
classDef beingLearnedSkill stroke-width:2px,stroke:#90E0EF,fill:#ADE8F4;
classDef learnedSkill stroke-width:2px,stroke:#00B4D8,fill:#48CAE4;
classDef newSkillGroup stroke-width:4px,stroke:#D6CCC2,fill:#EDEDE9;
classDef newSkill stroke-width:2px,stroke:#D6CCC2,fill:#EDEDE9;
classDef unknownSkill stroke-width:2px,stroke:#D6CCC2,fill:#EDEDE9;
class url_shortener normalSkillGroup;
```

```mermaid
flowchart TD
url_shortener(fa:fa-hashtag <br/>url shortener)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
subgraph groups.webui[fa:fa-desktop web ui]
groups.webui.skills.url_validator(fa:fa-globe <br/>url validator)
class groups.webui.skills.url_validator newSkill;
groups.webui.skills.react-->groups.webui.skills.url_validator
groups.webui.skills.react(fa:fa-list <br/>react)
class groups.webui.skills.react beingLearnedSkill;
end
class groups.webui normalSkillGroup;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
subgraph groups.native_client[fa:fa-desktop native client]
groups.native_client.skills.react_native(fa:fa-mobile <br/>react native)
class groups.native_client.skills.react_native newSkill;
groups.native_client.skills.other_clients(fa:fa-lock <br/>???)
class groups.native_client.skills.other_clients unknownSkill;
end
class groups.native_client newSkillGroup;
groups.webui-->groups.native_client
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
subgraph groups.backend[fa:fa-server backend]
groups.backend.skills.restapi(fa:fa-send <br/>REST API)
class groups.backend.skills.restapi learnedSkill;
groups.backend.skills.database(fa:fa-database <br/>database)
class groups.backend.skills.database learnedSkill;
end
class groups.backend normalSkillGroup;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
subgraph groups.partitioned_backend[fa:fa-copy partitioned backend]
groups.partitioned_backend.skills.proxy(fa:fa-anchor <br/>proxy)
class groups.partitioned_backend.skills.proxy beingLearnedSkill;
groups.partitioned_backend.skills.database(fa:fa-database <br/>partitioned database)
class groups.partitioned_backend.skills.database beingLearnedSkill;
end
class groups.partitioned_backend normalSkillGroup;
groups.backend-->groups.partitioned_backend
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
subgraph groups.cache[ cache]
groups.cache.skills.memcache(fa:fa-magnet <br/>memcache)
class groups.cache.skills.memcache learnedSkill;
groups.cache.skills.redis(fa:fa-lock <br/>???)
class groups.cache.skills.redis unknownSkill;
end
class groups.cache normalSkillGroup;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
url_shortener-->groups.webui
url_shortener-->groups.backend
url_shortener-->groups.cache
classDef normalSkillGroup stroke-width:4px,stroke:#DCEBCA,fill:#E9F5DB;
classDef beingLearnedSkill stroke-width:2px,stroke:#C2D5AA,fill:#CFE1B9;
classDef learnedSkill stroke-width:2px,stroke:#A6B98B,fill:#B5C99A;
classDef newSkillGroup stroke-width:4px,stroke:#D6CCC2,fill:#EDEDE9;
classDef newSkill stroke-width:2px,stroke:#D6CCC2,fill:#EDEDE9;
classDef unknownSkill stroke-width:2px,stroke:#D6CCC2,fill:#EDEDE9;
%% https://www.w3schools.com/colors/colors_groups.asp
linkStyle default stroke-width:2px,stroke:OliveDrab;
class url_shortener normalSkillGroup;
```
![ocean_theme_example](docs/images/ocean_theme_example.png)
![orientation_example](docs/images/orientation_example.png)

* Each node can have a string label and an fontawsome icon.
* Skills with different statuses will be shown with different colors.
* Unnamed skill will be shown as a locked skill.
* Pre-requisite skills will be connected with an directed edge.
* You can embed the generated mermaid diagram into github markdown directly, but the fontawesome icons in the diagrams are not shown by github so far.

# License
[MIT License](LICENSE)
Expand Down
Binary file added docs/images/ocean_theme_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/orientation_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions docs/skillmap_descriptor.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
* `name`: [optional] the name of the skillmap/group/skill. It will be used as a label in the diagram. .
* `icon`: [optional] a fontawsome icon name. It will be used as an icon in the diagram. You can find the fontawsome icon list [here](https://fontawesome.com/v4.7.0/icons/).
* `requires`: [optional] a list of strings. It indicates a list of skill groups or skills to be learned before this learning this skill group/skill. where each string is a toml table name of a group/skill. It will be rendered as an edge(s) from one node to another.
* `status`: [optional] only applies to a `skill` toml table. It indicates the status of the skill. Nodes will be rendered with different colors according to different statuses. It can be one of the following:
* `new`: the skill is newly unveiled and not master/learned yet (default value if not specified)
* `beingLearned`: the skill is being leanred currently.
* `learned`: the skill is learned.
* locked skill: if a skill table doesn't have name or icon, it will be rendered as a locked skill (a grey box + lock icon + `???` as name).

## Example
```toml
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ name = "skillmap"
version = "0.2.3"
description = "Skillmap generates a skill tree from a toml file"
authors = ["Yue Ni <[email protected]>"]
readme = "README.md"
homepage = "https://github.com/niyue/skillmap"
repository = "https://github.com/niyue/skillmap"
license = "MIT"

[tool.poetry.dependencies]
python = "^3.8"
Expand Down
16 changes: 13 additions & 3 deletions skillmap/skillmap_visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ def skill_node(skill_id, skill_value):
skill_value = locked_skill_value
skill_name = skill_value.get("name", "")
skill_icon = get_icon(skill_value)
skill_icon_label = get_icon_label(skill_icon, skill_name)
skill_status = skill_value.get("status", "new")
skill_id_and_name = f"{skill_id}({skill_icon} <br/>{skill_name})"
skill_id_and_name = f"{skill_id}({skill_icon_label})"
skill_style = f"class {skill_id} {skill_status}Skill;"
skill_requires = _required_node_edges(skill_id, skill_value.get("requires", []))
sections = [
Expand Down Expand Up @@ -79,6 +80,7 @@ def group_subgraph(group_id, group_value):
qualified_group_id = _qualify(group_id)
group_name = group_value.get("name", "")
group_icon = get_icon(group_value)
group_icon_label = get_icon_label(group_icon, group_name, False)
group_skills_list = get_group_skills_list(
qualified_group_id, group_value.get("skills", {})
)
Expand All @@ -88,7 +90,7 @@ def group_subgraph(group_id, group_value):
qualified_group_id, group_value.get("requires", [])
)

group_id_and_name = f"subgraph {qualified_group_id}[{group_icon} {group_name}]"
group_id_and_name = f"subgraph {qualified_group_id}[{group_icon_label}]"
group_style = f"class {qualified_group_id} {group_status}SkillGroup;"
group_subgraph_end = "end"
sections = [
Expand Down Expand Up @@ -117,6 +119,13 @@ def get_orientation(skill_map_dict):
orientation = "TD"
return orientation

def get_icon_label(icon, name, two_lines_layout=True):
if icon:
new_line = "<br/>" if two_lines_layout else " "
return f"{icon}{new_line}{name}"
else:
return name


def skill_map_graph(skill_map):
skill_map_dict = skill_map.get("skillmap", {})
Expand All @@ -125,11 +134,12 @@ def skill_map_graph(skill_map):
theme = skill_map_dict.get("theme", "ocean")
orientation = get_orientation(skill_map_dict)
map_icon = get_icon(skill_map_dict)
map_icon_label = get_icon_label(map_icon, map_name)

map_to_group_edges = groups_edges(map_id, skill_map.get("groups", {}))
map_group_subgraphs = group_subgraphs(skill_map.get("groups", {}))

skill_map_node = f"{map_id}({map_icon} <br/>{map_name})"
skill_map_node = f"{map_id}({map_icon_label})"
skill_map_node_style = f"class {map_id} normalSkillGroup;"
skill_map_header = f"flowchart {orientation}"
sections = [
Expand Down
12 changes: 6 additions & 6 deletions tests/skillmap_visitor_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,29 +84,29 @@ def test_skillmap_node_with_auto_required_groups():

def test_skill_node():
skill_graph = skill_node("s1", {"name": "url validator", "icon": "globe"})
sections = ["s1(fa:fa-globe <br/>url validator)", "class s1 newSkill;", ""]
sections = ["s1(fa:fa-globe<br/>url validator)", "class s1 newSkill;", ""]
assert skill_graph.split("\n") == sections


def test_skill_node_with_status():
skill_graph = skill_node(
"s1", {"name": "url validator", "icon": "globe", "status": "beingLearned"}
)
sections = ["s1(fa:fa-globe <br/>url validator)", "class s1 beingLearnedSkill;", ""]
sections = ["s1(fa:fa-globe<br/>url validator)", "class s1 beingLearnedSkill;", ""]
assert skill_graph.split("\n") == sections


def test_locked_skill_node():
skill_graph = skill_node("s1", {})
sections = ["s1(fa:fa-lock <br/>???)", "class s1 unknownSkill;", ""]
sections = ["s1(fa:fa-lock<br/>???)", "class s1 unknownSkill;", ""]
assert skill_graph.split("\n") == sections


def test_skill_node_with_requires():
skill_graph = skill_node(
"s1", {"name": "url validator", "icon": "globe", "requires": ["s2"]}
)
sections = ["s1(fa:fa-globe <br/>url validator)", "class s1 newSkill;", "s2-->s1"]
sections = ["s1(fa:fa-globe<br/>url validator)", "class s1 newSkill;", "s2-->s1"]
assert skill_graph.split("\n") == sections


Expand Down Expand Up @@ -144,10 +144,10 @@ def test_visit_group():
sections = [
SECTION_SEPARATOR,
"subgraph groups.g1[fa:fa-anchor web ui]",
"groups.g1.skills.s1(fa:fa-globe <br/>url validator)",
"groups.g1.skills.s1(fa:fa-globe<br/>url validator)",
"class groups.g1.skills.s1 newSkill;",
"",
"groups.g1.skills.s2(fa:fa-html5 <br/>React)",
"groups.g1.skills.s2(fa:fa-html5<br/>React)",
"class groups.g1.skills.s2 newSkill;",
"",
"end",
Expand Down
4 changes: 3 additions & 1 deletion tests/url_shortener.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
[skillmap]
name = "url shortener"
icon = "hashtag"
theme = "pale"
# theme = "pale"
# orientation = "LR"

[groups.webui]
name = "web ui"
Expand Down Expand Up @@ -51,6 +52,7 @@ requires = ["groups.backend"]

[groups.cache]
name = "cache"
icon = "archive"
[groups.cache.skills.memcache]
name = "memcache"
icon = "magnet"
Expand Down

0 comments on commit 6d07dc5

Please sign in to comment.