Skip to content

Commit 89ac96f

Browse files
Add a new page for fundable projects.
1 parent 4b4d0d8 commit 89ac96f

35 files changed

+11138
-2
lines changed

docusaurus.config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,13 @@ const config: Config = {
110110
className: "custom_navbar_item",
111111
label: "Blog",
112112
position: "left",
113+
},
114+
{
115+
to: "/fundable/",
116+
className: "custom_navbar_item",
117+
label: "Fundable projects",
118+
position: "right",
119+
className:"fundable_projects"
113120
},
114121
{
115122
to: "/contact/",

src/components/footer/Footer.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,16 @@ export default function Footer() {
6565
</li>
6666
</ul>
6767
</div>
68+
<div className="col flex-horizontally-centered">
69+
<ul>
70+
<li>
71+
<Link href={"/fundable"}>Fundable projects</Link>
72+
</li>
73+
<li>
74+
<Link href={"/contact"}>Contact us</Link>
75+
</li>
76+
</ul>
77+
</div>
6878
</div>
6979
</div>
7080
</div>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import styles from "./styles.module.css";
2+
import Link from "@docusaurus/Link";
3+
import GHPicture from "@site/static/img/socialmedias/GH.svg";
4+
import LinkedInPicture from "@site/static/img/socialmedias/LinkedIn.svg";
5+
import BlueskyPicture from "@site/static/img/socialmedias/Bluesky.svg";
6+
import MastodonPicture from "@site/static/img/socialmedias/Mastodon.svg";
7+
8+
export default function IconContainer({ project }) {
9+
const icons = project.icons
10+
return (
11+
12+
13+
<div className={styles.icon_container}>
14+
{icons.map((Icon, index) => (
15+
<div key={index} className={styles.iconWrapper}>
16+
<Icon height={"42px"} width={"42px"}
17+
alt={
18+
"Icon for the fundable project."
19+
} />
20+
</div>
21+
))}
22+
</div>
23+
);
24+
25+
26+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import styles from "./styles.module.css";
2+
import React from "react";
3+
4+
export default function LargeProjectCard({ project }) {
5+
return (
6+
<div className={styles.large_project_card}>
7+
<div className={"container"}>
8+
<div className={"row padding-none"}>
9+
<div className="col col--12 col--offset-1">
10+
<div className={styles.large_card_project_category}>
11+
{project.category}
12+
</div>
13+
<div className={styles.large_card_project_title}>{project.title}</div>
14+
</div>
15+
</div>
16+
<div className="row">
17+
<div className="col col--10 col--offset-1">
18+
<div className={styles.large_project_card_text_container}></div>
19+
<div className={styles.large_project_card_section_title}>Overview</div>
20+
<div className={styles.large_project_card_text}>
21+
<project.description />
22+
</div>
23+
</div>
24+
</div>
25+
26+
</div>
27+
</div>
28+
);
29+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { useHistory, useLocation } from "@docusaurus/router";
2+
import { useEffect } from "react";
3+
import styles from "./styles.module.css";
4+
import LargeProjectCard from "./LargeProjectCard";
5+
import { getCategoryFromProjectTitle } from ".";
6+
import FundableProjects from ".";
7+
import Layout from "@theme/Layout";
8+
import { Route } from 'react-router-dom';
9+
10+
11+
export default function LargeProjectCardPage() {
12+
const location = useLocation();
13+
const history = useHistory();
14+
15+
useEffect(() => {
16+
if (location.state?.fromFundable) {
17+
window.scrollTo({ top: location.state.scrollY ?? 0, behavior: 'auto' });
18+
}
19+
}, []);
20+
21+
const handleOverlayClick = () => {
22+
const scrollY = location.state?.scrollY;
23+
setTimeout(() => {
24+
if (scrollY !== undefined) {
25+
window.scrollTo({ top: scrollY, behavior: 'auto' });
26+
}
27+
}, 0);
28+
history.replace('/fundable');
29+
};
30+
31+
const handleClose = () => {
32+
const scrollY = location.state?.scrollY;
33+
if (location.state?.fromFundable) {
34+
history.replace('/fundable');
35+
36+
setTimeout(() => {
37+
if (scrollY !== undefined) {
38+
window.scrollTo({ top: scrollY, behavior: 'auto' });
39+
}
40+
}, 0);
41+
} else {
42+
history.goBack();
43+
}
44+
}
45+
return (
46+
<Layout>
47+
<FundableProjects />
48+
<Route
49+
path="/fundable/:shortTitle"
50+
render={({ match }) => {
51+
const { shortTitle } = match.params; /* extract the dynamic part from the url i.e. the shortTitle*/
52+
const projectsByCategory = getCategoryFromProjectTitle(shortTitle);
53+
console.log('projectsByCategory:', projectsByCategory);
54+
const project = projectsByCategory.find((project) => project.shortTitle.replace(/\s+/g, '') === shortTitle);
55+
if (!project) return null;
56+
57+
return (
58+
<div className={styles.modal_overlay} onClick={handleOverlayClick}>
59+
<div
60+
className={styles.modal_content}
61+
onClick={(e) => e.stopPropagation()}
62+
>
63+
<button
64+
className="close-button"
65+
style={{
66+
position: "absolute",
67+
top: "10px",
68+
right: "10px",
69+
}}
70+
onClick={handleClose}
71+
/>
72+
<LargeProjectCard project={project} />
73+
</div>
74+
</div>
75+
);
76+
}}
77+
/>
78+
</Layout>
79+
)
80+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// src/components/ScrollSidebar.js
2+
import React, { useEffect, useState } from 'react';
3+
import styles from "./styles.module.css";
4+
5+
const sections = [
6+
{ id: 'jupyter-ecosystem', label: 'Jupyter Ecosystem' },
7+
{ id: 'project-management', label: 'Project Management' },
8+
];
9+
10+
export default function MenuSideBar() {
11+
const [activeSectionId, setActiveSectionId] = useState(null);
12+
13+
useEffect(() => {
14+
const handleScroll = () => {
15+
const scrollPosition = window.scrollY + 200;
16+
for (const section of sections) {
17+
const element = document.getElementById(section.id);
18+
if (element && element.offsetTop <= scrollPosition) {
19+
setActiveSectionId(section.id);
20+
}
21+
}
22+
};
23+
window.addEventListener('scroll', handleScroll);
24+
handleScroll();
25+
return () => window.removeEventListener('scroll', handleScroll);
26+
}, []);
27+
28+
return (
29+
<div className={styles.menu_sidebar_container}>
30+
<aside className={styles.menu_sidebar}>
31+
<ul style={{ listStyle: 'none', padding: "0px" }}>
32+
{sections.map((section) => (
33+
<li key={section.id}>
34+
<a
35+
href={`#${section.id}`}
36+
className={`${activeSectionId === section.id ? styles.active_section : ''}`}
37+
>
38+
<span className={styles.indicator} />
39+
<span className={styles.menu_sidebar_item}>{section.label}</span>
40+
</a>
41+
42+
</li>
43+
))}
44+
</ul>
45+
</aside>
46+
</div>
47+
);
48+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from "react";
2+
3+
export default function ProgressBar({ value = 0, color = '#4caf50' }) {
4+
return (
5+
6+
<div style={{
7+
background: '#eee',
8+
borderRadius: '4px',
9+
border: 'solid 0.5px',
10+
height: '10px',
11+
width: '100px',
12+
margin: '10px 0'
13+
}}>
14+
15+
<div style={{
16+
width: `${value}%`,
17+
background: color,
18+
border: 'solid 0.5px',
19+
height: '100%',
20+
borderRadius: '4px',
21+
transition: 'width 0.3s ease-in-out',
22+
}} />
23+
</div>
24+
);
25+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import styles from "./styles.module.css";
2+
import { SmallProjectCard } from "./SmallProjectCard";
3+
4+
5+
export default function ProjectCategory({ projectCategoryName, projectCategory }) {
6+
return (
7+
<div className={styles.project_category_container}>
8+
<h2 className={styles.category_header} style={{margin: "0px"}}> {projectCategoryName }</h2>
9+
<div className={"container"}>
10+
<ul className="row padding-none row-with-margin-top">
11+
{projectCategory.map((project) => (
12+
<li className="cards-list" key={project.shortTitle}>
13+
<div className="col" style={{justifyContent: "left"}}>
14+
<SmallProjectCard project={project} />
15+
</div>
16+
</li>
17+
))}
18+
</ul>
19+
</div>
20+
</div>
21+
);
22+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import styles from "./styles.module.css";
2+
import ProgressBar from "./ProgressBar";
3+
import { useHistory } from "@docusaurus/router";
4+
import IconContainer from "./IconContainer";
5+
6+
export function SmallProjectCard({ project }) {
7+
const history = useHistory();
8+
9+
function openDialog() {
10+
const shortTitle = project.shortTitle.replace(/\s+/g, '');
11+
12+
history.push({
13+
pathname: `/fundable/${shortTitle}`,
14+
state: { fromFundable: true, scrollY: window.scrollY, },
15+
});
16+
}
17+
18+
19+
return (
20+
<div onClick={openDialog}>
21+
<div className={"card" + " " + styles.small_project_card}>
22+
<div className="card__header" style={{padding: "0"}}>
23+
<div
24+
className={styles.project_title
25+
}
26+
>
27+
{project.title}
28+
</div>
29+
</div>
30+
<div className="card__body" style={{padding: "0"}}>
31+
<div style={{display: "flex"}}>
32+
<div>
33+
<div><IconContainer project={project}/></div>
34+
<div
35+
className={styles.project_catch_up_phrase}
36+
>
37+
{project.catchUpPhrase}
38+
39+
</div>
40+
<div style={{ fontSize: "16px", padding: "8px 0" }}>
41+
Indicative Price: {project.price}
42+
</div>
43+
44+
<div style={{ fontSize: "16px", padding: "8px 0" }}>
45+
Shareable between {project.maxNbOfFunders} funder(s).
46+
</div>
47+
<div style={{ fontSize: "16px", padding: "8px 0" }}>
48+
Currently this project is supported by {project.currentNbOfFunders} funder(s).
49+
</div>
50+
<div style={{ fontSize: "16px", padding: "8px 0" }}>
51+
Financed at {project.currentFundingPercentage} %
52+
</div>
53+
<div>
54+
<ProgressBar value={project.currentFundingPercentage} color={'var(--ifm-color-primary-p1'}/>
55+
</div>
56+
</div>
57+
</div>
58+
</div>
59+
</div>
60+
61+
</div>
62+
)
63+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Emscripten-forge is a conda package distribution specifically designed for WebAssembly. When combined with JupyterLite and the jupyterlite-xeus extension, it enables easy deployment of JupyterLite with a preconfigured conda environment that includes essential packages like NumPy, Pandas, Matplotlib, and more.
2+
3+
While the number of available emscripten-forge packages is growing quickly, many packages are still missing from the ecosystem.
4+
5+
We will be working on adding new packages upon request.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Similar to QGIS, JupyterGIS currently offers a set of vector processing and conversion tools such as buffer creation, centroid calculation, and convex hull generation. These capabilities are powered by a GDAL WebAssembly (WASM) build running in the browser.
2+
3+
We will work on extending support to raster processing tools using the same underlying technology. Planned features (non-exhaustive and subject to request needs) include:
4+
5+
- Clipping by extent
6+
- Clipping by mask layer
7+
- Generating contours
8+
- Polygonizing raster data
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
JupyterGIS currently supports several vector processing and conversion tools such as buffer creation, centroid computation, and convex hull generation, similar to what QGIS offers. These features are powered by a GDAL WebAssembly (WASM) build and are currently available only through the JupyterGIS user interface.
2+
3+
We plan to extend these capabilities to the JupyterGIS Python API, enabling users to access the same processing tools programmatically, just as they would via the UI. This functionality will be implemented using the GDAL Python bindings.

src/components/fundable/descriptions/JupyterLabParquetFileViewer.md

Whitespace-only changes.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Conversion of Jupyter notebooks to PDF currently relies on nbconvert in the backend, which in turns uses a headless browser for producing the PDF. We propose to directly perform the PDF conversion in the user's browser, which will simplify the architecture and make it function with JupyterLite.
2+
3+
Nbconvert heavily relies on Jinja2 templates for conversion to different formats.
4+
5+
We will utilize a JavaScript implementation of Jinja2 covering the required features of Jinja to produce a frontend version of nbconvert that does not require Python but still provides a good coverage of the nbconvert features, including the use of custom templates.

0 commit comments

Comments
 (0)