Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: landing page improvements #796

Merged
merged 37 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
c1dc29b
feat: add sidebar template
jorgepiloto Dec 31, 2024
5e1eb69
feat: basic landing page
jorgepiloto Dec 31, 2024
f343639
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 31, 2024
73e01f0
feat: add families and tags in projects.yaml
jorgepiloto Dec 31, 2024
085c574
feat: from YML to JSON
jorgepiloto Dec 31, 2024
1ab48fc
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 31, 2024
4d31843
feat: basic script
jorgepiloto Dec 31, 2024
9ad6b4c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 31, 2024
ee52b17
fix: sort families by alphabetical order
jorgepiloto Dec 31, 2024
e24b515
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 31, 2024
60c2c86
feat: labels for families
jorgepiloto Dec 31, 2024
0cd5244
fix: labels style
jorgepiloto Dec 31, 2024
b19d8cd
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 31, 2024
7f8bb8d
fix: labels style
jorgepiloto Dec 31, 2024
6ecb73b
fix: numbering
jorgepiloto Dec 31, 2024
18dc4fb
feat: increase gap
jorgepiloto Dec 31, 2024
fd598f5
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 31, 2024
d406eee
doc: add families and tags
jorgepiloto Jan 7, 2025
cd33adf
fix: JS logic
jorgepiloto Jan 9, 2025
5e3cf51
fix: use families in card classes
jorgepiloto Jan 9, 2025
24fa63e
fix: tweak visibility of cards
jorgepiloto Jan 9, 2025
72c87e8
fix: use grid
jorgepiloto Jan 10, 2025
5cb62f6
fix: improve CSS
jorgepiloto Jan 10, 2025
6d0cf4f
fix: cards radius
jorgepiloto Jan 10, 2025
1e827fa
fix: scroll
jorgepiloto Jan 10, 2025
f6dad6c
fix: families
jorgepiloto Jan 10, 2025
88291b5
feat: complete tags
jorgepiloto Jan 10, 2025
300e8e4
fix: tags style
jorgepiloto Jan 10, 2025
0a463c6
fix: tags
jorgepiloto Jan 10, 2025
2e218f8
Merge branch 'main' into feat/landing-page
MaxJPRey Jan 13, 2025
d615f7c
doc: projects
jorgepiloto Jan 13, 2025
056018a
fix: typo in projects.yml
jorgepiloto Jan 13, 2025
96aec93
feat: update on tags and families
RobPasMue Jan 13, 2025
ae7480d
fix: TODO
jorgepiloto Jan 13, 2025
0f0d8f5
feat: make site responsive
jorgepiloto Jan 13, 2025
e9398f6
ci: check style for CSS and JS
jorgepiloto Jan 13, 2025
da6b1c4
fix: media query for cards
jorgepiloto Jan 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,6 @@ cython_debug/
#.idea/

# End of https://www.toptal.com/developers/gitignore/api/python

# Ignore generated project.json file used by documentation
doc/source/_static/projects.json
91 changes: 91 additions & 0 deletions doc/source/_static/css/landing_page.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
html {
overflow-y: scroll !important;
}

.landing-page-sidebar {
margin-top: 2rem;
display: flex;
flex-direction: column;
padding: 0rem 2rem;
}
.landing-page-sidebar-section {
margin-bottom: 2rem;
font-weight: bold;
display: flex;
flex-direction: column;
gap: 1rem;
}
.landing-page-sidebar-section span {
font-size: 18px;
font-weight: bold;
}
.family-row, .tag-row {
display: flex;
align-items: center;
margin: 5px 0;
}
.family-row input, .tag-row input {
margin-right: 10px;
}
.family-name {
margin-right: 10px;
}
.family-count {
margin-left: auto;
background-color: lightgrey;
border-radius: 50%;
padding: 0.25rem 0.75rem;
}
.selected-families {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 0.5rem;
}
.selected-family {
display: flex;
align-items: center;
gap: 1rem;
padding: 0.25rem 0.5rem;
border-radius: 5px;
background-color: lightgrey;
}
.remove-family {
cursor: pointer;
color: black;
font-weight: bold;
}

.projects {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
margin-bottom: 1.5rem;
}

.project-card {
display: flex;
flex-direction: column;
border-radius: 8px;
background-color: white;
}

.project-thumbnail {
padding: 0;
border-top-right-radius: 8px;
border-top-left-radius: 8px;
}

.project-title {
font-size: 1.2rem;
font-weight: bold;
margin-bottom: 0rem;
padding: 0.5rem;
padding-left: 1rem;
}

.project-description {
margin-top: 1rem;
padding: 0.5rem;
padding-left: 1rem;
}
194 changes: 194 additions & 0 deletions doc/source/_static/js/landing_page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
function collectFamilies(data) {
const familyCounts = {};

if (!data.projects || typeof data.projects !== 'object') {
console.error('Invalid projects data structure:', data.projects);
return familyCounts;
}

const projects = Object.values(data.projects);

for (const project of projects) {
if (!project || typeof project !== 'object') continue;

const family = project.family;

if (family) {
familyCounts[family] = (familyCounts[family] || 0) + 1;
}
}

return familyCounts;
}

function collectTags(data) {
const tagCounts = {};

if (!data.projects || typeof data.projects !== 'object') {
console.error('Invalid projects data structure:', data.projects);
return tagCounts;
}

const projects = Object.values(data.projects);

for (const project of projects) {
if (!project || typeof project !== 'object') continue;

const tags = project.tags;

if (Array.isArray(tags)) {
tags.forEach(tag => {
tagCounts[tag] = (tagCounts[tag] || 0) + 1;
});
}
}

return tagCounts;
}

function displayFamilies(familyCounts) {
const familiesContainer = document.getElementById('product-families-list');
familiesContainer.innerHTML = '';

const sortedFamilies = Object.keys(familyCounts).sort();

sortedFamilies.forEach(family => {
const familyCount = familyCounts[family];

const familyRow = document.createElement('div');
familyRow.className = 'family-row';

const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = `family-${CSS.escape(family)}`;
checkbox.addEventListener('change', handleFamilySelection);

const familyName = document.createElement('span');
familyName.className = 'family-name';
familyName.textContent = family;

const familyCountElem = document.createElement('span');
familyCountElem.className = 'family-count';
familyCountElem.textContent = `(${familyCount})`;

familyRow.appendChild(checkbox);
familyRow.appendChild(familyName);
//familyRow.appendChild(familyCountElem);

familiesContainer.appendChild(familyRow);
});
}

function displayTags(tagCounts) {
const tagsContainer = document.getElementById('product-tags-list');
tagsContainer.innerHTML = '';

const sortedTags = Object.keys(tagCounts).sort();

sortedTags.forEach(tag => {
const tagCount = tagCounts[tag];

const tagRow = document.createElement('div');
tagRow.className = 'tag-row';

const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = `tag-${CSS.escape(tag)}`;
checkbox.addEventListener('change', handleTagSelection);

const tagName = document.createElement('span');
tagName.className = 'tag-name';
tagName.textContent = tag;

const tagCountElem = document.createElement('span');
tagCountElem.className = 'tag-count';
tagCountElem.textContent = `(${tagCount})`;

tagRow.appendChild(checkbox);
tagRow.appendChild(tagName);
//tagRow.appendChild(tagCountElem);

tagsContainer.appendChild(tagRow);
});
}

function handleFamilySelection() {
const selectedFamilies = Array.from(
document.querySelectorAll('#product-families-list input[type="checkbox"]:checked')
).map(checkbox => checkbox.id.replace('family-', '').toLowerCase());

console.log('Selected families:', selectedFamilies);

const projectCards = document.querySelectorAll('.project-card');

projectCards.forEach(card => {
const family = card.getAttribute('data-family').toLowerCase();
card.style.display = selectedFamilies.length === 0 || selectedFamilies.includes(family) ? 'flex' : 'none';
});
}

function handleTagSelection() {
const selectedTags = Array.from(
document.querySelectorAll('#product-tags-list input[type="checkbox"]:checked')
).map(checkbox => checkbox.id.replace('tag-', '').toLowerCase());

console.log('Selected tags:', selectedTags);

const projectCards = document.querySelectorAll('.project-card');

projectCards.forEach(card => {
const rawTags = card.getAttribute('data-tags');

if (!rawTags) {
card.style.display = 'none';
return;
}

// Parse the data-tags string
let cardTags = [];
try {
cardTags = JSON.parse(rawTags.replace(/'/g, '"'));
} catch (error) {
console.error('Error parsing data-tags:', rawTags, error);
card.style.display = 'none';
return;
}

const cardTagsLower = cardTags.map(tag => tag.toLowerCase());
const hasMatchingTag = selectedTags.some(tag => cardTagsLower.includes(tag));

card.style.display = selectedTags.length === 0 || hasMatchingTag ? 'flex' : 'none';
});
}

function initializeAllCards() {
const articleElement = document.querySelector('article');
const projects = articleElement.querySelectorAll('.project-card');
projects.forEach(project => {
project.style.display = 'flex';
});
}

fetch('_static/projects.json')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
// Display families
const familyCounts = collectFamilies(data);
displayFamilies(familyCounts);

// Display tags
const tagCounts = collectTags(data);
displayTags(tagCounts);

// Render all cards
initializeAllCards();
})
.catch(error => {
console.error('Error fetching the projects data:', error);
});

19 changes: 19 additions & 0 deletions doc/source/_templates/landing_page_sidebar.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<div class="landing-page-sidebar">

<!-- Product families -->
<div class="landing-page-sidebar-section product-families">
<span>Product families</span>
<div id="product-families-list"></div>
<a class="show-more">Show more</a>
</div>

<hr>

<!-- Tags -->
<div class="landing-page-sidebar-section product-tags">
<span>Tags</span>
<div id="product-tags-list"></div>
<a class="show-more">Show more</a>
</div>

</div>
40 changes: 39 additions & 1 deletion doc/source/conf.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Configuration file for docs.pyansys.com landing page."""

from datetime import datetime
import json
import os
from pathlib import Path
import subprocess
Expand Down Expand Up @@ -61,7 +62,7 @@
cname = os.getenv("DOCUMENTATION_CNAME", default="nocname.com")
switcher_version = get_version_match(pyansys_version)

# get the PyAnsys version
# Get the PyAnsys version
release = version = pyansys_version

html_theme = "ansys_sphinx_theme"
Expand All @@ -70,13 +71,23 @@
# Favicon
html_favicon = ansys_favicon

html_sidebars = {
"index": ["landing_page_sidebar.html"],
}

extensions = [
"sphinx_design",
"sphinx_copybutton",
"sphinxcontrib.mermaid",
"sphinx_jinja",
]

# Static files
templates_path = ["_templates"]
html_static_path = ["_static"]
html_css_files = ["css/landing_page.css"]
html_js_files = ["js/landing_page.js"]

metadata = Path(__file__).parent.parent.parent / "projects.yaml"

jinja_contexts = {
Expand Down Expand Up @@ -439,6 +450,32 @@ def package_versions_table(app: sphinx.application.Sphinx):
)


def convert_yaml_to_json(app: sphinx.application.Sphinx):
"""
Convert a YAML file to a JSON file.

Parameters:
yaml_path (Path): Path to the YAML file.
json_path (Path): Path to save the JSON file.

Returns:
None
"""
if not metadata.exists() or not metadata.is_file():
raise FileNotFoundError(f"The file {metadata} does not exist or is not a file.")

with metadata.open("r", encoding="utf-8") as yaml_file:
try:
yaml_content = yaml.safe_load(yaml_file)
except yaml.YAMLError as e:
raise ValueError(f"Error parsing YAML file: {e}")

json_path = Path(__file__).parent / "_static" / "projects.json"
with json_path.open("w", encoding="utf-8") as json_file:
json.dump(yaml_content, json_file, indent=4)
print(f"JSON file successfully written to {json_path}")


def setup(app: sphinx.application.Sphinx):
"""Run different hook functions during the documentation build.

Expand All @@ -448,6 +485,7 @@ def setup(app: sphinx.application.Sphinx):
Sphinx instance containing all the configuration for the documentation build.
"""
# At the beginning of the build process - update the version in cheatsheet
app.connect("builder-inited", convert_yaml_to_json)
app.connect("builder-inited", resize_thumbnails)
app.connect("builder-inited", package_versions_table)

Expand Down
Loading
Loading