From f0aec83783a55d521ac69c2f41ee86d916974ae6 Mon Sep 17 00:00:00 2001 From: Frank Harkins Date: Tue, 16 Jul 2024 10:19:12 +0100 Subject: [PATCH] [DO NOT MERGE] Redirect ecosystem page (#752) ### Summary This PR removes the website generation logic and sets up a HTML redirect to the new ecosystem page. I decided on a HTML redirect as it seems [`external-sites.json`](https://docs.github.com/en/contributing/writing-for-github-docs/configuring-redirects#configuring-external-redirects) is actually for GitHub docs contributors, not GitHub pages. From what I can tell, there's no way to server-side redirect a GitHub pages site. > [!Caution] > **Do not merge** > > The redirect will take effect immediately after merging. Please do not merge until the new page is live. Commit-wise review may be easier. *** Closes #741 --- docs/project_overview.md | 5 +- ecosystem/cli/website.py | 175 ++-------------- ecosystem/html_templates/card.html.jinja | 19 -- ecosystem/html_templates/link.html.jinja | 20 -- ecosystem/html_templates/style.css.jinja | 221 -------------------- ecosystem/html_templates/tag.html.jinja | 8 - ecosystem/html_templates/webpage.html.jinja | 127 ----------- tox.ini | 2 +- website/Qiskit_gradient.svg | 38 ---- 9 files changed, 27 insertions(+), 588 deletions(-) delete mode 100644 ecosystem/html_templates/card.html.jinja delete mode 100644 ecosystem/html_templates/link.html.jinja delete mode 100644 ecosystem/html_templates/style.css.jinja delete mode 100644 ecosystem/html_templates/tag.html.jinja delete mode 100644 ecosystem/html_templates/webpage.html.jinja delete mode 100644 website/Qiskit_gradient.svg diff --git a/docs/project_overview.md b/docs/project_overview.md index 2ad0fb2d8f..31e73a48d6 100644 --- a/docs/project_overview.md +++ b/docs/project_overview.md @@ -44,10 +44,11 @@ class. ### Webpage -To generate the webpage from the TOML files, run: +To generate the ecosystem data from the TOML files, run: ```sh tox -e website ``` -Then open `website/index.html` in your browser. A GitHub action publishes the result of this command on every push to main. +Then open `website/ecosystem.json`. A GitHub action publishes the result of this command on every push to main. +This command also generates `website/index.html`, which is HTML file that redirects to the ecosystem page. This is needed because we used to host the ecosystem page on GitHub pages. diff --git a/ecosystem/cli/website.py b/ecosystem/cli/website.py index 0b3db1ae08..3f9b9b9b6d 100644 --- a/ecosystem/cli/website.py +++ b/ecosystem/cli/website.py @@ -1,162 +1,33 @@ """CliWebsite class for controlling all CLI functions.""" -from __future__ import annotations +from __future__ import annotations -from pathlib import Path -from typing import Any -import json import re -import toml - -from jinja2 import Environment, PackageLoader, Template - -from ecosystem.daos import DAO -from ecosystem.models.repository import Repository - - -def build_website(resources: str, output: str) -> None: - """ - Generates the ecosystem web page from data in `resources` dir, writing to `output` dir. - """ - html, css = build_website_strings(resources) - Path(output).write_text(html) - (Path(output).parent / "style.css").write_text(css) - +from pathlib import Path -def build_website_strings(resources: str) -> tuple[str, str]: - """ - Generates the ecosystem web page and css from data in `resources` dir. - """ - projects, web_data, label_descriptions, templates, custom_css = _load_from_file( - Path(resources) - ) - html = _build_html(projects, web_data, label_descriptions, templates) - css = templates["css"].render( - custom_css=custom_css, standalone=web_data.get("standalone", True) - ) - return html, css +NEW_URL = "https://ibm.com/quantum/ecosystem" -def _load_from_file( - resources_dir: Path, -) -> tuple[ - list[Repository], dict[str, Any], dict[str, str], dict[str, Template], str | None -]: +def build_website(output: str) -> None: """ - Loads website data from file. - Returns: - * Projects: List of Repository objects from `members` folder. - * Web data: Strings (title / descriptions etc.) from `website.toml`. - * Label descriptions: from `labels.json`. - * Jinja templates: from `html_templates` folder. - * Any custom css to be appended to the css file. + Generates a HTML redirect to the new ecosystem web page. """ - # Projects list - dao = DAO(path=resources_dir) - projects = sorted( - dao.get_all(), - key=lambda item: ( - -(item.stars or 0), - item.name, - ), - ) - - # Label descriptions: We flatten the dict to the form { label_name: description } - label_descriptions = {} - for category in json.loads((resources_dir / "labels.json").read_text()).values(): - for label in category: - label_descriptions[label["name"]] = label["description"] - label_descriptions["IBM maintained"] = "Officially maintained by IBM Quantum" - - # Website strings - web_data = toml.loads((resources_dir / "website.toml").read_text()) - - # Custom css - custom_css = None - if web_data.get("custom-css", False): - custom_css = (resources_dir / web_data["custom-css"]).read_text() - - # Jinja templates - environment = Environment(loader=PackageLoader("ecosystem", "html_templates/")) - templates = { - "website": environment.get_template("webpage.html.jinja"), - "card": environment.get_template("card.html.jinja"), - "tag": environment.get_template("tag.html.jinja"), - "link": environment.get_template("link.html.jinja"), - "css": environment.get_template("style.css.jinja"), - } - return projects, web_data, label_descriptions, templates, custom_css - - -def _build_html(projects, web_data, label_descriptions, templates) -> str: - """ - Take all data needed to build the website and produce a HTML string. + html = f""" + + + + + + + Qiskit ecosystem + + + If you are not redirected automatically, go to {NEW_URL}. + + """ - # pylint: disable=too-many-locals - sections = {group["id"]: group for group in web_data["groups"]} - for section in sections.values(): - section.setdefault("html", "") - - max_chars_description_visible = 400 - min_chars_description_hidden = 100 - count_read_more = 1 - for repo in projects: - if repo.ibm_maintained: - repo.labels.append("IBM maintained") - # Card tags - tags = "" - for index, label in enumerate(repo.labels): - tags += templates["tag"].render( - color="purple", - text=label, - tooltip=label_descriptions[label], - # Sometimes tooltips are clipped by the browser window. - # While not perfect, the following line solves 95% of cases - alignment="bottom" if (index % 3) == 2 else "bottom-left", - ) - - # Card links - links = "" - for url, link_text in ( - (repo.url, "repository"), - (repo.website, "website"), - (repo.reference_paper, "paper"), - (repo.documentation, "documentation"), - ): - if url: - links += templates["link"].render(url=url, place=link_text) - - # Card description - if ( - len(repo.description) - max_chars_description_visible - >= min_chars_description_hidden - ): - description = [ - repo.description[:max_chars_description_visible], - repo.description[max_chars_description_visible:], - ] - id_read_more = str(count_read_more) - count_read_more += 1 - else: - description = [repo.description, ""] - id_read_more = "None" - - # Create the card - card = templates["card"].render( - title=repo.name, - tags=tags, - description_visible=description[0], - description_hidden=description[1], - id_read_more=id_read_more, - links=links, - ) - - # Adding the card to a section - sections[repo.group]["html"] += card - - html = templates["website"].render( - is_standalone=web_data.get("standalone", True), - header=web_data["header"], - sections=sections.values(), - ) - return re.sub(r"^\s+", "", html, flags=re.MULTILINE) + html = re.sub(r"\n\s*", "", html) + Path(output).parent.mkdir(parents=True, exist_ok=True) + Path(output).write_text(html) diff --git a/ecosystem/html_templates/card.html.jinja b/ecosystem/html_templates/card.html.jinja deleted file mode 100644 index a522329113..0000000000 --- a/ecosystem/html_templates/card.html.jinja +++ /dev/null @@ -1,19 +0,0 @@ -
- -

{{title}}

-
{{tags}}
-
- {% if id_read_more != "None" %} - -

- {{description_visible}}...{{description_hidden}} -

- - {% else %} -

{{description_visible}}

- {% endif %} -
- -
-
diff --git a/ecosystem/html_templates/link.html.jinja b/ecosystem/html_templates/link.html.jinja deleted file mode 100644 index 0cb3f428c7..0000000000 --- a/ecosystem/html_templates/link.html.jinja +++ /dev/null @@ -1,20 +0,0 @@ - - Go to {{place}} - - - - diff --git a/ecosystem/html_templates/style.css.jinja b/ecosystem/html_templates/style.css.jinja deleted file mode 100644 index 9be7242bd0..0000000000 --- a/ecosystem/html_templates/style.css.jinja +++ /dev/null @@ -1,221 +0,0 @@ -{% if standalone %} -* { - box-sizing: inherit; -} - -html, -body { - height: 100%; - margin: 0; - background-color: #f4f4f4; -} - -body { - flex-flow: column nowrap; - font-family: "IBM Plex Sans", sans-serif; -} - -header { - padding: 3rem 0rem 2rem 0rem; - background-color: white; -} - -p { - font-size: 0.875rem; - color: #525252; -} -{% endif %} - -.inside-header { - padding: 0rem 2rem 0rem 2rem; - display: flex; -} - -.header-content{ - width: fit-content; -} - -.header-logo { - margin-right: 5rem; -} - -.ecosystem-title { - font-size: 3.75rem; - line-height: 4.375rem; - font-weight: 300; -} - -.header-qiskit-word { - font-weight: 450; -} - -.content { - padding: 3rem 2rem 3rem 2rem; - margin-bottom: 1rem; -} - -.cards { - display: flex; - flex-wrap: wrap; - gap: 1rem; - margin-top: 1.5rem; - margin-bottom: 3rem; -} - -.card { - flex: 0 1 20%; - background-color: white; - border-radius: 0.25rem; -} - -cds-tile { - display: flex; - flex-flow: column; - gap: 1rem; - background-color: white; - padding-left: 0; - padding-right: 0; -} - -.tags { - display: flex; - flex-flow: row wrap; -} - -cds-tag { - margin-left: 0; -} - -.project-title { - font-size: 1.25rem; - line-height: 1.25; - font-weight: normal; -} - -.section { - font-size: 1.25rem; - position: relative; - left: -1.25rem; - margin-bottom: 0.5rem; -} - -.title-description { - margin: 1.5rem 0; - width: 25rem; - color: black; -} - -.links { - display: flex; - flex-flow: column wrap; - gap: 0.5rem; -} - -.description { - display: block; -} - -.link svg { - vertical-align: middle; - margin-left: 0.25rem; -} - -.text { - word-break: break-word; -} - -.section-anchor { - display: inline; - visibility: hidden; - text-decoration:none; -} - -.section:hover .section-anchor{ - visibility: inherit; -} - - -/* ------------------------------ -* Read more button -* ------------------------------ */ - -.read-more-input { - visibility: hidden; - display: none; -} - -.extra-text { - visibility: hidden; - display: none; -} - -.read-more-input:checked ~ .text .extra-text { - visibility: inherit; - display: inline; -} - -.read-more-input:checked ~ .text .ellipsis { - visibility: hidden; - display: none; -} - -.read-more-input ~ .read-more-button:before { - content: "Read more"; - text-decoration: underline; -} - -.read-more-input:checked ~ .read-more-button:before { - content: "Read less"; - text-decoration: underline; -} - -.read-more-button { - cursor: pointer; -} - -{% if standalone %} -/* ------------------------------ */ - -@media only screen and (max-width: 1500px) { - .card { - flex: 0 1 28%; - } - .header-logo { - margin-right: 3rem; - } -} - -@media only screen and (max-width: 1200px) { - .card { - flex: 0 1 42%; - } -} - -@media only screen and (max-width: 750px) { - .card { - flex: 0 1 95%; - } -} - -@media only screen and (max-width: 725px) { - .header-logo { - display: none; - } -} - -@media only screen and (max-width: 400px) { - .title-description { - width: auto; - } -} -{% endif %} - -{% if custom_css %} - -/* ------------ */ -/* Custom rules */ -/* ------------ */ - -{{ custom_css }} - -{% endif %} diff --git a/ecosystem/html_templates/tag.html.jinja b/ecosystem/html_templates/tag.html.jinja deleted file mode 100644 index 1a1355f3b4..0000000000 --- a/ecosystem/html_templates/tag.html.jinja +++ /dev/null @@ -1,8 +0,0 @@ - -
- {{text}} -
- - {{ tooltip }} - -
diff --git a/ecosystem/html_templates/webpage.html.jinja b/ecosystem/html_templates/webpage.html.jinja deleted file mode 100644 index 007e54b2a5..0000000000 --- a/ecosystem/html_templates/webpage.html.jinja +++ /dev/null @@ -1,127 +0,0 @@ -{% if is_standalone %} - - - - - - - {{ header.title.bold }} {{ header.title.normal }} -{# These two CSS files include general rules that we don't want to interfere #} -{# with the page we're embedding in, so we only set them in standalone mode. #} - - -{% endif %} - - - - - - - -{% if is_standalone %} - - -{% endif %} -
-
-
-
-

{{ header.title.bold }} {{ header.title.normal }}

-

- {{ header.description.long }} -

- - - {{ header.add_project.text }} - - - - -
- -
-
- - {% for section in sections %} -
-

- - - - {{ section.title }} -

-

- {{ section.description }} -

-
{{ section.html }}
-
- {% endfor %} -
-{% if is_standalone %} - - -{% endif %} diff --git a/tox.ini b/tox.ini index 662bd0114e..0f19ec3dfb 100644 --- a/tox.ini +++ b/tox.ini @@ -38,5 +38,5 @@ commands = black {posargs} ecosystem tests --check allowlist_externals = bash basepython = python3 commands = - bash -ec "python manager.py build --resources ecosystem/resources --output website/index.html" + bash -ec "python manager.py build --output website/index.html" bash -ec "python manager.py members compile_json 'website/ecosystem.json'" diff --git a/website/Qiskit_gradient.svg b/website/Qiskit_gradient.svg deleted file mode 100644 index e59a8d4f45..0000000000 --- a/website/Qiskit_gradient.svg +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -