Skip to content

Commit 2061c3b

Browse files
Refactoring Gallery Generators (#256)
* move cookbooks up on main page * reorder nav bar (will have to do on cookbook template and foundations) * add subtitle * refactor code * add tag to entry * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * rm unused packages * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * import yaml * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * add menu_html to call * fix syntax error * edit subtitle code * add subtext * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * rm subtitle * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix subtitle/subtext when None and f-string submit button * move header to str * use same page_layout for both galleries * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent f37196d commit 2061c3b

File tree

7 files changed

+215
-308
lines changed

7 files changed

+215
-308
lines changed

portal/_extensions/cookbook_gallery_generator.py

Lines changed: 4 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,5 @@
1-
import pathlib
2-
from textwrap import dedent
3-
41
import yaml
5-
from truncatehtml import truncate
6-
7-
8-
def build_from_items(items, filename, title='Gallery', subtitle=None, menu_html='', max_descr_len=300):
9-
10-
# Build the gallery file
11-
panels_body = []
12-
for item in items:
13-
if not item.get('thumbnail'):
14-
item['thumbnail'] = '/_static/images/ebp-logo.png'
15-
thumbnail = item['thumbnail']
16-
17-
author_strs = set()
18-
institution_strs = set()
19-
for a in item['authors']:
20-
author_name = a.get('name', 'Anonymous')
21-
author_email = a.get('email', None)
22-
if author_email:
23-
_str = f'<a href="mailto:{author_email}">{author_name}</a>'
24-
else:
25-
_str = author_name
26-
author_strs.add(_str)
27-
28-
institution_name = a.get('institution', None)
29-
if institution_name:
30-
institution_url = a.get('institution_url', None)
31-
if institution_url:
32-
_str = f'<a href="{institution_url}">{institution_name}</a>'
33-
else:
34-
_str = institution_name
35-
institution_strs.add(_str)
36-
37-
authors_str = f"<strong>Author:</strong> {', '.join(author_strs)}"
38-
if institution_strs:
39-
institutions_str = f"<strong>Institution:</strong> {' '.join(institution_strs)}"
40-
else:
41-
institutions_str = ''
42-
43-
ellipsis_str = '<a class="modal-btn"> ... more</a>'
44-
short_description = truncate(item['description'], max_descr_len, ellipsis=ellipsis_str)
45-
46-
if ellipsis_str in short_description:
47-
modal_str = f"""
48-
<div class="modal">
49-
<div class="content">
50-
<img src="{thumbnail}" class="modal-img" />
51-
<h3 class="display-3">{item["title"]}</h3>
52-
{authors_str}
53-
<br/>
54-
{institutions_str}
55-
<p class="my-2">{item['description']}</p>
56-
<p class="mt-3 mb-0"><a href="{item["url"]}" class="btn btn-outline-primary btn-block">Visit Website</a></p>
57-
</div>
58-
</div>
59-
"""
60-
else:
61-
modal_str = ''
62-
63-
panels_body.append(
64-
f"""\
65-
---
66-
:column:
67-
68-
<div class="d-flex gallery-card">
69-
<img src="{thumbnail}" class="gallery-thumbnail" />
70-
<div class="container">
71-
<a href="{item["url"]}" class="text-decoration-none"><h4 class="display-4 p-0">{item["title"]}</h4></a>
72-
<p class="card-subtitle">{authors_str}<br/>{institutions_str}</p>
73-
<p class="my-2">{short_description}</p>
74-
</div>
75-
</div>
76-
{modal_str}
77-
78-
"""
79-
)
80-
81-
panels_body = '\n'.join(panels_body)
82-
83-
if subtitle:
84-
stitle = f'<span class="display-3">Displaying "{subtitle}" tags</span>'
85-
else:
86-
stitle = ''
87-
88-
panels = f"""
89-
# {title}
90-
91-
{stitle}
92-
93-
{menu_html}
94-
95-
````{{panels}}
96-
:column: col-12
97-
:card: +mb-4 w-100
98-
:header: d-none
99-
:body: p-3 m-0
100-
:footer: p-1
101-
102-
{dedent(panels_body)}
103-
````
104-
105-
<div class="modal-backdrop"></div>
106-
<script src="/_static/custom.js"></script>
107-
"""
108-
109-
pathlib.Path(f'{filename}.md').write_text(panels)
2+
from gallery_generator import build_from_items, generate_menu
1103

1114

1125
def main(app):
@@ -115,7 +8,9 @@ def main(app):
1158
all_items = yaml.safe_load(fid)
1169

11710
title = 'Pythia Cookbooks Gallery'
118-
build_from_items(all_items, 'cookbook-gallery', title=title)
11+
subtext = 'Pythia Cookbooks provide example workflows on more advanced and domain-specific problems developed by the Pythia community. Cookbooks build on top of skills you learn in Pythia Foundations.'
12+
menu_html = generate_menu(all_items)
13+
build_from_items(all_items, 'cookbook-gallery', title=title, subtext=subtext, menu_html=menu_html)
11914

12015

12116
def setup(app):
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import itertools
2+
import pathlib
3+
from textwrap import dedent
4+
5+
from truncatehtml import truncate
6+
7+
8+
def _generate_sorted_tag_keys(all_items):
9+
10+
key_set = set(itertools.chain(*[item['tags'].keys() for item in all_items]))
11+
return sorted(key_set)
12+
13+
14+
def _generate_tag_set(all_items, tag_key=None):
15+
16+
tag_set = set()
17+
for item in all_items:
18+
for k, e in item['tags'].items():
19+
if tag_key and k != tag_key:
20+
continue
21+
for t in e:
22+
tag_set.add(t)
23+
24+
return tag_set
25+
26+
27+
def _generate_tag_menu(all_items, tag_key):
28+
29+
tag_set = _generate_tag_set(all_items, tag_key)
30+
tag_list = sorted(tag_set)
31+
32+
options = ''.join(
33+
f'<li><label class="dropdown-item checkbox {tag_key}"><input type="checkbox" rel={tag.replace(" ", "-")} onchange="change();">&nbsp;{tag.capitalize()}</label></li>'
34+
for tag in tag_list
35+
)
36+
37+
return f"""
38+
<div class="dropdown">
39+
40+
<button class="btn btn-sm btn-outline-primary mx-1 dropdown-toggle" type="button" id="{tag_key}Dropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
41+
{tag_key.title()}
42+
</button>
43+
<ul class="dropdown-menu" aria-labelledby="{tag_key}Dropdown">
44+
{options}
45+
</ul>
46+
</div>
47+
"""
48+
49+
50+
def generate_menu(all_items, submit_btn_txt=None, submit_btn_link=None):
51+
52+
key_list = _generate_sorted_tag_keys(all_items)
53+
54+
menu_html = '<div class="d-sm-flex mt-3 mb-4">\n'
55+
menu_html += '<div class="d-flex gallery-menu">\n'
56+
if submit_btn_txt:
57+
menu_html += f'<div><a role="button" class="btn btn-primary btn-sm mx-1" href={submit_btn_link}>{submit_btn_txt}</a></div>\n'
58+
menu_html += '</div>\n'
59+
menu_html += '<div class="ml-auto d-flex">\n'
60+
menu_html += '<div><button class="btn btn-link btn-sm mx-1" onclick="clearCbs()">Clear all filters</button></div>\n'
61+
for tag_key in key_list:
62+
menu_html += _generate_tag_menu(all_items, tag_key) + '\n'
63+
menu_html += '</div>\n'
64+
menu_html += '</div>\n'
65+
menu_html += '<script>$(document).on("click",function(){$(".collapse").collapse("hide");}); </script>\n'
66+
return menu_html
67+
68+
69+
def build_from_items(items, filename, title='Gallery', subtitle=None, subtext=None, menu_html='', max_descr_len=300):
70+
71+
# Build the gallery file
72+
panels_body = []
73+
for item in items:
74+
if not item.get('thumbnail'):
75+
item['thumbnail'] = '/_static/images/ebp-logo.png'
76+
thumbnail = item['thumbnail']
77+
tag_list = sorted((itertools.chain(*item['tags'].values())))
78+
tag_list_f = [tag.replace(' ', '-') for tag in tag_list]
79+
80+
tags = [f'<span class="badge bg-primary">{tag}</span>' for tag in tag_list_f]
81+
tags = '\n'.join(tags)
82+
83+
tag_class_str = ' '.join(tag_list_f)
84+
85+
author_strs = set()
86+
institution_strs = set()
87+
for a in item['authors']:
88+
author_name = a.get('name', 'Anonymous')
89+
author_email = a.get('email', None)
90+
if author_email:
91+
_str = f'<a href="mailto:{author_email}">{author_name}</a>'
92+
else:
93+
_str = author_name
94+
author_strs.add(_str)
95+
96+
institution_name = a.get('institution', None)
97+
if institution_name:
98+
institution_url = a.get('institution_url', None)
99+
if institution_url:
100+
_str = f'<a href="{institution_url}">{institution_name}</a>'
101+
else:
102+
_str = institution_name
103+
institution_strs.add(_str)
104+
105+
authors_str = f"<strong>Author:</strong> {', '.join(author_strs)}"
106+
if institution_strs:
107+
institutions_str = f"<strong>Institution:</strong> {' '.join(institution_strs)}"
108+
else:
109+
institutions_str = ''
110+
111+
ellipsis_str = '<a class="modal-btn"> ... more</a>'
112+
short_description = truncate(item['description'], max_descr_len, ellipsis=ellipsis_str)
113+
114+
if ellipsis_str in short_description:
115+
modal_str = f"""
116+
<div class="modal">
117+
<div class="content">
118+
<img src="{thumbnail}" class="modal-img" />
119+
<h3 class="display-3">{item["title"]}</h3>
120+
{authors_str}
121+
<br/>
122+
{institutions_str}
123+
<p class="my-2">{item['description']}</p>
124+
<p class="my-2">{tags}</p>
125+
<p class="mt-3 mb-0"><a href="{item["url"]}" class="btn btn-outline-primary btn-block">Visit Website</a></p>
126+
</div>
127+
</div>
128+
"""
129+
else:
130+
modal_str = ''
131+
132+
panels_body.append(
133+
f"""\
134+
---
135+
:column: + tagged-card {tag_class_str}
136+
137+
<div class="d-flex gallery-card">
138+
<img src="{thumbnail}" class="gallery-thumbnail" />
139+
<div class="container">
140+
<a href="{item["url"]}" class="text-decoration-none"><h4 class="display-4 p-0">{item["title"]}</h4></a>
141+
<p class="card-subtitle">{authors_str}<br/>{institutions_str}</p>
142+
<p class="my-2">{short_description}</p>
143+
</div>
144+
</div>
145+
{modal_str}
146+
147+
+++
148+
149+
{tags}
150+
151+
"""
152+
)
153+
154+
panels_body = '\n'.join(panels_body)
155+
156+
stitle = f'#### {subtitle}' if subtitle else ''
157+
stext = subtext if subtext else ''
158+
159+
panels = f"""
160+
# {title}
161+
162+
{stitle}
163+
{stext}
164+
165+
{menu_html}
166+
167+
````{{panels}}
168+
:column: col-12
169+
:card: +mb-4 w-100
170+
:header: d-none
171+
:body: p-3 m-0
172+
:footer: p-1
173+
174+
{dedent(panels_body)}
175+
````
176+
177+
<div class="modal-backdrop"></div>
178+
<script src="/_static/custom.js"></script>
179+
"""
180+
181+
pathlib.Path(f'{filename}.md').write_text(panels)

0 commit comments

Comments
 (0)