Skip to content

Commit cd035af

Browse files
committed
feat: update release 2025.1 branch
2 parents 21d0c0c + 6690782 commit cd035af

File tree

9 files changed

+488
-26
lines changed

9 files changed

+488
-26
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,6 @@ cython_debug/
164164
#.idea/
165165

166166
# End of https://www.toptal.com/developers/gitignore/api/python
167+
168+
# Ignore generated project.json file used by documentation
169+
doc/source/_static/projects.json

.pre-commit-config.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
repos:
22

33
- repo: https://github.com/astral-sh/ruff-pre-commit
4-
rev: v0.8.3
4+
rev: v0.8.6
55
hooks:
66
- id: ruff
77
- id: ruff-format
@@ -39,3 +39,9 @@ repos:
3939
- id: add-license-headers
4040
args:
4141
- --start_year=2022
42+
43+
- repo: https://github.com/pre-commit/mirrors-prettier
44+
rev: 'v4.0.0-alpha.8'
45+
hooks:
46+
- id: prettier
47+
types_or: [css, javascript]
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
html {
2+
overflow-y: scroll !important;
3+
}
4+
5+
.landing-page-sidebar {
6+
margin-top: 2rem;
7+
display: flex;
8+
flex-direction: column;
9+
padding: 0rem 2rem;
10+
}
11+
.landing-page-sidebar-section {
12+
margin-bottom: 2rem;
13+
font-weight: bold;
14+
display: flex;
15+
flex-direction: column;
16+
gap: 1rem;
17+
}
18+
.landing-page-sidebar-section span {
19+
font-size: 18px;
20+
font-weight: bold;
21+
}
22+
.family-row,
23+
.tag-row {
24+
display: flex;
25+
align-items: center;
26+
margin: 5px 0;
27+
}
28+
.family-row input,
29+
.tag-row input {
30+
margin-right: 10px;
31+
}
32+
.family-name {
33+
margin-right: 10px;
34+
}
35+
.family-count {
36+
margin-left: auto;
37+
background-color: lightgrey;
38+
border-radius: 50%;
39+
padding: 0.25rem 0.75rem;
40+
}
41+
.selected-families {
42+
display: flex;
43+
flex-direction: row;
44+
flex-wrap: wrap;
45+
gap: 0.5rem;
46+
}
47+
.selected-family {
48+
display: flex;
49+
align-items: center;
50+
gap: 1rem;
51+
padding: 0.25rem 0.5rem;
52+
border-radius: 5px;
53+
background-color: lightgrey;
54+
}
55+
.remove-family {
56+
cursor: pointer;
57+
color: black;
58+
font-weight: bold;
59+
}
60+
61+
.projects {
62+
display: grid;
63+
grid-template-columns: repeat(3, 1fr);
64+
gap: 2rem;
65+
margin-bottom: 1.5rem;
66+
}
67+
68+
.project-card {
69+
display: flex;
70+
flex-direction: column;
71+
border-radius: 8px;
72+
background-color: white;
73+
}
74+
75+
.project-thumbnail {
76+
padding: 0;
77+
border-top-right-radius: 8px;
78+
border-top-left-radius: 8px;
79+
}
80+
81+
.project-title {
82+
font-size: 1.2rem;
83+
font-weight: bold;
84+
margin-bottom: 0rem;
85+
padding: 0.5rem;
86+
padding-left: 1rem;
87+
}
88+
89+
.project-description {
90+
margin-top: 1rem;
91+
padding: 0.5rem;
92+
padding-left: 1rem;
93+
}
94+
95+
@media screen and (max-width: 768px) {
96+
.projects {
97+
grid-template-columns: 1fr;
98+
}
99+
100+
.landing-page-sidebar {
101+
padding: 1rem;
102+
}
103+
104+
.project-card {
105+
margin: 0 auto;
106+
width: 90%;
107+
}
108+
}

doc/source/_static/js/landing_page.js

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
function collectFamilies(data) {
2+
const familyCounts = {};
3+
4+
if (!data.projects || typeof data.projects !== "object") {
5+
console.error("Invalid projects data structure:", data.projects);
6+
return familyCounts;
7+
}
8+
9+
const projects = Object.values(data.projects);
10+
11+
for (const project of projects) {
12+
if (!project || typeof project !== "object") continue;
13+
14+
const family = project.family;
15+
16+
if (family) {
17+
familyCounts[family] = (familyCounts[family] || 0) + 1;
18+
}
19+
}
20+
21+
return familyCounts;
22+
}
23+
24+
function collectTags(data) {
25+
const tagCounts = {};
26+
27+
if (!data.projects || typeof data.projects !== "object") {
28+
console.error("Invalid projects data structure:", data.projects);
29+
return tagCounts;
30+
}
31+
32+
const projects = Object.values(data.projects);
33+
34+
for (const project of projects) {
35+
if (!project || typeof project !== "object") continue;
36+
37+
const tags = project.tags;
38+
39+
if (Array.isArray(tags)) {
40+
tags.forEach((tag) => {
41+
tagCounts[tag] = (tagCounts[tag] || 0) + 1;
42+
});
43+
}
44+
}
45+
46+
return tagCounts;
47+
}
48+
49+
function displayFamilies(familyCounts) {
50+
const familiesContainer = document.getElementById("product-families-list");
51+
familiesContainer.innerHTML = "";
52+
53+
const sortedFamilies = Object.keys(familyCounts).sort();
54+
55+
sortedFamilies.forEach((family) => {
56+
const familyCount = familyCounts[family];
57+
58+
const familyRow = document.createElement("div");
59+
familyRow.className = "family-row";
60+
61+
const checkbox = document.createElement("input");
62+
checkbox.type = "checkbox";
63+
checkbox.id = `family-${CSS.escape(family)}`;
64+
checkbox.addEventListener("change", handleFamilySelection);
65+
66+
const familyName = document.createElement("span");
67+
familyName.className = "family-name";
68+
familyName.textContent = family;
69+
70+
const familyCountElem = document.createElement("span");
71+
familyCountElem.className = "family-count";
72+
familyCountElem.textContent = `(${familyCount})`;
73+
74+
familyRow.appendChild(checkbox);
75+
familyRow.appendChild(familyName);
76+
//familyRow.appendChild(familyCountElem);
77+
78+
familiesContainer.appendChild(familyRow);
79+
});
80+
}
81+
82+
function displayTags(tagCounts) {
83+
const tagsContainer = document.getElementById("product-tags-list");
84+
tagsContainer.innerHTML = "";
85+
86+
const sortedTags = Object.keys(tagCounts).sort();
87+
88+
sortedTags.forEach((tag) => {
89+
const tagCount = tagCounts[tag];
90+
91+
const tagRow = document.createElement("div");
92+
tagRow.className = "tag-row";
93+
94+
const checkbox = document.createElement("input");
95+
checkbox.type = "checkbox";
96+
checkbox.id = `tag-${CSS.escape(tag)}`;
97+
checkbox.addEventListener("change", handleTagSelection);
98+
99+
const tagName = document.createElement("span");
100+
tagName.className = "tag-name";
101+
tagName.textContent = tag;
102+
103+
const tagCountElem = document.createElement("span");
104+
tagCountElem.className = "tag-count";
105+
tagCountElem.textContent = `(${tagCount})`;
106+
107+
tagRow.appendChild(checkbox);
108+
tagRow.appendChild(tagName);
109+
//tagRow.appendChild(tagCountElem);
110+
111+
tagsContainer.appendChild(tagRow);
112+
});
113+
}
114+
115+
function handleFamilySelection() {
116+
const selectedFamilies = Array.from(
117+
document.querySelectorAll(
118+
'#product-families-list input[type="checkbox"]:checked',
119+
),
120+
).map((checkbox) =>
121+
checkbox.id.replace("family-", "").replace("\\ ", "-").toLowerCase(),
122+
);
123+
124+
console.log("Selected families:", selectedFamilies);
125+
126+
const projectCards = document.querySelectorAll(".project-card");
127+
128+
projectCards.forEach((card) => {
129+
const family = card.getAttribute("data-family").toLowerCase();
130+
console.log("Family:", family);
131+
card.style.display =
132+
selectedFamilies.length === 0 || selectedFamilies.includes(family)
133+
? "flex"
134+
: "none";
135+
});
136+
}
137+
138+
function handleTagSelection() {
139+
const selectedTags = Array.from(
140+
document.querySelectorAll(
141+
'#product-tags-list input[type="checkbox"]:checked',
142+
),
143+
).map((checkbox) =>
144+
checkbox.id.replace("tag-", "").replace("\\ ", "-").toLowerCase(),
145+
);
146+
147+
console.log("Selected tags:", selectedTags);
148+
149+
const projectCards = document.querySelectorAll(".project-card");
150+
151+
projectCards.forEach((card) => {
152+
const rawTags = card.getAttribute("data-tags");
153+
154+
if (!rawTags) {
155+
card.style.display = "none";
156+
return;
157+
}
158+
159+
// Parse the data-tags string
160+
let cardTags = [];
161+
try {
162+
cardTags = JSON.parse(rawTags.replace(/'/g, '"'));
163+
} catch (error) {
164+
console.error("Error parsing data-tags:", rawTags, error);
165+
card.style.display = "none";
166+
return;
167+
}
168+
169+
const cardTagsLower = cardTags.map((tag) => tag.toLowerCase());
170+
const hasMatchingTag = selectedTags.some((tag) =>
171+
cardTagsLower.includes(tag),
172+
);
173+
174+
card.style.display =
175+
selectedTags.length === 0 || hasMatchingTag ? "flex" : "none";
176+
});
177+
}
178+
179+
function initializeAllCards() {
180+
const articleElement = document.querySelector("article");
181+
const projects = articleElement.querySelectorAll(".project-card");
182+
projects.forEach((project) => {
183+
project.style.display = "flex";
184+
});
185+
}
186+
187+
fetch("_static/projects.json")
188+
.then((response) => {
189+
if (!response.ok) {
190+
throw new Error(`HTTP error! Status: ${response.status}`);
191+
}
192+
return response.json();
193+
})
194+
.then((data) => {
195+
// Display families
196+
const familyCounts = collectFamilies(data);
197+
displayFamilies(familyCounts);
198+
199+
// Display tags
200+
const tagCounts = collectTags(data);
201+
displayTags(tagCounts);
202+
203+
// Render all cards
204+
initializeAllCards();
205+
})
206+
.catch((error) => {
207+
console.error("Error fetching the projects data:", error);
208+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<div class="landing-page-sidebar">
2+
3+
<!-- Product families -->
4+
<div class="landing-page-sidebar-section product-families">
5+
<span>Product families</span>
6+
<div id="product-families-list"></div>
7+
<a class="show-more">Show more</a>
8+
</div>
9+
10+
<hr>
11+
12+
<!-- Tags -->
13+
<div class="landing-page-sidebar-section product-tags">
14+
<span>Tags</span>
15+
<div id="product-tags-list"></div>
16+
<a class="show-more">Show more</a>
17+
</div>
18+
19+
</div>

0 commit comments

Comments
 (0)